165309e5cSBrian Somers /*- 265309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 365309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 465309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 565309e5cSBrian Somers * All rights reserved. 6af57ed9fSAtsushi Murai * 765309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 865309e5cSBrian Somers * modification, are permitted provided that the following conditions 965309e5cSBrian Somers * are met: 1065309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1165309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1265309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1465309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 15af57ed9fSAtsushi Murai * 1665309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2065309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665309e5cSBrian Somers * SUCH DAMAGE. 27af57ed9fSAtsushi Murai * 2897d92980SPeter Wemm * $FreeBSD$ 29af57ed9fSAtsushi Murai */ 3075240ed1SBrian Somers 31972a1bcfSBrian Somers #include <sys/param.h> 3275240ed1SBrian Somers #include <sys/socket.h> 335d5e5070SBrian Somers #include <net/if_types.h> 34628d2ac1SGarrett Wollman #include <net/route.h> 35628d2ac1SGarrett Wollman #include <net/if.h> 36628d2ac1SGarrett Wollman #include <netinet/in.h> 37628d2ac1SGarrett Wollman #include <arpa/inet.h> 385d5e5070SBrian Somers #include <net/if_dl.h> 39eaa4df37SBrian Somers #include <netinet/in_systm.h> 40eaa4df37SBrian Somers #include <netinet/ip.h> 411fa665f5SBrian Somers #include <sys/un.h> 426b384664SBrian Somers #include <netdb.h> 43628d2ac1SGarrett Wollman 4475240ed1SBrian Somers #include <errno.h> 4575240ed1SBrian Somers #include <stdio.h> 4675240ed1SBrian Somers #include <stdlib.h> 4775240ed1SBrian Somers #include <string.h> 4875240ed1SBrian Somers #include <sys/sysctl.h> 4985b542cfSBrian Somers #include <termios.h> 5003a2501aSBrian Somers #include <unistd.h> 5175240ed1SBrian Somers 525d9e6103SBrian Somers #include "layer.h" 53c9e11a11SBrian Somers #include "defs.h" 54b6e82f33SBrian Somers #include "command.h" 5575240ed1SBrian Somers #include "mbuf.h" 56215a4696SAtsushi Murai #include "log.h" 57bcc332bdSBrian Somers #include "iplist.h" 5829e275ceSBrian Somers #include "timer.h" 5929e275ceSBrian Somers #include "throughput.h" 60879ed6faSBrian Somers #include "lqr.h" 618c07a7b2SBrian Somers #include "hdlc.h" 627308ec68SBrian Somers #include "fsm.h" 633b0f8d2eSBrian Somers #include "lcp.h" 643b0f8d2eSBrian Somers #include "ccp.h" 653b0f8d2eSBrian Somers #include "link.h" 66eaa4df37SBrian Somers #include "slcompress.h" 6730949fd4SBrian Somers #include "ncpaddr.h" 6830949fd4SBrian Somers #include "ip.h" 6929e275ceSBrian Somers #include "ipcp.h" 705ca5389aSBrian Somers #include "filter.h" 712f786681SBrian Somers #include "descriptor.h" 723b0f8d2eSBrian Somers #include "mp.h" 73972a1bcfSBrian Somers #ifndef NORADIUS 74972a1bcfSBrian Somers #include "radius.h" 75972a1bcfSBrian Somers #endif 7630949fd4SBrian Somers #include "ipv6cp.h" 7730949fd4SBrian Somers #include "ncp.h" 785828db6dSBrian Somers #include "bundle.h" 7975240ed1SBrian Somers #include "route.h" 8085b542cfSBrian Somers #include "prompt.h" 818fa6ebe4SBrian Somers #include "iface.h" 8203a2501aSBrian Somers #include "id.h" 83af57ed9fSAtsushi Murai 846b457978SBrian Somers 85af57ed9fSAtsushi Murai static void 86b6217683SBrian Somers p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 87b6217683SBrian Somers struct sockaddr *pmask, int width) 88af57ed9fSAtsushi Murai { 8930949fd4SBrian Somers struct ncprange range; 90b6e82f33SBrian Somers char buf[29]; 915d5e5070SBrian Somers struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 92af57ed9fSAtsushi Murai 936b384664SBrian Somers if (log_IsKept(LogDEBUG)) { 946b384664SBrian Somers char tmp[50]; 956b384664SBrian Somers 966b384664SBrian Somers log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 976b384664SBrian Somers log_Printf(LogDEBUG, " Family %d, len %d\n", 986b384664SBrian Somers (int)phost->sa_family, (int)phost->sa_len); 996b457978SBrian Somers inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 1006b384664SBrian Somers log_Printf(LogDEBUG, " Addr %s\n", tmp); 1016b384664SBrian Somers if (pmask) { 1026b457978SBrian Somers inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 1036b384664SBrian Somers log_Printf(LogDEBUG, " Mask %s\n", tmp); 1046b384664SBrian Somers } 1056b384664SBrian Somers } 1066b384664SBrian Somers 1075d5e5070SBrian Somers switch (phost->sa_family) { 1085d5e5070SBrian Somers case AF_INET: 10930949fd4SBrian Somers #ifndef NOINET6 11030949fd4SBrian Somers case AF_INET6: 11130949fd4SBrian Somers #endif 11230949fd4SBrian Somers ncprange_setsa(&range, phost, pmask); 11330949fd4SBrian Somers if (ncprange_isdefault(&range)) 11430949fd4SBrian Somers prompt_Printf(prompt, "%-*s ", width - 1, "default"); 1155d5e5070SBrian Somers else 11630949fd4SBrian Somers prompt_Printf(prompt, "%-*s ", width - 1, ncprange_ntoa(&range)); 11730949fd4SBrian Somers return; 1185d5e5070SBrian Somers 1195d5e5070SBrian Somers case AF_LINK: 1204bfaee90SBrian Somers if (dl->sdl_nlen) 1214bfaee90SBrian Somers snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 122c4c4aaacSBrian Somers else if (dl->sdl_alen) { 123c4c4aaacSBrian Somers if (dl->sdl_type == IFT_ETHER) { 12470ee81ffSBrian Somers if (dl->sdl_alen < sizeof buf / 3) { 1255d5e5070SBrian Somers int f; 1265d5e5070SBrian Somers u_char *MAC; 1275d5e5070SBrian Somers 1285d5e5070SBrian Somers MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 1295d5e5070SBrian Somers for (f = 0; f < dl->sdl_alen; f++) 1305d5e5070SBrian Somers sprintf(buf+f*3, "%02x:", MAC[f]); 1315d5e5070SBrian Somers buf[f*3-1] = '\0'; 1325d5e5070SBrian Somers } else 13383c0952dSBrian Somers strcpy(buf, "??:??:??:??:??:??"); 134c4c4aaacSBrian Somers } else 1354bfaee90SBrian Somers sprintf(buf, "<IFT type %d>", dl->sdl_type); 136c4c4aaacSBrian Somers } else if (dl->sdl_slen) 1374bfaee90SBrian Somers sprintf(buf, "<slen %d?>", dl->sdl_slen); 1384bfaee90SBrian Somers else 1394bfaee90SBrian Somers sprintf(buf, "link#%d", dl->sdl_index); 1405d5e5070SBrian Somers break; 1415d5e5070SBrian Somers 1425d5e5070SBrian Somers default: 1434bfaee90SBrian Somers sprintf(buf, "<AF type %d>", phost->sa_family); 1445d5e5070SBrian Somers break; 1455d5e5070SBrian Somers } 1465d5e5070SBrian Somers 147b6217683SBrian Somers prompt_Printf(prompt, "%-*s ", width-1, buf); 148af57ed9fSAtsushi Murai } 149af57ed9fSAtsushi Murai 150aa8e0519SBrian Somers static struct bits { 1513f06c599SBrian Somers u_int32_t b_mask; 152af57ed9fSAtsushi Murai char b_val; 153af57ed9fSAtsushi Murai } bits[] = { 1545d5e5070SBrian Somers { RTF_UP, 'U' }, 1555d5e5070SBrian Somers { RTF_GATEWAY, 'G' }, 1565d5e5070SBrian Somers { RTF_HOST, 'H' }, 1575d5e5070SBrian Somers { RTF_REJECT, 'R' }, 1585d5e5070SBrian Somers { RTF_DYNAMIC, 'D' }, 1595d5e5070SBrian Somers { RTF_MODIFIED, 'M' }, 1605d5e5070SBrian Somers { RTF_DONE, 'd' }, 1615d5e5070SBrian Somers { RTF_CLONING, 'C' }, 1625d5e5070SBrian Somers { RTF_XRESOLVE, 'X' }, 1635d5e5070SBrian Somers { RTF_LLINFO, 'L' }, 1645d5e5070SBrian Somers { RTF_STATIC, 'S' }, 1655d5e5070SBrian Somers { RTF_PROTO1, '1' }, 1665d5e5070SBrian Somers { RTF_PROTO2, '2' }, 1675d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 16832ca3341SBrian Somers #ifdef RTF_WASCLONED 1695d5e5070SBrian Somers { RTF_WASCLONED, 'W' }, 17032ca3341SBrian Somers #endif 17132ca3341SBrian Somers #ifdef RTF_PRCLONING 1725d5e5070SBrian Somers { RTF_PRCLONING, 'c' }, 17332ca3341SBrian Somers #endif 17432ca3341SBrian Somers #ifdef RTF_PROTO3 1755d5e5070SBrian Somers { RTF_PROTO3, '3' }, 17632ca3341SBrian Somers #endif 17732ca3341SBrian Somers #ifdef RTF_BROADCAST 1785d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 1795d5e5070SBrian Somers #endif 1805d5e5070SBrian Somers { 0, '\0' } 181af57ed9fSAtsushi Murai }; 182af57ed9fSAtsushi Murai 18332ca3341SBrian Somers #ifndef RTF_WASCLONED 18432ca3341SBrian Somers #define RTF_WASCLONED (0) 18532ca3341SBrian Somers #endif 18632ca3341SBrian Somers 187af57ed9fSAtsushi Murai static void 1883f06c599SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, int max) 189af57ed9fSAtsushi Murai { 190af57ed9fSAtsushi Murai char name[33], *flags; 191af57ed9fSAtsushi Murai register struct bits *p = bits; 192af57ed9fSAtsushi Murai 19370ee81ffSBrian Somers if (max > sizeof name - 1) 19470ee81ffSBrian Somers max = sizeof name - 1; 195d27d502cSBrian Somers 196d27d502cSBrian Somers for (flags = name; p->b_mask && flags - name < max; p++) 197af57ed9fSAtsushi Murai if (p->b_mask & f) 198af57ed9fSAtsushi Murai *flags++ = p->b_val; 199af57ed9fSAtsushi Murai *flags = '\0'; 200b6217683SBrian Somers prompt_Printf(prompt, "%-*.*s", max, max, name); 201af57ed9fSAtsushi Murai } 202af57ed9fSAtsushi Murai 203c6fe0cb2SBrian Somers const char * 2045d5e5070SBrian Somers Index2Nam(int idx) 2055d5e5070SBrian Somers { 206d93d3a9cSBrian Somers /* 207d93d3a9cSBrian Somers * XXX: Maybe we should select() on the routing socket so that we can 208d93d3a9cSBrian Somers * notice interfaces that come & go (PCCARD support). 209d93d3a9cSBrian Somers * Or we could even support a signal that resets these so that 210d93d3a9cSBrian Somers * the PCCARD insert/remove events can signal ppp. 211d93d3a9cSBrian Somers */ 212d93d3a9cSBrian Somers static char **ifs; /* Figure these out once */ 213d93d3a9cSBrian Somers static int nifs, debug_done; /* Figure out how many once, and debug once */ 2145d5e5070SBrian Somers 2158473f372SBrian Somers if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 216b1435e41SBrian Somers int mib[6], have, had; 217e7250038SBrian Somers size_t needed; 2185d5e5070SBrian Somers char *buf, *ptr, *end; 2195d5e5070SBrian Somers struct sockaddr_dl *dl; 2205d5e5070SBrian Somers struct if_msghdr *ifm; 2215d5e5070SBrian Somers 2228473f372SBrian Somers if (ifs) { 2238473f372SBrian Somers free(ifs); 2248473f372SBrian Somers ifs = NULL; 2258473f372SBrian Somers nifs = 0; 2268473f372SBrian Somers } 2278473f372SBrian Somers debug_done = 0; 2288473f372SBrian Somers 2295d5e5070SBrian Somers mib[0] = CTL_NET; 2305d5e5070SBrian Somers mib[1] = PF_ROUTE; 2315d5e5070SBrian Somers mib[2] = 0; 2325d5e5070SBrian Somers mib[3] = 0; 2335d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 2345d5e5070SBrian Somers mib[5] = 0; 2355d5e5070SBrian Somers 2365d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 237a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 238a33b2ef7SBrian Somers strerror(errno)); 239d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2405d5e5070SBrian Somers } 2415d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 242d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2435d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 2445d5e5070SBrian Somers free(buf); 245d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 2465d5e5070SBrian Somers } 2475d5e5070SBrian Somers end = buf + needed; 2485d5e5070SBrian Somers 249b1435e41SBrian Somers have = 0; 2509cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 2515d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 2526b457978SBrian Somers if (ifm->ifm_type != RTM_IFINFO) 25324731321SBrian Somers continue; 2545d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 255b1435e41SBrian Somers if (ifm->ifm_index > 0) { 256b1435e41SBrian Somers if (ifm->ifm_index > have) { 257fc254be9SBrian Somers char **newifs; 258fc254be9SBrian Somers 259b1435e41SBrian Somers had = have; 260b1435e41SBrian Somers have = ifm->ifm_index + 5; 261b1435e41SBrian Somers if (had) 262fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 263b1435e41SBrian Somers else 264fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 265fc254be9SBrian Somers if (!newifs) { 266dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 267b1435e41SBrian Somers nifs = 0; 2688473f372SBrian Somers if (ifs) { 269fc254be9SBrian Somers free(ifs); 2708473f372SBrian Somers ifs = NULL; 2718473f372SBrian Somers } 2728473f372SBrian Somers free(buf); 273d6d3eeabSBrian Somers return NumStr(idx, NULL, 0); 274b1435e41SBrian Somers } 275fc254be9SBrian Somers ifs = newifs; 276b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 277b1435e41SBrian Somers } 278b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 279b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 280b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 281b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 282b1435e41SBrian Somers if (nifs < ifm->ifm_index) 2839cb1d89eSBrian Somers nifs = ifm->ifm_index; 284b1435e41SBrian 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"); 2969cb1d89eSBrian Somers for (f = 0; f < 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 302b1435e41SBrian Somers if (idx < 1 || idx > 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); 3206b457978SBrian Somers } else 3216b457978SBrian Somers sa[rtax] = NULL; 3226b457978SBrian Somers } 3236b457978SBrian Somers 324af57ed9fSAtsushi Murai int 325dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 326af57ed9fSAtsushi Murai { 327af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3286b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 3296b457978SBrian Somers char *sp, *ep, *cp; 330e7250038SBrian Somers size_t needed; 331af57ed9fSAtsushi Murai int mib[6]; 332af57ed9fSAtsushi Murai 333af57ed9fSAtsushi Murai mib[0] = CTL_NET; 334af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 33553c9f6c0SAtsushi Murai mib[2] = 0; 33653c9f6c0SAtsushi Murai mib[3] = 0; 337af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 33853c9f6c0SAtsushi Murai mib[5] = 0; 33953c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 340dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 34153c9f6c0SAtsushi Murai return (1); 34253c9f6c0SAtsushi Murai } 343af57ed9fSAtsushi Murai sp = malloc(needed); 344af57ed9fSAtsushi Murai if (sp == NULL) 345af57ed9fSAtsushi Murai return (1); 34653c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 347dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 348b0cdb3ceSJordan K. Hubbard free(sp); 349af57ed9fSAtsushi Murai return (1); 35053c9f6c0SAtsushi Murai } 351af57ed9fSAtsushi Murai ep = sp + needed; 352af57ed9fSAtsushi Murai 353b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 354b6217683SBrian Somers "Destination", "Gateway"); 355af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 356af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 3575d5e5070SBrian Somers 3586b457978SBrian Somers route_ParseHdr(rtm, sa); 3596b384664SBrian Somers 3606b457978SBrian Somers if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 3616b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 3626b457978SBrian Somers p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 3635d5e5070SBrian Somers 364b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 365b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 3666b384664SBrian Somers } else 3676b384664SBrian Somers prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 368af57ed9fSAtsushi Murai } 369b0cdb3ceSJordan K. Hubbard free(sp); 370927145beSBrian Somers return 0; 371af57ed9fSAtsushi Murai } 372af57ed9fSAtsushi Murai 373af57ed9fSAtsushi Murai /* 374af57ed9fSAtsushi Murai * Delete routes associated with our interface 375af57ed9fSAtsushi Murai */ 376af57ed9fSAtsushi Murai void 377dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 378af57ed9fSAtsushi Murai { 379af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 3806b457978SBrian Somers struct sockaddr *sa[RTAX_MAX]; 38130949fd4SBrian Somers struct ncprange range; 382e7250038SBrian Somers int pass; 383e7250038SBrian Somers size_t needed; 384af57ed9fSAtsushi Murai char *sp, *cp, *ep; 385af57ed9fSAtsushi Murai int mib[6]; 386af57ed9fSAtsushi Murai 3878fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 388927145beSBrian Somers 389af57ed9fSAtsushi Murai mib[0] = CTL_NET; 390af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 39153c9f6c0SAtsushi Murai mib[2] = 0; 39253c9f6c0SAtsushi Murai mib[3] = 0; 393af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 39453c9f6c0SAtsushi Murai mib[5] = 0; 39553c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 396dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 397afc7fa2cSBrian Somers strerror(errno)); 39853c9f6c0SAtsushi Murai return; 39953c9f6c0SAtsushi Murai } 400af57ed9fSAtsushi Murai 401af57ed9fSAtsushi Murai sp = malloc(needed); 402af57ed9fSAtsushi Murai if (sp == NULL) 403af57ed9fSAtsushi Murai return; 404af57ed9fSAtsushi Murai 405af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 406dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 407afc7fa2cSBrian Somers strerror(errno)); 408af57ed9fSAtsushi Murai free(sp); 409af57ed9fSAtsushi Murai return; 410af57ed9fSAtsushi Murai } 411af57ed9fSAtsushi Murai ep = sp + needed; 412af57ed9fSAtsushi Murai 41332ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 41432ca3341SBrian Somers /* 41532ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 4166b457978SBrian Somers * deletes all non-cloned routes. This is done to avoid 41732ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 418ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 419ba081e43SBrian Somers * may have gone with route Y). 42032ca3341SBrian Somers */ 42132ca3341SBrian Somers if (RTF_WASCLONED == 0 && pass == 0) 42232ca3341SBrian Somers /* So we can't tell ! */ 42332ca3341SBrian Somers continue; 424af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 425af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *)cp; 4266b457978SBrian Somers route_ParseHdr(rtm, sa); 42730949fd4SBrian Somers if (rtm->rtm_index == bundle->iface->index && 42830949fd4SBrian Somers sa[RTAX_DST] && sa[RTAX_GATEWAY] && 42930949fd4SBrian Somers (sa[RTAX_DST]->sa_family == AF_INET 43030949fd4SBrian Somers #ifndef NOINET6 43130949fd4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 43230949fd4SBrian Somers #endif 43330949fd4SBrian Somers ) && 434af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 43530949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 43630949fd4SBrian Somers char gwstr[41]; 43730949fd4SBrian Somers struct ncpaddr gw; 43830949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 43930949fd4SBrian Somers ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]); 44030949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw)); 44130949fd4SBrian Somers log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr); 44230949fd4SBrian Somers } 4436b457978SBrian Somers if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 44430949fd4SBrian Somers #ifndef NOINET6 44530949fd4SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_INET6 || 44630949fd4SBrian Somers #endif 4476b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 44832ca3341SBrian Somers if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 44932ca3341SBrian Somers (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 45030949fd4SBrian Somers ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 45130949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0); 4525d5e5070SBrian Somers } else 453dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 45432ca3341SBrian Somers } else 455dd7e2610SBrian Somers log_Printf(LogDEBUG, 45630949fd4SBrian Somers "route_IfDelete: Can't remove routes for family %d\n", 4576b457978SBrian Somers sa[RTAX_GATEWAY]->sa_family); 4586b457978SBrian Somers } 459af57ed9fSAtsushi Murai } 460af57ed9fSAtsushi Murai } 461af57ed9fSAtsushi Murai free(sp); 462af57ed9fSAtsushi Murai } 463af57ed9fSAtsushi Murai 46403a2501aSBrian Somers 46503a2501aSBrian Somers /* 46603a2501aSBrian Somers * Update the MTU on all routes for the given interface 46703a2501aSBrian Somers */ 46803a2501aSBrian Somers void 46903a2501aSBrian Somers route_UpdateMTU(struct bundle *bundle) 47003a2501aSBrian Somers { 47103a2501aSBrian Somers struct rt_msghdr *rtm; 47203a2501aSBrian Somers struct sockaddr *sa[RTAX_MAX]; 47330949fd4SBrian Somers struct ncprange dst; 47403a2501aSBrian Somers size_t needed; 47503a2501aSBrian Somers char *sp, *cp, *ep; 47603a2501aSBrian Somers int mib[6]; 47703a2501aSBrian Somers 47803a2501aSBrian Somers log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 47903a2501aSBrian Somers 48003a2501aSBrian Somers mib[0] = CTL_NET; 48103a2501aSBrian Somers mib[1] = PF_ROUTE; 48203a2501aSBrian Somers mib[2] = 0; 48303a2501aSBrian Somers mib[3] = 0; 48403a2501aSBrian Somers mib[4] = NET_RT_DUMP; 48503a2501aSBrian Somers mib[5] = 0; 48603a2501aSBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 48703a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 48803a2501aSBrian Somers strerror(errno)); 48903a2501aSBrian Somers return; 49003a2501aSBrian Somers } 49103a2501aSBrian Somers 49203a2501aSBrian Somers sp = malloc(needed); 49303a2501aSBrian Somers if (sp == NULL) 49403a2501aSBrian Somers return; 49503a2501aSBrian Somers 49603a2501aSBrian Somers if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 49703a2501aSBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 49803a2501aSBrian Somers strerror(errno)); 49903a2501aSBrian Somers free(sp); 50003a2501aSBrian Somers return; 50103a2501aSBrian Somers } 50203a2501aSBrian Somers ep = sp + needed; 50303a2501aSBrian Somers 50403a2501aSBrian Somers for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 50503a2501aSBrian Somers rtm = (struct rt_msghdr *)cp; 50603a2501aSBrian Somers route_ParseHdr(rtm, sa); 5071d3d76d4SBrian Somers if (sa[RTAX_DST] && (sa[RTAX_DST]->sa_family == AF_INET 5085ae08329SBrian Somers #ifndef NOINET6 5091d3d76d4SBrian Somers || sa[RTAX_DST]->sa_family == AF_INET6 5105ae08329SBrian Somers #endif 5115ae08329SBrian Somers ) && 5125ae08329SBrian Somers sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index) { 5135ae08329SBrian Somers if (log_IsKept(LogTCPIP)) { 51430949fd4SBrian Somers ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]); 5155ae08329SBrian Somers log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s," 5165ae08329SBrian Somers " mtu %d\n", rtm->rtm_index, Index2Nam(rtm->rtm_index), 5175ae08329SBrian Somers ncprange_ntoa(&dst), bundle->iface->mtu); 5185ae08329SBrian Somers } 5195ae08329SBrian Somers rt_Update(bundle, sa[RTAX_DST], sa[RTAX_GATEWAY], sa[RTAX_NETMASK]); 52003a2501aSBrian Somers } 52103a2501aSBrian Somers } 52203a2501aSBrian Somers 52303a2501aSBrian Somers free(sp); 52403a2501aSBrian Somers } 52503a2501aSBrian Somers 526af57ed9fSAtsushi Murai int 527944f7098SBrian Somers GetIfIndex(char *name) 528af57ed9fSAtsushi Murai { 5295d5e5070SBrian Somers int idx; 530b6e82f33SBrian Somers const char *got; 531944f7098SBrian Somers 5329cb1d89eSBrian Somers idx = 1; 5335d5e5070SBrian Somers while (strcmp(got = Index2Nam(idx), "???")) 5345d5e5070SBrian Somers if (!strcmp(got, name)) 5357a6f8720SBrian Somers return idx; 5365d5e5070SBrian Somers else 5375d5e5070SBrian Somers idx++; 5385d5e5070SBrian Somers return -1; 539af57ed9fSAtsushi Murai } 540bcc332bdSBrian Somers 541610b185fSBrian Somers void 542610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 54330949fd4SBrian Somers const struct ncpaddr *me, const struct ncpaddr *peer) 544bcc332bdSBrian Somers { 54530949fd4SBrian Somers struct ncpaddr dst; 546bcc332bdSBrian Somers 547610b185fSBrian Somers for (; r; r = r->next) { 54830949fd4SBrian Somers ncprange_getaddr(&r->dst, &dst); 54930949fd4SBrian Somers if (ncpaddr_family(me) == AF_INET) { 55030949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) { 55130949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 55230949fd4SBrian Somers ncprange_sethost(&r->dst, me); 553610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 55430949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 55530949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) { 55630949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 55730949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 558610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 55930949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56030949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) { 56130949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE) 56230949fd4SBrian Somers continue; 56330949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 564d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 56530949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 56630949fd4SBrian Somers } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) { 56730949fd4SBrian Somers if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE) 56830949fd4SBrian Somers continue; 56930949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 570d568d6c4SBrian Somers if (r->type & ROUTE_GWHISADDR) 57130949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57230949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer)) 57330949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 57430949fd4SBrian Somers #ifndef NOINET6 57530949fd4SBrian Somers } else if (ncpaddr_family(me) == AF_INET6) { 57630949fd4SBrian Somers if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) { 57730949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 57830949fd4SBrian Somers ncprange_sethost(&r->dst, me); 57930949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58030949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58130949fd4SBrian Somers } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) { 58230949fd4SBrian Somers rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 58330949fd4SBrian Somers ncprange_sethost(&r->dst, peer); 58430949fd4SBrian Somers if (r->type & ROUTE_GWHISADDR) 58530949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58630949fd4SBrian Somers } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer)) 58730949fd4SBrian Somers ncpaddr_copy(&r->gw, peer); 58830949fd4SBrian Somers #endif 58930949fd4SBrian Somers } 59030949fd4SBrian Somers rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0); 591610b185fSBrian Somers } 592610b185fSBrian Somers } 593610b185fSBrian Somers 594610b185fSBrian Somers void 59530949fd4SBrian Somers route_Add(struct sticky_route **rp, int type, const struct ncprange *dst, 59630949fd4SBrian Somers const struct ncpaddr *gw) 597610b185fSBrian Somers { 598610b185fSBrian Somers struct sticky_route *r; 599610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 600610b185fSBrian Somers 601610b185fSBrian Somers r = NULL; 602610b185fSBrian Somers while (*rp) { 603183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 60430949fd4SBrian Somers (!dsttype && ncprange_equal(&(*rp)->dst, dst))) { 605972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 606972a1bcfSBrian Somers free(r); /* impossible really */ 607610b185fSBrian Somers r = *rp; 608610b185fSBrian Somers *rp = r->next; 609610b185fSBrian Somers } else 610610b185fSBrian Somers rp = &(*rp)->next; 611610b185fSBrian Somers } 612610b185fSBrian Somers 613610b185fSBrian Somers if (!r) 614610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 615610b185fSBrian Somers r->type = type; 616610b185fSBrian Somers r->next = NULL; 61730949fd4SBrian Somers ncprange_copy(&r->dst, dst); 61830949fd4SBrian Somers ncpaddr_copy(&r->gw, gw); 619bcd13e2eSBrian Somers *rp = r; 620610b185fSBrian Somers } 621610b185fSBrian Somers 622610b185fSBrian Somers void 62330949fd4SBrian Somers route_Delete(struct sticky_route **rp, int type, const struct ncprange *dst) 624610b185fSBrian Somers { 625610b185fSBrian Somers struct sticky_route *r; 626610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 627610b185fSBrian Somers 628610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 629610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 63030949fd4SBrian Somers (!dsttype && ncprange_equal(dst, &(*rp)->dst))) { 631610b185fSBrian Somers r = *rp; 632610b185fSBrian Somers *rp = r->next; 633610b185fSBrian Somers free(r); 634bcc332bdSBrian Somers break; 635bcc332bdSBrian Somers } 636bcc332bdSBrian Somers } 637bcc332bdSBrian Somers } 638bcc332bdSBrian Somers 639610b185fSBrian Somers void 640610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 641610b185fSBrian Somers { 642610b185fSBrian Somers struct sticky_route *r, *rn; 643610b185fSBrian Somers 644610b185fSBrian Somers for (r = *rp; r; r = rn) { 645610b185fSBrian Somers rn = r->next; 646610b185fSBrian Somers free(r); 647610b185fSBrian Somers } 648610b185fSBrian Somers *rp = NULL; 649610b185fSBrian Somers } 650610b185fSBrian Somers 651610b185fSBrian Somers void 652972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 653972a1bcfSBrian Somers int indent) 654610b185fSBrian Somers { 655972a1bcfSBrian Somers int tlen = strlen(tag); 656610b185fSBrian Somers 657972a1bcfSBrian Somers if (tlen + 2 > indent) 658972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 659972a1bcfSBrian Somers else 660972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 661972a1bcfSBrian Somers 662610b185fSBrian Somers for (; r; r = r->next) { 663972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 664972a1bcfSBrian Somers tlen = 0; 665610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 666610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 66730949fd4SBrian Somers else if (r->type & ROUTE_DSTMYADDR6) 66830949fd4SBrian Somers prompt_Printf(p, "MYADDR6"); 669610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 670610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 67130949fd4SBrian Somers else if (r->type & ROUTE_DSTHISADDR6) 67230949fd4SBrian Somers prompt_Printf(p, "HISADDR6"); 673d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS0) 674d568d6c4SBrian Somers prompt_Printf(p, "DNS0"); 675d568d6c4SBrian Somers else if (r->type & ROUTE_DSTDNS1) 676d568d6c4SBrian Somers prompt_Printf(p, "DNS1"); 67730949fd4SBrian Somers else if (ncprange_isdefault(&r->dst)) 678610b185fSBrian Somers prompt_Printf(p, "default"); 679610b185fSBrian Somers else 68030949fd4SBrian Somers prompt_Printf(p, "%s", ncprange_ntoa(&r->dst)); 681610b185fSBrian Somers 682610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 683610b185fSBrian Somers prompt_Printf(p, " HISADDR\n"); 68430949fd4SBrian Somers else if (r->type & ROUTE_GWHISADDR6) 68530949fd4SBrian Somers prompt_Printf(p, " HISADDR6\n"); 686610b185fSBrian Somers else 68730949fd4SBrian Somers prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw)); 688610b185fSBrian Somers } 689bcc332bdSBrian Somers } 69003a2501aSBrian Somers 69103a2501aSBrian Somers struct rtmsg { 69203a2501aSBrian Somers struct rt_msghdr m_rtm; 69330949fd4SBrian Somers char m_space[256]; 69403a2501aSBrian Somers }; 69503a2501aSBrian Somers 69603a2501aSBrian Somers int 69730949fd4SBrian Somers rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst, 69830949fd4SBrian Somers const struct ncpaddr *gw, int bang, int quiet) 69903a2501aSBrian Somers { 70003a2501aSBrian Somers struct rtmsg rtmes; 70126dceef0SBrian Somers int s, nb, wb, width; 70203a2501aSBrian Somers char *cp; 70303a2501aSBrian Somers const char *cmdstr; 70430949fd4SBrian Somers struct sockaddr_storage sadst, samask, sagw; 70503a2501aSBrian Somers int result = 1; 70603a2501aSBrian Somers 70703a2501aSBrian Somers if (bang) 70803a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 70903a2501aSBrian Somers else 71003a2501aSBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 71103a2501aSBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 71203a2501aSBrian Somers if (s < 0) { 71303a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 71403a2501aSBrian Somers return result; 71503a2501aSBrian Somers } 71603a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 71703a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 71803a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd; 71903a2501aSBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 72003a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 72103a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 72203a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 72303a2501aSBrian Somers 72403a2501aSBrian Somers if (cmd == RTM_ADD) { 72530949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 72630949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 72703a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 72803a2501aSBrian Somers } 72930949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 73030949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 73103a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 73203a2501aSBrian Somers } 73303a2501aSBrian Somers } 73403a2501aSBrian Somers 73530949fd4SBrian Somers ncprange_getsa(dst, &sadst, &samask); 73603a2501aSBrian Somers 73703a2501aSBrian Somers cp = rtmes.m_space; 73830949fd4SBrian Somers memcpy(cp, &sadst, sadst.ss_len); 73930949fd4SBrian Somers cp += sadst.ss_len; 74003a2501aSBrian Somers if (cmd == RTM_ADD) { 74130949fd4SBrian Somers if (gw == NULL) { 74230949fd4SBrian Somers log_Printf(LogERROR, "rt_Set: Program error\n"); 74330949fd4SBrian Somers close(s); 74430949fd4SBrian Somers return result; 74530949fd4SBrian Somers } 74630949fd4SBrian Somers ncpaddr_getsa(gw, &sagw); 74730949fd4SBrian Somers if (ncpaddr_isdefault(gw)) { 74830949fd4SBrian Somers if (!quiet) 74903a2501aSBrian Somers log_Printf(LogERROR, "rt_Set: Cannot add a route with" 750156a04e4SBrian Somers " gateway 0.0.0.0\n"); 75103a2501aSBrian Somers close(s); 75203a2501aSBrian Somers return result; 75303a2501aSBrian Somers } else { 75430949fd4SBrian Somers memcpy(cp, &sagw, sagw.ss_len); 75530949fd4SBrian Somers cp += sagw.ss_len; 75603a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 75703a2501aSBrian Somers } 75803a2501aSBrian Somers } 75903a2501aSBrian Somers 76026dceef0SBrian Somers if (!ncprange_ishost(dst)) { 76130949fd4SBrian Somers memcpy(cp, &samask, samask.ss_len); 76230949fd4SBrian Somers cp += samask.ss_len; 76303a2501aSBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 76403a2501aSBrian Somers } 76503a2501aSBrian Somers 76603a2501aSBrian Somers nb = cp - (char *)&rtmes; 76703a2501aSBrian Somers rtmes.m_rtm.rtm_msglen = nb; 76803a2501aSBrian Somers wb = ID0write(s, &rtmes, nb); 76903a2501aSBrian Somers if (wb < 0) { 77003a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set failure:\n"); 77103a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 77230949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst)); 77330949fd4SBrian Somers if (gw != NULL) 77430949fd4SBrian Somers log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw)); 77503a2501aSBrian Somers failed: 77603a2501aSBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 77703a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 77803a2501aSBrian Somers if (!bang) { 77903a2501aSBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 78030949fd4SBrian Somers ncprange_ntoa(dst)); 78103a2501aSBrian Somers result = 0; /* Don't add to our dynamic list */ 78203a2501aSBrian Somers } else { 78303a2501aSBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 78403a2501aSBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 78503a2501aSBrian Somers goto failed; 78603a2501aSBrian Somers } 78703a2501aSBrian Somers } else if (cmd == RTM_DELETE && 78803a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 78903a2501aSBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 79003a2501aSBrian Somers if (!bang) 79103a2501aSBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 79230949fd4SBrian Somers ncprange_ntoa(dst)); 79303a2501aSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 79430949fd4SBrian Somers if (!quiet || errno != ENETUNREACH) 79503a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 79630949fd4SBrian Somers ncprange_ntoa(dst), strerror(errno)); 79703a2501aSBrian Somers } else 79803a2501aSBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 79930949fd4SBrian Somers cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 80003a2501aSBrian Somers } 80103a2501aSBrian Somers 80230949fd4SBrian Somers if (log_IsKept(LogDEBUG)) { 80330949fd4SBrian Somers char gwstr[40]; 80430949fd4SBrian Somers 80530949fd4SBrian Somers if (gw) 80630949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw)); 80730949fd4SBrian Somers else 80830949fd4SBrian Somers snprintf(gwstr, sizeof gwstr, "<none>"); 80930949fd4SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n", 81030949fd4SBrian Somers wb, cmdstr, ncprange_ntoa(dst), gwstr); 81130949fd4SBrian Somers } 81203a2501aSBrian Somers close(s); 81303a2501aSBrian Somers 81403a2501aSBrian Somers return result; 81503a2501aSBrian Somers } 81603a2501aSBrian Somers 81703a2501aSBrian Somers void 8185ae08329SBrian Somers rt_Update(struct bundle *bundle, const struct sockaddr *dst, 8195ae08329SBrian Somers const struct sockaddr *gw, const struct sockaddr *mask) 82003a2501aSBrian Somers { 8215ae08329SBrian Somers struct ncprange ncpdst; 82203a2501aSBrian Somers struct rtmsg rtmes; 8235ae08329SBrian Somers char *p; 82403a2501aSBrian Somers int s, wb; 82503a2501aSBrian Somers 82603a2501aSBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 82703a2501aSBrian Somers if (s < 0) { 82803a2501aSBrian Somers log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 82903a2501aSBrian Somers return; 83003a2501aSBrian Somers } 83103a2501aSBrian Somers 83203a2501aSBrian Somers memset(&rtmes, '\0', sizeof rtmes); 83303a2501aSBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 83403a2501aSBrian Somers rtmes.m_rtm.rtm_type = RTM_CHANGE; 835d42d9220SBrian Somers rtmes.m_rtm.rtm_addrs = 0; 83603a2501aSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 83703a2501aSBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 83803a2501aSBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 83903a2501aSBrian Somers 84030949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0) { 84130949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 84203a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 84303a2501aSBrian Somers } 84403a2501aSBrian Somers 84530949fd4SBrian Somers if (bundle->ncp.cfg.recvpipe > 0) { 84630949fd4SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 84703a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 84803a2501aSBrian Somers } 84903a2501aSBrian Somers 850c8b9fb53SBrian Somers rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; 85103a2501aSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_MTU; 8525ae08329SBrian Somers p = rtmes.m_space; 85303a2501aSBrian Somers 8545ae08329SBrian Somers if (dst) { 8555ae08329SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_DST; 8565ae08329SBrian Somers memcpy(p, dst, dst->sa_len); 8575ae08329SBrian Somers p += dst->sa_len; 8585ae08329SBrian Somers } 859d42d9220SBrian Somers 860d42d9220SBrian Somers #ifdef __FreeBSD__ 861d42d9220SBrian Somers /* 862d42d9220SBrian Somers * In order to update the default route under FreeBSD, only the destination 863d42d9220SBrian Somers * address should be specified. If the (empty) mask or the gateway 864d42d9220SBrian Somers * address are used, the update fails... 865d42d9220SBrian Somers * Conversely, if the gateway and mask are omitted under OpenBSD, the 866d42d9220SBrian Somers * update will fail. 867d42d9220SBrian Somers */ 868d42d9220SBrian Somers if (dst) 869d42d9220SBrian Somers ncprange_setsa(&ncpdst, dst, mask); 870d42d9220SBrian Somers else 871d42d9220SBrian Somers ncprange_init(&ncpdst); 872d42d9220SBrian Somers 873d42d9220SBrian Somers if (!ncprange_isdefault(&ncpdst)) 874d42d9220SBrian Somers #endif 875d42d9220SBrian Somers { 876d42d9220SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 8775ae08329SBrian Somers memcpy(p, gw, gw->sa_len); 8785ae08329SBrian Somers p += gw->sa_len; 8795ae08329SBrian Somers if (mask) { 8805ae08329SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 8815ae08329SBrian Somers memcpy(p, mask, mask->sa_len); 8825ae08329SBrian Somers p += mask->sa_len; 8835ae08329SBrian Somers } 884d42d9220SBrian Somers } 88503a2501aSBrian Somers 8865ae08329SBrian Somers rtmes.m_rtm.rtm_msglen = p - (char *)&rtmes; 88703a2501aSBrian Somers 88803a2501aSBrian Somers wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 88903a2501aSBrian Somers if (wb < 0) { 8905ae08329SBrian Somers ncprange_setsa(&ncpdst, dst, mask); 8915ae08329SBrian Somers 89203a2501aSBrian Somers log_Printf(LogTCPIP, "rt_Update failure:\n"); 8935ae08329SBrian Somers log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst)); 89403a2501aSBrian Somers 89503a2501aSBrian Somers if (rtmes.m_rtm.rtm_errno == 0) 89603a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 8975ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(errno)); 89803a2501aSBrian Somers else 89903a2501aSBrian Somers log_Printf(LogWARN, "%s: Change route failed: %s\n", 9005ae08329SBrian Somers ncprange_ntoa(&ncpdst), strerror(rtmes.m_rtm.rtm_errno)); 90103a2501aSBrian Somers } 90203a2501aSBrian Somers close(s); 90303a2501aSBrian Somers } 904