28557e8d5adab1ecc7918d6aee1d79784e50093a
[reactos.git] / reactos / base / services / dhcp / dhclient.c
1 /* $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $ */
2
3 /*
4 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6 * The Internet Software Consortium. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of The Internet Software Consortium nor the names
18 * of its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * This software has been written for the Internet Software Consortium
36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37 * Enterprises. To learn more about the Internet Software Consortium,
38 * see ``http://www.vix.com/isc''. To learn more about Vixie
39 * Enterprises, see ``http://www.vix.com''.
40 *
41 * This client was substantially modified and enhanced by Elliot Poger
42 * for use on Linux while he was working on the MosquitoNet project at
43 * Stanford.
44 *
45 * The current version owes much to Elliot's Linux enhancements, but
46 * was substantially reorganized and partially rewritten by Ted Lemon
47 * so as to use the same networking framework that the Internet Software
48 * Consortium DHCP server uses. Much system-specific configuration code
49 * was moved into a shell script so that as support for more operating
50 * systems is added, it will not be necessary to port and maintain
51 * system-specific configuration code to these operating systems - instead,
52 * the shell script can invoke the native tools to accomplish the same
53 * purpose.
54 */
55
56 #include "rosdhcp.h"
57 #include <winsock2.h>
58 #include "dhcpd.h"
59 #include "privsep.h"
60
61 #define PERIOD 0x2e
62 #define hyphenchar(c) ((c) == 0x2d)
63 #define bslashchar(c) ((c) == 0x5c)
64 #define periodchar(c) ((c) == PERIOD)
65 #define asterchar(c) ((c) == 0x2a)
66 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
67 ((c) >= 0x61 && (c) <= 0x7a))
68 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
69
70 #define borderchar(c) (alphachar(c) || digitchar(c))
71 #define middlechar(c) (borderchar(c) || hyphenchar(c))
72 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
73
74 unsigned long debug_trace_level = 0; /* DEBUG_ULTRA */
75
76 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
77 char *path_dhclient_db = NULL;
78
79 int log_perror = 1;
80 int privfd;
81 //int nullfd = -1;
82
83 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
84 struct in_addr inaddr_any;
85 struct sockaddr_in sockaddr_broadcast;
86
87 /*
88 * ASSERT_STATE() does nothing now; it used to be
89 * assert (state_is == state_shouldbe).
90 */
91 #define ASSERT_STATE(state_is, state_shouldbe) {}
92
93 #define TIME_MAX 2147483647
94
95 int log_priority;
96 int no_daemon;
97 int unknown_ok = 1;
98 int routefd;
99
100 void usage(void);
101 int check_option(struct client_lease *l, int option);
102 int ipv4addrs(char * buf);
103 int res_hnok(const char *dn);
104 char *option_as_string(unsigned int code, unsigned char *data, int len);
105 int fork_privchld(int, int);
106 int check_arp( struct interface_info *ip, struct client_lease *lp );
107
108 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
109
110 time_t scripttime;
111
112 /* XXX Implement me */
113 int check_arp( struct interface_info *ip, struct client_lease *lp ) {
114 return 1;
115 }
116
117 static VOID CALLBACK
118 DispatchMain(DWORD argc, LPTSTR *argv)
119 {
120 dispatch();
121 }
122
123 static SERVICE_TABLE_ENTRY ServiceTable[2] =
124 {
125 {TEXT("DHCP"), DispatchMain},
126 {NULL, NULL}
127 };
128
129 int
130 main(int argc, char *argv[])
131 {
132 ApiInit();
133 AdapterInit();
134 PipeInit();
135
136 tzset();
137
138 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
139 sockaddr_broadcast.sin_family = AF_INET;
140 sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
141 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
142 inaddr_any.s_addr = INADDR_ANY;
143
144 DH_DbgPrint(MID_TRACE,("DHCP Service Started\n"));
145
146 bootp_packet_handler = do_packet;
147
148 DH_DbgPrint(MID_TRACE,("Going into dispatch()\n"));
149
150 StartServiceCtrlDispatcher(ServiceTable);
151
152 /* not reached */
153 return (0);
154 }
155
156 void
157 usage(void)
158 {
159 // extern char *__progname;
160
161 // fprintf(stderr, "usage: %s [-dqu] ", __progname);
162 fprintf(stderr, "usage: dhclient [-dqu] ");
163 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
164 exit(1);
165 }
166
167 /*
168 * Individual States:
169 *
170 * Each routine is called from the dhclient_state_machine() in one of
171 * these conditions:
172 * -> entering INIT state
173 * -> recvpacket_flag == 0: timeout in this state
174 * -> otherwise: received a packet in this state
175 *
176 * Return conditions as handled by dhclient_state_machine():
177 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
178 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
179 * Returns 0: finish the nap which was interrupted for no good reason.
180 *
181 * Several per-interface variables are used to keep track of the process:
182 * active_lease: the lease that is being used on the interface
183 * (null pointer if not configured yet).
184 * offered_leases: leases corresponding to DHCPOFFER messages that have
185 * been sent to us by DHCP servers.
186 * acked_leases: leases corresponding to DHCPACK messages that have been
187 * sent to us by DHCP servers.
188 * sendpacket: DHCP packet we're trying to send.
189 * destination: IP address to send sendpacket to
190 * In addition, there are several relevant per-lease variables.
191 * T1_expiry, T2_expiry, lease_expiry: lease milestones
192 * In the active lease, these control the process of renewing the lease;
193 * In leases on the acked_leases list, this simply determines when we
194 * can no longer legitimately use the lease.
195 */
196
197 void
198 state_reboot(void *ipp)
199 {
200 struct interface_info *ip = ipp;
201 ULONG foo = (ULONG) GetTickCount();
202
203 /* If we don't remember an active lease, go straight to INIT. */
204 if (!ip->client->active || ip->client->active->is_bootp) {
205 state_init(ip);
206 return;
207 }
208
209 /* We are in the rebooting state. */
210 ip->client->state = S_REBOOTING;
211
212 /* make_request doesn't initialize xid because it normally comes
213 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
214 so pick an xid now. */
215 ip->client->xid = RtlRandom(&foo);
216
217 /* Make a DHCPREQUEST packet, and set appropriate per-interface
218 flags. */
219 make_request(ip, ip->client->active);
220 ip->client->destination = iaddr_broadcast;
221 time(&ip->client->first_sending);
222 ip->client->interval = ip->client->config->initial_interval;
223
224 /* Zap the medium list... */
225 ip->client->medium = NULL;
226
227 /* Send out the first DHCPREQUEST packet. */
228 send_request(ip);
229 }
230
231 /*
232 * Called when a lease has completely expired and we've
233 * been unable to renew it.
234 */
235 void
236 state_init(void *ipp)
237 {
238 struct interface_info *ip = ipp;
239
240 ASSERT_STATE(state, S_INIT);
241
242 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
243 flags. */
244 make_discover(ip, ip->client->active);
245 ip->client->xid = ip->client->packet.xid;
246 ip->client->destination = iaddr_broadcast;
247 ip->client->state = S_SELECTING;
248 time(&ip->client->first_sending);
249 ip->client->interval = ip->client->config->initial_interval;
250
251 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
252 to go out. */
253 send_discover(ip);
254 }
255
256 /*
257 * state_selecting is called when one or more DHCPOFFER packets
258 * have been received and a configurable period of time has passed.
259 */
260 void
261 state_selecting(void *ipp)
262 {
263 struct interface_info *ip = ipp;
264 struct client_lease *lp, *next, *picked;
265 time_t cur_time;
266
267 ASSERT_STATE(state, S_SELECTING);
268
269 time(&cur_time);
270
271 /* Cancel state_selecting and send_discover timeouts, since either
272 one could have got us here. */
273 cancel_timeout(state_selecting, ip);
274 cancel_timeout(send_discover, ip);
275
276 /* We have received one or more DHCPOFFER packets. Currently,
277 the only criterion by which we judge leases is whether or
278 not we get a response when we arp for them. */
279 picked = NULL;
280 for (lp = ip->client->offered_leases; lp; lp = next) {
281 next = lp->next;
282
283 /* Check to see if we got an ARPREPLY for the address
284 in this particular lease. */
285 if (!picked) {
286 if( !check_arp(ip,lp) ) goto freeit;
287 picked = lp;
288 picked->next = NULL;
289 } else {
290 freeit:
291 free_client_lease(lp);
292 }
293 }
294 ip->client->offered_leases = NULL;
295
296 /* If we just tossed all the leases we were offered, go back
297 to square one. */
298 if (!picked) {
299 ip->client->state = S_INIT;
300 state_init(ip);
301 return;
302 }
303
304 /* If it was a BOOTREPLY, we can just take the address right now. */
305 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
306 ip->client->new = picked;
307
308 /* Make up some lease expiry times
309 XXX these should be configurable. */
310 ip->client->new->expiry = cur_time + 12000;
311 ip->client->new->renewal += cur_time + 8000;
312 ip->client->new->rebind += cur_time + 10000;
313
314 ip->client->state = S_REQUESTING;
315
316 /* Bind to the address we received. */
317 bind_lease(ip);
318 return;
319 }
320
321 /* Go to the REQUESTING state. */
322 ip->client->destination = iaddr_broadcast;
323 ip->client->state = S_REQUESTING;
324 ip->client->first_sending = cur_time;
325 ip->client->interval = ip->client->config->initial_interval;
326
327 /* Make a DHCPREQUEST packet from the lease we picked. */
328 make_request(ip, picked);
329 ip->client->xid = ip->client->packet.xid;
330
331 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
332 free_client_lease(picked);
333
334 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
335 send_request(ip);
336 }
337
338 /* state_requesting is called when we receive a DHCPACK message after
339 having sent out one or more DHCPREQUEST packets. */
340
341 void
342 dhcpack(struct packet *packet)
343 {
344 struct interface_info *ip = packet->interface;
345 struct client_lease *lease;
346 time_t cur_time;
347
348 time(&cur_time);
349
350 /* If we're not receptive to an offer right now, or if the offer
351 has an unrecognizable transaction id, then just drop it. */
352 if (packet->interface->client->xid != packet->raw->xid ||
353 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
354 (memcmp(packet->interface->hw_address.haddr,
355 packet->raw->chaddr, packet->raw->hlen)))
356 return;
357
358 if (ip->client->state != S_REBOOTING &&
359 ip->client->state != S_REQUESTING &&
360 ip->client->state != S_RENEWING &&
361 ip->client->state != S_REBINDING)
362 return;
363
364 note("DHCPACK from %s", piaddr(packet->client_addr));
365
366 lease = packet_to_lease(packet);
367 if (!lease) {
368 note("packet_to_lease failed.");
369 return;
370 }
371
372 ip->client->new = lease;
373
374 /* Stop resending DHCPREQUEST. */
375 cancel_timeout(send_request, ip);
376
377 /* Figure out the lease time. */
378 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
379 ip->client->new->expiry = getULong(
380 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
381 else
382 ip->client->new->expiry = DHCP_DEFAULT_LEASE_TIME;
383 /* A number that looks negative here is really just very large,
384 because the lease expiry offset is unsigned. */
385 if (ip->client->new->expiry < 0)
386 ip->client->new->expiry = TIME_MAX;
387 /* XXX should be fixed by resetting the client state */
388 if (ip->client->new->expiry < 60)
389 ip->client->new->expiry = 60;
390
391 /* Take the server-provided renewal time if there is one;
392 otherwise figure it out according to the spec. */
393 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
394 ip->client->new->renewal = getULong(
395 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
396 else
397 ip->client->new->renewal = ip->client->new->expiry / 2;
398
399 /* Same deal with the rebind time. */
400 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
401 ip->client->new->rebind = getULong(
402 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
403 else
404 ip->client->new->rebind = ip->client->new->renewal +
405 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
406
407 #ifdef __REACTOS__
408 ip->client->new->obtained = cur_time;
409 #endif
410 ip->client->new->expiry += cur_time;
411 /* Lease lengths can never be negative. */
412 if (ip->client->new->expiry < cur_time)
413 ip->client->new->expiry = TIME_MAX;
414 ip->client->new->renewal += cur_time;
415 if (ip->client->new->renewal < cur_time)
416 ip->client->new->renewal = TIME_MAX;
417 ip->client->new->rebind += cur_time;
418 if (ip->client->new->rebind < cur_time)
419 ip->client->new->rebind = TIME_MAX;
420
421 bind_lease(ip);
422 }
423
424 void set_name_servers( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
425 CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
426 HKEY RegKey;
427
428 strcat(Buffer, Adapter->DhclientInfo.name);
429 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &RegKey ) != ERROR_SUCCESS)
430 return;
431
432
433 if( new_lease->options[DHO_DOMAIN_NAME_SERVERS].len ) {
434
435 struct iaddr nameserver;
436 char *nsbuf;
437 int i, addrs =
438 new_lease->options[DHO_DOMAIN_NAME_SERVERS].len / sizeof(ULONG);
439
440 nsbuf = malloc( addrs * sizeof(IP_ADDRESS_STRING) );
441
442 if( nsbuf) {
443 nsbuf[0] = 0;
444 for( i = 0; i < addrs; i++ ) {
445 nameserver.len = sizeof(ULONG);
446 memcpy( nameserver.iabuf,
447 new_lease->options[DHO_DOMAIN_NAME_SERVERS].data +
448 (i * sizeof(ULONG)), sizeof(ULONG) );
449 strcat( nsbuf, piaddr(nameserver) );
450 if( i != addrs-1 ) strcat( nsbuf, "," );
451 }
452
453 DH_DbgPrint(MID_TRACE,("Setting DhcpNameserver: %s\n", nsbuf));
454
455 RegSetValueExA( RegKey, "DhcpNameServer", 0, REG_SZ,
456 (LPBYTE)nsbuf, strlen(nsbuf) + 1 );
457 free( nsbuf );
458 }
459
460 } else {
461 RegDeleteValueW( RegKey, L"DhcpNameServer" );
462 }
463
464 RegCloseKey( RegKey );
465
466 }
467
468 void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
469 CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
470 struct iaddr netmask;
471 HKEY hkey;
472 int i;
473 DWORD dwEnableDHCP;
474
475 strcat(Buffer, Adapter->DhclientInfo.name);
476 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS)
477 hkey = NULL;
478
479
480 if( Adapter->NteContext )
481 DeleteIPAddress( Adapter->NteContext );
482
483 /* Set up our default router if we got one from the DHCP server */
484 if( new_lease->options[DHO_SUBNET_MASK].len ) {
485 NTSTATUS Status;
486
487 memcpy( netmask.iabuf,
488 new_lease->options[DHO_SUBNET_MASK].data,
489 new_lease->options[DHO_SUBNET_MASK].len );
490 Status = AddIPAddress
491 ( *((ULONG*)new_lease->address.iabuf),
492 *((ULONG*)netmask.iabuf),
493 Adapter->IfMib.dwIndex,
494 &Adapter->NteContext,
495 &Adapter->NteInstance );
496 if (hkey) {
497 RegSetValueExA(hkey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)piaddr(new_lease->address), strlen(piaddr(new_lease->address))+1);
498 Buffer[0] = '\0';
499 for(i = 0; i < new_lease->options[DHO_SUBNET_MASK].len; i++)
500 {
501 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_SUBNET_MASK].data[i]);
502 if (i + 1 < new_lease->options[DHO_SUBNET_MASK].len)
503 strcat(Buffer, ".");
504 }
505 RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
506 RegSetValueExA(hkey, "IPAddress", 0, REG_SZ, (LPBYTE)"0.0.0.0", 8);
507 RegSetValueExA(hkey, "SubnetMask", 0, REG_SZ, (LPBYTE)"0.0.0.0", 8);
508 dwEnableDHCP = 1;
509 RegSetValueExA(hkey, "EnableDHCP", 0, REG_DWORD, (LPBYTE)&dwEnableDHCP, sizeof(DWORD));
510 }
511
512 if( !NT_SUCCESS(Status) )
513 warning("AddIPAddress: %lx\n", Status);
514 }
515
516 if( new_lease->options[DHO_ROUTERS].len ) {
517 NTSTATUS Status;
518
519 Adapter->RouterMib.dwForwardDest = 0; /* Default route */
520 Adapter->RouterMib.dwForwardMask = 0;
521 Adapter->RouterMib.dwForwardMetric1 = 1;
522
523 if( Adapter->RouterMib.dwForwardNextHop ) {
524 /* If we set a default route before, delete it before continuing */
525 DeleteIpForwardEntry( &Adapter->RouterMib );
526 }
527
528 Adapter->RouterMib.dwForwardNextHop =
529 *((ULONG*)new_lease->options[DHO_ROUTERS].data);
530
531 Status = CreateIpForwardEntry( &Adapter->RouterMib );
532
533 if( !NT_SUCCESS(Status) )
534 warning("CreateIpForwardEntry: %lx\n", Status);
535
536 if (hkey) {
537 Buffer[0] = '\0';
538 for(i = 0; i < new_lease->options[DHO_ROUTERS].len; i++)
539 {
540 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_ROUTERS].data[i]);
541 if (i + 1 < new_lease->options[DHO_ROUTERS].len)
542 strcat(Buffer, ".");
543 }
544 RegSetValueExA(hkey, "DhcpDefaultGateway", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
545 RegSetValueExA(hkey, "DefaultGateway", 0, REG_SZ, (LPBYTE)"0.0.0.0", 8);
546 }
547 }
548
549 if (hkey)
550 RegCloseKey(hkey);
551 }
552
553
554 void
555 bind_lease(struct interface_info *ip)
556 {
557 PDHCP_ADAPTER Adapter;
558 struct client_lease *new_lease = ip->client->new;
559 time_t cur_time;
560
561 time(&cur_time);
562
563 /* Remember the medium. */
564 ip->client->new->medium = ip->client->medium;
565 ip->client->active = ip->client->new;
566 ip->client->new = NULL;
567
568 /* Set up a timeout to start the renewal process. */
569 /* Timeout of zero means no timeout (some implementations seem to use
570 * one day).
571 */
572 if( ip->client->active->renewal - cur_time )
573 add_timeout(ip->client->active->renewal, state_bound, ip);
574
575 note("bound to %s -- renewal in %ld seconds.",
576 piaddr(ip->client->active->address),
577 (long int)(ip->client->active->renewal - cur_time));
578
579 ip->client->state = S_BOUND;
580
581 Adapter = AdapterFindInfo( ip );
582
583 if( Adapter ) setup_adapter( Adapter, new_lease );
584 else warning("Could not find adapter for info %p\n", ip);
585
586 set_name_servers( Adapter, new_lease );
587 }
588
589 /*
590 * state_bound is called when we've successfully bound to a particular
591 * lease, but the renewal time on that lease has expired. We are
592 * expected to unicast a DHCPREQUEST to the server that gave us our
593 * original lease.
594 */
595 void
596 state_bound(void *ipp)
597 {
598 struct interface_info *ip = ipp;
599
600 ASSERT_STATE(state, S_BOUND);
601
602 /* T1 has expired. */
603 make_request(ip, ip->client->active);
604 ip->client->xid = ip->client->packet.xid;
605
606 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
607 memcpy(ip->client->destination.iabuf, ip->client->active->
608 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
609 ip->client->destination.len = 4;
610 } else
611 ip->client->destination = iaddr_broadcast;
612
613 time(&ip->client->first_sending);
614 ip->client->interval = ip->client->config->initial_interval;
615 ip->client->state = S_RENEWING;
616
617 /* Send the first packet immediately. */
618 send_request(ip);
619 }
620
621 void
622 bootp(struct packet *packet)
623 {
624 struct iaddrlist *ap;
625
626 if (packet->raw->op != BOOTREPLY)
627 return;
628
629 /* If there's a reject list, make sure this packet's sender isn't
630 on it. */
631 for (ap = packet->interface->client->config->reject_list;
632 ap; ap = ap->next) {
633 if (addr_eq(packet->client_addr, ap->addr)) {
634 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
635 return;
636 }
637 }
638 dhcpoffer(packet);
639 }
640
641 void
642 dhcp(struct packet *packet)
643 {
644 struct iaddrlist *ap;
645 void (*handler)(struct packet *);
646 char *type;
647
648 switch (packet->packet_type) {
649 case DHCPOFFER:
650 handler = dhcpoffer;
651 type = "DHCPOFFER";
652 break;
653 case DHCPNAK:
654 handler = dhcpnak;
655 type = "DHCPNACK";
656 break;
657 case DHCPACK:
658 handler = dhcpack;
659 type = "DHCPACK";
660 break;
661 default:
662 return;
663 }
664
665 /* If there's a reject list, make sure this packet's sender isn't
666 on it. */
667 for (ap = packet->interface->client->config->reject_list;
668 ap; ap = ap->next) {
669 if (addr_eq(packet->client_addr, ap->addr)) {
670 note("%s from %s rejected.", type, piaddr(ap->addr));
671 return;
672 }
673 }
674 (*handler)(packet);
675 }
676
677 void
678 dhcpoffer(struct packet *packet)
679 {
680 struct interface_info *ip = packet->interface;
681 struct client_lease *lease, *lp;
682 int i;
683 int arp_timeout_needed = 0, stop_selecting;
684 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
685 "DHCPOFFER" : "BOOTREPLY";
686 time_t cur_time;
687
688 time(&cur_time);
689
690 /* If we're not receptive to an offer right now, or if the offer
691 has an unrecognizable transaction id, then just drop it. */
692 if (ip->client->state != S_SELECTING ||
693 packet->interface->client->xid != packet->raw->xid ||
694 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
695 (memcmp(packet->interface->hw_address.haddr,
696 packet->raw->chaddr, packet->raw->hlen)))
697 return;
698
699 note("%s from %s", name, piaddr(packet->client_addr));
700
701
702 /* If this lease doesn't supply the minimum required parameters,
703 blow it off. */
704 for (i = 0; ip->client->config->required_options[i]; i++) {
705 if (!packet->options[ip->client->config->
706 required_options[i]].len) {
707 note("%s isn't satisfactory.", name);
708 return;
709 }
710 }
711
712 /* If we've already seen this lease, don't record it again. */
713 for (lease = ip->client->offered_leases;
714 lease; lease = lease->next) {
715 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
716 !memcmp(lease->address.iabuf,
717 &packet->raw->yiaddr, lease->address.len)) {
718 debug("%s already seen.", name);
719 return;
720 }
721 }
722
723 lease = packet_to_lease(packet);
724 if (!lease) {
725 note("packet_to_lease failed.");
726 return;
727 }
728
729 /* If this lease was acquired through a BOOTREPLY, record that
730 fact. */
731 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
732 lease->is_bootp = 1;
733
734 /* Record the medium under which this lease was offered. */
735 lease->medium = ip->client->medium;
736
737 /* Send out an ARP Request for the offered IP address. */
738 if( !check_arp( ip, lease ) ) {
739 note("Arp check failed\n");
740 return;
741 }
742
743 /* Figure out when we're supposed to stop selecting. */
744 stop_selecting =
745 ip->client->first_sending + ip->client->config->select_interval;
746
747 /* If this is the lease we asked for, put it at the head of the
748 list, and don't mess with the arp request timeout. */
749 if (lease->address.len == ip->client->requested_address.len &&
750 !memcmp(lease->address.iabuf,
751 ip->client->requested_address.iabuf,
752 ip->client->requested_address.len)) {
753 lease->next = ip->client->offered_leases;
754 ip->client->offered_leases = lease;
755 } else {
756 /* If we already have an offer, and arping for this
757 offer would take us past the selection timeout,
758 then don't extend the timeout - just hope for the
759 best. */
760 if (ip->client->offered_leases &&
761 (cur_time + arp_timeout_needed) > stop_selecting)
762 arp_timeout_needed = 0;
763
764 /* Put the lease at the end of the list. */
765 lease->next = NULL;
766 if (!ip->client->offered_leases)
767 ip->client->offered_leases = lease;
768 else {
769 for (lp = ip->client->offered_leases; lp->next;
770 lp = lp->next)
771 ; /* nothing */
772 lp->next = lease;
773 }
774 }
775
776 /* If we're supposed to stop selecting before we've had time
777 to wait for the ARPREPLY, add some delay to wait for
778 the ARPREPLY. */
779 if (stop_selecting - cur_time < arp_timeout_needed)
780 stop_selecting = cur_time + arp_timeout_needed;
781
782 /* If the selecting interval has expired, go immediately to
783 state_selecting(). Otherwise, time out into
784 state_selecting at the select interval. */
785 if (stop_selecting <= 0)
786 state_selecting(ip);
787 else {
788 add_timeout(stop_selecting, state_selecting, ip);
789 cancel_timeout(send_discover, ip);
790 }
791 }
792
793 /* Allocate a client_lease structure and initialize it from the parameters
794 in the specified packet. */
795
796 struct client_lease *
797 packet_to_lease(struct packet *packet)
798 {
799 struct client_lease *lease;
800 int i;
801
802 lease = malloc(sizeof(struct client_lease));
803
804 if (!lease) {
805 warning("dhcpoffer: no memory to record lease.");
806 return (NULL);
807 }
808
809 memset(lease, 0, sizeof(*lease));
810
811 /* Copy the lease options. */
812 for (i = 0; i < 256; i++) {
813 if (packet->options[i].len) {
814 lease->options[i].data =
815 malloc(packet->options[i].len + 1);
816 if (!lease->options[i].data) {
817 warning("dhcpoffer: no memory for option %d", i);
818 free_client_lease(lease);
819 return (NULL);
820 } else {
821 memcpy(lease->options[i].data,
822 packet->options[i].data,
823 packet->options[i].len);
824 lease->options[i].len =
825 packet->options[i].len;
826 lease->options[i].data[lease->options[i].len] =
827 0;
828 }
829 if (!check_option(lease,i)) {
830 /* ignore a bogus lease offer */
831 warning("Invalid lease option - ignoring offer");
832 free_client_lease(lease);
833 return (NULL);
834 }
835 }
836 }
837
838 lease->address.len = sizeof(packet->raw->yiaddr);
839 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
840 #ifdef __REACTOS__
841 lease->serveraddress.len = sizeof(packet->raw->siaddr);
842 memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len);
843 #endif
844
845 /* If the server name was filled out, copy it. */
846 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
847 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
848 packet->raw->sname[0]) {
849 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
850 if (!lease->server_name) {
851 warning("dhcpoffer: no memory for server name.");
852 free_client_lease(lease);
853 return (NULL);
854 }
855 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
856 lease->server_name[DHCP_SNAME_LEN]='\0';
857 if (!res_hnok(lease->server_name) ) {
858 warning("Bogus server name %s", lease->server_name );
859 free_client_lease(lease);
860 return (NULL);
861 }
862
863 }
864
865 /* Ditto for the filename. */
866 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
867 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
868 packet->raw->file[0]) {
869 /* Don't count on the NUL terminator. */
870 lease->filename = malloc(DHCP_FILE_LEN + 1);
871 if (!lease->filename) {
872 warning("dhcpoffer: no memory for filename.");
873 free_client_lease(lease);
874 return (NULL);
875 }
876 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
877 lease->filename[DHCP_FILE_LEN]='\0';
878 }
879 return lease;
880 }
881
882 void
883 dhcpnak(struct packet *packet)
884 {
885 struct interface_info *ip = packet->interface;
886
887 /* If we're not receptive to an offer right now, or if the offer
888 has an unrecognizable transaction id, then just drop it. */
889 if (packet->interface->client->xid != packet->raw->xid ||
890 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
891 (memcmp(packet->interface->hw_address.haddr,
892 packet->raw->chaddr, packet->raw->hlen)))
893 return;
894
895 if (ip->client->state != S_REBOOTING &&
896 ip->client->state != S_REQUESTING &&
897 ip->client->state != S_RENEWING &&
898 ip->client->state != S_REBINDING)
899 return;
900
901 note("DHCPNAK from %s", piaddr(packet->client_addr));
902
903 if (!ip->client->active) {
904 note("DHCPNAK with no active lease.\n");
905 return;
906 }
907
908 free_client_lease(ip->client->active);
909 ip->client->active = NULL;
910
911 /* Stop sending DHCPREQUEST packets... */
912 cancel_timeout(send_request, ip);
913
914 ip->client->state = S_INIT;
915 state_init(ip);
916 }
917
918 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
919 one after the right interval has expired. If we don't get an offer by
920 the time we reach the panic interval, call the panic function. */
921
922 void
923 send_discover(void *ipp)
924 {
925 struct interface_info *ip = ipp;
926 int interval, increase = 1;
927 time_t cur_time;
928
929 DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip));
930
931 time(&cur_time);
932
933 /* Figure out how long it's been since we started transmitting. */
934 interval = cur_time - ip->client->first_sending;
935
936 /* If we're past the panic timeout, call the script and tell it
937 we haven't found anything for this interface yet. */
938 if (interval > ip->client->config->timeout) {
939 state_panic(ip);
940 return;
941 }
942
943 /* If we're selecting media, try the whole list before doing
944 the exponential backoff, but if we've already received an
945 offer, stop looping, because we obviously have it right. */
946 if (!ip->client->offered_leases &&
947 ip->client->config->media) {
948 int fail = 0;
949
950 if (ip->client->medium) {
951 ip->client->medium = ip->client->medium->next;
952 increase = 0;
953 }
954 if (!ip->client->medium) {
955 if (fail)
956 error("No valid media types for %s!", ip->name);
957 ip->client->medium = ip->client->config->media;
958 increase = 1;
959 }
960
961 note("Trying medium \"%s\" %d", ip->client->medium->string,
962 increase);
963 /* XXX Support other media types eventually */
964 }
965
966 /*
967 * If we're supposed to increase the interval, do so. If it's
968 * currently zero (i.e., we haven't sent any packets yet), set
969 * it to one; otherwise, add to it a random number between zero
970 * and two times itself. On average, this means that it will
971 * double with every transmission.
972 */
973 if (increase) {
974 if (!ip->client->interval)
975 ip->client->interval =
976 ip->client->config->initial_interval;
977 else {
978 ip->client->interval += (rand() >> 2) %
979 (2 * ip->client->interval);
980 }
981
982 /* Don't backoff past cutoff. */
983 if (ip->client->interval >
984 ip->client->config->backoff_cutoff)
985 ip->client->interval =
986 ((ip->client->config->backoff_cutoff / 2)
987 + ((rand() >> 2) %
988 ip->client->config->backoff_cutoff));
989 } else if (!ip->client->interval)
990 ip->client->interval =
991 ip->client->config->initial_interval;
992
993 /* If the backoff would take us to the panic timeout, just use that
994 as the interval. */
995 if (cur_time + ip->client->interval >
996 ip->client->first_sending + ip->client->config->timeout)
997 ip->client->interval =
998 (ip->client->first_sending +
999 ip->client->config->timeout) - cur_time + 1;
1000
1001 /* Record the number of seconds since we started sending. */
1002 if (interval < 65536)
1003 ip->client->packet.secs = htons(interval);
1004 else
1005 ip->client->packet.secs = htons(65535);
1006 ip->client->secs = ip->client->packet.secs;
1007
1008 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1009 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1010 ntohs(sockaddr_broadcast.sin_port), (long int)ip->client->interval);
1011
1012 /* Send out a packet. */
1013 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1014 inaddr_any, &sockaddr_broadcast, NULL);
1015
1016 DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n",
1017 cur_time, cur_time + ip->client->interval));
1018
1019 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1020 }
1021
1022 /*
1023 * state_panic gets called if we haven't received any offers in a preset
1024 * amount of time. When this happens, we try to use existing leases
1025 * that haven't yet expired, and failing that, we call the client script
1026 * and hope it can do something.
1027 */
1028 void
1029 state_panic(void *ipp)
1030 {
1031 struct interface_info *ip = ipp;
1032 struct client_lease *loop = ip->client->active;
1033 struct client_lease *lp;
1034 time_t cur_time;
1035
1036 note("No DHCPOFFERS received.");
1037
1038 time(&cur_time);
1039
1040 /* We may not have an active lease, but we may have some
1041 predefined leases that we can try. */
1042 if (!ip->client->active && ip->client->leases)
1043 goto activate_next;
1044
1045 /* Run through the list of leases and see if one can be used. */
1046 while (ip->client->active) {
1047 if (ip->client->active->expiry > cur_time) {
1048 note("Trying recorded lease %s",
1049 piaddr(ip->client->active->address));
1050 /* Run the client script with the existing
1051 parameters. */
1052 script_init("TIMEOUT",
1053 ip->client->active->medium);
1054 script_write_params("new_", ip->client->active);
1055 if (ip->client->alias)
1056 script_write_params("alias_",
1057 ip->client->alias);
1058
1059 /* If the old lease is still good and doesn't
1060 yet need renewal, go into BOUND state and
1061 timeout at the renewal time. */
1062 if (cur_time <
1063 ip->client->active->renewal) {
1064 ip->client->state = S_BOUND;
1065 note("bound: renewal in %ld seconds.",
1066 (long int)(ip->client->active->renewal -
1067 cur_time));
1068 add_timeout(
1069 ip->client->active->renewal,
1070 state_bound, ip);
1071 } else {
1072 ip->client->state = S_BOUND;
1073 note("bound: immediate renewal.");
1074 state_bound(ip);
1075 }
1076 return;
1077 }
1078
1079 /* If there are no other leases, give up. */
1080 if (!ip->client->leases) {
1081 ip->client->leases = ip->client->active;
1082 ip->client->active = NULL;
1083 break;
1084 }
1085
1086 activate_next:
1087 /* Otherwise, put the active lease at the end of the
1088 lease list, and try another lease.. */
1089 for (lp = ip->client->leases; lp->next; lp = lp->next)
1090 ;
1091 lp->next = ip->client->active;
1092 if (lp->next)
1093 lp->next->next = NULL;
1094 ip->client->active = ip->client->leases;
1095 ip->client->leases = ip->client->leases->next;
1096
1097 /* If we already tried this lease, we've exhausted the
1098 set of leases, so we might as well give up for
1099 now. */
1100 if (ip->client->active == loop)
1101 break;
1102 else if (!loop)
1103 loop = ip->client->active;
1104 }
1105
1106 /* No leases were available, or what was available didn't work, so
1107 tell the shell script that we failed to allocate an address,
1108 and try again later. */
1109 note("No working leases in persistent database - sleeping.\n");
1110 ip->client->state = S_INIT;
1111 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1112 ip);
1113 /* XXX Take any failure actions necessary */
1114 }
1115
1116 void
1117 send_request(void *ipp)
1118 {
1119 struct interface_info *ip = ipp;
1120 struct sockaddr_in destination;
1121 struct in_addr from;
1122 int interval;
1123 time_t cur_time;
1124
1125 time(&cur_time);
1126
1127 /* Figure out how long it's been since we started transmitting. */
1128 interval = cur_time - ip->client->first_sending;
1129
1130 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1131 past the reboot timeout, go to INIT and see if we can
1132 DISCOVER an address... */
1133 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1134 means either that we're on a network with no DHCP server,
1135 or that our server is down. In the latter case, assuming
1136 that there is a backup DHCP server, DHCPDISCOVER will get
1137 us a new address, but we could also have successfully
1138 reused our old address. In the former case, we're hosed
1139 anyway. This is not a win-prone situation. */
1140 if ((ip->client->state == S_REBOOTING ||
1141 ip->client->state == S_REQUESTING) &&
1142 interval > ip->client->config->reboot_timeout) {
1143 ip->client->state = S_INIT;
1144 cancel_timeout(send_request, ip);
1145 state_init(ip);
1146 return;
1147 }
1148
1149 /* If we're in the reboot state, make sure the media is set up
1150 correctly. */
1151 if (ip->client->state == S_REBOOTING &&
1152 !ip->client->medium &&
1153 ip->client->active->medium ) {
1154 script_init("MEDIUM", ip->client->active->medium);
1155
1156 /* If the medium we chose won't fly, go to INIT state. */
1157 /* XXX Nothing for now */
1158
1159 /* Record the medium. */
1160 ip->client->medium = ip->client->active->medium;
1161 }
1162
1163 /* If the lease has expired, relinquish the address and go back
1164 to the INIT state. */
1165 if (ip->client->state != S_REQUESTING &&
1166 cur_time > ip->client->active->expiry) {
1167 PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
1168 /* Run the client script with the new parameters. */
1169 /* No script actions necessary in the expiry case */
1170 /* Now do a preinit on the interface so that we can
1171 discover a new address. */
1172
1173 if( Adapter )
1174 DeleteIPAddress( Adapter->NteContext );
1175
1176 ip->client->state = S_INIT;
1177 state_init(ip);
1178 return;
1179 }
1180
1181 /* Do the exponential backoff... */
1182 if (!ip->client->interval)
1183 ip->client->interval = ip->client->config->initial_interval;
1184 else
1185 ip->client->interval += ((rand() >> 2) %
1186 (2 * ip->client->interval));
1187
1188 /* Don't backoff past cutoff. */
1189 if (ip->client->interval >
1190 ip->client->config->backoff_cutoff)
1191 ip->client->interval =
1192 ((ip->client->config->backoff_cutoff / 2) +
1193 ((rand() >> 2) % ip->client->interval));
1194
1195 /* If the backoff would take us to the expiry time, just set the
1196 timeout to the expiry time. */
1197 if (ip->client->state != S_REQUESTING &&
1198 cur_time + ip->client->interval >
1199 ip->client->active->expiry)
1200 ip->client->interval =
1201 ip->client->active->expiry - cur_time + 1;
1202
1203 /* If the lease T2 time has elapsed, or if we're not yet bound,
1204 broadcast the DHCPREQUEST rather than unicasting. */
1205 memset(&destination, 0, sizeof(destination));
1206 if (ip->client->state == S_REQUESTING ||
1207 ip->client->state == S_REBOOTING ||
1208 cur_time > ip->client->active->rebind)
1209 destination.sin_addr.s_addr = INADDR_BROADCAST;
1210 else
1211 memcpy(&destination.sin_addr.s_addr,
1212 ip->client->destination.iabuf,
1213 sizeof(destination.sin_addr.s_addr));
1214 destination.sin_port = htons(REMOTE_PORT);
1215 destination.sin_family = AF_INET;
1216 // destination.sin_len = sizeof(destination);
1217
1218 if (ip->client->state != S_REQUESTING)
1219 memcpy(&from, ip->client->active->address.iabuf,
1220 sizeof(from));
1221 else
1222 from.s_addr = INADDR_ANY;
1223
1224 /* Record the number of seconds since we started sending. */
1225 if (ip->client->state == S_REQUESTING)
1226 ip->client->packet.secs = ip->client->secs;
1227 else {
1228 if (interval < 65536)
1229 ip->client->packet.secs = htons(interval);
1230 else
1231 ip->client->packet.secs = htons(65535);
1232 }
1233
1234 note("DHCPREQUEST on %s to %s port %d", ip->name,
1235 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1236
1237 /* Send out a packet. */
1238 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1239 from, &destination, NULL);
1240
1241 add_timeout(cur_time + ip->client->interval, send_request, ip);
1242 }
1243
1244 void
1245 send_decline(void *ipp)
1246 {
1247 struct interface_info *ip = ipp;
1248
1249 note("DHCPDECLINE on %s to %s port %d", ip->name,
1250 inet_ntoa(sockaddr_broadcast.sin_addr),
1251 ntohs(sockaddr_broadcast.sin_port));
1252
1253 /* Send out a packet. */
1254 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1255 inaddr_any, &sockaddr_broadcast, NULL);
1256 }
1257
1258 void
1259 make_discover(struct interface_info *ip, struct client_lease *lease)
1260 {
1261 unsigned char discover = DHCPDISCOVER;
1262 struct tree_cache *options[256];
1263 struct tree_cache option_elements[256];
1264 int i;
1265 ULONG foo = (ULONG) GetTickCount();
1266
1267 memset(option_elements, 0, sizeof(option_elements));
1268 memset(options, 0, sizeof(options));
1269 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1270
1271 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1272 i = DHO_DHCP_MESSAGE_TYPE;
1273 options[i] = &option_elements[i];
1274 options[i]->value = &discover;
1275 options[i]->len = sizeof(discover);
1276 options[i]->buf_size = sizeof(discover);
1277 options[i]->timeout = 0xFFFFFFFF;
1278
1279 /* Request the options we want */
1280 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1281 options[i] = &option_elements[i];
1282 options[i]->value = ip->client->config->requested_options;
1283 options[i]->len = ip->client->config->requested_option_count;
1284 options[i]->buf_size =
1285 ip->client->config->requested_option_count;
1286 options[i]->timeout = 0xFFFFFFFF;
1287
1288 /* If we had an address, try to get it again. */
1289 if (lease) {
1290 ip->client->requested_address = lease->address;
1291 i = DHO_DHCP_REQUESTED_ADDRESS;
1292 options[i] = &option_elements[i];
1293 options[i]->value = lease->address.iabuf;
1294 options[i]->len = lease->address.len;
1295 options[i]->buf_size = lease->address.len;
1296 options[i]->timeout = 0xFFFFFFFF;
1297 } else
1298 ip->client->requested_address.len = 0;
1299
1300 /* Send any options requested in the config file. */
1301 for (i = 0; i < 256; i++)
1302 if (!options[i] &&
1303 ip->client->config->send_options[i].data) {
1304 options[i] = &option_elements[i];
1305 options[i]->value =
1306 ip->client->config->send_options[i].data;
1307 options[i]->len =
1308 ip->client->config->send_options[i].len;
1309 options[i]->buf_size =
1310 ip->client->config->send_options[i].len;
1311 options[i]->timeout = 0xFFFFFFFF;
1312 }
1313
1314 /* Set up the option buffer... */
1315 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1316 options, 0, 0, 0, NULL, 0);
1317 if (ip->client->packet_length < BOOTP_MIN_LEN)
1318 ip->client->packet_length = BOOTP_MIN_LEN;
1319
1320 ip->client->packet.op = BOOTREQUEST;
1321 ip->client->packet.htype = ip->hw_address.htype;
1322 ip->client->packet.hlen = ip->hw_address.hlen;
1323 ip->client->packet.hops = 0;
1324 ip->client->packet.xid = RtlRandom(&foo);
1325 ip->client->packet.secs = 0; /* filled in by send_discover. */
1326 ip->client->packet.flags = 0;
1327
1328 memset(&(ip->client->packet.ciaddr),
1329 0, sizeof(ip->client->packet.ciaddr));
1330 memset(&(ip->client->packet.yiaddr),
1331 0, sizeof(ip->client->packet.yiaddr));
1332 memset(&(ip->client->packet.siaddr),
1333 0, sizeof(ip->client->packet.siaddr));
1334 memset(&(ip->client->packet.giaddr),
1335 0, sizeof(ip->client->packet.giaddr));
1336 memcpy(ip->client->packet.chaddr,
1337 ip->hw_address.haddr, ip->hw_address.hlen);
1338 }
1339
1340
1341 void
1342 make_request(struct interface_info *ip, struct client_lease * lease)
1343 {
1344 unsigned char request = DHCPREQUEST;
1345 struct tree_cache *options[256];
1346 struct tree_cache option_elements[256];
1347 int i;
1348
1349 memset(options, 0, sizeof(options));
1350 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1351
1352 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1353 i = DHO_DHCP_MESSAGE_TYPE;
1354 options[i] = &option_elements[i];
1355 options[i]->value = &request;
1356 options[i]->len = sizeof(request);
1357 options[i]->buf_size = sizeof(request);
1358 options[i]->timeout = 0xFFFFFFFF;
1359
1360 /* Request the options we want */
1361 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1362 options[i] = &option_elements[i];
1363 options[i]->value = ip->client->config->requested_options;
1364 options[i]->len = ip->client->config->requested_option_count;
1365 options[i]->buf_size =
1366 ip->client->config->requested_option_count;
1367 options[i]->timeout = 0xFFFFFFFF;
1368
1369 /* If we are requesting an address that hasn't yet been assigned
1370 to us, use the DHCP Requested Address option. */
1371 if (ip->client->state == S_REQUESTING) {
1372 /* Send back the server identifier... */
1373 i = DHO_DHCP_SERVER_IDENTIFIER;
1374 options[i] = &option_elements[i];
1375 options[i]->value = lease->options[i].data;
1376 options[i]->len = lease->options[i].len;
1377 options[i]->buf_size = lease->options[i].len;
1378 options[i]->timeout = 0xFFFFFFFF;
1379 }
1380 if (ip->client->state == S_REQUESTING ||
1381 ip->client->state == S_REBOOTING) {
1382 ip->client->requested_address = lease->address;
1383 i = DHO_DHCP_REQUESTED_ADDRESS;
1384 options[i] = &option_elements[i];
1385 options[i]->value = lease->address.iabuf;
1386 options[i]->len = lease->address.len;
1387 options[i]->buf_size = lease->address.len;
1388 options[i]->timeout = 0xFFFFFFFF;
1389 } else
1390 ip->client->requested_address.len = 0;
1391
1392 /* Send any options requested in the config file. */
1393 for (i = 0; i < 256; i++)
1394 if (!options[i] &&
1395 ip->client->config->send_options[i].data) {
1396 options[i] = &option_elements[i];
1397 options[i]->value =
1398 ip->client->config->send_options[i].data;
1399 options[i]->len =
1400 ip->client->config->send_options[i].len;
1401 options[i]->buf_size =
1402 ip->client->config->send_options[i].len;
1403 options[i]->timeout = 0xFFFFFFFF;
1404 }
1405
1406 /* Set up the option buffer... */
1407 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1408 options, 0, 0, 0, NULL, 0);
1409 if (ip->client->packet_length < BOOTP_MIN_LEN)
1410 ip->client->packet_length = BOOTP_MIN_LEN;
1411
1412 ip->client->packet.op = BOOTREQUEST;
1413 ip->client->packet.htype = ip->hw_address.htype;
1414 ip->client->packet.hlen = ip->hw_address.hlen;
1415 ip->client->packet.hops = 0;
1416 ip->client->packet.xid = ip->client->xid;
1417 ip->client->packet.secs = 0; /* Filled in by send_request. */
1418
1419 /* If we own the address we're requesting, put it in ciaddr;
1420 otherwise set ciaddr to zero. */
1421 if (ip->client->state == S_BOUND ||
1422 ip->client->state == S_RENEWING ||
1423 ip->client->state == S_REBINDING) {
1424 memcpy(&ip->client->packet.ciaddr,
1425 lease->address.iabuf, lease->address.len);
1426 ip->client->packet.flags = 0;
1427 } else {
1428 memset(&ip->client->packet.ciaddr, 0,
1429 sizeof(ip->client->packet.ciaddr));
1430 ip->client->packet.flags = 0;
1431 }
1432
1433 memset(&ip->client->packet.yiaddr, 0,
1434 sizeof(ip->client->packet.yiaddr));
1435 memset(&ip->client->packet.siaddr, 0,
1436 sizeof(ip->client->packet.siaddr));
1437 memset(&ip->client->packet.giaddr, 0,
1438 sizeof(ip->client->packet.giaddr));
1439 memcpy(ip->client->packet.chaddr,
1440 ip->hw_address.haddr, ip->hw_address.hlen);
1441 }
1442
1443 void
1444 make_decline(struct interface_info *ip, struct client_lease *lease)
1445 {
1446 struct tree_cache *options[256], message_type_tree;
1447 struct tree_cache requested_address_tree;
1448 struct tree_cache server_id_tree, client_id_tree;
1449 unsigned char decline = DHCPDECLINE;
1450 int i;
1451
1452 memset(options, 0, sizeof(options));
1453 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1454
1455 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1456 i = DHO_DHCP_MESSAGE_TYPE;
1457 options[i] = &message_type_tree;
1458 options[i]->value = &decline;
1459 options[i]->len = sizeof(decline);
1460 options[i]->buf_size = sizeof(decline);
1461 options[i]->timeout = 0xFFFFFFFF;
1462
1463 /* Send back the server identifier... */
1464 i = DHO_DHCP_SERVER_IDENTIFIER;
1465 options[i] = &server_id_tree;
1466 options[i]->value = lease->options[i].data;
1467 options[i]->len = lease->options[i].len;
1468 options[i]->buf_size = lease->options[i].len;
1469 options[i]->timeout = 0xFFFFFFFF;
1470
1471 /* Send back the address we're declining. */
1472 i = DHO_DHCP_REQUESTED_ADDRESS;
1473 options[i] = &requested_address_tree;
1474 options[i]->value = lease->address.iabuf;
1475 options[i]->len = lease->address.len;
1476 options[i]->buf_size = lease->address.len;
1477 options[i]->timeout = 0xFFFFFFFF;
1478
1479 /* Send the uid if the user supplied one. */
1480 i = DHO_DHCP_CLIENT_IDENTIFIER;
1481 if (ip->client->config->send_options[i].len) {
1482 options[i] = &client_id_tree;
1483 options[i]->value = ip->client->config->send_options[i].data;
1484 options[i]->len = ip->client->config->send_options[i].len;
1485 options[i]->buf_size = ip->client->config->send_options[i].len;
1486 options[i]->timeout = 0xFFFFFFFF;
1487 }
1488
1489
1490 /* Set up the option buffer... */
1491 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1492 options, 0, 0, 0, NULL, 0);
1493 if (ip->client->packet_length < BOOTP_MIN_LEN)
1494 ip->client->packet_length = BOOTP_MIN_LEN;
1495
1496 ip->client->packet.op = BOOTREQUEST;
1497 ip->client->packet.htype = ip->hw_address.htype;
1498 ip->client->packet.hlen = ip->hw_address.hlen;
1499 ip->client->packet.hops = 0;
1500 ip->client->packet.xid = ip->client->xid;
1501 ip->client->packet.secs = 0; /* Filled in by send_request. */
1502 ip->client->packet.flags = 0;
1503
1504 /* ciaddr must always be zero. */
1505 memset(&ip->client->packet.ciaddr, 0,
1506 sizeof(ip->client->packet.ciaddr));
1507 memset(&ip->client->packet.yiaddr, 0,
1508 sizeof(ip->client->packet.yiaddr));
1509 memset(&ip->client->packet.siaddr, 0,
1510 sizeof(ip->client->packet.siaddr));
1511 memset(&ip->client->packet.giaddr, 0,
1512 sizeof(ip->client->packet.giaddr));
1513 memcpy(ip->client->packet.chaddr,
1514 ip->hw_address.haddr, ip->hw_address.hlen);
1515 }
1516
1517 void
1518 free_client_lease(struct client_lease *lease)
1519 {
1520 int i;
1521
1522 if (lease->server_name)
1523 free(lease->server_name);
1524 if (lease->filename)
1525 free(lease->filename);
1526 for (i = 0; i < 256; i++) {
1527 if (lease->options[i].len)
1528 free(lease->options[i].data);
1529 }
1530 free(lease);
1531 }
1532
1533 FILE *leaseFile;
1534
1535 void
1536 rewrite_client_leases(struct interface_info *ifi)
1537 {
1538 struct client_lease *lp;
1539
1540 if (!leaseFile) {
1541 leaseFile = fopen(path_dhclient_db, "w");
1542 if (!leaseFile)
1543 error("can't create %s", path_dhclient_db);
1544 } else {
1545 fflush(leaseFile);
1546 rewind(leaseFile);
1547 }
1548
1549 for (lp = ifi->client->leases; lp; lp = lp->next)
1550 write_client_lease(ifi, lp, 1);
1551 if (ifi->client->active)
1552 write_client_lease(ifi, ifi->client->active, 1);
1553
1554 fflush(leaseFile);
1555 }
1556
1557 void
1558 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1559 int rewrite)
1560 {
1561 static int leases_written;
1562 struct tm *t;
1563 int i;
1564
1565 if (!rewrite) {
1566 if (leases_written++ > 20) {
1567 rewrite_client_leases(ip);
1568 leases_written = 0;
1569 }
1570 }
1571
1572 /* If the lease came from the config file, we don't need to stash
1573 a copy in the lease database. */
1574 if (lease->is_static)
1575 return;
1576
1577 if (!leaseFile) { /* XXX */
1578 leaseFile = fopen(path_dhclient_db, "w");
1579 if (!leaseFile) {
1580 error("can't create %s", path_dhclient_db);
1581 return;
1582 }
1583 }
1584
1585 fprintf(leaseFile, "lease {\n");
1586 if (lease->is_bootp)
1587 fprintf(leaseFile, " bootp;\n");
1588 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1589 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1590 if (lease->filename)
1591 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1592 if (lease->server_name)
1593 fprintf(leaseFile, " server-name \"%s\";\n",
1594 lease->server_name);
1595 if (lease->medium)
1596 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1597 for (i = 0; i < 256; i++)
1598 if (lease->options[i].len)
1599 fprintf(leaseFile, " option %s %s;\n",
1600 dhcp_options[i].name,
1601 pretty_print_option(i, lease->options[i].data,
1602 lease->options[i].len, 1, 1));
1603
1604 t = gmtime(&lease->renewal);
1605 if (t)
1606 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1607 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1608 t->tm_hour, t->tm_min, t->tm_sec);
1609 t = gmtime(&lease->rebind);
1610 if (t)
1611 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1612 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1613 t->tm_hour, t->tm_min, t->tm_sec);
1614 t = gmtime(&lease->expiry);
1615 if (t)
1616 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1617 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1618 t->tm_hour, t->tm_min, t->tm_sec);
1619 fprintf(leaseFile, "}\n");
1620 fflush(leaseFile);
1621 }
1622
1623 void
1624 script_init(char *reason, struct string_list *medium)
1625 {
1626 size_t len, mediumlen = 0;
1627 struct imsg_hdr hdr;
1628 struct buf *buf;
1629 int errs;
1630
1631 if (medium != NULL && medium->string != NULL)
1632 mediumlen = strlen(medium->string);
1633
1634 hdr.code = IMSG_SCRIPT_INIT;
1635 hdr.len = sizeof(struct imsg_hdr) +
1636 sizeof(size_t) + mediumlen +
1637 sizeof(size_t) + strlen(reason);
1638
1639 if ((buf = buf_open(hdr.len)) == NULL)
1640 return;
1641
1642 errs = 0;
1643 errs += buf_add(buf, &hdr, sizeof(hdr));
1644 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1645 if (mediumlen > 0)
1646 errs += buf_add(buf, medium->string, mediumlen);
1647 len = strlen(reason);
1648 errs += buf_add(buf, &len, sizeof(len));
1649 errs += buf_add(buf, reason, len);
1650
1651 if (errs)
1652 error("buf_add: %d", WSAGetLastError());
1653
1654 if (buf_close(privfd, buf) == -1)
1655 error("buf_close: %d", WSAGetLastError());
1656 }
1657
1658 void
1659 priv_script_init(struct interface_info *ip, char *reason, char *medium)
1660 {
1661 if (ip) {
1662 // XXX Do we need to do anything?
1663 }
1664 }
1665
1666 void
1667 priv_script_write_params(struct interface_info *ip, char *prefix, struct client_lease *lease)
1668 {
1669 u_int8_t dbuf[1500];
1670 int i, len = 0;
1671
1672 #if 0
1673 script_set_env(ip->client, prefix, "ip_address",
1674 piaddr(lease->address));
1675 #endif
1676
1677 if (lease->options[DHO_SUBNET_MASK].len &&
1678 (lease->options[DHO_SUBNET_MASK].len <
1679 sizeof(lease->address.iabuf))) {
1680 struct iaddr netmask, subnet, broadcast;
1681
1682 memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data,
1683 lease->options[DHO_SUBNET_MASK].len);
1684 netmask.len = lease->options[DHO_SUBNET_MASK].len;
1685
1686 subnet = subnet_number(lease->address, netmask);
1687 if (subnet.len) {
1688 #if 0
1689 script_set_env(ip->client, prefix, "network_number",
1690 piaddr(subnet));
1691 #endif
1692 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1693 broadcast = broadcast_addr(subnet, netmask);
1694 if (broadcast.len)
1695 #if 0
1696 script_set_env(ip->client, prefix,
1697 "broadcast_address",
1698 piaddr(broadcast));
1699 #else
1700 ;
1701 #endif
1702 }
1703 }
1704 }
1705
1706 #if 0
1707 if (lease->filename)
1708 script_set_env(ip->client, prefix, "filename", lease->filename);
1709 if (lease->server_name)
1710 script_set_env(ip->client, prefix, "server_name",
1711 lease->server_name);
1712 #endif
1713
1714 for (i = 0; i < 256; i++) {
1715 u_int8_t *dp = NULL;
1716
1717 if (ip->client->config->defaults[i].len) {
1718 if (lease->options[i].len) {
1719 switch (
1720 ip->client->config->default_actions[i]) {
1721 case ACTION_DEFAULT:
1722 dp = lease->options[i].data;
1723 len = lease->options[i].len;
1724 break;
1725 case ACTION_SUPERSEDE:
1726 supersede:
1727 dp = ip->client->
1728 config->defaults[i].data;
1729 len = ip->client->
1730 config->defaults[i].len;
1731 break;
1732 case ACTION_PREPEND:
1733 len = ip->client->
1734 config->defaults[i].len +
1735 lease->options[i].len;
1736 if (len >= sizeof(dbuf)) {
1737 warning("no space to %s %s",
1738 "prepend option",
1739 dhcp_options[i].name);
1740 goto supersede;
1741 }
1742 dp = dbuf;
1743 memcpy(dp,
1744 ip->client->
1745 config->defaults[i].data,
1746 ip->client->
1747 config->defaults[i].len);
1748 memcpy(dp + ip->client->
1749 config->defaults[i].len,
1750 lease->options[i].data,
1751 lease->options[i].len);
1752 dp[len] = '\0';
1753 break;
1754 case ACTION_APPEND:
1755 len = ip->client->
1756 config->defaults[i].len +
1757 lease->options[i].len + 1;
1758 if (len > sizeof(dbuf)) {
1759 warning("no space to %s %s",
1760 "append option",
1761 dhcp_options[i].name);
1762 goto supersede;
1763 }
1764 dp = dbuf;
1765 memcpy(dp,
1766 lease->options[i].data,
1767 lease->options[i].len);
1768 memcpy(dp + lease->options[i].len,
1769 ip->client->
1770 config->defaults[i].data,
1771 ip->client->
1772 config->defaults[i].len);
1773 dp[len-1] = '\0';
1774 }
1775 } else {
1776 dp = ip->client->
1777 config->defaults[i].data;
1778 len = ip->client->
1779 config->defaults[i].len;
1780 }
1781 } else if (lease->options[i].len) {
1782 len = lease->options[i].len;
1783 dp = lease->options[i].data;
1784 } else {
1785 len = 0;
1786 }
1787 #if 0
1788 if (len) {
1789 char name[256];
1790
1791 if (dhcp_option_ev_name(name, sizeof(name),
1792 &dhcp_options[i]))
1793 script_set_env(ip->client, prefix, name,
1794 pretty_print_option(i, dp, len, 0, 0));
1795 }
1796 #endif
1797 }
1798 #if 0
1799 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
1800 script_set_env(ip->client, prefix, "expiry", tbuf);
1801 #endif
1802 }
1803
1804 void
1805 script_write_params(char *prefix, struct client_lease *lease)
1806 {
1807 size_t fn_len = 0, sn_len = 0, pr_len = 0;
1808 struct imsg_hdr hdr;
1809 struct buf *buf;
1810 int errs, i;
1811
1812 if (lease->filename != NULL)
1813 fn_len = strlen(lease->filename);
1814 if (lease->server_name != NULL)
1815 sn_len = strlen(lease->server_name);
1816 if (prefix != NULL)
1817 pr_len = strlen(prefix);
1818
1819 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
1820 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
1821 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
1822 sizeof(size_t) + pr_len;
1823
1824 for (i = 0; i < 256; i++)
1825 hdr.len += sizeof(int) + lease->options[i].len;
1826
1827 scripttime = time(NULL);
1828
1829 if ((buf = buf_open(hdr.len)) == NULL)
1830 return;
1831
1832 errs = 0;
1833 errs += buf_add(buf, &hdr, sizeof(hdr));
1834 errs += buf_add(buf, lease, sizeof(struct client_lease));
1835 errs += buf_add(buf, &fn_len, sizeof(fn_len));
1836 errs += buf_add(buf, lease->filename, fn_len);
1837 errs += buf_add(buf, &sn_len, sizeof(sn_len));
1838 errs += buf_add(buf, lease->server_name, sn_len);
1839 errs += buf_add(buf, &pr_len, sizeof(pr_len));
1840 errs += buf_add(buf, prefix, pr_len);
1841
1842 for (i = 0; i < 256; i++) {
1843 errs += buf_add(buf, &lease->options[i].len,
1844 sizeof(lease->options[i].len));
1845 errs += buf_add(buf, lease->options[i].data,
1846 lease->options[i].len);
1847 }
1848
1849 if (errs)
1850 error("buf_add: %d", WSAGetLastError());
1851
1852 if (buf_close(privfd, buf) == -1)
1853 error("buf_close: %d", WSAGetLastError());
1854 }
1855
1856 int
1857 dhcp_option_ev_name(char *buf, size_t buflen, struct dhcp_option *option)
1858 {
1859 int i;
1860
1861 for (i = 0; option->name[i]; i++) {
1862 if (i + 1 == buflen)
1863 return 0;
1864 if (option->name[i] == '-')
1865 buf[i] = '_';
1866 else
1867 buf[i] = option->name[i];
1868 }
1869
1870 buf[i] = 0;
1871 return 1;
1872 }
1873
1874 #if 0
1875 void
1876 go_daemon(void)
1877 {
1878 static int state = 0;
1879
1880 if (no_daemon || state)
1881 return;
1882
1883 state = 1;
1884
1885 /* Stop logging to stderr... */
1886 log_perror = 0;
1887
1888 if (daemon(1, 0) == -1)
1889 error("daemon");
1890
1891 /* we are chrooted, daemon(3) fails to open /dev/null */
1892 if (nullfd != -1) {
1893 dup2(nullfd, STDIN_FILENO);
1894 dup2(nullfd, STDOUT_FILENO);
1895 dup2(nullfd, STDERR_FILENO);
1896 close(nullfd);
1897 nullfd = -1;
1898 }
1899 }
1900 #endif
1901
1902 int
1903 check_option(struct client_lease *l, int option)
1904 {
1905 char *opbuf;
1906 char *sbuf;
1907
1908 /* we use this, since this is what gets passed to dhclient-script */
1909
1910 opbuf = pretty_print_option(option, l->options[option].data,
1911 l->options[option].len, 0, 0);
1912
1913 sbuf = option_as_string(option, l->options[option].data,
1914 l->options[option].len);
1915
1916 switch (option) {
1917 case DHO_SUBNET_MASK:
1918 case DHO_TIME_SERVERS:
1919 case DHO_NAME_SERVERS:
1920 case DHO_ROUTERS:
1921 case DHO_DOMAIN_NAME_SERVERS:
1922 case DHO_LOG_SERVERS:
1923 case DHO_COOKIE_SERVERS:
1924 case DHO_LPR_SERVERS:
1925 case DHO_IMPRESS_SERVERS:
1926 case DHO_RESOURCE_LOCATION_SERVERS:
1927 case DHO_SWAP_SERVER:
1928 case DHO_BROADCAST_ADDRESS:
1929 case DHO_NIS_SERVERS:
1930 case DHO_NTP_SERVERS:
1931 case DHO_NETBIOS_NAME_SERVERS:
1932 case DHO_NETBIOS_DD_SERVER:
1933 case DHO_FONT_SERVERS:
1934 case DHO_DHCP_SERVER_IDENTIFIER:
1935 if (!ipv4addrs(opbuf)) {
1936 warning("Invalid IP address in option(%d): %s", option, opbuf);
1937 return (0);
1938 }
1939 return (1) ;
1940 case DHO_HOST_NAME:
1941 case DHO_DOMAIN_NAME:
1942 case DHO_NIS_DOMAIN:
1943 if (!res_hnok(sbuf))
1944 warning("Bogus Host Name option %d: %s (%s)", option,
1945 sbuf, opbuf);
1946 return (1);
1947 case DHO_PAD:
1948 case DHO_TIME_OFFSET:
1949 case DHO_BOOT_SIZE:
1950 case DHO_MERIT_DUMP:
1951 case DHO_ROOT_PATH:
1952 case DHO_EXTENSIONS_PATH:
1953 case DHO_IP_FORWARDING:
1954 case DHO_NON_LOCAL_SOURCE_ROUTING:
1955 case DHO_POLICY_FILTER:
1956 case DHO_MAX_DGRAM_REASSEMBLY:
1957 case DHO_DEFAULT_IP_TTL:
1958 case DHO_PATH_MTU_AGING_TIMEOUT:
1959 case DHO_PATH_MTU_PLATEAU_TABLE:
1960 case DHO_INTERFACE_MTU:
1961 case DHO_ALL_SUBNETS_LOCAL:
1962 case DHO_PERFORM_MASK_DISCOVERY:
1963 case DHO_MASK_SUPPLIER:
1964 case DHO_ROUTER_DISCOVERY:
1965 case DHO_ROUTER_SOLICITATION_ADDRESS:
1966 case DHO_STATIC_ROUTES:
1967 case DHO_TRAILER_ENCAPSULATION:
1968 case DHO_ARP_CACHE_TIMEOUT:
1969 case DHO_IEEE802_3_ENCAPSULATION:
1970 case DHO_DEFAULT_TCP_TTL:
1971 case DHO_TCP_KEEPALIVE_INTERVAL:
1972 case DHO_TCP_KEEPALIVE_GARBAGE:
1973 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
1974 case DHO_NETBIOS_NODE_TYPE:
1975 case DHO_NETBIOS_SCOPE:
1976 case DHO_X_DISPLAY_MANAGER:
1977 case DHO_DHCP_REQUESTED_ADDRESS:
1978 case DHO_DHCP_LEASE_TIME:
1979 case DHO_DHCP_OPTION_OVERLOAD:
1980 case DHO_DHCP_MESSAGE_TYPE:
1981 case DHO_DHCP_PARAMETER_REQUEST_LIST:
1982 case DHO_DHCP_MESSAGE:
1983 case DHO_DHCP_MAX_MESSAGE_SIZE:
1984 case DHO_DHCP_RENEWAL_TIME:
1985 case DHO_DHCP_REBINDING_TIME:
1986 case DHO_DHCP_CLASS_IDENTIFIER:
1987 case DHO_DHCP_CLIENT_IDENTIFIER:
1988 case DHO_DHCP_USER_CLASS_ID:
1989 case DHO_END:
1990 return (1);
1991 default:
1992 warning("unknown dhcp option value 0x%x", option);
1993 return (unknown_ok);
1994 }
1995 }
1996
1997 int
1998 res_hnok(const char *dn)
1999 {
2000 int pch = PERIOD, ch = *dn++;
2001
2002 while (ch != '\0') {
2003 int nch = *dn++;
2004
2005 if (periodchar(ch)) {
2006 ;
2007 } else if (periodchar(pch)) {
2008 if (!borderchar(ch))
2009 return (0);
2010 } else if (periodchar(nch) || nch == '\0') {
2011 if (!borderchar(ch))
2012 return (0);
2013 } else {
2014 if (!middlechar(ch))
2015 return (0);
2016 }
2017 pch = ch, ch = nch;
2018 }
2019 return (1);
2020 }
2021
2022 /* Does buf consist only of dotted decimal ipv4 addrs?
2023 * return how many if so,
2024 * otherwise, return 0
2025 */
2026 int
2027 ipv4addrs(char * buf)
2028 {
2029 char *tmp;
2030 struct in_addr jnk;
2031 int i = 0;
2032
2033 note("Input: %s", buf);
2034
2035 do {
2036 tmp = strtok(buf, " ");
2037 note("got %s", tmp);
2038 if( tmp && inet_aton(tmp, &jnk) ) i++;
2039 buf = NULL;
2040 } while( tmp );
2041
2042 return (i);
2043 }
2044
2045
2046 char *
2047 option_as_string(unsigned int code, unsigned char *data, int len)
2048 {
2049 static char optbuf[32768]; /* XXX */
2050 char *op = optbuf;
2051 int opleft = sizeof(optbuf);
2052 unsigned char *dp = data;
2053
2054 if (code > 255)
2055 error("option_as_string: bad code %d", code);
2056
2057 for (; dp < data + len; dp++) {
2058 if (!isascii(*dp) || !isprint(*dp)) {
2059 if (dp + 1 != data + len || *dp != 0) {
2060 _snprintf(op, opleft, "\\%03o", *dp);
2061 op += 4;
2062 opleft -= 4;
2063 }
2064 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2065 *dp == '`' || *dp == '\\') {
2066 *op++ = '\\';
2067 *op++ = *dp;
2068 opleft -= 2;
2069 } else {
2070 *op++ = *dp;
2071 opleft--;
2072 }
2073 }
2074 if (opleft < 1)
2075 goto toobig;
2076 *op = 0;
2077 return optbuf;
2078 toobig:
2079 warning("dhcp option too large");
2080 return "<error>";
2081 }
2082