dispatch.c revision 1.7
1/* dispatch.c 2 3 Network input dispatcher... */ 4 5/* 6 * Copyright (c) 1995, 1996, 1997, 1998, 1999 7 * The Internet Software Consortium. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of The Internet Software Consortium nor the names 19 * of its contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * This software has been written for the Internet Software Consortium 37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 38 * Enterprises. To learn more about the Internet Software Consortium, 39 * see ``http://www.vix.com/isc''. To learn more about Vixie 40 * Enterprises, see ``http://www.vix.com''. 41 */ 42 43#include "dhcpd.h" 44#include <ifaddrs.h> 45#include <sys/ioctl.h> 46#include <poll.h> 47#include <net/if_media.h> 48 49 50/* Most boxes has less than 16 interfaces, so this might be a good guess. */ 51#define INITIAL_IFREQ_COUNT 16 52 53struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; 54struct protocol *protocols; 55struct timeout *timeouts; 56static struct timeout *free_timeouts; 57static int interfaces_invalidated; 58void (*bootp_packet_handler)(struct interface_info *, 59 struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *); 60 61static int interface_status(struct interface_info *ifinfo); 62 63int quiet_interface_discovery; 64 65/* Use getifaddrs() to get a list of all the attached interfaces. 66 For each interface that's of type INET and not the loopback interface, 67 register that interface with the network I/O software, figure out what 68 subnet it's on, and add it to the list of interfaces. */ 69 70void 71discover_interfaces(int state) 72{ 73 struct interface_info *tmp; 74 struct interface_info *last, *next; 75 struct subnet *subnet; 76 struct shared_network *share; 77 struct sockaddr_in foo; 78 int ir; 79 struct ifreq *tif; 80 struct ifaddrs *ifap, *ifa; 81#ifdef ALIAS_NAMES_PERMUTED 82 char *s; 83#endif 84 85 if (getifaddrs(&ifap) != 0) 86 error("getifaddrs failed"); 87 88 /* If we already have a list of interfaces, and we're running as 89 a DHCP server, the interfaces were requested. */ 90 if (interfaces && (state == DISCOVER_SERVER || 91 state == DISCOVER_RELAY || state == DISCOVER_REQUESTED)) 92 ir = 0; 93 else if (state == DISCOVER_UNCONFIGURED) 94 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC; 95 else 96 ir = INTERFACE_REQUESTED; 97 98 /* Cycle through the list of interfaces looking for IP addresses. */ 99 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 100 /* 101 * See if this is the sort of interface we want to 102 * deal with. Skip loopback, point-to-point and down 103 * interfaces, except don't skip down interfaces if we're 104 * trying to get a list of configurable interfaces. 105 */ 106 if ((ifa->ifa_flags & IFF_LOOPBACK) || 107 (ifa->ifa_flags & IFF_POINTOPOINT) || 108 (!(ifa->ifa_flags & IFF_UP) && 109 state != DISCOVER_UNCONFIGURED)) 110 continue; 111 112 /* See if we've seen an interface that matches this one. */ 113 for (tmp = interfaces; tmp; tmp = tmp->next) 114 if (!strcmp(tmp->name, ifa->ifa_name)) 115 break; 116 117 /* If there isn't already an interface by this name, 118 allocate one. */ 119 if (!tmp) { 120 tmp = ((struct interface_info *)dmalloc(sizeof *tmp, 121 "discover_interfaces")); 122 if (!tmp) 123 error("Insufficient memory to %s %s", 124 "record interface", ifa->ifa_name); 125 strlcpy(tmp->name, ifa->ifa_name, sizeof(tmp->name)); 126 tmp->next = interfaces; 127 tmp->flags = ir; 128 tmp->noifmedia = tmp->dead = tmp->errors = 0; 129 interfaces = tmp; 130 } 131 132 /* If we have the capability, extract link information 133 and record it in a linked list. */ 134 if (ifa->ifa_addr->sa_family == AF_LINK) { 135 struct sockaddr_dl *foo = 136 ((struct sockaddr_dl *)(ifa->ifa_addr)); 137 tmp->index = foo->sdl_index; 138 tmp->hw_address.hlen = foo->sdl_alen; 139 tmp->hw_address.htype = HTYPE_ETHER; /* XXX */ 140 memcpy(tmp->hw_address.haddr, 141 LLADDR(foo), foo->sdl_alen); 142 } else if (ifa->ifa_addr->sa_family == AF_INET) { 143 struct iaddr addr; 144 145 /* Get a pointer to the address... */ 146 bcopy(ifa->ifa_addr, &foo, sizeof(foo)); 147 148 /* We don't want the loopback interface. */ 149 if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK)) 150 continue; 151 152 /* If this is the first real IP address we've 153 found, keep a pointer to ifreq structure in 154 which we found it. */ 155 if (!tmp->ifp) { 156 int len = (IFNAMSIZ + ifa->ifa_addr->sa_len); 157 tif = (struct ifreq *)malloc(len); 158 if (!tif) 159 error("no space to remember ifp."); 160 strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); 161 memcpy(&tif->ifr_addr, ifa->ifa_addr, 162 ifa->ifa_addr->sa_len); 163 tmp->ifp = tif; 164 tmp->primary_address = foo.sin_addr; 165 } 166 167 /* Grab the address... */ 168 addr.len = 4; 169 memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len); 170 171 /* If there's a registered subnet for this address, 172 connect it together... */ 173 if ((subnet = find_subnet(addr))) { 174 /* If this interface has multiple aliases 175 on the same subnet, ignore all but the 176 first we encounter. */ 177 if (!subnet->interface) { 178 subnet->interface = tmp; 179 subnet->interface_address = addr; 180 } else if (subnet->interface != tmp) { 181 warn("Multiple %s %s: %s %s", 182 "interfaces match the", 183 "same subnet", 184 subnet->interface->name, 185 tmp->name); 186 } 187 share = subnet->shared_network; 188 if (tmp->shared_network && 189 tmp->shared_network != share) { 190 warn("Interface %s matches %s", 191 tmp->name, 192 "multiple shared networks"); 193 } else { 194 tmp->shared_network = share; 195 } 196 197 if (!share->interface) { 198 share->interface = tmp; 199 } else if (share->interface != tmp) { 200 warn("Multiple %s %s: %s %s", 201 "interfaces match the", 202 "same shared network", 203 share->interface->name, 204 tmp->name); 205 } 206 } 207 } 208 } 209 210 /* Now cycle through all the interfaces we found, looking for 211 hardware addresses. */ 212 213 /* If we're just trying to get a list of interfaces that we might 214 be able to configure, we can quit now. */ 215 if (state == DISCOVER_UNCONFIGURED) 216 return; 217 218 /* Weed out the interfaces that did not have IP addresses. */ 219 last = NULL; 220 for (tmp = interfaces; tmp; tmp = next) { 221 next = tmp->next; 222 if ((tmp->flags & INTERFACE_AUTOMATIC) && 223 state == DISCOVER_REQUESTED) 224 tmp->flags &= 225 ~(INTERFACE_AUTOMATIC | INTERFACE_REQUESTED); 226 if (!tmp->ifp || !(tmp->flags & INTERFACE_REQUESTED)) { 227 if ((tmp->flags & INTERFACE_REQUESTED) != ir) 228 error("%s: not found", tmp->name); 229 if (!last) 230 interfaces = interfaces->next; 231 else 232 last->next = tmp->next; 233 234 /* Remember the interface in case we need to know 235 about it later. */ 236 tmp->next = dummy_interfaces; 237 dummy_interfaces = tmp; 238 continue; 239 } 240 last = tmp; 241 242 memcpy(&foo, &tmp->ifp->ifr_addr, sizeof tmp->ifp->ifr_addr); 243 244 /* We must have a subnet declaration for each interface. */ 245 if (!tmp->shared_network && (state == DISCOVER_SERVER)) { 246 warn("No subnet declaration for %s (%s).", 247 tmp->name, inet_ntoa(foo.sin_addr)); 248 warn("Please write a subnet declaration in your %s", 249 "dhcpd.conf file for the"); 250 error("network segment to which interface %s %s", 251 tmp->name, "is attached."); 252 } 253 254 /* Find subnets that don't have valid interface 255 addresses... */ 256 for (subnet = (tmp->shared_network ? tmp->shared_network->subnets : 257 NULL); subnet; subnet = subnet->next_sibling) { 258 if (!subnet->interface_address.len) { 259 /* 260 * Set the interface address for this subnet 261 * to the first address we found. 262 */ 263 subnet->interface_address.len = 4; 264 memcpy(subnet->interface_address.iabuf, 265 &foo.sin_addr.s_addr, 4); 266 } 267 } 268 269 /* Register the interface... */ 270 if_register_receive(tmp); 271 if_register_send(tmp); 272 } 273 274 /* Now register all the remaining interfaces as protocols. */ 275 for (tmp = interfaces; tmp; tmp = tmp->next) 276 add_protocol(tmp->name, tmp->rfdesc, got_one, tmp); 277 278 freeifaddrs(ifap); 279} 280 281struct interface_info * 282setup_fallback(void) 283{ 284 fallback_interface = ((struct interface_info *)dmalloc( 285 sizeof *fallback_interface, "discover_interfaces")); 286 287 if (!fallback_interface) 288 error("Insufficient memory to record fallback interface."); 289 memset(fallback_interface, 0, sizeof *fallback_interface); 290 strlcpy(fallback_interface->name, "fallback", IFNAMSIZ); 291 fallback_interface->shared_network = 292 new_shared_network("parse_statement"); 293 if (!fallback_interface->shared_network) 294 error("No memory for shared subnet"); 295 memset(fallback_interface->shared_network, 0, 296 sizeof(struct shared_network)); 297 fallback_interface->shared_network->name = "fallback-net"; 298 return fallback_interface; 299} 300 301void 302reinitialize_interfaces(void) 303{ 304 interfaces_invalidated = 1; 305} 306 307/* 308 * Wait for packets to come in using poll(). When a packet comes in, 309 * call receive_packet to receive the packet and possibly strip hardware 310 * addressing information from it, and then call through the 311 * bootp_packet_handler hook to try to do something with it. 312 */ 313void 314dispatch(void) 315{ 316 int count, i, nfds = 0, to_msec; 317 struct protocol *l; 318 struct pollfd *fds; 319 time_t howlong; 320 321 for (l = protocols; l; l = l->next) 322 ++nfds; 323 fds = (struct pollfd *)malloc((nfds) * sizeof (struct pollfd)); 324 if (fds == NULL) 325 error("Can't allocate poll structures."); 326 327 do { 328 /* 329 * Call any expired timeouts, and then if there's 330 * still a timeout registered, time out the select 331 * call then. 332 */ 333another: 334 if (timeouts) { 335 struct timeout *t; 336 337 if (timeouts->when <= cur_time) { 338 t = timeouts; 339 timeouts = timeouts->next; 340 (*(t->func))(t->what); 341 t->next = free_timeouts; 342 free_timeouts = t; 343 goto another; 344 } 345 346 /* 347 * Figure timeout in milliseconds, and check for 348 * potential overflow, so we can cram into an int 349 * for poll, while not polling with a negative 350 * timeout and blocking indefinetely. 351 */ 352 howlong = timeouts->when - cur_time; 353 if (howlong > INT_MAX / 1000) 354 howlong = INT_MAX / 1000; 355 to_msec = howlong * 1000; 356 } else 357 to_msec = -1; 358 359 /* Set up the descriptors to be polled. */ 360 i = 0; 361 362 for (l = protocols; l; l = l->next) { 363 struct interface_info *ip = l->local; 364 365 if (ip && (l->handler != got_one || !ip->dead)) { 366 fds[i].fd = l->fd; 367 fds[i].events = POLLIN; 368 fds[i].revents = 0; 369 ++i; 370 } 371 } 372 373 if (i == 0) 374 error("No live interfaces to poll on - exiting."); 375 376 /* Wait for a packet or a timeout... XXX */ 377 count = poll(fds, nfds, to_msec); 378 379 /* Not likely to be transitory... */ 380 if (count == -1) { 381 if (errno == EAGAIN || errno == EINTR) { 382 time(&cur_time); 383 continue; 384 } else 385 error("poll: %m"); 386 } 387 388 /* Get the current time... */ 389 time(&cur_time); 390 391 i = 0; 392 for (l = protocols; l; l = l->next) { 393 struct interface_info *ip = l->local; 394 395 if ((fds[i].revents & POLLIN)) { 396 fds[i].revents = 0; 397 if (ip && (l->handler != got_one || 398 !ip->dead)) 399 (*(l->handler))(l); 400 if (interfaces_invalidated) 401 break; 402 } 403 ++i; 404 } 405 interfaces_invalidated = 0; 406 } while (1); 407} 408 409 410void 411got_one(struct protocol *l) 412{ 413 struct sockaddr_in from; 414 struct hardware hfrom; 415 struct iaddr ifrom; 416 size_t result; 417 union { 418 unsigned char packbuf[4095]; 419 struct dhcp_packet packet; 420 } u; 421 struct interface_info *ip = l->local; 422 423 if ((result = receive_packet (ip, u.packbuf, sizeof u, 424 &from, &hfrom)) == -1) { 425 warn("receive_packet failed on %s: %s", ip->name, 426 strerror(errno)); 427 ip->errors++; 428 if ((!interface_status(ip)) || 429 (ip->noifmedia && ip->errors > 20)) { 430 /* our interface has gone away. */ 431 warn("Interface %s no longer appears valid.", 432 ip->name); 433 ip->dead = 1; 434 interfaces_invalidated = 1; 435 close(l->fd); 436 remove_protocol(l); 437 free(ip); 438 } 439 return; 440 } 441 if (result == 0) 442 return; 443 444 if (bootp_packet_handler) { 445 ifrom.len = 4; 446 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 447 448 (*bootp_packet_handler)(ip, &u.packet, result, 449 from.sin_port, ifrom, &hfrom); 450 } 451} 452 453int 454interface_status(struct interface_info *ifinfo) 455{ 456 char * ifname = ifinfo->name; 457 int ifsock = ifinfo->rfdesc; 458 struct ifreq ifr; 459 struct ifmediareq ifmr; 460 461 /* get interface flags */ 462 memset(&ifr, 0, sizeof(ifr)); 463 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 464 if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 465 syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname); 466 goto inactive; 467 } 468 /* 469 * if one of UP and RUNNING flags is dropped, 470 * the interface is not active. 471 */ 472 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 473 goto inactive; 474 475 /* Next, check carrier on the interface, if possible */ 476 if (ifinfo->noifmedia) 477 goto active; 478 memset(&ifmr, 0, sizeof(ifmr)); 479 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 480 if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 481 if (errno != EINVAL) { 482 syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", 483 ifname); 484 ifinfo->noifmedia = 1; 485 goto active; 486 } 487 /* 488 * EINVAL (or ENOTTY) simply means that the interface 489 * does not support the SIOCGIFMEDIA ioctl. We regard it alive. 490 */ 491 ifinfo->noifmedia = 1; 492 goto active; 493 } 494 if (ifmr.ifm_status & IFM_AVALID) { 495 switch (ifmr.ifm_active & IFM_NMASK) { 496 case IFM_ETHER: 497 if (ifmr.ifm_status & IFM_ACTIVE) 498 goto active; 499 else 500 goto inactive; 501 break; 502 default: 503 goto inactive; 504 } 505 } 506 inactive: 507 return (0); 508 active: 509 return (1); 510} 511 512int 513locate_network(struct packet *packet) 514{ 515 struct iaddr ia; 516 517 /* If this came through a gateway, find the corresponding subnet... */ 518 if (packet->raw->giaddr.s_addr) { 519 struct subnet *subnet; 520 521 ia.len = 4; 522 memcpy(ia.iabuf, &packet->raw->giaddr, 4); 523 subnet = find_subnet(ia); 524 if (subnet) 525 packet->shared_network = subnet->shared_network; 526 else 527 packet->shared_network = NULL; 528 } else { 529 packet->shared_network = packet->interface->shared_network; 530 } 531 if (packet->shared_network) 532 return 1; 533 return 0; 534} 535 536void 537add_timeout(time_t when, void (*where)(void *), void *what) 538{ 539 struct timeout *t, *q; 540 541 /* See if this timeout supersedes an existing timeout. */ 542 t = NULL; 543 for (q = timeouts; q; q = q->next) { 544 if (q->func == where && q->what == what) { 545 if (t) 546 t->next = q->next; 547 else 548 timeouts = q->next; 549 break; 550 } 551 t = q; 552 } 553 554 /* If we didn't supersede a timeout, allocate a timeout 555 structure now. */ 556 if (!q) { 557 if (free_timeouts) { 558 q = free_timeouts; 559 free_timeouts = q->next; 560 q->func = where; 561 q->what = what; 562 } else { 563 q = (struct timeout *)malloc(sizeof (struct timeout)); 564 if (!q) 565 error("Can't allocate timeout structure!"); 566 q->func = where; 567 q->what = what; 568 } 569 } 570 571 q->when = when; 572 573 /* Now sort this timeout into the timeout list. */ 574 575 /* Beginning of list? */ 576 if (!timeouts || timeouts->when > q->when) { 577 q->next = timeouts; 578 timeouts = q; 579 return; 580 } 581 582 /* Middle of list? */ 583 for (t = timeouts; t->next; t = t->next) { 584 if (t->next->when > q->when) { 585 q->next = t->next; 586 t->next = q; 587 return; 588 } 589 } 590 591 /* End of list. */ 592 t->next = q; 593 q->next = NULL; 594} 595 596void 597cancel_timeout(void (*where)(void *), void *what) 598{ 599 struct timeout *t, *q; 600 601 /* Look for this timeout on the list, and unlink it if we find it. */ 602 t = NULL; 603 for (q = timeouts; q; q = q->next) { 604 if (q->func == where && q->what == what) { 605 if (t) 606 t->next = q->next; 607 else 608 timeouts = q->next; 609 break; 610 } 611 t = q; 612 } 613 614 /* If we found the timeout, put it on the free list. */ 615 if (q) { 616 q->next = free_timeouts; 617 free_timeouts = q; 618 } 619} 620 621/* Add a protocol to the list of protocols... */ 622void 623add_protocol(char *name, int fd, void (*handler)(struct protocol *), 624 void *local) 625{ 626 struct protocol *p; 627 628 p = (struct protocol *)malloc(sizeof *p); 629 if (!p) 630 error("can't allocate protocol struct for %s", name); 631 p->fd = fd; 632 p->handler = handler; 633 p->local = local; 634 p->next = protocols; 635 protocols = p; 636} 637 638void 639remove_protocol(struct protocol *proto) 640{ 641 struct protocol *p, *next, *prev = NULL; 642 643 for (p = protocols; p; p = next) { 644 next = p->next; 645 if (p == proto) { 646 if (prev) 647 prev->next = p->next; 648 else 649 protocols = p->next; 650 free(p); 651 } 652 } 653} 654