165309e5cSBrian Somers /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 465309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 565309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 665309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 765309e5cSBrian Somers * All rights reserved. 8af57ed9fSAtsushi Murai * 965309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 1065309e5cSBrian Somers * modification, are permitted provided that the following conditions 1165309e5cSBrian Somers * are met: 1265309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1465309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1565309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1665309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 17af57ed9fSAtsushi Murai * 1865309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1965309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2065309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2165309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2265309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2365309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2465309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2565309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2665309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2765309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2865309e5cSBrian Somers * SUCH DAMAGE. 29af57ed9fSAtsushi Murai * 3097d92980SPeter Wemm * $FreeBSD$ 31af57ed9fSAtsushi Murai */ 3275240ed1SBrian Somers 33972a1bcfSBrian Somers #include <sys/param.h> 3475240ed1SBrian Somers #include <sys/socket.h> 355d5e5070SBrian Somers #include <net/if_types.h> 36628d2ac1SGarrett Wollman #include <net/route.h> 37628d2ac1SGarrett Wollman #include <net/if.h> 38628d2ac1SGarrett Wollman #include <netinet/in.h> 39628d2ac1SGarrett Wollman #include <arpa/inet.h> 405d5e5070SBrian Somers #include <net/if_dl.h> 41eaa4df37SBrian Somers #include <netinet/in_systm.h> 42eaa4df37SBrian Somers #include <netinet/ip.h> 431fa665f5SBrian Somers #include <sys/un.h> 44628d2ac1SGarrett Wollman 4575240ed1SBrian Somers #include <errno.h> 466eafd353SBrian Somers #include <stdarg.h> 4775240ed1SBrian Somers #include <stdio.h> 4875240ed1SBrian Somers #include <stdlib.h> 4975240ed1SBrian Somers #include <string.h> 5075240ed1SBrian Somers #include <sys/sysctl.h> 5185b542cfSBrian Somers #include <termios.h> 5203a2501aSBrian Somers #include <unistd.h> 5375240ed1SBrian Somers 545d9e6103SBrian Somers #include "layer.h" 55c9e11a11SBrian Somers #include "defs.h" 56b6e82f33SBrian Somers #include "command.h" 5775240ed1SBrian Somers #include "mbuf.h" 58215a4696SAtsushi Murai #include "log.h" 59bcc332bdSBrian Somers #include "iplist.h" 6029e275ceSBrian Somers #include "timer.h" 6129e275ceSBrian Somers #include "throughput.h" 62879ed6faSBrian Somers #include "lqr.h" 638c07a7b2SBrian Somers #include "hdlc.h" 647308ec68SBrian Somers #include "fsm.h" 653b0f8d2eSBrian Somers #include "lcp.h" 663b0f8d2eSBrian Somers #include "ccp.h" 673b0f8d2eSBrian Somers #include "link.h" 68eaa4df37SBrian Somers #include "slcompress.h" 6930949fd4SBrian Somers #include "ncpaddr.h" 7029e275ceSBrian Somers #include "ipcp.h" 715ca5389aSBrian Somers #include "filter.h" 722f786681SBrian Somers #include "descriptor.h" 733b0f8d2eSBrian Somers #include "mp.h" 74972a1bcfSBrian Somers #ifndef NORADIUS 75972a1bcfSBrian Somers #include "radius.h" 76972a1bcfSBrian Somers #endif 7730949fd4SBrian Somers #include "ipv6cp.h" 7830949fd4SBrian Somers #include "ncp.h" 795828db6dSBrian Somers #include "bundle.h" 8075240ed1SBrian Somers #include "route.h" 8185b542cfSBrian Somers #include "prompt.h" 828fa6ebe4SBrian Somers #include "iface.h" 8303a2501aSBrian Somers #include "id.h" 84af57ed9fSAtsushi Murai 856b457978SBrian Somers 86af57ed9fSAtsushi Murai static void 87b6217683SBrian Somers p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 88b6217683SBrian Somers struct sockaddr *pmask, int width) 89af57ed9fSAtsushi Murai { 9030949fd4SBrian Somers struct ncprange range; 91b6e82f33SBrian Somers char buf[29]; 925d5e5070SBrian Somers struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 93af57ed9fSAtsushi Murai 946b384664SBrian Somers if (log_IsKept(LogDEBUG)) { 956b384664SBrian Somers char tmp[50]; 966b384664SBrian Somers 976b384664SBrian Somers log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 986b384664SBrian Somers log_Printf(LogDEBUG, " Family %d, len %d\n", 996b384664SBrian Somers (int)phost->sa_family, (int)phost->sa_len); 1006b457978SBrian Somers inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 1016b384664SBrian Somers log_Printf(LogDEBUG, " Addr %s\n", tmp); 1026b384664SBrian Somers if (pmask) { 1036b457978SBrian Somers inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 1046b384664SBrian Somers log_Printf(LogDEBUG, " Mask %s\n", tmp); 1056b384664SBrian Somers } 1066b384664SBrian Somers } 1076b384664SBrian Somers 1085d5e5070SBrian Somers switch (phost->sa_family) { 1095d5e5070SBrian Somers case AF_INET: 11030949fd4SBrian Somers #ifndef NOINET6 11130949fd4SBrian Somers case AF_INET6: 11230949fd4SBrian Somers #endif 11330949fd4SBrian Somers ncprange_setsa(&range, phost, pmask); 11430949fd4SBrian Somers if (ncprange_isdefault(&range)) 11530949fd4SBrian Somers prompt_Printf(prompt, "%-*s ", width - 1, "default"); 1165d5e5070SBrian Somers else 11730949fd4SBrian Somers prompt_Printf(prompt, "%-*s ", width - 1, ncprange_ntoa(&range)); 11830949fd4SBrian Somers return; 1195d5e5070SBrian Somers 1205d5e5070SBrian Somers case AF_LINK: 1214bfaee90SBrian Somers if (dl->sdl_nlen) 1224bfaee90SBrian Somers snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 123c4c4aaacSBrian Somers else if (dl->sdl_alen) { 124c4c4aaacSBrian Somers if (dl->sdl_type == IFT_ETHER) { 12570ee81ffSBrian Somers if (dl->sdl_alen < sizeof buf / 3) { 1265d5e5070SBrian Somers int f; 1275d5e5070SBrian Somers u_char *MAC; 1285d5e5070SBrian Somers 1295d5e5070SBrian Somers MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 1305d5e5070SBrian Somers for (f = 0; f < dl->sdl_alen; f++) 1315d5e5070SBrian Somers sprintf(buf+f*3, "%02x:", MAC[f]); 1325d5e5070SBrian Somers buf[f*3-1] = '\0'; 1335d5e5070SBrian Somers } else 13483c0952dSBrian Somers strcpy(buf, "??:??:??:??:??:??"); 135c4c4aaacSBrian Somers } else 1364bfaee90SBrian Somers sprintf(buf, "<IFT type %d>", dl->sdl_type); 137c4c4aaacSBrian Somers } else if (dl->sdl_slen) 1384bfaee90SBrian Somers sprintf(buf, "<slen %d?>", dl->sdl_slen); 1394bfaee90SBrian Somers else 1404bfaee90SBrian Somers sprintf(buf, "link#%d", dl->sdl_index); 1415d5e5070SBrian Somers break; 1425d5e5070SBrian Somers 1435d5e5070SBrian Somers default: 1444bfaee90SBrian Somers sprintf(buf, "<AF type %d>", phost->sa_family); 1455d5e5070SBrian Somers break; 1465d5e5070SBrian Somers } 1475d5e5070SBrian Somers 148b6217683SBrian Somers prompt_Printf(prompt, "%-*s ", width-1, buf); 149af57ed9fSAtsushi Murai } 150af57ed9fSAtsushi Murai 151aa8e0519SBrian Somers static struct bits { 1523f06c599SBrian Somers u_int32_t b_mask; 153af57ed9fSAtsushi Murai char b_val; 154af57ed9fSAtsushi Murai } bits[] = { 1555d5e5070SBrian Somers { RTF_UP, 'U' }, 1565d5e5070SBrian Somers { RTF_GATEWAY, 'G' }, 1575d5e5070SBrian Somers { RTF_HOST, 'H' }, 1585d5e5070SBrian Somers { RTF_REJECT, 'R' }, 1595d5e5070SBrian Somers { RTF_DYNAMIC, 'D' }, 1605d5e5070SBrian Somers { RTF_MODIFIED, 'M' }, 1615d5e5070SBrian Somers { RTF_DONE, 'd' }, 1625d5e5070SBrian Somers { RTF_XRESOLVE, 'X' }, 1635d5e5070SBrian Somers { RTF_STATIC, 'S' }, 1645d5e5070SBrian Somers { RTF_PROTO1, '1' }, 1655d5e5070SBrian Somers { RTF_PROTO2, '2' }, 1665d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 1676e6b3f7cSQing Li #ifdef RTF_LLINFO 1686e6b3f7cSQing Li { RTF_LLINFO, 'L' }, 1696e6b3f7cSQing Li #endif 1706e6b3f7cSQing Li #ifdef RTF_CLONING 1716e6b3f7cSQing Li { RTF_CLONING, 'C' }, 1726e6b3f7cSQing Li #endif 17332ca3341SBrian Somers #ifdef RTF_PROTO3 1745d5e5070SBrian Somers { RTF_PROTO3, '3' }, 17532ca3341SBrian Somers #endif 17632ca3341SBrian Somers #ifdef RTF_BROADCAST 1775d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 1785d5e5070SBrian Somers #endif 1795d5e5070SBrian Somers { 0, '\0' } 180af57ed9fSAtsushi Murai }; 181af57ed9fSAtsushi Murai 182af57ed9fSAtsushi Murai static void 183057f1760SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, unsigned max) 184af57ed9fSAtsushi Murai { 185af57ed9fSAtsushi Murai char name[33], *flags; 186af57ed9fSAtsushi Murai register struct bits *p = bits; 187af57ed9fSAtsushi Murai 18870ee81ffSBrian Somers if (max > sizeof name - 1) 18970ee81ffSBrian Somers max = sizeof name - 1; 190d27d502cSBrian Somers 191057f1760SBrian Somers for (flags = name; p->b_mask && flags - name < (int)max; p++) 192af57ed9fSAtsushi Murai if (p->b_mask & f) 193af57ed9fSAtsushi Murai *flags++ = p->b_val; 194af57ed9fSAtsushi Murai *flags = '\0'; 19500d9db03SBrian Somers prompt_Printf(prompt, "%-*.*s", (int)max, (int)max, name); 196af57ed9fSAtsushi Murai } 197af57ed9fSAtsushi Murai 198de59e178SBrian Somers static int route_nifs = -1; 199de59e178SBrian Somers 200c6fe0cb2SBrian Somers const char * 2015d5e5070SBrian Somers Index2Nam(int idx) 2025d5e5070SBrian Somers { 203d93d3a9cSBrian Somers /* 204d93d3a9cSBrian Somers * XXX: Maybe we should select() on the routing socket so that we can 205d93d3a9cSBrian Somers * notice interfaces that come & go (PCCARD support). 206d93d3a9cSBrian Somers * Or we could even support a signal that resets these so that 207d93d3a9cSBrian Somers * the PCCARD insert/remove events can signal ppp. 208d93d3a9cSBrian Somers */ 209d93d3a9cSBrian Somers static char **ifs; /* Figure these out once */ 210de59e178SBrian Somers static int debug_done; /* Debug once */ 2115d5e5070SBrian Somers 212de59e178SBrian Somers if (idx > route_nifs || (idx > 0 && ifs[idx-1] == NULL)) { 213b1435e41SBrian Somers int mib[6], have, had; 214e7250038SBrian Somers size_t needed; 2155d5e5070SBrian Somers char *buf, *ptr, *end; 2165d5e5070SBrian Somers struct sockaddr_dl *dl; 2175d5e5070SBrian Somers struct if_msghdr *ifm; 2185d5e5070SBrian Somers 2198473f372SBrian Somers if (ifs) { 2208473f372SBrian Somers free(ifs); 2218473f372SBrian Somers ifs = NULL; 222de59e178SBrian Somers route_nifs = 0; 2238473f372SBrian Somers } 2248473f372SBrian Somers debug_done = 0; 2258473f372SBrian Somers 2265d5e5070SBrian Somers mib[0] = CTL_NET; 2275d5e5070SBrian Somers mib[1] = PF_ROUTE; 2285d5e5070SBrian Somers mib[2] = 0; 2295d5e5070SBrian Somers mib[3] = 0; 2305d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 2315d5e5070SBrian Somers mib[5] = 0; 2325d5e5070SBrian Somers 2335d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 234a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 235a33b2ef7SBrian Somers strerror(errno)); 236d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2375d5e5070SBrian Somers } 2385d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 239d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2405d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 2415d5e5070SBrian Somers free(buf); 242d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2435d5e5070SBrian Somers } 2445d5e5070SBrian Somers end = buf + needed; 2455d5e5070SBrian Somers 246b1435e41SBrian Somers have = 0; 2479cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 2485d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 2496b457978SBrian Somers if (ifm->ifm_type != RTM_IFINFO) 25024731321SBrian Somers continue; 2515d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 252b1435e41SBrian Somers if (ifm->ifm_index > 0) { 253b1435e41SBrian Somers if (ifm->ifm_index > have) { 254fc254be9SBrian Somers char **newifs; 255fc254be9SBrian Somers 256b1435e41SBrian Somers had = have; 257b1435e41SBrian Somers have = ifm->ifm_index + 5; 258b1435e41SBrian Somers if (had) 259fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 260b1435e41SBrian Somers else 261fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 262fc254be9SBrian Somers if (!newifs) { 263dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 264de59e178SBrian Somers route_nifs = 0; 2658473f372SBrian Somers if (ifs) { 266fc254be9SBrian Somers free(ifs); 2678473f372SBrian Somers ifs = NULL; 2688473f372SBrian Somers } 2698473f372SBrian Somers free(buf); 270d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 271b1435e41SBrian Somers } 272fc254be9SBrian Somers ifs = newifs; 273b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 274b1435e41SBrian Somers } 275b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 276b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 2775d604c11SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) 2785d604c11SBrian Somers log_Printf(LogDEBUG, "Skipping interface %d: Out of memory\n", 2795d604c11SBrian Somers ifm->ifm_index); 2805d604c11SBrian Somers else { 281b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 282b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 283de59e178SBrian Somers if (route_nifs < ifm->ifm_index) 284de59e178SBrian Somers route_nifs = ifm->ifm_index; 285b1435e41SBrian Somers } 2865d604c11SBrian Somers } 287dd7e2610SBrian Somers } else if (log_IsKept(LogDEBUG)) 288dd7e2610SBrian Somers log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 2899cb1d89eSBrian Somers ifm->ifm_index); 2905d5e5070SBrian Somers } 2915d5e5070SBrian Somers free(buf); 2925d5e5070SBrian Somers } 2935d5e5070SBrian Somers 294dd7e2610SBrian Somers if (log_IsKept(LogDEBUG) && !debug_done) { 2959cb1d89eSBrian Somers int f; 2969cb1d89eSBrian Somers 297dd7e2610SBrian Somers log_Printf(LogDEBUG, "Found the following interfaces:\n"); 298de59e178SBrian Somers for (f = 0; f < route_nifs; f++) 299b1435e41SBrian Somers if (ifs[f] != NULL) 300dd7e2610SBrian Somers log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 3019cb1d89eSBrian Somers debug_done = 1; 3029cb1d89eSBrian Somers } 3039cb1d89eSBrian Somers 304de59e178SBrian Somers if (idx < 1 || idx > route_nifs || ifs[idx-1] == NULL) 305d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 3069cb1d89eSBrian Somers 3079cb1d89eSBrian Somers return ifs[idx-1]; 3085d5e5070SBrian Somers } 3095d5e5070SBrian Somers 3106b457978SBrian Somers void 3116b457978SBrian Somers route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 3126b457978SBrian Somers { 3136b457978SBrian Somers char *wp; 3146b457978SBrian Somers int rtax; 3156b457978SBrian Somers 3166b457978SBrian Somers wp = (char *)(rtm + 1); 3176b457978SBrian Somers 3186b457978SBrian Somers for (rtax = 0; rtax < RTAX_MAX; rtax++) 3196b457978SBrian Somers if (rtm->rtm_addrs & (1 << rtax)) { 3206b457978SBrian Somers sa[rtax] = (struct sockaddr *)wp; 3216b457978SBrian Somers wp += ROUNDUP(sa[rtax]->sa_len); 322a3d71c3dSBrian Somers if (sa[rtax]->sa_family == 0) 323a3d71c3dSBrian Somers sa[rtax] = NULL; /* ??? */ 3246b457978SBrian Somers } else 3256b457978SBrian Somers sa[rtax] = NULL; 3266b457978SBrian Somers } 3276b457978SBrian Somers 328af57ed9fSAtsushi Murai int 329dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 330af57ed9fSAtsushi Murai { 331af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3326b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 3336b457978SBrian Somers char *sp, *ep, *cp; 334e7250038SBrian Somers size_t needed; 335af57ed9fSAtsushi Murai int mib[6]; 336af57ed9fSAtsushi Murai 337af57ed9fSAtsushi Murai mib[0] = CTL_NET; 338af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 33953c9f6c0SAtsushi Murai mib[2] = 0; 34053c9f6c0SAtsushi Murai mib[3] = 0; 341af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 34253c9f6c0SAtsushi Murai mib[5] = 0; 34353c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 344dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 34553c9f6c0SAtsushi Murai return (1); 34653c9f6c0SAtsushi Murai } 347af57ed9fSAtsushi Murai sp = malloc(needed); 348af57ed9fSAtsushi Murai if (sp == NULL) 349af57ed9fSAtsushi Murai return (1); 35053c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 351dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 352b0cdb3ceSJordan K. Hubbard free(sp); 353af57ed9fSAtsushi Murai return (1); 35453c9f6c0SAtsushi Murai } 355af57ed9fSAtsushi Murai ep = sp + needed; 356af57ed9fSAtsushi Murai 357b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 358b6217683SBrian Somers "Destination", "Gateway"); 359af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 360af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 3615d5e5070SBrian Somers 3626b457978SBrian Somers route_ParseHdr(rtm, sa); 3636b384664SBrian Somers 3646b457978SBrian Somers if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 3656b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 3666b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 3675d5e5070SBrian Somers 368b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 369b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 3706b384664SBrian Somers } else 3716b384664SBrian Somers prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 372af57ed9fSAtsushi Murai } 373b0cdb3ceSJordan K. Hubbard free(sp); 374927145beSBrian Somers return 0; 375af57ed9fSAtsushi Murai } 376af57ed9fSAtsushi Murai 377af57ed9fSAtsushi Murai /* 378af57ed9fSAtsushi Murai * Delete routes associated with our interface 379af57ed9fSAtsushi Murai */ 380af57ed9fSAtsushi Murai void 381dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 382af57ed9fSAtsushi Murai { 383af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3846b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 38530949fd4SBrian Somers struct ncprange range; 386e7250038SBrian Somers int pass; 387e7250038SBrian Somers size_t needed; 388af57ed9fSAtsushi Murai char *sp, *cp, *ep; 389af57ed9fSAtsushi Murai int mib[6]; 390af57ed9fSAtsushi Murai 3918fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 392927145beSBrian Somers 393af57ed9fSAtsushi Murai mib[0] = CTL_NET; 394af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 39553c9f6c0SAtsushi Murai mib[2] = 0; 39653c9f6c0SAtsushi Murai mib[3] = 0; 397af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 39853c9f6c0SAtsushi Murai mib[5] = 0; 39953c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 400dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 401afc7fa2cSBrian Somers strerror(errno)); 40253c9f6c0SAtsushi Murai return; 40353c9f6c0SAtsushi Murai } 404af57ed9fSAtsushi Murai 405af57ed9fSAtsushi Murai sp = malloc(needed); 406af57ed9fSAtsushi Murai if (sp == NULL) 407af57ed9fSAtsushi Murai return; 408af57ed9fSAtsushi Murai 409af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 410dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 411afc7fa2cSBrian Somers strerror(errno)); 412af57ed9fSAtsushi Murai free(sp); 413af57ed9fSAtsushi Murai return; 414af57ed9fSAtsushi Murai } 415af57ed9fSAtsushi Murai ep = sp + needed; 416af57ed9fSAtsushi Murai 41732ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 41832ca3341SBrian Somers /* 41932ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 4206b457978SBrian Somers * deletes all non-cloned routes. This is done to avoid 42132ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 422ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 423ba081e43SBrian Somers * may have gone with route Y). 42432ca3341SBrian Somers */ 42566dcee72SGleb Smirnoff if (pass == 0) 42632ca3341SBrian Somers /* So we can't tell ! */ 42732ca3341SBrian Somers continue; 428af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 429af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4306b457978SBrian Somers route_ParseHdr(rtm, sa); 43130949fd4SBrian Somers if (rtm->rtm_index == bundle->iface->index && 43230949fd4SBrian Somers sa[RTAX_DST] && sa[RTAX_GATEWAY] && 43330949fd4SBrian Somers (sa[RTAX_DST]->sa_family == AF_INET 43430949fd4SBrian Somers #ifndef NOINET6 43530949fd4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 43630949fd4SBrian Somers #endif 43730949fd4SBrian Somers ) && 438af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 43930949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 440*6cd3353bSEugene Grosbein char gwstr[NCP_ASCIIBUFFERSIZE]; 44130949fd4SBrian Somers struct ncpaddr gw; 44230949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 44330949fd4SBrian Somers ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]); 44430949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw)); 44530949fd4SBrian Somers log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr); 44630949fd4SBrian Somers } 4476b457978SBrian Somers if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 44830949fd4SBrian Somers #ifndef NOINET6 44930949fd4SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_INET6 || 45030949fd4SBrian Somers #endif 4516b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 45266dcee72SGleb Smirnoff if (pass == 1) { 45330949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 45430949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0); 4555d5e5070SBrian Somers } else 456dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 45732ca3341SBrian Somers } else 458dd7e2610SBrian Somers log_Printf(LogDEBUG, 45930949fd4SBrian Somers "route_IfDelete: Can't remove routes for family %d\n", 4606b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family); 4616b457978SBrian Somers } 462af57ed9fSAtsushi Murai } 463af57ed9fSAtsushi Murai } 464af57ed9fSAtsushi Murai free(sp); 465af57ed9fSAtsushi Murai } 466af57ed9fSAtsushi Murai 46703a2501aSBrian Somers 46803a2501aSBrian Somers /* 46903a2501aSBrian Somers * Update the MTU on all routes for the given interface 47003a2501aSBrian Somers */ 47103a2501aSBrian Somers void 47203a2501aSBrian Somers route_UpdateMTU(struct bundle *bundle) 47303a2501aSBrian Somers { 47403a2501aSBrian Somers struct rt_msghdr *rtm; 47503a2501aSBrian Somers struct sockaddr *sa[RTAX_MAX]; 47630949fd4SBrian Somers struct ncprange dst; 47703a2501aSBrian Somers size_t needed; 47803a2501aSBrian Somers char *sp, *cp, *ep; 47903a2501aSBrian Somers int mib[6]; 48003a2501aSBrian Somers 48103a2501aSBrian Somers log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 48203a2501aSBrian Somers 48303a2501aSBrian Somers mib[0] = CTL_NET; 48403a2501aSBrian Somers mib[1] = PF_ROUTE; 48503a2501aSBrian Somers mib[2] = 0; 48603a2501aSBrian Somers mib[3] = 0; 48703a2501aSBrian Somers mib[4] = NET_RT_DUMP; 48803a2501aSBrian Somers mib[5] = 0; 48903a2501aSBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 49003a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 49103a2501aSBrian Somers strerror(errno)); 49203a2501aSBrian Somers return; 49303a2501aSBrian Somers } 49403a2501aSBrian Somers 49503a2501aSBrian Somers sp = malloc(needed); 49603a2501aSBrian Somers if (sp == NULL) 49703a2501aSBrian Somers return; 49803a2501aSBrian Somers 49903a2501aSBrian Somers if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 50003a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 50103a2501aSBrian Somers strerror(errno)); 50203a2501aSBrian Somers free(sp); 50303a2501aSBrian Somers return; 50403a2501aSBrian Somers } 50503a2501aSBrian Somers ep = sp + needed; 50603a2501aSBrian Somers 50703a2501aSBrian Somers for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 50803a2501aSBrian Somers rtm = (struct rt_msghdr *)cp; 50903a2501aSBrian Somers route_ParseHdr(rtm, sa); 5101d3d76d4SBrian Somers if (sa[RTAX_DST] && (sa[RTAX_DST]->sa_family == AF_INET 5115ae08329SBrian Somers #ifndef NOINET6 5121d3d76d4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 5135ae08329SBrian Somers #endif 5145ae08329SBrian Somers ) && 5155ae08329SBrian Somers sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index) { 5165ae08329SBrian Somers if (log_IsKept(LogTCPIP)) { 51730949fd4SBrian Somers ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]); 5185ae08329SBrian Somers log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s," 519057f1760SBrian Somers " mtu %lu\n", rtm->rtm_index, Index2Nam(rtm->rtm_index), 5205ae08329SBrian Somers ncprange_ntoa(&dst), bundle->iface->mtu); 5215ae08329SBrian Somers } 5220e81959dSBjoern A. Zeeb rt_Update(bundle, sa[RTAX_DST], sa[RTAX_GATEWAY], sa[RTAX_NETMASK], 5230e81959dSBjoern A. Zeeb sa[RTAX_IFP], sa[RTAX_IFA]); 52403a2501aSBrian Somers } 52503a2501aSBrian Somers } 52603a2501aSBrian Somers 52703a2501aSBrian Somers free(sp); 52803a2501aSBrian Somers } 52903a2501aSBrian Somers 530af57ed9fSAtsushi Murai int 531944f7098SBrian Somers GetIfIndex(char *name) 532af57ed9fSAtsushi Murai { 5335d5e5070SBrian Somers int idx; 534944f7098SBrian Somers 5359cb1d89eSBrian Somers idx = 1; 536de59e178SBrian Somers while (route_nifs == -1 || idx < route_nifs) 537de59e178SBrian Somers if (strcmp(Index2Nam(idx), name) == 0) 5387a6f8720SBrian Somers return idx; 5395d5e5070SBrian Somers else 5405d5e5070SBrian Somers idx++; 5415d5e5070SBrian Somers return -1; 542af57ed9fSAtsushi Murai } 543bcc332bdSBrian Somers 544610b185fSBrian Somers void 545610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 54630949fd4SBrian Somers const struct ncpaddr *me, const struct ncpaddr *peer) 547bcc332bdSBrian Somers { 54830949fd4SBrian Somers struct ncpaddr dst; 549bcc332bdSBrian Somers 550610b185fSBrian Somers for (; r; r = r->next) { 55130949fd4SBrian Somers ncprange_getaddr(&r->dst, &dst); 55230949fd4SBrian Somers if (ncpaddr_family(me) == AF_INET) { 55330949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) { 55430949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 55530949fd4SBrian Somers ncprange_sethost(&r->dst, me); 556610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 55730949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 55830949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) { 55930949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 56030949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 561610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 56230949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56330949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) { 56430949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE) 56530949fd4SBrian Somers continue; 56630949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 567d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 56830949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56930949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) { 57030949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE) 57130949fd4SBrian Somers continue; 57230949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 573d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 57430949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57530949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer)) 57630949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57730949fd4SBrian Somers #ifndef NOINET6 57830949fd4SBrian Somers } else if (ncpaddr_family(me) == AF_INET6) { 57930949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) { 58030949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 58130949fd4SBrian Somers ncprange_sethost(&r->dst, me); 58230949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58330949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58430949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) { 58530949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 58630949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 58730949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58830949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58930949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer)) 59030949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 59130949fd4SBrian Somers #endif 59230949fd4SBrian Somers } 59330949fd4SBrian Somers rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0); 594610b185fSBrian Somers } 595610b185fSBrian Somers } 596610b185fSBrian Somers 597610b185fSBrian Somers void 59830949fd4SBrian Somers route_Add(struct sticky_route **rp, int type, const struct ncprange *dst, 59930949fd4SBrian Somers const struct ncpaddr *gw) 600610b185fSBrian Somers { 601610b185fSBrian Somers struct sticky_route *r; 602610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 603610b185fSBrian Somers 604610b185fSBrian Somers r = NULL; 605610b185fSBrian Somers while (*rp) { 606183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 60730949fd4SBrian Somers (!dsttype && ncprange_equal(&(*rp)->dst, dst))) { 608972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 609972a1bcfSBrian Somers free(r); /* impossible really */ 610610b185fSBrian Somers r = *rp; 611610b185fSBrian Somers *rp = r->next; 612610b185fSBrian Somers } else 613610b185fSBrian Somers rp = &(*rp)->next; 614610b185fSBrian Somers } 615610b185fSBrian Somers 6165d604c11SBrian Somers if (r == NULL) { 617610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 6185d604c11SBrian Somers if (r == NULL) { 6195d604c11SBrian Somers log_Printf(LogERROR, "route_Add: Out of memory!\n"); 6205d604c11SBrian Somers return; 6215d604c11SBrian Somers } 6225d604c11SBrian Somers } 623610b185fSBrian Somers r->type = type; 624610b185fSBrian Somers r->next = NULL; 62530949fd4SBrian Somers ncprange_copy(&r->dst, dst); 62630949fd4SBrian Somers ncpaddr_copy(&r->gw, gw); 627bcd13e2eSBrian Somers *rp = r; 628610b185fSBrian Somers } 629610b185fSBrian Somers 630610b185fSBrian Somers void 63130949fd4SBrian Somers route_Delete(struct sticky_route **rp, int type, const struct ncprange *dst) 632610b185fSBrian Somers { 633610b185fSBrian Somers struct sticky_route *r; 634610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 635610b185fSBrian Somers 636610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 637610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 63830949fd4SBrian Somers (!dsttype && ncprange_equal(dst, &(*rp)->dst))) { 639610b185fSBrian Somers r = *rp; 640610b185fSBrian Somers *rp = r->next; 641610b185fSBrian Somers free(r); 642bcc332bdSBrian Somers break; 643bcc332bdSBrian Somers } 644bcc332bdSBrian Somers } 645bcc332bdSBrian Somers } 646bcc332bdSBrian Somers 647610b185fSBrian Somers void 648610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 649610b185fSBrian Somers { 650610b185fSBrian Somers struct sticky_route *r, *rn; 651610b185fSBrian Somers 652610b185fSBrian Somers for (r = *rp; r; r = rn) { 653610b185fSBrian Somers rn = r->next; 654610b185fSBrian Somers free(r); 655610b185fSBrian Somers } 656610b185fSBrian Somers *rp = NULL; 657610b185fSBrian Somers } 658610b185fSBrian Somers 659610b185fSBrian Somers void 660972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 661972a1bcfSBrian Somers int indent) 662610b185fSBrian Somers { 663972a1bcfSBrian Somers int tlen = strlen(tag); 664610b185fSBrian Somers 665972a1bcfSBrian Somers if (tlen + 2 > indent) 666972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 667972a1bcfSBrian Somers else 668972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 669972a1bcfSBrian Somers 670610b185fSBrian Somers for (; r; r = r->next) { 671972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 672972a1bcfSBrian Somers tlen = 0; 673610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 674610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 67530949fd4SBrian Somers else if (r->type & ROUTE_DSTMYADDR6) 67630949fd4SBrian Somers prompt_Printf(p, "MYADDR6"); 677610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 678610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 67930949fd4SBrian Somers else if (r->type & ROUTE_DSTHISADDR6) 68030949fd4SBrian Somers prompt_Printf(p, "HISADDR6"); 681d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS0) 682d568d6c4SBrian Somers prompt_Printf(p, "DNS0"); 683d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS1) 684d568d6c4SBrian Somers prompt_Printf(p, "DNS1"); 68530949fd4SBrian Somers else if (ncprange_isdefault(&r->dst)) 686610b185fSBrian Somers prompt_Printf(p, "default"); 687610b185fSBrian Somers else 68830949fd4SBrian Somers prompt_Printf(p, "%s", ncprange_ntoa(&r->dst)); 689610b185fSBrian Somers 690610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 691610b185fSBrian Somers prompt_Printf(p, " HISADDR\n"); 69230949fd4SBrian Somers else if (r->type & ROUTE_GWHISADDR6) 69330949fd4SBrian Somers prompt_Printf(p, " HISADDR6\n"); 694610b185fSBrian Somers else 69530949fd4SBrian Somers prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw)); 696610b185fSBrian Somers } 697bcc332bdSBrian Somers } 69803a2501aSBrian Somers 69903a2501aSBrian Somers struct rtmsg { 70003a2501aSBrian Somers struct rt_msghdr m_rtm; 70130949fd4SBrian Somers char m_space[256]; 70203a2501aSBrian Somers }; 70303a2501aSBrian Somers 704361a7b93SBrian Somers static size_t 705361a7b93SBrian Somers memcpy_roundup(char *cp, const void *data, size_t len) 706361a7b93SBrian Somers { 707361a7b93SBrian Somers size_t padlen; 708361a7b93SBrian Somers 709361a7b93SBrian Somers padlen = ROUNDUP(len); 710361a7b93SBrian Somers memcpy(cp, data, len); 711361a7b93SBrian Somers if (padlen > len) 712361a7b93SBrian Somers memset(cp + len, '\0', padlen - len); 713361a7b93SBrian Somers 714361a7b93SBrian Somers return padlen; 715361a7b93SBrian Somers } 716361a7b93SBrian Somers 71793193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 71893193fc7SHajimu UMEMOTO static void 71993193fc7SHajimu UMEMOTO add_scope(struct sockaddr *sa, int ifindex) 72093193fc7SHajimu UMEMOTO { 72193193fc7SHajimu UMEMOTO struct sockaddr_in6 *sa6; 72293193fc7SHajimu UMEMOTO 72393193fc7SHajimu UMEMOTO if (sa->sa_family != AF_INET6) 72493193fc7SHajimu UMEMOTO return; 72593193fc7SHajimu UMEMOTO sa6 = (struct sockaddr_in6 *)sa; 72693193fc7SHajimu UMEMOTO if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && 72793193fc7SHajimu UMEMOTO !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) 72893193fc7SHajimu UMEMOTO return; 72993193fc7SHajimu UMEMOTO if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0) 73093193fc7SHajimu UMEMOTO return; 73193193fc7SHajimu UMEMOTO *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex); 73293193fc7SHajimu UMEMOTO } 73393193fc7SHajimu UMEMOTO #endif 73493193fc7SHajimu UMEMOTO 73503a2501aSBrian Somers int 73630949fd4SBrian Somers rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst, 73730949fd4SBrian Somers const struct ncpaddr *gw, int bang, int quiet) 73803a2501aSBrian Somers { 73903a2501aSBrian Somers struct rtmsg rtmes; 740846e7227SBrian Somers int s, nb, wb; 74103a2501aSBrian Somers char *cp; 74203a2501aSBrian Somers const char *cmdstr; 74330949fd4SBrian Somers struct sockaddr_storage sadst, samask, sagw; 74403a2501aSBrian Somers int result = 1; 74503a2501aSBrian Somers 74603a2501aSBrian Somers if (bang) 74703a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 74803a2501aSBrian Somers else 74903a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 75063c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 75103a2501aSBrian Somers if (s < 0) { 75203a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 75303a2501aSBrian Somers return result; 75403a2501aSBrian Somers } 75503a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 75603a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 75703a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd; 75803a2501aSBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 75903a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 76003a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 76103a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 76203a2501aSBrian Somers 76303a2501aSBrian Somers if (cmd == RTM_ADD) { 76430949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 76530949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 76603a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 76703a2501aSBrian Somers } 76830949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 76930949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 77003a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 77103a2501aSBrian Somers } 77203a2501aSBrian Somers } 77303a2501aSBrian Somers 77430949fd4SBrian Somers ncprange_getsa(dst, &sadst, &samask); 77593193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 77693193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sadst, bundle->iface->index); 77793193fc7SHajimu UMEMOTO #endif 77803a2501aSBrian Somers 77903a2501aSBrian Somers cp = rtmes.m_space; 780361a7b93SBrian Somers cp += memcpy_roundup(cp, &sadst, sadst.ss_len); 78103a2501aSBrian Somers if (cmd == RTM_ADD) { 78230949fd4SBrian Somers if (gw == NULL) { 78330949fd4SBrian Somers log_Printf(LogERROR, "rt_Set: Program error\n"); 78430949fd4SBrian Somers close(s); 78530949fd4SBrian Somers return result; 78630949fd4SBrian Somers } 78730949fd4SBrian Somers ncpaddr_getsa(gw, &sagw); 78893193fc7SHajimu UMEMOTO #if defined(__KAME__) && !defined(NOINET6) 78993193fc7SHajimu UMEMOTO add_scope((struct sockaddr *)&sagw, bundle->iface->index); 79093193fc7SHajimu UMEMOTO #endif 79130949fd4SBrian Somers if (ncpaddr_isdefault(gw)) { 79230949fd4SBrian Somers if (!quiet) 79303a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: Cannot add a route with" 794156a04e4SBrian Somers " gateway 0.0.0.0\n"); 79503a2501aSBrian Somers close(s); 79603a2501aSBrian Somers return result; 79703a2501aSBrian Somers } else { 798361a7b93SBrian Somers cp += memcpy_roundup(cp, &sagw, sagw.ss_len); 79903a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 80003a2501aSBrian Somers } 80103a2501aSBrian Somers } 80203a2501aSBrian Somers 80326dceef0SBrian Somers if (!ncprange_ishost(dst)) { 804361a7b93SBrian Somers cp += memcpy_roundup(cp, &samask, samask.ss_len); 80503a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 80681a5dbd5SEugene Grosbein } else 807538abeb1SEugene Grosbein rtmes.m_rtm.rtm_flags |= RTF_HOST; 80803a2501aSBrian Somers 80903a2501aSBrian Somers nb = cp - (char *)&rtmes; 81003a2501aSBrian Somers rtmes.m_rtm.rtm_msglen = nb; 81103a2501aSBrian Somers wb = ID0write(s, &rtmes, nb); 81203a2501aSBrian Somers if (wb < 0) { 81303a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set failure:\n"); 81403a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 81530949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst)); 81630949fd4SBrian Somers if (gw != NULL) 81730949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw)); 81803a2501aSBrian Somers failed: 81903a2501aSBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 82003a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 82103a2501aSBrian Somers if (!bang) { 82203a2501aSBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 82330949fd4SBrian Somers ncprange_ntoa(dst)); 82403a2501aSBrian Somers result = 0; /* Don't add to our dynamic list */ 82503a2501aSBrian Somers } else { 82603a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 82703a2501aSBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 82803a2501aSBrian Somers goto failed; 82903a2501aSBrian Somers } 83003a2501aSBrian Somers } else if (cmd == RTM_DELETE && 83103a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 83203a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 83303a2501aSBrian Somers if (!bang) 83403a2501aSBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 83530949fd4SBrian Somers ncprange_ntoa(dst)); 83603a2501aSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 83730949fd4SBrian Somers if (!quiet || errno != ENETUNREACH) 83803a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 83930949fd4SBrian Somers ncprange_ntoa(dst), strerror(errno)); 84003a2501aSBrian Somers } else 84103a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 84230949fd4SBrian Somers cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 84303a2501aSBrian Somers } 84403a2501aSBrian Somers 84530949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 846*6cd3353bSEugene Grosbein char gwstr[NCP_ASCIIBUFFERSIZE]; 84730949fd4SBrian Somers 84830949fd4SBrian Somers if (gw) 84930949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw)); 85030949fd4SBrian Somers else 85130949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "<none>"); 85230949fd4SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n", 85330949fd4SBrian Somers wb, cmdstr, ncprange_ntoa(dst), gwstr); 85430949fd4SBrian Somers } 85503a2501aSBrian Somers close(s); 85603a2501aSBrian Somers 85703a2501aSBrian Somers return result; 85803a2501aSBrian Somers } 85903a2501aSBrian Somers 86003a2501aSBrian Somers void 8615ae08329SBrian Somers rt_Update(struct bundle *bundle, const struct sockaddr *dst, 8620e81959dSBjoern A. Zeeb const struct sockaddr *gw, const struct sockaddr *mask, 8630e81959dSBjoern A. Zeeb const struct sockaddr *ifp, const struct sockaddr *ifa) 86403a2501aSBrian Somers { 8655ae08329SBrian Somers struct ncprange ncpdst; 86603a2501aSBrian Somers struct rtmsg rtmes; 8675ae08329SBrian Somers char *p; 86803a2501aSBrian Somers int s, wb; 86903a2501aSBrian Somers 87063c6cac9SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 87103a2501aSBrian Somers if (s < 0) { 87203a2501aSBrian Somers log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 87303a2501aSBrian Somers return; 87403a2501aSBrian Somers } 87503a2501aSBrian Somers 87603a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 87703a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 87803a2501aSBrian Somers rtmes.m_rtm.rtm_type = RTM_CHANGE; 879d42d9220SBrian Somers rtmes.m_rtm.rtm_addrs = 0; 88003a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 88103a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 882afb28bf7SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_STATIC; 88303a2501aSBrian Somers 88430949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 88530949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 88603a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 88703a2501aSBrian Somers } 88803a2501aSBrian Somers 88930949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 89030949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 89103a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 89203a2501aSBrian Somers } 89303a2501aSBrian Somers 894c8b9fb53SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; 89503a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_MTU; 8965ae08329SBrian Somers p = rtmes.m_space; 89703a2501aSBrian Somers 8985ae08329SBrian Somers if (dst) { 8995ae08329SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_DST; 900361a7b93SBrian Somers p += memcpy_roundup(p, dst, dst->sa_len); 9015ae08329SBrian Somers } 90203a2501aSBrian Somers 9030fb550caSBjoern A. Zeeb if (gw) { 904afb28bf7SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 905afb28bf7SBrian Somers p += memcpy_roundup(p, gw, gw->sa_len); 9060fb550caSBjoern A. Zeeb } 9070fb550caSBjoern A. Zeeb 908afb28bf7SBrian Somers if (mask) { 909afb28bf7SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 910afb28bf7SBrian Somers p += memcpy_roundup(p, mask, mask->sa_len); 91181a5dbd5SEugene Grosbein } else 912538abeb1SEugene 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