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