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