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