1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * PPP Routing related Module 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Redistribution and use in source and binary forms are permitted 9af57ed9fSAtsushi Murai * provided that the above copyright notice and this paragraph are 10af57ed9fSAtsushi Murai * duplicated in all such forms and that any documentation, 11af57ed9fSAtsushi Murai * advertising materials, and other materials related to such 12af57ed9fSAtsushi Murai * distribution and use acknowledge that the software was developed 13af57ed9fSAtsushi Murai * by the Internet Initiative Japan, Inc. The name of the 14af57ed9fSAtsushi Murai * IIJ may not be used to endorse or promote products derived 15af57ed9fSAtsushi Murai * from this software without specific prior written permission. 16af57ed9fSAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17af57ed9fSAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18af57ed9fSAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19af57ed9fSAtsushi Murai * 20972a1bcfSBrian Somers * $Id: route.c,v 1.54 1998/10/22 02:32:50 brian Exp $ 2153c9f6c0SAtsushi Murai * 22af57ed9fSAtsushi Murai */ 2375240ed1SBrian Somers 24972a1bcfSBrian Somers #include <sys/param.h> 2575240ed1SBrian Somers #include <sys/socket.h> 265d5e5070SBrian Somers #include <net/if_types.h> 27628d2ac1SGarrett Wollman #include <net/route.h> 28628d2ac1SGarrett Wollman #include <net/if.h> 29628d2ac1SGarrett Wollman #include <netinet/in.h> 30628d2ac1SGarrett Wollman #include <arpa/inet.h> 315d5e5070SBrian Somers #include <net/if_dl.h> 32eaa4df37SBrian Somers #include <netinet/in_systm.h> 33eaa4df37SBrian Somers #include <netinet/ip.h> 341fa665f5SBrian Somers #include <sys/un.h> 35628d2ac1SGarrett Wollman 3675240ed1SBrian Somers #include <errno.h> 3775240ed1SBrian Somers #include <stdio.h> 3875240ed1SBrian Somers #include <stdlib.h> 3975240ed1SBrian Somers #include <string.h> 4075240ed1SBrian Somers #include <sys/sysctl.h> 4185b542cfSBrian Somers #include <termios.h> 4275240ed1SBrian Somers 43c9e11a11SBrian Somers #include "defs.h" 44b6e82f33SBrian Somers #include "command.h" 4575240ed1SBrian Somers #include "mbuf.h" 46215a4696SAtsushi Murai #include "log.h" 47bcc332bdSBrian Somers #include "iplist.h" 4829e275ceSBrian Somers #include "timer.h" 4929e275ceSBrian Somers #include "throughput.h" 50879ed6faSBrian Somers #include "lqr.h" 518c07a7b2SBrian Somers #include "hdlc.h" 527308ec68SBrian Somers #include "fsm.h" 533b0f8d2eSBrian Somers #include "lcp.h" 543b0f8d2eSBrian Somers #include "ccp.h" 553b0f8d2eSBrian Somers #include "link.h" 56eaa4df37SBrian Somers #include "slcompress.h" 5729e275ceSBrian Somers #include "ipcp.h" 585ca5389aSBrian Somers #include "filter.h" 592f786681SBrian Somers #include "descriptor.h" 603b0f8d2eSBrian Somers #include "mp.h" 61972a1bcfSBrian Somers #ifndef NORADIUS 62972a1bcfSBrian Somers #include "radius.h" 63972a1bcfSBrian Somers #endif 645828db6dSBrian Somers #include "bundle.h" 6575240ed1SBrian Somers #include "route.h" 6685b542cfSBrian Somers #include "prompt.h" 678fa6ebe4SBrian Somers #include "iface.h" 68af57ed9fSAtsushi Murai 69af57ed9fSAtsushi Murai static void 70b6217683SBrian Somers p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 71b6217683SBrian Somers struct sockaddr *pmask, int width) 72af57ed9fSAtsushi Murai { 73b6e82f33SBrian Somers char buf[29]; 745d5e5070SBrian Somers struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 755d5e5070SBrian Somers struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 765d5e5070SBrian Somers struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 77af57ed9fSAtsushi Murai 785d5e5070SBrian Somers switch (phost->sa_family) { 795d5e5070SBrian Somers case AF_INET: 805d5e5070SBrian Somers if (!phost) 814bfaee90SBrian Somers buf[0] = '\0'; 825d5e5070SBrian Somers else if (ihost->sin_addr.s_addr == INADDR_ANY) 834bfaee90SBrian Somers strcpy(buf, "default"); 845d5e5070SBrian Somers else if (!mask) 854bfaee90SBrian Somers strcpy(buf, inet_ntoa(ihost->sin_addr)); 865d5e5070SBrian Somers else { 873a2e4f62SBrian Somers u_int32_t msk = ntohl(mask->sin_addr.s_addr); 883a2e4f62SBrian Somers u_int32_t tst; 895d5e5070SBrian Somers int bits; 905d5e5070SBrian Somers int len; 915d5e5070SBrian Somers struct sockaddr_in net; 925d5e5070SBrian Somers 935d5e5070SBrian Somers for (tst = 1, bits=32; tst; tst <<= 1, bits--) 945d5e5070SBrian Somers if (msk & tst) 955d5e5070SBrian Somers break; 965d5e5070SBrian Somers 975d5e5070SBrian Somers for (tst <<= 1; tst; tst <<= 1) 985d5e5070SBrian Somers if (!(msk & tst)) 995d5e5070SBrian Somers break; 1005d5e5070SBrian Somers 1015d5e5070SBrian Somers net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 10283c0952dSBrian Somers strcpy(buf, inet_ntoa(net.sin_addr)); 1035d5e5070SBrian Somers for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 1045d5e5070SBrian Somers if (strcmp(buf + len - 2, ".0")) 1055d5e5070SBrian Somers break; 1065d5e5070SBrian Somers 1075d5e5070SBrian Somers if (tst) /* non-contiguous :-( */ 1083a2e4f62SBrian Somers sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 1095d5e5070SBrian Somers else 1105d5e5070SBrian Somers sprintf(buf + strlen(buf), "/%d", bits); 111927145beSBrian Somers } 1125d5e5070SBrian Somers break; 1135d5e5070SBrian Somers 1145d5e5070SBrian Somers case AF_LINK: 1154bfaee90SBrian Somers if (dl->sdl_nlen) 1164bfaee90SBrian Somers snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 117c4c4aaacSBrian Somers else if (dl->sdl_alen) { 118c4c4aaacSBrian Somers if (dl->sdl_type == IFT_ETHER) { 11970ee81ffSBrian Somers if (dl->sdl_alen < sizeof buf / 3) { 1205d5e5070SBrian Somers int f; 1215d5e5070SBrian Somers u_char *MAC; 1225d5e5070SBrian Somers 1235d5e5070SBrian Somers MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 1245d5e5070SBrian Somers for (f = 0; f < dl->sdl_alen; f++) 1255d5e5070SBrian Somers sprintf(buf+f*3, "%02x:", MAC[f]); 1265d5e5070SBrian Somers buf[f*3-1] = '\0'; 1275d5e5070SBrian Somers } else 12883c0952dSBrian Somers strcpy(buf, "??:??:??:??:??:??"); 129c4c4aaacSBrian Somers } else 1304bfaee90SBrian Somers sprintf(buf, "<IFT type %d>", dl->sdl_type); 131c4c4aaacSBrian Somers } else if (dl->sdl_slen) 1324bfaee90SBrian Somers sprintf(buf, "<slen %d?>", dl->sdl_slen); 1334bfaee90SBrian Somers else 1344bfaee90SBrian Somers sprintf(buf, "link#%d", dl->sdl_index); 1355d5e5070SBrian Somers break; 1365d5e5070SBrian Somers 1375d5e5070SBrian Somers default: 1384bfaee90SBrian Somers sprintf(buf, "<AF type %d>", phost->sa_family); 1395d5e5070SBrian Somers break; 1405d5e5070SBrian Somers } 1415d5e5070SBrian Somers 142b6217683SBrian Somers prompt_Printf(prompt, "%-*s ", width-1, buf); 143af57ed9fSAtsushi Murai } 144af57ed9fSAtsushi Murai 145aa8e0519SBrian Somers static struct bits { 1463f06c599SBrian Somers u_int32_t b_mask; 147af57ed9fSAtsushi Murai char b_val; 148af57ed9fSAtsushi Murai } bits[] = { 1495d5e5070SBrian Somers { RTF_UP, 'U' }, 1505d5e5070SBrian Somers { RTF_GATEWAY, 'G' }, 1515d5e5070SBrian Somers { RTF_HOST, 'H' }, 1525d5e5070SBrian Somers { RTF_REJECT, 'R' }, 1535d5e5070SBrian Somers { RTF_DYNAMIC, 'D' }, 1545d5e5070SBrian Somers { RTF_MODIFIED, 'M' }, 1555d5e5070SBrian Somers { RTF_DONE, 'd' }, 1565d5e5070SBrian Somers { RTF_CLONING, 'C' }, 1575d5e5070SBrian Somers { RTF_XRESOLVE, 'X' }, 1585d5e5070SBrian Somers { RTF_LLINFO, 'L' }, 1595d5e5070SBrian Somers { RTF_STATIC, 'S' }, 1605d5e5070SBrian Somers { RTF_PROTO1, '1' }, 1615d5e5070SBrian Somers { RTF_PROTO2, '2' }, 1625d5e5070SBrian Somers { RTF_BLACKHOLE, 'B' }, 16332ca3341SBrian Somers #ifdef RTF_WASCLONED 1645d5e5070SBrian Somers { RTF_WASCLONED, 'W' }, 16532ca3341SBrian Somers #endif 16632ca3341SBrian Somers #ifdef RTF_PRCLONING 1675d5e5070SBrian Somers { RTF_PRCLONING, 'c' }, 16832ca3341SBrian Somers #endif 16932ca3341SBrian Somers #ifdef RTF_PROTO3 1705d5e5070SBrian Somers { RTF_PROTO3, '3' }, 17132ca3341SBrian Somers #endif 17232ca3341SBrian Somers #ifdef RTF_BROADCAST 1735d5e5070SBrian Somers { RTF_BROADCAST, 'b' }, 1745d5e5070SBrian Somers #endif 1755d5e5070SBrian Somers { 0, '\0' } 176af57ed9fSAtsushi Murai }; 177af57ed9fSAtsushi Murai 17832ca3341SBrian Somers #ifndef RTF_WASCLONED 17932ca3341SBrian Somers #define RTF_WASCLONED (0) 18032ca3341SBrian Somers #endif 18132ca3341SBrian Somers 182af57ed9fSAtsushi Murai static void 1833f06c599SBrian Somers p_flags(struct prompt *prompt, u_int32_t f, int 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 191d27d502cSBrian Somers for (flags = name; p->b_mask && flags - name < max; p++) 192af57ed9fSAtsushi Murai if (p->b_mask & f) 193af57ed9fSAtsushi Murai *flags++ = p->b_val; 194af57ed9fSAtsushi Murai *flags = '\0'; 195b6217683SBrian Somers prompt_Printf(prompt, "%-*.*s", max, max, name); 196af57ed9fSAtsushi Murai } 197af57ed9fSAtsushi Murai 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 */ 208d93d3a9cSBrian Somers static int nifs, debug_done; /* Figure out how many once, and debug once */ 2095d5e5070SBrian Somers 2105d5e5070SBrian Somers if (!nifs) { 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 2175d5e5070SBrian Somers mib[0] = CTL_NET; 2185d5e5070SBrian Somers mib[1] = PF_ROUTE; 2195d5e5070SBrian Somers mib[2] = 0; 2205d5e5070SBrian Somers mib[3] = 0; 2215d5e5070SBrian Somers mib[4] = NET_RT_IFLIST; 2225d5e5070SBrian Somers mib[5] = 0; 2235d5e5070SBrian Somers 2245d5e5070SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 225a33b2ef7SBrian Somers log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 226a33b2ef7SBrian Somers strerror(errno)); 2275d5e5070SBrian Somers return "???"; 2285d5e5070SBrian Somers } 2295d5e5070SBrian Somers if ((buf = malloc(needed)) == NULL) 2305d5e5070SBrian Somers return "???"; 2315d5e5070SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 2325d5e5070SBrian Somers free(buf); 2335d5e5070SBrian Somers return "???"; 2345d5e5070SBrian Somers } 2355d5e5070SBrian Somers end = buf + needed; 2365d5e5070SBrian Somers 237b1435e41SBrian Somers have = 0; 2389cb1d89eSBrian Somers for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 2395d5e5070SBrian Somers ifm = (struct if_msghdr *)ptr; 2405d5e5070SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); 241b1435e41SBrian Somers if (ifm->ifm_index > 0) { 242b1435e41SBrian Somers if (ifm->ifm_index > have) { 243fc254be9SBrian Somers char **newifs; 244fc254be9SBrian Somers 245b1435e41SBrian Somers had = have; 246b1435e41SBrian Somers have = ifm->ifm_index + 5; 247b1435e41SBrian Somers if (had) 248fc254be9SBrian Somers newifs = (char **)realloc(ifs, sizeof(char *) * have); 249b1435e41SBrian Somers else 250fc254be9SBrian Somers newifs = (char **)malloc(sizeof(char *) * have); 251fc254be9SBrian Somers if (!newifs) { 252dd7e2610SBrian Somers log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 253b1435e41SBrian Somers nifs = 0; 254fc254be9SBrian Somers if (ifs) 255fc254be9SBrian Somers free(ifs); 256b1435e41SBrian Somers return "???"; 257b1435e41SBrian Somers } 258fc254be9SBrian Somers ifs = newifs; 259b1435e41SBrian Somers memset(ifs + had, '\0', sizeof(char *) * (have - had)); 260b1435e41SBrian Somers } 261b1435e41SBrian Somers if (ifs[ifm->ifm_index-1] == NULL) { 262b1435e41SBrian Somers ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 263b1435e41SBrian Somers memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 264b1435e41SBrian Somers ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 265b1435e41SBrian Somers if (nifs < ifm->ifm_index) 2669cb1d89eSBrian Somers nifs = ifm->ifm_index; 267b1435e41SBrian Somers } 268dd7e2610SBrian Somers } else if (log_IsKept(LogDEBUG)) 269dd7e2610SBrian Somers log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 2709cb1d89eSBrian Somers ifm->ifm_index); 2715d5e5070SBrian Somers } 2725d5e5070SBrian Somers free(buf); 2735d5e5070SBrian Somers } 2745d5e5070SBrian Somers 275dd7e2610SBrian Somers if (log_IsKept(LogDEBUG) && !debug_done) { 2769cb1d89eSBrian Somers int f; 2779cb1d89eSBrian Somers 278dd7e2610SBrian Somers log_Printf(LogDEBUG, "Found the following interfaces:\n"); 2799cb1d89eSBrian Somers for (f = 0; f < nifs; f++) 280b1435e41SBrian Somers if (ifs[f] != NULL) 281dd7e2610SBrian Somers log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 2829cb1d89eSBrian Somers debug_done = 1; 2839cb1d89eSBrian Somers } 2849cb1d89eSBrian Somers 285b1435e41SBrian Somers if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 2865d5e5070SBrian Somers return "???"; 2879cb1d89eSBrian Somers 2889cb1d89eSBrian Somers return ifs[idx-1]; 2895d5e5070SBrian Somers } 2905d5e5070SBrian Somers 291af57ed9fSAtsushi Murai int 292dd7e2610SBrian Somers route_Show(struct cmdargs const *arg) 293af57ed9fSAtsushi Murai { 294af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 2955d5e5070SBrian Somers struct sockaddr *sa_dst, *sa_gw, *sa_mask; 2965d5e5070SBrian Somers char *sp, *ep, *cp, *wp; 297e7250038SBrian Somers size_t needed; 298af57ed9fSAtsushi Murai int mib[6]; 299af57ed9fSAtsushi Murai 300af57ed9fSAtsushi Murai mib[0] = CTL_NET; 301af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 30253c9f6c0SAtsushi Murai mib[2] = 0; 30353c9f6c0SAtsushi Murai mib[3] = 0; 304af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 30553c9f6c0SAtsushi Murai mib[5] = 0; 30653c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 307dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 30853c9f6c0SAtsushi Murai return (1); 30953c9f6c0SAtsushi Murai } 310af57ed9fSAtsushi Murai sp = malloc(needed); 311af57ed9fSAtsushi Murai if (sp == NULL) 312af57ed9fSAtsushi Murai return (1); 31353c9f6c0SAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 314dd7e2610SBrian Somers log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 315b0cdb3ceSJordan K. Hubbard free(sp); 316af57ed9fSAtsushi Murai return (1); 31753c9f6c0SAtsushi Murai } 318af57ed9fSAtsushi Murai ep = sp + needed; 319af57ed9fSAtsushi Murai 320b6217683SBrian Somers prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 321b6217683SBrian Somers "Destination", "Gateway"); 322af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 323af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *) cp; 3245d5e5070SBrian Somers wp = (char *)(rtm+1); 3255d5e5070SBrian Somers 3265d5e5070SBrian Somers if (rtm->rtm_addrs & RTA_DST) { 3275d5e5070SBrian Somers sa_dst = (struct sockaddr *)wp; 3285d5e5070SBrian Somers wp += sa_dst->sa_len; 3295d5e5070SBrian Somers } else 3305d5e5070SBrian Somers sa_dst = NULL; 3315d5e5070SBrian Somers 3325d5e5070SBrian Somers if (rtm->rtm_addrs & RTA_GATEWAY) { 3335d5e5070SBrian Somers sa_gw = (struct sockaddr *)wp; 3345d5e5070SBrian Somers wp += sa_gw->sa_len; 3355d5e5070SBrian Somers } else 3365d5e5070SBrian Somers sa_gw = NULL; 3375d5e5070SBrian Somers 3385d5e5070SBrian Somers if (rtm->rtm_addrs & RTA_NETMASK) { 3395d5e5070SBrian Somers sa_mask = (struct sockaddr *)wp; 3405d5e5070SBrian Somers wp += sa_mask->sa_len; 3415d5e5070SBrian Somers } else 3425d5e5070SBrian Somers sa_mask = NULL; 3435d5e5070SBrian Somers 344b6217683SBrian Somers p_sockaddr(arg->prompt, sa_dst, sa_mask, 20); 345b6217683SBrian Somers p_sockaddr(arg->prompt, sa_gw, NULL, 20); 3465d5e5070SBrian Somers 347b6217683SBrian Somers p_flags(arg->prompt, rtm->rtm_flags, 6); 348b6217683SBrian Somers prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 349af57ed9fSAtsushi Murai } 350b0cdb3ceSJordan K. Hubbard free(sp); 351927145beSBrian Somers return 0; 352af57ed9fSAtsushi Murai } 353af57ed9fSAtsushi Murai 354af57ed9fSAtsushi Murai /* 355af57ed9fSAtsushi Murai * Delete routes associated with our interface 356af57ed9fSAtsushi Murai */ 357af57ed9fSAtsushi Murai void 358dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all) 359af57ed9fSAtsushi Murai { 360af57ed9fSAtsushi Murai struct rt_msghdr *rtm; 361af57ed9fSAtsushi Murai struct sockaddr *sa; 362f01e577bSBrian Somers struct in_addr sa_dst, sa_none; 363e7250038SBrian Somers int pass; 364e7250038SBrian Somers size_t needed; 365af57ed9fSAtsushi Murai char *sp, *cp, *ep; 366af57ed9fSAtsushi Murai int mib[6]; 367af57ed9fSAtsushi Murai 3688fa6ebe4SBrian Somers log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 369f01e577bSBrian Somers sa_none.s_addr = INADDR_ANY; 370927145beSBrian Somers 371af57ed9fSAtsushi Murai mib[0] = CTL_NET; 372af57ed9fSAtsushi Murai mib[1] = PF_ROUTE; 37353c9f6c0SAtsushi Murai mib[2] = 0; 37453c9f6c0SAtsushi Murai mib[3] = 0; 375af57ed9fSAtsushi Murai mib[4] = NET_RT_DUMP; 37653c9f6c0SAtsushi Murai mib[5] = 0; 37753c9f6c0SAtsushi Murai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 378dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 379afc7fa2cSBrian Somers strerror(errno)); 38053c9f6c0SAtsushi Murai return; 38153c9f6c0SAtsushi Murai } 382af57ed9fSAtsushi Murai 383af57ed9fSAtsushi Murai sp = malloc(needed); 384af57ed9fSAtsushi Murai if (sp == NULL) 385af57ed9fSAtsushi Murai return; 386af57ed9fSAtsushi Murai 387af57ed9fSAtsushi Murai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 388dd7e2610SBrian Somers log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 389afc7fa2cSBrian Somers strerror(errno)); 390af57ed9fSAtsushi Murai free(sp); 391af57ed9fSAtsushi Murai return; 392af57ed9fSAtsushi Murai } 393af57ed9fSAtsushi Murai ep = sp + needed; 394af57ed9fSAtsushi Murai 39532ca3341SBrian Somers for (pass = 0; pass < 2; pass++) { 39632ca3341SBrian Somers /* 39732ca3341SBrian Somers * We do 2 passes. The first deletes all cloned routes. The second 39832ca3341SBrian Somers * deletes all non-cloned routes. This is necessary to avoid 39932ca3341SBrian Somers * potential errors from trying to delete route X after route Y where 400ba081e43SBrian Somers * route X was cloned from route Y (and is no longer there 'cos it 401ba081e43SBrian Somers * may have gone with route Y). 40232ca3341SBrian Somers */ 40332ca3341SBrian Somers if (RTF_WASCLONED == 0 && pass == 0) 40432ca3341SBrian Somers /* So we can't tell ! */ 40532ca3341SBrian Somers continue; 406af57ed9fSAtsushi Murai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 407af57ed9fSAtsushi Murai rtm = (struct rt_msghdr *) cp; 408af57ed9fSAtsushi Murai sa = (struct sockaddr *) (rtm + 1); 409dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 41032ca3341SBrian Somers " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 4115d5e5070SBrian Somers Index2Nam(rtm->rtm_index), rtm->rtm_flags, 4129b5a20e1SBrian Somers inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 4135d5e5070SBrian Somers if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 4148fa6ebe4SBrian Somers rtm->rtm_index == bundle->iface->index && 415af57ed9fSAtsushi Murai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 4165d5e5070SBrian Somers sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 4175d5e5070SBrian Somers sa = (struct sockaddr *)((char *)sa + sa->sa_len); 418f01e577bSBrian Somers if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) { 41932ca3341SBrian Somers if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 42032ca3341SBrian Somers (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 421dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass); 4222062443fSBrian Somers bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0, 0); 4235d5e5070SBrian Somers } else 424dd7e2610SBrian Somers log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 42532ca3341SBrian Somers } else 426dd7e2610SBrian Somers log_Printf(LogDEBUG, 427dd7e2610SBrian Somers "route_IfDelete: Can't remove routes of %d family !\n", 428f01e577bSBrian Somers sa->sa_family); 429af57ed9fSAtsushi Murai } 430af57ed9fSAtsushi Murai } 43132ca3341SBrian Somers } 432af57ed9fSAtsushi Murai free(sp); 433af57ed9fSAtsushi Murai } 434af57ed9fSAtsushi Murai 435af57ed9fSAtsushi Murai int 436944f7098SBrian Somers GetIfIndex(char *name) 437af57ed9fSAtsushi Murai { 4385d5e5070SBrian Somers int idx; 439b6e82f33SBrian Somers const char *got; 440944f7098SBrian Somers 4419cb1d89eSBrian Somers idx = 1; 4425d5e5070SBrian Somers while (strcmp(got = Index2Nam(idx), "???")) 4435d5e5070SBrian Somers if (!strcmp(got, name)) 4447a6f8720SBrian Somers return idx; 4455d5e5070SBrian Somers else 4465d5e5070SBrian Somers idx++; 4475d5e5070SBrian Somers return -1; 448af57ed9fSAtsushi Murai } 449bcc332bdSBrian Somers 450610b185fSBrian Somers void 451610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r, 452610b185fSBrian Somers struct in_addr me, struct in_addr peer) 453bcc332bdSBrian Somers { 454610b185fSBrian Somers struct in_addr none, del; 455bcc332bdSBrian Somers 456610b185fSBrian Somers none.s_addr = INADDR_ANY; 457610b185fSBrian Somers for (; r; r = r->next) { 458610b185fSBrian Somers if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 459610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 4602062443fSBrian Somers bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 461610b185fSBrian Somers r->dst = me; 462610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 463610b185fSBrian Somers r->gw = peer; 464610b185fSBrian Somers } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 465610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 4662062443fSBrian Somers bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 467610b185fSBrian Somers r->dst = peer; 468610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 469610b185fSBrian Somers r->gw = peer; 470610b185fSBrian Somers } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 471610b185fSBrian Somers r->gw = peer; 4722062443fSBrian Somers bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 473610b185fSBrian Somers } 474610b185fSBrian Somers } 475610b185fSBrian Somers 476610b185fSBrian Somers void 477610b185fSBrian Somers route_Clean(struct bundle *bundle, struct sticky_route *r) 478610b185fSBrian Somers { 479610b185fSBrian Somers struct in_addr none, del; 480610b185fSBrian Somers 481610b185fSBrian Somers none.s_addr = INADDR_ANY; 482610b185fSBrian Somers for (; r; r = r->next) { 483610b185fSBrian Somers del.s_addr = r->dst.s_addr & r->mask.s_addr; 4842062443fSBrian Somers bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 485610b185fSBrian Somers } 486610b185fSBrian Somers } 487610b185fSBrian Somers 488610b185fSBrian Somers void 489610b185fSBrian Somers route_Add(struct sticky_route **rp, int type, struct in_addr dst, 490610b185fSBrian Somers struct in_addr mask, struct in_addr gw) 491610b185fSBrian Somers { 492610b185fSBrian Somers struct sticky_route *r; 493610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 494610b185fSBrian Somers 495610b185fSBrian Somers r = NULL; 496610b185fSBrian Somers while (*rp) { 497183df580SBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 498183df580SBrian Somers (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 499972a1bcfSBrian Somers /* Oops, we already have this route - unlink it */ 500972a1bcfSBrian Somers free(r); /* impossible really */ 501610b185fSBrian Somers r = *rp; 502610b185fSBrian Somers *rp = r->next; 503610b185fSBrian Somers } else 504610b185fSBrian Somers rp = &(*rp)->next; 505610b185fSBrian Somers } 506610b185fSBrian Somers 507610b185fSBrian Somers if (!r) 508610b185fSBrian Somers r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 509610b185fSBrian Somers r->type = type; 510610b185fSBrian Somers r->next = NULL; 511610b185fSBrian Somers r->dst = dst; 512610b185fSBrian Somers r->mask = mask; 513610b185fSBrian Somers r->gw = gw; 514610b185fSBrian Somers *rp = r; 515610b185fSBrian Somers } 516610b185fSBrian Somers 517610b185fSBrian Somers void 518610b185fSBrian Somers route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 519610b185fSBrian Somers { 520610b185fSBrian Somers struct sticky_route *r; 521610b185fSBrian Somers int dsttype = type & ROUTE_DSTANY; 522610b185fSBrian Somers 523610b185fSBrian Somers for (; *rp; rp = &(*rp)->next) { 524610b185fSBrian Somers if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 525610b185fSBrian Somers (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 526610b185fSBrian Somers r = *rp; 527610b185fSBrian Somers *rp = r->next; 528610b185fSBrian Somers free(r); 529bcc332bdSBrian Somers break; 530bcc332bdSBrian Somers } 531bcc332bdSBrian Somers } 532bcc332bdSBrian Somers } 533bcc332bdSBrian Somers 534610b185fSBrian Somers void 535610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp) 536610b185fSBrian Somers { 537610b185fSBrian Somers struct sticky_route *r, *rn; 538610b185fSBrian Somers 539610b185fSBrian Somers for (r = *rp; r; r = rn) { 540610b185fSBrian Somers rn = r->next; 541610b185fSBrian Somers free(r); 542610b185fSBrian Somers } 543610b185fSBrian Somers *rp = NULL; 544610b185fSBrian Somers } 545610b185fSBrian Somers 546610b185fSBrian Somers void 547972a1bcfSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 548972a1bcfSBrian Somers int indent) 549610b185fSBrian Somers { 550610b185fSBrian Somers int def; 551972a1bcfSBrian Somers int tlen = strlen(tag); 552610b185fSBrian Somers 553972a1bcfSBrian Somers if (tlen + 2 > indent) 554972a1bcfSBrian Somers prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 555972a1bcfSBrian Somers else 556972a1bcfSBrian Somers prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 557972a1bcfSBrian Somers 558610b185fSBrian Somers for (; r; r = r->next) { 559610b185fSBrian Somers def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 560610b185fSBrian Somers 561972a1bcfSBrian Somers prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 562972a1bcfSBrian Somers tlen = 0; 563610b185fSBrian Somers if (r->type & ROUTE_DSTMYADDR) 564610b185fSBrian Somers prompt_Printf(p, "MYADDR"); 565610b185fSBrian Somers else if (r->type & ROUTE_DSTHISADDR) 566610b185fSBrian Somers prompt_Printf(p, "HISADDR"); 567610b185fSBrian Somers else if (!def) 568610b185fSBrian Somers prompt_Printf(p, "%s", inet_ntoa(r->dst)); 569610b185fSBrian Somers 570610b185fSBrian Somers if (def) 571610b185fSBrian Somers prompt_Printf(p, "default "); 572610b185fSBrian Somers else 573610b185fSBrian Somers prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 574610b185fSBrian Somers 575610b185fSBrian Somers if (r->type & ROUTE_GWHISADDR) 576610b185fSBrian Somers prompt_Printf(p, "HISADDR\n"); 577610b185fSBrian Somers else 578610b185fSBrian Somers prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 579610b185fSBrian Somers } 580bcc332bdSBrian Somers } 581