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