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