blob: 64989451e0f837781d54f6cb61bd3f1a8c67325e [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>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <unistd.h>
29#include <string.h>
30#include <errno.h>
31#include <fcntl.h>
32
33#include <stdio.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000037#include <sys/ioctl.h>
38#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000039#include <errno.h>
jjakoa7cd2492003-04-11 09:40:12 +000040#include <net/route.h>
Harald Welte2e48a442017-08-03 00:47:03 +020041#include <net/if.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_tun.h>
jjako409b8552004-02-04 22:57:41 +000045
46#elif defined (__FreeBSD__)
jjako409b8552004-02-04 22:57:41 +000047#include <net/if_tun.h>
Harald Welte2e48a442017-08-03 00:47:03 +020048#include <net/if_var.h>
49#include <netinet/in_var.h>
jjako409b8552004-02-04 22:57:41 +000050
jjako0fe0df02004-09-17 11:30:40 +000051#elif defined (__APPLE__)
52#include <net/if.h>
53
jjako409b8552004-02-04 22:57:41 +000054#else
55#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +000056#endif
57
jjako52c24142002-12-16 13:33:51 +000058#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000059#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000060
Harald Welte9a6da452018-04-25 17:19:18 +020061static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
62 struct in_addr *dstaddr, struct in_addr *netmask)
63{
64 int rc;
65 rc = netdev_setaddr4(this->devname, addr, dstaddr, netmask);
66 if (rc < 0)
67 return rc;
68
69 if (addr)
70 this->addr.s_addr = addr->s_addr;
71 if (dstaddr)
72 this->dstaddr.s_addr = dstaddr->s_addr;
73 if (netmask)
74 this->netmask.s_addr = netmask->s_addr;
75 this->addrs++;
76#if defined(__FreeBSD__) || defined (__APPLE__)
77 this->routes = 1;
78#endif
79
80 return rc;
81}
82
Harald Welte9a6da452018-04-25 17:19:18 +020083static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
84 size_t prefixlen)
85{
86 int rc;
87 rc = netdev_setaddr6(this->devname, addr, dstaddr, prefixlen);
88 if (rc < 0)
89 return rc;
90 if (dstaddr)
91 memcpy(&this->dstaddr, dstaddr, sizeof(*dstaddr));
92 this->addrs++;
93#if defined(__FreeBSD__) || defined (__APPLE__)
94 this->routes = 1;
95#endif
96
97 return rc;
98}
99
Harald Welte9a6da452018-04-25 17:19:18 +0200100static int tun_addaddr4(struct tun_t *this, struct in_addr *addr,
101 struct in_addr *dstaddr, struct in_addr *netmask)
102{
103 int rc;
104
105 /* TODO: Is this needed on FreeBSD? */
106 if (!this->addrs) /* Use ioctl for first addr to make ping work */
107 return tun_setaddr4(this, addr, dstaddr, netmask); /* TODO dstaddr */
108
109 rc = netdev_addaddr4(this->devname, addr, dstaddr, netmask);
110 if (rc < 0)
111 return rc;
112
113 this->addrs++;
114
115 return rc;
116}
117
Harald Welte9a6da452018-04-25 17:19:18 +0200118static int tun_addaddr6(struct tun_t *this,
119 struct in6_addr *addr,
120 struct in6_addr *dstaddr, int prefixlen)
121{
122 int rc;
123
124 if (!this->addrs) /* Use ioctl for first addr to make ping work */
125 return tun_setaddr6(this, addr, dstaddr, prefixlen);
126
127 rc = netdev_addaddr6(this->devname, addr, dstaddr, prefixlen);
128 if (rc < 0)
129 return rc;
130
131 this->addrs++;
132
133 return rc;
134}
135
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100136int tun_addaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
137{
138 struct in_addr netmask;
139 switch (addr->len) {
140 case 4:
141 netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
142 return tun_addaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
143 case 16:
144 return tun_addaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
145 default:
146 return -1;
147 }
148}
149
Harald Weltedda21ed2017-08-12 15:07:02 +0200150int tun_new(struct tun_t **tun, const char *dev_name)
jjakoa7cd2492003-04-11 09:40:12 +0000151{
jjakoec89e9f2004-01-10 06:38:43 +0000152
jjako409b8552004-02-04 22:57:41 +0000153#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100154 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000155
jjako0fe0df02004-09-17 11:30:40 +0000156#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100157 char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
158 int devnum;
159 struct ifaliasreq areq;
160 int fd;
jjakoec89e9f2004-01-10 06:38:43 +0000161#endif
Harald Weltebed35df2011-11-02 13:06:18 +0100162
163 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100164 SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100165 return EOF;
166 }
167
168 (*tun)->cb_ind = NULL;
169 (*tun)->addrs = 0;
170 (*tun)->routes = 0;
171
jjako409b8552004-02-04 22:57:41 +0000172#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100173 /* Open the actual tun device */
174 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100175 SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200176 goto err_free;
Harald Weltebed35df2011-11-02 13:06:18 +0100177 }
178
179 /* Set device flags. For some weird reason this is also the method
180 used to obtain the network interface name */
181 memset(&ifr, 0, sizeof(ifr));
Harald Weltedda21ed2017-08-12 15:07:02 +0200182 if (dev_name)
183 strcpy(ifr.ifr_name, dev_name);
Harald Weltebed35df2011-11-02 13:06:18 +0100184 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
185 if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100186 SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200187 goto err_close;
Harald Weltebed35df2011-11-02 13:06:18 +0100188 }
189
190 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
191 (*tun)->devname[IFNAMSIZ - 1] = 0;
192
193 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
194 return 0;
195
jjako0fe0df02004-09-17 11:30:40 +0000196#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000197
Harald Weltebed35df2011-11-02 13:06:18 +0100198 /* Find suitable device */
199 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
200 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
Harald Weltebed35df2011-11-02 13:06:18 +0100201 if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
202 break;
203 if (errno != EBUSY)
204 break;
205 }
206 if ((*tun)->fd < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100207 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100208 "Can't find tunnel device");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200209 goto err_free;
Harald Weltebed35df2011-11-02 13:06:18 +0100210 }
jjakoec89e9f2004-01-10 06:38:43 +0000211
Harald Weltebed35df2011-11-02 13:06:18 +0100212 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
Harald Welte81bc2ae2017-08-11 12:56:30 +0200213 (*tun)->devname[sizeof((*tun)->devname)-1] = 0;
jjako1f158642004-02-05 20:39:57 +0000214
Harald Weltebed35df2011-11-02 13:06:18 +0100215 /* The tun device we found might have "old" IP addresses allocated */
216 /* We need to delete those. This problem is not present on Linux */
jjako1f158642004-02-05 20:39:57 +0000217
Harald Weltebed35df2011-11-02 13:06:18 +0100218 memset(&areq, 0, sizeof(areq));
jjako1f158642004-02-05 20:39:57 +0000219
Harald Weltebed35df2011-11-02 13:06:18 +0100220 /* Set up interface name */
221 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
222 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako1f158642004-02-05 20:39:57 +0000223
Harald Weltebed35df2011-11-02 13:06:18 +0100224 /* Create a channel to the NET kernel. */
225 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100226 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200227 goto err_close;
Harald Weltebed35df2011-11-02 13:06:18 +0100228 }
jjako1f158642004-02-05 20:39:57 +0000229
Harald Weltebed35df2011-11-02 13:06:18 +0100230 /* Delete any IP addresses until SIOCDIFADDR fails */
231 while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
232
233 close(fd);
234 return 0;
jjako409b8552004-02-04 22:57:41 +0000235#endif
236
Harald Welte9e6dfa02017-08-12 15:06:19 +0200237err_close:
238 close((*tun)->fd);
239err_free:
240 free(*tun);
241 *tun = NULL;
242 return -1;
jjako52c24142002-12-16 13:33:51 +0000243}
244
jjakoa7cd2492003-04-11 09:40:12 +0000245int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000246{
jjako163b4552004-12-30 15:33:58 +0000247
Harald Weltebed35df2011-11-02 13:06:18 +0100248 if (tun->routes) {
Harald Welteb4c08282018-04-25 16:55:39 +0200249 netdev_delroute(&tun->dstaddr, &tun->addr, &tun->netmask);
Harald Weltebed35df2011-11-02 13:06:18 +0100250 }
jjako163b4552004-12-30 15:33:58 +0000251
Harald Weltebed35df2011-11-02 13:06:18 +0100252 if (close(tun->fd)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100253 SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100254 }
jjakoa7cd2492003-04-11 09:40:12 +0000255
Harald Weltebed35df2011-11-02 13:06:18 +0100256 /* TODO: For solaris we need to unlink streams */
jjakoec89e9f2004-01-10 06:38:43 +0000257
Harald Weltebed35df2011-11-02 13:06:18 +0100258 free(tun);
259 return 0;
jjako52c24142002-12-16 13:33:51 +0000260}
261
Harald Weltebed35df2011-11-02 13:06:18 +0100262int tun_set_cb_ind(struct tun_t *this,
263 int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
264{
265 this->cb_ind = cb_ind;
266 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000267}
268
jjakoa7cd2492003-04-11 09:40:12 +0000269int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000270{
Harald Weltebed35df2011-11-02 13:06:18 +0100271 unsigned char buffer[PACKET_MAX];
272 int status;
jjako52c24142002-12-16 13:33:51 +0000273
Harald Weltebed35df2011-11-02 13:06:18 +0100274 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100275 SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100276 return -1;
277 }
278
279 if (this->cb_ind)
280 return this->cb_ind(this, buffer, status);
281
282 return 0;
jjako52c24142002-12-16 13:33:51 +0000283}
284
285int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
286{
Harald Weltebed35df2011-11-02 13:06:18 +0100287 return write(tun->fd, pack, len);
jjakoa7cd2492003-04-11 09:40:12 +0000288}
289
Harald Weltebed35df2011-11-02 13:06:18 +0100290int tun_runscript(struct tun_t *tun, char *script)
291{
jjakoa7cd2492003-04-11 09:40:12 +0000292
Harald Weltebed35df2011-11-02 13:06:18 +0100293 char buf[TUN_SCRIPTSIZE];
294 char snet[TUN_ADDRSIZE];
295 char smask[TUN_ADDRSIZE];
296 int rc;
297
298 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
299 snet[sizeof(snet) - 1] = 0;
300 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
301 smask[sizeof(smask) - 1] = 0;
302
303 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
304 snprintf(buf, sizeof(buf), "%s %s %s %s",
305 script, tun->devname, snet, smask);
306 buf[sizeof(buf) - 1] = 0;
307 rc = system(buf);
308 if (rc == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100309 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100310 "Error executing command %s", buf);
311 return -1;
312 }
313 return 0;
jjako52c24142002-12-16 13:33:51 +0000314}
Harald Weltef85fe972017-09-24 20:00:34 +0800315
Harald Welte4c7d2912017-11-08 15:19:17 +0900316/*! Obtain the local address of the tun device.
317 * \param[in] tun Target device owning the IP
318 * \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
319 * \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
320 * \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
321 * \returns The number of ips found following the criteria specified by flags, -1 on error.
322 *
323 * This function will fill prefix_list with up to prefix_size IPs following the
324 * criteria specified by flags parameter. It returns the number of IPs matching
325 * the criteria. As a result, the number returned can be bigger than
326 * prefix_size. It can be used with prefix_size=0 to get an estimate of the size
327 * needed for prefix_list.
328 */
329int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
330{
331 return netdev_ip_local_get(tun->devname, prefix_list, prefix_size, flags);
332}