165309e5cSBrian Somers /*- 265309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 365309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 465309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 565309e5cSBrian Somers * All rights reserved. 6af57ed9fSAtsushi Murai * 765309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 865309e5cSBrian Somers * modification, are permitted provided that the following conditions 965309e5cSBrian Somers * are met: 1065309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1165309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1265309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1465309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 15af57ed9fSAtsushi Murai * 1665309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2065309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665309e5cSBrian Somers * SUCH DAMAGE. 27af57ed9fSAtsushi Murai * 2897d92980SPeter Wemm * $FreeBSD$ 29af57ed9fSAtsushi Murai */ 3075240ed1SBrian Somers 31972a1bcfSBrian Somers #include <sys/param.h> 3275240ed1SBrian Somers #include <sys/socket.h> 335d5e5070SBrian Somers #include <net/if_types.h> 34628d2ac1SGarrett Wollman #include <net/route.h> 35628d2ac1SGarrett Wollman #include <net/if.h> 36628d2ac1SGarrett Wollman #include <netinet/in.h> 37628d2ac1SGarrett Wollman #include <arpa/inet.h> 385d5e5070SBrian Somers #include <net/if_dl.h> 39eaa4df37SBrian Somers #include <netinet/in_systm.h> 40eaa4df37SBrian Somers #include <netinet/ip.h> 411fa665f5SBrian Somers #include <sys/un.h> 426b384664SBrian Somers #include <netdb.h> 43628d2ac1SGarrett Wollman 4475240ed1SBrian Somers #include <errno.h> 4575240ed1SBrian Somers #include <stdio.h> 4675240ed1SBrian Somers #include <stdlib.h> 4775240ed1SBrian Somers #include <string.h> 4875240ed1SBrian Somers #include <sys/sysctl.h> 4985b542cfSBrian Somers #include <termios.h> 5003a2501aSBrian Somers #include <unistd.h> 5175240ed1SBrian Somers 525d9e6103SBrian Somers #include "layer.h" 53c9e11a11SBrian Somers #include "defs.h" 54b6e82f33SBrian Somers #include "command.h" 5575240ed1SBrian Somers #include "mbuf.h" 56215a4696SAtsushi Murai #include "log.h" 57bcc332bdSBrian Somers #include "iplist.h" 5829e275ceSBrian Somers #include "timer.h" 5929e275ceSBrian Somers #include "throughput.h" 60879ed6faSBrian Somers #include "lqr.h" 618c07a7b2SBrian Somers #include "hdlc.h" 627308ec68SBrian Somers #include "fsm.h" 633b0f8d2eSBrian Somers #include "lcp.h" 643b0f8d2eSBrian Somers #include "ccp.h" 653b0f8d2eSBrian Somers #include "link.h" 66eaa4df37SBrian Somers #include "slcompress.h" 6729e275ceSBrian Somers #include "ipcp.h" 685ca5389aSBrian Somers #include "filter.h" 692f786681SBrian Somers #include "descriptor.h" 703b0f8d2eSBrian Somers #include "mp.h" 71972a1bcfSBrian Somers #ifndef NORADIUS 72972a1bcfSBrian Somers #include "radius.h" 73972a1bcfSBrian Somers #endif 745828db6dSBrian Somers #include "bundle.h" 7575240ed1SBrian Somers #include "route.h" 7685b542cfSBrian Somers #include "prompt.h" 778fa6ebe4SBrian Somers #include "iface.h" 7803a2501aSBrian Somers #include "id.h" 79af57ed9fSAtsushi Murai 806b457978SBrian Somers 81af57ed9fSAtsushi Murai static void 82b6217683SBrian Somers p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 83b6217683SBrian Somers struct sockaddr *pmask, int width) 84af57ed9fSAtsushi Murai { 85b6e82f33SBrian Somers char buf[29]; 866b384664SBrian Somers struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 876b384664SBrian Somers struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 885d5e5070SBrian Somers struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 89af57ed9fSAtsushi Murai 906b384664SBrian Somers if (log_IsKept(LogDEBUG)) { 916b384664SBrian Somers char tmp[50]; 926b384664SBrian Somers 936b384664SBrian Somers log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 946b384664SBrian Somers log_Printf(LogDEBUG, " Family %d, len %d\n", 956b384664SBrian Somers (int)phost->sa_family, (int)phost->sa_len); 966b457978SBrian Somers inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 976b384664SBrian Somers log_Printf(LogDEBUG, " Addr %s\n", tmp); 986b384664SBrian Somers if (pmask) { 996b457978SBrian Somers inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 1006b384664SBrian Somers log_Printf(LogDEBUG, " Mask %s\n", tmp); 1016b384664SBrian Somers } 1026b384664SBrian Somers } 1036b384664SBrian Somers 1045d5e5070SBrian Somers switch (phost->sa_family) { 1055d5e5070SBrian Somers case AF_INET: 1065d5e5070SBrian Somers if (!phost) 1074bfaee90SBrian Somers buf[0] = '\0'; 1086b384664SBrian Somers else if (ihost4->sin_addr.s_addr == INADDR_ANY) 1094bfaee90SBrian Somers strcpy(buf, "default"); 1106b384664SBrian Somers else if (!pmask) 1116b384664SBrian Somers strcpy(buf, inet_ntoa(ihost4->sin_addr)); 1125d5e5070SBrian Somers else { 1136b384664SBrian Somers u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 1143a2e4f62SBrian Somers u_int32_t tst; 1155d5e5070SBrian Somers int bits; 1165d5e5070SBrian Somers int len; 1175d5e5070SBrian Somers struct sockaddr_in net; 1185d5e5070SBrian Somers 1195d5e5070SBrian Somers for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 1205d5e5070SBrian Somers if (msk & tst) 1215d5e5070SBrian Somers break; 1225d5e5070SBrian Somers 1235d5e5070SBrian Somers for (tst <<= 1; tst; tst <<= 1) 1245d5e5070SBrian Somers if (!(msk & tst)) 1255d5e5070SBrian Somers break; 1265d5e5070SBrian Somers 1276b384664SBrian Somers net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 12883c0952dSBrian Somers strcpy(buf, inet_ntoa(net.sin_addr)); 1295d5e5070SBrian Somers for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 1305d5e5070SBrian Somers if (strcmp(buf + len - 2, ".0")) 1315d5e5070SBrian Somers break; 1325d5e5070SBrian Somers 1335d5e5070SBrian Somers if (tst) /* non-contiguous :-( */ 1343a2e4f62SBrian Somers sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 1355d5e5070SBrian Somers else 1365d5e5070SBrian Somers sprintf(buf + strlen(buf), "/%d", bits); 137927145beSBrian Somers } 1385d5e5070SBrian Somers break; 1395d5e5070SBrian Somers 1405d5e5070SBrian Somers case AF_LINK: 1414bfaee90SBrian Somers if (dl->sdl_nlen) 1424bfaee90SBrian Somers snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 143c4c4aaacSBrian Somers else if (dl->sdl_alen) { 144c4c4aaacSBrian Somers if (dl->sdl_type == IFT_ETHER) { 14570ee81ffSBrian Somers if (dl->sdl_alen < sizeof buf / 3) { 1465d5e5070SBrian Somers int f; 1475d5e5070SBrian Somers u_char *MAC; 1485d5e5070SBrian Somers 1495d5e5070SBrian Somers MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 1505d5e5070SBrian Somers for (f = 0; f < dl->sdl_alen; f++) 1515d5e5070SBrian Somers sprintf(buf+f*3, "%02x:", MAC[f]); 1525d5e5070SBrian Somers buf[f*3-1] = '\0'; 1535d5e5070SBrian Somers } else 15483c0952dSBrian Somers strcpy(buf, "??:??:??:??:??:??"); 155c4c4aaacSBrian Somers } else 1564bfaee90SBrian Somers sprintf(buf, "<IFT type %d>", dl->sdl_type); 157c4c4aaacSBrian Somers } else if (dl->sdl_slen) 1584bfaee90SBrian Somers sprintf(buf, "<slen %d?>", dl->sdl_slen); 1594bfaee90SBrian Somers else 1604bfaee90SBrian Somers sprintf(buf, "link#%d", dl->sdl_index); 1615d5e5070SBrian Somers break; 1625d5e5070SBrian Somers 1636b384664SBrian Somers #ifndef NOINET6 1646b384664SBrian Somers case AF_INET6: 1656b384664SBrian Somers if (!phost) 1666b384664SBrian Somers buf[0] = '\0'; 1676b384664SBrian Somers else { 1686b384664SBrian Somers const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 1696b384664SBrian Somers struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 1706b384664SBrian Somers struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 1716b384664SBrian Somers int masklen, len; 1726b384664SBrian Somers const u_char *c; 1736b384664SBrian Somers 1746b384664SBrian Somers /* XXX: ?????!?!?!!!!! This is horrible ! */ 1756b384664SBrian Somers if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 1766b384664SBrian Somers IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 1776b384664SBrian Somers ihost6->sin6_scope_id = 1786b384664SBrian Somers ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 1796b384664SBrian Somers *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 1806b384664SBrian Somers } 1816b384664SBrian Somers 1826b384664SBrian Somers if (mask6) { 1836b384664SBrian Somers const u_char *p, *end; 1846b384664SBrian Somers 1856b384664SBrian Somers p = (const u_char *)&mask6->sin6_addr; 1866b384664SBrian Somers end = p + 16; 1876b384664SBrian Somers for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 1886b384664SBrian Somers masklen += 8; 1896b384664SBrian Somers 1906b384664SBrian Somers if (p < end) { 1916b384664SBrian Somers for (c = masks; c < masks + sizeof masks; c++) 1926b384664SBrian Somers if (*c == *p) { 1936b384664SBrian Somers masklen += c - masks; 1946b384664SBrian Somers break; 1956b384664SBrian Somers } 1966b384664SBrian Somers } 1976b384664SBrian Somers } else 1986b384664SBrian Somers masklen = 128; 1996b384664SBrian Somers 2006b384664SBrian Somers if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 2016b384664SBrian Somers snprintf(buf, sizeof buf, "default"); 2026b384664SBrian Somers else { 2036b384664SBrian Somers getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 2046b384664SBrian Somers NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 2056b384664SBrian Somers if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 2066b384664SBrian Somers snprintf(buf + len, sizeof buf - len, "/%d", masklen); 2076b384664SBrian Somers } 2086b384664SBrian Somers } 2096b384664SBrian Somers break; 2106b384664SBrian Somers #endif 2116b384664SBrian Somers 2125d5e5070SBrian Somers default: 2134bfaee90SBrian Somers sprintf(buf, "<AF type %d>", phost->sa_family); 2145d5e5070SBrian Somers break; 2155d5e5070SBrian Somers } 2165d5e5070SBrian Somers 217b6217683SBrian Somers prompt_Printf(prompt, "%-*s ", width-1, buf); 218af57ed9fSAtsushi Murai } 219af57ed9fSAtsushi Murai 220aa8e0519SBrian Somers static struct bits { 2213f06c599SBrian Somers u_int32_t b_mask; 222af57ed9fSAtsushi Murai char b_val; 223af57ed9fSAtsushi Murai } bits[] = { 2245d5e5070SBrian Somers { RTF_UP, 'U' }, 2255d5e5070SBrian Somers { RTF_GATEWAY, 'G' }, 2265d5e5070SBrian Somers { RTF_HOST, 'H' }, 2275d5e5070SBrian Somers { RTF_REJECT, 'R' }, 2285d5e5070SBrian Somers { RTF_DYNAMIC, 'D' }, 2295d5e5070SBrian Somers { RTF_MODIFIED, 'M' }, 2305d5e5070SBrian Somers { RTF_DONE, 'd' }, 2315d5e5070SBrian Somers { RTF_CLONING, 'C' }, 2325d5e5070SBrian Somers { RTF_XRESOLVE, 'X' }, 2335d5e5070SBrian Somers { RTF_LLINFO, 'L' }, 2345d5e5070SBrian Somers { RTF_STATIC, 'S' }, 2355d5e5070SBrian Somers { RTF_PROTO1, '1' }, 2365d5e5070SBrian Somers { RTF_PROTO2, '2' }, 2375d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 23832ca3341SBrian Somers #ifdef RTF_WASCLONED 2395d5e5070SBrian Somers { RTF_WASCLONED, 'W' }, 24032ca3341SBrian Somers #endif 24132ca3341SBrian Somers #ifdef RTF_PRCLONING 2425d5e5070SBrian Somers { RTF_PRCLONING, 'c' }, 24332ca3341SBrian Somers #endif 24432ca3341SBrian Somers #ifdef RTF_PROTO3 2455d5e5070SBrian Somers { RTF_PROTO3, '3' }, 24632ca3341SBrian Somers #endif 24732ca3341SBrian Somers #ifdef RTF_BROADCAST 2485d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 2495d5e5070SBrian Somers #endif 2505d5e5070SBrian Somers { 0, '\0' } 251af57ed9fSAtsushi Murai }; 252af57ed9fSAtsushi Murai 25332ca3341SBrian Somers #ifndef RTF_WASCLONED 25432ca3341SBrian Somers #define RTF_WASCLONED (0) 25532ca3341SBrian Somers #endif 25632ca3341SBrian Somers 257af57ed9fSAtsushi Murai static void 2583f06c599SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, int max) 259af57ed9fSAtsushi Murai { 260af57ed9fSAtsushi Murai char name[33], *flags; 261af57ed9fSAtsushi Murai register struct bits *p = bits; 262af57ed9fSAtsushi Murai 26370ee81ffSBrian Somers if (max > sizeof name - 1) 26470ee81ffSBrian Somers max = sizeof name - 1; 265d27d502cSBrian Somers 266d27d502cSBrian Somers for (flags = name; p->b_mask && flags - name < max; p++) 267af57ed9fSAtsushi Murai if (p->b_mask & f) 268af57ed9fSAtsushi Murai *flags++ = p->b_val; 269af57ed9fSAtsushi Murai *flags = '\0'; 270b6217683SBrian Somers prompt_Printf(prompt, "%-*.*s", max, max, name); 271af57ed9fSAtsushi Murai } 272af57ed9fSAtsushi Murai 273c6fe0cb2SBrian Somers const char * 2745d5e5070SBrian Somers Index2Nam(int idx) 2755d5e5070SBrian Somers { 276d93d3a9cSBrian Somers /* 277d93d3a9cSBrian Somers * XXX: Maybe we should select() on the routing socket so that we can 278d93d3a9cSBrian Somers * notice interfaces that come & go (PCCARD support). 279d93d3a9cSBrian Somers * Or we could even support a signal that resets these so that 280d93d3a9cSBrian Somers * the PCCARD insert/remove events can signal ppp. 281d93d3a9cSBrian Somers */ 282d93d3a9cSBrian Somers static char **ifs; /* Figure these out once */ 283d93d3a9cSBrian Somers static int nifs, debug_done; /* Figure out how many once, and debug once */ 2845d5e5070SBrian Somers 2858473f372SBrian Somers if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 286b1435e41SBrian Somers int mib[6], have, had; 287e7250038SBrian Somers size_t needed; 2885d5e5070SBrian Somers char *buf, *ptr, *end; 2895d5e5070SBrian Somers struct sockaddr_dl *dl; 2905d5e5070SBrian Somers struct if_msghdr *ifm; 2915d5e5070SBrian Somers 2928473f372SBrian Somers if (ifs) { 2938473f372SBrian Somers free(ifs); 2948473f372SBrian Somers ifs = NULL; 2958473f372SBrian Somers nifs = 0; 2968473f372SBrian Somers } 2978473f372SBrian Somers debug_done = 0; 2988473f372SBrian Somers 2995d5e5070SBrian Somers mib[0] = CTL_NET; 3005d5e5070SBrian Somers mib[1] = PF_ROUTE; 3015d5e5070SBrian Somers mib[2] = 0; 3025d5e5070SBrian Somers mib[3] = 0; 3035d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 3045d5e5070SBrian Somers mib[5] = 0; 3055d5e5070SBrian Somers 3065d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 307a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 308a33b2ef7SBrian Somers strerror(errno)); 309d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3105d5e5070SBrian Somers } 3115d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 312d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3135d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 3145d5e5070SBrian Somers free(buf); 315d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3165d5e5070SBrian Somers } 3175d5e5070SBrian Somers end = buf + needed; 3185d5e5070SBrian Somers 319b1435e41SBrian Somers have = 0; 3209cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 3215d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 3226b457978SBrian Somers if (ifm->ifm_type != RTM_IFINFO) 32324731321SBrian Somers continue; 3245d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 325b1435e41SBrian Somers if (ifm->ifm_index > 0) { 326b1435e41SBrian Somers if (ifm->ifm_index > have) { 327fc254be9SBrian Somers char **newifs; 328fc254be9SBrian Somers 329b1435e41SBrian Somers had = have; 330b1435e41SBrian Somers have = ifm->ifm_index + 5; 331b1435e41SBrian Somers if (had) 332fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 333b1435e41SBrian Somers else 334fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 335fc254be9SBrian Somers if (!newifs) { 336dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 337b1435e41SBrian Somers nifs = 0; 3388473f372SBrian Somers if (ifs) { 339fc254be9SBrian Somers free(ifs); 3408473f372SBrian Somers ifs = NULL; 3418473f372SBrian Somers } 3428473f372SBrian Somers free(buf); 343d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 344b1435e41SBrian Somers } 345fc254be9SBrian Somers ifs = newifs; 346b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 347b1435e41SBrian Somers } 348b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 349b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 350b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 351b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 352b1435e41SBrian Somers if (nifs < ifm->ifm_index) 3539cb1d89eSBrian Somers nifs = ifm->ifm_index; 354b1435e41SBrian Somers } 355dd7e2610SBrian Somers } else if (log_IsKept(LogDEBUG)) 356dd7e2610SBrian Somers log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 3579cb1d89eSBrian Somers ifm->ifm_index); 3585d5e5070SBrian Somers } 3595d5e5070SBrian Somers free(buf); 3605d5e5070SBrian Somers } 3615d5e5070SBrian Somers 362dd7e2610SBrian Somers if (log_IsKept(LogDEBUG) && !debug_done) { 3639cb1d89eSBrian Somers int f; 3649cb1d89eSBrian Somers 365dd7e2610SBrian Somers log_Printf(LogDEBUG, "Found the following interfaces:\n"); 3669cb1d89eSBrian Somers for (f = 0; f < nifs; f++) 367b1435e41SBrian Somers if (ifs[f] != NULL) 368dd7e2610SBrian Somers log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 3699cb1d89eSBrian Somers debug_done = 1; 3709cb1d89eSBrian Somers } 3719cb1d89eSBrian Somers 372b1435e41SBrian Somers if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 373d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3749cb1d89eSBrian Somers 3759cb1d89eSBrian Somers return ifs[idx-1]; 3765d5e5070SBrian Somers } 3775d5e5070SBrian Somers 3786b457978SBrian Somers void 3796b457978SBrian Somers route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 3806b457978SBrian Somers { 3816b457978SBrian Somers char *wp; 3826b457978SBrian Somers int rtax; 3836b457978SBrian Somers 3846b457978SBrian Somers wp = (char *)(rtm + 1); 3856b457978SBrian Somers 3866b457978SBrian Somers for (rtax = 0; rtax < RTAX_MAX; rtax++) 3876b457978SBrian Somers if (rtm->rtm_addrs & (1 << rtax)) { 3886b457978SBrian Somers sa[rtax] = (struct sockaddr *)wp; 3896b457978SBrian Somers wp += ROUNDUP(sa[rtax]->sa_len); 3906b457978SBrian Somers } else 3916b457978SBrian Somers sa[rtax] = NULL; 3926b457978SBrian Somers } 3936b457978SBrian Somers 394af57ed9fSAtsushi Murai int 395dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 396af57ed9fSAtsushi Murai { 397af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3986b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 3996b457978SBrian Somers char *sp, *ep, *cp; 400e7250038SBrian Somers size_t needed; 401af57ed9fSAtsushi Murai int mib[6]; 402af57ed9fSAtsushi Murai 403af57ed9fSAtsushi Murai mib[0] = CTL_NET; 404af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 40553c9f6c0SAtsushi Murai mib[2] = 0; 40653c9f6c0SAtsushi Murai mib[3] = 0; 407af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 40853c9f6c0SAtsushi Murai mib[5] = 0; 40953c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 410dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 41153c9f6c0SAtsushi Murai return (1); 41253c9f6c0SAtsushi Murai } 413af57ed9fSAtsushi Murai sp = malloc(needed); 414af57ed9fSAtsushi Murai if (sp == NULL) 415af57ed9fSAtsushi Murai return (1); 41653c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 417dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 418b0cdb3ceSJordan K. Hubbard free(sp); 419af57ed9fSAtsushi Murai return (1); 42053c9f6c0SAtsushi Murai } 421af57ed9fSAtsushi Murai ep = sp + needed; 422af57ed9fSAtsushi Murai 423b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 424b6217683SBrian Somers "Destination", "Gateway"); 425af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 426af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4275d5e5070SBrian Somers 4286b457978SBrian Somers route_ParseHdr(rtm, sa); 4296b384664SBrian Somers 4306b457978SBrian Somers if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 4316b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 4326b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 4335d5e5070SBrian Somers 434b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 435b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 4366b384664SBrian Somers } else 4376b384664SBrian Somers prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 438af57ed9fSAtsushi Murai } 439b0cdb3ceSJordan K. Hubbard free(sp); 440927145beSBrian Somers return 0; 441af57ed9fSAtsushi Murai } 442af57ed9fSAtsushi Murai 443af57ed9fSAtsushi Murai /* 444af57ed9fSAtsushi Murai * Delete routes associated with our interface 445af57ed9fSAtsushi Murai */ 446af57ed9fSAtsushi Murai void 447dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 448af57ed9fSAtsushi Murai { 449af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 4506b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 4516b457978SBrian Somers struct sockaddr_in **in; 4526b457978SBrian Somers struct in_addr sa_none; 453e7250038SBrian Somers int pass; 454e7250038SBrian Somers size_t needed; 455af57ed9fSAtsushi Murai char *sp, *cp, *ep; 456af57ed9fSAtsushi Murai int mib[6]; 457af57ed9fSAtsushi Murai 4588fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 459f01e577bSBrian Somers sa_none.s_addr = INADDR_ANY; 4606b457978SBrian Somers in = (struct sockaddr_in **)sa; 461927145beSBrian Somers 462af57ed9fSAtsushi Murai mib[0] = CTL_NET; 463af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 46453c9f6c0SAtsushi Murai mib[2] = 0; 46553c9f6c0SAtsushi Murai mib[3] = 0; 466af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 46753c9f6c0SAtsushi Murai mib[5] = 0; 46853c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 469dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 470afc7fa2cSBrian Somers strerror(errno)); 47153c9f6c0SAtsushi Murai return; 47253c9f6c0SAtsushi Murai } 473af57ed9fSAtsushi Murai 474af57ed9fSAtsushi Murai sp = malloc(needed); 475af57ed9fSAtsushi Murai if (sp == NULL) 476af57ed9fSAtsushi Murai return; 477af57ed9fSAtsushi Murai 478af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 479dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 480afc7fa2cSBrian Somers strerror(errno)); 481af57ed9fSAtsushi Murai free(sp); 482af57ed9fSAtsushi Murai return; 483af57ed9fSAtsushi Murai } 484af57ed9fSAtsushi Murai ep = sp + needed; 485af57ed9fSAtsushi Murai 48632ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 48732ca3341SBrian Somers /* 48832ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 4896b457978SBrian Somers * deletes all non-cloned routes. This is done to avoid 49032ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 491ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 492ba081e43SBrian Somers * may have gone with route Y). 49332ca3341SBrian Somers */ 49432ca3341SBrian Somers if (RTF_WASCLONED == 0 && pass == 0) 49532ca3341SBrian Somers /* So we can't tell ! */ 49632ca3341SBrian Somers continue; 497af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 498af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4996b457978SBrian Somers route_ParseHdr(rtm, sa); 500759c81cbSBrian Somers if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET) { 501dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 50232ca3341SBrian Somers " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 5035d5e5070SBrian Somers Index2Nam(rtm->rtm_index), rtm->rtm_flags, 5046b457978SBrian Somers inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 5056b457978SBrian Somers if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 506af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 5076b457978SBrian Somers if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 5086b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 50932ca3341SBrian Somers if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 51032ca3341SBrian Somers (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 5116b457978SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 5126b457978SBrian Somers pass); 51303a2501aSBrian Somers rt_Set(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 5146b457978SBrian Somers sa_none, sa_none, 0, 0); 5155d5e5070SBrian Somers } else 516dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 51732ca3341SBrian Somers } else 518dd7e2610SBrian Somers log_Printf(LogDEBUG, 519dd7e2610SBrian Somers "route_IfDelete: Can't remove routes of %d family !\n", 5206b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family); 5216b457978SBrian Somers } 522af57ed9fSAtsushi Murai } 523af57ed9fSAtsushi Murai } 52432ca3341SBrian Somers } 525af57ed9fSAtsushi Murai free(sp); 526af57ed9fSAtsushi Murai } 527af57ed9fSAtsushi Murai 52803a2501aSBrian Somers 52903a2501aSBrian Somers /* 53003a2501aSBrian Somers * Update the MTU on all routes for the given interface 53103a2501aSBrian Somers */ 53203a2501aSBrian Somers void 53303a2501aSBrian Somers route_UpdateMTU(struct bundle *bundle) 53403a2501aSBrian Somers { 53503a2501aSBrian Somers struct rt_msghdr *rtm; 53603a2501aSBrian Somers struct sockaddr *sa[RTAX_MAX]; 53703a2501aSBrian Somers struct sockaddr_in **in; 53803a2501aSBrian Somers size_t needed; 53903a2501aSBrian Somers char *sp, *cp, *ep; 54003a2501aSBrian Somers int mib[6]; 54103a2501aSBrian Somers 54203a2501aSBrian Somers log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 54303a2501aSBrian Somers in = (struct sockaddr_in **)sa; 54403a2501aSBrian Somers 54503a2501aSBrian Somers mib[0] = CTL_NET; 54603a2501aSBrian Somers mib[1] = PF_ROUTE; 54703a2501aSBrian Somers mib[2] = 0; 54803a2501aSBrian Somers mib[3] = 0; 54903a2501aSBrian Somers mib[4] = NET_RT_DUMP; 55003a2501aSBrian Somers mib[5] = 0; 55103a2501aSBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 55203a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 55303a2501aSBrian Somers strerror(errno)); 55403a2501aSBrian Somers return; 55503a2501aSBrian Somers } 55603a2501aSBrian Somers 55703a2501aSBrian Somers sp = malloc(needed); 55803a2501aSBrian Somers if (sp == NULL) 55903a2501aSBrian Somers return; 56003a2501aSBrian Somers 56103a2501aSBrian Somers if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 56203a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 56303a2501aSBrian Somers strerror(errno)); 56403a2501aSBrian Somers free(sp); 56503a2501aSBrian Somers return; 56603a2501aSBrian Somers } 56703a2501aSBrian Somers ep = sp + needed; 56803a2501aSBrian Somers 56903a2501aSBrian Somers for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 57003a2501aSBrian Somers rtm = (struct rt_msghdr *)cp; 57103a2501aSBrian Somers route_ParseHdr(rtm, sa); 57203a2501aSBrian Somers if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET && 57303a2501aSBrian Somers sa[RTAX_GATEWAY] && /* sa[RTAX_NETMASK] && */ 57403a2501aSBrian Somers rtm->rtm_index == bundle->iface->index && 57503a2501aSBrian Somers (sa[RTAX_GATEWAY]->sa_family == AF_INET || 57603a2501aSBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK)) { 57703a2501aSBrian Somers log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s, mtu %d\n", 57803a2501aSBrian Somers rtm->rtm_index, Index2Nam(rtm->rtm_index), 57903a2501aSBrian Somers inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr), 58003a2501aSBrian Somers bundle->mtu); 58103a2501aSBrian Somers rt_Update(bundle, in[RTAX_DST]->sin_addr, 58203a2501aSBrian Somers in[RTAX_GATEWAY]->sin_addr); 58303a2501aSBrian Somers } 58403a2501aSBrian Somers } 58503a2501aSBrian Somers 58603a2501aSBrian Somers free(sp); 58703a2501aSBrian Somers } 58803a2501aSBrian Somers 589af57ed9fSAtsushi Murai int 590944f7098SBrian Somers GetIfIndex(char *name) 591af57ed9fSAtsushi Murai { 5925d5e5070SBrian Somers int idx; 593b6e82f33SBrian Somers const char *got; 594944f7098SBrian Somers 5959cb1d89eSBrian Somers idx = 1; 5965d5e5070SBrian Somers while (strcmp(got = Index2Nam(idx), "???")) 5975d5e5070SBrian Somers if (!strcmp(got, name)) 5987a6f8720SBrian Somers return idx; 5995d5e5070SBrian Somers else 6005d5e5070SBrian Somers idx++; 6015d5e5070SBrian Somers return -1; 602af57ed9fSAtsushi Murai } 603bcc332bdSBrian Somers 604610b185fSBrian Somers void 605610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 606d568d6c4SBrian Somers struct in_addr me, struct in_addr peer, struct in_addr dns[2]) 607bcc332bdSBrian Somers { 608610b185fSBrian Somers struct in_addr none, del; 609bcc332bdSBrian Somers 610610b185fSBrian Somers none.s_addr = INADDR_ANY; 611610b185fSBrian Somers for (; r; r = r->next) { 612610b185fSBrian Somers if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 613610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 61403a2501aSBrian Somers rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 615610b185fSBrian Somers r->dst = me; 616610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 617610b185fSBrian Somers r->gw = peer; 618610b185fSBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 619610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 62003a2501aSBrian Somers rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 621610b185fSBrian Somers r->dst = peer; 622610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 623610b185fSBrian Somers r->gw = peer; 624d568d6c4SBrian Somers } else if ((r->type & ROUTE_DSTDNS0) && r->dst.s_addr != peer.s_addr) { 625d568d6c4SBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 62603a2501aSBrian Somers rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 627d568d6c4SBrian Somers r->dst = dns[0]; 628d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 629d568d6c4SBrian Somers r->gw = peer; 630d568d6c4SBrian Somers } else if ((r->type & ROUTE_DSTDNS1) && r->dst.s_addr != peer.s_addr) { 631d568d6c4SBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 63203a2501aSBrian Somers rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 633d568d6c4SBrian Somers r->dst = dns[1]; 634d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 635d568d6c4SBrian Somers r->gw = peer; 636610b185fSBrian Somers } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 637610b185fSBrian Somers r->gw = peer; 63803a2501aSBrian Somers rt_Set(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 639610b185fSBrian Somers } 640610b185fSBrian Somers } 641610b185fSBrian Somers 642610b185fSBrian Somers void 643610b185fSBrian Somers route_Add(struct sticky_route **rp, int type, struct in_addr dst, 644610b185fSBrian Somers struct in_addr mask, struct in_addr gw) 645610b185fSBrian Somers { 646610b185fSBrian Somers struct sticky_route *r; 647610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 648610b185fSBrian Somers 649610b185fSBrian Somers r = NULL; 650610b185fSBrian Somers while (*rp) { 651183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 652183df580SBrian Somers (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 653972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 654972a1bcfSBrian Somers free(r); /* impossible really */ 655610b185fSBrian Somers r = *rp; 656610b185fSBrian Somers *rp = r->next; 657610b185fSBrian Somers } else 658610b185fSBrian Somers rp = &(*rp)->next; 659610b185fSBrian Somers } 660610b185fSBrian Somers 661610b185fSBrian Somers if (!r) 662610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 663610b185fSBrian Somers r->type = type; 664610b185fSBrian Somers r->next = NULL; 665610b185fSBrian Somers r->dst = dst; 666610b185fSBrian Somers r->mask = mask; 667610b185fSBrian Somers r->gw = gw; 668610b185fSBrian Somers *rp = r; 669610b185fSBrian Somers } 670610b185fSBrian Somers 671610b185fSBrian Somers void 672610b185fSBrian Somers route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 673610b185fSBrian Somers { 674610b185fSBrian Somers struct sticky_route *r; 675610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 676610b185fSBrian Somers 677610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 678610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 679610b185fSBrian Somers (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 680610b185fSBrian Somers r = *rp; 681610b185fSBrian Somers *rp = r->next; 682610b185fSBrian Somers free(r); 683bcc332bdSBrian Somers break; 684bcc332bdSBrian Somers } 685bcc332bdSBrian Somers } 686bcc332bdSBrian Somers } 687bcc332bdSBrian Somers 688610b185fSBrian Somers void 689610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 690610b185fSBrian Somers { 691610b185fSBrian Somers struct sticky_route *r, *rn; 692610b185fSBrian Somers 693610b185fSBrian Somers for (r = *rp; r; r = rn) { 694610b185fSBrian Somers rn = r->next; 695610b185fSBrian Somers free(r); 696610b185fSBrian Somers } 697610b185fSBrian Somers *rp = NULL; 698610b185fSBrian Somers } 699610b185fSBrian Somers 700610b185fSBrian Somers void 701972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 702972a1bcfSBrian Somers int indent) 703610b185fSBrian Somers { 704610b185fSBrian Somers int def; 705972a1bcfSBrian Somers int tlen = strlen(tag); 706610b185fSBrian Somers 707972a1bcfSBrian Somers if (tlen + 2 > indent) 708972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 709972a1bcfSBrian Somers else 710972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 711972a1bcfSBrian Somers 712610b185fSBrian Somers for (; r; r = r->next) { 713610b185fSBrian Somers def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 714610b185fSBrian Somers 715972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 716972a1bcfSBrian Somers tlen = 0; 717610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 718610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 719610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 720610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 721d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS0) 722d568d6c4SBrian Somers prompt_Printf(p, "DNS0"); 723d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS1) 724d568d6c4SBrian Somers prompt_Printf(p, "DNS1"); 725610b185fSBrian Somers else if (!def) 726610b185fSBrian Somers prompt_Printf(p, "%s", inet_ntoa(r->dst)); 727610b185fSBrian Somers 728610b185fSBrian Somers if (def) 729610b185fSBrian Somers prompt_Printf(p, "default "); 730610b185fSBrian Somers else 731610b185fSBrian Somers prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 732610b185fSBrian Somers 733610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 734610b185fSBrian Somers prompt_Printf(p, "HISADDR\n"); 735610b185fSBrian Somers else 736610b185fSBrian Somers prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 737610b185fSBrian Somers } 738bcc332bdSBrian Somers } 73903a2501aSBrian Somers 74003a2501aSBrian Somers struct rtmsg { 74103a2501aSBrian Somers struct rt_msghdr m_rtm; 74203a2501aSBrian Somers char m_space[64]; 74303a2501aSBrian Somers }; 74403a2501aSBrian Somers 74503a2501aSBrian Somers int 74603a2501aSBrian Somers rt_Set(struct bundle *bundle, int cmd, struct in_addr dst, 74703a2501aSBrian Somers struct in_addr gateway, struct in_addr mask, int bang, int ssh) 74803a2501aSBrian Somers { 74903a2501aSBrian Somers struct rtmsg rtmes; 75003a2501aSBrian Somers int s, nb, wb; 75103a2501aSBrian Somers char *cp; 75203a2501aSBrian Somers const char *cmdstr; 75303a2501aSBrian Somers struct sockaddr_in rtdata; 75403a2501aSBrian Somers int result = 1; 75503a2501aSBrian Somers 75603a2501aSBrian Somers if (bang) 75703a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 75803a2501aSBrian Somers else 75903a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 76003a2501aSBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 76103a2501aSBrian Somers if (s < 0) { 76203a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 76303a2501aSBrian Somers return result; 76403a2501aSBrian Somers } 76503a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 76603a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 76703a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd; 76803a2501aSBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 76903a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 77003a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 77103a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 77203a2501aSBrian Somers 77303a2501aSBrian Somers if (cmd == RTM_ADD) { 77403a2501aSBrian Somers if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 77503a2501aSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 77603a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 77703a2501aSBrian Somers } 77803a2501aSBrian Somers if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 77903a2501aSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 78003a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 78103a2501aSBrian Somers } 78203a2501aSBrian Somers } 78303a2501aSBrian Somers 78403a2501aSBrian Somers memset(&rtdata, '\0', sizeof rtdata); 78503a2501aSBrian Somers rtdata.sin_len = sizeof rtdata; 78603a2501aSBrian Somers rtdata.sin_family = AF_INET; 78703a2501aSBrian Somers rtdata.sin_port = 0; 78803a2501aSBrian Somers rtdata.sin_addr = dst; 78903a2501aSBrian Somers 79003a2501aSBrian Somers cp = rtmes.m_space; 79103a2501aSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 79203a2501aSBrian Somers cp += rtdata.sin_len; 79303a2501aSBrian Somers if (cmd == RTM_ADD) { 79403a2501aSBrian Somers if (gateway.s_addr == INADDR_ANY) { 79503a2501aSBrian Somers if (!ssh) 79603a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: Cannot add a route with" 79703a2501aSBrian Somers " destination 0.0.0.0\n"); 79803a2501aSBrian Somers close(s); 79903a2501aSBrian Somers return result; 80003a2501aSBrian Somers } else { 80103a2501aSBrian Somers rtdata.sin_addr = gateway; 80203a2501aSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 80303a2501aSBrian Somers cp += rtdata.sin_len; 80403a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 80503a2501aSBrian Somers } 80603a2501aSBrian Somers } 80703a2501aSBrian Somers 80803a2501aSBrian Somers if (dst.s_addr == INADDR_ANY) 80903a2501aSBrian Somers mask.s_addr = INADDR_ANY; 81003a2501aSBrian Somers 81103a2501aSBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 81203a2501aSBrian Somers rtdata.sin_addr = mask; 81303a2501aSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 81403a2501aSBrian Somers cp += rtdata.sin_len; 81503a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 81603a2501aSBrian Somers } 81703a2501aSBrian Somers 81803a2501aSBrian Somers nb = cp - (char *)&rtmes; 81903a2501aSBrian Somers rtmes.m_rtm.rtm_msglen = nb; 82003a2501aSBrian Somers wb = ID0write(s, &rtmes, nb); 82103a2501aSBrian Somers if (wb < 0) { 82203a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set failure:\n"); 82303a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 82403a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", inet_ntoa(dst)); 82503a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", 82603a2501aSBrian Somers inet_ntoa(gateway)); 82703a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Mask = %s\n", inet_ntoa(mask)); 82803a2501aSBrian Somers failed: 82903a2501aSBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 83003a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 83103a2501aSBrian Somers if (!bang) { 83203a2501aSBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 83303a2501aSBrian Somers dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 83403a2501aSBrian Somers result = 0; /* Don't add to our dynamic list */ 83503a2501aSBrian Somers } else { 83603a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 83703a2501aSBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 83803a2501aSBrian Somers goto failed; 83903a2501aSBrian Somers } 84003a2501aSBrian Somers } else if (cmd == RTM_DELETE && 84103a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 84203a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 84303a2501aSBrian Somers if (!bang) 84403a2501aSBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 84503a2501aSBrian Somers inet_ntoa(dst)); 84603a2501aSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 84703a2501aSBrian Somers if (!ssh || errno != ENETUNREACH) 84803a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 84903a2501aSBrian Somers inet_ntoa(dst), strerror(errno)); 85003a2501aSBrian Somers } else 85103a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 85203a2501aSBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 85303a2501aSBrian Somers } 85403a2501aSBrian Somers 85503a2501aSBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 85603a2501aSBrian Somers wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 85703a2501aSBrian Somers close(s); 85803a2501aSBrian Somers 85903a2501aSBrian Somers return result; 86003a2501aSBrian Somers } 86103a2501aSBrian Somers 86203a2501aSBrian Somers void 86303a2501aSBrian Somers rt_Update(struct bundle *bundle, struct in_addr dst, struct in_addr gw) 86403a2501aSBrian Somers { 86503a2501aSBrian Somers struct rtmsg rtmes; 86603a2501aSBrian Somers int s, wb; 86703a2501aSBrian Somers struct sockaddr_in rtdata; 86803a2501aSBrian Somers 86903a2501aSBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 87003a2501aSBrian Somers if (s < 0) { 87103a2501aSBrian Somers log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 87203a2501aSBrian Somers return; 87303a2501aSBrian Somers } 87403a2501aSBrian Somers 87503a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 87603a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 87703a2501aSBrian Somers rtmes.m_rtm.rtm_type = RTM_CHANGE; 87803a2501aSBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 87903a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 88003a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 88103a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 88203a2501aSBrian Somers 88303a2501aSBrian Somers if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 88403a2501aSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 88503a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 88603a2501aSBrian Somers } 88703a2501aSBrian Somers 88803a2501aSBrian Somers if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 88903a2501aSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 89003a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 89103a2501aSBrian Somers } 89203a2501aSBrian Somers 89303a2501aSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->mtu; 89403a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_MTU; 89503a2501aSBrian Somers 89603a2501aSBrian Somers memset(&rtdata, '\0', sizeof rtdata); 89703a2501aSBrian Somers rtdata.sin_len = sizeof rtdata; 89803a2501aSBrian Somers rtdata.sin_family = AF_INET; 89903a2501aSBrian Somers rtdata.sin_port = 0; 90003a2501aSBrian Somers rtdata.sin_addr = dst; 90103a2501aSBrian Somers 90203a2501aSBrian Somers memcpy(rtmes.m_space, &rtdata, rtdata.sin_len); 90303a2501aSBrian Somers rtmes.m_rtm.rtm_msglen = rtmes.m_space + rtdata.sin_len - (char *)&rtmes; 90403a2501aSBrian Somers 90503a2501aSBrian Somers wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 90603a2501aSBrian Somers if (wb < 0) { 90703a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Update failure:\n"); 90803a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", inet_ntoa(dst)); 90903a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Update: Gateway = %s\n", inet_ntoa(gw)); 91003a2501aSBrian Somers 91103a2501aSBrian Somers if (rtmes.m_rtm.rtm_errno == 0) 91203a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 91303a2501aSBrian Somers inet_ntoa(dst), strerror(errno)); 91403a2501aSBrian Somers else 91503a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: %s\n", 91603a2501aSBrian Somers inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 91703a2501aSBrian Somers } 91803a2501aSBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = Change, dst = %x, gateway = %x\n", 91903a2501aSBrian Somers wb, (unsigned)dst.s_addr, (unsigned)gw.s_addr); 92003a2501aSBrian Somers close(s); 92103a2501aSBrian Somers } 922