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