]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/discover.c
- Merge changes between 3.0.3RC1 and 3.0.4-BETA-3 into HEAD (silence
[thirdparty/dhcp.git] / common / discover.c
1 /* dispatch.c
2
3 Network input dispatcher... */
4
5 /*
6 * Copyright (c) 2004-2006 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
33 */
34
35 #ifndef lint
36 static char copyright[] =
37 "$Id: discover.c,v 1.49 2006/02/24 23:16:28 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
39
40 #include "dhcpd.h"
41 #include <sys/ioctl.h>
42
43 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
44 int interfaces_invalidated;
45 int quiet_interface_discovery;
46 u_int16_t local_port;
47 u_int16_t remote_port;
48 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
49 int (*dhcp_interface_discovery_hook) (struct interface_info *);
50 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
51 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
52
53 struct in_addr limited_broadcast;
54 struct in_addr local_address;
55
56 void (*bootp_packet_handler) PROTO ((struct interface_info *,
57 struct dhcp_packet *, unsigned,
58 unsigned int,
59 struct iaddr, struct hardware *));
60
61 omapi_object_type_t *dhcp_type_interface;
62 #if defined (TRACING)
63 trace_type_t *interface_trace;
64 trace_type_t *inpacket_trace;
65 trace_type_t *outpacket_trace;
66 #endif
67 struct interface_info **interface_vector;
68 int interface_count;
69 int interface_max;
70
71 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
72
73 isc_result_t interface_setup ()
74 {
75 isc_result_t status;
76 status = omapi_object_type_register (&dhcp_type_interface,
77 "interface",
78 dhcp_interface_set_value,
79 dhcp_interface_get_value,
80 dhcp_interface_destroy,
81 dhcp_interface_signal_handler,
82 dhcp_interface_stuff_values,
83 dhcp_interface_lookup,
84 dhcp_interface_create,
85 dhcp_interface_remove,
86 0, 0, 0,
87 sizeof (struct interface_info),
88 interface_initialize, RC_MISC);
89 if (status != ISC_R_SUCCESS)
90 log_fatal ("Can't register interface object type: %s",
91 isc_result_totext (status));
92
93 return status;
94 }
95
96 #if defined (TRACING)
97 void interface_trace_setup ()
98 {
99 interface_trace = trace_type_register ("interface", (void *)0,
100 trace_interface_input,
101 trace_interface_stop, MDL);
102 inpacket_trace = trace_type_register ("inpacket", (void *)0,
103 trace_inpacket_input,
104 trace_inpacket_stop, MDL);
105 outpacket_trace = trace_type_register ("outpacket", (void *)0,
106 trace_outpacket_input,
107 trace_outpacket_stop, MDL);
108 }
109 #endif
110
111 isc_result_t interface_initialize (omapi_object_t *ipo,
112 const char *file, int line)
113 {
114 struct interface_info *ip = (struct interface_info *)ipo;
115 ip -> rfdesc = ip -> wfdesc = -1;
116 return ISC_R_SUCCESS;
117 }
118
119 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
120 For each interface that's of type INET and not the loopback interface,
121 register that interface with the network I/O software, figure out what
122 subnet it's on, and add it to the list of interfaces. */
123
124 void discover_interfaces (state)
125 int state;
126 {
127 struct interface_info *tmp, *ip;
128 struct interface_info *last, *next;
129 char buf [2048];
130 struct ifconf ic;
131 struct ifreq ifr;
132 int i;
133 int sock;
134 int address_count = 0;
135 struct subnet *subnet;
136 struct shared_network *share;
137 struct sockaddr_in foo;
138 int ir;
139 struct ifreq *tif;
140 #ifdef ALIAS_NAMES_PERMUTED
141 char *s;
142 #endif
143 isc_result_t status;
144 static int setup_fallback = 0;
145 int wifcount = 0;
146
147 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
148 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
149 log_fatal ("Can't create addrlist socket");
150
151 /* Get the interface configuration information... */
152
153 #ifdef SIOCGIFCONF_ZERO_PROBE
154 /* linux will only tell us how long a buffer it wants if we give it
155 * a null buffer first. So, do a dry run to figure out the length.
156 *
157 * XXX this code is duplicated from below because trying to fold
158 * the logic into the if statement and goto resulted in excesssive
159 * obfuscation. The intent is that unless you run Linux you shouldn't
160 * have to deal with this. */
161
162 ic.ifc_len = 0;
163 ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
164 #else
165 /* otherwise, we just feed it a starting size, and it'll tell us if
166 * it needs more */
167
168 ic.ifc_len = sizeof buf;
169 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
170 #endif
171
172 gifconf_again:
173 i = ioctl(sock, SIOCGIFCONF, &ic);
174
175 if (i < 0)
176 log_fatal ("ioctl: SIOCGIFCONF: %m");
177
178 #ifdef SIOCGIFCONF_ZERO_PROBE
179 /* Workaround for SIOCGIFCONF bug on some Linux versions. */
180 if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
181 ic.ifc_len = sizeof buf;
182 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
183 goto gifconf_again;
184 }
185 #endif
186
187 /* If the SIOCGIFCONF resulted in more data than would fit in
188 a buffer, allocate a bigger buffer. */
189 if ((ic.ifc_ifcu.ifcu_buf == buf
190 #ifdef SIOCGIFCONF_ZERO_PROBE
191 || ic.ifc_ifcu.ifcu_buf == 0
192 #endif
193 ) && ic.ifc_len > sizeof buf) {
194 ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL);
195 if (!ic.ifc_ifcu.ifcu_buf)
196 log_fatal ("Can't allocate SIOCGIFCONF buffer.");
197 goto gifconf_again;
198 #ifdef SIOCGIFCONF_ZERO_PROBE
199 } else if (ic.ifc_ifcu.ifcu_buf == 0) {
200 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
201 ic.ifc_len = sizeof buf;
202 goto gifconf_again;
203 #endif
204 }
205
206
207 /* If we already have a list of interfaces, and we're running as
208 a DHCP server, the interfaces were requested. */
209 if (interfaces && (state == DISCOVER_SERVER ||
210 state == DISCOVER_RELAY ||
211 state == DISCOVER_REQUESTED))
212 ir = 0;
213 else if (state == DISCOVER_UNCONFIGURED)
214 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
215 else
216 ir = INTERFACE_REQUESTED;
217
218 /* Cycle through the list of interfaces looking for IP addresses. */
219 for (i = 0; i < ic.ifc_len;) {
220 struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
221 #ifdef HAVE_SA_LEN
222 if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
223 i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
224 else
225 #endif
226 i += sizeof *ifp;
227
228 #ifdef ALIAS_NAMES_PERMUTED
229 if ((s = strrchr (ifp -> ifr_name, ':'))) {
230 *s = 0;
231 }
232 #endif
233
234 #ifdef SKIP_DUMMY_INTERFACES
235 if (!strncmp (ifp -> ifr_name, "dummy", 5))
236 continue;
237 #endif
238
239
240 /* See if this is the sort of interface we want to
241 deal with. */
242 strcpy (ifr.ifr_name, ifp -> ifr_name);
243 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
244 log_fatal ("Can't get interface flags for %s: %m",
245 ifr.ifr_name);
246
247 /* See if we've seen an interface that matches this one. */
248 for (tmp = interfaces; tmp; tmp = tmp -> next)
249 if (!strcmp (tmp -> name, ifp -> ifr_name))
250 break;
251
252 /* Skip non broadcast interfaces (plus loopback and
253 point-to-point in case an OS incorrectly marks them
254 as broadcast). Also skip down interfaces unless we're
255 trying to get a list of configurable interfaces. */
256 if (((!(ifr.ifr_flags & IFF_BROADCAST) ||
257 ifr.ifr_flags & IFF_LOOPBACK ||
258 ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) ||
259 (!(ifr.ifr_flags & IFF_UP) &&
260 state != DISCOVER_UNCONFIGURED))
261 continue;
262
263 /* If there isn't already an interface by this name,
264 allocate one. */
265 if (!tmp) {
266 tmp = (struct interface_info *)0;
267 status = interface_allocate (&tmp, MDL);
268 if (status != ISC_R_SUCCESS)
269 log_fatal ("Error allocating interface %s: %s",
270 ifp -> ifr_name,
271 isc_result_totext (status));
272 strcpy (tmp -> name, ifp -> ifr_name);
273 interface_snorf (tmp, ir);
274 interface_dereference (&tmp, MDL);
275 tmp = interfaces; /* XXX */
276 }
277
278 if (dhcp_interface_discovery_hook)
279 (*dhcp_interface_discovery_hook) (tmp);
280
281 /* If we have the capability, extract link information
282 and record it in a linked list. */
283 #ifdef HAVE_AF_LINK
284 if (ifp -> ifr_addr.sa_family == AF_LINK) {
285 struct sockaddr_dl *foo = ((struct sockaddr_dl *)
286 (&ifp -> ifr_addr));
287 #if defined (HAVE_SIN_LEN)
288 tmp -> hw_address.hlen = foo -> sdl_alen;
289 #else
290 tmp -> hw_address.hlen = 6; /* XXX!!! */
291 #endif
292 tmp -> hw_address.hbuf [0] = HTYPE_ETHER; /* XXX */
293 memcpy (&tmp -> hw_address.hbuf [1],
294 LLADDR (foo), tmp -> hw_address.hlen);
295 tmp -> hw_address.hlen++; /* for type. */
296 } else
297 #endif /* AF_LINK */
298
299 if (ifp -> ifr_addr.sa_family == AF_INET) {
300 struct iaddr addr;
301
302 /* Get a pointer to the address... */
303 memcpy (&foo, &ifp -> ifr_addr,
304 sizeof ifp -> ifr_addr);
305
306 /* We don't want the loopback interface. */
307 if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) &&
308 ((tmp -> flags & INTERFACE_AUTOMATIC) &&
309 state == DISCOVER_SERVER))
310 continue;
311
312
313 /* If this is the first real IP address we've
314 found, keep a pointer to ifreq structure in
315 which we found it. */
316 if (!tmp -> ifp) {
317 #ifdef HAVE_SA_LEN
318 unsigned len = ((sizeof ifp -> ifr_name) +
319 ifp -> ifr_addr.sa_len);
320 #else
321 unsigned len = sizeof *ifp;
322 #endif
323 tif = (struct ifreq *)dmalloc (len, MDL);
324 if (!tif)
325 log_fatal ("no space for ifp.");
326 memcpy (tif, ifp, len);
327 tmp -> ifp = tif;
328 tmp -> primary_address = foo.sin_addr;
329 }
330
331 /* Grab the address... */
332 addr.len = 4;
333 memcpy (addr.iabuf, &foo.sin_addr.s_addr,
334 addr.len);
335 if (dhcp_interface_setup_hook)
336 (*dhcp_interface_setup_hook) (tmp, &addr);
337 }
338 }
339
340 /* If we allocated a buffer, free it. */
341 if (ic.ifc_ifcu.ifcu_buf != buf)
342 dfree (ic.ifc_ifcu.ifcu_buf, MDL);
343
344 #if defined (LINUX_SLASHPROC_DISCOVERY)
345 /* On Linux, interfaces that don't have IP addresses don't
346 show up in the SIOCGIFCONF syscall. This only matters for
347 the DHCP client, of course - the relay agent and server
348 should only care about interfaces that are configured with
349 IP addresses anyway.
350
351 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
352 that, when read, prints a human readable network status. We
353 extract the names of the network devices by skipping the first
354 two lines (which are header) and then parsing off everything
355 up to the colon in each subsequent line - these lines start
356 with the interface name, then a colon, then a bunch of
357 statistics. */
358
359 if (state == DISCOVER_UNCONFIGURED) {
360 FILE *proc_dev;
361 char buffer [256];
362 int skip = 2;
363
364 proc_dev = fopen (PROCDEV_DEVICE, "r");
365 if (!proc_dev)
366 log_fatal ("%s: %m", PROCDEV_DEVICE);
367
368 while (fgets (buffer, sizeof buffer, proc_dev)) {
369 char *name = buffer;
370 char *sep;
371
372 /* Skip the first two blocks, which are header
373 lines. */
374 if (skip) {
375 --skip;
376 continue;
377 }
378
379 sep = strrchr (buffer, ':');
380 if (sep)
381 *sep = '\0';
382 while (*name == ' ')
383 name++;
384
385 /* See if we've seen an interface that matches
386 this one. */
387 for (tmp = interfaces; tmp; tmp = tmp -> next)
388 if (!strcmp (tmp -> name, name))
389 break;
390
391 /* If we found one, nothing more to do.. */
392 if (tmp)
393 continue;
394
395 strncpy (ifr.ifr_name, name, IFNAMSIZ);
396
397 /* Skip non broadcast interfaces (plus loopback and
398 * point-to-point in case an OS incorrectly marks them
399 * as broadcast).
400 */
401 if ((ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) ||
402 (!(ifr.ifr_flags & IFF_BROADCAST)) ||
403 (ifr.ifr_flags & IFF_LOOPBACK ) ||
404 (ifr.ifr_flags & IFF_POINTOPOINT))
405 continue;
406
407 /* Otherwise, allocate one. */
408 tmp = (struct interface_info *)0;
409 status = interface_allocate (&tmp, MDL);
410 if (status != ISC_R_SUCCESS)
411 log_fatal ("Can't allocate interface %s: %s",
412 name, isc_result_totext (status));
413 tmp -> flags = ir;
414 strncpy (tmp -> name, name, IFNAMSIZ);
415 if (interfaces) {
416 interface_reference (&tmp -> next,
417 interfaces, MDL);
418 interface_dereference (&interfaces, MDL);
419 }
420 interface_reference (&interfaces, tmp, MDL);
421 interface_dereference (&tmp, MDL);
422 tmp = interfaces;
423
424 if (dhcp_interface_discovery_hook)
425 (*dhcp_interface_discovery_hook) (tmp);
426
427 }
428 fclose (proc_dev);
429 }
430 #endif
431
432 /* Now cycle through all the interfaces we found, looking for
433 hardware addresses. */
434 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
435 for (tmp = interfaces; tmp; tmp = tmp -> next) {
436 struct ifreq ifr;
437 struct sockaddr sa;
438 int b, sk;
439
440 if (!tmp -> ifp) {
441 /* Make up an ifreq structure. */
442 tif = (struct ifreq *)dmalloc (sizeof (struct ifreq),
443 MDL);
444 if (!tif)
445 log_fatal ("no space to remember ifp.");
446 memset (tif, 0, sizeof (struct ifreq));
447 strcpy (tif -> ifr_name, tmp -> name);
448 tmp -> ifp = tif;
449 }
450
451 /* Read the hardware address from this interface. */
452 ifr = *tmp -> ifp;
453 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
454 continue;
455
456 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
457
458 switch (sa.sa_family) {
459 #ifdef HAVE_ARPHRD_TUNNEL
460 case ARPHRD_TUNNEL:
461 /* ignore tunnel interfaces. */
462 #endif
463 #ifdef HAVE_ARPHRD_ROSE
464 case ARPHRD_ROSE:
465 #endif
466 #ifdef HAVE_ARPHRD_IRDA
467 case ARPHRD_IRDA:
468 /* ignore infrared interfaces. */
469 #endif
470 #ifdef HAVE_ARPHRD_SIT
471 case ARPHRD_SIT:
472 /* ignore IPv6-in-IPv4 interfaces. */
473 #endif
474 #ifdef HAVE_ARPHRD_IEEE1394
475 case ARPHRD_IEEE1394:
476 /* ignore IEEE1394 interfaces. */
477 #endif
478 #ifdef HAVE_ARPHRD_LOOPBACK
479 case ARPHRD_LOOPBACK:
480 /* ignore loopback interface */
481 break;
482 #endif
483
484 case ARPHRD_ETHER:
485 tmp -> hw_address.hlen = 7;
486 tmp -> hw_address.hbuf [0] = ARPHRD_ETHER;
487 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
488 break;
489
490 #ifndef HAVE_ARPHRD_IEEE802
491 # define ARPHRD_IEEE802 HTYPE_IEEE802
492 #endif
493 #if defined (HAVE_ARPHRD_IEEE802_TR)
494 case ARPHRD_IEEE802_TR:
495 #endif
496 case ARPHRD_IEEE802:
497 tmp -> hw_address.hlen = 7;
498 tmp -> hw_address.hbuf [0] = ARPHRD_IEEE802;
499 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
500 break;
501
502 #ifndef HAVE_ARPHRD_FDDI
503 # define ARPHRD_FDDI HTYPE_FDDI
504 #endif
505 case ARPHRD_FDDI:
506 tmp -> hw_address.hlen = 17;
507 tmp -> hw_address.hbuf [0] = HTYPE_FDDI; /* XXX */
508 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 16);
509 break;
510
511 #ifdef HAVE_ARPHRD_METRICOM
512 case ARPHRD_METRICOM:
513 tmp -> hw_address.hlen = 7;
514 tmp -> hw_address.hbuf [0] = ARPHRD_METRICOM;
515 memcpy (&tmp -> hw_address.hbuf [0], sa.sa_data, 6);
516 break;
517 #endif
518
519 #ifdef HAVE_ARPHRD_AX25
520 case ARPHRD_AX25:
521 tmp -> hw_address.hlen = 7;
522 tmp -> hw_address.hbuf [0] = ARPHRD_AX25;
523 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
524 break;
525 #endif
526
527 #ifdef HAVE_ARPHRD_NETROM
528 case ARPHRD_NETROM:
529 tmp -> hw_address.hlen = 7;
530 tmp -> hw_address.hbuf [0] = ARPHRD_NETROM;
531 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
532 break;
533 #endif
534
535 default:
536 log_error ("%s: unknown hardware address type %d",
537 ifr.ifr_name, sa.sa_family);
538 break;
539 }
540 }
541 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
542
543 /* If we're just trying to get a list of interfaces that we might
544 be able to configure, we can quit now. */
545 if (state == DISCOVER_UNCONFIGURED) {
546 close (sock);
547 return;
548 }
549
550 /* Weed out the interfaces that did not have IP addresses. */
551 tmp = last = next = (struct interface_info *)0;
552 if (interfaces)
553 interface_reference (&tmp, interfaces, MDL);
554 while (tmp) {
555 if (next)
556 interface_dereference (&next, MDL);
557 if (tmp -> next)
558 interface_reference (&next, tmp -> next, MDL);
559 /* skip interfaces that are running already */
560 if (tmp -> flags & INTERFACE_RUNNING) {
561 interface_dereference(&tmp, MDL);
562 if(next)
563 interface_reference(&tmp, next, MDL);
564 continue;
565 }
566 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
567 state == DISCOVER_REQUESTED)
568 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
569 INTERFACE_REQUESTED);
570 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
571 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
572 log_fatal ("%s: not found", tmp -> name);
573 if (!last) {
574 if (interfaces)
575 interface_dereference (&interfaces,
576 MDL);
577 if (next)
578 interface_reference (&interfaces, next, MDL);
579 } else {
580 interface_dereference (&last -> next, MDL);
581 if (next)
582 interface_reference (&last -> next,
583 next, MDL);
584 }
585 if (tmp -> next)
586 interface_dereference (&tmp -> next, MDL);
587
588 /* Remember the interface in case we need to know
589 about it later. */
590 if (dummy_interfaces) {
591 interface_reference (&tmp -> next,
592 dummy_interfaces, MDL);
593 interface_dereference (&dummy_interfaces, MDL);
594 }
595 interface_reference (&dummy_interfaces, tmp, MDL);
596 interface_dereference (&tmp, MDL);
597 if (next)
598 interface_reference (&tmp, next, MDL);
599 continue;
600 }
601 last = tmp;
602
603 memcpy (&foo, &tmp -> ifp -> ifr_addr,
604 sizeof tmp -> ifp -> ifr_addr);
605
606 /* We must have a subnet declaration for each interface. */
607 if (!tmp -> shared_network && (state == DISCOVER_SERVER)) {
608 log_error ("%s", "");
609 log_error ("No subnet declaration for %s (%s).",
610 tmp -> name, inet_ntoa (foo.sin_addr));
611 if (supports_multiple_interfaces (tmp)) {
612 log_error ("** Ignoring requests on %s. %s",
613 tmp -> name, "If this is not what");
614 log_error (" you want, please write %s",
615 "a subnet declaration");
616 log_error (" in your dhcpd.conf file %s",
617 "for the network segment");
618 log_error (" to %s %s %s",
619 "which interface",
620 tmp -> name, "is attached. **");
621 log_error ("%s", "");
622 goto next;
623 } else {
624 log_error ("You must write a subnet %s",
625 " declaration for this");
626 log_error ("subnet. You cannot prevent %s",
627 "the DHCP server");
628 log_error ("from listening on this subnet %s",
629 "because your");
630 log_fatal ("operating system does not %s.",
631 "support this capability");
632 }
633 }
634
635 /* Find subnets that don't have valid interface
636 addresses... */
637 for (subnet = (tmp -> shared_network
638 ? tmp -> shared_network -> subnets
639 : (struct subnet *)0);
640 subnet; subnet = subnet -> next_sibling) {
641 if (!subnet -> interface_address.len) {
642 /* Set the interface address for this subnet
643 to the first address we found. */
644 subnet -> interface_address.len = 4;
645 memcpy (subnet -> interface_address.iabuf,
646 &foo.sin_addr.s_addr, 4);
647 }
648 }
649
650 /* Flag the index as not having been set, so that the
651 interface registerer can set it or not as it chooses. */
652 tmp -> index = -1;
653
654 /* Register the interface... */
655 if_register_receive (tmp);
656 if_register_send (tmp);
657
658 interface_stash (tmp);
659 wifcount++;
660 #if defined (HAVE_SETFD)
661 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
662 log_error ("Can't set close-on-exec on %s: %m",
663 tmp -> name);
664 if (tmp -> rfdesc != tmp -> wfdesc) {
665 if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
666 log_error ("Can't set close-on-exec on %s: %m",
667 tmp -> name);
668 }
669 #endif
670 next:
671 interface_dereference (&tmp, MDL);
672 if (next)
673 interface_reference (&tmp, next, MDL);
674 }
675
676 /* Now register all the remaining interfaces as protocols. */
677 for (tmp = interfaces; tmp; tmp = tmp -> next) {
678 /* not if it's been registered before */
679 if (tmp -> flags & INTERFACE_RUNNING)
680 continue;
681 if (tmp -> rfdesc == -1)
682 continue;
683 status = omapi_register_io_object ((omapi_object_t *)tmp,
684 if_readsocket, 0,
685 got_one, 0, 0);
686 if (status != ISC_R_SUCCESS)
687 log_fatal ("Can't register I/O handle for %s: %s",
688 tmp -> name, isc_result_totext (status));
689 }
690
691 close (sock);
692
693 if (state == DISCOVER_SERVER && wifcount == 0) {
694 log_info ("%s", "");
695 log_fatal ("Not configured to listen on any interfaces!");
696 }
697
698 if (!setup_fallback) {
699 setup_fallback = 1;
700 maybe_setup_fallback ();
701 }
702
703 #if defined (HAVE_SETFD)
704 if (fallback_interface) {
705 if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
706 log_error ("Can't set close-on-exec on fallback: %m");
707 if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
708 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
709 log_error ("Can't set close-on-exec on fallback: %m");
710 }
711 }
712 #endif
713 }
714
715 int if_readsocket (h)
716 omapi_object_t *h;
717 {
718 struct interface_info *ip;
719
720 if (h -> type != dhcp_type_interface)
721 return -1;
722 ip = (struct interface_info *)h;
723 return ip -> rfdesc;
724 }
725
726 int setup_fallback (struct interface_info **fp, const char *file, int line)
727 {
728 isc_result_t status;
729
730 status = interface_allocate (&fallback_interface, file, line);
731 if (status != ISC_R_SUCCESS)
732 log_fatal ("Error allocating fallback interface: %s",
733 isc_result_totext (status));
734 strcpy (fallback_interface -> name, "fallback");
735 if (dhcp_interface_setup_hook)
736 (*dhcp_interface_setup_hook) (fallback_interface,
737 (struct iaddr *)0);
738 status = interface_reference (fp, fallback_interface, file, line);
739
740 fallback_interface -> index = -1;
741 interface_stash (fallback_interface);
742 return status == ISC_R_SUCCESS;
743 }
744
745 void reinitialize_interfaces ()
746 {
747 struct interface_info *ip;
748
749 for (ip = interfaces; ip; ip = ip -> next) {
750 if_reinitialize_receive (ip);
751 if_reinitialize_send (ip);
752 }
753
754 if (fallback_interface)
755 if_reinitialize_send (fallback_interface);
756
757 interfaces_invalidated = 1;
758 }
759
760 isc_result_t got_one (h)
761 omapi_object_t *h;
762 {
763 struct sockaddr_in from;
764 struct hardware hfrom;
765 struct iaddr ifrom;
766 int result;
767 union {
768 unsigned char packbuf [4095]; /* Packet input buffer.
769 Must be as large as largest
770 possible MTU. */
771 struct dhcp_packet packet;
772 } u;
773 struct interface_info *ip;
774
775 if (h -> type != dhcp_type_interface)
776 return ISC_R_INVALIDARG;
777 ip = (struct interface_info *)h;
778
779 again:
780 if ((result =
781 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
782 log_error ("receive_packet failed on %s: %m", ip -> name);
783 return ISC_R_UNEXPECTED;
784 }
785 if (result == 0)
786 return ISC_R_UNEXPECTED;
787
788 /* If we didn't at least get the fixed portion of the BOOTP
789 packet, drop the packet. We're allowing packets with no
790 sname or filename, because we're aware of at least one
791 client that sends such packets, but this definitely falls
792 into the category of being forgiving. */
793 if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN)
794 return ISC_R_UNEXPECTED;
795
796 if (bootp_packet_handler) {
797 ifrom.len = 4;
798 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
799
800 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
801 from.sin_port, ifrom, &hfrom);
802 }
803
804 /* If there is buffered data, read again. This is for, e.g.,
805 bpf, which may return two packets at once. */
806 if (ip -> rbuf_offset != ip -> rbuf_len)
807 goto again;
808 return ISC_R_SUCCESS;
809 }
810
811 isc_result_t dhcp_interface_set_value (omapi_object_t *h,
812 omapi_object_t *id,
813 omapi_data_string_t *name,
814 omapi_typed_data_t *value)
815 {
816 struct interface_info *interface;
817 isc_result_t status;
818 int foo;
819
820 if (h -> type != dhcp_type_interface)
821 return ISC_R_INVALIDARG;
822 interface = (struct interface_info *)h;
823
824 if (!omapi_ds_strcmp (name, "name")) {
825 if ((value -> type == omapi_datatype_data ||
826 value -> type == omapi_datatype_string) &&
827 value -> u.buffer.len < sizeof interface -> name) {
828 memcpy (interface -> name,
829 value -> u.buffer.value,
830 value -> u.buffer.len);
831 interface -> name [value -> u.buffer.len] = 0;
832 } else
833 return ISC_R_INVALIDARG;
834 return ISC_R_SUCCESS;
835 }
836
837 /* Try to find some inner object that can take the value. */
838 if (h -> inner && h -> inner -> type -> set_value) {
839 status = ((*(h -> inner -> type -> set_value))
840 (h -> inner, id, name, value));
841 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
842 return status;
843 }
844
845 return ISC_R_NOTFOUND;
846 }
847
848
849 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
850 omapi_object_t *id,
851 omapi_data_string_t *name,
852 omapi_value_t **value)
853 {
854 return ISC_R_NOTIMPLEMENTED;
855 }
856
857 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
858 const char *file, int line)
859 {
860 struct interface_info *interface;
861 isc_result_t status;
862
863 if (h -> type != dhcp_type_interface)
864 return ISC_R_INVALIDARG;
865 interface = (struct interface_info *)h;
866
867 if (interface -> ifp) {
868 dfree (interface -> ifp, file, line);
869 interface -> ifp = 0;
870 }
871 if (interface -> next)
872 interface_dereference (&interface -> next, file, line);
873 if (interface -> rbuf) {
874 dfree (interface -> rbuf, file, line);
875 interface -> rbuf = (unsigned char *)0;
876 }
877 if (interface -> client)
878 interface -> client = (struct client_state *)0;
879
880 if (interface -> shared_network)
881 omapi_object_dereference ((omapi_object_t **)
882 &interface -> shared_network, MDL);
883
884 return ISC_R_SUCCESS;
885 }
886
887 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
888 const char *name, va_list ap)
889 {
890 struct interface_info *ip, *interface;
891 struct client_config *config;
892 struct client_state *client;
893 isc_result_t status;
894
895 if (h -> type != dhcp_type_interface)
896 return ISC_R_INVALIDARG;
897 interface = (struct interface_info *)h;
898
899 /* If it's an update signal, see if the interface is dead right
900 now, or isn't known at all, and if that's the case, revive it. */
901 if (!strcmp (name, "update")) {
902 for (ip = dummy_interfaces; ip; ip = ip -> next)
903 if (ip == interface)
904 break;
905 if (ip && dhcp_interface_startup_hook)
906 return (*dhcp_interface_startup_hook) (ip);
907
908 for (ip = interfaces; ip; ip = ip -> next)
909 if (ip == interface)
910 break;
911 if (!ip && dhcp_interface_startup_hook)
912 return (*dhcp_interface_startup_hook) (ip);
913 }
914
915 /* Try to find some inner object that can take the value. */
916 if (h -> inner && h -> inner -> type -> get_value) {
917 status = ((*(h -> inner -> type -> signal_handler))
918 (h -> inner, name, ap));
919 if (status == ISC_R_SUCCESS)
920 return status;
921 }
922 return ISC_R_NOTFOUND;
923 }
924
925 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
926 omapi_object_t *id,
927 omapi_object_t *h)
928 {
929 struct interface_info *interface;
930 isc_result_t status;
931
932 if (h -> type != dhcp_type_interface)
933 return ISC_R_INVALIDARG;
934 interface = (struct interface_info *)h;
935
936 /* Write out all the values. */
937
938 status = omapi_connection_put_name (c, "state");
939 if (status != ISC_R_SUCCESS)
940 return status;
941 if (interface -> flags && INTERFACE_REQUESTED)
942 status = omapi_connection_put_string (c, "up");
943 else
944 status = omapi_connection_put_string (c, "down");
945 if (status != ISC_R_SUCCESS)
946 return status;
947
948 /* Write out the inner object, if any. */
949 if (h -> inner && h -> inner -> type -> stuff_values) {
950 status = ((*(h -> inner -> type -> stuff_values))
951 (c, id, h -> inner));
952 if (status == ISC_R_SUCCESS)
953 return status;
954 }
955
956 return ISC_R_SUCCESS;
957 }
958
959 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
960 omapi_object_t *id,
961 omapi_object_t *ref)
962 {
963 omapi_value_t *tv = (omapi_value_t *)0;
964 isc_result_t status;
965 struct interface_info *interface;
966
967 if (!ref)
968 return ISC_R_NOKEYS;
969
970 /* First see if we were sent a handle. */
971 status = omapi_get_value_str (ref, id, "handle", &tv);
972 if (status == ISC_R_SUCCESS) {
973 status = omapi_handle_td_lookup (ip, tv -> value);
974
975 omapi_value_dereference (&tv, MDL);
976 if (status != ISC_R_SUCCESS)
977 return status;
978
979 /* Don't return the object if the type is wrong. */
980 if ((*ip) -> type != dhcp_type_interface) {
981 omapi_object_dereference (ip, MDL);
982 return ISC_R_INVALIDARG;
983 }
984 }
985
986 /* Now look for an interface name. */
987 status = omapi_get_value_str (ref, id, "name", &tv);
988 if (status == ISC_R_SUCCESS) {
989 char *s;
990 unsigned len;
991 for (interface = interfaces; interface;
992 interface = interface -> next) {
993 s = memchr (interface -> name, 0, IFNAMSIZ);
994 if (s)
995 len = s - &interface -> name [0];
996 else
997 len = IFNAMSIZ;
998 if ((tv -> value -> u.buffer.len == len &&
999 !memcmp (interface -> name,
1000 (char *)tv -> value -> u.buffer.value,
1001 len)))
1002 break;
1003 }
1004 if (!interface) {
1005 for (interface = dummy_interfaces;
1006 interface; interface = interface -> next) {
1007 s = memchr (interface -> name, 0, IFNAMSIZ);
1008 if (s)
1009 len = s - &interface -> name [0];
1010 else
1011 len = IFNAMSIZ;
1012 if ((tv -> value -> u.buffer.len == len &&
1013 !memcmp (interface -> name,
1014 (char *)
1015 tv -> value -> u.buffer.value,
1016 len)))
1017 break;
1018 }
1019 }
1020
1021 omapi_value_dereference (&tv, MDL);
1022 if (*ip && *ip != (omapi_object_t *)interface) {
1023 omapi_object_dereference (ip, MDL);
1024 return ISC_R_KEYCONFLICT;
1025 } else if (!interface) {
1026 if (*ip)
1027 omapi_object_dereference (ip, MDL);
1028 return ISC_R_NOTFOUND;
1029 } else if (!*ip)
1030 omapi_object_reference (ip,
1031 (omapi_object_t *)interface,
1032 MDL);
1033 }
1034
1035 /* If we get to here without finding an interface, no valid key was
1036 specified. */
1037 if (!*ip)
1038 return ISC_R_NOKEYS;
1039 return ISC_R_SUCCESS;
1040 }
1041
1042 /* actually just go discover the interface */
1043 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1044 omapi_object_t *id)
1045 {
1046 struct interface_info *hp;
1047 isc_result_t status;
1048
1049 hp = (struct interface_info *)0;
1050 status = interface_allocate (&hp, MDL);
1051 if (status != ISC_R_SUCCESS)
1052 return status;
1053 hp -> flags = INTERFACE_REQUESTED;
1054 status = interface_reference ((struct interface_info **)lp, hp, MDL);
1055 interface_dereference (&hp, MDL);
1056 return status;
1057 }
1058
1059 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1060 omapi_object_t *id)
1061 {
1062 struct interface_info *interface, *ip, *last;
1063
1064 interface = (struct interface_info *)lp;
1065
1066 /* remove from interfaces */
1067 last = 0;
1068 for (ip = interfaces; ip; ip = ip -> next) {
1069 if (ip == interface) {
1070 if (last) {
1071 interface_dereference (&last -> next, MDL);
1072 if (ip -> next)
1073 interface_reference (&last -> next,
1074 ip -> next, MDL);
1075 } else {
1076 interface_dereference (&interfaces, MDL);
1077 if (ip -> next)
1078 interface_reference (&interfaces,
1079 ip -> next, MDL);
1080 }
1081 if (ip -> next)
1082 interface_dereference (&ip -> next, MDL);
1083 break;
1084 }
1085 last = ip;
1086 }
1087 if (!ip)
1088 return ISC_R_NOTFOUND;
1089
1090 /* add the interface to the dummy_interface list */
1091 if (dummy_interfaces) {
1092 interface_reference (&interface -> next,
1093 dummy_interfaces, MDL);
1094 interface_dereference (&dummy_interfaces, MDL);
1095 }
1096 interface_reference (&dummy_interfaces, interface, MDL);
1097
1098 /* do a DHCPRELEASE */
1099 if (dhcp_interface_shutdown_hook)
1100 (*dhcp_interface_shutdown_hook) (interface);
1101
1102 /* remove the io object */
1103 omapi_unregister_io_object ((omapi_object_t *)interface);
1104
1105 if_deregister_send (interface);
1106 if_deregister_receive (interface);
1107
1108 return ISC_R_SUCCESS;
1109 }
1110
1111 void interface_stash (struct interface_info *tptr)
1112 {
1113 struct interface_info **vec;
1114 int delta;
1115
1116 /* If the registerer didn't assign an index, assign one now. */
1117 if (tptr -> index == -1) {
1118 tptr -> index = interface_count++;
1119 while (tptr -> index < interface_max &&
1120 interface_vector [tptr -> index])
1121 tptr -> index = interface_count++;
1122 }
1123
1124 if (interface_max <= tptr -> index) {
1125 delta = tptr -> index - interface_max + 10;
1126 vec = dmalloc ((interface_max + delta) *
1127 sizeof (struct interface_info *), MDL);
1128 if (!vec)
1129 return;
1130 memset (&vec [interface_max], 0,
1131 (sizeof (struct interface_info *)) * delta);
1132 interface_max += delta;
1133 if (interface_vector) {
1134 memcpy (vec, interface_vector,
1135 (interface_count *
1136 sizeof (struct interface_info *)));
1137 dfree (interface_vector, MDL);
1138 }
1139 interface_vector = vec;
1140 }
1141 interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1142 if (tptr -> index >= interface_count)
1143 interface_count = tptr -> index + 1;
1144 #if defined (TRACING)
1145 trace_interface_register (interface_trace, tptr);
1146 #endif
1147 }
1148
1149 void interface_snorf (struct interface_info *tmp, int ir)
1150 {
1151 tmp -> circuit_id = (u_int8_t *)tmp -> name;
1152 tmp -> circuit_id_len = strlen (tmp -> name);
1153 tmp -> remote_id = 0;
1154 tmp -> remote_id_len = 0;
1155 tmp -> flags = ir;
1156 if (interfaces) {
1157 interface_reference (&tmp -> next,
1158 interfaces, MDL);
1159 interface_dereference (&interfaces, MDL);
1160 }
1161 interface_reference (&interfaces, tmp, MDL);
1162 }