A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
tap-device-creator.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 University of Washington
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18 
19 #include <arpa/inet.h>
20 #include <unistd.h>
21 #include <stdint.h>
22 #include <iostream>
23 #include <iomanip>
24 #include <sstream>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <net/if.h>
33 #include <linux/if_tun.h>
34 #include <net/route.h>
35 #include <netinet/in.h>
36 
37 #include "creator-utils.h"
38 
39 #define TAP_MAGIC 95549
40 
41 //
42 // Lots of the following helper code taken from corresponding functions in src/node.
43 //
44 #define ASCII_DOT (0x2e)
45 #define ASCII_ZERO (0x30)
46 #define ASCII_a (0x41)
47 #define ASCII_z (0x5a)
48 #define ASCII_A (0x61)
49 #define ASCII_Z (0x7a)
50 #define ASCII_COLON (0x3a)
51 #define ASCII_ZERO (0x30)
52 
53 using namespace ns3;
54 
55 struct in6_ifreq {
56  struct in6_addr ifr6_addr;
57  uint32_t ifr6_prefixlen;
58  int32_t ifr6_ifindex;
59 };
60 
61 char
63 {
64  if (c >= ASCII_a && c <= ASCII_z)
65  {
66  return c;
67  }
68  else if (c >= ASCII_A && c <= ASCII_Z)
69  {
70  return c + (ASCII_a - ASCII_A);
71  }
72  else
73  {
74  return c;
75  }
76 }
77 
78 void
79 AsciiToMac48 (const char *str, uint8_t addr[6])
80 {
81  int i = 0;
82  while (*str != 0 && i < 6)
83  {
84  uint8_t byte = 0;
85  while (*str != ASCII_COLON && *str != 0)
86  {
87  byte <<= 4;
88  char low = AsciiToLowCase (*str);
89  if (low >= ASCII_a)
90  {
91  byte |= low - ASCII_a + 10;
92  }
93  else
94  {
95  byte |= low - ASCII_ZERO;
96  }
97  str++;
98  }
99  addr[i] = byte;
100  i++;
101  if (*str == 0)
102  {
103  break;
104  }
105  str++;
106  }
107 }
108 
109 void
110 SetIpv4 (const char *deviceName, const char *ip, const char *netmask)
111 {
112  struct ifreq ifr;
113  struct sockaddr_in *sin;
114 
115  int sock = socket(AF_INET, SOCK_DGRAM, 0);
116 
117  //
118  // Set the IP address of the new interface/device.
119  //
120  memset(&ifr, 0, sizeof(struct ifreq));
121  strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
122 
123  sin = (struct sockaddr_in*) &ifr.ifr_addr;
124  inet_pton(AF_INET, ip, &sin->sin_addr);
125  ifr.ifr_addr.sa_family = AF_INET;
126 
127  ABORT_IF (ioctl (sock, SIOCSIFADDR, &ifr) == -1,
128  "Could not set IP address", true);
129 
130  LOG ("Set device IP address to " << ip);
131 
132  //
133  // Set the net mask of the new interface/device
134  //
135  memset(&ifr, 0, sizeof(struct ifreq));
136  strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
137 
138  sin = (struct sockaddr_in*) &ifr.ifr_netmask;
139  inet_pton(AF_INET, netmask, &sin->sin_addr);
140  ifr.ifr_addr.sa_family = AF_INET;
141 
142  ABORT_IF (ioctl (sock, SIOCSIFNETMASK, &ifr) == -1,
143  "Could not set net mask", true);
144 
145  LOG ("Set device Net Mask to " << netmask);
146  close(sock);
147 }
148 
149 void
150 SetIpv6 (const char* deviceName, const char *ip, int netprefix)
151 {
152  struct ifreq ifr;
153  struct sockaddr_in6 sin;
154  struct in6_ifreq ifr6;
155 
156  int sock = socket(AF_INET6, SOCK_DGRAM, 0);
157  memset(&ifr, 0, sizeof(struct ifreq));
158  strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
159 
160  ABORT_IF (ioctl (sock, SIOGIFINDEX, &ifr) == -1,
161  "Could not get interface index", true);
162 
163  LOG ("Set device IP v6 address to " << ip);
164 
165  memset(&sin, 0, sizeof(struct sockaddr_in6));
166  sin.sin6_family = AF_INET6;
167  inet_pton(AF_INET6, ip, (void *) &sin.sin6_addr);
168 
169  memset(&ifr6, 0, sizeof(in6_ifreq));
170  memcpy((char *) &ifr6.ifr6_addr, (char *) &sin.sin6_addr, sizeof(struct in6_addr));
171 
172  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
173  ifr6.ifr6_prefixlen = netprefix;
174 
175  //
176  // Set the IP address of the new interface/device.
177  //
178  ABORT_IF (ioctl (sock, SIOCSIFADDR, &ifr6) == -1,
179  "Could not set IP v6 address", true);
180 
181  LOG ("Set device IP v6 address to " << ip);
182  close (sock);
183 
184 }
185 
186 void
187 SetMacAddress (int fd, const char* mac)
188 {
189  struct ifreq ifr;
190  memset(&ifr, 0, sizeof(struct ifreq));
191 
192  ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
193  AsciiToMac48 (mac, (uint8_t*)ifr.ifr_hwaddr.sa_data);
194  ABORT_IF (ioctl (fd, SIOCSIFHWADDR, &ifr) == -1, "Could not set MAC address", true);
195  LOG ("Set device MAC address to " << mac);
196 }
197 
198 void
199 SetUp (char *deviceName)
200 {
201  struct ifreq ifr;
202 
203  int sock = socket(AF_INET, SOCK_DGRAM, 0);
204 
205  memset(&ifr, 0, sizeof(struct ifreq));
206  strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
207 
208  ABORT_IF (ioctl (sock, SIOCGIFFLAGS, &ifr) == -1,
209  "Could not get flags for interface", true);
210  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
211 
212  ABORT_IF (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1,
213  "Could not bring interface up", true);
214 
215  LOG ("Device is up");
216  close (sock);
217 }
218 
219 int
220 CreateTap (char *deviceName, const char *mac, const int ifftap, const int iffpi,
221  const char *ip4, const char *netmask, const char *ip6, const int netprefix)
222 {
223 
224  //
225  // Creation and management of Tap devices is done via the tun device
226  //
227  int fd = open ("/dev/net/tun", O_RDWR);
228  ABORT_IF (fd == -1, "Could not open /dev/net/tun", true);
229 
230  //
231  // Set flags for device type and PI header.
232  //
233  struct ifreq ifr;
234 
235  memset(&ifr, 0, sizeof(struct ifreq));
236 
237  ifr.ifr_flags = (ifftap ? IFF_TAP : IFF_TUN);
238  if (!iffpi)
239  {
240  ifr.ifr_flags |= IFF_NO_PI;
241  }
242 
243  //
244  // If device name is not specified, the kernel chooses one.
245  //
246  if (*deviceName)
247  {
248  strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
249  }
250 
251 
252  ABORT_IF (ioctl (fd, TUNSETIFF, (void *) &ifr) == -1,
253  "Could not allocate tap device", true);
254 
255  LOG ("Allocated TAP device " << deviceName);
256 
257  //
258  // Set the hardware (MAC) address of the new device
259  //
260  if (ifftap)
261  {
262  SetMacAddress(fd, mac);
263  }
264 
265  //
266  // Set the IP address and netmask of the new interface/device.
267  //
268  if (ip4)
269  {
270  SetIpv4(deviceName, ip4, netmask);
271  }
272 
273  if (ip6)
274  {
275  SetIpv6(deviceName, ip6, netprefix);
276  }
277 
278  //
279  // Bring the interface up.
280  //
281  SetUp(deviceName);
282 
283  return fd;
284 }
285 
286 
287 int
288 main (int argc, char *argv[])
289 {
290  int c;
291  char *dev = NULL;
292  char *ip4 = NULL;
293  char *ip6 = NULL;
294  char *mac = NULL;
295  char *netmask = NULL;
296  char *path = NULL;
297  int tap = false;
298  int pi = false;
299  int prefix = -1;
300 
301  while ((c = getopt (argc, argv, "vd:i:m:n:I:P:thp:")) != -1)
302  {
303  switch (c)
304  {
305  case 'd':
306  dev = optarg; // name of the new tap device
307  break;
308  case 'i':
309  ip4 = optarg; // ip v4 address of the new device
310  break;
311  case 'I':
312  ip6 = optarg; // ip v6 address of the new device
313  break;
314  case 'm':
315  mac = optarg; // mac address of the new device
316  break;
317  case 'n':
318  netmask = optarg; // ip v4 net mask for the new device
319  break;
320  case 'P':
321  prefix = atoi(optarg); // ip v6 prefix for the new device
322  break;
323  case 't':
324  tap = true; // mode for the device (TAP or TUN)
325  break;
326  case 'h':
327  pi = true; // set the IFF_NO_PI flag
328  break;
329  case 'p':
330  path = optarg; // path back to the tap bridge
331  break;
332  case 'v':
333  gVerbose = true;
334  break;
335  }
336  }
337 
338  //
339  // We have got to be able to coordinate the name of the tap device we are
340  // going to create and or open with the device that an external Linux host
341  // will use. If this name is provided we use it. If not we let the system
342  // create the device for us. This name is given in dev
343  //
344  LOG ("Provided Device Name is \"" << dev << "\"");
345 
346  //
347  // We have got to be able to assign an IP address to the tap device we are
348  // allocating. This address is allocated in the simulation and assigned to
349  // the tap bridge. This address is given in ip.
350  //
351  ABORT_IF (ip4 == NULL && ip6 == NULL, "IP Address is a required argument", 0);
352  if (ip4)
353  {
354  ABORT_IF (netmask == NULL, "Net mask is a required argument", 0);
355  LOG ("Provided IP v4 Address is \"" << ip4 << "\"");
356  LOG ("Provided IP v4 Net Mask is \"" << netmask << "\"");
357  }
358  if (ip6)
359  {
360  ABORT_IF (prefix == -1, "Prefix is a required argument", 0);
361  LOG ("Provided IP v6 Address is \"" << ip6 << "\"");
362  LOG ("Provided IP v6 Prefix is \"" << prefix << "\"");
363  }
364 
365  //
366  // We have got to be able to assign a Mac address to the tap device we are
367  // allocating. This address is allocated in the simulation and assigned to
368  // the bridged device. This allows packets addressed to the bridged device
369  // to appear in the Linux host as if they were received there.
370  //
371  ABORT_IF (mac == NULL, "MAC Address is a required argument", 0);
372  LOG ("Provided MAC Address is \"" << mac << "\"");
373 
374  //
375  // We have got to know whether or not to create the TAP.
376  //
377  if (tap)
378  {
379  LOG ("Provided device Mode is TAP");
380  }
381  else
382  {
383  LOG ("Provided device Mode is TUN");
384  }
385 
386  //
387  // IFF_NO_PI flag.
388  //
389  if (pi)
390  {
391  LOG ("IFF_NO_PI flag set. Packet Information will be present in the traffic");
392  }
393 
394  //
395  // This program is spawned by a tap bridge running in a simulation. It
396  // wants to create a socket as described below. We are going to do the
397  // work here since we're running suid root. Once we create the socket,
398  // we have to send it back to the tap bridge. We do that over a Unix
399  // (local interprocess) socket. The tap bridge created a socket to
400  // listen for our response on, and it is expected to have encoded the address
401  // information as a string and to have passed that string as an argument to
402  // us. We see it here as the "path" string. We can't do anything useful
403  // unless we have that string.
404  //
405  ABORT_IF (path == NULL, "path is a required argument", 0);
406  LOG ("Provided path is \"" << path << "\"");
407 
408  //
409  // The whole reason for all of the hoops we went through to call out to this
410  // program will pay off here. We created this program to run as suid root
411  // in order to keep the main simulation program from having to be run with
412  // root privileges. We need root privileges to be able to futz with the
413  // Tap device underlying all of this. So all of these hoops are to allow
414  // us to execute the following code:
415  //
416  LOG ("Creating Tap");
417  int sock = CreateTap (dev, mac, tap, pi, ip4, netmask, ip6, prefix);
418  ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
419 
420  //
421  // Send the socket back to the tap net device so it can go about its business
422  //
423  SendSocket (path, sock, TAP_MAGIC);
424 
425  return 0;
426 }
void SetIpv4(const char *deviceName, const char *ip, const char *netmask)
uint32_t ifr6_prefixlen
#define ASCII_z
#define ABORT_IF(cond, msg, printErrno)
#define ASCII_a
#define ASCII_Z
#define ASCII_ZERO
struct in6_addr ifr6_addr
static char AsciiToLowCase(char c)
void SetUp(char *deviceName)
int gVerbose
void SendSocket(const char *path, int fd, const int magic_number)
Send the file descriptor back to the code that invoked the creation.
int CreateTap(char *deviceName, const char *mac, const int ifftap, const int iffpi, const char *ip4, const char *netmask, const char *ip6, const int netprefix)
#define ASCII_A
#define LOG(x)
int32_t ifr6_ifindex
#define ASCII_COLON
#define TAP_MAGIC
void SetIpv6(const char *deviceName, const char *ip, int netprefix)
int main(int argc, char *argv[])
void SetMacAddress(int fd, const char *mac)
void AsciiToMac48(const char *str, uint8_t addr[6])