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