blob: 3436972bd1f4d70cca152bcfe8c453a11660ad41 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
jjakoa7cd2492003-04-11 09:40:12 +00002 * TUN interface functions.
3 * Copyright (C) 2002, 2003 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 *
jjakoa7cd2492003-04-11 09:40:12 +000010 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
jjako52c24142002-12-16 13:33:51 +000012 *
jjakoa7cd2492003-04-11 09:40:12 +000013 * Contributor(s):
jjako52c24142002-12-16 13:33:51 +000014 *
15 */
16
17/*
jjakoa7cd2492003-04-11 09:40:12 +000018 * tun.c: Contains all TUN functionality. Is able to handle multiple
19 * tunnels in the same program. Each tunnel is identified by the struct,
20 * which is passed to functions.
jjako52c24142002-12-16 13:33:51 +000021 *
jjako52c24142002-12-16 13:33:51 +000022 */
23
24
25#include <syslog.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <unistd.h>
35#include <string.h>
36#include <errno.h>
37#include <fcntl.h>
38
39#include <stdio.h>
40#include <fcntl.h>
41#include <unistd.h>
42#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000043#include <sys/ioctl.h>
44#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000045#include <errno.h>
jjakoa7cd2492003-04-11 09:40:12 +000046#include <net/route.h>
jjako52c24142002-12-16 13:33:51 +000047
jjako409b8552004-02-04 22:57:41 +000048#if defined(__linux__)
jjako0141d202004-01-09 15:19:20 +000049#include <linux/if.h>
50#include <linux/if_tun.h>
jjakoa7cd2492003-04-11 09:40:12 +000051#include <linux/netlink.h>
52#include <linux/rtnetlink.h>
jjako409b8552004-02-04 22:57:41 +000053
54#elif defined (__FreeBSD__)
55#include <net/if.h>
56#include <net/if_tun.h>
57
jjako0141d202004-01-09 15:19:20 +000058#elif defined (__sun__)
jjakoec89e9f2004-01-10 06:38:43 +000059#include <stropts.h>
60#include <sys/sockio.h>
61#include <net/if.h>
jjako0141d202004-01-09 15:19:20 +000062#include <net/if_tun.h>
jjakoec89e9f2004-01-10 06:38:43 +000063/*#include "sun_if_tun.h"*/
jjako409b8552004-02-04 22:57:41 +000064
65#else
66#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +000067#endif
68
jjako52c24142002-12-16 13:33:51 +000069
70#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000071#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000072
73
jjako409b8552004-02-04 22:57:41 +000074#if defined(__linux__)
75
jjakoa7cd2492003-04-11 09:40:12 +000076int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000077{
jjakoa7cd2492003-04-11 09:40:12 +000078 int len = RTA_LENGTH(dlen);
79 int alen = NLMSG_ALIGN(n->nlmsg_len);
80 struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
81 if (alen + len > nsize)
82 return -1;
83 rta->rta_len = len;
84 rta->rta_type = type;
85 memcpy(RTA_DATA(rta), d, dlen);
86 n->nlmsg_len = alen + len;
87 return 0;
88}
89
90int tun_gifindex(struct tun_t *this, int *index) {
jjako52c24142002-12-16 13:33:51 +000091 struct ifreq ifr;
jjakoa7cd2492003-04-11 09:40:12 +000092 int fd;
jjako52c24142002-12-16 13:33:51 +000093
jjakoa7cd2492003-04-11 09:40:12 +000094 memset (&ifr, '\0', sizeof (ifr));
95 ifr.ifr_addr.sa_family = AF_INET;
96 ifr.ifr_dstaddr.sa_family = AF_INET;
97 ifr.ifr_netmask.sa_family = AF_INET;
98 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
99 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
100 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
101 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
102 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000103 }
jjakoa7cd2492003-04-11 09:40:12 +0000104 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
105 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
106 "ioctl() failed");
107 close(fd);
108 return -1;
109 }
110 close(fd);
111 *index = ifr.ifr_ifindex;
112 return 0;
113}
jjakoec89e9f2004-01-10 06:38:43 +0000114#endif
jjako52c24142002-12-16 13:33:51 +0000115
jjakoa7cd2492003-04-11 09:40:12 +0000116int tun_sifflags(struct tun_t *this, int flags) {
117 struct ifreq ifr;
118 int fd;
119
120 memset (&ifr, '\0', sizeof (ifr));
121 ifr.ifr_flags = flags;
122 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
123 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
124 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
125 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
126 "socket() failed");
127 }
128 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
129 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
130 "ioctl(SIOCSIFFLAGS) failed");
131 close(fd);
132 return -1;
133 }
134 close(fd);
135 return 0;
136}
137
138
jjako0141d202004-01-09 15:19:20 +0000139/* Currently unused
jjakoa7cd2492003-04-11 09:40:12 +0000140int tun_addroute2(struct tun_t *this,
141 struct in_addr *dst,
142 struct in_addr *gateway,
143 struct in_addr *mask) {
144
145 struct {
146 struct nlmsghdr n;
147 struct rtmsg r;
148 char buf[TUN_NLBUFSIZE];
149 } req;
150
151 struct sockaddr_nl local;
152 int addr_len;
153 int fd;
154 int status;
155 struct sockaddr_nl nladdr;
156 struct iovec iov;
157 struct msghdr msg;
158
159 memset(&req, 0, sizeof(req));
160 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
161 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
162 req.n.nlmsg_type = RTM_NEWROUTE;
163 req.r.rtm_family = AF_INET;
164 req.r.rtm_table = RT_TABLE_MAIN;
165 req.r.rtm_protocol = RTPROT_BOOT;
166 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
167 req.r.rtm_type = RTN_UNICAST;
168 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
169 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
170
171 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
172 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
173 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000174 return -1;
175 }
176
jjakoa7cd2492003-04-11 09:40:12 +0000177 memset(&local, 0, sizeof(local));
178 local.nl_family = AF_NETLINK;
179 local.nl_groups = 0;
180
181 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
182 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
183 "bind() failed");
184 close(fd);
185 return -1;
186 }
187
188 addr_len = sizeof(local);
189 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
190 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
191 "getsockname() failed");
192 close(fd);
193 return -1;
194 }
195
196 if (addr_len != sizeof(local)) {
197 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
198 "Wrong address length %d", addr_len);
199 close(fd);
200 return -1;
201 }
202
203 if (local.nl_family != AF_NETLINK) {
204 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
205 "Wrong address family %d", local.nl_family);
206 close(fd);
207 return -1;
208 }
209
210 iov.iov_base = (void*)&req.n;
211 iov.iov_len = req.n.nlmsg_len;
212
213 msg.msg_name = (void*)&nladdr;
214 msg.msg_namelen = sizeof(nladdr),
215 msg.msg_iov = &iov;
216 msg.msg_iovlen = 1;
217 msg.msg_control = NULL;
218 msg.msg_controllen = 0;
219 msg.msg_flags = 0;
220
221 memset(&nladdr, 0, sizeof(nladdr));
222 nladdr.nl_family = AF_NETLINK;
223 nladdr.nl_pid = 0;
224 nladdr.nl_groups = 0;
225
226 req.n.nlmsg_seq = 0;
227 req.n.nlmsg_flags |= NLM_F_ACK;
228
jjako0141d202004-01-09 15:19:20 +0000229 status = sendmsg(fd, &msg, 0); * TODO: Error check *
jjakoa7cd2492003-04-11 09:40:12 +0000230 close(fd);
231 return 0;
232}
jjako0141d202004-01-09 15:19:20 +0000233*/
jjakoa7cd2492003-04-11 09:40:12 +0000234
235int tun_addaddr(struct tun_t *this,
236 struct in_addr *addr,
237 struct in_addr *dstaddr,
238 struct in_addr *netmask) {
jjako0141d202004-01-09 15:19:20 +0000239
jjako409b8552004-02-04 22:57:41 +0000240#if defined(__linux__)
jjakoa7cd2492003-04-11 09:40:12 +0000241 struct {
242 struct nlmsghdr n;
243 struct ifaddrmsg i;
244 char buf[TUN_NLBUFSIZE];
245 } req;
246
247 struct sockaddr_nl local;
248 int addr_len;
249 int fd;
250 int status;
jjako409b8552004-02-04 22:57:41 +0000251
jjakoa7cd2492003-04-11 09:40:12 +0000252 struct sockaddr_nl nladdr;
253 struct iovec iov;
254 struct msghdr msg;
255
256 if (!this->addrs) /* Use ioctl for first addr to make ping work */
257 return tun_setaddr(this, addr, dstaddr, netmask);
258
259 memset(&req, 0, sizeof(req));
260 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
261 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
262 req.n.nlmsg_type = RTM_NEWADDR;
263 req.i.ifa_family = AF_INET;
264 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
265 req.i.ifa_flags = 0;
266 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
267 if (tun_gifindex(this, &req.i.ifa_index)) {
268 return -1;
269 }
270
271 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
272 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
273
274 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
275 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
276 "socket() failed");
277 return -1;
278 }
279
280 memset(&local, 0, sizeof(local));
281 local.nl_family = AF_NETLINK;
282 local.nl_groups = 0;
283
284 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
285 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
286 "bind() failed");
287 close(fd);
288 return -1;
289 }
290
291 addr_len = sizeof(local);
292 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
293 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
294 "getsockname() failed");
295 close(fd);
296 return -1;
297 }
298
299 if (addr_len != sizeof(local)) {
300 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
301 "Wrong address length %d", addr_len);
302 close(fd);
303 return -1;
304 }
305
306 if (local.nl_family != AF_NETLINK) {
307 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
308 "Wrong address family %d", local.nl_family);
309 close(fd);
310 return -1;
311 }
312
313 iov.iov_base = (void*)&req.n;
314 iov.iov_len = req.n.nlmsg_len;
315
316 msg.msg_name = (void*)&nladdr;
317 msg.msg_namelen = sizeof(nladdr),
318 msg.msg_iov = &iov;
319 msg.msg_iovlen = 1;
320 msg.msg_control = NULL;
321 msg.msg_controllen = 0;
322 msg.msg_flags = 0;
323
324 memset(&nladdr, 0, sizeof(nladdr));
325 nladdr.nl_family = AF_NETLINK;
326 nladdr.nl_pid = 0;
327 nladdr.nl_groups = 0;
328
329 req.n.nlmsg_seq = 0;
330 req.n.nlmsg_flags |= NLM_F_ACK;
331
332 status = sendmsg(fd, &msg, 0); /* TODO Error check */
333
jjako409b8552004-02-04 22:57:41 +0000334 tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
jjakoa7cd2492003-04-11 09:40:12 +0000335 close(fd);
336 this->addrs++;
337 return 0;
jjako409b8552004-02-04 22:57:41 +0000338
339#elif defined (__FreeBSD__)
340
341 int fd;
342 struct ifaliasreq areq;
343
344 /* TODO: Is this needed on FreeBSD? */
345 if (!this->addrs) /* Use ioctl for first addr to make ping work */
jjako1f158642004-02-05 20:39:57 +0000346 return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
jjako409b8552004-02-04 22:57:41 +0000347
348 memset(&areq, 0, sizeof(areq));
349
350 /* Set up interface name */
351 strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
jjako1f158642004-02-05 20:39:57 +0000352 areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
jjako409b8552004-02-04 22:57:41 +0000353
jjako1f158642004-02-05 20:39:57 +0000354 ((struct sockaddr_in*) &areq.ifra_addr)->sin_family = AF_INET;
355 ((struct sockaddr_in*) &areq.ifra_addr)->sin_len = sizeof(areq.ifra_addr);
356 ((struct sockaddr_in*) &areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000357
jjako1f158642004-02-05 20:39:57 +0000358 ((struct sockaddr_in*) &areq.ifra_mask)->sin_family = AF_INET;
359 ((struct sockaddr_in*) &areq.ifra_mask)->sin_len = sizeof(areq.ifra_mask);
360 ((struct sockaddr_in*) &areq.ifra_mask)->sin_addr.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000361
jjako1f158642004-02-05 20:39:57 +0000362 /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
363 ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_family = AF_INET;
364 ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_len =
365 sizeof(areq.ifra_broadaddr);
366 ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_addr.s_addr =
367 dstaddr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000368
369 /* Create a channel to the NET kernel. */
370 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
371 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
372 "socket() failed");
373 return -1;
374 }
375
376 if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
377 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
378 "ioctl(SIOCAIFADDR) failed");
379 close(fd);
380 return -1;
381 }
382
383 close(fd);
384 this->addrs++;
385 return 0;
386
387#elif defined (__sun__)
388
389 if (!this->addrs) /* Use ioctl for first addr to make ping work */
390 return tun_setaddr(this, addr, dstaddr, netmask);
391
392 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
393 "Setting multiple addresses not possible on Solaris");
394 return -1;
395
396#else
397#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +0000398#endif
jjako409b8552004-02-04 22:57:41 +0000399
jjakoa7cd2492003-04-11 09:40:12 +0000400}
401
402
403int tun_setaddr(struct tun_t *this,
404 struct in_addr *addr,
405 struct in_addr *dstaddr,
406 struct in_addr *netmask)
407{
408 struct ifreq ifr;
409 int fd;
410
411 memset (&ifr, '\0', sizeof (ifr));
412 ifr.ifr_addr.sa_family = AF_INET;
413 ifr.ifr_dstaddr.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000414
415#if defined(__linux__)
jjakoa7cd2492003-04-11 09:40:12 +0000416 ifr.ifr_netmask.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000417
418#elif defined(__FreeBSD__)
jjako243bfe62004-01-26 23:06:05 +0000419 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_len =
420 sizeof (struct sockaddr_in);
421 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len =
422 sizeof (struct sockaddr_in);
423#endif
jjako409b8552004-02-04 22:57:41 +0000424
jjakoa7cd2492003-04-11 09:40:12 +0000425 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
426 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
427
428 /* Create a channel to the NET kernel. */
429 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
430 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
431 "socket() failed");
432 return -1;
433 }
434
435 if (addr) { /* Set the interface address */
436 this->addr.s_addr = addr->s_addr;
437 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
438 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
439 if (errno != EEXIST) {
440 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
441 "ioctl(SIOCSIFADDR) failed");
442 }
443 else {
444 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
445 "ioctl(SIOCSIFADDR): Address already exists");
446 }
447 close(fd);
448 return -1;
449 }
450 }
451
452 if (dstaddr) { /* Set the destination address */
453 this->dstaddr.s_addr = dstaddr->s_addr;
454 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
455 dstaddr->s_addr;
456 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
457 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
458 "ioctl(SIOCSIFDSTADDR) failed");
459 close(fd);
460 return -1;
461 }
462 }
463
464 if (netmask) { /* Set the netmask */
465 this->netmask.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000466#if defined(__linux__)
467 ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
jjako243bfe62004-01-26 23:06:05 +0000468 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000469
jjako243bfe62004-01-26 23:06:05 +0000470#elif defined(__FreeBSD__)
471 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
472 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000473
474#elif defined(__sun__)
475 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
jjakoa7cd2492003-04-11 09:40:12 +0000476 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000477#else
478#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000479#endif
jjako409b8552004-02-04 22:57:41 +0000480
jjakoa7cd2492003-04-11 09:40:12 +0000481 if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
482 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
483 "ioctl(SIOCSIFNETMASK) failed");
484 close(fd);
485 return -1;
486 }
487 }
jjako409b8552004-02-04 22:57:41 +0000488
jjakoa7cd2492003-04-11 09:40:12 +0000489 close(fd);
490 this->addrs++;
jjako409b8552004-02-04 22:57:41 +0000491
jjako1ea66342004-01-28 09:27:34 +0000492 /* On linux the route to the interface is set automatically
493 on FreeBSD we have to do this manually */
494
jjako409b8552004-02-04 22:57:41 +0000495 /* TODO: How does it work on Solaris? */
496
jjako1ea66342004-01-28 09:27:34 +0000497#if defined(__FreeBSD__)
498 tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
499 return tun_addroute(this, addr, addr, netmask);
500#else
501 return tun_sifflags(this, IFF_UP | IFF_RUNNING);
502#endif
503
jjakoa7cd2492003-04-11 09:40:12 +0000504}
505
506int tun_addroute(struct tun_t *this,
507 struct in_addr *dst,
508 struct in_addr *gateway,
509 struct in_addr *mask)
510{
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;
536
537 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
538 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
539 "ioctl(SIOCADDRT) failed");
540 close(fd);
541 return -1;
542 }
543 close(fd);
jjako409b8552004-02-04 22:57:41 +0000544 return 0;
jjakoec89e9f2004-01-10 06:38:43 +0000545
jjako1ea66342004-01-28 09:27:34 +0000546#elif defined(__FreeBSD__)
547
548struct {
549 struct rt_msghdr rt;
550 struct sockaddr_in dst;
551 struct sockaddr_in gate;
552 struct sockaddr_in mask;
553} req;
554
555 int fd;
556 struct rt_msghdr *rtm;
557
558 if((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
559 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
560 "socket() failed");
561 return -1;
562 }
563
564 memset(&req, 0x00, sizeof(req));
565
566 rtm = &req.rt;
567
568 rtm->rtm_msglen = sizeof(req);
569 rtm->rtm_version = RTM_VERSION;
570 rtm->rtm_type = RTM_ADD;
571 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
572 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
573 rtm->rtm_pid = getpid();
574 rtm->rtm_seq = 0044; /* TODO */
575
576 req.dst.sin_family = AF_INET;
577 req.dst.sin_len = sizeof(req.dst);
578 req.mask.sin_family = AF_INET;
579 req.mask.sin_len = sizeof(req.mask);
580 req.gate.sin_family = AF_INET;
581 req.gate.sin_len = sizeof(req.gate);
582
583 req.dst.sin_addr.s_addr = dst->s_addr;
584 req.mask.sin_addr.s_addr = mask->s_addr;
585 req.gate.sin_addr.s_addr = gateway->s_addr;
586
587 if(write(fd, rtm, rtm->rtm_msglen) < 0) {
588 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
589 "write() failed");
590 close(fd);
591 return -1;
592 }
593 close(fd);
jjako409b8552004-02-04 22:57:41 +0000594 return 0;
jjako1ea66342004-01-28 09:27:34 +0000595
jjako409b8552004-02-04 22:57:41 +0000596#elif defined(__sun__)
597 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
598 "Could not set up routing on Solaris. Please add route manually.");
599 return 0;
600
601#else
602#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000603#endif
604
jjakoa7cd2492003-04-11 09:40:12 +0000605}
606
jjakoa7cd2492003-04-11 09:40:12 +0000607int tun_new(struct tun_t **tun)
608{
jjakoec89e9f2004-01-10 06:38:43 +0000609
jjako409b8552004-02-04 22:57:41 +0000610#if defined(__linux__)
611 struct ifreq ifr;
612
jjako243bfe62004-01-26 23:06:05 +0000613#elif defined(__FreeBSD__)
614 char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
615 int devnum;
jjako1f158642004-02-05 20:39:57 +0000616 struct ifaliasreq areq;
617 int fd;
jjako409b8552004-02-04 22:57:41 +0000618
619#elif defined(__sun__)
620 int if_fd, ppa = -1;
621 static int ip_fd = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000622 int muxid;
623 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000624
jjako06e9f122004-01-19 18:37:58 +0000625#else
jjako409b8552004-02-04 22:57:41 +0000626#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000627#endif
jjakoa7cd2492003-04-11 09:40:12 +0000628
629 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
630 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
631 return EOF;
632 }
633
634 (*tun)->cb_ind = NULL;
635 (*tun)->addrs = 0;
jjako409b8552004-02-04 22:57:41 +0000636
637#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000638 /* Open the actual tun device */
jjakoa7cd2492003-04-11 09:40:12 +0000639 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
640 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
641 return -1;
642 }
jjako409b8552004-02-04 22:57:41 +0000643
jjakoec89e9f2004-01-10 06:38:43 +0000644 /* Set device flags. For some weird reason this is also the method
645 used to obtain the network interface name */
jjako52c24142002-12-16 13:33:51 +0000646 memset(&ifr, 0, sizeof(ifr));
647 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
jjako52c24142002-12-16 13:33:51 +0000648 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000649 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000650 close((*tun)->fd);
651 return -1;
652 }
jjako409b8552004-02-04 22:57:41 +0000653
jjako52c24142002-12-16 13:33:51 +0000654 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000655 (*tun)->devname[IFNAMSIZ] = 0;
jjako409b8552004-02-04 22:57:41 +0000656
jjakoec89e9f2004-01-10 06:38:43 +0000657 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
jjako409b8552004-02-04 22:57:41 +0000658 return 0;
659
660#elif defined(__FreeBSD__)
jjakoec89e9f2004-01-10 06:38:43 +0000661
jjako409b8552004-02-04 22:57:41 +0000662 /* Find suitable device */
663 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
664 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
665 devname[sizeof(devname)] = 0;
666 if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
667 if (errno != EBUSY) break;
668 }
669 if ((*tun)->fd < 0) {
670 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
671 return -1;
672 }
jjakoec89e9f2004-01-10 06:38:43 +0000673
jjako409b8552004-02-04 22:57:41 +0000674 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
675 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjako1f158642004-02-05 20:39:57 +0000676
677 /* The tun device we found might have "old" IP addresses allocated */
678 /* We need to delete those. This problem is not present on Linux */
679
680 memset(&areq, 0, sizeof(areq));
681
682 /* Set up interface name */
683 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
684 areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
685
686 /* Create a channel to the NET kernel. */
687 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
688 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
689 "socket() failed");
690 return -1;
691 }
692
693 /* Delete any IP addresses until SIOCDIFADDR fails */
694 while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
695
696 close(fd);
jjako409b8552004-02-04 22:57:41 +0000697 return 0;
698
699#elif defined(__sun__)
jjakoec89e9f2004-01-10 06:38:43 +0000700
jjakoc6762cf2004-04-28 14:52:58 +0000701 if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
702 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp");
jjakoec89e9f2004-01-10 06:38:43 +0000703 return -1;
704 }
705
706 if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
707 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
708 return -1;
709 }
710
711 /* Assign a new PPA and get its unit number. */
712 if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000713 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface");
jjakoec89e9f2004-01-10 06:38:43 +0000714 return -1;
715 }
716
717 if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000718 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)");
jjakoec89e9f2004-01-10 06:38:43 +0000719 return -1;
720 }
721 if(ioctl(if_fd, I_PUSH, "ip") < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000722 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module");
jjakoec89e9f2004-01-10 06:38:43 +0000723 return -1;
724 }
725
726 /* Assign ppa according to the unit number returned by tun device */
727 if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000728 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa);
jjakoec89e9f2004-01-10 06:38:43 +0000729 return -1;
730 }
731
732 /* Link the two streams */
jjakoc6762cf2004-04-28 14:52:58 +0000733 if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
734 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't link TUN device to IP");
jjakoec89e9f2004-01-10 06:38:43 +0000735 return -1;
736 }
737
738 close (if_fd);
739
jjako243bfe62004-01-26 23:06:05 +0000740 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
741 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000742
743 memset(&ifr, 0, sizeof(ifr));
744 strcpy(ifr.ifr_name, (*tun)->devname);
745 ifr.ifr_ip_muxid = muxid;
746
747 if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
748 ioctl(ip_fd, I_PUNLINK, muxid);
749 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set multiplexor id");
750 return -1;
751 }
752
753 /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
754 msg (M_ERR, "Set file descriptor to non-blocking failed"); */
755
jjakoa7cd2492003-04-11 09:40:12 +0000756 return 0;
jjako409b8552004-02-04 22:57:41 +0000757
758#else
759#error "Unknown platform!"
760#endif
761
jjako52c24142002-12-16 13:33:51 +0000762}
763
jjakoa7cd2492003-04-11 09:40:12 +0000764int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000765{
766 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000767 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000768 }
jjakoa7cd2492003-04-11 09:40:12 +0000769
jjakoec89e9f2004-01-10 06:38:43 +0000770 /* TODO: For solaris we need to unlink streams */
771
jjako52c24142002-12-16 13:33:51 +0000772 free(tun);
773 return 0;
774}
775
776
jjakoa7cd2492003-04-11 09:40:12 +0000777int tun_set_cb_ind(struct tun_t *this,
778 int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
779 this->cb_ind = cb_ind;
780 return 0;
781}
782
783
784int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000785{
jjakoc6762cf2004-04-28 14:52:58 +0000786
787#if defined(__linux__) || defined (__FreeBSD__)
788
jjakoa7cd2492003-04-11 09:40:12 +0000789 unsigned char buffer[PACKET_MAX];
790 int status;
791
792 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
793 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
794 return -1;
795 }
796
797 if (this->cb_ind)
798 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000799
jjakoa7cd2492003-04-11 09:40:12 +0000800 return 0;
jjakoc6762cf2004-04-28 14:52:58 +0000801
802#elif defined (__sun__)
803
804 unsigned char buffer[PACKET_MAX];
805 struct strbuf sbuf;
806 int f = 0;
807
808 sbuf.maxlen = PACKET_MAX;
809 sbuf.buf = buffer;
810 if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
811 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed");
812 return -1;
813 }
814
815 if (this->cb_ind)
816 return this->cb_ind(this, buffer, sbuf.len);
817
818 return 0;
819
820#endif
821
jjako52c24142002-12-16 13:33:51 +0000822}
823
jjakoc6762cf2004-04-28 14:52:58 +0000824
jjako52c24142002-12-16 13:33:51 +0000825int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
826{
jjakoc6762cf2004-04-28 14:52:58 +0000827
828#if defined(__linux__) || defined (__FreeBSD__)
829
jjakoa7cd2492003-04-11 09:40:12 +0000830 return write(tun->fd, pack, len);
jjakoc6762cf2004-04-28 14:52:58 +0000831
832#elif defined (__sun__)
833
834 struct strbuf sbuf;
835 sbuf.len = len;
836 sbuf.buf = pack;
837 return putmsg(tun->fd, NULL, &sbuf, 0);
838
839#endif
jjakoa7cd2492003-04-11 09:40:12 +0000840}
841
842int tun_runscript(struct tun_t *tun, char* script) {
843
844 char buf[TUN_SCRIPTSIZE];
845 char snet[TUN_ADDRSIZE];
846 char smask[TUN_ADDRSIZE];
847
848 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
849 snet[sizeof(snet)-1] = 0;
850 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
851 smask[sizeof(smask)-1] = 0;
852
853 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
854 snprintf(buf, sizeof(buf), "%s %s %s %s",
855 script, tun->devname, snet, smask);
856 buf[sizeof(buf)-1] = 0;
857 system(buf);
858 return 0;
jjako52c24142002-12-16 13:33:51 +0000859}