route.c revision 58044
16059Samurai/* 26059Samurai * PPP Routing related Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2050479Speter * $FreeBSD: head/usr.sbin/ppp/route.c 58044 2000-03-14 01:47:27Z brian $ 218857Srgrimes * 226059Samurai */ 2330715Sbrian 2443313Sbrian#include <sys/param.h> 256059Samurai#include <sys/socket.h> 2631176Sbrian#include <net/if_types.h> 2730715Sbrian#include <net/route.h> 2830715Sbrian#include <net/if.h> 2930715Sbrian#include <netinet/in.h> 3030715Sbrian#include <arpa/inet.h> 3131176Sbrian#include <net/if_dl.h> 3236285Sbrian#include <netinet/in_systm.h> 3336285Sbrian#include <netinet/ip.h> 3436285Sbrian#include <sys/un.h> 3558031Sbrian#include <netdb.h> 3620287Swollman 3720287Swollman#include <errno.h> 3830715Sbrian#include <stdio.h> 396059Samurai#include <stdlib.h> 406059Samurai#include <string.h> 4130715Sbrian#include <sys/sysctl.h> 4236285Sbrian#include <termios.h> 4320287Swollman 4446686Sbrian#include "layer.h" 4537009Sbrian#include "defs.h" 4631343Sbrian#include "command.h" 4730715Sbrian#include "mbuf.h" 489439Samurai#include "log.h" 4936285Sbrian#include "iplist.h" 5036285Sbrian#include "timer.h" 5136285Sbrian#include "throughput.h" 5236285Sbrian#include "lqr.h" 5336285Sbrian#include "hdlc.h" 5436285Sbrian#include "fsm.h" 5536285Sbrian#include "lcp.h" 5636285Sbrian#include "ccp.h" 5736285Sbrian#include "link.h" 5836285Sbrian#include "slcompress.h" 5931690Sbrian#include "ipcp.h" 6036285Sbrian#include "filter.h" 6136285Sbrian#include "descriptor.h" 6236285Sbrian#include "mp.h" 6343313Sbrian#ifndef NORADIUS 6443313Sbrian#include "radius.h" 6543313Sbrian#endif 6636285Sbrian#include "bundle.h" 6730715Sbrian#include "route.h" 6836285Sbrian#include "prompt.h" 6940561Sbrian#include "iface.h" 706059Samurai 7158032Sbrian 726059Samuraistatic void 7336285Sbrianp_sockaddr(struct prompt *prompt, struct sockaddr *phost, 7436285Sbrian struct sockaddr *pmask, int width) 756059Samurai{ 7631343Sbrian char buf[29]; 7758031Sbrian struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 7858031Sbrian struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 7931176Sbrian struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 806059Samurai 8158031Sbrian if (log_IsKept(LogDEBUG)) { 8258031Sbrian char tmp[50]; 8358031Sbrian 8458031Sbrian log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 8558031Sbrian log_Printf(LogDEBUG, " Family %d, len %d\n", 8658031Sbrian (int)phost->sa_family, (int)phost->sa_len); 8758032Sbrian inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 8858031Sbrian log_Printf(LogDEBUG, " Addr %s\n", tmp); 8958031Sbrian if (pmask) { 9058032Sbrian inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 9158031Sbrian log_Printf(LogDEBUG, " Mask %s\n", tmp); 9258031Sbrian } 9358031Sbrian } 9458031Sbrian 9531176Sbrian switch (phost->sa_family) { 9631176Sbrian case AF_INET: 9731176Sbrian if (!phost) 9831541Sbrian buf[0] = '\0'; 9958031Sbrian else if (ihost4->sin_addr.s_addr == INADDR_ANY) 10031541Sbrian strcpy(buf, "default"); 10158031Sbrian else if (!pmask) 10258031Sbrian strcpy(buf, inet_ntoa(ihost4->sin_addr)); 10331176Sbrian else { 10458031Sbrian u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 10537210Sbrian u_int32_t tst; 10631176Sbrian int bits; 10731176Sbrian int len; 10831176Sbrian struct sockaddr_in net; 10931176Sbrian 11058031Sbrian for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 11131176Sbrian if (msk & tst) 11231176Sbrian break; 11331176Sbrian 11437210Sbrian for (tst <<= 1; tst; tst <<= 1) 11531176Sbrian if (!(msk & tst)) 11631176Sbrian break; 11731176Sbrian 11858031Sbrian net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 11931791Sbrian strcpy(buf, inet_ntoa(net.sin_addr)); 12037210Sbrian for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 12137210Sbrian if (strcmp(buf + len - 2, ".0")) 12231176Sbrian break; 12331176Sbrian 12431176Sbrian if (tst) /* non-contiguous :-( */ 12537210Sbrian sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 12631176Sbrian else 12737210Sbrian sprintf(buf + strlen(buf), "/%d", bits); 12831176Sbrian } 12931176Sbrian break; 13031176Sbrian 13131176Sbrian case AF_LINK: 13231541Sbrian if (dl->sdl_nlen) 13331541Sbrian snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 13434536Sbrian else if (dl->sdl_alen) { 13534536Sbrian if (dl->sdl_type == IFT_ETHER) { 13631962Sbrian if (dl->sdl_alen < sizeof buf / 3) { 13731541Sbrian int f; 13831541Sbrian u_char *MAC; 13931541Sbrian 14031541Sbrian MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 14131541Sbrian for (f = 0; f < dl->sdl_alen; f++) 14231541Sbrian sprintf(buf+f*3, "%02x:", MAC[f]); 14331541Sbrian buf[f*3-1] = '\0'; 14431541Sbrian } else 14531791Sbrian strcpy(buf, "??:??:??:??:??:??"); 14634536Sbrian } else 14731541Sbrian sprintf(buf, "<IFT type %d>", dl->sdl_type); 14836285Sbrian } else if (dl->sdl_slen) 14931541Sbrian sprintf(buf, "<slen %d?>", dl->sdl_slen); 15031541Sbrian else 15131176Sbrian sprintf(buf, "link#%d", dl->sdl_index); 15231176Sbrian break; 15331176Sbrian 15458031Sbrian#ifndef NOINET6 15558031Sbrian case AF_INET6: 15658031Sbrian if (!phost) 15758031Sbrian buf[0] = '\0'; 15858031Sbrian else { 15958031Sbrian const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 16058031Sbrian struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 16158031Sbrian struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 16258031Sbrian int masklen, len; 16358031Sbrian const u_char *c; 16458031Sbrian 16558031Sbrian /* XXX: ?????!?!?!!!!! This is horrible ! */ 16658031Sbrian if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 16758031Sbrian IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 16858031Sbrian ihost6->sin6_scope_id = 16958031Sbrian ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 17058031Sbrian *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 17158031Sbrian } 17258031Sbrian 17358031Sbrian if (mask6) { 17458031Sbrian const u_char *p, *end; 17558031Sbrian 17658031Sbrian p = (const u_char *)&mask6->sin6_addr; 17758031Sbrian end = p + 16; 17858031Sbrian for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 17958031Sbrian masklen += 8; 18058031Sbrian 18158031Sbrian if (p < end) { 18258031Sbrian for (c = masks; c < masks + sizeof masks; c++) 18358031Sbrian if (*c == *p) { 18458031Sbrian masklen += c - masks; 18558031Sbrian break; 18658031Sbrian } 18758031Sbrian } 18858031Sbrian } else 18958031Sbrian masklen = 128; 19058031Sbrian 19158031Sbrian if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 19258031Sbrian snprintf(buf, sizeof buf, "default"); 19358031Sbrian else { 19458031Sbrian getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 19558031Sbrian NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 19658031Sbrian if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 19758031Sbrian snprintf(buf + len, sizeof buf - len, "/%d", masklen); 19858031Sbrian } 19958031Sbrian } 20058031Sbrian break; 20158031Sbrian#endif 20258031Sbrian 20331176Sbrian default: 20431541Sbrian sprintf(buf, "<AF type %d>", phost->sa_family); 20531176Sbrian break; 20626516Sbrian } 20731176Sbrian 20836285Sbrian prompt_Printf(prompt, "%-*s ", width-1, buf); 2096059Samurai} 2106059Samurai 21132663Sbrianstatic struct bits { 21237189Sbrian u_int32_t b_mask; 21328679Sbrian char b_val; 21431176Sbrian} bits[] = { 21531176Sbrian { RTF_UP, 'U' }, 21631176Sbrian { RTF_GATEWAY, 'G' }, 21731176Sbrian { RTF_HOST, 'H' }, 21831176Sbrian { RTF_REJECT, 'R' }, 21931176Sbrian { RTF_DYNAMIC, 'D' }, 22031176Sbrian { RTF_MODIFIED, 'M' }, 22131176Sbrian { RTF_DONE, 'd' }, 22231176Sbrian { RTF_CLONING, 'C' }, 22331176Sbrian { RTF_XRESOLVE, 'X' }, 22431176Sbrian { RTF_LLINFO, 'L' }, 22531176Sbrian { RTF_STATIC, 'S' }, 22631176Sbrian { RTF_PROTO1, '1' }, 22731176Sbrian { RTF_PROTO2, '2' }, 22831176Sbrian { RTF_BLACKHOLE, 'B' }, 22931739Sbrian#ifdef RTF_WASCLONED 23031176Sbrian { RTF_WASCLONED, 'W' }, 23131739Sbrian#endif 23231739Sbrian#ifdef RTF_PRCLONING 23331176Sbrian { RTF_PRCLONING, 'c' }, 23431739Sbrian#endif 23531739Sbrian#ifdef RTF_PROTO3 23631176Sbrian { RTF_PROTO3, '3' }, 23731739Sbrian#endif 23831739Sbrian#ifdef RTF_BROADCAST 23931176Sbrian { RTF_BROADCAST, 'b' }, 24031176Sbrian#endif 24131176Sbrian { 0, '\0' } 2426059Samurai}; 2436059Samurai 24431739Sbrian#ifndef RTF_WASCLONED 24531739Sbrian#define RTF_WASCLONED (0) 24631739Sbrian#endif 24731739Sbrian 2486059Samuraistatic void 24937189Sbrianp_flags(struct prompt *prompt, u_int32_t f, int max) 2506059Samurai{ 25136285Sbrian char name[33], *flags; 25236285Sbrian register struct bits *p = bits; 2536059Samurai 25436285Sbrian if (max > sizeof name - 1) 25536285Sbrian max = sizeof name - 1; 25631827Sbrian 25736285Sbrian for (flags = name; p->b_mask && flags - name < max; p++) 25836285Sbrian if (p->b_mask & f) 25936285Sbrian *flags++ = p->b_val; 26036285Sbrian *flags = '\0'; 26136285Sbrian prompt_Printf(prompt, "%-*.*s", max, max, name); 2626059Samurai} 2636059Samurai 26432616Sbrianconst char * 26531176SbrianIndex2Nam(int idx) 26631176Sbrian{ 26737010Sbrian /* 26837010Sbrian * XXX: Maybe we should select() on the routing socket so that we can 26937010Sbrian * notice interfaces that come & go (PCCARD support). 27037010Sbrian * Or we could even support a signal that resets these so that 27137010Sbrian * the PCCARD insert/remove events can signal ppp. 27237010Sbrian */ 27337010Sbrian static char **ifs; /* Figure these out once */ 27437010Sbrian static int nifs, debug_done; /* Figure out how many once, and debug once */ 27531176Sbrian 27650427Sbrian if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 27732425Sbrian int mib[6], have, had; 27832021Sbrian size_t needed; 27931176Sbrian char *buf, *ptr, *end; 28031176Sbrian struct sockaddr_dl *dl; 28131176Sbrian struct if_msghdr *ifm; 28231176Sbrian 28350427Sbrian if (ifs) { 28450427Sbrian free(ifs); 28550427Sbrian ifs = NULL; 28650427Sbrian nifs = 0; 28750427Sbrian } 28850427Sbrian debug_done = 0; 28950427Sbrian 29031176Sbrian mib[0] = CTL_NET; 29131176Sbrian mib[1] = PF_ROUTE; 29231176Sbrian mib[2] = 0; 29331176Sbrian mib[3] = 0; 29431176Sbrian mib[4] = NET_RT_IFLIST; 29531176Sbrian mib[5] = 0; 29631176Sbrian 29731176Sbrian if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 29837019Sbrian log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 29937019Sbrian strerror(errno)); 30058034Sbrian return NumStr(idx, NULL, 0); 30131176Sbrian } 30231176Sbrian if ((buf = malloc(needed)) == NULL) 30358034Sbrian return NumStr(idx, NULL, 0); 30431176Sbrian if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 30531176Sbrian free(buf); 30658034Sbrian return NumStr(idx, NULL, 0); 30731176Sbrian } 30831176Sbrian end = buf + needed; 30931176Sbrian 31032425Sbrian have = 0; 31131354Sbrian for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 31231176Sbrian ifm = (struct if_msghdr *)ptr; 31358032Sbrian if (ifm->ifm_type != RTM_IFINFO) 31458035Sbrian continue; 31531176Sbrian dl = (struct sockaddr_dl *)(ifm + 1); 31632425Sbrian if (ifm->ifm_index > 0) { 31732425Sbrian if (ifm->ifm_index > have) { 31838381Sbrian char **newifs; 31938381Sbrian 32032425Sbrian had = have; 32132425Sbrian have = ifm->ifm_index + 5; 32232425Sbrian if (had) 32338381Sbrian newifs = (char **)realloc(ifs, sizeof(char *) * have); 32432425Sbrian else 32538381Sbrian newifs = (char **)malloc(sizeof(char *) * have); 32638381Sbrian if (!newifs) { 32736285Sbrian log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 32832425Sbrian nifs = 0; 32950427Sbrian if (ifs) { 33038381Sbrian free(ifs); 33150427Sbrian ifs = NULL; 33250427Sbrian } 33350427Sbrian free(buf); 33458034Sbrian return NumStr(idx, NULL, 0); 33532425Sbrian } 33638381Sbrian ifs = newifs; 33732425Sbrian memset(ifs + had, '\0', sizeof(char *) * (have - had)); 33832425Sbrian } 33932425Sbrian if (ifs[ifm->ifm_index-1] == NULL) { 34032425Sbrian ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 34132425Sbrian memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 34232425Sbrian ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 34332425Sbrian if (nifs < ifm->ifm_index) 34432425Sbrian nifs = ifm->ifm_index; 34532425Sbrian } 34636285Sbrian } else if (log_IsKept(LogDEBUG)) 34736285Sbrian log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 34831354Sbrian ifm->ifm_index); 34931176Sbrian } 35031176Sbrian free(buf); 35131176Sbrian } 35231176Sbrian 35336285Sbrian if (log_IsKept(LogDEBUG) && !debug_done) { 35431354Sbrian int f; 35531354Sbrian 35636285Sbrian log_Printf(LogDEBUG, "Found the following interfaces:\n"); 35731354Sbrian for (f = 0; f < nifs; f++) 35832425Sbrian if (ifs[f] != NULL) 35936285Sbrian log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 36031354Sbrian debug_done = 1; 36131354Sbrian } 36231354Sbrian 36332425Sbrian if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 36458034Sbrian return NumStr(idx, NULL, 0); 36531354Sbrian 36631354Sbrian return ifs[idx-1]; 36731176Sbrian} 36831176Sbrian 36958032Sbrianvoid 37058032Sbrianroute_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 37158032Sbrian{ 37258032Sbrian char *wp; 37358032Sbrian int rtax; 37458032Sbrian 37558032Sbrian wp = (char *)(rtm + 1); 37658032Sbrian 37758032Sbrian for (rtax = 0; rtax < RTAX_MAX; rtax++) 37858032Sbrian if (rtm->rtm_addrs & (1 << rtax)) { 37958032Sbrian sa[rtax] = (struct sockaddr *)wp; 38058032Sbrian wp += ROUNDUP(sa[rtax]->sa_len); 38158032Sbrian } else 38258032Sbrian sa[rtax] = NULL; 38358032Sbrian} 38458032Sbrian 3856059Samuraiint 38636285Sbrianroute_Show(struct cmdargs const *arg) 3876059Samurai{ 3886059Samurai struct rt_msghdr *rtm; 38958032Sbrian struct sockaddr *sa[RTAX_MAX]; 39058032Sbrian char *sp, *ep, *cp; 39132021Sbrian size_t needed; 3926735Samurai int mib[6]; 3936059Samurai 3946059Samurai mib[0] = CTL_NET; 3956059Samurai mib[1] = PF_ROUTE; 3966735Samurai mib[2] = 0; 3976735Samurai mib[3] = 0; 3986059Samurai mib[4] = NET_RT_DUMP; 3996735Samurai mib[5] = 0; 4006735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 40136285Sbrian log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 40228679Sbrian return (1); 4036735Samurai } 4046059Samurai sp = malloc(needed); 4056059Samurai if (sp == NULL) 40628679Sbrian return (1); 4076735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 40836285Sbrian log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 40918885Sjkh free(sp); 41028679Sbrian return (1); 4116735Samurai } 4126059Samurai ep = sp + needed; 4136059Samurai 41436285Sbrian prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 41536285Sbrian "Destination", "Gateway"); 4166059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 41758032Sbrian rtm = (struct rt_msghdr *)cp; 41831176Sbrian 41958032Sbrian route_ParseHdr(rtm, sa); 42058031Sbrian 42158032Sbrian if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 42258032Sbrian p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 42358032Sbrian p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 42431176Sbrian 42558031Sbrian p_flags(arg->prompt, rtm->rtm_flags, 6); 42658031Sbrian prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 42758031Sbrian } else 42858031Sbrian prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 4296059Samurai } 43018885Sjkh free(sp); 43126516Sbrian return 0; 4326059Samurai} 4336059Samurai 4346059Samurai/* 4356059Samurai * Delete routes associated with our interface 4366059Samurai */ 4376059Samuraivoid 43836285Sbrianroute_IfDelete(struct bundle *bundle, int all) 4396059Samurai{ 4406059Samurai struct rt_msghdr *rtm; 44158032Sbrian struct sockaddr *sa[RTAX_MAX]; 44258032Sbrian struct sockaddr_in **in; 44358032Sbrian struct in_addr sa_none; 44432021Sbrian int pass; 44532021Sbrian size_t needed; 4466059Samurai char *sp, *cp, *ep; 4476735Samurai int mib[6]; 4486059Samurai 44940561Sbrian log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 45031598Sbrian sa_none.s_addr = INADDR_ANY; 45158032Sbrian in = (struct sockaddr_in **)sa; 45226516Sbrian 4536059Samurai mib[0] = CTL_NET; 4546059Samurai mib[1] = PF_ROUTE; 4556735Samurai mib[2] = 0; 4566735Samurai mib[3] = 0; 4576059Samurai mib[4] = NET_RT_DUMP; 4586735Samurai mib[5] = 0; 4596735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 46036285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 46128974Sbrian strerror(errno)); 4626735Samurai return; 4636735Samurai } 4646059Samurai 4656059Samurai sp = malloc(needed); 4666059Samurai if (sp == NULL) 4676059Samurai return; 4686059Samurai 4696735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 47036285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 47128974Sbrian strerror(errno)); 4726059Samurai free(sp); 4736059Samurai return; 4746059Samurai } 4756059Samurai ep = sp + needed; 4766059Samurai 47731739Sbrian for (pass = 0; pass < 2; pass++) { 47831739Sbrian /* 47931739Sbrian * We do 2 passes. The first deletes all cloned routes. The second 48058032Sbrian * deletes all non-cloned routes. This is done to avoid 48131739Sbrian * potential errors from trying to delete route X after route Y where 48236285Sbrian * route X was cloned from route Y (and is no longer there 'cos it 48336285Sbrian * may have gone with route Y). 48431739Sbrian */ 48531739Sbrian if (RTF_WASCLONED == 0 && pass == 0) 48631739Sbrian /* So we can't tell ! */ 48731739Sbrian continue; 48831739Sbrian for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 48958032Sbrian rtm = (struct rt_msghdr *)cp; 49058032Sbrian route_ParseHdr(rtm, sa); 49158032Sbrian if (sa[RTAX_DST]) { 49258032Sbrian log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 49358032Sbrian " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 49458032Sbrian Index2Nam(rtm->rtm_index), rtm->rtm_flags, 49558032Sbrian inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 49658032Sbrian if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 49758032Sbrian (all || (rtm->rtm_flags & RTF_GATEWAY))) { 49858032Sbrian if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 49958032Sbrian sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 50058032Sbrian if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 50158032Sbrian (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 50258032Sbrian log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 50358032Sbrian pass); 50458032Sbrian bundle_SetRoute(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 50558032Sbrian sa_none, sa_none, 0, 0); 50658032Sbrian } else 50758032Sbrian log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 50831739Sbrian } else 50958032Sbrian log_Printf(LogDEBUG, 51058032Sbrian "route_IfDelete: Can't remove routes of %d family !\n", 51158032Sbrian sa[RTAX_GATEWAY]->sa_family); 51258032Sbrian } 51331739Sbrian } 5146059Samurai } 5156059Samurai } 5166059Samurai free(sp); 5176059Samurai} 5186059Samurai 5196059Samuraiint 52028679SbrianGetIfIndex(char *name) 5216059Samurai{ 52231176Sbrian int idx; 52331343Sbrian const char *got; 52428679Sbrian 52531354Sbrian idx = 1; 52631176Sbrian while (strcmp(got = Index2Nam(idx), "???")) 52731176Sbrian if (!strcmp(got, name)) 52836285Sbrian return idx; 52931176Sbrian else 53031176Sbrian idx++; 53131176Sbrian return -1; 5326059Samurai} 53331690Sbrian 53436285Sbrianvoid 53536285Sbrianroute_Change(struct bundle *bundle, struct sticky_route *r, 53658044Sbrian struct in_addr me, struct in_addr peer, struct in_addr dns[2]) 53731690Sbrian{ 53836285Sbrian struct in_addr none, del; 53931690Sbrian 54036285Sbrian none.s_addr = INADDR_ANY; 54136285Sbrian for (; r; r = r->next) { 54236285Sbrian if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 54336285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 54437927Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 54536285Sbrian r->dst = me; 54636285Sbrian if (r->type & ROUTE_GWHISADDR) 54736285Sbrian r->gw = peer; 54836285Sbrian } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 54936285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 55037927Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 55136285Sbrian r->dst = peer; 55236285Sbrian if (r->type & ROUTE_GWHISADDR) 55336285Sbrian r->gw = peer; 55458044Sbrian } else if ((r->type & ROUTE_DSTDNS0) && r->dst.s_addr != peer.s_addr) { 55558044Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 55658044Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 55758044Sbrian r->dst = dns[0]; 55858044Sbrian if (r->type & ROUTE_GWHISADDR) 55958044Sbrian r->gw = peer; 56058044Sbrian } else if ((r->type & ROUTE_DSTDNS1) && r->dst.s_addr != peer.s_addr) { 56158044Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 56258044Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 56358044Sbrian r->dst = dns[1]; 56458044Sbrian if (r->type & ROUTE_GWHISADDR) 56558044Sbrian r->gw = peer; 56636285Sbrian } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 56736285Sbrian r->gw = peer; 56837927Sbrian bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 56936285Sbrian } 57036285Sbrian} 57136285Sbrian 57236285Sbrianvoid 57336285Sbrianroute_Clean(struct bundle *bundle, struct sticky_route *r) 57436285Sbrian{ 57536285Sbrian struct in_addr none, del; 57636285Sbrian 57736285Sbrian none.s_addr = INADDR_ANY; 57836285Sbrian for (; r; r = r->next) { 57936285Sbrian del.s_addr = r->dst.s_addr & r->mask.s_addr; 58037927Sbrian bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 58136285Sbrian } 58236285Sbrian} 58336285Sbrian 58436285Sbrianvoid 58536285Sbrianroute_Add(struct sticky_route **rp, int type, struct in_addr dst, 58636285Sbrian struct in_addr mask, struct in_addr gw) 58736285Sbrian{ 58843313Sbrian struct sticky_route *r; 58943313Sbrian int dsttype = type & ROUTE_DSTANY; 59036285Sbrian 59143313Sbrian r = NULL; 59243313Sbrian while (*rp) { 59343313Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 59443313Sbrian (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 59543313Sbrian /* Oops, we already have this route - unlink it */ 59643313Sbrian free(r); /* impossible really */ 59743313Sbrian r = *rp; 59843313Sbrian *rp = r->next; 59943313Sbrian } else 60043313Sbrian rp = &(*rp)->next; 60143313Sbrian } 60236285Sbrian 60343313Sbrian if (!r) 60443313Sbrian r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 60543313Sbrian r->type = type; 60643313Sbrian r->next = NULL; 60743313Sbrian r->dst = dst; 60843313Sbrian r->mask = mask; 60943313Sbrian r->gw = gw; 61043313Sbrian *rp = r; 61136285Sbrian} 61236285Sbrian 61336285Sbrianvoid 61436285Sbrianroute_Delete(struct sticky_route **rp, int type, struct in_addr dst) 61536285Sbrian{ 61636285Sbrian struct sticky_route *r; 61736285Sbrian int dsttype = type & ROUTE_DSTANY; 61836285Sbrian 61936285Sbrian for (; *rp; rp = &(*rp)->next) { 62036285Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 62136285Sbrian (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 62236285Sbrian r = *rp; 62336285Sbrian *rp = r->next; 62436285Sbrian free(r); 62531690Sbrian break; 62631690Sbrian } 62731690Sbrian } 62836285Sbrian} 62931690Sbrian 63036285Sbrianvoid 63136285Sbrianroute_DeleteAll(struct sticky_route **rp) 63236285Sbrian{ 63336285Sbrian struct sticky_route *r, *rn; 63436285Sbrian 63536285Sbrian for (r = *rp; r; r = rn) { 63636285Sbrian rn = r->next; 63736285Sbrian free(r); 63831690Sbrian } 63936285Sbrian *rp = NULL; 64036285Sbrian} 64131690Sbrian 64236285Sbrianvoid 64343313Sbrianroute_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 64443313Sbrian int indent) 64536285Sbrian{ 64636285Sbrian int def; 64743313Sbrian int tlen = strlen(tag); 64836285Sbrian 64943313Sbrian if (tlen + 2 > indent) 65043313Sbrian prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 65143313Sbrian else 65243313Sbrian prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 65343313Sbrian 65436285Sbrian for (; r; r = r->next) { 65536285Sbrian def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 65636285Sbrian 65743313Sbrian prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 65843313Sbrian tlen = 0; 65936285Sbrian if (r->type & ROUTE_DSTMYADDR) 66036285Sbrian prompt_Printf(p, "MYADDR"); 66136285Sbrian else if (r->type & ROUTE_DSTHISADDR) 66236285Sbrian prompt_Printf(p, "HISADDR"); 66358044Sbrian else if (r->type & ROUTE_DSTDNS0) 66458044Sbrian prompt_Printf(p, "DNS0"); 66558044Sbrian else if (r->type & ROUTE_DSTDNS1) 66658044Sbrian prompt_Printf(p, "DNS1"); 66736285Sbrian else if (!def) 66836285Sbrian prompt_Printf(p, "%s", inet_ntoa(r->dst)); 66936285Sbrian 67036285Sbrian if (def) 67136285Sbrian prompt_Printf(p, "default "); 67236285Sbrian else 67336285Sbrian prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 67436285Sbrian 67536285Sbrian if (r->type & ROUTE_GWHISADDR) 67636285Sbrian prompt_Printf(p, "HISADDR\n"); 67736285Sbrian else 67836285Sbrian prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 67936285Sbrian } 68031690Sbrian} 681