Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I/O with a Tun interface

The intent is to have a program intercept a collection of IP packets and read its raw content and then reinsert it to the network after tinkering with it.

My approach is based around setting up a Tuntap interface (Tun, to be specific), and then have iptables and similar redirect the desired packets to this tunnel interface.

For testing purposes, I've written this short shell script that sets up the Tun interface and adds the required rules. For now, I intend to test this on any packet sent from my local machine with a destination of 123.123.123.123. Here's the startup script:

# Set up the tunnel
ip tuntap add dev maintun mode tun
ifconfig maintun inet 10.10.10.1 netmask 255.255.255.0 up

# Mark packets for forwarding to tun
iptables -t mangle -A PREROUTING -d 123.123.123.123 -j MARK --set-mark 2

# Apply ClientRouter table to mark 2 as it's defined in /etc/iproute2/rt_tables
# 201 ClientRouter
ip rule add fwmark 2 table ClientRouter

# Apply gw if to ClienRouter
ip route add default via 10.10.10.1 dev maintun table ClientRouter

I started writing a perl script to read from the Tun device, but I'm stuck on multiple points at once:

  1. It seems to me that the way to do this is to have the script itself create the interface by calling ioctl() on a filehandle to /dev/net/tun, but I'm unsure of the other arguements ioctl() wants. Which leads me to the next two points:
  2. I see references to the second arguement being TUNSETIFF. All I know is that it has to be numeric. What is it asking for?
  3. From what I've gathered, the third arguement is supposed to be flags of some sort, but I have not managed to find info on them. Presumably, one flag would be for selecting if it should be a Tun or Tap tunnel. Any info on this?

As I'm stuck with the ioctl() flag, I would like to take a step back and ask: How does one programatically read from a Tun device, preferably a preconfigured one set up in advance?

Also, if someone sees anything wrong with the startup-script, feel free to shout out.

While ideally the sollution would be in perl, it doesn't have to be, it's just that that's the language that I can read the easiest. Java would also be decent. Unfortunately, my C literacy isn't even close to as good as it should be for this.

Edit:

If a different approach than Tun/Tap would allow me to do as described in the first paragraph, any suggestions would of course be welcome.


Note:

I came cross this question and while similar, it does not provide an answer to the ioctl() arguements. It was, however, what indicated the need for an ioctl() call.

like image 463
Jarmund Avatar asked May 25 '15 22:05

Jarmund


People also ask

What is a tun network interface?

The tun interface is a software loopback mechanism that can be loosely described as the network interface analog of the pty(4), that is, tun does for network interfaces what the pty(4) driver does for terminals.

How does a tun tap work?

To put the matter more simply, the TUN/TAP driver creates a virtual network interface on your Linux box. This interface works just like any other; you can assign IP addresses, route to it, and so on. But when you send traffic to that interface, the traffic is routed to your program instead of to a real network.

What is Linux Tunctl command?

Description. tunctl allows the host sysadmin to preconfigure a TUN/TAP network interface for use by a particular user. That user may open and use the network/write side of the interface, but may not change any aspects of the host side of the interface.

What is a tap device?

Introduction. A network TAP (Test Access Point) is a simple device that connects directly to the cabling infrastructure to split or copy packets for use in analysis, security or general network management.


1 Answers

First, the TUN/TAP interface is documented in the Linux kernel documentation, which is worth a read if you haven't already seen it. The examples are in C, of course, but hopefully still useful.

I see references to the second arguement being TUNSETIFF. All I know is that it has to be numeric. What is it asking for?

This is a C library constant, the value of which you can determine with code like the following:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>

int main(int argc, char **argv) {
  printf("TUNSETIFF: %d\n", TUNSETIFF);
  return 0;
}

Which on my system returns:

TUNSETIFF: 1074025674

From what I've gathered, the third arguement is supposed to be flags of some sort, but I have not managed to find info on them. Presumably, one flag would be for selecting if it should be a Tun or Tap tunnel. Any info on this?

The third argument is a pointer to a structure that has an ifr_name attribute, containing the device name, and an ifr_flags attribute containing the flags. The kernel documentation provides the following sample code:

  /* Flags: IFF_TUN   - TUN device (no Ethernet headers) 
   *        IFF_TAP   - TAP device  
   *
   *        IFF_NO_PI - Do not provide packet information  
   */ 
  ifr.ifr_flags = IFF_TUN; 
  if( *dev )
     strncpy(ifr.ifr_name, dev, IFNAMSIZ);

  if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
     close(fd);
     return err;
  }

You can find the values for the different flags (IFF_TUN, IFF_TAP) using the same code from above that we used to find the value of TUNSETIFF.

If you are writing code in Perl, you would need a way to create the corresponding C-compatible structure. My Perl is too rusty to suggest the proper solution off the top of my head.

However, there appear to be a number of Perl modules available that simplify the whole process:

  • http://search.cpan.org/~mooli/Linux-TunTap-0.001/lib/Linux/TunTap.pm
  • http://search.cpan.org/~gomor/Net-Libdnet/
like image 51
larsks Avatar answered Oct 06 '22 20:10

larsks