1 /** $MirOS: src/usr.sbin/dhcpd/dispatch.c,v 1.4 2006/09/20 20:03:32 tg Exp $ */
2 /* $OpenBSD: dispatch.c,v 1.21 2006/05/30 23:43:46 ckuethe Exp $ */
3
4 /*
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
42 #include "dhcpd.h"
43 #include <ifaddrs.h>
44 #include <sys/ioctl.h>
45 #include <poll.h>
46 #include <net/if_media.h>
47
48
49 /* Most boxes has less than 16 interfaces, so this might be a good guess. */
50 #define INITIAL_IFREQ_COUNT 16
51
52 struct interface_info *interfaces;
53 struct protocol *protocols;
54 struct dhcpd_timeout *timeouts;
55 static struct dhcpd_timeout *free_timeouts;
56 static int interfaces_invalidated;
57 void (*bootp_packet_handler)(struct interface_info *,
58 struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *);
59
60 static int interface_status(struct interface_info *ifinfo);
61
62 /* Use getifaddrs() to get a list of all the attached interfaces.
63 For each interface that's of type INET and not the loopback interface,
64 register that interface with the network I/O software, figure out what
65 subnet it's on, and add it to the list of interfaces. */
66
67 void
discover_interfaces(void)68 discover_interfaces(void)
69 {
70 struct interface_info *tmp;
71 struct interface_info *last, *next;
72 struct subnet *subnet;
73 struct shared_network *share;
74 struct sockaddr_in foo;
75 int ir = 0;
76 struct ifreq *tif;
77 struct ifaddrs *ifap, *ifa;
78 #ifdef ALIAS_NAMES_PERMUTED
79 char *s;
80 #endif
81
82 if (getifaddrs(&ifap) != 0)
83 error("getifaddrs failed");
84
85 /*
86 * If we already have a list of interfaces, the interfaces were
87 * requested.
88 */
89 if (interfaces != NULL)
90 ir = 1;
91
92 /* Cycle through the list of interfaces looking for IP addresses. */
93 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
94 /*
95 * See if this is the sort of interface we want to
96 * deal with. Skip loopback, point-to-point and down
97 * interfaces, except don't skip down interfaces if we're
98 * trying to get a list of configurable interfaces.
99 */
100 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
101 (ifa->ifa_flags & IFF_POINTOPOINT) ||
102 (!(ifa->ifa_flags & IFF_UP)))
103 continue;
104
105 /* See if we've seen an interface that matches this one. */
106 for (tmp = interfaces; tmp; tmp = tmp->next)
107 if (!strcmp(tmp->name, ifa->ifa_name))
108 break;
109
110 /* If we are looking for specific interfaces, ignore others. */
111 if (tmp == NULL && ir)
112 continue;
113
114 /* If there isn't already an interface by this name,
115 allocate one. */
116 if (tmp == NULL) {
117 tmp = ((struct interface_info *)dmalloc(sizeof *tmp,
118 "discover_interfaces"));
119 if (!tmp)
120 error("Insufficient memory to %s %s",
121 "record interface", ifa->ifa_name);
122 strlcpy(tmp->name, ifa->ifa_name, sizeof(tmp->name));
123 tmp->next = interfaces;
124 tmp->noifmedia = tmp->dead = tmp->errors = 0;
125 interfaces = tmp;
126 }
127
128 /* If we have the capability, extract link information
129 and record it in a linked list. */
130 if (ifa->ifa_addr->sa_family == AF_LINK) {
131 struct sockaddr_dl *foo =
132 ((struct sockaddr_dl *)(ifa->ifa_addr));
133 tmp->index = foo->sdl_index;
134 tmp->hw_address.hlen = foo->sdl_alen;
135 tmp->hw_address.htype = HTYPE_ETHER; /* XXX */
136 memcpy(tmp->hw_address.haddr,
137 LLADDR(foo), foo->sdl_alen);
138 } else if (ifa->ifa_addr->sa_family == AF_INET) {
139 struct iaddr addr;
140
141 /* Get a pointer to the address... */
142 memmove(&foo, ifa->ifa_addr, sizeof(foo));
143
144 /* We don't want the loopback interface. */
145 if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK))
146 continue;
147
148 /* If this is the first real IP address we've
149 found, keep a pointer to ifreq structure in
150 which we found it. */
151 if (!tmp->ifp) {
152 int len = (IFNAMSIZ + ifa->ifa_addr->sa_len);
153 tif = (struct ifreq *)malloc(len);
154 if (!tif)
155 error("no space to remember ifp.");
156 strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ);
157 memcpy(&tif->ifr_addr, ifa->ifa_addr,
158 ifa->ifa_addr->sa_len);
159 tmp->ifp = tif;
160 tmp->primary_address = foo.sin_addr;
161 }
162
163 /* Grab the address... */
164 addr.len = 4;
165 memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len);
166
167 /* If there's a registered subnet for this address,
168 connect it together... */
169 if ((subnet = find_subnet(addr))) {
170 /* If this interface has multiple aliases
171 on the same subnet, ignore all but the
172 first we encounter. */
173 if (!subnet->interface) {
174 subnet->interface = tmp;
175 subnet->interface_address = addr;
176 } else if (subnet->interface != tmp) {
177 warning("Multiple %s %s: %s %s",
178 "interfaces match the",
179 "same subnet",
180 subnet->interface->name,
181 tmp->name);
182 }
183 share = subnet->shared_network;
184 if (tmp->shared_network &&
185 tmp->shared_network != share) {
186 warning("Interface %s matches %s",
187 tmp->name,
188 "multiple shared networks");
189 } else {
190 tmp->shared_network = share;
191 }
192
193 if (!share->interface) {
194 share->interface = tmp;
195 } else if (share->interface != tmp) {
196 warning("Multiple %s %s: %s %s",
197 "interfaces match the",
198 "same shared network",
199 share->interface->name,
200 tmp->name);
201 }
202 }
203 }
204 }
205
206 /* Discard interfaces we can't listen on. */
207 last = NULL;
208 for (tmp = interfaces; tmp; tmp = next) {
209 next = tmp->next;
210
211 if (!tmp->ifp) {
212 warning("Can't listen on %s - it has no IP address.",
213 tmp->name);
214 /* Remove tmp from the list of interfaces. */
215 if (!last)
216 interfaces = interfaces->next;
217 else
218 last->next = tmp->next;
219 continue;
220 }
221
222 memcpy(&foo, &tmp->ifp->ifr_addr, sizeof tmp->ifp->ifr_addr);
223
224 if (!tmp->shared_network) {
225 warning("Can't listen on %s - dhcpd.conf has no subnet "
226 "declaration for %s.", tmp->name,
227 inet_ntoa(foo.sin_addr));
228 /* Remove tmp from the list of interfaces. */
229 if (!last)
230 interfaces = interfaces->next;
231 else
232 last->next = tmp->next;
233 continue;
234 }
235
236 last = tmp;
237
238 /* Find subnets that don't have valid interface addresses. */
239 for (subnet = (tmp->shared_network ? tmp->shared_network->subnets :
240 NULL); subnet; subnet = subnet->next_sibling) {
241 if (!subnet->interface_address.len) {
242 /*
243 * Set the interface address for this subnet
244 * to the first address we found.
245 */
246 subnet->interface_address.len = 4;
247 memcpy(subnet->interface_address.iabuf,
248 &foo.sin_addr.s_addr, 4);
249 }
250 }
251
252 /* Register the interface... */
253 if_register_receive(tmp);
254 if_register_send(tmp);
255 }
256
257 if (interfaces == NULL)
258 error("No interfaces to listen on.");
259
260 /* Now register all the remaining interfaces as protocols. */
261 for (tmp = interfaces; tmp; tmp = tmp->next)
262 add_protocol(tmp->name, tmp->rfdesc, got_one, tmp);
263
264 freeifaddrs(ifap);
265 }
266
267 /*
268 * Wait for packets to come in using poll(). When a packet comes in,
269 * call receive_packet to receive the packet and possibly strip hardware
270 * addressing information from it, and then call through the
271 * bootp_packet_handler hook to try to do something with it.
272 */
273 void
dispatch(void)274 dispatch(void)
275 {
276 int nfds, i, to_msec;
277 struct protocol *l;
278 static struct pollfd *fds;
279 static int nfds_max;
280 time_t howlong;
281
282 for (nfds = 0, l = protocols; l; l = l->next)
283 nfds++;
284 if (nfds > nfds_max) {
285 fds = realloc(fds, nfds * sizeof(struct pollfd));
286 if (fds == NULL)
287 error("Can't allocate poll structures.");
288 nfds_max = nfds;
289 }
290
291 for (;;) {
292 /*
293 * Call any expired timeouts, and then if there's
294 * still a timeout registered, time out the poll
295 * call then.
296 */
297 time(&cur_time);
298 another:
299 if (timeouts) {
300 if (timeouts->when <= cur_time) {
301 struct dhcpd_timeout *t = timeouts;
302 timeouts = timeouts->next;
303 (*(t->func))(t->what);
304 t->next = free_timeouts;
305 free_timeouts = t;
306 goto another;
307 }
308
309 /*
310 * Figure timeout in milliseconds, and check for
311 * potential overflow, so we can cram into an int
312 * for poll, while not polling with a negative
313 * timeout and blocking indefinitely.
314 */
315 howlong = timeouts->when - cur_time;
316 if (howlong > INT_MAX / 1000)
317 howlong = INT_MAX / 1000;
318 to_msec = howlong * 1000;
319 } else
320 to_msec = -1;
321
322 /* Set up the descriptors to be polled. */
323 for (i = 0, l = protocols; l; l = l->next) {
324 struct interface_info *ip = l->local;
325
326 if (ip && (l->handler != got_one || !ip->dead)) {
327 fds[i].fd = l->fd;
328 fds[i].events = POLLIN;
329 ++i;
330 }
331 }
332 if (i == 0)
333 error("No live interfaces to poll on - exiting.");
334
335 /* Wait for a packet or a timeout... */
336 switch (poll(fds, nfds, to_msec)) {
337 case -1:
338 if (errno != EAGAIN && errno != EINTR)
339 error("poll: %m");
340 /* FALLTHROUGH */
341 case 0:
342 continue; /* no packets */
343 }
344
345 for (i = 0, l = protocols; l; l = l->next) {
346 struct interface_info *ip = l->local;
347
348 if ((fds[i].revents & (POLLIN | POLLHUP))) {
349 if (ip && (l->handler != got_one ||
350 !ip->dead))
351 (*(l->handler))(l);
352 if (interfaces_invalidated)
353 break;
354 }
355 ++i;
356 }
357 interfaces_invalidated = 0;
358 }
359 }
360
361
362 void
got_one(struct protocol * l)363 got_one(struct protocol *l)
364 {
365 struct sockaddr_in from;
366 struct hardware hfrom;
367 struct iaddr ifrom;
368 ssize_t result;
369 union {
370 unsigned char packbuf[4095];
371 struct dhcp_packet packet;
372 } u;
373 struct interface_info *ip = l->local;
374
375 if ((result = receive_packet(ip, u.packbuf, sizeof u,
376 &from, &hfrom)) == -1) {
377 warning("receive_packet failed on %s: %s", ip->name,
378 strerror(errno));
379 ip->errors++;
380 if ((!interface_status(ip)) ||
381 (ip->noifmedia && ip->errors > 20)) {
382 /* our interface has gone away. */
383 warning("Interface %s no longer appears valid.",
384 ip->name);
385 ip->dead = 1;
386 interfaces_invalidated = 1;
387 close(l->fd);
388 remove_protocol(l);
389 free(ip);
390 }
391 return;
392 }
393 if (result == 0)
394 return;
395
396 if (bootp_packet_handler) {
397 ifrom.len = 4;
398 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len);
399
400 (*bootp_packet_handler)(ip, &u.packet, result,
401 from.sin_port, ifrom, &hfrom);
402 }
403 }
404
405 int
interface_status(struct interface_info * ifinfo)406 interface_status(struct interface_info *ifinfo)
407 {
408 char * ifname = ifinfo->name;
409 int ifsock = ifinfo->rfdesc;
410 struct ifreq ifr;
411 struct ifmediareq ifmr;
412
413 /* get interface flags */
414 memset(&ifr, 0, sizeof(ifr));
415 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
416 if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
417 syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
418 goto inactive;
419 }
420 /*
421 * if one of UP and RUNNING flags is dropped,
422 * the interface is not active.
423 */
424 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
425 goto inactive;
426
427 /* Next, check carrier on the interface, if possible */
428 if (ifinfo->noifmedia)
429 goto active;
430 memset(&ifmr, 0, sizeof(ifmr));
431 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
432 if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
433 if (errno != EINVAL) {
434 syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m",
435 ifname);
436 ifinfo->noifmedia = 1;
437 goto active;
438 }
439 /*
440 * EINVAL (or ENOTTY) simply means that the interface
441 * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
442 */
443 ifinfo->noifmedia = 1;
444 goto active;
445 }
446 if (ifmr.ifm_status & IFM_AVALID) {
447 switch (ifmr.ifm_active & IFM_NMASK) {
448 case IFM_ETHER:
449 if (ifmr.ifm_status & IFM_ACTIVE)
450 goto active;
451 else
452 goto inactive;
453 break;
454 default:
455 goto inactive;
456 }
457 }
458 inactive:
459 return (0);
460 active:
461 return (1);
462 }
463
464 int
locate_network(struct packet * packet)465 locate_network(struct packet *packet)
466 {
467 struct iaddr ia;
468
469 /* If this came through a gateway, find the corresponding subnet... */
470 if (packet->raw->giaddr.s_addr) {
471 struct subnet *subnet;
472
473 ia.len = 4;
474 memcpy(ia.iabuf, &packet->raw->giaddr, 4);
475 subnet = find_subnet(ia);
476 if (subnet)
477 packet->shared_network = subnet->shared_network;
478 else
479 packet->shared_network = NULL;
480 } else {
481 packet->shared_network = packet->interface->shared_network;
482 }
483 if (packet->shared_network)
484 return 1;
485 return 0;
486 }
487
488 void
add_timeout(time_t when,void (* where)(void *),void * what)489 add_timeout(time_t when, void (*where)(void *), void *what)
490 {
491 struct dhcpd_timeout *t, *q;
492
493 /* See if this timeout supersedes an existing timeout. */
494 t = NULL;
495 for (q = timeouts; q; q = q->next) {
496 if (q->func == where && q->what == what) {
497 if (t)
498 t->next = q->next;
499 else
500 timeouts = q->next;
501 break;
502 }
503 t = q;
504 }
505
506 /* If we didn't supersede a timeout, allocate a timeout
507 structure now. */
508 if (!q) {
509 if (free_timeouts) {
510 q = free_timeouts;
511 free_timeouts = q->next;
512 q->func = where;
513 q->what = what;
514 } else {
515 q = (struct dhcpd_timeout *)malloc(sizeof (struct dhcpd_timeout));
516 if (!q)
517 error("Can't allocate timeout structure!");
518 q->func = where;
519 q->what = what;
520 }
521 }
522
523 q->when = when;
524
525 /* Now sort this timeout into the timeout list. */
526
527 /* Beginning of list? */
528 if (!timeouts || timeouts->when > q->when) {
529 q->next = timeouts;
530 timeouts = q;
531 return;
532 }
533
534 /* Middle of list? */
535 for (t = timeouts; t->next; t = t->next) {
536 if (t->next->when > q->when) {
537 q->next = t->next;
538 t->next = q;
539 return;
540 }
541 }
542
543 /* End of list. */
544 t->next = q;
545 q->next = NULL;
546 }
547
548 void
cancel_timeout(void (* where)(void *),void * what)549 cancel_timeout(void (*where)(void *), void *what)
550 {
551 struct dhcpd_timeout *t, *q;
552
553 /* Look for this timeout on the list, and unlink it if we find it. */
554 t = NULL;
555 for (q = timeouts; q; q = q->next) {
556 if (q->func == where && q->what == what) {
557 if (t)
558 t->next = q->next;
559 else
560 timeouts = q->next;
561 break;
562 }
563 t = q;
564 }
565
566 /* If we found the timeout, put it on the free list. */
567 if (q) {
568 q->next = free_timeouts;
569 free_timeouts = q;
570 }
571 }
572
573 /* Add a protocol to the list of protocols... */
574 void
add_protocol(char * name,int fd,void (* handler)(struct protocol *),void * local)575 add_protocol(char *name, int fd, void (*handler)(struct protocol *),
576 void *local)
577 {
578 struct protocol *p;
579
580 p = (struct protocol *)malloc(sizeof *p);
581 if (!p)
582 error("can't allocate protocol struct for %s", name);
583 p->fd = fd;
584 p->handler = handler;
585 p->local = local;
586 p->next = protocols;
587 protocols = p;
588 }
589
590 void
remove_protocol(struct protocol * proto)591 remove_protocol(struct protocol *proto)
592 {
593 struct protocol *p, *next, *prev = NULL;
594
595 for (p = protocols; p; p = next) {
596 next = p->next;
597 if (p == proto) {
598 if (prev)
599 prev->next = p->next;
600 else
601 protocols = p->next;
602 free(p);
603 }
604 }
605 }
606