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