eee8e26f34e31a733007863ec543003ca05563e2
[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 {
585 warning("Could not find adapter for info %p\n", ip);
586 return;
587 }
588 set_name_servers( Adapter, new_lease );
589 }
590
591 /*
592 * state_bound is called when we've successfully bound to a particular
593 * lease, but the renewal time on that lease has expired. We are
594 * expected to unicast a DHCPREQUEST to the server that gave us our
595 * original lease.
596 */
597 void
598 state_bound(void *ipp)
599 {
600 struct interface_info *ip = ipp;
601
602 ASSERT_STATE(state, S_BOUND);
603
604 /* T1 has expired. */
605 make_request(ip, ip->client->active);
606 ip->client->xid = ip->client->packet.xid;
607
608 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
609 memcpy(ip->client->destination.iabuf, ip->client->active->
610 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
611 ip->client->destination.len = 4;
612 } else
613 ip->client->destination = iaddr_broadcast;
614
615 time(&ip->client->first_sending);
616 ip->client->interval = ip->client->config->initial_interval;
617 ip->client->state = S_RENEWING;
618
619 /* Send the first packet immediately. */
620 send_request(ip);
621 }
622
623 void
624 bootp(struct packet *packet)
625 {
626 struct iaddrlist *ap;
627
628 if (packet->raw->op != BOOTREPLY)
629 return;
630
631 /* If there's a reject list, make sure this packet's sender isn't
632 on it. */
633 for (ap = packet->interface->client->config->reject_list;
634 ap; ap = ap->next) {
635 if (addr_eq(packet->client_addr, ap->addr)) {
636 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
637 return;
638 }
639 }
640 dhcpoffer(packet);
641 }
642
643 void
644 dhcp(struct packet *packet)
645 {
646 struct iaddrlist *ap;
647 void (*handler)(struct packet *);
648 char *type;
649
650 switch (packet->packet_type) {
651 case DHCPOFFER:
652 handler = dhcpoffer;
653 type = "DHCPOFFER";
654 break;
655 case DHCPNAK:
656 handler = dhcpnak;
657 type = "DHCPNACK";
658 break;
659 case DHCPACK:
660 handler = dhcpack;
661 type = "DHCPACK";
662 break;
663 default:
664 return;
665 }
666
667 /* If there's a reject list, make sure this packet's sender isn't
668 on it. */
669 for (ap = packet->interface->client->config->reject_list;
670 ap; ap = ap->next) {
671 if (addr_eq(packet->client_addr, ap->addr)) {
672 note("%s from %s rejected.", type, piaddr(ap->addr));
673 return;
674 }
675 }
676 (*handler)(packet);
677 }
678
679 void
680 dhcpoffer(struct packet *packet)
681 {
682 struct interface_info *ip = packet->interface;
683 struct client_lease *lease, *lp;
684 int i;
685 int arp_timeout_needed = 0, stop_selecting;
686 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
687 "DHCPOFFER" : "BOOTREPLY";
688 time_t cur_time;
689
690 time(&cur_time);
691
692 /* If we're not receptive to an offer right now, or if the offer
693 has an unrecognizable transaction id, then just drop it. */
694 if (ip->client->state != S_SELECTING ||
695 packet->interface->client->xid != packet->raw->xid ||
696 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
697 (memcmp(packet->interface->hw_address.haddr,
698 packet->raw->chaddr, packet->raw->hlen)))
699 return;
700
701 note("%s from %s", name, piaddr(packet->client_addr));
702
703
704 /* If this lease doesn't supply the minimum required parameters,
705 blow it off. */
706 for (i = 0; ip->client->config->required_options[i]; i++) {
707 if (!packet->options[ip->client->config->
708 required_options[i]].len) {
709 note("%s isn't satisfactory.", name);
710 return;
711 }
712 }
713
714 /* If we've already seen this lease, don't record it again. */
715 for (lease = ip->client->offered_leases;
716 lease; lease = lease->next) {
717 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
718 !memcmp(lease->address.iabuf,
719 &packet->raw->yiaddr, lease->address.len)) {
720 debug("%s already seen.", name);
721 return;
722 }
723 }
724
725 lease = packet_to_lease(packet);
726 if (!lease) {
727 note("packet_to_lease failed.");
728 return;
729 }
730
731 /* If this lease was acquired through a BOOTREPLY, record that
732 fact. */
733 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
734 lease->is_bootp = 1;
735
736 /* Record the medium under which this lease was offered. */
737 lease->medium = ip->client->medium;
738
739 /* Send out an ARP Request for the offered IP address. */
740 if( !check_arp( ip, lease ) ) {
741 note("Arp check failed\n");
742 return;
743 }
744
745 /* Figure out when we're supposed to stop selecting. */
746 stop_selecting =
747 ip->client->first_sending + ip->client->config->select_interval;
748
749 /* If this is the lease we asked for, put it at the head of the
750 list, and don't mess with the arp request timeout. */
751 if (lease->address.len == ip->client->requested_address.len &&
752 !memcmp(lease->address.iabuf,
753 ip->client->requested_address.iabuf,
754 ip->client->requested_address.len)) {
755 lease->next = ip->client->offered_leases;
756 ip->client->offered_leases = lease;
757 } else {
758 /* If we already have an offer, and arping for this
759 offer would take us past the selection timeout,
760 then don't extend the timeout - just hope for the
761 best. */
762 if (ip->client->offered_leases &&
763 (cur_time + arp_timeout_needed) > stop_selecting)
764 arp_timeout_needed = 0;
765
766 /* Put the lease at the end of the list. */
767 lease->next = NULL;
768 if (!ip->client->offered_leases)
769 ip->client->offered_leases = lease;
770 else {
771 for (lp = ip->client->offered_leases; lp->next;
772 lp = lp->next)
773 ; /* nothing */
774 lp->next = lease;
775 }
776 }
777
778 /* If we're supposed to stop selecting before we've had time
779 to wait for the ARPREPLY, add some delay to wait for
780 the ARPREPLY. */
781 if (stop_selecting - cur_time < arp_timeout_needed)
782 stop_selecting = cur_time + arp_timeout_needed;
783
784 /* If the selecting interval has expired, go immediately to
785 state_selecting(). Otherwise, time out into
786 state_selecting at the select interval. */
787 if (stop_selecting <= 0)
788 state_selecting(ip);
789 else {
790 add_timeout(stop_selecting, state_selecting, ip);
791 cancel_timeout(send_discover, ip);
792 }
793 }
794
795 /* Allocate a client_lease structure and initialize it from the parameters
796 in the specified packet. */
797
798 struct client_lease *
799 packet_to_lease(struct packet *packet)
800 {
801 struct client_lease *lease;
802 int i;
803
804 lease = malloc(sizeof(struct client_lease));
805
806 if (!lease) {
807 warning("dhcpoffer: no memory to record lease.");
808 return (NULL);
809 }
810
811 memset(lease, 0, sizeof(*lease));
812
813 /* Copy the lease options. */
814 for (i = 0; i < 256; i++) {
815 if (packet->options[i].len) {
816 lease->options[i].data =
817 malloc(packet->options[i].len + 1);
818 if (!lease->options[i].data) {
819 warning("dhcpoffer: no memory for option %d", i);
820 free_client_lease(lease);
821 return (NULL);
822 } else {
823 memcpy(lease->options[i].data,
824 packet->options[i].data,
825 packet->options[i].len);
826 lease->options[i].len =
827 packet->options[i].len;
828 lease->options[i].data[lease->options[i].len] =
829 0;
830 }
831 if (!check_option(lease,i)) {
832 /* ignore a bogus lease offer */
833 warning("Invalid lease option - ignoring offer");
834 free_client_lease(lease);
835 return (NULL);
836 }
837 }
838 }
839
840 lease->address.len = sizeof(packet->raw->yiaddr);
841 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
842 #ifdef __REACTOS__
843 lease->serveraddress.len = sizeof(packet->raw->siaddr);
844 memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len);
845 #endif
846
847 /* If the server name was filled out, copy it. */
848 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
849 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
850 packet->raw->sname[0]) {
851 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
852 if (!lease->server_name) {
853 warning("dhcpoffer: no memory for server name.");
854 free_client_lease(lease);
855 return (NULL);
856 }
857 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
858 lease->server_name[DHCP_SNAME_LEN]='\0';
859 if (!res_hnok(lease->server_name) ) {
860 warning("Bogus server name %s", lease->server_name );
861 free_client_lease(lease);
862 return (NULL);
863 }
864
865 }
866
867 /* Ditto for the filename. */
868 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
869 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
870 packet->raw->file[0]) {
871 /* Don't count on the NUL terminator. */
872 lease->filename = malloc(DHCP_FILE_LEN + 1);
873 if (!lease->filename) {
874 warning("dhcpoffer: no memory for filename.");
875 free_client_lease(lease);
876 return (NULL);
877 }
878 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
879 lease->filename[DHCP_FILE_LEN]='\0';
880 }
881 return lease;
882 }
883
884 void
885 dhcpnak(struct packet *packet)
886 {
887 struct interface_info *ip = packet->interface;
888
889 /* If we're not receptive to an offer right now, or if the offer
890 has an unrecognizable transaction id, then just drop it. */
891 if (packet->interface->client->xid != packet->raw->xid ||
892 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
893 (memcmp(packet->interface->hw_address.haddr,
894 packet->raw->chaddr, packet->raw->hlen)))
895 return;
896
897 if (ip->client->state != S_REBOOTING &&
898 ip->client->state != S_REQUESTING &&
899 ip->client->state != S_RENEWING &&
900 ip->client->state != S_REBINDING)
901 return;
902
903 note("DHCPNAK from %s", piaddr(packet->client_addr));
904
905 if (!ip->client->active) {
906 note("DHCPNAK with no active lease.\n");
907 return;
908 }
909
910 free_client_lease(ip->client->active);
911 ip->client->active = NULL;
912
913 /* Stop sending DHCPREQUEST packets... */
914 cancel_timeout(send_request, ip);
915
916 ip->client->state = S_INIT;
917 state_init(ip);
918 }
919
920 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
921 one after the right interval has expired. If we don't get an offer by
922 the time we reach the panic interval, call the panic function. */
923
924 void
925 send_discover(void *ipp)
926 {
927 struct interface_info *ip = ipp;
928 int interval, increase = 1;
929 time_t cur_time;
930
931 DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip));
932
933 time(&cur_time);
934
935 /* Figure out how long it's been since we started transmitting. */
936 interval = cur_time - ip->client->first_sending;
937
938 /* If we're past the panic timeout, call the script and tell it
939 we haven't found anything for this interface yet. */
940 if (interval > ip->client->config->timeout) {
941 state_panic(ip);
942 return;
943 }
944
945 /* If we're selecting media, try the whole list before doing
946 the exponential backoff, but if we've already received an
947 offer, stop looping, because we obviously have it right. */
948 if (!ip->client->offered_leases &&
949 ip->client->config->media) {
950 int fail = 0;
951
952 if (ip->client->medium) {
953 ip->client->medium = ip->client->medium->next;
954 increase = 0;
955 }
956 if (!ip->client->medium) {
957 if (fail)
958 error("No valid media types for %s!", ip->name);
959 ip->client->medium = ip->client->config->media;
960 increase = 1;
961 }
962
963 note("Trying medium \"%s\" %d", ip->client->medium->string,
964 increase);
965 /* XXX Support other media types eventually */
966 }
967
968 /*
969 * If we're supposed to increase the interval, do so. If it's
970 * currently zero (i.e., we haven't sent any packets yet), set
971 * it to one; otherwise, add to it a random number between zero
972 * and two times itself. On average, this means that it will
973 * double with every transmission.
974 */
975 if (increase) {
976 if (!ip->client->interval)
977 ip->client->interval =
978 ip->client->config->initial_interval;
979 else {
980 ip->client->interval += (rand() >> 2) %
981 (2 * ip->client->interval);
982 }
983
984 /* Don't backoff past cutoff. */
985 if (ip->client->interval >
986 ip->client->config->backoff_cutoff)
987 ip->client->interval =
988 ((ip->client->config->backoff_cutoff / 2)
989 + ((rand() >> 2) %
990 ip->client->config->backoff_cutoff));
991 } else if (!ip->client->interval)
992 ip->client->interval =
993 ip->client->config->initial_interval;
994
995 /* If the backoff would take us to the panic timeout, just use that
996 as the interval. */
997 if (cur_time + ip->client->interval >
998 ip->client->first_sending + ip->client->config->timeout)
999 ip->client->interval =
1000 (ip->client->first_sending +
1001 ip->client->config->timeout) - cur_time + 1;
1002
1003 /* Record the number of seconds since we started sending. */
1004 if (interval < 65536)
1005 ip->client->packet.secs = htons(interval);
1006 else
1007 ip->client->packet.secs = htons(65535);
1008 ip->client->secs = ip->client->packet.secs;
1009
1010 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1011 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1012 ntohs(sockaddr_broadcast.sin_port), (long int)ip->client->interval);
1013
1014 /* Send out a packet. */
1015 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1016 inaddr_any, &sockaddr_broadcast, NULL);
1017
1018 DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n",
1019 cur_time, cur_time + ip->client->interval));
1020
1021 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1022 }
1023
1024 /*
1025 * state_panic gets called if we haven't received any offers in a preset
1026 * amount of time. When this happens, we try to use existing leases
1027 * that haven't yet expired, and failing that, we call the client script
1028 * and hope it can do something.
1029 */
1030 void
1031 state_panic(void *ipp)
1032 {
1033 struct interface_info *ip = ipp;
1034 struct client_lease *loop = ip->client->active;
1035 struct client_lease *lp;
1036 time_t cur_time;
1037
1038 note("No DHCPOFFERS received.");
1039
1040 time(&cur_time);
1041
1042 /* We may not have an active lease, but we may have some
1043 predefined leases that we can try. */
1044 if (!ip->client->active && ip->client->leases)
1045 goto activate_next;
1046
1047 /* Run through the list of leases and see if one can be used. */
1048 while (ip->client->active) {
1049 if (ip->client->active->expiry > cur_time) {
1050 note("Trying recorded lease %s",
1051 piaddr(ip->client->active->address));
1052 /* Run the client script with the existing
1053 parameters. */
1054 script_init("TIMEOUT",
1055 ip->client->active->medium);
1056 script_write_params("new_", ip->client->active);
1057 if (ip->client->alias)
1058 script_write_params("alias_",
1059 ip->client->alias);
1060
1061 /* If the old lease is still good and doesn't
1062 yet need renewal, go into BOUND state and
1063 timeout at the renewal time. */
1064 if (cur_time <
1065 ip->client->active->renewal) {
1066 ip->client->state = S_BOUND;
1067 note("bound: renewal in %ld seconds.",
1068 (long int)(ip->client->active->renewal -
1069 cur_time));
1070 add_timeout(
1071 ip->client->active->renewal,
1072 state_bound, ip);
1073 } else {
1074 ip->client->state = S_BOUND;
1075 note("bound: immediate renewal.");
1076 state_bound(ip);
1077 }
1078 return;
1079 }
1080
1081 /* If there are no other leases, give up. */
1082 if (!ip->client->leases) {
1083 ip->client->leases = ip->client->active;
1084 ip->client->active = NULL;
1085 break;
1086 }
1087
1088 activate_next:
1089 /* Otherwise, put the active lease at the end of the
1090 lease list, and try another lease.. */
1091 for (lp = ip->client->leases; lp->next; lp = lp->next)
1092 ;
1093 lp->next = ip->client->active;
1094 if (lp->next)
1095 lp->next->next = NULL;
1096 ip->client->active = ip->client->leases;
1097 ip->client->leases = ip->client->leases->next;
1098
1099 /* If we already tried this lease, we've exhausted the
1100 set of leases, so we might as well give up for
1101 now. */
1102 if (ip->client->active == loop)
1103 break;
1104 else if (!loop)
1105 loop = ip->client->active;
1106 }
1107
1108 /* No leases were available, or what was available didn't work, so
1109 tell the shell script that we failed to allocate an address,
1110 and try again later. */
1111 note("No working leases in persistent database - sleeping.\n");
1112 ip->client->state = S_INIT;
1113 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1114 ip);
1115 /* XXX Take any failure actions necessary */
1116 }
1117
1118 void
1119 send_request(void *ipp)
1120 {
1121 struct interface_info *ip = ipp;
1122 struct sockaddr_in destination;
1123 struct in_addr from;
1124 int interval;
1125 time_t cur_time;
1126
1127 time(&cur_time);
1128
1129 /* Figure out how long it's been since we started transmitting. */
1130 interval = cur_time - ip->client->first_sending;
1131
1132 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1133 past the reboot timeout, go to INIT and see if we can
1134 DISCOVER an address... */
1135 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1136 means either that we're on a network with no DHCP server,
1137 or that our server is down. In the latter case, assuming
1138 that there is a backup DHCP server, DHCPDISCOVER will get
1139 us a new address, but we could also have successfully
1140 reused our old address. In the former case, we're hosed
1141 anyway. This is not a win-prone situation. */
1142 if ((ip->client->state == S_REBOOTING ||
1143 ip->client->state == S_REQUESTING) &&
1144 interval > ip->client->config->reboot_timeout) {
1145 ip->client->state = S_INIT;
1146 cancel_timeout(send_request, ip);
1147 state_init(ip);
1148 return;
1149 }
1150
1151 /* If we're in the reboot state, make sure the media is set up
1152 correctly. */
1153 if (ip->client->state == S_REBOOTING &&
1154 !ip->client->medium &&
1155 ip->client->active->medium ) {
1156 script_init("MEDIUM", ip->client->active->medium);
1157
1158 /* If the medium we chose won't fly, go to INIT state. */
1159 /* XXX Nothing for now */
1160
1161 /* Record the medium. */
1162 ip->client->medium = ip->client->active->medium;
1163 }
1164
1165 /* If the lease has expired, relinquish the address and go back
1166 to the INIT state. */
1167 if (ip->client->state != S_REQUESTING &&
1168 cur_time > ip->client->active->expiry) {
1169 PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
1170 /* Run the client script with the new parameters. */
1171 /* No script actions necessary in the expiry case */
1172 /* Now do a preinit on the interface so that we can
1173 discover a new address. */
1174
1175 if( Adapter )
1176 DeleteIPAddress( Adapter->NteContext );
1177
1178 ip->client->state = S_INIT;
1179 state_init(ip);
1180 return;
1181 }
1182
1183 /* Do the exponential backoff... */
1184 if (!ip->client->interval)
1185 ip->client->interval = ip->client->config->initial_interval;
1186 else
1187 ip->client->interval += ((rand() >> 2) %
1188 (2 * ip->client->interval));
1189
1190 /* Don't backoff past cutoff. */
1191 if (ip->client->interval >
1192 ip->client->config->backoff_cutoff)
1193 ip->client->interval =
1194 ((ip->client->config->backoff_cutoff / 2) +
1195 ((rand() >> 2) % ip->client->interval));
1196
1197 /* If the backoff would take us to the expiry time, just set the
1198 timeout to the expiry time. */
1199 if (ip->client->state != S_REQUESTING &&
1200 cur_time + ip->client->interval >
1201 ip->client->active->expiry)
1202 ip->client->interval =
1203 ip->client->active->expiry - cur_time + 1;
1204
1205 /* If the lease T2 time has elapsed, or if we're not yet bound,
1206 broadcast the DHCPREQUEST rather than unicasting. */
1207 memset(&destination, 0, sizeof(destination));
1208 if (ip->client->state == S_REQUESTING ||
1209 ip->client->state == S_REBOOTING ||
1210 cur_time > ip->client->active->rebind)
1211 destination.sin_addr.s_addr = INADDR_BROADCAST;
1212 else
1213 memcpy(&destination.sin_addr.s_addr,
1214 ip->client->destination.iabuf,
1215 sizeof(destination.sin_addr.s_addr));
1216 destination.sin_port = htons(REMOTE_PORT);
1217 destination.sin_family = AF_INET;
1218 // destination.sin_len = sizeof(destination);
1219
1220 if (ip->client->state != S_REQUESTING)
1221 memcpy(&from, ip->client->active->address.iabuf,
1222 sizeof(from));
1223 else
1224 from.s_addr = INADDR_ANY;
1225
1226 /* Record the number of seconds since we started sending. */
1227 if (ip->client->state == S_REQUESTING)
1228 ip->client->packet.secs = ip->client->secs;
1229 else {
1230 if (interval < 65536)
1231 ip->client->packet.secs = htons(interval);
1232 else
1233 ip->client->packet.secs = htons(65535);
1234 }
1235
1236 note("DHCPREQUEST on %s to %s port %d", ip->name,
1237 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1238
1239 /* Send out a packet. */
1240 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1241 from, &destination, NULL);
1242
1243 add_timeout(cur_time + ip->client->interval, send_request, ip);
1244 }
1245
1246 void
1247 send_decline(void *ipp)
1248 {
1249 struct interface_info *ip = ipp;
1250
1251 note("DHCPDECLINE on %s to %s port %d", ip->name,
1252 inet_ntoa(sockaddr_broadcast.sin_addr),
1253 ntohs(sockaddr_broadcast.sin_port));
1254
1255 /* Send out a packet. */
1256 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1257 inaddr_any, &sockaddr_broadcast, NULL);
1258 }
1259
1260 void
1261 make_discover(struct interface_info *ip, struct client_lease *lease)
1262 {
1263 unsigned char discover = DHCPDISCOVER;
1264 struct tree_cache *options[256];
1265 struct tree_cache option_elements[256];
1266 int i;
1267 ULONG foo = (ULONG) GetTickCount();
1268
1269 memset(option_elements, 0, sizeof(option_elements));
1270 memset(options, 0, sizeof(options));
1271 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1272
1273 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1274 i = DHO_DHCP_MESSAGE_TYPE;
1275 options[i] = &option_elements[i];
1276 options[i]->value = &discover;
1277 options[i]->len = sizeof(discover);
1278 options[i]->buf_size = sizeof(discover);
1279 options[i]->timeout = 0xFFFFFFFF;
1280
1281 /* Request the options we want */
1282 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1283 options[i] = &option_elements[i];
1284 options[i]->value = ip->client->config->requested_options;
1285 options[i]->len = ip->client->config->requested_option_count;
1286 options[i]->buf_size =
1287 ip->client->config->requested_option_count;
1288 options[i]->timeout = 0xFFFFFFFF;
1289
1290 /* If we had an address, try to get it again. */
1291 if (lease) {
1292 ip->client->requested_address = lease->address;
1293 i = DHO_DHCP_REQUESTED_ADDRESS;
1294 options[i] = &option_elements[i];
1295 options[i]->value = lease->address.iabuf;
1296 options[i]->len = lease->address.len;
1297 options[i]->buf_size = lease->address.len;
1298 options[i]->timeout = 0xFFFFFFFF;
1299 } else
1300 ip->client->requested_address.len = 0;
1301
1302 /* Send any options requested in the config file. */
1303 for (i = 0; i < 256; i++)
1304 if (!options[i] &&
1305 ip->client->config->send_options[i].data) {
1306 options[i] = &option_elements[i];
1307 options[i]->value =
1308 ip->client->config->send_options[i].data;
1309 options[i]->len =
1310 ip->client->config->send_options[i].len;
1311 options[i]->buf_size =
1312 ip->client->config->send_options[i].len;
1313 options[i]->timeout = 0xFFFFFFFF;
1314 }
1315
1316 /* Set up the option buffer... */
1317 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1318 options, 0, 0, 0, NULL, 0);
1319 if (ip->client->packet_length < BOOTP_MIN_LEN)
1320 ip->client->packet_length = BOOTP_MIN_LEN;
1321
1322 ip->client->packet.op = BOOTREQUEST;
1323 ip->client->packet.htype = ip->hw_address.htype;
1324 ip->client->packet.hlen = ip->hw_address.hlen;
1325 ip->client->packet.hops = 0;
1326 ip->client->packet.xid = RtlRandom(&foo);
1327 ip->client->packet.secs = 0; /* filled in by send_discover. */
1328 ip->client->packet.flags = 0;
1329
1330 memset(&(ip->client->packet.ciaddr),
1331 0, sizeof(ip->client->packet.ciaddr));
1332 memset(&(ip->client->packet.yiaddr),
1333 0, sizeof(ip->client->packet.yiaddr));
1334 memset(&(ip->client->packet.siaddr),
1335 0, sizeof(ip->client->packet.siaddr));
1336 memset(&(ip->client->packet.giaddr),
1337 0, sizeof(ip->client->packet.giaddr));
1338 memcpy(ip->client->packet.chaddr,
1339 ip->hw_address.haddr, ip->hw_address.hlen);
1340 }
1341
1342
1343 void
1344 make_request(struct interface_info *ip, struct client_lease * lease)
1345 {
1346 unsigned char request = DHCPREQUEST;
1347 struct tree_cache *options[256];
1348 struct tree_cache option_elements[256];
1349 int i;
1350
1351 memset(options, 0, sizeof(options));
1352 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1353
1354 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1355 i = DHO_DHCP_MESSAGE_TYPE;
1356 options[i] = &option_elements[i];
1357 options[i]->value = &request;
1358 options[i]->len = sizeof(request);
1359 options[i]->buf_size = sizeof(request);
1360 options[i]->timeout = 0xFFFFFFFF;
1361
1362 /* Request the options we want */
1363 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1364 options[i] = &option_elements[i];
1365 options[i]->value = ip->client->config->requested_options;
1366 options[i]->len = ip->client->config->requested_option_count;
1367 options[i]->buf_size =
1368 ip->client->config->requested_option_count;
1369 options[i]->timeout = 0xFFFFFFFF;
1370
1371 /* If we are requesting an address that hasn't yet been assigned
1372 to us, use the DHCP Requested Address option. */
1373 if (ip->client->state == S_REQUESTING) {
1374 /* Send back the server identifier... */
1375 i = DHO_DHCP_SERVER_IDENTIFIER;
1376 options[i] = &option_elements[i];
1377 options[i]->value = lease->options[i].data;
1378 options[i]->len = lease->options[i].len;
1379 options[i]->buf_size = lease->options[i].len;
1380 options[i]->timeout = 0xFFFFFFFF;
1381 }
1382 if (ip->client->state == S_REQUESTING ||
1383 ip->client->state == S_REBOOTING) {
1384 ip->client->requested_address = lease->address;
1385 i = DHO_DHCP_REQUESTED_ADDRESS;
1386 options[i] = &option_elements[i];
1387 options[i]->value = lease->address.iabuf;
1388 options[i]->len = lease->address.len;
1389 options[i]->buf_size = lease->address.len;
1390 options[i]->timeout = 0xFFFFFFFF;
1391 } else
1392 ip->client->requested_address.len = 0;
1393
1394 /* Send any options requested in the config file. */
1395 for (i = 0; i < 256; i++)
1396 if (!options[i] &&
1397 ip->client->config->send_options[i].data) {
1398 options[i] = &option_elements[i];
1399 options[i]->value =
1400 ip->client->config->send_options[i].data;
1401 options[i]->len =
1402 ip->client->config->send_options[i].len;
1403 options[i]->buf_size =
1404 ip->client->config->send_options[i].len;
1405 options[i]->timeout = 0xFFFFFFFF;
1406 }
1407
1408 /* Set up the option buffer... */
1409 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1410 options, 0, 0, 0, NULL, 0);
1411 if (ip->client->packet_length < BOOTP_MIN_LEN)
1412 ip->client->packet_length = BOOTP_MIN_LEN;
1413
1414 ip->client->packet.op = BOOTREQUEST;
1415 ip->client->packet.htype = ip->hw_address.htype;
1416 ip->client->packet.hlen = ip->hw_address.hlen;
1417 ip->client->packet.hops = 0;
1418 ip->client->packet.xid = ip->client->xid;
1419 ip->client->packet.secs = 0; /* Filled in by send_request. */
1420
1421 /* If we own the address we're requesting, put it in ciaddr;
1422 otherwise set ciaddr to zero. */
1423 if (ip->client->state == S_BOUND ||
1424 ip->client->state == S_RENEWING ||
1425 ip->client->state == S_REBINDING) {
1426 memcpy(&ip->client->packet.ciaddr,
1427 lease->address.iabuf, lease->address.len);
1428 ip->client->packet.flags = 0;
1429 } else {
1430 memset(&ip->client->packet.ciaddr, 0,
1431 sizeof(ip->client->packet.ciaddr));
1432 ip->client->packet.flags = 0;
1433 }
1434
1435 memset(&ip->client->packet.yiaddr, 0,
1436 sizeof(ip->client->packet.yiaddr));
1437 memset(&ip->client->packet.siaddr, 0,
1438 sizeof(ip->client->packet.siaddr));
1439 memset(&ip->client->packet.giaddr, 0,
1440 sizeof(ip->client->packet.giaddr));
1441 memcpy(ip->client->packet.chaddr,
1442 ip->hw_address.haddr, ip->hw_address.hlen);
1443 }
1444
1445 void
1446 make_decline(struct interface_info *ip, struct client_lease *lease)
1447 {
1448 struct tree_cache *options[256], message_type_tree;
1449 struct tree_cache requested_address_tree;
1450 struct tree_cache server_id_tree, client_id_tree;
1451 unsigned char decline = DHCPDECLINE;
1452 int i;
1453
1454 memset(options, 0, sizeof(options));
1455 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1456
1457 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1458 i = DHO_DHCP_MESSAGE_TYPE;
1459 options[i] = &message_type_tree;
1460 options[i]->value = &decline;
1461 options[i]->len = sizeof(decline);
1462 options[i]->buf_size = sizeof(decline);
1463 options[i]->timeout = 0xFFFFFFFF;
1464
1465 /* Send back the server identifier... */
1466 i = DHO_DHCP_SERVER_IDENTIFIER;
1467 options[i] = &server_id_tree;
1468 options[i]->value = lease->options[i].data;
1469 options[i]->len = lease->options[i].len;
1470 options[i]->buf_size = lease->options[i].len;
1471 options[i]->timeout = 0xFFFFFFFF;
1472
1473 /* Send back the address we're declining. */
1474 i = DHO_DHCP_REQUESTED_ADDRESS;
1475 options[i] = &requested_address_tree;
1476 options[i]->value = lease->address.iabuf;
1477 options[i]->len = lease->address.len;
1478 options[i]->buf_size = lease->address.len;
1479 options[i]->timeout = 0xFFFFFFFF;
1480
1481 /* Send the uid if the user supplied one. */
1482 i = DHO_DHCP_CLIENT_IDENTIFIER;
1483 if (ip->client->config->send_options[i].len) {
1484 options[i] = &client_id_tree;
1485 options[i]->value = ip->client->config->send_options[i].data;
1486 options[i]->len = ip->client->config->send_options[i].len;
1487 options[i]->buf_size = ip->client->config->send_options[i].len;
1488 options[i]->timeout = 0xFFFFFFFF;
1489 }
1490
1491
1492 /* Set up the option buffer... */
1493 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1494 options, 0, 0, 0, NULL, 0);
1495 if (ip->client->packet_length < BOOTP_MIN_LEN)
1496 ip->client->packet_length = BOOTP_MIN_LEN;
1497
1498 ip->client->packet.op = BOOTREQUEST;
1499 ip->client->packet.htype = ip->hw_address.htype;
1500 ip->client->packet.hlen = ip->hw_address.hlen;
1501 ip->client->packet.hops = 0;
1502 ip->client->packet.xid = ip->client->xid;
1503 ip->client->packet.secs = 0; /* Filled in by send_request. */
1504 ip->client->packet.flags = 0;
1505
1506 /* ciaddr must always be zero. */
1507 memset(&ip->client->packet.ciaddr, 0,
1508 sizeof(ip->client->packet.ciaddr));
1509 memset(&ip->client->packet.yiaddr, 0,
1510 sizeof(ip->client->packet.yiaddr));
1511 memset(&ip->client->packet.siaddr, 0,
1512 sizeof(ip->client->packet.siaddr));
1513 memset(&ip->client->packet.giaddr, 0,
1514 sizeof(ip->client->packet.giaddr));
1515 memcpy(ip->client->packet.chaddr,
1516 ip->hw_address.haddr, ip->hw_address.hlen);
1517 }
1518
1519 void
1520 free_client_lease(struct client_lease *lease)
1521 {
1522 int i;
1523
1524 if (lease->server_name)
1525 free(lease->server_name);
1526 if (lease->filename)
1527 free(lease->filename);
1528 for (i = 0; i < 256; i++) {
1529 if (lease->options[i].len)
1530 free(lease->options[i].data);
1531 }
1532 free(lease);
1533 }
1534
1535 FILE *leaseFile;
1536
1537 void
1538 rewrite_client_leases(struct interface_info *ifi)
1539 {
1540 struct client_lease *lp;
1541
1542 if (!leaseFile) {
1543 leaseFile = fopen(path_dhclient_db, "w");
1544 if (!leaseFile)
1545 error("can't create %s", path_dhclient_db);
1546 } else {
1547 fflush(leaseFile);
1548 rewind(leaseFile);
1549 }
1550
1551 for (lp = ifi->client->leases; lp; lp = lp->next)
1552 write_client_lease(ifi, lp, 1);
1553 if (ifi->client->active)
1554 write_client_lease(ifi, ifi->client->active, 1);
1555
1556 fflush(leaseFile);
1557 }
1558
1559 void
1560 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1561 int rewrite)
1562 {
1563 static int leases_written;
1564 struct tm *t;
1565 int i;
1566
1567 if (!rewrite) {
1568 if (leases_written++ > 20) {
1569 rewrite_client_leases(ip);
1570 leases_written = 0;
1571 }
1572 }
1573
1574 /* If the lease came from the config file, we don't need to stash
1575 a copy in the lease database. */
1576 if (lease->is_static)
1577 return;
1578
1579 if (!leaseFile) { /* XXX */
1580 leaseFile = fopen(path_dhclient_db, "w");
1581 if (!leaseFile) {
1582 error("can't create %s", path_dhclient_db);
1583 return;
1584 }
1585 }
1586
1587 fprintf(leaseFile, "lease {\n");
1588 if (lease->is_bootp)
1589 fprintf(leaseFile, " bootp;\n");
1590 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1591 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1592 if (lease->filename)
1593 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1594 if (lease->server_name)
1595 fprintf(leaseFile, " server-name \"%s\";\n",
1596 lease->server_name);
1597 if (lease->medium)
1598 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1599 for (i = 0; i < 256; i++)
1600 if (lease->options[i].len)
1601 fprintf(leaseFile, " option %s %s;\n",
1602 dhcp_options[i].name,
1603 pretty_print_option(i, lease->options[i].data,
1604 lease->options[i].len, 1, 1));
1605
1606 t = gmtime(&lease->renewal);
1607 if (t)
1608 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1609 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1610 t->tm_hour, t->tm_min, t->tm_sec);
1611 t = gmtime(&lease->rebind);
1612 if (t)
1613 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1614 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1615 t->tm_hour, t->tm_min, t->tm_sec);
1616 t = gmtime(&lease->expiry);
1617 if (t)
1618 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1619 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1620 t->tm_hour, t->tm_min, t->tm_sec);
1621 fprintf(leaseFile, "}\n");
1622 fflush(leaseFile);
1623 }
1624
1625 void
1626 script_init(char *reason, struct string_list *medium)
1627 {
1628 size_t len, mediumlen = 0;
1629 struct imsg_hdr hdr;
1630 struct buf *buf;
1631 int errs;
1632
1633 if (medium != NULL && medium->string != NULL)
1634 mediumlen = strlen(medium->string);
1635
1636 hdr.code = IMSG_SCRIPT_INIT;
1637 hdr.len = sizeof(struct imsg_hdr) +
1638 sizeof(size_t) + mediumlen +
1639 sizeof(size_t) + strlen(reason);
1640
1641 if ((buf = buf_open(hdr.len)) == NULL)
1642 return;
1643
1644 errs = 0;
1645 errs += buf_add(buf, &hdr, sizeof(hdr));
1646 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1647 if (mediumlen > 0)
1648 errs += buf_add(buf, medium->string, mediumlen);
1649 len = strlen(reason);
1650 errs += buf_add(buf, &len, sizeof(len));
1651 errs += buf_add(buf, reason, len);
1652
1653 if (errs)
1654 error("buf_add: %d", WSAGetLastError());
1655
1656 if (buf_close(privfd, buf) == -1)
1657 error("buf_close: %d", WSAGetLastError());
1658 }
1659
1660 void
1661 priv_script_init(struct interface_info *ip, char *reason, char *medium)
1662 {
1663 if (ip) {
1664 // XXX Do we need to do anything?
1665 }
1666 }
1667
1668 void
1669 priv_script_write_params(struct interface_info *ip, char *prefix, struct client_lease *lease)
1670 {
1671 u_int8_t dbuf[1500];
1672 int i, len = 0;
1673
1674 #if 0
1675 script_set_env(ip->client, prefix, "ip_address",
1676 piaddr(lease->address));
1677 #endif
1678
1679 if (lease->options[DHO_SUBNET_MASK].len &&
1680 (lease->options[DHO_SUBNET_MASK].len <
1681 sizeof(lease->address.iabuf))) {
1682 struct iaddr netmask, subnet, broadcast;
1683
1684 memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data,
1685 lease->options[DHO_SUBNET_MASK].len);
1686 netmask.len = lease->options[DHO_SUBNET_MASK].len;
1687
1688 subnet = subnet_number(lease->address, netmask);
1689 if (subnet.len) {
1690 #if 0
1691 script_set_env(ip->client, prefix, "network_number",
1692 piaddr(subnet));
1693 #endif
1694 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1695 broadcast = broadcast_addr(subnet, netmask);
1696 if (broadcast.len)
1697 #if 0
1698 script_set_env(ip->client, prefix,
1699 "broadcast_address",
1700 piaddr(broadcast));
1701 #else
1702 ;
1703 #endif
1704 }
1705 }
1706 }
1707
1708 #if 0
1709 if (lease->filename)
1710 script_set_env(ip->client, prefix, "filename", lease->filename);
1711 if (lease->server_name)
1712 script_set_env(ip->client, prefix, "server_name",
1713 lease->server_name);
1714 #endif
1715
1716 for (i = 0; i < 256; i++) {
1717 u_int8_t *dp = NULL;
1718
1719 if (ip->client->config->defaults[i].len) {
1720 if (lease->options[i].len) {
1721 switch (
1722 ip->client->config->default_actions[i]) {
1723 case ACTION_DEFAULT:
1724 dp = lease->options[i].data;
1725 len = lease->options[i].len;
1726 break;
1727 case ACTION_SUPERSEDE:
1728 supersede:
1729 dp = ip->client->
1730 config->defaults[i].data;
1731 len = ip->client->
1732 config->defaults[i].len;
1733 break;
1734 case ACTION_PREPEND:
1735 len = ip->client->
1736 config->defaults[i].len +
1737 lease->options[i].len;
1738 if (len >= sizeof(dbuf)) {
1739 warning("no space to %s %s",
1740 "prepend option",
1741 dhcp_options[i].name);
1742 goto supersede;
1743 }
1744 dp = dbuf;
1745 memcpy(dp,
1746 ip->client->
1747 config->defaults[i].data,
1748 ip->client->
1749 config->defaults[i].len);
1750 memcpy(dp + ip->client->
1751 config->defaults[i].len,
1752 lease->options[i].data,
1753 lease->options[i].len);
1754 dp[len] = '\0';
1755 break;
1756 case ACTION_APPEND:
1757 len = ip->client->
1758 config->defaults[i].len +
1759 lease->options[i].len + 1;
1760 if (len > sizeof(dbuf)) {
1761 warning("no space to %s %s",
1762 "append option",
1763 dhcp_options[i].name);
1764 goto supersede;
1765 }
1766 dp = dbuf;
1767 memcpy(dp,
1768 lease->options[i].data,
1769 lease->options[i].len);
1770 memcpy(dp + lease->options[i].len,
1771 ip->client->
1772 config->defaults[i].data,
1773 ip->client->
1774 config->defaults[i].len);
1775 dp[len-1] = '\0';
1776 }
1777 } else {
1778 dp = ip->client->
1779 config->defaults[i].data;
1780 len = ip->client->
1781 config->defaults[i].len;
1782 }
1783 } else if (lease->options[i].len) {
1784 len = lease->options[i].len;
1785 dp = lease->options[i].data;
1786 } else {
1787 len = 0;
1788 }
1789 #if 0
1790 if (len) {
1791 char name[256];
1792
1793 if (dhcp_option_ev_name(name, sizeof(name),
1794 &dhcp_options[i]))
1795 script_set_env(ip->client, prefix, name,
1796 pretty_print_option(i, dp, len, 0, 0));
1797 }
1798 #endif
1799 }
1800 #if 0
1801 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
1802 script_set_env(ip->client, prefix, "expiry", tbuf);
1803 #endif
1804 }
1805
1806 void
1807 script_write_params(char *prefix, struct client_lease *lease)
1808 {
1809 size_t fn_len = 0, sn_len = 0, pr_len = 0;
1810 struct imsg_hdr hdr;
1811 struct buf *buf;
1812 int errs, i;
1813
1814 if (lease->filename != NULL)
1815 fn_len = strlen(lease->filename);
1816 if (lease->server_name != NULL)
1817 sn_len = strlen(lease->server_name);
1818 if (prefix != NULL)
1819 pr_len = strlen(prefix);
1820
1821 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
1822 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
1823 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
1824 sizeof(size_t) + pr_len;
1825
1826 for (i = 0; i < 256; i++)
1827 hdr.len += sizeof(int) + lease->options[i].len;
1828
1829 scripttime = time(NULL);
1830
1831 if ((buf = buf_open(hdr.len)) == NULL)
1832 return;
1833
1834 errs = 0;
1835 errs += buf_add(buf, &hdr, sizeof(hdr));
1836 errs += buf_add(buf, lease, sizeof(struct client_lease));
1837 errs += buf_add(buf, &fn_len, sizeof(fn_len));
1838 errs += buf_add(buf, lease->filename, fn_len);
1839 errs += buf_add(buf, &sn_len, sizeof(sn_len));
1840 errs += buf_add(buf, lease->server_name, sn_len);
1841 errs += buf_add(buf, &pr_len, sizeof(pr_len));
1842 errs += buf_add(buf, prefix, pr_len);
1843
1844 for (i = 0; i < 256; i++) {
1845 errs += buf_add(buf, &lease->options[i].len,
1846 sizeof(lease->options[i].len));
1847 errs += buf_add(buf, lease->options[i].data,
1848 lease->options[i].len);
1849 }
1850
1851 if (errs)
1852 error("buf_add: %d", WSAGetLastError());
1853
1854 if (buf_close(privfd, buf) == -1)
1855 error("buf_close: %d", WSAGetLastError());
1856 }
1857
1858 int
1859 dhcp_option_ev_name(char *buf, size_t buflen, struct dhcp_option *option)
1860 {
1861 int i;
1862
1863 for (i = 0; option->name[i]; i++) {
1864 if (i + 1 == buflen)
1865 return 0;
1866 if (option->name[i] == '-')
1867 buf[i] = '_';
1868 else
1869 buf[i] = option->name[i];
1870 }
1871
1872 buf[i] = 0;
1873 return 1;
1874 }
1875
1876 #if 0
1877 void
1878 go_daemon(void)
1879 {
1880 static int state = 0;
1881
1882 if (no_daemon || state)
1883 return;
1884
1885 state = 1;
1886
1887 /* Stop logging to stderr... */
1888 log_perror = 0;
1889
1890 if (daemon(1, 0) == -1)
1891 error("daemon");
1892
1893 /* we are chrooted, daemon(3) fails to open /dev/null */
1894 if (nullfd != -1) {
1895 dup2(nullfd, STDIN_FILENO);
1896 dup2(nullfd, STDOUT_FILENO);
1897 dup2(nullfd, STDERR_FILENO);
1898 close(nullfd);
1899 nullfd = -1;
1900 }
1901 }
1902 #endif
1903
1904 int
1905 check_option(struct client_lease *l, int option)
1906 {
1907 char *opbuf;
1908 char *sbuf;
1909
1910 /* we use this, since this is what gets passed to dhclient-script */
1911
1912 opbuf = pretty_print_option(option, l->options[option].data,
1913 l->options[option].len, 0, 0);
1914
1915 sbuf = option_as_string(option, l->options[option].data,
1916 l->options[option].len);
1917
1918 switch (option) {
1919 case DHO_SUBNET_MASK:
1920 case DHO_TIME_SERVERS:
1921 case DHO_NAME_SERVERS:
1922 case DHO_ROUTERS:
1923 case DHO_DOMAIN_NAME_SERVERS:
1924 case DHO_LOG_SERVERS:
1925 case DHO_COOKIE_SERVERS:
1926 case DHO_LPR_SERVERS:
1927 case DHO_IMPRESS_SERVERS:
1928 case DHO_RESOURCE_LOCATION_SERVERS:
1929 case DHO_SWAP_SERVER:
1930 case DHO_BROADCAST_ADDRESS:
1931 case DHO_NIS_SERVERS:
1932 case DHO_NTP_SERVERS:
1933 case DHO_NETBIOS_NAME_SERVERS:
1934 case DHO_NETBIOS_DD_SERVER:
1935 case DHO_FONT_SERVERS:
1936 case DHO_DHCP_SERVER_IDENTIFIER:
1937 if (!ipv4addrs(opbuf)) {
1938 warning("Invalid IP address in option(%d): %s", option, opbuf);
1939 return (0);
1940 }
1941 return (1) ;
1942 case DHO_HOST_NAME:
1943 case DHO_DOMAIN_NAME:
1944 case DHO_NIS_DOMAIN:
1945 if (!res_hnok(sbuf))
1946 warning("Bogus Host Name option %d: %s (%s)", option,
1947 sbuf, opbuf);
1948 return (1);
1949 case DHO_PAD:
1950 case DHO_TIME_OFFSET:
1951 case DHO_BOOT_SIZE:
1952 case DHO_MERIT_DUMP:
1953 case DHO_ROOT_PATH:
1954 case DHO_EXTENSIONS_PATH:
1955 case DHO_IP_FORWARDING:
1956 case DHO_NON_LOCAL_SOURCE_ROUTING:
1957 case DHO_POLICY_FILTER:
1958 case DHO_MAX_DGRAM_REASSEMBLY:
1959 case DHO_DEFAULT_IP_TTL:
1960 case DHO_PATH_MTU_AGING_TIMEOUT:
1961 case DHO_PATH_MTU_PLATEAU_TABLE:
1962 case DHO_INTERFACE_MTU:
1963 case DHO_ALL_SUBNETS_LOCAL:
1964 case DHO_PERFORM_MASK_DISCOVERY:
1965 case DHO_MASK_SUPPLIER:
1966 case DHO_ROUTER_DISCOVERY:
1967 case DHO_ROUTER_SOLICITATION_ADDRESS:
1968 case DHO_STATIC_ROUTES:
1969 case DHO_TRAILER_ENCAPSULATION:
1970 case DHO_ARP_CACHE_TIMEOUT:
1971 case DHO_IEEE802_3_ENCAPSULATION:
1972 case DHO_DEFAULT_TCP_TTL:
1973 case DHO_TCP_KEEPALIVE_INTERVAL:
1974 case DHO_TCP_KEEPALIVE_GARBAGE:
1975 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
1976 case DHO_NETBIOS_NODE_TYPE:
1977 case DHO_NETBIOS_SCOPE:
1978 case DHO_X_DISPLAY_MANAGER:
1979 case DHO_DHCP_REQUESTED_ADDRESS:
1980 case DHO_DHCP_LEASE_TIME:
1981 case DHO_DHCP_OPTION_OVERLOAD:
1982 case DHO_DHCP_MESSAGE_TYPE:
1983 case DHO_DHCP_PARAMETER_REQUEST_LIST:
1984 case DHO_DHCP_MESSAGE:
1985 case DHO_DHCP_MAX_MESSAGE_SIZE:
1986 case DHO_DHCP_RENEWAL_TIME:
1987 case DHO_DHCP_REBINDING_TIME:
1988 case DHO_DHCP_CLASS_IDENTIFIER:
1989 case DHO_DHCP_CLIENT_IDENTIFIER:
1990 case DHO_DHCP_USER_CLASS_ID:
1991 case DHO_END:
1992 return (1);
1993 default:
1994 warning("unknown dhcp option value 0x%x", option);
1995 return (unknown_ok);
1996 }
1997 }
1998
1999 int
2000 res_hnok(const char *dn)
2001 {
2002 int pch = PERIOD, ch = *dn++;
2003
2004 while (ch != '\0') {
2005 int nch = *dn++;
2006
2007 if (periodchar(ch)) {
2008 ;
2009 } else if (periodchar(pch)) {
2010 if (!borderchar(ch))
2011 return (0);
2012 } else if (periodchar(nch) || nch == '\0') {
2013 if (!borderchar(ch))
2014 return (0);
2015 } else {
2016 if (!middlechar(ch))
2017 return (0);
2018 }
2019 pch = ch, ch = nch;
2020 }
2021 return (1);
2022 }
2023
2024 /* Does buf consist only of dotted decimal ipv4 addrs?
2025 * return how many if so,
2026 * otherwise, return 0
2027 */
2028 int
2029 ipv4addrs(char * buf)
2030 {
2031 char *tmp;
2032 struct in_addr jnk;
2033 int i = 0;
2034
2035 note("Input: %s", buf);
2036
2037 do {
2038 tmp = strtok(buf, " ");
2039 note("got %s", tmp);
2040 if( tmp && inet_aton(tmp, &jnk) ) i++;
2041 buf = NULL;
2042 } while( tmp );
2043
2044 return (i);
2045 }
2046
2047
2048 char *
2049 option_as_string(unsigned int code, unsigned char *data, int len)
2050 {
2051 static char optbuf[32768]; /* XXX */
2052 char *op = optbuf;
2053 int opleft = sizeof(optbuf);
2054 unsigned char *dp = data;
2055
2056 if (code > 255)
2057 error("option_as_string: bad code %d", code);
2058
2059 for (; dp < data + len; dp++) {
2060 if (!isascii(*dp) || !isprint(*dp)) {
2061 if (dp + 1 != data + len || *dp != 0) {
2062 _snprintf(op, opleft, "\\%03o", *dp);
2063 op += 4;
2064 opleft -= 4;
2065 }
2066 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2067 *dp == '`' || *dp == '\\') {
2068 *op++ = '\\';
2069 *op++ = *dp;
2070 opleft -= 2;
2071 } else {
2072 *op++ = *dp;
2073 opleft--;
2074 }
2075 }
2076 if (opleft < 1)
2077 goto toobig;
2078 *op = 0;
2079 return optbuf;
2080 toobig:
2081 warning("dhcp option too large");
2082 return "<error>";
2083 }
2084