blob: 1cc706bb28851585177c17fa48ec7dc8b0f44e8d [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
88int tun_gifindex(struct tun_t *this, int *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;
435 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
436 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
437 if (errno != EEXIST) {
438 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
439 "ioctl(SIOCSIFADDR) failed");
440 }
441 else {
442 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
443 "ioctl(SIOCSIFADDR): Address already exists");
444 }
445 close(fd);
446 return -1;
447 }
448 }
449
450 if (dstaddr) { /* Set the destination address */
451 this->dstaddr.s_addr = dstaddr->s_addr;
452 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
453 dstaddr->s_addr;
454 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
455 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
456 "ioctl(SIOCSIFDSTADDR) failed");
457 close(fd);
458 return -1;
459 }
460 }
461
462 if (netmask) { /* Set the netmask */
463 this->netmask.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000464#if defined(__linux__)
465 ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
jjako243bfe62004-01-26 23:06:05 +0000466 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000467
jjako0fe0df02004-09-17 11:30:40 +0000468#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako243bfe62004-01-26 23:06:05 +0000469 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
470 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000471
472#elif defined(__sun__)
473 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
jjakoa7cd2492003-04-11 09:40:12 +0000474 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000475#else
476#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000477#endif
jjako409b8552004-02-04 22:57:41 +0000478
jjakoa7cd2492003-04-11 09:40:12 +0000479 if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
480 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
481 "ioctl(SIOCSIFNETMASK) failed");
482 close(fd);
483 return -1;
484 }
485 }
jjako409b8552004-02-04 22:57:41 +0000486
jjakoa7cd2492003-04-11 09:40:12 +0000487 close(fd);
488 this->addrs++;
jjako409b8552004-02-04 22:57:41 +0000489
jjako1ea66342004-01-28 09:27:34 +0000490 /* On linux the route to the interface is set automatically
491 on FreeBSD we have to do this manually */
492
jjako409b8552004-02-04 22:57:41 +0000493 /* TODO: How does it work on Solaris? */
494
jjako163b4552004-12-30 15:33:58 +0000495 tun_sifflags(this, IFF_UP | IFF_RUNNING);
496
jjako0fe0df02004-09-17 11:30:40 +0000497#if defined(__FreeBSD__) || defined (__APPLE__)
jjako163b4552004-12-30 15:33:58 +0000498 tun_addroute(this, dstaddr, addr, netmask);
499 this->routes = 1;
jjako1ea66342004-01-28 09:27:34 +0000500#endif
501
jjako163b4552004-12-30 15:33:58 +0000502 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000503}
504
jjako163b4552004-12-30 15:33:58 +0000505int tun_route(struct tun_t *this,
506 struct in_addr *dst,
507 struct in_addr *gateway,
508 struct in_addr *mask,
509 int delete)
jjakoa7cd2492003-04-11 09:40:12 +0000510{
jjakoec89e9f2004-01-10 06:38:43 +0000511
jjako1ea66342004-01-28 09:27:34 +0000512
513 /* 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
jjakoa7cd2492003-04-11 09:40:12 +0000517 struct rtentry r;
518 int fd;
519
520 memset (&r, '\0', sizeof (r));
521 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
522
523 /* Create a channel to the NET kernel. */
524 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
525 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
526 "socket() failed");
527 return -1;
528 }
529
530 r.rt_dst.sa_family = AF_INET;
531 r.rt_gateway.sa_family = AF_INET;
532 r.rt_genmask.sa_family = AF_INET;
533 ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
534 ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
535 ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
jjako163b4552004-12-30 15:33:58 +0000536
537 if (delete) {
538 if (ioctl(fd, SIOCDELRT, (void *) &r) < 0) {
539 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
540 "ioctl(SIOCDELRT) failed");
541 close(fd);
542 return -1;
543 }
544 }
545 else {
546 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) {
547 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
548 "ioctl(SIOCADDRT) failed");
549 close(fd);
550 return -1;
551 }
jjakoa7cd2492003-04-11 09:40:12 +0000552 }
553 close(fd);
jjako409b8552004-02-04 22:57:41 +0000554 return 0;
jjako163b4552004-12-30 15:33:58 +0000555
jjako0fe0df02004-09-17 11:30:40 +0000556#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako1ea66342004-01-28 09:27:34 +0000557
558struct {
559 struct rt_msghdr rt;
560 struct sockaddr_in dst;
561 struct sockaddr_in gate;
562 struct sockaddr_in mask;
563} req;
564
565 int fd;
566 struct rt_msghdr *rtm;
567
568 if((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
569 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
570 "socket() failed");
571 return -1;
572 }
573
574 memset(&req, 0x00, sizeof(req));
575
576 rtm = &req.rt;
577
578 rtm->rtm_msglen = sizeof(req);
579 rtm->rtm_version = RTM_VERSION;
jjako163b4552004-12-30 15:33:58 +0000580 if (delete) {
581 rtm->rtm_type = RTM_DELETE;
582 }
583 else {
584 rtm->rtm_type = RTM_ADD;
585 }
jjako1ea66342004-01-28 09:27:34 +0000586 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
587 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
588 rtm->rtm_pid = getpid();
589 rtm->rtm_seq = 0044; /* TODO */
590
591 req.dst.sin_family = AF_INET;
592 req.dst.sin_len = sizeof(req.dst);
593 req.mask.sin_family = AF_INET;
594 req.mask.sin_len = sizeof(req.mask);
595 req.gate.sin_family = AF_INET;
596 req.gate.sin_len = sizeof(req.gate);
597
598 req.dst.sin_addr.s_addr = dst->s_addr;
599 req.mask.sin_addr.s_addr = mask->s_addr;
600 req.gate.sin_addr.s_addr = gateway->s_addr;
601
602 if(write(fd, rtm, rtm->rtm_msglen) < 0) {
603 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
604 "write() failed");
605 close(fd);
606 return -1;
607 }
608 close(fd);
jjako409b8552004-02-04 22:57:41 +0000609 return 0;
jjako1ea66342004-01-28 09:27:34 +0000610
jjako409b8552004-02-04 22:57:41 +0000611#elif defined(__sun__)
612 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
613 "Could not set up routing on Solaris. Please add route manually.");
614 return 0;
615
616#else
617#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000618#endif
619
jjakoa7cd2492003-04-11 09:40:12 +0000620}
621
jjako163b4552004-12-30 15:33:58 +0000622int tun_addroute(struct tun_t *this,
623 struct in_addr *dst,
624 struct in_addr *gateway,
625 struct in_addr *mask)
626{
627 return tun_route(this, dst, gateway, mask, 0);
628}
629
630int tun_delroute(struct tun_t *this,
631 struct in_addr *dst,
632 struct in_addr *gateway,
633 struct in_addr *mask)
634{
635 return tun_route(this, dst, gateway, mask, 1);
636}
637
638
jjakoa7cd2492003-04-11 09:40:12 +0000639int tun_new(struct tun_t **tun)
640{
jjakoec89e9f2004-01-10 06:38:43 +0000641
jjako409b8552004-02-04 22:57:41 +0000642#if defined(__linux__)
643 struct ifreq ifr;
644
jjako0fe0df02004-09-17 11:30:40 +0000645#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako243bfe62004-01-26 23:06:05 +0000646 char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
647 int devnum;
jjako1f158642004-02-05 20:39:57 +0000648 struct ifaliasreq areq;
649 int fd;
jjako409b8552004-02-04 22:57:41 +0000650
651#elif defined(__sun__)
652 int if_fd, ppa = -1;
653 static int ip_fd = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000654 int muxid;
655 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000656
jjako06e9f122004-01-19 18:37:58 +0000657#else
jjako409b8552004-02-04 22:57:41 +0000658#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000659#endif
jjakoa7cd2492003-04-11 09:40:12 +0000660
661 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
662 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
663 return EOF;
664 }
665
666 (*tun)->cb_ind = NULL;
667 (*tun)->addrs = 0;
jjako163b4552004-12-30 15:33:58 +0000668 (*tun)->routes = 0;
jjako409b8552004-02-04 22:57:41 +0000669
670#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000671 /* Open the actual tun device */
jjakoa7cd2492003-04-11 09:40:12 +0000672 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
673 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
674 return -1;
675 }
jjako409b8552004-02-04 22:57:41 +0000676
jjakoec89e9f2004-01-10 06:38:43 +0000677 /* Set device flags. For some weird reason this is also the method
678 used to obtain the network interface name */
jjako52c24142002-12-16 13:33:51 +0000679 memset(&ifr, 0, sizeof(ifr));
680 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
jjako52c24142002-12-16 13:33:51 +0000681 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000682 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000683 close((*tun)->fd);
684 return -1;
685 }
jjako409b8552004-02-04 22:57:41 +0000686
jjako52c24142002-12-16 13:33:51 +0000687 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000688 (*tun)->devname[IFNAMSIZ] = 0;
jjako409b8552004-02-04 22:57:41 +0000689
jjakoec89e9f2004-01-10 06:38:43 +0000690 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
jjako409b8552004-02-04 22:57:41 +0000691 return 0;
692
jjako0fe0df02004-09-17 11:30:40 +0000693#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000694
jjako409b8552004-02-04 22:57:41 +0000695 /* Find suitable device */
696 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
697 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
698 devname[sizeof(devname)] = 0;
699 if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
700 if (errno != EBUSY) break;
701 }
702 if ((*tun)->fd < 0) {
703 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
704 return -1;
705 }
jjakoec89e9f2004-01-10 06:38:43 +0000706
jjako409b8552004-02-04 22:57:41 +0000707 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
708 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjako1f158642004-02-05 20:39:57 +0000709
710 /* The tun device we found might have "old" IP addresses allocated */
711 /* We need to delete those. This problem is not present on Linux */
712
713 memset(&areq, 0, sizeof(areq));
714
715 /* Set up interface name */
716 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
717 areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
718
719 /* Create a channel to the NET kernel. */
720 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
721 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
722 "socket() failed");
723 return -1;
724 }
725
726 /* Delete any IP addresses until SIOCDIFADDR fails */
727 while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
728
729 close(fd);
jjako409b8552004-02-04 22:57:41 +0000730 return 0;
731
732#elif defined(__sun__)
jjakoec89e9f2004-01-10 06:38:43 +0000733
jjakoc6762cf2004-04-28 14:52:58 +0000734 if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
735 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp");
jjakoec89e9f2004-01-10 06:38:43 +0000736 return -1;
737 }
738
739 if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
740 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
741 return -1;
742 }
743
744 /* Assign a new PPA and get its unit number. */
745 if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000746 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface");
jjakoec89e9f2004-01-10 06:38:43 +0000747 return -1;
748 }
749
750 if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000751 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)");
jjakoec89e9f2004-01-10 06:38:43 +0000752 return -1;
753 }
754 if(ioctl(if_fd, I_PUSH, "ip") < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000755 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module");
jjakoec89e9f2004-01-10 06:38:43 +0000756 return -1;
757 }
758
759 /* Assign ppa according to the unit number returned by tun device */
760 if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000761 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa);
jjakoec89e9f2004-01-10 06:38:43 +0000762 return -1;
763 }
764
765 /* Link the two streams */
jjakoc6762cf2004-04-28 14:52:58 +0000766 if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
767 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't link TUN device to IP");
jjakoec89e9f2004-01-10 06:38:43 +0000768 return -1;
769 }
770
771 close (if_fd);
772
jjako243bfe62004-01-26 23:06:05 +0000773 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
774 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000775
776 memset(&ifr, 0, sizeof(ifr));
777 strcpy(ifr.ifr_name, (*tun)->devname);
778 ifr.ifr_ip_muxid = muxid;
779
780 if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
781 ioctl(ip_fd, I_PUNLINK, muxid);
782 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set multiplexor id");
783 return -1;
784 }
785
786 /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
787 msg (M_ERR, "Set file descriptor to non-blocking failed"); */
788
jjakoa7cd2492003-04-11 09:40:12 +0000789 return 0;
jjako409b8552004-02-04 22:57:41 +0000790
791#else
792#error "Unknown platform!"
793#endif
794
jjako52c24142002-12-16 13:33:51 +0000795}
796
jjakoa7cd2492003-04-11 09:40:12 +0000797int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000798{
jjako163b4552004-12-30 15:33:58 +0000799
800 if (tun->routes) {
801 tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
802 }
803
jjako52c24142002-12-16 13:33:51 +0000804 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000805 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000806 }
jjakoa7cd2492003-04-11 09:40:12 +0000807
jjakoec89e9f2004-01-10 06:38:43 +0000808 /* TODO: For solaris we need to unlink streams */
809
jjako52c24142002-12-16 13:33:51 +0000810 free(tun);
811 return 0;
812}
813
814
jjakoa7cd2492003-04-11 09:40:12 +0000815int tun_set_cb_ind(struct tun_t *this,
816 int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
817 this->cb_ind = cb_ind;
818 return 0;
819}
820
821
822int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000823{
jjakoc6762cf2004-04-28 14:52:58 +0000824
jjako0fe0df02004-09-17 11:30:40 +0000825#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000826
jjakoa7cd2492003-04-11 09:40:12 +0000827 unsigned char buffer[PACKET_MAX];
828 int status;
829
830 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
831 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
832 return -1;
833 }
834
835 if (this->cb_ind)
836 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000837
jjakoa7cd2492003-04-11 09:40:12 +0000838 return 0;
jjakoc6762cf2004-04-28 14:52:58 +0000839
840#elif defined (__sun__)
841
842 unsigned char buffer[PACKET_MAX];
843 struct strbuf sbuf;
844 int f = 0;
845
846 sbuf.maxlen = PACKET_MAX;
847 sbuf.buf = buffer;
848 if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
849 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed");
850 return -1;
851 }
852
853 if (this->cb_ind)
854 return this->cb_ind(this, buffer, sbuf.len);
855
856 return 0;
857
858#endif
859
jjako52c24142002-12-16 13:33:51 +0000860}
861
jjakoc6762cf2004-04-28 14:52:58 +0000862
jjako52c24142002-12-16 13:33:51 +0000863int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
864{
jjakoc6762cf2004-04-28 14:52:58 +0000865
jjako0fe0df02004-09-17 11:30:40 +0000866#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000867
jjakoa7cd2492003-04-11 09:40:12 +0000868 return write(tun->fd, pack, len);
jjakoc6762cf2004-04-28 14:52:58 +0000869
870#elif defined (__sun__)
871
872 struct strbuf sbuf;
873 sbuf.len = len;
874 sbuf.buf = pack;
875 return putmsg(tun->fd, NULL, &sbuf, 0);
876
877#endif
jjakoa7cd2492003-04-11 09:40:12 +0000878}
879
880int tun_runscript(struct tun_t *tun, char* script) {
881
882 char buf[TUN_SCRIPTSIZE];
883 char snet[TUN_ADDRSIZE];
884 char smask[TUN_ADDRSIZE];
885
886 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
887 snet[sizeof(snet)-1] = 0;
888 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
889 smask[sizeof(smask)-1] = 0;
890
891 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
892 snprintf(buf, sizeof(buf), "%s %s %s %s",
893 script, tun->devname, snet, smask);
894 buf[sizeof(buf)-1] = 0;
895 system(buf);
896 return 0;
jjako52c24142002-12-16 13:33:51 +0000897}