Permalink
Browse files

Tap device support for Linux and FreeBSD

  • Loading branch information...
demirten committed Nov 3, 2015
1 parent 5285dee commit 737f68bdf894d593b708e4cf11e50f183a2283a1
Showing with 119 additions and 1 deletion.
  1. +27 −0 configure.ac
  2. +85 −1 src/common/sendpacket.c
  3. +1 −0 src/common/sendpacket.h
  4. +6 −0 src/config.h.in
View
@@ -477,6 +477,25 @@ if test x$inet_addr = no ; then
AC_MSG_ERROR([We need inet_addr. See bug 26])
fi
dnl #####################################################
dnl Checks for tuntap device support
dnl #####################################################
have_tuntap=no
AC_ARG_ENABLE([tuntap],
AS_HELP_STRING([--disable-tuntap], [Disable tuntap support]), [:],
[case "$build_os" in
linux*)
AC_CHECK_HEADER([linux/if_tun.h], [have_tuntap=yes])
;;
freebsd*)
AC_CHECK_HEADER([net/if_tun.h], [have_tuntap=yes])
;;
esac])
if test $have_tuntap = yes ; then
AC_DEFINE([HAVE_TUNTAP], [1],
[Do we have TUNTAP device support?])
fi
dnl #####################################################
dnl Checks for libpcap
dnl #####################################################
@@ -1619,6 +1638,13 @@ case $host in
AC_MSG_RESULT(OpenBSD)
;;
*-*-freebsd*)
nic1=em0
nic2=em0
AC_DEFINE([HAVE_FREEBSD], [1], [Building Free BSD])
AC_MSG_RESULT(FreeBSD)
;;
*-*-cygwin)
AC_MSG_RESULT(Win32/Cygwin)
nic1=%0
@@ -1718,6 +1744,7 @@ pcap_sendpacket: ${have_pcap_sendpacket} **
pcap_netmap ${have_pcap_netmap}
Linux Quick TX: ${have_linux_quick_tx} ${kerneldir}
Linux/BSD netmap: ${have_netmap}
Tuntap device support: ${have_tuntap}
* In order of preference; see configure --help to override
** Required for tcpbridge
View
@@ -158,6 +158,15 @@ static int get_iface_index(int fd, const char *device, char *);
#endif /* HAVE_PF_PACKET */
#ifdef HAVE_TUNTAP
#ifdef HAVE_LINUX
#include <linux/if_tun.h>
#elif defined(HAVE_FREEBSD)
#define TUNTAP_DEVICE_PREFIX "/dev/"
#endif
static sendpacket_t *sendpacket_open_tuntap(const char *, char *);
#endif
#if defined HAVE_BPF && ! defined INJECT_METHOD
#undef INJECT_METHOD
#define INJECT_METHOD "bpf send()"
@@ -289,6 +298,10 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr
break;
case SP_TYPE_TUNTAP:
retcode = write(sp->handle.fd, (void *)data, len);
break;
/* Linux PF_PACKET and TX_RING */
case SP_TYPE_PF_PACKET:
case SP_TYPE_TX_RING:
@@ -510,6 +523,10 @@ sendpacket_open(const char *device, char *errbuf, tcpr_dir_t direction,
break;
}
}
#ifdef HAVE_TUNTAP
} else if (strncmp(device, "tap", 3) == 0) {
sp = sendpacket_open_tuntap(device, errbuf);
#endif
} else {
#ifdef HAVE_QUICK_TX
if (sendpacket_type == SP_TYPE_QUICK_TX)
@@ -633,6 +650,11 @@ sendpacket_close(sendpacket_t *sp)
#endif /* HAVE_NETMAP */
break;
case SP_TYPE_TUNTAP:
#ifdef HAVE_TUNTAP
close(sp->handle.fd);
#endif
break;
case SP_TYPE_NONE:
err(-1, "no injector selected!");
break;
@@ -800,6 +822,67 @@ sendpacket_get_hwaddr_libdnet(sendpacket_t *sp)
}
#endif /* HAVE_LIBDNET */
#if defined HAVE_TUNTAP
/**
* Inner sendpacket_open() method for tuntap devices
*/
static sendpacket_t *
sendpacket_open_tuntap(const char *device, char *errbuf)
{
sendpacket_t *sp;
struct ifreq ifr;
int flags = 0;
int tapfd;
assert(device);
assert(errbuf);
#if defined HAVE_LINUX
if ((tapfd = open("/dev/net/tun", O_RDWR)) < 0) {
snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Could not open /dev/net/tun control file: %s", strerror(errno));
return NULL;

This comment has been minimized.

Show comment
Hide comment
@fklassen

fklassen Dec 15, 2015

Should this be /dev/net/<device_name> ?? For example, /dev/net/tap0 ??

@fklassen

fklassen Dec 15, 2015

Should this be /dev/net/<device_name> ?? For example, /dev/net/tap0 ??

This comment has been minimized.

Show comment
Hide comment
@demirten

demirten Dec 15, 2015

Owner

No, you should use /dev/net/tun control device both of the TUN and TAP interfaces and use ioctl with IFF_TUN or IFF_TAP. See: https://www.kernel.org/doc/Documentation/networking/tuntap.txt

@demirten

demirten Dec 15, 2015

Owner

No, you should use /dev/net/tun control device both of the TUN and TAP interfaces and use ioctl with IFF_TUN or IFF_TAP. See: https://www.kernel.org/doc/Documentation/networking/tuntap.txt

This comment has been minimized.

Show comment
Hide comment
@fklassen

fklassen Dec 16, 2015

Right, I got confused between device name and interface name. Name is correct.

@fklassen

fklassen Dec 16, 2015

Right, I got confused between device name and interface name. Name is correct.

}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = (IFF_TAP | IFF_NO_PI);

This comment has been minimized.

Show comment
Hide comment
@fklassen

fklassen Dec 15, 2015

Taps and Tuns are different on Linux. If device name is tapX suspect that you should use IFF_TAP. If device name is tunX, flag should be IFF_TUN. But above you give the device a name of '/dev/net/tun'. Should be '/dev/net/tapX'.

Also, Tun may be harder to implement. Packets must be fed without Ethernet layer (feed Layer 3 packets rather than Layer 2 frames). For now, I suggest only supporting Tap.

@fklassen

fklassen Dec 15, 2015

Taps and Tuns are different on Linux. If device name is tapX suspect that you should use IFF_TAP. If device name is tunX, flag should be IFF_TUN. But above you give the device a name of '/dev/net/tun'. Should be '/dev/net/tapX'.

Also, Tun may be harder to implement. Packets must be fed without Ethernet layer (feed Layer 3 packets rather than Layer 2 frames). For now, I suggest only supporting Tap.

This comment has been minimized.

Show comment
Hide comment
@demirten

demirten Dec 15, 2015

Owner

See my previous line comments about /dev/net/tun. I'm using tap device support in tcpdump effectively, on the other hand I can't see any usefull example with tun device support. I don't have much experience with tun devices so maybe we should get more comments to clarify.

@demirten

demirten Dec 15, 2015

Owner

See my previous line comments about /dev/net/tun. I'm using tap device support in tcpdump effectively, on the other hand I can't see any usefull example with tun device support. I don't have much experience with tun devices so maybe we should get more comments to clarify.

This comment has been minimized.

Show comment
Hide comment
@fklassen

fklassen Dec 16, 2015

I implemented a TUN server/client so that any 2 clients are not on the same collision domain. It works well for security, making sure that one client will never see the other client's traffic. On the client side, you see one TUN interface (in this example ani0). On the server side you see many aniX interfaces, one per connection.

I plan to do some compression optimization in a few months. I'll take a stab at implementing the TUN interface at that time, if you like. It will get well used, and therefore well tested. I may have to use a PTP DLT instead of Ethernet, so it may be a bit more work than just simply flipping the bit.

Here is what a TUN looks like...

ani0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:172.18.1.158  P-t-P:172.18.1.158  Mask:255.255.255.252
          UP POINTOPOINT RUNNING  MTU:1500  Metric:1
          RX packets:155810 errors:0 dropped:0 overruns:0 frame:0
          TX packets:174179 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500 
          RX bytes:23256221 (22.1 MiB)  TX bytes:12869314 (12.2 MiB)

eth0      Link encap:Ethernet  HWaddr f0:ad:4e:01:14:3e  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:89 

eth1      Link encap:Ethernet  HWaddr f0:ad:4e:01:14:3f  
          inet addr:172.16.124.32  Bcast:172.16.125.255  Mask:255.255.254.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:67667585 errors:0 dropped:1268 overruns:0 frame:0
          TX packets:31241239 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:3919479366 (3.6 GiB)  TX bytes:3896468586 (3.6 GiB)
          Interrupt:90 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:498078 errors:0 dropped:0 overruns:0 frame:0
          TX packets:498078 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:34185290 (32.6 MiB)  TX bytes:34185290 (32.6 MiB)
@fklassen

fklassen Dec 16, 2015

I implemented a TUN server/client so that any 2 clients are not on the same collision domain. It works well for security, making sure that one client will never see the other client's traffic. On the client side, you see one TUN interface (in this example ani0). On the server side you see many aniX interfaces, one per connection.

I plan to do some compression optimization in a few months. I'll take a stab at implementing the TUN interface at that time, if you like. It will get well used, and therefore well tested. I may have to use a PTP DLT instead of Ethernet, so it may be a bit more work than just simply flipping the bit.

Here is what a TUN looks like...

ani0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:172.18.1.158  P-t-P:172.18.1.158  Mask:255.255.255.252
          UP POINTOPOINT RUNNING  MTU:1500  Metric:1
          RX packets:155810 errors:0 dropped:0 overruns:0 frame:0
          TX packets:174179 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500 
          RX bytes:23256221 (22.1 MiB)  TX bytes:12869314 (12.2 MiB)

eth0      Link encap:Ethernet  HWaddr f0:ad:4e:01:14:3e  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:89 

eth1      Link encap:Ethernet  HWaddr f0:ad:4e:01:14:3f  
          inet addr:172.16.124.32  Bcast:172.16.125.255  Mask:255.255.254.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:67667585 errors:0 dropped:1268 overruns:0 frame:0
          TX packets:31241239 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:3919479366 (3.6 GiB)  TX bytes:3896468586 (3.6 GiB)
          Interrupt:90 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:498078 errors:0 dropped:0 overruns:0 frame:0
          TX packets:498078 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:34185290 (32.6 MiB)  TX bytes:34185290 (32.6 MiB)
strncpy(ifr.ifr_name, device, strlen(device));
if (ioctl(tapfd, TUNSETIFF, (void *) &ifr) < 0) {
snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to create tuntap interface: %s", device);
return NULL;
}
#elif defined(HAVE_FREEBSD)
if (*device == '/') {
if ((tapfd = open(device, O_RDWR)) < 0) {
snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Could not open device %s: %s", device, strerror(errno));
return NULL;
}
} else {
/* full path needed */
char *path;
int prefix_length = strlen(TUNTAP_DEVICE_PREFIX);
if ((path = malloc(strlen(device) + prefix_length + 1)) == NULL) {
snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Malloc error: %s", strerror(errno));
return NULL;
}
snprintf(path, strlen(device) + prefix_length + 1, "%s%s", TUNTAP_DEVICE_PREFIX, device);
if ((tapfd = open(path, O_RDWR)) < 0) {
snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Could not open device %s: %s", path, strerror(errno));
free(path);
return NULL;
}
free(path);
}
#endif
/* prep & return our sp handle */
sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
strlcpy(sp->device, device, sizeof(sp->device));
sp->handle.fd = tapfd;
sp->handle_type = SP_TYPE_TUNTAP;
return sp;
}
#endif
#if defined HAVE_PF_PACKET
/**
* Inner sendpacket_open() method for using Linux's PF_PACKET or TX_RING
@@ -1162,7 +1245,8 @@ sendpacket_get_dlt(sendpacket_t *sp)
if (sp->handle_type == SP_TYPE_KHIAL ||
sp->handle_type == SP_TYPE_NETMAP ||
sp->handle_type == SP_TYPE_QUICK_TX) {
sp->handle_type == SP_TYPE_QUICK_TX ||
sp->handle_type == SP_TYPE_TUNTAP) {
/* always EN10MB */
;
} else {
View
@@ -79,6 +79,7 @@ typedef enum sendpacket_type_e {
SP_TYPE_KHIAL,
SP_TYPE_NETMAP,
SP_TYPE_QUICK_TX,
SP_TYPE_TUNTAP

This comment has been minimized.

Show comment
Hide comment
@fklassen

fklassen Dec 15, 2015

Should this be SP_TYPE_TAP, and we can implement SP_TYPE_TUN in the future?

@fklassen

fklassen Dec 15, 2015

Should this be SP_TYPE_TAP, and we can implement SP_TYPE_TUN in the future?

} sendpacket_type_t;
/* these are the file_operations ioctls */
View
@@ -145,6 +145,9 @@
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Building Free BSD */
#undef HAVE_FREEBSD
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#undef HAVE_FSEEKO
@@ -518,6 +521,9 @@
/* Do we have tcpdump? */
#undef HAVE_TCPDUMP
/* Do we have TUNTAP device support? */
#undef HAVE_TUNTAP
/* Do we have Linux TX_RING socket support? */
#undef HAVE_TX_RING

0 comments on commit 737f68b

Please sign in to comment.