blob: 576e32e6d36f03ffcd3be00435bd52b96dddce8f [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;
246 int addr_len;
247 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
jjako0fe0df02004-09-17 11:30:40 +0000495#if defined(__FreeBSD__) || defined (__APPLE__)
jjako1ea66342004-01-28 09:27:34 +0000496 tun_sifflags(this, IFF_UP | IFF_RUNNING); /* TODO */
497 return tun_addroute(this, addr, addr, netmask);
498#else
499 return tun_sifflags(this, IFF_UP | IFF_RUNNING);
500#endif
501
jjakoa7cd2492003-04-11 09:40:12 +0000502}
503
504int tun_addroute(struct tun_t *this,
505 struct in_addr *dst,
506 struct in_addr *gateway,
507 struct in_addr *mask)
508{
jjakoec89e9f2004-01-10 06:38:43 +0000509
jjako1ea66342004-01-28 09:27:34 +0000510
511 /* TODO: Learn how to set routing table on sun */
jjako409b8552004-02-04 22:57:41 +0000512
513#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000514
jjakoa7cd2492003-04-11 09:40:12 +0000515 struct rtentry r;
516 int fd;
517
518 memset (&r, '\0', sizeof (r));
519 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
520
521 /* Create a channel to the NET kernel. */
522 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
523 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
524 "socket() failed");
525 return -1;
526 }
527
528 r.rt_dst.sa_family = AF_INET;
529 r.rt_gateway.sa_family = AF_INET;
530 r.rt_genmask.sa_family = AF_INET;
531 ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
532 ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
533 ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
534
535 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
536 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
537 "ioctl(SIOCADDRT) failed");
538 close(fd);
539 return -1;
540 }
541 close(fd);
jjako409b8552004-02-04 22:57:41 +0000542 return 0;
jjakoec89e9f2004-01-10 06:38:43 +0000543
jjako0fe0df02004-09-17 11:30:40 +0000544#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako1ea66342004-01-28 09:27:34 +0000545
546struct {
547 struct rt_msghdr rt;
548 struct sockaddr_in dst;
549 struct sockaddr_in gate;
550 struct sockaddr_in mask;
551} req;
552
553 int fd;
554 struct rt_msghdr *rtm;
555
556 if((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
557 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
558 "socket() failed");
559 return -1;
560 }
561
562 memset(&req, 0x00, sizeof(req));
563
564 rtm = &req.rt;
565
566 rtm->rtm_msglen = sizeof(req);
567 rtm->rtm_version = RTM_VERSION;
568 rtm->rtm_type = RTM_ADD;
569 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
570 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
571 rtm->rtm_pid = getpid();
572 rtm->rtm_seq = 0044; /* TODO */
573
574 req.dst.sin_family = AF_INET;
575 req.dst.sin_len = sizeof(req.dst);
576 req.mask.sin_family = AF_INET;
577 req.mask.sin_len = sizeof(req.mask);
578 req.gate.sin_family = AF_INET;
579 req.gate.sin_len = sizeof(req.gate);
580
581 req.dst.sin_addr.s_addr = dst->s_addr;
582 req.mask.sin_addr.s_addr = mask->s_addr;
583 req.gate.sin_addr.s_addr = gateway->s_addr;
584
585 if(write(fd, rtm, rtm->rtm_msglen) < 0) {
586 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
587 "write() failed");
588 close(fd);
589 return -1;
590 }
591 close(fd);
jjako409b8552004-02-04 22:57:41 +0000592 return 0;
jjako1ea66342004-01-28 09:27:34 +0000593
jjako409b8552004-02-04 22:57:41 +0000594#elif defined(__sun__)
595 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
596 "Could not set up routing on Solaris. Please add route manually.");
597 return 0;
598
599#else
600#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000601#endif
602
jjakoa7cd2492003-04-11 09:40:12 +0000603}
604
jjakoa7cd2492003-04-11 09:40:12 +0000605int tun_new(struct tun_t **tun)
606{
jjakoec89e9f2004-01-10 06:38:43 +0000607
jjako409b8552004-02-04 22:57:41 +0000608#if defined(__linux__)
609 struct ifreq ifr;
610
jjako0fe0df02004-09-17 11:30:40 +0000611#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako243bfe62004-01-26 23:06:05 +0000612 char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
613 int devnum;
jjako1f158642004-02-05 20:39:57 +0000614 struct ifaliasreq areq;
615 int fd;
jjako409b8552004-02-04 22:57:41 +0000616
617#elif defined(__sun__)
618 int if_fd, ppa = -1;
619 static int ip_fd = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000620 int muxid;
621 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000622
jjako06e9f122004-01-19 18:37:58 +0000623#else
jjako409b8552004-02-04 22:57:41 +0000624#error "Unknown platform!"
jjakoec89e9f2004-01-10 06:38:43 +0000625#endif
jjakoa7cd2492003-04-11 09:40:12 +0000626
627 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
628 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
629 return EOF;
630 }
631
632 (*tun)->cb_ind = NULL;
633 (*tun)->addrs = 0;
jjako409b8552004-02-04 22:57:41 +0000634
635#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000636 /* Open the actual tun device */
jjakoa7cd2492003-04-11 09:40:12 +0000637 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
638 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
639 return -1;
640 }
jjako409b8552004-02-04 22:57:41 +0000641
jjakoec89e9f2004-01-10 06:38:43 +0000642 /* Set device flags. For some weird reason this is also the method
643 used to obtain the network interface name */
jjako52c24142002-12-16 13:33:51 +0000644 memset(&ifr, 0, sizeof(ifr));
645 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
jjako52c24142002-12-16 13:33:51 +0000646 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000647 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000648 close((*tun)->fd);
649 return -1;
650 }
jjako409b8552004-02-04 22:57:41 +0000651
jjako52c24142002-12-16 13:33:51 +0000652 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000653 (*tun)->devname[IFNAMSIZ] = 0;
jjako409b8552004-02-04 22:57:41 +0000654
jjakoec89e9f2004-01-10 06:38:43 +0000655 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
jjako409b8552004-02-04 22:57:41 +0000656 return 0;
657
jjako0fe0df02004-09-17 11:30:40 +0000658#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000659
jjako409b8552004-02-04 22:57:41 +0000660 /* Find suitable device */
661 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
662 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
663 devname[sizeof(devname)] = 0;
664 if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
665 if (errno != EBUSY) break;
666 }
667 if ((*tun)->fd < 0) {
668 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
669 return -1;
670 }
jjakoec89e9f2004-01-10 06:38:43 +0000671
jjako409b8552004-02-04 22:57:41 +0000672 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
673 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjako1f158642004-02-05 20:39:57 +0000674
675 /* The tun device we found might have "old" IP addresses allocated */
676 /* We need to delete those. This problem is not present on Linux */
677
678 memset(&areq, 0, sizeof(areq));
679
680 /* Set up interface name */
681 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
682 areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
683
684 /* Create a channel to the NET kernel. */
685 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
686 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
687 "socket() failed");
688 return -1;
689 }
690
691 /* Delete any IP addresses until SIOCDIFADDR fails */
692 while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
693
694 close(fd);
jjako409b8552004-02-04 22:57:41 +0000695 return 0;
696
697#elif defined(__sun__)
jjakoec89e9f2004-01-10 06:38:43 +0000698
jjakoc6762cf2004-04-28 14:52:58 +0000699 if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
700 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp");
jjakoec89e9f2004-01-10 06:38:43 +0000701 return -1;
702 }
703
704 if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
705 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
706 return -1;
707 }
708
709 /* Assign a new PPA and get its unit number. */
710 if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000711 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface");
jjakoec89e9f2004-01-10 06:38:43 +0000712 return -1;
713 }
714
715 if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000716 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)");
jjakoec89e9f2004-01-10 06:38:43 +0000717 return -1;
718 }
719 if(ioctl(if_fd, I_PUSH, "ip") < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000720 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module");
jjakoec89e9f2004-01-10 06:38:43 +0000721 return -1;
722 }
723
724 /* Assign ppa according to the unit number returned by tun device */
725 if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
jjakoc6762cf2004-04-28 14:52:58 +0000726 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa);
jjakoec89e9f2004-01-10 06:38:43 +0000727 return -1;
728 }
729
730 /* Link the two streams */
jjakoc6762cf2004-04-28 14:52:58 +0000731 if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
732 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't link TUN device to IP");
jjakoec89e9f2004-01-10 06:38:43 +0000733 return -1;
734 }
735
736 close (if_fd);
737
jjako243bfe62004-01-26 23:06:05 +0000738 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
739 (*tun)->devname[sizeof((*tun)->devname)] = 0;
jjakoc6762cf2004-04-28 14:52:58 +0000740
741 memset(&ifr, 0, sizeof(ifr));
742 strcpy(ifr.ifr_name, (*tun)->devname);
743 ifr.ifr_ip_muxid = muxid;
744
745 if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
746 ioctl(ip_fd, I_PUNLINK, muxid);
747 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set multiplexor id");
748 return -1;
749 }
750
751 /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
752 msg (M_ERR, "Set file descriptor to non-blocking failed"); */
753
jjakoa7cd2492003-04-11 09:40:12 +0000754 return 0;
jjako409b8552004-02-04 22:57:41 +0000755
756#else
757#error "Unknown platform!"
758#endif
759
jjako52c24142002-12-16 13:33:51 +0000760}
761
jjakoa7cd2492003-04-11 09:40:12 +0000762int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000763{
764 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000765 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000766 }
jjakoa7cd2492003-04-11 09:40:12 +0000767
jjakoec89e9f2004-01-10 06:38:43 +0000768 /* TODO: For solaris we need to unlink streams */
769
jjako52c24142002-12-16 13:33:51 +0000770 free(tun);
771 return 0;
772}
773
774
jjakoa7cd2492003-04-11 09:40:12 +0000775int tun_set_cb_ind(struct tun_t *this,
776 int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
777 this->cb_ind = cb_ind;
778 return 0;
779}
780
781
782int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000783{
jjakoc6762cf2004-04-28 14:52:58 +0000784
jjako0fe0df02004-09-17 11:30:40 +0000785#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000786
jjakoa7cd2492003-04-11 09:40:12 +0000787 unsigned char buffer[PACKET_MAX];
788 int status;
789
790 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
791 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
792 return -1;
793 }
794
795 if (this->cb_ind)
796 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000797
jjakoa7cd2492003-04-11 09:40:12 +0000798 return 0;
jjakoc6762cf2004-04-28 14:52:58 +0000799
800#elif defined (__sun__)
801
802 unsigned char buffer[PACKET_MAX];
803 struct strbuf sbuf;
804 int f = 0;
805
806 sbuf.maxlen = PACKET_MAX;
807 sbuf.buf = buffer;
808 if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
809 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed");
810 return -1;
811 }
812
813 if (this->cb_ind)
814 return this->cb_ind(this, buffer, sbuf.len);
815
816 return 0;
817
818#endif
819
jjako52c24142002-12-16 13:33:51 +0000820}
821
jjakoc6762cf2004-04-28 14:52:58 +0000822
jjako52c24142002-12-16 13:33:51 +0000823int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
824{
jjakoc6762cf2004-04-28 14:52:58 +0000825
jjako0fe0df02004-09-17 11:30:40 +0000826#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)
jjakoc6762cf2004-04-28 14:52:58 +0000827
jjakoa7cd2492003-04-11 09:40:12 +0000828 return write(tun->fd, pack, len);
jjakoc6762cf2004-04-28 14:52:58 +0000829
830#elif defined (__sun__)
831
832 struct strbuf sbuf;
833 sbuf.len = len;
834 sbuf.buf = pack;
835 return putmsg(tun->fd, NULL, &sbuf, 0);
836
837#endif
jjakoa7cd2492003-04-11 09:40:12 +0000838}
839
840int tun_runscript(struct tun_t *tun, char* script) {
841
842 char buf[TUN_SCRIPTSIZE];
843 char snet[TUN_ADDRSIZE];
844 char smask[TUN_ADDRSIZE];
845
846 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
847 snet[sizeof(snet)-1] = 0;
848 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
849 smask[sizeof(smask)-1] = 0;
850
851 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
852 snprintf(buf, sizeof(buf), "%s %s %s %s",
853 script, tun->devname, snet, smask);
854 buf[sizeof(buf)-1] = 0;
855 system(buf);
856 return 0;
jjako52c24142002-12-16 13:33:51 +0000857}