2 * TUN interface functions.
3 * Copyright (C) 2002, 2003, 2004 Mondru AB.
4 * Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
6 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
14 * tun.c: Contains all TUN functionality. Is able to handle multiple
15 * tunnels in the same program. Each tunnel is identified by the struct,
16 * which is passed to functions.
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
40 #include <net/route.h>
43 #if defined(__linux__)
44 #include <linux/if_tun.h>
45 #include <linux/netlink.h>
46 #include <linux/rtnetlink.h>
48 #elif defined (__FreeBSD__)
49 #include <net/if_tun.h>
50 #include <net/if_var.h>
51 #include <netinet/in_var.h>
53 #elif defined (__APPLE__)
56 #elif defined (__sun__)
58 #include <sys/sockio.h>
60 #include <net/if_tun.h>
61 /*#include "sun_if_tun.h"*/
64 #error "Unknown platform!"
70 static int tun_setaddr4(struct tun_t
*this, struct in_addr
*addr
,
71 struct in_addr
*dstaddr
, struct in_addr
*netmask
);
73 #if defined(__linux__)
75 #include <linux/ipv6.h>
77 int tun_nlattr(struct nlmsghdr
*n
, int nsize
, int type
, void *d
, int dlen
)
79 int len
= RTA_LENGTH(dlen
);
80 int alen
= NLMSG_ALIGN(n
->nlmsg_len
);
81 struct rtattr
*rta
= (struct rtattr
*)(((void *)n
) + alen
);
82 if (alen
+ len
> nsize
)
86 memcpy(RTA_DATA(rta
), d
, dlen
);
87 n
->nlmsg_len
= alen
+ len
;
92 int tun_sifflags(struct tun_t
*this, int flags
)
97 memset(&ifr
, '\0', sizeof(ifr
));
98 ifr
.ifr_flags
= flags
;
99 strncpy(ifr
.ifr_name
, this->devname
, IFNAMSIZ
);
100 ifr
.ifr_name
[IFNAMSIZ
- 1] = 0; /* Make sure to terminate */
101 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
102 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "socket() failed");
105 if (ioctl(fd
, SIOCSIFFLAGS
, &ifr
)) {
106 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
107 "ioctl(SIOCSIFFLAGS) failed");
116 int tun_addroute2(struct tun_t *this,
118 struct in_addr *gateway,
119 struct in_addr *mask) {
124 char buf[TUN_NLBUFSIZE];
127 struct sockaddr_nl local;
131 struct sockaddr_nl nladdr;
135 memset(&req, 0, sizeof(req));
136 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
137 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
138 req.n.nlmsg_type = RTM_NEWROUTE;
139 req.r.rtm_family = AF_INET;
140 req.r.rtm_table = RT_TABLE_MAIN;
141 req.r.rtm_protocol = RTPROT_BOOT;
142 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
143 req.r.rtm_type = RTN_UNICAST;
144 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
145 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
147 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
148 SYS_ERR(DTUN, LOGL_ERROR, errno,
153 memset(&local, 0, sizeof(local));
154 local.nl_family = AF_NETLINK;
157 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
158 SYS_ERR(DTUN, LOGL_ERROR, errno,
164 addr_len = sizeof(local);
165 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
166 SYS_ERR(DTUN, LOGL_ERROR, errno,
167 "getsockname() failed");
172 if (addr_len != sizeof(local)) {
173 SYS_ERR(DTUN, LOGL_ERROR, 0,
174 "Wrong address length %d", addr_len);
179 if (local.nl_family != AF_NETLINK) {
180 SYS_ERR(DTUN, LOGL_ERROR, 0,
181 "Wrong address family %d", local.nl_family);
186 iov.iov_base = (void*)&req.n;
187 iov.iov_len = req.n.nlmsg_len;
189 msg.msg_name = (void*)&nladdr;
190 msg.msg_namelen = sizeof(nladdr),
193 msg.msg_control = NULL;
194 msg.msg_controllen = 0;
197 memset(&nladdr, 0, sizeof(nladdr));
198 nladdr.nl_family = AF_NETLINK;
200 nladdr.nl_groups = 0;
203 req.n.nlmsg_flags |= NLM_F_ACK;
205 status = sendmsg(fd, &msg, 0); * TODO: Error check *
211 int tun_addaddr(struct tun_t
*this,
212 struct in_addr
*addr
,
213 struct in_addr
*dstaddr
, struct in_addr
*netmask
)
216 #if defined(__linux__)
220 char buf
[TUN_NLBUFSIZE
];
223 struct sockaddr_nl local
;
228 struct sockaddr_nl nladdr
;
232 if (!this->addrs
) /* Use ioctl for first addr to make ping work */
233 return tun_setaddr4(this, addr
, dstaddr
, netmask
);
235 memset(&req
, 0, sizeof(req
));
236 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
237 req
.n
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_CREATE
;
238 req
.n
.nlmsg_type
= RTM_NEWADDR
;
239 req
.i
.ifa_family
= AF_INET
;
240 req
.i
.ifa_prefixlen
= 32; /* 32 FOR IPv4 */
242 req
.i
.ifa_scope
= RT_SCOPE_HOST
; /* TODO or 0 */
243 req
.i
.ifa_index
= if_nametoindex(this->devname
);
244 if (!req
.i
.ifa_index
) {
245 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "Unable to get ifindex for %s", this->devname
);
249 tun_nlattr(&req
.n
, sizeof(req
), IFA_ADDRESS
, addr
, sizeof(addr
));
250 tun_nlattr(&req
.n
, sizeof(req
), IFA_LOCAL
, dstaddr
, sizeof(dstaddr
));
252 if ((fd
= socket(AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
)) < 0) {
253 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "socket() failed");
257 memset(&local
, 0, sizeof(local
));
258 local
.nl_family
= AF_NETLINK
;
261 if (bind(fd
, (struct sockaddr
*)&local
, sizeof(local
)) < 0) {
262 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "bind() failed");
267 addr_len
= sizeof(local
);
268 if (getsockname(fd
, (struct sockaddr
*)&local
, &addr_len
) < 0) {
269 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
270 "getsockname() failed");
275 if (addr_len
!= sizeof(local
)) {
276 SYS_ERR(DTUN
, LOGL_ERROR
, 0,
277 "Wrong address length %d", addr_len
);
282 if (local
.nl_family
!= AF_NETLINK
) {
283 SYS_ERR(DTUN
, LOGL_ERROR
, 0,
284 "Wrong address family %d", local
.nl_family
);
289 iov
.iov_base
= (void *)&req
.n
;
290 iov
.iov_len
= req
.n
.nlmsg_len
;
292 msg
.msg_name
= (void *)&nladdr
;
293 msg
.msg_namelen
= sizeof(nladdr
);
296 msg
.msg_control
= NULL
;
297 msg
.msg_controllen
= 0;
300 memset(&nladdr
, 0, sizeof(nladdr
));
301 nladdr
.nl_family
= AF_NETLINK
;
303 nladdr
.nl_groups
= 0;
306 req
.n
.nlmsg_flags
|= NLM_F_ACK
;
308 status
= sendmsg(fd
, &msg
, 0);
309 if (status
!= req
.n
.nlmsg_len
) {
310 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "sendmsg() failed, returned %d", status
);
315 status
= tun_sifflags(this, IFF_UP
| IFF_RUNNING
);
326 #elif defined (__FreeBSD__) || defined (__APPLE__)
329 struct ifaliasreq areq
;
331 /* TODO: Is this needed on FreeBSD? */
332 if (!this->addrs
) /* Use ioctl for first addr to make ping work */
333 return tun_setaddr4(this, addr
, dstaddr
, netmask
); /* TODO dstaddr */
335 memset(&areq
, 0, sizeof(areq
));
337 /* Set up interface name */
338 strncpy(areq
.ifra_name
, this->devname
, IFNAMSIZ
);
339 areq
.ifra_name
[IFNAMSIZ
- 1] = 0; /* Make sure to terminate */
341 ((struct sockaddr_in
*)&areq
.ifra_addr
)->sin_family
= AF_INET
;
342 ((struct sockaddr_in
*)&areq
.ifra_addr
)->sin_len
=
343 sizeof(areq
.ifra_addr
);
344 ((struct sockaddr_in
*)&areq
.ifra_addr
)->sin_addr
.s_addr
= addr
->s_addr
;
346 ((struct sockaddr_in
*)&areq
.ifra_mask
)->sin_family
= AF_INET
;
347 ((struct sockaddr_in
*)&areq
.ifra_mask
)->sin_len
=
348 sizeof(areq
.ifra_mask
);
349 ((struct sockaddr_in
*)&areq
.ifra_mask
)->sin_addr
.s_addr
=
352 /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
353 ((struct sockaddr_in
*)&areq
.ifra_broadaddr
)->sin_family
= AF_INET
;
354 ((struct sockaddr_in
*)&areq
.ifra_broadaddr
)->sin_len
=
355 sizeof(areq
.ifra_broadaddr
);
356 ((struct sockaddr_in
*)&areq
.ifra_broadaddr
)->sin_addr
.s_addr
=
359 /* Create a channel to the NET kernel. */
360 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
361 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "socket() failed");
365 if (ioctl(fd
, SIOCAIFADDR
, (void *)&areq
) < 0) {
366 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
367 "ioctl(SIOCAIFADDR) failed");
376 #elif defined (__sun__)
378 if (!this->addrs
) /* Use ioctl for first addr to make ping work */
379 return tun_setaddr4(this, addr
, dstaddr
, netmask
);
381 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
382 "Setting multiple addresses not possible on Solaris");
386 #error "Unknown platform!"
391 static int tun_setaddr4(struct tun_t
*this, struct in_addr
*addr
,
392 struct in_addr
*dstaddr
, struct in_addr
*netmask
)
397 memset(&ifr
, '\0', sizeof(ifr
));
398 ifr
.ifr_addr
.sa_family
= AF_INET
;
399 ifr
.ifr_dstaddr
.sa_family
= AF_INET
;
401 #if defined(__linux__)
402 ifr
.ifr_netmask
.sa_family
= AF_INET
;
404 #elif defined(__FreeBSD__) || defined (__APPLE__)
405 ((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_len
=
406 sizeof(struct sockaddr_in
);
407 ((struct sockaddr_in
*)&ifr
.ifr_dstaddr
)->sin_len
=
408 sizeof(struct sockaddr_in
);
411 strncpy(ifr
.ifr_name
, this->devname
, IFNAMSIZ
);
412 ifr
.ifr_name
[IFNAMSIZ
- 1] = 0; /* Make sure to terminate */
414 /* Create a channel to the NET kernel. */
415 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
416 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "socket() failed");
420 if (addr
) { /* Set the interface address */
421 this->addr
.s_addr
= addr
->s_addr
;
422 memcpy(&((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
, addr
,
424 if (ioctl(fd
, SIOCSIFADDR
, (void *)&ifr
) < 0) {
425 if (errno
!= EEXIST
) {
426 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
427 "ioctl(SIOCSIFADDR) failed");
429 SYS_ERR(DTUN
, LOGL_NOTICE
, errno
,
430 "ioctl(SIOCSIFADDR): Address already exists");
437 if (dstaddr
) { /* Set the destination address */
438 this->dstaddr
.s_addr
= dstaddr
->s_addr
;
439 memcpy(&((struct sockaddr_in
*)&ifr
.ifr_dstaddr
)->sin_addr
,
440 dstaddr
, sizeof(*dstaddr
));
441 if (ioctl(fd
, SIOCSIFDSTADDR
, (caddr_t
) & ifr
) < 0) {
442 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
443 "ioctl(SIOCSIFDSTADDR) failed");
449 if (netmask
) { /* Set the netmask */
450 this->netmask
.s_addr
= netmask
->s_addr
;
451 #if defined(__linux__)
452 memcpy(&((struct sockaddr_in
*)&ifr
.ifr_netmask
)->sin_addr
,
453 netmask
, sizeof(*netmask
));
455 #elif defined(__FreeBSD__) || defined (__APPLE__)
456 ((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
.s_addr
=
459 #elif defined(__sun__)
460 ((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
.s_addr
=
463 #error "Unknown platform!"
466 if (ioctl(fd
, SIOCSIFNETMASK
, (void *)&ifr
) < 0) {
467 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
468 "ioctl(SIOCSIFNETMASK) failed");
477 /* On linux the route to the interface is set automatically
478 on FreeBSD we have to do this manually */
480 /* TODO: How does it work on Solaris? */
482 tun_sifflags(this, IFF_UP
| IFF_RUNNING
);
484 #if defined(__FreeBSD__) || defined (__APPLE__)
485 tun_addroute(this, dstaddr
, addr
, &this->netmask
);
492 static int tun_setaddr6(struct tun_t
*this, struct in6_addr
*addr
, struct in6_addr
*dstaddr
,
495 struct in6_ifreq ifr
;
498 memset(&ifr
, 0, sizeof(ifr
));
500 #if defined(__linux__)
501 ifr
.ifr6_prefixlen
= prefixlen
;
502 ifr
.ifr6_ifindex
= if_nametoindex(this->devname
);
503 if (ifr
.ifr6_ifindex
== 0) {
504 SYS_ERR(DTUN
, LOGL_ERROR
, 0, "Error getting ifindex for %s\n", this->devname
);
507 #elif defined(__FreeBSD__) || defined (__APPLE__)
508 strncpy(ifr
.ifr_name
, this->devname
, IFNAMSIZ
);
511 /* Create a channel to the NET kernel */
512 if ((fd
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
513 SYS_ERR(DTUN
, LOGL_ERROR
, 0, "socket() failed");
517 #if defined(__linux__)
519 memcpy(&this->addr
, addr
, sizeof(*addr
));
520 memcpy(&ifr
.ifr6_addr
, addr
, sizeof(*addr
));
521 if (ioctl(fd
, SIOCSIFADDR
, (void *) &ifr
) < 0) {
522 if (errno
!= EEXIST
) {
523 SYS_ERR(DTUN
, LOGL_ERROR
, 0, "ioctl(SIOCSIFADDR) failed");
525 SYS_ERR(DTUN
, LOGL_NOTICE
, 0, "ioctl(SIOCSIFADDR): Address alreadsy exists");
533 /* FIXME: looks like this is not possible/necessary for IPv6? */
535 memcpy(&this->dstaddr
, dstaddr
, sizeof(*dstaddr
));
536 memcpy(&ifr
.ifr6_addr
, dstaddr
, sizeof(*dstaddr
));
537 if (ioctl(fd
, SIOCSIFDSTADDR
, (caddr_t
*) &ifr
) < 0) {
538 SYS_ERR(DTUN
, LOGL_ERROR
, "ioctl(SIOCSIFDSTADDR) failed");
545 #elif defined(__FreeBSD__) || defined (__APPLE__)
547 memcpy(&ifr
.ifr_ifru
.ifru_addr
, addr
, sizeof(ifr
.ifr_ifru
.ifru_addr
));
549 memcpy(&ifr
.ifr_ifru
.ifru_dstaddr
, dstaddr
, sizeof(ifr
.ifr_ifru
.ifru_dstaddr
));
551 if (ioctl(fd
, SIOCSIFADDR_IN6
, (struct ifreq
*)&ifr
) < 0) {
552 SYS_ERR(DTUN
, LOGL_ERROR
, 0, "ioctl(SIOCSIFADDR_IN6) failed");
561 /* On linux the route to the interface is set automatically
562 on FreeBSD we have to do this manually */
564 /* TODO: How does it work on Solaris? */
566 tun_sifflags(this, IFF_UP
| IFF_RUNNING
);
569 //#if defined(__FreeBSD__) || defined (__APPLE__)
570 tun_addroute6(this, dstaddr
, addr
, prefixlen
);
577 int tun_setaddr(struct tun_t
*this, struct in46_addr
*addr
, struct in46_addr
*dstaddr
, size_t prefixlen
)
579 struct in_addr netmask
;
582 netmask
.s_addr
= htonl(0xffffffff << (32 - prefixlen
));
583 return tun_setaddr4(this, &addr
->v4
, dstaddr
? &dstaddr
->v4
: NULL
, &netmask
);
585 return tun_setaddr6(this, &addr
->v6
, dstaddr
? &dstaddr
->v6
: NULL
, prefixlen
);
591 int tun_route(struct tun_t
*this,
593 struct in_addr
*gateway
, struct in_addr
*mask
, int delete)
596 /* TODO: Learn how to set routing table on sun */
598 #if defined(__linux__)
603 memset(&r
, '\0', sizeof(r
));
604 r
.rt_flags
= RTF_UP
| RTF_GATEWAY
; /* RTF_HOST not set */
606 /* Create a channel to the NET kernel. */
607 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
608 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "socket() failed");
612 r
.rt_dst
.sa_family
= AF_INET
;
613 r
.rt_gateway
.sa_family
= AF_INET
;
614 r
.rt_genmask
.sa_family
= AF_INET
;
615 memcpy(&((struct sockaddr_in
*)&r
.rt_dst
)->sin_addr
, dst
, sizeof(*dst
));
616 memcpy(&((struct sockaddr_in
*)&r
.rt_gateway
)->sin_addr
, gateway
,
618 memcpy(&((struct sockaddr_in
*)&r
.rt_genmask
)->sin_addr
, mask
,
622 if (ioctl(fd
, SIOCDELRT
, (void *)&r
) < 0) {
623 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
624 "ioctl(SIOCDELRT) failed");
629 if (ioctl(fd
, SIOCADDRT
, (void *)&r
) < 0) {
630 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
631 "ioctl(SIOCADDRT) failed");
639 #elif defined(__FreeBSD__) || defined (__APPLE__)
643 struct sockaddr_in dst
;
644 struct sockaddr_in gate
;
645 struct sockaddr_in mask
;
649 struct rt_msghdr
*rtm
;
651 if ((fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1) {
652 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "socket() failed");
656 memset(&req
, 0x00, sizeof(req
));
660 rtm
->rtm_msglen
= sizeof(req
);
661 rtm
->rtm_version
= RTM_VERSION
;
663 rtm
->rtm_type
= RTM_DELETE
;
665 rtm
->rtm_type
= RTM_ADD
;
667 rtm
->rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
; /* TODO */
668 rtm
->rtm_addrs
= RTA_DST
| RTA_GATEWAY
| RTA_NETMASK
;
669 rtm
->rtm_pid
= getpid();
670 rtm
->rtm_seq
= 0044; /* TODO */
672 req
.dst
.sin_family
= AF_INET
;
673 req
.dst
.sin_len
= sizeof(req
.dst
);
674 req
.mask
.sin_family
= AF_INET
;
675 req
.mask
.sin_len
= sizeof(req
.mask
);
676 req
.gate
.sin_family
= AF_INET
;
677 req
.gate
.sin_len
= sizeof(req
.gate
);
679 req
.dst
.sin_addr
.s_addr
= dst
->s_addr
;
680 req
.mask
.sin_addr
.s_addr
= mask
->s_addr
;
681 req
.gate
.sin_addr
.s_addr
= gateway
->s_addr
;
683 if (write(fd
, rtm
, rtm
->rtm_msglen
) < 0) {
684 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "write() failed");
691 #elif defined(__sun__)
692 SYS_ERR(DTUN
, LOGL_NOTICE
, errno
,
693 "Could not set up routing on Solaris. Please add route manually.");
697 #error "Unknown platform!"
702 int tun_addroute(struct tun_t
*this,
704 struct in_addr
*gateway
, struct in_addr
*mask
)
706 return tun_route(this, dst
, gateway
, mask
, 0);
709 int tun_delroute(struct tun_t
*this,
711 struct in_addr
*gateway
, struct in_addr
*mask
)
713 return tun_route(this, dst
, gateway
, mask
, 1);
716 int tun_new(struct tun_t
**tun
)
719 #if defined(__linux__)
722 #elif defined(__FreeBSD__) || defined (__APPLE__)
723 char devname
[IFNAMSIZ
+ 5]; /* "/dev/" + ifname */
725 struct ifaliasreq areq
;
728 #elif defined(__sun__)
730 static int ip_fd
= 0;
735 #error "Unknown platform!"
738 if (!(*tun
= calloc(1, sizeof(struct tun_t
)))) {
739 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "calloc() failed");
743 (*tun
)->cb_ind
= NULL
;
747 #if defined(__linux__)
748 /* Open the actual tun device */
749 if (((*tun
)->fd
= open("/dev/net/tun", O_RDWR
)) < 0) {
750 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "open() failed");
754 /* Set device flags. For some weird reason this is also the method
755 used to obtain the network interface name */
756 memset(&ifr
, 0, sizeof(ifr
));
757 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
; /* Tun device, no packet info */
758 if (ioctl((*tun
)->fd
, TUNSETIFF
, (void *)&ifr
) < 0) {
759 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "ioctl() failed");
763 strncpy((*tun
)->devname
, ifr
.ifr_name
, IFNAMSIZ
);
764 (*tun
)->devname
[IFNAMSIZ
- 1] = 0;
766 ioctl((*tun
)->fd
, TUNSETNOCSUM
, 1); /* Disable checksums */
769 #elif defined(__FreeBSD__) || defined (__APPLE__)
771 /* Find suitable device */
772 for (devnum
= 0; devnum
< 255; devnum
++) { /* TODO 255 */
773 snprintf(devname
, sizeof(devname
), "/dev/tun%d", devnum
);
774 if (((*tun
)->fd
= open(devname
, O_RDWR
)) >= 0)
779 if ((*tun
)->fd
< 0) {
780 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
781 "Can't find tunnel device");
785 snprintf((*tun
)->devname
, sizeof((*tun
)->devname
), "tun%d", devnum
);
786 (*tun
)->devname
[sizeof((*tun
)->devname
)-1] = 0;
788 /* The tun device we found might have "old" IP addresses allocated */
789 /* We need to delete those. This problem is not present on Linux */
791 memset(&areq
, 0, sizeof(areq
));
793 /* Set up interface name */
794 strncpy(areq
.ifra_name
, (*tun
)->devname
, IFNAMSIZ
);
795 areq
.ifra_name
[IFNAMSIZ
- 1] = 0; /* Make sure to terminate */
797 /* Create a channel to the NET kernel. */
798 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
799 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "socket() failed");
803 /* Delete any IP addresses until SIOCDIFADDR fails */
804 while (ioctl(fd
, SIOCDIFADDR
, (void *)&areq
) != -1) ;
809 #elif defined(__sun__)
811 if ((ip_fd
= open("/dev/udp", O_RDWR
, 0)) < 0) {
812 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
813 "Can't open /dev/udp");
817 if (((*tun
)->fd
= open("/dev/tun", O_RDWR
, 0)) < 0) {
818 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
819 "Can't open /dev/tun");
824 /* Assign a new PPA and get its unit number. */
825 if ((ppa
= ioctl((*tun
)->fd
, TUNNEWPPA
, -1)) < 0) {
826 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
827 "Can't assign new interface");
831 if ((if_fd
= open("/dev/tun", O_RDWR
, 0)) < 0) {
832 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
833 "Can't open /dev/tun (2)");
836 if (ioctl(if_fd
, I_PUSH
, "ip") < 0) {
837 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
838 "Can't push IP module");
842 /* Assign ppa according to the unit number returned by tun device */
843 if (ioctl(if_fd
, IF_UNITSEL
, (char *)&ppa
) < 0) {
844 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "Can't set PPA %d",
849 /* Link the two streams */
850 if ((muxid
= ioctl(ip_fd
, I_LINK
, if_fd
)) < 0) {
851 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
852 "Can't link TUN device to IP");
856 /* Link the two streams */
857 if ((muxid
= ioctl(ip_fd
, I_LINK
, if_fd
)) < 0) {
858 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
859 "Can't link TUN device to IP");
865 snprintf((*tun
)->devname
, sizeof((*tun
)->devname
), "tun%d", ppa
);
866 (*tun
)->devname
[sizeof((*tun
)->devname
)] = 0;
868 memset(&ifr
, 0, sizeof(ifr
));
869 strcpy(ifr
.ifr_name
, (*tun
)->devname
);
870 ifr
.ifr_ip_muxid
= muxid
;
872 if (ioctl(ip_fd
, SIOCSIFMUXID
, &ifr
) < 0) {
873 ioctl(ip_fd
, I_PUNLINK
, muxid
);
874 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
875 "Can't set multiplexor id");
879 /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
880 msg (M_ERR, "Set file descriptor to non-blocking failed"); */
891 #error "Unknown platform!"
902 int tun_free(struct tun_t
*tun
)
906 tun_delroute(tun
, &tun
->dstaddr
, &tun
->addr
, &tun
->netmask
);
909 if (close(tun
->fd
)) {
910 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "close() failed");
913 /* TODO: For solaris we need to unlink streams */
919 int tun_set_cb_ind(struct tun_t
*this,
920 int (*cb_ind
) (struct tun_t
* tun
, void *pack
, unsigned len
))
922 this->cb_ind
= cb_ind
;
926 int tun_decaps(struct tun_t
*this)
929 #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
931 unsigned char buffer
[PACKET_MAX
];
934 if ((status
= read(this->fd
, buffer
, sizeof(buffer
))) <= 0) {
935 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "read() failed");
940 return this->cb_ind(this, buffer
, status
);
944 #elif defined (__sun__)
946 unsigned char buffer
[PACKET_MAX
];
950 sbuf
.maxlen
= PACKET_MAX
;
952 if (getmsg(this->fd
, NULL
, &sbuf
, &f
) < 0) {
953 SYS_ERR(DTUN
, LOGL_ERROR
, errno
, "getmsg() failed");
958 return this->cb_ind(this, buffer
, sbuf
.len
);
966 int tun_encaps(struct tun_t
*tun
, void *pack
, unsigned len
)
969 #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
971 return write(tun
->fd
, pack
, len
);
973 #elif defined (__sun__)
978 return putmsg(tun
->fd
, NULL
, &sbuf
, 0);
983 int tun_runscript(struct tun_t
*tun
, char *script
)
986 char buf
[TUN_SCRIPTSIZE
];
987 char snet
[TUN_ADDRSIZE
];
988 char smask
[TUN_ADDRSIZE
];
991 strncpy(snet
, inet_ntoa(tun
->addr
), sizeof(snet
));
992 snet
[sizeof(snet
) - 1] = 0;
993 strncpy(smask
, inet_ntoa(tun
->netmask
), sizeof(smask
));
994 smask
[sizeof(smask
) - 1] = 0;
996 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
997 snprintf(buf
, sizeof(buf
), "%s %s %s %s",
998 script
, tun
->devname
, snet
, smask
);
999 buf
[sizeof(buf
) - 1] = 0;
1002 SYS_ERR(DTUN
, LOGL_ERROR
, errno
,
1003 "Error executing command %s", buf
);