blob: 0369796f1e304047aa63b72670bf516fa4f5dbe3 [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"*/
jjako0141d202004-01-09 15:19:20 +000059#endif
60
jjako52c24142002-12-16 13:33:51 +000061
62#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000063#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000064
65
jjako0141d202004-01-09 15:19:20 +000066#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +000067int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000068{
jjakoa7cd2492003-04-11 09:40:12 +000069 int len = RTA_LENGTH(dlen);
70 int alen = NLMSG_ALIGN(n->nlmsg_len);
71 struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
72 if (alen + len > nsize)
73 return -1;
74 rta->rta_len = len;
75 rta->rta_type = type;
76 memcpy(RTA_DATA(rta), d, dlen);
77 n->nlmsg_len = alen + len;
78 return 0;
79}
80
81int tun_gifindex(struct tun_t *this, int *index) {
jjako52c24142002-12-16 13:33:51 +000082 struct ifreq ifr;
jjakoa7cd2492003-04-11 09:40:12 +000083 int fd;
jjako52c24142002-12-16 13:33:51 +000084
jjakoa7cd2492003-04-11 09:40:12 +000085 memset (&ifr, '\0', sizeof (ifr));
86 ifr.ifr_addr.sa_family = AF_INET;
87 ifr.ifr_dstaddr.sa_family = AF_INET;
88 ifr.ifr_netmask.sa_family = AF_INET;
89 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
90 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
91 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
92 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
93 "socket() failed");
jjako52c24142002-12-16 13:33:51 +000094 }
jjakoa7cd2492003-04-11 09:40:12 +000095 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
96 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
97 "ioctl() failed");
98 close(fd);
99 return -1;
100 }
101 close(fd);
102 *index = ifr.ifr_ifindex;
103 return 0;
104}
jjakoec89e9f2004-01-10 06:38:43 +0000105#endif
jjako52c24142002-12-16 13:33:51 +0000106
jjakoa7cd2492003-04-11 09:40:12 +0000107int tun_sifflags(struct tun_t *this, int flags) {
108 struct ifreq ifr;
109 int fd;
110
111 memset (&ifr, '\0', sizeof (ifr));
112 ifr.ifr_flags = flags;
113 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
114 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
115 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
116 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
117 "socket() failed");
118 }
119 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
120 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
121 "ioctl(SIOCSIFFLAGS) failed");
122 close(fd);
123 return -1;
124 }
125 close(fd);
126 return 0;
127}
128
129
jjako0141d202004-01-09 15:19:20 +0000130/* Currently unused
jjakoa7cd2492003-04-11 09:40:12 +0000131int tun_addroute2(struct tun_t *this,
132 struct in_addr *dst,
133 struct in_addr *gateway,
134 struct in_addr *mask) {
135
136 struct {
137 struct nlmsghdr n;
138 struct rtmsg r;
139 char buf[TUN_NLBUFSIZE];
140 } req;
141
142 struct sockaddr_nl local;
143 int addr_len;
144 int fd;
145 int status;
146 struct sockaddr_nl nladdr;
147 struct iovec iov;
148 struct msghdr msg;
149
150 memset(&req, 0, sizeof(req));
151 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
152 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
153 req.n.nlmsg_type = RTM_NEWROUTE;
154 req.r.rtm_family = AF_INET;
155 req.r.rtm_table = RT_TABLE_MAIN;
156 req.r.rtm_protocol = RTPROT_BOOT;
157 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
158 req.r.rtm_type = RTN_UNICAST;
159 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
160 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
161
162 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
163 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
164 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000165 return -1;
166 }
167
jjakoa7cd2492003-04-11 09:40:12 +0000168 memset(&local, 0, sizeof(local));
169 local.nl_family = AF_NETLINK;
170 local.nl_groups = 0;
171
172 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
173 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
174 "bind() failed");
175 close(fd);
176 return -1;
177 }
178
179 addr_len = sizeof(local);
180 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
181 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
182 "getsockname() failed");
183 close(fd);
184 return -1;
185 }
186
187 if (addr_len != sizeof(local)) {
188 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
189 "Wrong address length %d", addr_len);
190 close(fd);
191 return -1;
192 }
193
194 if (local.nl_family != AF_NETLINK) {
195 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
196 "Wrong address family %d", local.nl_family);
197 close(fd);
198 return -1;
199 }
200
201 iov.iov_base = (void*)&req.n;
202 iov.iov_len = req.n.nlmsg_len;
203
204 msg.msg_name = (void*)&nladdr;
205 msg.msg_namelen = sizeof(nladdr),
206 msg.msg_iov = &iov;
207 msg.msg_iovlen = 1;
208 msg.msg_control = NULL;
209 msg.msg_controllen = 0;
210 msg.msg_flags = 0;
211
212 memset(&nladdr, 0, sizeof(nladdr));
213 nladdr.nl_family = AF_NETLINK;
214 nladdr.nl_pid = 0;
215 nladdr.nl_groups = 0;
216
217 req.n.nlmsg_seq = 0;
218 req.n.nlmsg_flags |= NLM_F_ACK;
219
jjako0141d202004-01-09 15:19:20 +0000220 status = sendmsg(fd, &msg, 0); * TODO: Error check *
jjakoa7cd2492003-04-11 09:40:12 +0000221 close(fd);
222 return 0;
223}
jjako0141d202004-01-09 15:19:20 +0000224*/
jjakoa7cd2492003-04-11 09:40:12 +0000225
226int tun_addaddr(struct tun_t *this,
227 struct in_addr *addr,
228 struct in_addr *dstaddr,
229 struct in_addr *netmask) {
jjako0141d202004-01-09 15:19:20 +0000230
231#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +0000232 struct {
233 struct nlmsghdr n;
234 struct ifaddrmsg i;
235 char buf[TUN_NLBUFSIZE];
236 } req;
237
238 struct sockaddr_nl local;
239 int addr_len;
240 int fd;
241 int status;
242
243 struct sockaddr_nl nladdr;
244 struct iovec iov;
245 struct msghdr msg;
jjako0141d202004-01-09 15:19:20 +0000246#endif
jjakoa7cd2492003-04-11 09:40:12 +0000247
248 if (!this->addrs) /* Use ioctl for first addr to make ping work */
249 return tun_setaddr(this, addr, dstaddr, netmask);
250
jjako0141d202004-01-09 15:19:20 +0000251#ifndef __linux__
252 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
253 "Setting multiple addresses only possible on linux");
254 return -1;
255#else
jjakoa7cd2492003-04-11 09:40:12 +0000256 memset(&req, 0, sizeof(req));
257 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
258 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
259 req.n.nlmsg_type = RTM_NEWADDR;
260 req.i.ifa_family = AF_INET;
261 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
262 req.i.ifa_flags = 0;
263 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
264 if (tun_gifindex(this, &req.i.ifa_index)) {
265 return -1;
266 }
267
268 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
269 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
270
271 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
272 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
273 "socket() failed");
274 return -1;
275 }
276
277 memset(&local, 0, sizeof(local));
278 local.nl_family = AF_NETLINK;
279 local.nl_groups = 0;
280
281 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
282 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
283 "bind() failed");
284 close(fd);
285 return -1;
286 }
287
288 addr_len = sizeof(local);
289 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
290 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
291 "getsockname() failed");
292 close(fd);
293 return -1;
294 }
295
296 if (addr_len != sizeof(local)) {
297 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
298 "Wrong address length %d", addr_len);
299 close(fd);
300 return -1;
301 }
302
303 if (local.nl_family != AF_NETLINK) {
304 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
305 "Wrong address family %d", local.nl_family);
306 close(fd);
307 return -1;
308 }
309
310 iov.iov_base = (void*)&req.n;
311 iov.iov_len = req.n.nlmsg_len;
312
313 msg.msg_name = (void*)&nladdr;
314 msg.msg_namelen = sizeof(nladdr),
315 msg.msg_iov = &iov;
316 msg.msg_iovlen = 1;
317 msg.msg_control = NULL;
318 msg.msg_controllen = 0;
319 msg.msg_flags = 0;
320
321 memset(&nladdr, 0, sizeof(nladdr));
322 nladdr.nl_family = AF_NETLINK;
323 nladdr.nl_pid = 0;
324 nladdr.nl_groups = 0;
325
326 req.n.nlmsg_seq = 0;
327 req.n.nlmsg_flags |= NLM_F_ACK;
328
329 status = sendmsg(fd, &msg, 0); /* TODO Error check */
330
331 tun_sifflags(this, IFF_UP | IFF_RUNNING);
332 close(fd);
333 this->addrs++;
334 return 0;
jjako0141d202004-01-09 15:19:20 +0000335#endif
jjakoa7cd2492003-04-11 09:40:12 +0000336}
337
338
339int tun_setaddr(struct tun_t *this,
340 struct in_addr *addr,
341 struct in_addr *dstaddr,
342 struct in_addr *netmask)
343{
344 struct ifreq ifr;
345 int fd;
346
347 memset (&ifr, '\0', sizeof (ifr));
348 ifr.ifr_addr.sa_family = AF_INET;
349 ifr.ifr_dstaddr.sa_family = AF_INET;
jjakoec89e9f2004-01-10 06:38:43 +0000350#ifndef __sun__
jjakoa7cd2492003-04-11 09:40:12 +0000351 ifr.ifr_netmask.sa_family = AF_INET;
jjakoec89e9f2004-01-10 06:38:43 +0000352#endif
jjakoa7cd2492003-04-11 09:40:12 +0000353 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
354 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
355
356 /* Create a channel to the NET kernel. */
357 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
358 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
359 "socket() failed");
360 return -1;
361 }
362
363 if (addr) { /* Set the interface address */
364 this->addr.s_addr = addr->s_addr;
365 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
366 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
367 if (errno != EEXIST) {
368 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
369 "ioctl(SIOCSIFADDR) failed");
370 }
371 else {
372 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
373 "ioctl(SIOCSIFADDR): Address already exists");
374 }
375 close(fd);
376 return -1;
377 }
378 }
379
380 if (dstaddr) { /* Set the destination address */
381 this->dstaddr.s_addr = dstaddr->s_addr;
382 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
383 dstaddr->s_addr;
384 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
385 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
386 "ioctl(SIOCSIFDSTADDR) failed");
387 close(fd);
388 return -1;
389 }
390 }
391
392 if (netmask) { /* Set the netmask */
393 this->netmask.s_addr = netmask->s_addr;
jjakoec89e9f2004-01-10 06:38:43 +0000394#ifdef __sun__
395 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
396 dstaddr->s_addr;
397#else
jjakoa7cd2492003-04-11 09:40:12 +0000398 ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
399 netmask->s_addr;
jjakoec89e9f2004-01-10 06:38:43 +0000400#endif
jjakoa7cd2492003-04-11 09:40:12 +0000401 if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
402 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
403 "ioctl(SIOCSIFNETMASK) failed");
404 close(fd);
405 return -1;
406 }
407 }
408
409 close(fd);
410 this->addrs++;
411 return tun_sifflags(this, IFF_UP | IFF_RUNNING);
412}
413
414int tun_addroute(struct tun_t *this,
415 struct in_addr *dst,
416 struct in_addr *gateway,
417 struct in_addr *mask)
418{
jjakoec89e9f2004-01-10 06:38:43 +0000419
420 /* TODO: Learn how to set routing table on sun */
421#ifndef __sun__
422
jjakoa7cd2492003-04-11 09:40:12 +0000423 struct rtentry r;
424 int fd;
425
426 memset (&r, '\0', sizeof (r));
427 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
428
429 /* Create a channel to the NET kernel. */
430 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
431 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
432 "socket() failed");
433 return -1;
434 }
435
436 r.rt_dst.sa_family = AF_INET;
437 r.rt_gateway.sa_family = AF_INET;
438 r.rt_genmask.sa_family = AF_INET;
439 ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
440 ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
441 ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
442
443 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
444 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
445 "ioctl(SIOCADDRT) failed");
446 close(fd);
447 return -1;
448 }
449 close(fd);
jjakoec89e9f2004-01-10 06:38:43 +0000450
451#endif
452
jjakoa7cd2492003-04-11 09:40:12 +0000453 return 0;
454}
455
456
457int tun_new(struct tun_t **tun)
458{
jjakoec89e9f2004-01-10 06:38:43 +0000459
460#ifndef __sun__
jjakoa7cd2492003-04-11 09:40:12 +0000461 struct ifreq ifr;
jjakoec89e9f2004-01-10 06:38:43 +0000462#else
463 int if_fd, ppa = -1;
464 static int ip_fd = 0;
465#endif
jjakoa7cd2492003-04-11 09:40:12 +0000466
467 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
468 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
469 return EOF;
470 }
471
472 (*tun)->cb_ind = NULL;
473 (*tun)->addrs = 0;
jjakoec89e9f2004-01-10 06:38:43 +0000474
475#ifdef __linux__
476 /* Open the actual tun device */
jjakoa7cd2492003-04-11 09:40:12 +0000477 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
478 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
479 return -1;
480 }
jjakoec89e9f2004-01-10 06:38:43 +0000481
482 /* Set device flags. For some weird reason this is also the method
483 used to obtain the network interface name */
jjako52c24142002-12-16 13:33:51 +0000484 memset(&ifr, 0, sizeof(ifr));
485 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
jjako52c24142002-12-16 13:33:51 +0000486 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000487 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000488 close((*tun)->fd);
489 return -1;
490 }
jjakoec89e9f2004-01-10 06:38:43 +0000491
jjako52c24142002-12-16 13:33:51 +0000492 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000493 (*tun)->devname[IFNAMSIZ] = 0;
jjakoec89e9f2004-01-10 06:38:43 +0000494
495 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
496
497#endif
498
499#ifdef __sun__
500
501 if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
502 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/ip");
503 return -1;
504 }
505
506 if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
507 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
508 return -1;
509 }
510
511 /* Assign a new PPA and get its unit number. */
512 if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
513 syslog(LOG_ERR, "Can't assign new interface");
514 return -1;
515 }
516
517 if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
518 syslog(LOG_ERR, "Can't open /dev/tun (2)");
519 return -1;
520 }
521 if(ioctl(if_fd, I_PUSH, "ip") < 0){
522 syslog(LOG_ERR, "Can't push IP module");
523 return -1;
524 }
525
526 /* Assign ppa according to the unit number returned by tun device */
527 if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
528 syslog(LOG_ERR, "Can't set PPA %d", ppa);
529 return -1;
530 }
531
532 /* Link the two streams */
533 if(ioctl(ip_fd, I_LINK, if_fd) < 0){
534 syslog(LOG_ERR, "Can't link TUN device to IP");
535 return -1;
536 }
537
538 close (if_fd);
539
540 sprintf((*tun)->devname, "tun%d", ppa);
541
542#endif
jjakoa7cd2492003-04-11 09:40:12 +0000543
544 return 0;
jjako52c24142002-12-16 13:33:51 +0000545}
546
jjakoa7cd2492003-04-11 09:40:12 +0000547int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000548{
549 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000550 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000551 }
jjakoa7cd2492003-04-11 09:40:12 +0000552
jjakoec89e9f2004-01-10 06:38:43 +0000553 /* TODO: For solaris we need to unlink streams */
554
jjako52c24142002-12-16 13:33:51 +0000555 free(tun);
556 return 0;
557}
558
559
jjakoa7cd2492003-04-11 09:40:12 +0000560int tun_set_cb_ind(struct tun_t *this,
561 int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
562 this->cb_ind = cb_ind;
563 return 0;
564}
565
566
567int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000568{
jjakoa7cd2492003-04-11 09:40:12 +0000569 unsigned char buffer[PACKET_MAX];
570 int status;
571
572 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
573 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
574 return -1;
575 }
576
577 if (this->cb_ind)
578 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000579
jjakoa7cd2492003-04-11 09:40:12 +0000580 return 0;
jjako52c24142002-12-16 13:33:51 +0000581}
582
583int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
584{
jjakoa7cd2492003-04-11 09:40:12 +0000585 return write(tun->fd, pack, len);
586}
587
588int tun_runscript(struct tun_t *tun, char* script) {
589
590 char buf[TUN_SCRIPTSIZE];
591 char snet[TUN_ADDRSIZE];
592 char smask[TUN_ADDRSIZE];
593
594 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
595 snet[sizeof(snet)-1] = 0;
596 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
597 smask[sizeof(smask)-1] = 0;
598
599 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
600 snprintf(buf, sizeof(buf), "%s %s %s %s",
601 script, tun->devname, snet, smask);
602 buf[sizeof(buf)-1] = 0;
603 system(buf);
604 return 0;
jjako52c24142002-12-16 13:33:51 +0000605}