1 /* $OpenBSD: interface.c,v 1.88 2024/08/21 15:18:00 florian Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/ioctl.h> 22 #include <sys/time.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <net/if.h> 27 #include <net/if_types.h> 28 #include <ctype.h> 29 #include <err.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <event.h> 35 36 #include "ospfd.h" 37 #include "ospf.h" 38 #include "log.h" 39 #include "ospfe.h" 40 41 void if_hello_timer(int, short, void *); 42 void if_start_hello_timer(struct iface *); 43 void if_stop_hello_timer(struct iface *); 44 void if_stop_wait_timer(struct iface *); 45 void if_wait_timer(int, short, void *); 46 void if_start_wait_timer(struct iface *); 47 void if_stop_wait_timer(struct iface *); 48 struct nbr *if_elect(struct nbr *, struct nbr *); 49 50 struct { 51 int state; 52 enum iface_event event; 53 enum iface_action action; 54 int new_state; 55 } iface_fsm[] = { 56 /* current state event that happened action to take resulting state */ 57 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 58 {IF_STA_WAITING, IF_EVT_BACKUP_SEEN, IF_ACT_ELECT, 0}, 59 {IF_STA_WAITING, IF_EVT_WTIMER, IF_ACT_ELECT, 0}, 60 {IF_STA_ANY, IF_EVT_WTIMER, IF_ACT_NOTHING, 0}, 61 {IF_STA_WAITING, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0}, 62 {IF_STA_MULTI, IF_EVT_NBR_CHNG, IF_ACT_ELECT, 0}, 63 {IF_STA_ANY, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0}, 64 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 65 {IF_STA_ANY, IF_EVT_LOOP, IF_ACT_RST, IF_STA_LOOPBACK}, 66 {IF_STA_LOOPBACK, IF_EVT_UNLOOP, IF_ACT_NOTHING, IF_STA_DOWN}, 67 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 68 }; 69 70 static int vlink_cnt = 0; 71 72 const char * const if_event_names[] = { 73 "NOTHING", 74 "UP", 75 "WAITTIMER", 76 "BACKUPSEEN", 77 "NEIGHBORCHANGE", 78 "LOOP", 79 "UNLOOP", 80 "DOWN" 81 }; 82 83 const char * const if_action_names[] = { 84 "NOTHING", 85 "START", 86 "ELECT", 87 "RESET" 88 }; 89 90 int 91 if_fsm(struct iface *iface, enum iface_event event) 92 { 93 int old_state; 94 int new_state = 0; 95 int i, ret = 0; 96 97 old_state = iface->state; 98 99 for (i = 0; iface_fsm[i].state != -1; i++) 100 if ((iface_fsm[i].state & old_state) && 101 (iface_fsm[i].event == event)) { 102 new_state = iface_fsm[i].new_state; 103 break; 104 } 105 106 if (iface_fsm[i].state == -1) { 107 /* event outside of the defined fsm, ignore it. */ 108 log_debug("if_fsm: interface %s, " 109 "event %s not expected in state %s", iface->name, 110 if_event_names[event], if_state_name(old_state)); 111 return (0); 112 } 113 114 switch (iface_fsm[i].action) { 115 case IF_ACT_STRT: 116 ret = if_act_start(iface); 117 break; 118 case IF_ACT_ELECT: 119 ret = if_act_elect(iface); 120 break; 121 case IF_ACT_RST: 122 ret = if_act_reset(iface); 123 break; 124 case IF_ACT_NOTHING: 125 /* do nothing */ 126 break; 127 } 128 129 if (ret) { 130 log_debug("if_fsm: error changing state for interface %s, " 131 "event %s, state %s", iface->name, if_event_names[event], 132 if_state_name(old_state)); 133 return (-1); 134 } 135 136 if (new_state != 0) 137 iface->state = new_state; 138 139 if (iface->state != old_state) { 140 area_track(iface->area); 141 orig_rtr_lsa(iface->area); 142 } 143 144 if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) && 145 (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) 146 ospfe_demote_iface(iface, 0); 147 if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 && 148 iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) 149 ospfe_demote_iface(iface, 1); 150 151 log_debug("if_fsm: event %s resulted in action %s and changing " 152 "state for interface %s from %s to %s", 153 if_event_names[event], if_action_names[iface_fsm[i].action], 154 iface->name, if_state_name(old_state), if_state_name(iface->state)); 155 156 return (ret); 157 } 158 159 struct iface * 160 if_new(struct kif *kif, struct kif_addr *ka) 161 { 162 struct iface *iface; 163 164 if ((iface = calloc(1, sizeof(*iface))) == NULL) 165 err(1, "if_new: calloc"); 166 167 iface->state = IF_STA_DOWN; 168 169 LIST_INIT(&iface->nbr_list); 170 TAILQ_INIT(&iface->ls_ack_list); 171 TAILQ_INIT(&iface->auth_md_list); 172 RB_INIT(&iface->lsa_tree); 173 174 iface->crypt_seq_num = arc4random() & 0x0fffffff; 175 176 if (kif == NULL) { 177 iface->type = IF_TYPE_VIRTUALLINK; 178 snprintf(iface->name, sizeof(iface->name), "vlink%d", 179 vlink_cnt++); 180 iface->flags |= IFF_UP; 181 iface->mtu = IP_MSS; 182 return (iface); 183 } 184 185 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 186 187 /* get type */ 188 if (kif->flags & IFF_POINTOPOINT) 189 iface->type = IF_TYPE_POINTOPOINT; 190 if (kif->flags & IFF_BROADCAST && 191 kif->flags & IFF_MULTICAST) 192 iface->type = IF_TYPE_BROADCAST; 193 if (kif->flags & IFF_LOOPBACK) { 194 iface->type = IF_TYPE_POINTOPOINT; 195 iface->passive = 1; 196 } 197 198 /* get mtu, index and flags */ 199 iface->mtu = kif->mtu; 200 iface->ifindex = kif->ifindex; 201 iface->rdomain = kif->rdomain; 202 iface->flags = kif->flags; 203 iface->linkstate = kif->link_state; 204 iface->if_type = kif->if_type; 205 iface->baudrate = kif->baudrate; 206 207 /* set address, mask and p2p addr */ 208 iface->addr = ka->addr; 209 iface->mask = ka->mask; 210 if (kif->flags & IFF_POINTOPOINT) { 211 iface->dst = ka->dstbrd; 212 } 213 214 return (iface); 215 } 216 217 void 218 if_del(struct iface *iface) 219 { 220 struct nbr *nbr = NULL; 221 222 /* revert the demotion when the interface is deleted */ 223 if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) 224 ospfe_demote_iface(iface, 1); 225 226 /* clear lists etc */ 227 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) 228 nbr_del(nbr); 229 230 if (evtimer_pending(&iface->hello_timer, NULL)) 231 evtimer_del(&iface->hello_timer); 232 if (evtimer_pending(&iface->wait_timer, NULL)) 233 evtimer_del(&iface->wait_timer); 234 if (evtimer_pending(&iface->lsack_tx_timer, NULL)) 235 evtimer_del(&iface->lsack_tx_timer); 236 237 ls_ack_list_clr(iface); 238 md_list_clr(&iface->auth_md_list); 239 free(iface); 240 } 241 242 void 243 if_init(struct ospfd_conf *xconf, struct iface *iface) 244 { 245 /* init the dummy local neighbor */ 246 iface->self = nbr_new(ospfe_router_id(), iface, 1); 247 248 /* set event handlers for interface */ 249 evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface); 250 evtimer_set(&iface->hello_timer, if_hello_timer, iface); 251 evtimer_set(&iface->wait_timer, if_wait_timer, iface); 252 253 iface->fd = xconf->ospf_socket; 254 255 ospfe_demote_iface(iface, 0); 256 } 257 258 /* timers */ 259 void 260 if_hello_timer(int fd, short event, void *arg) 261 { 262 struct iface *iface = arg; 263 struct timeval tv; 264 265 send_hello(iface); 266 267 /* reschedule hello_timer */ 268 timerclear(&tv); 269 if (iface->dead_interval == FAST_RTR_DEAD_TIME) 270 tv.tv_usec = iface->fast_hello_interval * 1000; 271 else 272 tv.tv_sec = iface->hello_interval; 273 if (evtimer_add(&iface->hello_timer, &tv) == -1) 274 fatal("if_hello_timer"); 275 } 276 277 void 278 if_start_hello_timer(struct iface *iface) 279 { 280 struct timeval tv; 281 282 timerclear(&tv); 283 if (evtimer_add(&iface->hello_timer, &tv) == -1) 284 fatal("if_start_hello_timer"); 285 } 286 287 void 288 if_stop_hello_timer(struct iface *iface) 289 { 290 if (evtimer_del(&iface->hello_timer) == -1) 291 fatal("if_stop_hello_timer"); 292 } 293 294 void 295 if_wait_timer(int fd, short event, void *arg) 296 { 297 struct iface *iface = arg; 298 299 if_fsm(iface, IF_EVT_WTIMER); 300 } 301 302 void 303 if_start_wait_timer(struct iface *iface) 304 { 305 struct timeval tv; 306 307 timerclear(&tv); 308 tv.tv_sec = iface->dead_interval; 309 if (evtimer_add(&iface->wait_timer, &tv) == -1) 310 fatal("if_start_wait_timer"); 311 } 312 313 void 314 if_stop_wait_timer(struct iface *iface) 315 { 316 if (evtimer_del(&iface->wait_timer) == -1) 317 fatal("if_stop_wait_timer"); 318 } 319 320 /* actions */ 321 int 322 if_act_start(struct iface *iface) 323 { 324 struct in_addr addr; 325 struct timeval now; 326 327 if (!(iface->flags & IFF_UP) || 328 (!LINK_STATE_IS_UP(iface->linkstate) && 329 !(iface->if_type == IFT_CARP && 330 iface->linkstate == LINK_STATE_DOWN))) 331 return (0); 332 333 if (iface->if_type == IFT_CARP && iface->passive == 0) { 334 /* force passive mode on carp interfaces */ 335 log_warnx("if_act_start: forcing interface %s to passive", 336 iface->name); 337 iface->passive = 1; 338 } 339 340 gettimeofday(&now, NULL); 341 iface->uptime = now.tv_sec; 342 343 /* loopback interfaces have a special state and are passive */ 344 if (iface->flags & IFF_LOOPBACK) 345 iface->state = IF_STA_LOOPBACK; 346 347 if (iface->passive) { 348 /* for an update of stub network entries */ 349 orig_rtr_lsa(iface->area); 350 return (0); 351 } 352 353 switch (iface->type) { 354 case IF_TYPE_POINTOPOINT: 355 inet_pton(AF_INET, AllSPFRouters, &addr); 356 if (if_join_group(iface, &addr)) 357 return (-1); 358 iface->state = IF_STA_POINTTOPOINT; 359 break; 360 case IF_TYPE_VIRTUALLINK: 361 iface->state = IF_STA_POINTTOPOINT; 362 break; 363 case IF_TYPE_POINTOMULTIPOINT: 364 case IF_TYPE_NBMA: 365 log_debug("if_act_start: type %s not supported, interface %s", 366 if_type_name(iface->type), iface->name); 367 return (-1); 368 case IF_TYPE_BROADCAST: 369 inet_pton(AF_INET, AllSPFRouters, &addr); 370 if (if_join_group(iface, &addr)) 371 return (-1); 372 if (iface->priority == 0) { 373 iface->state = IF_STA_DROTHER; 374 } else { 375 iface->state = IF_STA_WAITING; 376 if_start_wait_timer(iface); 377 } 378 break; 379 default: 380 fatalx("if_act_start: unknown interface type"); 381 } 382 383 /* hello timer needs to be started in any case */ 384 if_start_hello_timer(iface); 385 return (0); 386 } 387 388 struct nbr * 389 if_elect(struct nbr *a, struct nbr *b) 390 { 391 if (a->priority > b->priority) 392 return (a); 393 if (a->priority < b->priority) 394 return (b); 395 if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr)) 396 return (a); 397 return (b); 398 } 399 400 int 401 if_act_elect(struct iface *iface) 402 { 403 struct in_addr addr; 404 struct nbr *nbr, *bdr = NULL, *dr = NULL; 405 int round = 0; 406 int changed = 0; 407 int old_state; 408 char b1[16], b2[16], b3[16], b4[16]; 409 410 start: 411 /* elect backup designated router */ 412 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 413 if (nbr->priority == 0 || nbr == dr || /* not electable */ 414 nbr->state & NBR_STA_PRELIM || /* not available */ 415 nbr->dr.s_addr == nbr->addr.s_addr) /* don't elect DR */ 416 continue; 417 if (bdr != NULL) { 418 /* 419 * routers announcing themselves as BDR have higher 420 * precedence over those routers announcing a 421 * different BDR. 422 */ 423 if (nbr->bdr.s_addr == nbr->addr.s_addr) { 424 if (bdr->bdr.s_addr == bdr->addr.s_addr) 425 bdr = if_elect(bdr, nbr); 426 else 427 bdr = nbr; 428 } else if (bdr->bdr.s_addr != bdr->addr.s_addr) 429 bdr = if_elect(bdr, nbr); 430 } else 431 bdr = nbr; 432 } 433 434 /* elect designated router */ 435 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 436 if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM || 437 (nbr != dr && nbr->dr.s_addr != nbr->addr.s_addr)) 438 /* only DR may be elected check priority too */ 439 continue; 440 if (dr == NULL) 441 dr = nbr; 442 else 443 dr = if_elect(dr, nbr); 444 } 445 446 if (dr == NULL) { 447 /* no designated router found use backup DR */ 448 dr = bdr; 449 bdr = NULL; 450 } 451 452 /* 453 * if we are involved in the election (e.g. new DR or no 454 * longer BDR) redo the election 455 */ 456 if (round == 0 && 457 ((iface->self == dr && iface->self != iface->dr) || 458 (iface->self != dr && iface->self == iface->dr) || 459 (iface->self == bdr && iface->self != iface->bdr) || 460 (iface->self != bdr && iface->self == iface->bdr))) { 461 /* 462 * Reset announced DR/BDR to calculated one, so 463 * that we may get elected in the second round. 464 * This is needed to drop from a DR to a BDR. 465 */ 466 iface->self->dr.s_addr = dr->addr.s_addr; 467 if (bdr) 468 iface->self->bdr.s_addr = bdr->addr.s_addr; 469 round = 1; 470 goto start; 471 } 472 473 log_debug("if_act_elect: interface %s old dr %s new dr %s, " 474 "old bdr %s new bdr %s", iface->name, 475 iface->dr ? inet_ntop(AF_INET, &iface->dr->addr, b1, sizeof(b1)) : 476 "none", dr ? inet_ntop(AF_INET, &dr->addr, b2, sizeof(b2)) : "none", 477 iface->bdr ? inet_ntop(AF_INET, &iface->bdr->addr, b3, sizeof(b3)) : 478 "none", bdr ? inet_ntop(AF_INET, &bdr->addr, b4, sizeof(b4)) : 479 "none"); 480 481 /* 482 * After the second round still DR or BDR change state to DR or BDR, 483 * etc. 484 */ 485 old_state = iface->state; 486 if (dr == iface->self) 487 iface->state = IF_STA_DR; 488 else if (bdr == iface->self) 489 iface->state = IF_STA_BACKUP; 490 else 491 iface->state = IF_STA_DROTHER; 492 493 /* TODO if iface is NBMA send all non eligible neighbors event Start */ 494 495 /* 496 * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way 497 */ 498 if (iface->dr != dr || iface->bdr != bdr) 499 changed = 1; 500 501 iface->dr = dr; 502 iface->bdr = bdr; 503 504 if (changed) { 505 inet_pton(AF_INET, AllDRouters, &addr); 506 if (old_state & IF_STA_DRORBDR && 507 (iface->state & IF_STA_DRORBDR) == 0) { 508 if (if_leave_group(iface, &addr)) 509 return (-1); 510 } else if ((old_state & IF_STA_DRORBDR) == 0 && 511 iface->state & IF_STA_DRORBDR) { 512 if (if_join_group(iface, &addr)) 513 return (-1); 514 } 515 516 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 517 if (nbr->state & NBR_STA_BIDIR) 518 nbr_fsm(nbr, NBR_EVT_ADJ_OK); 519 } 520 521 orig_rtr_lsa(iface->area); 522 if (iface->state & IF_STA_DR || old_state & IF_STA_DR) 523 orig_net_lsa(iface); 524 } 525 526 if_start_hello_timer(iface); 527 return (0); 528 } 529 530 int 531 if_act_reset(struct iface *iface) 532 { 533 struct nbr *nbr = NULL; 534 struct in_addr addr; 535 536 if (iface->passive) { 537 /* for an update of stub network entries */ 538 orig_rtr_lsa(iface->area); 539 return (0); 540 } 541 542 switch (iface->type) { 543 case IF_TYPE_POINTOPOINT: 544 case IF_TYPE_BROADCAST: 545 /* try to cleanup */ 546 inet_pton(AF_INET, AllSPFRouters, &addr); 547 if_leave_group(iface, &addr); 548 if (iface->state & IF_STA_DRORBDR) { 549 inet_pton(AF_INET, AllDRouters, &addr); 550 if_leave_group(iface, &addr); 551 } 552 break; 553 case IF_TYPE_VIRTUALLINK: 554 /* nothing */ 555 break; 556 case IF_TYPE_NBMA: 557 case IF_TYPE_POINTOMULTIPOINT: 558 log_debug("if_act_reset: type %s not supported, interface %s", 559 if_type_name(iface->type), iface->name); 560 return (-1); 561 default: 562 fatalx("if_act_reset: unknown interface type"); 563 } 564 565 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 566 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 567 log_debug("if_act_reset: error killing neighbor %s", 568 inet_ntoa(nbr->id)); 569 } 570 } 571 572 iface->dr = NULL; 573 iface->bdr = NULL; 574 575 ls_ack_list_clr(iface); 576 stop_ls_ack_tx_timer(iface); 577 if_stop_hello_timer(iface); 578 if_stop_wait_timer(iface); 579 580 /* send empty hello to tell everybody that we are going down */ 581 send_hello(iface); 582 583 return (0); 584 } 585 586 struct ctl_iface * 587 if_to_ctl(struct iface *iface) 588 { 589 static struct ctl_iface ictl; 590 struct timeval tv, now, res; 591 struct nbr *nbr; 592 593 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 594 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 595 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 596 ictl.rtr_id.s_addr = ospfe_router_id(); 597 memcpy(&ictl.area, &iface->area->id, sizeof(ictl.area)); 598 if (iface->dr) { 599 memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id)); 600 memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr)); 601 } else { 602 bzero(&ictl.dr_id, sizeof(ictl.dr_id)); 603 bzero(&ictl.dr_addr, sizeof(ictl.dr_addr)); 604 } 605 if (iface->bdr) { 606 memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id)); 607 memcpy(&ictl.bdr_addr, &iface->bdr->addr, 608 sizeof(ictl.bdr_addr)); 609 } else { 610 bzero(&ictl.bdr_id, sizeof(ictl.bdr_id)); 611 bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr)); 612 } 613 ictl.ifindex = iface->ifindex; 614 ictl.state = iface->state; 615 ictl.mtu = iface->mtu; 616 ictl.nbr_cnt = 0; 617 ictl.adj_cnt = 0; 618 ictl.baudrate = iface->baudrate; 619 ictl.dead_interval = iface->dead_interval; 620 ictl.fast_hello_interval = iface->fast_hello_interval; 621 ictl.transmit_delay = iface->transmit_delay; 622 ictl.hello_interval = iface->hello_interval; 623 ictl.flags = iface->flags; 624 ictl.metric = iface->metric; 625 ictl.rxmt_interval = iface->rxmt_interval; 626 ictl.type = iface->type; 627 ictl.linkstate = iface->linkstate; 628 ictl.if_type = iface->if_type; 629 ictl.priority = iface->priority; 630 ictl.passive = iface->passive; 631 ictl.auth_type = iface->auth_type; 632 ictl.auth_keyid = iface->auth_keyid; 633 634 memcpy(ictl.dependon, iface->dependon, sizeof(ictl.dependon)); 635 ictl.depend_ok = iface->depend_ok; 636 637 gettimeofday(&now, NULL); 638 if (evtimer_pending(&iface->hello_timer, &tv)) { 639 timersub(&tv, &now, &res); 640 ictl.hello_timer = res; 641 } else { 642 ictl.hello_timer.tv_sec = -1; 643 } 644 645 if (iface->state != IF_STA_DOWN && 646 iface->uptime != 0) { 647 ictl.uptime = now.tv_sec - iface->uptime; 648 } else 649 ictl.uptime = 0; 650 651 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 652 if (nbr == iface->self) 653 continue; 654 ictl.nbr_cnt++; 655 if (nbr->state & NBR_STA_ADJFORM) 656 ictl.adj_cnt++; 657 } 658 659 return (&ictl); 660 } 661 662 /* misc */ 663 int 664 if_set_recvif(int fd, int enable) 665 { 666 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 667 sizeof(enable)) == -1) { 668 log_warn("if_set_recvif: error setting IP_RECVIF"); 669 return (-1); 670 } 671 return (0); 672 } 673 674 void 675 if_set_sockbuf(int fd) 676 { 677 int bsize; 678 679 bsize = 256 * 1024; 680 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 681 sizeof(bsize)) == -1) 682 bsize /= 2; 683 684 if (bsize != 256 * 1024) 685 log_warnx("if_set_sockbuf: recvbuf size only %d", bsize); 686 687 bsize = 64 * 1024; 688 while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize, 689 sizeof(bsize)) == -1) 690 bsize /= 2; 691 692 if (bsize != 64 * 1024) 693 log_warnx("if_set_sockbuf: sendbuf size only %d", bsize); 694 } 695 696 /* 697 * only one JOIN or DROP per interface and address is allowed so we need 698 * to keep track of what is added and removed. 699 */ 700 struct if_group_count { 701 LIST_ENTRY(if_group_count) entry; 702 struct in_addr addr; 703 unsigned int ifindex; 704 int count; 705 }; 706 707 LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist); 708 709 int 710 if_join_group(struct iface *iface, struct in_addr *addr) 711 { 712 struct ip_mreqn mreq; 713 struct if_group_count *ifg; 714 715 switch (iface->type) { 716 case IF_TYPE_POINTOPOINT: 717 case IF_TYPE_BROADCAST: 718 LIST_FOREACH(ifg, &ifglist, entry) 719 if (iface->ifindex == ifg->ifindex && 720 addr->s_addr == ifg->addr.s_addr) 721 break; 722 if (ifg == NULL) { 723 if ((ifg = calloc(1, sizeof(*ifg))) == NULL) 724 fatal("if_join_group"); 725 ifg->addr.s_addr = addr->s_addr; 726 ifg->ifindex = iface->ifindex; 727 LIST_INSERT_HEAD(&ifglist, ifg, entry); 728 } 729 730 if (ifg->count++ != 0) 731 /* already joined */ 732 return (0); 733 734 memset(&mreq, 0, sizeof(mreq)); 735 mreq.imr_multiaddr.s_addr = addr->s_addr; 736 mreq.imr_ifindex = iface->ifindex; 737 738 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 739 (void *)&mreq, sizeof(mreq)) == -1) { 740 log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " 741 "interface %s address %s", iface->name, 742 inet_ntoa(*addr)); 743 return (-1); 744 } 745 break; 746 case IF_TYPE_POINTOMULTIPOINT: 747 case IF_TYPE_VIRTUALLINK: 748 case IF_TYPE_NBMA: 749 log_debug("if_join_group: type %s not supported, interface %s", 750 if_type_name(iface->type), iface->name); 751 return (-1); 752 default: 753 fatalx("if_join_group: unknown interface type"); 754 } 755 756 return (0); 757 } 758 759 int 760 if_leave_group(struct iface *iface, struct in_addr *addr) 761 { 762 struct ip_mreqn mreq; 763 struct if_group_count *ifg; 764 765 switch (iface->type) { 766 case IF_TYPE_POINTOPOINT: 767 case IF_TYPE_BROADCAST: 768 LIST_FOREACH(ifg, &ifglist, entry) 769 if (iface->ifindex == ifg->ifindex && 770 addr->s_addr == ifg->addr.s_addr) 771 break; 772 773 /* if interface is not found just try to drop membership */ 774 if (ifg) { 775 if (--ifg->count != 0) 776 /* others still joined */ 777 return (0); 778 779 LIST_REMOVE(ifg, entry); 780 free(ifg); 781 } 782 783 memset(&mreq, 0, sizeof(mreq)); 784 mreq.imr_multiaddr.s_addr = addr->s_addr; 785 mreq.imr_ifindex = iface->ifindex; 786 787 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 788 (void *)&mreq, sizeof(mreq)) == -1) { 789 log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, " 790 "interface %s address %s", iface->name, 791 inet_ntoa(*addr)); 792 return (-1); 793 } 794 break; 795 case IF_TYPE_POINTOMULTIPOINT: 796 case IF_TYPE_VIRTUALLINK: 797 case IF_TYPE_NBMA: 798 log_debug("if_leave_group: type %s not supported, interface %s", 799 if_type_name(iface->type), iface->name); 800 return (-1); 801 default: 802 fatalx("if_leave_group: unknown interface type"); 803 } 804 805 return (0); 806 } 807 808 int 809 if_set_mcast(struct iface *iface) 810 { 811 struct ip_mreqn mreq; 812 813 switch (iface->type) { 814 case IF_TYPE_POINTOPOINT: 815 case IF_TYPE_BROADCAST: 816 memset(&mreq, 0, sizeof(mreq)); 817 mreq.imr_ifindex = iface->ifindex; 818 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 819 &mreq, sizeof(mreq)) == -1) { 820 log_warn("if_set_mcast: error setting " 821 "IP_MULTICAST_IF, interface %s", iface->name); 822 return (-1); 823 } 824 break; 825 case IF_TYPE_POINTOMULTIPOINT: 826 case IF_TYPE_VIRTUALLINK: 827 case IF_TYPE_NBMA: 828 log_debug("if_set_mcast: type %s not supported, interface %s", 829 if_type_name(iface->type), iface->name); 830 return (-1); 831 default: 832 fatalx("if_set_mcast: unknown interface type"); 833 } 834 835 return (0); 836 } 837 838 int 839 if_set_mcast_loop(int fd) 840 { 841 u_int8_t loop = 0; 842 843 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 844 (char *)&loop, sizeof(loop)) == -1) { 845 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 846 return (-1); 847 } 848 849 return (0); 850 } 851 852 int 853 if_set_ip_hdrincl(int fd) 854 { 855 int hincl = 1; 856 857 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) == -1) { 858 log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL"); 859 return (-1); 860 } 861 862 return (0); 863 } 864