blob: 766214680d2334a44c1d96e548d1cead62be47b9 [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 Welte2e48a442017-08-03 00:47:03 +02004 * Copyright (C) 2017 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>
jjakoa7cd2492003-04-11 09:40:12 +000045#include <linux/netlink.h>
46#include <linux/rtnetlink.h>
jjako409b8552004-02-04 22:57:41 +000047
48#elif defined (__FreeBSD__)
jjako409b8552004-02-04 22:57:41 +000049#include <net/if_tun.h>
Harald Welte2e48a442017-08-03 00:47:03 +020050#include <net/if_var.h>
51#include <netinet/in_var.h>
jjako409b8552004-02-04 22:57:41 +000052
jjako0fe0df02004-09-17 11:30:40 +000053#elif defined (__APPLE__)
54#include <net/if.h>
55
jjako409b8552004-02-04 22:57:41 +000056#else
57#error "Unknown platform!"
jjako0141d202004-01-09 15:19:20 +000058#endif
59
jjako52c24142002-12-16 13:33:51 +000060#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000061#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000062
Harald Welte2e48a442017-08-03 00:47:03 +020063static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
64 struct in_addr *dstaddr, struct in_addr *netmask);
65
jjako409b8552004-02-04 22:57:41 +000066#if defined(__linux__)
67
Harald Welte2e48a442017-08-03 00:47:03 +020068#include <linux/ipv6.h>
69
Harald Welte2778ae22017-08-12 16:38:44 +020070static int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000071{
Harald Weltebed35df2011-11-02 13:06:18 +010072 int len = RTA_LENGTH(dlen);
73 int alen = NLMSG_ALIGN(n->nlmsg_len);
74 struct rtattr *rta = (struct rtattr *)(((void *)n) + alen);
75 if (alen + len > nsize)
76 return -1;
77 rta->rta_len = len;
78 rta->rta_type = type;
79 memcpy(RTA_DATA(rta), d, dlen);
80 n->nlmsg_len = alen + len;
81 return 0;
jjakoa7cd2492003-04-11 09:40:12 +000082}
jjakoec89e9f2004-01-10 06:38:43 +000083#endif
jjako52c24142002-12-16 13:33:51 +000084
Harald Welte2778ae22017-08-12 16:38:44 +020085static int tun_sifflags(struct tun_t *this, int flags)
Harald Weltebed35df2011-11-02 13:06:18 +010086{
87 struct ifreq ifr;
88 int fd;
jjakoa7cd2492003-04-11 09:40:12 +000089
Harald Weltebed35df2011-11-02 13:06:18 +010090 memset(&ifr, '\0', sizeof(ifr));
91 ifr.ifr_flags = flags;
92 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
93 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
94 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010095 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Michael McTernanb07d0702015-05-02 07:52:23 +020096 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +010097 }
98 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010099 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100100 "ioctl(SIOCSIFFLAGS) failed");
101 close(fd);
102 return -1;
103 }
104 close(fd);
105 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000106}
107
jjakoa7cd2492003-04-11 09:40:12 +0000108int tun_addaddr(struct tun_t *this,
109 struct in_addr *addr,
Harald Weltebed35df2011-11-02 13:06:18 +0100110 struct in_addr *dstaddr, struct in_addr *netmask)
111{
jjako0141d202004-01-09 15:19:20 +0000112
jjako409b8552004-02-04 22:57:41 +0000113#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100114 struct {
115 struct nlmsghdr n;
116 struct ifaddrmsg i;
117 char buf[TUN_NLBUFSIZE];
118 } req;
jjakoa7cd2492003-04-11 09:40:12 +0000119
Harald Weltebed35df2011-11-02 13:06:18 +0100120 struct sockaddr_nl local;
121 socklen_t addr_len;
122 int fd;
123 int status;
jjakoa7cd2492003-04-11 09:40:12 +0000124
Harald Weltebed35df2011-11-02 13:06:18 +0100125 struct sockaddr_nl nladdr;
126 struct iovec iov;
127 struct msghdr msg;
jjakoa7cd2492003-04-11 09:40:12 +0000128
Harald Weltebed35df2011-11-02 13:06:18 +0100129 if (!this->addrs) /* Use ioctl for first addr to make ping work */
Harald Welte2e48a442017-08-03 00:47:03 +0200130 return tun_setaddr4(this, addr, dstaddr, netmask);
jjakoa7cd2492003-04-11 09:40:12 +0000131
Harald Weltebed35df2011-11-02 13:06:18 +0100132 memset(&req, 0, sizeof(req));
133 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
134 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
135 req.n.nlmsg_type = RTM_NEWADDR;
136 req.i.ifa_family = AF_INET;
137 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
138 req.i.ifa_flags = 0;
139 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
Harald Welteab6d1892017-08-11 12:31:59 +0200140 req.i.ifa_index = if_nametoindex(this->devname);
141 if (!req.i.ifa_index) {
142 SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", this->devname);
Harald Weltebed35df2011-11-02 13:06:18 +0100143 return -1;
144 }
jjakoa7cd2492003-04-11 09:40:12 +0000145
Harald Weltebed35df2011-11-02 13:06:18 +0100146 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
147 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
jjakoa7cd2492003-04-11 09:40:12 +0000148
Harald Weltebed35df2011-11-02 13:06:18 +0100149 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100150 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100151 return -1;
152 }
jjakoa7cd2492003-04-11 09:40:12 +0000153
Harald Weltebed35df2011-11-02 13:06:18 +0100154 memset(&local, 0, sizeof(local));
155 local.nl_family = AF_NETLINK;
156 local.nl_groups = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000157
Harald Weltebed35df2011-11-02 13:06:18 +0100158 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100159 SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100160 close(fd);
161 return -1;
162 }
jjakoa7cd2492003-04-11 09:40:12 +0000163
Harald Weltebed35df2011-11-02 13:06:18 +0100164 addr_len = sizeof(local);
165 if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100166 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100167 "getsockname() failed");
168 close(fd);
169 return -1;
170 }
jjakoa7cd2492003-04-11 09:40:12 +0000171
Harald Weltebed35df2011-11-02 13:06:18 +0100172 if (addr_len != sizeof(local)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100173 SYS_ERR(DTUN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100174 "Wrong address length %d", addr_len);
175 close(fd);
176 return -1;
177 }
jjakoa7cd2492003-04-11 09:40:12 +0000178
Harald Weltebed35df2011-11-02 13:06:18 +0100179 if (local.nl_family != AF_NETLINK) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100180 SYS_ERR(DTUN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100181 "Wrong address family %d", local.nl_family);
182 close(fd);
183 return -1;
184 }
jjakoa7cd2492003-04-11 09:40:12 +0000185
Harald Weltebed35df2011-11-02 13:06:18 +0100186 iov.iov_base = (void *)&req.n;
187 iov.iov_len = req.n.nlmsg_len;
jjakoa7cd2492003-04-11 09:40:12 +0000188
Harald Weltebed35df2011-11-02 13:06:18 +0100189 msg.msg_name = (void *)&nladdr;
Michael McTernanb07d0702015-05-02 07:52:23 +0200190 msg.msg_namelen = sizeof(nladdr);
191 msg.msg_iov = &iov;
Harald Weltebed35df2011-11-02 13:06:18 +0100192 msg.msg_iovlen = 1;
193 msg.msg_control = NULL;
194 msg.msg_controllen = 0;
195 msg.msg_flags = 0;
196
197 memset(&nladdr, 0, sizeof(nladdr));
198 nladdr.nl_family = AF_NETLINK;
199 nladdr.nl_pid = 0;
200 nladdr.nl_groups = 0;
201
202 req.n.nlmsg_seq = 0;
203 req.n.nlmsg_flags |= NLM_F_ACK;
204
Michael McTernanb07d0702015-05-02 07:52:23 +0200205 status = sendmsg(fd, &msg, 0);
206 if (status != req.n.nlmsg_len) {
207 SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
208 close(fd);
209 return -1;
210 }
Harald Weltebed35df2011-11-02 13:06:18 +0100211
Michael McTernanb07d0702015-05-02 07:52:23 +0200212 status = tun_sifflags(this, IFF_UP | IFF_RUNNING);
213 if (status == -1) {
214 close(fd);
215 return -1;
216 }
217
218
Harald Weltebed35df2011-11-02 13:06:18 +0100219 close(fd);
220 this->addrs++;
221 return 0;
jjako409b8552004-02-04 22:57:41 +0000222
jjako0fe0df02004-09-17 11:30:40 +0000223#elif defined (__FreeBSD__) || defined (__APPLE__)
jjako409b8552004-02-04 22:57:41 +0000224
Harald Weltebed35df2011-11-02 13:06:18 +0100225 int fd;
226 struct ifaliasreq areq;
jjako409b8552004-02-04 22:57:41 +0000227
Harald Weltebed35df2011-11-02 13:06:18 +0100228 /* TODO: Is this needed on FreeBSD? */
229 if (!this->addrs) /* Use ioctl for first addr to make ping work */
Harald Welte2e48a442017-08-03 00:47:03 +0200230 return tun_setaddr4(this, addr, dstaddr, netmask); /* TODO dstaddr */
jjako409b8552004-02-04 22:57:41 +0000231
Harald Weltebed35df2011-11-02 13:06:18 +0100232 memset(&areq, 0, sizeof(areq));
jjako409b8552004-02-04 22:57:41 +0000233
Harald Weltebed35df2011-11-02 13:06:18 +0100234 /* Set up interface name */
235 strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
236 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako409b8552004-02-04 22:57:41 +0000237
Harald Weltebed35df2011-11-02 13:06:18 +0100238 ((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
239 ((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
240 sizeof(areq.ifra_addr);
241 ((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000242
Harald Weltebed35df2011-11-02 13:06:18 +0100243 ((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
244 ((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
245 sizeof(areq.ifra_mask);
246 ((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
247 netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000248
Harald Weltebed35df2011-11-02 13:06:18 +0100249 /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
250 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
251 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
252 sizeof(areq.ifra_broadaddr);
253 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
254 dstaddr->s_addr;
jjako409b8552004-02-04 22:57:41 +0000255
Harald Weltebed35df2011-11-02 13:06:18 +0100256 /* Create a channel to the NET kernel. */
257 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100258 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100259 return -1;
260 }
jjako409b8552004-02-04 22:57:41 +0000261
Harald Weltebed35df2011-11-02 13:06:18 +0100262 if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100263 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100264 "ioctl(SIOCAIFADDR) failed");
265 close(fd);
266 return -1;
267 }
268
269 close(fd);
270 this->addrs++;
271 return 0;
jjako409b8552004-02-04 22:57:41 +0000272
jjako0141d202004-01-09 15:19:20 +0000273#endif
jjakoa7cd2492003-04-11 09:40:12 +0000274
Harald Weltebed35df2011-11-02 13:06:18 +0100275}
jjakoa7cd2492003-04-11 09:40:12 +0000276
Harald Welte2e48a442017-08-03 00:47:03 +0200277static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
278 struct in_addr *dstaddr, struct in_addr *netmask)
jjakoa7cd2492003-04-11 09:40:12 +0000279{
Harald Weltebed35df2011-11-02 13:06:18 +0100280 struct ifreq ifr;
281 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000282
Harald Weltebed35df2011-11-02 13:06:18 +0100283 memset(&ifr, '\0', sizeof(ifr));
284 ifr.ifr_addr.sa_family = AF_INET;
285 ifr.ifr_dstaddr.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000286
287#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100288 ifr.ifr_netmask.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000289
jjako0fe0df02004-09-17 11:30:40 +0000290#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100291 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
292 sizeof(struct sockaddr_in);
293 ((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
294 sizeof(struct sockaddr_in);
jjako243bfe62004-01-26 23:06:05 +0000295#endif
jjako409b8552004-02-04 22:57:41 +0000296
Harald Weltebed35df2011-11-02 13:06:18 +0100297 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
298 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjakoa7cd2492003-04-11 09:40:12 +0000299
Harald Weltebed35df2011-11-02 13:06:18 +0100300 /* Create a channel to the NET kernel. */
301 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100302 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100303 return -1;
304 }
jjakoa7cd2492003-04-11 09:40:12 +0000305
Harald Weltebed35df2011-11-02 13:06:18 +0100306 if (addr) { /* Set the interface address */
307 this->addr.s_addr = addr->s_addr;
308 memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
309 sizeof(*addr));
310 if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
311 if (errno != EEXIST) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100312 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100313 "ioctl(SIOCSIFADDR) failed");
314 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100315 SYS_ERR(DTUN, LOGL_NOTICE, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100316 "ioctl(SIOCSIFADDR): Address already exists");
317 }
318 close(fd);
319 return -1;
320 }
321 }
jjakoa7cd2492003-04-11 09:40:12 +0000322
Harald Weltebed35df2011-11-02 13:06:18 +0100323 if (dstaddr) { /* Set the destination address */
324 this->dstaddr.s_addr = dstaddr->s_addr;
325 memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
326 dstaddr, sizeof(*dstaddr));
327 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100328 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100329 "ioctl(SIOCSIFDSTADDR) failed");
330 close(fd);
331 return -1;
332 }
333 }
jjakoa7cd2492003-04-11 09:40:12 +0000334
Harald Weltebed35df2011-11-02 13:06:18 +0100335 if (netmask) { /* Set the netmask */
336 this->netmask.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000337#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100338 memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
339 netmask, sizeof(*netmask));
jjako409b8552004-02-04 22:57:41 +0000340
jjako0fe0df02004-09-17 11:30:40 +0000341#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100342 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
343 netmask->s_addr;
jjakoec89e9f2004-01-10 06:38:43 +0000344#endif
jjako409b8552004-02-04 22:57:41 +0000345
Harald Weltebed35df2011-11-02 13:06:18 +0100346 if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100347 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100348 "ioctl(SIOCSIFNETMASK) failed");
349 close(fd);
350 return -1;
351 }
352 }
jjako1ea66342004-01-28 09:27:34 +0000353
Harald Weltebed35df2011-11-02 13:06:18 +0100354 close(fd);
355 this->addrs++;
jjako409b8552004-02-04 22:57:41 +0000356
Harald Weltebed35df2011-11-02 13:06:18 +0100357 /* On linux the route to the interface is set automatically
358 on FreeBSD we have to do this manually */
359
360 /* TODO: How does it work on Solaris? */
361
362 tun_sifflags(this, IFF_UP | IFF_RUNNING);
jjako163b4552004-12-30 15:33:58 +0000363
jjako0fe0df02004-09-17 11:30:40 +0000364#if defined(__FreeBSD__) || defined (__APPLE__)
Harald Welte2e48a442017-08-03 00:47:03 +0200365 tun_addroute(this, dstaddr, addr, &this->netmask);
Harald Weltebed35df2011-11-02 13:06:18 +0100366 this->routes = 1;
jjako1ea66342004-01-28 09:27:34 +0000367#endif
368
Harald Weltebed35df2011-11-02 13:06:18 +0100369 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000370}
371
Harald Welte2e48a442017-08-03 00:47:03 +0200372static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
373 size_t prefixlen)
374{
375 struct in6_ifreq ifr;
376 int fd;
377
378 memset(&ifr, 0, sizeof(ifr));
379
380#if defined(__linux__)
381 ifr.ifr6_prefixlen = prefixlen;
382 ifr.ifr6_ifindex = if_nametoindex(this->devname);
383 if (ifr.ifr6_ifindex == 0) {
384 SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", this->devname);
385 return -1;
386 }
387#elif defined(__FreeBSD__) || defined (__APPLE__)
388 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
389#endif
390
391 /* Create a channel to the NET kernel */
392 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
393 SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed");
394 return -1;
395 }
396
397#if defined(__linux__)
398 if (addr) {
399 memcpy(&this->addr, addr, sizeof(*addr));
400 memcpy(&ifr.ifr6_addr, addr, sizeof(*addr));
401 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
402 if (errno != EEXIST) {
403 SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed");
404 } else {
405 SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address alreadsy exists");
406 }
407 close(fd);
408 return -1;
409 }
410 }
411
412#if 0
413 /* FIXME: looks like this is not possible/necessary for IPv6? */
414 if (dstaddr) {
415 memcpy(&this->dstaddr, dstaddr, sizeof(*dstaddr));
416 memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr));
417 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) {
418 SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed");
419 close(fd);
420 return -1;
421 }
422 }
423#endif
424
425#elif defined(__FreeBSD__) || defined (__APPLE__)
426 if (addr)
427 memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr));
428 if (dstaddr)
429 memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
430
431 if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) {
432 SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed");
433 close(fd);
434 return -1;
435 }
436#endif
437
438 close(fd);
439 this->addrs++;
440
441 /* On linux the route to the interface is set automatically
442 on FreeBSD we have to do this manually */
443
444 /* TODO: How does it work on Solaris? */
445
446 tun_sifflags(this, IFF_UP | IFF_RUNNING);
447
448#if 0 /* FIXME */
449//#if defined(__FreeBSD__) || defined (__APPLE__)
450 tun_addroute6(this, dstaddr, addr, prefixlen);
451 this->routes = 1;
452#endif
453
454 return 0;
455}
456
457int tun_setaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
458{
459 struct in_addr netmask;
460 switch (addr->len) {
461 case 4:
462 netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
463 return tun_setaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
464 case 16:
465 return tun_setaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
466 default:
467 return -1;
468 }
469}
470
Harald Welte2778ae22017-08-12 16:38:44 +0200471static int tun_route(struct tun_t *this,
jjako163b4552004-12-30 15:33:58 +0000472 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100473 struct in_addr *gateway, struct in_addr *mask, int delete)
jjakoa7cd2492003-04-11 09:40:12 +0000474{
jjakoec89e9f2004-01-10 06:38:43 +0000475
jjako409b8552004-02-04 22:57:41 +0000476#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000477
Harald Weltebed35df2011-11-02 13:06:18 +0100478 struct rtentry r;
479 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000480
Harald Weltebed35df2011-11-02 13:06:18 +0100481 memset(&r, '\0', sizeof(r));
482 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
jjakoa7cd2492003-04-11 09:40:12 +0000483
Harald Weltebed35df2011-11-02 13:06:18 +0100484 /* Create a channel to the NET kernel. */
485 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100486 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100487 return -1;
488 }
jjakoa7cd2492003-04-11 09:40:12 +0000489
Harald Weltebed35df2011-11-02 13:06:18 +0100490 r.rt_dst.sa_family = AF_INET;
491 r.rt_gateway.sa_family = AF_INET;
492 r.rt_genmask.sa_family = AF_INET;
493 memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst));
494 memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway,
495 sizeof(*gateway));
496 memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask,
497 sizeof(*mask));
498
499 if (delete) {
500 if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100501 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100502 "ioctl(SIOCDELRT) failed");
503 close(fd);
504 return -1;
505 }
506 } else {
507 if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100508 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100509 "ioctl(SIOCADDRT) failed");
510 close(fd);
511 return -1;
512 }
513 }
514 close(fd);
515 return 0;
516
jjako0fe0df02004-09-17 11:30:40 +0000517#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako3eaf4532004-01-27 19:47:49 +0000518
Harald Weltebed35df2011-11-02 13:06:18 +0100519 struct {
520 struct rt_msghdr rt;
521 struct sockaddr_in dst;
522 struct sockaddr_in gate;
523 struct sockaddr_in mask;
524 } req;
jjako3eaf4532004-01-27 19:47:49 +0000525
Harald Weltebed35df2011-11-02 13:06:18 +0100526 int fd;
527 struct rt_msghdr *rtm;
jjako1ea66342004-01-28 09:27:34 +0000528
Harald Weltebed35df2011-11-02 13:06:18 +0100529 if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100530 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100531 return -1;
532 }
533
534 memset(&req, 0x00, sizeof(req));
535
536 rtm = &req.rt;
537
538 rtm->rtm_msglen = sizeof(req);
539 rtm->rtm_version = RTM_VERSION;
540 if (delete) {
541 rtm->rtm_type = RTM_DELETE;
542 } else {
543 rtm->rtm_type = RTM_ADD;
544 }
545 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
546 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
547 rtm->rtm_pid = getpid();
548 rtm->rtm_seq = 0044; /* TODO */
549
550 req.dst.sin_family = AF_INET;
551 req.dst.sin_len = sizeof(req.dst);
552 req.mask.sin_family = AF_INET;
553 req.mask.sin_len = sizeof(req.mask);
554 req.gate.sin_family = AF_INET;
555 req.gate.sin_len = sizeof(req.gate);
556
557 req.dst.sin_addr.s_addr = dst->s_addr;
558 req.mask.sin_addr.s_addr = mask->s_addr;
559 req.gate.sin_addr.s_addr = gateway->s_addr;
560
561 if (write(fd, rtm, rtm->rtm_msglen) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100562 SYS_ERR(DTUN, LOGL_ERROR, errno, "write() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100563 close(fd);
564 return -1;
565 }
566 close(fd);
567 return 0;
jjakoec89e9f2004-01-10 06:38:43 +0000568#endif
569
jjakoa7cd2492003-04-11 09:40:12 +0000570}
571
jjako163b4552004-12-30 15:33:58 +0000572int tun_addroute(struct tun_t *this,
573 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100574 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000575{
Harald Weltebed35df2011-11-02 13:06:18 +0100576 return tun_route(this, dst, gateway, mask, 0);
jjako163b4552004-12-30 15:33:58 +0000577}
578
579int tun_delroute(struct tun_t *this,
580 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100581 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000582{
Harald Weltebed35df2011-11-02 13:06:18 +0100583 return tun_route(this, dst, gateway, mask, 1);
jjako163b4552004-12-30 15:33:58 +0000584}
585
Harald Weltedda21ed2017-08-12 15:07:02 +0200586int tun_new(struct tun_t **tun, const char *dev_name)
jjakoa7cd2492003-04-11 09:40:12 +0000587{
jjakoec89e9f2004-01-10 06:38:43 +0000588
jjako409b8552004-02-04 22:57:41 +0000589#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100590 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000591
jjako0fe0df02004-09-17 11:30:40 +0000592#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100593 char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
594 int devnum;
595 struct ifaliasreq areq;
596 int fd;
jjakoec89e9f2004-01-10 06:38:43 +0000597#endif
Harald Weltebed35df2011-11-02 13:06:18 +0100598
599 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100600 SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100601 return EOF;
602 }
603
604 (*tun)->cb_ind = NULL;
605 (*tun)->addrs = 0;
606 (*tun)->routes = 0;
607
jjako409b8552004-02-04 22:57:41 +0000608#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100609 /* Open the actual tun device */
610 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100611 SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200612 goto err_free;
Harald Weltebed35df2011-11-02 13:06:18 +0100613 }
614
615 /* Set device flags. For some weird reason this is also the method
616 used to obtain the network interface name */
617 memset(&ifr, 0, sizeof(ifr));
Harald Weltedda21ed2017-08-12 15:07:02 +0200618 if (dev_name)
619 strcpy(ifr.ifr_name, dev_name);
Harald Weltebed35df2011-11-02 13:06:18 +0100620 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
621 if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100622 SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200623 goto err_close;
Harald Weltebed35df2011-11-02 13:06:18 +0100624 }
625
626 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
627 (*tun)->devname[IFNAMSIZ - 1] = 0;
628
629 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
630 return 0;
631
jjako0fe0df02004-09-17 11:30:40 +0000632#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000633
Harald Weltebed35df2011-11-02 13:06:18 +0100634 /* Find suitable device */
635 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
636 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
Harald Weltebed35df2011-11-02 13:06:18 +0100637 if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
638 break;
639 if (errno != EBUSY)
640 break;
641 }
642 if ((*tun)->fd < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100643 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100644 "Can't find tunnel device");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200645 goto err_free;
Harald Weltebed35df2011-11-02 13:06:18 +0100646 }
jjakoec89e9f2004-01-10 06:38:43 +0000647
Harald Weltebed35df2011-11-02 13:06:18 +0100648 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
Harald Welte81bc2ae2017-08-11 12:56:30 +0200649 (*tun)->devname[sizeof((*tun)->devname)-1] = 0;
jjako1f158642004-02-05 20:39:57 +0000650
Harald Weltebed35df2011-11-02 13:06:18 +0100651 /* The tun device we found might have "old" IP addresses allocated */
652 /* We need to delete those. This problem is not present on Linux */
jjako1f158642004-02-05 20:39:57 +0000653
Harald Weltebed35df2011-11-02 13:06:18 +0100654 memset(&areq, 0, sizeof(areq));
jjako1f158642004-02-05 20:39:57 +0000655
Harald Weltebed35df2011-11-02 13:06:18 +0100656 /* Set up interface name */
657 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
658 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako1f158642004-02-05 20:39:57 +0000659
Harald Weltebed35df2011-11-02 13:06:18 +0100660 /* Create a channel to the NET kernel. */
661 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100662 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200663 goto err_close;
Harald Weltebed35df2011-11-02 13:06:18 +0100664 }
jjako1f158642004-02-05 20:39:57 +0000665
Harald Weltebed35df2011-11-02 13:06:18 +0100666 /* Delete any IP addresses until SIOCDIFADDR fails */
667 while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
668
669 close(fd);
670 return 0;
jjako409b8552004-02-04 22:57:41 +0000671#endif
672
Harald Welte9e6dfa02017-08-12 15:06:19 +0200673err_close:
674 close((*tun)->fd);
675err_free:
676 free(*tun);
677 *tun = NULL;
678 return -1;
jjako52c24142002-12-16 13:33:51 +0000679}
680
jjakoa7cd2492003-04-11 09:40:12 +0000681int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000682{
jjako163b4552004-12-30 15:33:58 +0000683
Harald Weltebed35df2011-11-02 13:06:18 +0100684 if (tun->routes) {
685 tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
686 }
jjako163b4552004-12-30 15:33:58 +0000687
Harald Weltebed35df2011-11-02 13:06:18 +0100688 if (close(tun->fd)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100689 SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100690 }
jjakoa7cd2492003-04-11 09:40:12 +0000691
Harald Weltebed35df2011-11-02 13:06:18 +0100692 /* TODO: For solaris we need to unlink streams */
jjakoec89e9f2004-01-10 06:38:43 +0000693
Harald Weltebed35df2011-11-02 13:06:18 +0100694 free(tun);
695 return 0;
jjako52c24142002-12-16 13:33:51 +0000696}
697
Harald Weltebed35df2011-11-02 13:06:18 +0100698int tun_set_cb_ind(struct tun_t *this,
699 int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
700{
701 this->cb_ind = cb_ind;
702 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000703}
704
jjakoa7cd2492003-04-11 09:40:12 +0000705int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000706{
Harald Weltebed35df2011-11-02 13:06:18 +0100707 unsigned char buffer[PACKET_MAX];
708 int status;
jjako52c24142002-12-16 13:33:51 +0000709
Harald Weltebed35df2011-11-02 13:06:18 +0100710 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100711 SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100712 return -1;
713 }
714
715 if (this->cb_ind)
716 return this->cb_ind(this, buffer, status);
717
718 return 0;
jjako52c24142002-12-16 13:33:51 +0000719}
720
721int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
722{
Harald Weltebed35df2011-11-02 13:06:18 +0100723 return write(tun->fd, pack, len);
jjakoa7cd2492003-04-11 09:40:12 +0000724}
725
Harald Weltebed35df2011-11-02 13:06:18 +0100726int tun_runscript(struct tun_t *tun, char *script)
727{
jjakoa7cd2492003-04-11 09:40:12 +0000728
Harald Weltebed35df2011-11-02 13:06:18 +0100729 char buf[TUN_SCRIPTSIZE];
730 char snet[TUN_ADDRSIZE];
731 char smask[TUN_ADDRSIZE];
732 int rc;
733
734 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
735 snet[sizeof(snet) - 1] = 0;
736 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
737 smask[sizeof(smask) - 1] = 0;
738
739 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
740 snprintf(buf, sizeof(buf), "%s %s %s %s",
741 script, tun->devname, snet, smask);
742 buf[sizeof(buf) - 1] = 0;
743 rc = system(buf);
744 if (rc == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100745 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100746 "Error executing command %s", buf);
747 return -1;
748 }
749 return 0;
jjako52c24142002-12-16 13:33:51 +0000750}
Harald Weltef85fe972017-09-24 20:00:34 +0800751
752#include <ifaddrs.h>
753
754/* obtain the link-local address of the tun device */
755int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in6_addr *ia)
756{
757 struct ifaddrs *ifaddr, *ifa;
758 static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
759
760 if (getifaddrs(&ifaddr) == -1) {
761 return -1;
762 }
763
764 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
765 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
766 if (ifa->ifa_addr == NULL)
767 continue;
768
769 if (ifa->ifa_addr->sa_family != AF_INET6)
770 continue;
771
772 if (strcmp(ifa->ifa_name, tun->devname))
773 continue;
774
775 if (memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix)))
776 continue;
777
778 *ia = sin6->sin6_addr;
Pau Espin Pedrol58c0da72017-10-12 16:42:46 +0200779 freeifaddrs(ifaddr);
Harald Weltef85fe972017-09-24 20:00:34 +0800780 return 0;
781 }
Pau Espin Pedrol58c0da72017-10-12 16:42:46 +0200782 freeifaddrs(ifaddr);
Harald Weltef85fe972017-09-24 20:00:34 +0800783 return -1;
784}