blob: a19fd5bed53d44cd8e5dd805f5c885a6add70ed2 [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
jjako0141d202004-01-09 15:19:20 +000048#ifdef __linux__
49#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>
jjako0141d202004-01-09 15:19:20 +000053#elif defined (__sun__)
jjakoec89e9f2004-01-10 06:38:43 +000054#include <stropts.h>
55#include <sys/sockio.h>
56#include <net/if.h>
jjako0141d202004-01-09 15:19:20 +000057#include <net/if_tun.h>
jjakoec89e9f2004-01-10 06:38:43 +000058/*#include "sun_if_tun.h"*/
jjako06e9f122004-01-19 18:37:58 +000059#elif defined (__FreeBSD__)
60#include <net/if.h>
61#include <net/if_tun.h>
jjako0141d202004-01-09 15:19:20 +000062#endif
63
jjako52c24142002-12-16 13:33:51 +000064
65#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000066#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000067
68
jjako0141d202004-01-09 15:19:20 +000069#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +000070int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000071{
jjakoa7cd2492003-04-11 09:40:12 +000072 int len = RTA_LENGTH(dlen);
73 int alen = NLMSG_ALIGN(n->nlmsg_len);
74 struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
75 if (alen + len > nsize)
76 return -1;
77 rta->rta_len = len;
78 rta->rta_type = type;
79 memcpy(RTA_DATA(rta), d, dlen);
80 n->nlmsg_len = alen + len;
81 return 0;
82}
83
84int tun_gifindex(struct tun_t *this, int *index) {
jjako52c24142002-12-16 13:33:51 +000085 struct ifreq ifr;
jjakoa7cd2492003-04-11 09:40:12 +000086 int fd;
jjako52c24142002-12-16 13:33:51 +000087
jjakoa7cd2492003-04-11 09:40:12 +000088 memset (&ifr, '\0', sizeof (ifr));
89 ifr.ifr_addr.sa_family = AF_INET;
90 ifr.ifr_dstaddr.sa_family = AF_INET;
91 ifr.ifr_netmask.sa_family = AF_INET;
92 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
93 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
94 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
95 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
96 "socket() failed");
jjako52c24142002-12-16 13:33:51 +000097 }
jjakoa7cd2492003-04-11 09:40:12 +000098 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
99 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
100 "ioctl() failed");
101 close(fd);
102 return -1;
103 }
104 close(fd);
105 *index = ifr.ifr_ifindex;
106 return 0;
107}
jjakoec89e9f2004-01-10 06:38:43 +0000108#endif
jjako52c24142002-12-16 13:33:51 +0000109
jjakoa7cd2492003-04-11 09:40:12 +0000110int tun_sifflags(struct tun_t *this, int flags) {
111 struct ifreq ifr;
112 int fd;
113
114 memset (&ifr, '\0', sizeof (ifr));
115 ifr.ifr_flags = flags;
116 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
117 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
118 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
119 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
120 "socket() failed");
121 }
122 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
123 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
124 "ioctl(SIOCSIFFLAGS) failed");
125 close(fd);
126 return -1;
127 }
128 close(fd);
129 return 0;
130}
131
132
jjako0141d202004-01-09 15:19:20 +0000133/* Currently unused
jjakoa7cd2492003-04-11 09:40:12 +0000134int tun_addroute2(struct tun_t *this,
135 struct in_addr *dst,
136 struct in_addr *gateway,
137 struct in_addr *mask) {
138
139 struct {
140 struct nlmsghdr n;
141 struct rtmsg r;
142 char buf[TUN_NLBUFSIZE];
143 } req;
144
145 struct sockaddr_nl local;
146 int addr_len;
147 int fd;
148 int status;
149 struct sockaddr_nl nladdr;
150 struct iovec iov;
151 struct msghdr msg;
152
153 memset(&req, 0, sizeof(req));
154 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
155 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
156 req.n.nlmsg_type = RTM_NEWROUTE;
157 req.r.rtm_family = AF_INET;
158 req.r.rtm_table = RT_TABLE_MAIN;
159 req.r.rtm_protocol = RTPROT_BOOT;
160 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
161 req.r.rtm_type = RTN_UNICAST;
162 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
163 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
164
165 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
166 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
167 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000168 return -1;
169 }
170
jjakoa7cd2492003-04-11 09:40:12 +0000171 memset(&local, 0, sizeof(local));
172 local.nl_family = AF_NETLINK;
173 local.nl_groups = 0;
174
175 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
176 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
177 "bind() failed");
178 close(fd);
179 return -1;
180 }
181
182 addr_len = sizeof(local);
183 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
184 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
185 "getsockname() failed");
186 close(fd);
187 return -1;
188 }
189
190 if (addr_len != sizeof(local)) {
191 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
192 "Wrong address length %d", addr_len);
193 close(fd);
194 return -1;
195 }
196
197 if (local.nl_family != AF_NETLINK) {
198 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
199 "Wrong address family %d", local.nl_family);
200 close(fd);
201 return -1;
202 }
203
204 iov.iov_base = (void*)&req.n;
205 iov.iov_len = req.n.nlmsg_len;
206
207 msg.msg_name = (void*)&nladdr;
208 msg.msg_namelen = sizeof(nladdr),
209 msg.msg_iov = &iov;
210 msg.msg_iovlen = 1;
211 msg.msg_control = NULL;
212 msg.msg_controllen = 0;
213 msg.msg_flags = 0;
214
215 memset(&nladdr, 0, sizeof(nladdr));
216 nladdr.nl_family = AF_NETLINK;
217 nladdr.nl_pid = 0;
218 nladdr.nl_groups = 0;
219
220 req.n.nlmsg_seq = 0;
221 req.n.nlmsg_flags |= NLM_F_ACK;
222
jjako0141d202004-01-09 15:19:20 +0000223 status = sendmsg(fd, &msg, 0); * TODO: Error check *
jjakoa7cd2492003-04-11 09:40:12 +0000224 close(fd);
225 return 0;
226}
jjako0141d202004-01-09 15:19:20 +0000227*/
jjakoa7cd2492003-04-11 09:40:12 +0000228
229int tun_addaddr(struct tun_t *this,
230 struct in_addr *addr,
231 struct in_addr *dstaddr,
232 struct in_addr *netmask) {
jjako0141d202004-01-09 15:19:20 +0000233
234#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +0000235 struct {
236 struct nlmsghdr n;
237 struct ifaddrmsg i;
238 char buf[TUN_NLBUFSIZE];
239 } req;
240
241 struct sockaddr_nl local;
242 int addr_len;
243 int fd;
244 int status;
245
246 struct sockaddr_nl nladdr;
247 struct iovec iov;
248 struct msghdr msg;
jjako0141d202004-01-09 15:19:20 +0000249#endif
jjakoa7cd2492003-04-11 09:40:12 +0000250
251 if (!this->addrs) /* Use ioctl for first addr to make ping work */
252 return tun_setaddr(this, addr, dstaddr, netmask);
253
jjako0141d202004-01-09 15:19:20 +0000254#ifndef __linux__
255 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
256 "Setting multiple addresses only possible on linux");
257 return -1;
258#else
jjakoa7cd2492003-04-11 09:40:12 +0000259 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
334 tun_sifflags(this, IFF_UP | IFF_RUNNING);
335 close(fd);
336 this->addrs++;
337 return 0;
jjako0141d202004-01-09 15:19:20 +0000338#endif
jjakoa7cd2492003-04-11 09:40:12 +0000339}
340
341
342int tun_setaddr(struct tun_t *this,
343 struct in_addr *addr,
344 struct in_addr *dstaddr,
345 struct in_addr *netmask)
346{
347 struct ifreq ifr;
348 int fd;
349
350 memset (&ifr, '\0', sizeof (ifr));
351 ifr.ifr_addr.sa_family = AF_INET;
352 ifr.ifr_dstaddr.sa_family = AF_INET;
jjako06e9f122004-01-19 18:37:58 +0000353#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +0000354 ifr.ifr_netmask.sa_family = AF_INET;
jjakoec89e9f2004-01-10 06:38:43 +0000355#endif
jjako243bfe62004-01-26 23:06:05 +0000356#ifdef __FreeBSD__
357 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_len =
358 sizeof (struct sockaddr_in);
359 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len =
360 sizeof (struct sockaddr_in);
361#endif
jjakoa7cd2492003-04-11 09:40:12 +0000362 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
363 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
364
365 /* Create a channel to the NET kernel. */
366 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
367 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
368 "socket() failed");
369 return -1;
370 }
371
372 if (addr) { /* Set the interface address */
373 this->addr.s_addr = addr->s_addr;
374 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
375 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
376 if (errno != EEXIST) {
377 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
378 "ioctl(SIOCSIFADDR) failed");
379 }
380 else {
381 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
382 "ioctl(SIOCSIFADDR): Address already exists");
383 }
384 close(fd);
385 return -1;
386 }
387 }
388
389 if (dstaddr) { /* Set the destination address */
390 this->dstaddr.s_addr = dstaddr->s_addr;
391 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
392 dstaddr->s_addr;
393 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
394 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
395 "ioctl(SIOCSIFDSTADDR) failed");
396 close(fd);
397 return -1;
398 }
399 }
400
401 if (netmask) { /* Set the netmask */
402 this->netmask.s_addr = netmask->s_addr;
jjako243bfe62004-01-26 23:06:05 +0000403#if defined(__sun__)
404 /* TODO: This should probably be ifr_addr */
jjakoec89e9f2004-01-10 06:38:43 +0000405 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
jjako243bfe62004-01-26 23:06:05 +0000406 netmask->s_addr;
407#elif defined(__FreeBSD__)
408 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr =
409 netmask->s_addr;
jjakoec89e9f2004-01-10 06:38:43 +0000410#else
jjakoa7cd2492003-04-11 09:40:12 +0000411 ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
412 netmask->s_addr;
jjakoec89e9f2004-01-10 06:38:43 +0000413#endif
jjakoa7cd2492003-04-11 09:40:12 +0000414 if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
415 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
416 "ioctl(SIOCSIFNETMASK) failed");
417 close(fd);
418 return -1;
419 }
420 }
421
422 close(fd);
423 this->addrs++;
jjako1ea66342004-01-28 09:27:34 +0000424
425 /* On linux the route to the interface is set automatically
426 on FreeBSD we have to do this manually */
427
428#if defined(__FreeBSD__)
429 tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
430 return tun_addroute(this, addr, addr, netmask);
431#else
432 return tun_sifflags(this, IFF_UP | IFF_RUNNING);
433#endif
434
jjakoa7cd2492003-04-11 09:40:12 +0000435}
436
437int tun_addroute(struct tun_t *this,
438 struct in_addr *dst,
439 struct in_addr *gateway,
440 struct in_addr *mask)
441{
jjakoec89e9f2004-01-10 06:38:43 +0000442
jjako1ea66342004-01-28 09:27:34 +0000443
444 /* TODO: Learn how to set routing table on sun */
jjako06e9f122004-01-19 18:37:58 +0000445#ifdef __linux__
jjakoec89e9f2004-01-10 06:38:43 +0000446
jjakoa7cd2492003-04-11 09:40:12 +0000447 struct rtentry r;
448 int fd;
449
450 memset (&r, '\0', sizeof (r));
451 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
452
453 /* Create a channel to the NET kernel. */
454 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
455 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
456 "socket() failed");
457 return -1;
458 }
459
460 r.rt_dst.sa_family = AF_INET;
461 r.rt_gateway.sa_family = AF_INET;
462 r.rt_genmask.sa_family = AF_INET;
463 ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
464 ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
465 ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
466
467 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
468 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
469 "ioctl(SIOCADDRT) failed");
470 close(fd);
471 return -1;
472 }
473 close(fd);
jjakoec89e9f2004-01-10 06:38:43 +0000474
jjako1ea66342004-01-28 09:27:34 +0000475#elif defined(__FreeBSD__)
476
477struct {
478 struct rt_msghdr rt;
479 struct sockaddr_in dst;
480 struct sockaddr_in gate;
481 struct sockaddr_in mask;
482} req;
483
484 int fd;
485 struct rt_msghdr *rtm;
486
487 if((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
488 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
489 "socket() failed");
490 return -1;
491 }
492
493 memset(&req, 0x00, sizeof(req));
494
495 rtm = &req.rt;
496
497 rtm->rtm_msglen = sizeof(req);
498 rtm->rtm_version = RTM_VERSION;
499 rtm->rtm_type = RTM_ADD;
500 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
501 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
502 rtm->rtm_pid = getpid();
503 rtm->rtm_seq = 0044; /* TODO */
504
505 req.dst.sin_family = AF_INET;
506 req.dst.sin_len = sizeof(req.dst);
507 req.mask.sin_family = AF_INET;
508 req.mask.sin_len = sizeof(req.mask);
509 req.gate.sin_family = AF_INET;
510 req.gate.sin_len = sizeof(req.gate);
511
512 req.dst.sin_addr.s_addr = dst->s_addr;
513 req.mask.sin_addr.s_addr = mask->s_addr;
514 req.gate.sin_addr.s_addr = gateway->s_addr;
515
516 if(write(fd, rtm, rtm->rtm_msglen) < 0) {
517 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
518 "write() failed");
519 close(fd);
520 return -1;
521 }
522 close(fd);
523
jjakoec89e9f2004-01-10 06:38:43 +0000524#endif
525
jjakoa7cd2492003-04-11 09:40:12 +0000526 return 0;
527}
528
529
530int tun_new(struct tun_t **tun)
531{
jjakoec89e9f2004-01-10 06:38:43 +0000532
jjako06e9f122004-01-19 18:37:58 +0000533#ifdef __sun__
jjakoec89e9f2004-01-10 06:38:43 +0000534 int if_fd, ppa = -1;
535 static int ip_fd = 0;
jjako243bfe62004-01-26 23:06:05 +0000536#elif defined(__FreeBSD__)
537 char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
538 int devnum;
jjako06e9f122004-01-19 18:37:58 +0000539#else
540 struct ifreq ifr;
jjakoec89e9f2004-01-10 06:38:43 +0000541#endif
jjakoa7cd2492003-04-11 09:40:12 +0000542
543 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
544 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
545 return EOF;
546 }
547
548 (*tun)->cb_ind = NULL;
549 (*tun)->addrs = 0;
jjakoec89e9f2004-01-10 06:38:43 +0000550
551#ifdef __linux__
552 /* Open the actual tun device */
jjakoa7cd2492003-04-11 09:40:12 +0000553 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
554 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
555 return -1;
556 }
jjakoec89e9f2004-01-10 06:38:43 +0000557
558 /* Set device flags. For some weird reason this is also the method
559 used to obtain the network interface name */
jjako52c24142002-12-16 13:33:51 +0000560 memset(&ifr, 0, sizeof(ifr));
561 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
jjako52c24142002-12-16 13:33:51 +0000562 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000563 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000564 close((*tun)->fd);
565 return -1;
566 }
jjakoec89e9f2004-01-10 06:38:43 +0000567
jjako52c24142002-12-16 13:33:51 +0000568 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000569 (*tun)->devname[IFNAMSIZ] = 0;
jjakoec89e9f2004-01-10 06:38:43 +0000570
571 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
572
573#endif
574
575#ifdef __sun__
576
577 if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
578 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/ip");
579 return -1;
580 }
581
582 if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
583 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
584 return -1;
585 }
586
587 /* Assign a new PPA and get its unit number. */
588 if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
589 syslog(LOG_ERR, "Can't assign new interface");
590 return -1;
591 }
592
593 if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
594 syslog(LOG_ERR, "Can't open /dev/tun (2)");
595 return -1;
596 }
597 if(ioctl(if_fd, I_PUSH, "ip") < 0){
598 syslog(LOG_ERR, "Can't push IP module");
599 return -1;
600 }
601
602 /* Assign ppa according to the unit number returned by tun device */
603 if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
604 syslog(LOG_ERR, "Can't set PPA %d", ppa);
605 return -1;
606 }
607
608 /* Link the two streams */
609 if(ioctl(ip_fd, I_LINK, if_fd) < 0){
610 syslog(LOG_ERR, "Can't link TUN device to IP");
611 return -1;
612 }
613
614 close (if_fd);
615
jjako243bfe62004-01-26 23:06:05 +0000616 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
617 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjakoec89e9f2004-01-10 06:38:43 +0000618
619#endif
jjako243bfe62004-01-26 23:06:05 +0000620
621#ifdef __FreeBSD__
622 /* Find suitable device */
623 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
624 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
625 devname[sizeof(devname)] = 0;
626 if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
627 if (errno != EBUSY) break;
628 }
629 if ((*tun)->fd < 0) {
630 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
631 return -1;
632 }
633
634 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
635 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjako1ea66342004-01-28 09:27:34 +0000636
jjako243bfe62004-01-26 23:06:05 +0000637#endif
638
jjakoa7cd2492003-04-11 09:40:12 +0000639 return 0;
jjako52c24142002-12-16 13:33:51 +0000640}
641
jjakoa7cd2492003-04-11 09:40:12 +0000642int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000643{
644 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000645 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000646 }
jjakoa7cd2492003-04-11 09:40:12 +0000647
jjakoec89e9f2004-01-10 06:38:43 +0000648 /* TODO: For solaris we need to unlink streams */
649
jjako52c24142002-12-16 13:33:51 +0000650 free(tun);
651 return 0;
652}
653
654
jjakoa7cd2492003-04-11 09:40:12 +0000655int tun_set_cb_ind(struct tun_t *this,
656 int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
657 this->cb_ind = cb_ind;
658 return 0;
659}
660
661
662int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000663{
jjakoa7cd2492003-04-11 09:40:12 +0000664 unsigned char buffer[PACKET_MAX];
665 int status;
666
667 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
668 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
669 return -1;
670 }
671
672 if (this->cb_ind)
673 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000674
jjakoa7cd2492003-04-11 09:40:12 +0000675 return 0;
jjako52c24142002-12-16 13:33:51 +0000676}
677
678int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
679{
jjakoa7cd2492003-04-11 09:40:12 +0000680 return write(tun->fd, pack, len);
681}
682
683int tun_runscript(struct tun_t *tun, char* script) {
684
685 char buf[TUN_SCRIPTSIZE];
686 char snet[TUN_ADDRSIZE];
687 char smask[TUN_ADDRSIZE];
688
689 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
690 snet[sizeof(snet)-1] = 0;
691 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
692 smask[sizeof(smask)-1] = 0;
693
694 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
695 snprintf(buf, sizeof(buf), "%s %s %s %s",
696 script, tun->devname, snet, smask);
697 buf[sizeof(buf)-1] = 0;
698 system(buf);
699 return 0;
jjako52c24142002-12-16 13:33:51 +0000700}