~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/Documentation/networking/ethertap.txt

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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
  6 
  7 Ethertap programming mini-HOWTO
  8 -------------------------------
  9 
 10 The ethertap driver was written by Jay Schulist <jschlst@turbolinux.com>,
 11 you should contact him for further information. This document was written by
 12 bert hubert <bert.hubert@netherlabs.nl>. Updates are welcome.
 13 
 14 What ethertap can do for you
 15 ----------------------------
 16 
 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.
 22 
 23 The more technical blurb:
 24 
 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.
 28 
 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.
 31 
 32 Configuring your kernel
 33 -----------------------
 34 
 35 Firstly, you need this in Networking Options:
 36 
 37         #
 38         # Code maturity level options
 39         #
 40         CONFIG_EXPERIMENTAL=y
 41 
 42 Then you need Netlink support:
 43 
 44         CONFIG_NETLINK=y
 45 
 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.inr.ac.ru/ip-routing/iproute2*
 51 
 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
 54 
 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.
 57 
 58 The older way works by opening character special files with major node 36.
 59 Enable this with:
 60 
 61         CONFIG_NETLINK_DEV=m
 62 
 63 Please be advised that this support is going to be dropped somewhere in the
 64 future!
 65 
 66 Then finally in the Network Devices section, 
 67 
 68         CONFIG_ETHERTAP=m
 69 
 70 You can include it directly in the kernel if you want, of course, no need
 71 for modules.
 72 
 73 Setting it all up
 74 -----------------
 75 
 76 First we need to create the /dev/tap0 device node:
 77 
 78         # mknod /dev/tap0 c 36 16
 79         # mknod /dev/tap1 c 36 17
 80         (etc)
 81 
 82 Include the relevant modules (ethertap.o, netlink_dev.o, perhaps netlink.o),
 83 and bring up your tap0 device:
 84 
 85         # ifconfig tap0 10.0.0.123 up
 86 
 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?
 90 
 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:
 93 
 94         # route add -host 10.0.0.124 gw 10.0.0.123
 95 
 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.
 98 
 99         # cat /dev/tap0
100         :ßVU:9````````````````````````şışET@?'
101 
102 
103 Getting this to work from other hosts
104 -------------------------------------
105 
106 For this to work, you often need proxy ARP. 
107 
108         # echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp 
109 
110 eth0 here stands for the interface that connects to 'other hosts'.
111 
112 Chances are that you are trying this on a non-routing desktop computer, so
113 you need to enable ip forwarding:
114 
115         # echo 1 > /proc/sys/net/ipv4/ip_forward 
116 
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
119 everywhere.
120 
121 ARP
122 ---
123 
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:
128 
129         # ifconfig tap0 10.0.0.123 up arp
130 
131 This may also be useful when implementing a bridge, which needs to bridge
132 ARP packets as well.
133 
134 The sample program below will no longer work then, because it does not
135 implement ARP. 
136 
137 Sample program
138 --------------
139 
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
144 packet.
145 
146 /* Simple program to listen to /dev/tap0 and reply to pings. */
147 #include <fcntl.h>
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>
153 #else
154 #include <linux/tcp.h>
155 #include <linux/udp.h>
156 #endif
157 #include <string.h>
158 #include <stdio.h>
159 #include <errno.h>
160 #include <unistd.h>
161 
162 u_int16_t csum_partial(void *buffer, unsigned int len, u_int16_t prevsum)
163 {
164         u_int32_t sum = 0;
165         u_int16_t *ptr = buffer;
166 
167         while (len > 1)  {
168                 sum += *ptr++;
169                 len -= 2;
170         }
171         if (len) {
172                 union {
173                         u_int8_t byte;
174                         u_int16_t wyde;
175                 } odd;
176                 odd.wyde = 0;
177                 odd.byte = *((u_int8_t *)ptr);
178                 sum += odd.wyde;
179         }
180         sum = (sum >> 16) + (sum & 0xFFFF);
181         sum += prevsum;
182         return (sum + (sum >> 16));
183 }
184 
185 int main()
186 {
187         int fd, len;
188         union {
189                 struct {
190                         char etherhdr[16];
191                         struct iphdr ip;
192                 } fmt;
193                 unsigned char raw[65536];
194         } u;
195 
196         fd = open("/dev/tap0", O_RDWR);
197         if (fd < 0) {
198                 perror("Opening `/dev/tap0'");
199                 return 1;
200         }
201 
202         /* u.fmt.ip.ihl in host order!  Film at 11. */
203         while ((len = read(fd, &u, sizeof(u))) > 0) {
204                 u_int32_t tmp;
205                 struct icmphdr *icmp
206                         = (void *)((u_int32_t *)&u.fmt.ip + u.fmt.ip.ihl );
207                 struct tcphdr *tcp = (void *)icmp;
208                 struct udphdr *udp = (void *)icmp;
209                 
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);
219 
220                 switch (u.fmt.ip.protocol) {
221                 case IPPROTO_ICMP:
222                         if (icmp->type == ICMP_ECHO) {
223                                 fprintf(stderr, "PONG! (iphdr = %u bytes)\n",
224                                         (unsigned int)((char *)icmp
225                                                        - (char *)&u.fmt.ip));
226 
227                                 /* Turn it around */
228                                 tmp = u.fmt.ip.saddr;
229                                 u.fmt.ip.saddr = u.fmt.ip.daddr;
230                                 u.fmt.ip.daddr = tmp;
231 
232                                 icmp->type = ICMP_ECHOREPLY;
233                                 icmp->checksum = 0;
234                                 icmp->checksum
235                                         = ~csum_partial(icmp,
236                                                         ntohs(u.fmt.ip.tot_len)
237                                                         - u.fmt.ip.ihl*4, 0);
238 
239                                 {
240                                         unsigned int i;
241                                         for (i = 44;
242                                              i < ntohs(u.fmt.ip.tot_len); i++){
243                                                 printf("%u:0x%02X ", i,
244                                                        ((unsigned char *)
245                                                         &u.fmt.ip)[i]);
246                                         }
247                                         printf("\n");
248                                 }
249                                 write(fd, &u, len);
250                         }
251                         break;
252                 case IPPROTO_TCP:
253                         fprintf(stderr, "TCP: %u -> %u\n", ntohs(tcp->source),
254                                 ntohs(tcp->dest));
255                         break;
256 
257                 case IPPROTO_UDP:
258                         fprintf(stderr, "UDP: %u -> %u\n", ntohs(udp->source),
259                                 ntohs(udp->dest));
260                         break;
261                 }
262         }
263         if (len < 0)
264                 perror("Reading from `/dev/tap0'");
265         else fprintf(stderr, "Empty read from `/dev/tap0'");
266         return len < 0 ? 1 : 0;
267 }
268                         

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.