blob: 94d92ef82af4adcadeda4654c70527e38cb1677f [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
jjakoa7cd2492003-04-11 09:40:12 +00002 * TUN interface functions.
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
jjakoa7cd2492003-04-11 09:40:12 +00005 * 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.
jjako52c24142002-12-16 13:33:51 +00009 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
jjakoa7cd2492003-04-11 09:40:12 +000013 * 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.
jjako52c24142002-12-16 13:33:51 +000016 *
jjako52c24142002-12-16 13:33:51 +000017 */
18
jjako52c24142002-12-16 13:33:51 +000019#include <stdio.h>
20#include <stdlib.h>
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <sys/stat.h>
26#include <sys/time.h>
27#include <unistd.h>
28#include <string.h>
29#include <errno.h>
30#include <fcntl.h>
31
32#include <stdio.h>
33#include <fcntl.h>
34#include <unistd.h>
35#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000036#include <sys/ioctl.h>
37#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000038#include <errno.h>
jjakoa7cd2492003-04-11 09:40:12 +000039#include <net/route.h>
jjako52c24142002-12-16 13:33:51 +000040
jjako409b8552004-02-04 22:57:41 +000041#if defined(__linux__)
jjako0141d202004-01-09 15:19:20 +000042#include <linux/if.h>
43#include <linux/if_tun.h>
jjakoa7cd2492003-04-11 09:40:12 +000044#include <linux/netlink.h>
45#include <linux/rtnetlink.h>
jjako409b8552004-02-04 22:57:41 +000046
47#elif defined (__FreeBSD__)
48#include <net/if.h>
49#include <net/if_tun.h>
50
jjako0fe0df02004-09-17 11:30:40 +000051#elif defined (__APPLE__)
52#include <net/if.h>
53
jjako0141d202004-01-09 15:19:20 +000054#elif defined (__sun__)
jjakoec89e9f2004-01-10 06:38:43 +000055#include <stropts.h>
56#include <sys/sockio.h>
57#include <net/if.h>
jjako0141d202004-01-09 15:19:20 +000058#include <net/if_tun.h>
jjakoec89e9f2004-01-10 06:38:43 +000059/*#include "sun_if_tun.h"*/
jjako409b8552004-02-04 22:57:41 +000060
61#else
62#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +000063#endif
64
jjako52c24142002-12-16 13:33:51 +000065#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000066#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000067
jjako409b8552004-02-04 22:57:41 +000068#if defined(__linux__)
69
jjakoa7cd2492003-04-11 09:40:12 +000070int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000071{
Harald Weltebed35df2011-11-02 13:06:18 +010072 int len = RTA_LENGTH(dlen);
73 int alen = NLMSG_ALIGN(n->nlmsg_len);
74 struct rtattr *rta = (struct rtattr *)(((void *)n) + alen);
75 if (alen + len > nsize)
76 return -1;
77 rta->rta_len = len;
78 rta->rta_type = type;
79 memcpy(RTA_DATA(rta), d, dlen);
80 n->nlmsg_len = alen + len;
81 return 0;
jjakoa7cd2492003-04-11 09:40:12 +000082}
83
Harald Weltebed35df2011-11-02 13:06:18 +010084int tun_gifindex(struct tun_t *this, __u32 * index)
85{
86 struct ifreq ifr;
87 int fd;
jjako52c24142002-12-16 13:33:51 +000088
Harald Weltebed35df2011-11-02 13:06:18 +010089 memset(&ifr, '\0', sizeof(ifr));
90 ifr.ifr_addr.sa_family = AF_INET;
91 ifr.ifr_dstaddr.sa_family = AF_INET;
92 ifr.ifr_netmask.sa_family = AF_INET;
93 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
94 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
95 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010096 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +010097 }
98 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010099 SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100100 close(fd);
101 return -1;
102 }
103 close(fd);
104 *index = ifr.ifr_ifindex;
105 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000106}
jjakoec89e9f2004-01-10 06:38:43 +0000107#endif
jjako52c24142002-12-16 13:33:51 +0000108
Harald Weltebed35df2011-11-02 13:06:18 +0100109int tun_sifflags(struct tun_t *this, int flags)
110{
111 struct ifreq ifr;
112 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000113
Harald Weltebed35df2011-11-02 13:06:18 +0100114 memset(&ifr, '\0', sizeof(ifr));
115 ifr.ifr_flags = flags;
116 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
117 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
118 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100119 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100120 }
121 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100122 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100123 "ioctl(SIOCSIFFLAGS) failed");
124 close(fd);
125 return -1;
126 }
127 close(fd);
128 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000129}
130
jjako0141d202004-01-09 15:19:20 +0000131/* Currently unused
jjakoa7cd2492003-04-11 09:40:12 +0000132int tun_addroute2(struct tun_t *this,
133 struct in_addr *dst,
134 struct in_addr *gateway,
135 struct in_addr *mask) {
136
137 struct {
138 struct nlmsghdr n;
139 struct rtmsg r;
140 char buf[TUN_NLBUFSIZE];
141 } req;
142
143 struct sockaddr_nl local;
144 int addr_len;
145 int fd;
146 int status;
147 struct sockaddr_nl nladdr;
148 struct iovec iov;
149 struct msghdr msg;
150
151 memset(&req, 0, sizeof(req));
152 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
153 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
154 req.n.nlmsg_type = RTM_NEWROUTE;
155 req.r.rtm_family = AF_INET;
156 req.r.rtm_table = RT_TABLE_MAIN;
157 req.r.rtm_protocol = RTPROT_BOOT;
158 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
159 req.r.rtm_type = RTN_UNICAST;
160 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
161 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
162
163 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100164 SYS_ERR(DTUN, LOGL_ERROR, errno,
jjakoa7cd2492003-04-11 09:40:12 +0000165 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000166 return -1;
167 }
168
jjakoa7cd2492003-04-11 09:40:12 +0000169 memset(&local, 0, sizeof(local));
170 local.nl_family = AF_NETLINK;
171 local.nl_groups = 0;
172
173 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100174 SYS_ERR(DTUN, LOGL_ERROR, errno,
jjakoa7cd2492003-04-11 09:40:12 +0000175 "bind() failed");
176 close(fd);
177 return -1;
178 }
179
180 addr_len = sizeof(local);
181 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100182 SYS_ERR(DTUN, LOGL_ERROR, errno,
jjakoa7cd2492003-04-11 09:40:12 +0000183 "getsockname() failed");
184 close(fd);
185 return -1;
186 }
187
188 if (addr_len != sizeof(local)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100189 SYS_ERR(DTUN, LOGL_ERROR, 0,
jjakoa7cd2492003-04-11 09:40:12 +0000190 "Wrong address length %d", addr_len);
191 close(fd);
192 return -1;
193 }
194
195 if (local.nl_family != AF_NETLINK) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100196 SYS_ERR(DTUN, LOGL_ERROR, 0,
jjakoa7cd2492003-04-11 09:40:12 +0000197 "Wrong address family %d", local.nl_family);
198 close(fd);
199 return -1;
200 }
201
202 iov.iov_base = (void*)&req.n;
203 iov.iov_len = req.n.nlmsg_len;
204
205 msg.msg_name = (void*)&nladdr;
206 msg.msg_namelen = sizeof(nladdr),
207 msg.msg_iov = &iov;
208 msg.msg_iovlen = 1;
209 msg.msg_control = NULL;
210 msg.msg_controllen = 0;
211 msg.msg_flags = 0;
212
213 memset(&nladdr, 0, sizeof(nladdr));
214 nladdr.nl_family = AF_NETLINK;
215 nladdr.nl_pid = 0;
216 nladdr.nl_groups = 0;
217
218 req.n.nlmsg_seq = 0;
219 req.n.nlmsg_flags |= NLM_F_ACK;
220
jjako0141d202004-01-09 15:19:20 +0000221 status = sendmsg(fd, &msg, 0); * TODO: Error check *
jjakoa7cd2492003-04-11 09:40:12 +0000222 close(fd);
223 return 0;
224}
jjako0141d202004-01-09 15:19:20 +0000225*/
jjakoa7cd2492003-04-11 09:40:12 +0000226
227int tun_addaddr(struct tun_t *this,
228 struct in_addr *addr,
Harald Weltebed35df2011-11-02 13:06:18 +0100229 struct in_addr *dstaddr, struct in_addr *netmask)
230{
jjako0141d202004-01-09 15:19:20 +0000231
jjako409b8552004-02-04 22:57:41 +0000232#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100233 struct {
234 struct nlmsghdr n;
235 struct ifaddrmsg i;
236 char buf[TUN_NLBUFSIZE];
237 } req;
jjakoa7cd2492003-04-11 09:40:12 +0000238
Harald Weltebed35df2011-11-02 13:06:18 +0100239 struct sockaddr_nl local;
240 socklen_t addr_len;
241 int fd;
242 int status;
jjakoa7cd2492003-04-11 09:40:12 +0000243
Harald Weltebed35df2011-11-02 13:06:18 +0100244 struct sockaddr_nl nladdr;
245 struct iovec iov;
246 struct msghdr msg;
jjakoa7cd2492003-04-11 09:40:12 +0000247
Harald Weltebed35df2011-11-02 13:06:18 +0100248 if (!this->addrs) /* Use ioctl for first addr to make ping work */
249 return tun_setaddr(this, addr, dstaddr, netmask);
jjakoa7cd2492003-04-11 09:40:12 +0000250
Harald Weltebed35df2011-11-02 13:06:18 +0100251 memset(&req, 0, sizeof(req));
252 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
253 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
254 req.n.nlmsg_type = RTM_NEWADDR;
255 req.i.ifa_family = AF_INET;
256 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
257 req.i.ifa_flags = 0;
258 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
259 if (tun_gifindex(this, &req.i.ifa_index)) {
260 return -1;
261 }
jjakoa7cd2492003-04-11 09:40:12 +0000262
Harald Weltebed35df2011-11-02 13:06:18 +0100263 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
264 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
jjakoa7cd2492003-04-11 09:40:12 +0000265
Harald Weltebed35df2011-11-02 13:06:18 +0100266 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100267 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100268 return -1;
269 }
jjakoa7cd2492003-04-11 09:40:12 +0000270
Harald Weltebed35df2011-11-02 13:06:18 +0100271 memset(&local, 0, sizeof(local));
272 local.nl_family = AF_NETLINK;
273 local.nl_groups = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000274
Harald Weltebed35df2011-11-02 13:06:18 +0100275 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100276 SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100277 close(fd);
278 return -1;
279 }
jjakoa7cd2492003-04-11 09:40:12 +0000280
Harald Weltebed35df2011-11-02 13:06:18 +0100281 addr_len = sizeof(local);
282 if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100283 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100284 "getsockname() failed");
285 close(fd);
286 return -1;
287 }
jjakoa7cd2492003-04-11 09:40:12 +0000288
Harald Weltebed35df2011-11-02 13:06:18 +0100289 if (addr_len != sizeof(local)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100290 SYS_ERR(DTUN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100291 "Wrong address length %d", addr_len);
292 close(fd);
293 return -1;
294 }
jjakoa7cd2492003-04-11 09:40:12 +0000295
Harald Weltebed35df2011-11-02 13:06:18 +0100296 if (local.nl_family != AF_NETLINK) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100297 SYS_ERR(DTUN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100298 "Wrong address family %d", local.nl_family);
299 close(fd);
300 return -1;
301 }
jjakoa7cd2492003-04-11 09:40:12 +0000302
Harald Weltebed35df2011-11-02 13:06:18 +0100303 iov.iov_base = (void *)&req.n;
304 iov.iov_len = req.n.nlmsg_len;
jjakoa7cd2492003-04-11 09:40:12 +0000305
Harald Weltebed35df2011-11-02 13:06:18 +0100306 msg.msg_name = (void *)&nladdr;
307 msg.msg_namelen = sizeof(nladdr), msg.msg_iov = &iov;
308 msg.msg_iovlen = 1;
309 msg.msg_control = NULL;
310 msg.msg_controllen = 0;
311 msg.msg_flags = 0;
312
313 memset(&nladdr, 0, sizeof(nladdr));
314 nladdr.nl_family = AF_NETLINK;
315 nladdr.nl_pid = 0;
316 nladdr.nl_groups = 0;
317
318 req.n.nlmsg_seq = 0;
319 req.n.nlmsg_flags |= NLM_F_ACK;
320
321 status = sendmsg(fd, &msg, 0); /* TODO Error check */
322
323 tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
324 close(fd);
325 this->addrs++;
326 return 0;
jjako409b8552004-02-04 22:57:41 +0000327
jjako0fe0df02004-09-17 11:30:40 +0000328#elif defined (__FreeBSD__) || defined (__APPLE__)
jjako409b8552004-02-04 22:57:41 +0000329
Harald Weltebed35df2011-11-02 13:06:18 +0100330 int fd;
331 struct ifaliasreq areq;
jjako409b8552004-02-04 22:57:41 +0000332
Harald Weltebed35df2011-11-02 13:06:18 +0100333 /* TODO: Is this needed on FreeBSD? */
334 if (!this->addrs) /* Use ioctl for first addr to make ping work */
335 return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
jjako409b8552004-02-04 22:57:41 +0000336
Harald Weltebed35df2011-11-02 13:06:18 +0100337 memset(&areq, 0, sizeof(areq));
jjako409b8552004-02-04 22:57:41 +0000338
Harald Weltebed35df2011-11-02 13:06:18 +0100339 /* Set up interface name */
340 strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
341 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako409b8552004-02-04 22:57:41 +0000342
Harald Weltebed35df2011-11-02 13:06:18 +0100343 ((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
344 ((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
345 sizeof(areq.ifra_addr);
346 ((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000347
Harald Weltebed35df2011-11-02 13:06:18 +0100348 ((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
349 ((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
350 sizeof(areq.ifra_mask);
351 ((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
352 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000353
Harald Weltebed35df2011-11-02 13:06:18 +0100354 /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
355 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
356 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
357 sizeof(areq.ifra_broadaddr);
358 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
359 dstaddr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000360
Harald Weltebed35df2011-11-02 13:06:18 +0100361 /* Create a channel to the NET kernel. */
362 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100363 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100364 return -1;
365 }
jjako409b8552004-02-04 22:57:41 +0000366
Harald Weltebed35df2011-11-02 13:06:18 +0100367 if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100368 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100369 "ioctl(SIOCAIFADDR) failed");
370 close(fd);
371 return -1;
372 }
373
374 close(fd);
375 this->addrs++;
376 return 0;
jjako409b8552004-02-04 22:57:41 +0000377
378#elif defined (__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100379
380 if (!this->addrs) /* Use ioctl for first addr to make ping work */
381 return tun_setaddr(this, addr, dstaddr, netmask);
382
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100383 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100384 "Setting multiple addresses not possible on Solaris");
385 return -1;
jjako409b8552004-02-04 22:57:41 +0000386
387#else
388#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +0000389#endif
jjakoa7cd2492003-04-11 09:40:12 +0000390
Harald Weltebed35df2011-11-02 13:06:18 +0100391}
jjakoa7cd2492003-04-11 09:40:12 +0000392
393int tun_setaddr(struct tun_t *this,
394 struct in_addr *addr,
Harald Weltebed35df2011-11-02 13:06:18 +0100395 struct in_addr *dstaddr, struct in_addr *netmask)
jjakoa7cd2492003-04-11 09:40:12 +0000396{
Harald Weltebed35df2011-11-02 13:06:18 +0100397 struct ifreq ifr;
398 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000399
Harald Weltebed35df2011-11-02 13:06:18 +0100400 memset(&ifr, '\0', sizeof(ifr));
401 ifr.ifr_addr.sa_family = AF_INET;
402 ifr.ifr_dstaddr.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000403
404#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100405 ifr.ifr_netmask.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000406
jjako0fe0df02004-09-17 11:30:40 +0000407#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100408 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
409 sizeof(struct sockaddr_in);
410 ((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
411 sizeof(struct sockaddr_in);
jjako243bfe62004-01-26 23:06:05 +0000412#endif
jjako409b8552004-02-04 22:57:41 +0000413
Harald Weltebed35df2011-11-02 13:06:18 +0100414 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
415 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjakoa7cd2492003-04-11 09:40:12 +0000416
Harald Weltebed35df2011-11-02 13:06:18 +0100417 /* Create a channel to the NET kernel. */
418 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100419 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100420 return -1;
421 }
jjakoa7cd2492003-04-11 09:40:12 +0000422
Harald Weltebed35df2011-11-02 13:06:18 +0100423 if (addr) { /* Set the interface address */
424 this->addr.s_addr = addr->s_addr;
425 memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
426 sizeof(*addr));
427 if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
428 if (errno != EEXIST) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100429 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100430 "ioctl(SIOCSIFADDR) failed");
431 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100432 SYS_ERR(DTUN, LOGL_NOTICE, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100433 "ioctl(SIOCSIFADDR): Address already exists");
434 }
435 close(fd);
436 return -1;
437 }
438 }
jjakoa7cd2492003-04-11 09:40:12 +0000439
Harald Weltebed35df2011-11-02 13:06:18 +0100440 if (dstaddr) { /* Set the destination address */
441 this->dstaddr.s_addr = dstaddr->s_addr;
442 memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
443 dstaddr, sizeof(*dstaddr));
444 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100445 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100446 "ioctl(SIOCSIFDSTADDR) failed");
447 close(fd);
448 return -1;
449 }
450 }
jjakoa7cd2492003-04-11 09:40:12 +0000451
Harald Weltebed35df2011-11-02 13:06:18 +0100452 if (netmask) { /* Set the netmask */
453 this->netmask.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000454#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100455 memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
456 netmask, sizeof(*netmask));
jjako409b8552004-02-04 22:57:41 +0000457
jjako0fe0df02004-09-17 11:30:40 +0000458#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100459 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
460 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000461
462#elif defined(__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100463 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
464 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000465#else
466#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000467#endif
jjako409b8552004-02-04 22:57:41 +0000468
Harald Weltebed35df2011-11-02 13:06:18 +0100469 if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100470 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100471 "ioctl(SIOCSIFNETMASK) failed");
472 close(fd);
473 return -1;
474 }
475 }
jjako1ea66342004-01-28 09:27:34 +0000476
Harald Weltebed35df2011-11-02 13:06:18 +0100477 close(fd);
478 this->addrs++;
jjako409b8552004-02-04 22:57:41 +0000479
Harald Weltebed35df2011-11-02 13:06:18 +0100480 /* On linux the route to the interface is set automatically
481 on FreeBSD we have to do this manually */
482
483 /* TODO: How does it work on Solaris? */
484
485 tun_sifflags(this, IFF_UP | IFF_RUNNING);
jjako163b4552004-12-30 15:33:58 +0000486
jjako0fe0df02004-09-17 11:30:40 +0000487#if defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100488 tun_addroute(this, dstaddr, addr, netmask);
489 this->routes = 1;
jjako1ea66342004-01-28 09:27:34 +0000490#endif
491
Harald Weltebed35df2011-11-02 13:06:18 +0100492 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000493}
494
jjako163b4552004-12-30 15:33:58 +0000495int tun_route(struct tun_t *this,
496 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100497 struct in_addr *gateway, struct in_addr *mask, int delete)
jjakoa7cd2492003-04-11 09:40:12 +0000498{
jjakoec89e9f2004-01-10 06:38:43 +0000499
Harald Weltebed35df2011-11-02 13:06:18 +0100500 /* TODO: Learn how to set routing table on sun */
jjako409b8552004-02-04 22:57:41 +0000501
502#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000503
Harald Weltebed35df2011-11-02 13:06:18 +0100504 struct rtentry r;
505 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000506
Harald Weltebed35df2011-11-02 13:06:18 +0100507 memset(&r, '\0', sizeof(r));
508 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
jjakoa7cd2492003-04-11 09:40:12 +0000509
Harald Weltebed35df2011-11-02 13:06:18 +0100510 /* Create a channel to the NET kernel. */
511 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100512 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100513 return -1;
514 }
jjakoa7cd2492003-04-11 09:40:12 +0000515
Harald Weltebed35df2011-11-02 13:06:18 +0100516 r.rt_dst.sa_family = AF_INET;
517 r.rt_gateway.sa_family = AF_INET;
518 r.rt_genmask.sa_family = AF_INET;
519 memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst));
520 memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway,
521 sizeof(*gateway));
522 memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask,
523 sizeof(*mask));
524
525 if (delete) {
526 if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100527 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100528 "ioctl(SIOCDELRT) failed");
529 close(fd);
530 return -1;
531 }
532 } else {
533 if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100534 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100535 "ioctl(SIOCADDRT) failed");
536 close(fd);
537 return -1;
538 }
539 }
540 close(fd);
541 return 0;
542
jjako0fe0df02004-09-17 11:30:40 +0000543#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako3eaf4532004-01-27 19:47:49 +0000544
Harald Weltebed35df2011-11-02 13:06:18 +0100545 struct {
546 struct rt_msghdr rt;
547 struct sockaddr_in dst;
548 struct sockaddr_in gate;
549 struct sockaddr_in mask;
550 } req;
jjako3eaf4532004-01-27 19:47:49 +0000551
Harald Weltebed35df2011-11-02 13:06:18 +0100552 int fd;
553 struct rt_msghdr *rtm;
jjako1ea66342004-01-28 09:27:34 +0000554
Harald Weltebed35df2011-11-02 13:06:18 +0100555 if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100556 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100557 return -1;
558 }
559
560 memset(&req, 0x00, sizeof(req));
561
562 rtm = &req.rt;
563
564 rtm->rtm_msglen = sizeof(req);
565 rtm->rtm_version = RTM_VERSION;
566 if (delete) {
567 rtm->rtm_type = RTM_DELETE;
568 } else {
569 rtm->rtm_type = RTM_ADD;
570 }
571 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
572 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
573 rtm->rtm_pid = getpid();
574 rtm->rtm_seq = 0044; /* TODO */
575
576 req.dst.sin_family = AF_INET;
577 req.dst.sin_len = sizeof(req.dst);
578 req.mask.sin_family = AF_INET;
579 req.mask.sin_len = sizeof(req.mask);
580 req.gate.sin_family = AF_INET;
581 req.gate.sin_len = sizeof(req.gate);
582
583 req.dst.sin_addr.s_addr = dst->s_addr;
584 req.mask.sin_addr.s_addr = mask->s_addr;
585 req.gate.sin_addr.s_addr = gateway->s_addr;
586
587 if (write(fd, rtm, rtm->rtm_msglen) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100588 SYS_ERR(DTUN, LOGL_ERROR, errno, "write() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100589 close(fd);
590 return -1;
591 }
592 close(fd);
593 return 0;
jjako1ea66342004-01-28 09:27:34 +0000594
jjako409b8552004-02-04 22:57:41 +0000595#elif defined(__sun__)
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100596 SYS_ERR(DTUN, LOGL_NOTICE, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100597 "Could not set up routing on Solaris. Please add route manually.");
598 return 0;
599
jjako409b8552004-02-04 22:57:41 +0000600#else
601#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000602#endif
603
jjakoa7cd2492003-04-11 09:40:12 +0000604}
605
jjako163b4552004-12-30 15:33:58 +0000606int tun_addroute(struct tun_t *this,
607 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100608 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000609{
Harald Weltebed35df2011-11-02 13:06:18 +0100610 return tun_route(this, dst, gateway, mask, 0);
jjako163b4552004-12-30 15:33:58 +0000611}
612
613int tun_delroute(struct tun_t *this,
614 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100615 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000616{
Harald Weltebed35df2011-11-02 13:06:18 +0100617 return tun_route(this, dst, gateway, mask, 1);
jjako163b4552004-12-30 15:33:58 +0000618}
619
jjakoa7cd2492003-04-11 09:40:12 +0000620int tun_new(struct tun_t **tun)
621{
jjakoec89e9f2004-01-10 06:38:43 +0000622
jjako409b8552004-02-04 22:57:41 +0000623#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100624 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000625
jjako0fe0df02004-09-17 11:30:40 +0000626#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100627 char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
628 int devnum;
629 struct ifaliasreq areq;
630 int fd;
jjako409b8552004-02-04 22:57:41 +0000631
632#elif defined(__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100633 int if_fd, ppa = -1;
634 static int ip_fd = 0;
635 int muxid;
636 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000637
jjako06e9f122004-01-19 18:37:58 +0000638#else
jjako409b8552004-02-04 22:57:41 +0000639#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000640#endif
Harald Weltebed35df2011-11-02 13:06:18 +0100641
642 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100643 SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100644 return EOF;
645 }
646
647 (*tun)->cb_ind = NULL;
648 (*tun)->addrs = 0;
649 (*tun)->routes = 0;
650
jjako409b8552004-02-04 22:57:41 +0000651#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100652 /* Open the actual tun device */
653 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100654 SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100655 return -1;
656 }
657
658 /* Set device flags. For some weird reason this is also the method
659 used to obtain the network interface name */
660 memset(&ifr, 0, sizeof(ifr));
661 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
662 if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100663 SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100664 close((*tun)->fd);
665 return -1;
666 }
667
668 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
669 (*tun)->devname[IFNAMSIZ - 1] = 0;
670
671 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
672 return 0;
673
jjako0fe0df02004-09-17 11:30:40 +0000674#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000675
Harald Weltebed35df2011-11-02 13:06:18 +0100676 /* Find suitable device */
677 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
678 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
Harald Weltebed35df2011-11-02 13:06:18 +0100679 if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
680 break;
681 if (errno != EBUSY)
682 break;
683 }
684 if ((*tun)->fd < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100685 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100686 "Can't find tunnel device");
687 return -1;
688 }
jjakoec89e9f2004-01-10 06:38:43 +0000689
Harald Weltebed35df2011-11-02 13:06:18 +0100690 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
691 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjako1f158642004-02-05 20:39:57 +0000692
Harald Weltebed35df2011-11-02 13:06:18 +0100693 /* The tun device we found might have "old" IP addresses allocated */
694 /* We need to delete those. This problem is not present on Linux */
jjako1f158642004-02-05 20:39:57 +0000695
Harald Weltebed35df2011-11-02 13:06:18 +0100696 memset(&areq, 0, sizeof(areq));
jjako1f158642004-02-05 20:39:57 +0000697
Harald Weltebed35df2011-11-02 13:06:18 +0100698 /* Set up interface name */
699 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
700 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako1f158642004-02-05 20:39:57 +0000701
Harald Weltebed35df2011-11-02 13:06:18 +0100702 /* Create a channel to the NET kernel. */
703 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100704 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100705 return -1;
706 }
jjako1f158642004-02-05 20:39:57 +0000707
Harald Weltebed35df2011-11-02 13:06:18 +0100708 /* Delete any IP addresses until SIOCDIFADDR fails */
709 while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
710
711 close(fd);
712 return 0;
jjako409b8552004-02-04 22:57:41 +0000713
714#elif defined(__sun__)
jjakoec89e9f2004-01-10 06:38:43 +0000715
Harald Weltebed35df2011-11-02 13:06:18 +0100716 if ((ip_fd = open("/dev/udp", O_RDWR, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100717 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100718 "Can't open /dev/udp");
719 return -1;
720 }
jjakoec89e9f2004-01-10 06:38:43 +0000721
Harald Weltebed35df2011-11-02 13:06:18 +0100722 if (((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100723 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100724 "Can't open /dev/tun");
725 return -1;
726 }
jjakoec89e9f2004-01-10 06:38:43 +0000727
Harald Weltebed35df2011-11-02 13:06:18 +0100728 /* Assign a new PPA and get its unit number. */
729 if ((ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100730 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100731 "Can't assign new interface");
732 return -1;
733 }
jjakoc6762cf2004-04-28 14:52:58 +0000734
Harald Weltebed35df2011-11-02 13:06:18 +0100735 if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100736 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100737 "Can't open /dev/tun (2)");
738 return -1;
739 }
740 if (ioctl(if_fd, I_PUSH, "ip") < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100741 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100742 "Can't push IP module");
743 return -1;
744 }
jjakoc6762cf2004-04-28 14:52:58 +0000745
Harald Weltebed35df2011-11-02 13:06:18 +0100746 /* Assign ppa according to the unit number returned by tun device */
747 if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100748 SYS_ERR(DTUN, LOGL_ERROR, errno, "Can't set PPA %d",
Harald Weltebed35df2011-11-02 13:06:18 +0100749 ppa);
750 return -1;
751 }
752
753 /* Link the two streams */
754 if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100755 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100756 "Can't link TUN device to IP");
757 return -1;
758 }
759
760 close(if_fd);
761
762 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
763 (*tun)->devname[sizeof((*tun)->devname)] = 0;
764
765 memset(&ifr, 0, sizeof(ifr));
766 strcpy(ifr.ifr_name, (*tun)->devname);
767 ifr.ifr_ip_muxid = muxid;
768
769 if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
770 ioctl(ip_fd, I_PUNLINK, muxid);
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100771 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100772 "Can't set multiplexor id");
773 return -1;
774 }
775
776 /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
777 msg (M_ERR, "Set file descriptor to non-blocking failed"); */
778
779 return 0;
jjako409b8552004-02-04 22:57:41 +0000780
781#else
782#error "Unknown platform!"
783#endif
784
jjako52c24142002-12-16 13:33:51 +0000785}
786
jjakoa7cd2492003-04-11 09:40:12 +0000787int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000788{
jjako163b4552004-12-30 15:33:58 +0000789
Harald Weltebed35df2011-11-02 13:06:18 +0100790 if (tun->routes) {
791 tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
792 }
jjako163b4552004-12-30 15:33:58 +0000793
Harald Weltebed35df2011-11-02 13:06:18 +0100794 if (close(tun->fd)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100795 SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100796 }
jjakoa7cd2492003-04-11 09:40:12 +0000797
Harald Weltebed35df2011-11-02 13:06:18 +0100798 /* TODO: For solaris we need to unlink streams */
jjakoec89e9f2004-01-10 06:38:43 +0000799
Harald Weltebed35df2011-11-02 13:06:18 +0100800 free(tun);
801 return 0;
jjako52c24142002-12-16 13:33:51 +0000802}
803
Harald Weltebed35df2011-11-02 13:06:18 +0100804int tun_set_cb_ind(struct tun_t *this,
805 int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
806{
807 this->cb_ind = cb_ind;
808 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000809}
810
jjakoa7cd2492003-04-11 09:40:12 +0000811int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000812{
jjakoc6762cf2004-04-28 14:52:58 +0000813
jjako0fe0df02004-09-17 11:30:40 +0000814#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000815
Harald Weltebed35df2011-11-02 13:06:18 +0100816 unsigned char buffer[PACKET_MAX];
817 int status;
jjako52c24142002-12-16 13:33:51 +0000818
Harald Weltebed35df2011-11-02 13:06:18 +0100819 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100820 SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100821 return -1;
822 }
823
824 if (this->cb_ind)
825 return this->cb_ind(this, buffer, status);
826
827 return 0;
jjakoc6762cf2004-04-28 14:52:58 +0000828
829#elif defined (__sun__)
830
Harald Weltebed35df2011-11-02 13:06:18 +0100831 unsigned char buffer[PACKET_MAX];
832 struct strbuf sbuf;
833 int f = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000834
Harald Weltebed35df2011-11-02 13:06:18 +0100835 sbuf.maxlen = PACKET_MAX;
836 sbuf.buf = buffer;
837 if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100838 SYS_ERR(DTUN, LOGL_ERROR, errno, "getmsg() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100839 return -1;
840 }
jjakoc6762cf2004-04-28 14:52:58 +0000841
Harald Weltebed35df2011-11-02 13:06:18 +0100842 if (this->cb_ind)
843 return this->cb_ind(this, buffer, sbuf.len);
844
845 return 0;
846
jjakoc6762cf2004-04-28 14:52:58 +0000847#endif
848
jjako52c24142002-12-16 13:33:51 +0000849}
850
851int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
852{
jjakoc6762cf2004-04-28 14:52:58 +0000853
jjako0fe0df02004-09-17 11:30:40 +0000854#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000855
Harald Weltebed35df2011-11-02 13:06:18 +0100856 return write(tun->fd, pack, len);
jjakoc6762cf2004-04-28 14:52:58 +0000857
858#elif defined (__sun__)
859
Harald Weltebed35df2011-11-02 13:06:18 +0100860 struct strbuf sbuf;
861 sbuf.len = len;
862 sbuf.buf = pack;
863 return putmsg(tun->fd, NULL, &sbuf, 0);
jjakoc6762cf2004-04-28 14:52:58 +0000864
865#endif
jjakoa7cd2492003-04-11 09:40:12 +0000866}
867
Harald Weltebed35df2011-11-02 13:06:18 +0100868int tun_runscript(struct tun_t *tun, char *script)
869{
jjakoa7cd2492003-04-11 09:40:12 +0000870
Harald Weltebed35df2011-11-02 13:06:18 +0100871 char buf[TUN_SCRIPTSIZE];
872 char snet[TUN_ADDRSIZE];
873 char smask[TUN_ADDRSIZE];
874 int rc;
875
876 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
877 snet[sizeof(snet) - 1] = 0;
878 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
879 smask[sizeof(smask) - 1] = 0;
880
881 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
882 snprintf(buf, sizeof(buf), "%s %s %s %s",
883 script, tun->devname, snet, smask);
884 buf[sizeof(buf) - 1] = 0;
885 rc = system(buf);
886 if (rc == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100887 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100888 "Error executing command %s", buf);
889 return -1;
890 }
891 return 0;
jjako52c24142002-12-16 13:33:51 +0000892}