1 /* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright 2004 Henning Brauer <[email protected]> 7 * Copyright (c) 1995, 1996, 1997, 1998, 1999 8 * The Internet Software Consortium. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of The Internet Software Consortium nor the names 20 * of its contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 24 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 31 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * This software has been written for the Internet Software Consortium 38 * by Ted Lemon <[email protected]> in cooperation with Vixie 39 * Enterprises. To learn more about the Internet Software Consortium, 40 * see ``http://www.vix.com/isc''. To learn more about Vixie 41 * Enterprises, see ``http://www.vix.com''. 42 */ 43 44 #include <sys/cdefs.h> 45 #include "dhcpd.h" 46 #include "privsep.h" 47 48 #include <sys/ioctl.h> 49 50 #include <assert.h> 51 #include <net/if_media.h> 52 #include <ifaddrs.h> 53 #include <poll.h> 54 55 /* Assert that pointer p is aligned to at least align bytes */ 56 #define assert_aligned(p, align) assert((((uintptr_t)p) & ((align) - 1)) == 0) 57 58 static struct protocol *protocols; 59 static struct timeout *timeouts; 60 static struct timeout *free_timeouts; 61 static int interfaces_invalidated; 62 void (*bootp_packet_handler)(struct interface_info *, 63 struct dhcp_packet *, int, unsigned int, 64 struct iaddr, struct hardware *); 65 66 static int interface_status(struct interface_info *ifinfo); 67 68 /* 69 * Use getifaddrs() to get a list of all the attached interfaces. For 70 * each interface that's of type INET and not the loopback interface, 71 * register that interface with the network I/O software, figure out 72 * what subnet it's on, and add it to the list of interfaces. 73 */ 74 void 75 discover_interfaces(struct interface_info *iface) 76 { 77 struct ifaddrs *ifap, *ifa; 78 struct ifreq *tif; 79 int len = IFNAMSIZ + sizeof(struct sockaddr_storage); 80 81 if (getifaddrs(&ifap) != 0) 82 error("getifaddrs failed"); 83 84 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 85 if ((ifa->ifa_flags & IFF_LOOPBACK) || 86 (ifa->ifa_flags & IFF_POINTOPOINT) || 87 (!(ifa->ifa_flags & IFF_UP))) 88 continue; 89 90 if (strcmp(iface->name, ifa->ifa_name)) 91 continue; 92 93 /* 94 * If we have the capability, extract link information 95 * and record it in a linked list. 96 */ 97 if (ifa->ifa_addr->sa_family == AF_LINK) { 98 struct sockaddr_dl *foo; 99 100 /* 101 * The implementation of getifaddrs should guarantee 102 * this alignment 103 */ 104 assert_aligned(ifa->ifa_addr, 105 _Alignof(struct sockaddr_dl)); 106 #ifdef __clang__ 107 #pragma clang diagnostic push 108 #pragma clang diagnostic ignored "-Wcast-align" 109 #endif 110 foo = (struct sockaddr_dl *)ifa->ifa_addr; 111 #ifdef __clang__ 112 #pragma clang diagnostic pop 113 #endif 114 115 iface->index = foo->sdl_index; 116 iface->hw_address.hlen = foo->sdl_alen; 117 iface->hw_address.htype = HTYPE_ETHER; /* XXX */ 118 memcpy(iface->hw_address.haddr, 119 LLADDR(foo), foo->sdl_alen); 120 } 121 if (!iface->ifp) { 122 if ((tif = calloc(1, len)) == NULL) 123 error("no space to remember ifp"); 124 strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); 125 iface->ifp = tif; 126 } 127 128 } 129 130 if (!iface->ifp) 131 error("%s: not found", iface->name); 132 133 /* Register the interface... */ 134 if_register_receive(iface); 135 if_register_send(iface); 136 add_protocol(iface->name, iface->rfdesc, got_one, iface); 137 freeifaddrs(ifap); 138 } 139 140 void 141 reinitialize_interfaces(void) 142 { 143 interfaces_invalidated = 1; 144 } 145 146 /* 147 * Wait for packets to come in using poll(). When a packet comes in, 148 * call receive_packet to receive the packet and possibly strip hardware 149 * addressing information from it, and then call through the 150 * bootp_packet_handler hook to try to do something with it. 151 */ 152 void 153 dispatch(void) 154 { 155 int count, live_interfaces, i, to_msec, nfds = 0; 156 struct protocol *l; 157 struct pollfd *fds; 158 struct timespec howlong; 159 time_now.tv_sec = cur_time; 160 time_now.tv_nsec = 0; 161 162 for (l = protocols; l; l = l->next) 163 nfds++; 164 165 fds = malloc(nfds * sizeof(struct pollfd)); 166 if (fds == NULL) 167 error("Can't allocate poll structures."); 168 169 do { 170 /* 171 * Call any expired timeouts, and then if there's still 172 * a timeout registered, time out the select call then. 173 */ 174 another: 175 if (timeouts) { 176 struct timeout *t; 177 178 if (timespeccmp(&timeouts->when, &time_now, <=)) { 179 t = timeouts; 180 timeouts = timeouts->next; 181 (*(t->func))(t->what); 182 t->next = free_timeouts; 183 free_timeouts = t; 184 goto another; 185 } 186 187 /* 188 * Figure timeout in milliseconds, and check for 189 * potential overflow, so we can cram into an 190 * int for poll, while not polling with a 191 * negative timeout and blocking indefinitely. 192 */ 193 timespecsub(&timeouts->when, &time_now, &howlong); 194 if (howlong.tv_sec > INT_MAX / 1000) 195 howlong.tv_sec = INT_MAX / 1000; 196 to_msec = howlong.tv_sec * 1000; 197 } else 198 to_msec = -1; 199 200 /* Set up the descriptors to be polled. */ 201 live_interfaces = 0; 202 for (i = 0, l = protocols; l; l = l->next) { 203 struct interface_info *ip = l->local; 204 205 if (ip == NULL || ip->dead) 206 continue; 207 fds[i].fd = l->fd; 208 fds[i].events = POLLIN; 209 fds[i].revents = 0; 210 i++; 211 if (l->handler == got_one) 212 live_interfaces++; 213 } 214 if (live_interfaces == 0) 215 error("No live interfaces to poll on - exiting."); 216 217 /* Wait for a packet or a timeout... XXX */ 218 count = poll(fds, nfds, to_msec); 219 220 /* Not likely to be transitory... */ 221 if (count == -1) { 222 if (errno == EAGAIN || errno == EINTR) { 223 time(&cur_time); 224 time_now.tv_sec = cur_time; 225 continue; 226 } else 227 error("poll: %m"); 228 } 229 230 /* Get the current time... */ 231 time(&cur_time); 232 time_now.tv_sec = cur_time; 233 234 i = 0; 235 for (l = protocols; l; l = l->next) { 236 struct interface_info *ip; 237 ip = l->local; 238 if ((fds[i].revents & (POLLIN | POLLHUP))) { 239 fds[i].revents = 0; 240 if (ip && (l->handler != got_one || 241 !ip->dead)) 242 (*(l->handler))(l); 243 if (interfaces_invalidated) 244 break; 245 } 246 i++; 247 } 248 interfaces_invalidated = 0; 249 } while (1); 250 } 251 252 253 void 254 got_one(struct protocol *l) 255 { 256 struct sockaddr_in from; 257 struct hardware hfrom; 258 struct iaddr ifrom; 259 ssize_t result; 260 union { 261 /* 262 * Packet input buffer. Must be as large as largest 263 * possible MTU. 264 */ 265 unsigned char packbuf[4095]; 266 struct dhcp_packet packet; 267 } u; 268 struct interface_info *ip = l->local; 269 270 if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, 271 &hfrom)) == -1) { 272 warning("receive_packet failed on %s: %s", ip->name, 273 strerror(errno)); 274 ip->errors++; 275 if ((!interface_status(ip)) || 276 (ip->noifmedia && ip->errors > 20)) { 277 /* our interface has gone away. */ 278 warning("Interface %s no longer appears valid.", 279 ip->name); 280 ip->dead = 1; 281 interfaces_invalidated = 1; 282 close(l->fd); 283 remove_protocol(l); 284 free(ip); 285 } 286 return; 287 } 288 if (result == 0) 289 return; 290 291 if (bootp_packet_handler) { 292 ifrom.len = 4; 293 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 294 295 (*bootp_packet_handler)(ip, &u.packet, result, 296 from.sin_port, ifrom, &hfrom); 297 } 298 } 299 300 int 301 interface_status(struct interface_info *ifinfo) 302 { 303 char *ifname = ifinfo->name; 304 int ifsock = ifinfo->rfdesc; 305 struct ifreq ifr; 306 struct ifmediareq ifmr; 307 308 /* get interface flags */ 309 memset(&ifr, 0, sizeof(ifr)); 310 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 311 if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 312 cap_syslog(capsyslog, LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", 313 ifname); 314 goto inactive; 315 } 316 317 /* 318 * if one of UP and RUNNING flags is dropped, 319 * the interface is not active. 320 */ 321 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 322 goto inactive; 323 324 /* Next, check carrier on the interface, if possible */ 325 if (ifinfo->noifmedia) 326 goto active; 327 memset(&ifmr, 0, sizeof(ifmr)); 328 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 329 if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 330 if (errno != EINVAL) { 331 cap_syslog(capsyslog, LOG_DEBUG, 332 "ioctl(SIOCGIFMEDIA) on %s: %m", ifname); 333 ifinfo->noifmedia = 1; 334 goto active; 335 } 336 /* 337 * EINVAL (or ENOTTY) simply means that the interface 338 * does not support the SIOCGIFMEDIA ioctl. We regard it alive. 339 */ 340 ifinfo->noifmedia = 1; 341 goto active; 342 } 343 if (ifmr.ifm_status & IFM_AVALID) { 344 switch (ifmr.ifm_active & IFM_NMASK) { 345 case IFM_ETHER: 346 case IFM_IEEE80211: 347 if (ifmr.ifm_status & IFM_ACTIVE) 348 goto active; 349 else 350 goto inactive; 351 break; 352 default: 353 goto inactive; 354 } 355 } 356 inactive: 357 return (0); 358 active: 359 return (1); 360 } 361 362 void 363 add_timeout(time_t when_s, void (*where)(void *), void *what) 364 { 365 struct timespec when = { .tv_sec = when_s, .tv_nsec = 0 }; 366 add_timeout_timespec(when, where, what); 367 } 368 369 void 370 add_timeout_timespec(struct timespec when, void (*where)(void *), void *what) 371 { 372 struct timeout *t, *q; 373 374 /* See if this timeout supersedes an existing timeout. */ 375 t = NULL; 376 for (q = timeouts; q; q = q->next) { 377 if (q->func == where && q->what == what) { 378 if (t) 379 t->next = q->next; 380 else 381 timeouts = q->next; 382 break; 383 } 384 t = q; 385 } 386 387 /* If we didn't supersede a timeout, allocate a timeout 388 structure now. */ 389 if (!q) { 390 if (free_timeouts) { 391 q = free_timeouts; 392 free_timeouts = q->next; 393 q->func = where; 394 q->what = what; 395 } else { 396 q = malloc(sizeof(struct timeout)); 397 if (!q) 398 error("Can't allocate timeout structure!"); 399 q->func = where; 400 q->what = what; 401 } 402 } 403 404 q->when = when; 405 406 /* Now sort this timeout into the timeout list. */ 407 408 /* Beginning of list? */ 409 if (!timeouts || timespeccmp(&timeouts->when, &q->when, >)) { 410 q->next = timeouts; 411 timeouts = q; 412 return; 413 } 414 415 /* Middle of list? */ 416 for (t = timeouts; t->next; t = t->next) { 417 if (timespeccmp(&t->next->when, &q->when, >)) { 418 q->next = t->next; 419 t->next = q; 420 return; 421 } 422 } 423 424 /* End of list. */ 425 t->next = q; 426 q->next = NULL; 427 } 428 429 void 430 cancel_timeout(void (*where)(void *), void *what) 431 { 432 struct timeout *t, *q; 433 434 /* Look for this timeout on the list, and unlink it if we find it. */ 435 t = NULL; 436 for (q = timeouts; q; q = q->next) { 437 if (q->func == where && q->what == what) { 438 if (t) 439 t->next = q->next; 440 else 441 timeouts = q->next; 442 break; 443 } 444 t = q; 445 } 446 447 /* If we found the timeout, put it on the free list. */ 448 if (q) { 449 q->next = free_timeouts; 450 free_timeouts = q; 451 } 452 } 453 454 /* Add a protocol to the list of protocols... */ 455 void 456 add_protocol(const char *name, int fd, void (*handler)(struct protocol *), 457 void *local) 458 { 459 struct protocol *p; 460 461 p = malloc(sizeof(*p)); 462 if (!p) 463 error("can't allocate protocol struct for %s", name); 464 465 p->fd = fd; 466 p->handler = handler; 467 p->local = local; 468 p->next = protocols; 469 protocols = p; 470 } 471 472 void 473 remove_protocol(struct protocol *proto) 474 { 475 struct protocol *p, *prev; 476 477 for (p = protocols, prev = NULL; p != NULL; prev = p, p = p->next) { 478 if (p == proto) { 479 if (prev == NULL) 480 protocols = p->next; 481 else 482 prev->next = p->next; 483 free(p); 484 break; 485 } 486 } 487 } 488 489 int 490 interface_link_status(char *ifname) 491 { 492 struct ifmediareq ifmr; 493 int sock; 494 495 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 496 error("Can't create socket"); 497 498 memset(&ifmr, 0, sizeof(ifmr)); 499 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 500 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 501 /* EINVAL -> link state unknown. treat as active */ 502 if (errno != EINVAL) 503 cap_syslog(capsyslog, LOG_DEBUG, 504 "ioctl(SIOCGIFMEDIA) on %s: %m", ifname); 505 close(sock); 506 return (1); 507 } 508 close(sock); 509 510 if (ifmr.ifm_status & IFM_AVALID) { 511 switch (ifmr.ifm_active & IFM_NMASK) { 512 case IFM_ETHER: 513 case IFM_IEEE80211: 514 if (ifmr.ifm_status & IFM_ACTIVE) 515 return (1); 516 else 517 return (0); 518 } 519 } 520 return (1); 521 } 522 523 void 524 interface_set_mtu_unpriv(int privfd, u_int16_t mtu) 525 { 526 struct imsg_hdr hdr; 527 struct buf *buf; 528 int errs = 0; 529 530 hdr.code = IMSG_SET_INTERFACE_MTU; 531 hdr.len = sizeof(hdr) + 532 sizeof(u_int16_t); 533 534 if ((buf = buf_open(hdr.len)) == NULL) 535 error("buf_open: %m"); 536 537 errs += buf_add(buf, &hdr, sizeof(hdr)); 538 errs += buf_add(buf, &mtu, sizeof(mtu)); 539 if (errs) 540 error("buf_add: %m"); 541 542 if (buf_close(privfd, buf) == -1) 543 error("buf_close: %m"); 544 } 545 546 void 547 interface_set_mtu_priv(char *ifname, u_int16_t mtu) 548 { 549 struct ifreq ifr; 550 int sock; 551 u_int16_t old_mtu; 552 553 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 554 error("Can't create socket"); 555 556 memset(&ifr, 0, sizeof(ifr)); 557 old_mtu = 0; 558 559 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 560 561 if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) == -1) 562 warning("SIOCGIFMTU failed (%s): %s", ifname, 563 strerror(errno)); 564 else 565 old_mtu = ifr.ifr_mtu; 566 567 if (mtu != old_mtu) { 568 ifr.ifr_mtu = mtu; 569 570 if (ioctl(sock, SIOCSIFMTU, &ifr) == -1) 571 warning("SIOCSIFMTU failed (%d): %s", mtu, 572 strerror(errno)); 573 } 574 575 close(sock); 576 } 577