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