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_XRESOLVE, 'X' }, 1616e6b3f7cSQing Li #ifdef RTF_CLONING 1626e6b3f7cSQing Li { RTF_CLONING, 'C' }, 1636e6b3f7cSQing Li #endif 1645d5e5070SBrian Somers { RTF_STATIC, 'S' }, 1655d5e5070SBrian Somers { RTF_PROTO1, '1' }, 1665d5e5070SBrian Somers { RTF_PROTO2, '2' }, 1675d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 1686e6b3f7cSQing Li 1696e6b3f7cSQing Li #ifdef RTF_LLINFO 1706e6b3f7cSQing Li { RTF_LLINFO, 'L' }, 1716e6b3f7cSQing Li #endif 1726e6b3f7cSQing Li #ifdef RTF_CLONING 1736e6b3f7cSQing Li { RTF_CLONING, 'C' }, 1746e6b3f7cSQing Li #endif 17532ca3341SBrian Somers #ifdef RTF_WASCLONED 1765d5e5070SBrian Somers { RTF_WASCLONED, 'W' }, 17732ca3341SBrian Somers #endif 17832ca3341SBrian Somers #ifdef RTF_PRCLONING 1795d5e5070SBrian Somers { RTF_PRCLONING, 'c' }, 18032ca3341SBrian Somers #endif 18132ca3341SBrian Somers #ifdef RTF_PROTO3 1825d5e5070SBrian Somers { RTF_PROTO3, '3' }, 18332ca3341SBrian Somers #endif 18432ca3341SBrian Somers #ifdef RTF_BROADCAST 1855d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 1865d5e5070SBrian Somers #endif 1875d5e5070SBrian Somers { 0, '\0' } 188af57ed9fSAtsushi Murai }; 189af57ed9fSAtsushi Murai 19032ca3341SBrian Somers #ifndef RTF_WASCLONED 19132ca3341SBrian Somers #define RTF_WASCLONED (0) 19232ca3341SBrian Somers #endif 19332ca3341SBrian Somers 194af57ed9fSAtsushi Murai static void 195057f1760SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, unsigned max) 196af57ed9fSAtsushi Murai { 197af57ed9fSAtsushi Murai char name[33], *flags; 198af57ed9fSAtsushi Murai register struct bits *p = bits; 199af57ed9fSAtsushi Murai 20070ee81ffSBrian Somers if (max > sizeof name - 1) 20170ee81ffSBrian Somers max = sizeof name - 1; 202d27d502cSBrian Somers 203057f1760SBrian Somers for (flags = name; p->b_mask && flags - name < (int)max; p++) 204af57ed9fSAtsushi Murai if (p->b_mask & f) 205af57ed9fSAtsushi Murai *flags++ = p->b_val; 206af57ed9fSAtsushi Murai *flags = '\0'; 20700d9db03SBrian Somers prompt_Printf(prompt, "%-*.*s", (int)max, (int)max, name); 208af57ed9fSAtsushi Murai } 209af57ed9fSAtsushi Murai 210de59e178SBrian Somers static int route_nifs = -1; 211de59e178SBrian Somers 212c6fe0cb2SBrian Somers const char * 2135d5e5070SBrian Somers Index2Nam(int idx) 2145d5e5070SBrian Somers { 215d93d3a9cSBrian Somers /* 216d93d3a9cSBrian Somers * XXX: Maybe we should select() on the routing socket so that we can 217d93d3a9cSBrian Somers * notice interfaces that come & go (PCCARD support). 218d93d3a9cSBrian Somers * Or we could even support a signal that resets these so that 219d93d3a9cSBrian Somers * the PCCARD insert/remove events can signal ppp. 220d93d3a9cSBrian Somers */ 221d93d3a9cSBrian Somers static char **ifs; /* Figure these out once */ 222de59e178SBrian Somers static int debug_done; /* Debug once */ 2235d5e5070SBrian Somers 224de59e178SBrian Somers if (idx > route_nifs || (idx > 0 && ifs[idx-1] == NULL)) { 225b1435e41SBrian Somers int mib[6], have, had; 226e7250038SBrian Somers size_t needed; 2275d5e5070SBrian Somers char *buf, *ptr, *end; 2285d5e5070SBrian Somers struct sockaddr_dl *dl; 2295d5e5070SBrian Somers struct if_msghdr *ifm; 2305d5e5070SBrian Somers 2318473f372SBrian Somers if (ifs) { 2328473f372SBrian Somers free(ifs); 2338473f372SBrian Somers ifs = NULL; 234de59e178SBrian Somers route_nifs = 0; 2358473f372SBrian Somers } 2368473f372SBrian Somers debug_done = 0; 2378473f372SBrian Somers 2385d5e5070SBrian Somers mib[0] = CTL_NET; 2395d5e5070SBrian Somers mib[1] = PF_ROUTE; 2405d5e5070SBrian Somers mib[2] = 0; 2415d5e5070SBrian Somers mib[3] = 0; 2425d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 2435d5e5070SBrian Somers mib[5] = 0; 2445d5e5070SBrian Somers 2455d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 246a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 247a33b2ef7SBrian Somers strerror(errno)); 248d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2495d5e5070SBrian Somers } 2505d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 251d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2525d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 2535d5e5070SBrian Somers free(buf); 254d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2555d5e5070SBrian Somers } 2565d5e5070SBrian Somers end = buf + needed; 2575d5e5070SBrian Somers 258b1435e41SBrian Somers have = 0; 2599cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 2605d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 2616b457978SBrian Somers if (ifm->ifm_type != RTM_IFINFO) 26224731321SBrian Somers continue; 2635d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 264b1435e41SBrian Somers if (ifm->ifm_index > 0) { 265b1435e41SBrian Somers if (ifm->ifm_index > have) { 266fc254be9SBrian Somers char **newifs; 267fc254be9SBrian Somers 268b1435e41SBrian Somers had = have; 269b1435e41SBrian Somers have = ifm->ifm_index + 5; 270b1435e41SBrian Somers if (had) 271fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 272b1435e41SBrian Somers else 273fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 274fc254be9SBrian Somers if (!newifs) { 275dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 276de59e178SBrian Somers route_nifs = 0; 2778473f372SBrian Somers if (ifs) { 278fc254be9SBrian Somers free(ifs); 2798473f372SBrian Somers ifs = NULL; 2808473f372SBrian Somers } 2818473f372SBrian Somers free(buf); 282d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 283b1435e41SBrian Somers } 284fc254be9SBrian Somers ifs = newifs; 285b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 286b1435e41SBrian Somers } 287b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 288b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 2895d604c11SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) 2905d604c11SBrian Somers log_Printf(LogDEBUG, "Skipping interface %d: Out of memory\n", 2915d604c11SBrian Somers ifm->ifm_index); 2925d604c11SBrian Somers else { 293b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 294b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 295de59e178SBrian Somers if (route_nifs < ifm->ifm_index) 296de59e178SBrian Somers route_nifs = ifm->ifm_index; 297b1435e41SBrian Somers } 2985d604c11SBrian Somers } 299dd7e2610SBrian Somers } else if (log_IsKept(LogDEBUG)) 300dd7e2610SBrian Somers log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 3019cb1d89eSBrian Somers ifm->ifm_index); 3025d5e5070SBrian Somers } 3035d5e5070SBrian Somers free(buf); 3045d5e5070SBrian Somers } 3055d5e5070SBrian Somers 306dd7e2610SBrian Somers if (log_IsKept(LogDEBUG) && !debug_done) { 3079cb1d89eSBrian Somers int f; 3089cb1d89eSBrian Somers 309dd7e2610SBrian Somers log_Printf(LogDEBUG, "Found the following interfaces:\n"); 310de59e178SBrian Somers for (f = 0; f < route_nifs; f++) 311b1435e41SBrian Somers if (ifs[f] != NULL) 312dd7e2610SBrian Somers log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 3139cb1d89eSBrian Somers debug_done = 1; 3149cb1d89eSBrian Somers } 3159cb1d89eSBrian Somers 316de59e178SBrian Somers if (idx < 1 || idx > route_nifs || ifs[idx-1] == NULL) 317d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3189cb1d89eSBrian Somers 3199cb1d89eSBrian Somers return ifs[idx-1]; 3205d5e5070SBrian Somers } 3215d5e5070SBrian Somers 3226b457978SBrian Somers void 3236b457978SBrian Somers route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 3246b457978SBrian Somers { 3256b457978SBrian Somers char *wp; 3266b457978SBrian Somers int rtax; 3276b457978SBrian Somers 3286b457978SBrian Somers wp = (char *)(rtm + 1); 3296b457978SBrian Somers 3306b457978SBrian Somers for (rtax = 0; rtax < RTAX_MAX; rtax++) 3316b457978SBrian Somers if (rtm->rtm_addrs & (1 << rtax)) { 3326b457978SBrian Somers sa[rtax] = (struct sockaddr *)wp; 3336b457978SBrian Somers wp += ROUNDUP(sa[rtax]->sa_len); 334a3d71c3dSBrian Somers if (sa[rtax]->sa_family == 0) 335a3d71c3dSBrian Somers sa[rtax] = NULL; /* ??? */ 3366b457978SBrian Somers } else 3376b457978SBrian Somers sa[rtax] = NULL; 3386b457978SBrian Somers } 3396b457978SBrian Somers 340af57ed9fSAtsushi Murai int 341dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 342af57ed9fSAtsushi Murai { 343af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3446b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 3456b457978SBrian Somers char *sp, *ep, *cp; 346e7250038SBrian Somers size_t needed; 347af57ed9fSAtsushi Murai int mib[6]; 348af57ed9fSAtsushi Murai 349af57ed9fSAtsushi Murai mib[0] = CTL_NET; 350af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 35153c9f6c0SAtsushi Murai mib[2] = 0; 35253c9f6c0SAtsushi Murai mib[3] = 0; 353af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 35453c9f6c0SAtsushi Murai mib[5] = 0; 35553c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 356dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 35753c9f6c0SAtsushi Murai return (1); 35853c9f6c0SAtsushi Murai } 359af57ed9fSAtsushi Murai sp = malloc(needed); 360af57ed9fSAtsushi Murai if (sp == NULL) 361af57ed9fSAtsushi Murai return (1); 36253c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 363dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 364b0cdb3ceSJordan K. Hubbard free(sp); 365af57ed9fSAtsushi Murai return (1); 36653c9f6c0SAtsushi Murai } 367af57ed9fSAtsushi Murai ep = sp + needed; 368af57ed9fSAtsushi Murai 369b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 370b6217683SBrian Somers "Destination", "Gateway"); 371af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 372af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 3735d5e5070SBrian Somers 3746b457978SBrian Somers route_ParseHdr(rtm, sa); 3756b384664SBrian Somers 3766b457978SBrian Somers if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 3776b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 3786b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 3795d5e5070SBrian Somers 380b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 381b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 3826b384664SBrian Somers } else 3836b384664SBrian Somers prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 384af57ed9fSAtsushi Murai } 385b0cdb3ceSJordan K. Hubbard free(sp); 386927145beSBrian Somers return 0; 387af57ed9fSAtsushi Murai } 388af57ed9fSAtsushi Murai 389af57ed9fSAtsushi Murai /* 390af57ed9fSAtsushi Murai * Delete routes associated with our interface 391af57ed9fSAtsushi Murai */ 392af57ed9fSAtsushi Murai void 393dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 394af57ed9fSAtsushi Murai { 395af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3966b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 39730949fd4SBrian Somers struct ncprange range; 398e7250038SBrian Somers int pass; 399e7250038SBrian Somers size_t needed; 400af57ed9fSAtsushi Murai char *sp, *cp, *ep; 401af57ed9fSAtsushi Murai int mib[6]; 402af57ed9fSAtsushi Murai 4038fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 404927145beSBrian Somers 405af57ed9fSAtsushi Murai mib[0] = CTL_NET; 406af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 40753c9f6c0SAtsushi Murai mib[2] = 0; 40853c9f6c0SAtsushi Murai mib[3] = 0; 409af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 41053c9f6c0SAtsushi Murai mib[5] = 0; 41153c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 412dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 413afc7fa2cSBrian Somers strerror(errno)); 41453c9f6c0SAtsushi Murai return; 41553c9f6c0SAtsushi Murai } 416af57ed9fSAtsushi Murai 417af57ed9fSAtsushi Murai sp = malloc(needed); 418af57ed9fSAtsushi Murai if (sp == NULL) 419af57ed9fSAtsushi Murai return; 420af57ed9fSAtsushi Murai 421af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 422dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 423afc7fa2cSBrian Somers strerror(errno)); 424af57ed9fSAtsushi Murai free(sp); 425af57ed9fSAtsushi Murai return; 426af57ed9fSAtsushi Murai } 427af57ed9fSAtsushi Murai ep = sp + needed; 428af57ed9fSAtsushi Murai 42932ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 43032ca3341SBrian Somers /* 43132ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 4326b457978SBrian Somers * deletes all non-cloned routes. This is done to avoid 43332ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 434ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 435ba081e43SBrian Somers * may have gone with route Y). 43632ca3341SBrian Somers */ 43732ca3341SBrian Somers if (RTF_WASCLONED == 0 && pass == 0) 43832ca3341SBrian Somers /* So we can't tell ! */ 43932ca3341SBrian Somers continue; 440af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 441af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4426b457978SBrian Somers route_ParseHdr(rtm, sa); 44330949fd4SBrian Somers if (rtm->rtm_index == bundle->iface->index && 44430949fd4SBrian Somers sa[RTAX_DST] && sa[RTAX_GATEWAY] && 44530949fd4SBrian Somers (sa[RTAX_DST]->sa_family == AF_INET 44630949fd4SBrian Somers #ifndef NOINET6 44730949fd4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 44830949fd4SBrian Somers #endif 44930949fd4SBrian Somers ) && 450af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 45130949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 45230949fd4SBrian Somers char gwstr[41]; 45330949fd4SBrian Somers struct ncpaddr gw; 45430949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 45530949fd4SBrian Somers ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]); 45630949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw)); 45730949fd4SBrian Somers log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr); 45830949fd4SBrian Somers } 4596b457978SBrian Somers if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 46030949fd4SBrian Somers #ifndef NOINET6 46130949fd4SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_INET6 || 46230949fd4SBrian Somers #endif 4636b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 46432ca3341SBrian Somers if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 46532ca3341SBrian Somers (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 46630949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 46730949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0); 4685d5e5070SBrian Somers } else 469dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 47032ca3341SBrian Somers } else 471dd7e2610SBrian Somers log_Printf(LogDEBUG, 47230949fd4SBrian Somers "route_IfDelete: Can't remove routes for family %d\n", 4736b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family); 4746b457978SBrian Somers } 475af57ed9fSAtsushi Murai } 476af57ed9fSAtsushi Murai } 477af57ed9fSAtsushi Murai free(sp); 478af57ed9fSAtsushi Murai } 479af57ed9fSAtsushi Murai 48003a2501aSBrian Somers 48103a2501aSBrian Somers /* 48203a2501aSBrian Somers * Update the MTU on all routes for the given interface 48303a2501aSBrian Somers */ 48403a2501aSBrian Somers void 48503a2501aSBrian Somers route_UpdateMTU(struct bundle *bundle) 48603a2501aSBrian Somers { 48703a2501aSBrian Somers struct rt_msghdr *rtm; 48803a2501aSBrian Somers struct sockaddr *sa[RTAX_MAX]; 48930949fd4SBrian Somers struct ncprange dst; 49003a2501aSBrian Somers size_t needed; 49103a2501aSBrian Somers char *sp, *cp, *ep; 49203a2501aSBrian Somers int mib[6]; 49303a2501aSBrian Somers 49403a2501aSBrian Somers log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 49503a2501aSBrian Somers 49603a2501aSBrian Somers mib[0] = CTL_NET; 49703a2501aSBrian Somers mib[1] = PF_ROUTE; 49803a2501aSBrian Somers mib[2] = 0; 49903a2501aSBrian Somers mib[3] = 0; 50003a2501aSBrian Somers mib[4] = NET_RT_DUMP; 50103a2501aSBrian Somers mib[5] = 0; 50203a2501aSBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 50303a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 50403a2501aSBrian Somers strerror(errno)); 50503a2501aSBrian Somers return; 50603a2501aSBrian Somers } 50703a2501aSBrian Somers 50803a2501aSBrian Somers sp = malloc(needed); 50903a2501aSBrian Somers if (sp == NULL) 51003a2501aSBrian Somers return; 51103a2501aSBrian Somers 51203a2501aSBrian Somers if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 51303a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 51403a2501aSBrian Somers strerror(errno)); 51503a2501aSBrian Somers free(sp); 51603a2501aSBrian Somers return; 51703a2501aSBrian Somers } 51803a2501aSBrian Somers ep = sp + needed; 51903a2501aSBrian Somers 52003a2501aSBrian Somers for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 52103a2501aSBrian Somers rtm = (struct rt_msghdr *)cp; 52203a2501aSBrian Somers route_ParseHdr(rtm, sa); 5231d3d76d4SBrian Somers if (sa[RTAX_DST] && (sa[RTAX_DST]->sa_family == AF_INET 5245ae08329SBrian Somers #ifndef NOINET6 5251d3d76d4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 5265ae08329SBrian Somers #endif 5275ae08329SBrian Somers ) && 5285ae08329SBrian Somers sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index) { 5295ae08329SBrian Somers if (log_IsKept(LogTCPIP)) { 53030949fd4SBrian Somers ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]); 5315ae08329SBrian Somers log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s," 532057f1760SBrian Somers " mtu %lu\n", rtm->rtm_index, Index2Nam(rtm->rtm_index), 5335ae08329SBrian Somers ncprange_ntoa(&dst), bundle->iface->mtu); 5345ae08329SBrian Somers } 5355ae08329SBrian Somers rt_Update(bundle, sa[RTAX_DST], sa[RTAX_GATEWAY], sa[RTAX_NETMASK]); 53603a2501aSBrian Somers } 53703a2501aSBrian Somers } 53803a2501aSBrian Somers 53903a2501aSBrian Somers free(sp); 54003a2501aSBrian Somers } 54103a2501aSBrian Somers 542af57ed9fSAtsushi Murai int 543944f7098SBrian Somers GetIfIndex(char *name) 544af57ed9fSAtsushi Murai { 5455d5e5070SBrian Somers int idx; 546944f7098SBrian Somers 5479cb1d89eSBrian Somers idx = 1; 548de59e178SBrian Somers while (route_nifs == -1 || idx < route_nifs) 549de59e178SBrian Somers if (strcmp(Index2Nam(idx), name) == 0) 5507a6f8720SBrian Somers return idx; 5515d5e5070SBrian Somers else 5525d5e5070SBrian Somers idx++; 5535d5e5070SBrian Somers return -1; 554af57ed9fSAtsushi Murai } 555bcc332bdSBrian Somers 556610b185fSBrian Somers void 557610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 55830949fd4SBrian Somers const struct ncpaddr *me, const struct ncpaddr *peer) 559bcc332bdSBrian Somers { 56030949fd4SBrian Somers struct ncpaddr dst; 561bcc332bdSBrian Somers 562610b185fSBrian Somers for (; r; r = r->next) { 56330949fd4SBrian Somers ncprange_getaddr(&r->dst, &dst); 56430949fd4SBrian Somers if (ncpaddr_family(me) == AF_INET) { 56530949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) { 56630949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 56730949fd4SBrian Somers ncprange_sethost(&r->dst, me); 568610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 56930949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57030949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) { 57130949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 57230949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 573610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 57430949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57530949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) { 57630949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE) 57730949fd4SBrian Somers continue; 57830949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 579d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58030949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58130949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) { 58230949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE) 58330949fd4SBrian Somers continue; 58430949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 585d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58630949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58730949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer)) 58830949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58930949fd4SBrian Somers #ifndef NOINET6 59030949fd4SBrian Somers } else if (ncpaddr_family(me) == AF_INET6) { 59130949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) { 59230949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 59330949fd4SBrian Somers ncprange_sethost(&r->dst, me); 59430949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 59530949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 59630949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) { 59730949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 59830949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 59930949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 60030949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 60130949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer)) 60230949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 60330949fd4SBrian Somers #endif 60430949fd4SBrian Somers } 60530949fd4SBrian Somers rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0); 606610b185fSBrian Somers } 607610b185fSBrian Somers } 608610b185fSBrian Somers 609610b185fSBrian Somers void 61030949fd4SBrian Somers route_Add(struct sticky_route **rp, int type, const struct ncprange *dst, 61130949fd4SBrian Somers const struct ncpaddr *gw) 612610b185fSBrian Somers { 613610b185fSBrian Somers struct sticky_route *r; 614610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 615610b185fSBrian Somers 616610b185fSBrian Somers r = NULL; 617610b185fSBrian Somers while (*rp) { 618183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 61930949fd4SBrian Somers (!dsttype && ncprange_equal(&(*rp)->dst, dst))) { 620972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 621972a1bcfSBrian Somers free(r); /* impossible really */ 622610b185fSBrian Somers r = *rp; 623610b185fSBrian Somers *rp = r->next; 624610b185fSBrian Somers } else 625610b185fSBrian Somers rp = &(*rp)->next; 626610b185fSBrian Somers } 627610b185fSBrian Somers 6285d604c11SBrian Somers if (r == NULL) { 629610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 6305d604c11SBrian Somers if (r == NULL) { 6315d604c11SBrian Somers log_Printf(LogERROR, "route_Add: Out of memory!\n"); 6325d604c11SBrian Somers return; 6335d604c11SBrian Somers } 6345d604c11SBrian Somers } 635610b185fSBrian Somers r->type = type; 636610b185fSBrian Somers r->next = NULL; 63730949fd4SBrian Somers ncprange_copy(&r->dst, dst); 63830949fd4SBrian Somers ncpaddr_copy(&r->gw, gw); 639bcd13e2eSBrian Somers *rp = r; 640610b185fSBrian Somers } 641610b185fSBrian Somers 642610b185fSBrian Somers void 64330949fd4SBrian Somers route_Delete(struct sticky_route **rp, int type, const struct ncprange *dst) 644610b185fSBrian Somers { 645610b185fSBrian Somers struct sticky_route *r; 646610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 647610b185fSBrian Somers 648610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 649610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 65030949fd4SBrian Somers (!dsttype && ncprange_equal(dst, &(*rp)->dst))) { 651610b185fSBrian Somers r = *rp; 652610b185fSBrian Somers *rp = r->next; 653610b185fSBrian Somers free(r); 654bcc332bdSBrian Somers break; 655bcc332bdSBrian Somers } 656bcc332bdSBrian Somers } 657bcc332bdSBrian Somers } 658bcc332bdSBrian Somers 659610b185fSBrian Somers void 660610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 661610b185fSBrian Somers { 662610b185fSBrian Somers struct sticky_route *r, *rn; 663610b185fSBrian Somers 664610b185fSBrian Somers for (r = *rp; r; r = rn) { 665610b185fSBrian Somers rn = r->next; 666610b185fSBrian Somers free(r); 667610b185fSBrian Somers } 668610b185fSBrian Somers *rp = NULL; 669610b185fSBrian Somers } 670610b185fSBrian Somers 671610b185fSBrian Somers void 672972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 673972a1bcfSBrian Somers int indent) 674610b185fSBrian Somers { 675972a1bcfSBrian Somers int tlen = strlen(tag); 676610b185fSBrian Somers 677972a1bcfSBrian Somers if (tlen + 2 > indent) 678972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 679972a1bcfSBrian Somers else 680972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 681972a1bcfSBrian Somers 682610b185fSBrian Somers for (; r; r = r->next) { 683972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 684972a1bcfSBrian Somers tlen = 0; 685610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 686610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 68730949fd4SBrian Somers else if (r->type & ROUTE_DSTMYADDR6) 68830949fd4SBrian Somers prompt_Printf(p, "MYADDR6"); 689610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 690610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 69130949fd4SBrian Somers else if (r->type & ROUTE_DSTHISADDR6) 69230949fd4SBrian Somers prompt_Printf(p, "HISADDR6"); 693d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS0) 694d568d6c4SBrian Somers prompt_Printf(p, "DNS0"); 695d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS1) 696d568d6c4SBrian Somers prompt_Printf(p, "DNS1"); 69730949fd4SBrian Somers else if (ncprange_isdefault(&r->dst)) 698610b185fSBrian Somers prompt_Printf(p, "default"); 699610b185fSBrian Somers else 70030949fd4SBrian Somers prompt_Printf(p, "%s", ncprange_ntoa(&r->dst)); 701610b185fSBrian Somers 702610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 703610b185fSBrian Somers prompt_Printf(p, " HISADDR\n"); 70430949fd4SBrian Somers else if (r->type & ROUTE_GWHISADDR6) 70530949fd4SBrian Somers prompt_Printf(p, " HISADDR6\n"); 706610b185fSBrian Somers else 70730949fd4SBrian Somers prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw)); 708610b185fSBrian Somers } 709bcc332bdSBrian Somers } 71003a2501aSBrian Somers 71103a2501aSBrian Somers struct rtmsg { 71203a2501aSBrian Somers struct rt_msghdr m_rtm; 71330949fd4SBrian Somers char m_space[256]; 71403a2501aSBrian Somers }; 71503a2501aSBrian Somers 716361a7b93SBrian Somers static size_t 717361a7b93SBrian Somers memcpy_roundup(char *cp, const void *data, size_t len) 718361a7b93SBrian Somers { 719361a7b93SBrian Somers size_t padlen; 720361a7b93SBrian Somers 721361a7b93SBrian Somers padlen = ROUNDUP(len); 722361a7b93SBrian Somers memcpy(cp, data, len); 723361a7b93SBrian Somers if (padlen > len) 724361a7b93SBrian Somers memset(cp + len, '\0', padlen - len); 725361a7b93SBrian Somers 726361a7b93SBrian Somers return padlen; 727361a7b93SBrian Somers } 728361a7b93SBrian Somers 72993193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 73093193fc7SHajimu UMEMOTO static void 73193193fc7SHajimu UMEMOTO add_scope(struct sockaddr *sa, int ifindex) 73293193fc7SHajimu UMEMOTO { 73393193fc7SHajimu UMEMOTO struct sockaddr_in6 *sa6; 73493193fc7SHajimu UMEMOTO 73593193fc7SHajimu UMEMOTO if (sa->sa_family != AF_INET6) 73693193fc7SHajimu UMEMOTO return; 73793193fc7SHajimu UMEMOTO sa6 = (struct sockaddr_in6 *)sa; 73893193fc7SHajimu UMEMOTO if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && 73993193fc7SHajimu UMEMOTO !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) 74093193fc7SHajimu UMEMOTO return; 74193193fc7SHajimu UMEMOTO if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0) 74293193fc7SHajimu UMEMOTO return; 74393193fc7SHajimu UMEMOTO *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex); 74493193fc7SHajimu UMEMOTO } 74593193fc7SHajimu UMEMOTO #endif 74693193fc7SHajimu UMEMOTO 74703a2501aSBrian Somers int 74830949fd4SBrian Somers rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst, 74930949fd4SBrian Somers const struct ncpaddr *gw, int bang, int quiet) 75003a2501aSBrian Somers { 75103a2501aSBrian Somers struct rtmsg rtmes; 752846e7227SBrian Somers int s, nb, wb; 75303a2501aSBrian Somers char *cp; 75403a2501aSBrian Somers const char *cmdstr; 75530949fd4SBrian Somers struct sockaddr_storage sadst, samask, sagw; 75603a2501aSBrian Somers int result = 1; 75703a2501aSBrian Somers 75803a2501aSBrian Somers if (bang) 75903a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 76003a2501aSBrian Somers else 76103a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 76263c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 76303a2501aSBrian Somers if (s < 0) { 76403a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 76503a2501aSBrian Somers return result; 76603a2501aSBrian Somers } 76703a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 76803a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 76903a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd; 77003a2501aSBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 77103a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 77203a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 77303a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 77403a2501aSBrian Somers 77503a2501aSBrian Somers if (cmd == RTM_ADD) { 77630949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 77730949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 77803a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 77903a2501aSBrian Somers } 78030949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 78130949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 78203a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 78303a2501aSBrian Somers } 78403a2501aSBrian Somers } 78503a2501aSBrian Somers 78630949fd4SBrian Somers ncprange_getsa(dst, &sadst, &samask); 78793193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 78893193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sadst, bundle->iface->index); 78993193fc7SHajimu UMEMOTO #endif 79003a2501aSBrian Somers 79103a2501aSBrian Somers cp = rtmes.m_space; 792361a7b93SBrian Somers cp += memcpy_roundup(cp, &sadst, sadst.ss_len); 79303a2501aSBrian Somers if (cmd == RTM_ADD) { 79430949fd4SBrian Somers if (gw == NULL) { 79530949fd4SBrian Somers log_Printf(LogERROR, "rt_Set: Program error\n"); 79630949fd4SBrian Somers close(s); 79730949fd4SBrian Somers return result; 79830949fd4SBrian Somers } 79930949fd4SBrian Somers ncpaddr_getsa(gw, &sagw); 80093193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 80193193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sagw, bundle->iface->index); 80293193fc7SHajimu UMEMOTO #endif 80330949fd4SBrian Somers if (ncpaddr_isdefault(gw)) { 80430949fd4SBrian Somers if (!quiet) 80503a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: Cannot add a route with" 806156a04e4SBrian Somers " gateway 0.0.0.0\n"); 80703a2501aSBrian Somers close(s); 80803a2501aSBrian Somers return result; 80903a2501aSBrian Somers } else { 810361a7b93SBrian Somers cp += memcpy_roundup(cp, &sagw, sagw.ss_len); 81103a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 81203a2501aSBrian Somers } 81303a2501aSBrian Somers } 81403a2501aSBrian Somers 81526dceef0SBrian Somers if (!ncprange_ishost(dst)) { 816361a7b93SBrian Somers cp += memcpy_roundup(cp, &samask, samask.ss_len); 81703a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 81803a2501aSBrian Somers } 81903a2501aSBrian Somers 82003a2501aSBrian Somers nb = cp - (char *)&rtmes; 82103a2501aSBrian Somers rtmes.m_rtm.rtm_msglen = nb; 82203a2501aSBrian Somers wb = ID0write(s, &rtmes, nb); 82303a2501aSBrian Somers if (wb < 0) { 82403a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set failure:\n"); 82503a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 82630949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst)); 82730949fd4SBrian Somers if (gw != NULL) 82830949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw)); 82903a2501aSBrian Somers failed: 83003a2501aSBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 83103a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 83203a2501aSBrian Somers if (!bang) { 83303a2501aSBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 83430949fd4SBrian Somers ncprange_ntoa(dst)); 83503a2501aSBrian Somers result = 0; /* Don't add to our dynamic list */ 83603a2501aSBrian Somers } else { 83703a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 83803a2501aSBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 83903a2501aSBrian Somers goto failed; 84003a2501aSBrian Somers } 84103a2501aSBrian Somers } else if (cmd == RTM_DELETE && 84203a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 84303a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 84403a2501aSBrian Somers if (!bang) 84503a2501aSBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 84630949fd4SBrian Somers ncprange_ntoa(dst)); 84703a2501aSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 84830949fd4SBrian Somers if (!quiet || errno != ENETUNREACH) 84903a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 85030949fd4SBrian Somers ncprange_ntoa(dst), strerror(errno)); 85103a2501aSBrian Somers } else 85203a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 85330949fd4SBrian Somers cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 85403a2501aSBrian Somers } 85503a2501aSBrian Somers 85630949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 85730949fd4SBrian Somers char gwstr[40]; 85830949fd4SBrian Somers 85930949fd4SBrian Somers if (gw) 86030949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw)); 86130949fd4SBrian Somers else 86230949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "<none>"); 86330949fd4SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n", 86430949fd4SBrian Somers wb, cmdstr, ncprange_ntoa(dst), gwstr); 86530949fd4SBrian Somers } 86603a2501aSBrian Somers close(s); 86703a2501aSBrian Somers 86803a2501aSBrian Somers return result; 86903a2501aSBrian Somers } 87003a2501aSBrian Somers 87103a2501aSBrian Somers void 8725ae08329SBrian Somers rt_Update(struct bundle *bundle, const struct sockaddr *dst, 8735ae08329SBrian Somers const struct sockaddr *gw, const struct sockaddr *mask) 87403a2501aSBrian Somers { 8755ae08329SBrian Somers struct ncprange ncpdst; 87603a2501aSBrian Somers struct rtmsg rtmes; 8775ae08329SBrian Somers char *p; 87803a2501aSBrian Somers int s, wb; 87903a2501aSBrian Somers 88063c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 88103a2501aSBrian Somers if (s < 0) { 88203a2501aSBrian Somers log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 88303a2501aSBrian Somers return; 88403a2501aSBrian Somers } 88503a2501aSBrian Somers 88603a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 88703a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 88803a2501aSBrian Somers rtmes.m_rtm.rtm_type = RTM_CHANGE; 889d42d9220SBrian Somers rtmes.m_rtm.rtm_addrs = 0; 89003a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 89103a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 892afb28bf7SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_STATIC; 89303a2501aSBrian Somers 89430949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 89530949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 89603a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 89703a2501aSBrian Somers } 89803a2501aSBrian Somers 89930949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 90030949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 90103a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 90203a2501aSBrian Somers } 90303a2501aSBrian Somers 904c8b9fb53SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; 90503a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_MTU; 9065ae08329SBrian Somers p = rtmes.m_space; 90703a2501aSBrian Somers 9085ae08329SBrian Somers if (dst) { 9095ae08329SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_DST; 910361a7b93SBrian Somers p += memcpy_roundup(p, dst, dst->sa_len); 9115ae08329SBrian Somers } 91203a2501aSBrian Somers 9130fb550caSBjoern A. Zeeb if (gw) { 914afb28bf7SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 915afb28bf7SBrian Somers p += memcpy_roundup(p, gw, gw->sa_len); 9160fb550caSBjoern A. Zeeb } 9170fb550caSBjoern A. Zeeb 918afb28bf7SBrian Somers if (mask) { 919afb28bf7SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 920afb28bf7SBrian Somers p += memcpy_roundup(p, mask, mask->sa_len); 921afb28bf7SBrian Somers } 922afb28bf7SBrian Somers 9235ae08329SBrian Somers rtmes.m_rtm.rtm_msglen = p - (char *)&rtmes; 92403a2501aSBrian Somers 92503a2501aSBrian Somers wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 92603a2501aSBrian Somers if (wb < 0) { 9275ae08329SBrian Somers ncprange_setsa(&ncpdst, dst, mask); 9285ae08329SBrian Somers 92903a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Update failure:\n"); 9305ae08329SBrian Somers log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst)); 93103a2501aSBrian Somers 93203a2501aSBrian Somers if (rtmes.m_rtm.rtm_errno == 0) 93303a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 9345ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(errno)); 93503a2501aSBrian Somers else 93603a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: %s\n", 9375ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(rtmes.m_rtm.rtm_errno)); 93803a2501aSBrian Somers } 93903a2501aSBrian Somers close(s); 94003a2501aSBrian Somers } 941