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