A Discrete-Event Network Simulator
API
tap-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 <unistd.h>
20 #include <stdint.h>
21 #include <string>
22 #include <cstring> // for strerror
23 #include <iostream>
24 #include <iomanip>
25 #include <sstream>
26 #include <cstdlib>
27 #include <cerrno>
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 "tap-encode-decode.h"
39 
40 #define TAP_MAGIC 95549
41 
42 static int gVerbose = 0; // Set to true to turn on logging messages.
43 
44 #define LOG(msg) \
45  if (gVerbose) \
46  { \
47  std::cout << __FUNCTION__ << "(): " << msg << std::endl; \
48  }
49 
50 #define ABORT(msg, printErrno) \
51  std::cout << __FILE__ << ": fatal error at line " << __LINE__ << ": " << __FUNCTION__ << "(): " << msg << std::endl; \
52  if (printErrno) \
53  { \
54  std::cout << " errno = " << errno << " (" << std::strerror (errno) << ")" << std::endl; \
55  } \
56  std::exit (-1);
57 
58 #define ABORT_IF(cond, msg, printErrno) \
59  if (cond) \
60  { \
61  ABORT (msg, printErrno); \
62  }
63 
64 //
65 // Lots of the following helper code taken from corresponding functions in src/node.
66 //
67 #define ASCII_DOT (0x2e)
68 #define ASCII_ZERO (0x30)
69 #define ASCII_a (0x41)
70 #define ASCII_z (0x5a)
71 #define ASCII_A (0x61)
72 #define ASCII_Z (0x7a)
73 #define ASCII_COLON (0x3a)
74 #define ASCII_ZERO (0x30)
75 
76 static char
78 {
79  if (c >= ASCII_a && c <= ASCII_z) {
80  return c;
81  } else if (c >= ASCII_A && c <= ASCII_Z) {
82  return c + (ASCII_a - ASCII_A);
83  } else {
84  return c;
85  }
86 }
87 
88 static uint32_t
89 AsciiToIpv4 (const char *address)
90 {
91  uint32_t host = 0;
92  while (true) {
93  uint8_t byte = 0;
94  while (*address != ASCII_DOT &&
95  *address != 0) {
96  byte *= 10;
97  byte += *address - ASCII_ZERO;
98  address++;
99  }
100  host <<= 8;
101  host |= byte;
102  if (*address == 0) {
103  break;
104  }
105  address++;
106  }
107  return host;
108 }
109 
110 static void
111 AsciiToMac48 (const char *str, uint8_t addr[6])
112 {
113  int i = 0;
114  while (*str != 0 && i < 6)
115  {
116  uint8_t byte = 0;
117  while (*str != ASCII_COLON && *str != 0)
118  {
119  byte <<= 4;
120  char low = AsciiToLowCase (*str);
121  if (low >= ASCII_a)
122  {
123  byte |= low - ASCII_a + 10;
124  }
125  else
126  {
127  byte |= low - ASCII_ZERO;
128  }
129  str++;
130  }
131  addr[i] = byte;
132  i++;
133  if (*str == 0)
134  {
135  break;
136  }
137  str++;
138  }
139 }
140 
141 static sockaddr
142 CreateInetAddress (uint32_t networkOrder)
143 {
144  union {
145  struct sockaddr any_socket;
146  struct sockaddr_in si;
147  } s;
148  s.si.sin_family = AF_INET;
149  s.si.sin_port = 0; // unused
150  s.si.sin_addr.s_addr = htonl (networkOrder);
151  return s.any_socket;
152 }
153 
154 static void
155 SendSocket (const char *path, int fd)
156 {
157  //
158  // Open a Unix (local interprocess) socket to call back to the tap bridge
159  //
160  LOG ("Create Unix socket");
161  int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
162  ABORT_IF (sock == -1, "Unable to open socket", 1);
163 
164  //
165  // We have this string called path, which is really a hex representation
166  // of the endpoint that the tap bridge created. It used a forward encoding
167  // method (TapBufferToString) to take the sockaddr_un it made and passed
168  // the resulting string to us. So we need to take the inverse method
169  // (TapStringToBuffer) and build the same sockaddr_un over here.
170  //
171  socklen_t clientAddrLen;
172  struct sockaddr_un clientAddr;
173 
174  LOG ("Decode address " << path);
175  bool rc = ns3::TapStringToBuffer (path, (uint8_t *)&clientAddr, &clientAddrLen);
176  ABORT_IF (rc == false, "Unable to decode path", 0);
177 
178  LOG ("Connect");
179  int status = connect (sock, (struct sockaddr*)&clientAddr, clientAddrLen);
180  ABORT_IF (status == -1, "Unable to connect to tap bridge", 1);
181 
182  LOG ("Connected");
183 
184  //
185  // This is arcane enough that a few words are worthwhile to explain what's
186  // going on here.
187  //
188  // The interesting information (the socket FD) is going to go back to the
189  // tap bridge as an integer of ancillary data. Ancillary data is bits
190  // that are not a part a socket payload (out-of-band data). We're also
191  // going to send one integer back. It's just initialized to a magic number
192  // we use to make sure that the tap bridge is talking to the tap socket
193  // creator and not some other creator process (emu, specifically)
194  //
195  // The struct iovec below is part of a scatter-gather list. It describes a
196  // buffer. In this case, it describes a buffer (an integer) containing the
197  // data that we're going to send back to the tap bridge (that magic number).
198  //
199  struct iovec iov;
200  uint32_t magic = TAP_MAGIC;
201  iov.iov_base = &magic;
202  iov.iov_len = sizeof(magic);
203 
204  //
205  // The CMSG macros you'll see below are used to create and access control
206  // messages (which is another name for ancillary data). The ancillary
207  // data is made up of pairs of struct cmsghdr structures and associated
208  // data arrays.
209  //
210  // First, we're going to allocate a buffer on the stack to contain our
211  // data array (that contains the socket). Sometimes you'll see this called
212  // an "ancillary element" but the msghdr uses the control message termimology
213  // so we call it "control."
214  //
215  size_t msg_size = sizeof(int);
216  char control[CMSG_SPACE (msg_size)];
217 
218  //
219  // There is a msghdr that is used to minimize the number of parameters
220  // passed to sendmsg (which we will use to send our ancillary data). This
221  // structure uses terminology corresponding to control messages, so you'll
222  // see msg_control, which is the pointer to the ancillary data and controllen
223  // which is the size of the ancillary data array.
224  //
225  // So, initialize the message header that describes our ancillary/control data
226  // and point it to the control message/ancillary data we just allocated space
227  // for.
228  //
229  struct msghdr msg;
230  msg.msg_name = 0;
231  msg.msg_namelen = 0;
232  msg.msg_iov = &iov;
233  msg.msg_iovlen = 1;
234  msg.msg_control = control;
235  msg.msg_controllen = sizeof (control);
236  msg.msg_flags = 0;
237 
238  //
239  // A cmsghdr contains a length field that is the length of the header and
240  // the data. It has a cmsg_level field corresponding to the originating
241  // protocol. This takes values which are legal levels for getsockopt and
242  // setsockopt (here SOL_SOCKET). We're going to use the SCM_RIGHTS type of
243  // cmsg, that indicates that the ancillary data array contains access rights
244  // that we are sending back to the tap bridge.
245  //
246  // We have to put together the first (and only) cmsghdr that will describe
247  // the whole package we're sending.
248  //
249  struct cmsghdr *cmsg;
250  cmsg = CMSG_FIRSTHDR (&msg);
251  cmsg->cmsg_level = SOL_SOCKET;
252  cmsg->cmsg_type = SCM_RIGHTS;
253  cmsg->cmsg_len = CMSG_LEN (msg_size);
254  //
255  // We also have to update the controllen in case other stuff is actually
256  // in there we may not be aware of (due to macros).
257  //
258  msg.msg_controllen = cmsg->cmsg_len;
259 
260  //
261  // Finally, we get a pointer to the start of the ancillary data array and
262  // put our file descriptor in.
263  //
264  int *fdptr = (int*)(CMSG_DATA (cmsg));
265  *fdptr = fd; //
266 
267  //
268  // Actually send the file descriptor back to the tap bridge.
269  //
270  ssize_t len = sendmsg (sock, &msg, 0);
271  ABORT_IF (len == -1, "Could not send socket back to tap bridge", 1);
272 
273  LOG ("sendmsg complete");
274 }
275 
276 static int
277 CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, const char *mode, const char *netmask)
278 {
279  //
280  // Creation and management of Tap devices is done via the tun device
281  //
282  int tap = open ("/dev/net/tun", O_RDWR);
283  ABORT_IF (tap == -1, "Could not open /dev/net/tun", true);
284 
285  //
286  // Allocate a tap device, making sure that it will not send the tun_pi header.
287  // If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
288  // a name for us (i.e., tapn where n = 0..255.
289  //
290  // If the device does not already exist, the system will create one.
291  //
292  struct ifreq ifr;
293  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
294  strcpy (ifr.ifr_name, dev);
295  int status = ioctl (tap, TUNSETIFF, (void *) &ifr);
296  ABORT_IF (status == -1, "Could not allocate tap device", true);
297 
298  std::string tapDeviceName = (char *)ifr.ifr_name;
299  LOG ("Allocated TAP device " << tapDeviceName);
300 
301  //
302  // Operating mode "2" corresponds to USE_LOCAL and "3" to USE_BRIDGE mode.
303  // This means that we expect that the user will have named, created and
304  // configured a network tap that we are just going to use. So don't mess
305  // up his hard work by changing anything, just return the tap fd.
306  //
307  if (strcmp (mode, "2") == 0 || strcmp (mode, "3") == 0)
308  {
309  LOG ("Returning precreated tap ");
310  return tap;
311  }
312 
313  //
314  // Set the hardware (MAC) address of the new device
315  //
316  ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
317  AsciiToMac48 (mac, (uint8_t*)ifr.ifr_hwaddr.sa_data);
318  status = ioctl (tap, SIOCSIFHWADDR, &ifr);
319  ABORT_IF (status == -1, "Could not set MAC address", true);
320  LOG ("Set device MAC address to " << mac);
321 
322  int fd = socket (AF_INET, SOCK_DGRAM, 0);
323 
324  //
325  // Bring the interface up.
326  //
327  status = ioctl (fd, SIOCGIFFLAGS, &ifr);
328  ABORT_IF (status == -1, "Could not get flags for interface", true);
329  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
330  status = ioctl (fd, SIOCSIFFLAGS, &ifr);
331  ABORT_IF (status == -1, "Could not bring interface up", true);
332  LOG ("Device is up");
333 
334  //
335  // Set the IP address of the new interface/device.
336  //
337  ifr.ifr_addr = CreateInetAddress (AsciiToIpv4 (ip));
338  status = ioctl (fd, SIOCSIFADDR, &ifr);
339  ABORT_IF (status == -1, "Could not set IP address", true);
340  LOG ("Set device IP address to " << ip);
341 
342  //
343  // Set the net mask of the new interface/device
344  //
345  ifr.ifr_netmask = CreateInetAddress (AsciiToIpv4 (netmask));
346  status = ioctl (fd, SIOCSIFNETMASK, &ifr);
347  ABORT_IF (status == -1, "Could not set net mask", true);
348  LOG ("Set device Net Mask to " << netmask);
349 
350  return tap;
351 }
352 
353 int
354 main (int argc, char *argv[])
355 {
356  int c;
357  char *dev = (char *)"";
358  char *gw = NULL;
359  char *ip = NULL;
360  char *mac = NULL;
361  char *netmask = NULL;
362  char *operatingMode = NULL;
363  char *path = NULL;
364 
365  opterr = 0;
366 
367  while ((c = getopt (argc, argv, "vd:g:i:m:n:o:p:")) != -1)
368  {
369  switch (c)
370  {
371  case 'd':
372  dev = optarg; // name of the new tap device
373  break;
374  case 'g':
375  gw = optarg; // gateway address for the new device
376  break;
377  case 'i':
378  ip = optarg; // ip address of the new device
379  break;
380  case 'm':
381  mac = optarg; // mac address of the new device
382  break;
383  case 'n':
384  netmask = optarg; // net mask for the new device
385  break;
386  case 'o':
387  operatingMode = optarg; // operating mode of tap bridge
388  break;
389  case 'p':
390  path = optarg; // path back to the tap bridge
391  break;
392  case 'v':
393  gVerbose = true;
394  break;
395  }
396  }
397 
398  //
399  // We have got to be able to coordinate the name of the tap device we are
400  // going to create and or open with the device that an external Linux host
401  // will use. If this name is provided we use it. If not we let the system
402  // create the device for us. This name is given in dev
403  //
404  LOG ("Provided Device Name is \"" << dev << "\"");
405 
406  //
407  // We have got to be able to provide a gateway to the external Linux host
408  // so it can talk to the ns-3 network. This ip address is provided in
409  // gw.
410  //
411  ABORT_IF (gw == NULL, "Gateway Address is a required argument", 0);
412  LOG ("Provided Gateway Address is \"" << gw << "\"");
413 
414  //
415  // We have got to be able to assign an IP address to the tap device we are
416  // allocating. This address is allocated in the simulation and assigned to
417  // the tap bridge. This address is given in ip.
418  //
419  ABORT_IF (ip == NULL, "IP Address is a required argument", 0);
420  LOG ("Provided IP Address is \"" << ip << "\"");
421 
422  //
423  // We have got to be able to assign a Mac address to the tap device we are
424  // allocating. This address is allocated in the simulation and assigned to
425  // the bridged device. This allows packets addressed to the bridged device
426  // to appear in the Linux host as if they were received there.
427  //
428  ABORT_IF (mac == NULL, "MAC Address is a required argument", 0);
429  LOG ("Provided MAC Address is \"" << mac << "\"");
430 
431  //
432  // We have got to be able to assign a net mask to the tap device we are
433  // allocating. This mask is allocated in the simulation and given to
434  // the bridged device.
435  //
436  ABORT_IF (netmask == NULL, "Net Mask is a required argument", 0);
437  LOG ("Provided Net Mask is \"" << netmask << "\"");
438 
439  //
440  // We have got to know whether or not to create the TAP.
441  //
442  ABORT_IF (operatingMode == NULL, "Operating Mode is a required argument", 0);
443  LOG ("Provided Operating Mode is \"" << operatingMode << "\"");
444 
445  //
446  // This program is spawned by a tap bridge running in a simulation. It
447  // wants to create a socket as described below. We are going to do the
448  // work here since we're running suid root. Once we create the socket,
449  // we have to send it back to the tap bridge. We do that over a Unix
450  // (local interprocess) socket. The tap bridge created a socket to
451  // listen for our response on, and it is expected to have encoded the address
452  // information as a string and to have passed that string as an argument to
453  // us. We see it here as the "path" string. We can't do anything useful
454  // unless we have that string.
455  //
456  ABORT_IF (path == NULL, "path is a required argument", 0);
457  LOG ("Provided path is \"" << path << "\"");
458 
459  //
460  // The whole reason for all of the hoops we went through to call out to this
461  // program will pay off here. We created this program to run as suid root
462  // in order to keep the main simulation program from having to be run with
463  // root privileges. We need root privileges to be able to futz with the
464  // Tap device underlying all of this. So all of these hoops are to allow
465  // us to exeucte the following code:
466  //
467  LOG ("Creating Tap");
468  int sock = CreateTap (dev, gw, ip, mac, operatingMode, netmask);
469  ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
470 
471  //
472  // Send the socket back to the tap net device so it can go about its business
473  //
474  SendSocket (path, sock);
475 
476  return 0;
477 }
#define ASCII_ZERO
Definition: tap-creator.cc:74
#define ASCII_z
Definition: tap-creator.cc:70
#define ASCII_Z
Definition: tap-creator.cc:72
bool TapStringToBuffer(std::string s, uint8_t *buffer, uint32_t *len)
Convert string encoded by the inverse function (TapBufferToString) back into a byte buffer...
#define ASCII_a
Definition: tap-creator.cc:69
static uint32_t AsciiToIpv4(const char *address)
Definition: tap-creator.cc:89
static char AsciiToLowCase(char c)
Definition: tap-creator.cc:77
#define ASCII_DOT
Definition: tap-creator.cc:67
mac
Definition: third.py:99
static void SendSocket(const char *path, int fd)
Definition: tap-creator.cc:155
#define TAP_MAGIC
Definition: tap-creator.cc:40
static int CreateTap(const char *dev, const char *gw, const char *ip, const char *mac, const char *mode, const char *netmask)
Definition: tap-creator.cc:277
#define ASCII_COLON
Definition: tap-creator.cc:73
address
Definition: first.py:37
static sockaddr CreateInetAddress(uint32_t networkOrder)
Definition: tap-creator.cc:142
#define LOG(msg)
Definition: tap-creator.cc:44
#define ASCII_A
Definition: tap-creator.cc:71
static void AsciiToMac48(const char *str, uint8_t addr[6])
Definition: tap-creator.cc:111
#define ABORT_IF(cond, msg, printErrno)
Definition: tap-creator.cc:58
static int gVerbose
Definition: tap-creator.cc:42