blob: 5b8cc95fdedb5915d150ffa3a287c6370bd346d1 [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>
46#include <linux/if.h>
47#include <errno.h>
48#include <linux/if_tun.h>
jjakoa7cd2492003-04-11 09:40:12 +000049#include <net/route.h>
jjako52c24142002-12-16 13:33:51 +000050
jjakoa7cd2492003-04-11 09:40:12 +000051#include <linux/netlink.h>
52#include <linux/rtnetlink.h>
jjako52c24142002-12-16 13:33:51 +000053
54#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000055#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000056
57
jjakoa7cd2492003-04-11 09:40:12 +000058
59int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000060{
jjakoa7cd2492003-04-11 09:40:12 +000061 int len = RTA_LENGTH(dlen);
62 int alen = NLMSG_ALIGN(n->nlmsg_len);
63 struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
64 if (alen + len > nsize)
65 return -1;
66 rta->rta_len = len;
67 rta->rta_type = type;
68 memcpy(RTA_DATA(rta), d, dlen);
69 n->nlmsg_len = alen + len;
70 return 0;
71}
72
73int tun_gifindex(struct tun_t *this, int *index) {
jjako52c24142002-12-16 13:33:51 +000074 struct ifreq ifr;
jjakoa7cd2492003-04-11 09:40:12 +000075 int fd;
jjako52c24142002-12-16 13:33:51 +000076
jjakoa7cd2492003-04-11 09:40:12 +000077 memset (&ifr, '\0', sizeof (ifr));
78 ifr.ifr_addr.sa_family = AF_INET;
79 ifr.ifr_dstaddr.sa_family = AF_INET;
80 ifr.ifr_netmask.sa_family = AF_INET;
81 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
82 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
83 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
84 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
85 "socket() failed");
jjako52c24142002-12-16 13:33:51 +000086 }
jjakoa7cd2492003-04-11 09:40:12 +000087 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
88 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
89 "ioctl() failed");
90 close(fd);
91 return -1;
92 }
93 close(fd);
94 *index = ifr.ifr_ifindex;
95 return 0;
96}
jjako52c24142002-12-16 13:33:51 +000097
jjakoa7cd2492003-04-11 09:40:12 +000098int tun_sifflags(struct tun_t *this, int flags) {
99 struct ifreq ifr;
100 int fd;
101
102 memset (&ifr, '\0', sizeof (ifr));
103 ifr.ifr_flags = flags;
104 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
105 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
106 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
107 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
108 "socket() failed");
109 }
110 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
111 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
112 "ioctl(SIOCSIFFLAGS) failed");
113 close(fd);
114 return -1;
115 }
116 close(fd);
117 return 0;
118}
119
120
121/* Currently unused */
122int tun_addroute2(struct tun_t *this,
123 struct in_addr *dst,
124 struct in_addr *gateway,
125 struct in_addr *mask) {
126
127 struct {
128 struct nlmsghdr n;
129 struct rtmsg r;
130 char buf[TUN_NLBUFSIZE];
131 } req;
132
133 struct sockaddr_nl local;
134 int addr_len;
135 int fd;
136 int status;
137 struct sockaddr_nl nladdr;
138 struct iovec iov;
139 struct msghdr msg;
140
141 memset(&req, 0, sizeof(req));
142 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
143 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
144 req.n.nlmsg_type = RTM_NEWROUTE;
145 req.r.rtm_family = AF_INET;
146 req.r.rtm_table = RT_TABLE_MAIN;
147 req.r.rtm_protocol = RTPROT_BOOT;
148 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
149 req.r.rtm_type = RTN_UNICAST;
150 tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
151 tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
152
153 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
154 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
155 "socket() failed");
jjako52c24142002-12-16 13:33:51 +0000156 return -1;
157 }
158
jjakoa7cd2492003-04-11 09:40:12 +0000159 memset(&local, 0, sizeof(local));
160 local.nl_family = AF_NETLINK;
161 local.nl_groups = 0;
162
163 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
164 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
165 "bind() failed");
166 close(fd);
167 return -1;
168 }
169
170 addr_len = sizeof(local);
171 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
172 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
173 "getsockname() failed");
174 close(fd);
175 return -1;
176 }
177
178 if (addr_len != sizeof(local)) {
179 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
180 "Wrong address length %d", addr_len);
181 close(fd);
182 return -1;
183 }
184
185 if (local.nl_family != AF_NETLINK) {
186 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
187 "Wrong address family %d", local.nl_family);
188 close(fd);
189 return -1;
190 }
191
192 iov.iov_base = (void*)&req.n;
193 iov.iov_len = req.n.nlmsg_len;
194
195 msg.msg_name = (void*)&nladdr;
196 msg.msg_namelen = sizeof(nladdr),
197 msg.msg_iov = &iov;
198 msg.msg_iovlen = 1;
199 msg.msg_control = NULL;
200 msg.msg_controllen = 0;
201 msg.msg_flags = 0;
202
203 memset(&nladdr, 0, sizeof(nladdr));
204 nladdr.nl_family = AF_NETLINK;
205 nladdr.nl_pid = 0;
206 nladdr.nl_groups = 0;
207
208 req.n.nlmsg_seq = 0;
209 req.n.nlmsg_flags |= NLM_F_ACK;
210
211 status = sendmsg(fd, &msg, 0); /* TODO: Error check */
212 close(fd);
213 return 0;
214}
215
216
217int tun_addaddr(struct tun_t *this,
218 struct in_addr *addr,
219 struct in_addr *dstaddr,
220 struct in_addr *netmask) {
221 struct {
222 struct nlmsghdr n;
223 struct ifaddrmsg i;
224 char buf[TUN_NLBUFSIZE];
225 } req;
226
227 struct sockaddr_nl local;
228 int addr_len;
229 int fd;
230 int status;
231
232 struct sockaddr_nl nladdr;
233 struct iovec iov;
234 struct msghdr msg;
235
236 if (!this->addrs) /* Use ioctl for first addr to make ping work */
237 return tun_setaddr(this, addr, dstaddr, netmask);
238
239 memset(&req, 0, sizeof(req));
240 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
241 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
242 req.n.nlmsg_type = RTM_NEWADDR;
243 req.i.ifa_family = AF_INET;
244 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
245 req.i.ifa_flags = 0;
246 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
247 if (tun_gifindex(this, &req.i.ifa_index)) {
248 return -1;
249 }
250
251 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
252 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
253
254 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
255 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
256 "socket() failed");
257 return -1;
258 }
259
260 memset(&local, 0, sizeof(local));
261 local.nl_family = AF_NETLINK;
262 local.nl_groups = 0;
263
264 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
265 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
266 "bind() failed");
267 close(fd);
268 return -1;
269 }
270
271 addr_len = sizeof(local);
272 if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
273 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
274 "getsockname() failed");
275 close(fd);
276 return -1;
277 }
278
279 if (addr_len != sizeof(local)) {
280 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
281 "Wrong address length %d", addr_len);
282 close(fd);
283 return -1;
284 }
285
286 if (local.nl_family != AF_NETLINK) {
287 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
288 "Wrong address family %d", local.nl_family);
289 close(fd);
290 return -1;
291 }
292
293 iov.iov_base = (void*)&req.n;
294 iov.iov_len = req.n.nlmsg_len;
295
296 msg.msg_name = (void*)&nladdr;
297 msg.msg_namelen = sizeof(nladdr),
298 msg.msg_iov = &iov;
299 msg.msg_iovlen = 1;
300 msg.msg_control = NULL;
301 msg.msg_controllen = 0;
302 msg.msg_flags = 0;
303
304 memset(&nladdr, 0, sizeof(nladdr));
305 nladdr.nl_family = AF_NETLINK;
306 nladdr.nl_pid = 0;
307 nladdr.nl_groups = 0;
308
309 req.n.nlmsg_seq = 0;
310 req.n.nlmsg_flags |= NLM_F_ACK;
311
312 status = sendmsg(fd, &msg, 0); /* TODO Error check */
313
314 tun_sifflags(this, IFF_UP | IFF_RUNNING);
315 close(fd);
316 this->addrs++;
317 return 0;
318}
319
320
321int tun_setaddr(struct tun_t *this,
322 struct in_addr *addr,
323 struct in_addr *dstaddr,
324 struct in_addr *netmask)
325{
326 struct ifreq ifr;
327 int fd;
328
329 memset (&ifr, '\0', sizeof (ifr));
330 ifr.ifr_addr.sa_family = AF_INET;
331 ifr.ifr_dstaddr.sa_family = AF_INET;
332 ifr.ifr_netmask.sa_family = AF_INET;
333 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
334 ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
335
336 /* Create a channel to the NET kernel. */
337 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
338 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
339 "socket() failed");
340 return -1;
341 }
342
343 if (addr) { /* Set the interface address */
344 this->addr.s_addr = addr->s_addr;
345 ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = addr->s_addr;
346 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
347 if (errno != EEXIST) {
348 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
349 "ioctl(SIOCSIFADDR) failed");
350 }
351 else {
352 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
353 "ioctl(SIOCSIFADDR): Address already exists");
354 }
355 close(fd);
356 return -1;
357 }
358 }
359
360 if (dstaddr) { /* Set the destination address */
361 this->dstaddr.s_addr = dstaddr->s_addr;
362 ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr =
363 dstaddr->s_addr;
364 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
365 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
366 "ioctl(SIOCSIFDSTADDR) failed");
367 close(fd);
368 return -1;
369 }
370 }
371
372 if (netmask) { /* Set the netmask */
373 this->netmask.s_addr = netmask->s_addr;
374 ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr =
375 netmask->s_addr;
376 if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
377 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
378 "ioctl(SIOCSIFNETMASK) failed");
379 close(fd);
380 return -1;
381 }
382 }
383
384 close(fd);
385 this->addrs++;
386 return tun_sifflags(this, IFF_UP | IFF_RUNNING);
387}
388
389int tun_addroute(struct tun_t *this,
390 struct in_addr *dst,
391 struct in_addr *gateway,
392 struct in_addr *mask)
393{
394 struct rtentry r;
395 int fd;
396
397 memset (&r, '\0', sizeof (r));
398 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
399
400 /* Create a channel to the NET kernel. */
401 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
402 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
403 "socket() failed");
404 return -1;
405 }
406
407 r.rt_dst.sa_family = AF_INET;
408 r.rt_gateway.sa_family = AF_INET;
409 r.rt_genmask.sa_family = AF_INET;
410 ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
411 ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
412 ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
413
414 if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) { /* SIOCDELRT */
415 sys_err(LOG_ERR, __FILE__, __LINE__, errno,
416 "ioctl(SIOCADDRT) failed");
417 close(fd);
418 return -1;
419 }
420 close(fd);
421 return 0;
422}
423
424
425int tun_new(struct tun_t **tun)
426{
427 struct ifreq ifr;
428
429 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
430 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
431 return EOF;
432 }
433
434 (*tun)->cb_ind = NULL;
435 (*tun)->addrs = 0;
436
437 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
438 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
439 return -1;
440 }
441
jjako52c24142002-12-16 13:33:51 +0000442 memset(&ifr, 0, sizeof(ifr));
443 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
444 strncpy(ifr.ifr_name, (*tun)->devname, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000445
jjako52c24142002-12-16 13:33:51 +0000446 if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000447 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
jjako52c24142002-12-16 13:33:51 +0000448 close((*tun)->fd);
449 return -1;
450 }
jjakoa7cd2492003-04-11 09:40:12 +0000451
jjako52c24142002-12-16 13:33:51 +0000452 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
jjakoa7cd2492003-04-11 09:40:12 +0000453
jjako52c24142002-12-16 13:33:51 +0000454 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
jjakoa7cd2492003-04-11 09:40:12 +0000455 (*tun)->devname[IFNAMSIZ] = 0;
456
457 return 0;
jjako52c24142002-12-16 13:33:51 +0000458}
459
jjakoa7cd2492003-04-11 09:40:12 +0000460int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000461{
462 if (close(tun->fd)) {
jjakoa7cd2492003-04-11 09:40:12 +0000463 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
jjako52c24142002-12-16 13:33:51 +0000464 }
jjakoa7cd2492003-04-11 09:40:12 +0000465
jjako52c24142002-12-16 13:33:51 +0000466 free(tun);
467 return 0;
468}
469
470
jjakoa7cd2492003-04-11 09:40:12 +0000471int tun_set_cb_ind(struct tun_t *this,
472 int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
473 this->cb_ind = cb_ind;
474 return 0;
475}
476
477
478int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000479{
jjakoa7cd2492003-04-11 09:40:12 +0000480 unsigned char buffer[PACKET_MAX];
481 int status;
482
483 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
484 sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
485 return -1;
486 }
487
488 if (this->cb_ind)
489 return this->cb_ind(this, buffer, status);
jjako52c24142002-12-16 13:33:51 +0000490
jjakoa7cd2492003-04-11 09:40:12 +0000491 return 0;
jjako52c24142002-12-16 13:33:51 +0000492}
493
494int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
495{
jjakoa7cd2492003-04-11 09:40:12 +0000496 return write(tun->fd, pack, len);
497}
498
499int tun_runscript(struct tun_t *tun, char* script) {
500
501 char buf[TUN_SCRIPTSIZE];
502 char snet[TUN_ADDRSIZE];
503 char smask[TUN_ADDRSIZE];
504
505 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
506 snet[sizeof(snet)-1] = 0;
507 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
508 smask[sizeof(smask)-1] = 0;
509
510 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
511 snprintf(buf, sizeof(buf), "%s %s %s %s",
512 script, tun->devname, snet, smask);
513 buf[sizeof(buf)-1] = 0;
514 system(buf);
515 return 0;
jjako52c24142002-12-16 13:33:51 +0000516}