11ae349f5Scvs2svn /* 21ae349f5Scvs2svn * PPP Routing related Module 31ae349f5Scvs2svn * 41ae349f5Scvs2svn * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 51ae349f5Scvs2svn * 61ae349f5Scvs2svn * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 71ae349f5Scvs2svn * 81ae349f5Scvs2svn * Redistribution and use in source and binary forms are permitted 91ae349f5Scvs2svn * provided that the above copyright notice and this paragraph are 101ae349f5Scvs2svn * duplicated in all such forms and that any documentation, 111ae349f5Scvs2svn * advertising materials, and other materials related to such 121ae349f5Scvs2svn * distribution and use acknowledge that the software was developed 131ae349f5Scvs2svn * by the Internet Initiative Japan, Inc. The name of the 141ae349f5Scvs2svn * IIJ may not be used to endorse or promote products derived 151ae349f5Scvs2svn * from this software without specific prior written permission. 161ae349f5Scvs2svn * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 171ae349f5Scvs2svn * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 181ae349f5Scvs2svn * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 191ae349f5Scvs2svn * 208c07a7b2SBrian Somers * $Id: route.c,v 1.42.2.1 1998/01/29 23:11:42 brian Exp $ 211ae349f5Scvs2svn * 221ae349f5Scvs2svn */ 231ae349f5Scvs2svn 241ae349f5Scvs2svn #include <sys/param.h> 251ae349f5Scvs2svn #include <sys/time.h> 261ae349f5Scvs2svn #include <sys/socket.h> 271ae349f5Scvs2svn #include <net/if_types.h> 281ae349f5Scvs2svn #include <net/route.h> 291ae349f5Scvs2svn #include <net/if.h> 301ae349f5Scvs2svn #include <netinet/in.h> 311ae349f5Scvs2svn #include <arpa/inet.h> 321ae349f5Scvs2svn #include <net/if_dl.h> 331ae349f5Scvs2svn 341ae349f5Scvs2svn #include <errno.h> 351ae349f5Scvs2svn #include <machine/endian.h> 361ae349f5Scvs2svn #include <stdio.h> 371ae349f5Scvs2svn #include <stdlib.h> 381ae349f5Scvs2svn #include <string.h> 391ae349f5Scvs2svn #include <sys/ioctl.h> 401ae349f5Scvs2svn #include <sys/sysctl.h> 411ae349f5Scvs2svn #include <unistd.h> 421ae349f5Scvs2svn 431ae349f5Scvs2svn #include "command.h" 441ae349f5Scvs2svn #include "mbuf.h" 451ae349f5Scvs2svn #include "log.h" 461ae349f5Scvs2svn #include "loadalias.h" 471ae349f5Scvs2svn #include "defs.h" 481ae349f5Scvs2svn #include "vars.h" 491ae349f5Scvs2svn #include "id.h" 501ae349f5Scvs2svn #include "os.h" 511ae349f5Scvs2svn #include "iplist.h" 5229e275ceSBrian Somers #include "timer.h" 5329e275ceSBrian Somers #include "throughput.h" 548c07a7b2SBrian Somers #include "hdlc.h" 558c07a7b2SBrian Somers #include "link.h" 5629e275ceSBrian Somers #include "ipcp.h" 571ae349f5Scvs2svn #include "route.h" 581ae349f5Scvs2svn 591ae349f5Scvs2svn static int IfIndex; 601ae349f5Scvs2svn 611ae349f5Scvs2svn struct rtmsg { 621ae349f5Scvs2svn struct rt_msghdr m_rtm; 631ae349f5Scvs2svn char m_space[64]; 641ae349f5Scvs2svn }; 651ae349f5Scvs2svn 661ae349f5Scvs2svn static int seqno; 671ae349f5Scvs2svn 681ae349f5Scvs2svn void 691ae349f5Scvs2svn OsSetRoute(int cmd, 701ae349f5Scvs2svn struct in_addr dst, 711ae349f5Scvs2svn struct in_addr gateway, 721ae349f5Scvs2svn struct in_addr mask, 731ae349f5Scvs2svn int bang) 741ae349f5Scvs2svn { 751ae349f5Scvs2svn struct rtmsg rtmes; 761ae349f5Scvs2svn int s, nb, wb; 771ae349f5Scvs2svn char *cp; 781ae349f5Scvs2svn const char *cmdstr; 791ae349f5Scvs2svn struct sockaddr_in rtdata; 801ae349f5Scvs2svn 811ae349f5Scvs2svn if (bang) 821ae349f5Scvs2svn cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 831ae349f5Scvs2svn else 841ae349f5Scvs2svn cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 851ae349f5Scvs2svn s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 861ae349f5Scvs2svn if (s < 0) { 871ae349f5Scvs2svn LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 881ae349f5Scvs2svn return; 891ae349f5Scvs2svn } 901ae349f5Scvs2svn memset(&rtmes, '\0', sizeof rtmes); 911ae349f5Scvs2svn rtmes.m_rtm.rtm_version = RTM_VERSION; 921ae349f5Scvs2svn rtmes.m_rtm.rtm_type = cmd; 931ae349f5Scvs2svn rtmes.m_rtm.rtm_addrs = RTA_DST; 941ae349f5Scvs2svn rtmes.m_rtm.rtm_seq = ++seqno; 951ae349f5Scvs2svn rtmes.m_rtm.rtm_pid = getpid(); 961ae349f5Scvs2svn rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 971ae349f5Scvs2svn 981ae349f5Scvs2svn memset(&rtdata, '\0', sizeof rtdata); 991ae349f5Scvs2svn rtdata.sin_len = 16; 1001ae349f5Scvs2svn rtdata.sin_family = AF_INET; 1011ae349f5Scvs2svn rtdata.sin_port = 0; 1021ae349f5Scvs2svn rtdata.sin_addr = dst; 1031ae349f5Scvs2svn 1041ae349f5Scvs2svn cp = rtmes.m_space; 1051ae349f5Scvs2svn memcpy(cp, &rtdata, 16); 1061ae349f5Scvs2svn cp += 16; 1071ae349f5Scvs2svn if (cmd == RTM_ADD) 1081ae349f5Scvs2svn if (gateway.s_addr == INADDR_ANY) { 1091ae349f5Scvs2svn /* Add a route through the interface */ 1101ae349f5Scvs2svn struct sockaddr_dl dl; 1111ae349f5Scvs2svn const char *iname; 1121ae349f5Scvs2svn int ilen; 1131ae349f5Scvs2svn 1141ae349f5Scvs2svn iname = Index2Nam(IfIndex); 1151ae349f5Scvs2svn ilen = strlen(iname); 1161ae349f5Scvs2svn dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 1171ae349f5Scvs2svn dl.sdl_family = AF_LINK; 1181ae349f5Scvs2svn dl.sdl_index = IfIndex; 1191ae349f5Scvs2svn dl.sdl_type = 0; 1201ae349f5Scvs2svn dl.sdl_nlen = ilen; 1211ae349f5Scvs2svn dl.sdl_alen = 0; 1221ae349f5Scvs2svn dl.sdl_slen = 0; 1231ae349f5Scvs2svn strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 1241ae349f5Scvs2svn 1251ae349f5Scvs2svn memcpy(cp, &dl, dl.sdl_len); 1261ae349f5Scvs2svn cp += dl.sdl_len; 1271ae349f5Scvs2svn rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 1281ae349f5Scvs2svn } else { 1291ae349f5Scvs2svn rtdata.sin_addr = gateway; 1301ae349f5Scvs2svn memcpy(cp, &rtdata, 16); 1311ae349f5Scvs2svn cp += 16; 1321ae349f5Scvs2svn rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 1331ae349f5Scvs2svn } 1341ae349f5Scvs2svn 1351ae349f5Scvs2svn if (dst.s_addr == INADDR_ANY) 1361ae349f5Scvs2svn mask.s_addr = INADDR_ANY; 1371ae349f5Scvs2svn 1381ae349f5Scvs2svn if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 1391ae349f5Scvs2svn rtdata.sin_addr = mask; 1401ae349f5Scvs2svn memcpy(cp, &rtdata, 16); 1411ae349f5Scvs2svn cp += 16; 1421ae349f5Scvs2svn rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 1431ae349f5Scvs2svn } 1441ae349f5Scvs2svn 1451ae349f5Scvs2svn nb = cp - (char *) &rtmes; 1461ae349f5Scvs2svn rtmes.m_rtm.rtm_msglen = nb; 1471ae349f5Scvs2svn wb = ID0write(s, &rtmes, nb); 1481ae349f5Scvs2svn if (wb < 0) { 1491ae349f5Scvs2svn LogPrintf(LogTCPIP, "OsSetRoute failure:\n"); 1501ae349f5Scvs2svn LogPrintf(LogTCPIP, "OsSetRoute: Cmd = %s\n", cmd); 1511ae349f5Scvs2svn LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 1521ae349f5Scvs2svn LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 1531ae349f5Scvs2svn LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 1541ae349f5Scvs2svn failed: 1551ae349f5Scvs2svn if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 1561ae349f5Scvs2svn (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) 1571ae349f5Scvs2svn if (!bang) 1581ae349f5Scvs2svn LogPrintf(LogWARN, "Add route failed: %s already exists\n", 1591ae349f5Scvs2svn inet_ntoa(dst)); 1601ae349f5Scvs2svn else { 1611ae349f5Scvs2svn rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 1621ae349f5Scvs2svn if ((wb = ID0write(s, &rtmes, nb)) < 0) 1631ae349f5Scvs2svn goto failed; 1641ae349f5Scvs2svn } 1651ae349f5Scvs2svn else if (cmd == RTM_DELETE && 1661ae349f5Scvs2svn (rtmes.m_rtm.rtm_errno == ESRCH || 1671ae349f5Scvs2svn (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 1681ae349f5Scvs2svn if (!bang) 1691ae349f5Scvs2svn LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", 1701ae349f5Scvs2svn inet_ntoa(dst)); 1711ae349f5Scvs2svn } else if (rtmes.m_rtm.rtm_errno == 0) 1721ae349f5Scvs2svn LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 1731ae349f5Scvs2svn inet_ntoa(dst), strerror(errno)); 1741ae349f5Scvs2svn else 1751ae349f5Scvs2svn LogPrintf(LogWARN, "%s route failed: %s: %s\n", 1761ae349f5Scvs2svn cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 1771ae349f5Scvs2svn } 1781ae349f5Scvs2svn LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 1791ae349f5Scvs2svn wb, cmdstr, dst.s_addr, gateway.s_addr); 1801ae349f5Scvs2svn close(s); 1811ae349f5Scvs2svn } 1821ae349f5Scvs2svn 1831ae349f5Scvs2svn static void 1841ae349f5Scvs2svn p_sockaddr(struct sockaddr *phost, struct sockaddr *pmask, int width) 1851ae349f5Scvs2svn { 1861ae349f5Scvs2svn char buf[29]; 1871ae349f5Scvs2svn struct sockaddr_in *ihost = (struct sockaddr_in *)phost; 1881ae349f5Scvs2svn struct sockaddr_in *mask = (struct sockaddr_in *)pmask; 1891ae349f5Scvs2svn struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 1901ae349f5Scvs2svn 1911ae349f5Scvs2svn switch (phost->sa_family) { 1921ae349f5Scvs2svn case AF_INET: 1931ae349f5Scvs2svn if (!phost) 1941ae349f5Scvs2svn buf[0] = '\0'; 1951ae349f5Scvs2svn else if (ihost->sin_addr.s_addr == INADDR_ANY) 1961ae349f5Scvs2svn strcpy(buf, "default"); 1971ae349f5Scvs2svn else if (!mask) 1981ae349f5Scvs2svn strcpy(buf, inet_ntoa(ihost->sin_addr)); 1991ae349f5Scvs2svn else { 2001ae349f5Scvs2svn u_int msk = ntohl(mask->sin_addr.s_addr); 2011ae349f5Scvs2svn u_int tst; 2021ae349f5Scvs2svn int bits; 2031ae349f5Scvs2svn int len; 2041ae349f5Scvs2svn struct sockaddr_in net; 2051ae349f5Scvs2svn 2061ae349f5Scvs2svn for (tst = 1, bits=32; tst; tst <<= 1, bits--) 2071ae349f5Scvs2svn if (msk & tst) 2081ae349f5Scvs2svn break; 2091ae349f5Scvs2svn 2101ae349f5Scvs2svn for (tst <<=1; tst; tst <<= 1) 2111ae349f5Scvs2svn if (!(msk & tst)) 2121ae349f5Scvs2svn break; 2131ae349f5Scvs2svn 2141ae349f5Scvs2svn net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr; 2151ae349f5Scvs2svn strcpy(buf, inet_ntoa(net.sin_addr)); 2161ae349f5Scvs2svn for (len = strlen(buf); len > 3; buf[len-=2] = '\0') 2171ae349f5Scvs2svn if (strcmp(buf+len-2, ".0")) 2181ae349f5Scvs2svn break; 2191ae349f5Scvs2svn 2201ae349f5Scvs2svn if (tst) /* non-contiguous :-( */ 2211ae349f5Scvs2svn sprintf(buf+strlen(buf),"&0x%08x", msk); 2221ae349f5Scvs2svn else 2231ae349f5Scvs2svn sprintf(buf+strlen(buf), "/%d", bits); 2241ae349f5Scvs2svn } 2251ae349f5Scvs2svn break; 2261ae349f5Scvs2svn 2271ae349f5Scvs2svn case AF_LINK: 2281ae349f5Scvs2svn if (dl->sdl_nlen) 2291ae349f5Scvs2svn snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 2301ae349f5Scvs2svn else if (dl->sdl_alen) 2311ae349f5Scvs2svn if (dl->sdl_type == IFT_ETHER) 2321ae349f5Scvs2svn if (dl->sdl_alen < sizeof buf / 3) { 2331ae349f5Scvs2svn int f; 2341ae349f5Scvs2svn u_char *MAC; 2351ae349f5Scvs2svn 2361ae349f5Scvs2svn MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 2371ae349f5Scvs2svn for (f = 0; f < dl->sdl_alen; f++) 2381ae349f5Scvs2svn sprintf(buf+f*3, "%02x:", MAC[f]); 2391ae349f5Scvs2svn buf[f*3-1] = '\0'; 2401ae349f5Scvs2svn } else 2411ae349f5Scvs2svn strcpy(buf, "??:??:??:??:??:??"); 2421ae349f5Scvs2svn else 2431ae349f5Scvs2svn sprintf(buf, "<IFT type %d>", dl->sdl_type); 2441ae349f5Scvs2svn else if (dl->sdl_slen) 2451ae349f5Scvs2svn sprintf(buf, "<slen %d?>", dl->sdl_slen); 2461ae349f5Scvs2svn else 2471ae349f5Scvs2svn sprintf(buf, "link#%d", dl->sdl_index); 2481ae349f5Scvs2svn break; 2491ae349f5Scvs2svn 2501ae349f5Scvs2svn default: 2511ae349f5Scvs2svn sprintf(buf, "<AF type %d>", phost->sa_family); 2521ae349f5Scvs2svn break; 2531ae349f5Scvs2svn } 2541ae349f5Scvs2svn 2551ae349f5Scvs2svn fprintf(VarTerm, "%-*s ", width-1, buf); 2561ae349f5Scvs2svn } 2571ae349f5Scvs2svn 2581ae349f5Scvs2svn static struct bits { 2591ae349f5Scvs2svn u_long b_mask; 2601ae349f5Scvs2svn char b_val; 2611ae349f5Scvs2svn } bits[] = { 2621ae349f5Scvs2svn { RTF_UP, 'U' }, 2631ae349f5Scvs2svn { RTF_GATEWAY, 'G' }, 2641ae349f5Scvs2svn { RTF_HOST, 'H' }, 2651ae349f5Scvs2svn { RTF_REJECT, 'R' }, 2661ae349f5Scvs2svn { RTF_DYNAMIC, 'D' }, 2671ae349f5Scvs2svn { RTF_MODIFIED, 'M' }, 2681ae349f5Scvs2svn { RTF_DONE, 'd' }, 2691ae349f5Scvs2svn { RTF_CLONING, 'C' }, 2701ae349f5Scvs2svn { RTF_XRESOLVE, 'X' }, 2711ae349f5Scvs2svn { RTF_LLINFO, 'L' }, 2721ae349f5Scvs2svn { RTF_STATIC, 'S' }, 2731ae349f5Scvs2svn { RTF_PROTO1, '1' }, 2741ae349f5Scvs2svn { RTF_PROTO2, '2' }, 2751ae349f5Scvs2svn { RTF_BLACKHOLE, 'B' }, 2761ae349f5Scvs2svn #ifdef RTF_WASCLONED 2771ae349f5Scvs2svn { RTF_WASCLONED, 'W' }, 2781ae349f5Scvs2svn #endif 2791ae349f5Scvs2svn #ifdef RTF_PRCLONING 2801ae349f5Scvs2svn { RTF_PRCLONING, 'c' }, 2811ae349f5Scvs2svn #endif 2821ae349f5Scvs2svn #ifdef RTF_PROTO3 2831ae349f5Scvs2svn { RTF_PROTO3, '3' }, 2841ae349f5Scvs2svn #endif 2851ae349f5Scvs2svn #ifdef RTF_BROADCAST 2861ae349f5Scvs2svn { RTF_BROADCAST, 'b' }, 2871ae349f5Scvs2svn #endif 2881ae349f5Scvs2svn { 0, '\0' } 2891ae349f5Scvs2svn }; 2901ae349f5Scvs2svn 2911ae349f5Scvs2svn #ifndef RTF_WASCLONED 2921ae349f5Scvs2svn #define RTF_WASCLONED (0) 2931ae349f5Scvs2svn #endif 2941ae349f5Scvs2svn 2951ae349f5Scvs2svn static void 2961ae349f5Scvs2svn p_flags(u_long f, int max) 2971ae349f5Scvs2svn { 2981ae349f5Scvs2svn if (VarTerm) { 2991ae349f5Scvs2svn char name[33], *flags; 3001ae349f5Scvs2svn register struct bits *p = bits; 3011ae349f5Scvs2svn 3021ae349f5Scvs2svn if (max > sizeof name - 1) 3031ae349f5Scvs2svn max = sizeof name - 1; 3041ae349f5Scvs2svn 3051ae349f5Scvs2svn for (flags = name; p->b_mask && flags - name < max; p++) 3061ae349f5Scvs2svn if (p->b_mask & f) 3071ae349f5Scvs2svn *flags++ = p->b_val; 3081ae349f5Scvs2svn *flags = '\0'; 3091ae349f5Scvs2svn fprintf(VarTerm, "%-*.*s", max, max, name); 3101ae349f5Scvs2svn } 3111ae349f5Scvs2svn } 3121ae349f5Scvs2svn 3131ae349f5Scvs2svn const char * 3141ae349f5Scvs2svn Index2Nam(int idx) 3151ae349f5Scvs2svn { 3161ae349f5Scvs2svn static char **ifs; 3171ae349f5Scvs2svn static int nifs, debug_done; 3181ae349f5Scvs2svn 3191ae349f5Scvs2svn if (!nifs) { 3201ae349f5Scvs2svn int mib[6], have, had; 3211ae349f5Scvs2svn size_t needed; 3221ae349f5Scvs2svn char *buf, *ptr, *end; 3231ae349f5Scvs2svn struct sockaddr_dl *dl; 3241ae349f5Scvs2svn struct if_msghdr *ifm; 3251ae349f5Scvs2svn 3261ae349f5Scvs2svn mib[0] = CTL_NET; 3271ae349f5Scvs2svn mib[1] = PF_ROUTE; 3281ae349f5Scvs2svn mib[2] = 0; 3291ae349f5Scvs2svn mib[3] = 0; 3301ae349f5Scvs2svn mib[4] = NET_RT_IFLIST; 3311ae349f5Scvs2svn mib[5] = 0; 3321ae349f5Scvs2svn 3331ae349f5Scvs2svn if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 3341ae349f5Scvs2svn LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); 3351ae349f5Scvs2svn return "???"; 3361ae349f5Scvs2svn } 3371ae349f5Scvs2svn if ((buf = malloc(needed)) == NULL) 3381ae349f5Scvs2svn return "???"; 3391ae349f5Scvs2svn if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 3401ae349f5Scvs2svn free(buf); 3411ae349f5Scvs2svn return "???"; 3421ae349f5Scvs2svn } 3431ae349f5Scvs2svn end = buf + needed; 3441ae349f5Scvs2svn 3451ae349f5Scvs2svn have = 0; 3461ae349f5Scvs2svn for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 3471ae349f5Scvs2svn ifm = (struct if_msghdr *)ptr; 3481ae349f5Scvs2svn dl = (struct sockaddr_dl *)(ifm + 1); 3491ae349f5Scvs2svn if (ifm->ifm_index > 0) { 3501ae349f5Scvs2svn if (ifm->ifm_index > have) { 3511ae349f5Scvs2svn had = have; 3521ae349f5Scvs2svn have = ifm->ifm_index + 5; 3531ae349f5Scvs2svn if (had) 3541ae349f5Scvs2svn ifs = (char **)realloc(ifs, sizeof(char *) * have); 3551ae349f5Scvs2svn else 3561ae349f5Scvs2svn ifs = (char **)malloc(sizeof(char *) * have); 3571ae349f5Scvs2svn if (!ifs) { 3581ae349f5Scvs2svn LogPrintf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 3591ae349f5Scvs2svn nifs = 0; 3601ae349f5Scvs2svn return "???"; 3611ae349f5Scvs2svn } 3621ae349f5Scvs2svn memset(ifs + had, '\0', sizeof(char *) * (have - had)); 3631ae349f5Scvs2svn } 3641ae349f5Scvs2svn if (ifs[ifm->ifm_index-1] == NULL) { 3651ae349f5Scvs2svn ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 3661ae349f5Scvs2svn memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 3671ae349f5Scvs2svn ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 3681ae349f5Scvs2svn if (nifs < ifm->ifm_index) 3691ae349f5Scvs2svn nifs = ifm->ifm_index; 3701ae349f5Scvs2svn } 3711ae349f5Scvs2svn } else if (LogIsKept(LogDEBUG)) 3721ae349f5Scvs2svn LogPrintf(LogDEBUG, "Skipping out-of-range interface %d!\n", 3731ae349f5Scvs2svn ifm->ifm_index); 3741ae349f5Scvs2svn } 3751ae349f5Scvs2svn free(buf); 3761ae349f5Scvs2svn } 3771ae349f5Scvs2svn 3781ae349f5Scvs2svn if (LogIsKept(LogDEBUG) && !debug_done) { 3791ae349f5Scvs2svn int f; 3801ae349f5Scvs2svn 3811ae349f5Scvs2svn LogPrintf(LogDEBUG, "Found the following interfaces:\n"); 3821ae349f5Scvs2svn for (f = 0; f < nifs; f++) 3831ae349f5Scvs2svn if (ifs[f] != NULL) 3841ae349f5Scvs2svn LogPrintf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 3851ae349f5Scvs2svn debug_done = 1; 3861ae349f5Scvs2svn } 3871ae349f5Scvs2svn 3881ae349f5Scvs2svn if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 3891ae349f5Scvs2svn return "???"; 3901ae349f5Scvs2svn 3911ae349f5Scvs2svn return ifs[idx-1]; 3921ae349f5Scvs2svn } 3931ae349f5Scvs2svn 3941ae349f5Scvs2svn int 3951ae349f5Scvs2svn ShowRoute(struct cmdargs const *arg) 3961ae349f5Scvs2svn { 3971ae349f5Scvs2svn struct rt_msghdr *rtm; 3981ae349f5Scvs2svn struct sockaddr *sa_dst, *sa_gw, *sa_mask; 3991ae349f5Scvs2svn char *sp, *ep, *cp, *wp; 4001ae349f5Scvs2svn size_t needed; 4011ae349f5Scvs2svn int mib[6]; 4021ae349f5Scvs2svn 4031ae349f5Scvs2svn if (!VarTerm) 4041ae349f5Scvs2svn return 1; 4051ae349f5Scvs2svn 4061ae349f5Scvs2svn mib[0] = CTL_NET; 4071ae349f5Scvs2svn mib[1] = PF_ROUTE; 4081ae349f5Scvs2svn mib[2] = 0; 4091ae349f5Scvs2svn mib[3] = 0; 4101ae349f5Scvs2svn mib[4] = NET_RT_DUMP; 4111ae349f5Scvs2svn mib[5] = 0; 4121ae349f5Scvs2svn if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 4131ae349f5Scvs2svn LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 4141ae349f5Scvs2svn return (1); 4151ae349f5Scvs2svn } 4161ae349f5Scvs2svn if (needed < 0) 4171ae349f5Scvs2svn return (1); 4181ae349f5Scvs2svn sp = malloc(needed); 4191ae349f5Scvs2svn if (sp == NULL) 4201ae349f5Scvs2svn return (1); 4211ae349f5Scvs2svn if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 4221ae349f5Scvs2svn LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 4231ae349f5Scvs2svn free(sp); 4241ae349f5Scvs2svn return (1); 4251ae349f5Scvs2svn } 4261ae349f5Scvs2svn ep = sp + needed; 4271ae349f5Scvs2svn 4281ae349f5Scvs2svn fprintf(VarTerm, "%-20s%-20sFlags Netif\n", "Destination", "Gateway"); 4291ae349f5Scvs2svn for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 4301ae349f5Scvs2svn rtm = (struct rt_msghdr *) cp; 4311ae349f5Scvs2svn wp = (char *)(rtm+1); 4321ae349f5Scvs2svn 4331ae349f5Scvs2svn if (rtm->rtm_addrs & RTA_DST) { 4341ae349f5Scvs2svn sa_dst = (struct sockaddr *)wp; 4351ae349f5Scvs2svn wp += sa_dst->sa_len; 4361ae349f5Scvs2svn } else 4371ae349f5Scvs2svn sa_dst = NULL; 4381ae349f5Scvs2svn 4391ae349f5Scvs2svn if (rtm->rtm_addrs & RTA_GATEWAY) { 4401ae349f5Scvs2svn sa_gw = (struct sockaddr *)wp; 4411ae349f5Scvs2svn wp += sa_gw->sa_len; 4421ae349f5Scvs2svn } else 4431ae349f5Scvs2svn sa_gw = NULL; 4441ae349f5Scvs2svn 4451ae349f5Scvs2svn if (rtm->rtm_addrs & RTA_NETMASK) { 4461ae349f5Scvs2svn sa_mask = (struct sockaddr *)wp; 4471ae349f5Scvs2svn wp += sa_mask->sa_len; 4481ae349f5Scvs2svn } else 4491ae349f5Scvs2svn sa_mask = NULL; 4501ae349f5Scvs2svn 4511ae349f5Scvs2svn p_sockaddr(sa_dst, sa_mask, 20); 4521ae349f5Scvs2svn p_sockaddr(sa_gw, NULL, 20); 4531ae349f5Scvs2svn 4541ae349f5Scvs2svn p_flags(rtm->rtm_flags, 6); 4551ae349f5Scvs2svn fprintf(VarTerm, " %s\n", Index2Nam(rtm->rtm_index)); 4561ae349f5Scvs2svn } 4571ae349f5Scvs2svn free(sp); 4581ae349f5Scvs2svn return 0; 4591ae349f5Scvs2svn } 4601ae349f5Scvs2svn 4611ae349f5Scvs2svn /* 4621ae349f5Scvs2svn * Delete routes associated with our interface 4631ae349f5Scvs2svn */ 4641ae349f5Scvs2svn void 4651ae349f5Scvs2svn DeleteIfRoutes(int all) 4661ae349f5Scvs2svn { 4671ae349f5Scvs2svn struct rt_msghdr *rtm; 4681ae349f5Scvs2svn struct sockaddr *sa; 4691ae349f5Scvs2svn struct in_addr sa_dst, sa_none; 4701ae349f5Scvs2svn int pass; 4711ae349f5Scvs2svn size_t needed; 4721ae349f5Scvs2svn char *sp, *cp, *ep; 4731ae349f5Scvs2svn int mib[6]; 4741ae349f5Scvs2svn 4751ae349f5Scvs2svn LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 4761ae349f5Scvs2svn sa_none.s_addr = INADDR_ANY; 4771ae349f5Scvs2svn 4781ae349f5Scvs2svn mib[0] = CTL_NET; 4791ae349f5Scvs2svn mib[1] = PF_ROUTE; 4801ae349f5Scvs2svn mib[2] = 0; 4811ae349f5Scvs2svn mib[3] = 0; 4821ae349f5Scvs2svn mib[4] = NET_RT_DUMP; 4831ae349f5Scvs2svn mib[5] = 0; 4841ae349f5Scvs2svn if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 4851ae349f5Scvs2svn LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 4861ae349f5Scvs2svn strerror(errno)); 4871ae349f5Scvs2svn return; 4881ae349f5Scvs2svn } 4891ae349f5Scvs2svn if (needed < 0) 4901ae349f5Scvs2svn return; 4911ae349f5Scvs2svn 4921ae349f5Scvs2svn sp = malloc(needed); 4931ae349f5Scvs2svn if (sp == NULL) 4941ae349f5Scvs2svn return; 4951ae349f5Scvs2svn 4961ae349f5Scvs2svn if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 4971ae349f5Scvs2svn LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 4981ae349f5Scvs2svn strerror(errno)); 4991ae349f5Scvs2svn free(sp); 5001ae349f5Scvs2svn return; 5011ae349f5Scvs2svn } 5021ae349f5Scvs2svn ep = sp + needed; 5031ae349f5Scvs2svn 5041ae349f5Scvs2svn for (pass = 0; pass < 2; pass++) { 5051ae349f5Scvs2svn /* 5061ae349f5Scvs2svn * We do 2 passes. The first deletes all cloned routes. The second 5071ae349f5Scvs2svn * deletes all non-cloned routes. This is necessary to avoid 5081ae349f5Scvs2svn * potential errors from trying to delete route X after route Y where 5091ae349f5Scvs2svn * route X was cloned from route Y (which is no longer there). 5101ae349f5Scvs2svn */ 5111ae349f5Scvs2svn if (RTF_WASCLONED == 0 && pass == 0) 5121ae349f5Scvs2svn /* So we can't tell ! */ 5131ae349f5Scvs2svn continue; 5141ae349f5Scvs2svn for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 5151ae349f5Scvs2svn rtm = (struct rt_msghdr *) cp; 5161ae349f5Scvs2svn sa = (struct sockaddr *) (rtm + 1); 5171ae349f5Scvs2svn LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, Netif: %d (%s)," 5181ae349f5Scvs2svn " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 5191ae349f5Scvs2svn Index2Nam(rtm->rtm_index), rtm->rtm_flags, 5201ae349f5Scvs2svn inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 5211ae349f5Scvs2svn if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY && 5221ae349f5Scvs2svn rtm->rtm_index == IfIndex && 5231ae349f5Scvs2svn (all || (rtm->rtm_flags & RTF_GATEWAY))) { 5241ae349f5Scvs2svn sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 5251ae349f5Scvs2svn sa = (struct sockaddr *)((char *)sa + sa->sa_len); 5261ae349f5Scvs2svn if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) { 5271ae349f5Scvs2svn if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 5281ae349f5Scvs2svn (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 5291ae349f5Scvs2svn LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it (pass %d)\n", pass); 5301ae349f5Scvs2svn OsSetRoute(RTM_DELETE, sa_dst, sa_none, sa_none, 0); 5311ae349f5Scvs2svn } else 5321ae349f5Scvs2svn LogPrintf(LogDEBUG, "DeleteIfRoutes: Skip it (pass %d)\n", pass); 5331ae349f5Scvs2svn } else 5341ae349f5Scvs2svn LogPrintf(LogDEBUG, 5351ae349f5Scvs2svn "DeleteIfRoutes: Can't remove routes of %d family !\n", 5361ae349f5Scvs2svn sa->sa_family); 5371ae349f5Scvs2svn } 5381ae349f5Scvs2svn } 5391ae349f5Scvs2svn } 5401ae349f5Scvs2svn free(sp); 5411ae349f5Scvs2svn } 5421ae349f5Scvs2svn 5431ae349f5Scvs2svn int 5441ae349f5Scvs2svn GetIfIndex(char *name) 5451ae349f5Scvs2svn { 5461ae349f5Scvs2svn int idx; 5471ae349f5Scvs2svn const char *got; 5481ae349f5Scvs2svn 5491ae349f5Scvs2svn idx = 1; 5501ae349f5Scvs2svn while (strcmp(got = Index2Nam(idx), "???")) 5511ae349f5Scvs2svn if (!strcmp(got, name)) 5521ae349f5Scvs2svn return IfIndex = idx; 5531ae349f5Scvs2svn else 5541ae349f5Scvs2svn idx++; 5551ae349f5Scvs2svn return -1; 5561ae349f5Scvs2svn } 5571ae349f5Scvs2svn 5581ae349f5Scvs2svn struct in_addr 5591ae349f5Scvs2svn ChooseHisAddr(const struct in_addr gw) 5601ae349f5Scvs2svn { 5611ae349f5Scvs2svn struct in_addr try; 5621ae349f5Scvs2svn int f; 5631ae349f5Scvs2svn 56429e275ceSBrian Somers for (f = 0; f < IpcpInfo.DefHisChoice.nItems; f++) { 56529e275ceSBrian Somers try = iplist_next(&IpcpInfo.DefHisChoice); 5661ae349f5Scvs2svn LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n", 5671ae349f5Scvs2svn f, inet_ntoa(try)); 5681ae349f5Scvs2svn if (OsTrySetIpaddress(gw, try) == 0) { 5691ae349f5Scvs2svn LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n", 5701ae349f5Scvs2svn inet_ntoa(try)); 5711ae349f5Scvs2svn break; 5721ae349f5Scvs2svn } 5731ae349f5Scvs2svn } 5741ae349f5Scvs2svn 57529e275ceSBrian Somers if (f == IpcpInfo.DefHisChoice.nItems) { 5761ae349f5Scvs2svn LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 5771ae349f5Scvs2svn try.s_addr = INADDR_ANY; 5781ae349f5Scvs2svn } 5791ae349f5Scvs2svn 5801ae349f5Scvs2svn return try; 5811ae349f5Scvs2svn } 582