tun.c cleanup and support for setting multiple addresses on FreeBSD
This commit is contained in:
parent
3cfb81cee9
commit
409b855839
16
README
16
README
|
@ -208,6 +208,22 @@ http://sources.redhat.com/autobook/autobook/autobook_25.html#SEC25
|
||||||
for details on autotools.
|
for details on autotools.
|
||||||
|
|
||||||
|
|
||||||
|
Checking out from CVS
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
To download the latest source code from anonymous CVS:
|
||||||
|
|
||||||
|
cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/ggsn login
|
||||||
|
cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/ggsn co openggsn
|
||||||
|
|
||||||
|
Or to download from developer CVS:
|
||||||
|
|
||||||
|
export CVS_RSH=ssh
|
||||||
|
cvs -z3 -d:ext:developername@cvs.sourceforge.net:/cvsroot/ggsn co openggsn
|
||||||
|
|
||||||
|
Both the above sets of commands creates a new directory called openggsn.
|
||||||
|
|
||||||
|
|
||||||
Compilation and installation
|
Compilation and installation
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
195
ggsn/tun.c
195
ggsn/tun.c
|
@ -45,20 +45,25 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/if_tun.h>
|
#include <linux/if_tun.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
#elif defined (__FreeBSD__)
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_tun.h>
|
||||||
|
|
||||||
#elif defined (__sun__)
|
#elif defined (__sun__)
|
||||||
#include <stropts.h>
|
#include <stropts.h>
|
||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/if_tun.h>
|
#include <net/if_tun.h>
|
||||||
/*#include "sun_if_tun.h"*/
|
/*#include "sun_if_tun.h"*/
|
||||||
#elif defined (__FreeBSD__)
|
|
||||||
#include <net/if.h>
|
#else
|
||||||
#include <net/if_tun.h>
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,7 +71,8 @@
|
||||||
#include "syserr.h"
|
#include "syserr.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
|
|
||||||
int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
|
int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
|
||||||
{
|
{
|
||||||
int len = RTA_LENGTH(dlen);
|
int len = RTA_LENGTH(dlen);
|
||||||
|
@ -231,7 +237,7 @@ int tun_addaddr(struct tun_t *this,
|
||||||
struct in_addr *dstaddr,
|
struct in_addr *dstaddr,
|
||||||
struct in_addr *netmask) {
|
struct in_addr *netmask) {
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr n;
|
struct nlmsghdr n;
|
||||||
struct ifaddrmsg i;
|
struct ifaddrmsg i;
|
||||||
|
@ -242,20 +248,14 @@ int tun_addaddr(struct tun_t *this,
|
||||||
int addr_len;
|
int addr_len;
|
||||||
int fd;
|
int fd;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
struct sockaddr_nl nladdr;
|
struct sockaddr_nl nladdr;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||||
return tun_setaddr(this, addr, dstaddr, netmask);
|
return tun_setaddr(this, addr, dstaddr, netmask);
|
||||||
|
|
||||||
#ifndef __linux__
|
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
|
||||||
"Setting multiple addresses only possible on linux");
|
|
||||||
return -1;
|
|
||||||
#else
|
|
||||||
memset(&req, 0, sizeof(req));
|
memset(&req, 0, sizeof(req));
|
||||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||||
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||||
|
@ -331,11 +331,66 @@ int tun_addaddr(struct tun_t *this,
|
||||||
|
|
||||||
status = sendmsg(fd, &msg, 0); /* TODO Error check */
|
status = sendmsg(fd, &msg, 0); /* TODO Error check */
|
||||||
|
|
||||||
tun_sifflags(this, IFF_UP | IFF_RUNNING);
|
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
|
||||||
close(fd);
|
close(fd);
|
||||||
this->addrs++;
|
this->addrs++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
#elif defined (__FreeBSD__)
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
struct ifaliasreq areq;
|
||||||
|
|
||||||
|
/* TODO: Is this needed on FreeBSD? */
|
||||||
|
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||||
|
return tun_setaddr(this, addr, dstaddr, netmask);
|
||||||
|
|
||||||
|
memset(&areq, 0, sizeof(areq));
|
||||||
|
|
||||||
|
/* Set up interface name */
|
||||||
|
strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
|
||||||
|
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
|
||||||
|
|
||||||
|
((struct sockaddr_in) areq.ifra_addr).sin_family = AF_INET;
|
||||||
|
((struct sockaddr_in) areq.ifra_addr).sin_len = sizeof(areq.ifra_addr);
|
||||||
|
((struct sockaddr_in) areq.ifra_addr).sin_addr.s_addr = addr->s_addr;
|
||||||
|
|
||||||
|
((struct sockaddr_in) areq.ifra_mask).sin_family = AF_INET;
|
||||||
|
((struct sockaddr_in) areq.ifra_mask).sin_len = sizeof(areq.ifra_mask);
|
||||||
|
((struct sockaddr_in) areq.ifra_mask).sin_addr.s_addr = netmask->s_addr;
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a channel to the NET kernel. */
|
||||||
|
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
|
"socket() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
|
"ioctl(SIOCAIFADDR) failed");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
this->addrs++;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined (__sun__)
|
||||||
|
|
||||||
|
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||||
|
return tun_setaddr(this, addr, dstaddr, netmask);
|
||||||
|
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
|
"Setting multiple addresses not possible on Solaris");
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,15 +405,17 @@ int tun_setaddr(struct tun_t *this,
|
||||||
memset (&ifr, '\0', sizeof (ifr));
|
memset (&ifr, '\0', sizeof (ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
ifr.ifr_dstaddr.sa_family = AF_INET;
|
ifr.ifr_dstaddr.sa_family = AF_INET;
|
||||||
#ifdef __linux__
|
|
||||||
|
#if defined(__linux__)
|
||||||
ifr.ifr_netmask.sa_family = AF_INET;
|
ifr.ifr_netmask.sa_family = AF_INET;
|
||||||
#endif
|
|
||||||
#ifdef __FreeBSD__
|
#elif defined(__FreeBSD__)
|
||||||
((struct sockaddr_in *) &ifr.ifr_addr)->sin_len =
|
((struct sockaddr_in *) &ifr.ifr_addr)->sin_len =
|
||||||
sizeof (struct sockaddr_in);
|
sizeof (struct sockaddr_in);
|
||||||
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len =
|
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len =
|
||||||
sizeof (struct sockaddr_in);
|
sizeof (struct sockaddr_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
|
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
|
||||||
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
|
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
|
||||||
|
|
||||||
|
@ -400,17 +457,21 @@ int tun_setaddr(struct tun_t *this,
|
||||||
|
|
||||||
if (netmask) { /* Set the netmask */
|
if (netmask) { /* Set the netmask */
|
||||||
this->netmask.s_addr = netmask->s_addr;
|
this->netmask.s_addr = netmask->s_addr;
|
||||||
#if defined(__sun__)
|
#if defined(__linux__)
|
||||||
/* TODO: This should probably be ifr_addr */
|
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
|
||||||
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
|
|
||||||
netmask->s_addr;
|
netmask->s_addr;
|
||||||
|
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
|
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
|
||||||
netmask->s_addr;
|
netmask->s_addr;
|
||||||
#else
|
|
||||||
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
|
#elif defined(__sun__)
|
||||||
|
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
|
||||||
netmask->s_addr;
|
netmask->s_addr;
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
|
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
"ioctl(SIOCSIFNETMASK) failed");
|
"ioctl(SIOCSIFNETMASK) failed");
|
||||||
|
@ -418,13 +479,15 @@ int tun_setaddr(struct tun_t *this,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
this->addrs++;
|
this->addrs++;
|
||||||
|
|
||||||
/* On linux the route to the interface is set automatically
|
/* On linux the route to the interface is set automatically
|
||||||
on FreeBSD we have to do this manually */
|
on FreeBSD we have to do this manually */
|
||||||
|
|
||||||
|
/* TODO: How does it work on Solaris? */
|
||||||
|
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
|
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
|
||||||
return tun_addroute(this, addr, addr, netmask);
|
return tun_addroute(this, addr, addr, netmask);
|
||||||
|
@ -442,7 +505,8 @@ int tun_addroute(struct tun_t *this,
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Learn how to set routing table on sun */
|
/* TODO: Learn how to set routing table on sun */
|
||||||
#ifdef __linux__
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
struct rtentry r;
|
struct rtentry r;
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -471,6 +535,7 @@ int tun_addroute(struct tun_t *this,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
|
|
||||||
|
@ -520,24 +585,35 @@ struct {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__sun__)
|
||||||
|
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
|
||||||
|
"Could not set up routing on Solaris. Please add route manually.");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int tun_new(struct tun_t **tun)
|
int tun_new(struct tun_t **tun)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef __sun__
|
#if defined(__linux__)
|
||||||
int if_fd, ppa = -1;
|
struct ifreq ifr;
|
||||||
static int ip_fd = 0;
|
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
|
char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
|
||||||
int devnum;
|
int devnum;
|
||||||
|
|
||||||
|
#elif defined(__sun__)
|
||||||
|
int if_fd, ppa = -1;
|
||||||
|
static int ip_fd = 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
struct ifreq ifr;
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
|
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
|
||||||
|
@ -547,14 +623,14 @@ int tun_new(struct tun_t **tun)
|
||||||
|
|
||||||
(*tun)->cb_ind = NULL;
|
(*tun)->cb_ind = NULL;
|
||||||
(*tun)->addrs = 0;
|
(*tun)->addrs = 0;
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
/* Open the actual tun device */
|
/* Open the actual tun device */
|
||||||
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set device flags. For some weird reason this is also the method
|
/* Set device flags. For some weird reason this is also the method
|
||||||
used to obtain the network interface name */
|
used to obtain the network interface name */
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
@ -564,15 +640,32 @@ int tun_new(struct tun_t **tun)
|
||||||
close((*tun)->fd);
|
close((*tun)->fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
|
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
|
||||||
(*tun)->devname[IFNAMSIZ] = 0;
|
(*tun)->devname[IFNAMSIZ] = 0;
|
||||||
|
|
||||||
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
|
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
|
||||||
#endif
|
/* Find suitable device */
|
||||||
|
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
|
||||||
|
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
|
||||||
|
devname[sizeof(devname)] = 0;
|
||||||
|
if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
|
||||||
|
if (errno != EBUSY) break;
|
||||||
|
}
|
||||||
|
if ((*tun)->fd < 0) {
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __sun__
|
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
|
||||||
|
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__sun__)
|
||||||
|
|
||||||
if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
|
if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/ip");
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/ip");
|
||||||
|
@ -615,28 +708,12 @@ int tun_new(struct tun_t **tun)
|
||||||
|
|
||||||
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
|
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
|
||||||
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
/* Find suitable device */
|
|
||||||
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
|
|
||||||
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
|
|
||||||
devname[sizeof(devname)] = 0;
|
|
||||||
if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
|
|
||||||
if (errno != EBUSY) break;
|
|
||||||
}
|
|
||||||
if ((*tun)->fd < 0) {
|
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
|
|
||||||
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int tun_free(struct tun_t *tun)
|
int tun_free(struct tun_t *tun)
|
||||||
|
|
195
sgsnemu/tun.c
195
sgsnemu/tun.c
|
@ -45,20 +45,25 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/if_tun.h>
|
#include <linux/if_tun.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
#elif defined (__FreeBSD__)
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_tun.h>
|
||||||
|
|
||||||
#elif defined (__sun__)
|
#elif defined (__sun__)
|
||||||
#include <stropts.h>
|
#include <stropts.h>
|
||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/if_tun.h>
|
#include <net/if_tun.h>
|
||||||
/*#include "sun_if_tun.h"*/
|
/*#include "sun_if_tun.h"*/
|
||||||
#elif defined (__FreeBSD__)
|
|
||||||
#include <net/if.h>
|
#else
|
||||||
#include <net/if_tun.h>
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,7 +71,8 @@
|
||||||
#include "syserr.h"
|
#include "syserr.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
|
|
||||||
int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
|
int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
|
||||||
{
|
{
|
||||||
int len = RTA_LENGTH(dlen);
|
int len = RTA_LENGTH(dlen);
|
||||||
|
@ -231,7 +237,7 @@ int tun_addaddr(struct tun_t *this,
|
||||||
struct in_addr *dstaddr,
|
struct in_addr *dstaddr,
|
||||||
struct in_addr *netmask) {
|
struct in_addr *netmask) {
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr n;
|
struct nlmsghdr n;
|
||||||
struct ifaddrmsg i;
|
struct ifaddrmsg i;
|
||||||
|
@ -242,20 +248,14 @@ int tun_addaddr(struct tun_t *this,
|
||||||
int addr_len;
|
int addr_len;
|
||||||
int fd;
|
int fd;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
struct sockaddr_nl nladdr;
|
struct sockaddr_nl nladdr;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||||
return tun_setaddr(this, addr, dstaddr, netmask);
|
return tun_setaddr(this, addr, dstaddr, netmask);
|
||||||
|
|
||||||
#ifndef __linux__
|
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
|
||||||
"Setting multiple addresses only possible on linux");
|
|
||||||
return -1;
|
|
||||||
#else
|
|
||||||
memset(&req, 0, sizeof(req));
|
memset(&req, 0, sizeof(req));
|
||||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||||
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||||
|
@ -331,11 +331,66 @@ int tun_addaddr(struct tun_t *this,
|
||||||
|
|
||||||
status = sendmsg(fd, &msg, 0); /* TODO Error check */
|
status = sendmsg(fd, &msg, 0); /* TODO Error check */
|
||||||
|
|
||||||
tun_sifflags(this, IFF_UP | IFF_RUNNING);
|
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
|
||||||
close(fd);
|
close(fd);
|
||||||
this->addrs++;
|
this->addrs++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
#elif defined (__FreeBSD__)
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
struct ifaliasreq areq;
|
||||||
|
|
||||||
|
/* TODO: Is this needed on FreeBSD? */
|
||||||
|
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||||
|
return tun_setaddr(this, addr, dstaddr, netmask);
|
||||||
|
|
||||||
|
memset(&areq, 0, sizeof(areq));
|
||||||
|
|
||||||
|
/* Set up interface name */
|
||||||
|
strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
|
||||||
|
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
|
||||||
|
|
||||||
|
((struct sockaddr_in) areq.ifra_addr).sin_family = AF_INET;
|
||||||
|
((struct sockaddr_in) areq.ifra_addr).sin_len = sizeof(areq.ifra_addr);
|
||||||
|
((struct sockaddr_in) areq.ifra_addr).sin_addr.s_addr = addr->s_addr;
|
||||||
|
|
||||||
|
((struct sockaddr_in) areq.ifra_mask).sin_family = AF_INET;
|
||||||
|
((struct sockaddr_in) areq.ifra_mask).sin_len = sizeof(areq.ifra_mask);
|
||||||
|
((struct sockaddr_in) areq.ifra_mask).sin_addr.s_addr = netmask->s_addr;
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a channel to the NET kernel. */
|
||||||
|
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
|
"socket() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
|
"ioctl(SIOCAIFADDR) failed");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
this->addrs++;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined (__sun__)
|
||||||
|
|
||||||
|
if (!this->addrs) /* Use ioctl for first addr to make ping work */
|
||||||
|
return tun_setaddr(this, addr, dstaddr, netmask);
|
||||||
|
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
|
"Setting multiple addresses not possible on Solaris");
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,15 +405,17 @@ int tun_setaddr(struct tun_t *this,
|
||||||
memset (&ifr, '\0', sizeof (ifr));
|
memset (&ifr, '\0', sizeof (ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
ifr.ifr_dstaddr.sa_family = AF_INET;
|
ifr.ifr_dstaddr.sa_family = AF_INET;
|
||||||
#ifdef __linux__
|
|
||||||
|
#if defined(__linux__)
|
||||||
ifr.ifr_netmask.sa_family = AF_INET;
|
ifr.ifr_netmask.sa_family = AF_INET;
|
||||||
#endif
|
|
||||||
#ifdef __FreeBSD__
|
#elif defined(__FreeBSD__)
|
||||||
((struct sockaddr_in *) &ifr.ifr_addr)->sin_len =
|
((struct sockaddr_in *) &ifr.ifr_addr)->sin_len =
|
||||||
sizeof (struct sockaddr_in);
|
sizeof (struct sockaddr_in);
|
||||||
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len =
|
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len =
|
||||||
sizeof (struct sockaddr_in);
|
sizeof (struct sockaddr_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
|
strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
|
||||||
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
|
ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
|
||||||
|
|
||||||
|
@ -400,17 +457,21 @@ int tun_setaddr(struct tun_t *this,
|
||||||
|
|
||||||
if (netmask) { /* Set the netmask */
|
if (netmask) { /* Set the netmask */
|
||||||
this->netmask.s_addr = netmask->s_addr;
|
this->netmask.s_addr = netmask->s_addr;
|
||||||
#if defined(__sun__)
|
#if defined(__linux__)
|
||||||
/* TODO: This should probably be ifr_addr */
|
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
|
||||||
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
|
|
||||||
netmask->s_addr;
|
netmask->s_addr;
|
||||||
|
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
|
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
|
||||||
netmask->s_addr;
|
netmask->s_addr;
|
||||||
#else
|
|
||||||
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
|
#elif defined(__sun__)
|
||||||
|
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
|
||||||
netmask->s_addr;
|
netmask->s_addr;
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
|
if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno,
|
||||||
"ioctl(SIOCSIFNETMASK) failed");
|
"ioctl(SIOCSIFNETMASK) failed");
|
||||||
|
@ -418,13 +479,15 @@ int tun_setaddr(struct tun_t *this,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
this->addrs++;
|
this->addrs++;
|
||||||
|
|
||||||
/* On linux the route to the interface is set automatically
|
/* On linux the route to the interface is set automatically
|
||||||
on FreeBSD we have to do this manually */
|
on FreeBSD we have to do this manually */
|
||||||
|
|
||||||
|
/* TODO: How does it work on Solaris? */
|
||||||
|
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
|
tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
|
||||||
return tun_addroute(this, addr, addr, netmask);
|
return tun_addroute(this, addr, addr, netmask);
|
||||||
|
@ -442,7 +505,8 @@ int tun_addroute(struct tun_t *this,
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Learn how to set routing table on sun */
|
/* TODO: Learn how to set routing table on sun */
|
||||||
#ifdef __linux__
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
struct rtentry r;
|
struct rtentry r;
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -471,6 +535,7 @@ int tun_addroute(struct tun_t *this,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
|
|
||||||
|
@ -520,24 +585,35 @@ struct {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__sun__)
|
||||||
|
sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
|
||||||
|
"Could not set up routing on Solaris. Please add route manually.");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int tun_new(struct tun_t **tun)
|
int tun_new(struct tun_t **tun)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef __sun__
|
#if defined(__linux__)
|
||||||
int if_fd, ppa = -1;
|
struct ifreq ifr;
|
||||||
static int ip_fd = 0;
|
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
|
char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
|
||||||
int devnum;
|
int devnum;
|
||||||
|
|
||||||
|
#elif defined(__sun__)
|
||||||
|
int if_fd, ppa = -1;
|
||||||
|
static int ip_fd = 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
struct ifreq ifr;
|
#error "Unknown platform!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
|
if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
|
||||||
|
@ -547,14 +623,14 @@ int tun_new(struct tun_t **tun)
|
||||||
|
|
||||||
(*tun)->cb_ind = NULL;
|
(*tun)->cb_ind = NULL;
|
||||||
(*tun)->addrs = 0;
|
(*tun)->addrs = 0;
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__)
|
||||||
/* Open the actual tun device */
|
/* Open the actual tun device */
|
||||||
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set device flags. For some weird reason this is also the method
|
/* Set device flags. For some weird reason this is also the method
|
||||||
used to obtain the network interface name */
|
used to obtain the network interface name */
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
@ -564,15 +640,32 @@ int tun_new(struct tun_t **tun)
|
||||||
close((*tun)->fd);
|
close((*tun)->fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
|
strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
|
||||||
(*tun)->devname[IFNAMSIZ] = 0;
|
(*tun)->devname[IFNAMSIZ] = 0;
|
||||||
|
|
||||||
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
|
ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
|
||||||
#endif
|
/* Find suitable device */
|
||||||
|
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
|
||||||
|
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
|
||||||
|
devname[sizeof(devname)] = 0;
|
||||||
|
if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
|
||||||
|
if (errno != EBUSY) break;
|
||||||
|
}
|
||||||
|
if ((*tun)->fd < 0) {
|
||||||
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __sun__
|
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
|
||||||
|
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#elif defined(__sun__)
|
||||||
|
|
||||||
if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
|
if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/ip");
|
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/ip");
|
||||||
|
@ -615,28 +708,12 @@ int tun_new(struct tun_t **tun)
|
||||||
|
|
||||||
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
|
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
|
||||||
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
/* Find suitable device */
|
|
||||||
for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
|
|
||||||
snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
|
|
||||||
devname[sizeof(devname)] = 0;
|
|
||||||
if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
|
|
||||||
if (errno != EBUSY) break;
|
|
||||||
}
|
|
||||||
if ((*tun)->fd < 0) {
|
|
||||||
sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
|
|
||||||
(*tun)->devname[sizeof((*tun)->devname)] = 0;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown platform!"
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int tun_free(struct tun_t *tun)
|
int tun_free(struct tun_t *tun)
|
||||||
|
|
Reference in New Issue