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> 42628d2ac1SGarrett Wollman 4375240ed1SBrian Somers #include <errno.h> 446eafd353SBrian Somers #include <stdarg.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" 6730949fd4SBrian Somers #include "ncpaddr.h" 6829e275ceSBrian Somers #include "ipcp.h" 695ca5389aSBrian Somers #include "filter.h" 702f786681SBrian Somers #include "descriptor.h" 713b0f8d2eSBrian Somers #include "mp.h" 72972a1bcfSBrian Somers #ifndef NORADIUS 73972a1bcfSBrian Somers #include "radius.h" 74972a1bcfSBrian Somers #endif 7530949fd4SBrian Somers #include "ipv6cp.h" 7630949fd4SBrian Somers #include "ncp.h" 775828db6dSBrian Somers #include "bundle.h" 7875240ed1SBrian Somers #include "route.h" 7985b542cfSBrian Somers #include "prompt.h" 808fa6ebe4SBrian Somers #include "iface.h" 8103a2501aSBrian Somers #include "id.h" 82af57ed9fSAtsushi Murai 836b457978SBrian Somers 84af57ed9fSAtsushi Murai static void 85b6217683SBrian Somers p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 86b6217683SBrian Somers struct sockaddr *pmask, int width) 87af57ed9fSAtsushi Murai { 8830949fd4SBrian Somers struct ncprange range; 89b6e82f33SBrian Somers char buf[29]; 905d5e5070SBrian Somers struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 91af57ed9fSAtsushi Murai 926b384664SBrian Somers if (log_IsKept(LogDEBUG)) { 936b384664SBrian Somers char tmp[50]; 946b384664SBrian Somers 956b384664SBrian Somers log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 966b384664SBrian Somers log_Printf(LogDEBUG, " Family %d, len %d\n", 976b384664SBrian Somers (int)phost->sa_family, (int)phost->sa_len); 986b457978SBrian Somers inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 996b384664SBrian Somers log_Printf(LogDEBUG, " Addr %s\n", tmp); 1006b384664SBrian Somers if (pmask) { 1016b457978SBrian Somers inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 1026b384664SBrian Somers log_Printf(LogDEBUG, " Mask %s\n", tmp); 1036b384664SBrian Somers } 1046b384664SBrian Somers } 1056b384664SBrian Somers 1065d5e5070SBrian Somers switch (phost->sa_family) { 1075d5e5070SBrian Somers case AF_INET: 10830949fd4SBrian Somers #ifndef NOINET6 10930949fd4SBrian Somers case AF_INET6: 11030949fd4SBrian Somers #endif 11130949fd4SBrian Somers ncprange_setsa(&range, phost, pmask); 11230949fd4SBrian Somers if (ncprange_isdefault(&range)) 11330949fd4SBrian Somers prompt_Printf(prompt, "%-*s ", width - 1, "default"); 1145d5e5070SBrian Somers else 11530949fd4SBrian Somers prompt_Printf(prompt, "%-*s ", width - 1, ncprange_ntoa(&range)); 11630949fd4SBrian Somers return; 1175d5e5070SBrian Somers 1185d5e5070SBrian Somers case AF_LINK: 1194bfaee90SBrian Somers if (dl->sdl_nlen) 1204bfaee90SBrian Somers snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 121c4c4aaacSBrian Somers else if (dl->sdl_alen) { 122c4c4aaacSBrian Somers if (dl->sdl_type == IFT_ETHER) { 12370ee81ffSBrian Somers if (dl->sdl_alen < sizeof buf / 3) { 1245d5e5070SBrian Somers int f; 1255d5e5070SBrian Somers u_char *MAC; 1265d5e5070SBrian Somers 1275d5e5070SBrian Somers MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 1285d5e5070SBrian Somers for (f = 0; f < dl->sdl_alen; f++) 1295d5e5070SBrian Somers sprintf(buf+f*3, "%02x:", MAC[f]); 1305d5e5070SBrian Somers buf[f*3-1] = '\0'; 1315d5e5070SBrian Somers } else 13283c0952dSBrian Somers strcpy(buf, "??:??:??:??:??:??"); 133c4c4aaacSBrian Somers } else 1344bfaee90SBrian Somers sprintf(buf, "<IFT type %d>", dl->sdl_type); 135c4c4aaacSBrian Somers } else if (dl->sdl_slen) 1364bfaee90SBrian Somers sprintf(buf, "<slen %d?>", dl->sdl_slen); 1374bfaee90SBrian Somers else 1384bfaee90SBrian Somers sprintf(buf, "link#%d", dl->sdl_index); 1395d5e5070SBrian Somers break; 1405d5e5070SBrian Somers 1415d5e5070SBrian Somers default: 1424bfaee90SBrian Somers sprintf(buf, "<AF type %d>", phost->sa_family); 1435d5e5070SBrian Somers break; 1445d5e5070SBrian Somers } 1455d5e5070SBrian Somers 146b6217683SBrian Somers prompt_Printf(prompt, "%-*s ", width-1, buf); 147af57ed9fSAtsushi Murai } 148af57ed9fSAtsushi Murai 149aa8e0519SBrian Somers static struct bits { 1503f06c599SBrian Somers u_int32_t b_mask; 151af57ed9fSAtsushi Murai char b_val; 152af57ed9fSAtsushi Murai } bits[] = { 1535d5e5070SBrian Somers { RTF_UP, 'U' }, 1545d5e5070SBrian Somers { RTF_GATEWAY, 'G' }, 1555d5e5070SBrian Somers { RTF_HOST, 'H' }, 1565d5e5070SBrian Somers { RTF_REJECT, 'R' }, 1575d5e5070SBrian Somers { RTF_DYNAMIC, 'D' }, 1585d5e5070SBrian Somers { RTF_MODIFIED, 'M' }, 1595d5e5070SBrian Somers { RTF_DONE, 'd' }, 1605d5e5070SBrian Somers { RTF_CLONING, 'C' }, 1615d5e5070SBrian Somers { RTF_XRESOLVE, 'X' }, 1625d5e5070SBrian Somers { RTF_LLINFO, 'L' }, 1635d5e5070SBrian Somers { RTF_STATIC, 'S' }, 1645d5e5070SBrian Somers { RTF_PROTO1, '1' }, 1655d5e5070SBrian Somers { RTF_PROTO2, '2' }, 1665d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 16732ca3341SBrian Somers #ifdef RTF_WASCLONED 1685d5e5070SBrian Somers { RTF_WASCLONED, 'W' }, 16932ca3341SBrian Somers #endif 17032ca3341SBrian Somers #ifdef RTF_PRCLONING 1715d5e5070SBrian Somers { RTF_PRCLONING, 'c' }, 17232ca3341SBrian Somers #endif 17332ca3341SBrian Somers #ifdef RTF_PROTO3 1745d5e5070SBrian Somers { RTF_PROTO3, '3' }, 17532ca3341SBrian Somers #endif 17632ca3341SBrian Somers #ifdef RTF_BROADCAST 1775d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 1785d5e5070SBrian Somers #endif 1795d5e5070SBrian Somers { 0, '\0' } 180af57ed9fSAtsushi Murai }; 181af57ed9fSAtsushi Murai 18232ca3341SBrian Somers #ifndef RTF_WASCLONED 18332ca3341SBrian Somers #define RTF_WASCLONED (0) 18432ca3341SBrian Somers #endif 18532ca3341SBrian Somers 186af57ed9fSAtsushi Murai static void 187057f1760SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, unsigned max) 188af57ed9fSAtsushi Murai { 189af57ed9fSAtsushi Murai char name[33], *flags; 190af57ed9fSAtsushi Murai register struct bits *p = bits; 191af57ed9fSAtsushi Murai 19270ee81ffSBrian Somers if (max > sizeof name - 1) 19370ee81ffSBrian Somers max = sizeof name - 1; 194d27d502cSBrian Somers 195057f1760SBrian Somers for (flags = name; p->b_mask && flags - name < (int)max; p++) 196af57ed9fSAtsushi Murai if (p->b_mask & f) 197af57ed9fSAtsushi Murai *flags++ = p->b_val; 198af57ed9fSAtsushi Murai *flags = '\0'; 19900d9db03SBrian Somers prompt_Printf(prompt, "%-*.*s", (int)max, (int)max, name); 200af57ed9fSAtsushi Murai } 201af57ed9fSAtsushi Murai 202de59e178SBrian Somers static int route_nifs = -1; 203de59e178SBrian Somers 204c6fe0cb2SBrian Somers const char * 2055d5e5070SBrian Somers Index2Nam(int idx) 2065d5e5070SBrian Somers { 207d93d3a9cSBrian Somers /* 208d93d3a9cSBrian Somers * XXX: Maybe we should select() on the routing socket so that we can 209d93d3a9cSBrian Somers * notice interfaces that come & go (PCCARD support). 210d93d3a9cSBrian Somers * Or we could even support a signal that resets these so that 211d93d3a9cSBrian Somers * the PCCARD insert/remove events can signal ppp. 212d93d3a9cSBrian Somers */ 213d93d3a9cSBrian Somers static char **ifs; /* Figure these out once */ 214de59e178SBrian Somers static int debug_done; /* Debug once */ 2155d5e5070SBrian Somers 216de59e178SBrian Somers if (idx > route_nifs || (idx > 0 && ifs[idx-1] == NULL)) { 217b1435e41SBrian Somers int mib[6], have, had; 218e7250038SBrian Somers size_t needed; 2195d5e5070SBrian Somers char *buf, *ptr, *end; 2205d5e5070SBrian Somers struct sockaddr_dl *dl; 2215d5e5070SBrian Somers struct if_msghdr *ifm; 2225d5e5070SBrian Somers 2238473f372SBrian Somers if (ifs) { 2248473f372SBrian Somers free(ifs); 2258473f372SBrian Somers ifs = NULL; 226de59e178SBrian Somers route_nifs = 0; 2278473f372SBrian Somers } 2288473f372SBrian Somers debug_done = 0; 2298473f372SBrian Somers 2305d5e5070SBrian Somers mib[0] = CTL_NET; 2315d5e5070SBrian Somers mib[1] = PF_ROUTE; 2325d5e5070SBrian Somers mib[2] = 0; 2335d5e5070SBrian Somers mib[3] = 0; 2345d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 2355d5e5070SBrian Somers mib[5] = 0; 2365d5e5070SBrian Somers 2375d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 238a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 239a33b2ef7SBrian Somers strerror(errno)); 240d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2415d5e5070SBrian Somers } 2425d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 243d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2445d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 2455d5e5070SBrian Somers free(buf); 246d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2475d5e5070SBrian Somers } 2485d5e5070SBrian Somers end = buf + needed; 2495d5e5070SBrian Somers 250b1435e41SBrian Somers have = 0; 2519cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 2525d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 2536b457978SBrian Somers if (ifm->ifm_type != RTM_IFINFO) 25424731321SBrian Somers continue; 2555d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 256b1435e41SBrian Somers if (ifm->ifm_index > 0) { 257b1435e41SBrian Somers if (ifm->ifm_index > have) { 258fc254be9SBrian Somers char **newifs; 259fc254be9SBrian Somers 260b1435e41SBrian Somers had = have; 261b1435e41SBrian Somers have = ifm->ifm_index + 5; 262b1435e41SBrian Somers if (had) 263fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 264b1435e41SBrian Somers else 265fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 266fc254be9SBrian Somers if (!newifs) { 267dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 268de59e178SBrian Somers route_nifs = 0; 2698473f372SBrian Somers if (ifs) { 270fc254be9SBrian Somers free(ifs); 2718473f372SBrian Somers ifs = NULL; 2728473f372SBrian Somers } 2738473f372SBrian Somers free(buf); 274d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 275b1435e41SBrian Somers } 276fc254be9SBrian Somers ifs = newifs; 277b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 278b1435e41SBrian Somers } 279b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 280b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 2815d604c11SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) 2825d604c11SBrian Somers log_Printf(LogDEBUG, "Skipping interface %d: Out of memory\n", 2835d604c11SBrian Somers ifm->ifm_index); 2845d604c11SBrian Somers else { 285b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 286b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 287de59e178SBrian Somers if (route_nifs < ifm->ifm_index) 288de59e178SBrian Somers route_nifs = ifm->ifm_index; 289b1435e41SBrian Somers } 2905d604c11SBrian Somers } 291dd7e2610SBrian Somers } else if (log_IsKept(LogDEBUG)) 292dd7e2610SBrian Somers log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 2939cb1d89eSBrian Somers ifm->ifm_index); 2945d5e5070SBrian Somers } 2955d5e5070SBrian Somers free(buf); 2965d5e5070SBrian Somers } 2975d5e5070SBrian Somers 298dd7e2610SBrian Somers if (log_IsKept(LogDEBUG) && !debug_done) { 2999cb1d89eSBrian Somers int f; 3009cb1d89eSBrian Somers 301dd7e2610SBrian Somers log_Printf(LogDEBUG, "Found the following interfaces:\n"); 302de59e178SBrian Somers for (f = 0; f < route_nifs; f++) 303b1435e41SBrian Somers if (ifs[f] != NULL) 304dd7e2610SBrian Somers log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 3059cb1d89eSBrian Somers debug_done = 1; 3069cb1d89eSBrian Somers } 3079cb1d89eSBrian Somers 308de59e178SBrian Somers if (idx < 1 || idx > route_nifs || ifs[idx-1] == NULL) 309d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3109cb1d89eSBrian Somers 3119cb1d89eSBrian Somers return ifs[idx-1]; 3125d5e5070SBrian Somers } 3135d5e5070SBrian Somers 3146b457978SBrian Somers void 3156b457978SBrian Somers route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 3166b457978SBrian Somers { 3176b457978SBrian Somers char *wp; 3186b457978SBrian Somers int rtax; 3196b457978SBrian Somers 3206b457978SBrian Somers wp = (char *)(rtm + 1); 3216b457978SBrian Somers 3226b457978SBrian Somers for (rtax = 0; rtax < RTAX_MAX; rtax++) 3236b457978SBrian Somers if (rtm->rtm_addrs & (1 << rtax)) { 3246b457978SBrian Somers sa[rtax] = (struct sockaddr *)wp; 3256b457978SBrian Somers wp += ROUNDUP(sa[rtax]->sa_len); 326a3d71c3dSBrian Somers if (sa[rtax]->sa_family == 0) 327a3d71c3dSBrian Somers sa[rtax] = NULL; /* ??? */ 3286b457978SBrian Somers } else 3296b457978SBrian Somers sa[rtax] = NULL; 3306b457978SBrian Somers } 3316b457978SBrian Somers 332af57ed9fSAtsushi Murai int 333dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 334af57ed9fSAtsushi Murai { 335af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3366b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 3376b457978SBrian Somers char *sp, *ep, *cp; 338e7250038SBrian Somers size_t needed; 339af57ed9fSAtsushi Murai int mib[6]; 340af57ed9fSAtsushi Murai 341af57ed9fSAtsushi Murai mib[0] = CTL_NET; 342af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 34353c9f6c0SAtsushi Murai mib[2] = 0; 34453c9f6c0SAtsushi Murai mib[3] = 0; 345af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 34653c9f6c0SAtsushi Murai mib[5] = 0; 34753c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 348dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 34953c9f6c0SAtsushi Murai return (1); 35053c9f6c0SAtsushi Murai } 351af57ed9fSAtsushi Murai sp = malloc(needed); 352af57ed9fSAtsushi Murai if (sp == NULL) 353af57ed9fSAtsushi Murai return (1); 35453c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 355dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 356b0cdb3ceSJordan K. Hubbard free(sp); 357af57ed9fSAtsushi Murai return (1); 35853c9f6c0SAtsushi Murai } 359af57ed9fSAtsushi Murai ep = sp + needed; 360af57ed9fSAtsushi Murai 361b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 362b6217683SBrian Somers "Destination", "Gateway"); 363af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 364af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 3655d5e5070SBrian Somers 3666b457978SBrian Somers route_ParseHdr(rtm, sa); 3676b384664SBrian Somers 3686b457978SBrian Somers if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 3696b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 3706b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 3715d5e5070SBrian Somers 372b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 373b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 3746b384664SBrian Somers } else 3756b384664SBrian Somers prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 376af57ed9fSAtsushi Murai } 377b0cdb3ceSJordan K. Hubbard free(sp); 378927145beSBrian Somers return 0; 379af57ed9fSAtsushi Murai } 380af57ed9fSAtsushi Murai 381af57ed9fSAtsushi Murai /* 382af57ed9fSAtsushi Murai * Delete routes associated with our interface 383af57ed9fSAtsushi Murai */ 384af57ed9fSAtsushi Murai void 385dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 386af57ed9fSAtsushi Murai { 387af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3886b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 38930949fd4SBrian Somers struct ncprange range; 390e7250038SBrian Somers int pass; 391e7250038SBrian Somers size_t needed; 392af57ed9fSAtsushi Murai char *sp, *cp, *ep; 393af57ed9fSAtsushi Murai int mib[6]; 394af57ed9fSAtsushi Murai 3958fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 396927145beSBrian Somers 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_IfDelete: sysctl: estimate: %s\n", 405afc7fa2cSBrian Somers strerror(errno)); 40653c9f6c0SAtsushi Murai return; 40753c9f6c0SAtsushi Murai } 408af57ed9fSAtsushi Murai 409af57ed9fSAtsushi Murai sp = malloc(needed); 410af57ed9fSAtsushi Murai if (sp == NULL) 411af57ed9fSAtsushi Murai return; 412af57ed9fSAtsushi Murai 413af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 414dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 415afc7fa2cSBrian Somers strerror(errno)); 416af57ed9fSAtsushi Murai free(sp); 417af57ed9fSAtsushi Murai return; 418af57ed9fSAtsushi Murai } 419af57ed9fSAtsushi Murai ep = sp + needed; 420af57ed9fSAtsushi Murai 42132ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 42232ca3341SBrian Somers /* 42332ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 4246b457978SBrian Somers * deletes all non-cloned routes. This is done to avoid 42532ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 426ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 427ba081e43SBrian Somers * may have gone with route Y). 42832ca3341SBrian Somers */ 42932ca3341SBrian Somers if (RTF_WASCLONED == 0 && pass == 0) 43032ca3341SBrian Somers /* So we can't tell ! */ 43132ca3341SBrian Somers continue; 432af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 433af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4346b457978SBrian Somers route_ParseHdr(rtm, sa); 43530949fd4SBrian Somers if (rtm->rtm_index == bundle->iface->index && 43630949fd4SBrian Somers sa[RTAX_DST] && sa[RTAX_GATEWAY] && 43730949fd4SBrian Somers (sa[RTAX_DST]->sa_family == AF_INET 43830949fd4SBrian Somers #ifndef NOINET6 43930949fd4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 44030949fd4SBrian Somers #endif 44130949fd4SBrian Somers ) && 442af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 44330949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 44430949fd4SBrian Somers char gwstr[41]; 44530949fd4SBrian Somers struct ncpaddr gw; 44630949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 44730949fd4SBrian Somers ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]); 44830949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw)); 44930949fd4SBrian Somers log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr); 45030949fd4SBrian Somers } 4516b457978SBrian Somers if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 45230949fd4SBrian Somers #ifndef NOINET6 45330949fd4SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_INET6 || 45430949fd4SBrian Somers #endif 4556b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 45632ca3341SBrian Somers if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 45732ca3341SBrian Somers (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 45830949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 45930949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0); 4605d5e5070SBrian Somers } else 461dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 46232ca3341SBrian Somers } else 463dd7e2610SBrian Somers log_Printf(LogDEBUG, 46430949fd4SBrian Somers "route_IfDelete: Can't remove routes for family %d\n", 4656b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family); 4666b457978SBrian Somers } 467af57ed9fSAtsushi Murai } 468af57ed9fSAtsushi Murai } 469af57ed9fSAtsushi Murai free(sp); 470af57ed9fSAtsushi Murai } 471af57ed9fSAtsushi Murai 47203a2501aSBrian Somers 47303a2501aSBrian Somers /* 47403a2501aSBrian Somers * Update the MTU on all routes for the given interface 47503a2501aSBrian Somers */ 47603a2501aSBrian Somers void 47703a2501aSBrian Somers route_UpdateMTU(struct bundle *bundle) 47803a2501aSBrian Somers { 47903a2501aSBrian Somers struct rt_msghdr *rtm; 48003a2501aSBrian Somers struct sockaddr *sa[RTAX_MAX]; 48130949fd4SBrian Somers struct ncprange dst; 48203a2501aSBrian Somers size_t needed; 48303a2501aSBrian Somers char *sp, *cp, *ep; 48403a2501aSBrian Somers int mib[6]; 48503a2501aSBrian Somers 48603a2501aSBrian Somers log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 48703a2501aSBrian Somers 48803a2501aSBrian Somers mib[0] = CTL_NET; 48903a2501aSBrian Somers mib[1] = PF_ROUTE; 49003a2501aSBrian Somers mib[2] = 0; 49103a2501aSBrian Somers mib[3] = 0; 49203a2501aSBrian Somers mib[4] = NET_RT_DUMP; 49303a2501aSBrian Somers mib[5] = 0; 49403a2501aSBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 49503a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 49603a2501aSBrian Somers strerror(errno)); 49703a2501aSBrian Somers return; 49803a2501aSBrian Somers } 49903a2501aSBrian Somers 50003a2501aSBrian Somers sp = malloc(needed); 50103a2501aSBrian Somers if (sp == NULL) 50203a2501aSBrian Somers return; 50303a2501aSBrian Somers 50403a2501aSBrian Somers if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 50503a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 50603a2501aSBrian Somers strerror(errno)); 50703a2501aSBrian Somers free(sp); 50803a2501aSBrian Somers return; 50903a2501aSBrian Somers } 51003a2501aSBrian Somers ep = sp + needed; 51103a2501aSBrian Somers 51203a2501aSBrian Somers for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 51303a2501aSBrian Somers rtm = (struct rt_msghdr *)cp; 51403a2501aSBrian Somers route_ParseHdr(rtm, sa); 5151d3d76d4SBrian Somers if (sa[RTAX_DST] && (sa[RTAX_DST]->sa_family == AF_INET 5165ae08329SBrian Somers #ifndef NOINET6 5171d3d76d4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 5185ae08329SBrian Somers #endif 5195ae08329SBrian Somers ) && 5205ae08329SBrian Somers sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index) { 5215ae08329SBrian Somers if (log_IsKept(LogTCPIP)) { 52230949fd4SBrian Somers ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]); 5235ae08329SBrian Somers log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s," 524057f1760SBrian Somers " mtu %lu\n", rtm->rtm_index, Index2Nam(rtm->rtm_index), 5255ae08329SBrian Somers ncprange_ntoa(&dst), bundle->iface->mtu); 5265ae08329SBrian Somers } 5275ae08329SBrian Somers rt_Update(bundle, sa[RTAX_DST], sa[RTAX_GATEWAY], sa[RTAX_NETMASK]); 52803a2501aSBrian Somers } 52903a2501aSBrian Somers } 53003a2501aSBrian Somers 53103a2501aSBrian Somers free(sp); 53203a2501aSBrian Somers } 53303a2501aSBrian Somers 534af57ed9fSAtsushi Murai int 535944f7098SBrian Somers GetIfIndex(char *name) 536af57ed9fSAtsushi Murai { 5375d5e5070SBrian Somers int idx; 538944f7098SBrian Somers 5399cb1d89eSBrian Somers idx = 1; 540de59e178SBrian Somers while (route_nifs == -1 || idx < route_nifs) 541de59e178SBrian Somers if (strcmp(Index2Nam(idx), name) == 0) 5427a6f8720SBrian Somers return idx; 5435d5e5070SBrian Somers else 5445d5e5070SBrian Somers idx++; 5455d5e5070SBrian Somers return -1; 546af57ed9fSAtsushi Murai } 547bcc332bdSBrian Somers 548610b185fSBrian Somers void 549610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 55030949fd4SBrian Somers const struct ncpaddr *me, const struct ncpaddr *peer) 551bcc332bdSBrian Somers { 55230949fd4SBrian Somers struct ncpaddr dst; 553bcc332bdSBrian Somers 554610b185fSBrian Somers for (; r; r = r->next) { 55530949fd4SBrian Somers ncprange_getaddr(&r->dst, &dst); 55630949fd4SBrian Somers if (ncpaddr_family(me) == AF_INET) { 55730949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) { 55830949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 55930949fd4SBrian Somers ncprange_sethost(&r->dst, me); 560610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 56130949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56230949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) { 56330949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 56430949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 565610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 56630949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56730949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) { 56830949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE) 56930949fd4SBrian Somers continue; 57030949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 571d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 57230949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57330949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) { 57430949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE) 57530949fd4SBrian Somers continue; 57630949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 577d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 57830949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57930949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer)) 58030949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58130949fd4SBrian Somers #ifndef NOINET6 58230949fd4SBrian Somers } else if (ncpaddr_family(me) == AF_INET6) { 58330949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) { 58430949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 58530949fd4SBrian Somers ncprange_sethost(&r->dst, me); 58630949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58730949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58830949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) { 58930949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 59030949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 59130949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 59230949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 59330949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer)) 59430949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 59530949fd4SBrian Somers #endif 59630949fd4SBrian Somers } 59730949fd4SBrian Somers rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0); 598610b185fSBrian Somers } 599610b185fSBrian Somers } 600610b185fSBrian Somers 601610b185fSBrian Somers void 60230949fd4SBrian Somers route_Add(struct sticky_route **rp, int type, const struct ncprange *dst, 60330949fd4SBrian Somers const struct ncpaddr *gw) 604610b185fSBrian Somers { 605610b185fSBrian Somers struct sticky_route *r; 606610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 607610b185fSBrian Somers 608610b185fSBrian Somers r = NULL; 609610b185fSBrian Somers while (*rp) { 610183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 61130949fd4SBrian Somers (!dsttype && ncprange_equal(&(*rp)->dst, dst))) { 612972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 613972a1bcfSBrian Somers free(r); /* impossible really */ 614610b185fSBrian Somers r = *rp; 615610b185fSBrian Somers *rp = r->next; 616610b185fSBrian Somers } else 617610b185fSBrian Somers rp = &(*rp)->next; 618610b185fSBrian Somers } 619610b185fSBrian Somers 6205d604c11SBrian Somers if (r == NULL) { 621610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 6225d604c11SBrian Somers if (r == NULL) { 6235d604c11SBrian Somers log_Printf(LogERROR, "route_Add: Out of memory!\n"); 6245d604c11SBrian Somers return; 6255d604c11SBrian Somers } 6265d604c11SBrian Somers } 627610b185fSBrian Somers r->type = type; 628610b185fSBrian Somers r->next = NULL; 62930949fd4SBrian Somers ncprange_copy(&r->dst, dst); 63030949fd4SBrian Somers ncpaddr_copy(&r->gw, gw); 631bcd13e2eSBrian Somers *rp = r; 632610b185fSBrian Somers } 633610b185fSBrian Somers 634610b185fSBrian Somers void 63530949fd4SBrian Somers route_Delete(struct sticky_route **rp, int type, const struct ncprange *dst) 636610b185fSBrian Somers { 637610b185fSBrian Somers struct sticky_route *r; 638610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 639610b185fSBrian Somers 640610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 641610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 64230949fd4SBrian Somers (!dsttype && ncprange_equal(dst, &(*rp)->dst))) { 643610b185fSBrian Somers r = *rp; 644610b185fSBrian Somers *rp = r->next; 645610b185fSBrian Somers free(r); 646bcc332bdSBrian Somers break; 647bcc332bdSBrian Somers } 648bcc332bdSBrian Somers } 649bcc332bdSBrian Somers } 650bcc332bdSBrian Somers 651610b185fSBrian Somers void 652610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 653610b185fSBrian Somers { 654610b185fSBrian Somers struct sticky_route *r, *rn; 655610b185fSBrian Somers 656610b185fSBrian Somers for (r = *rp; r; r = rn) { 657610b185fSBrian Somers rn = r->next; 658610b185fSBrian Somers free(r); 659610b185fSBrian Somers } 660610b185fSBrian Somers *rp = NULL; 661610b185fSBrian Somers } 662610b185fSBrian Somers 663610b185fSBrian Somers void 664972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 665972a1bcfSBrian Somers int indent) 666610b185fSBrian Somers { 667972a1bcfSBrian Somers int tlen = strlen(tag); 668610b185fSBrian Somers 669972a1bcfSBrian Somers if (tlen + 2 > indent) 670972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 671972a1bcfSBrian Somers else 672972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 673972a1bcfSBrian Somers 674610b185fSBrian Somers for (; r; r = r->next) { 675972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 676972a1bcfSBrian Somers tlen = 0; 677610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 678610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 67930949fd4SBrian Somers else if (r->type & ROUTE_DSTMYADDR6) 68030949fd4SBrian Somers prompt_Printf(p, "MYADDR6"); 681610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 682610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 68330949fd4SBrian Somers else if (r->type & ROUTE_DSTHISADDR6) 68430949fd4SBrian Somers prompt_Printf(p, "HISADDR6"); 685d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS0) 686d568d6c4SBrian Somers prompt_Printf(p, "DNS0"); 687d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS1) 688d568d6c4SBrian Somers prompt_Printf(p, "DNS1"); 68930949fd4SBrian Somers else if (ncprange_isdefault(&r->dst)) 690610b185fSBrian Somers prompt_Printf(p, "default"); 691610b185fSBrian Somers else 69230949fd4SBrian Somers prompt_Printf(p, "%s", ncprange_ntoa(&r->dst)); 693610b185fSBrian Somers 694610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 695610b185fSBrian Somers prompt_Printf(p, " HISADDR\n"); 69630949fd4SBrian Somers else if (r->type & ROUTE_GWHISADDR6) 69730949fd4SBrian Somers prompt_Printf(p, " HISADDR6\n"); 698610b185fSBrian Somers else 69930949fd4SBrian Somers prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw)); 700610b185fSBrian Somers } 701bcc332bdSBrian Somers } 70203a2501aSBrian Somers 70303a2501aSBrian Somers struct rtmsg { 70403a2501aSBrian Somers struct rt_msghdr m_rtm; 70530949fd4SBrian Somers char m_space[256]; 70603a2501aSBrian Somers }; 70703a2501aSBrian Somers 708361a7b93SBrian Somers static size_t 709361a7b93SBrian Somers memcpy_roundup(char *cp, const void *data, size_t len) 710361a7b93SBrian Somers { 711361a7b93SBrian Somers size_t padlen; 712361a7b93SBrian Somers 713361a7b93SBrian Somers padlen = ROUNDUP(len); 714361a7b93SBrian Somers memcpy(cp, data, len); 715361a7b93SBrian Somers if (padlen > len) 716361a7b93SBrian Somers memset(cp + len, '\0', padlen - len); 717361a7b93SBrian Somers 718361a7b93SBrian Somers return padlen; 719361a7b93SBrian Somers } 720361a7b93SBrian Somers 72193193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 72293193fc7SHajimu UMEMOTO static void 72393193fc7SHajimu UMEMOTO add_scope(struct sockaddr *sa, int ifindex) 72493193fc7SHajimu UMEMOTO { 72593193fc7SHajimu UMEMOTO struct sockaddr_in6 *sa6; 72693193fc7SHajimu UMEMOTO 72793193fc7SHajimu UMEMOTO if (sa->sa_family != AF_INET6) 72893193fc7SHajimu UMEMOTO return; 72993193fc7SHajimu UMEMOTO sa6 = (struct sockaddr_in6 *)sa; 73093193fc7SHajimu UMEMOTO if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && 73193193fc7SHajimu UMEMOTO !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) 73293193fc7SHajimu UMEMOTO return; 73393193fc7SHajimu UMEMOTO if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0) 73493193fc7SHajimu UMEMOTO return; 73593193fc7SHajimu UMEMOTO *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex); 73693193fc7SHajimu UMEMOTO } 73793193fc7SHajimu UMEMOTO #endif 73893193fc7SHajimu UMEMOTO 73903a2501aSBrian Somers int 74030949fd4SBrian Somers rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst, 74130949fd4SBrian Somers const struct ncpaddr *gw, int bang, int quiet) 74203a2501aSBrian Somers { 74303a2501aSBrian Somers struct rtmsg rtmes; 744846e7227SBrian Somers int s, nb, wb; 74503a2501aSBrian Somers char *cp; 74603a2501aSBrian Somers const char *cmdstr; 74730949fd4SBrian Somers struct sockaddr_storage sadst, samask, sagw; 74803a2501aSBrian Somers int result = 1; 74903a2501aSBrian Somers 75003a2501aSBrian Somers if (bang) 75103a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 75203a2501aSBrian Somers else 75303a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 75463c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 75503a2501aSBrian Somers if (s < 0) { 75603a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 75703a2501aSBrian Somers return result; 75803a2501aSBrian Somers } 75903a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 76003a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 76103a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd; 76203a2501aSBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 76303a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 76403a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 76503a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 76603a2501aSBrian Somers 76703a2501aSBrian Somers if (cmd == RTM_ADD) { 76830949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 76930949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 77003a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 77103a2501aSBrian Somers } 77230949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 77330949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 77403a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 77503a2501aSBrian Somers } 77603a2501aSBrian Somers } 77703a2501aSBrian Somers 77830949fd4SBrian Somers ncprange_getsa(dst, &sadst, &samask); 77993193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 78093193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sadst, bundle->iface->index); 78193193fc7SHajimu UMEMOTO #endif 78203a2501aSBrian Somers 78303a2501aSBrian Somers cp = rtmes.m_space; 784361a7b93SBrian Somers cp += memcpy_roundup(cp, &sadst, sadst.ss_len); 78503a2501aSBrian Somers if (cmd == RTM_ADD) { 78630949fd4SBrian Somers if (gw == NULL) { 78730949fd4SBrian Somers log_Printf(LogERROR, "rt_Set: Program error\n"); 78830949fd4SBrian Somers close(s); 78930949fd4SBrian Somers return result; 79030949fd4SBrian Somers } 79130949fd4SBrian Somers ncpaddr_getsa(gw, &sagw); 79293193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 79393193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sagw, bundle->iface->index); 79493193fc7SHajimu UMEMOTO #endif 79530949fd4SBrian Somers if (ncpaddr_isdefault(gw)) { 79630949fd4SBrian Somers if (!quiet) 79703a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: Cannot add a route with" 798156a04e4SBrian Somers " gateway 0.0.0.0\n"); 79903a2501aSBrian Somers close(s); 80003a2501aSBrian Somers return result; 80103a2501aSBrian Somers } else { 802361a7b93SBrian Somers cp += memcpy_roundup(cp, &sagw, sagw.ss_len); 80303a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 80403a2501aSBrian Somers } 80503a2501aSBrian Somers } 80603a2501aSBrian Somers 80726dceef0SBrian Somers if (!ncprange_ishost(dst)) { 808361a7b93SBrian Somers cp += memcpy_roundup(cp, &samask, samask.ss_len); 80903a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 81003a2501aSBrian Somers } 81103a2501aSBrian Somers 81203a2501aSBrian Somers nb = cp - (char *)&rtmes; 81303a2501aSBrian Somers rtmes.m_rtm.rtm_msglen = nb; 81403a2501aSBrian Somers wb = ID0write(s, &rtmes, nb); 81503a2501aSBrian Somers if (wb < 0) { 81603a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set failure:\n"); 81703a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 81830949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst)); 81930949fd4SBrian Somers if (gw != NULL) 82030949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw)); 82103a2501aSBrian Somers failed: 82203a2501aSBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 82303a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 82403a2501aSBrian Somers if (!bang) { 82503a2501aSBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 82630949fd4SBrian Somers ncprange_ntoa(dst)); 82703a2501aSBrian Somers result = 0; /* Don't add to our dynamic list */ 82803a2501aSBrian Somers } else { 82903a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 83003a2501aSBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 83103a2501aSBrian Somers goto failed; 83203a2501aSBrian Somers } 83303a2501aSBrian Somers } else if (cmd == RTM_DELETE && 83403a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 83503a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 83603a2501aSBrian Somers if (!bang) 83703a2501aSBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 83830949fd4SBrian Somers ncprange_ntoa(dst)); 83903a2501aSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 84030949fd4SBrian Somers if (!quiet || errno != ENETUNREACH) 84103a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 84230949fd4SBrian Somers ncprange_ntoa(dst), strerror(errno)); 84303a2501aSBrian Somers } else 84403a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 84530949fd4SBrian Somers cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 84603a2501aSBrian Somers } 84703a2501aSBrian Somers 84830949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 84930949fd4SBrian Somers char gwstr[40]; 85030949fd4SBrian Somers 85130949fd4SBrian Somers if (gw) 85230949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw)); 85330949fd4SBrian Somers else 85430949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "<none>"); 85530949fd4SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n", 85630949fd4SBrian Somers wb, cmdstr, ncprange_ntoa(dst), gwstr); 85730949fd4SBrian Somers } 85803a2501aSBrian Somers close(s); 85903a2501aSBrian Somers 86003a2501aSBrian Somers return result; 86103a2501aSBrian Somers } 86203a2501aSBrian Somers 86303a2501aSBrian Somers void 8645ae08329SBrian Somers rt_Update(struct bundle *bundle, const struct sockaddr *dst, 8655ae08329SBrian Somers const struct sockaddr *gw, const struct sockaddr *mask) 86603a2501aSBrian Somers { 8675ae08329SBrian Somers struct ncprange ncpdst; 86803a2501aSBrian Somers struct rtmsg rtmes; 8695ae08329SBrian Somers char *p; 87003a2501aSBrian Somers int s, wb; 87103a2501aSBrian Somers 87263c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 87303a2501aSBrian Somers if (s < 0) { 87403a2501aSBrian Somers log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 87503a2501aSBrian Somers return; 87603a2501aSBrian Somers } 87703a2501aSBrian Somers 87803a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 87903a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 88003a2501aSBrian Somers rtmes.m_rtm.rtm_type = RTM_CHANGE; 881d42d9220SBrian Somers rtmes.m_rtm.rtm_addrs = 0; 88203a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 88303a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 884afb28bf7SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_STATIC; 88503a2501aSBrian Somers 88630949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 88730949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 88803a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 88903a2501aSBrian Somers } 89003a2501aSBrian Somers 89130949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 89230949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 89303a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 89403a2501aSBrian Somers } 89503a2501aSBrian Somers 896c8b9fb53SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; 89703a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_MTU; 8985ae08329SBrian Somers p = rtmes.m_space; 89903a2501aSBrian Somers 9005ae08329SBrian Somers if (dst) { 9015ae08329SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_DST; 902361a7b93SBrian Somers p += memcpy_roundup(p, dst, dst->sa_len); 9035ae08329SBrian Somers } 90403a2501aSBrian Somers 905afb28bf7SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 906afb28bf7SBrian Somers p += memcpy_roundup(p, gw, gw->sa_len); 907afb28bf7SBrian Somers if (mask) { 908afb28bf7SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 909afb28bf7SBrian Somers p += memcpy_roundup(p, mask, mask->sa_len); 910afb28bf7SBrian Somers } 911afb28bf7SBrian Somers 9125ae08329SBrian Somers rtmes.m_rtm.rtm_msglen = p - (char *)&rtmes; 91303a2501aSBrian Somers 91403a2501aSBrian Somers wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 91503a2501aSBrian Somers if (wb < 0) { 9165ae08329SBrian Somers ncprange_setsa(&ncpdst, dst, mask); 9175ae08329SBrian Somers 91803a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Update failure:\n"); 9195ae08329SBrian Somers log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst)); 92003a2501aSBrian Somers 92103a2501aSBrian Somers if (rtmes.m_rtm.rtm_errno == 0) 92203a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 9235ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(errno)); 92403a2501aSBrian Somers else 92503a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: %s\n", 9265ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(rtmes.m_rtm.rtm_errno)); 92703a2501aSBrian Somers } 92803a2501aSBrian Somers close(s); 92903a2501aSBrian Somers } 930