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