2 * TUN interface functions.
3 * Copyright (C) 2002, 2003, 2004 Mondru AB.
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
13 * tun.c: Contains all TUN functionality. Is able to handle multiple
14 * tunnels in the same program. Each tunnel is identified by the struct,
15 * which is passed to functions.
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
41 #include <net/route.h>
43 #if defined(__linux__)
45 #include <linux/if_tun.h>
46 #include <linux/netlink.h>
47 #include <linux/rtnetlink.h>
49 #elif defined (__FreeBSD__)
51 #include <net/if_tun.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!"
72 #if defined(__linux__)
74 int tun_nlattr(struct nlmsghdr
*n
, int nsize
, int type
, void *d
, int dlen
)
76 int len
= RTA_LENGTH(dlen
);
77 int alen
= NLMSG_ALIGN(n
->nlmsg_len
);
78 struct rtattr
*rta
= (struct rtattr
*) (((void*)n
) + alen
);
79 if (alen
+ len
> nsize
)
83 memcpy(RTA_DATA(rta
), d
, dlen
);
84 n
->nlmsg_len
= alen
+ len
;
88 int tun_gifindex(struct tun_t
*this, __u32
*index
) {
92 memset (&ifr
, '\0', sizeof (ifr
));
93 ifr
.ifr_addr
.sa_family
= AF_INET
;
94 ifr
.ifr_dstaddr
.sa_family
= AF_INET
;
95 ifr
.ifr_netmask
.sa_family
= AF_INET
;
96 strncpy(ifr
.ifr_name
, this->devname
, IFNAMSIZ
);
97 ifr
.ifr_name
[IFNAMSIZ
-1] = 0; /* Make sure to terminate */
98 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
99 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
102 if (ioctl(fd
, SIOCGIFINDEX
, &ifr
)) {
103 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
109 *index
= ifr
.ifr_ifindex
;
114 int tun_sifflags(struct tun_t
*this, int flags
) {
118 memset (&ifr
, '\0', sizeof (ifr
));
119 ifr
.ifr_flags
= flags
;
120 strncpy(ifr
.ifr_name
, this->devname
, IFNAMSIZ
);
121 ifr
.ifr_name
[IFNAMSIZ
-1] = 0; /* Make sure to terminate */
122 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
123 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
126 if (ioctl(fd
, SIOCSIFFLAGS
, &ifr
)) {
127 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
128 "ioctl(SIOCSIFFLAGS) failed");
138 int tun_addroute2(struct tun_t *this,
140 struct in_addr *gateway,
141 struct in_addr *mask) {
146 char buf[TUN_NLBUFSIZE];
149 struct sockaddr_nl local;
153 struct sockaddr_nl nladdr;
157 memset(&req, 0, sizeof(req));
158 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
159 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
160 req.n.nlmsg_type = RTM_NEWROUTE;
161 req.r.rtm_family = AF_INET;
162 req.r.rtm_table = RT_TABLE_MAIN;
163 req.r.rtm_protocol = RTPROT_BOOT;
164 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
165 req.r.rtm_type = RTN_UNICAST;
166 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
167 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
169 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
170 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
175 memset(&local, 0, sizeof(local));
176 local.nl_family = AF_NETLINK;
179 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
180 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
186 addr_len = sizeof(local);
187 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
188 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
189 "getsockname() failed");
194 if (addr_len != sizeof(local)) {
195 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
196 "Wrong address length %d", addr_len);
201 if (local.nl_family != AF_NETLINK) {
202 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
203 "Wrong address family %d", local.nl_family);
208 iov.iov_base = (void*)&req.n;
209 iov.iov_len = req.n.nlmsg_len;
211 msg.msg_name = (void*)&nladdr;
212 msg.msg_namelen = sizeof(nladdr),
215 msg.msg_control = NULL;
216 msg.msg_controllen = 0;
219 memset(&nladdr, 0, sizeof(nladdr));
220 nladdr.nl_family = AF_NETLINK;
222 nladdr.nl_groups = 0;
225 req.n.nlmsg_flags |= NLM_F_ACK;
227 status = sendmsg(fd, &msg, 0); * TODO: Error check *
233 int tun_addaddr(struct tun_t
*this,
234 struct in_addr
*addr
,
235 struct in_addr
*dstaddr
,
236 struct in_addr
*netmask
) {
238 #if defined(__linux__)
242 char buf
[TUN_NLBUFSIZE
];
245 struct sockaddr_nl local
;
250 struct sockaddr_nl nladdr
;
254 if (!this->addrs
) /* Use ioctl for first addr to make ping work */
255 return tun_setaddr(this, addr
, dstaddr
, netmask
);
257 memset(&req
, 0, sizeof(req
));
258 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
259 req
.n
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_CREATE
;
260 req
.n
.nlmsg_type
= RTM_NEWADDR
;
261 req
.i
.ifa_family
= AF_INET
;
262 req
.i
.ifa_prefixlen
= 32; /* 32 FOR IPv4 */
264 req
.i
.ifa_scope
= RT_SCOPE_HOST
; /* TODO or 0 */
265 if (tun_gifindex(this, &req
.i
.ifa_index
)) {
269 tun_nlattr(&req
.n
, sizeof(req
), IFA_ADDRESS
, addr
, sizeof(addr
));
270 tun_nlattr(&req
.n
, sizeof(req
), IFA_LOCAL
, dstaddr
, sizeof(dstaddr
));
272 if ((fd
= socket(AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
)) < 0) {
273 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
278 memset(&local
, 0, sizeof(local
));
279 local
.nl_family
= AF_NETLINK
;
282 if (bind(fd
, (struct sockaddr
*)&local
, sizeof(local
)) < 0) {
283 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
289 addr_len
= sizeof(local
);
290 if (getsockname(fd
, (struct sockaddr
*)&local
, &addr_len
) < 0) {
291 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
292 "getsockname() failed");
297 if (addr_len
!= sizeof(local
)) {
298 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
299 "Wrong address length %d", addr_len
);
304 if (local
.nl_family
!= AF_NETLINK
) {
305 sys_err(LOG_ERR
, __FILE__
, __LINE__
, 0,
306 "Wrong address family %d", local
.nl_family
);
311 iov
.iov_base
= (void*)&req
.n
;
312 iov
.iov_len
= req
.n
.nlmsg_len
;
314 msg
.msg_name
= (void*)&nladdr
;
315 msg
.msg_namelen
= sizeof(nladdr
),
318 msg
.msg_control
= NULL
;
319 msg
.msg_controllen
= 0;
322 memset(&nladdr
, 0, sizeof(nladdr
));
323 nladdr
.nl_family
= AF_NETLINK
;
325 nladdr
.nl_groups
= 0;
328 req
.n
.nlmsg_flags
|= NLM_F_ACK
;
330 status
= sendmsg(fd
, &msg
, 0); /* TODO Error check */
332 tun_sifflags(this, IFF_UP
| IFF_RUNNING
); /* TODO */
337 #elif defined (__FreeBSD__) || defined (__APPLE__)
340 struct ifaliasreq areq
;
342 /* TODO: Is this needed on FreeBSD? */
343 if (!this->addrs
) /* Use ioctl for first addr to make ping work */
344 return tun_setaddr(this, addr
, dstaddr
, netmask
); /* TODO dstaddr */
346 memset(&areq
, 0, sizeof(areq
));
348 /* Set up interface name */
349 strncpy(areq
.ifra_name
, this->devname
, IFNAMSIZ
);
350 areq
.ifra_name
[IFNAMSIZ
-1] = 0; /* Make sure to terminate */
352 ((struct sockaddr_in
*) &areq
.ifra_addr
)->sin_family
= AF_INET
;
353 ((struct sockaddr_in
*) &areq
.ifra_addr
)->sin_len
= sizeof(areq
.ifra_addr
);
354 ((struct sockaddr_in
*) &areq
.ifra_addr
)->sin_addr
.s_addr
= addr
->s_addr
;
356 ((struct sockaddr_in
*) &areq
.ifra_mask
)->sin_family
= AF_INET
;
357 ((struct sockaddr_in
*) &areq
.ifra_mask
)->sin_len
= sizeof(areq
.ifra_mask
);
358 ((struct sockaddr_in
*) &areq
.ifra_mask
)->sin_addr
.s_addr
= netmask
->s_addr
;
360 /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
361 ((struct sockaddr_in
*) &areq
.ifra_broadaddr
)->sin_family
= AF_INET
;
362 ((struct sockaddr_in
*) &areq
.ifra_broadaddr
)->sin_len
=
363 sizeof(areq
.ifra_broadaddr
);
364 ((struct sockaddr_in
*) &areq
.ifra_broadaddr
)->sin_addr
.s_addr
=
367 /* Create a channel to the NET kernel. */
368 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
369 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
374 if (ioctl(fd
, SIOCAIFADDR
, (void *) &areq
) < 0) {
375 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
376 "ioctl(SIOCAIFADDR) failed");
385 #elif defined (__sun__)
387 if (!this->addrs
) /* Use ioctl for first addr to make ping work */
388 return tun_setaddr(this, addr
, dstaddr
, netmask
);
390 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
391 "Setting multiple addresses not possible on Solaris");
395 #error "Unknown platform!"
401 int tun_setaddr(struct tun_t
*this,
402 struct in_addr
*addr
,
403 struct in_addr
*dstaddr
,
404 struct in_addr
*netmask
)
409 memset (&ifr
, '\0', sizeof (ifr
));
410 ifr
.ifr_addr
.sa_family
= AF_INET
;
411 ifr
.ifr_dstaddr
.sa_family
= AF_INET
;
413 #if defined(__linux__)
414 ifr
.ifr_netmask
.sa_family
= AF_INET
;
416 #elif defined(__FreeBSD__) || defined (__APPLE__)
417 ((struct sockaddr_in
*) &ifr
.ifr_addr
)->sin_len
=
418 sizeof (struct sockaddr_in
);
419 ((struct sockaddr_in
*) &ifr
.ifr_dstaddr
)->sin_len
=
420 sizeof (struct sockaddr_in
);
423 strncpy(ifr
.ifr_name
, this->devname
, IFNAMSIZ
);
424 ifr
.ifr_name
[IFNAMSIZ
-1] = 0; /* Make sure to terminate */
426 /* Create a channel to the NET kernel. */
427 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
428 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
433 if (addr
) { /* Set the interface address */
434 this->addr
.s_addr
= addr
->s_addr
;
435 memcpy(&((struct sockaddr_in
*) &ifr
.ifr_addr
)->sin_addr
, addr
,
437 if (ioctl(fd
, SIOCSIFADDR
, (void *) &ifr
) < 0) {
438 if (errno
!= EEXIST
) {
439 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
440 "ioctl(SIOCSIFADDR) failed");
443 sys_err(LOG_WARNING
, __FILE__
, __LINE__
, errno
,
444 "ioctl(SIOCSIFADDR): Address already exists");
451 if (dstaddr
) { /* Set the destination address */
452 this->dstaddr
.s_addr
= dstaddr
->s_addr
;
453 memcpy(&((struct sockaddr_in
*) &ifr
.ifr_dstaddr
)->sin_addr
,
454 dstaddr
, sizeof(*dstaddr
));
455 if (ioctl(fd
, SIOCSIFDSTADDR
, (caddr_t
) &ifr
) < 0) {
456 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
457 "ioctl(SIOCSIFDSTADDR) failed");
463 if (netmask
) { /* Set the netmask */
464 this->netmask
.s_addr
= netmask
->s_addr
;
465 #if defined(__linux__)
466 memcpy(&((struct sockaddr_in
*) &ifr
.ifr_netmask
)->sin_addr
,
467 netmask
, sizeof(*netmask
));
469 #elif defined(__FreeBSD__) || defined (__APPLE__)
470 ((struct sockaddr_in
*) &ifr
.ifr_addr
)->sin_addr
.s_addr
=
473 #elif defined(__sun__)
474 ((struct sockaddr_in
*) &ifr
.ifr_addr
)->sin_addr
.s_addr
=
477 #error "Unknown platform!"
480 if (ioctl(fd
, SIOCSIFNETMASK
, (void *) &ifr
) < 0) {
481 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
482 "ioctl(SIOCSIFNETMASK) failed");
491 /* On linux the route to the interface is set automatically
492 on FreeBSD we have to do this manually */
494 /* TODO: How does it work on Solaris? */
496 tun_sifflags(this, IFF_UP
| IFF_RUNNING
);
498 #if defined(__FreeBSD__) || defined (__APPLE__)
499 tun_addroute(this, dstaddr
, addr
, netmask
);
506 int tun_route(struct tun_t
*this,
508 struct in_addr
*gateway
,
509 struct in_addr
*mask
,
514 /* TODO: Learn how to set routing table on sun */
516 #if defined(__linux__)
521 memset (&r
, '\0', sizeof (r
));
522 r
.rt_flags
= RTF_UP
| RTF_GATEWAY
; /* RTF_HOST not set */
524 /* Create a channel to the NET kernel. */
525 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
526 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
531 r
.rt_dst
.sa_family
= AF_INET
;
532 r
.rt_gateway
.sa_family
= AF_INET
;
533 r
.rt_genmask
.sa_family
= AF_INET
;
534 memcpy(&((struct sockaddr_in
*) &r
.rt_dst
)->sin_addr
, dst
, sizeof(*dst
));
535 memcpy(&((struct sockaddr_in
*) &r
.rt_gateway
)->sin_addr
, gateway
,
537 memcpy(&((struct sockaddr_in
*) &r
.rt_genmask
)->sin_addr
, mask
,
541 if (ioctl(fd
, SIOCDELRT
, (void *) &r
) < 0) {
542 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
543 "ioctl(SIOCDELRT) failed");
549 if (ioctl(fd
, SIOCADDRT
, (void *) &r
) < 0) {
550 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
551 "ioctl(SIOCADDRT) failed");
559 #elif defined(__FreeBSD__) || defined (__APPLE__)
563 struct sockaddr_in dst
;
564 struct sockaddr_in gate
;
565 struct sockaddr_in mask
;
569 struct rt_msghdr
*rtm
;
571 if((fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1) {
572 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
577 memset(&req
, 0x00, sizeof(req
));
581 rtm
->rtm_msglen
= sizeof(req
);
582 rtm
->rtm_version
= RTM_VERSION
;
584 rtm
->rtm_type
= RTM_DELETE
;
587 rtm
->rtm_type
= RTM_ADD
;
589 rtm
->rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
; /* TODO */
590 rtm
->rtm_addrs
= RTA_DST
| RTA_GATEWAY
| RTA_NETMASK
;
591 rtm
->rtm_pid
= getpid();
592 rtm
->rtm_seq
= 0044; /* TODO */
594 req
.dst
.sin_family
= AF_INET
;
595 req
.dst
.sin_len
= sizeof(req
.dst
);
596 req
.mask
.sin_family
= AF_INET
;
597 req
.mask
.sin_len
= sizeof(req
.mask
);
598 req
.gate
.sin_family
= AF_INET
;
599 req
.gate
.sin_len
= sizeof(req
.gate
);
601 req
.dst
.sin_addr
.s_addr
= dst
->s_addr
;
602 req
.mask
.sin_addr
.s_addr
= mask
->s_addr
;
603 req
.gate
.sin_addr
.s_addr
= gateway
->s_addr
;
605 if(write(fd
, rtm
, rtm
->rtm_msglen
) < 0) {
606 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
614 #elif defined(__sun__)
615 sys_err(LOG_WARNING
, __FILE__
, __LINE__
, errno
,
616 "Could not set up routing on Solaris. Please add route manually.");
620 #error "Unknown platform!"
625 int tun_addroute(struct tun_t
*this,
627 struct in_addr
*gateway
,
628 struct in_addr
*mask
)
630 return tun_route(this, dst
, gateway
, mask
, 0);
633 int tun_delroute(struct tun_t
*this,
635 struct in_addr
*gateway
,
636 struct in_addr
*mask
)
638 return tun_route(this, dst
, gateway
, mask
, 1);
642 int tun_new(struct tun_t
**tun
)
645 #if defined(__linux__)
648 #elif defined(__FreeBSD__) || defined (__APPLE__)
649 char devname
[IFNAMSIZ
+5]; /* "/dev/" + ifname */
651 struct ifaliasreq areq
;
654 #elif defined(__sun__)
656 static int ip_fd
= 0;
661 #error "Unknown platform!"
664 if (!(*tun
= calloc(1, sizeof(struct tun_t
)))) {
665 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "calloc() failed");
669 (*tun
)->cb_ind
= NULL
;
673 #if defined(__linux__)
674 /* Open the actual tun device */
675 if (((*tun
)->fd
= open("/dev/net/tun", O_RDWR
)) < 0) {
676 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "open() failed");
680 /* Set device flags. For some weird reason this is also the method
681 used to obtain the network interface name */
682 memset(&ifr
, 0, sizeof(ifr
));
683 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
; /* Tun device, no packet info */
684 if (ioctl((*tun
)->fd
, TUNSETIFF
, (void *) &ifr
) < 0) {
685 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "ioctl() failed");
690 strncpy((*tun
)->devname
, ifr
.ifr_name
, IFNAMSIZ
);
691 (*tun
)->devname
[IFNAMSIZ
] = 0;
693 ioctl((*tun
)->fd
, TUNSETNOCSUM
, 1); /* Disable checksums */
696 #elif defined(__FreeBSD__) || defined (__APPLE__)
698 /* Find suitable device */
699 for (devnum
= 0; devnum
< 255; devnum
++) { /* TODO 255 */
700 snprintf(devname
, sizeof(devname
), "/dev/tun%d", devnum
);
701 devname
[sizeof(devname
)] = 0;
702 if (((*tun
)->fd
= open(devname
, O_RDWR
)) >= 0) break;
703 if (errno
!= EBUSY
) break;
705 if ((*tun
)->fd
< 0) {
706 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't find tunnel device");
710 snprintf((*tun
)->devname
, sizeof((*tun
)->devname
), "tun%d", devnum
);
711 (*tun
)->devname
[sizeof((*tun
)->devname
)] = 0;
713 /* The tun device we found might have "old" IP addresses allocated */
714 /* We need to delete those. This problem is not present on Linux */
716 memset(&areq
, 0, sizeof(areq
));
718 /* Set up interface name */
719 strncpy(areq
.ifra_name
, (*tun
)->devname
, IFNAMSIZ
);
720 areq
.ifra_name
[IFNAMSIZ
-1] = 0; /* Make sure to terminate */
722 /* Create a channel to the NET kernel. */
723 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
724 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
,
729 /* Delete any IP addresses until SIOCDIFADDR fails */
730 while (ioctl(fd
, SIOCDIFADDR
, (void *) &areq
) != -1);
735 #elif defined(__sun__)
737 if( (ip_fd
= open("/dev/udp", O_RDWR
, 0)) < 0){
738 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't open /dev/udp");
742 if( ((*tun
)->fd
= open("/dev/tun", O_RDWR
, 0)) < 0){
743 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't open /dev/tun");
747 /* Assign a new PPA and get its unit number. */
748 if( (ppa
= ioctl((*tun
)->fd
, TUNNEWPPA
, -1)) < 0){
749 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't assign new interface");
753 if( (if_fd
= open("/dev/tun", O_RDWR
, 0)) < 0){
754 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't open /dev/tun (2)");
757 if(ioctl(if_fd
, I_PUSH
, "ip") < 0){
758 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't push IP module");
762 /* Assign ppa according to the unit number returned by tun device */
763 if(ioctl(if_fd
, IF_UNITSEL
, (char *)&ppa
) < 0){
764 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't set PPA %d", ppa
);
768 /* Link the two streams */
769 if ((muxid
= ioctl(ip_fd
, I_LINK
, if_fd
)) < 0) {
770 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't link TUN device to IP");
776 snprintf((*tun
)->devname
, sizeof((*tun
)->devname
), "tun%d", ppa
);
777 (*tun
)->devname
[sizeof((*tun
)->devname
)] = 0;
779 memset(&ifr
, 0, sizeof(ifr
));
780 strcpy(ifr
.ifr_name
, (*tun
)->devname
);
781 ifr
.ifr_ip_muxid
= muxid
;
783 if (ioctl(ip_fd
, SIOCSIFMUXID
, &ifr
) < 0) {
784 ioctl(ip_fd
, I_PUNLINK
, muxid
);
785 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Can't set multiplexor id");
789 /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
790 msg (M_ERR, "Set file descriptor to non-blocking failed"); */
795 #error "Unknown platform!"
800 int tun_free(struct tun_t
*tun
)
804 tun_delroute(tun
, &tun
->dstaddr
, &tun
->addr
, &tun
->netmask
);
807 if (close(tun
->fd
)) {
808 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "close() failed");
811 /* TODO: For solaris we need to unlink streams */
818 int tun_set_cb_ind(struct tun_t
*this,
819 int (*cb_ind
) (struct tun_t
*tun
, void *pack
, unsigned len
)) {
820 this->cb_ind
= cb_ind
;
825 int tun_decaps(struct tun_t
*this)
828 #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
830 unsigned char buffer
[PACKET_MAX
];
833 if ((status
= read(this->fd
, buffer
, sizeof(buffer
))) <= 0) {
834 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "read() failed");
839 return this->cb_ind(this, buffer
, status
);
843 #elif defined (__sun__)
845 unsigned char buffer
[PACKET_MAX
];
849 sbuf
.maxlen
= PACKET_MAX
;
851 if (getmsg(this->fd
, NULL
, &sbuf
, &f
) < 0) {
852 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "getmsg() failed");
857 return this->cb_ind(this, buffer
, sbuf
.len
);
866 int tun_encaps(struct tun_t
*tun
, void *pack
, unsigned len
)
869 #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
871 return write(tun
->fd
, pack
, len
);
873 #elif defined (__sun__)
878 return putmsg(tun
->fd
, NULL
, &sbuf
, 0);
883 int tun_runscript(struct tun_t
*tun
, char* script
) {
885 char buf
[TUN_SCRIPTSIZE
];
886 char snet
[TUN_ADDRSIZE
];
887 char smask
[TUN_ADDRSIZE
];
890 strncpy(snet
, inet_ntoa(tun
->addr
), sizeof(snet
));
891 snet
[sizeof(snet
)-1] = 0;
892 strncpy(smask
, inet_ntoa(tun
->netmask
), sizeof(smask
));
893 smask
[sizeof(smask
)-1] = 0;
895 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
896 snprintf(buf
, sizeof(buf
), "%s %s %s %s",
897 script
, tun
->devname
, snet
, smask
);
898 buf
[sizeof(buf
)-1] = 0;
901 sys_err(LOG_ERR
, __FILE__
, __LINE__
, errno
, "Error executing command %s",