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