blob: 03d057c73a060a9565de0237528bd35df8262ec4 [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
19
20#include <syslog.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <unistd.h>
30#include <string.h>
31#include <errno.h>
32#include <fcntl.h>
33
34#include <stdio.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000038#include <sys/ioctl.h>
39#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000040#include <errno.h>
jjakoa7cd2492003-04-11 09:40:12 +000041#include <net/route.h>
jjako52c24142002-12-16 13:33:51 +000042
jjako409b8552004-02-04 22:57:41 +000043#if defined(__linux__)
jjako0141d202004-01-09 15:19:20 +000044#include <linux/if.h>
45#include <linux/if_tun.h>
jjakoa7cd2492003-04-11 09:40:12 +000046#include <linux/netlink.h>
47#include <linux/rtnetlink.h>
jjako409b8552004-02-04 22:57:41 +000048
49#elif defined (__FreeBSD__)
50#include <net/if.h>
51#include <net/if_tun.h>
52
jjako0fe0df02004-09-17 11:30:40 +000053#elif defined (__APPLE__)
54#include <net/if.h>
55
jjako0141d202004-01-09 15:19:20 +000056#elif defined (__sun__)
jjakoec89e9f2004-01-10 06:38:43 +000057#include <stropts.h>
58#include <sys/sockio.h>
59#include <net/if.h>
jjako0141d202004-01-09 15:19:20 +000060#include <net/if_tun.h>
jjakoec89e9f2004-01-10 06:38:43 +000061/*#include "sun_if_tun.h"*/
jjako409b8552004-02-04 22:57:41 +000062
63#else
64#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +000065#endif
66
jjako52c24142002-12-16 13:33:51 +000067
68#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000069#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000070
71
jjako409b8552004-02-04 22:57:41 +000072#if defined(__linux__)
73
jjakoa7cd2492003-04-11 09:40:12 +000074int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000075{
jjakoa7cd2492003-04-11 09:40:12 +000076 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)
80 return -1;
81 rta->rta_len = len;
82 rta->rta_type = type;
83 memcpy(RTA_DATA(rta), d, dlen);
84 n->nlmsg_len = alen + len;
85 return 0;
86}
87
Emmanuel Bretelle4e56c832010-09-07 20:06:12 +020088int tun_gifindex(struct tun_t *this, __u32 *index) {
jjako52c24142002-12-16 13:33:51 +000089 struct ifreq ifr;
jjakoa7cd2492003-04-11 09:40:12 +000090 int fd;
jjako52c24142002-12-16 13:33:51 +000091
jjakoa7cd2492003-04-11 09:40:12 +000092 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,
100 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000101 }
jjakoa7cd2492003-04-11 09:40:12 +0000102 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
103 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
104 "ioctl() failed");
105 close(fd);
106 return -1;
107 }
108 close(fd);
109 *index = ifr.ifr_ifindex;
110 return 0;
111}
jjakoec89e9f2004-01-10 06:38:43 +0000112#endif
jjako52c24142002-12-16 13:33:51 +0000113
jjakoa7cd2492003-04-11 09:40:12 +0000114int tun_sifflags(struct tun_t *this, int flags) {
115 struct ifreq ifr;
116 int fd;
117
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,
124 "socket() failed");
125 }
126 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
127 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
128 "ioctl(SIOCSIFFLAGS) failed");
129 close(fd);
130 return -1;
131 }
132 close(fd);
133 return 0;
134}
135
136
jjako0141d202004-01-09 15:19:20 +0000137/* Currently unused
jjakoa7cd2492003-04-11 09:40:12 +0000138int tun_addroute2(struct tun_t *this,
139 struct in_addr *dst,
140 struct in_addr *gateway,
141 struct in_addr *mask) {
142
143 struct {
144 struct nlmsghdr n;
145 struct rtmsg r;
146 char buf[TUN_NLBUFSIZE];
147 } req;
148
149 struct sockaddr_nl local;
150 int addr_len;
151 int fd;
152 int status;
153 struct sockaddr_nl nladdr;
154 struct iovec iov;
155 struct msghdr msg;
156
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);
168
169 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
170 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
171 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000172 return -1;
173 }
174
jjakoa7cd2492003-04-11 09:40:12 +0000175 memset(&local, 0, sizeof(local));
176 local.nl_family = AF_NETLINK;
177 local.nl_groups = 0;
178
179 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
180 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
181 "bind() failed");
182 close(fd);
183 return -1;
184 }
185
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");
190 close(fd);
191 return -1;
192 }
193
194 if (addr_len != sizeof(local)) {
195 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
196 "Wrong address length %d", addr_len);
197 close(fd);
198 return -1;
199 }
200
201 if (local.nl_family != AF_NETLINK) {
202 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
203 "Wrong address family %d", local.nl_family);
204 close(fd);
205 return -1;
206 }
207
208 iov.iov_base = (void*)&req.n;
209 iov.iov_len = req.n.nlmsg_len;
210
211 msg.msg_name = (void*)&nladdr;
212 msg.msg_namelen = sizeof(nladdr),
213 msg.msg_iov = &iov;
214 msg.msg_iovlen = 1;
215 msg.msg_control = NULL;
216 msg.msg_controllen = 0;
217 msg.msg_flags = 0;
218
219 memset(&nladdr, 0, sizeof(nladdr));
220 nladdr.nl_family = AF_NETLINK;
221 nladdr.nl_pid = 0;
222 nladdr.nl_groups = 0;
223
224 req.n.nlmsg_seq = 0;
225 req.n.nlmsg_flags |= NLM_F_ACK;
226
jjako0141d202004-01-09 15:19:20 +0000227 status = sendmsg(fd, &msg, 0); * TODO: Error check *
jjakoa7cd2492003-04-11 09:40:12 +0000228 close(fd);
229 return 0;
230}
jjako0141d202004-01-09 15:19:20 +0000231*/
jjakoa7cd2492003-04-11 09:40:12 +0000232
233int tun_addaddr(struct tun_t *this,
234 struct in_addr *addr,
235 struct in_addr *dstaddr,
236 struct in_addr *netmask) {
jjako0141d202004-01-09 15:19:20 +0000237
jjako409b8552004-02-04 22:57:41 +0000238#if defined(__linux__)
jjakoa7cd2492003-04-11 09:40:12 +0000239 struct {
240 struct nlmsghdr n;
241 struct ifaddrmsg i;
242 char buf[TUN_NLBUFSIZE];
243 } req;
244
245 struct sockaddr_nl local;
Harald Weltef54a1f42010-05-04 11:08:38 +0200246 socklen_t addr_len;
jjakoa7cd2492003-04-11 09:40:12 +0000247 int fd;
248 int status;
jjako409b8552004-02-04 22:57:41 +0000249
jjakoa7cd2492003-04-11 09:40:12 +0000250 struct sockaddr_nl nladdr;
251 struct iovec iov;
252 struct msghdr msg;
253
254 if (!this->addrs) /* Use ioctl for first addr to make ping work */
255 return tun_setaddr(this, addr, dstaddr, netmask);
256
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 */
263 req.i.ifa_flags = 0;
264 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
265 if (tun_gifindex(this, &req.i.ifa_index)) {
266 return -1;
267 }
268
269 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
270 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
271
272 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
273 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
274 "socket() failed");
275 return -1;
276 }
277
278 memset(&local, 0, sizeof(local));
279 local.nl_family = AF_NETLINK;
280 local.nl_groups = 0;
281
282 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
283 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
284 "bind() failed");
285 close(fd);
286 return -1;
287 }
288
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");
293 close(fd);
294 return -1;
295 }
296
297 if (addr_len != sizeof(local)) {
298 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
299 "Wrong address length %d", addr_len);
300 close(fd);
301 return -1;
302 }
303
304 if (local.nl_family != AF_NETLINK) {
305 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
306 "Wrong address family %d", local.nl_family);
307 close(fd);
308 return -1;
309 }
310
311 iov.iov_base = (void*)&req.n;
312 iov.iov_len = req.n.nlmsg_len;
313
314 msg.msg_name = (void*)&nladdr;
315 msg.msg_namelen = sizeof(nladdr),
316 msg.msg_iov = &iov;
317 msg.msg_iovlen = 1;
318 msg.msg_control = NULL;
319 msg.msg_controllen = 0;
320 msg.msg_flags = 0;
321
322 memset(&nladdr, 0, sizeof(nladdr));
323 nladdr.nl_family = AF_NETLINK;
324 nladdr.nl_pid = 0;
325 nladdr.nl_groups = 0;
326
327 req.n.nlmsg_seq = 0;
328 req.n.nlmsg_flags |= NLM_F_ACK;
329
330 status = sendmsg(fd, &msg, 0); /* TODO Error check */
331
jjako409b8552004-02-04 22:57:41 +0000332 tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
jjakoa7cd2492003-04-11 09:40:12 +0000333 close(fd);
334 this->addrs++;
335 return 0;
jjako409b8552004-02-04 22:57:41 +0000336
jjako0fe0df02004-09-17 11:30:40 +0000337#elif defined (__FreeBSD__) || defined (__APPLE__)
jjako409b8552004-02-04 22:57:41 +0000338
339 int fd;
340 struct ifaliasreq areq;
341
342 /* TODO: Is this needed on FreeBSD? */
343 if (!this->addrs) /* Use ioctl for first addr to make ping work */
jjako1f158642004-02-05 20:39:57 +0000344 return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
jjako409b8552004-02-04 22:57:41 +0000345
346 memset(&areq, 0, sizeof(areq));
347
348 /* Set up interface name */
349 strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
jjako1f158642004-02-05 20:39:57 +0000350 areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
jjako409b8552004-02-04 22:57:41 +0000351
jjako1f158642004-02-05 20:39:57 +0000352 ((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;
jjako409b8552004-02-04 22:57:41 +0000355
jjako1f158642004-02-05 20:39:57 +0000356 ((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;
jjako409b8552004-02-04 22:57:41 +0000359
jjako1f158642004-02-05 20:39:57 +0000360 /* 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 =
365 dstaddr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000366
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,
370 "socket() failed");
371 return -1;
372 }
373
374 if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
375 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
376 "ioctl(SIOCAIFADDR) failed");
377 close(fd);
378 return -1;
379 }
380
381 close(fd);
382 this->addrs++;
383 return 0;
384
385#elif defined (__sun__)
386
387 if (!this->addrs) /* Use ioctl for first addr to make ping work */
388 return tun_setaddr(this, addr, dstaddr, netmask);
389
390 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
391 "Setting multiple addresses not possible on Solaris");
392 return -1;
393
394#else
395#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +0000396#endif
jjako409b8552004-02-04 22:57:41 +0000397
jjakoa7cd2492003-04-11 09:40:12 +0000398}
399
400
401int tun_setaddr(struct tun_t *this,
402 struct in_addr *addr,
403 struct in_addr *dstaddr,
404 struct in_addr *netmask)
405{
406 struct ifreq ifr;
407 int fd;
408
409 memset (&ifr, '\0', sizeof (ifr));
410 ifr.ifr_addr.sa_family = AF_INET;
411 ifr.ifr_dstaddr.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000412
413#if defined(__linux__)
jjakoa7cd2492003-04-11 09:40:12 +0000414 ifr.ifr_netmask.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000415
jjako0fe0df02004-09-17 11:30:40 +0000416#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako243bfe62004-01-26 23:06:05 +0000417 ((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);
421#endif
jjako409b8552004-02-04 22:57:41 +0000422
jjakoa7cd2492003-04-11 09:40:12 +0000423 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
424 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
425
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,
429 "socket() failed");
430 return -1;
431 }
432
433 if (addr) { /* Set the interface address */
434 this->addr.s_addr = addr->s_addr;
Emmanuel Bretelle4e56c832010-09-07 20:06:12 +0200435 memcpy(&((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr, addr,
436 sizeof(*addr));
jjakoa7cd2492003-04-11 09:40:12 +0000437 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
438 if (errno != EEXIST) {
439 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
440 "ioctl(SIOCSIFADDR) failed");
441 }
442 else {
443 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
444 "ioctl(SIOCSIFADDR): Address already exists");
445 }
446 close(fd);
447 return -1;
448 }
449 }
450
451 if (dstaddr) { /* Set the destination address */
452 this->dstaddr.s_addr = dstaddr->s_addr;
Emmanuel Bretelle4e56c832010-09-07 20:06:12 +0200453 memcpy(&((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr,
454 dstaddr, sizeof(*dstaddr));
jjakoa7cd2492003-04-11 09:40:12 +0000455 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
456 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
457 "ioctl(SIOCSIFDSTADDR) failed");
458 close(fd);
459 return -1;
460 }
461 }
462
463 if (netmask) { /* Set the netmask */
464 this->netmask.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000465#if defined(__linux__)
Emmanuel Bretelle4e56c832010-09-07 20:06:12 +0200466 memcpy(&((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr,
467 netmask, sizeof(*netmask));
jjako409b8552004-02-04 22:57:41 +0000468
jjako0fe0df02004-09-17 11:30:40 +0000469#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako243bfe62004-01-26 23:06:05 +0000470 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
471 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000472
473#elif defined(__sun__)
474 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
jjakoa7cd2492003-04-11 09:40:12 +0000475 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000476#else
477#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000478#endif
jjako409b8552004-02-04 22:57:41 +0000479
jjakoa7cd2492003-04-11 09:40:12 +0000480 if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
481 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
482 "ioctl(SIOCSIFNETMASK) failed");
483 close(fd);
484 return -1;
485 }
486 }
jjako409b8552004-02-04 22:57:41 +0000487
jjakoa7cd2492003-04-11 09:40:12 +0000488 close(fd);
489 this->addrs++;
jjako409b8552004-02-04 22:57:41 +0000490
jjako1ea66342004-01-28 09:27:34 +0000491 /* On linux the route to the interface is set automatically
492 on FreeBSD we have to do this manually */
493
jjako409b8552004-02-04 22:57:41 +0000494 /* TODO: How does it work on Solaris? */
495
jjako163b4552004-12-30 15:33:58 +0000496 tun_sifflags(this, IFF_UP | IFF_RUNNING);
497
jjako0fe0df02004-09-17 11:30:40 +0000498#if defined(__FreeBSD__) || defined (__APPLE__)
jjako163b4552004-12-30 15:33:58 +0000499 tun_addroute(this, dstaddr, addr, netmask);
500 this->routes = 1;
jjako1ea66342004-01-28 09:27:34 +0000501#endif
502
jjako163b4552004-12-30 15:33:58 +0000503 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000504}
505
jjako163b4552004-12-30 15:33:58 +0000506int tun_route(struct tun_t *this,
507 struct in_addr *dst,
508 struct in_addr *gateway,
509 struct in_addr *mask,
510 int delete)
jjakoa7cd2492003-04-11 09:40:12 +0000511{
jjakoec89e9f2004-01-10 06:38:43 +0000512
jjako1ea66342004-01-28 09:27:34 +0000513
514 /* TODO: Learn how to set routing table on sun */
jjako409b8552004-02-04 22:57:41 +0000515
516#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000517
jjakoa7cd2492003-04-11 09:40:12 +0000518 struct rtentry r;
519 int fd;
520
521 memset (&r, '\0', sizeof (r));
522 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
523
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,
527 "socket() failed");
528 return -1;
529 }
530
531 r.rt_dst.sa_family = AF_INET;
532 r.rt_gateway.sa_family = AF_INET;
533 r.rt_genmask.sa_family = AF_INET;
Emmanuel Bretelle4e56c832010-09-07 20:06:12 +0200534 memcpy(&((struct sockaddr_in *) &r.rt_dst)->sin_addr, dst, sizeof(*dst));
535 memcpy(&((struct sockaddr_in *) &r.rt_gateway)->sin_addr, gateway,
536 sizeof(*gateway));
537 memcpy(&((struct sockaddr_in *) &r.rt_genmask)->sin_addr, mask,
538 sizeof(*mask));
jjako163b4552004-12-30 15:33:58 +0000539
540 if (delete) {
541 if (ioctl(fd, SIOCDELRT, (void *) &r) < 0) {
542 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
543 "ioctl(SIOCDELRT) failed");
544 close(fd);
545 return -1;
546 }
547 }
548 else {
549 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) {
550 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
551 "ioctl(SIOCADDRT) failed");
552 close(fd);
553 return -1;
554 }
jjakoa7cd2492003-04-11 09:40:12 +0000555 }
556 close(fd);
jjako409b8552004-02-04 22:57:41 +0000557 return 0;
jjako163b4552004-12-30 15:33:58 +0000558
jjako0fe0df02004-09-17 11:30:40 +0000559#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako3eaf4532004-01-27 19:47:49 +0000560
jjako1ea66342004-01-28 09:27:34 +0000561struct {
562 struct rt_msghdr rt;
563 struct sockaddr_in dst;
564 struct sockaddr_in gate;
565 struct sockaddr_in mask;
566} req;
jjako3eaf4532004-01-27 19:47:49 +0000567
jjako1ea66342004-01-28 09:27:34 +0000568 int fd;
jjako3eaf4532004-01-27 19:47:49 +0000569 struct rt_msghdr *rtm;
jjako3eaf4532004-01-27 19:47:49 +0000570
jjako1ea66342004-01-28 09:27:34 +0000571 if((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
572 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
573 "socket() failed");
574 return -1;
575 }
jjako3eaf4532004-01-27 19:47:49 +0000576
jjako1ea66342004-01-28 09:27:34 +0000577 memset(&req, 0x00, sizeof(req));
jjako3eaf4532004-01-27 19:47:49 +0000578
jjako1ea66342004-01-28 09:27:34 +0000579 rtm = &req.rt;
jjako3eaf4532004-01-27 19:47:49 +0000580
jjako1ea66342004-01-28 09:27:34 +0000581 rtm->rtm_msglen = sizeof(req);
582 rtm->rtm_version = RTM_VERSION;
jjako163b4552004-12-30 15:33:58 +0000583 if (delete) {
584 rtm->rtm_type = RTM_DELETE;
585 }
586 else {
587 rtm->rtm_type = RTM_ADD;
588 }
jjako3eaf4532004-01-27 19:47:49 +0000589 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
jjako3eaf4532004-01-27 19:47:49 +0000590 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
591 rtm->rtm_pid = getpid();
jjako1ea66342004-01-28 09:27:34 +0000592 rtm->rtm_seq = 0044; /* TODO */
jjako3eaf4532004-01-27 19:47:49 +0000593
jjako1ea66342004-01-28 09:27:34 +0000594 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);
600
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;
jjako3eaf4532004-01-27 19:47:49 +0000604
jjako1ea66342004-01-28 09:27:34 +0000605 if(write(fd, rtm, rtm->rtm_msglen) < 0) {
606 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
607 "write() failed");
608 close(fd);
609 return -1;
610 }
611 close(fd);
jjako409b8552004-02-04 22:57:41 +0000612 return 0;
jjako1ea66342004-01-28 09:27:34 +0000613
jjako409b8552004-02-04 22:57:41 +0000614#elif defined(__sun__)
615 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
616 "Could not set up routing on Solaris. Please add route manually.");
617 return 0;
618
619#else
620#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000621#endif
622
jjakoa7cd2492003-04-11 09:40:12 +0000623}
624
jjako163b4552004-12-30 15:33:58 +0000625int tun_addroute(struct tun_t *this,
626 struct in_addr *dst,
627 struct in_addr *gateway,
628 struct in_addr *mask)
629{
630 return tun_route(this, dst, gateway, mask, 0);
631}
632
633int tun_delroute(struct tun_t *this,
634 struct in_addr *dst,
635 struct in_addr *gateway,
636 struct in_addr *mask)
637{
638 return tun_route(this, dst, gateway, mask, 1);
639}
640
641
jjakoa7cd2492003-04-11 09:40:12 +0000642int tun_new(struct tun_t **tun)
643{
jjakoec89e9f2004-01-10 06:38:43 +0000644
jjako409b8552004-02-04 22:57:41 +0000645#if defined(__linux__)
646 struct ifreq ifr;
647
jjako0fe0df02004-09-17 11:30:40 +0000648#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako243bfe62004-01-26 23:06:05 +0000649 char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
650 int devnum;
jjako1f158642004-02-05 20:39:57 +0000651 struct ifaliasreq areq;
652 int fd;
jjako409b8552004-02-04 22:57:41 +0000653
654#elif defined(__sun__)
655 int if_fd, ppa = -1;
656 static int ip_fd = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000657 int muxid;
658 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000659
jjako06e9f122004-01-19 18:37:58 +0000660#else
jjako409b8552004-02-04 22:57:41 +0000661#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000662#endif
jjakoa7cd2492003-04-11 09:40:12 +0000663
664 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
665 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
666 return EOF;
667 }
668
669 (*tun)->cb_ind = NULL;
670 (*tun)->addrs = 0;
jjako163b4552004-12-30 15:33:58 +0000671 (*tun)->routes = 0;
jjako409b8552004-02-04 22:57:41 +0000672
673#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000674 /* Open the actual tun device */
jjakoa7cd2492003-04-11 09:40:12 +0000675 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
676 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
677 return -1;
678 }
jjako409b8552004-02-04 22:57:41 +0000679
jjakoec89e9f2004-01-10 06:38:43 +0000680 /* Set device flags. For some weird reason this is also the method
681 used to obtain the network interface name */
jjako52c24142002-12-16 13:33:51 +0000682 memset(&ifr, 0, sizeof(ifr));
683 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
jjako52c24142002-12-16 13:33:51 +0000684 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000685 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000686 close((*tun)->fd);
687 return -1;
688 }
jjako409b8552004-02-04 22:57:41 +0000689
jjako52c24142002-12-16 13:33:51 +0000690 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
Emmanuel Bretelle87490d72010-09-07 20:22:36 +0200691 (*tun)->devname[IFNAMSIZ-1] = 0;
jjako409b8552004-02-04 22:57:41 +0000692
jjakoec89e9f2004-01-10 06:38:43 +0000693 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
jjako409b8552004-02-04 22:57:41 +0000694 return 0;
695
jjako0fe0df02004-09-17 11:30:40 +0000696#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000697
jjako409b8552004-02-04 22:57:41 +0000698 /* 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;
704 }
705 if ((*tun)->fd < 0) {
706 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
707 return -1;
708 }
jjakoec89e9f2004-01-10 06:38:43 +0000709
jjako409b8552004-02-04 22:57:41 +0000710 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
711 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjako1f158642004-02-05 20:39:57 +0000712
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 */
715
716 memset(&areq, 0, sizeof(areq));
717
718 /* Set up interface name */
719 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
720 areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
721
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,
725 "socket() failed");
726 return -1;
727 }
728
729 /* Delete any IP addresses until SIOCDIFADDR fails */
730 while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
731
732 close(fd);
jjako409b8552004-02-04 22:57:41 +0000733 return 0;
734
735#elif defined(__sun__)
jjakoec89e9f2004-01-10 06:38:43 +0000736
jjakoc6762cf2004-04-28 14:52:58 +0000737 if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
738 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp");
jjakoec89e9f2004-01-10 06:38:43 +0000739 return -1;
740 }
741
742 if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
743 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
744 return -1;
745 }
746
747 /* Assign a new PPA and get its unit number. */
748 if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000749 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface");
jjakoec89e9f2004-01-10 06:38:43 +0000750 return -1;
751 }
752
753 if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000754 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)");
jjakoec89e9f2004-01-10 06:38:43 +0000755 return -1;
756 }
757 if(ioctl(if_fd, I_PUSH, "ip") < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000758 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module");
jjakoec89e9f2004-01-10 06:38:43 +0000759 return -1;
760 }
761
762 /* Assign ppa according to the unit number returned by tun device */
763 if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000764 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa);
jjakoec89e9f2004-01-10 06:38:43 +0000765 return -1;
766 }
767
768 /* Link the two streams */
jjakoc6762cf2004-04-28 14:52:58 +0000769 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");
jjakoec89e9f2004-01-10 06:38:43 +0000771 return -1;
772 }
773
774 close (if_fd);
775
jjako243bfe62004-01-26 23:06:05 +0000776 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
777 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000778
779 memset(&ifr, 0, sizeof(ifr));
780 strcpy(ifr.ifr_name, (*tun)->devname);
781 ifr.ifr_ip_muxid = muxid;
782
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");
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
jjakoa7cd2492003-04-11 09:40:12 +0000792 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
803 if (tun->routes) {
804 tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
805 }
806
jjako52c24142002-12-16 13:33:51 +0000807 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000808 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000809 }
jjakoa7cd2492003-04-11 09:40:12 +0000810
jjakoec89e9f2004-01-10 06:38:43 +0000811 /* TODO: For solaris we need to unlink streams */
812
jjako52c24142002-12-16 13:33:51 +0000813 free(tun);
814 return 0;
815}
816
817
jjakoa7cd2492003-04-11 09:40:12 +0000818int 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;
821 return 0;
822}
823
824
825int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000826{
jjakoc6762cf2004-04-28 14:52:58 +0000827
jjako0fe0df02004-09-17 11:30:40 +0000828#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000829
jjakoa7cd2492003-04-11 09:40:12 +0000830 unsigned char buffer[PACKET_MAX];
831 int status;
832
833 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
834 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
835 return -1;
836 }
837
838 if (this->cb_ind)
839 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000840
jjakoa7cd2492003-04-11 09:40:12 +0000841 return 0;
jjakoc6762cf2004-04-28 14:52:58 +0000842
843#elif defined (__sun__)
844
845 unsigned char buffer[PACKET_MAX];
846 struct strbuf sbuf;
847 int f = 0;
848
849 sbuf.maxlen = PACKET_MAX;
850 sbuf.buf = buffer;
851 if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
852 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed");
853 return -1;
854 }
855
856 if (this->cb_ind)
857 return this->cb_ind(this, buffer, sbuf.len);
858
859 return 0;
860
861#endif
862
jjako52c24142002-12-16 13:33:51 +0000863}
864
jjakoc6762cf2004-04-28 14:52:58 +0000865
jjako52c24142002-12-16 13:33:51 +0000866int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
867{
jjakoc6762cf2004-04-28 14:52:58 +0000868
jjako0fe0df02004-09-17 11:30:40 +0000869#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000870
jjakoa7cd2492003-04-11 09:40:12 +0000871 return write(tun->fd, pack, len);
jjakoc6762cf2004-04-28 14:52:58 +0000872
873#elif defined (__sun__)
874
875 struct strbuf sbuf;
876 sbuf.len = len;
877 sbuf.buf = pack;
878 return putmsg(tun->fd, NULL, &sbuf, 0);
879
880#endif
jjakoa7cd2492003-04-11 09:40:12 +0000881}
882
883int tun_runscript(struct tun_t *tun, char* script) {
884
885 char buf[TUN_SCRIPTSIZE];
886 char snet[TUN_ADDRSIZE];
887 char smask[TUN_ADDRSIZE];
Emmanuel Bretelle4e56c832010-09-07 20:06:12 +0200888 int rc;
jjakoa7cd2492003-04-11 09:40:12 +0000889
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;
894
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;
Emmanuel Bretelle4e56c832010-09-07 20:06:12 +0200899 rc = system(buf);
900 if (rc == -1) {
901 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Error executing command %s",
902 buf);
903 return -1;
904 }
jjakoa7cd2492003-04-11 09:40:12 +0000905 return 0;
jjako52c24142002-12-16 13:33:51 +0000906}