EMANE  1.2.1
tuntap.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2016 - Adjacent Link LLC, Bridgewater, New Jersey
3  * Copyright (c) 2008 - DRS CenGen, LLC, Columbia, Maryland
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * * Neither the name of DRS CenGen, LLC nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 
35 #include "tuntap.h"
36 
37 #include <arpa/inet.h>
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/uio.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 
45 /*
46  Create device node: mknod /dev/net/tun c 10 200
47  Add following line to the /etc/modules.conf: alias char-major-10-200 tun
48  Run: depmod -a
49  Driver will be automatically loaded when application access /dev/net/tun.
50 */
51 
52 
61  pPlatformService_(pPlatformService),
62  tunHandle_(-1),
63  tunName_(""),
64  tunPath_(""),
65  tunIndex_(-1)
66 {}
67 
68 
75 {}
76 
77 
78 
79 int
80 EMANE::Transports::Virtual::TunTap::open(const char *sDevicePath, const char *sDeviceName)
81 {
82  int result;
83 
84  // open tuntap device
85  if((tunHandle_ = ::open(sDevicePath, O_RDWR)) == -1)
86  {
87  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
89  "TunTap::%s:open:error %s",
90  __func__,
91  strerror(errno));
92 
93  // fail
94  return -1;
95  }
96 
97  // interface info
98  struct ifreq ifr;
99 
100  // clear ifr
101  memset(&ifr, 0, sizeof(ifr));
102 
103  // copy dev name
104  strncpy(ifr.ifr_name, sDeviceName, sizeof(ifr.ifr_name));
105 
106  // set flags no proto info and tap mode
107  ifr.ifr_flags = IFF_NO_PI | IFF_TAP;
108 
109  // set tun flags
110  if(ioctl(tunHandle_, TUNSETIFF, &ifr) < 0)
111  {
112  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
113  ABORT_LEVEL,
114  "TunTap::%s:ioctl:error %s",
115  __func__,
116  strerror(errno));
117 
118  // fail
119  return -1;
120  }
121 
122  // clear ifr
123  memset(&ifr, 0, sizeof(ifr));
124 
125  // copy dev name
126  strncpy(ifr.ifr_name, sDeviceName, sizeof(ifr.ifr_name));
127 
128  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
129 
130  // get iff index
131  if(ioctl(ctrlsock, SIOCGIFINDEX, &ifr) < 0)
132  {
133  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
134  ABORT_LEVEL,
135  "TunTap::%s:getindex:error %s",
136  __func__,
137  strerror(errno));
138 
139  // fail
140  return -1;
141  }
142 
143  // save the dev path, name, guid and index
144  tunPath_ = sDevicePath;
145  tunName_ = sDeviceName;
146  tunGuid_ = "n/a";
147  tunIndex_ = ifr.ifr_ifindex;
148 
149  // close control socket
150  ::close(ctrlsock);
151 
152  // success
153  result = 0;
154 
155 
156  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
157  DEBUG_LEVEL,
158  "TunTap::%s, path %s, name %s, guid %s, index %d",
159  __func__,
160  tunPath_.c_str(),
161  tunName_.c_str(),
162  tunGuid_.c_str(),
163  tunIndex_);
164 
165  // return result
166  return result;
167 }
168 
169 
171 {
172  ::close(tunHandle_);
173 
174  // return 0
175  return 0;
176 }
177 
178 
180 {
181  return tunHandle_;
182 }
183 
184 
185 int
187 {
188  // set if flags
189  int flags = IFF_UP;
190 
191  if(arpEnabled == false)
192  {
193  flags |= IFF_NOARP;
194  }
195 
196  return set_flags(flags, 1);
197 }
198 
199 
200 int
202 {
203  return set_flags(IFF_UP, -1);
204 }
205 
206 
207 int
209 {
210  // save of copy of the addr and mask in string format
211  std::string sAddress{addr.str(false)};
212  std::string sNetMask{mask.str(false)};
213 
214  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
215  DEBUG_LEVEL,
216  "TunTap::%s, type %s, addr %s, mask %s", __func__,
217  addr.isIPv4() ? "ipv4" :
218  addr.isIPv6() ? "ipv6" : "?",
219  addr.str().c_str(),
220  mask.str().c_str());
221 
222  // addr type ipv4
223  if(addr.isIPv4())
224  {
225  // interface info
226  struct ifreq ifr;
227 
228  // clear ifr
229  memset(&ifr, 0, sizeof(ifr));
230 
231  // copy dev name
232  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
233 
234  // copy addr and family
235  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_family = AF_INET;
236 
237  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_addr.s_addr =
238  reinterpret_cast<sockaddr_in *>(addr.getSockAddr())->sin_addr.s_addr;
239 
240  // open ipv4 control socket
241  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
242 
243  // set addr
244  if(ioctl(ctrlsock, SIOCSIFADDR, &ifr) < 0)
245  {
246  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
247  ABORT_LEVEL,
248  "TunTap::%s:setaddr:error %s",
249  __func__,
250  strerror(errno));
251  return -1;
252  }
253  else
254  {
255  // save tun addr
256  tunAddr_ = addr;
257  }
258 
259  // clear ifr
260  memset(&ifr, 0, sizeof(ifr));
261 
262  // copy dev name
263  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
264 
265  // copy addr and family
266  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_family = AF_INET;
267  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_addr.s_addr =
268  reinterpret_cast<sockaddr_in *>(mask.getSockAddr())->sin_addr.s_addr;
269 
270  // set netmask
271  if(ioctl(ctrlsock, SIOCSIFNETMASK, &ifr) < 0)
272  {
273  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
274  ABORT_LEVEL,
275  "TunTap::%s:setmask:error %s",
276  __func__,
277  strerror(errno));
278 
279  // fail
280  return -1;
281  }
282  else
283  {
284  // save tun mask
285  tunMask_ = mask;
286  }
287 
288  // close control socket
289  ::close(ctrlsock);
290  }
291  // addr type ipv6
292  else if(addr.isIPv6())
293  {
294  // interface info ipv6
295  struct in6_ifreq
296  {
297  struct in6_addr ifr6_addr;
298  std::uint32_t ifr6_prefixlen;
299  std::uint32_t ifr6_ifindex;
300  } ifr6;
301 
302  // ipv6 prefix
303  struct in6_addr in6_prefix;
304 
305  // clear ifr6
306  memset(&ifr6, 0, sizeof(ifr6));
307 
308  // copy index
309  ifr6.ifr6_ifindex = tunIndex_;
310 
311  // copy mask
312  if(inet_pton(AF_INET6, sNetMask.c_str(), &in6_prefix) < 0)
313  {
314  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
315  ABORT_LEVEL,
316  "TunTap::%s:copyprefix:error %s",
317  __func__,
318  strerror(errno));
319  return -1;
320  }
321 
322  // copy prefix len
323  ifr6.ifr6_prefixlen = Utils::get_prefixlen(&in6_prefix);
324 
325  // copy address
326  if(inet_pton(AF_INET6, sAddress.c_str(), &ifr6.ifr6_addr) < 0)
327  {
328  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
329  ABORT_LEVEL,
330  "TunTap::%s:copyaddr:error %s",
331  __func__,
332  strerror(errno));
333  return -1;
334  }
335 
336  int ctrlsock = socket(AF_INET6,SOCK_DGRAM,0);
337 
338  // open ipv6 control socket
339  // set addr
340  if(ioctl(ctrlsock, SIOCSIFADDR, &ifr6) < 0)
341  {
342  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
343  ABORT_LEVEL,
344  "TunTap::%s:setaddr:error %s",
345  __func__,
346  strerror(errno));
347  return -1;
348  }
349  else
350  {
351  // save tun addr
352  tunAddr_ = addr;
353 
354  // save tun mask
355  tunMask_ = mask;
356  }
357 
358  // close control socket
359  ::close(ctrlsock);
360  }
361 
362 
363  // success
364  return 0;
365 }
366 
367 
369 {
370  // eth addr
371  Utils::EtherAddr ethAddr;
372 
373  // locally administered 02:02:00:00:XX:XX
374  ethAddr.words.word1 = htons(0x0202);
375  ethAddr.words.word2 = htons(0x0000);
376  ethAddr.words.word3 = htons(id);
377 
378  return set_ethaddr(ethAddr);
379 }
380 
382 {
383  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
384  DEBUG_LEVEL,
385  "TunTap::%s:%s",
386  __func__,
387  addr_to_string(&ethAddr));
388 
389  // interface info
390  struct ifreq ifr;
391 
392  // clear ifr
393  memset(&ifr, 0, sizeof(ifr));
394 
395  // copy dev name
396  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
397 
398  // copy hwaddr
399  memcpy(ifr.ifr_hwaddr.sa_data, &ethAddr, Utils::ETH_ALEN);
400 
401  // copy hwaddr family
402  ifr.ifr_hwaddr.sa_family = Utils::ARPHRD_ETHER;
403 
404  // open ipv4 control socket
405  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
406 
407  // set hw addr
408  if(ioctl(ctrlsock, SIOCSIFHWADDR, &ifr) < 0)
409  {
410  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
411  ABORT_LEVEL,
412  "TunTap::%s:sethwaddr:error %s",
413  __func__,
414  strerror(errno));
415 
416  // fail
417  return -1;
418  }
419 
420  // close control socket
421  ::close(ctrlsock);
422 
423 
424  // success
425  return 0;
426 }
427 
428 
429 
430 int EMANE::Transports::Virtual::TunTap::writev(const struct iovec *iov, size_t iov_len)
431 {
432  int result;
433 
434  result = ::writev(tunHandle_, iov, iov_len);
435 
436  // check result
437  if(result < 0)
438  {
439  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
440  ABORT_LEVEL,
441  "TunTap::%s:write:error %s",
442  __func__,
443  strerror(errno));
444  }
445 
446  // return result
447  return result;
448 }
449 
450 
451 
452 int EMANE::Transports::Virtual::TunTap::readv(struct iovec *iov, size_t iov_len)
453 {
454  int result;
455 
456  result = ::readv(tunHandle_, iov, iov_len);
457 
458  // check result
459  if(result < 0)
460  {
461  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
462  ABORT_LEVEL,
463  "TunTap::%s:read:error %s",
464  __func__,
465  strerror(errno));
466  }
467 
468  // return result
469  return result;
470 }
471 
472 
474 {
475  // return tun address
476  return tunAddr_;
477 }
478 
479 
481 {
482  // return tun address
483  return tunMask_;
484 }
485 
486 
487 
488 // private methods
489 int EMANE::Transports::Virtual::TunTap::set_flags(int newflags, int cmd)
490 {
491  // interface info
492  struct ifreq ifr;
493 
494  // clear ifr
495  memset(&ifr, 0, sizeof(ifr));
496 
497  // copy dev name
498  strncpy(ifr.ifr_name, tunName_.c_str(), IFNAMSIZ);
499 
500  // add flags
501  if(cmd > 0)
502  {
503  ifr.ifr_flags =(get_flags() | newflags);
504  }
505  // del flags
506  else if(cmd < 0)
507  {
508  ifr.ifr_flags =(get_flags() & ~newflags);
509  }
510  // set flags
511  else
512  {
513  ifr.ifr_flags = newflags;
514  }
515 
516  // open ipv4 control socket
517  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
518 
519  // set flags
520  if(ioctl(ctrlsock, SIOCSIFFLAGS, &ifr) < 0)
521  {
522  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
523  ABORT_LEVEL,
524  "TunTap::%s:setflags:error %s",
525  __func__,
526  strerror(errno));
527 
528  // fail
529  return -1;
530  }
531 
532  // close control socket
533  ::close(ctrlsock);
534 
535  // success
536  return 0;
537 }
538 
539 
540 
541 int EMANE::Transports::Virtual::TunTap::get_flags()
542 {
543  // interface info
544  struct ifreq ifr;
545 
546  // clear ifr
547  memset(&ifr, 0, sizeof(ifr));
548 
549  // copy dev name
550  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
551 
552  // open ipv4 control socket
553  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
554 
555  // get flags
556  if(ioctl(ctrlsock, SIOCGIFFLAGS, &ifr) < 0)
557  {
558  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
559  ABORT_LEVEL,
560  "TunTap::%s:getflags:error %s",
561  __func__,
562  strerror(errno));
563 
564  // fail
565  return -1;
566  }
567 
568  // close control socket
569  ::close(ctrlsock);
570 
571  // return flags
572  return ifr.ifr_flags;
573 }
struct EtherAddrWords words
Definition: netutils.h:424
TunTap(PlatformServiceProvider *pPlatformService)
Definition: tuntap.cc:60
bool isIPv6() const
Definition: inetaddr.cc:379
sockaddr * getSockAddr() const
Definition: inetaddr.cc:399
bool isIPv4() const
Definition: inetaddr.cc:384
The PlatformServiceProvider interface provides access to emulator services.
struct in_addr sin_addr
Definition: tuntap.h:544
int writev(const struct iovec *, size_t)
Definition: tuntap.cc:430
std::string str(bool bWithPort=true) const
Definition: inetaddr.cc:409
std::uint16_t NEMId
Definition: types.h:52
Definition of the ethernet frame address as an array of 6 bytes or set of 3 words.
Definition: netutils.h:422
int set_ethaddr(const Utils::EtherAddr &)
Definition: tuntap.cc:381
int readv(struct iovec *, size_t)
Definition: tuntap.cc:452
virtual LogServiceProvider & logService()=0
const std::uint16_t ETH_ALEN
Ethernet hardware address length.
Definition: netutils.h:335
void addr_to_string(const std::uint8_t *addr, size_t addrlen, const char *delim, char *buf, size_t buflen)
Definition: netutils.h:248
const std::uint16_t ARPHRD_ETHER
Ethernet hardware type.
Definition: netutils.h:366
int set_addr(const INETAddr &, const INETAddr &)
Definition: tuntap.cc:208
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
int open(const char *, const char *)
Definition: tuntap.cc:80
std::uint8_t get_prefixlen(const in6_addr *prefix)
Definition: netutils.h:755