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