17b6ab19dSGarrett Wollman /* 27b6ab19dSGarrett Wollman * Copyright (c) 1983, 1988, 1993 37b6ab19dSGarrett Wollman * The Regents of the University of California. All rights reserved. 47b6ab19dSGarrett Wollman * 57b6ab19dSGarrett Wollman * Redistribution and use in source and binary forms, with or without 67b6ab19dSGarrett Wollman * modification, are permitted provided that the following conditions 77b6ab19dSGarrett Wollman * are met: 87b6ab19dSGarrett Wollman * 1. Redistributions of source code must retain the above copyright 97b6ab19dSGarrett Wollman * notice, this list of conditions and the following disclaimer. 107b6ab19dSGarrett Wollman * 2. Redistributions in binary form must reproduce the above copyright 117b6ab19dSGarrett Wollman * notice, this list of conditions and the following disclaimer in the 127b6ab19dSGarrett Wollman * documentation and/or other materials provided with the distribution. 137b6ab19dSGarrett Wollman * 4. Neither the name of the University nor the names of its contributors 147b6ab19dSGarrett Wollman * may be used to endorse or promote products derived from this software 157b6ab19dSGarrett Wollman * without specific prior written permission. 167b6ab19dSGarrett Wollman * 177b6ab19dSGarrett Wollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 187b6ab19dSGarrett Wollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 197b6ab19dSGarrett Wollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 207b6ab19dSGarrett Wollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 217b6ab19dSGarrett Wollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 227b6ab19dSGarrett Wollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 237b6ab19dSGarrett Wollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 247b6ab19dSGarrett Wollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 257b6ab19dSGarrett Wollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 267b6ab19dSGarrett Wollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 277b6ab19dSGarrett Wollman * SUCH DAMAGE. 28c90fe7dcSMark Murray * 297f3dea24SPeter Wemm * $FreeBSD$ 307b6ab19dSGarrett Wollman */ 317b6ab19dSGarrett Wollman 327b6ab19dSGarrett Wollman #include "defs.h" 337b6ab19dSGarrett Wollman 34caa79e36SBruce M Simpson #ifdef __NetBSD__ 352c7a9781SMark Murray __RCSID("$NetBSD$"); 36caa79e36SBruce M Simpson #elif defined(__FreeBSD__) 37caa79e36SBruce M Simpson __RCSID("$FreeBSD$"); 38caa79e36SBruce M Simpson #else 39caa79e36SBruce M Simpson __RCSID("$Revision: 2.27 $"); 40caa79e36SBruce M Simpson #ident "$Revision: 2.27 $" 412c7a9781SMark Murray #endif 427b6ab19dSGarrett Wollman 432c7a9781SMark Murray 442c7a9781SMark Murray u_int update_seqno; 457b6ab19dSGarrett Wollman 467b6ab19dSGarrett Wollman 477b6ab19dSGarrett Wollman /* walk the tree of routes with this for output 487b6ab19dSGarrett Wollman */ 497b6ab19dSGarrett Wollman struct { 507b6ab19dSGarrett Wollman struct sockaddr_in to; 517b6ab19dSGarrett Wollman naddr to_mask; 527b6ab19dSGarrett Wollman naddr to_net; 537b6ab19dSGarrett Wollman naddr to_std_mask; 547b6ab19dSGarrett Wollman naddr to_std_net; 557b6ab19dSGarrett Wollman struct interface *ifp; /* usually output interface */ 5671965874SGarrett Wollman struct auth *a; 577b6ab19dSGarrett Wollman char metric; /* adjust metrics by interface */ 587b6ab19dSGarrett Wollman int npackets; 597b6ab19dSGarrett Wollman int gen_limit; 607b6ab19dSGarrett Wollman u_int state; 617b6ab19dSGarrett Wollman #define WS_ST_FLASH 0x001 /* send only changed routes */ 62d5b718b3SGarrett Wollman #define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */ 63d5b718b3SGarrett Wollman #define WS_ST_AG 0x004 /* ok to aggregate subnets */ 64d5b718b3SGarrett Wollman #define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */ 652c7a9781SMark Murray #define WS_ST_QUERY 0x010 /* responding to a query */ 662c7a9781SMark Murray #define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */ 672c7a9781SMark Murray #define WS_ST_DEFAULT 0x040 /* faking a default */ 687b6ab19dSGarrett Wollman } ws; 697b6ab19dSGarrett Wollman 707b6ab19dSGarrett Wollman /* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ 71d5b718b3SGarrett Wollman struct ws_buf v12buf; 727b6ab19dSGarrett Wollman union pkt_buf ripv12_buf; 737b6ab19dSGarrett Wollman 747b6ab19dSGarrett Wollman /* Another for only RIPv2 listeners */ 75d5b718b3SGarrett Wollman struct ws_buf v2buf; 767b6ab19dSGarrett Wollman union pkt_buf rip_v2_buf; 777b6ab19dSGarrett Wollman 787b6ab19dSGarrett Wollman 797b6ab19dSGarrett Wollman 80d5b718b3SGarrett Wollman void 81d5b718b3SGarrett Wollman bufinit(void) 82d5b718b3SGarrett Wollman { 83d5b718b3SGarrett Wollman ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE; 84d5b718b3SGarrett Wollman v12buf.buf = &ripv12_buf.rip; 85d5b718b3SGarrett Wollman v12buf.base = &v12buf.buf->rip_nets[0]; 86d5b718b3SGarrett Wollman 87d5b718b3SGarrett Wollman rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE; 88d5b718b3SGarrett Wollman rip_v2_buf.rip.rip_vers = RIPv2; 89d5b718b3SGarrett Wollman v2buf.buf = &rip_v2_buf.rip; 90d5b718b3SGarrett Wollman v2buf.base = &v2buf.buf->rip_nets[0]; 91d5b718b3SGarrett Wollman } 92d5b718b3SGarrett Wollman 93d5b718b3SGarrett Wollman 947b6ab19dSGarrett Wollman /* Send the contents of the global buffer via the non-multicast socket 957b6ab19dSGarrett Wollman */ 967b6ab19dSGarrett Wollman int /* <0 on failure */ 977b6ab19dSGarrett Wollman output(enum output_type type, 987b6ab19dSGarrett Wollman struct sockaddr_in *dst, /* send to here */ 997b6ab19dSGarrett Wollman struct interface *ifp, 1007b6ab19dSGarrett Wollman struct rip *buf, 1017b6ab19dSGarrett Wollman int size) /* this many bytes */ 1027b6ab19dSGarrett Wollman { 103caa79e36SBruce M Simpson struct sockaddr_in osin; 1047b6ab19dSGarrett Wollman int flags; 1052c7a9781SMark Murray const char *msg; 1067b6ab19dSGarrett Wollman int res; 1077b6ab19dSGarrett Wollman int soc; 1087b6ab19dSGarrett Wollman int serrno; 1097b6ab19dSGarrett Wollman 110caa79e36SBruce M Simpson osin = *dst; 111caa79e36SBruce M Simpson if (osin.sin_port == 0) 112caa79e36SBruce M Simpson osin.sin_port = htons(RIP_PORT); 1137b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 114caa79e36SBruce M Simpson if (osin.sin_len == 0) 115caa79e36SBruce M Simpson osin.sin_len = sizeof(osin); 1167b6ab19dSGarrett Wollman #endif 1177b6ab19dSGarrett Wollman 1187b6ab19dSGarrett Wollman soc = rip_sock; 1197b6ab19dSGarrett Wollman flags = 0; 1207b6ab19dSGarrett Wollman 1217b6ab19dSGarrett Wollman switch (type) { 1227b6ab19dSGarrett Wollman case OUT_QUERY: 1237b6ab19dSGarrett Wollman msg = "Answer Query"; 1247b6ab19dSGarrett Wollman if (soc < 0) 1257b6ab19dSGarrett Wollman soc = ifp->int_rip_sock; 1267b6ab19dSGarrett Wollman break; 1277b6ab19dSGarrett Wollman case OUT_UNICAST: 1287b6ab19dSGarrett Wollman msg = "Send"; 1297b6ab19dSGarrett Wollman if (soc < 0) 1307b6ab19dSGarrett Wollman soc = ifp->int_rip_sock; 1317b6ab19dSGarrett Wollman flags = MSG_DONTROUTE; 1327b6ab19dSGarrett Wollman break; 1337b6ab19dSGarrett Wollman case OUT_BROADCAST: 1347b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 1357b6ab19dSGarrett Wollman msg = "Send"; 1367b6ab19dSGarrett Wollman } else { 1377b6ab19dSGarrett Wollman msg = "Send bcast"; 1387b6ab19dSGarrett Wollman } 1397b6ab19dSGarrett Wollman flags = MSG_DONTROUTE; 1407b6ab19dSGarrett Wollman break; 1417b6ab19dSGarrett Wollman case OUT_MULTICAST: 142c2aabe68SPoul-Henning Kamp if (ifp->int_if_flags & (IFF_POINTOPOINT|IFF_MULTICAST) == 143c2aabe68SPoul-Henning Kamp IFF_POINTOPOINT) { 1447b6ab19dSGarrett Wollman msg = "Send pt-to-pt"; 1457b6ab19dSGarrett Wollman } else if (ifp->int_state & IS_DUP) { 1467b6ab19dSGarrett Wollman trace_act("abort multicast output via %s" 147d5b718b3SGarrett Wollman " with duplicate address", 1487b6ab19dSGarrett Wollman ifp->int_name); 1497b6ab19dSGarrett Wollman return 0; 1507b6ab19dSGarrett Wollman } else { 1517b6ab19dSGarrett Wollman msg = "Send mcast"; 1527b6ab19dSGarrett Wollman if (rip_sock_mcast != ifp) { 15368b22388SPoul-Henning Kamp struct ip_mreqn mreqn; 15468b22388SPoul-Henning Kamp 15568b22388SPoul-Henning Kamp memset(&mreqn, 0, sizeof(struct ip_mreqn)); 15668b22388SPoul-Henning Kamp mreqn.imr_ifindex = ifp->int_index; 1577b6ab19dSGarrett Wollman if (0 > setsockopt(rip_sock, 15868b22388SPoul-Henning Kamp IPPROTO_IP, 15968b22388SPoul-Henning Kamp IP_MULTICAST_IF, 16068b22388SPoul-Henning Kamp &mreqn, 16168b22388SPoul-Henning Kamp sizeof(mreqn))) { 1627b6ab19dSGarrett Wollman serrno = errno; 1637b6ab19dSGarrett Wollman LOGERR("setsockopt(rip_sock, " 1647b6ab19dSGarrett Wollman "IP_MULTICAST_IF)"); 1657b6ab19dSGarrett Wollman errno = serrno; 1667b6ab19dSGarrett Wollman ifp = 0; 1677b6ab19dSGarrett Wollman return -1; 1687b6ab19dSGarrett Wollman } 1697b6ab19dSGarrett Wollman rip_sock_mcast = ifp; 1707b6ab19dSGarrett Wollman } 171caa79e36SBruce M Simpson osin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); 1727b6ab19dSGarrett Wollman } 17371965874SGarrett Wollman break; 1747b6ab19dSGarrett Wollman 1757b6ab19dSGarrett Wollman case NO_OUT_MULTICAST: 1767b6ab19dSGarrett Wollman case NO_OUT_RIPV2: 17771965874SGarrett Wollman default: 17871965874SGarrett Wollman #ifdef DEBUG 17971965874SGarrett Wollman abort(); 18071965874SGarrett Wollman #endif 18171965874SGarrett Wollman return -1; 1827b6ab19dSGarrett Wollman } 1837b6ab19dSGarrett Wollman 184caa79e36SBruce M Simpson trace_rip(msg, "to", &osin, ifp, buf, size); 1857b6ab19dSGarrett Wollman 1867b6ab19dSGarrett Wollman res = sendto(soc, buf, size, flags, 187caa79e36SBruce M Simpson (struct sockaddr *)&osin, sizeof(osin)); 1887b6ab19dSGarrett Wollman if (res < 0 1897b6ab19dSGarrett Wollman && (ifp == 0 || !(ifp->int_state & IS_BROKE))) { 1907b6ab19dSGarrett Wollman serrno = errno; 1917b6ab19dSGarrett Wollman msglog("%s sendto(%s%s%s.%d): %s", msg, 1927b6ab19dSGarrett Wollman ifp != 0 ? ifp->int_name : "", 1937b6ab19dSGarrett Wollman ifp != 0 ? ", " : "", 194caa79e36SBruce M Simpson inet_ntoa(osin.sin_addr), 195caa79e36SBruce M Simpson ntohs(osin.sin_port), 1967b6ab19dSGarrett Wollman strerror(errno)); 1977b6ab19dSGarrett Wollman errno = serrno; 1987b6ab19dSGarrett Wollman } 1997b6ab19dSGarrett Wollman 2007b6ab19dSGarrett Wollman return res; 2017b6ab19dSGarrett Wollman } 2027b6ab19dSGarrett Wollman 2037b6ab19dSGarrett Wollman 20471965874SGarrett Wollman /* Find the first key for a packet to send. 20590100551SPhilippe Charnier * Try for a key that is eligible and has not expired, but settle for 206d5b718b3SGarrett Wollman * the last key if they have all expired. 207d5b718b3SGarrett Wollman * If no key is ready yet, give up. 208d5b718b3SGarrett Wollman */ 20971965874SGarrett Wollman struct auth * 210d5b718b3SGarrett Wollman find_auth(struct interface *ifp) 211d5b718b3SGarrett Wollman { 21271965874SGarrett Wollman struct auth *ap, *res; 213d5b718b3SGarrett Wollman int i; 214d5b718b3SGarrett Wollman 215d5b718b3SGarrett Wollman 21671965874SGarrett Wollman if (ifp == 0) 217d5b718b3SGarrett Wollman return 0; 218d5b718b3SGarrett Wollman 219d5b718b3SGarrett Wollman res = 0; 22071965874SGarrett Wollman ap = ifp->int_auth; 221d5b718b3SGarrett Wollman for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) { 22271965874SGarrett Wollman /* stop looking after the last key */ 22371965874SGarrett Wollman if (ap->type == RIP_AUTH_NONE) 22471965874SGarrett Wollman break; 22571965874SGarrett Wollman 22671965874SGarrett Wollman /* ignore keys that are not ready yet */ 22771965874SGarrett Wollman if ((u_long)ap->start > (u_long)clk.tv_sec) 22871965874SGarrett Wollman continue; 22971965874SGarrett Wollman 23071965874SGarrett Wollman if ((u_long)ap->end < (u_long)clk.tv_sec) { 23171965874SGarrett Wollman /* note best expired password as a fall-back */ 23271965874SGarrett Wollman if (res == 0 || (u_long)ap->end > (u_long)res->end) 233d5b718b3SGarrett Wollman res = ap; 23471965874SGarrett Wollman continue; 235d5b718b3SGarrett Wollman } 23671965874SGarrett Wollman 23771965874SGarrett Wollman /* note key with the best future */ 23871965874SGarrett Wollman if (res == 0 || (u_long)res->end < (u_long)ap->end) 23971965874SGarrett Wollman res = ap; 240d5b718b3SGarrett Wollman } 241d5b718b3SGarrett Wollman return res; 242d5b718b3SGarrett Wollman } 243d5b718b3SGarrett Wollman 244d5b718b3SGarrett Wollman 245d5b718b3SGarrett Wollman void 246d5b718b3SGarrett Wollman clr_ws_buf(struct ws_buf *wb, 24771965874SGarrett Wollman struct auth *ap) 248d5b718b3SGarrett Wollman { 249d5b718b3SGarrett Wollman struct netauth *na; 250d5b718b3SGarrett Wollman 251d5b718b3SGarrett Wollman wb->lim = wb->base + NETS_LEN; 252d5b718b3SGarrett Wollman wb->n = wb->base; 2532c7a9781SMark Murray memset(wb->n, 0, NETS_LEN*sizeof(*wb->n)); 254d5b718b3SGarrett Wollman 2552c7a9781SMark Murray /* (start to) install authentication if appropriate 2567b6ab19dSGarrett Wollman */ 257d5b718b3SGarrett Wollman if (ap == 0) 258d5b718b3SGarrett Wollman return; 2592c7a9781SMark Murray 260d5b718b3SGarrett Wollman na = (struct netauth*)wb->n; 26171965874SGarrett Wollman if (ap->type == RIP_AUTH_PW) { 262d5b718b3SGarrett Wollman na->a_family = RIP_AF_AUTH; 263d5b718b3SGarrett Wollman na->a_type = RIP_AUTH_PW; 2642c7a9781SMark Murray memcpy(na->au.au_pw, ap->key, sizeof(na->au.au_pw)); 265d5b718b3SGarrett Wollman wb->n++; 266d5b718b3SGarrett Wollman 26771965874SGarrett Wollman } else if (ap->type == RIP_AUTH_MD5) { 268d5b718b3SGarrett Wollman na->a_family = RIP_AF_AUTH; 269d5b718b3SGarrett Wollman na->a_type = RIP_AUTH_MD5; 270d5b718b3SGarrett Wollman na->au.a_md5.md5_keyid = ap->keyid; 271caa79e36SBruce M Simpson na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN; 2722c7a9781SMark Murray na->au.a_md5.md5_seqno = htonl(clk.tv_sec); 273d5b718b3SGarrett Wollman wb->n++; 274d5b718b3SGarrett Wollman wb->lim--; /* make room for trailer */ 2757b6ab19dSGarrett Wollman } 2767b6ab19dSGarrett Wollman } 2777b6ab19dSGarrett Wollman 2787b6ab19dSGarrett Wollman 279d5b718b3SGarrett Wollman void 280d5b718b3SGarrett Wollman end_md5_auth(struct ws_buf *wb, 28171965874SGarrett Wollman struct auth *ap) 282d5b718b3SGarrett Wollman { 283d5b718b3SGarrett Wollman struct netauth *na, *na2; 284d5b718b3SGarrett Wollman MD5_CTX md5_ctx; 2852c7a9781SMark Murray int len; 286d5b718b3SGarrett Wollman 287d5b718b3SGarrett Wollman 288d5b718b3SGarrett Wollman na = (struct netauth*)wb->base; 289d5b718b3SGarrett Wollman na2 = (struct netauth*)wb->n; 2902c7a9781SMark Murray len = (char *)na2-(char *)wb->buf; 291d5b718b3SGarrett Wollman na2->a_family = RIP_AF_AUTH; 2922c7a9781SMark Murray na2->a_type = htons(1); 2932c7a9781SMark Murray na->au.a_md5.md5_pkt_len = htons(len); 294d5b718b3SGarrett Wollman MD5Init(&md5_ctx); 295caa79e36SBruce M Simpson MD5Update(&md5_ctx, (u_char *)wb->buf, len + RIP_AUTH_MD5_HASH_XTRA); 296caa79e36SBruce M Simpson MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_KEY_LEN); 297d5b718b3SGarrett Wollman MD5Final(na2->au.au_pw, &md5_ctx); 298d5b718b3SGarrett Wollman wb->n++; 299d5b718b3SGarrett Wollman } 300d5b718b3SGarrett Wollman 301d5b718b3SGarrett Wollman 3027b6ab19dSGarrett Wollman /* Send the buffer 3037b6ab19dSGarrett Wollman */ 3047b6ab19dSGarrett Wollman static void 3057b6ab19dSGarrett Wollman supply_write(struct ws_buf *wb) 3067b6ab19dSGarrett Wollman { 3077b6ab19dSGarrett Wollman /* Output multicast only if legal. 30890100551SPhilippe Charnier * If we would multicast and it would be illegal, then discard the 3097b6ab19dSGarrett Wollman * packet. 3107b6ab19dSGarrett Wollman */ 3117b6ab19dSGarrett Wollman switch (wb->type) { 3127b6ab19dSGarrett Wollman case NO_OUT_MULTICAST: 313d5b718b3SGarrett Wollman trace_pkt("skip multicast to %s because impossible", 3147b6ab19dSGarrett Wollman naddr_ntoa(ws.to.sin_addr.s_addr)); 3157b6ab19dSGarrett Wollman break; 3167b6ab19dSGarrett Wollman case NO_OUT_RIPV2: 3177b6ab19dSGarrett Wollman break; 3187b6ab19dSGarrett Wollman default: 31971965874SGarrett Wollman if (ws.a != 0 && ws.a->type == RIP_AUTH_MD5) 320d5b718b3SGarrett Wollman end_md5_auth(wb,ws.a); 3217b6ab19dSGarrett Wollman if (output(wb->type, &ws.to, ws.ifp, wb->buf, 3227b6ab19dSGarrett Wollman ((char *)wb->n - (char*)wb->buf)) < 0 3237b6ab19dSGarrett Wollman && ws.ifp != 0) 3247b6ab19dSGarrett Wollman if_sick(ws.ifp); 3257b6ab19dSGarrett Wollman ws.npackets++; 3267b6ab19dSGarrett Wollman break; 3277b6ab19dSGarrett Wollman } 3287b6ab19dSGarrett Wollman 32971965874SGarrett Wollman clr_ws_buf(wb,ws.a); 3307b6ab19dSGarrett Wollman } 3317b6ab19dSGarrett Wollman 3327b6ab19dSGarrett Wollman 3337b6ab19dSGarrett Wollman /* put an entry into the packet 3347b6ab19dSGarrett Wollman */ 3357b6ab19dSGarrett Wollman static void 3367b6ab19dSGarrett Wollman supply_out(struct ag_info *ag) 3377b6ab19dSGarrett Wollman { 3387b6ab19dSGarrett Wollman int i; 33971965874SGarrett Wollman naddr mask, v1_mask, dst_h, ddst_h = 0; 3407b6ab19dSGarrett Wollman struct ws_buf *wb; 3417b6ab19dSGarrett Wollman 3427b6ab19dSGarrett Wollman 3437b6ab19dSGarrett Wollman /* Skip this route if doing a flash update and it and the routes 3447b6ab19dSGarrett Wollman * it aggregates have not changed recently. 3457b6ab19dSGarrett Wollman */ 3467b6ab19dSGarrett Wollman if (ag->ag_seqno < update_seqno 3477b6ab19dSGarrett Wollman && (ws.state & WS_ST_FLASH)) 3487b6ab19dSGarrett Wollman return; 3497b6ab19dSGarrett Wollman 3507b6ab19dSGarrett Wollman dst_h = ag->ag_dst_h; 3517b6ab19dSGarrett Wollman mask = ag->ag_mask; 3527b6ab19dSGarrett Wollman v1_mask = ripv1_mask_host(htonl(dst_h), 3537b6ab19dSGarrett Wollman (ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0); 3547b6ab19dSGarrett Wollman i = 0; 3557b6ab19dSGarrett Wollman 3567b6ab19dSGarrett Wollman /* If we are sending RIPv2 packets that cannot (or must not) be 3577b6ab19dSGarrett Wollman * heard by RIPv1 listeners, do not worry about sub- or supernets. 3587b6ab19dSGarrett Wollman * Subnets (from other networks) can only be sent via multicast. 3597b6ab19dSGarrett Wollman * A pair of subnet routes might have been promoted so that they 3607b6ab19dSGarrett Wollman * are legal to send by RIPv1. 361d5b718b3SGarrett Wollman * If RIPv1 is off, use the multicast buffer. 3627b6ab19dSGarrett Wollman */ 363d5b718b3SGarrett Wollman if ((ws.state & WS_ST_RIP2_ALL) 3647b6ab19dSGarrett Wollman || ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) { 3657b6ab19dSGarrett Wollman /* use the RIPv2-only buffer */ 366d5b718b3SGarrett Wollman wb = &v2buf; 3677b6ab19dSGarrett Wollman 3687b6ab19dSGarrett Wollman } else { 3697b6ab19dSGarrett Wollman /* use the RIPv1-or-RIPv2 buffer */ 370d5b718b3SGarrett Wollman wb = &v12buf; 3717b6ab19dSGarrett Wollman 3727b6ab19dSGarrett Wollman /* Convert supernet route into corresponding set of network 3737b6ab19dSGarrett Wollman * routes for RIPv1, but leave non-contiguous netmasks 3747b6ab19dSGarrett Wollman * to ag_check(). 3757b6ab19dSGarrett Wollman */ 3767b6ab19dSGarrett Wollman if (v1_mask > mask 3777b6ab19dSGarrett Wollman && mask + (mask & -mask) == 0) { 3787b6ab19dSGarrett Wollman ddst_h = v1_mask & -v1_mask; 3797b6ab19dSGarrett Wollman i = (v1_mask & ~mask)/ddst_h; 3807b6ab19dSGarrett Wollman 3817b6ab19dSGarrett Wollman if (i > ws.gen_limit) { 3827b6ab19dSGarrett Wollman /* Punt if we would have to generate an 3837b6ab19dSGarrett Wollman * unreasonable number of routes. 3847b6ab19dSGarrett Wollman */ 3852c7a9781SMark Murray if (TRACECONTENTS) 3862c7a9781SMark Murray trace_misc("sending %s-->%s as 1" 3872c7a9781SMark Murray " instead of %d routes", 3882c7a9781SMark Murray addrname(htonl(dst_h), mask, 3892c7a9781SMark Murray 1), 3902c7a9781SMark Murray naddr_ntoa(ws.to.sin_addr 3912c7a9781SMark Murray .s_addr), 3927b6ab19dSGarrett Wollman i+1); 3937b6ab19dSGarrett Wollman i = 0; 3947b6ab19dSGarrett Wollman 3957b6ab19dSGarrett Wollman } else { 3967b6ab19dSGarrett Wollman mask = v1_mask; 3977b6ab19dSGarrett Wollman ws.gen_limit -= i; 3987b6ab19dSGarrett Wollman } 3997b6ab19dSGarrett Wollman } 4007b6ab19dSGarrett Wollman } 4017b6ab19dSGarrett Wollman 4027b6ab19dSGarrett Wollman do { 4037b6ab19dSGarrett Wollman wb->n->n_family = RIP_AF_INET; 4047b6ab19dSGarrett Wollman wb->n->n_dst = htonl(dst_h); 4057b6ab19dSGarrett Wollman /* If the route is from router-discovery or we are 4067b6ab19dSGarrett Wollman * shutting down, admit only a bad metric. 4077b6ab19dSGarrett Wollman */ 4087b6ab19dSGarrett Wollman wb->n->n_metric = ((stopint || ag->ag_metric < 1) 4097b6ab19dSGarrett Wollman ? HOPCNT_INFINITY 4107b6ab19dSGarrett Wollman : ag->ag_metric); 411fd8e4ebcSMike Barcroft wb->n->n_metric = htonl(wb->n->n_metric); 412d5b718b3SGarrett Wollman /* Any non-zero bits in the supposedly unused RIPv1 fields 413d5b718b3SGarrett Wollman * cause the old `routed` to ignore the route. 414d5b718b3SGarrett Wollman * That means the mask and so forth cannot be sent 415d5b718b3SGarrett Wollman * in the hybrid RIPv1/RIPv2 mode. 416d5b718b3SGarrett Wollman */ 417d5b718b3SGarrett Wollman if (ws.state & WS_ST_RIP2_ALL) { 4187b6ab19dSGarrett Wollman if (ag->ag_nhop != 0 4197b6ab19dSGarrett Wollman && ((ws.state & WS_ST_QUERY) 4207b6ab19dSGarrett Wollman || (ag->ag_nhop != ws.ifp->int_addr 4217b6ab19dSGarrett Wollman && on_net(ag->ag_nhop, 4227b6ab19dSGarrett Wollman ws.ifp->int_net, 4237b6ab19dSGarrett Wollman ws.ifp->int_mask)))) 4247b6ab19dSGarrett Wollman wb->n->n_nhop = ag->ag_nhop; 4257b6ab19dSGarrett Wollman wb->n->n_mask = htonl(mask); 4267b6ab19dSGarrett Wollman wb->n->n_tag = ag->ag_tag; 4277b6ab19dSGarrett Wollman } 4287b6ab19dSGarrett Wollman dst_h += ddst_h; 4297b6ab19dSGarrett Wollman 4307b6ab19dSGarrett Wollman if (++wb->n >= wb->lim) 4317b6ab19dSGarrett Wollman supply_write(wb); 4327b6ab19dSGarrett Wollman } while (i-- != 0); 4337b6ab19dSGarrett Wollman } 4347b6ab19dSGarrett Wollman 4357b6ab19dSGarrett Wollman 4367b6ab19dSGarrett Wollman /* supply one route from the table 4377b6ab19dSGarrett Wollman */ 4387b6ab19dSGarrett Wollman /* ARGSUSED */ 4397b6ab19dSGarrett Wollman static int 4407b6ab19dSGarrett Wollman walk_supply(struct radix_node *rn, 4412c7a9781SMark Murray struct walkarg *argp UNUSED) 4427b6ab19dSGarrett Wollman { 4437b6ab19dSGarrett Wollman #define RT ((struct rt_entry *)rn) 4447b6ab19dSGarrett Wollman u_short ags; 4457b6ab19dSGarrett Wollman char metric, pref; 4467b6ab19dSGarrett Wollman naddr dst, nhop; 4472c7a9781SMark Murray struct rt_spare *rts; 4482c7a9781SMark Murray int i; 4497b6ab19dSGarrett Wollman 4507b6ab19dSGarrett Wollman 451d5b718b3SGarrett Wollman /* Do not advertise external remote interfaces or passive interfaces. 4527b6ab19dSGarrett Wollman */ 4537b6ab19dSGarrett Wollman if ((RT->rt_state & RS_IF) 4547b6ab19dSGarrett Wollman && RT->rt_ifp != 0 455f7434bbdSSheldon Hearn && (RT->rt_ifp->int_state & IS_PASSIVE) 4567b6ab19dSGarrett Wollman && !(RT->rt_state & RS_MHOME)) 4577b6ab19dSGarrett Wollman return 0; 4587b6ab19dSGarrett Wollman 4597b6ab19dSGarrett Wollman /* If being quiet about our ability to forward, then 460d5b718b3SGarrett Wollman * do not say anything unless responding to a query, 461d5b718b3SGarrett Wollman * except about our main interface. 4627b6ab19dSGarrett Wollman */ 463d5b718b3SGarrett Wollman if (!supplier && !(ws.state & WS_ST_QUERY) 464d5b718b3SGarrett Wollman && !(RT->rt_state & RS_MHOME)) 4657b6ab19dSGarrett Wollman return 0; 4667b6ab19dSGarrett Wollman 4677b6ab19dSGarrett Wollman dst = RT->rt_dst; 4687b6ab19dSGarrett Wollman 4697b6ab19dSGarrett Wollman /* do not collide with the fake default route */ 4707b6ab19dSGarrett Wollman if (dst == RIP_DEFAULT 4717b6ab19dSGarrett Wollman && (ws.state & WS_ST_DEFAULT)) 4727b6ab19dSGarrett Wollman return 0; 4737b6ab19dSGarrett Wollman 4747b6ab19dSGarrett Wollman if (RT->rt_state & RS_NET_SYN) { 4757b6ab19dSGarrett Wollman if (RT->rt_state & RS_NET_INT) { 4767b6ab19dSGarrett Wollman /* Do not send manual synthetic network routes 4777b6ab19dSGarrett Wollman * into the subnet. 4787b6ab19dSGarrett Wollman */ 4797b6ab19dSGarrett Wollman if (on_net(ws.to.sin_addr.s_addr, 4807b6ab19dSGarrett Wollman ntohl(dst), RT->rt_mask)) 4817b6ab19dSGarrett Wollman return 0; 4827b6ab19dSGarrett Wollman 4837b6ab19dSGarrett Wollman } else { 4847b6ab19dSGarrett Wollman /* Do not send automatic synthetic network routes 48590100551SPhilippe Charnier * if they are not needed because no RIPv1 listeners 4867b6ab19dSGarrett Wollman * can hear them. 4877b6ab19dSGarrett Wollman */ 4887b6ab19dSGarrett Wollman if (ws.state & WS_ST_RIP2_ALL) 4897b6ab19dSGarrett Wollman return 0; 4907b6ab19dSGarrett Wollman 4917b6ab19dSGarrett Wollman /* Do not send automatic synthetic network routes to 4927b6ab19dSGarrett Wollman * the real subnet. 4937b6ab19dSGarrett Wollman */ 4947b6ab19dSGarrett Wollman if (on_net(ws.to.sin_addr.s_addr, 4957b6ab19dSGarrett Wollman ntohl(dst), RT->rt_mask)) 4967b6ab19dSGarrett Wollman return 0; 4977b6ab19dSGarrett Wollman } 4987b6ab19dSGarrett Wollman nhop = 0; 4997b6ab19dSGarrett Wollman 5007b6ab19dSGarrett Wollman } else { 5017b6ab19dSGarrett Wollman /* Advertise the next hop if this is not a route for one 5027b6ab19dSGarrett Wollman * of our interfaces and the next hop is on the same 5037b6ab19dSGarrett Wollman * network as the target. 5042c7a9781SMark Murray * The final determination is made by supply_out(). 5057b6ab19dSGarrett Wollman */ 5067b6ab19dSGarrett Wollman if (!(RT->rt_state & RS_IF) 5077b6ab19dSGarrett Wollman && RT->rt_gate != myaddr 5087b6ab19dSGarrett Wollman && RT->rt_gate != loopaddr) 5097b6ab19dSGarrett Wollman nhop = RT->rt_gate; 5107b6ab19dSGarrett Wollman else 5117b6ab19dSGarrett Wollman nhop = 0; 5127b6ab19dSGarrett Wollman } 5137b6ab19dSGarrett Wollman 5147b6ab19dSGarrett Wollman metric = RT->rt_metric; 5157b6ab19dSGarrett Wollman ags = 0; 5167b6ab19dSGarrett Wollman 5177b6ab19dSGarrett Wollman if (RT->rt_state & RS_MHOME) { 5187b6ab19dSGarrett Wollman /* retain host route of multi-homed servers */ 5197b6ab19dSGarrett Wollman ; 5207b6ab19dSGarrett Wollman 5217b6ab19dSGarrett Wollman } else if (RT_ISHOST(RT)) { 5222c7a9781SMark Murray /* We should always suppress (into existing network routes) 5232c7a9781SMark Murray * the host routes for the local end of our point-to-point 5242c7a9781SMark Murray * links. 5257b6ab19dSGarrett Wollman * If we are suppressing host routes in general, then do so. 5267b6ab19dSGarrett Wollman * Avoid advertising host routes onto their own network, 5277b6ab19dSGarrett Wollman * where they should be handled by proxy-ARP. 5287b6ab19dSGarrett Wollman */ 5297b6ab19dSGarrett Wollman if ((RT->rt_state & RS_LOCAL) 5307b6ab19dSGarrett Wollman || ridhosts 5317b6ab19dSGarrett Wollman || on_net(dst, ws.to_net, ws.to_mask)) 5327b6ab19dSGarrett Wollman ags |= AGS_SUPPRESS; 5337b6ab19dSGarrett Wollman 5342c7a9781SMark Murray /* Aggregate stray host routes into network routes if allowed. 5352c7a9781SMark Murray * We cannot aggregate host routes into small network routes 5362c7a9781SMark Murray * without confusing RIPv1 listeners into thinking the 5372c7a9781SMark Murray * network routes are host routes. 5382c7a9781SMark Murray */ 539caa79e36SBruce M Simpson if ((ws.state & WS_ST_AG) && (ws.state & WS_ST_RIP2_ALL)) 5402c7a9781SMark Murray ags |= AGS_AGGREGATE; 5417b6ab19dSGarrett Wollman 5422c7a9781SMark Murray } else { 5432c7a9781SMark Murray /* Always suppress network routes into other, existing 5442c7a9781SMark Murray * network routes 5457b6ab19dSGarrett Wollman */ 5467b6ab19dSGarrett Wollman ags |= AGS_SUPPRESS; 5477b6ab19dSGarrett Wollman 5487b6ab19dSGarrett Wollman /* Generate supernets if allowed. 5497b6ab19dSGarrett Wollman * If we can be heard by RIPv1 systems, we will 5507b6ab19dSGarrett Wollman * later convert back to ordinary nets. 5517b6ab19dSGarrett Wollman * This unifies dealing with received supernets. 5527b6ab19dSGarrett Wollman */ 5532c7a9781SMark Murray if ((ws.state & WS_ST_AG) 5542c7a9781SMark Murray && ((RT->rt_state & RS_SUBNET) 5552c7a9781SMark Murray || (ws.state & WS_ST_SUPER_AG))) 5562c7a9781SMark Murray ags |= AGS_AGGREGATE; 5577b6ab19dSGarrett Wollman } 5587b6ab19dSGarrett Wollman 5597b6ab19dSGarrett Wollman /* Do not send RIPv1 advertisements of subnets to other 5607b6ab19dSGarrett Wollman * networks. If possible, multicast them by RIPv2. 5617b6ab19dSGarrett Wollman */ 5627b6ab19dSGarrett Wollman if ((RT->rt_state & RS_SUBNET) 5637b6ab19dSGarrett Wollman && !(ws.state & WS_ST_RIP2_ALL) 5642c7a9781SMark Murray && !on_net(dst, ws.to_std_net, ws.to_std_mask)) 5652c7a9781SMark Murray ags |= AGS_RIPV2 | AGS_AGGREGATE; 5662c7a9781SMark Murray 5677b6ab19dSGarrett Wollman 5687b6ab19dSGarrett Wollman /* Do not send a route back to where it came from, except in 5697b6ab19dSGarrett Wollman * response to a query. This is "split-horizon". That means not 5707b6ab19dSGarrett Wollman * advertising back to the same network and so via the same interface. 5717b6ab19dSGarrett Wollman * 5727b6ab19dSGarrett Wollman * We want to suppress routes that might have been fragmented 5737b6ab19dSGarrett Wollman * from this route by a RIPv1 router and sent back to us, and so we 5747b6ab19dSGarrett Wollman * cannot forget this route here. Let the split-horizon route 5752c7a9781SMark Murray * suppress the fragmented routes and then itself be forgotten. 5767b6ab19dSGarrett Wollman * 5777b6ab19dSGarrett Wollman * Include the routes for both ends of point-to-point interfaces 57871965874SGarrett Wollman * among those suppressed by split-horizon, since the other side 57971965874SGarrett Wollman * should knows them as well as we do. 5802c7a9781SMark Murray * 5812c7a9781SMark Murray * Notice spare routes with the same metric that we are about to 5822c7a9781SMark Murray * advertise, to split the horizon on redundant, inactive paths. 583caa79e36SBruce M Simpson * 584caa79e36SBruce M Simpson * Do not suppress advertisements of interface-related addresses on 585caa79e36SBruce M Simpson * non-point-to-point interfaces. This ensures that we have something 586caa79e36SBruce M Simpson * to say every 30 seconds to help detect broken Ethernets or 587caa79e36SBruce M Simpson * other interfaces where one packet every 30 seconds costs nothing. 5887b6ab19dSGarrett Wollman */ 5892c7a9781SMark Murray if (ws.ifp != 0 5907b6ab19dSGarrett Wollman && !(ws.state & WS_ST_QUERY) 5917b6ab19dSGarrett Wollman && (ws.state & WS_ST_TO_ON_NET) 5927b6ab19dSGarrett Wollman && (!(RT->rt_state & RS_IF) 5937b6ab19dSGarrett Wollman || ws.ifp->int_if_flags & IFF_POINTOPOINT)) { 5942c7a9781SMark Murray for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) { 5952c7a9781SMark Murray if (rts->rts_metric > metric 5962c7a9781SMark Murray || rts->rts_ifp != ws.ifp) 5972c7a9781SMark Murray continue; 5982c7a9781SMark Murray 59971965874SGarrett Wollman /* If we do not mark the route with AGS_SPLIT_HZ here, 6002c7a9781SMark Murray * it will be poisoned-reverse, or advertised back 6012c7a9781SMark Murray * toward its source with an infinite metric. 6022c7a9781SMark Murray * If we have recently advertised the route with a 6032c7a9781SMark Murray * better metric than we now have, then we should 6042c7a9781SMark Murray * poison-reverse the route before suppressing it for 6052c7a9781SMark Murray * split-horizon. 60671965874SGarrett Wollman * 6072c7a9781SMark Murray * In almost all cases, if there is no spare for the 6082c7a9781SMark Murray * route then it is either old and dead or a brand 6092c7a9781SMark Murray * new route. If it is brand new, there is no need 6102c7a9781SMark Murray * for poison-reverse. If it is old and dead, it 6112c7a9781SMark Murray * is already poisoned. 6127b6ab19dSGarrett Wollman */ 6137b6ab19dSGarrett Wollman if (RT->rt_poison_time < now_expire 61471965874SGarrett Wollman || RT->rt_poison_metric >= metric 6157b6ab19dSGarrett Wollman || RT->rt_spares[1].rts_gate == 0) { 6167b6ab19dSGarrett Wollman ags |= AGS_SPLIT_HZ; 6172c7a9781SMark Murray ags &= ~AGS_SUPPRESS; 6187b6ab19dSGarrett Wollman } 61971965874SGarrett Wollman metric = HOPCNT_INFINITY; 6202c7a9781SMark Murray break; 6212c7a9781SMark Murray } 6227b6ab19dSGarrett Wollman } 6237b6ab19dSGarrett Wollman 6247b6ab19dSGarrett Wollman /* Keep track of the best metric with which the 6257b6ab19dSGarrett Wollman * route has been advertised recently. 6267b6ab19dSGarrett Wollman */ 6277b6ab19dSGarrett Wollman if (RT->rt_poison_metric >= metric 6287b6ab19dSGarrett Wollman || RT->rt_poison_time < now_expire) { 6297b6ab19dSGarrett Wollman RT->rt_poison_time = now.tv_sec; 6307b6ab19dSGarrett Wollman RT->rt_poison_metric = metric; 6317b6ab19dSGarrett Wollman } 6327b6ab19dSGarrett Wollman 6332c7a9781SMark Murray /* Adjust the outgoing metric by the cost of the link. 6342c7a9781SMark Murray * Avoid aggregation when a route is counting to infinity. 6352c7a9781SMark Murray */ 6362c7a9781SMark Murray pref = RT->rt_poison_metric + ws.metric; 6372c7a9781SMark Murray metric += ws.metric; 6382c7a9781SMark Murray 6397b6ab19dSGarrett Wollman /* Do not advertise stable routes that will be ignored, 640d5b718b3SGarrett Wollman * unless we are answering a query. 641d5b718b3SGarrett Wollman * If the route recently was advertised with a metric that 642d5b718b3SGarrett Wollman * would have been less than infinity through this interface, 643d5b718b3SGarrett Wollman * we need to continue to advertise it in order to poison it. 6447b6ab19dSGarrett Wollman */ 6452c7a9781SMark Murray if (metric >= HOPCNT_INFINITY) { 646d5b718b3SGarrett Wollman if (!(ws.state & WS_ST_QUERY) 647d5b718b3SGarrett Wollman && (pref >= HOPCNT_INFINITY 648d5b718b3SGarrett Wollman || RT->rt_poison_time < now_garbage)) 6497b6ab19dSGarrett Wollman return 0; 6507b6ab19dSGarrett Wollman 6517b6ab19dSGarrett Wollman metric = HOPCNT_INFINITY; 6527b6ab19dSGarrett Wollman } 6537b6ab19dSGarrett Wollman 6547b6ab19dSGarrett Wollman ag_check(dst, RT->rt_mask, 0, nhop, metric, pref, 6557b6ab19dSGarrett Wollman RT->rt_seqno, RT->rt_tag, ags, supply_out); 6567b6ab19dSGarrett Wollman return 0; 6577b6ab19dSGarrett Wollman #undef RT 6587b6ab19dSGarrett Wollman } 6597b6ab19dSGarrett Wollman 6607b6ab19dSGarrett Wollman 6617b6ab19dSGarrett Wollman /* Supply dst with the contents of the routing tables. 6627b6ab19dSGarrett Wollman * If this won't fit in one packet, chop it up into several. 6637b6ab19dSGarrett Wollman */ 6647b6ab19dSGarrett Wollman void 6657b6ab19dSGarrett Wollman supply(struct sockaddr_in *dst, 6667b6ab19dSGarrett Wollman struct interface *ifp, /* output interface */ 6677b6ab19dSGarrett Wollman enum output_type type, 6687b6ab19dSGarrett Wollman int flash, /* 1=flash update */ 669d5b718b3SGarrett Wollman int vers, /* RIP version */ 670d5b718b3SGarrett Wollman int passwd_ok) /* OK to include cleartext password */ 6717b6ab19dSGarrett Wollman { 6727b6ab19dSGarrett Wollman struct rt_entry *rt; 673d5b718b3SGarrett Wollman int def_metric; 6747b6ab19dSGarrett Wollman 6757b6ab19dSGarrett Wollman 6767b6ab19dSGarrett Wollman ws.state = 0; 6777b6ab19dSGarrett Wollman ws.gen_limit = 1024; 6787b6ab19dSGarrett Wollman 6797b6ab19dSGarrett Wollman ws.to = *dst; 6807b6ab19dSGarrett Wollman ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr); 6817b6ab19dSGarrett Wollman ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask; 6827b6ab19dSGarrett Wollman 6837b6ab19dSGarrett Wollman if (ifp != 0) { 6847b6ab19dSGarrett Wollman ws.to_mask = ifp->int_mask; 6857b6ab19dSGarrett Wollman ws.to_net = ifp->int_net; 6867b6ab19dSGarrett Wollman if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask)) 6877b6ab19dSGarrett Wollman ws.state |= WS_ST_TO_ON_NET; 6887b6ab19dSGarrett Wollman 6897b6ab19dSGarrett Wollman } else { 6907b6ab19dSGarrett Wollman ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0); 6917b6ab19dSGarrett Wollman ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask; 6927b6ab19dSGarrett Wollman rt = rtfind(dst->sin_addr.s_addr); 6937b6ab19dSGarrett Wollman if (rt) 6947b6ab19dSGarrett Wollman ifp = rt->rt_ifp; 6957b6ab19dSGarrett Wollman } 6967b6ab19dSGarrett Wollman 6977b6ab19dSGarrett Wollman ws.npackets = 0; 6987b6ab19dSGarrett Wollman if (flash) 6997b6ab19dSGarrett Wollman ws.state |= WS_ST_FLASH; 7007b6ab19dSGarrett Wollman 7017b6ab19dSGarrett Wollman if ((ws.ifp = ifp) == 0) { 7027b6ab19dSGarrett Wollman ws.metric = 1; 7037b6ab19dSGarrett Wollman } else { 7047b6ab19dSGarrett Wollman /* Adjust the advertised metric by the outgoing interface 7057b6ab19dSGarrett Wollman * metric. 7067b6ab19dSGarrett Wollman */ 707caa79e36SBruce M Simpson ws.metric = ifp->int_metric + 1 + ifp->int_adj_outmetric; 7087b6ab19dSGarrett Wollman } 7097b6ab19dSGarrett Wollman 7107b6ab19dSGarrett Wollman ripv12_buf.rip.rip_vers = vers; 7117b6ab19dSGarrett Wollman 7127b6ab19dSGarrett Wollman switch (type) { 7137b6ab19dSGarrett Wollman case OUT_MULTICAST: 7142c7a9781SMark Murray if (ifp->int_if_flags & IFF_MULTICAST) 7152c7a9781SMark Murray v2buf.type = OUT_MULTICAST; 7162c7a9781SMark Murray else 7172c7a9781SMark Murray v2buf.type = NO_OUT_MULTICAST; 718d5b718b3SGarrett Wollman v12buf.type = OUT_BROADCAST; 7197b6ab19dSGarrett Wollman break; 7202c7a9781SMark Murray 7217b6ab19dSGarrett Wollman case OUT_QUERY: 7222c7a9781SMark Murray ws.state |= WS_ST_QUERY; 7237fed38d0SPhilippe Charnier /* FALLTHROUGH */ 7242c7a9781SMark Murray case OUT_BROADCAST: 7252c7a9781SMark Murray case OUT_UNICAST: 726d5b718b3SGarrett Wollman v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; 727d5b718b3SGarrett Wollman v12buf.type = type; 7287b6ab19dSGarrett Wollman break; 7292c7a9781SMark Murray 7302c7a9781SMark Murray case NO_OUT_MULTICAST: 7312c7a9781SMark Murray case NO_OUT_RIPV2: 7322c7a9781SMark Murray break; /* no output */ 7337b6ab19dSGarrett Wollman } 7347b6ab19dSGarrett Wollman 7357b6ab19dSGarrett Wollman if (vers == RIPv2) { 7367b6ab19dSGarrett Wollman /* full RIPv2 only if cannot be heard by RIPv1 listeners */ 7377b6ab19dSGarrett Wollman if (type != OUT_BROADCAST) 7387b6ab19dSGarrett Wollman ws.state |= WS_ST_RIP2_ALL; 7392c7a9781SMark Murray if ((ws.state & WS_ST_QUERY) 7402c7a9781SMark Murray || !(ws.state & WS_ST_TO_ON_NET)) { 7417b6ab19dSGarrett Wollman ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); 742d5b718b3SGarrett Wollman } else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) { 7437b6ab19dSGarrett Wollman ws.state |= WS_ST_AG; 7447b6ab19dSGarrett Wollman if (type != OUT_BROADCAST 7452c7a9781SMark Murray && (ifp == 0 7462c7a9781SMark Murray || !(ifp->int_state & IS_NO_SUPER_AG))) 7477b6ab19dSGarrett Wollman ws.state |= WS_ST_SUPER_AG; 7487b6ab19dSGarrett Wollman } 7497b6ab19dSGarrett Wollman } 7507b6ab19dSGarrett Wollman 751d5b718b3SGarrett Wollman ws.a = (vers == RIPv2) ? find_auth(ifp) : 0; 75271965874SGarrett Wollman if (!passwd_ok && ws.a != 0 && ws.a->type == RIP_AUTH_PW) 753d5b718b3SGarrett Wollman ws.a = 0; 75471965874SGarrett Wollman clr_ws_buf(&v12buf,ws.a); 75571965874SGarrett Wollman clr_ws_buf(&v2buf,ws.a); 756d5b718b3SGarrett Wollman 757d5b718b3SGarrett Wollman /* Fake a default route if asked and if there is not already 7587b6ab19dSGarrett Wollman * a better, real default route. 7597b6ab19dSGarrett Wollman */ 760d5b718b3SGarrett Wollman if (supplier && (def_metric = ifp->int_d_metric) != 0) { 761d5b718b3SGarrett Wollman if (0 == (rt = rtget(RIP_DEFAULT, 0)) 762d5b718b3SGarrett Wollman || rt->rt_metric+ws.metric >= def_metric) { 7637b6ab19dSGarrett Wollman ws.state |= WS_ST_DEFAULT; 764d5b718b3SGarrett Wollman ag_check(0, 0, 0, 0, def_metric, def_metric, 7657b6ab19dSGarrett Wollman 0, 0, 0, supply_out); 766d5b718b3SGarrett Wollman } else { 767d5b718b3SGarrett Wollman def_metric = rt->rt_metric+ws.metric; 7687b6ab19dSGarrett Wollman } 769d5b718b3SGarrett Wollman 770d5b718b3SGarrett Wollman /* If both RIPv2 and the poor-man's router discovery 771d5b718b3SGarrett Wollman * kludge are on, arrange to advertise an extra 772d5b718b3SGarrett Wollman * default route via RIPv1. 773d5b718b3SGarrett Wollman */ 7747b6ab19dSGarrett Wollman if ((ws.state & WS_ST_RIP2_ALL) 7757b6ab19dSGarrett Wollman && (ifp->int_state & IS_PM_RDISC)) { 7767b6ab19dSGarrett Wollman ripv12_buf.rip.rip_vers = RIPv1; 777d5b718b3SGarrett Wollman v12buf.n->n_family = RIP_AF_INET; 778d5b718b3SGarrett Wollman v12buf.n->n_dst = htonl(RIP_DEFAULT); 779d5b718b3SGarrett Wollman v12buf.n->n_metric = htonl(def_metric); 780d5b718b3SGarrett Wollman v12buf.n++; 7817b6ab19dSGarrett Wollman } 7827b6ab19dSGarrett Wollman } 7837b6ab19dSGarrett Wollman 7847b6ab19dSGarrett Wollman (void)rn_walktree(rhead, walk_supply, 0); 7857b6ab19dSGarrett Wollman ag_flush(0,0,supply_out); 7867b6ab19dSGarrett Wollman 7877b6ab19dSGarrett Wollman /* Flush the packet buffers, provided they are not empty and 7887b6ab19dSGarrett Wollman * do not contain only the password. 7897b6ab19dSGarrett Wollman */ 790d5b718b3SGarrett Wollman if (v12buf.n != v12buf.base 791d5b718b3SGarrett Wollman && (v12buf.n > v12buf.base+1 792d5b718b3SGarrett Wollman || v12buf.base->n_family != RIP_AF_AUTH)) 793d5b718b3SGarrett Wollman supply_write(&v12buf); 794d5b718b3SGarrett Wollman if (v2buf.n != v2buf.base 795d5b718b3SGarrett Wollman && (v2buf.n > v2buf.base+1 796d5b718b3SGarrett Wollman || v2buf.base->n_family != RIP_AF_AUTH)) 797d5b718b3SGarrett Wollman supply_write(&v2buf); 7987b6ab19dSGarrett Wollman 7997b6ab19dSGarrett Wollman /* If we sent nothing and this is an answer to a query, send 8007b6ab19dSGarrett Wollman * an empty buffer. 8017b6ab19dSGarrett Wollman */ 8027b6ab19dSGarrett Wollman if (ws.npackets == 0 8037b6ab19dSGarrett Wollman && (ws.state & WS_ST_QUERY)) 804d5b718b3SGarrett Wollman supply_write(&v12buf); 8057b6ab19dSGarrett Wollman } 8067b6ab19dSGarrett Wollman 8077b6ab19dSGarrett Wollman 8087b6ab19dSGarrett Wollman /* send all of the routing table or just do a flash update 8097b6ab19dSGarrett Wollman */ 8107b6ab19dSGarrett Wollman void 8117b6ab19dSGarrett Wollman rip_bcast(int flash) 8127b6ab19dSGarrett Wollman { 8137b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 814f7434bbdSSheldon Hearn static struct sockaddr_in dst = {sizeof(dst), AF_INET, 0, {0}, {0}}; 8157b6ab19dSGarrett Wollman #else 8167b6ab19dSGarrett Wollman static struct sockaddr_in dst = {AF_INET}; 8177b6ab19dSGarrett Wollman #endif 8187b6ab19dSGarrett Wollman struct interface *ifp; 8197b6ab19dSGarrett Wollman enum output_type type; 8207b6ab19dSGarrett Wollman int vers; 8217b6ab19dSGarrett Wollman struct timeval rtime; 8227b6ab19dSGarrett Wollman 8237b6ab19dSGarrett Wollman 8247b6ab19dSGarrett Wollman need_flash = 0; 8257b6ab19dSGarrett Wollman intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME); 8267b6ab19dSGarrett Wollman no_flash = rtime; 8277b6ab19dSGarrett Wollman timevaladd(&no_flash, &now); 8287b6ab19dSGarrett Wollman 8297b6ab19dSGarrett Wollman if (rip_sock < 0) 8307b6ab19dSGarrett Wollman return; 8317b6ab19dSGarrett Wollman 832d5b718b3SGarrett Wollman trace_act("send %s and inhibit dynamic updates for %.3f sec", 8337b6ab19dSGarrett Wollman flash ? "dynamic update" : "all routes", 8347b6ab19dSGarrett Wollman rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0); 8357b6ab19dSGarrett Wollman 83638ae6523SPoul-Henning Kamp LIST_FOREACH(ifp, &ifnet, int_list) { 837d5b718b3SGarrett Wollman /* Skip interfaces not doing RIP. 838d5b718b3SGarrett Wollman * Do try broken interfaces to see if they have healed. 8397b6ab19dSGarrett Wollman */ 840d5b718b3SGarrett Wollman if (IS_RIP_OUT_OFF(ifp->int_state)) 8417b6ab19dSGarrett Wollman continue; 8427b6ab19dSGarrett Wollman 8437b6ab19dSGarrett Wollman /* skip turned off interfaces */ 8442c7a9781SMark Murray if (!iff_up(ifp->int_if_flags)) 8457b6ab19dSGarrett Wollman continue; 8467b6ab19dSGarrett Wollman 847d5b718b3SGarrett Wollman vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; 8487b6ab19dSGarrett Wollman 8497b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_BROADCAST) { 8507b6ab19dSGarrett Wollman /* ordinary, hardware interface */ 8517b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_brdaddr; 852d5b718b3SGarrett Wollman 8537b6ab19dSGarrett Wollman if (vers == RIPv2 8542c7a9781SMark Murray && !(ifp->int_state & IS_NO_RIP_MCAST)) { 8557b6ab19dSGarrett Wollman type = OUT_MULTICAST; 8567b6ab19dSGarrett Wollman } else { 8577b6ab19dSGarrett Wollman type = OUT_BROADCAST; 8587b6ab19dSGarrett Wollman } 8597b6ab19dSGarrett Wollman 8607b6ab19dSGarrett Wollman } else if (ifp->int_if_flags & IFF_POINTOPOINT) { 8617b6ab19dSGarrett Wollman /* point-to-point hardware interface */ 8627b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_dstaddr; 863c2aabe68SPoul-Henning Kamp if (vers == RIPv2 && 864c2aabe68SPoul-Henning Kamp ifp->int_if_flags & IFF_MULTICAST && 865c2aabe68SPoul-Henning Kamp !(ifp->int_state & IS_NO_RIP_MCAST)) { 866c2aabe68SPoul-Henning Kamp type = OUT_MULTICAST; 867c2aabe68SPoul-Henning Kamp } else { 8687b6ab19dSGarrett Wollman type = OUT_UNICAST; 869c2aabe68SPoul-Henning Kamp } 8707b6ab19dSGarrett Wollman 871d5b718b3SGarrett Wollman } else if (ifp->int_state & IS_REMOTE) { 8727b6ab19dSGarrett Wollman /* remote interface */ 8737b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_addr; 8747b6ab19dSGarrett Wollman type = OUT_UNICAST; 875d5b718b3SGarrett Wollman 876d5b718b3SGarrett Wollman } else { 877d5b718b3SGarrett Wollman /* ATM, HIPPI, etc. */ 878d5b718b3SGarrett Wollman continue; 8797b6ab19dSGarrett Wollman } 8807b6ab19dSGarrett Wollman 881d5b718b3SGarrett Wollman supply(&dst, ifp, type, flash, vers, 1); 8827b6ab19dSGarrett Wollman } 8837b6ab19dSGarrett Wollman 8847b6ab19dSGarrett Wollman update_seqno++; /* all routes are up to date */ 8857b6ab19dSGarrett Wollman } 8867b6ab19dSGarrett Wollman 8877b6ab19dSGarrett Wollman 8887b6ab19dSGarrett Wollman /* Ask for routes 8897b6ab19dSGarrett Wollman * Do it only once to an interface, and not even after the interface 8907b6ab19dSGarrett Wollman * was broken and recovered. 8917b6ab19dSGarrett Wollman */ 8927b6ab19dSGarrett Wollman void 8937b6ab19dSGarrett Wollman rip_query(void) 8947b6ab19dSGarrett Wollman { 8957b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 896f7434bbdSSheldon Hearn static struct sockaddr_in dst = {sizeof(dst), AF_INET, 0, {0}, {0}}; 8977b6ab19dSGarrett Wollman #else 8987b6ab19dSGarrett Wollman static struct sockaddr_in dst = {AF_INET}; 8997b6ab19dSGarrett Wollman #endif 9007b6ab19dSGarrett Wollman struct interface *ifp; 9017b6ab19dSGarrett Wollman struct rip buf; 9027b6ab19dSGarrett Wollman enum output_type type; 9037b6ab19dSGarrett Wollman 9047b6ab19dSGarrett Wollman 9057b6ab19dSGarrett Wollman if (rip_sock < 0) 9067b6ab19dSGarrett Wollman return; 9077b6ab19dSGarrett Wollman 9082c7a9781SMark Murray memset(&buf, 0, sizeof(buf)); 9097b6ab19dSGarrett Wollman 91038ae6523SPoul-Henning Kamp LIST_FOREACH(ifp, &ifnet, int_list) { 911d5b718b3SGarrett Wollman /* Skip interfaces those already queried. 912d5b718b3SGarrett Wollman * Do not ask via interfaces through which we don't 913d5b718b3SGarrett Wollman * accept input. Do not ask via interfaces that cannot 914d5b718b3SGarrett Wollman * send RIP packets. 915d5b718b3SGarrett Wollman * Do try broken interfaces to see if they have healed. 9167b6ab19dSGarrett Wollman */ 917d5b718b3SGarrett Wollman if (IS_RIP_IN_OFF(ifp->int_state) 918d5b718b3SGarrett Wollman || ifp->int_query_time != NEVER) 9197b6ab19dSGarrett Wollman continue; 9207b6ab19dSGarrett Wollman 9217b6ab19dSGarrett Wollman /* skip turned off interfaces */ 9222c7a9781SMark Murray if (!iff_up(ifp->int_if_flags)) 9237b6ab19dSGarrett Wollman continue; 9247b6ab19dSGarrett Wollman 925d5b718b3SGarrett Wollman buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1; 9267b6ab19dSGarrett Wollman buf.rip_cmd = RIPCMD_REQUEST; 9277b6ab19dSGarrett Wollman buf.rip_nets[0].n_family = RIP_AF_UNSPEC; 9287b6ab19dSGarrett Wollman buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 9297b6ab19dSGarrett Wollman 9302c7a9781SMark Murray /* Send a RIPv1 query only if allowed and if we will 9312c7a9781SMark Murray * listen to RIPv1 routers. 9322c7a9781SMark Murray */ 9332c7a9781SMark Murray if ((ifp->int_state & IS_NO_RIPV1_OUT) 9342c7a9781SMark Murray || (ifp->int_state & IS_NO_RIPV1_IN)) { 9352c7a9781SMark Murray buf.rip_vers = RIPv2; 9362c7a9781SMark Murray } else { 9372c7a9781SMark Murray buf.rip_vers = RIPv1; 9382c7a9781SMark Murray } 9392c7a9781SMark Murray 9407b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_BROADCAST) { 9417b6ab19dSGarrett Wollman /* ordinary, hardware interface */ 9427b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_brdaddr; 9432c7a9781SMark Murray 9442c7a9781SMark Murray /* Broadcast RIPv1 queries and RIPv2 queries 9452c7a9781SMark Murray * when the hardware cannot multicast. 9467b6ab19dSGarrett Wollman */ 9477b6ab19dSGarrett Wollman if (buf.rip_vers == RIPv2 9482c7a9781SMark Murray && (ifp->int_if_flags & IFF_MULTICAST) 9492c7a9781SMark Murray && !(ifp->int_state & IS_NO_RIP_MCAST)) { 9507b6ab19dSGarrett Wollman type = OUT_MULTICAST; 9517b6ab19dSGarrett Wollman } else { 9527b6ab19dSGarrett Wollman type = OUT_BROADCAST; 9537b6ab19dSGarrett Wollman } 9547b6ab19dSGarrett Wollman 9557b6ab19dSGarrett Wollman } else if (ifp->int_if_flags & IFF_POINTOPOINT) { 9567b6ab19dSGarrett Wollman /* point-to-point hardware interface */ 9577b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_dstaddr; 9587b6ab19dSGarrett Wollman type = OUT_UNICAST; 9597b6ab19dSGarrett Wollman 960d5b718b3SGarrett Wollman } else if (ifp->int_state & IS_REMOTE) { 9617b6ab19dSGarrett Wollman /* remote interface */ 9627b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_addr; 9637b6ab19dSGarrett Wollman type = OUT_UNICAST; 964d5b718b3SGarrett Wollman 965d5b718b3SGarrett Wollman } else { 966d5b718b3SGarrett Wollman /* ATM, HIPPI, etc. */ 967d5b718b3SGarrett Wollman continue; 9687b6ab19dSGarrett Wollman } 9697b6ab19dSGarrett Wollman 970d5b718b3SGarrett Wollman ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL; 9717b6ab19dSGarrett Wollman if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0) 9727b6ab19dSGarrett Wollman if_sick(ifp); 9737b6ab19dSGarrett Wollman } 9747b6ab19dSGarrett Wollman } 975