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' }, 1615d5e5070SBrian Somers { RTF_STATIC, 'S' }, 1625d5e5070SBrian Somers { RTF_PROTO1, '1' }, 1635d5e5070SBrian Somers { RTF_PROTO2, '2' }, 1645d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 1656e6b3f7cSQing Li #ifdef RTF_LLINFO 1666e6b3f7cSQing Li { RTF_LLINFO, 'L' }, 1676e6b3f7cSQing Li #endif 1686e6b3f7cSQing Li #ifdef RTF_CLONING 1696e6b3f7cSQing Li { RTF_CLONING, 'C' }, 1706e6b3f7cSQing Li #endif 17132ca3341SBrian Somers #ifdef RTF_PROTO3 1725d5e5070SBrian Somers { RTF_PROTO3, '3' }, 17332ca3341SBrian Somers #endif 17432ca3341SBrian Somers #ifdef RTF_BROADCAST 1755d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 1765d5e5070SBrian Somers #endif 1775d5e5070SBrian Somers { 0, '\0' } 178af57ed9fSAtsushi Murai }; 179af57ed9fSAtsushi Murai 180af57ed9fSAtsushi Murai static void 181057f1760SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, unsigned max) 182af57ed9fSAtsushi Murai { 183af57ed9fSAtsushi Murai char name[33], *flags; 184af57ed9fSAtsushi Murai register struct bits *p = bits; 185af57ed9fSAtsushi Murai 18670ee81ffSBrian Somers if (max > sizeof name - 1) 18770ee81ffSBrian Somers max = sizeof name - 1; 188d27d502cSBrian Somers 189057f1760SBrian Somers for (flags = name; p->b_mask && flags - name < (int)max; p++) 190af57ed9fSAtsushi Murai if (p->b_mask & f) 191af57ed9fSAtsushi Murai *flags++ = p->b_val; 192af57ed9fSAtsushi Murai *flags = '\0'; 19300d9db03SBrian Somers prompt_Printf(prompt, "%-*.*s", (int)max, (int)max, name); 194af57ed9fSAtsushi Murai } 195af57ed9fSAtsushi Murai 196de59e178SBrian Somers static int route_nifs = -1; 197de59e178SBrian Somers 198c6fe0cb2SBrian Somers const char * 1995d5e5070SBrian Somers Index2Nam(int idx) 2005d5e5070SBrian Somers { 201d93d3a9cSBrian Somers /* 202d93d3a9cSBrian Somers * XXX: Maybe we should select() on the routing socket so that we can 203d93d3a9cSBrian Somers * notice interfaces that come & go (PCCARD support). 204d93d3a9cSBrian Somers * Or we could even support a signal that resets these so that 205d93d3a9cSBrian Somers * the PCCARD insert/remove events can signal ppp. 206d93d3a9cSBrian Somers */ 207d93d3a9cSBrian Somers static char **ifs; /* Figure these out once */ 208de59e178SBrian Somers static int debug_done; /* Debug once */ 2095d5e5070SBrian Somers 210de59e178SBrian Somers if (idx > route_nifs || (idx > 0 && ifs[idx-1] == NULL)) { 211b1435e41SBrian Somers int mib[6], have, had; 212e7250038SBrian Somers size_t needed; 2135d5e5070SBrian Somers char *buf, *ptr, *end; 2145d5e5070SBrian Somers struct sockaddr_dl *dl; 2155d5e5070SBrian Somers struct if_msghdr *ifm; 2165d5e5070SBrian Somers 2178473f372SBrian Somers if (ifs) { 2188473f372SBrian Somers free(ifs); 2198473f372SBrian Somers ifs = NULL; 220de59e178SBrian Somers route_nifs = 0; 2218473f372SBrian Somers } 2228473f372SBrian Somers debug_done = 0; 2238473f372SBrian Somers 2245d5e5070SBrian Somers mib[0] = CTL_NET; 2255d5e5070SBrian Somers mib[1] = PF_ROUTE; 2265d5e5070SBrian Somers mib[2] = 0; 2275d5e5070SBrian Somers mib[3] = 0; 2285d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 2295d5e5070SBrian Somers mib[5] = 0; 2305d5e5070SBrian Somers 2315d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 232a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 233a33b2ef7SBrian Somers strerror(errno)); 234d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2355d5e5070SBrian Somers } 2365d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 237d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2385d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 2395d5e5070SBrian Somers free(buf); 240d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2415d5e5070SBrian Somers } 2425d5e5070SBrian Somers end = buf + needed; 2435d5e5070SBrian Somers 244b1435e41SBrian Somers have = 0; 2459cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 2465d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 2476b457978SBrian Somers if (ifm->ifm_type != RTM_IFINFO) 24824731321SBrian Somers continue; 2495d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 250b1435e41SBrian Somers if (ifm->ifm_index > 0) { 251b1435e41SBrian Somers if (ifm->ifm_index > have) { 252fc254be9SBrian Somers char **newifs; 253fc254be9SBrian Somers 254b1435e41SBrian Somers had = have; 255b1435e41SBrian Somers have = ifm->ifm_index + 5; 256b1435e41SBrian Somers if (had) 257fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 258b1435e41SBrian Somers else 259fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 260fc254be9SBrian Somers if (!newifs) { 261dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 262de59e178SBrian Somers route_nifs = 0; 2638473f372SBrian Somers if (ifs) { 264fc254be9SBrian Somers free(ifs); 2658473f372SBrian Somers ifs = NULL; 2668473f372SBrian Somers } 2678473f372SBrian Somers free(buf); 268d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 269b1435e41SBrian Somers } 270fc254be9SBrian Somers ifs = newifs; 271b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 272b1435e41SBrian Somers } 273b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 274b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 2755d604c11SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) 2765d604c11SBrian Somers log_Printf(LogDEBUG, "Skipping interface %d: Out of memory\n", 2775d604c11SBrian Somers ifm->ifm_index); 2785d604c11SBrian Somers else { 279b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 280b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 281de59e178SBrian Somers if (route_nifs < ifm->ifm_index) 282de59e178SBrian Somers route_nifs = ifm->ifm_index; 283b1435e41SBrian Somers } 2845d604c11SBrian Somers } 285dd7e2610SBrian Somers } else if (log_IsKept(LogDEBUG)) 286dd7e2610SBrian Somers log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 2879cb1d89eSBrian Somers ifm->ifm_index); 2885d5e5070SBrian Somers } 2895d5e5070SBrian Somers free(buf); 2905d5e5070SBrian Somers } 2915d5e5070SBrian Somers 292dd7e2610SBrian Somers if (log_IsKept(LogDEBUG) && !debug_done) { 2939cb1d89eSBrian Somers int f; 2949cb1d89eSBrian Somers 295dd7e2610SBrian Somers log_Printf(LogDEBUG, "Found the following interfaces:\n"); 296de59e178SBrian Somers for (f = 0; f < route_nifs; f++) 297b1435e41SBrian Somers if (ifs[f] != NULL) 298dd7e2610SBrian Somers log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 2999cb1d89eSBrian Somers debug_done = 1; 3009cb1d89eSBrian Somers } 3019cb1d89eSBrian Somers 302de59e178SBrian Somers if (idx < 1 || idx > route_nifs || ifs[idx-1] == NULL) 303d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3049cb1d89eSBrian Somers 3059cb1d89eSBrian Somers return ifs[idx-1]; 3065d5e5070SBrian Somers } 3075d5e5070SBrian Somers 3086b457978SBrian Somers void 3096b457978SBrian Somers route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 3106b457978SBrian Somers { 3116b457978SBrian Somers char *wp; 3126b457978SBrian Somers int rtax; 3136b457978SBrian Somers 3146b457978SBrian Somers wp = (char *)(rtm + 1); 3156b457978SBrian Somers 3166b457978SBrian Somers for (rtax = 0; rtax < RTAX_MAX; rtax++) 3176b457978SBrian Somers if (rtm->rtm_addrs & (1 << rtax)) { 3186b457978SBrian Somers sa[rtax] = (struct sockaddr *)wp; 3196b457978SBrian Somers wp += ROUNDUP(sa[rtax]->sa_len); 320a3d71c3dSBrian Somers if (sa[rtax]->sa_family == 0) 321a3d71c3dSBrian Somers sa[rtax] = NULL; /* ??? */ 3226b457978SBrian Somers } else 3236b457978SBrian Somers sa[rtax] = NULL; 3246b457978SBrian Somers } 3256b457978SBrian Somers 326af57ed9fSAtsushi Murai int 327dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 328af57ed9fSAtsushi Murai { 329af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3306b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 3316b457978SBrian Somers char *sp, *ep, *cp; 332e7250038SBrian Somers size_t needed; 333af57ed9fSAtsushi Murai int mib[6]; 334af57ed9fSAtsushi Murai 335af57ed9fSAtsushi Murai mib[0] = CTL_NET; 336af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 33753c9f6c0SAtsushi Murai mib[2] = 0; 33853c9f6c0SAtsushi Murai mib[3] = 0; 339af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 34053c9f6c0SAtsushi Murai mib[5] = 0; 34153c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 342dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 34353c9f6c0SAtsushi Murai return (1); 34453c9f6c0SAtsushi Murai } 345af57ed9fSAtsushi Murai sp = malloc(needed); 346af57ed9fSAtsushi Murai if (sp == NULL) 347af57ed9fSAtsushi Murai return (1); 34853c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 349dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 350b0cdb3ceSJordan K. Hubbard free(sp); 351af57ed9fSAtsushi Murai return (1); 35253c9f6c0SAtsushi Murai } 353af57ed9fSAtsushi Murai ep = sp + needed; 354af57ed9fSAtsushi Murai 355b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 356b6217683SBrian Somers "Destination", "Gateway"); 357af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 358af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 3595d5e5070SBrian Somers 3606b457978SBrian Somers route_ParseHdr(rtm, sa); 3616b384664SBrian Somers 3626b457978SBrian Somers if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 3636b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 3646b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 3655d5e5070SBrian Somers 366b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 367b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 3686b384664SBrian Somers } else 3696b384664SBrian Somers prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 370af57ed9fSAtsushi Murai } 371b0cdb3ceSJordan K. Hubbard free(sp); 372927145beSBrian Somers return 0; 373af57ed9fSAtsushi Murai } 374af57ed9fSAtsushi Murai 375af57ed9fSAtsushi Murai /* 376af57ed9fSAtsushi Murai * Delete routes associated with our interface 377af57ed9fSAtsushi Murai */ 378af57ed9fSAtsushi Murai void 379dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 380af57ed9fSAtsushi Murai { 381af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3826b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 38330949fd4SBrian Somers struct ncprange range; 384e7250038SBrian Somers int pass; 385e7250038SBrian Somers size_t needed; 386af57ed9fSAtsushi Murai char *sp, *cp, *ep; 387af57ed9fSAtsushi Murai int mib[6]; 388af57ed9fSAtsushi Murai 3898fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 390927145beSBrian Somers 391af57ed9fSAtsushi Murai mib[0] = CTL_NET; 392af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 39353c9f6c0SAtsushi Murai mib[2] = 0; 39453c9f6c0SAtsushi Murai mib[3] = 0; 395af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 39653c9f6c0SAtsushi Murai mib[5] = 0; 39753c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 398dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 399afc7fa2cSBrian Somers strerror(errno)); 40053c9f6c0SAtsushi Murai return; 40153c9f6c0SAtsushi Murai } 402af57ed9fSAtsushi Murai 403af57ed9fSAtsushi Murai sp = malloc(needed); 404af57ed9fSAtsushi Murai if (sp == NULL) 405af57ed9fSAtsushi Murai return; 406af57ed9fSAtsushi Murai 407af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 408dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 409afc7fa2cSBrian Somers strerror(errno)); 410af57ed9fSAtsushi Murai free(sp); 411af57ed9fSAtsushi Murai return; 412af57ed9fSAtsushi Murai } 413af57ed9fSAtsushi Murai ep = sp + needed; 414af57ed9fSAtsushi Murai 41532ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 41632ca3341SBrian Somers /* 41732ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 4186b457978SBrian Somers * deletes all non-cloned routes. This is done to avoid 41932ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 420ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 421ba081e43SBrian Somers * may have gone with route Y). 42232ca3341SBrian Somers */ 42366dcee72SGleb Smirnoff if (pass == 0) 42432ca3341SBrian Somers /* So we can't tell ! */ 42532ca3341SBrian Somers continue; 426af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 427af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4286b457978SBrian Somers route_ParseHdr(rtm, sa); 42930949fd4SBrian Somers if (rtm->rtm_index == bundle->iface->index && 43030949fd4SBrian Somers sa[RTAX_DST] && sa[RTAX_GATEWAY] && 43130949fd4SBrian Somers (sa[RTAX_DST]->sa_family == AF_INET 43230949fd4SBrian Somers #ifndef NOINET6 43330949fd4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 43430949fd4SBrian Somers #endif 43530949fd4SBrian Somers ) && 436af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 43730949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 43830949fd4SBrian Somers char gwstr[41]; 43930949fd4SBrian Somers struct ncpaddr gw; 44030949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 44130949fd4SBrian Somers ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]); 44230949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw)); 44330949fd4SBrian Somers log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr); 44430949fd4SBrian Somers } 4456b457978SBrian Somers if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 44630949fd4SBrian Somers #ifndef NOINET6 44730949fd4SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_INET6 || 44830949fd4SBrian Somers #endif 4496b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 45066dcee72SGleb Smirnoff if (pass == 1) { 45130949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 45230949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0); 4535d5e5070SBrian Somers } else 454dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 45532ca3341SBrian Somers } else 456dd7e2610SBrian Somers log_Printf(LogDEBUG, 45730949fd4SBrian Somers "route_IfDelete: Can't remove routes for family %d\n", 4586b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family); 4596b457978SBrian Somers } 460af57ed9fSAtsushi Murai } 461af57ed9fSAtsushi Murai } 462af57ed9fSAtsushi Murai free(sp); 463af57ed9fSAtsushi Murai } 464af57ed9fSAtsushi Murai 46503a2501aSBrian Somers 46603a2501aSBrian Somers /* 46703a2501aSBrian Somers * Update the MTU on all routes for the given interface 46803a2501aSBrian Somers */ 46903a2501aSBrian Somers void 47003a2501aSBrian Somers route_UpdateMTU(struct bundle *bundle) 47103a2501aSBrian Somers { 47203a2501aSBrian Somers struct rt_msghdr *rtm; 47303a2501aSBrian Somers struct sockaddr *sa[RTAX_MAX]; 47430949fd4SBrian Somers struct ncprange dst; 47503a2501aSBrian Somers size_t needed; 47603a2501aSBrian Somers char *sp, *cp, *ep; 47703a2501aSBrian Somers int mib[6]; 47803a2501aSBrian Somers 47903a2501aSBrian Somers log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 48003a2501aSBrian Somers 48103a2501aSBrian Somers mib[0] = CTL_NET; 48203a2501aSBrian Somers mib[1] = PF_ROUTE; 48303a2501aSBrian Somers mib[2] = 0; 48403a2501aSBrian Somers mib[3] = 0; 48503a2501aSBrian Somers mib[4] = NET_RT_DUMP; 48603a2501aSBrian Somers mib[5] = 0; 48703a2501aSBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 48803a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 48903a2501aSBrian Somers strerror(errno)); 49003a2501aSBrian Somers return; 49103a2501aSBrian Somers } 49203a2501aSBrian Somers 49303a2501aSBrian Somers sp = malloc(needed); 49403a2501aSBrian Somers if (sp == NULL) 49503a2501aSBrian Somers return; 49603a2501aSBrian Somers 49703a2501aSBrian Somers if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 49803a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 49903a2501aSBrian Somers strerror(errno)); 50003a2501aSBrian Somers free(sp); 50103a2501aSBrian Somers return; 50203a2501aSBrian Somers } 50303a2501aSBrian Somers ep = sp + needed; 50403a2501aSBrian Somers 50503a2501aSBrian Somers for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 50603a2501aSBrian Somers rtm = (struct rt_msghdr *)cp; 50703a2501aSBrian Somers route_ParseHdr(rtm, sa); 5081d3d76d4SBrian Somers if (sa[RTAX_DST] && (sa[RTAX_DST]->sa_family == AF_INET 5095ae08329SBrian Somers #ifndef NOINET6 5101d3d76d4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 5115ae08329SBrian Somers #endif 5125ae08329SBrian Somers ) && 5135ae08329SBrian Somers sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index) { 5145ae08329SBrian Somers if (log_IsKept(LogTCPIP)) { 51530949fd4SBrian Somers ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]); 5165ae08329SBrian Somers log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s," 517057f1760SBrian Somers " mtu %lu\n", rtm->rtm_index, Index2Nam(rtm->rtm_index), 5185ae08329SBrian Somers ncprange_ntoa(&dst), bundle->iface->mtu); 5195ae08329SBrian Somers } 5200e81959dSBjoern A. Zeeb rt_Update(bundle, sa[RTAX_DST], sa[RTAX_GATEWAY], sa[RTAX_NETMASK], 5210e81959dSBjoern A. Zeeb sa[RTAX_IFP], sa[RTAX_IFA]); 52203a2501aSBrian Somers } 52303a2501aSBrian Somers } 52403a2501aSBrian Somers 52503a2501aSBrian Somers free(sp); 52603a2501aSBrian Somers } 52703a2501aSBrian Somers 528af57ed9fSAtsushi Murai int 529944f7098SBrian Somers GetIfIndex(char *name) 530af57ed9fSAtsushi Murai { 5315d5e5070SBrian Somers int idx; 532944f7098SBrian Somers 5339cb1d89eSBrian Somers idx = 1; 534de59e178SBrian Somers while (route_nifs == -1 || idx < route_nifs) 535de59e178SBrian Somers if (strcmp(Index2Nam(idx), name) == 0) 5367a6f8720SBrian Somers return idx; 5375d5e5070SBrian Somers else 5385d5e5070SBrian Somers idx++; 5395d5e5070SBrian Somers return -1; 540af57ed9fSAtsushi Murai } 541bcc332bdSBrian Somers 542610b185fSBrian Somers void 543610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 54430949fd4SBrian Somers const struct ncpaddr *me, const struct ncpaddr *peer) 545bcc332bdSBrian Somers { 54630949fd4SBrian Somers struct ncpaddr dst; 547bcc332bdSBrian Somers 548610b185fSBrian Somers for (; r; r = r->next) { 54930949fd4SBrian Somers ncprange_getaddr(&r->dst, &dst); 55030949fd4SBrian Somers if (ncpaddr_family(me) == AF_INET) { 55130949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) { 55230949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 55330949fd4SBrian Somers ncprange_sethost(&r->dst, me); 554610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 55530949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 55630949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) { 55730949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 55830949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 559610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 56030949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56130949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) { 56230949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE) 56330949fd4SBrian Somers continue; 56430949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 565d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 56630949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56730949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) { 56830949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[1].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_GWHISADDR) && !ncpaddr_equal(&r->gw, peer)) 57430949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57530949fd4SBrian Somers #ifndef NOINET6 57630949fd4SBrian Somers } else if (ncpaddr_family(me) == AF_INET6) { 57730949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) { 57830949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 57930949fd4SBrian Somers ncprange_sethost(&r->dst, me); 58030949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58130949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58230949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) { 58330949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 58430949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 58530949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58630949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58730949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer)) 58830949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58930949fd4SBrian Somers #endif 59030949fd4SBrian Somers } 59130949fd4SBrian Somers rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0); 592610b185fSBrian Somers } 593610b185fSBrian Somers } 594610b185fSBrian Somers 595610b185fSBrian Somers void 59630949fd4SBrian Somers route_Add(struct sticky_route **rp, int type, const struct ncprange *dst, 59730949fd4SBrian Somers const struct ncpaddr *gw) 598610b185fSBrian Somers { 599610b185fSBrian Somers struct sticky_route *r; 600610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 601610b185fSBrian Somers 602610b185fSBrian Somers r = NULL; 603610b185fSBrian Somers while (*rp) { 604183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 60530949fd4SBrian Somers (!dsttype && ncprange_equal(&(*rp)->dst, dst))) { 606972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 607972a1bcfSBrian Somers free(r); /* impossible really */ 608610b185fSBrian Somers r = *rp; 609610b185fSBrian Somers *rp = r->next; 610610b185fSBrian Somers } else 611610b185fSBrian Somers rp = &(*rp)->next; 612610b185fSBrian Somers } 613610b185fSBrian Somers 6145d604c11SBrian Somers if (r == NULL) { 615610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 6165d604c11SBrian Somers if (r == NULL) { 6175d604c11SBrian Somers log_Printf(LogERROR, "route_Add: Out of memory!\n"); 6185d604c11SBrian Somers return; 6195d604c11SBrian Somers } 6205d604c11SBrian Somers } 621610b185fSBrian Somers r->type = type; 622610b185fSBrian Somers r->next = NULL; 62330949fd4SBrian Somers ncprange_copy(&r->dst, dst); 62430949fd4SBrian Somers ncpaddr_copy(&r->gw, gw); 625bcd13e2eSBrian Somers *rp = r; 626610b185fSBrian Somers } 627610b185fSBrian Somers 628610b185fSBrian Somers void 62930949fd4SBrian Somers route_Delete(struct sticky_route **rp, int type, const struct ncprange *dst) 630610b185fSBrian Somers { 631610b185fSBrian Somers struct sticky_route *r; 632610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 633610b185fSBrian Somers 634610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 635610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 63630949fd4SBrian Somers (!dsttype && ncprange_equal(dst, &(*rp)->dst))) { 637610b185fSBrian Somers r = *rp; 638610b185fSBrian Somers *rp = r->next; 639610b185fSBrian Somers free(r); 640bcc332bdSBrian Somers break; 641bcc332bdSBrian Somers } 642bcc332bdSBrian Somers } 643bcc332bdSBrian Somers } 644bcc332bdSBrian Somers 645610b185fSBrian Somers void 646610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 647610b185fSBrian Somers { 648610b185fSBrian Somers struct sticky_route *r, *rn; 649610b185fSBrian Somers 650610b185fSBrian Somers for (r = *rp; r; r = rn) { 651610b185fSBrian Somers rn = r->next; 652610b185fSBrian Somers free(r); 653610b185fSBrian Somers } 654610b185fSBrian Somers *rp = NULL; 655610b185fSBrian Somers } 656610b185fSBrian Somers 657610b185fSBrian Somers void 658972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 659972a1bcfSBrian Somers int indent) 660610b185fSBrian Somers { 661972a1bcfSBrian Somers int tlen = strlen(tag); 662610b185fSBrian Somers 663972a1bcfSBrian Somers if (tlen + 2 > indent) 664972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 665972a1bcfSBrian Somers else 666972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 667972a1bcfSBrian Somers 668610b185fSBrian Somers for (; r; r = r->next) { 669972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 670972a1bcfSBrian Somers tlen = 0; 671610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 672610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 67330949fd4SBrian Somers else if (r->type & ROUTE_DSTMYADDR6) 67430949fd4SBrian Somers prompt_Printf(p, "MYADDR6"); 675610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 676610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 67730949fd4SBrian Somers else if (r->type & ROUTE_DSTHISADDR6) 67830949fd4SBrian Somers prompt_Printf(p, "HISADDR6"); 679d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS0) 680d568d6c4SBrian Somers prompt_Printf(p, "DNS0"); 681d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS1) 682d568d6c4SBrian Somers prompt_Printf(p, "DNS1"); 68330949fd4SBrian Somers else if (ncprange_isdefault(&r->dst)) 684610b185fSBrian Somers prompt_Printf(p, "default"); 685610b185fSBrian Somers else 68630949fd4SBrian Somers prompt_Printf(p, "%s", ncprange_ntoa(&r->dst)); 687610b185fSBrian Somers 688610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 689610b185fSBrian Somers prompt_Printf(p, " HISADDR\n"); 69030949fd4SBrian Somers else if (r->type & ROUTE_GWHISADDR6) 69130949fd4SBrian Somers prompt_Printf(p, " HISADDR6\n"); 692610b185fSBrian Somers else 69330949fd4SBrian Somers prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw)); 694610b185fSBrian Somers } 695bcc332bdSBrian Somers } 69603a2501aSBrian Somers 69703a2501aSBrian Somers struct rtmsg { 69803a2501aSBrian Somers struct rt_msghdr m_rtm; 69930949fd4SBrian Somers char m_space[256]; 70003a2501aSBrian Somers }; 70103a2501aSBrian Somers 702361a7b93SBrian Somers static size_t 703361a7b93SBrian Somers memcpy_roundup(char *cp, const void *data, size_t len) 704361a7b93SBrian Somers { 705361a7b93SBrian Somers size_t padlen; 706361a7b93SBrian Somers 707361a7b93SBrian Somers padlen = ROUNDUP(len); 708361a7b93SBrian Somers memcpy(cp, data, len); 709361a7b93SBrian Somers if (padlen > len) 710361a7b93SBrian Somers memset(cp + len, '\0', padlen - len); 711361a7b93SBrian Somers 712361a7b93SBrian Somers return padlen; 713361a7b93SBrian Somers } 714361a7b93SBrian Somers 71593193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 71693193fc7SHajimu UMEMOTO static void 71793193fc7SHajimu UMEMOTO add_scope(struct sockaddr *sa, int ifindex) 71893193fc7SHajimu UMEMOTO { 71993193fc7SHajimu UMEMOTO struct sockaddr_in6 *sa6; 72093193fc7SHajimu UMEMOTO 72193193fc7SHajimu UMEMOTO if (sa->sa_family != AF_INET6) 72293193fc7SHajimu UMEMOTO return; 72393193fc7SHajimu UMEMOTO sa6 = (struct sockaddr_in6 *)sa; 72493193fc7SHajimu UMEMOTO if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && 72593193fc7SHajimu UMEMOTO !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) 72693193fc7SHajimu UMEMOTO return; 72793193fc7SHajimu UMEMOTO if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0) 72893193fc7SHajimu UMEMOTO return; 72993193fc7SHajimu UMEMOTO *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex); 73093193fc7SHajimu UMEMOTO } 73193193fc7SHajimu UMEMOTO #endif 73293193fc7SHajimu UMEMOTO 73303a2501aSBrian Somers int 73430949fd4SBrian Somers rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst, 73530949fd4SBrian Somers const struct ncpaddr *gw, int bang, int quiet) 73603a2501aSBrian Somers { 73703a2501aSBrian Somers struct rtmsg rtmes; 738846e7227SBrian Somers int s, nb, wb; 73903a2501aSBrian Somers char *cp; 74003a2501aSBrian Somers const char *cmdstr; 74130949fd4SBrian Somers struct sockaddr_storage sadst, samask, sagw; 74203a2501aSBrian Somers int result = 1; 74303a2501aSBrian Somers 74403a2501aSBrian Somers if (bang) 74503a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 74603a2501aSBrian Somers else 74703a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 74863c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 74903a2501aSBrian Somers if (s < 0) { 75003a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 75103a2501aSBrian Somers return result; 75203a2501aSBrian Somers } 75303a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 75403a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 75503a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd; 75603a2501aSBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 75703a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 75803a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 75903a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 76003a2501aSBrian Somers 76103a2501aSBrian Somers if (cmd == RTM_ADD) { 76230949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 76330949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 76403a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 76503a2501aSBrian Somers } 76630949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 76730949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 76803a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 76903a2501aSBrian Somers } 77003a2501aSBrian Somers } 77103a2501aSBrian Somers 77230949fd4SBrian Somers ncprange_getsa(dst, &sadst, &samask); 77393193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 77493193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sadst, bundle->iface->index); 77593193fc7SHajimu UMEMOTO #endif 77603a2501aSBrian Somers 77703a2501aSBrian Somers cp = rtmes.m_space; 778361a7b93SBrian Somers cp += memcpy_roundup(cp, &sadst, sadst.ss_len); 77903a2501aSBrian Somers if (cmd == RTM_ADD) { 78030949fd4SBrian Somers if (gw == NULL) { 78130949fd4SBrian Somers log_Printf(LogERROR, "rt_Set: Program error\n"); 78230949fd4SBrian Somers close(s); 78330949fd4SBrian Somers return result; 78430949fd4SBrian Somers } 78530949fd4SBrian Somers ncpaddr_getsa(gw, &sagw); 78693193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 78793193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sagw, bundle->iface->index); 78893193fc7SHajimu UMEMOTO #endif 78930949fd4SBrian Somers if (ncpaddr_isdefault(gw)) { 79030949fd4SBrian Somers if (!quiet) 79103a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: Cannot add a route with" 792156a04e4SBrian Somers " gateway 0.0.0.0\n"); 79303a2501aSBrian Somers close(s); 79403a2501aSBrian Somers return result; 79503a2501aSBrian Somers } else { 796361a7b93SBrian Somers cp += memcpy_roundup(cp, &sagw, sagw.ss_len); 79703a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 79803a2501aSBrian Somers } 79903a2501aSBrian Somers } 80003a2501aSBrian Somers 80126dceef0SBrian Somers if (!ncprange_ishost(dst)) { 802361a7b93SBrian Somers cp += memcpy_roundup(cp, &samask, samask.ss_len); 80303a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 80403a2501aSBrian Somers } 805*538abeb1SEugene Grosbein else 806*538abeb1SEugene Grosbein rtmes.m_rtm.rtm_flags |= RTF_HOST; 80703a2501aSBrian Somers 80803a2501aSBrian Somers nb = cp - (char *)&rtmes; 80903a2501aSBrian Somers rtmes.m_rtm.rtm_msglen = nb; 81003a2501aSBrian Somers wb = ID0write(s, &rtmes, nb); 81103a2501aSBrian Somers if (wb < 0) { 81203a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set failure:\n"); 81303a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 81430949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst)); 81530949fd4SBrian Somers if (gw != NULL) 81630949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw)); 81703a2501aSBrian Somers failed: 81803a2501aSBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 81903a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 82003a2501aSBrian Somers if (!bang) { 82103a2501aSBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 82230949fd4SBrian Somers ncprange_ntoa(dst)); 82303a2501aSBrian Somers result = 0; /* Don't add to our dynamic list */ 82403a2501aSBrian Somers } else { 82503a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 82603a2501aSBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 82703a2501aSBrian Somers goto failed; 82803a2501aSBrian Somers } 82903a2501aSBrian Somers } else if (cmd == RTM_DELETE && 83003a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 83103a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 83203a2501aSBrian Somers if (!bang) 83303a2501aSBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 83430949fd4SBrian Somers ncprange_ntoa(dst)); 83503a2501aSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 83630949fd4SBrian Somers if (!quiet || errno != ENETUNREACH) 83703a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 83830949fd4SBrian Somers ncprange_ntoa(dst), strerror(errno)); 83903a2501aSBrian Somers } else 84003a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 84130949fd4SBrian Somers cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 84203a2501aSBrian Somers } 84303a2501aSBrian Somers 84430949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 84530949fd4SBrian Somers char gwstr[40]; 84630949fd4SBrian Somers 84730949fd4SBrian Somers if (gw) 84830949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw)); 84930949fd4SBrian Somers else 85030949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "<none>"); 85130949fd4SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n", 85230949fd4SBrian Somers wb, cmdstr, ncprange_ntoa(dst), gwstr); 85330949fd4SBrian Somers } 85403a2501aSBrian Somers close(s); 85503a2501aSBrian Somers 85603a2501aSBrian Somers return result; 85703a2501aSBrian Somers } 85803a2501aSBrian Somers 85903a2501aSBrian Somers void 8605ae08329SBrian Somers rt_Update(struct bundle *bundle, const struct sockaddr *dst, 8610e81959dSBjoern A. Zeeb const struct sockaddr *gw, const struct sockaddr *mask, 8620e81959dSBjoern A. Zeeb const struct sockaddr *ifp, const struct sockaddr *ifa) 86303a2501aSBrian Somers { 8645ae08329SBrian Somers struct ncprange ncpdst; 86503a2501aSBrian Somers struct rtmsg rtmes; 8665ae08329SBrian Somers char *p; 86703a2501aSBrian Somers int s, wb; 86803a2501aSBrian Somers 86963c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 87003a2501aSBrian Somers if (s < 0) { 87103a2501aSBrian Somers log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 87203a2501aSBrian Somers return; 87303a2501aSBrian Somers } 87403a2501aSBrian Somers 87503a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 87603a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 87703a2501aSBrian Somers rtmes.m_rtm.rtm_type = RTM_CHANGE; 878d42d9220SBrian Somers rtmes.m_rtm.rtm_addrs = 0; 87903a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 88003a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 881afb28bf7SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_STATIC; 88203a2501aSBrian Somers 88330949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 88430949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 88503a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 88603a2501aSBrian Somers } 88703a2501aSBrian Somers 88830949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 88930949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 89003a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 89103a2501aSBrian Somers } 89203a2501aSBrian Somers 893c8b9fb53SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; 89403a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_MTU; 8955ae08329SBrian Somers p = rtmes.m_space; 89603a2501aSBrian Somers 8975ae08329SBrian Somers if (dst) { 8985ae08329SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_DST; 899361a7b93SBrian Somers p += memcpy_roundup(p, dst, dst->sa_len); 9005ae08329SBrian Somers } 90103a2501aSBrian Somers 9020fb550caSBjoern A. Zeeb if (gw) { 903afb28bf7SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 904afb28bf7SBrian Somers p += memcpy_roundup(p, gw, gw->sa_len); 9050fb550caSBjoern A. Zeeb } 9060fb550caSBjoern A. Zeeb 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 } 911*538abeb1SEugene Grosbein else 912*538abeb1SEugene Grosbein rtmes.m_rtm.rtm_flags |= RTF_HOST; 913afb28bf7SBrian Somers 9140e81959dSBjoern A. Zeeb if (ifa && ifp && ifp->sa_family == AF_LINK) { 9150e81959dSBjoern A. Zeeb rtmes.m_rtm.rtm_addrs |= RTA_IFP; 9160e81959dSBjoern A. Zeeb p += memcpy_roundup(p, ifp, ifp->sa_len); 9170e81959dSBjoern A. Zeeb rtmes.m_rtm.rtm_addrs |= RTA_IFA; 9180e81959dSBjoern A. Zeeb p += memcpy_roundup(p, ifa, ifa->sa_len); 9190e81959dSBjoern A. Zeeb } 9200e81959dSBjoern A. Zeeb 9215ae08329SBrian Somers rtmes.m_rtm.rtm_msglen = p - (char *)&rtmes; 92203a2501aSBrian Somers 92303a2501aSBrian Somers wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 92403a2501aSBrian Somers if (wb < 0) { 9255ae08329SBrian Somers ncprange_setsa(&ncpdst, dst, mask); 9265ae08329SBrian Somers 92703a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Update failure:\n"); 9285ae08329SBrian Somers log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst)); 92903a2501aSBrian Somers 93003a2501aSBrian Somers if (rtmes.m_rtm.rtm_errno == 0) 93103a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 9325ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(errno)); 93303a2501aSBrian Somers else 93403a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: %s\n", 9355ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(rtmes.m_rtm.rtm_errno)); 93603a2501aSBrian Somers } 93703a2501aSBrian Somers close(s); 93803a2501aSBrian Somers } 939