1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1995 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include "defs.h" 33 #include <netinet/in_systm.h> 34 #include <netinet/ip.h> 35 #include <netinet/ip_icmp.h> 36 /* router advertisement ICMP packet */ 37 struct icmp_ad { 38 u_int8_t icmp_type; /* type of message */ 39 u_int8_t icmp_code; /* type sub code */ 40 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 41 u_int8_t icmp_ad_num; /* # of following router addresses */ 42 u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ 43 u_int16_t icmp_ad_life; /* seconds of validity */ 44 struct icmp_ad_info { 45 n_long icmp_ad_addr; 46 n_long icmp_ad_pref; 47 } icmp_ad_info[1]; 48 }; 49 50 /* router solicitation ICMP packet */ 51 struct icmp_so { 52 u_int8_t icmp_type; /* type of message */ 53 u_int8_t icmp_code; /* type sub code */ 54 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 55 n_long icmp_so_rsvd; 56 }; 57 58 union ad_u { 59 struct icmp icmp; 60 struct icmp_ad ad; 61 struct icmp_so so; 62 }; 63 64 65 int rdisc_sock = -1; /* router-discovery raw socket */ 66 static const struct interface *rdisc_sock_mcast; /* current multicast interface */ 67 68 struct timeval rdisc_timer; 69 int rdisc_ok; /* using solicited route */ 70 71 72 #define MAX_ADS 16 /* at least one per interface */ 73 struct dr { /* accumulated advertisements */ 74 struct interface *dr_ifp; 75 naddr dr_gate; /* gateway */ 76 time_t dr_ts; /* when received */ 77 time_t dr_life; /* lifetime in host byte order */ 78 n_long dr_recv_pref; /* received but biased preference */ 79 n_long dr_pref; /* preference adjusted by metric */ 80 }; 81 static const struct dr *cur_drp; 82 static struct dr drs[MAX_ADS]; 83 84 /* convert between signed, balanced around zero, 85 * and unsigned zero-based preferences */ 86 #define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel) 87 #define UNSIGN_PREF(p) SIGN_PREF(p) 88 /* adjust unsigned preference by interface metric, 89 * without driving it to infinity */ 90 #define PREF(p, ifp) ((int)(p) <= ((ifp)->int_metric+(ifp)->int_adj_outmetric)\ 91 ? ((p) != 0 ? 1 : 0) \ 92 : (p) - ((ifp)->int_metric+(ifp)->int_adj_outmetric)) 93 94 static void rdisc_sort(void); 95 96 97 /* dump an ICMP Router Discovery Advertisement Message 98 */ 99 static void 100 trace_rdisc(const char *act, 101 naddr from, 102 naddr to, 103 struct interface *ifp, 104 union ad_u *p, 105 u_int len) 106 { 107 int i; 108 n_long *wp, *lim; 109 110 111 if (!TRACEPACKETS || ftrace == NULL) 112 return; 113 114 lastlog(); 115 116 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 117 (void)fprintf(ftrace, "%s Router Ad" 118 " from %s to %s via %s life=%d\n", 119 act, naddr_ntoa(from), naddr_ntoa(to), 120 ifp ? ifp->int_name : "?", 121 ntohs(p->ad.icmp_ad_life)); 122 if (!TRACECONTENTS) 123 return; 124 125 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 126 lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; 127 for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 128 (void)fprintf(ftrace, "\t%s preference=%d", 129 naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 130 wp += p->ad.icmp_ad_asize; 131 } 132 (void)fputc('\n',ftrace); 133 134 } else { 135 trace_act("%s Router Solic. from %s to %s via %s value=%#x", 136 act, naddr_ntoa(from), naddr_ntoa(to), 137 ifp ? ifp->int_name : "?", 138 (int)ntohl(p->so.icmp_so_rsvd)); 139 } 140 } 141 142 /* prepare Router Discovery socket. 143 */ 144 static void 145 get_rdisc_sock(void) 146 { 147 if (rdisc_sock < 0) { 148 rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 149 if (rdisc_sock < 0) 150 BADERR(1,"rdisc_sock = socket()"); 151 fix_sock(rdisc_sock,"rdisc_sock"); 152 fix_select(); 153 } 154 } 155 156 157 /* Pick multicast group for router-discovery socket 158 */ 159 void 160 set_rdisc_mg(struct interface *ifp, 161 int on) /* 0=turn it off */ 162 { 163 struct group_req gr; 164 struct sockaddr_in *sin; 165 166 assert(ifp != NULL); 167 168 if (rdisc_sock < 0) { 169 /* Create the raw socket so that we can hear at least 170 * broadcast router discovery packets. 171 */ 172 if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC 173 || !on) 174 return; 175 get_rdisc_sock(); 176 } 177 178 if (!(ifp->int_if_flags & IFF_MULTICAST)) { 179 ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 180 return; 181 } 182 183 memset(&gr, 0, sizeof(gr)); 184 gr.gr_interface = ifp->int_index; 185 sin = (struct sockaddr_in *)&gr.gr_group; 186 sin->sin_family = AF_INET; 187 #ifdef _HAVE_SIN_LEN 188 sin->sin_len = sizeof(struct sockaddr_in); 189 #endif 190 191 if (supplier 192 || (ifp->int_state & IS_NO_ADV_IN) 193 || !on) { 194 /* stop listening to advertisements 195 */ 196 if (ifp->int_state & IS_ALL_HOSTS) { 197 sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 198 if (setsockopt(rdisc_sock, IPPROTO_IP, 199 MCAST_LEAVE_GROUP, 200 &gr, sizeof(gr)) < 0) 201 LOGERR("MCAST_LEAVE_GROUP ALLHOSTS"); 202 ifp->int_state &= ~IS_ALL_HOSTS; 203 } 204 205 } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 206 /* start listening to advertisements 207 */ 208 sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 209 if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 210 &gr, sizeof(gr)) < 0) { 211 LOGERR("MCAST_JOIN_GROUP ALLHOSTS"); 212 } else { 213 ifp->int_state |= IS_ALL_HOSTS; 214 } 215 } 216 217 if (!supplier 218 || (ifp->int_state & IS_NO_ADV_OUT) 219 || !on) { 220 /* stop listening to solicitations 221 */ 222 if (ifp->int_state & IS_ALL_ROUTERS) { 223 sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); 224 if (setsockopt(rdisc_sock, IPPROTO_IP, 225 MCAST_LEAVE_GROUP, 226 &gr, sizeof(gr)) < 0) 227 LOGERR("MCAST_LEAVE_GROUP ALLROUTERS"); 228 ifp->int_state &= ~IS_ALL_ROUTERS; 229 } 230 231 } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 232 /* start hearing solicitations 233 */ 234 sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); 235 if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 236 &gr, sizeof(gr)) < 0) { 237 LOGERR("MCAST_JOIN_GROUP ALLROUTERS"); 238 } else { 239 ifp->int_state |= IS_ALL_ROUTERS; 240 } 241 } 242 } 243 244 245 /* start supplying routes 246 */ 247 void 248 set_supplier(void) 249 { 250 struct interface *ifp; 251 struct dr *drp; 252 253 if (supplier_set) 254 return; 255 256 trace_act("start supplying routes"); 257 258 /* Forget discovered routes. 259 */ 260 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 261 drp->dr_recv_pref = 0; 262 drp->dr_life = 0; 263 } 264 rdisc_age(0); 265 266 supplier_set = 1; 267 supplier = 1; 268 269 /* Do not start advertising until we have heard some RIP routes */ 270 LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 271 272 /* Switch router discovery multicast groups from soliciting 273 * to advertising. 274 */ 275 LIST_FOREACH(ifp, &ifnet, int_list) { 276 if (ifp->int_state & IS_BROKE) 277 continue; 278 ifp->int_rdisc_cnt = 0; 279 ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 280 ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 281 set_rdisc_mg(ifp, 1); 282 } 283 284 /* get rid of any redirects */ 285 del_redirects(0,0); 286 } 287 288 289 /* age discovered routes and find the best one 290 */ 291 void 292 rdisc_age(naddr bad_gate) 293 { 294 time_t sec; 295 struct dr *drp; 296 297 298 /* If only advertising, then do only that. */ 299 if (supplier) { 300 /* If switching from client to server, get rid of old 301 * default routes. 302 */ 303 if (cur_drp != NULL) 304 rdisc_sort(); 305 rdisc_adv(); 306 return; 307 } 308 309 /* If we are being told about a bad router, 310 * then age the discovered default route, and if there is 311 * no alternative, solicit a replacement. 312 */ 313 if (bad_gate != 0) { 314 /* Look for the bad discovered default route. 315 * Age it and note its interface. 316 */ 317 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 318 if (drp->dr_ts == 0) 319 continue; 320 321 /* When we find the bad router, then age the route 322 * to at most SUPPLY_INTERVAL. 323 * This is contrary to RFC 1256, but defends against 324 * black holes. 325 */ 326 if (drp->dr_gate == bad_gate) { 327 sec = (now.tv_sec - drp->dr_life 328 + SUPPLY_INTERVAL); 329 if (drp->dr_ts > sec) { 330 trace_act("age 0.0.0.0 --> %s via %s", 331 naddr_ntoa(drp->dr_gate), 332 drp->dr_ifp->int_name); 333 drp->dr_ts = sec; 334 } 335 break; 336 } 337 } 338 } 339 340 rdisc_sol(); 341 rdisc_sort(); 342 343 /* Delete old redirected routes to keep the kernel table small, 344 * and to prevent black holes. Check that the kernel table 345 * matches the daemon table (i.e. has the default route). 346 * But only if RIP is not running and we are not dealing with 347 * a bad gateway, since otherwise age() will be called. 348 */ 349 if (rip_sock < 0 && bad_gate == 0) 350 age(0); 351 } 352 353 354 /* Zap all routes discovered via an interface that has gone bad 355 * This should only be called when !(ifp->int_state & IS_ALIAS) 356 */ 357 void 358 if_bad_rdisc(struct interface *ifp) 359 { 360 struct dr *drp; 361 362 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 363 if (drp->dr_ifp != ifp) 364 continue; 365 drp->dr_recv_pref = 0; 366 drp->dr_ts = 0; 367 drp->dr_life = 0; 368 } 369 370 /* make a note to re-solicit, turn RIP on or off, etc. */ 371 rdisc_timer.tv_sec = 0; 372 } 373 374 375 /* mark an interface ok for router discovering. 376 */ 377 void 378 if_ok_rdisc(struct interface *ifp) 379 { 380 set_rdisc_mg(ifp, 1); 381 382 ifp->int_rdisc_cnt = 0; 383 ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 384 ? MIN_WAITTIME 385 : MAX_SOLICITATION_DELAY); 386 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 387 rdisc_timer = ifp->int_rdisc_timer; 388 } 389 390 391 /* get rid of a dead discovered router 392 */ 393 static void 394 del_rdisc(struct dr *drp) 395 { 396 struct interface *ifp; 397 naddr gate; 398 int i; 399 400 401 del_redirects(gate = drp->dr_gate, 0); 402 drp->dr_ts = 0; 403 drp->dr_life = 0; 404 405 406 /* Count the other discovered routes on the interface. 407 */ 408 i = 0; 409 ifp = drp->dr_ifp; 410 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 411 if (drp->dr_ts != 0 412 && drp->dr_ifp == ifp) 413 i++; 414 } 415 416 /* If that was the last good discovered router on the interface, 417 * then solicit a new one. 418 * This is contrary to RFC 1256, but defends against black holes. 419 */ 420 if (i != 0) { 421 trace_act("discovered router %s via %s" 422 " is bad--have %d remaining", 423 naddr_ntoa(gate), ifp->int_name, i); 424 } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 425 trace_act("last discovered router %s via %s" 426 " is bad--re-solicit", 427 naddr_ntoa(gate), ifp->int_name); 428 ifp->int_rdisc_cnt = 0; 429 ifp->int_rdisc_timer.tv_sec = 0; 430 rdisc_sol(); 431 } else { 432 trace_act("last discovered router %s via %s" 433 " is bad--wait to solicit", 434 naddr_ntoa(gate), ifp->int_name); 435 } 436 } 437 438 439 /* Find the best discovered route, 440 * and discard stale routers. 441 */ 442 static void 443 rdisc_sort(void) 444 { 445 struct dr *drp, *new_drp; 446 struct rt_entry *rt; 447 struct rt_spare new; 448 struct interface *ifp; 449 u_int new_st = 0; 450 n_long new_pref = 0; 451 452 453 /* Find the best discovered route. 454 */ 455 new_drp = NULL; 456 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 457 if (drp->dr_ts == 0) 458 continue; 459 ifp = drp->dr_ifp; 460 461 /* Get rid of expired discovered routers. 462 */ 463 if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 464 del_rdisc(drp); 465 continue; 466 } 467 468 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); 469 470 /* Update preference with possibly changed interface 471 * metric. 472 */ 473 drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 474 475 /* Prefer the current route to prevent thrashing. 476 * Prefer shorter lifetimes to speed the detection of 477 * bad routers. 478 * Avoid sick interfaces. 479 */ 480 if (new_drp == NULL 481 || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) 482 && (new_pref < drp->dr_pref 483 || (new_pref == drp->dr_pref 484 && (drp == cur_drp 485 || (new_drp != cur_drp 486 && new_drp->dr_life > drp->dr_life))))) 487 || ((new_st & IS_SICK) 488 && !(drp->dr_ifp->int_state & IS_SICK))) { 489 new_drp = drp; 490 new_st = drp->dr_ifp->int_state; 491 new_pref = drp->dr_pref; 492 } 493 } 494 495 /* switch to a better default route 496 */ 497 if (new_drp != cur_drp) { 498 rt = rtget(RIP_DEFAULT, 0); 499 500 /* Stop using discovered routes if they are all bad 501 */ 502 if (new_drp == NULL) { 503 trace_act("turn off Router Discovery client"); 504 rdisc_ok = 0; 505 506 if (rt != NULL 507 && (rt->rt_state & RS_RDISC)) { 508 new = rt->rt_spares[0]; 509 new.rts_metric = HOPCNT_INFINITY; 510 new.rts_time = now.tv_sec - GARBAGE_TIME; 511 rtchange(rt, rt->rt_state & ~RS_RDISC, 512 &new, 0); 513 rtswitch(rt, 0); 514 } 515 516 } else { 517 if (cur_drp == NULL) { 518 trace_act("turn on Router Discovery client" 519 " using %s via %s", 520 naddr_ntoa(new_drp->dr_gate), 521 new_drp->dr_ifp->int_name); 522 rdisc_ok = 1; 523 524 } else { 525 trace_act("switch Router Discovery from" 526 " %s via %s to %s via %s", 527 naddr_ntoa(cur_drp->dr_gate), 528 cur_drp->dr_ifp->int_name, 529 naddr_ntoa(new_drp->dr_gate), 530 new_drp->dr_ifp->int_name); 531 } 532 533 memset(&new, 0, sizeof(new)); 534 new.rts_ifp = new_drp->dr_ifp; 535 new.rts_gate = new_drp->dr_gate; 536 new.rts_router = new_drp->dr_gate; 537 new.rts_metric = HOPCNT_INFINITY-1; 538 new.rts_time = now.tv_sec; 539 if (rt != NULL) { 540 rtchange(rt, rt->rt_state | RS_RDISC, &new, 0); 541 } else { 542 rtadd(RIP_DEFAULT, 0, RS_RDISC, &new); 543 } 544 } 545 546 cur_drp = new_drp; 547 } 548 549 /* turn RIP on or off */ 550 if (!rdisc_ok || rip_interfaces > 1) { 551 rip_on(0); 552 } else { 553 rip_off(); 554 } 555 } 556 557 558 /* handle a single address in an advertisement 559 */ 560 static void 561 parse_ad(naddr from, 562 naddr gate, 563 n_long pref, /* signed and in network order */ 564 u_short life, /* in host byte order */ 565 struct interface *ifp) 566 { 567 static struct msg_limit bad_gate; 568 struct dr *drp, *new_drp; 569 570 571 if (gate == RIP_DEFAULT 572 || !check_dst(gate)) { 573 msglim(&bad_gate, from,"router %s advertising bad gateway %s", 574 naddr_ntoa(from), 575 naddr_ntoa(gate)); 576 return; 577 } 578 579 /* ignore pointers to ourself and routes via unreachable networks 580 */ 581 if (ifwithaddr(gate, 1, 0) != NULL) { 582 trace_pkt(" discard Router Discovery Ad pointing at us"); 583 return; 584 } 585 if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 586 trace_pkt(" discard Router Discovery Ad" 587 " toward unreachable net"); 588 return; 589 } 590 591 /* Convert preference to an unsigned value 592 * and later bias it by the metric of the interface. 593 */ 594 pref = UNSIGN_PREF(ntohl(pref)); 595 596 if (pref == 0 || life < MinMaxAdvertiseInterval) { 597 pref = 0; 598 life = 0; 599 } 600 601 for (new_drp = NULL, drp = drs; drp < &drs[MAX_ADS]; drp++) { 602 /* accept new info for a familiar entry 603 */ 604 if (drp->dr_gate == gate) { 605 new_drp = drp; 606 break; 607 } 608 609 if (life == 0) 610 continue; /* do not worry about dead ads */ 611 612 if (drp->dr_ts == 0) { 613 new_drp = drp; /* use unused entry */ 614 615 } else if (new_drp == NULL) { 616 /* look for an entry worse than the new one to 617 * reuse. 618 */ 619 if ((!(ifp->int_state & IS_SICK) 620 && (drp->dr_ifp->int_state & IS_SICK)) 621 || (pref > drp->dr_pref 622 && !((ifp->int_state ^ drp->dr_ifp->int_state) 623 & IS_SICK))) 624 new_drp = drp; 625 626 } else if (new_drp->dr_ts != 0) { 627 /* look for the least valuable entry to reuse 628 */ 629 if ((!(new_drp->dr_ifp->int_state & IS_SICK) 630 && (drp->dr_ifp->int_state & IS_SICK)) 631 || (new_drp->dr_pref > drp->dr_pref 632 && !((new_drp->dr_ifp->int_state 633 ^ drp->dr_ifp->int_state) 634 & IS_SICK))) 635 new_drp = drp; 636 } 637 } 638 639 /* forget it if all of the current entries are better */ 640 if (new_drp == NULL) 641 return; 642 643 new_drp->dr_ifp = ifp; 644 new_drp->dr_gate = gate; 645 new_drp->dr_ts = now.tv_sec; 646 new_drp->dr_life = life; 647 new_drp->dr_recv_pref = pref; 648 /* bias functional preference by metric of the interface */ 649 new_drp->dr_pref = PREF(pref,ifp); 650 651 /* after hearing a good advertisement, stop asking 652 */ 653 if (!(ifp->int_state & IS_SICK)) 654 ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 655 } 656 657 658 /* Compute the IP checksum 659 * This assumes the packet is less than 32K long. 660 */ 661 static u_short 662 in_cksum(u_short *p, 663 u_int len) 664 { 665 u_int sum = 0; 666 int nwords = len >> 1; 667 668 while (nwords-- != 0) 669 sum += *p++; 670 671 if (len & 1) 672 sum += *(u_char *)p; 673 674 /* end-around-carry */ 675 sum = (sum >> 16) + (sum & 0xffff); 676 sum += (sum >> 16); 677 return (~sum); 678 } 679 680 681 /* Send a router discovery advertisement or solicitation ICMP packet. 682 */ 683 static void 684 send_rdisc(union ad_u *p, 685 int p_size, 686 struct interface *ifp, 687 naddr dst, /* 0 or unicast destination */ 688 int type) /* 0=unicast, 1=bcast, 2=mcast */ 689 { 690 struct sockaddr_in rsin; 691 int flags; 692 const char *msg; 693 694 695 memset(&rsin, 0, sizeof(rsin)); 696 rsin.sin_addr.s_addr = dst; 697 rsin.sin_family = AF_INET; 698 #ifdef _HAVE_SIN_LEN 699 rsin.sin_len = sizeof(rsin); 700 #endif 701 flags = MSG_DONTROUTE; 702 703 switch (type) { 704 case 0: /* unicast */ 705 default: 706 msg = "Send"; 707 break; 708 709 case 1: /* broadcast */ 710 if (ifp->int_if_flags & IFF_POINTOPOINT) { 711 msg = "Send pt-to-pt"; 712 rsin.sin_addr.s_addr = ifp->int_dstaddr; 713 } else { 714 msg = "Send broadcast"; 715 rsin.sin_addr.s_addr = ifp->int_brdaddr; 716 } 717 break; 718 719 case 2: /* multicast */ 720 msg = "Send multicast"; 721 if (ifp->int_state & IS_DUP) { 722 trace_act("abort multicast output via %s" 723 " with duplicate address", 724 ifp->int_name); 725 return; 726 } 727 if (rdisc_sock_mcast != ifp) { 728 /* select the right interface. */ 729 struct ip_mreqn mreqn; 730 731 memset(&mreqn, 0, sizeof(struct ip_mreqn)); 732 mreqn.imr_ifindex = ifp->int_index; 733 if (0 > setsockopt(rdisc_sock, 734 IPPROTO_IP, IP_MULTICAST_IF, 735 &mreqn, 736 sizeof(mreqn))) { 737 LOGERR("setsockopt(rdisc_sock," 738 "IP_MULTICAST_IF)"); 739 rdisc_sock_mcast = NULL; 740 return; 741 } 742 rdisc_sock_mcast = ifp; 743 } 744 flags = 0; 745 break; 746 } 747 748 if (rdisc_sock < 0) 749 get_rdisc_sock(); 750 751 trace_rdisc(msg, (ifp ? ifp->int_addr : 0), rsin.sin_addr.s_addr, ifp, 752 p, p_size); 753 754 if (0 > sendto(rdisc_sock, p, p_size, flags, 755 (struct sockaddr *)&rsin, sizeof(rsin))) { 756 if (ifp == NULL || !(ifp->int_state & IS_BROKE)) 757 msglog("sendto(%s%s%s): %s", 758 ifp != NULL ? ifp->int_name : "", 759 ifp != NULL ? ", " : "", 760 inet_ntoa(rsin.sin_addr), 761 strerror(errno)); 762 if (ifp != NULL) 763 if_sick(ifp); 764 } 765 } 766 767 768 /* Send an advertisement 769 */ 770 static void 771 send_adv(struct interface *ifp, 772 naddr dst, /* 0 or unicast destination */ 773 int type) /* 0=unicast, 1=bcast, 2=mcast */ 774 { 775 union ad_u u; 776 n_long pref; 777 778 779 memset(&u, 0, sizeof(u.ad)); 780 781 u.ad.icmp_type = ICMP_ROUTERADVERT; 782 u.ad.icmp_ad_num = 1; 783 u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 784 785 u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 786 787 /* Convert the configured preference to an unsigned value, 788 * bias it by the interface metric, and then send it as a 789 * signed, network byte order value. 790 */ 791 pref = UNSIGN_PREF(ifp->int_rdisc_pref); 792 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); 793 794 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 795 796 u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 797 798 send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 799 } 800 801 802 /* Advertise for Router Discovery 803 */ 804 void 805 rdisc_adv(void) 806 { 807 struct interface *ifp; 808 809 if (!supplier) 810 return; 811 812 rdisc_timer.tv_sec = now.tv_sec + NEVER; 813 814 LIST_FOREACH(ifp, &ifnet, int_list) { 815 if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE))) 816 continue; 817 818 if (!timercmp(&ifp->int_rdisc_timer, &now, >) 819 || stopint) { 820 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 821 (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 822 ifp->int_rdisc_cnt++; 823 824 intvl_random(&ifp->int_rdisc_timer, 825 (ifp->int_rdisc_int*3)/4, 826 ifp->int_rdisc_int); 827 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 828 && (ifp->int_rdisc_timer.tv_sec 829 > MAX_INITIAL_ADVERT_INTERVAL)) { 830 ifp->int_rdisc_timer.tv_sec 831 = MAX_INITIAL_ADVERT_INTERVAL; 832 } 833 timevaladd(&ifp->int_rdisc_timer, &now); 834 } 835 836 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 837 rdisc_timer = ifp->int_rdisc_timer; 838 } 839 } 840 841 842 /* Solicit for Router Discovery 843 */ 844 void 845 rdisc_sol(void) 846 { 847 struct interface *ifp; 848 union ad_u u; 849 850 851 if (supplier) 852 return; 853 854 rdisc_timer.tv_sec = now.tv_sec + NEVER; 855 856 LIST_FOREACH(ifp, &ifnet, int_list) { 857 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) 858 || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 859 continue; 860 861 if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 862 memset(&u, 0, sizeof(u.so)); 863 u.so.icmp_type = ICMP_ROUTERSOLICIT; 864 u.so.icmp_cksum = in_cksum((u_short*)&u.so, 865 sizeof(u.so)); 866 send_rdisc(&u, sizeof(u.so), ifp, 867 htonl(INADDR_ALLROUTERS_GROUP), 868 ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 869 870 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 871 continue; 872 873 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 874 ifp->int_rdisc_timer.tv_usec = 0; 875 timevaladd(&ifp->int_rdisc_timer, &now); 876 } 877 878 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 879 rdisc_timer = ifp->int_rdisc_timer; 880 } 881 } 882 883 884 /* check the IP header of a possible Router Discovery ICMP packet */ 885 static struct interface * /* 0 if bad */ 886 ck_icmp(const char *act, 887 naddr from, 888 struct interface *ifp, 889 naddr to, 890 union ad_u *p, 891 u_int len) 892 { 893 const char *type; 894 895 896 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 897 type = "advertisement"; 898 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 899 type = "solicitation"; 900 } else { 901 return 0; 902 } 903 904 if (p->icmp.icmp_code != 0) { 905 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 906 type, p->icmp.icmp_code, 907 naddr_ntoa(from), naddr_ntoa(to)); 908 return 0; 909 } 910 911 trace_rdisc(act, from, to, ifp, p, len); 912 913 if (ifp == NULL) 914 trace_pkt("unknown interface for router-discovery %s" 915 " from %s to %s", 916 type, naddr_ntoa(from), naddr_ntoa(to)); 917 918 return ifp; 919 } 920 921 922 /* read packets from the router discovery socket 923 */ 924 void 925 read_d(void) 926 { 927 static struct msg_limit bad_asize, bad_len; 928 #ifdef USE_PASSIFNAME 929 static struct msg_limit bad_name; 930 #endif 931 struct sockaddr_in from; 932 int n, fromlen, cc, hlen; 933 struct { 934 #ifdef USE_PASSIFNAME 935 char ifname[IFNAMSIZ]; 936 #endif 937 union { 938 struct ip ip; 939 u_char b[512]; 940 } pkt; 941 } buf; 942 union ad_u *p; 943 n_long *wp; 944 struct interface *ifp; 945 946 947 for (;;) { 948 fromlen = sizeof(from); 949 cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0, 950 (struct sockaddr*)&from, 951 &fromlen); 952 if (cc <= 0) { 953 if (cc < 0 && errno != EWOULDBLOCK) 954 LOGERR("recvfrom(rdisc_sock)"); 955 break; 956 } 957 if (fromlen != sizeof(struct sockaddr_in)) 958 logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 959 fromlen); 960 #ifdef USE_PASSIFNAME 961 if ((cc -= sizeof(buf.ifname)) < 0) 962 logbad(0,"missing USE_PASSIFNAME; only %d bytes", 963 cc+sizeof(buf.ifname)); 964 #endif 965 966 hlen = buf.pkt.ip.ip_hl << 2; 967 if (cc < hlen + ICMP_MINLEN) 968 continue; 969 p = (union ad_u *)&buf.pkt.b[hlen]; 970 cc -= hlen; 971 972 #ifdef USE_PASSIFNAME 973 ifp = ifwithname(buf.ifname, 0); 974 if (ifp == NULL) 975 msglim(&bad_name, from.sin_addr.s_addr, 976 "impossible rdisc if_ name %.*s", 977 IFNAMSIZ, buf.ifname); 978 #else 979 /* If we could tell the interface on which a packet from 980 * address 0 arrived, we could deal with such solicitations. 981 */ 982 ifp = ((from.sin_addr.s_addr == 0) 983 ? 0 : iflookup(from.sin_addr.s_addr)); 984 #endif 985 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 986 buf.pkt.ip.ip_dst.s_addr, p, cc); 987 if (ifp == NULL) 988 continue; 989 if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 990 trace_pkt(" " 991 "discard our own Router Discovery message"); 992 continue; 993 } 994 995 switch (p->icmp.icmp_type) { 996 case ICMP_ROUTERADVERT: 997 if (p->ad.icmp_ad_asize*4 998 < (int)sizeof(p->ad.icmp_ad_info[0])) { 999 msglim(&bad_asize, from.sin_addr.s_addr, 1000 "intolerable rdisc address size=%d", 1001 p->ad.icmp_ad_asize); 1002 continue; 1003 } 1004 if (p->ad.icmp_ad_num == 0) { 1005 trace_pkt(" empty?"); 1006 continue; 1007 } 1008 if (cc != (int)(sizeof(p->ad) 1009 - sizeof(p->ad.icmp_ad_info) 1010 + (p->ad.icmp_ad_num 1011 * sizeof(p->ad.icmp_ad_info[0])))) { 1012 msglim(&bad_len, from.sin_addr.s_addr, 1013 "rdisc length %d does not match ad_num" 1014 " %d", cc, p->ad.icmp_ad_num); 1015 continue; 1016 } 1017 if (supplier) 1018 continue; 1019 if (ifp->int_state & IS_NO_ADV_IN) 1020 continue; 1021 1022 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1023 for (n = 0; n < p->ad.icmp_ad_num; n++) { 1024 parse_ad(from.sin_addr.s_addr, 1025 wp[0], wp[1], 1026 ntohs(p->ad.icmp_ad_life), 1027 ifp); 1028 wp += p->ad.icmp_ad_asize; 1029 } 1030 break; 1031 1032 1033 case ICMP_ROUTERSOLICIT: 1034 if (!supplier) 1035 continue; 1036 if (ifp->int_state & IS_NO_ADV_OUT) 1037 continue; 1038 if (stopint) 1039 continue; 1040 1041 /* XXX 1042 * We should handle messages from address 0. 1043 */ 1044 1045 /* Respond with a point-to-point advertisement */ 1046 send_adv(ifp, from.sin_addr.s_addr, 0); 1047 break; 1048 } 1049 } 1050 1051 rdisc_sort(); 1052 } 1053