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