From 1eddba0dd389d6a2684fbab9c204779d7e44f90b Mon Sep 17 00:00:00 2001 From: Rick V Date: Sun, 24 Mar 2019 23:14:32 -0500 Subject: [PATCH] that _should_ be just enough to implement TUN on Solaris 2.x sadly this is ineligble for upstream because we don't bother to use TAP in the slightest --- include/tuntap.h | 4 + vendor/libtuntap-master/tuntap-unix-bsd.c | 1 - vendor/libtuntap-master/tuntap-unix-sunos.c | 268 ++++++++++++++++++-- vendor/libtuntap-master/tuntap-unix.c | 5 + 4 files changed, 258 insertions(+), 20 deletions(-) diff --git a/include/tuntap.h b/include/tuntap.h index 479c86d20..d6117851b 100644 --- a/include/tuntap.h +++ b/include/tuntap.h @@ -147,6 +147,10 @@ extern "C" char if_name[IF_NAMESIZE]; #if defined(FreeBSD) int mode; +#endif +#if defined(__sun) + int ip_fd; + char internal_name[IF_NAMESIZE]; #endif }; diff --git a/vendor/libtuntap-master/tuntap-unix-bsd.c b/vendor/libtuntap-master/tuntap-unix-bsd.c index 25c743712..ec3524e62 100644 --- a/vendor/libtuntap-master/tuntap-unix-bsd.c +++ b/vendor/libtuntap-master/tuntap-unix-bsd.c @@ -47,5 +47,4 @@ tuntap_sys_set_ifname(struct device *dev, const char *ifname, size_t len) */ return -1; } - #endif diff --git a/vendor/libtuntap-master/tuntap-unix-sunos.c b/vendor/libtuntap-master/tuntap-unix-sunos.c index 10090d5e0..b694485b7 100644 --- a/vendor/libtuntap-master/tuntap-unix-sunos.c +++ b/vendor/libtuntap-master/tuntap-unix-sunos.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -27,13 +28,22 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include +#include #include +#include +#include +#include +#include #include "tuntap.h" @@ -42,50 +52,270 @@ static int tuntap_sys_create_dev(struct device *dev, int tun) { - return -1; + int if_fd, ip_muxid, ppa = -1; + struct lifreq lifr; + struct ifreq ifr; + const char *ptr = NULL; + struct strioctl strioc_ppa; + + /* improved generic TUN/TAP driver from + * http://www.whiteboard.ne.jp/~admin2/tuntap/ + * has IPv6 support. Most open-source variants of + * Solaris already have this driver in their package + * repos, Oracle Solaris users need to compile/load + * manually. + */ + + explicit_bzero(&lifr, sizeof lifr); + + if ((dev->ip_fd = open("/dev/udp", O_RDWR, 0)) < 0) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't open /dev/udp"); + return -1; + } + + if ((dev->tun_fd = open("/dev/tun", O_RDWR, 0)) < 0) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't open /dev/tun"); + return -1; + } + + /* get unit number */ + if (*dev->if_name) + { + ptr = dev->if_name; + while (*ptr && !isdigit((int) *ptr)) + { + ptr++; + } + ppa = atoi(ptr); + } + + /* Assign a new PPA and get its unit number. */ + strioc_ppa.ic_cmd = TUNNEWPPA; + strioc_ppa.ic_timout = 0; + strioc_ppa.ic_len = sizeof(ppa); + strioc_ppa.ic_dp = (char *)&ppa; + + if (*ptr == '\0') /* no number given, try dynamic */ + { + bool found_one = false; + while (!found_one && ppa < 64) + { + int new_ppa = ioctl(dev->tun_fd, I_STR, &strioc_ppa); + if (new_ppa >= 0) + { + char* msg = alloca(512); + sprintf(msg, "got dynamic interface tun%i", new_ppa); + tuntap_log( TUNTAP_LOG_INFO, msg ); + ppa = new_ppa; + found_one = true; + break; + } + if (errno != EEXIST) + { + tuntap_log(TUNTAP_LOG_ERR, "unexpected error trying to find free tun interface"); + return -1; + } + ppa++; + } + if (!found_one) + { + tuntap_log(TUNTAP_LOG_ERR, "could not find free tun interface, give up."); + return -1; + } + } + else /* try this particular one */ + { + if ((ppa = ioctl(dev->tun_fd, I_STR, &strioc_ppa)) < 0) + { + char *msg = alloca(512); + sprintf(msg, "Can't assign PPA for new interface (tun%i)", ppa); + tuntap_log(TUNTAP_LOG_ERR, msg); + return -1; + } + } + + if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't open /dev/tun (2)"); + return -1; + } + + if (ioctl(if_fd, I_PUSH, "ip") < 0) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't push IP module"); + return -1; + } + + /* Assign ppa according to the unit number returned by tun device */ + if (ioctl(if_fd, IF_UNITSEL, (char *) &ppa) < 0) + { + char *msg = alloca(512); + sprintf(msg, "Can't set PPA %i", ppa); + tuntap_log(TUNTAP_LOG_ERR, msg); + return -1; + } + + snprintf(dev->internal_name, IF_NAMESIZE, "%s%d", "tun", ppa); + + if ((ip_muxid = ioctl(dev->ip_fd, I_PLINK, if_fd)) < 0) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't link tun device to IP"); + return -1; + } + + explicit_bzero(&lifr, sizeof lifr); + explicit_bzero(&ifr, sizeof ifr); + memcpy(lifr.lifr_name, dev->internal_name, sizeof(lifr.lifr_name)); + lifr.lifr_ip_muxid = ip_muxid; + + if (ioctl(dev->ip_fd, SIOCSLIFMUXID, &lifr) < 0) + { + ioctl(dev->ip_fd, I_PUNLINK, ip_muxid); + tuntap_log(TUNTAP_LOG_ERR, "Can't set multiplexor id"); + return -1; + } + + fcntl(dev->tun_fd, F_SETFL, O_NONBLOCK); + fcntl(dev->tun_fd, F_SETFD, FD_CLOEXEC); + fcntl(dev->ip_fd, F_SETFD, FD_CLOEXEC); + char *msg = alloca(512); + sprintf(msg, "TUN device %s opened as %s", dev->if_name, dev->internal_name); + tuntap_log(TUNTAP_LOG_INFO, msg); + + (void)memcpy(ifr.ifr_name, dev->internal_name, sizeof dev->internal_name); + + /* Get the interface default values */ + if(ioctl(dev->ctrl_sock, SIOCGIFFLAGS, &ifr) == -1) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't get interface values"); + return -1; + } + /* Save flags for tuntap_{up, down} */ + dev->flags = ifr.ifr_flags; + return 0; } int -tuntap_sys_start(struct device *dev, int mode, int tun) +tuntap_sys_start(struct device *dev, int mode, int tun) { - return -1; + /* Forces automatic selection of device instance + * in tuntap_sys_create_dev(). + * This also clears the specified interface name. + */ + if (tun == TUNTAP_ID_ANY) + memset(&dev->if_name, '\0', sizeof dev->if_name); + + if (mode == TUNTAP_MODE_TUNNEL) + { + return tuntap_sys_create_dev(dev, tun); + } + else + return -1; + /* NOTREACHED */ } + void tuntap_sys_destroy(struct device *dev) { - return /*-1*/; -} + struct lifreq ifr; -int -tuntap_sys_set_hwaddr(struct device *dev, struct ether_addr *eth_addr) -{ - return -1; + explicit_bzero(&ifr, sizeof ifr); + strncpy(ifr.lifr_name, dev->internal_name, sizeof(ifr.lifr_name)); + + if (ioctl(dev->ip_fd, SIOCGLIFFLAGS, &ifr) < 0) + { + tuntap_log(TUNTAP_LOG_WARN, "Can't get iface flags"); + } + + if (ioctl(dev->ip_fd, SIOCGLIFMUXID, &ifr) < 0) + { + tuntap_log(TUNTAP_LOG_WARN, "Can't get multiplexor id"); + } + + /* we don't support TAP, and i think jaff stripped out TAP code a while + * back... + */ + + if (ioctl(dev->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0) + { + tuntap_log(TUNTAP_LOG_WARN, "Can't unlink interface(ip)"); + } + + close(dev->ip_fd); + dev->ip_fd = -1; } + int -tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s4, uint32_t imask) +tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s4, uint32_t bits) { - return -1; + struct lifreq ifr; + struct sockaddr_in mask; + + (void)memset(&ifr, '\0', sizeof ifr); + (void)memcpy(ifr.lifr_name, dev->internal_name, sizeof dev->internal_name); + + /* Set the IP address first */ + (void)memcpy(&(((struct sockaddr_in *)&ifr.lifr_addr)->sin_addr), s4, + sizeof(struct in_addr)); + ifr.lifr_addr.ss_family = AF_INET; + if(ioctl(dev->ctrl_sock, SIOCSLIFADDR, &ifr) == -1) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't set IP address"); + return -1; + } + + /* Reinit the struct ifr */ + (void)memset(&ifr.lifr_addr, '\0', sizeof ifr.lifr_addr); + + /* Then set the netmask */ + (void)memset(&mask, '\0', sizeof mask); + mask.sin_family = AF_INET; + mask.sin_addr.s_addr = bits; + (void)memcpy(&ifr.lifr_addr, &mask, sizeof mask); + if(ioctl(dev->ctrl_sock, SIOCSLIFNETMASK, &ifr) == -1) + { + tuntap_log(TUNTAP_LOG_ERR, "Can't set netmask"); + return -1; + } + + return 0; } int tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s6, uint32_t imask) { - return -1; + (void)dev; + (void)s6; + (void)imask; + tuntap_log(TUNTAP_LOG_NOTICE, "IPv6 is configured manually, this is currently unsupported"); + return -1; } int -tuntap_sys_set_ifname(struct device *dev, const char *ifname, size_t len) +tuntap_sys_set_ifname(struct device *dev, const char *ifname, size_t len) { - return -1; + /* Not quite sure if solaris SIOCSLIFNAME work the same way as on Linux, + * given the correct parameters. + */ + (void)dev; + (void)ifname; + (void)len; + tuntap_log(TUNTAP_LOG_NOTICE, + "Your system does not support tuntap_set_ifname()"); + return -1; } int tuntap_sys_set_descr(struct device *dev, const char *descr, size_t len) { - (void)dev; - (void)descr; - (void)len; - return -1; -} + (void)dev; + (void)descr; + (void)len; + tuntap_log(TUNTAP_LOG_NOTICE, + "Your system does not support tuntap_set_descr()"); + return -1; +} \ No newline at end of file diff --git a/vendor/libtuntap-master/tuntap-unix.c b/vendor/libtuntap-master/tuntap-unix.c index facf04965..f7ffc9eda 100644 --- a/vendor/libtuntap-master/tuntap-unix.c +++ b/vendor/libtuntap-master/tuntap-unix.c @@ -173,6 +173,10 @@ tuntap_set_ifname(struct device *dev, const char *ifname) int tuntap_up(struct device *dev) { + /* On Solaris, the interface automatically comes up when an IP + * address is first assigned. + */ +#ifndef __sun struct ifreq ifr; (void)memset(&ifr, '\0', sizeof ifr); @@ -186,6 +190,7 @@ tuntap_up(struct device *dev) } dev->flags = ifr.ifr_flags; +#endif return 0; }