Index: stable/10/usr.sbin/ppp/defs.h =================================================================== --- stable/10/usr.sbin/ppp/defs.h (revision 330804) +++ stable/10/usr.sbin/ppp/defs.h (revision 330805) @@ -1,142 +1,144 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* Check the following definitions for your machine environment */ #ifdef __FreeBSD__ # define MODEM_LIST "/dev/cuau1\0/dev/cuau0" /* name of tty device */ #else # ifdef __OpenBSD__ # define MODEM_LIST "/dev/cua01\0/dev/cua00" /* name of tty device */ # else # define MODEM_LIST "/dev/tty01\0/dev/tty00" /* name of tty device */ # endif #endif #define NMODEMS 2 #ifndef PPP_CONFDIR #define PPP_CONFDIR "/etc/ppp" #endif #define TUN_NAME "tun" #define TUN_PREFIX (_PATH_DEV TUN_NAME) /* /dev/tun */ #define MODEM_SPEED B38400 /* tty speed */ #define SERVER_PORT 3000 /* Base server port no. */ #define MODEM_CTSRTS 1 /* Default (true): use CTS/RTS signals */ #define RECONNECT_TIMEOUT 3 /* Default timer for carrier loss */ #define DIAL_TIMEOUT 30 /* Default and Max random time to redial */ #define DIAL_NEXT_TIMEOUT 3 /* Default Hold time to next number redial */ #define SCRIPT_LEN 512 /* Size of login/dial/hangup scripts */ #define LINE_LEN SCRIPT_LEN /* Size of lines */ #define DEVICE_LEN SCRIPT_LEN /* Size of individual devices */ #define AUTHLEN 100 /* Size of authname/authkey */ #define CHAPDIGESTLEN 100 /* Maximum chap digest */ #define CHAPCHALLENGELEN 48 /* Maximum chap challenge */ #define CHAPAUTHRESPONSELEN 48 /* Maximum chap authresponse (chap81) */ #define MAXARGS 40 /* How many args per config line */ #define NCP_IDLE_TIMEOUT 180 /* Drop all links */ #define CHOKED_TIMEOUT 120 /* Delete queued packets w/ blocked tun */ #define MIN_LQRPERIOD 1 /* Minimum LQR frequency */ #define DEF_LQRPERIOD 30 /* Default LQR frequency */ #define MIN_FSMRETRY 1 /* Minimum FSM retry frequency */ #define DEF_FSMRETRY 3 /* FSM retry frequency */ #define DEF_FSMTRIES 5 /* Default max retries */ #define DEF_FSMAUTHTRIES 3 /* Default max auth retries */ #define DEF_IFQUEUE 30 /* Default interface queue size */ #define CONFFILE "ppp.conf" #define LINKUPFILE "ppp.linkup" #define LINKDOWNFILE "ppp.linkdown" #define SECRETFILE "ppp.secret" #define EX_SIG -1 #define EX_NORMAL 0 #define EX_START 1 #define EX_SOCK 2 #define EX_MODEM 3 #define EX_DIAL 4 #define EX_DEAD 5 #define EX_DONE 6 #define EX_REBOOT 7 #define EX_ERRDEAD 8 #define EX_HANGUP 9 #define EX_TERM 10 #define EX_NODIAL 11 #define EX_NOLOGIN 12 /* return values for -background mode, not really exits */ #define EX_REDIAL 13 #define EX_RECONNECT 14 /* physical::type values (OR'd in bundle::phys_type) */ #define PHYS_NONE 0 #define PHYS_INTERACTIVE 1 /* Manual link */ #define PHYS_AUTO 2 /* Dial-on-demand link */ #define PHYS_DIRECT 4 /* Incoming link, deleted when closed */ #define PHYS_DEDICATED 8 /* Dedicated link */ #define PHYS_DDIAL 16 /* Dial immediately, stay connected */ #define PHYS_BACKGROUND 32 /* Dial immediately, deleted when closed */ #define PHYS_FOREGROUND 64 /* Pseudo mode, same as background */ #define PHYS_ALL 127 /* flags passed to findblank() and MakeArgs() */ #define PARSE_NORMAL 0 #define PARSE_REDUCE 1 #define PARSE_NOHASH 2 /* flags passed to loadmodules */ #define LOAD_QUIETLY 1 #define LOAD_VERBOSLY 2 #define ROUNDUP(x) ((x) ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define NCP_ASCIIBUFFERSIZE 52 + #ifdef __NetBSD__ extern void randinit(void); #else #define random arc4random #define randinit() #endif extern ssize_t fullread(int, void *, size_t); extern const char *mode2Nam(int); extern int Nam2mode(const char *); extern struct in_addr GetIpAddr(const char *); extern unsigned SpeedToUnsigned(speed_t); extern speed_t UnsignedToSpeed(unsigned); extern char *findblank(char *, int); extern int MakeArgs(char *, char **, int, int); extern const char *NumStr(long, char *, size_t); extern const char *HexStr(long, char *, size_t); extern const char *ex_desc(int); extern void SetTitle(const char *); extern fd_set *mkfdset(void); extern void zerofdset(fd_set *); extern void Concatinate(char *, size_t, int, const char *const *); extern int loadmodules(int, const char *, ...); Index: stable/10/usr.sbin/ppp/iface.c =================================================================== --- stable/10/usr.sbin/ppp/iface.c (revision 330804) +++ stable/10/usr.sbin/ppp/iface.c (revision 330805) @@ -1,839 +1,843 @@ /*- * Copyright (c) 1998 Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #ifdef __FreeBSD__ #include #endif #include #include #include #include #ifndef NOINET6 #include #endif #include #include #include #include #include #include #include #include #include #include #include "layer.h" #include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" #include "id.h" #include "timer.h" #include "fsm.h" #include "iplist.h" #include "lqr.h" #include "hdlc.h" #include "throughput.h" #include "slcompress.h" #include "descriptor.h" #include "ncpaddr.h" #include "ipcp.h" #include "filter.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" #include "prompt.h" #include "iface.h" #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}} static const struct in6_addr in6mask128 = IN6MASK128; 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; } static int iface_addr_Zap(const char *name, struct iface_addr *addr, int s) { struct ifaliasreq ifra; #ifndef NOINET6 struct in6_aliasreq ifra6; #endif struct sockaddr_in *me4, *msk4, *peer4; struct sockaddr_storage ssme, sspeer, ssmsk; - int res; + int res, saved_errno; ncprange_getsa(&addr->ifa, &ssme, &ssmsk); ncpaddr_getsa(&addr->peer, &sspeer); res = 0; switch (ncprange_family(&addr->ifa)) { case AF_INET: memset(&ifra, '\0', sizeof ifra); strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1); me4 = (struct sockaddr_in *)&ifra.ifra_addr; memcpy(me4, &ssme, sizeof *me4); msk4 = (struct sockaddr_in *)&ifra.ifra_mask; memcpy(msk4, &ssmsk, sizeof *msk4); peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr; if (ncpaddr_family(&addr->peer) == AF_UNSPEC) { peer4->sin_family = AF_INET; peer4->sin_len = sizeof(*peer4); peer4->sin_addr.s_addr = INADDR_NONE; } else memcpy(peer4, &sspeer, sizeof *peer4); res = ID0ioctl(s, SIOCDIFADDR, &ifra); + saved_errno = errno; if (log_IsKept(LogDEBUG)) { - char buf[100]; + char buf[NCP_ASCIIBUFFERSIZE]; snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa)); log_Printf(LogWARN, "%s: DIFADDR %s -> %s returns %d\n", ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res); } break; #ifndef NOINET6 case AF_INET6: memset(&ifra6, '\0', sizeof ifra6); strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1); memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr); memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask); ifra6.ifra_prefixmask.sin6_family = AF_UNSPEC; if (ncpaddr_family(&addr->peer) == AF_UNSPEC) ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC; else memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr); ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; res = ID0ioctl(s, SIOCDIFADDR_IN6, &ifra6); + saved_errno = errno; break; #endif } if (res == -1) { - char dst[40]; + char dst[NCP_ASCIIBUFFERSIZE]; const char *end = #ifndef NOINET6 ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" : #endif ""; if (ncpaddr_family(&addr->peer) == AF_UNSPEC) log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n", - end, ncprange_ntoa(&addr->ifa), strerror(errno)); + end, ncprange_ntoa(&addr->ifa), strerror(saved_errno)); else { snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer)); log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n", - end, ncprange_ntoa(&addr->ifa), dst, strerror(errno)); + end, ncprange_ntoa(&addr->ifa), dst, strerror(saved_errno)); } } return res != -1; } static int iface_addr_Add(const char *name, struct iface_addr *addr, int s) { struct ifaliasreq ifra; #ifndef NOINET6 struct in6_aliasreq ifra6; #endif struct sockaddr_in *me4, *msk4, *peer4; struct sockaddr_storage ssme, sspeer, ssmsk; - int res; + int res, saved_errno; ncprange_getsa(&addr->ifa, &ssme, &ssmsk); ncpaddr_getsa(&addr->peer, &sspeer); res = 0; switch (ncprange_family(&addr->ifa)) { case AF_INET: memset(&ifra, '\0', sizeof ifra); strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1); me4 = (struct sockaddr_in *)&ifra.ifra_addr; memcpy(me4, &ssme, sizeof *me4); msk4 = (struct sockaddr_in *)&ifra.ifra_mask; memcpy(msk4, &ssmsk, sizeof *msk4); peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr; if (ncpaddr_family(&addr->peer) == AF_UNSPEC) { peer4->sin_family = AF_INET; peer4->sin_len = sizeof(*peer4); peer4->sin_addr.s_addr = INADDR_NONE; } else memcpy(peer4, &sspeer, sizeof *peer4); res = ID0ioctl(s, SIOCAIFADDR, &ifra); + saved_errno = errno; if (log_IsKept(LogDEBUG)) { - char buf[100]; + char buf[NCP_ASCIIBUFFERSIZE]; snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa)); log_Printf(LogWARN, "%s: AIFADDR %s -> %s returns %d\n", ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res); } break; #ifndef NOINET6 case AF_INET6: memset(&ifra6, '\0', sizeof ifra6); strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1); memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr); memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask); if (ncpaddr_family(&addr->peer) == AF_UNSPEC) ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC; else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128, sizeof in6mask128) == 0) memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr); ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6); + saved_errno = errno; break; #endif } if (res == -1) { - char dst[40]; + char dst[NCP_ASCIIBUFFERSIZE]; const char *end = #ifndef NOINET6 ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" : #endif ""; if (ncpaddr_family(&addr->peer) == AF_UNSPEC) log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n", - end, ncprange_ntoa(&addr->ifa), strerror(errno)); + end, ncprange_ntoa(&addr->ifa), strerror(saved_errno)); else { snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer)); log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n", - end, ncprange_ntoa(&addr->ifa), dst, strerror(errno)); + end, ncprange_ntoa(&addr->ifa), dst, strerror(saved_errno)); } } return res != -1; } int iface_Name(struct iface *iface, const char *name) { struct ifreq ifr; int s; char *newname; if ((newname = strdup(name)) == NULL) { log_Printf(LogWARN, "iface name: strdup failed: %s\n", strerror(errno)); return 0; } if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) { log_Printf(LogERROR, "iface name: socket(): %s\n", strerror(errno)); free(newname); return 0; } strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); ifr.ifr_data = newname; if (ID0ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { log_Printf(LogWARN, "iface name: ioctl(SIOCSIFNAME, %s -> %s): %s\n", name, newname, strerror(errno)); free(newname); return 0; } free(iface->name); iface->name = newname; return 1; } int iface_Descr(struct cmdargs const *arg) { struct ifreq ifr; struct iface *iface; size_t sz, len; int s, n, ifdescr_maxlen; char *descr; sz = sizeof(int); if (sysctlbyname("net.ifdescr_maxlen", &ifdescr_maxlen, &sz, NULL, 0) < 0) { log_Printf(LogERROR, "iface descr: sysctl failed: %s\n", strerror(errno)); return 1; } if (ifdescr_maxlen < 1) { log_Printf(LogERROR, "iface descr: sysctl net.ifdescr_maxlen < 1\n"); return 1; } sz = sizeof(char) * ifdescr_maxlen; if ((descr = malloc(sz)) == NULL) { log_Printf(LogERROR, "iface descr: malloc failed: %s\n", strerror(errno)); return 1; } *descr = '\0'; n = arg->argn; while (n < arg->argc) { if (n > arg->argn && (len = strlcat(descr, " ", sz)) >= sz) break; if ((len = strlcat(descr, arg->argv[n], sz)) >= sz) break; ++n; } if (len >= sz) { log_Printf(LogERROR, "iface descr: description exceeds maximum (%d)\n", ifdescr_maxlen-1); free(descr); return 1; } if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) { log_Printf(LogERROR, "iface descr: socket(): %s\n", strerror(errno)); free(descr); return 1; } iface = arg->bundle->iface; strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); ifr.ifr_buffer.length = strlen(descr) + 1; ifr.ifr_buffer.buffer = descr; if (ID0ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) { log_Printf(LogWARN, "iface descr: ioctl(SIOCSIFDESCR, %s): %s\n", descr, strerror(errno)); free(descr); return 1; } free(iface->descr); iface->descr = descr; return 0; } void iface_Clear(struct iface *iface, struct ncp *ncp, int family, int how) { int af, inskip, in6skip, s4 = -1, s6 = -1, *s; unsigned n; if (iface->addrs) { inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1; for (n = 0; n < iface->addrs; n++) { af = ncprange_family(&iface->addr[n].ifa); if (family == 0 || family == af) { if (!iface->addr[n].system && (how & IFACE_SYSTEM)) continue; switch (af) { case AF_INET: if (inskip) { inskip = 0; continue; } s = &s4; break; #ifndef NOINET6 case AF_INET6: if (in6skip) { in6skip = 0; continue; } s = &s6; break; #endif default: continue; } if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1) log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno)); else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) { ncp_IfaceAddrDeleted(ncp, iface->addr + n); bcopy(iface->addr + n + 1, iface->addr + n, (iface->addrs - n - 1) * sizeof *iface->addr); iface->addrs--; n--; } } } /* Don't bother realloc()ing - we have little to gain */ if (s4) close(s4); if (s6) close(s6); } } int iface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa, const struct ncpaddr *peer, int how) { int af, removed, s; unsigned n; struct ncpaddr ncplocal; struct iface_addr *addr, newaddr; af = ncprange_family(ifa); if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) { log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno)); return 0; } ncprange_getaddr(ifa, &ncplocal); for (n = 0; n < iface->addrs; n++) { if (ncprange_contains(&iface->addr[n].ifa, &ncplocal) || ncpaddr_equal(&iface->addr[n].peer, peer)) { /* Replace this sockaddr */ if (!(how & IFACE_FORCE_ADD)) { close(s); return 0; /* errno = EEXIST; */ } if (ncprange_equal(&iface->addr[n].ifa, ifa) && ncpaddr_equal(&iface->addr[n].peer, peer)) { close(s); ncp_IfaceAddrAdded(ncp, iface->addr + n); return 1; /* Already there */ } removed = iface_addr_Zap(iface->name, iface->addr + n, s); if (removed) ncp_IfaceAddrDeleted(ncp, iface->addr + n); ncprange_copy(&iface->addr[n].ifa, ifa); ncpaddr_copy(&iface->addr[n].peer, peer); if (!iface_addr_Add(iface->name, iface->addr + n, s)) { if (removed) { bcopy(iface->addr + n + 1, iface->addr + n, (iface->addrs - n - 1) * sizeof *iface->addr); iface->addrs--; n--; } close(s); return 0; } close(s); ncp_IfaceAddrAdded(ncp, iface->addr + n); return 1; } } addr = (struct iface_addr *)realloc (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]); if (addr == NULL) { log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno)); close(s); return 0; } iface->addr = addr; ncprange_copy(&newaddr.ifa, ifa); ncpaddr_copy(&newaddr.peer, peer); newaddr.system = !!(how & IFACE_SYSTEM); if (!iface_addr_Add(iface->name, &newaddr, s)) { close(s); return 0; } if (how & IFACE_ADD_FIRST) { /* Stuff it at the start of our list */ n = 0; bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr); } else n = iface->addrs; iface->addrs++; memcpy(iface->addr + n, &newaddr, sizeof(*iface->addr)); close(s); ncp_IfaceAddrAdded(ncp, iface->addr + n); return 1; } int iface_Delete(struct iface *iface, struct ncp *ncp, const struct ncpaddr *del) { struct ncpaddr found; unsigned n; int res, s; if ((s = ID0socket(ncpaddr_family(del), SOCK_DGRAM, 0)) == -1) { log_Printf(LogERROR, "iface_Delete: socket(): %s\n", strerror(errno)); return 0; } for (n = res = 0; n < iface->addrs; n++) { ncprange_getaddr(&iface->addr[n].ifa, &found); if (ncpaddr_equal(&found, del)) { if (iface_addr_Zap(iface->name, iface->addr + n, s)) { ncp_IfaceAddrDeleted(ncp, iface->addr + n); bcopy(iface->addr + n + 1, iface->addr + n, (iface->addrs - n - 1) * sizeof *iface->addr); iface->addrs--; res = 1; } break; } } close(s); return res; } #define IFACE_ADDFLAGS 1 #define IFACE_DELFLAGS 2 static int iface_ChangeFlags(const char *ifname, int flags, int how) { struct ifreq ifrq; int s, new_flags; s = ID0socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) { log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno)); return 0; } memset(&ifrq, '\0', sizeof ifrq); strncpy(ifrq.ifr_name, ifname, sizeof ifrq.ifr_name - 1); ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n", strerror(errno)); close(s); return 0; } #ifdef __FreeBSD__ new_flags = (ifrq.ifr_flags & 0xffff) | (ifrq.ifr_flagshigh << 16); #else new_flags = ifrq.ifr_flags & 0xffff; #endif if (how == IFACE_ADDFLAGS) new_flags |= flags; else new_flags &= ~flags; ifrq.ifr_flags = new_flags & 0xffff; #ifdef __FreeBSD__ ifrq.ifr_flagshigh = new_flags >> 16; #endif if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n", strerror(errno)); close(s); return 0; } close(s); return 1; /* Success */ } int iface_SetFlags(const char *ifname, int flags) { return iface_ChangeFlags(ifname, flags, IFACE_ADDFLAGS); } int iface_ClearFlags(const char *ifname, int flags) { return iface_ChangeFlags(ifname, flags, IFACE_DELFLAGS); } void iface_Free(struct iface *iface) { free(iface->name); free(iface->descr); free(iface->addr); free(iface); } void iface_Destroy(struct iface *iface) { struct ifreq ifr; int s; if (iface != NULL) { if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) { log_Printf(LogERROR, "iface_Destroy: socket(): %s\n", strerror(errno)); } else { strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); if (ID0ioctl(s, SIOCIFDESTROY, (caddr_t)&ifr) < 0) log_Printf(LogWARN, "iface_Destroy: ioctl(SIOCIFDESTROY, %s): %s\n", iface->name, strerror(errno)); } iface_Free(iface); } } #define if_entry(x) { IFF_##x, #x } struct { int flag; const char *value; } if_flags[] = { if_entry(UP), if_entry(BROADCAST), if_entry(DEBUG), if_entry(LOOPBACK), if_entry(POINTOPOINT), if_entry(RUNNING), if_entry(NOARP), if_entry(PROMISC), if_entry(ALLMULTI), if_entry(OACTIVE), if_entry(SIMPLEX), if_entry(LINK0), if_entry(LINK1), if_entry(LINK2), if_entry(MULTICAST), { 0, "???" } }; int iface_Show(struct cmdargs const *arg) { struct ncpaddr ncpaddr; struct iface *iface = arg->bundle->iface, *current; unsigned f; int flags; #ifndef NOINET6 int scopeid, width; #endif struct in_addr mask; current = iface_Create(iface->name); flags = iface->flags = current->flags; iface_Free(current); prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index); for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++) if ((if_flags[f].flag & flags)) { prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",", if_flags[f].value); flags &= ~if_flags[f].flag; } #if 0 if (flags) prompt_Printf(arg->prompt, "%s0x%x", flags == iface->flags ? "" : ",", flags); #endif prompt_Printf(arg->prompt, "> mtu %lu has %d address%s:\n", iface->mtu, iface->addrs, iface->addrs == 1 ? "" : "es"); for (f = 0; f < iface->addrs; f++) { ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr); switch (ncprange_family(&iface->addr[f].ifa)) { case AF_INET: prompt_Printf(arg->prompt, " inet %s --> ", ncpaddr_ntoa(&ncpaddr)); if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC) prompt_Printf(arg->prompt, "255.255.255.255"); else prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer)); ncprange_getip4mask(&iface->addr[f].ifa, &mask); prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr)); break; #ifndef NOINET6 case AF_INET6: prompt_Printf(arg->prompt, " inet6 %s", ncpaddr_ntoa(&ncpaddr)); if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC) prompt_Printf(arg->prompt, " --> %s", ncpaddr_ntoa(&iface->addr[f].peer)); ncprange_getwidth(&iface->addr[f].ifa, &width); if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC) prompt_Printf(arg->prompt, " prefixlen %d", width); if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1) prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid); break; #endif } prompt_Printf(arg->prompt, "\n"); } return 0; } void iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX]) { char *wp; int rtax; wp = (char *)(ifam + 1); for (rtax = 0; rtax < RTAX_MAX; rtax++) if (ifam->ifam_addrs & (1 << rtax)) { sa[rtax] = (struct sockaddr *)wp; wp += ROUNDUP(sa[rtax]->sa_len); } else sa[rtax] = NULL; } Index: stable/10/usr.sbin/ppp/ip.c =================================================================== --- stable/10/usr.sbin/ppp/ip.c (revision 330804) +++ stable/10/usr.sbin/ppp/ip.c (revision 330805) @@ -1,993 +1,993 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #ifndef NOINET6 #include #include #endif #include #include #include #include #include #include #include #include #include #include #include "layer.h" #include "proto.h" #include "mbuf.h" #include "log.h" #include "defs.h" #include "timer.h" #include "fsm.h" #include "lqr.h" #include "hdlc.h" #include "throughput.h" #include "iplist.h" #include "slcompress.h" #include "ncpaddr.h" #include "ip.h" #include "ipcp.h" #include "filter.h" #include "descriptor.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" #include "tun.h" #define OPCODE_QUERY 0 #define OPCODE_IQUERY 1 #define OPCODE_STATUS 2 struct dns_header { u_short id; unsigned qr : 1; unsigned opcode : 4; unsigned aa : 1; unsigned tc : 1; unsigned rd : 1; unsigned ra : 1; unsigned z : 3; unsigned rcode : 4; u_short qdcount; u_short ancount; u_short nscount; u_short arcount; }; static const char * dns_Qclass2Txt(u_short qclass) { static char failure[6]; struct { u_short id; const char *txt; } qtxt[] = { /* rfc1035 */ { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" } }; unsigned f; for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++) if (qtxt[f].id == qclass) return qtxt[f].txt; return HexStr(qclass, failure, sizeof failure); } static const char * dns_Qtype2Txt(u_short qtype) { static char failure[6]; struct { u_short id; const char *txt; } qtxt[] = { /* rfc1035/rfc1700 */ { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" }, { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" }, { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" }, { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" }, { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" }, { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" }, { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" }, { 254, "MAILA" }, { 255, "*" } }; unsigned f; for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++) if (qtxt[f].id == qtype) return qtxt[f].txt; return HexStr(qtype, failure, sizeof failure); } static __inline int PortMatch(int op, u_short pport, u_short rport) { switch (op) { case OP_EQ: return pport == rport; case OP_GT: return pport > rport; case OP_LT: return pport < rport; default: return 0; } } /* * Return a text string representing the cproto protocol number. * * The purpose of this routine is calculate this result, for * the many times it is needed in FilterCheck, only on demand * (i.e. when the corresponding logging functions are invoked). * * This optimization saves, over the previous implementation, which * calculated prototxt at the beginning of FilterCheck, an * open/read/close system call sequence per packet, approximately * halving the ppp system overhead and reducing the overall (u + s) * time by 38%. * * The caching performed here is just a side effect. */ static const char * prototxt(int cproto) { static int oproto = -1; static char protobuff[16] = "-1"; struct protoent *pe; if (cproto == oproto) return protobuff; if ((pe = getprotobynumber(cproto)) == NULL) snprintf(protobuff, sizeof protobuff, "%d", cproto); else snprintf(protobuff, sizeof protobuff, "%s", pe->p_name); oproto = cproto; return (protobuff); } /* * Check a packet against the given filter * Returns 0 to accept the packet, non-zero to drop the packet. * If psecs is not NULL, populate it with the timeout associated * with the filter rule matched. * * If filtering is enabled, the initial fragment of a datagram must * contain the complete protocol header, and subsequent fragments * must not attempt to over-write it. * * One (and only one) of pip or pip6 must be set. */ int FilterCheck(const unsigned char *packet, #ifdef NOINET6 u_int32_t family __unused, #else u_int32_t family, #endif const struct filter *filter, unsigned *psecs) { int gotinfo; /* true if IP payload decoded */ int cproto; /* IPPROTO_* protocol number if (gotinfo) */ int estab, syn, finrst; /* TCP state flags if (gotinfo) */ u_short sport, dport; /* src, dest port from packet if (gotinfo) */ int n; /* filter rule to process */ int len; /* bytes used in dbuff */ int didname; /* true if filter header printed */ int match; /* true if condition matched */ int mindata; /* minimum data size or zero */ const struct filterent *fp = filter->rule; - char dbuff[100], dstip[16]; + char dbuff[100], dstip[NCP_ASCIIBUFFERSIZE]; struct ncpaddr srcaddr, dstaddr; const char *payload; /* IP payload */ int datalen; /* IP datagram length */ if (fp->f_action == A_NONE) return 0; /* No rule is given. Permit this packet */ #ifndef NOINET6 if (family == AF_INET6) { const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet; ncpaddr_setip6(&srcaddr, &pip6->ip6_src); ncpaddr_setip6(&dstaddr, &pip6->ip6_dst); datalen = ntohs(pip6->ip6_plen); payload = packet + sizeof *pip6; cproto = pip6->ip6_nxt; } else #endif { /* * Deny any packet fragment that tries to over-write the header. * Since we no longer have the real header available, punt on the * largest normal header - 20 bytes for TCP without options, rounded * up to the next possible fragment boundary. Since the smallest * `legal' MTU is 576, and the smallest recommended MTU is 296, any * fragmentation within this range is dubious at best */ const struct ip *pip = (const struct ip *)packet; len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */ if (len > 0) { /* Not first fragment within datagram */ if (len < (24 >> 3)) { /* don't allow fragment to over-write header */ log_Printf(LogFILTER, " error: illegal header\n"); return 1; } /* permit fragments on in and out filter */ if (!filter->fragok) { log_Printf(LogFILTER, " error: illegal fragmentation\n"); return 1; } else return 0; } ncpaddr_setip4(&srcaddr, pip->ip_src); ncpaddr_setip4(&dstaddr, pip->ip_dst); datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2); payload = packet + (pip->ip_hl << 2); cproto = pip->ip_p; } gotinfo = estab = syn = finrst = didname = 0; sport = dport = 0; for (n = 0; n < MAXFILTERS; ) { if (fp->f_action == A_NONE) { n++; fp++; continue; } if (!didname) { log_Printf(LogDEBUG, "%s filter:\n", filter->name); didname = 1; } match = 0; if ((ncprange_family(&fp->f_src) == AF_UNSPEC || ncprange_contains(&fp->f_src, &srcaddr)) && (ncprange_family(&fp->f_dst) == AF_UNSPEC || ncprange_contains(&fp->f_dst, &dstaddr))) { if (fp->f_proto != 0) { if (!gotinfo) { const struct tcphdr *th; const struct udphdr *uh; const struct icmp *ih; #ifndef NOINET6 const struct icmp6_hdr *ih6; #endif mindata = 0; sport = dport = 0; estab = syn = finrst = -1; switch (cproto) { case IPPROTO_ICMP: mindata = 8; /* ICMP must be at least 8 octets */ ih = (const struct icmp *)payload; sport = ih->icmp_type; if (log_IsKept(LogDEBUG)) snprintf(dbuff, sizeof dbuff, "sport = %d", sport); break; #ifndef NOINET6 case IPPROTO_ICMPV6: mindata = 8; /* ICMP must be at least 8 octets */ ih6 = (const struct icmp6_hdr *)payload; sport = ih6->icmp6_type; if (log_IsKept(LogDEBUG)) snprintf(dbuff, sizeof dbuff, "sport = %d", sport); break; #endif case IPPROTO_IGMP: mindata = 8; /* IGMP uses 8-octet messages */ break; #ifdef IPPROTO_GRE case IPPROTO_GRE: mindata = 2; /* GRE uses 2-octet+ messages */ break; #endif #ifdef IPPROTO_OSPFIGP case IPPROTO_OSPFIGP: mindata = 8; /* IGMP uses 8-octet messages */ break; #endif #ifndef NOINET6 case IPPROTO_IPV6: mindata = 20; /* RFC2893 Section 3.5: 5 * 32bit words */ break; #endif case IPPROTO_UDP: mindata = 8; /* UDP header is 8 octets */ uh = (const struct udphdr *)payload; sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport); if (log_IsKept(LogDEBUG)) snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", sport, dport); break; case IPPROTO_TCP: th = (const struct tcphdr *)payload; /* * TCP headers are variable length. The following code * ensures that the TCP header length isn't de-referenced if * the datagram is too short */ if (datalen < 20 || datalen < (th->th_off << 2)) { log_Printf(LogFILTER, " error: TCP header incorrect\n"); return 1; } sport = ntohs(th->th_sport); dport = ntohs(th->th_dport); estab = (th->th_flags & TH_ACK); syn = (th->th_flags & TH_SYN); finrst = (th->th_flags & (TH_FIN|TH_RST)); if (log_IsKept(LogDEBUG)) { if (!estab) snprintf(dbuff, sizeof dbuff, "flags = %02x, sport = %d, dport = %d", th->th_flags, sport, dport); else *dbuff = '\0'; } break; default: break; } if (datalen < mindata) { log_Printf(LogFILTER, " error: proto %s must be at least" " %d octets\n", prototxt(cproto), mindata); return 1; } if (log_IsKept(LogDEBUG)) { if (estab != -1) { len = strlen(dbuff); snprintf(dbuff + len, sizeof dbuff - len, ", estab = %d, syn = %d, finrst = %d", estab, syn, finrst); } log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", prototxt(cproto), dbuff); } gotinfo = 1; } if (log_IsKept(LogDEBUG)) { if (fp->f_srcop != OP_NONE) { snprintf(dbuff, sizeof dbuff, ", src %s %d", filter_Op2Nam(fp->f_srcop), fp->f_srcport); len = strlen(dbuff); } else len = 0; if (fp->f_dstop != OP_NONE) { snprintf(dbuff + len, sizeof dbuff - len, ", dst %s %d", filter_Op2Nam(fp->f_dstop), fp->f_dstport); } else if (!len) *dbuff = '\0'; log_Printf(LogDEBUG, " rule = %d: Address match, " "check against proto %d%s, action = %s\n", n, fp->f_proto, dbuff, filter_Action2Nam(fp->f_action)); } if (cproto == fp->f_proto) { if ((fp->f_srcop == OP_NONE || PortMatch(fp->f_srcop, sport, fp->f_srcport)) && (fp->f_dstop == OP_NONE || PortMatch(fp->f_dstop, dport, fp->f_dstport)) && (fp->f_estab == 0 || estab) && (fp->f_syn == 0 || syn) && (fp->f_finrst == 0 || finrst)) { match = 1; } } } else { /* Address is matched and no protocol specified. Make a decision. */ log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, filter_Action2Nam(fp->f_action)); match = 1; } } else log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); if (match != fp->f_invert) { /* Take specified action */ if (fp->f_action < A_NONE) fp = &filter->rule[n = fp->f_action]; else { if (fp->f_action == A_PERMIT) { if (psecs != NULL) *psecs = fp->timeout; if (strcmp(filter->name, "DIAL") == 0) { /* If dial filter then even print out accept packets */ if (log_IsKept(LogFILTER)) { snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr)); log_Printf(LogFILTER, "%sbound rule = %d accept %s " "src = %s:%d dst = %s:%d\n", filter->name, n, prototxt(cproto), ncpaddr_ntoa(&srcaddr), sport, dstip, dport); } } return 0; } else { if (log_IsKept(LogFILTER)) { snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr)); log_Printf(LogFILTER, "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n", filter->name, n, prototxt(cproto), ncpaddr_ntoa(&srcaddr), sport, dstip, dport); } return 1; } /* Explicit match. Deny this packet */ } } else { n++; fp++; } } if (log_IsKept(LogFILTER)) { snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr)); log_Printf(LogFILTER, "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n", filter->name, prototxt(cproto), ncpaddr_ntoa(&srcaddr), sport, dstip, dport); } return 1; /* No rule matched, deny this packet */ } static void ip_LogDNS(const struct udphdr *uh, const char *direction) { struct dns_header header; const u_short *pktptr; const u_char *ptr; u_short *hptr, tmp; unsigned len; ptr = (const char *)uh + sizeof *uh; len = ntohs(uh->uh_ulen) - sizeof *uh; if (len < sizeof header + 5) /* rfc1024 */ return; pktptr = (const u_short *)ptr; hptr = (u_short *)&header; ptr += sizeof header; len -= sizeof header; while (pktptr < (const u_short *)ptr) { *hptr++ = ntohs(*pktptr); /* Careful of macro side-effects ! */ pktptr++; } if (header.opcode == OPCODE_QUERY && header.qr == 0) { /* rfc1035 */ char namewithdot[MAXHOSTNAMELEN + 1], *n; const char *qtype, *qclass; const u_char *end; n = namewithdot; end = ptr + len - 4; if (end - ptr >= (int)sizeof namewithdot) end = ptr + sizeof namewithdot - 1; while (ptr < end) { len = *ptr++; if ((int)len > end - ptr) len = end - ptr; if (n != namewithdot) *n++ = '.'; memcpy(n, ptr, len); ptr += len; n += len; } *n = '\0'; if (log_IsKept(LogDNS)) { memcpy(&tmp, end, sizeof tmp); qtype = dns_Qtype2Txt(ntohs(tmp)); memcpy(&tmp, end + 2, sizeof tmp); qclass = dns_Qclass2Txt(ntohs(tmp)); log_Printf(LogDNS, "%sbound query %s %s %s\n", direction, qclass, qtype, namewithdot); } } } /* * Check if the given packet matches the given filter. * One of pip or pip6 must be set. */ int PacketCheck(struct bundle *bundle, u_int32_t family, const unsigned char *packet, int nb, struct filter *filter, const char *prefix, unsigned *psecs) { char logbuf[200]; static const char *const TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; const struct tcphdr *th; const struct udphdr *uh; const struct icmp *icmph; #ifndef NOINET6 const struct icmp6_hdr *icmp6h; #endif const unsigned char *payload; struct ncpaddr srcaddr, dstaddr; int cproto, mask, len, n, pri, logit, result, datalen, frag; unsigned loglen; u_char tos; logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) && (!filter || filter->logok); loglen = 0; pri = 0; #ifndef NOINET6 if (family == AF_INET6) { const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet; ncpaddr_setip6(&srcaddr, &pip6->ip6_src); ncpaddr_setip6(&dstaddr, &pip6->ip6_dst); datalen = ntohs(pip6->ip6_plen); payload = packet + sizeof *pip6; cproto = pip6->ip6_nxt; tos = 0; /* XXX: pip6->ip6_vfc >> 4 ? */ frag = 0; /* XXX: ??? */ } else #endif { const struct ip *pip = (const struct ip *)packet; ncpaddr_setip4(&srcaddr, pip->ip_src); ncpaddr_setip4(&dstaddr, pip->ip_dst); datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2); payload = packet + (pip->ip_hl << 2); cproto = pip->ip_p; tos = pip->ip_tos; frag = ntohs(pip->ip_off) & IP_OFFMASK; } uh = NULL; if (logit && loglen < sizeof logbuf) { if (prefix) snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix); else if (filter) snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); else snprintf(logbuf + loglen, sizeof logbuf - loglen, " "); loglen += strlen(logbuf + loglen); } switch (cproto) { case IPPROTO_ICMP: if (logit && loglen < sizeof logbuf) { len = datalen - sizeof *icmph; icmph = (const struct icmp *)payload; snprintf(logbuf + loglen, sizeof logbuf - loglen, "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmph->icmp_type); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb); loglen += strlen(logbuf + loglen); } break; #ifndef NOINET6 case IPPROTO_ICMPV6: if (logit && loglen < sizeof logbuf) { len = datalen - sizeof *icmp6h; icmp6h = (const struct icmp6_hdr *)payload; snprintf(logbuf + loglen, sizeof logbuf - loglen, "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmp6h->icmp6_type); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb); loglen += strlen(logbuf + loglen); } break; #endif case IPPROTO_UDP: uh = (const struct udphdr *)payload; if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos) pri++; if (!frag && ncp_IsUrgentUdpPort(&bundle->ncp, ntohs(uh->uh_sport), ntohs(uh->uh_dport))) pri++; if (logit && loglen < sizeof logbuf) { len = datalen - sizeof *uh; snprintf(logbuf + loglen, sizeof logbuf - loglen, "UDP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s:%d (%d/%d)", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport), len, nb); loglen += strlen(logbuf + loglen); } if (Enabled(bundle, OPT_FILTERDECAP) && payload[sizeof *uh] == HDLC_ADDR && payload[sizeof *uh + 1] == HDLC_UI) { u_short proto; const char *type; memcpy(&proto, payload + sizeof *uh + 2, sizeof proto); type = NULL; switch (ntohs(proto)) { case PROTO_IP: snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains "); result = PacketCheck(bundle, AF_INET, payload + sizeof *uh + 4, nb - (payload - packet) - sizeof *uh - 4, filter, logbuf, psecs); if (result != -2) return result; type = "IP"; break; case PROTO_VJUNCOMP: type = "compressed VJ"; break; case PROTO_VJCOMP: type = "uncompressed VJ"; break; case PROTO_MP: type = "Multi-link"; break; case PROTO_ICOMPD: type = "Individual link CCP"; break; case PROTO_COMPD: type = "CCP"; break; case PROTO_IPCP: type = "IPCP"; break; case PROTO_LCP: type = "LCP"; break; case PROTO_PAP: type = "PAP"; break; case PROTO_CBCP: type = "CBCP"; break; case PROTO_LQR: type = "LQR"; break; case PROTO_CHAP: type = "CHAP"; break; } if (type) { snprintf(logbuf + loglen, sizeof logbuf - loglen, " - %s data", type); loglen += strlen(logbuf + loglen); } } break; #ifdef IPPROTO_GRE case IPPROTO_GRE: if (logit && loglen < sizeof logbuf) { snprintf(logbuf + loglen, sizeof logbuf - loglen, "GRE: %s ---> ", ncpaddr_ntoa(&srcaddr)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb); loglen += strlen(logbuf + loglen); } break; #endif #ifdef IPPROTO_OSPFIGP case IPPROTO_OSPFIGP: if (logit && loglen < sizeof logbuf) { snprintf(logbuf + loglen, sizeof logbuf - loglen, "OSPF: %s ---> ", ncpaddr_ntoa(&srcaddr)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb); loglen += strlen(logbuf + loglen); } break; #endif #ifndef NOINET6 case IPPROTO_IPV6: if (logit && loglen < sizeof logbuf) { snprintf(logbuf + loglen, sizeof logbuf - loglen, "IPv6: %s ---> ", ncpaddr_ntoa(&srcaddr)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb); loglen += strlen(logbuf + loglen); } if (Enabled(bundle, OPT_FILTERDECAP)) { snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains "); result = PacketCheck(bundle, AF_INET6, payload, nb - (payload - packet), filter, logbuf, psecs); if (result != -2) return result; } break; #endif case IPPROTO_IPIP: if (logit && loglen < sizeof logbuf) { snprintf(logbuf + loglen, sizeof logbuf - loglen, "IPIP: %s ---> ", ncpaddr_ntoa(&srcaddr)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", ncpaddr_ntoa(&dstaddr)); loglen += strlen(logbuf + loglen); } if (Enabled(bundle, OPT_FILTERDECAP) && ((const struct ip *)payload)->ip_v == 4) { snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains "); result = PacketCheck(bundle, AF_INET, payload, nb - (payload - packet), filter, logbuf, psecs); loglen += strlen(logbuf + loglen); if (result != -2) return result; } break; case IPPROTO_ESP: if (logit && loglen < sizeof logbuf) { snprintf(logbuf + loglen, sizeof logbuf - loglen, "ESP: %s ---> ", ncpaddr_ntoa(&srcaddr)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p", ncpaddr_ntoa(&dstaddr), payload); loglen += strlen(logbuf + loglen); } break; case IPPROTO_AH: if (logit && loglen < sizeof logbuf) { snprintf(logbuf + loglen, sizeof logbuf - loglen, "AH: %s ---> ", ncpaddr_ntoa(&srcaddr)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p", ncpaddr_ntoa(&dstaddr), payload + sizeof(u_int32_t)); loglen += strlen(logbuf + loglen); } break; case IPPROTO_IGMP: if (logit && loglen < sizeof logbuf) { uh = (const struct udphdr *)payload; snprintf(logbuf + loglen, sizeof logbuf - loglen, "IGMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport)); loglen += strlen(logbuf + loglen); } break; case IPPROTO_TCP: th = (const struct tcphdr *)payload; if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos) pri++; if (!frag && ncp_IsUrgentTcpPort(&bundle->ncp, ntohs(th->th_sport), ntohs(th->th_dport))) pri++; if (logit && loglen < sizeof logbuf) { len = datalen - (th->th_off << 2); snprintf(logbuf + loglen, sizeof logbuf - loglen, "TCP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(th->th_sport)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(th->th_dport)); loglen += strlen(logbuf + loglen); n = 0; for (mask = TH_FIN; mask != 0x40; mask <<= 1) { if (th->th_flags & mask) { snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); loglen += strlen(logbuf + loglen); } n++; } snprintf(logbuf + loglen, sizeof logbuf - loglen, " seq:%lx ack:%lx (%d/%d)", (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); loglen += strlen(logbuf + loglen); if ((th->th_flags & TH_SYN) && nb > 40) { const u_short *sp; sp = (const u_short *)(payload + 20); if (ntohs(sp[0]) == 0x0204) { snprintf(logbuf + loglen, sizeof logbuf - loglen, " MSS = %d", ntohs(sp[1])); loglen += strlen(logbuf + loglen); } } } break; default: if (prefix) return -2; if (logit && loglen < sizeof logbuf) { snprintf(logbuf + loglen, sizeof logbuf - loglen, "<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr)); loglen += strlen(logbuf + loglen); snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s (%d)", ncpaddr_ntoa(&dstaddr), nb); loglen += strlen(logbuf + loglen); } break; } if (filter && FilterCheck(packet, family, filter, psecs)) { if (logit) log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); result = -1; } else { /* Check Keep Alive filter */ if (logit && log_IsKept(LogTCPIP)) { unsigned alivesecs; alivesecs = 0; if (filter && FilterCheck(packet, family, &bundle->filter.alive, &alivesecs)) log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); else if (psecs != NULL) { if(*psecs == 0) *psecs = alivesecs; if (*psecs) { if (*psecs != alivesecs) log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n", logbuf, *psecs, alivesecs); else log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs); } else log_Printf(LogTCPIP, "%s\n", logbuf); } } result = pri; } if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS)) ip_LogDNS(uh, filter->name); return result; } static size_t ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af) { ssize_t nw; size_t nb; struct tun_data tun; char *data; unsigned secs, alivesecs; nb = m_length(bp); if (nb > sizeof tun.data) { log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %zd, max %d)\n", l->name, nb, (int)(sizeof tun.data)); m_freem(bp); return 0; } mbuf_Read(bp, tun.data, nb); secs = 0; if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in, NULL, &secs) < 0) return 0; alivesecs = 0; if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) { if (secs == 0) secs = alivesecs; bundle_StartIdleTimer(bundle, secs); } if (bundle->dev.header) { tun.header.family = htonl(af); nb += sizeof tun - sizeof tun.data; data = (char *)&tun; } else data = tun.data; nw = write(bundle->dev.fd, data, nb); if (nw != (ssize_t)nb) { if (nw == -1) log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %s\n", l->name, nb, strerror(errno)); else log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %zd\n", l->name, nb, nw); } return nb; } struct mbuf * ipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) { int nb; if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n"); m_freem(bp); return NULL; } m_settype(bp, MB_IPIN); nb = ip_Input(bundle, l, bp, AF_INET); ipcp_AddInOctets(&bundle->ncp.ipcp, nb); return NULL; } #ifndef NOINET6 struct mbuf * ipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) { int nb; if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) { log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n"); m_freem(bp); return NULL; } m_settype(bp, MB_IPV6IN); nb = ip_Input(bundle, l, bp, AF_INET6); ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb); return NULL; } #endif Index: stable/10/usr.sbin/ppp/ipv6cp.c =================================================================== --- stable/10/usr.sbin/ppp/ipv6cp.c (revision 330804) +++ stable/10/usr.sbin/ppp/ipv6cp.c (revision 330805) @@ -1,786 +1,786 @@ /*- * Copyright (c) 2001 Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "layer.h" #include "defs.h" #include "mbuf.h" #include "timer.h" #include "fsm.h" #include "iplist.h" #include "throughput.h" #include "slcompress.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "ncpaddr.h" #include "ip.h" #include "ipcp.h" #include "ipv6cp.h" #include "filter.h" #include "descriptor.h" #include "ccp.h" #include "link.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "ncp.h" #include "bundle.h" #include "route.h" #include "iface.h" #include "log.h" #include "proto.h" #include "command.h" #include "prompt.h" #include "async.h" #include "physical.h" #include "probe.h" #include "systems.h" #ifndef NOINET6 #define IN6ADDR_LINKLOCAL_MCAST_INIT \ {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} static const struct in6_addr in6addr_linklocal_mcast = IN6ADDR_LINKLOCAL_MCAST_INIT; static int ipv6cp_LayerUp(struct fsm *); static void ipv6cp_LayerDown(struct fsm *); static void ipv6cp_LayerStart(struct fsm *); static void ipv6cp_LayerFinish(struct fsm *); static void ipv6cp_InitRestartCounter(struct fsm *, int); static void ipv6cp_SendConfigReq(struct fsm *); static void ipv6cp_SentTerminateReq(struct fsm *); static void ipv6cp_SendTerminateAck(struct fsm *, u_char); static void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int, struct fsm_decode *); static struct fsm_callbacks ipv6cp_Callbacks = { ipv6cp_LayerUp, ipv6cp_LayerDown, ipv6cp_LayerStart, ipv6cp_LayerFinish, ipv6cp_InitRestartCounter, ipv6cp_SendConfigReq, ipv6cp_SentTerminateReq, ipv6cp_SendTerminateAck, ipv6cp_DecodeConfig, fsm_NullRecvResetReq, fsm_NullRecvResetAck }; static void SetInterfaceID(u_char *ifid, int userandom) { struct ifaddrs *ifa, *ifap = NULL; struct sockaddr_dl *sdl; const u_long i32_max = 0xffffffff; u_long r1, r2; /* configure an interface ID based on Section 4.1 of RFC 2472 */ memset(ifid, 0, IPV6CP_IFIDLEN); /* * 1) If an IEEE global identifier (EUI-48 or EUI-64) is * available anywhere on the node, it should be used to construct * the tentative Interface-Identifier due to its uniqueness * properties. */ if (userandom) goto randomid; if (getifaddrs(&ifap) < 0) goto randomid; for (ifa = ifap; ifa; ifa = ifa->ifa_next) { char *cp; if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; if (sdl->sdl_alen < 6) continue; /* we're only interested in IEEE hardware addresses */ switch(sdl->sdl_type) { case IFT_ETHER: case IFT_FDDI: case IFT_L2VLAN: /* XXX need more cases? */ break; default: continue; } cp = (char *)(sdl->sdl_data + sdl->sdl_nlen); ifid[0] = cp[0]; ifid[0] ^= 0x02; /* reverse the u/l bit*/ ifid[1] = cp[1]; ifid[2] = cp[2]; ifid[3] = 0xff; ifid[4] = 0xfe; ifid[5] = cp[3]; ifid[6] = cp[4]; ifid[7] = cp[5]; freeifaddrs(ifap); return; } freeifaddrs(ifap); /* * 2) If an IEEE global identifier is not available a different source * of uniqueness should be used. * XXX: we skip this case. */ /* * 3) If a good source of uniqueness cannot be found, it is * recommended that a random number be generated. In this case the * "u" bit of the interface identifier MUST be set to zero (0). */ randomid: randinit(); r1 = (((u_long)random()) % i32_max) + 1; r2 = (((u_long)random()) % i32_max) + 1; memcpy(ifid, &r1, sizeof(r1)); memcpy(ifid + 4, &r2, sizeof(r2)); ifid[0] &= 0xfd; return; } static int ipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid) { struct bundle *bundle = ipv6cp->fsm.bundle; struct in6_addr myaddr, hisaddr; struct ncprange myrange, range; struct ncpaddr addr; struct sockaddr_storage ssdst, ssgw, ssmask; struct sockaddr *sadst, *sagw, *samask; sadst = (struct sockaddr *)&ssdst; sagw = (struct sockaddr *)&ssgw; samask = (struct sockaddr *)&ssmask; memset(&myaddr, '\0', sizeof myaddr); memset(&hisaddr, '\0', sizeof hisaddr); myaddr.s6_addr[0] = 0xfe; myaddr.s6_addr[1] = 0x80; memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN); #if 0 myaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ #endif hisaddr.s6_addr[0] = 0xfe; hisaddr.s6_addr[1] = 0x80; memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN); #if 0 hisaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ #endif ncpaddr_setip6(&ipv6cp->myaddr, &myaddr); ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr); ncprange_set(&myrange, &ipv6cp->myaddr, 64); if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr, IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) return 0; if (!Enabled(bundle, OPT_IFACEALIAS)) iface_Clear(bundle->iface, &bundle->ncp, AF_INET6, IFACE_CLEAR_ALIASES|IFACE_SYSTEM); ncpaddr_setip6(&addr, &in6addr_linklocal_mcast); ncprange_set(&range, &addr, 32); rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0); if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { ncprange_getsa(&myrange, &ssgw, &ssmask); if (ncpaddr_isset(&ipv6cp->hisaddr)) ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst); else sadst = NULL; rt_Update(bundle, sadst, sagw, samask, NULL, NULL); } if (Enabled(bundle, OPT_SROUTES)) route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr); #ifndef NORADIUS if (bundle->radius.valid) route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr, &ipv6cp->hisaddr); #endif return 1; /* Ok */ } void ipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l, const struct fsm_parent *parent) { static const char * const timer_names[] = {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"}; int n; fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP, bundle, l, parent, &ipv6cp_Callbacks, timer_names); ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY; ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES; ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES; SetInterfaceID(ipv6cp->my_ifid, 0); do { SetInterfaceID(ipv6cp->his_ifid, 1); } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); if (probe.ipv6_available) { n = 100; while (n && !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { do { n--; SetInterfaceID(ipv6cp->my_ifid, 1); } while (n && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); } } throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD); memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue); ipv6cp_Setup(ipv6cp); } void ipv6cp_Destroy(struct ipv6cp *ipv6cp) { throughput_destroy(&ipv6cp->throughput); } void ipv6cp_Setup(struct ipv6cp *ipv6cp) { ncpaddr_init(&ipv6cp->myaddr); ncpaddr_init(&ipv6cp->hisaddr); ipv6cp->his_reject = 0; ipv6cp->my_reject = 0; } void ipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l) { ipv6cp->fsm.link = l; } int ipv6cp_Show(struct cmdargs const *arg) { struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp; prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name, State2Nam(ipv6cp->fsm.state)); if (ipv6cp->fsm.state == ST_OPENED) { prompt_Printf(arg->prompt, " His side: %s\n", ncpaddr_ntoa(&ipv6cp->hisaddr)); prompt_Printf(arg->prompt, " My side: %s\n", ncpaddr_ntoa(&ipv6cp->myaddr)); prompt_Printf(arg->prompt, " Queued packets: %lu\n", (unsigned long)ipv6cp_QueueLen(ipv6cp)); } prompt_Printf(arg->prompt, "\nDefaults:\n"); prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout, ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s", ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s"); throughput_disp(&ipv6cp->throughput, arg->prompt); return 0; } struct mbuf * ipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) { /* Got PROTO_IPV6CP from link */ m_settype(bp, MB_IPV6CPIN); if (bundle_Phase(bundle) == PHASE_NETWORK) fsm_Input(&bundle->ncp.ipv6cp.fsm, bp); else { if (bundle_Phase(bundle) < PHASE_NETWORK) log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s" " (ignored)\n", l->name, bundle_PhaseName(bundle)); m_freem(bp); } return NULL; } void ipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n) { throughput_addin(&ipv6cp->throughput, n); } void ipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n) { throughput_addout(&ipv6cp->throughput, n); } void ipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused, const struct iface_addr *addr __unused) { } void ipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused, const struct iface_addr *addr __unused) { } int ipv6cp_InterfaceUp(struct ipv6cp *ipv6cp) { if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n"); return 0; } if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) { log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP" " flag on %s\n", ipv6cp->fsm.bundle->iface->name); return 0; } return 1; } size_t ipv6cp_QueueLen(struct ipv6cp *ipv6cp) { struct mqueue *q; size_t result; result = 0; for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++) result += q->len; return result; } int ipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l) { struct bundle *bundle = ipv6cp->fsm.bundle; struct mqueue *queue; struct mbuf *bp; int m_len; u_int32_t secs = 0; unsigned alivesecs = 0; if (ipv6cp->fsm.state != ST_OPENED) return 0; /* * If ccp is not open but is required, do nothing. */ if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); return 0; } queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1; do { if (queue->top) { bp = m_dequeue(queue); bp = mbuf_Read(bp, &secs, sizeof secs); bp = m_pullup(bp); m_len = m_length(bp); if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive, &alivesecs)) { if (secs == 0) secs = alivesecs; bundle_StartIdleTimer(bundle, secs); } link_PushPacket(l, bp, bundle, 0, PROTO_IPV6); ipv6cp_AddOutOctets(ipv6cp, m_len); return 1; } } while (queue-- != ipv6cp->Queue); return 0; } static int ipv6cp_LayerUp(struct fsm *fp) { /* We're now up */ struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); - char tbuff[40]; + char tbuff[NCP_ASCIIBUFFERSIZE]; log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name); if (!ipv6cp_InterfaceUp(ipv6cp)) return 0; snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n", tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr)); #ifndef NORADIUS radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid); radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, fp->bundle->links, RAD_START, &ipv6cp->throughput); /* * XXX: Avoid duplicate evaluation of filterid between IPCP and * IPV6CP. When IPCP is enabled and rejected, filterid is not * evaluated. */ if (!Enabled(fp->bundle, OPT_IPCP)) { if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE, NULL, NULL); } #endif /* * XXX this stuff should really live in the FSM. Our config should * associate executable sections in files with events. */ if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { /* * XXX: Avoid duplicate evaluation of label between IPCP and * IPV6CP. When IPCP is enabled and rejected, label is not * evaluated. */ if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), LINKUPFILE, NULL, NULL) < 0) system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); } else system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); } fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; log_DisplayPrompts(); return 1; } static void ipv6cp_LayerDown(struct fsm *fp) { /* About to come down */ struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); static int recursing; - char addr[40]; + char addr[NCP_ASCIIBUFFERSIZE]; if (!recursing++) { snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr); #ifndef NORADIUS radius_Flush(&fp->bundle->radius); radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, fp->bundle->links, RAD_STOP, &ipv6cp->throughput); /* * XXX: Avoid duplicate evaluation of filterid between IPCP and * IPV6CP. When IPCP is enabled and rejected, filterid is not * evaluated. */ if (!Enabled(fp->bundle, OPT_IPCP)) { if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE, NULL, NULL); } #endif /* * XXX this stuff should really live in the FSM. Our config should * associate executable sections in files with events. */ if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) { /* * XXX: Avoid duplicate evaluation of label between IPCP and * IPV6CP. When IPCP is enabled and rejected, label is not * evaluated. */ if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), LINKDOWNFILE, NULL, NULL) < 0) system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); } else system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); } ipv6cp_Setup(ipv6cp); } recursing--; } static void ipv6cp_LayerStart(struct fsm *fp) { /* We're about to start up ! */ struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name); throughput_start(&ipv6cp->throughput, "IPV6CP throughput", Enabled(fp->bundle, OPT_THROUGHPUT)); fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; ipv6cp->peer_tokenreq = 0; } static void ipv6cp_LayerFinish(struct fsm *fp) { /* We're now down */ struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name); throughput_stop(&ipv6cp->throughput); throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL); } static void ipv6cp_InitRestartCounter(struct fsm *fp, int what) { /* Set fsm timer load */ struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS; switch (what) { case FSM_REQ_TIMER: fp->restart = ipv6cp->cfg.fsm.maxreq; break; case FSM_TRM_TIMER: fp->restart = ipv6cp->cfg.fsm.maxtrm; break; default: fp->restart = 1; break; } } static void ipv6cp_SendConfigReq(struct fsm *fp) { /* Send config REQ please */ struct physical *p = link2physical(fp->link); struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); u_char buff[IPV6CP_IFIDLEN+2]; struct fsm_opt *o; o = (struct fsm_opt *)buff; if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) { memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN); INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o); } fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, MB_IPV6CPOUT); } static void ipv6cp_SentTerminateReq(struct fsm *fp __unused) { /* Term REQ just sent by FSM */ } static void ipv6cp_SendTerminateAck(struct fsm *fp, u_char id) { /* Send Term ACK please */ fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT); } static const char * protoname(unsigned proto) { static const char *cftypes[] = { "IFACEID", "COMPPROTO" }; if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes) return cftypes[proto - 1]; return NumStr(proto, NULL, 0); } static void ipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid, struct fsm_decode *dec) { struct fsm_opt opt; u_char zero[IPV6CP_IFIDLEN]; memset(zero, 0, IPV6CP_IFIDLEN); if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0 && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN); opt.hdr.id = TY_TOKEN; opt.hdr.len = IPV6CP_IFIDLEN + 2; memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN); if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) fsm_ack(dec, &opt); else fsm_nak(dec, &opt); } static void ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, struct fsm_decode *dec) { /* Deal with incoming PROTO_IPV6CP */ struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); int n; char tbuff[100]; u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN]; struct fsm_opt *opt; memset(zero, 0, IPV6CP_IFIDLEN); while (end - cp >= (int)sizeof(opt->hdr)) { if ((opt = fsm_readopt(&cp)) == NULL) break; snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id), opt->hdr.len); switch (opt->hdr.id) { case TY_TOKEN: memcpy(ifid, opt->data, IPV6CP_IFIDLEN); log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); switch (mode_type) { case MODE_REQ: ipv6cp->peer_tokenreq = 1; ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); break; case MODE_NAK: if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) { log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, "0x0000000000000000: Unacceptable IntefaceID!\n"); fsm_Close(&ipv6cp->fsm); } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) { log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, "0x%02x%02x%02x%02x%02x%02x%02x%02x: " "Unacceptable IntefaceID!\n", ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) { n = 100; while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) { do { n--; SetInterfaceID(ifid, 1); } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0); } if (n == 0) { log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, "0x0000000000000000: Unacceptable IntefaceID!\n"); fsm_Close(&ipv6cp->fsm); } else { log_Printf(LogIPV6CP, "%s changing IntefaceID: " "0x%02x%02x%02x%02x%02x%02x%02x%02x " "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, ipv6cp->my_ifid[0], ipv6cp->my_ifid[1], ipv6cp->my_ifid[2], ipv6cp->my_ifid[3], ipv6cp->my_ifid[4], ipv6cp->my_ifid[5], ipv6cp->my_ifid[6], ipv6cp->my_ifid[7], ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN); bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL); } } break; case MODE_REJ: ipv6cp->his_reject |= (1 << opt->hdr.id); break; } break; default: if (mode_type != MODE_NOP) { ipv6cp->my_reject |= (1 << opt->hdr.id); fsm_rej(dec, opt); } break; } } if (mode_type != MODE_NOP) { if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) { if (dec->rejend == dec->rej && dec->nakend == dec->nak) { /* * Pretend the peer has requested a TOKEN. * We do this to ensure that we only send one NAK if the only * reason for the NAK is because the peer isn't sending a * TY_TOKEN REQ. This stops us from repeatedly trying to tell * the peer that we have to have an IP address on their end. */ ipv6cp->peer_tokenreq = 1; } memset(ifid, 0, IPV6CP_IFIDLEN); ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); } fsm_opt_normalise(dec); } } #endif Index: stable/10/usr.sbin/ppp/ncpaddr.c =================================================================== --- stable/10/usr.sbin/ppp/ncpaddr.c (revision 330804) +++ stable/10/usr.sbin/ppp/ncpaddr.c (revision 330805) @@ -1,1010 +1,1008 @@ /*- * Copyright (c) 2001 Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #ifdef __OpenBSD__ #include #include #endif #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "ncpaddr.h" #include "timer.h" #include "fsm.h" #include "defs.h" #include "slcompress.h" #include "iplist.h" #include "throughput.h" #include "mbuf.h" #include "ipcp.h" #include "descriptor.h" #include "layer.h" #include "lqr.h" #include "hdlc.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "mp.h" #include "ipv6cp.h" #include "ncp.h" #define ncprange_ip4addr u.ip4.ipaddr #define ncprange_ip4mask u.ip4.mask #define ncprange_ip4width u.ip4.width #define ncpaddr_ip4addr u.ip4addr #ifndef NOINET6 #define ncprange_ip6addr u.ip6.ipaddr #define ncprange_ip6width u.ip6.width #define ncpaddr_ip6addr u.ip6addr #endif -#define NCP_ASCIIBUFFERSIZE 52 - static struct in_addr bits2mask4(int bits) { struct in_addr result; u_int32_t bit = 0x80000000; result.s_addr = 0; while (bits) { result.s_addr |= bit; bit >>= 1; bits--; } result.s_addr = htonl(result.s_addr); return result; } static int mask42bits(struct in_addr mask) { u_int32_t msk = ntohl(mask.s_addr); u_int32_t tst; int ret; for (ret = 32, tst = 1; tst; ret--, tst <<= 1) if (msk & tst) break; for (tst <<= 1; tst; tst <<= 1) if (!(msk & tst)) break; return tst ? -1 : ret; } #ifndef NOINET6 static struct in6_addr bits2mask6(int bits) { struct in6_addr result; u_int32_t bit = 0x80; u_char *c = result.s6_addr; memset(&result, '\0', sizeof result); while (bits) { if (bit == 0) { bit = 0x80; c++; } *c |= bit; bit >>= 1; bits--; } return result; } static int mask62bits(const struct in6_addr *mask) { const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; const u_char *c, *p, *end; int masklen, m; p = (const u_char *)mask; for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) masklen += 8; if (p < end) { for (c = masks, m = 0; c < masks + sizeof masks; c++, m++) if (*c == *p) { masklen += m; break; } } return masklen; } #if 0 static void adjust_linklocal(struct sockaddr_in6 *sin6) { /* XXX: ?????!?!?!!!!! This is horrible ! */ /* * The kernel does not understand sin6_scope_id for routing at this moment. * We should rather keep the embedded ID. * jinmei@kame.net, 20011026 */ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) { sin6->sin6_scope_id = ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]); *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0; } } #endif #endif void ncpaddr_init(struct ncpaddr *addr) { addr->ncpaddr_family = AF_UNSPEC; } int ncpaddr_isset(const struct ncpaddr *addr) { return addr->ncpaddr_family != AF_UNSPEC; } int ncpaddr_isdefault(const struct ncpaddr *addr) { switch (addr->ncpaddr_family) { case AF_INET: if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY) return 1; break; #ifndef NOINET6 case AF_INET6: if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr)) return 1; break; #endif } return 0; } int ncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp) { if (addr->ncpaddr_family != cmp->ncpaddr_family) return 0; switch (addr->ncpaddr_family) { case AF_INET: return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr; #ifndef NOINET6 case AF_INET6: return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr, sizeof addr->ncpaddr_ip6addr); #endif case AF_UNSPEC: return 1; } return 0; } void ncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from) { switch (from->ncpaddr_family) { case AF_INET: addr->ncpaddr_family = AF_INET; addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr; break; #ifndef NOINET6 case AF_INET6: addr->ncpaddr_family = AF_INET6; addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr; break; #endif default: addr->ncpaddr_family = AF_UNSPEC; } } void ncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip) { addr->ncpaddr_family = AF_INET; addr->ncpaddr_ip4addr.s_addr = ip; } int ncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip) { if (addr->ncpaddr_family != AF_INET) return 0; *ip = addr->ncpaddr_ip4addr.s_addr; return 1; } void ncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip) { addr->ncpaddr_family = AF_INET; addr->ncpaddr_ip4addr = ip; } int ncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip) { if (addr->ncpaddr_family != AF_INET) return 0; *ip = addr->ncpaddr_ip4addr; return 1; } #ifndef NOINET6 void ncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6) { addr->ncpaddr_family = AF_INET6; addr->ncpaddr_ip6addr = *ip6; } int ncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6) { if (addr->ncpaddr_family != AF_INET6) return 0; *ip6 = addr->ncpaddr_ip6addr; return 1; } #endif void ncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host) { struct sockaddr_in *host4 = (struct sockaddr_in *)host; #ifndef NOINET6 struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; #endif memset(host, '\0', sizeof(*host)); switch (addr->ncpaddr_family) { case AF_INET: host4->sin_family = AF_INET; host4->sin_len = sizeof(*host4); host4->sin_addr = addr->ncpaddr_ip4addr; break; #ifndef NOINET6 case AF_INET6: host6->sin6_family = AF_INET6; host6->sin6_len = sizeof(*host6); host6->sin6_addr = addr->ncpaddr_ip6addr; break; #endif default: host->ss_family = AF_UNSPEC; break; } } void ncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host) { const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; #ifndef NOINET6 const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; #endif switch (host->sa_family) { case AF_INET: addr->ncpaddr_family = AF_INET; addr->ncpaddr_ip4addr = host4->sin_addr; break; #ifndef NOINET6 case AF_INET6: if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) { addr->ncpaddr_family = AF_INET; addr->ncpaddr_ip4addr.s_addr = *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12); } else { addr->ncpaddr_family = AF_INET6; addr->ncpaddr_ip6addr = host6->sin6_addr; } break; #endif default: addr->ncpaddr_family = AF_UNSPEC; } } static char * ncpaddr_ntowa(const struct ncpaddr *addr) { static char res[NCP_ASCIIBUFFERSIZE]; #ifndef NOINET6 struct sockaddr_in6 sin6; #endif switch (addr->ncpaddr_family) { case AF_INET: snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr)); return res; #ifndef NOINET6 case AF_INET6: memset(&sin6, '\0', sizeof(sin6)); sin6.sin6_len = sizeof(sin6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = addr->ncpaddr_ip6addr; #if 0 adjust_linklocal(&sin6); #endif if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res), NULL, 0, NI_NUMERICHOST) != 0) break; return res; #endif } snprintf(res, sizeof res, ""); return res; } const char * ncpaddr_ntoa(const struct ncpaddr *addr) { return ncpaddr_ntowa(addr); } int ncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data) { struct ncprange range; if (!ncprange_aton(&range, ncp, data)) return 0; if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32 && range.ncprange_ip4addr.s_addr != INADDR_ANY) { log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data); return 0; } #ifndef NOINET6 if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128 && !IN6_IS_ADDR_UNSPECIFIED(&range.ncprange_ip6addr)) { log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data); return 0; } #endif switch (range.ncprange_family) { case AF_INET: addr->ncpaddr_family = range.ncprange_family; addr->ncpaddr_ip4addr = range.ncprange_ip4addr; return 1; #ifndef NOINET6 case AF_INET6: addr->ncpaddr_family = range.ncprange_family; addr->ncpaddr_ip6addr = range.ncprange_ip6addr; return 1; #endif } return 0; } void ncprange_init(struct ncprange *range) { range->ncprange_family = AF_UNSPEC; } int ncprange_isset(const struct ncprange *range) { return range->ncprange_family != AF_UNSPEC; } int ncprange_equal(const struct ncprange *range, const struct ncprange *cmp) { if (range->ncprange_family != cmp->ncprange_family) return 0; switch (range->ncprange_family) { case AF_INET: if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr) return 0; return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr; #ifndef NOINET6 case AF_INET6: if (range->ncprange_ip6width != cmp->ncprange_ip6width) return 0; return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr, sizeof range->ncprange_ip6addr); #endif case AF_UNSPEC: return 1; } return 0; } int ncprange_isdefault(const struct ncprange *range) { switch (range->ncprange_family) { case AF_INET: if (range->ncprange_ip4addr.s_addr == INADDR_ANY) return 1; break; #ifndef NOINET6 case AF_INET6: if (range->ncprange_ip6width == 0 && IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) return 1; break; #endif } return 0; } void ncprange_setdefault(struct ncprange *range, int af) { memset(range, '\0', sizeof *range); range->ncprange_family = af; } int ncprange_contains(const struct ncprange *range, const struct ncpaddr *addr) { #ifndef NOINET6 const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; const u_char *addrp, *rangep; int bits; #endif if (range->ncprange_family != addr->ncpaddr_family) return 0; switch (range->ncprange_family) { case AF_INET: return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) & range->ncprange_ip4mask.s_addr); #ifndef NOINET6 case AF_INET6: rangep = (const u_char *)range->ncprange_ip6addr.s6_addr; addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr; for (bits = range->ncprange_ip6width; bits > 0; bits -= 8) if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1]) return 0; return 1; #endif } return 0; } int ncprange_containsip4(const struct ncprange *range, struct in_addr addr) { switch (range->ncprange_family) { case AF_INET: return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) & range->ncprange_ip4mask.s_addr); } return 0; } void ncprange_copy(struct ncprange *range, const struct ncprange *from) { switch (from->ncprange_family) { case AF_INET: range->ncprange_family = AF_INET; range->ncprange_ip4addr = from->ncprange_ip4addr; range->ncprange_ip4mask = from->ncprange_ip4mask; range->ncprange_ip4width = from->ncprange_ip4width; break; #ifndef NOINET6 case AF_INET6: range->ncprange_family = AF_INET6; range->ncprange_ip6addr = from->ncprange_ip6addr; range->ncprange_ip6width = from->ncprange_ip6width; break; #endif default: range->ncprange_family = AF_UNSPEC; } } void ncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width) { ncprange_sethost(range, addr); ncprange_setwidth(range, width); } void ncprange_sethost(struct ncprange *range, const struct ncpaddr *from) { switch (from->ncpaddr_family) { case AF_INET: range->ncprange_family = AF_INET; range->ncprange_ip4addr = from->ncpaddr_ip4addr; if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) { range->ncprange_ip4mask.s_addr = INADDR_ANY; range->ncprange_ip4width = 0; } else { range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; } break; #ifndef NOINET6 case AF_INET6: range->ncprange_family = AF_INET6; range->ncprange_ip6addr = from->ncpaddr_ip6addr; range->ncprange_ip6width = 128; break; #endif default: range->ncprange_family = AF_UNSPEC; } } int ncprange_ishost(const struct ncprange *range) { switch (range->ncprange_family) { case AF_INET: return range->ncprange_ip4width == 32; #ifndef NOINET6 case AF_INET6: return range->ncprange_ip6width == 128; #endif } return (0); } int ncprange_setwidth(struct ncprange *range, int width) { switch (range->ncprange_family) { case AF_INET: if (width < 0 || width > 32) break; range->ncprange_ip4width = width; range->ncprange_ip4mask = bits2mask4(width); break; #ifndef NOINET6 case AF_INET6: if (width < 0 || width > 128) break; range->ncprange_ip6width = width; break; #endif case AF_UNSPEC: return 1; } return 0; } void ncprange_setip4host(struct ncprange *range, struct in_addr from) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = from; if (from.s_addr == INADDR_ANY) { range->ncprange_ip4mask.s_addr = INADDR_ANY; range->ncprange_ip4width = 0; } else { range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; } } void ncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = from; range->ncprange_ip4mask = msk; range->ncprange_ip4width = mask42bits(msk); } int ncprange_setip4mask(struct ncprange *range, struct in_addr mask) { if (range->ncprange_family != AF_INET) return 0; range->ncprange_ip4mask = mask; range->ncprange_ip4width = mask42bits(mask); return 1; } void ncprange_setsa(struct ncprange *range, const struct sockaddr *host, const struct sockaddr *mask) { const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; #ifndef NOINET6 const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask; #endif switch (host->sa_family) { case AF_INET: range->ncprange_family = AF_INET; range->ncprange_ip4addr = host4->sin_addr; if (host4->sin_addr.s_addr == INADDR_ANY) { range->ncprange_ip4mask.s_addr = INADDR_ANY; range->ncprange_ip4width = 0; } else if (mask4 && mask4->sin_family == AF_INET) { range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr; range->ncprange_ip4width = mask42bits(mask4->sin_addr); } else { range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; } break; #ifndef NOINET6 case AF_INET6: range->ncprange_family = AF_INET6; range->ncprange_ip6addr = host6->sin6_addr; if (IN6_IS_ADDR_UNSPECIFIED(&host6->sin6_addr)) range->ncprange_ip6width = 0; else range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128; break; #endif default: range->ncprange_family = AF_UNSPEC; } } void ncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host, struct sockaddr_storage *mask) { struct sockaddr_in *host4 = (struct sockaddr_in *)host; struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; #ifndef NOINET6 struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; #endif memset(host, '\0', sizeof(*host)); if (mask) memset(mask, '\0', sizeof(*mask)); switch (range->ncprange_family) { case AF_INET: host4->sin_family = AF_INET; host4->sin_len = sizeof(*host4); host4->sin_addr = range->ncprange_ip4addr; if (mask4) { mask4->sin_family = AF_INET; mask4->sin_len = sizeof(*host4); mask4->sin_addr = range->ncprange_ip4mask; } break; #ifndef NOINET6 case AF_INET6: host6->sin6_family = AF_INET6; host6->sin6_len = sizeof(*host6); host6->sin6_addr = range->ncprange_ip6addr; if (mask6) { mask6->sin6_family = AF_INET6; mask6->sin6_len = sizeof(*host6); mask6->sin6_addr = bits2mask6(range->ncprange_ip6width); } break; #endif default: host->ss_family = AF_UNSPEC; if (mask) mask->ss_family = AF_UNSPEC; break; } } int ncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr) { switch (range->ncprange_family) { case AF_INET: addr->ncpaddr_family = AF_INET; addr->ncpaddr_ip4addr = range->ncprange_ip4addr; return 1; #ifndef NOINET6 case AF_INET6: addr->ncpaddr_family = AF_INET6; addr->ncpaddr_ip6addr = range->ncprange_ip6addr; return 1; #endif } return 0; } int ncprange_getip4addr(const struct ncprange *range, struct in_addr *addr) { if (range->ncprange_family != AF_INET) return 0; *addr = range->ncprange_ip4addr; return 1; } int ncprange_getip4mask(const struct ncprange *range, struct in_addr *mask) { switch (range->ncprange_family) { case AF_INET: *mask = range->ncprange_ip4mask; return 1; } return 0; } int ncprange_getwidth(const struct ncprange *range, int *width) { switch (range->ncprange_family) { case AF_INET: *width = range->ncprange_ip4width; return 1; #ifndef NOINET6 case AF_INET6: *width = range->ncprange_ip6width; return 1; #endif } return 0; } const char * ncprange_ntoa(const struct ncprange *range) { char *res; struct ncpaddr addr; int len; if (!ncprange_getaddr(range, &addr)) return ""; res = ncpaddr_ntowa(&addr); len = strlen(res); if (len >= NCP_ASCIIBUFFERSIZE - 1) return res; switch (range->ncprange_family) { case AF_INET: if (range->ncprange_ip4width == -1) { /* A non-contiguous mask */ for (; len >= 3; res[len -= 2] = '\0') if (strcmp(res + len - 2, ".0")) break; snprintf(res + len, sizeof res - len, "&0x%08lx", (unsigned long)ntohl(range->ncprange_ip4mask.s_addr)); } else if (range->ncprange_ip4width < 32) snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width); return res; #ifndef NOINET6 case AF_INET6: if (range->ncprange_ip6width != 128) snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width); return res; #endif } return ""; } #ifndef NOINET6 int ncprange_scopeid(const struct ncprange *range) { const struct in6_addr *sin6; int scopeid = -1; if (range->ncprange_family == AF_INET6) { sin6 = &range->ncprange_ip6addr; if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) scopeid = -1; } return scopeid; } #endif int ncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) { int bits, len; char *wp; const char *cp; char *s; len = strcspn(data, "/"); if (ncp && strncasecmp(data, "HISADDR", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.peer_ip; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; #ifndef NOINET6 } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { range->ncprange_family = AF_INET6; range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr; range->ncprange_ip6width = 128; return 1; #endif } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.my_ip; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; #ifndef NOINET6 } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { range->ncprange_family = AF_INET6; range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr; range->ncprange_ip6width = 128; return 1; #endif } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; return 1; } s = (char *)alloca(len + 1); strncpy(s, data, len); s[len] = '\0'; bits = -1; if (data[len] != '\0') { bits = strtol(data + len + 1, &wp, 0); if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); return 0; } } if ((cp = strchr(data, ':')) == NULL) { range->ncprange_family = AF_INET; range->ncprange_ip4addr = GetIpAddr(s); if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); return 0; } if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { range->ncprange_ip4mask.s_addr = INADDR_ANY; range->ncprange_ip4width = 0; } else if (bits == -1) { range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; range->ncprange_ip4width = 32; } else if (bits > 32) { log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); return 0; } else { range->ncprange_ip4mask = bits2mask4(bits); range->ncprange_ip4width = bits; } return 1; #ifndef NOINET6 } else if (strchr(cp + 1, ':') != NULL) { range->ncprange_family = AF_INET6; if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); return 0; } if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) range->ncprange_ip6width = 0; else range->ncprange_ip6width = (bits == -1) ? 128 : bits; return 1; #endif } return 0; } Index: stable/10/usr.sbin/ppp/route.c =================================================================== --- stable/10/usr.sbin/ppp/route.c (revision 330804) +++ stable/10/usr.sbin/ppp/route.c (revision 330805) @@ -1,934 +1,934 @@ /*- * Copyright (c) 1996 - 2001 Brian Somers * based on work by Toshiharu OHNO * Internet Initiative Japan, Inc (IIJ) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "layer.h" #include "defs.h" #include "command.h" #include "mbuf.h" #include "log.h" #include "iplist.h" #include "timer.h" #include "throughput.h" #include "lqr.h" #include "hdlc.h" #include "fsm.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "slcompress.h" #include "ncpaddr.h" #include "ipcp.h" #include "filter.h" #include "descriptor.h" #include "mp.h" #ifndef NORADIUS #include "radius.h" #endif #include "ipv6cp.h" #include "ncp.h" #include "bundle.h" #include "route.h" #include "prompt.h" #include "iface.h" #include "id.h" 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, "", dl->sdl_type); } else if (dl->sdl_slen) sprintf(buf, "", dl->sdl_slen); else sprintf(buf, "link#%d", dl->sdl_index); break; default: sprintf(buf, "", phost->sa_family); break; } prompt_Printf(prompt, "%-*s ", width-1, buf); } static struct bits { u_int32_t b_mask; char b_val; } bits[] = { { RTF_UP, 'U' }, { RTF_GATEWAY, 'G' }, { RTF_HOST, 'H' }, { RTF_REJECT, 'R' }, { RTF_DYNAMIC, 'D' }, { RTF_MODIFIED, 'M' }, { RTF_DONE, 'd' }, { RTF_XRESOLVE, 'X' }, { RTF_STATIC, 'S' }, { RTF_PROTO1, '1' }, { RTF_PROTO2, '2' }, { RTF_BLACKHOLE, 'B' }, #ifdef RTF_LLINFO { RTF_LLINFO, 'L' }, #endif #ifdef RTF_CLONING { RTF_CLONING, 'C' }, #endif #ifdef RTF_PROTO3 { RTF_PROTO3, '3' }, #endif #ifdef RTF_BROADCAST { RTF_BROADCAST, 'b' }, #endif { 0, '\0' } }; static void p_flags(struct prompt *prompt, u_int32_t f, unsigned max) { char name[33], *flags; register struct bits *p = bits; if (max > sizeof name - 1) max = sizeof name - 1; for (flags = name; p->b_mask && flags - name < (int)max; p++) if (p->b_mask & f) *flags++ = p->b_val; *flags = '\0'; prompt_Printf(prompt, "%-*.*s", (int)max, (int)max, name); } static int route_nifs = -1; const char * Index2Nam(int idx) { /* * XXX: Maybe we should select() on the routing socket so that we can * notice interfaces that come & go (PCCARD support). * Or we could even support a signal that resets these so that * the PCCARD insert/remove events can signal ppp. */ static char **ifs; /* Figure these out once */ static int debug_done; /* Debug once */ if (idx > route_nifs || (idx > 0 && ifs[idx-1] == NULL)) { int mib[6], have, had; size_t needed; char *buf, *ptr, *end; struct sockaddr_dl *dl; struct if_msghdr *ifm; if (ifs) { free(ifs); ifs = NULL; route_nifs = 0; } debug_done = 0; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno)); return NumStr(idx, NULL, 0); } if ((buf = malloc(needed)) == NULL) return NumStr(idx, NULL, 0); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); return NumStr(idx, NULL, 0); } end = buf + needed; have = 0; for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { ifm = (struct if_msghdr *)ptr; if (ifm->ifm_type != RTM_IFINFO) continue; dl = (struct sockaddr_dl *)(ifm + 1); if (ifm->ifm_index > 0) { if (ifm->ifm_index > have) { char **newifs; had = have; have = ifm->ifm_index + 5; if (had) newifs = (char **)realloc(ifs, sizeof(char *) * have); else newifs = (char **)malloc(sizeof(char *) * have); if (!newifs) { log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); route_nifs = 0; if (ifs) { free(ifs); ifs = NULL; } free(buf); return NumStr(idx, NULL, 0); } ifs = newifs; memset(ifs + had, '\0', sizeof(char *) * (have - had)); } if (ifs[ifm->ifm_index-1] == NULL) { ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); if (ifs[ifm->ifm_index-1] == NULL) log_Printf(LogDEBUG, "Skipping interface %d: Out of memory\n", ifm->ifm_index); else { memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; if (route_nifs < ifm->ifm_index) route_nifs = ifm->ifm_index; } } } else if (log_IsKept(LogDEBUG)) log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", ifm->ifm_index); } free(buf); } if (log_IsKept(LogDEBUG) && !debug_done) { int f; log_Printf(LogDEBUG, "Found the following interfaces:\n"); for (f = 0; f < route_nifs; f++) if (ifs[f] != NULL) log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); debug_done = 1; } if (idx < 1 || idx > route_nifs || ifs[idx-1] == NULL) return NumStr(idx, NULL, 0); return ifs[idx-1]; } void route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) { char *wp; int rtax; wp = (char *)(rtm + 1); for (rtax = 0; rtax < RTAX_MAX; rtax++) if (rtm->rtm_addrs & (1 << rtax)) { sa[rtax] = (struct sockaddr *)wp; wp += ROUNDUP(sa[rtax]->sa_len); if (sa[rtax]->sa_family == 0) sa[rtax] = NULL; /* ??? */ } else sa[rtax] = NULL; } int route_Show(struct cmdargs const *arg) { struct rt_msghdr *rtm; struct sockaddr *sa[RTAX_MAX]; char *sp, *ep, *cp; size_t needed; int mib[6]; 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_Show: sysctl: estimate: %s\n", strerror(errno)); return (1); } sp = malloc(needed); if (sp == NULL) return (1); if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); free(sp); return (1); } ep = sp + needed; prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", "Destination", "Gateway"); for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)cp; route_ParseHdr(rtm, sa); if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); p_flags(arg->prompt, rtm->rtm_flags, 6); prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); } else prompt_Printf(arg->prompt, "\n"); } free(sp); return 0; } /* * 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 (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]; + char gwstr[NCP_ASCIIBUFFERSIZE]; 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 == 1) { 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); } /* * 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); } int GetIfIndex(char *name) { int idx; idx = 1; while (route_nifs == -1 || idx < route_nifs) if (strcmp(Index2Nam(idx), name) == 0) return idx; else idx++; return -1; } void route_Change(struct bundle *bundle, struct sticky_route *r, const struct ncpaddr *me, const struct ncpaddr *peer) { struct ncpaddr dst; for (; r; r = r->next) { ncprange_getaddr(&r->dst, &dst); if (ncpaddr_family(me) == AF_INET) { if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) { rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); ncprange_sethost(&r->dst, me); if (r->type & ROUTE_GWHISADDR) ncpaddr_copy(&r->gw, peer); } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) { rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); ncprange_sethost(&r->dst, peer); if (r->type & ROUTE_GWHISADDR) ncpaddr_copy(&r->gw, peer); } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) { if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE) continue; rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); if (r->type & ROUTE_GWHISADDR) ncpaddr_copy(&r->gw, peer); } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) { if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE) continue; rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); if (r->type & ROUTE_GWHISADDR) ncpaddr_copy(&r->gw, peer); } else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer)) ncpaddr_copy(&r->gw, peer); #ifndef NOINET6 } else if (ncpaddr_family(me) == AF_INET6) { if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) { rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); ncprange_sethost(&r->dst, me); if (r->type & ROUTE_GWHISADDR) ncpaddr_copy(&r->gw, peer); } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) { rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); ncprange_sethost(&r->dst, peer); if (r->type & ROUTE_GWHISADDR) ncpaddr_copy(&r->gw, peer); } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer)) ncpaddr_copy(&r->gw, peer); #endif } rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0); } } void route_Add(struct sticky_route **rp, int type, const struct ncprange *dst, const struct ncpaddr *gw) { struct sticky_route *r; int dsttype = type & ROUTE_DSTANY; r = NULL; while (*rp) { if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || (!dsttype && ncprange_equal(&(*rp)->dst, dst))) { /* Oops, we already have this route - unlink it */ free(r); /* impossible really */ r = *rp; *rp = r->next; } else rp = &(*rp)->next; } if (r == NULL) { r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); if (r == NULL) { log_Printf(LogERROR, "route_Add: Out of memory!\n"); return; } } r->type = type; r->next = NULL; ncprange_copy(&r->dst, dst); ncpaddr_copy(&r->gw, gw); *rp = r; } void route_Delete(struct sticky_route **rp, int type, const struct ncprange *dst) { struct sticky_route *r; int dsttype = type & ROUTE_DSTANY; for (; *rp; rp = &(*rp)->next) { if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || (!dsttype && ncprange_equal(dst, &(*rp)->dst))) { r = *rp; *rp = r->next; free(r); break; } } } void route_DeleteAll(struct sticky_route **rp) { struct sticky_route *r, *rn; for (r = *rp; r; r = rn) { rn = r->next; free(r); } *rp = NULL; } void route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, int indent) { int tlen = strlen(tag); if (tlen + 2 > indent) prompt_Printf(p, "%s:\n%*s", tag, indent, ""); else prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); for (; r; r = r->next) { prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); tlen = 0; if (r->type & ROUTE_DSTMYADDR) prompt_Printf(p, "MYADDR"); else if (r->type & ROUTE_DSTMYADDR6) prompt_Printf(p, "MYADDR6"); else if (r->type & ROUTE_DSTHISADDR) prompt_Printf(p, "HISADDR"); else if (r->type & ROUTE_DSTHISADDR6) prompt_Printf(p, "HISADDR6"); else if (r->type & ROUTE_DSTDNS0) prompt_Printf(p, "DNS0"); else if (r->type & ROUTE_DSTDNS1) prompt_Printf(p, "DNS1"); else if (ncprange_isdefault(&r->dst)) prompt_Printf(p, "default"); else prompt_Printf(p, "%s", ncprange_ntoa(&r->dst)); if (r->type & ROUTE_GWHISADDR) prompt_Printf(p, " HISADDR\n"); else if (r->type & ROUTE_GWHISADDR6) prompt_Printf(p, " HISADDR6\n"); else prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw)); } } struct rtmsg { struct rt_msghdr m_rtm; char m_space[256]; }; static size_t memcpy_roundup(char *cp, const void *data, size_t len) { size_t padlen; padlen = ROUNDUP(len); memcpy(cp, data, len); if (padlen > len) memset(cp + len, '\0', padlen - len); return padlen; } #if defined(__KAME__) && !defined(NOINET6) static void add_scope(struct sockaddr *sa, int ifindex) { struct sockaddr_in6 *sa6; if (sa->sa_family != AF_INET6) return; sa6 = (struct sockaddr_in6 *)sa; if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) return; if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0) return; *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex); } #endif int rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst, const struct ncpaddr *gw, int bang, int quiet) { struct rtmsg rtmes; int s, nb, wb; char *cp; const char *cmdstr; struct sockaddr_storage sadst, samask, sagw; int result = 1; if (bang) cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); else cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); s = ID0socket(PF_ROUTE, SOCK_RAW, 0); if (s < 0) { log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); return result; } memset(&rtmes, '\0', sizeof rtmes); rtmes.m_rtm.rtm_version = RTM_VERSION; rtmes.m_rtm.rtm_type = cmd; rtmes.m_rtm.rtm_addrs = RTA_DST; rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; rtmes.m_rtm.rtm_pid = getpid(); rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; if (cmd == RTM_ADD) { 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; } } ncprange_getsa(dst, &sadst, &samask); #if defined(__KAME__) && !defined(NOINET6) add_scope((struct sockaddr *)&sadst, bundle->iface->index); #endif cp = rtmes.m_space; cp += memcpy_roundup(cp, &sadst, sadst.ss_len); if (cmd == RTM_ADD) { if (gw == NULL) { log_Printf(LogERROR, "rt_Set: Program error\n"); close(s); return result; } ncpaddr_getsa(gw, &sagw); #if defined(__KAME__) && !defined(NOINET6) add_scope((struct sockaddr *)&sagw, bundle->iface->index); #endif if (ncpaddr_isdefault(gw)) { if (!quiet) log_Printf(LogERROR, "rt_Set: Cannot add a route with" " gateway 0.0.0.0\n"); close(s); return result; } else { cp += memcpy_roundup(cp, &sagw, sagw.ss_len); rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; } } if (!ncprange_ishost(dst)) { cp += memcpy_roundup(cp, &samask, samask.ss_len); rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; } nb = cp - (char *)&rtmes; rtmes.m_rtm.rtm_msglen = nb; wb = ID0write(s, &rtmes, nb); if (wb < 0) { log_Printf(LogTCPIP, "rt_Set failure:\n"); log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst)); if (gw != NULL) log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw)); failed: if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { if (!bang) { log_Printf(LogWARN, "Add route failed: %s already exists\n", ncprange_ntoa(dst)); result = 0; /* Don't add to our dynamic list */ } else { rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; if ((wb = ID0write(s, &rtmes, nb)) < 0) goto failed; } } else if (cmd == RTM_DELETE && (rtmes.m_rtm.rtm_errno == ESRCH || (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { if (!bang) log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", ncprange_ntoa(dst)); } else if (rtmes.m_rtm.rtm_errno == 0) { if (!quiet || errno != ENETUNREACH) log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, ncprange_ntoa(dst), strerror(errno)); } else log_Printf(LogWARN, "%s route failed: %s: %s\n", cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); } if (log_IsKept(LogDEBUG)) { - char gwstr[40]; + char gwstr[NCP_ASCIIBUFFERSIZE]; if (gw) snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw)); else snprintf(gwstr, sizeof gwstr, ""); log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n", wb, cmdstr, ncprange_ntoa(dst), gwstr); } close(s); return result; } void rt_Update(struct bundle *bundle, const struct sockaddr *dst, const struct sockaddr *gw, const struct sockaddr *mask, const struct sockaddr *ifp, const struct sockaddr *ifa) { 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); } if (gw) { 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); } if (ifa && ifp && ifp->sa_family == AF_LINK) { rtmes.m_rtm.rtm_addrs |= RTA_IFP; p += memcpy_roundup(p, ifp, ifp->sa_len); rtmes.m_rtm.rtm_addrs |= RTA_IFA; p += memcpy_roundup(p, ifa, ifa->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); } Index: stable/10 =================================================================== --- stable/10 (revision 330804) +++ stable/10 (revision 330805) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r329105