/* * Update the MTU on all routes for the given interface */ void route_UpdateMTU(struct bundle *bundle) { struct rt_msghdr *rtm; struct sockaddr *sa[RTAX_MAX]; struct ncprange dst; size_t needed; char *sp, *cp, *ep; int mib[6]; log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", strerror(errno)); return; } sp = malloc(needed); if (sp == NULL) return; if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", strerror(errno)); free(sp); return; } ep = sp + needed; for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)cp; route_ParseHdr(rtm, sa); if (sa[RTAX_DST] && (sa[RTAX_DST]->sa_family == AF_INET #ifndef NOINET6 || sa[RTAX_DST]->sa_family == AF_INET6 #endif ) && sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index) { if (log_IsKept(LogTCPIP)) { ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]); log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s," " mtu %lu\n", rtm->rtm_index, Index2Nam(rtm->rtm_index), ncprange_ntoa(&dst), bundle->iface->mtu); } rt_Update(bundle, sa[RTAX_DST], sa[RTAX_GATEWAY], sa[RTAX_NETMASK], sa[RTAX_IFP], sa[RTAX_IFA]); } } free(sp); }
void rt_Update(struct bundle *bundle, const struct sockaddr *dst, const struct sockaddr *gw, const struct sockaddr *mask) { struct ncprange ncpdst; struct rtmsg rtmes; char *p; int s, wb; s = ID0socket(PF_ROUTE, SOCK_RAW, 0); if (s < 0) { log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); return; } memset(&rtmes, '\0', sizeof rtmes); rtmes.m_rtm.rtm_version = RTM_VERSION; rtmes.m_rtm.rtm_type = RTM_CHANGE; rtmes.m_rtm.rtm_addrs = 0; rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; rtmes.m_rtm.rtm_pid = getpid(); rtmes.m_rtm.rtm_flags = RTF_UP | RTF_STATIC; if (bundle->ncp.cfg.sendpipe > 0) { rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; rtmes.m_rtm.rtm_inits |= RTV_SPIPE; } if (bundle->ncp.cfg.recvpipe > 0) { rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; rtmes.m_rtm.rtm_inits |= RTV_RPIPE; } rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; rtmes.m_rtm.rtm_inits |= RTV_MTU; p = rtmes.m_space; if (dst) { rtmes.m_rtm.rtm_addrs |= RTA_DST; p += memcpy_roundup(p, dst, dst->sa_len); } rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; p += memcpy_roundup(p, gw, gw->sa_len); if (mask) { rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; p += memcpy_roundup(p, mask, mask->sa_len); } rtmes.m_rtm.rtm_msglen = p - (char *)&rtmes; wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); if (wb < 0) { ncprange_setsa(&ncpdst, dst, mask); log_Printf(LogTCPIP, "rt_Update failure:\n"); log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst)); if (rtmes.m_rtm.rtm_errno == 0) log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", ncprange_ntoa(&ncpdst), strerror(errno)); else log_Printf(LogWARN, "%s: Change route failed: %s\n", ncprange_ntoa(&ncpdst), strerror(rtmes.m_rtm.rtm_errno)); } close(s); }
static void p_sockaddr(struct prompt *prompt, struct sockaddr *phost, struct sockaddr *pmask, int width) { struct ncprange range; char buf[29]; struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; if (log_IsKept(LogDEBUG)) { char tmp[50]; log_Printf(LogDEBUG, "Found the following sockaddr:\n"); log_Printf(LogDEBUG, " Family %d, len %d\n", (int)phost->sa_family, (int)phost->sa_len); inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); log_Printf(LogDEBUG, " Addr %s\n", tmp); if (pmask) { inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); log_Printf(LogDEBUG, " Mask %s\n", tmp); } } switch (phost->sa_family) { case AF_INET: #ifndef NOINET6 case AF_INET6: #endif ncprange_setsa(&range, phost, pmask); if (ncprange_isdefault(&range)) prompt_Printf(prompt, "%-*s ", width - 1, "default"); else prompt_Printf(prompt, "%-*s ", width - 1, ncprange_ntoa(&range)); return; case AF_LINK: if (dl->sdl_nlen) snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); else if (dl->sdl_alen) { if (dl->sdl_type == IFT_ETHER) { if (dl->sdl_alen < sizeof buf / 3) { int f; u_char *MAC; MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; for (f = 0; f < dl->sdl_alen; f++) sprintf(buf+f*3, "%02x:", MAC[f]); buf[f*3-1] = '\0'; } else strcpy(buf, "??:??:??:??:??:??"); } else sprintf(buf, "<IFT type %d>", dl->sdl_type); } else if (dl->sdl_slen) sprintf(buf, "<slen %d?>", dl->sdl_slen); else sprintf(buf, "link#%d", dl->sdl_index); break; default: sprintf(buf, "<AF type %d>", phost->sa_family); break; } prompt_Printf(prompt, "%-*s ", width-1, buf); }
/* * Delete routes associated with our interface */ void route_IfDelete(struct bundle *bundle, int all) { struct rt_msghdr *rtm; struct sockaddr *sa[RTAX_MAX]; struct ncprange range; int pass; size_t needed; char *sp, *cp, *ep; int mib[6]; log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", strerror(errno)); return; } sp = malloc(needed); if (sp == NULL) return; if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", strerror(errno)); free(sp); return; } ep = sp + needed; for (pass = 0; pass < 2; pass++) { /* * We do 2 passes. The first deletes all cloned routes. The second * deletes all non-cloned routes. This is done to avoid * potential errors from trying to delete route X after route Y where * route X was cloned from route Y (and is no longer there 'cos it * may have gone with route Y). */ if (RTF_WASCLONED == 0 && pass == 0) /* So we can't tell ! */ continue; for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)cp; route_ParseHdr(rtm, sa); if (rtm->rtm_index == bundle->iface->index && sa[RTAX_DST] && sa[RTAX_GATEWAY] && (sa[RTAX_DST]->sa_family == AF_INET #ifndef NOINET6 || sa[RTAX_DST]->sa_family == AF_INET6 #endif ) && (all || (rtm->rtm_flags & RTF_GATEWAY))) { if (log_IsKept(LogDEBUG)) { char gwstr[41]; struct ncpaddr gw; ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]); snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw)); log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr); } if (sa[RTAX_GATEWAY]->sa_family == AF_INET || #ifndef NOINET6 sa[RTAX_GATEWAY]->sa_family == AF_INET6 || #endif sa[RTAX_GATEWAY]->sa_family == AF_LINK) { if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0); } else log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); } else log_Printf(LogDEBUG, "route_IfDelete: Can't remove routes for family %d\n", sa[RTAX_GATEWAY]->sa_family); } } } free(sp); }
struct iface * iface_Create(const char *name) { int mib[6], maxtries, err; size_t needed, namelen; char *buf, *ptr, *end; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *dl; struct sockaddr *sa[RTAX_MAX]; struct iface *iface; struct iface_addr *addr; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_IFLIST; mib[5] = 0; maxtries = 20; err = 0; do { if (maxtries-- == 0 || (err && err != ENOMEM)) { fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err)); return NULL; } if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { fprintf(stderr, "iface_Create: sysctl: estimate: %s\n", strerror(errno)); return NULL; } if ((buf = (char *)malloc(needed)) == NULL) { fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno)); return NULL; } if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { err = errno; free(buf); buf = NULL; } } while (buf == NULL); ptr = buf; end = buf + needed; iface = NULL; namelen = strlen(name); while (ptr < end && iface == NULL) { ifm = (struct if_msghdr *)ptr; /* On if_msghdr */ if (ifm->ifm_type != RTM_IFINFO) break; dl = (struct sockaddr_dl *)(ifm + 1); /* Single _dl at end */ if (dl->sdl_nlen == namelen && !strncmp(name, dl->sdl_data, namelen)) { iface = (struct iface *)malloc(sizeof *iface); if (iface == NULL) { fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno)); return NULL; } iface->name = strdup(name); iface->descr = NULL; iface->index = ifm->ifm_index; iface->flags = ifm->ifm_flags; iface->mtu = 0; iface->addrs = 0; iface->addr = NULL; } ptr += ifm->ifm_msglen; /* First ifa_msghdr */ for (; ptr < end; ptr += ifam->ifam_msglen) { ifam = (struct ifa_msghdr *)ptr; /* Next if address */ if (ifam->ifam_type != RTM_NEWADDR) /* finished this if */ break; if (iface != NULL && ifam->ifam_addrs & RTA_IFA) { /* Found a configured interface ! */ iface_ParseHdr(ifam, sa); if (sa[RTAX_IFA] && (sa[RTAX_IFA]->sa_family == AF_INET #ifndef NOINET6 || sa[RTAX_IFA]->sa_family == AF_INET6 #endif )) { /* Record the address */ addr = (struct iface_addr *) realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]); if (addr == NULL) break; iface->addr = addr; addr += iface->addrs; iface->addrs++; ncprange_setsa(&addr->ifa, sa[RTAX_IFA], sa[RTAX_NETMASK]); if (sa[RTAX_BRD]) ncpaddr_setsa(&addr->peer, sa[RTAX_BRD]); else ncpaddr_init(&addr->peer); } } } } free(buf); return iface; }
struct iface * iface_Create(const char *name) { size_t namelen; struct sockaddr_dl *dl; struct ifaddrs *ifap, *ifa; struct iface *iface; struct iface_addr *addr; if (getifaddrs(&ifap) != 0) { fprintf(stderr, "iface_Create: getifaddrs: %s\n", strerror(errno)); return NULL; } iface = NULL; namelen = strlen(name); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (strcmp(name, ifa->ifa_name)) continue; if (ifa->ifa_addr->sa_family == AF_LINK) { dl = (struct sockaddr_dl *)ifa->ifa_addr; iface = (struct iface *)malloc(sizeof *iface); if (iface == NULL) { fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno)); freeifaddrs(ifap); return NULL; } iface->name = strdup(name); iface->index = if_nametoindex(name); iface->flags = ifa->ifa_flags; iface->mtu = 0; iface->addrs = 0; iface->addr = NULL; } if (ifa->ifa_addr->sa_family == AF_INET #ifndef NOINET6 || ifa->ifa_addr->sa_family == AF_INET6 #endif ) { /* Record the address */ addr = (struct iface_addr *) realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]); if (addr == NULL) break; iface->addr = addr; addr += iface->addrs; iface->addrs++; ncprange_setsa(&addr->ifa, ifa->ifa_addr, ifa->ifa_netmask); if (ifa->ifa_broadaddr) ncpaddr_setsa(&addr->peer, ifa->ifa_broadaddr); else ncpaddr_init(&addr->peer); } } freeifaddrs(ifap); return iface; }