#include "netlink.h"
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
struct buffer_if *buff; /* We receive packets into here
and send them to the netlink code. */
netlink_deliver_fn *netlink_to_tunnel;
- uint32_t local_address; /* host interface address */
};
static cstring_t tun_flavour_str(uint32_t flavour)
}
static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
- int *timeout_io, const struct timeval *tv_now,
- uint64_t *now)
+ int *timeout_io)
{
struct tun *st=sst;
*nfds_io=1;
return 0;
}
-static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds,
- const struct timeval *tv_now, uint64_t *now)
+static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds)
{
struct tun *st=sst;
int l;
}
if (fds[0].revents&POLLIN) {
BUF_ALLOC(st->buff,"tun_afterpoll");
- buffer_init(st->buff,st->nl.max_start_pad);
- l=read(st->fd,st->buff->start,st->buff->len-st->nl.max_start_pad);
+ buffer_init(st->buff,calculate_max_start_pad());
+ l=read(st->fd, st->buff->start, buf_remaining_space(st->buff));
if (l<0) {
fatal_perror("tun_afterpoll: read()");
}
static void tun_deliver_to_kernel(void *sst, struct buffer_if *buf)
{
struct tun *st=sst;
+ ssize_t rc;
BUF_ASSERT_USED(buf);
- /* No error checking, because we'd just throw the packet away
- anyway if it didn't work. */
- write(st->fd,buf->start,buf->size);
+
+ /* Log errors, so we can tell what's going on, but only once a
+ minute, so we don't flood the logs. Short writes count as
+ errors. */
+ rc = write(st->fd,buf->start,buf->size);
+ if(rc != buf->size) {
+ static struct timeval last_report;
+ if(tv_now_global.tv_sec >= last_report.tv_sec + 60) {
+ if(rc < 0)
+ Message(M_WARNING,
+ "failed to deliver packet to tun device: %s\n",
+ strerror(errno));
+ else
+ Message(M_WARNING,
+ "truncated packet delivered to tun device\n");
+ last_report = tv_now_global;
+ }
+ }
BUF_FREE(buf);
}
struct tun *st=sst;
string_t network, mask, secnetaddr;
struct subnet_list *nets;
- uint32_t i;
+ int32_t i;
int fd=-1;
+ bool_t up;
- if (routes->up == routes->kup) return False;
+ if (routes->options & OPT_SOFTROUTE)
+ up = routes->up;
+ else
+ up = routes->link_quality > LINK_QUALITY_UNUSED;
+
+ if (up == routes->kup) return False;
if (st->route_type==TUN_CONFIG_IOCTL) {
if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
fd=open(st->ip_path,O_RDWR);
network=ipaddr_to_string(nets->list[i].prefix);
mask=ipaddr_to_string(nets->list[i].mask);
Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
- st->nl.name,routes->up?"adding":"deleting",network,
- nets->list[i].len,routes->up?"to":"from");
+ st->nl.name,up?"adding":"deleting",network,
+ nets->list[i].len,up?"to":"from");
switch (st->route_type) {
case TUN_CONFIG_LINUX:
- sys_cmd(st->route_path,"route",routes->up?"add":"del",
+ sys_cmd(st->route_path,"route",up?"add":"del",
"-net",network,"netmask",mask,
"gw",secnetaddr,(char *)0);
break;
case TUN_CONFIG_BSD:
- sys_cmd(st->route_path,"route",routes->up?"add":"del",
+ sys_cmd(st->route_path,"route",up?"add":"del",
"-net",network,secnetaddr,mask,(char *)0);
break;
case TUN_CONFIG_SOLARIS25:
- sys_cmd(st->route_path,"route",routes->up?"add":"del",
+ sys_cmd(st->route_path,"route",up?"add":"del",
network,secnetaddr,(char *)0);
break;
case TUN_CONFIG_IOCTL:
{
-#ifdef HAVE_NET_ROUTE_H
+ /* darwin rtentry has a different format, use /sbin/route instead */
+#if HAVE_NET_ROUTE_H && ! __APPLE__
struct rtentry rt;
struct sockaddr_in *sa;
int action;
- memset(&rt,0,sizeof(rt));
+ FILLZERO(rt);
sa=(struct sockaddr_in *)&rt.rt_dst;
sa->sin_family=AF_INET;
sa->sin_addr.s_addr=htonl(nets->list[i].prefix);
sa->sin_family=AF_INET;
sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
rt.rt_flags=RTF_UP|RTF_GATEWAY;
- action=routes->up?SIOCADDRT:SIOCDELRT;
+ action=up?SIOCADDRT:SIOCDELRT;
if (ioctl(fd,action,&rt)<0) {
fatal_perror("tun_set_route: ioctl()");
}
fatal("tun_set_route: unsupported route command type");
break;
}
- free(network); free(mask);
}
- free(secnetaddr);
- if (st->route_type==TUN_CONFIG_IOCTL) {
+ if (fd >= 0) {
close(fd);
}
- routes->kup=routes->up;
+ routes->kup=up;
return True;
}
{
struct tun *st=sst;
string_t hostaddr,secnetaddr;
- uint8_t mtu[6];
+ char mtu[6];
struct netlink_client *r;
if (st->tun_flavour==TUN_FLAVOUR_BSD) {
fatal_perror("%s: can't open device file %s",st->nl.name,
st->device_path);
}
- memset(&ifr,0,sizeof(ifr));
+ FILLZERO(ifr);
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
no extra headers */
if (st->interface_name)
st->interface_name=safe_malloc(10,"tun_apply");
sprintf(st->interface_name,"tun%d",ppa);
st->fd=tun_fd;
+ setcloexec(if_ifd);
+ setcloexec(ip_ifd);
#else
fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected");
#endif /* HAVE_TUN_STREAMS */
to set the TUN device's address, and route to add routes to all
our networks. */
- hostaddr=ipaddr_to_string(st->local_address);
+ setcloexec(st->fd);
+
+ hostaddr=ipaddr_to_string(st->nl.local_address);
secnetaddr=ipaddr_to_string(st->nl.secnet_address);
- snprintf(mtu,6,"%d",st->nl.mtu);
+ snprintf(mtu,sizeof(mtu),"%d",st->nl.mtu);
mtu[5]=0;
switch (st->ifconfig_type) {
hostaddr,secnetaddr,"mtu",mtu,"up",(char *)0);
break;
case TUN_CONFIG_IOCTL:
-#ifdef HAVE_NET_IF_H
+#if HAVE_NET_IF_H && ! __APPLE__
{
int fd;
struct ifreq ifr;
/* Interface address */
strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
sa=(struct sockaddr_in *)&ifr.ifr_addr;
- memset(sa,0,sizeof(*sa));
+ FILLZERO(*sa);
sa->sin_family=AF_INET;
- sa->sin_addr.s_addr=htonl(st->local_address);
+ sa->sin_addr.s_addr=htonl(st->nl.local_address);
if (ioctl(fd,SIOCSIFADDR, &ifr)!=0) {
fatal_perror("tun_apply: SIOCSIFADDR");
}
/* Netmask */
strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
sa=(struct sockaddr_in *)&ifr.ifr_netmask;
- memset(sa,0,sizeof(*sa));
+ FILLZERO(*sa);
sa->sin_family=AF_INET;
sa->sin_addr.s_addr=htonl(0xffffffff);
if (ioctl(fd,SIOCSIFNETMASK, &ifr)!=0) {
/* Destination address (point-to-point) */
strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
sa=(struct sockaddr_in *)&ifr.ifr_dstaddr;
- memset(sa,0,sizeof(*sa));
+ FILLZERO(*sa);
sa->sin_family=AF_INET;
sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
if (ioctl(fd,SIOCSIFDSTADDR, &ifr)!=0) {
st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
- st->local_address=string_item_to_ipaddr(
- dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
/* If we haven't been told what type of TUN we're using, take
fatal_perror("tun_create: uname");
}
if (strcmp(u.sysname,"Linux")==0) {
- if (u.release[0]=='2' && u.release[1]=='.' && u.release[3]=='.') {
- if (u.release[2]=='2') st->tun_flavour=TUN_FLAVOUR_BSD;
- else if (u.release[2]=='4') st->tun_flavour=TUN_FLAVOUR_LINUX;
- }
+ st->tun_flavour=TUN_FLAVOUR_LINUX;
} else if (strcmp(u.sysname,"SunOS")==0) {
st->tun_flavour=TUN_FLAVOUR_STREAMS;
- } else if (strcmp(u.sysname,"FreeBSD")==0) {
+ } else if (strcmp(u.sysname,"FreeBSD")==0
+ || strcmp(u.sysname,"Darwin")==0) {
st->tun_flavour=TUN_FLAVOUR_BSD;
}
}
st->ifconfig_type=TUN_CONFIG_IOCTL;
break;
case TUN_FLAVOUR_BSD:
+#if __linux__
/* XXX on Linux we still want TUN_CONFIG_IOCTL. Perhaps we can
use this on BSD too. */
st->ifconfig_type=TUN_CONFIG_IOCTL;
+#else
+ st->ifconfig_type=TUN_CONFIG_BSD;
+#endif
break;
case TUN_FLAVOUR_STREAMS:
st->ifconfig_type=TUN_CONFIG_BSD;
return tun_create(self,loc,context,args,TUN_FLAVOUR_BSD);
}
-init_module tun_module;
void tun_module(dict_t *dict)
{
add_closure(dict,"tun",tun_apply);