1 /* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */ 2 3 /* 4 * Copyright 2004 Henning Brauer <henning@openbsd.org> 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 <sys/cdefs.h> 43 __FBSDID("$FreeBSD$"); 44 45 #include "dhcpd.h" 46 #include "privsep.h" 47 48 #include <sys/ioctl.h> 49 50 #include <net/if_media.h> 51 #include <ifaddrs.h> 52 #include <poll.h> 53 54 struct protocol *protocols; 55 struct timeout *timeouts; 56 static struct timeout *free_timeouts; 57 static int interfaces_invalidated; 58 void (*bootp_packet_handler)(struct interface_info *, 59 struct dhcp_packet *, int, unsigned int, 60 struct iaddr, struct hardware *); 61 62 static int interface_status(struct interface_info *ifinfo); 63 64 /* 65 * Use getifaddrs() to get a list of all the attached interfaces. For 66 * each interface that's of type INET and not the loopback interface, 67 * register that interface with the network I/O software, figure out 68 * what subnet it's on, and add it to the list of interfaces. 69 */ 70 void 71 discover_interfaces(struct interface_info *iface) 72 { 73 struct ifaddrs *ifap, *ifa; 74 struct sockaddr_in foo; 75 struct ifreq *tif; 76 77 if (getifaddrs(&ifap) != 0) 78 error("getifaddrs failed"); 79 80 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 81 if ((ifa->ifa_flags & IFF_LOOPBACK) || 82 (ifa->ifa_flags & IFF_POINTOPOINT) || 83 (!(ifa->ifa_flags & IFF_UP))) 84 continue; 85 86 if (strcmp(iface->name, ifa->ifa_name)) 87 continue; 88 89 /* 90 * If we have the capability, extract link information 91 * and record it in a linked list. 92 */ 93 if (ifa->ifa_addr->sa_family == AF_LINK) { 94 struct sockaddr_dl *foo = 95 (struct sockaddr_dl *)ifa->ifa_addr; 96 97 iface->index = foo->sdl_index; 98 iface->hw_address.hlen = foo->sdl_alen; 99 iface->hw_address.htype = HTYPE_ETHER; /* XXX */ 100 memcpy(iface->hw_address.haddr, 101 LLADDR(foo), foo->sdl_alen); 102 } else if (ifa->ifa_addr->sa_family == AF_INET) { 103 struct iaddr addr; 104 105 memcpy(&foo, ifa->ifa_addr, sizeof(foo)); 106 if (foo.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) 107 continue; 108 if (!iface->ifp) { 109 if ((tif = calloc(1, sizeof(struct ifreq))) 110 == NULL) 111 error("no space to remember ifp"); 112 strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); 113 memcpy(&tif->ifr_addr, ifa->ifa_addr, 114 ifa->ifa_addr->sa_len); 115 iface->ifp = tif; 116 iface->primary_address = foo.sin_addr; 117 } 118 addr.len = 4; 119 memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len); 120 } 121 } 122 123 if (!iface->ifp) 124 error("%s: not found", iface->name); 125 126 /* Register the interface... */ 127 if_register_receive(iface); 128 if_register_send(iface); 129 add_protocol(iface->name, iface->rfdesc, got_one, iface); 130 freeifaddrs(ifap); 131 } 132 133 void 134 reinitialize_interfaces(void) 135 { 136 interfaces_invalidated = 1; 137 } 138 139 /* 140 * Wait for packets to come in using poll(). When a packet comes in, 141 * call receive_packet to receive the packet and possibly strip hardware 142 * addressing information from it, and then call through the 143 * bootp_packet_handler hook to try to do something with it. 144 */ 145 void 146 dispatch(void) 147 { 148 int count, live_interfaces, i, to_msec, nfds = 0; 149 struct protocol *l; 150 struct pollfd *fds; 151 time_t howlong; 152 153 for (l = protocols; l; l = l->next) 154 nfds++; 155 156 fds = malloc(nfds * sizeof(struct pollfd)); 157 if (fds == NULL) 158 error("Can't allocate poll structures."); 159 160 do { 161 /* 162 * Call any expired timeouts, and then if there's still 163 * a timeout registered, time out the select call then. 164 */ 165 another: 166 if (timeouts) { 167 struct timeout *t; 168 169 if (timeouts->when <= cur_time) { 170 t = timeouts; 171 timeouts = timeouts->next; 172 (*(t->func))(t->what); 173 t->next = free_timeouts; 174 free_timeouts = t; 175 goto another; 176 } 177 178 /* 179 * Figure timeout in milliseconds, and check for 180 * potential overflow, so we can cram into an 181 * int for poll, while not polling with a 182 * negative timeout and blocking indefinitely. 183 */ 184 howlong = timeouts->when - cur_time; 185 if (howlong > INT_MAX / 1000) 186 howlong = INT_MAX / 1000; 187 to_msec = howlong * 1000; 188 } else 189 to_msec = -1; 190 191 /* Set up the descriptors to be polled. */ 192 live_interfaces = 0; 193 for (i = 0, l = protocols; l; l = l->next) { 194 struct interface_info *ip = l->local; 195 196 if (ip == NULL || ip->dead) 197 continue; 198 fds[i].fd = l->fd; 199 fds[i].events = POLLIN; 200 fds[i].revents = 0; 201 i++; 202 if (l->handler == got_one) 203 live_interfaces++; 204 } 205 if (live_interfaces == 0) 206 error("No live interfaces to poll on - exiting."); 207 208 /* Wait for a packet or a timeout... XXX */ 209 count = poll(fds, nfds, to_msec); 210 211 /* Not likely to be transitory... */ 212 if (count == -1) { 213 if (errno == EAGAIN || errno == EINTR) { 214 time(&cur_time); 215 continue; 216 } else 217 error("poll: %m"); 218 } 219 220 /* Get the current time... */ 221 time(&cur_time); 222 223 i = 0; 224 for (l = protocols; l; l = l->next) { 225 struct interface_info *ip; 226 ip = l->local; 227 if ((fds[i].revents & (POLLIN | POLLHUP))) { 228 fds[i].revents = 0; 229 if (ip && (l->handler != got_one || 230 !ip->dead)) 231 (*(l->handler))(l); 232 if (interfaces_invalidated) 233 break; 234 } 235 i++; 236 } 237 interfaces_invalidated = 0; 238 } while (1); 239 } 240 241 242 void 243 got_one(struct protocol *l) 244 { 245 struct sockaddr_in from; 246 struct hardware hfrom; 247 struct iaddr ifrom; 248 ssize_t result; 249 union { 250 /* 251 * Packet input buffer. Must be as large as largest 252 * possible MTU. 253 */ 254 unsigned char packbuf[4095]; 255 struct dhcp_packet packet; 256 } u; 257 struct interface_info *ip = l->local; 258 259 if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, 260 &hfrom)) == -1) { 261 warning("receive_packet failed on %s: %s", ip->name, 262 strerror(errno)); 263 ip->errors++; 264 if ((!interface_status(ip)) || 265 (ip->noifmedia && ip->errors > 20)) { 266 /* our interface has gone away. */ 267 warning("Interface %s no longer appears valid.", 268 ip->name); 269 ip->dead = 1; 270 interfaces_invalidated = 1; 271 close(l->fd); 272 remove_protocol(l); 273 free(ip); 274 } 275 return; 276 } 277 if (result == 0) 278 return; 279 280 if (bootp_packet_handler) { 281 ifrom.len = 4; 282 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 283 284 (*bootp_packet_handler)(ip, &u.packet, result, 285 from.sin_port, ifrom, &hfrom); 286 } 287 } 288 289 int 290 interface_status(struct interface_info *ifinfo) 291 { 292 char *ifname = ifinfo->name; 293 int ifsock = ifinfo->rfdesc; 294 struct ifreq ifr; 295 struct ifmediareq ifmr; 296 297 /* get interface flags */ 298 memset(&ifr, 0, sizeof(ifr)); 299 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 300 if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 301 syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname); 302 goto inactive; 303 } 304 305 /* 306 * if one of UP and RUNNING flags is dropped, 307 * the interface is not active. 308 */ 309 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 310 goto inactive; 311 312 /* Next, check carrier on the interface, if possible */ 313 if (ifinfo->noifmedia) 314 goto active; 315 memset(&ifmr, 0, sizeof(ifmr)); 316 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 317 if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 318 if (errno != EINVAL) { 319 syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", 320 ifname); 321 322 ifinfo->noifmedia = 1; 323 goto active; 324 } 325 /* 326 * EINVAL (or ENOTTY) simply means that the interface 327 * does not support the SIOCGIFMEDIA ioctl. We regard it alive. 328 */ 329 ifinfo->noifmedia = 1; 330 goto active; 331 } 332 if (ifmr.ifm_status & IFM_AVALID) { 333 switch (ifmr.ifm_active & IFM_NMASK) { 334 case IFM_ETHER: 335 case IFM_IEEE80211: 336 if (ifmr.ifm_status & IFM_ACTIVE) 337 goto active; 338 else 339 goto inactive; 340 break; 341 default: 342 goto inactive; 343 } 344 } 345 inactive: 346 return (0); 347 active: 348 return (1); 349 } 350 351 void 352 add_timeout(time_t when, void (*where)(void *), void *what) 353 { 354 struct timeout *t, *q; 355 356 /* See if this timeout supersedes an existing timeout. */ 357 t = NULL; 358 for (q = timeouts; q; q = q->next) { 359 if (q->func == where && q->what == what) { 360 if (t) 361 t->next = q->next; 362 else 363 timeouts = q->next; 364 break; 365 } 366 t = q; 367 } 368 369 /* If we didn't supersede a timeout, allocate a timeout 370 structure now. */ 371 if (!q) { 372 if (free_timeouts) { 373 q = free_timeouts; 374 free_timeouts = q->next; 375 q->func = where; 376 q->what = what; 377 } else { 378 q = malloc(sizeof(struct timeout)); 379 if (!q) 380 error("Can't allocate timeout structure!"); 381 q->func = where; 382 q->what = what; 383 } 384 } 385 386 q->when = when; 387 388 /* Now sort this timeout into the timeout list. */ 389 390 /* Beginning of list? */ 391 if (!timeouts || timeouts->when > q->when) { 392 q->next = timeouts; 393 timeouts = q; 394 return; 395 } 396 397 /* Middle of list? */ 398 for (t = timeouts; t->next; t = t->next) { 399 if (t->next->when > q->when) { 400 q->next = t->next; 401 t->next = q; 402 return; 403 } 404 } 405 406 /* End of list. */ 407 t->next = q; 408 q->next = NULL; 409 } 410 411 void 412 cancel_timeout(void (*where)(void *), void *what) 413 { 414 struct timeout *t, *q; 415 416 /* Look for this timeout on the list, and unlink it if we find it. */ 417 t = NULL; 418 for (q = timeouts; q; q = q->next) { 419 if (q->func == where && q->what == what) { 420 if (t) 421 t->next = q->next; 422 else 423 timeouts = q->next; 424 break; 425 } 426 t = q; 427 } 428 429 /* If we found the timeout, put it on the free list. */ 430 if (q) { 431 q->next = free_timeouts; 432 free_timeouts = q; 433 } 434 } 435 436 /* Add a protocol to the list of protocols... */ 437 void 438 add_protocol(char *name, int fd, void (*handler)(struct protocol *), 439 void *local) 440 { 441 struct protocol *p; 442 443 p = malloc(sizeof(*p)); 444 if (!p) 445 error("can't allocate protocol struct for %s", name); 446 447 p->fd = fd; 448 p->handler = handler; 449 p->local = local; 450 p->next = protocols; 451 protocols = p; 452 } 453 454 void 455 remove_protocol(struct protocol *proto) 456 { 457 struct protocol *p, *next; 458 459 for (p = protocols; p; p = next) { 460 next = p->next; 461 if (p == proto) { 462 protocols = p->next; 463 free(p); 464 } 465 } 466 } 467 468 int 469 interface_link_status(char *ifname) 470 { 471 struct ifmediareq ifmr; 472 int sock; 473 474 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 475 error("Can't create socket"); 476 477 memset(&ifmr, 0, sizeof(ifmr)); 478 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 479 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 480 /* EINVAL -> link state unknown. treat as active */ 481 if (errno != EINVAL) 482 syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m", 483 ifname); 484 close(sock); 485 return (1); 486 } 487 close(sock); 488 489 if (ifmr.ifm_status & IFM_AVALID) { 490 switch (ifmr.ifm_active & IFM_NMASK) { 491 case IFM_ETHER: 492 case IFM_IEEE80211: 493 if (ifmr.ifm_status & IFM_ACTIVE) 494 return (1); 495 else 496 return (0); 497 } 498 } 499 return (1); 500 } 501 502 void 503 interface_set_mtu_unpriv(int privfd, u_int16_t mtu) 504 { 505 struct imsg_hdr hdr; 506 struct buf *buf; 507 int errs = 0; 508 509 hdr.code = IMSG_SET_INTERFACE_MTU; 510 hdr.len = sizeof(hdr) + 511 sizeof(u_int16_t); 512 513 if ((buf = buf_open(hdr.len)) == NULL) 514 error("buf_open: %m"); 515 516 errs += buf_add(buf, &hdr, sizeof(hdr)); 517 errs += buf_add(buf, &mtu, sizeof(mtu)); 518 if (errs) 519 error("buf_add: %m"); 520 521 if (buf_close(privfd, buf) == -1) 522 error("buf_close: %m"); 523 } 524 525 void 526 interface_set_mtu_priv(char *ifname, u_int16_t mtu) 527 { 528 struct ifreq ifr; 529 int sock; 530 531 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 532 error("Can't create socket"); 533 534 memset(&ifr, 0, sizeof(ifr)); 535 536 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 537 ifr.ifr_mtu = mtu; 538 539 if (ioctl(sock, SIOCSIFMTU, &ifr) == -1) 540 warning("SIOCSIFMTU failed (%d): %s", mtu, 541 strerror(errno)); 542 close(sock); 543 } 544