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 * 3. All advertising materials mentioning features or use of this software 142c7a9781SMark Murray * must display the following acknowledgment: 157b6ab19dSGarrett Wollman * This product includes software developed by the University of 167b6ab19dSGarrett Wollman * California, Berkeley and its contributors. 177b6ab19dSGarrett Wollman * 4. Neither the name of the University nor the names of its contributors 187b6ab19dSGarrett Wollman * may be used to endorse or promote products derived from this software 197b6ab19dSGarrett Wollman * without specific prior written permission. 207b6ab19dSGarrett Wollman * 217b6ab19dSGarrett Wollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 227b6ab19dSGarrett Wollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 237b6ab19dSGarrett Wollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 247b6ab19dSGarrett Wollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 257b6ab19dSGarrett Wollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 267b6ab19dSGarrett Wollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 277b6ab19dSGarrett Wollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 287b6ab19dSGarrett Wollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 297b6ab19dSGarrett Wollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 307b6ab19dSGarrett Wollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 317b6ab19dSGarrett Wollman * SUCH DAMAGE. 327b6ab19dSGarrett Wollman */ 337b6ab19dSGarrett Wollman 347b6ab19dSGarrett Wollman #include "defs.h" 357b6ab19dSGarrett Wollman 362c7a9781SMark Murray #if !defined(sgi) && !defined(__NetBSD__) 372c7a9781SMark Murray static char sccsid[] __attribute__((unused)) = "@(#)output.c 8.1 (Berkeley) 6/5/93"; 382c7a9781SMark Murray #elif defined(__NetBSD__) 392c7a9781SMark Murray __RCSID("$NetBSD$"); 402c7a9781SMark Murray #endif 412c7a9781SMark Murray #ident "$Revision: 2.17 $" 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 { 1037b6ab19dSGarrett Wollman struct sockaddr_in sin; 1047b6ab19dSGarrett Wollman int flags; 1052c7a9781SMark Murray const char *msg; 1067b6ab19dSGarrett Wollman int res; 1077b6ab19dSGarrett Wollman naddr tgt_mcast; 1087b6ab19dSGarrett Wollman int soc; 1097b6ab19dSGarrett Wollman int serrno; 1107b6ab19dSGarrett Wollman 1117b6ab19dSGarrett Wollman sin = *dst; 1127b6ab19dSGarrett Wollman if (sin.sin_port == 0) 1137b6ab19dSGarrett Wollman sin.sin_port = htons(RIP_PORT); 1147b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 1157b6ab19dSGarrett Wollman if (sin.sin_len == 0) 1167b6ab19dSGarrett Wollman sin.sin_len = sizeof(sin); 1177b6ab19dSGarrett Wollman #endif 1187b6ab19dSGarrett Wollman 1197b6ab19dSGarrett Wollman soc = rip_sock; 1207b6ab19dSGarrett Wollman flags = 0; 1217b6ab19dSGarrett Wollman 1227b6ab19dSGarrett Wollman switch (type) { 1237b6ab19dSGarrett Wollman case OUT_QUERY: 1247b6ab19dSGarrett Wollman msg = "Answer Query"; 1257b6ab19dSGarrett Wollman if (soc < 0) 1267b6ab19dSGarrett Wollman soc = ifp->int_rip_sock; 1277b6ab19dSGarrett Wollman break; 1287b6ab19dSGarrett Wollman case OUT_UNICAST: 1297b6ab19dSGarrett Wollman msg = "Send"; 1307b6ab19dSGarrett Wollman if (soc < 0) 1317b6ab19dSGarrett Wollman soc = ifp->int_rip_sock; 1327b6ab19dSGarrett Wollman flags = MSG_DONTROUTE; 1337b6ab19dSGarrett Wollman break; 1347b6ab19dSGarrett Wollman case OUT_BROADCAST: 1357b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 1367b6ab19dSGarrett Wollman msg = "Send"; 1377b6ab19dSGarrett Wollman } else { 1387b6ab19dSGarrett Wollman msg = "Send bcast"; 1397b6ab19dSGarrett Wollman } 1407b6ab19dSGarrett Wollman flags = MSG_DONTROUTE; 1417b6ab19dSGarrett Wollman break; 1427b6ab19dSGarrett Wollman case OUT_MULTICAST: 1437b6ab19dSGarrett Wollman if (ifp->int_if_flags & 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) { 1537b6ab19dSGarrett Wollman #ifdef MCAST_PPP_BUG 1542c7a9781SMark Murray /* Do not specify the primary interface 1557b6ab19dSGarrett Wollman * explicitly if we have the multicast 1567b6ab19dSGarrett Wollman * point-to-point kernel bug, since the 1577b6ab19dSGarrett Wollman * kernel will do the wrong thing if the 1587b6ab19dSGarrett Wollman * local address of a point-to-point link 1597b6ab19dSGarrett Wollman * is the same as the address of an ordinary 1607b6ab19dSGarrett Wollman * interface. 1617b6ab19dSGarrett Wollman */ 1627b6ab19dSGarrett Wollman if (ifp->int_addr == myaddr) { 1637b6ab19dSGarrett Wollman tgt_mcast = 0; 1647b6ab19dSGarrett Wollman } else 1657b6ab19dSGarrett Wollman #endif 1667b6ab19dSGarrett Wollman tgt_mcast = ifp->int_addr; 1677b6ab19dSGarrett Wollman if (0 > setsockopt(rip_sock, 1687b6ab19dSGarrett Wollman IPPROTO_IP, IP_MULTICAST_IF, 1697b6ab19dSGarrett Wollman &tgt_mcast, 1707b6ab19dSGarrett Wollman sizeof(tgt_mcast))) { 1717b6ab19dSGarrett Wollman serrno = errno; 1727b6ab19dSGarrett Wollman LOGERR("setsockopt(rip_sock," 1737b6ab19dSGarrett Wollman "IP_MULTICAST_IF)"); 1747b6ab19dSGarrett Wollman errno = serrno; 1757b6ab19dSGarrett Wollman ifp = 0; 1767b6ab19dSGarrett Wollman return -1; 1777b6ab19dSGarrett Wollman } 1787b6ab19dSGarrett Wollman rip_sock_mcast = ifp; 1797b6ab19dSGarrett Wollman } 1807b6ab19dSGarrett Wollman sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); 1817b6ab19dSGarrett Wollman } 18271965874SGarrett Wollman break; 1837b6ab19dSGarrett Wollman 1847b6ab19dSGarrett Wollman case NO_OUT_MULTICAST: 1857b6ab19dSGarrett Wollman case NO_OUT_RIPV2: 18671965874SGarrett Wollman default: 18771965874SGarrett Wollman #ifdef DEBUG 18871965874SGarrett Wollman abort(); 18971965874SGarrett Wollman #endif 19071965874SGarrett Wollman return -1; 1917b6ab19dSGarrett Wollman } 1927b6ab19dSGarrett Wollman 1937b6ab19dSGarrett Wollman trace_rip(msg, "to", &sin, ifp, buf, size); 1947b6ab19dSGarrett Wollman 1957b6ab19dSGarrett Wollman res = sendto(soc, buf, size, flags, 1967b6ab19dSGarrett Wollman (struct sockaddr *)&sin, sizeof(sin)); 1977b6ab19dSGarrett Wollman if (res < 0 1987b6ab19dSGarrett Wollman && (ifp == 0 || !(ifp->int_state & IS_BROKE))) { 1997b6ab19dSGarrett Wollman serrno = errno; 2007b6ab19dSGarrett Wollman msglog("%s sendto(%s%s%s.%d): %s", msg, 2017b6ab19dSGarrett Wollman ifp != 0 ? ifp->int_name : "", 2027b6ab19dSGarrett Wollman ifp != 0 ? ", " : "", 2037b6ab19dSGarrett Wollman inet_ntoa(sin.sin_addr), 2047b6ab19dSGarrett Wollman ntohs(sin.sin_port), 2057b6ab19dSGarrett Wollman strerror(errno)); 2067b6ab19dSGarrett Wollman errno = serrno; 2077b6ab19dSGarrett Wollman } 2087b6ab19dSGarrett Wollman 2097b6ab19dSGarrett Wollman return res; 2107b6ab19dSGarrett Wollman } 2117b6ab19dSGarrett Wollman 2127b6ab19dSGarrett Wollman 21371965874SGarrett Wollman /* Find the first key for a packet to send. 2142c7a9781SMark Murray * Try for a key that is eligible and has not expired, but settle for 215d5b718b3SGarrett Wollman * the last key if they have all expired. 216d5b718b3SGarrett Wollman * If no key is ready yet, give up. 217d5b718b3SGarrett Wollman */ 21871965874SGarrett Wollman struct auth * 219d5b718b3SGarrett Wollman find_auth(struct interface *ifp) 220d5b718b3SGarrett Wollman { 22171965874SGarrett Wollman struct auth *ap, *res; 222d5b718b3SGarrett Wollman int i; 223d5b718b3SGarrett Wollman 224d5b718b3SGarrett Wollman 22571965874SGarrett Wollman if (ifp == 0) 226d5b718b3SGarrett Wollman return 0; 227d5b718b3SGarrett Wollman 228d5b718b3SGarrett Wollman res = 0; 22971965874SGarrett Wollman ap = ifp->int_auth; 230d5b718b3SGarrett Wollman for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) { 23171965874SGarrett Wollman /* stop looking after the last key */ 23271965874SGarrett Wollman if (ap->type == RIP_AUTH_NONE) 23371965874SGarrett Wollman break; 23471965874SGarrett Wollman 23571965874SGarrett Wollman /* ignore keys that are not ready yet */ 23671965874SGarrett Wollman if ((u_long)ap->start > (u_long)clk.tv_sec) 23771965874SGarrett Wollman continue; 23871965874SGarrett Wollman 23971965874SGarrett Wollman if ((u_long)ap->end < (u_long)clk.tv_sec) { 24071965874SGarrett Wollman /* note best expired password as a fall-back */ 24171965874SGarrett Wollman if (res == 0 || (u_long)ap->end > (u_long)res->end) 242d5b718b3SGarrett Wollman res = ap; 24371965874SGarrett Wollman continue; 244d5b718b3SGarrett Wollman } 24571965874SGarrett Wollman 24671965874SGarrett Wollman /* note key with the best future */ 24771965874SGarrett Wollman if (res == 0 || (u_long)res->end < (u_long)ap->end) 24871965874SGarrett Wollman res = ap; 249d5b718b3SGarrett Wollman } 250d5b718b3SGarrett Wollman return res; 251d5b718b3SGarrett Wollman } 252d5b718b3SGarrett Wollman 253d5b718b3SGarrett Wollman 254d5b718b3SGarrett Wollman void 255d5b718b3SGarrett Wollman clr_ws_buf(struct ws_buf *wb, 25671965874SGarrett Wollman struct auth *ap) 257d5b718b3SGarrett Wollman { 258d5b718b3SGarrett Wollman struct netauth *na; 259d5b718b3SGarrett Wollman 260d5b718b3SGarrett Wollman wb->lim = wb->base + NETS_LEN; 261d5b718b3SGarrett Wollman wb->n = wb->base; 2622c7a9781SMark Murray memset(wb->n, 0, NETS_LEN*sizeof(*wb->n)); 263d5b718b3SGarrett Wollman 2642c7a9781SMark Murray /* (start to) install authentication if appropriate 2657b6ab19dSGarrett Wollman */ 266d5b718b3SGarrett Wollman if (ap == 0) 267d5b718b3SGarrett Wollman return; 2682c7a9781SMark Murray 269d5b718b3SGarrett Wollman na = (struct netauth*)wb->n; 27071965874SGarrett Wollman if (ap->type == RIP_AUTH_PW) { 271d5b718b3SGarrett Wollman na->a_family = RIP_AF_AUTH; 272d5b718b3SGarrett Wollman na->a_type = RIP_AUTH_PW; 2732c7a9781SMark Murray memcpy(na->au.au_pw, ap->key, sizeof(na->au.au_pw)); 274d5b718b3SGarrett Wollman wb->n++; 275d5b718b3SGarrett Wollman 27671965874SGarrett Wollman } else if (ap->type == RIP_AUTH_MD5) { 277d5b718b3SGarrett Wollman na->a_family = RIP_AF_AUTH; 278d5b718b3SGarrett Wollman na->a_type = RIP_AUTH_MD5; 279d5b718b3SGarrett Wollman na->au.a_md5.md5_keyid = ap->keyid; 2802c7a9781SMark Murray na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; 2812c7a9781SMark Murray na->au.a_md5.md5_seqno = htonl(clk.tv_sec); 282d5b718b3SGarrett Wollman wb->n++; 283d5b718b3SGarrett Wollman wb->lim--; /* make room for trailer */ 2847b6ab19dSGarrett Wollman } 2857b6ab19dSGarrett Wollman } 2867b6ab19dSGarrett Wollman 2877b6ab19dSGarrett Wollman 288d5b718b3SGarrett Wollman void 289d5b718b3SGarrett Wollman end_md5_auth(struct ws_buf *wb, 29071965874SGarrett Wollman struct auth *ap) 291d5b718b3SGarrett Wollman { 292d5b718b3SGarrett Wollman struct netauth *na, *na2; 293d5b718b3SGarrett Wollman MD5_CTX md5_ctx; 2942c7a9781SMark Murray int len; 295d5b718b3SGarrett Wollman 296d5b718b3SGarrett Wollman 297d5b718b3SGarrett Wollman na = (struct netauth*)wb->base; 298d5b718b3SGarrett Wollman na2 = (struct netauth*)wb->n; 2992c7a9781SMark Murray len = (char *)na2-(char *)wb->buf; 300d5b718b3SGarrett Wollman na2->a_family = RIP_AF_AUTH; 3012c7a9781SMark Murray na2->a_type = htons(1); 3022c7a9781SMark Murray na->au.a_md5.md5_pkt_len = htons(len); 303d5b718b3SGarrett Wollman MD5Init(&md5_ctx); 3042c7a9781SMark Murray MD5Update(&md5_ctx, (u_char *)wb->buf, len); 3052c7a9781SMark Murray MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_LEN); 306d5b718b3SGarrett Wollman MD5Final(na2->au.au_pw, &md5_ctx); 307d5b718b3SGarrett Wollman wb->n++; 308d5b718b3SGarrett Wollman } 309d5b718b3SGarrett Wollman 310d5b718b3SGarrett Wollman 3117b6ab19dSGarrett Wollman /* Send the buffer 3127b6ab19dSGarrett Wollman */ 3137b6ab19dSGarrett Wollman static void 3147b6ab19dSGarrett Wollman supply_write(struct ws_buf *wb) 3157b6ab19dSGarrett Wollman { 3167b6ab19dSGarrett Wollman /* Output multicast only if legal. 3172c7a9781SMark Murray * If we would multicast and it would be illegal, then discard the 3187b6ab19dSGarrett Wollman * packet. 3197b6ab19dSGarrett Wollman */ 3207b6ab19dSGarrett Wollman switch (wb->type) { 3217b6ab19dSGarrett Wollman case NO_OUT_MULTICAST: 322d5b718b3SGarrett Wollman trace_pkt("skip multicast to %s because impossible", 3237b6ab19dSGarrett Wollman naddr_ntoa(ws.to.sin_addr.s_addr)); 3247b6ab19dSGarrett Wollman break; 3257b6ab19dSGarrett Wollman case NO_OUT_RIPV2: 3267b6ab19dSGarrett Wollman break; 3277b6ab19dSGarrett Wollman default: 32871965874SGarrett Wollman if (ws.a != 0 && ws.a->type == RIP_AUTH_MD5) 329d5b718b3SGarrett Wollman end_md5_auth(wb,ws.a); 3307b6ab19dSGarrett Wollman if (output(wb->type, &ws.to, ws.ifp, wb->buf, 3317b6ab19dSGarrett Wollman ((char *)wb->n - (char*)wb->buf)) < 0 3327b6ab19dSGarrett Wollman && ws.ifp != 0) 3337b6ab19dSGarrett Wollman if_sick(ws.ifp); 3347b6ab19dSGarrett Wollman ws.npackets++; 3357b6ab19dSGarrett Wollman break; 3367b6ab19dSGarrett Wollman } 3377b6ab19dSGarrett Wollman 33871965874SGarrett Wollman clr_ws_buf(wb,ws.a); 3397b6ab19dSGarrett Wollman } 3407b6ab19dSGarrett Wollman 3417b6ab19dSGarrett Wollman 3427b6ab19dSGarrett Wollman /* put an entry into the packet 3437b6ab19dSGarrett Wollman */ 3447b6ab19dSGarrett Wollman static void 3457b6ab19dSGarrett Wollman supply_out(struct ag_info *ag) 3467b6ab19dSGarrett Wollman { 3477b6ab19dSGarrett Wollman int i; 34871965874SGarrett Wollman naddr mask, v1_mask, dst_h, ddst_h = 0; 3497b6ab19dSGarrett Wollman struct ws_buf *wb; 3507b6ab19dSGarrett Wollman 3517b6ab19dSGarrett Wollman 3527b6ab19dSGarrett Wollman /* Skip this route if doing a flash update and it and the routes 3537b6ab19dSGarrett Wollman * it aggregates have not changed recently. 3547b6ab19dSGarrett Wollman */ 3557b6ab19dSGarrett Wollman if (ag->ag_seqno < update_seqno 3567b6ab19dSGarrett Wollman && (ws.state & WS_ST_FLASH)) 3577b6ab19dSGarrett Wollman return; 3587b6ab19dSGarrett Wollman 3597b6ab19dSGarrett Wollman dst_h = ag->ag_dst_h; 3607b6ab19dSGarrett Wollman mask = ag->ag_mask; 3617b6ab19dSGarrett Wollman v1_mask = ripv1_mask_host(htonl(dst_h), 3627b6ab19dSGarrett Wollman (ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0); 3637b6ab19dSGarrett Wollman i = 0; 3647b6ab19dSGarrett Wollman 3657b6ab19dSGarrett Wollman /* If we are sending RIPv2 packets that cannot (or must not) be 3667b6ab19dSGarrett Wollman * heard by RIPv1 listeners, do not worry about sub- or supernets. 3677b6ab19dSGarrett Wollman * Subnets (from other networks) can only be sent via multicast. 3687b6ab19dSGarrett Wollman * A pair of subnet routes might have been promoted so that they 3697b6ab19dSGarrett Wollman * are legal to send by RIPv1. 370d5b718b3SGarrett Wollman * If RIPv1 is off, use the multicast buffer. 3717b6ab19dSGarrett Wollman */ 372d5b718b3SGarrett Wollman if ((ws.state & WS_ST_RIP2_ALL) 3737b6ab19dSGarrett Wollman || ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) { 3747b6ab19dSGarrett Wollman /* use the RIPv2-only buffer */ 375d5b718b3SGarrett Wollman wb = &v2buf; 3767b6ab19dSGarrett Wollman 3777b6ab19dSGarrett Wollman } else { 3787b6ab19dSGarrett Wollman /* use the RIPv1-or-RIPv2 buffer */ 379d5b718b3SGarrett Wollman wb = &v12buf; 3807b6ab19dSGarrett Wollman 3817b6ab19dSGarrett Wollman /* Convert supernet route into corresponding set of network 3827b6ab19dSGarrett Wollman * routes for RIPv1, but leave non-contiguous netmasks 3837b6ab19dSGarrett Wollman * to ag_check(). 3847b6ab19dSGarrett Wollman */ 3857b6ab19dSGarrett Wollman if (v1_mask > mask 3867b6ab19dSGarrett Wollman && mask + (mask & -mask) == 0) { 3877b6ab19dSGarrett Wollman ddst_h = v1_mask & -v1_mask; 3887b6ab19dSGarrett Wollman i = (v1_mask & ~mask)/ddst_h; 3897b6ab19dSGarrett Wollman 3907b6ab19dSGarrett Wollman if (i > ws.gen_limit) { 3917b6ab19dSGarrett Wollman /* Punt if we would have to generate an 3927b6ab19dSGarrett Wollman * unreasonable number of routes. 3937b6ab19dSGarrett Wollman */ 3942c7a9781SMark Murray if (TRACECONTENTS) 3952c7a9781SMark Murray trace_misc("sending %s-->%s as 1" 3962c7a9781SMark Murray " instead of %d routes", 3972c7a9781SMark Murray addrname(htonl(dst_h), mask, 3982c7a9781SMark Murray 1), 3992c7a9781SMark Murray naddr_ntoa(ws.to.sin_addr 4002c7a9781SMark Murray .s_addr), 4017b6ab19dSGarrett Wollman i+1); 4027b6ab19dSGarrett Wollman i = 0; 4037b6ab19dSGarrett Wollman 4047b6ab19dSGarrett Wollman } else { 4057b6ab19dSGarrett Wollman mask = v1_mask; 4067b6ab19dSGarrett Wollman ws.gen_limit -= i; 4077b6ab19dSGarrett Wollman } 4087b6ab19dSGarrett Wollman } 4097b6ab19dSGarrett Wollman } 4107b6ab19dSGarrett Wollman 4117b6ab19dSGarrett Wollman do { 4127b6ab19dSGarrett Wollman wb->n->n_family = RIP_AF_INET; 4137b6ab19dSGarrett Wollman wb->n->n_dst = htonl(dst_h); 4147b6ab19dSGarrett Wollman /* If the route is from router-discovery or we are 4157b6ab19dSGarrett Wollman * shutting down, admit only a bad metric. 4167b6ab19dSGarrett Wollman */ 4177b6ab19dSGarrett Wollman wb->n->n_metric = ((stopint || ag->ag_metric < 1) 4187b6ab19dSGarrett Wollman ? HOPCNT_INFINITY 4197b6ab19dSGarrett Wollman : ag->ag_metric); 4207b6ab19dSGarrett Wollman HTONL(wb->n->n_metric); 421d5b718b3SGarrett Wollman /* Any non-zero bits in the supposedly unused RIPv1 fields 422d5b718b3SGarrett Wollman * cause the old `routed` to ignore the route. 423d5b718b3SGarrett Wollman * That means the mask and so forth cannot be sent 424d5b718b3SGarrett Wollman * in the hybrid RIPv1/RIPv2 mode. 425d5b718b3SGarrett Wollman */ 426d5b718b3SGarrett Wollman if (ws.state & WS_ST_RIP2_ALL) { 4277b6ab19dSGarrett Wollman if (ag->ag_nhop != 0 4287b6ab19dSGarrett Wollman && ((ws.state & WS_ST_QUERY) 4297b6ab19dSGarrett Wollman || (ag->ag_nhop != ws.ifp->int_addr 4307b6ab19dSGarrett Wollman && on_net(ag->ag_nhop, 4317b6ab19dSGarrett Wollman ws.ifp->int_net, 4327b6ab19dSGarrett Wollman ws.ifp->int_mask)))) 4337b6ab19dSGarrett Wollman wb->n->n_nhop = ag->ag_nhop; 4347b6ab19dSGarrett Wollman wb->n->n_mask = htonl(mask); 4357b6ab19dSGarrett Wollman wb->n->n_tag = ag->ag_tag; 4367b6ab19dSGarrett Wollman } 4377b6ab19dSGarrett Wollman dst_h += ddst_h; 4387b6ab19dSGarrett Wollman 4397b6ab19dSGarrett Wollman if (++wb->n >= wb->lim) 4407b6ab19dSGarrett Wollman supply_write(wb); 4417b6ab19dSGarrett Wollman } while (i-- != 0); 4427b6ab19dSGarrett Wollman } 4437b6ab19dSGarrett Wollman 4447b6ab19dSGarrett Wollman 4457b6ab19dSGarrett Wollman /* supply one route from the table 4467b6ab19dSGarrett Wollman */ 4477b6ab19dSGarrett Wollman /* ARGSUSED */ 4487b6ab19dSGarrett Wollman static int 4497b6ab19dSGarrett Wollman walk_supply(struct radix_node *rn, 4502c7a9781SMark Murray struct walkarg *argp UNUSED) 4517b6ab19dSGarrett Wollman { 4527b6ab19dSGarrett Wollman #define RT ((struct rt_entry *)rn) 4537b6ab19dSGarrett Wollman u_short ags; 4547b6ab19dSGarrett Wollman char metric, pref; 4557b6ab19dSGarrett Wollman naddr dst, nhop; 4562c7a9781SMark Murray struct rt_spare *rts; 4572c7a9781SMark Murray int i; 4587b6ab19dSGarrett Wollman 4597b6ab19dSGarrett Wollman 460d5b718b3SGarrett Wollman /* Do not advertise external remote interfaces or passive interfaces. 4617b6ab19dSGarrett Wollman */ 4627b6ab19dSGarrett Wollman if ((RT->rt_state & RS_IF) 4637b6ab19dSGarrett Wollman && RT->rt_ifp != 0 464d5b718b3SGarrett Wollman && (RT->rt_ifp->int_if_flags & IS_PASSIVE) 4657b6ab19dSGarrett Wollman && !(RT->rt_state & RS_MHOME)) 4667b6ab19dSGarrett Wollman return 0; 4677b6ab19dSGarrett Wollman 4687b6ab19dSGarrett Wollman /* If being quiet about our ability to forward, then 469d5b718b3SGarrett Wollman * do not say anything unless responding to a query, 470d5b718b3SGarrett Wollman * except about our main interface. 4717b6ab19dSGarrett Wollman */ 472d5b718b3SGarrett Wollman if (!supplier && !(ws.state & WS_ST_QUERY) 473d5b718b3SGarrett Wollman && !(RT->rt_state & RS_MHOME)) 4747b6ab19dSGarrett Wollman return 0; 4757b6ab19dSGarrett Wollman 4767b6ab19dSGarrett Wollman dst = RT->rt_dst; 4777b6ab19dSGarrett Wollman 4787b6ab19dSGarrett Wollman /* do not collide with the fake default route */ 4797b6ab19dSGarrett Wollman if (dst == RIP_DEFAULT 4807b6ab19dSGarrett Wollman && (ws.state & WS_ST_DEFAULT)) 4817b6ab19dSGarrett Wollman return 0; 4827b6ab19dSGarrett Wollman 4837b6ab19dSGarrett Wollman if (RT->rt_state & RS_NET_SYN) { 4847b6ab19dSGarrett Wollman if (RT->rt_state & RS_NET_INT) { 4857b6ab19dSGarrett Wollman /* Do not send manual synthetic network routes 4867b6ab19dSGarrett Wollman * into the subnet. 4877b6ab19dSGarrett Wollman */ 4887b6ab19dSGarrett Wollman if (on_net(ws.to.sin_addr.s_addr, 4897b6ab19dSGarrett Wollman ntohl(dst), RT->rt_mask)) 4907b6ab19dSGarrett Wollman return 0; 4917b6ab19dSGarrett Wollman 4927b6ab19dSGarrett Wollman } else { 4937b6ab19dSGarrett Wollman /* Do not send automatic synthetic network routes 4942c7a9781SMark Murray * if they are not needed because no RIPv1 listeners 4957b6ab19dSGarrett Wollman * can hear them. 4967b6ab19dSGarrett Wollman */ 4977b6ab19dSGarrett Wollman if (ws.state & WS_ST_RIP2_ALL) 4987b6ab19dSGarrett Wollman return 0; 4997b6ab19dSGarrett Wollman 5007b6ab19dSGarrett Wollman /* Do not send automatic synthetic network routes to 5017b6ab19dSGarrett Wollman * the real subnet. 5027b6ab19dSGarrett Wollman */ 5037b6ab19dSGarrett Wollman if (on_net(ws.to.sin_addr.s_addr, 5047b6ab19dSGarrett Wollman ntohl(dst), RT->rt_mask)) 5057b6ab19dSGarrett Wollman return 0; 5067b6ab19dSGarrett Wollman } 5077b6ab19dSGarrett Wollman nhop = 0; 5087b6ab19dSGarrett Wollman 5097b6ab19dSGarrett Wollman } else { 5107b6ab19dSGarrett Wollman /* Advertise the next hop if this is not a route for one 5117b6ab19dSGarrett Wollman * of our interfaces and the next hop is on the same 5127b6ab19dSGarrett Wollman * network as the target. 5132c7a9781SMark Murray * The final determination is made by supply_out(). 5147b6ab19dSGarrett Wollman */ 5157b6ab19dSGarrett Wollman if (!(RT->rt_state & RS_IF) 5167b6ab19dSGarrett Wollman && RT->rt_gate != myaddr 5177b6ab19dSGarrett Wollman && RT->rt_gate != loopaddr) 5187b6ab19dSGarrett Wollman nhop = RT->rt_gate; 5197b6ab19dSGarrett Wollman else 5207b6ab19dSGarrett Wollman nhop = 0; 5217b6ab19dSGarrett Wollman } 5227b6ab19dSGarrett Wollman 5237b6ab19dSGarrett Wollman metric = RT->rt_metric; 5247b6ab19dSGarrett Wollman ags = 0; 5257b6ab19dSGarrett Wollman 5267b6ab19dSGarrett Wollman if (RT->rt_state & RS_MHOME) { 5277b6ab19dSGarrett Wollman /* retain host route of multi-homed servers */ 5287b6ab19dSGarrett Wollman ; 5297b6ab19dSGarrett Wollman 5307b6ab19dSGarrett Wollman } else if (RT_ISHOST(RT)) { 5312c7a9781SMark Murray /* We should always suppress (into existing network routes) 5322c7a9781SMark Murray * the host routes for the local end of our point-to-point 5332c7a9781SMark Murray * links. 5347b6ab19dSGarrett Wollman * If we are suppressing host routes in general, then do so. 5357b6ab19dSGarrett Wollman * Avoid advertising host routes onto their own network, 5367b6ab19dSGarrett Wollman * where they should be handled by proxy-ARP. 5377b6ab19dSGarrett Wollman */ 5387b6ab19dSGarrett Wollman if ((RT->rt_state & RS_LOCAL) 5397b6ab19dSGarrett Wollman || ridhosts 5407b6ab19dSGarrett Wollman || on_net(dst, ws.to_net, ws.to_mask)) 5417b6ab19dSGarrett Wollman ags |= AGS_SUPPRESS; 5427b6ab19dSGarrett Wollman 5432c7a9781SMark Murray /* Aggregate stray host routes into network routes if allowed. 5442c7a9781SMark Murray * We cannot aggregate host routes into small network routes 5452c7a9781SMark Murray * without confusing RIPv1 listeners into thinking the 5462c7a9781SMark Murray * network routes are host routes. 5472c7a9781SMark Murray */ 5482c7a9781SMark Murray if ((ws.state & WS_ST_AG) 5492c7a9781SMark Murray && !(ws.state & WS_ST_RIP2_ALL)) 5502c7a9781SMark Murray ags |= AGS_AGGREGATE; 5517b6ab19dSGarrett Wollman 5522c7a9781SMark Murray } else { 5532c7a9781SMark Murray /* Always suppress network routes into other, existing 5542c7a9781SMark Murray * network routes 5557b6ab19dSGarrett Wollman */ 5567b6ab19dSGarrett Wollman ags |= AGS_SUPPRESS; 5577b6ab19dSGarrett Wollman 5587b6ab19dSGarrett Wollman /* Generate supernets if allowed. 5597b6ab19dSGarrett Wollman * If we can be heard by RIPv1 systems, we will 5607b6ab19dSGarrett Wollman * later convert back to ordinary nets. 5617b6ab19dSGarrett Wollman * This unifies dealing with received supernets. 5627b6ab19dSGarrett Wollman */ 5632c7a9781SMark Murray if ((ws.state & WS_ST_AG) 5642c7a9781SMark Murray && ((RT->rt_state & RS_SUBNET) 5652c7a9781SMark Murray || (ws.state & WS_ST_SUPER_AG))) 5662c7a9781SMark Murray ags |= AGS_AGGREGATE; 5677b6ab19dSGarrett Wollman } 5687b6ab19dSGarrett Wollman 5697b6ab19dSGarrett Wollman /* Do not send RIPv1 advertisements of subnets to other 5707b6ab19dSGarrett Wollman * networks. If possible, multicast them by RIPv2. 5717b6ab19dSGarrett Wollman */ 5727b6ab19dSGarrett Wollman if ((RT->rt_state & RS_SUBNET) 5737b6ab19dSGarrett Wollman && !(ws.state & WS_ST_RIP2_ALL) 5742c7a9781SMark Murray && !on_net(dst, ws.to_std_net, ws.to_std_mask)) 5752c7a9781SMark Murray ags |= AGS_RIPV2 | AGS_AGGREGATE; 5762c7a9781SMark Murray 5777b6ab19dSGarrett Wollman 5787b6ab19dSGarrett Wollman /* Do not send a route back to where it came from, except in 5797b6ab19dSGarrett Wollman * response to a query. This is "split-horizon". That means not 5807b6ab19dSGarrett Wollman * advertising back to the same network and so via the same interface. 5817b6ab19dSGarrett Wollman * 5827b6ab19dSGarrett Wollman * We want to suppress routes that might have been fragmented 5837b6ab19dSGarrett Wollman * from this route by a RIPv1 router and sent back to us, and so we 5847b6ab19dSGarrett Wollman * cannot forget this route here. Let the split-horizon route 5852c7a9781SMark Murray * suppress the fragmented routes and then itself be forgotten. 5867b6ab19dSGarrett Wollman * 5877b6ab19dSGarrett Wollman * Include the routes for both ends of point-to-point interfaces 58871965874SGarrett Wollman * among those suppressed by split-horizon, since the other side 58971965874SGarrett Wollman * should knows them as well as we do. 5902c7a9781SMark Murray * 5912c7a9781SMark Murray * Notice spare routes with the same metric that we are about to 5922c7a9781SMark Murray * advertise, to split the horizon on redundant, inactive paths. 5937b6ab19dSGarrett Wollman */ 5942c7a9781SMark Murray if (ws.ifp != 0 5957b6ab19dSGarrett Wollman && !(ws.state & WS_ST_QUERY) 5967b6ab19dSGarrett Wollman && (ws.state & WS_ST_TO_ON_NET) 5977b6ab19dSGarrett Wollman && (!(RT->rt_state & RS_IF) 5987b6ab19dSGarrett Wollman || ws.ifp->int_if_flags & IFF_POINTOPOINT)) { 5992c7a9781SMark Murray for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) { 6002c7a9781SMark Murray if (rts->rts_metric > metric 6012c7a9781SMark Murray || rts->rts_ifp != ws.ifp) 6022c7a9781SMark Murray continue; 6032c7a9781SMark Murray 60471965874SGarrett Wollman /* If we do not mark the route with AGS_SPLIT_HZ here, 6052c7a9781SMark Murray * it will be poisoned-reverse, or advertised back 6062c7a9781SMark Murray * toward its source with an infinite metric. 6072c7a9781SMark Murray * If we have recently advertised the route with a 6082c7a9781SMark Murray * better metric than we now have, then we should 6092c7a9781SMark Murray * poison-reverse the route before suppressing it for 6102c7a9781SMark Murray * split-horizon. 61171965874SGarrett Wollman * 6122c7a9781SMark Murray * In almost all cases, if there is no spare for the 6132c7a9781SMark Murray * route then it is either old and dead or a brand 6142c7a9781SMark Murray * new route. If it is brand new, there is no need 6152c7a9781SMark Murray * for poison-reverse. If it is old and dead, it 6162c7a9781SMark Murray * is already poisoned. 6177b6ab19dSGarrett Wollman */ 6187b6ab19dSGarrett Wollman if (RT->rt_poison_time < now_expire 61971965874SGarrett Wollman || RT->rt_poison_metric >= metric 6207b6ab19dSGarrett Wollman || RT->rt_spares[1].rts_gate == 0) { 6217b6ab19dSGarrett Wollman ags |= AGS_SPLIT_HZ; 6222c7a9781SMark Murray ags &= ~AGS_SUPPRESS; 6237b6ab19dSGarrett Wollman } 62471965874SGarrett Wollman metric = HOPCNT_INFINITY; 6252c7a9781SMark Murray break; 6262c7a9781SMark Murray } 6277b6ab19dSGarrett Wollman } 6287b6ab19dSGarrett Wollman 6297b6ab19dSGarrett Wollman /* Keep track of the best metric with which the 6307b6ab19dSGarrett Wollman * route has been advertised recently. 6317b6ab19dSGarrett Wollman */ 6327b6ab19dSGarrett Wollman if (RT->rt_poison_metric >= metric 6337b6ab19dSGarrett Wollman || RT->rt_poison_time < now_expire) { 6347b6ab19dSGarrett Wollman RT->rt_poison_time = now.tv_sec; 6357b6ab19dSGarrett Wollman RT->rt_poison_metric = metric; 6367b6ab19dSGarrett Wollman } 6377b6ab19dSGarrett Wollman 6382c7a9781SMark Murray /* Adjust the outgoing metric by the cost of the link. 6392c7a9781SMark Murray * Avoid aggregation when a route is counting to infinity. 6402c7a9781SMark Murray */ 6412c7a9781SMark Murray pref = RT->rt_poison_metric + ws.metric; 6422c7a9781SMark Murray metric += ws.metric; 6432c7a9781SMark Murray 6447b6ab19dSGarrett Wollman /* Do not advertise stable routes that will be ignored, 645d5b718b3SGarrett Wollman * unless we are answering a query. 646d5b718b3SGarrett Wollman * If the route recently was advertised with a metric that 647d5b718b3SGarrett Wollman * would have been less than infinity through this interface, 648d5b718b3SGarrett Wollman * we need to continue to advertise it in order to poison it. 6497b6ab19dSGarrett Wollman */ 6502c7a9781SMark Murray if (metric >= HOPCNT_INFINITY) { 651d5b718b3SGarrett Wollman if (!(ws.state & WS_ST_QUERY) 652d5b718b3SGarrett Wollman && (pref >= HOPCNT_INFINITY 653d5b718b3SGarrett Wollman || RT->rt_poison_time < now_garbage)) 6547b6ab19dSGarrett Wollman return 0; 6557b6ab19dSGarrett Wollman 6567b6ab19dSGarrett Wollman metric = HOPCNT_INFINITY; 6577b6ab19dSGarrett Wollman } 6587b6ab19dSGarrett Wollman 6597b6ab19dSGarrett Wollman ag_check(dst, RT->rt_mask, 0, nhop, metric, pref, 6607b6ab19dSGarrett Wollman RT->rt_seqno, RT->rt_tag, ags, supply_out); 6617b6ab19dSGarrett Wollman return 0; 6627b6ab19dSGarrett Wollman #undef RT 6637b6ab19dSGarrett Wollman } 6647b6ab19dSGarrett Wollman 6657b6ab19dSGarrett Wollman 6667b6ab19dSGarrett Wollman /* Supply dst with the contents of the routing tables. 6677b6ab19dSGarrett Wollman * If this won't fit in one packet, chop it up into several. 6687b6ab19dSGarrett Wollman */ 6697b6ab19dSGarrett Wollman void 6707b6ab19dSGarrett Wollman supply(struct sockaddr_in *dst, 6717b6ab19dSGarrett Wollman struct interface *ifp, /* output interface */ 6727b6ab19dSGarrett Wollman enum output_type type, 6737b6ab19dSGarrett Wollman int flash, /* 1=flash update */ 674d5b718b3SGarrett Wollman int vers, /* RIP version */ 675d5b718b3SGarrett Wollman int passwd_ok) /* OK to include cleartext password */ 6767b6ab19dSGarrett Wollman { 6777b6ab19dSGarrett Wollman struct rt_entry *rt; 678d5b718b3SGarrett Wollman int def_metric; 6797b6ab19dSGarrett Wollman 6807b6ab19dSGarrett Wollman 6817b6ab19dSGarrett Wollman ws.state = 0; 6827b6ab19dSGarrett Wollman ws.gen_limit = 1024; 6837b6ab19dSGarrett Wollman 6847b6ab19dSGarrett Wollman ws.to = *dst; 6857b6ab19dSGarrett Wollman ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr); 6867b6ab19dSGarrett Wollman ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask; 6877b6ab19dSGarrett Wollman 6887b6ab19dSGarrett Wollman if (ifp != 0) { 6897b6ab19dSGarrett Wollman ws.to_mask = ifp->int_mask; 6907b6ab19dSGarrett Wollman ws.to_net = ifp->int_net; 6917b6ab19dSGarrett Wollman if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask)) 6927b6ab19dSGarrett Wollman ws.state |= WS_ST_TO_ON_NET; 6937b6ab19dSGarrett Wollman 6947b6ab19dSGarrett Wollman } else { 6957b6ab19dSGarrett Wollman ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0); 6967b6ab19dSGarrett Wollman ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask; 6977b6ab19dSGarrett Wollman rt = rtfind(dst->sin_addr.s_addr); 6987b6ab19dSGarrett Wollman if (rt) 6997b6ab19dSGarrett Wollman ifp = rt->rt_ifp; 7007b6ab19dSGarrett Wollman } 7017b6ab19dSGarrett Wollman 7027b6ab19dSGarrett Wollman ws.npackets = 0; 7037b6ab19dSGarrett Wollman if (flash) 7047b6ab19dSGarrett Wollman ws.state |= WS_ST_FLASH; 7057b6ab19dSGarrett Wollman 7067b6ab19dSGarrett Wollman if ((ws.ifp = ifp) == 0) { 7077b6ab19dSGarrett Wollman ws.metric = 1; 7087b6ab19dSGarrett Wollman } else { 7097b6ab19dSGarrett Wollman /* Adjust the advertised metric by the outgoing interface 7107b6ab19dSGarrett Wollman * metric. 7117b6ab19dSGarrett Wollman */ 7127b6ab19dSGarrett Wollman ws.metric = ifp->int_metric+1; 7137b6ab19dSGarrett Wollman } 7147b6ab19dSGarrett Wollman 7157b6ab19dSGarrett Wollman ripv12_buf.rip.rip_vers = vers; 7167b6ab19dSGarrett Wollman 7177b6ab19dSGarrett Wollman switch (type) { 7187b6ab19dSGarrett Wollman case OUT_MULTICAST: 7192c7a9781SMark Murray if (ifp->int_if_flags & IFF_MULTICAST) 7202c7a9781SMark Murray v2buf.type = OUT_MULTICAST; 7212c7a9781SMark Murray else 7222c7a9781SMark Murray v2buf.type = NO_OUT_MULTICAST; 723d5b718b3SGarrett Wollman v12buf.type = OUT_BROADCAST; 7247b6ab19dSGarrett Wollman break; 7252c7a9781SMark Murray 7267b6ab19dSGarrett Wollman case OUT_QUERY: 7272c7a9781SMark Murray ws.state |= WS_ST_QUERY; 7282c7a9781SMark Murray /* fall through */ 7292c7a9781SMark Murray case OUT_BROADCAST: 7302c7a9781SMark Murray case OUT_UNICAST: 731d5b718b3SGarrett Wollman v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; 732d5b718b3SGarrett Wollman v12buf.type = type; 7337b6ab19dSGarrett Wollman break; 7342c7a9781SMark Murray 7352c7a9781SMark Murray case NO_OUT_MULTICAST: 7362c7a9781SMark Murray case NO_OUT_RIPV2: 7372c7a9781SMark Murray break; /* no output */ 7387b6ab19dSGarrett Wollman } 7397b6ab19dSGarrett Wollman 7407b6ab19dSGarrett Wollman if (vers == RIPv2) { 7417b6ab19dSGarrett Wollman /* full RIPv2 only if cannot be heard by RIPv1 listeners */ 7427b6ab19dSGarrett Wollman if (type != OUT_BROADCAST) 7437b6ab19dSGarrett Wollman ws.state |= WS_ST_RIP2_ALL; 7442c7a9781SMark Murray if ((ws.state & WS_ST_QUERY) 7452c7a9781SMark Murray || !(ws.state & WS_ST_TO_ON_NET)) { 7467b6ab19dSGarrett Wollman ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); 747d5b718b3SGarrett Wollman } else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) { 7487b6ab19dSGarrett Wollman ws.state |= WS_ST_AG; 7497b6ab19dSGarrett Wollman if (type != OUT_BROADCAST 7502c7a9781SMark Murray && (ifp == 0 7512c7a9781SMark Murray || !(ifp->int_state & IS_NO_SUPER_AG))) 7527b6ab19dSGarrett Wollman ws.state |= WS_ST_SUPER_AG; 7537b6ab19dSGarrett Wollman } 7547b6ab19dSGarrett Wollman } 7557b6ab19dSGarrett Wollman 756d5b718b3SGarrett Wollman ws.a = (vers == RIPv2) ? find_auth(ifp) : 0; 75771965874SGarrett Wollman if (!passwd_ok && ws.a != 0 && ws.a->type == RIP_AUTH_PW) 758d5b718b3SGarrett Wollman ws.a = 0; 75971965874SGarrett Wollman clr_ws_buf(&v12buf,ws.a); 76071965874SGarrett Wollman clr_ws_buf(&v2buf,ws.a); 761d5b718b3SGarrett Wollman 762d5b718b3SGarrett Wollman /* Fake a default route if asked and if there is not already 7637b6ab19dSGarrett Wollman * a better, real default route. 7647b6ab19dSGarrett Wollman */ 765d5b718b3SGarrett Wollman if (supplier && (def_metric = ifp->int_d_metric) != 0) { 766d5b718b3SGarrett Wollman if (0 == (rt = rtget(RIP_DEFAULT, 0)) 767d5b718b3SGarrett Wollman || rt->rt_metric+ws.metric >= def_metric) { 7687b6ab19dSGarrett Wollman ws.state |= WS_ST_DEFAULT; 769d5b718b3SGarrett Wollman ag_check(0, 0, 0, 0, def_metric, def_metric, 7707b6ab19dSGarrett Wollman 0, 0, 0, supply_out); 771d5b718b3SGarrett Wollman } else { 772d5b718b3SGarrett Wollman def_metric = rt->rt_metric+ws.metric; 7737b6ab19dSGarrett Wollman } 774d5b718b3SGarrett Wollman 775d5b718b3SGarrett Wollman /* If both RIPv2 and the poor-man's router discovery 776d5b718b3SGarrett Wollman * kludge are on, arrange to advertise an extra 777d5b718b3SGarrett Wollman * default route via RIPv1. 778d5b718b3SGarrett Wollman */ 7797b6ab19dSGarrett Wollman if ((ws.state & WS_ST_RIP2_ALL) 7807b6ab19dSGarrett Wollman && (ifp->int_state & IS_PM_RDISC)) { 7817b6ab19dSGarrett Wollman ripv12_buf.rip.rip_vers = RIPv1; 782d5b718b3SGarrett Wollman v12buf.n->n_family = RIP_AF_INET; 783d5b718b3SGarrett Wollman v12buf.n->n_dst = htonl(RIP_DEFAULT); 784d5b718b3SGarrett Wollman v12buf.n->n_metric = htonl(def_metric); 785d5b718b3SGarrett Wollman v12buf.n++; 7867b6ab19dSGarrett Wollman } 7877b6ab19dSGarrett Wollman } 7887b6ab19dSGarrett Wollman 7897b6ab19dSGarrett Wollman (void)rn_walktree(rhead, walk_supply, 0); 7907b6ab19dSGarrett Wollman ag_flush(0,0,supply_out); 7917b6ab19dSGarrett Wollman 7927b6ab19dSGarrett Wollman /* Flush the packet buffers, provided they are not empty and 7937b6ab19dSGarrett Wollman * do not contain only the password. 7947b6ab19dSGarrett Wollman */ 795d5b718b3SGarrett Wollman if (v12buf.n != v12buf.base 796d5b718b3SGarrett Wollman && (v12buf.n > v12buf.base+1 797d5b718b3SGarrett Wollman || v12buf.base->n_family != RIP_AF_AUTH)) 798d5b718b3SGarrett Wollman supply_write(&v12buf); 799d5b718b3SGarrett Wollman if (v2buf.n != v2buf.base 800d5b718b3SGarrett Wollman && (v2buf.n > v2buf.base+1 801d5b718b3SGarrett Wollman || v2buf.base->n_family != RIP_AF_AUTH)) 802d5b718b3SGarrett Wollman supply_write(&v2buf); 8037b6ab19dSGarrett Wollman 8047b6ab19dSGarrett Wollman /* If we sent nothing and this is an answer to a query, send 8057b6ab19dSGarrett Wollman * an empty buffer. 8067b6ab19dSGarrett Wollman */ 8077b6ab19dSGarrett Wollman if (ws.npackets == 0 8087b6ab19dSGarrett Wollman && (ws.state & WS_ST_QUERY)) 809d5b718b3SGarrett Wollman supply_write(&v12buf); 8107b6ab19dSGarrett Wollman } 8117b6ab19dSGarrett Wollman 8127b6ab19dSGarrett Wollman 8137b6ab19dSGarrett Wollman /* send all of the routing table or just do a flash update 8147b6ab19dSGarrett Wollman */ 8157b6ab19dSGarrett Wollman void 8167b6ab19dSGarrett Wollman rip_bcast(int flash) 8177b6ab19dSGarrett Wollman { 8187b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 8197b6ab19dSGarrett Wollman static struct sockaddr_in dst = {sizeof(dst), AF_INET}; 8207b6ab19dSGarrett Wollman #else 8217b6ab19dSGarrett Wollman static struct sockaddr_in dst = {AF_INET}; 8227b6ab19dSGarrett Wollman #endif 8237b6ab19dSGarrett Wollman struct interface *ifp; 8247b6ab19dSGarrett Wollman enum output_type type; 8257b6ab19dSGarrett Wollman int vers; 8267b6ab19dSGarrett Wollman struct timeval rtime; 8277b6ab19dSGarrett Wollman 8287b6ab19dSGarrett Wollman 8297b6ab19dSGarrett Wollman need_flash = 0; 8307b6ab19dSGarrett Wollman intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME); 8317b6ab19dSGarrett Wollman no_flash = rtime; 8327b6ab19dSGarrett Wollman timevaladd(&no_flash, &now); 8337b6ab19dSGarrett Wollman 8347b6ab19dSGarrett Wollman if (rip_sock < 0) 8357b6ab19dSGarrett Wollman return; 8367b6ab19dSGarrett Wollman 837d5b718b3SGarrett Wollman trace_act("send %s and inhibit dynamic updates for %.3f sec", 8387b6ab19dSGarrett Wollman flash ? "dynamic update" : "all routes", 8397b6ab19dSGarrett Wollman rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0); 8407b6ab19dSGarrett Wollman 8417b6ab19dSGarrett Wollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 842d5b718b3SGarrett Wollman /* Skip interfaces not doing RIP. 843d5b718b3SGarrett Wollman * Do try broken interfaces to see if they have healed. 8447b6ab19dSGarrett Wollman */ 845d5b718b3SGarrett Wollman if (IS_RIP_OUT_OFF(ifp->int_state)) 8467b6ab19dSGarrett Wollman continue; 8477b6ab19dSGarrett Wollman 8487b6ab19dSGarrett Wollman /* skip turned off interfaces */ 8492c7a9781SMark Murray if (!iff_up(ifp->int_if_flags)) 8507b6ab19dSGarrett Wollman continue; 8517b6ab19dSGarrett Wollman 852d5b718b3SGarrett Wollman vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; 8537b6ab19dSGarrett Wollman 8547b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_BROADCAST) { 8557b6ab19dSGarrett Wollman /* ordinary, hardware interface */ 8567b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_brdaddr; 857d5b718b3SGarrett Wollman 8587b6ab19dSGarrett Wollman if (vers == RIPv2 8592c7a9781SMark Murray && !(ifp->int_state & IS_NO_RIP_MCAST)) { 8607b6ab19dSGarrett Wollman type = OUT_MULTICAST; 8617b6ab19dSGarrett Wollman } else { 8627b6ab19dSGarrett Wollman type = OUT_BROADCAST; 8637b6ab19dSGarrett Wollman } 8647b6ab19dSGarrett Wollman 8657b6ab19dSGarrett Wollman } else if (ifp->int_if_flags & IFF_POINTOPOINT) { 8667b6ab19dSGarrett Wollman /* point-to-point hardware interface */ 8677b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_dstaddr; 8687b6ab19dSGarrett Wollman type = OUT_UNICAST; 8697b6ab19dSGarrett Wollman 870d5b718b3SGarrett Wollman } else if (ifp->int_state & IS_REMOTE) { 8717b6ab19dSGarrett Wollman /* remote interface */ 8727b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_addr; 8737b6ab19dSGarrett Wollman type = OUT_UNICAST; 874d5b718b3SGarrett Wollman 875d5b718b3SGarrett Wollman } else { 876d5b718b3SGarrett Wollman /* ATM, HIPPI, etc. */ 877d5b718b3SGarrett Wollman continue; 8787b6ab19dSGarrett Wollman } 8797b6ab19dSGarrett Wollman 880d5b718b3SGarrett Wollman supply(&dst, ifp, type, flash, vers, 1); 8817b6ab19dSGarrett Wollman } 8827b6ab19dSGarrett Wollman 8837b6ab19dSGarrett Wollman update_seqno++; /* all routes are up to date */ 8847b6ab19dSGarrett Wollman } 8857b6ab19dSGarrett Wollman 8867b6ab19dSGarrett Wollman 8877b6ab19dSGarrett Wollman /* Ask for routes 8887b6ab19dSGarrett Wollman * Do it only once to an interface, and not even after the interface 8897b6ab19dSGarrett Wollman * was broken and recovered. 8907b6ab19dSGarrett Wollman */ 8917b6ab19dSGarrett Wollman void 8927b6ab19dSGarrett Wollman rip_query(void) 8937b6ab19dSGarrett Wollman { 8947b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 8957b6ab19dSGarrett Wollman static struct sockaddr_in dst = {sizeof(dst), AF_INET}; 8967b6ab19dSGarrett Wollman #else 8977b6ab19dSGarrett Wollman static struct sockaddr_in dst = {AF_INET}; 8987b6ab19dSGarrett Wollman #endif 8997b6ab19dSGarrett Wollman struct interface *ifp; 9007b6ab19dSGarrett Wollman struct rip buf; 9017b6ab19dSGarrett Wollman enum output_type type; 9027b6ab19dSGarrett Wollman 9037b6ab19dSGarrett Wollman 9047b6ab19dSGarrett Wollman if (rip_sock < 0) 9057b6ab19dSGarrett Wollman return; 9067b6ab19dSGarrett Wollman 9072c7a9781SMark Murray memset(&buf, 0, sizeof(buf)); 9087b6ab19dSGarrett Wollman 9097b6ab19dSGarrett Wollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 910d5b718b3SGarrett Wollman /* Skip interfaces those already queried. 911d5b718b3SGarrett Wollman * Do not ask via interfaces through which we don't 912d5b718b3SGarrett Wollman * accept input. Do not ask via interfaces that cannot 913d5b718b3SGarrett Wollman * send RIP packets. 914d5b718b3SGarrett Wollman * Do try broken interfaces to see if they have healed. 9157b6ab19dSGarrett Wollman */ 916d5b718b3SGarrett Wollman if (IS_RIP_IN_OFF(ifp->int_state) 917d5b718b3SGarrett Wollman || ifp->int_query_time != NEVER) 9187b6ab19dSGarrett Wollman continue; 9197b6ab19dSGarrett Wollman 9207b6ab19dSGarrett Wollman /* skip turned off interfaces */ 9212c7a9781SMark Murray if (!iff_up(ifp->int_if_flags)) 9227b6ab19dSGarrett Wollman continue; 9237b6ab19dSGarrett Wollman 924d5b718b3SGarrett Wollman buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1; 9257b6ab19dSGarrett Wollman buf.rip_cmd = RIPCMD_REQUEST; 9267b6ab19dSGarrett Wollman buf.rip_nets[0].n_family = RIP_AF_UNSPEC; 9277b6ab19dSGarrett Wollman buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 9287b6ab19dSGarrett Wollman 9292c7a9781SMark Murray /* Send a RIPv1 query only if allowed and if we will 9302c7a9781SMark Murray * listen to RIPv1 routers. 9312c7a9781SMark Murray */ 9322c7a9781SMark Murray if ((ifp->int_state & IS_NO_RIPV1_OUT) 9332c7a9781SMark Murray || (ifp->int_state & IS_NO_RIPV1_IN)) { 9342c7a9781SMark Murray buf.rip_vers = RIPv2; 9352c7a9781SMark Murray } else { 9362c7a9781SMark Murray buf.rip_vers = RIPv1; 9372c7a9781SMark Murray } 9382c7a9781SMark Murray 9397b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_BROADCAST) { 9407b6ab19dSGarrett Wollman /* ordinary, hardware interface */ 9417b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_brdaddr; 9422c7a9781SMark Murray 9432c7a9781SMark Murray /* Broadcast RIPv1 queries and RIPv2 queries 9442c7a9781SMark Murray * when the hardware cannot multicast. 9457b6ab19dSGarrett Wollman */ 9467b6ab19dSGarrett Wollman if (buf.rip_vers == RIPv2 9472c7a9781SMark Murray && (ifp->int_if_flags & IFF_MULTICAST) 9482c7a9781SMark Murray && !(ifp->int_state & IS_NO_RIP_MCAST)) { 9497b6ab19dSGarrett Wollman type = OUT_MULTICAST; 9507b6ab19dSGarrett Wollman } else { 9517b6ab19dSGarrett Wollman type = OUT_BROADCAST; 9527b6ab19dSGarrett Wollman } 9537b6ab19dSGarrett Wollman 9547b6ab19dSGarrett Wollman } else if (ifp->int_if_flags & IFF_POINTOPOINT) { 9557b6ab19dSGarrett Wollman /* point-to-point hardware interface */ 9567b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_dstaddr; 9577b6ab19dSGarrett Wollman type = OUT_UNICAST; 9587b6ab19dSGarrett Wollman 959d5b718b3SGarrett Wollman } else if (ifp->int_state & IS_REMOTE) { 9607b6ab19dSGarrett Wollman /* remote interface */ 9617b6ab19dSGarrett Wollman dst.sin_addr.s_addr = ifp->int_addr; 9627b6ab19dSGarrett Wollman type = OUT_UNICAST; 963d5b718b3SGarrett Wollman 964d5b718b3SGarrett Wollman } else { 965d5b718b3SGarrett Wollman /* ATM, HIPPI, etc. */ 966d5b718b3SGarrett Wollman continue; 9677b6ab19dSGarrett Wollman } 9687b6ab19dSGarrett Wollman 969d5b718b3SGarrett Wollman ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL; 9707b6ab19dSGarrett Wollman if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0) 9717b6ab19dSGarrett Wollman if_sick(ifp); 9727b6ab19dSGarrett Wollman } 9737b6ab19dSGarrett Wollman } 974