blob: 1aeed5525ca864a7acefb6ecd2aeee984831a918 [file] [log] [blame]
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +02001/*
jjakoa7cd2492003-04-11 09:40:12 +00002 * TUN interface functions.
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
Harald Weltedf3dcac2018-04-25 16:20:32 +02004 * Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +02005 *
jjakoa7cd2492003-04-11 09:40:12 +00006 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
Pau Espin Pedrolfdd732b2017-10-13 14:32:24 +020010 *
jjako52c24142002-12-16 13:33:51 +000011 */
12
13/*
jjakoa7cd2492003-04-11 09:40:12 +000014 * tun.c: Contains all TUN functionality. Is able to handle multiple
15 * tunnels in the same program. Each tunnel is identified by the struct,
16 * which is passed to functions.
jjako52c24142002-12-16 13:33:51 +000017 *
jjako52c24142002-12-16 13:33:51 +000018 */
19
jjako52c24142002-12-16 13:33:51 +000020#include <stdio.h>
21#include <stdlib.h>
Harald Weltef2286392018-04-25 19:02:31 +020022#include <stdbool.h>
jjako52c24142002-12-16 13:33:51 +000023#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>
Harald Welte2e48a442017-08-03 00:47:03 +020042#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000043
jjako409b8552004-02-04 22:57:41 +000044#if defined(__linux__)
jjako0141d202004-01-09 15:19:20 +000045#include <linux/if_tun.h>
jjako409b8552004-02-04 22:57:41 +000046
47#elif defined (__FreeBSD__)
jjako409b8552004-02-04 22:57:41 +000048#include <net/if_tun.h>
Harald Welte2e48a442017-08-03 00:47:03 +020049#include <net/if_var.h>
50#include <netinet/in_var.h>
jjako409b8552004-02-04 22:57:41 +000051
jjako0fe0df02004-09-17 11:30:40 +000052#elif defined (__APPLE__)
53#include <net/if.h>
54
jjako409b8552004-02-04 22:57:41 +000055#else
56#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +000057#endif
58
jjako52c24142002-12-16 13:33:51 +000059#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000060#include "syserr.h"
Harald Weltef2286392018-04-25 19:02:31 +020061#include "gtp-kernel.h"
jjako52c24142002-12-16 13:33:51 +000062
Harald Welte9a6da452018-04-25 17:19:18 +020063static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
64 struct in_addr *dstaddr, struct in_addr *netmask)
65{
66 int rc;
67 rc = netdev_setaddr4(this->devname, addr, dstaddr, netmask);
68 if (rc < 0)
69 return rc;
70
Stefan Sperlingb0b9c282018-11-22 08:36:35 +010071 if (addr) {
72 this->addr.len = sizeof(struct in_addr);
73 this->addr.v4.s_addr = addr->s_addr;
74 }
75 if (dstaddr) {
76 this->dstaddr.len = sizeof(struct in_addr);
77 this->dstaddr.v4.s_addr = dstaddr->s_addr;
78 }
Harald Welte9a6da452018-04-25 17:19:18 +020079 if (netmask)
80 this->netmask.s_addr = netmask->s_addr;
81 this->addrs++;
82#if defined(__FreeBSD__) || defined (__APPLE__)
83 this->routes = 1;
84#endif
85
86 return rc;
87}
88
Harald Welte9a6da452018-04-25 17:19:18 +020089static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
90 size_t prefixlen)
91{
92 int rc;
93 rc = netdev_setaddr6(this->devname, addr, dstaddr, prefixlen);
94 if (rc < 0)
95 return rc;
Stefan Sperlingb0b9c282018-11-22 08:36:35 +010096 if (dstaddr) {
97 this->dstaddr.len = sizeof(*dstaddr);
98 memcpy(&this->dstaddr.v6, dstaddr, sizeof(*dstaddr));
99 }
Harald Welte9a6da452018-04-25 17:19:18 +0200100 this->addrs++;
101#if defined(__FreeBSD__) || defined (__APPLE__)
102 this->routes = 1;
103#endif
104
105 return rc;
106}
107
Harald Welte9a6da452018-04-25 17:19:18 +0200108static int tun_addaddr4(struct tun_t *this, struct in_addr *addr,
109 struct in_addr *dstaddr, struct in_addr *netmask)
110{
111 int rc;
112
113 /* TODO: Is this needed on FreeBSD? */
114 if (!this->addrs) /* Use ioctl for first addr to make ping work */
115 return tun_setaddr4(this, addr, dstaddr, netmask); /* TODO dstaddr */
116
117 rc = netdev_addaddr4(this->devname, addr, dstaddr, netmask);
118 if (rc < 0)
119 return rc;
120
121 this->addrs++;
122
123 return rc;
124}
125
Harald Welte9a6da452018-04-25 17:19:18 +0200126static int tun_addaddr6(struct tun_t *this,
127 struct in6_addr *addr,
128 struct in6_addr *dstaddr, int prefixlen)
129{
130 int rc;
131
132 if (!this->addrs) /* Use ioctl for first addr to make ping work */
133 return tun_setaddr6(this, addr, dstaddr, prefixlen);
134
135 rc = netdev_addaddr6(this->devname, addr, dstaddr, prefixlen);
136 if (rc < 0)
137 return rc;
138
139 this->addrs++;
140
141 return rc;
142}
143
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100144int tun_addaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
145{
146 struct in_addr netmask;
147 switch (addr->len) {
148 case 4:
149 netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
150 return tun_addaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
151 case 16:
152 return tun_addaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
153 default:
154 return -1;
155 }
156}
157
Harald Weltef2286392018-04-25 19:02:31 +0200158int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u)
jjakoa7cd2492003-04-11 09:40:12 +0000159{
jjakoec89e9f2004-01-10 06:38:43 +0000160
jjako409b8552004-02-04 22:57:41 +0000161#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100162 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000163
jjako0fe0df02004-09-17 11:30:40 +0000164#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100165 char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
166 int devnum;
167 struct ifaliasreq areq;
168 int fd;
jjakoec89e9f2004-01-10 06:38:43 +0000169#endif
Harald Weltebed35df2011-11-02 13:06:18 +0100170
171 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100172 SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100173 return EOF;
174 }
175
176 (*tun)->cb_ind = NULL;
177 (*tun)->addrs = 0;
178 (*tun)->routes = 0;
179
jjako409b8552004-02-04 22:57:41 +0000180#if defined(__linux__)
Harald Weltef2286392018-04-25 19:02:31 +0200181 if (!use_kernel) {
182 /* Open the actual tun device */
183 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
184 SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
185 goto err_free;
186 }
187
188 /* Set device flags. For some weird reason this is also the method
189 used to obtain the network interface name */
190 memset(&ifr, 0, sizeof(ifr));
191 if (dev_name)
192 strcpy(ifr.ifr_name, dev_name);
193 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
194 if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
195 SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
196 goto err_close;
197 }
198
199 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
200 (*tun)->devname[IFNAMSIZ - 1] = 0;
201
Stefan Sperlingaee905b2018-11-21 14:12:22 +0100202 /* Disable checksums */
203 if (ioctl((*tun)->fd, TUNSETNOCSUM, 1) < 0) {
204 SYS_ERR(DTUN, LOGL_NOTICE, errno, "could not disable checksum on %s", (*tun)->devname);
205 }
Harald Weltef2286392018-04-25 19:02:31 +0200206 return 0;
207 } else {
208 strncpy((*tun)->devname, dev_name, IFNAMSIZ);
209 (*tun)->devname[IFNAMSIZ - 1] = 0;
210 (*tun)->fd = -1;
211
212 if (gtp_kernel_create(-1, dev_name, fd0, fd1u) < 0) {
213 LOGP(DTUN, LOGL_ERROR, "cannot create GTP tunnel device: %s\n",
214 strerror(errno));
215 return -1;
216 }
217 LOGP(DTUN, LOGL_NOTICE, "GTP kernel configured\n");
218 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100219 }
220
jjako0fe0df02004-09-17 11:30:40 +0000221#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000222
Harald Weltef2286392018-04-25 19:02:31 +0200223 if (use_kernel) {
224 LOGP(DTUN, LOGL_ERROR, "No kernel GTP-U support in FreeBSD!\n");
225 return -1;
226 }
227
Harald Weltebed35df2011-11-02 13:06:18 +0100228 /* Find suitable device */
229 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
230 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
Harald Weltebed35df2011-11-02 13:06:18 +0100231 if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
232 break;
233 if (errno != EBUSY)
234 break;
235 }
236 if ((*tun)->fd < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100237 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100238 "Can't find tunnel device");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200239 goto err_free;
Harald Weltebed35df2011-11-02 13:06:18 +0100240 }
jjakoec89e9f2004-01-10 06:38:43 +0000241
Harald Weltebed35df2011-11-02 13:06:18 +0100242 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
Harald Welte81bc2ae2017-08-11 12:56:30 +0200243 (*tun)->devname[sizeof((*tun)->devname)-1] = 0;
jjako1f158642004-02-05 20:39:57 +0000244
Harald Weltebed35df2011-11-02 13:06:18 +0100245 /* The tun device we found might have "old" IP addresses allocated */
246 /* We need to delete those. This problem is not present on Linux */
jjako1f158642004-02-05 20:39:57 +0000247
Harald Weltebed35df2011-11-02 13:06:18 +0100248 memset(&areq, 0, sizeof(areq));
jjako1f158642004-02-05 20:39:57 +0000249
Harald Weltebed35df2011-11-02 13:06:18 +0100250 /* Set up interface name */
251 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
252 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako1f158642004-02-05 20:39:57 +0000253
Harald Weltebed35df2011-11-02 13:06:18 +0100254 /* Create a channel to the NET kernel. */
255 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100256 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200257 goto err_close;
Harald Weltebed35df2011-11-02 13:06:18 +0100258 }
jjako1f158642004-02-05 20:39:57 +0000259
Harald Weltebed35df2011-11-02 13:06:18 +0100260 /* Delete any IP addresses until SIOCDIFADDR fails */
261 while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
262
263 close(fd);
264 return 0;
jjako409b8552004-02-04 22:57:41 +0000265#endif
266
Harald Welte9e6dfa02017-08-12 15:06:19 +0200267err_close:
268 close((*tun)->fd);
269err_free:
270 free(*tun);
271 *tun = NULL;
272 return -1;
jjako52c24142002-12-16 13:33:51 +0000273}
274
jjakoa7cd2492003-04-11 09:40:12 +0000275int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000276{
jjako163b4552004-12-30 15:33:58 +0000277
Harald Weltebed35df2011-11-02 13:06:18 +0100278 if (tun->routes) {
Stefan Sperlingb0b9c282018-11-22 08:36:35 +0100279 netdev_delroute(&tun->dstaddr.v4, &tun->addr.v4, &tun->netmask);
Harald Weltebed35df2011-11-02 13:06:18 +0100280 }
jjako163b4552004-12-30 15:33:58 +0000281
Harald Weltef2286392018-04-25 19:02:31 +0200282 if (tun->fd >= 0) {
283 if (close(tun->fd)) {
284 SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
285 }
Harald Weltebed35df2011-11-02 13:06:18 +0100286 }
jjakoa7cd2492003-04-11 09:40:12 +0000287
Harald Weltef2286392018-04-25 19:02:31 +0200288 gtp_kernel_stop(tun->devname);
289
Harald Weltebed35df2011-11-02 13:06:18 +0100290 /* TODO: For solaris we need to unlink streams */
jjakoec89e9f2004-01-10 06:38:43 +0000291
Harald Weltebed35df2011-11-02 13:06:18 +0100292 free(tun);
293 return 0;
jjako52c24142002-12-16 13:33:51 +0000294}
295
Harald Weltebed35df2011-11-02 13:06:18 +0100296int tun_set_cb_ind(struct tun_t *this,
297 int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
298{
299 this->cb_ind = cb_ind;
300 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000301}
302
jjakoa7cd2492003-04-11 09:40:12 +0000303int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000304{
Harald Weltebed35df2011-11-02 13:06:18 +0100305 unsigned char buffer[PACKET_MAX];
306 int status;
jjako52c24142002-12-16 13:33:51 +0000307
Harald Weltebed35df2011-11-02 13:06:18 +0100308 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100309 SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100310 return -1;
311 }
312
313 if (this->cb_ind)
314 return this->cb_ind(this, buffer, status);
315
316 return 0;
jjako52c24142002-12-16 13:33:51 +0000317}
318
319int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
320{
Harald Weltebed35df2011-11-02 13:06:18 +0100321 return write(tun->fd, pack, len);
jjakoa7cd2492003-04-11 09:40:12 +0000322}
323
Harald Weltebed35df2011-11-02 13:06:18 +0100324int tun_runscript(struct tun_t *tun, char *script)
325{
jjakoa7cd2492003-04-11 09:40:12 +0000326
Harald Weltebed35df2011-11-02 13:06:18 +0100327 char buf[TUN_SCRIPTSIZE];
328 char snet[TUN_ADDRSIZE];
329 char smask[TUN_ADDRSIZE];
330 int rc;
331
Stefan Sperlingb0b9c282018-11-22 08:36:35 +0100332 strncpy(snet, inet_ntoa(tun->addr.v4), sizeof(snet));
Harald Weltebed35df2011-11-02 13:06:18 +0100333 snet[sizeof(snet) - 1] = 0;
334 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
335 smask[sizeof(smask) - 1] = 0;
336
337 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
338 snprintf(buf, sizeof(buf), "%s %s %s %s",
339 script, tun->devname, snet, smask);
340 buf[sizeof(buf) - 1] = 0;
341 rc = system(buf);
342 if (rc == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100343 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100344 "Error executing command %s", buf);
345 return -1;
346 }
347 return 0;
jjako52c24142002-12-16 13:33:51 +0000348}
Harald Weltef85fe972017-09-24 20:00:34 +0800349
Harald Welte4c7d2912017-11-08 15:19:17 +0900350/*! Obtain the local address of the tun device.
351 * \param[in] tun Target device owning the IP
352 * \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
353 * \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
354 * \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
355 * \returns The number of ips found following the criteria specified by flags, -1 on error.
356 *
357 * This function will fill prefix_list with up to prefix_size IPs following the
358 * criteria specified by flags parameter. It returns the number of IPs matching
359 * the criteria. As a result, the number returned can be bigger than
360 * prefix_size. It can be used with prefix_size=0 to get an estimate of the size
361 * needed for prefix_list.
362 */
363int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
364{
365 return netdev_ip_local_get(tun->devname, prefix_list, prefix_size, flags);
366}