EMANE  1.0.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 <unistd.h>
42 #include <fcntl.h>
43 
44 /*
45  Create device node: mknod /dev/net/tun c 10 200
46  Add following line to the /etc/modules.conf: alias char-major-10-200 tun
47  Run: depmod -a
48  Driver will be automatically loaded when application access /dev/net/tun.
49 */
50 
51 
60  pPlatformService_(pPlatformService),
61  tunHandle_(-1),
62  tunName_(""),
63  tunPath_(""),
64  tunIndex_(-1)
65 {}
66 
67 
74 {}
75 
76 
77 
78 int
79 EMANE::Transports::Virtual::TunTap::open(const char *sDevicePath, const char *sDeviceName)
80 {
81  int result;
82 
83  // open tuntap device
84  if((tunHandle_ = ::open(sDevicePath, O_RDWR)) == -1)
85  {
86  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
88  "TunTap::%s:open:error %s",
89  __func__,
90  strerror(errno));
91 
92  // fail
93  return -1;
94  }
95 
96  // interface info
97  struct ifreq ifr;
98 
99  // clear ifr
100  memset(&ifr, 0, sizeof(ifr));
101 
102  // copy dev name
103  strncpy(ifr.ifr_name, sDeviceName, sizeof(ifr.ifr_name));
104 
105  // set flags no proto info and tap mode
106  ifr.ifr_flags = IFF_NO_PI | IFF_TAP;
107 
108  // set tun flags
109  if(ioctl(tunHandle_, TUNSETIFF, &ifr) < 0)
110  {
111  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
112  ABORT_LEVEL,
113  "TunTap::%s:ioctl:error %s",
114  __func__,
115  strerror(errno));
116 
117  // fail
118  return -1;
119  }
120 
121  // clear ifr
122  memset(&ifr, 0, sizeof(ifr));
123 
124  // copy dev name
125  strncpy(ifr.ifr_name, sDeviceName, sizeof(ifr.ifr_name));
126 
127  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
128 
129  // get iff index
130  if(ioctl(ctrlsock, SIOCGIFINDEX, &ifr) < 0)
131  {
132  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
133  ABORT_LEVEL,
134  "TunTap::%s:getindex:error %s",
135  __func__,
136  strerror(errno));
137 
138  // fail
139  return -1;
140  }
141 
142  // save the dev path, name, guid and index
143  tunPath_ = sDevicePath;
144  tunName_ = sDeviceName;
145  tunGuid_ = "n/a";
146  tunIndex_ = ifr.ifr_ifindex;
147 
148  // close control socket
149  ::close(ctrlsock);
150 
151  // success
152  result = 0;
153 
154 
155  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
156  DEBUG_LEVEL,
157  "TunTap::%s, path %s, name %s, guid %s, index %d",
158  __func__,
159  tunPath_.c_str(),
160  tunName_.c_str(),
161  tunGuid_.c_str(),
162  tunIndex_);
163 
164  // return result
165  return result;
166 }
167 
168 
170 {
171  ::close(tunHandle_);
172 
173  // return 0
174  return 0;
175 }
176 
177 
179 {
180  return tunHandle_;
181 }
182 
183 
184 int
186 {
187  // set if flags
188  int flags = IFF_UP;
189 
190  if(arpEnabled == false)
191  {
192  flags |= IFF_NOARP;
193  }
194 
195  return set_flags(flags, 1);
196 }
197 
198 
199 int
201 {
202  return set_flags(IFF_UP, -1);
203 }
204 
205 
206 int
208 {
209  // save of copy of the addr and mask in string format
210  std::string sAddress{addr.str(false)};
211  std::string sNetMask{mask.str(false)};
212 
213  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
214  DEBUG_LEVEL,
215  "TunTap::%s, type %s, addr %s, mask %s", __func__,
216  addr.isIPv4() ? "ipv4" :
217  addr.isIPv6() ? "ipv6" : "?",
218  addr.str().c_str(),
219  mask.str().c_str());
220 
221  // addr type ipv4
222  if(addr.isIPv4())
223  {
224  // interface info
225  struct ifreq ifr;
226 
227  // clear ifr
228  memset(&ifr, 0, sizeof(ifr));
229 
230  // copy dev name
231  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
232 
233  // copy addr and family
234  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_family = AF_INET;
235 
236  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_addr.s_addr =
237  reinterpret_cast<sockaddr_in *>(addr.getSockAddr())->sin_addr.s_addr;
238 
239  // open ipv4 control socket
240  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
241 
242  // set addr
243  if(ioctl(ctrlsock, SIOCSIFADDR, &ifr) < 0)
244  {
245  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
246  ABORT_LEVEL,
247  "TunTap::%s:setaddr:error %s",
248  __func__,
249  strerror(errno));
250  return -1;
251  }
252  else
253  {
254  // save tun addr
255  tunAddr_ = addr;
256  }
257 
258  // clear ifr
259  memset(&ifr, 0, sizeof(ifr));
260 
261  // copy dev name
262  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
263 
264  // copy addr and family
265  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_family = AF_INET;
266  ((struct sockaddr_in_t *) &ifr.ifr_addr)->sin_addr.s_addr =
267  reinterpret_cast<sockaddr_in *>(mask.getSockAddr())->sin_addr.s_addr;
268 
269  // set netmask
270  if(ioctl(ctrlsock, SIOCSIFNETMASK, &ifr) < 0)
271  {
272  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
273  ABORT_LEVEL,
274  "TunTap::%s:setmask:error %s",
275  __func__,
276  strerror(errno));
277 
278  // fail
279  return -1;
280  }
281  else
282  {
283  // save tun mask
284  tunMask_ = mask;
285  }
286 
287  // close control socket
288  ::close(ctrlsock);
289  }
290  // addr type ipv6
291  else if(addr.isIPv6())
292  {
293  // interface info ipv6
294  struct in6_ifreq
295  {
296  struct in6_addr ifr6_addr;
297  std::uint32_t ifr6_prefixlen;
298  std::uint32_t ifr6_ifindex;
299  } ifr6;
300 
301  // ipv6 prefix
302  struct in6_addr in6_prefix;
303 
304  // clear ifr6
305  memset(&ifr6, 0, sizeof(ifr6));
306 
307  // copy index
308  ifr6.ifr6_ifindex = tunIndex_;
309 
310  // copy mask
311  if(inet_pton(AF_INET6, sNetMask.c_str(), &in6_prefix) < 0)
312  {
313  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
314  ABORT_LEVEL,
315  "TunTap::%s:copyprefix:error %s",
316  __func__,
317  strerror(errno));
318  return -1;
319  }
320 
321  // copy prefix len
322  ifr6.ifr6_prefixlen = Utils::get_prefixlen(&in6_prefix);
323 
324  // copy address
325  if(inet_pton(AF_INET6, sAddress.c_str(), &ifr6.ifr6_addr) < 0)
326  {
327  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
328  ABORT_LEVEL,
329  "TunTap::%s:copyaddr:error %s",
330  __func__,
331  strerror(errno));
332  return -1;
333  }
334 
335  int ctrlsock = socket(AF_INET6,SOCK_DGRAM,0);
336 
337  // open ipv6 control socket
338  // set addr
339  if(ioctl(ctrlsock, SIOCSIFADDR, &ifr6) < 0)
340  {
341  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
342  ABORT_LEVEL,
343  "TunTap::%s:setaddr:error %s",
344  __func__,
345  strerror(errno));
346  return -1;
347  }
348  else
349  {
350  // save tun addr
351  tunAddr_ = addr;
352 
353  // save tun mask
354  tunMask_ = mask;
355  }
356 
357  // close control socket
358  ::close(ctrlsock);
359  }
360 
361 
362  // success
363  return 0;
364 }
365 
366 
368 {
369  // eth addr
370  Utils::EtherAddr ethAddr;
371 
372  // locally administered 02:02:00:00:XX:XX
373  ethAddr.words.word1 = htons(0x0202);
374  ethAddr.words.word2 = htons(0x0000);
375  ethAddr.words.word3 = htons(id);
376 
377  return set_ethaddr(ethAddr);
378 }
379 
381 {
382  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
383  DEBUG_LEVEL,
384  "TunTap::%s:%s",
385  __func__,
386  addr_to_string(&ethAddr));
387 
388  // interface info
389  struct ifreq ifr;
390 
391  // clear ifr
392  memset(&ifr, 0, sizeof(ifr));
393 
394  // copy dev name
395  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
396 
397  // copy hwaddr
398  memcpy(ifr.ifr_hwaddr.sa_data, &ethAddr, Utils::ETH_ALEN);
399 
400  // copy hwaddr family
401  ifr.ifr_hwaddr.sa_family = Utils::ARPHRD_ETHER;
402 
403  // open ipv4 control socket
404  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
405 
406  // set hw addr
407  if(ioctl(ctrlsock, SIOCSIFHWADDR, &ifr) < 0)
408  {
409  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
410  ABORT_LEVEL,
411  "TunTap::%s:sethwaddr:error %s",
412  __func__,
413  strerror(errno));
414 
415  // fail
416  return -1;
417  }
418 
419  // close control socket
420  ::close(ctrlsock);
421 
422 
423  // success
424  return 0;
425 }
426 
427 
428 
429 int EMANE::Transports::Virtual::TunTap::writev(const struct iovec *iov, size_t iov_len)
430 {
431  int result;
432 
433  result = ::writev(tunHandle_, iov, iov_len);
434 
435  // check result
436  if(result < 0)
437  {
438  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
439  ABORT_LEVEL,
440  "TunTap::%s:write:error %s",
441  __func__,
442  strerror(errno));
443  }
444 
445  // return result
446  return result;
447 }
448 
449 
450 
451 int EMANE::Transports::Virtual::TunTap::readv(struct iovec *iov, size_t iov_len)
452 {
453  int result;
454 
455  result = ::readv(tunHandle_, iov, iov_len);
456 
457  // check result
458  if(result < 0)
459  {
460  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
461  ABORT_LEVEL,
462  "TunTap::%s:read:error %s",
463  __func__,
464  strerror(errno));
465  }
466 
467  // return result
468  return result;
469 }
470 
471 
473 {
474  // return tun address
475  return tunAddr_;
476 }
477 
478 
480 {
481  // return tun address
482  return tunMask_;
483 }
484 
485 
486 
487 // private methods
488 int EMANE::Transports::Virtual::TunTap::set_flags(int newflags, int cmd)
489 {
490  // interface info
491  struct ifreq ifr;
492 
493  // clear ifr
494  memset(&ifr, 0, sizeof(ifr));
495 
496  // copy dev name
497  strncpy(ifr.ifr_name, tunName_.c_str(), IFNAMSIZ);
498 
499  // add flags
500  if(cmd > 0)
501  {
502  ifr.ifr_flags =(get_flags() | newflags);
503  }
504  // del flags
505  else if(cmd < 0)
506  {
507  ifr.ifr_flags =(get_flags() & ~newflags);
508  }
509  // set flags
510  else
511  {
512  ifr.ifr_flags = newflags;
513  }
514 
515  // open ipv4 control socket
516  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
517 
518  // set flags
519  if(ioctl(ctrlsock, SIOCSIFFLAGS, &ifr) < 0)
520  {
521  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
522  ABORT_LEVEL,
523  "TunTap::%s:setflags:error %s",
524  __func__,
525  strerror(errno));
526 
527  // fail
528  return -1;
529  }
530 
531  // close control socket
532  ::close(ctrlsock);
533 
534  // success
535  return 0;
536 }
537 
538 
539 
540 int EMANE::Transports::Virtual::TunTap::get_flags()
541 {
542  // interface info
543  struct ifreq ifr;
544 
545  // clear ifr
546  memset(&ifr, 0, sizeof(ifr));
547 
548  // copy dev name
549  strncpy(ifr.ifr_name, tunName_.c_str(), sizeof(ifr.ifr_name));
550 
551  // open ipv4 control socket
552  int ctrlsock = socket(AF_INET,SOCK_DGRAM,0);
553 
554  // get flags
555  if(ioctl(ctrlsock, SIOCGIFFLAGS, &ifr) < 0)
556  {
557  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
558  ABORT_LEVEL,
559  "TunTap::%s:getflags:error %s",
560  __func__,
561  strerror(errno));
562 
563  // fail
564  return -1;
565  }
566 
567  // close control socket
568  ::close(ctrlsock);
569 
570  // return flags
571  return ifr.ifr_flags;
572 }
struct EtherAddrWords words
Definition: netutils.h:424
TunTap(PlatformServiceProvider *pPlatformService)
Definition: tuntap.cc:59
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:543
int writev(const struct iovec *, size_t)
Definition: tuntap.cc:429
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:380
int readv(struct iovec *, size_t)
Definition: tuntap.cc:451
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:207
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
int open(const char *, const char *)
Definition: tuntap.cc:79
std::uint8_t get_prefixlen(const in6_addr *prefix)
Definition: netutils.h:755