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