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 
56 /**
57  * Struct holding IPv6 address data
58  */
59 struct in6_ifreq {
60   struct in6_addr ifr6_addr;      //!< IPv6 address
61   uint32_t        ifr6_prefixlen; //!< IPv6 prefix length
62   int32_t         ifr6_ifindex;   //!< interface index
63 };
64 
65 char
AsciiToLowCase(char c)66 AsciiToLowCase (char c)
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
AsciiToMac48(const char * str,uint8_t addr[6])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
SetIpv4(const char * deviceName,const char * ip,const char * netmask)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
SetIpv6(const char * deviceName,const char * ip,int netprefix)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
SetMacAddress(int fd,const char * mac)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
SetUp(char * deviceName)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
CreateTap(char * deviceName,const char * mac,const int ifftap,const int iffpi,const char * ip4,const char * netmask,const char * ip6,const int netprefix)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
main(int argc,char * argv[])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 }
431