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
This commit is contained in:
Rick V 2019-03-24 23:14:32 -05:00
parent 9f3d0cafc4
commit 1eddba0dd3
No known key found for this signature in database
GPG Key ID: C0EDC8723FDC3465
4 changed files with 258 additions and 20 deletions

View File

@ -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
};

View File

@ -47,5 +47,4 @@ tuntap_sys_set_ifname(struct device *dev, const char *ifname, size_t len)
*/
return -1;
}
#endif

View File

@ -20,6 +20,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <arpa/inet.h>
#include <net/if.h>
@ -27,13 +28,22 @@
#include <net/if_types.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stropts.h>
#include <unistd.h>
#include <ctype.h>
#include <stdbool.h>
#include <errno.h>
#include <alloca.h>
#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;
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_hwaddr(struct device *dev, struct ether_addr *eth_addr)
{
return -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;
}

View File

@ -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;
}