1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * PPP Routing related Module 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Redistribution and use in source and binary forms are permitted 9af57ed9fSAtsushi Murai * provided that the above copyright notice and this paragraph are 10af57ed9fSAtsushi Murai * duplicated in all such forms and that any documentation, 11af57ed9fSAtsushi Murai * advertising materials, and other materials related to such 12af57ed9fSAtsushi Murai * distribution and use acknowledge that the software was developed 13af57ed9fSAtsushi Murai * by the Internet Initiative Japan, Inc. The name of the 14af57ed9fSAtsushi Murai * IIJ may not be used to endorse or promote products derived 15af57ed9fSAtsushi Murai * from this software without specific prior written permission. 16af57ed9fSAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17af57ed9fSAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18af57ed9fSAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19af57ed9fSAtsushi Murai * 2097d92980SPeter Wemm * $FreeBSD$ 2153c9f6c0SAtsushi Murai * 22af57ed9fSAtsushi Murai */ 2375240ed1SBrian Somers 24972a1bcfSBrian Somers #include <sys/param.h> 2575240ed1SBrian Somers #include <sys/socket.h> 265d5e5070SBrian Somers #include <net/if_types.h> 27628d2ac1SGarrett Wollman #include <net/route.h> 28628d2ac1SGarrett Wollman #include <net/if.h> 29628d2ac1SGarrett Wollman #include <netinet/in.h> 30628d2ac1SGarrett Wollman #include <arpa/inet.h> 315d5e5070SBrian Somers #include <net/if_dl.h> 32eaa4df37SBrian Somers #include <netinet/in_systm.h> 33eaa4df37SBrian Somers #include <netinet/ip.h> 341fa665f5SBrian Somers #include <sys/un.h> 356b384664SBrian Somers #ifndef NOINET6 366b384664SBrian Somers #include <netinet6/in6.h> 376b384664SBrian Somers #endif 386b384664SBrian Somers #include <netdb.h> 39628d2ac1SGarrett Wollman 4075240ed1SBrian Somers #include <errno.h> 4175240ed1SBrian Somers #include <stdio.h> 4275240ed1SBrian Somers #include <stdlib.h> 4375240ed1SBrian Somers #include <string.h> 4475240ed1SBrian Somers #include <sys/sysctl.h> 4585b542cfSBrian Somers #include <termios.h> 4675240ed1SBrian Somers 475d9e6103SBrian Somers #include "layer.h" 48c9e11a11SBrian Somers #include "defs.h" 49b6e82f33SBrian Somers #include "command.h" 5075240ed1SBrian Somers #include "mbuf.h" 51215a4696SAtsushi Murai #include "log.h" 52bcc332bdSBrian Somers #include "iplist.h" 5329e275ceSBrian Somers #include "timer.h" 5429e275ceSBrian Somers #include "throughput.h" 55879ed6faSBrian Somers #include "lqr.h" 568c07a7b2SBrian Somers #include "hdlc.h" 577308ec68SBrian Somers #include "fsm.h" 583b0f8d2eSBrian Somers #include "lcp.h" 593b0f8d2eSBrian Somers #include "ccp.h" 603b0f8d2eSBrian Somers #include "link.h" 61eaa4df37SBrian Somers #include "slcompress.h" 6229e275ceSBrian Somers #include "ipcp.h" 635ca5389aSBrian Somers #include "filter.h" 642f786681SBrian Somers #include "descriptor.h" 653b0f8d2eSBrian Somers #include "mp.h" 66972a1bcfSBrian Somers #ifndef NORADIUS 67972a1bcfSBrian Somers #include "radius.h" 68972a1bcfSBrian Somers #endif 695828db6dSBrian Somers #include "bundle.h" 7075240ed1SBrian Somers #include "route.h" 7185b542cfSBrian Somers #include "prompt.h" 728fa6ebe4SBrian Somers #include "iface.h" 73af57ed9fSAtsushi Murai 746b457978SBrian Somers 75af57ed9fSAtsushi Murai static void 76b6217683SBrian Somers p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 77b6217683SBrian Somers struct sockaddr *pmask, int width) 78af57ed9fSAtsushi Murai { 79b6e82f33SBrian Somers char buf[29]; 806b384664SBrian Somers struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 816b384664SBrian Somers struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 825d5e5070SBrian Somers struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 83af57ed9fSAtsushi Murai 846b384664SBrian Somers if (log_IsKept(LogDEBUG)) { 856b384664SBrian Somers char tmp[50]; 866b384664SBrian Somers 876b384664SBrian Somers log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 886b384664SBrian Somers log_Printf(LogDEBUG, " Family %d, len %d\n", 896b384664SBrian Somers (int)phost->sa_family, (int)phost->sa_len); 906b457978SBrian Somers inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 916b384664SBrian Somers log_Printf(LogDEBUG, " Addr %s\n", tmp); 926b384664SBrian Somers if (pmask) { 936b457978SBrian Somers inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 946b384664SBrian Somers log_Printf(LogDEBUG, " Mask %s\n", tmp); 956b384664SBrian Somers } 966b384664SBrian Somers } 976b384664SBrian Somers 985d5e5070SBrian Somers switch (phost->sa_family) { 995d5e5070SBrian Somers case AF_INET: 1005d5e5070SBrian Somers if (!phost) 1014bfaee90SBrian Somers buf[0] = '\0'; 1026b384664SBrian Somers else if (ihost4->sin_addr.s_addr == INADDR_ANY) 1034bfaee90SBrian Somers strcpy(buf, "default"); 1046b384664SBrian Somers else if (!pmask) 1056b384664SBrian Somers strcpy(buf, inet_ntoa(ihost4->sin_addr)); 1065d5e5070SBrian Somers else { 1076b384664SBrian Somers u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 1083a2e4f62SBrian Somers u_int32_t tst; 1095d5e5070SBrian Somers int bits; 1105d5e5070SBrian Somers int len; 1115d5e5070SBrian Somers struct sockaddr_in net; 1125d5e5070SBrian Somers 1135d5e5070SBrian Somers for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 1145d5e5070SBrian Somers if (msk & tst) 1155d5e5070SBrian Somers break; 1165d5e5070SBrian Somers 1175d5e5070SBrian Somers for (tst <<= 1; tst; tst <<= 1) 1185d5e5070SBrian Somers if (!(msk & tst)) 1195d5e5070SBrian Somers break; 1205d5e5070SBrian Somers 1216b384664SBrian Somers net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 12283c0952dSBrian Somers strcpy(buf, inet_ntoa(net.sin_addr)); 1235d5e5070SBrian Somers for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 1245d5e5070SBrian Somers if (strcmp(buf + len - 2, ".0")) 1255d5e5070SBrian Somers break; 1265d5e5070SBrian Somers 1275d5e5070SBrian Somers if (tst) /* non-contiguous :-( */ 1283a2e4f62SBrian Somers sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 1295d5e5070SBrian Somers else 1305d5e5070SBrian Somers sprintf(buf + strlen(buf), "/%d", bits); 131927145beSBrian Somers } 1325d5e5070SBrian Somers break; 1335d5e5070SBrian Somers 1345d5e5070SBrian Somers case AF_LINK: 1354bfaee90SBrian Somers if (dl->sdl_nlen) 1364bfaee90SBrian Somers snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 137c4c4aaacSBrian Somers else if (dl->sdl_alen) { 138c4c4aaacSBrian Somers if (dl->sdl_type == IFT_ETHER) { 13970ee81ffSBrian Somers if (dl->sdl_alen < sizeof buf / 3) { 1405d5e5070SBrian Somers int f; 1415d5e5070SBrian Somers u_char *MAC; 1425d5e5070SBrian Somers 1435d5e5070SBrian Somers MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 1445d5e5070SBrian Somers for (f = 0; f < dl->sdl_alen; f++) 1455d5e5070SBrian Somers sprintf(buf+f*3, "%02x:", MAC[f]); 1465d5e5070SBrian Somers buf[f*3-1] = '\0'; 1475d5e5070SBrian Somers } else 14883c0952dSBrian Somers strcpy(buf, "??:??:??:??:??:??"); 149c4c4aaacSBrian Somers } else 1504bfaee90SBrian Somers sprintf(buf, "<IFT type %d>", dl->sdl_type); 151c4c4aaacSBrian Somers } else if (dl->sdl_slen) 1524bfaee90SBrian Somers sprintf(buf, "<slen %d?>", dl->sdl_slen); 1534bfaee90SBrian Somers else 1544bfaee90SBrian Somers sprintf(buf, "link#%d", dl->sdl_index); 1555d5e5070SBrian Somers break; 1565d5e5070SBrian Somers 1576b384664SBrian Somers #ifndef NOINET6 1586b384664SBrian Somers case AF_INET6: 1596b384664SBrian Somers if (!phost) 1606b384664SBrian Somers buf[0] = '\0'; 1616b384664SBrian Somers else { 1626b384664SBrian Somers const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 1636b384664SBrian Somers struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 1646b384664SBrian Somers struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 1656b384664SBrian Somers int masklen, len; 1666b384664SBrian Somers const u_char *c; 1676b384664SBrian Somers 1686b384664SBrian Somers /* XXX: ?????!?!?!!!!! This is horrible ! */ 1696b384664SBrian Somers if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 1706b384664SBrian Somers IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 1716b384664SBrian Somers ihost6->sin6_scope_id = 1726b384664SBrian Somers ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 1736b384664SBrian Somers *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 1746b384664SBrian Somers } 1756b384664SBrian Somers 1766b384664SBrian Somers if (mask6) { 1776b384664SBrian Somers const u_char *p, *end; 1786b384664SBrian Somers 1796b384664SBrian Somers p = (const u_char *)&mask6->sin6_addr; 1806b384664SBrian Somers end = p + 16; 1816b384664SBrian Somers for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 1826b384664SBrian Somers masklen += 8; 1836b384664SBrian Somers 1846b384664SBrian Somers if (p < end) { 1856b384664SBrian Somers for (c = masks; c < masks + sizeof masks; c++) 1866b384664SBrian Somers if (*c == *p) { 1876b384664SBrian Somers masklen += c - masks; 1886b384664SBrian Somers break; 1896b384664SBrian Somers } 1906b384664SBrian Somers } 1916b384664SBrian Somers } else 1926b384664SBrian Somers masklen = 128; 1936b384664SBrian Somers 1946b384664SBrian Somers if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 1956b384664SBrian Somers snprintf(buf, sizeof buf, "default"); 1966b384664SBrian Somers else { 1976b384664SBrian Somers getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 1986b384664SBrian Somers NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 1996b384664SBrian Somers if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 2006b384664SBrian Somers snprintf(buf + len, sizeof buf - len, "/%d", masklen); 2016b384664SBrian Somers } 2026b384664SBrian Somers } 2036b384664SBrian Somers break; 2046b384664SBrian Somers #endif 2056b384664SBrian Somers 2065d5e5070SBrian Somers default: 2074bfaee90SBrian Somers sprintf(buf, "<AF type %d>", phost->sa_family); 2085d5e5070SBrian Somers break; 2095d5e5070SBrian Somers } 2105d5e5070SBrian Somers 211b6217683SBrian Somers prompt_Printf(prompt, "%-*s ", width-1, buf); 212af57ed9fSAtsushi Murai } 213af57ed9fSAtsushi Murai 214aa8e0519SBrian Somers static struct bits { 2153f06c599SBrian Somers u_int32_t b_mask; 216af57ed9fSAtsushi Murai char b_val; 217af57ed9fSAtsushi Murai } bits[] = { 2185d5e5070SBrian Somers { RTF_UP, 'U' }, 2195d5e5070SBrian Somers { RTF_GATEWAY, 'G' }, 2205d5e5070SBrian Somers { RTF_HOST, 'H' }, 2215d5e5070SBrian Somers { RTF_REJECT, 'R' }, 2225d5e5070SBrian Somers { RTF_DYNAMIC, 'D' }, 2235d5e5070SBrian Somers { RTF_MODIFIED, 'M' }, 2245d5e5070SBrian Somers { RTF_DONE, 'd' }, 2255d5e5070SBrian Somers { RTF_CLONING, 'C' }, 2265d5e5070SBrian Somers { RTF_XRESOLVE, 'X' }, 2275d5e5070SBrian Somers { RTF_LLINFO, 'L' }, 2285d5e5070SBrian Somers { RTF_STATIC, 'S' }, 2295d5e5070SBrian Somers { RTF_PROTO1, '1' }, 2305d5e5070SBrian Somers { RTF_PROTO2, '2' }, 2315d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 23232ca3341SBrian Somers #ifdef RTF_WASCLONED 2335d5e5070SBrian Somers { RTF_WASCLONED, 'W' }, 23432ca3341SBrian Somers #endif 23532ca3341SBrian Somers #ifdef RTF_PRCLONING 2365d5e5070SBrian Somers { RTF_PRCLONING, 'c' }, 23732ca3341SBrian Somers #endif 23832ca3341SBrian Somers #ifdef RTF_PROTO3 2395d5e5070SBrian Somers { RTF_PROTO3, '3' }, 24032ca3341SBrian Somers #endif 24132ca3341SBrian Somers #ifdef RTF_BROADCAST 2425d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 2435d5e5070SBrian Somers #endif 2445d5e5070SBrian Somers { 0, '\0' } 245af57ed9fSAtsushi Murai }; 246af57ed9fSAtsushi Murai 24732ca3341SBrian Somers #ifndef RTF_WASCLONED 24832ca3341SBrian Somers #define RTF_WASCLONED (0) 24932ca3341SBrian Somers #endif 25032ca3341SBrian Somers 251af57ed9fSAtsushi Murai static void 2523f06c599SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, int max) 253af57ed9fSAtsushi Murai { 254af57ed9fSAtsushi Murai char name[33], *flags; 255af57ed9fSAtsushi Murai register struct bits *p = bits; 256af57ed9fSAtsushi Murai 25770ee81ffSBrian Somers if (max > sizeof name - 1) 25870ee81ffSBrian Somers max = sizeof name - 1; 259d27d502cSBrian Somers 260d27d502cSBrian Somers for (flags = name; p->b_mask && flags - name < max; p++) 261af57ed9fSAtsushi Murai if (p->b_mask & f) 262af57ed9fSAtsushi Murai *flags++ = p->b_val; 263af57ed9fSAtsushi Murai *flags = '\0'; 264b6217683SBrian Somers prompt_Printf(prompt, "%-*.*s", max, max, name); 265af57ed9fSAtsushi Murai } 266af57ed9fSAtsushi Murai 267c6fe0cb2SBrian Somers const char * 2685d5e5070SBrian Somers Index2Nam(int idx) 2695d5e5070SBrian Somers { 270d93d3a9cSBrian Somers /* 271d93d3a9cSBrian Somers * XXX: Maybe we should select() on the routing socket so that we can 272d93d3a9cSBrian Somers * notice interfaces that come & go (PCCARD support). 273d93d3a9cSBrian Somers * Or we could even support a signal that resets these so that 274d93d3a9cSBrian Somers * the PCCARD insert/remove events can signal ppp. 275d93d3a9cSBrian Somers */ 276d93d3a9cSBrian Somers static char **ifs; /* Figure these out once */ 277d93d3a9cSBrian Somers static int nifs, debug_done; /* Figure out how many once, and debug once */ 2785d5e5070SBrian Somers 2798473f372SBrian Somers if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 280b1435e41SBrian Somers int mib[6], have, had; 281e7250038SBrian Somers size_t needed; 2825d5e5070SBrian Somers char *buf, *ptr, *end; 2835d5e5070SBrian Somers struct sockaddr_dl *dl; 2845d5e5070SBrian Somers struct if_msghdr *ifm; 2855d5e5070SBrian Somers 2868473f372SBrian Somers if (ifs) { 2878473f372SBrian Somers free(ifs); 2888473f372SBrian Somers ifs = NULL; 2898473f372SBrian Somers nifs = 0; 2908473f372SBrian Somers } 2918473f372SBrian Somers debug_done = 0; 2928473f372SBrian Somers 2935d5e5070SBrian Somers mib[0] = CTL_NET; 2945d5e5070SBrian Somers mib[1] = PF_ROUTE; 2955d5e5070SBrian Somers mib[2] = 0; 2965d5e5070SBrian Somers mib[3] = 0; 2975d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 2985d5e5070SBrian Somers mib[5] = 0; 2995d5e5070SBrian Somers 3005d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 301a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 302a33b2ef7SBrian Somers strerror(errno)); 303d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3045d5e5070SBrian Somers } 3055d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 306d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3075d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 3085d5e5070SBrian Somers free(buf); 309d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3105d5e5070SBrian Somers } 3115d5e5070SBrian Somers end = buf + needed; 3125d5e5070SBrian Somers 313b1435e41SBrian Somers have = 0; 3149cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 3155d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 3166b457978SBrian Somers if (ifm->ifm_type != RTM_IFINFO) 3176b457978SBrian Somers break; 3185d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 319b1435e41SBrian Somers if (ifm->ifm_index > 0) { 320b1435e41SBrian Somers if (ifm->ifm_index > have) { 321fc254be9SBrian Somers char **newifs; 322fc254be9SBrian Somers 323b1435e41SBrian Somers had = have; 324b1435e41SBrian Somers have = ifm->ifm_index + 5; 325b1435e41SBrian Somers if (had) 326fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 327b1435e41SBrian Somers else 328fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 329fc254be9SBrian Somers if (!newifs) { 330dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 331b1435e41SBrian Somers nifs = 0; 3328473f372SBrian Somers if (ifs) { 333fc254be9SBrian Somers free(ifs); 3348473f372SBrian Somers ifs = NULL; 3358473f372SBrian Somers } 3368473f372SBrian Somers free(buf); 337d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 338b1435e41SBrian Somers } 339fc254be9SBrian Somers ifs = newifs; 340b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 341b1435e41SBrian Somers } 342b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 343b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 344b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 345b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 346b1435e41SBrian Somers if (nifs < ifm->ifm_index) 3479cb1d89eSBrian Somers nifs = ifm->ifm_index; 348b1435e41SBrian Somers } 349dd7e2610SBrian Somers } else if (log_IsKept(LogDEBUG)) 350dd7e2610SBrian Somers log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 3519cb1d89eSBrian Somers ifm->ifm_index); 3525d5e5070SBrian Somers } 3535d5e5070SBrian Somers free(buf); 3545d5e5070SBrian Somers } 3555d5e5070SBrian Somers 356dd7e2610SBrian Somers if (log_IsKept(LogDEBUG) && !debug_done) { 3579cb1d89eSBrian Somers int f; 3589cb1d89eSBrian Somers 359dd7e2610SBrian Somers log_Printf(LogDEBUG, "Found the following interfaces:\n"); 3609cb1d89eSBrian Somers for (f = 0; f < nifs; f++) 361b1435e41SBrian Somers if (ifs[f] != NULL) 362dd7e2610SBrian Somers log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 3639cb1d89eSBrian Somers debug_done = 1; 3649cb1d89eSBrian Somers } 3659cb1d89eSBrian Somers 366b1435e41SBrian Somers if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 367d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3689cb1d89eSBrian Somers 3699cb1d89eSBrian Somers return ifs[idx-1]; 3705d5e5070SBrian Somers } 3715d5e5070SBrian Somers 3726b457978SBrian Somers void 3736b457978SBrian Somers route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 3746b457978SBrian Somers { 3756b457978SBrian Somers char *wp; 3766b457978SBrian Somers int rtax; 3776b457978SBrian Somers 3786b457978SBrian Somers wp = (char *)(rtm + 1); 3796b457978SBrian Somers 3806b457978SBrian Somers for (rtax = 0; rtax < RTAX_MAX; rtax++) 3816b457978SBrian Somers if (rtm->rtm_addrs & (1 << rtax)) { 3826b457978SBrian Somers sa[rtax] = (struct sockaddr *)wp; 3836b457978SBrian Somers wp += ROUNDUP(sa[rtax]->sa_len); 3846b457978SBrian Somers } else 3856b457978SBrian Somers sa[rtax] = NULL; 3866b457978SBrian Somers } 3876b457978SBrian Somers 388af57ed9fSAtsushi Murai int 389dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 390af57ed9fSAtsushi Murai { 391af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3926b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 3936b457978SBrian Somers char *sp, *ep, *cp; 394e7250038SBrian Somers size_t needed; 395af57ed9fSAtsushi Murai int mib[6]; 396af57ed9fSAtsushi Murai 397af57ed9fSAtsushi Murai mib[0] = CTL_NET; 398af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 39953c9f6c0SAtsushi Murai mib[2] = 0; 40053c9f6c0SAtsushi Murai mib[3] = 0; 401af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 40253c9f6c0SAtsushi Murai mib[5] = 0; 40353c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 404dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 40553c9f6c0SAtsushi Murai return (1); 40653c9f6c0SAtsushi Murai } 407af57ed9fSAtsushi Murai sp = malloc(needed); 408af57ed9fSAtsushi Murai if (sp == NULL) 409af57ed9fSAtsushi Murai return (1); 41053c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 411dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 412b0cdb3ceSJordan K. Hubbard free(sp); 413af57ed9fSAtsushi Murai return (1); 41453c9f6c0SAtsushi Murai } 415af57ed9fSAtsushi Murai ep = sp + needed; 416af57ed9fSAtsushi Murai 417b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 418b6217683SBrian Somers "Destination", "Gateway"); 419af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 420af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4215d5e5070SBrian Somers 4226b457978SBrian Somers route_ParseHdr(rtm, sa); 4236b384664SBrian Somers 4246b457978SBrian Somers if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 4256b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 4266b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 4275d5e5070SBrian Somers 428b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 429b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 4306b384664SBrian Somers } else 4316b384664SBrian Somers prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 432af57ed9fSAtsushi Murai } 433b0cdb3ceSJordan K. Hubbard free(sp); 434927145beSBrian Somers return 0; 435af57ed9fSAtsushi Murai } 436af57ed9fSAtsushi Murai 437af57ed9fSAtsushi Murai /* 438af57ed9fSAtsushi Murai * Delete routes associated with our interface 439af57ed9fSAtsushi Murai */ 440af57ed9fSAtsushi Murai void 441dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 442af57ed9fSAtsushi Murai { 443af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 4446b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 4456b457978SBrian Somers struct sockaddr_in **in; 4466b457978SBrian Somers struct in_addr sa_none; 447e7250038SBrian Somers int pass; 448e7250038SBrian Somers size_t needed; 449af57ed9fSAtsushi Murai char *sp, *cp, *ep; 450af57ed9fSAtsushi Murai int mib[6]; 451af57ed9fSAtsushi Murai 4528fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 453f01e577bSBrian Somers sa_none.s_addr = INADDR_ANY; 4546b457978SBrian Somers in = (struct sockaddr_in **)sa; 455927145beSBrian Somers 456af57ed9fSAtsushi Murai mib[0] = CTL_NET; 457af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 45853c9f6c0SAtsushi Murai mib[2] = 0; 45953c9f6c0SAtsushi Murai mib[3] = 0; 460af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 46153c9f6c0SAtsushi Murai mib[5] = 0; 46253c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 463dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 464afc7fa2cSBrian Somers strerror(errno)); 46553c9f6c0SAtsushi Murai return; 46653c9f6c0SAtsushi Murai } 467af57ed9fSAtsushi Murai 468af57ed9fSAtsushi Murai sp = malloc(needed); 469af57ed9fSAtsushi Murai if (sp == NULL) 470af57ed9fSAtsushi Murai return; 471af57ed9fSAtsushi Murai 472af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 473dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 474afc7fa2cSBrian Somers strerror(errno)); 475af57ed9fSAtsushi Murai free(sp); 476af57ed9fSAtsushi Murai return; 477af57ed9fSAtsushi Murai } 478af57ed9fSAtsushi Murai ep = sp + needed; 479af57ed9fSAtsushi Murai 48032ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 48132ca3341SBrian Somers /* 48232ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 4836b457978SBrian Somers * deletes all non-cloned routes. This is done to avoid 48432ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 485ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 486ba081e43SBrian Somers * may have gone with route Y). 48732ca3341SBrian Somers */ 48832ca3341SBrian Somers if (RTF_WASCLONED == 0 && pass == 0) 48932ca3341SBrian Somers /* So we can't tell ! */ 49032ca3341SBrian Somers continue; 491af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 492af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4936b457978SBrian Somers route_ParseHdr(rtm, sa); 4946b457978SBrian Somers if (sa[RTAX_DST]) { 495dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 49632ca3341SBrian Somers " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 4975d5e5070SBrian Somers Index2Nam(rtm->rtm_index), rtm->rtm_flags, 4986b457978SBrian Somers inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 4996b457978SBrian Somers if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 500af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 5016b457978SBrian Somers if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 5026b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 50332ca3341SBrian Somers if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 50432ca3341SBrian Somers (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 5056b457978SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 5066b457978SBrian Somers pass); 5076b457978SBrian Somers bundle_SetRoute(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 5086b457978SBrian Somers sa_none, sa_none, 0, 0); 5095d5e5070SBrian Somers } else 510dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 51132ca3341SBrian Somers } else 512dd7e2610SBrian Somers log_Printf(LogDEBUG, 513dd7e2610SBrian Somers "route_IfDelete: Can't remove routes of %d family !\n", 5146b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family); 5156b457978SBrian Somers } 516af57ed9fSAtsushi Murai } 517af57ed9fSAtsushi Murai } 51832ca3341SBrian Somers } 519af57ed9fSAtsushi Murai free(sp); 520af57ed9fSAtsushi Murai } 521af57ed9fSAtsushi Murai 522af57ed9fSAtsushi Murai int 523944f7098SBrian Somers GetIfIndex(char *name) 524af57ed9fSAtsushi Murai { 5255d5e5070SBrian Somers int idx; 526b6e82f33SBrian Somers const char *got; 527944f7098SBrian Somers 5289cb1d89eSBrian Somers idx = 1; 5295d5e5070SBrian Somers while (strcmp(got = Index2Nam(idx), "???")) 5305d5e5070SBrian Somers if (!strcmp(got, name)) 5317a6f8720SBrian Somers return idx; 5325d5e5070SBrian Somers else 5335d5e5070SBrian Somers idx++; 5345d5e5070SBrian Somers return -1; 535af57ed9fSAtsushi Murai } 536bcc332bdSBrian Somers 537610b185fSBrian Somers void 538610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 539610b185fSBrian Somers struct in_addr me, struct in_addr peer) 540bcc332bdSBrian Somers { 541610b185fSBrian Somers struct in_addr none, del; 542bcc332bdSBrian Somers 543610b185fSBrian Somers none.s_addr = INADDR_ANY; 544610b185fSBrian Somers for (; r; r = r->next) { 545610b185fSBrian Somers if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 546610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 5472062443fSBrian Somers bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 548610b185fSBrian Somers r->dst = me; 549610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 550610b185fSBrian Somers r->gw = peer; 551610b185fSBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 552610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 5532062443fSBrian Somers bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 554610b185fSBrian Somers r->dst = peer; 555610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 556610b185fSBrian Somers r->gw = peer; 557610b185fSBrian Somers } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 558610b185fSBrian Somers r->gw = peer; 5592062443fSBrian Somers bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 560610b185fSBrian Somers } 561610b185fSBrian Somers } 562610b185fSBrian Somers 563610b185fSBrian Somers void 564610b185fSBrian Somers route_Clean(struct bundle *bundle, struct sticky_route *r) 565610b185fSBrian Somers { 566610b185fSBrian Somers struct in_addr none, del; 567610b185fSBrian Somers 568610b185fSBrian Somers none.s_addr = INADDR_ANY; 569610b185fSBrian Somers for (; r; r = r->next) { 570610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 5712062443fSBrian Somers bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 572610b185fSBrian Somers } 573610b185fSBrian Somers } 574610b185fSBrian Somers 575610b185fSBrian Somers void 576610b185fSBrian Somers route_Add(struct sticky_route **rp, int type, struct in_addr dst, 577610b185fSBrian Somers struct in_addr mask, struct in_addr gw) 578610b185fSBrian Somers { 579610b185fSBrian Somers struct sticky_route *r; 580610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 581610b185fSBrian Somers 582610b185fSBrian Somers r = NULL; 583610b185fSBrian Somers while (*rp) { 584183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 585183df580SBrian Somers (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 586972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 587972a1bcfSBrian Somers free(r); /* impossible really */ 588610b185fSBrian Somers r = *rp; 589610b185fSBrian Somers *rp = r->next; 590610b185fSBrian Somers } else 591610b185fSBrian Somers rp = &(*rp)->next; 592610b185fSBrian Somers } 593610b185fSBrian Somers 594610b185fSBrian Somers if (!r) 595610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 596610b185fSBrian Somers r->type = type; 597610b185fSBrian Somers r->next = NULL; 598610b185fSBrian Somers r->dst = dst; 599610b185fSBrian Somers r->mask = mask; 600610b185fSBrian Somers r->gw = gw; 601610b185fSBrian Somers *rp = r; 602610b185fSBrian Somers } 603610b185fSBrian Somers 604610b185fSBrian Somers void 605610b185fSBrian Somers route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 606610b185fSBrian Somers { 607610b185fSBrian Somers struct sticky_route *r; 608610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 609610b185fSBrian Somers 610610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 611610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 612610b185fSBrian Somers (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 613610b185fSBrian Somers r = *rp; 614610b185fSBrian Somers *rp = r->next; 615610b185fSBrian Somers free(r); 616bcc332bdSBrian Somers break; 617bcc332bdSBrian Somers } 618bcc332bdSBrian Somers } 619bcc332bdSBrian Somers } 620bcc332bdSBrian Somers 621610b185fSBrian Somers void 622610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 623610b185fSBrian Somers { 624610b185fSBrian Somers struct sticky_route *r, *rn; 625610b185fSBrian Somers 626610b185fSBrian Somers for (r = *rp; r; r = rn) { 627610b185fSBrian Somers rn = r->next; 628610b185fSBrian Somers free(r); 629610b185fSBrian Somers } 630610b185fSBrian Somers *rp = NULL; 631610b185fSBrian Somers } 632610b185fSBrian Somers 633610b185fSBrian Somers void 634972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 635972a1bcfSBrian Somers int indent) 636610b185fSBrian Somers { 637610b185fSBrian Somers int def; 638972a1bcfSBrian Somers int tlen = strlen(tag); 639610b185fSBrian Somers 640972a1bcfSBrian Somers if (tlen + 2 > indent) 641972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 642972a1bcfSBrian Somers else 643972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 644972a1bcfSBrian Somers 645610b185fSBrian Somers for (; r; r = r->next) { 646610b185fSBrian Somers def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 647610b185fSBrian Somers 648972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 649972a1bcfSBrian Somers tlen = 0; 650610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 651610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 652610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 653610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 654610b185fSBrian Somers else if (!def) 655610b185fSBrian Somers prompt_Printf(p, "%s", inet_ntoa(r->dst)); 656610b185fSBrian Somers 657610b185fSBrian Somers if (def) 658610b185fSBrian Somers prompt_Printf(p, "default "); 659610b185fSBrian Somers else 660610b185fSBrian Somers prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 661610b185fSBrian Somers 662610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 663610b185fSBrian Somers prompt_Printf(p, "HISADDR\n"); 664610b185fSBrian Somers else 665610b185fSBrian Somers prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 666610b185fSBrian Somers } 667bcc332bdSBrian Somers } 668