1 NOTE: Ethertap is now an obsolete facility, and is scheduled
2 to be removed in the 2.5.x kernel series. Those writing
3 applications using ethertap should convert their code to
4 use the TUN/TAP driver instead, see 'tuntap.txt' in this
5 directory for more details. -DaveM
7 Ethertap programming mini-HOWTO
8 -------------------------------
10 The ethertap driver was written by Jay Schulist <jschlst@samba.org>,
11 you should contact him for further information. This document was written by
12 bert hubert <bert.hubert@netherlabs.nl>. Updates are welcome.
14 What ethertap can do for you
15 ----------------------------
17 Ethertap allows you to easily run your own network stack from userspace.
18 Tunnels can benefit greatly from this. You can also use it to do network
19 experiments. The alternative would be to use a raw socket to send data and
20 use libpcap to receive it. Using ethertap saves you this multiplicity and
21 also does ARP for you if you want.
23 The more technical blurb:
25 Ethertap provides packet reception and transmission for user space programs.
26 It can be viewed as a simple Ethernet device, which instead of receiving
27 packets from a network wire, it receives them from user space.
29 Ethertap can be used for anything from AppleTalk to IPX to even building
30 bridging tunnels. It also has many other general purpose uses.
32 Configuring your kernel
33 -----------------------
35 Firstly, you need this in Networking Options:
38 # Code maturity level options
42 Then you need Netlink support:
46 This allows the kernel to exchange data with userspace applications. There
47 are two ways of doing this, the new way works with netlink sockets and I
48 have no experience with that yet. ANK uses it in his excellent iproute2
49 package, see for example rtmon.c. iproute2 can be found on
50 ftp://ftp.tux.org/pub/net/ip-routing/iproute2*
52 The new way is described, partly in netlink(7), available on
53 http://www.europe.redhat.com/documentation/man-pages/man7/netlink.7.php3
55 There is also a Netlink-HOWTO, available on http://snafu.freedom.org/linux2.2/docs/netlink-HOWTO.html
56 Sadly I know of no code using ethertap with this new interface.
58 The older way works by opening character special files with major node 36.
63 Please be advised that this support is going to be dropped somewhere in the
66 Then finally in the Network Devices section,
70 You can include it directly in the kernel if you want, of course, no need
76 First we need to create the /dev/tap0 device node:
78 # mknod /dev/tap0 c 36 16
79 # mknod /dev/tap1 c 36 17
82 Include the relevant modules (ethertap.o, netlink_dev.o, perhaps netlink.o),
83 and bring up your tap0 device:
85 # ifconfig tap0 10.0.0.123 up
87 Now your device is up and running, you can ping it as well. This is what
88 confused me to no end, because nothing is connected to our ethertap as yet,
89 how is it that we can ping it?
91 It turns out that the ethertap is just like a regular network interface -
92 even when it's down you can ping it. We need to route stuff to it:
94 # route add -host 10.0.0.124 gw 10.0.0.123
96 Now we can read /dev/tap0 and when we ping 10.0.0.124 from our
97 localhost, output should appear on the screen.
100 :ßVU:9````````````````````````þýþET@?'
103 Getting this to work from other hosts
104 -------------------------------------
106 For this to work, you often need proxy ARP.
108 # echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp
110 eth0 here stands for the interface that connects to 'other hosts'.
112 Chances are that you are trying this on a non-routing desktop computer, so
113 you need to enable ip forwarding:
115 # echo 1 > /proc/sys/net/ipv4/ip_forward
117 You should now be able to ping 10.0.0.124 from other hosts on your
118 10.0.0.0/8 subnet. If you are using public ip space, it should work from
124 If we were to take things very literally, your tcp/ip pseudo stack would
125 also have to implement ARP and MAC addresses. This is often a bit silly as
126 the ethertap device is a figment of our imagination anyway. However, should
127 you want to go 'all the way', you can add the 'arp' flag to ifconfig:
129 # ifconfig tap0 10.0.0.123 up arp
131 This may also be useful when implementing a bridge, which needs to bridge
134 The sample program below will no longer work then, because it does not
140 A sample program is included somewhere in the bowels of the netfilter
141 source. I've extracted this program and list it here. It implements a very
142 tiny part of the IP stack and can respond to any pings it receives. It gets
143 confused if it receives ARP, as it tries to parse it by treating it as an IP
146 /* Simple program to listen to /dev/tap0 and reply to pings. */
148 #include <netinet/ip.h>
149 #include <netinet/ip_icmp.h>
150 #if defined(__GLIBC__) && (__GLIBC__ == 2)
151 #include <netinet/tcp.h>
152 #include <netinet/udp.h>
154 #include <linux/tcp.h>
155 #include <linux/udp.h>
162 u_int16_t csum_partial(void *buffer, unsigned int len, u_int16_t prevsum)
165 u_int16_t *ptr = buffer;
177 odd.byte = *((u_int8_t *)ptr);
180 sum = (sum >> 16) + (sum & 0xFFFF);
182 return (sum + (sum >> 16));
193 unsigned char raw[65536];
196 fd = open("/dev/tap0", O_RDWR);
198 perror("Opening `/dev/tap0'");
202 /* u.fmt.ip.ihl in host order! Film at 11. */
203 while ((len = read(fd, &u, sizeof(u))) > 0) {
206 = (void *)((u_int32_t *)&u.fmt.ip + u.fmt.ip.ihl );
207 struct tcphdr *tcp = (void *)icmp;
208 struct udphdr *udp = (void *)icmp;
210 fprintf(stderr, "SRC = %u.%u.%u.%u DST = %u.%u.%u.%u\n",
211 (ntohl(u.fmt.ip.saddr) >> 24) & 0xFF,
212 (ntohl(u.fmt.ip.saddr) >> 16) & 0xFF,
213 (ntohl(u.fmt.ip.saddr) >> 8) & 0xFF,
214 (ntohl(u.fmt.ip.saddr) >> 0) & 0xFF,
215 (ntohl(u.fmt.ip.daddr) >> 24) & 0xFF,
216 (ntohl(u.fmt.ip.daddr) >> 16) & 0xFF,
217 (ntohl(u.fmt.ip.daddr) >> 8) & 0xFF,
218 (ntohl(u.fmt.ip.daddr) >> 0) & 0xFF);
220 switch (u.fmt.ip.protocol) {
222 if (icmp->type == ICMP_ECHO) {
223 fprintf(stderr, "PONG! (iphdr = %u bytes)\n",
224 (unsigned int)((char *)icmp
225 - (char *)&u.fmt.ip));
228 tmp = u.fmt.ip.saddr;
229 u.fmt.ip.saddr = u.fmt.ip.daddr;
230 u.fmt.ip.daddr = tmp;
232 icmp->type = ICMP_ECHOREPLY;
235 = ~csum_partial(icmp,
236 ntohs(u.fmt.ip.tot_len)
237 - u.fmt.ip.ihl*4, 0);
242 i < ntohs(u.fmt.ip.tot_len); i++){
243 printf("%u:0x%02X ", i,
253 fprintf(stderr, "TCP: %u -> %u\n", ntohs(tcp->source),
258 fprintf(stderr, "UDP: %u -> %u\n", ntohs(udp->source),
264 perror("Reading from `/dev/tap0'");
265 else fprintf(stderr, "Empty read from `/dev/tap0'");
266 return len < 0 ? 1 : 0;