blob: 8325f5dc98a86b6b461442d56872a54a18b3dd45 [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");
Michael McTernanb07d0702015-05-02 07:52:23 +0200120 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100121 }
122 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100123 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100124 "ioctl(SIOCSIFFLAGS) failed");
125 close(fd);
126 return -1;
127 }
128 close(fd);
129 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000130}
131
jjako0141d202004-01-09 15:19:20 +0000132/* Currently unused
jjakoa7cd2492003-04-11 09:40:12 +0000133int tun_addroute2(struct tun_t *this,
134 struct in_addr *dst,
135 struct in_addr *gateway,
136 struct in_addr *mask) {
137
138 struct {
139 struct nlmsghdr n;
140 struct rtmsg r;
141 char buf[TUN_NLBUFSIZE];
142 } req;
143
144 struct sockaddr_nl local;
145 int addr_len;
146 int fd;
147 int status;
148 struct sockaddr_nl nladdr;
149 struct iovec iov;
150 struct msghdr msg;
151
152 memset(&req, 0, sizeof(req));
153 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
154 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
155 req.n.nlmsg_type = RTM_NEWROUTE;
156 req.r.rtm_family = AF_INET;
157 req.r.rtm_table = RT_TABLE_MAIN;
158 req.r.rtm_protocol = RTPROT_BOOT;
159 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
160 req.r.rtm_type = RTN_UNICAST;
161 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
162 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
163
164 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100165 SYS_ERR(DTUN, LOGL_ERROR, errno,
jjakoa7cd2492003-04-11 09:40:12 +0000166 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000167 return -1;
168 }
169
jjakoa7cd2492003-04-11 09:40:12 +0000170 memset(&local, 0, sizeof(local));
171 local.nl_family = AF_NETLINK;
172 local.nl_groups = 0;
173
174 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100175 SYS_ERR(DTUN, LOGL_ERROR, errno,
jjakoa7cd2492003-04-11 09:40:12 +0000176 "bind() failed");
177 close(fd);
178 return -1;
179 }
180
181 addr_len = sizeof(local);
182 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100183 SYS_ERR(DTUN, LOGL_ERROR, errno,
jjakoa7cd2492003-04-11 09:40:12 +0000184 "getsockname() failed");
185 close(fd);
186 return -1;
187 }
188
189 if (addr_len != sizeof(local)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100190 SYS_ERR(DTUN, LOGL_ERROR, 0,
jjakoa7cd2492003-04-11 09:40:12 +0000191 "Wrong address length %d", addr_len);
192 close(fd);
193 return -1;
194 }
195
196 if (local.nl_family != AF_NETLINK) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100197 SYS_ERR(DTUN, LOGL_ERROR, 0,
jjakoa7cd2492003-04-11 09:40:12 +0000198 "Wrong address family %d", local.nl_family);
199 close(fd);
200 return -1;
201 }
202
203 iov.iov_base = (void*)&req.n;
204 iov.iov_len = req.n.nlmsg_len;
205
206 msg.msg_name = (void*)&nladdr;
207 msg.msg_namelen = sizeof(nladdr),
208 msg.msg_iov = &iov;
209 msg.msg_iovlen = 1;
210 msg.msg_control = NULL;
211 msg.msg_controllen = 0;
212 msg.msg_flags = 0;
213
214 memset(&nladdr, 0, sizeof(nladdr));
215 nladdr.nl_family = AF_NETLINK;
216 nladdr.nl_pid = 0;
217 nladdr.nl_groups = 0;
218
219 req.n.nlmsg_seq = 0;
220 req.n.nlmsg_flags |= NLM_F_ACK;
221
jjako0141d202004-01-09 15:19:20 +0000222 status = sendmsg(fd, &msg, 0); * TODO: Error check *
jjakoa7cd2492003-04-11 09:40:12 +0000223 close(fd);
224 return 0;
225}
jjako0141d202004-01-09 15:19:20 +0000226*/
jjakoa7cd2492003-04-11 09:40:12 +0000227
228int tun_addaddr(struct tun_t *this,
229 struct in_addr *addr,
Harald Weltebed35df2011-11-02 13:06:18 +0100230 struct in_addr *dstaddr, struct in_addr *netmask)
231{
jjako0141d202004-01-09 15:19:20 +0000232
jjako409b8552004-02-04 22:57:41 +0000233#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100234 struct {
235 struct nlmsghdr n;
236 struct ifaddrmsg i;
237 char buf[TUN_NLBUFSIZE];
238 } req;
jjakoa7cd2492003-04-11 09:40:12 +0000239
Harald Weltebed35df2011-11-02 13:06:18 +0100240 struct sockaddr_nl local;
241 socklen_t addr_len;
242 int fd;
243 int status;
jjakoa7cd2492003-04-11 09:40:12 +0000244
Harald Weltebed35df2011-11-02 13:06:18 +0100245 struct sockaddr_nl nladdr;
246 struct iovec iov;
247 struct msghdr msg;
jjakoa7cd2492003-04-11 09:40:12 +0000248
Harald Weltebed35df2011-11-02 13:06:18 +0100249 if (!this->addrs) /* Use ioctl for first addr to make ping work */
250 return tun_setaddr(this, addr, dstaddr, netmask);
jjakoa7cd2492003-04-11 09:40:12 +0000251
Harald Weltebed35df2011-11-02 13:06:18 +0100252 memset(&req, 0, sizeof(req));
253 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
254 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
255 req.n.nlmsg_type = RTM_NEWADDR;
256 req.i.ifa_family = AF_INET;
257 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
258 req.i.ifa_flags = 0;
259 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
260 if (tun_gifindex(this, &req.i.ifa_index)) {
261 return -1;
262 }
jjakoa7cd2492003-04-11 09:40:12 +0000263
Harald Weltebed35df2011-11-02 13:06:18 +0100264 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
265 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
jjakoa7cd2492003-04-11 09:40:12 +0000266
Harald Weltebed35df2011-11-02 13:06:18 +0100267 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100268 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100269 return -1;
270 }
jjakoa7cd2492003-04-11 09:40:12 +0000271
Harald Weltebed35df2011-11-02 13:06:18 +0100272 memset(&local, 0, sizeof(local));
273 local.nl_family = AF_NETLINK;
274 local.nl_groups = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000275
Harald Weltebed35df2011-11-02 13:06:18 +0100276 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100277 SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100278 close(fd);
279 return -1;
280 }
jjakoa7cd2492003-04-11 09:40:12 +0000281
Harald Weltebed35df2011-11-02 13:06:18 +0100282 addr_len = sizeof(local);
283 if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100284 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100285 "getsockname() failed");
286 close(fd);
287 return -1;
288 }
jjakoa7cd2492003-04-11 09:40:12 +0000289
Harald Weltebed35df2011-11-02 13:06:18 +0100290 if (addr_len != sizeof(local)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100291 SYS_ERR(DTUN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100292 "Wrong address length %d", addr_len);
293 close(fd);
294 return -1;
295 }
jjakoa7cd2492003-04-11 09:40:12 +0000296
Harald Weltebed35df2011-11-02 13:06:18 +0100297 if (local.nl_family != AF_NETLINK) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100298 SYS_ERR(DTUN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100299 "Wrong address family %d", local.nl_family);
300 close(fd);
301 return -1;
302 }
jjakoa7cd2492003-04-11 09:40:12 +0000303
Harald Weltebed35df2011-11-02 13:06:18 +0100304 iov.iov_base = (void *)&req.n;
305 iov.iov_len = req.n.nlmsg_len;
jjakoa7cd2492003-04-11 09:40:12 +0000306
Harald Weltebed35df2011-11-02 13:06:18 +0100307 msg.msg_name = (void *)&nladdr;
Michael McTernanb07d0702015-05-02 07:52:23 +0200308 msg.msg_namelen = sizeof(nladdr);
309 msg.msg_iov = &iov;
Harald Weltebed35df2011-11-02 13:06:18 +0100310 msg.msg_iovlen = 1;
311 msg.msg_control = NULL;
312 msg.msg_controllen = 0;
313 msg.msg_flags = 0;
314
315 memset(&nladdr, 0, sizeof(nladdr));
316 nladdr.nl_family = AF_NETLINK;
317 nladdr.nl_pid = 0;
318 nladdr.nl_groups = 0;
319
320 req.n.nlmsg_seq = 0;
321 req.n.nlmsg_flags |= NLM_F_ACK;
322
Michael McTernanb07d0702015-05-02 07:52:23 +0200323 status = sendmsg(fd, &msg, 0);
324 if (status != req.n.nlmsg_len) {
325 SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
326 close(fd);
327 return -1;
328 }
Harald Weltebed35df2011-11-02 13:06:18 +0100329
Michael McTernanb07d0702015-05-02 07:52:23 +0200330 status = tun_sifflags(this, IFF_UP | IFF_RUNNING);
331 if (status == -1) {
332 close(fd);
333 return -1;
334 }
335
336
Harald Weltebed35df2011-11-02 13:06:18 +0100337 close(fd);
338 this->addrs++;
339 return 0;
jjako409b8552004-02-04 22:57:41 +0000340
jjako0fe0df02004-09-17 11:30:40 +0000341#elif defined (__FreeBSD__) || defined (__APPLE__)
jjako409b8552004-02-04 22:57:41 +0000342
Harald Weltebed35df2011-11-02 13:06:18 +0100343 int fd;
344 struct ifaliasreq areq;
jjako409b8552004-02-04 22:57:41 +0000345
Harald Weltebed35df2011-11-02 13:06:18 +0100346 /* TODO: Is this needed on FreeBSD? */
347 if (!this->addrs) /* Use ioctl for first addr to make ping work */
348 return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
jjako409b8552004-02-04 22:57:41 +0000349
Harald Weltebed35df2011-11-02 13:06:18 +0100350 memset(&areq, 0, sizeof(areq));
jjako409b8552004-02-04 22:57:41 +0000351
Harald Weltebed35df2011-11-02 13:06:18 +0100352 /* Set up interface name */
353 strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
354 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako409b8552004-02-04 22:57:41 +0000355
Harald Weltebed35df2011-11-02 13:06:18 +0100356 ((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
357 ((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
358 sizeof(areq.ifra_addr);
359 ((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000360
Harald Weltebed35df2011-11-02 13:06:18 +0100361 ((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
362 ((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
363 sizeof(areq.ifra_mask);
364 ((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
365 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000366
Harald Weltebed35df2011-11-02 13:06:18 +0100367 /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
368 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
369 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
370 sizeof(areq.ifra_broadaddr);
371 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
372 dstaddr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000373
Harald Weltebed35df2011-11-02 13:06:18 +0100374 /* Create a channel to the NET kernel. */
375 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100376 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100377 return -1;
378 }
jjako409b8552004-02-04 22:57:41 +0000379
Harald Weltebed35df2011-11-02 13:06:18 +0100380 if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100381 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100382 "ioctl(SIOCAIFADDR) failed");
383 close(fd);
384 return -1;
385 }
386
387 close(fd);
388 this->addrs++;
389 return 0;
jjako409b8552004-02-04 22:57:41 +0000390
391#elif defined (__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100392
393 if (!this->addrs) /* Use ioctl for first addr to make ping work */
394 return tun_setaddr(this, addr, dstaddr, netmask);
395
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100396 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100397 "Setting multiple addresses not possible on Solaris");
398 return -1;
jjako409b8552004-02-04 22:57:41 +0000399
400#else
401#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +0000402#endif
jjakoa7cd2492003-04-11 09:40:12 +0000403
Harald Weltebed35df2011-11-02 13:06:18 +0100404}
jjakoa7cd2492003-04-11 09:40:12 +0000405
406int tun_setaddr(struct tun_t *this,
407 struct in_addr *addr,
Harald Weltebed35df2011-11-02 13:06:18 +0100408 struct in_addr *dstaddr, struct in_addr *netmask)
jjakoa7cd2492003-04-11 09:40:12 +0000409{
Harald Weltebed35df2011-11-02 13:06:18 +0100410 struct ifreq ifr;
411 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000412
Harald Weltebed35df2011-11-02 13:06:18 +0100413 memset(&ifr, '\0', sizeof(ifr));
414 ifr.ifr_addr.sa_family = AF_INET;
415 ifr.ifr_dstaddr.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000416
417#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100418 ifr.ifr_netmask.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000419
jjako0fe0df02004-09-17 11:30:40 +0000420#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100421 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
422 sizeof(struct sockaddr_in);
423 ((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
424 sizeof(struct sockaddr_in);
jjako243bfe62004-01-26 23:06:05 +0000425#endif
jjako409b8552004-02-04 22:57:41 +0000426
Harald Weltebed35df2011-11-02 13:06:18 +0100427 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
428 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjakoa7cd2492003-04-11 09:40:12 +0000429
Harald Weltebed35df2011-11-02 13:06:18 +0100430 /* Create a channel to the NET kernel. */
431 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100432 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100433 return -1;
434 }
jjakoa7cd2492003-04-11 09:40:12 +0000435
Harald Weltebed35df2011-11-02 13:06:18 +0100436 if (addr) { /* Set the interface address */
437 this->addr.s_addr = addr->s_addr;
438 memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
439 sizeof(*addr));
440 if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
441 if (errno != EEXIST) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100442 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100443 "ioctl(SIOCSIFADDR) failed");
444 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100445 SYS_ERR(DTUN, LOGL_NOTICE, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100446 "ioctl(SIOCSIFADDR): Address already exists");
447 }
448 close(fd);
449 return -1;
450 }
451 }
jjakoa7cd2492003-04-11 09:40:12 +0000452
Harald Weltebed35df2011-11-02 13:06:18 +0100453 if (dstaddr) { /* Set the destination address */
454 this->dstaddr.s_addr = dstaddr->s_addr;
455 memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
456 dstaddr, sizeof(*dstaddr));
457 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100458 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100459 "ioctl(SIOCSIFDSTADDR) failed");
460 close(fd);
461 return -1;
462 }
463 }
jjakoa7cd2492003-04-11 09:40:12 +0000464
Harald Weltebed35df2011-11-02 13:06:18 +0100465 if (netmask) { /* Set the netmask */
466 this->netmask.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000467#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100468 memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
469 netmask, sizeof(*netmask));
jjako409b8552004-02-04 22:57:41 +0000470
jjako0fe0df02004-09-17 11:30:40 +0000471#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100472 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
473 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000474
475#elif defined(__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100476 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
477 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000478#else
479#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000480#endif
jjako409b8552004-02-04 22:57:41 +0000481
Harald Weltebed35df2011-11-02 13:06:18 +0100482 if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100483 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100484 "ioctl(SIOCSIFNETMASK) failed");
485 close(fd);
486 return -1;
487 }
488 }
jjako1ea66342004-01-28 09:27:34 +0000489
Harald Weltebed35df2011-11-02 13:06:18 +0100490 close(fd);
491 this->addrs++;
jjako409b8552004-02-04 22:57:41 +0000492
Harald Weltebed35df2011-11-02 13:06:18 +0100493 /* On linux the route to the interface is set automatically
494 on FreeBSD we have to do this manually */
495
496 /* TODO: How does it work on Solaris? */
497
498 tun_sifflags(this, IFF_UP | IFF_RUNNING);
jjako163b4552004-12-30 15:33:58 +0000499
jjako0fe0df02004-09-17 11:30:40 +0000500#if defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100501 tun_addroute(this, dstaddr, addr, netmask);
502 this->routes = 1;
jjako1ea66342004-01-28 09:27:34 +0000503#endif
504
Harald Weltebed35df2011-11-02 13:06:18 +0100505 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000506}
507
jjako163b4552004-12-30 15:33:58 +0000508int tun_route(struct tun_t *this,
509 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100510 struct in_addr *gateway, struct in_addr *mask, int delete)
jjakoa7cd2492003-04-11 09:40:12 +0000511{
jjakoec89e9f2004-01-10 06:38:43 +0000512
Harald Weltebed35df2011-11-02 13:06:18 +0100513 /* TODO: Learn how to set routing table on sun */
jjako409b8552004-02-04 22:57:41 +0000514
515#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000516
Harald Weltebed35df2011-11-02 13:06:18 +0100517 struct rtentry r;
518 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000519
Harald Weltebed35df2011-11-02 13:06:18 +0100520 memset(&r, '\0', sizeof(r));
521 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
jjakoa7cd2492003-04-11 09:40:12 +0000522
Harald Weltebed35df2011-11-02 13:06:18 +0100523 /* Create a channel to the NET kernel. */
524 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100525 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100526 return -1;
527 }
jjakoa7cd2492003-04-11 09:40:12 +0000528
Harald Weltebed35df2011-11-02 13:06:18 +0100529 r.rt_dst.sa_family = AF_INET;
530 r.rt_gateway.sa_family = AF_INET;
531 r.rt_genmask.sa_family = AF_INET;
532 memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst));
533 memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway,
534 sizeof(*gateway));
535 memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask,
536 sizeof(*mask));
537
538 if (delete) {
539 if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100540 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100541 "ioctl(SIOCDELRT) failed");
542 close(fd);
543 return -1;
544 }
545 } else {
546 if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100547 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100548 "ioctl(SIOCADDRT) failed");
549 close(fd);
550 return -1;
551 }
552 }
553 close(fd);
554 return 0;
555
jjako0fe0df02004-09-17 11:30:40 +0000556#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako3eaf4532004-01-27 19:47:49 +0000557
Harald Weltebed35df2011-11-02 13:06:18 +0100558 struct {
559 struct rt_msghdr rt;
560 struct sockaddr_in dst;
561 struct sockaddr_in gate;
562 struct sockaddr_in mask;
563 } req;
jjako3eaf4532004-01-27 19:47:49 +0000564
Harald Weltebed35df2011-11-02 13:06:18 +0100565 int fd;
566 struct rt_msghdr *rtm;
jjako1ea66342004-01-28 09:27:34 +0000567
Harald Weltebed35df2011-11-02 13:06:18 +0100568 if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100569 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100570 return -1;
571 }
572
573 memset(&req, 0x00, sizeof(req));
574
575 rtm = &req.rt;
576
577 rtm->rtm_msglen = sizeof(req);
578 rtm->rtm_version = RTM_VERSION;
579 if (delete) {
580 rtm->rtm_type = RTM_DELETE;
581 } else {
582 rtm->rtm_type = RTM_ADD;
583 }
584 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
585 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
586 rtm->rtm_pid = getpid();
587 rtm->rtm_seq = 0044; /* TODO */
588
589 req.dst.sin_family = AF_INET;
590 req.dst.sin_len = sizeof(req.dst);
591 req.mask.sin_family = AF_INET;
592 req.mask.sin_len = sizeof(req.mask);
593 req.gate.sin_family = AF_INET;
594 req.gate.sin_len = sizeof(req.gate);
595
596 req.dst.sin_addr.s_addr = dst->s_addr;
597 req.mask.sin_addr.s_addr = mask->s_addr;
598 req.gate.sin_addr.s_addr = gateway->s_addr;
599
600 if (write(fd, rtm, rtm->rtm_msglen) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100601 SYS_ERR(DTUN, LOGL_ERROR, errno, "write() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100602 close(fd);
603 return -1;
604 }
605 close(fd);
606 return 0;
jjako1ea66342004-01-28 09:27:34 +0000607
jjako409b8552004-02-04 22:57:41 +0000608#elif defined(__sun__)
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100609 SYS_ERR(DTUN, LOGL_NOTICE, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100610 "Could not set up routing on Solaris. Please add route manually.");
611 return 0;
612
jjako409b8552004-02-04 22:57:41 +0000613#else
614#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000615#endif
616
jjakoa7cd2492003-04-11 09:40:12 +0000617}
618
jjako163b4552004-12-30 15:33:58 +0000619int tun_addroute(struct tun_t *this,
620 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100621 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000622{
Harald Weltebed35df2011-11-02 13:06:18 +0100623 return tun_route(this, dst, gateway, mask, 0);
jjako163b4552004-12-30 15:33:58 +0000624}
625
626int tun_delroute(struct tun_t *this,
627 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100628 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000629{
Harald Weltebed35df2011-11-02 13:06:18 +0100630 return tun_route(this, dst, gateway, mask, 1);
jjako163b4552004-12-30 15:33:58 +0000631}
632
jjakoa7cd2492003-04-11 09:40:12 +0000633int tun_new(struct tun_t **tun)
634{
jjakoec89e9f2004-01-10 06:38:43 +0000635
jjako409b8552004-02-04 22:57:41 +0000636#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100637 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000638
jjako0fe0df02004-09-17 11:30:40 +0000639#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100640 char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
641 int devnum;
642 struct ifaliasreq areq;
643 int fd;
jjako409b8552004-02-04 22:57:41 +0000644
645#elif defined(__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100646 int if_fd, ppa = -1;
647 static int ip_fd = 0;
648 int muxid;
649 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000650
jjako06e9f122004-01-19 18:37:58 +0000651#else
jjako409b8552004-02-04 22:57:41 +0000652#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000653#endif
Harald Weltebed35df2011-11-02 13:06:18 +0100654
655 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100656 SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100657 return EOF;
658 }
659
660 (*tun)->cb_ind = NULL;
661 (*tun)->addrs = 0;
662 (*tun)->routes = 0;
663
jjako409b8552004-02-04 22:57:41 +0000664#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100665 /* Open the actual tun device */
666 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100667 SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100668 return -1;
669 }
670
671 /* Set device flags. For some weird reason this is also the method
672 used to obtain the network interface name */
673 memset(&ifr, 0, sizeof(ifr));
674 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
675 if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100676 SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100677 close((*tun)->fd);
678 return -1;
679 }
680
681 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
682 (*tun)->devname[IFNAMSIZ - 1] = 0;
683
684 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
685 return 0;
686
jjako0fe0df02004-09-17 11:30:40 +0000687#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000688
Harald Weltebed35df2011-11-02 13:06:18 +0100689 /* Find suitable device */
690 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
691 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
Harald Weltebed35df2011-11-02 13:06:18 +0100692 if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
693 break;
694 if (errno != EBUSY)
695 break;
696 }
697 if ((*tun)->fd < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100698 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100699 "Can't find tunnel device");
700 return -1;
701 }
jjakoec89e9f2004-01-10 06:38:43 +0000702
Harald Weltebed35df2011-11-02 13:06:18 +0100703 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
704 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjako1f158642004-02-05 20:39:57 +0000705
Harald Weltebed35df2011-11-02 13:06:18 +0100706 /* The tun device we found might have "old" IP addresses allocated */
707 /* We need to delete those. This problem is not present on Linux */
jjako1f158642004-02-05 20:39:57 +0000708
Harald Weltebed35df2011-11-02 13:06:18 +0100709 memset(&areq, 0, sizeof(areq));
jjako1f158642004-02-05 20:39:57 +0000710
Harald Weltebed35df2011-11-02 13:06:18 +0100711 /* Set up interface name */
712 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
713 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako1f158642004-02-05 20:39:57 +0000714
Harald Weltebed35df2011-11-02 13:06:18 +0100715 /* Create a channel to the NET kernel. */
716 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100717 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100718 return -1;
719 }
jjako1f158642004-02-05 20:39:57 +0000720
Harald Weltebed35df2011-11-02 13:06:18 +0100721 /* Delete any IP addresses until SIOCDIFADDR fails */
722 while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
723
724 close(fd);
725 return 0;
jjako409b8552004-02-04 22:57:41 +0000726
727#elif defined(__sun__)
jjakoec89e9f2004-01-10 06:38:43 +0000728
Harald Weltebed35df2011-11-02 13:06:18 +0100729 if ((ip_fd = open("/dev/udp", O_RDWR, 0)) < 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 open /dev/udp");
732 return -1;
733 }
jjakoec89e9f2004-01-10 06:38:43 +0000734
Harald Weltebed35df2011-11-02 13:06:18 +0100735 if (((*tun)->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");
738 return -1;
739 }
jjakoec89e9f2004-01-10 06:38:43 +0000740
Harald Weltebed35df2011-11-02 13:06:18 +0100741 /* Assign a new PPA and get its unit number. */
742 if ((ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100743 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100744 "Can't assign new interface");
745 return -1;
746 }
jjakoc6762cf2004-04-28 14:52:58 +0000747
Harald Weltebed35df2011-11-02 13:06:18 +0100748 if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100749 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100750 "Can't open /dev/tun (2)");
751 return -1;
752 }
753 if (ioctl(if_fd, I_PUSH, "ip") < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100754 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100755 "Can't push IP module");
756 return -1;
757 }
jjakoc6762cf2004-04-28 14:52:58 +0000758
Harald Weltebed35df2011-11-02 13:06:18 +0100759 /* Assign ppa according to the unit number returned by tun device */
760 if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100761 SYS_ERR(DTUN, LOGL_ERROR, errno, "Can't set PPA %d",
Harald Weltebed35df2011-11-02 13:06:18 +0100762 ppa);
763 return -1;
764 }
765
766 /* Link the two streams */
767 if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100768 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100769 "Can't link TUN device to IP");
770 return -1;
771 }
772
773 close(if_fd);
774
775 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
776 (*tun)->devname[sizeof((*tun)->devname)] = 0;
777
778 memset(&ifr, 0, sizeof(ifr));
779 strcpy(ifr.ifr_name, (*tun)->devname);
780 ifr.ifr_ip_muxid = muxid;
781
782 if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
783 ioctl(ip_fd, I_PUNLINK, muxid);
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100784 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100785 "Can't set multiplexor id");
786 return -1;
787 }
788
789 /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
790 msg (M_ERR, "Set file descriptor to non-blocking failed"); */
791
792 return 0;
jjako409b8552004-02-04 22:57:41 +0000793
794#else
795#error "Unknown platform!"
796#endif
797
jjako52c24142002-12-16 13:33:51 +0000798}
799
jjakoa7cd2492003-04-11 09:40:12 +0000800int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000801{
jjako163b4552004-12-30 15:33:58 +0000802
Harald Weltebed35df2011-11-02 13:06:18 +0100803 if (tun->routes) {
804 tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
805 }
jjako163b4552004-12-30 15:33:58 +0000806
Harald Weltebed35df2011-11-02 13:06:18 +0100807 if (close(tun->fd)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100808 SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100809 }
jjakoa7cd2492003-04-11 09:40:12 +0000810
Harald Weltebed35df2011-11-02 13:06:18 +0100811 /* TODO: For solaris we need to unlink streams */
jjakoec89e9f2004-01-10 06:38:43 +0000812
Harald Weltebed35df2011-11-02 13:06:18 +0100813 free(tun);
814 return 0;
jjako52c24142002-12-16 13:33:51 +0000815}
816
Harald Weltebed35df2011-11-02 13:06:18 +0100817int tun_set_cb_ind(struct tun_t *this,
818 int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
819{
820 this->cb_ind = cb_ind;
821 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000822}
823
jjakoa7cd2492003-04-11 09:40:12 +0000824int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000825{
jjakoc6762cf2004-04-28 14:52:58 +0000826
jjako0fe0df02004-09-17 11:30:40 +0000827#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000828
Harald Weltebed35df2011-11-02 13:06:18 +0100829 unsigned char buffer[PACKET_MAX];
830 int status;
jjako52c24142002-12-16 13:33:51 +0000831
Harald Weltebed35df2011-11-02 13:06:18 +0100832 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100833 SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100834 return -1;
835 }
836
837 if (this->cb_ind)
838 return this->cb_ind(this, buffer, status);
839
840 return 0;
jjakoc6762cf2004-04-28 14:52:58 +0000841
842#elif defined (__sun__)
843
Harald Weltebed35df2011-11-02 13:06:18 +0100844 unsigned char buffer[PACKET_MAX];
845 struct strbuf sbuf;
846 int f = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000847
Harald Weltebed35df2011-11-02 13:06:18 +0100848 sbuf.maxlen = PACKET_MAX;
849 sbuf.buf = buffer;
850 if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100851 SYS_ERR(DTUN, LOGL_ERROR, errno, "getmsg() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100852 return -1;
853 }
jjakoc6762cf2004-04-28 14:52:58 +0000854
Harald Weltebed35df2011-11-02 13:06:18 +0100855 if (this->cb_ind)
856 return this->cb_ind(this, buffer, sbuf.len);
857
858 return 0;
859
jjakoc6762cf2004-04-28 14:52:58 +0000860#endif
861
jjako52c24142002-12-16 13:33:51 +0000862}
863
864int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
865{
jjakoc6762cf2004-04-28 14:52:58 +0000866
jjako0fe0df02004-09-17 11:30:40 +0000867#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000868
Harald Weltebed35df2011-11-02 13:06:18 +0100869 return write(tun->fd, pack, len);
jjakoc6762cf2004-04-28 14:52:58 +0000870
871#elif defined (__sun__)
872
Harald Weltebed35df2011-11-02 13:06:18 +0100873 struct strbuf sbuf;
874 sbuf.len = len;
875 sbuf.buf = pack;
876 return putmsg(tun->fd, NULL, &sbuf, 0);
jjakoc6762cf2004-04-28 14:52:58 +0000877
878#endif
jjakoa7cd2492003-04-11 09:40:12 +0000879}
880
Harald Weltebed35df2011-11-02 13:06:18 +0100881int tun_runscript(struct tun_t *tun, char *script)
882{
jjakoa7cd2492003-04-11 09:40:12 +0000883
Harald Weltebed35df2011-11-02 13:06:18 +0100884 char buf[TUN_SCRIPTSIZE];
885 char snet[TUN_ADDRSIZE];
886 char smask[TUN_ADDRSIZE];
887 int rc;
888
889 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
890 snet[sizeof(snet) - 1] = 0;
891 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
892 smask[sizeof(smask) - 1] = 0;
893
894 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
895 snprintf(buf, sizeof(buf), "%s %s %s %s",
896 script, tun->devname, snet, smask);
897 buf[sizeof(buf) - 1] = 0;
898 rc = system(buf);
899 if (rc == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100900 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100901 "Error executing command %s", buf);
902 return -1;
903 }
904 return 0;
jjako52c24142002-12-16 13:33:51 +0000905}