blob: 2ad7cc91a65eb69242b7dc0b6f5c03d2b8ccb546 [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>
43#include <sys/types.h>
44#include <sys/ioctl.h>
45#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000046#include <errno.h>
jjakoa7cd2492003-04-11 09:40:12 +000047#include <net/route.h>
jjako52c24142002-12-16 13:33:51 +000048
jjako0141d202004-01-09 15:19:20 +000049#ifdef __linux__
50#include <linux/if.h>
51#include <linux/if_tun.h>
jjakoa7cd2492003-04-11 09:40:12 +000052#include <linux/netlink.h>
53#include <linux/rtnetlink.h>
jjako0141d202004-01-09 15:19:20 +000054#elif defined (__sun__)
55#include <net/if_tun.h>
56#endif
57
jjako52c24142002-12-16 13:33:51 +000058
59#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000060#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000061
62
jjako0141d202004-01-09 15:19:20 +000063#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +000064int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000065{
jjakoa7cd2492003-04-11 09:40:12 +000066 int len = RTA_LENGTH(dlen);
67 int alen = NLMSG_ALIGN(n->nlmsg_len);
68 struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
69 if (alen + len > nsize)
70 return -1;
71 rta->rta_len = len;
72 rta->rta_type = type;
73 memcpy(RTA_DATA(rta), d, dlen);
74 n->nlmsg_len = alen + len;
75 return 0;
76}
jjako0141d202004-01-09 15:19:20 +000077#endif
jjakoa7cd2492003-04-11 09:40:12 +000078
79int tun_gifindex(struct tun_t *this, int *index) {
jjako52c24142002-12-16 13:33:51 +000080 struct ifreq ifr;
jjakoa7cd2492003-04-11 09:40:12 +000081 int fd;
jjako52c24142002-12-16 13:33:51 +000082
jjakoa7cd2492003-04-11 09:40:12 +000083 memset (&ifr, '\0', sizeof (ifr));
84 ifr.ifr_addr.sa_family = AF_INET;
85 ifr.ifr_dstaddr.sa_family = AF_INET;
86 ifr.ifr_netmask.sa_family = AF_INET;
87 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
88 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
89 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
90 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
91 "socket() failed");
jjako52c24142002-12-16 13:33:51 +000092 }
jjakoa7cd2492003-04-11 09:40:12 +000093 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
94 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
95 "ioctl() failed");
96 close(fd);
97 return -1;
98 }
99 close(fd);
100 *index = ifr.ifr_ifindex;
101 return 0;
102}
jjako52c24142002-12-16 13:33:51 +0000103
jjakoa7cd2492003-04-11 09:40:12 +0000104int tun_sifflags(struct tun_t *this, int flags) {
105 struct ifreq ifr;
106 int fd;
107
108 memset (&ifr, '\0', sizeof (ifr));
109 ifr.ifr_flags = flags;
110 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
111 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
112 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
113 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
114 "socket() failed");
115 }
116 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
117 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
118 "ioctl(SIOCSIFFLAGS) failed");
119 close(fd);
120 return -1;
121 }
122 close(fd);
123 return 0;
124}
125
126
jjako0141d202004-01-09 15:19:20 +0000127/* Currently unused
jjakoa7cd2492003-04-11 09:40:12 +0000128int tun_addroute2(struct tun_t *this,
129 struct in_addr *dst,
130 struct in_addr *gateway,
131 struct in_addr *mask) {
132
133 struct {
134 struct nlmsghdr n;
135 struct rtmsg r;
136 char buf[TUN_NLBUFSIZE];
137 } req;
138
139 struct sockaddr_nl local;
140 int addr_len;
141 int fd;
142 int status;
143 struct sockaddr_nl nladdr;
144 struct iovec iov;
145 struct msghdr msg;
146
147 memset(&req, 0, sizeof(req));
148 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
149 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
150 req.n.nlmsg_type = RTM_NEWROUTE;
151 req.r.rtm_family = AF_INET;
152 req.r.rtm_table = RT_TABLE_MAIN;
153 req.r.rtm_protocol = RTPROT_BOOT;
154 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
155 req.r.rtm_type = RTN_UNICAST;
156 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
157 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
158
159 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
160 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
161 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000162 return -1;
163 }
164
jjakoa7cd2492003-04-11 09:40:12 +0000165 memset(&local, 0, sizeof(local));
166 local.nl_family = AF_NETLINK;
167 local.nl_groups = 0;
168
169 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
170 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
171 "bind() failed");
172 close(fd);
173 return -1;
174 }
175
176 addr_len = sizeof(local);
177 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
178 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
179 "getsockname() failed");
180 close(fd);
181 return -1;
182 }
183
184 if (addr_len != sizeof(local)) {
185 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
186 "Wrong address length %d", addr_len);
187 close(fd);
188 return -1;
189 }
190
191 if (local.nl_family != AF_NETLINK) {
192 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
193 "Wrong address family %d", local.nl_family);
194 close(fd);
195 return -1;
196 }
197
198 iov.iov_base = (void*)&req.n;
199 iov.iov_len = req.n.nlmsg_len;
200
201 msg.msg_name = (void*)&nladdr;
202 msg.msg_namelen = sizeof(nladdr),
203 msg.msg_iov = &iov;
204 msg.msg_iovlen = 1;
205 msg.msg_control = NULL;
206 msg.msg_controllen = 0;
207 msg.msg_flags = 0;
208
209 memset(&nladdr, 0, sizeof(nladdr));
210 nladdr.nl_family = AF_NETLINK;
211 nladdr.nl_pid = 0;
212 nladdr.nl_groups = 0;
213
214 req.n.nlmsg_seq = 0;
215 req.n.nlmsg_flags |= NLM_F_ACK;
216
jjako0141d202004-01-09 15:19:20 +0000217 status = sendmsg(fd, &msg, 0); * TODO: Error check *
jjakoa7cd2492003-04-11 09:40:12 +0000218 close(fd);
219 return 0;
220}
jjako0141d202004-01-09 15:19:20 +0000221*/
jjakoa7cd2492003-04-11 09:40:12 +0000222
223int tun_addaddr(struct tun_t *this,
224 struct in_addr *addr,
225 struct in_addr *dstaddr,
226 struct in_addr *netmask) {
jjako0141d202004-01-09 15:19:20 +0000227
228#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +0000229 struct {
230 struct nlmsghdr n;
231 struct ifaddrmsg i;
232 char buf[TUN_NLBUFSIZE];
233 } req;
234
235 struct sockaddr_nl local;
236 int addr_len;
237 int fd;
238 int status;
239
240 struct sockaddr_nl nladdr;
241 struct iovec iov;
242 struct msghdr msg;
jjako0141d202004-01-09 15:19:20 +0000243#endif
jjakoa7cd2492003-04-11 09:40:12 +0000244
245 if (!this->addrs) /* Use ioctl for first addr to make ping work */
246 return tun_setaddr(this, addr, dstaddr, netmask);
247
jjako0141d202004-01-09 15:19:20 +0000248#ifndef __linux__
249 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
250 "Setting multiple addresses only possible on linux");
251 return -1;
252#else
jjakoa7cd2492003-04-11 09:40:12 +0000253 memset(&req, 0, sizeof(req));
254 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
255 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
256 req.n.nlmsg_type = RTM_NEWADDR;
257 req.i.ifa_family = AF_INET;
258 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
259 req.i.ifa_flags = 0;
260 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
261 if (tun_gifindex(this, &req.i.ifa_index)) {
262 return -1;
263 }
264
265 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
266 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
267
268 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
269 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
270 "socket() failed");
271 return -1;
272 }
273
274 memset(&local, 0, sizeof(local));
275 local.nl_family = AF_NETLINK;
276 local.nl_groups = 0;
277
278 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
279 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
280 "bind() failed");
281 close(fd);
282 return -1;
283 }
284
285 addr_len = sizeof(local);
286 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
287 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
288 "getsockname() failed");
289 close(fd);
290 return -1;
291 }
292
293 if (addr_len != sizeof(local)) {
294 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
295 "Wrong address length %d", addr_len);
296 close(fd);
297 return -1;
298 }
299
300 if (local.nl_family != AF_NETLINK) {
301 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
302 "Wrong address family %d", local.nl_family);
303 close(fd);
304 return -1;
305 }
306
307 iov.iov_base = (void*)&req.n;
308 iov.iov_len = req.n.nlmsg_len;
309
310 msg.msg_name = (void*)&nladdr;
311 msg.msg_namelen = sizeof(nladdr),
312 msg.msg_iov = &iov;
313 msg.msg_iovlen = 1;
314 msg.msg_control = NULL;
315 msg.msg_controllen = 0;
316 msg.msg_flags = 0;
317
318 memset(&nladdr, 0, sizeof(nladdr));
319 nladdr.nl_family = AF_NETLINK;
320 nladdr.nl_pid = 0;
321 nladdr.nl_groups = 0;
322
323 req.n.nlmsg_seq = 0;
324 req.n.nlmsg_flags |= NLM_F_ACK;
325
326 status = sendmsg(fd, &msg, 0); /* TODO Error check */
327
328 tun_sifflags(this, IFF_UP | IFF_RUNNING);
329 close(fd);
330 this->addrs++;
331 return 0;
jjako0141d202004-01-09 15:19:20 +0000332#endif
jjakoa7cd2492003-04-11 09:40:12 +0000333}
334
335
336int tun_setaddr(struct tun_t *this,
337 struct in_addr *addr,
338 struct in_addr *dstaddr,
339 struct in_addr *netmask)
340{
341 struct ifreq ifr;
342 int fd;
343
344 memset (&ifr, '\0', sizeof (ifr));
345 ifr.ifr_addr.sa_family = AF_INET;
346 ifr.ifr_dstaddr.sa_family = AF_INET;
347 ifr.ifr_netmask.sa_family = AF_INET;
348 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
349 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
350
351 /* Create a channel to the NET kernel. */
352 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
353 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
354 "socket() failed");
355 return -1;
356 }
357
358 if (addr) { /* Set the interface address */
359 this->addr.s_addr = addr->s_addr;
360 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
361 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
362 if (errno != EEXIST) {
363 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
364 "ioctl(SIOCSIFADDR) failed");
365 }
366 else {
367 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
368 "ioctl(SIOCSIFADDR): Address already exists");
369 }
370 close(fd);
371 return -1;
372 }
373 }
374
375 if (dstaddr) { /* Set the destination address */
376 this->dstaddr.s_addr = dstaddr->s_addr;
377 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
378 dstaddr->s_addr;
379 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
380 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
381 "ioctl(SIOCSIFDSTADDR) failed");
382 close(fd);
383 return -1;
384 }
385 }
386
387 if (netmask) { /* Set the netmask */
388 this->netmask.s_addr = netmask->s_addr;
389 ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
390 netmask->s_addr;
391 if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
392 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
393 "ioctl(SIOCSIFNETMASK) failed");
394 close(fd);
395 return -1;
396 }
397 }
398
399 close(fd);
400 this->addrs++;
401 return tun_sifflags(this, IFF_UP | IFF_RUNNING);
402}
403
404int tun_addroute(struct tun_t *this,
405 struct in_addr *dst,
406 struct in_addr *gateway,
407 struct in_addr *mask)
408{
409 struct rtentry r;
410 int fd;
411
412 memset (&r, '\0', sizeof (r));
413 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
414
415 /* Create a channel to the NET kernel. */
416 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
417 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
418 "socket() failed");
419 return -1;
420 }
421
422 r.rt_dst.sa_family = AF_INET;
423 r.rt_gateway.sa_family = AF_INET;
424 r.rt_genmask.sa_family = AF_INET;
425 ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
426 ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
427 ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
428
429 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
430 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
431 "ioctl(SIOCADDRT) failed");
432 close(fd);
433 return -1;
434 }
435 close(fd);
436 return 0;
437}
438
439
440int tun_new(struct tun_t **tun)
441{
442 struct ifreq ifr;
443
444 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
445 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
446 return EOF;
447 }
448
449 (*tun)->cb_ind = NULL;
450 (*tun)->addrs = 0;
451
452 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
453 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
454 return -1;
455 }
456
jjako52c24142002-12-16 13:33:51 +0000457 memset(&ifr, 0, sizeof(ifr));
458 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
459 strncpy(ifr.ifr_name, (*tun)->devname, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000460
jjako52c24142002-12-16 13:33:51 +0000461 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000462 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000463 close((*tun)->fd);
464 return -1;
465 }
jjakoa7cd2492003-04-11 09:40:12 +0000466
jjako52c24142002-12-16 13:33:51 +0000467 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
jjakoa7cd2492003-04-11 09:40:12 +0000468
jjako52c24142002-12-16 13:33:51 +0000469 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000470 (*tun)->devname[IFNAMSIZ] = 0;
471
472 return 0;
jjako52c24142002-12-16 13:33:51 +0000473}
474
jjakoa7cd2492003-04-11 09:40:12 +0000475int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000476{
477 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000478 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000479 }
jjakoa7cd2492003-04-11 09:40:12 +0000480
jjako52c24142002-12-16 13:33:51 +0000481 free(tun);
482 return 0;
483}
484
485
jjakoa7cd2492003-04-11 09:40:12 +0000486int tun_set_cb_ind(struct tun_t *this,
487 int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
488 this->cb_ind = cb_ind;
489 return 0;
490}
491
492
493int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000494{
jjakoa7cd2492003-04-11 09:40:12 +0000495 unsigned char buffer[PACKET_MAX];
496 int status;
497
498 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
499 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
500 return -1;
501 }
502
503 if (this->cb_ind)
504 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000505
jjakoa7cd2492003-04-11 09:40:12 +0000506 return 0;
jjako52c24142002-12-16 13:33:51 +0000507}
508
509int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
510{
jjakoa7cd2492003-04-11 09:40:12 +0000511 return write(tun->fd, pack, len);
512}
513
514int tun_runscript(struct tun_t *tun, char* script) {
515
516 char buf[TUN_SCRIPTSIZE];
517 char snet[TUN_ADDRSIZE];
518 char smask[TUN_ADDRSIZE];
519
520 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
521 snet[sizeof(snet)-1] = 0;
522 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
523 smask[sizeof(smask)-1] = 0;
524
525 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
526 snprintf(buf, sizeof(buf), "%s %s %s %s",
527 script, tun->devname, snet, smask);
528 buf[sizeof(buf)-1] = 0;
529 system(buf);
530 return 0;
jjako52c24142002-12-16 13:33:51 +0000531}