blob: 3081575386b9d468d459e9d1dbb5bb99e60d03d4 [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
jjako409b8552004-02-04 22:57:41 +000063#if defined(__linux__)
64
Harald Welte2e48a442017-08-03 00:47:03 +020065#include <linux/ipv6.h>
66
Harald Welte2778ae22017-08-12 16:38:44 +020067static int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen)
jjako52c24142002-12-16 13:33:51 +000068{
Harald Weltebed35df2011-11-02 13:06:18 +010069 int len = RTA_LENGTH(dlen);
70 int alen = NLMSG_ALIGN(n->nlmsg_len);
71 struct rtattr *rta = (struct rtattr *)(((void *)n) + alen);
72 if (alen + len > nsize)
73 return -1;
74 rta->rta_len = len;
75 rta->rta_type = type;
76 memcpy(RTA_DATA(rta), d, dlen);
77 n->nlmsg_len = alen + len;
78 return 0;
jjakoa7cd2492003-04-11 09:40:12 +000079}
jjakoec89e9f2004-01-10 06:38:43 +000080#endif
jjako52c24142002-12-16 13:33:51 +000081
Harald Welte2778ae22017-08-12 16:38:44 +020082static int tun_sifflags(struct tun_t *this, int flags)
Harald Weltebed35df2011-11-02 13:06:18 +010083{
84 struct ifreq ifr;
85 int fd;
jjakoa7cd2492003-04-11 09:40:12 +000086
Harald Weltebed35df2011-11-02 13:06:18 +010087 memset(&ifr, '\0', sizeof(ifr));
88 ifr.ifr_flags = flags;
89 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
90 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
91 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010092 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Michael McTernanb07d0702015-05-02 07:52:23 +020093 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +010094 }
95 if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010096 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +010097 "ioctl(SIOCSIFFLAGS) failed");
98 close(fd);
99 return -1;
100 }
101 close(fd);
102 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000103}
104
Harald Welte2e48a442017-08-03 00:47:03 +0200105static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
106 struct in_addr *dstaddr, struct in_addr *netmask)
jjakoa7cd2492003-04-11 09:40:12 +0000107{
Harald Weltebed35df2011-11-02 13:06:18 +0100108 struct ifreq ifr;
109 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000110
Harald Weltebed35df2011-11-02 13:06:18 +0100111 memset(&ifr, '\0', sizeof(ifr));
112 ifr.ifr_addr.sa_family = AF_INET;
113 ifr.ifr_dstaddr.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000114
115#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100116 ifr.ifr_netmask.sa_family = AF_INET;
jjako409b8552004-02-04 22:57:41 +0000117
jjako0fe0df02004-09-17 11:30:40 +0000118#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100119 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_len =
120 sizeof(struct sockaddr_in);
121 ((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_len =
122 sizeof(struct sockaddr_in);
jjako243bfe62004-01-26 23:06:05 +0000123#endif
jjako409b8552004-02-04 22:57:41 +0000124
Harald Weltebed35df2011-11-02 13:06:18 +0100125 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
126 ifr.ifr_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjakoa7cd2492003-04-11 09:40:12 +0000127
Harald Weltebed35df2011-11-02 13:06:18 +0100128 /* Create a channel to the NET kernel. */
129 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100130 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100131 return -1;
132 }
jjakoa7cd2492003-04-11 09:40:12 +0000133
Harald Weltebed35df2011-11-02 13:06:18 +0100134 if (addr) { /* Set the interface address */
135 this->addr.s_addr = addr->s_addr;
136 memcpy(&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, addr,
137 sizeof(*addr));
138 if (ioctl(fd, SIOCSIFADDR, (void *)&ifr) < 0) {
139 if (errno != EEXIST) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100140 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100141 "ioctl(SIOCSIFADDR) failed");
142 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100143 SYS_ERR(DTUN, LOGL_NOTICE, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100144 "ioctl(SIOCSIFADDR): Address already exists");
145 }
146 close(fd);
147 return -1;
148 }
149 }
jjakoa7cd2492003-04-11 09:40:12 +0000150
Harald Weltebed35df2011-11-02 13:06:18 +0100151 if (dstaddr) { /* Set the destination address */
152 this->dstaddr.s_addr = dstaddr->s_addr;
153 memcpy(&((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr,
154 dstaddr, sizeof(*dstaddr));
155 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) & ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100156 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100157 "ioctl(SIOCSIFDSTADDR) failed");
158 close(fd);
159 return -1;
160 }
161 }
jjakoa7cd2492003-04-11 09:40:12 +0000162
Harald Weltebed35df2011-11-02 13:06:18 +0100163 if (netmask) { /* Set the netmask */
164 this->netmask.s_addr = netmask->s_addr;
jjako409b8552004-02-04 22:57:41 +0000165#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100166 memcpy(&((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr,
167 netmask, sizeof(*netmask));
jjako409b8552004-02-04 22:57:41 +0000168
jjako0fe0df02004-09-17 11:30:40 +0000169#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100170 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr =
171 netmask->s_addr;
jjakoec89e9f2004-01-10 06:38:43 +0000172#endif
jjako409b8552004-02-04 22:57:41 +0000173
Harald Weltebed35df2011-11-02 13:06:18 +0100174 if (ioctl(fd, SIOCSIFNETMASK, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100175 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100176 "ioctl(SIOCSIFNETMASK) failed");
177 close(fd);
178 return -1;
179 }
180 }
jjako1ea66342004-01-28 09:27:34 +0000181
Harald Weltebed35df2011-11-02 13:06:18 +0100182 close(fd);
183 this->addrs++;
jjako409b8552004-02-04 22:57:41 +0000184
Harald Weltebed35df2011-11-02 13:06:18 +0100185 /* On linux the route to the interface is set automatically
186 on FreeBSD we have to do this manually */
187
188 /* TODO: How does it work on Solaris? */
189
190 tun_sifflags(this, IFF_UP | IFF_RUNNING);
jjako163b4552004-12-30 15:33:58 +0000191
jjako0fe0df02004-09-17 11:30:40 +0000192#if defined(__FreeBSD__) || defined (__APPLE__)
Harald Welte2e48a442017-08-03 00:47:03 +0200193 tun_addroute(this, dstaddr, addr, &this->netmask);
Harald Weltebed35df2011-11-02 13:06:18 +0100194 this->routes = 1;
jjako1ea66342004-01-28 09:27:34 +0000195#endif
196
Harald Weltebed35df2011-11-02 13:06:18 +0100197 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000198}
199
Harald Welte2e48a442017-08-03 00:47:03 +0200200static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
201 size_t prefixlen)
202{
203 struct in6_ifreq ifr;
204 int fd;
205
206 memset(&ifr, 0, sizeof(ifr));
207
208#if defined(__linux__)
209 ifr.ifr6_prefixlen = prefixlen;
210 ifr.ifr6_ifindex = if_nametoindex(this->devname);
211 if (ifr.ifr6_ifindex == 0) {
212 SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", this->devname);
213 return -1;
214 }
215#elif defined(__FreeBSD__) || defined (__APPLE__)
216 strncpy(ifr.ifr_name, this->devname, IFNAMSIZ);
217#endif
218
219 /* Create a channel to the NET kernel */
220 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
221 SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed");
222 return -1;
223 }
224
225#if defined(__linux__)
226 if (addr) {
Harald Welte2e48a442017-08-03 00:47:03 +0200227 memcpy(&ifr.ifr6_addr, addr, sizeof(*addr));
228 if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
229 if (errno != EEXIST) {
230 SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed");
231 } else {
Pau Espin Pedrold9fff0c2017-12-01 15:39:28 +0100232 SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address already exists");
Harald Welte2e48a442017-08-03 00:47:03 +0200233 }
234 close(fd);
235 return -1;
236 }
237 }
238
239#if 0
240 /* FIXME: looks like this is not possible/necessary for IPv6? */
241 if (dstaddr) {
242 memcpy(&this->dstaddr, dstaddr, sizeof(*dstaddr));
243 memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr));
244 if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) {
245 SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed");
246 close(fd);
247 return -1;
248 }
249 }
250#endif
251
252#elif defined(__FreeBSD__) || defined (__APPLE__)
253 if (addr)
254 memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr));
255 if (dstaddr)
256 memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr));
257
258 if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) {
259 SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed");
260 close(fd);
261 return -1;
262 }
263#endif
264
265 close(fd);
266 this->addrs++;
267
268 /* On linux the route to the interface is set automatically
269 on FreeBSD we have to do this manually */
270
271 /* TODO: How does it work on Solaris? */
272
273 tun_sifflags(this, IFF_UP | IFF_RUNNING);
274
275#if 0 /* FIXME */
276//#if defined(__FreeBSD__) || defined (__APPLE__)
277 tun_addroute6(this, dstaddr, addr, prefixlen);
278 this->routes = 1;
279#endif
280
281 return 0;
282}
283
284int tun_setaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen)
285{
286 struct in_addr netmask;
287 switch (addr->len) {
288 case 4:
289 netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
290 return tun_setaddr4(this, &addr->v4, dstaddr ? &dstaddr->v4 : NULL, &netmask);
291 case 16:
292 return tun_setaddr6(this, &addr->v6, dstaddr ? &dstaddr->v6 : NULL, prefixlen);
293 default:
294 return -1;
295 }
296}
297
Pau Espin Pedrolb9ace142017-12-01 14:45:31 +0100298int tun_addaddr(struct tun_t *this,
299 struct in_addr *addr,
300 struct in_addr *dstaddr, struct in_addr *netmask)
301{
302
303#if defined(__linux__)
304 struct {
305 struct nlmsghdr n;
306 struct ifaddrmsg i;
307 char buf[TUN_NLBUFSIZE];
308 } req;
309
310 struct sockaddr_nl local;
311 socklen_t addr_len;
312 int fd;
313 int status;
314
315 struct sockaddr_nl nladdr;
316 struct iovec iov;
317 struct msghdr msg;
318
319 if (!this->addrs) /* Use ioctl for first addr to make ping work */
320 return tun_setaddr4(this, addr, dstaddr, netmask);
321
322 memset(&req, 0, sizeof(req));
323 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
324 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
325 req.n.nlmsg_type = RTM_NEWADDR;
326 req.i.ifa_family = AF_INET;
327 req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
328 req.i.ifa_flags = 0;
329 req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
330 req.i.ifa_index = if_nametoindex(this->devname);
331 if (!req.i.ifa_index) {
332 SYS_ERR(DTUN, LOGL_ERROR, errno, "Unable to get ifindex for %s", this->devname);
333 return -1;
334 }
335
Pau Espin Pedrol02e21af2017-12-14 13:48:12 +0100336 tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(*addr));
337 if (dstaddr)
338 tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(*dstaddr));
Pau Espin Pedrolb9ace142017-12-01 14:45:31 +0100339
340 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
341 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
342 return -1;
343 }
344
345 memset(&local, 0, sizeof(local));
346 local.nl_family = AF_NETLINK;
347 local.nl_groups = 0;
348
349 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) {
350 SYS_ERR(DTUN, LOGL_ERROR, errno, "bind() failed");
351 close(fd);
352 return -1;
353 }
354
355 addr_len = sizeof(local);
356 if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0) {
357 SYS_ERR(DTUN, LOGL_ERROR, errno,
358 "getsockname() failed");
359 close(fd);
360 return -1;
361 }
362
363 if (addr_len != sizeof(local)) {
364 SYS_ERR(DTUN, LOGL_ERROR, 0,
365 "Wrong address length %d", addr_len);
366 close(fd);
367 return -1;
368 }
369
370 if (local.nl_family != AF_NETLINK) {
371 SYS_ERR(DTUN, LOGL_ERROR, 0,
372 "Wrong address family %d", local.nl_family);
373 close(fd);
374 return -1;
375 }
376
377 iov.iov_base = (void *)&req.n;
378 iov.iov_len = req.n.nlmsg_len;
379
380 msg.msg_name = (void *)&nladdr;
381 msg.msg_namelen = sizeof(nladdr);
382 msg.msg_iov = &iov;
383 msg.msg_iovlen = 1;
384 msg.msg_control = NULL;
385 msg.msg_controllen = 0;
386 msg.msg_flags = 0;
387
388 memset(&nladdr, 0, sizeof(nladdr));
389 nladdr.nl_family = AF_NETLINK;
390 nladdr.nl_pid = 0;
391 nladdr.nl_groups = 0;
392
393 req.n.nlmsg_seq = 0;
394 req.n.nlmsg_flags |= NLM_F_ACK;
395
396 status = sendmsg(fd, &msg, 0);
397 if (status != req.n.nlmsg_len) {
398 SYS_ERR(DTUN, LOGL_ERROR, errno, "sendmsg() failed, returned %d", status);
399 close(fd);
400 return -1;
401 }
402
403 status = tun_sifflags(this, IFF_UP | IFF_RUNNING);
404 if (status == -1) {
405 close(fd);
406 return -1;
407 }
408
409
410 close(fd);
411 this->addrs++;
412 return 0;
413
414#elif defined (__FreeBSD__) || defined (__APPLE__)
415
416 int fd;
417 struct ifaliasreq areq;
418
419 /* TODO: Is this needed on FreeBSD? */
420 if (!this->addrs) /* Use ioctl for first addr to make ping work */
421 return tun_setaddr4(this, addr, dstaddr, netmask); /* TODO dstaddr */
422
423 memset(&areq, 0, sizeof(areq));
424
425 /* Set up interface name */
426 strncpy(areq.ifra_name, this->devname, IFNAMSIZ);
427 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
428
429 ((struct sockaddr_in *)&areq.ifra_addr)->sin_family = AF_INET;
430 ((struct sockaddr_in *)&areq.ifra_addr)->sin_len =
431 sizeof(areq.ifra_addr);
432 ((struct sockaddr_in *)&areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
433
434 ((struct sockaddr_in *)&areq.ifra_mask)->sin_family = AF_INET;
435 ((struct sockaddr_in *)&areq.ifra_mask)->sin_len =
436 sizeof(areq.ifra_mask);
437 ((struct sockaddr_in *)&areq.ifra_mask)->sin_addr.s_addr =
438 netmask->s_addr;
439
440 /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
441 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_family = AF_INET;
442 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_len =
443 sizeof(areq.ifra_broadaddr);
444 ((struct sockaddr_in *)&areq.ifra_broadaddr)->sin_addr.s_addr =
445 dstaddr->s_addr;
446
447 /* Create a channel to the NET kernel. */
448 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
449 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
450 return -1;
451 }
452
453 if (ioctl(fd, SIOCAIFADDR, (void *)&areq) < 0) {
454 SYS_ERR(DTUN, LOGL_ERROR, errno,
455 "ioctl(SIOCAIFADDR) failed");
456 close(fd);
457 return -1;
458 }
459
460 close(fd);
461 this->addrs++;
462 return 0;
463
464#endif
465
466}
467
Harald Welte2778ae22017-08-12 16:38:44 +0200468static int tun_route(struct tun_t *this,
jjako163b4552004-12-30 15:33:58 +0000469 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100470 struct in_addr *gateway, struct in_addr *mask, int delete)
jjakoa7cd2492003-04-11 09:40:12 +0000471{
jjakoec89e9f2004-01-10 06:38:43 +0000472
jjako409b8552004-02-04 22:57:41 +0000473#if defined(__linux__)
jjakoec89e9f2004-01-10 06:38:43 +0000474
Harald Weltebed35df2011-11-02 13:06:18 +0100475 struct rtentry r;
476 int fd;
jjakoa7cd2492003-04-11 09:40:12 +0000477
Harald Weltebed35df2011-11-02 13:06:18 +0100478 memset(&r, '\0', sizeof(r));
479 r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
jjakoa7cd2492003-04-11 09:40:12 +0000480
Harald Weltebed35df2011-11-02 13:06:18 +0100481 /* Create a channel to the NET kernel. */
482 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100483 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100484 return -1;
485 }
jjakoa7cd2492003-04-11 09:40:12 +0000486
Harald Weltebed35df2011-11-02 13:06:18 +0100487 r.rt_dst.sa_family = AF_INET;
488 r.rt_gateway.sa_family = AF_INET;
489 r.rt_genmask.sa_family = AF_INET;
490 memcpy(&((struct sockaddr_in *)&r.rt_dst)->sin_addr, dst, sizeof(*dst));
491 memcpy(&((struct sockaddr_in *)&r.rt_gateway)->sin_addr, gateway,
492 sizeof(*gateway));
493 memcpy(&((struct sockaddr_in *)&r.rt_genmask)->sin_addr, mask,
494 sizeof(*mask));
495
496 if (delete) {
497 if (ioctl(fd, SIOCDELRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100498 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100499 "ioctl(SIOCDELRT) failed");
500 close(fd);
501 return -1;
502 }
503 } else {
504 if (ioctl(fd, SIOCADDRT, (void *)&r) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100505 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100506 "ioctl(SIOCADDRT) failed");
507 close(fd);
508 return -1;
509 }
510 }
511 close(fd);
512 return 0;
513
jjako0fe0df02004-09-17 11:30:40 +0000514#elif defined(__FreeBSD__) || defined (__APPLE__)
jjako3eaf4532004-01-27 19:47:49 +0000515
Harald Weltebed35df2011-11-02 13:06:18 +0100516 struct {
517 struct rt_msghdr rt;
518 struct sockaddr_in dst;
519 struct sockaddr_in gate;
520 struct sockaddr_in mask;
521 } req;
jjako3eaf4532004-01-27 19:47:49 +0000522
Harald Weltebed35df2011-11-02 13:06:18 +0100523 int fd;
524 struct rt_msghdr *rtm;
jjako1ea66342004-01-28 09:27:34 +0000525
Harald Weltebed35df2011-11-02 13:06:18 +0100526 if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100527 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100528 return -1;
529 }
530
531 memset(&req, 0x00, sizeof(req));
532
533 rtm = &req.rt;
534
535 rtm->rtm_msglen = sizeof(req);
536 rtm->rtm_version = RTM_VERSION;
537 if (delete) {
538 rtm->rtm_type = RTM_DELETE;
539 } else {
540 rtm->rtm_type = RTM_ADD;
541 }
542 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
543 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
544 rtm->rtm_pid = getpid();
545 rtm->rtm_seq = 0044; /* TODO */
546
547 req.dst.sin_family = AF_INET;
548 req.dst.sin_len = sizeof(req.dst);
549 req.mask.sin_family = AF_INET;
550 req.mask.sin_len = sizeof(req.mask);
551 req.gate.sin_family = AF_INET;
552 req.gate.sin_len = sizeof(req.gate);
553
554 req.dst.sin_addr.s_addr = dst->s_addr;
555 req.mask.sin_addr.s_addr = mask->s_addr;
556 req.gate.sin_addr.s_addr = gateway->s_addr;
557
558 if (write(fd, rtm, rtm->rtm_msglen) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100559 SYS_ERR(DTUN, LOGL_ERROR, errno, "write() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100560 close(fd);
561 return -1;
562 }
563 close(fd);
564 return 0;
jjakoec89e9f2004-01-10 06:38:43 +0000565#endif
566
jjakoa7cd2492003-04-11 09:40:12 +0000567}
568
jjako163b4552004-12-30 15:33:58 +0000569int tun_addroute(struct tun_t *this,
570 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100571 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000572{
Harald Weltebed35df2011-11-02 13:06:18 +0100573 return tun_route(this, dst, gateway, mask, 0);
jjako163b4552004-12-30 15:33:58 +0000574}
575
576int tun_delroute(struct tun_t *this,
577 struct in_addr *dst,
Harald Weltebed35df2011-11-02 13:06:18 +0100578 struct in_addr *gateway, struct in_addr *mask)
jjako163b4552004-12-30 15:33:58 +0000579{
Harald Weltebed35df2011-11-02 13:06:18 +0100580 return tun_route(this, dst, gateway, mask, 1);
jjako163b4552004-12-30 15:33:58 +0000581}
582
Harald Weltedda21ed2017-08-12 15:07:02 +0200583int tun_new(struct tun_t **tun, const char *dev_name)
jjakoa7cd2492003-04-11 09:40:12 +0000584{
jjakoec89e9f2004-01-10 06:38:43 +0000585
jjako409b8552004-02-04 22:57:41 +0000586#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100587 struct ifreq ifr;
jjako409b8552004-02-04 22:57:41 +0000588
jjako0fe0df02004-09-17 11:30:40 +0000589#elif defined(__FreeBSD__) || defined (__APPLE__)
Harald Weltebed35df2011-11-02 13:06:18 +0100590 char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
591 int devnum;
592 struct ifaliasreq areq;
593 int fd;
jjakoec89e9f2004-01-10 06:38:43 +0000594#endif
Harald Weltebed35df2011-11-02 13:06:18 +0100595
596 if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100597 SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100598 return EOF;
599 }
600
601 (*tun)->cb_ind = NULL;
602 (*tun)->addrs = 0;
603 (*tun)->routes = 0;
604
jjako409b8552004-02-04 22:57:41 +0000605#if defined(__linux__)
Harald Weltebed35df2011-11-02 13:06:18 +0100606 /* Open the actual tun device */
607 if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100608 SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200609 goto err_free;
Harald Weltebed35df2011-11-02 13:06:18 +0100610 }
611
612 /* Set device flags. For some weird reason this is also the method
613 used to obtain the network interface name */
614 memset(&ifr, 0, sizeof(ifr));
Harald Weltedda21ed2017-08-12 15:07:02 +0200615 if (dev_name)
616 strcpy(ifr.ifr_name, dev_name);
Harald Weltebed35df2011-11-02 13:06:18 +0100617 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
618 if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100619 SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200620 goto err_close;
Harald Weltebed35df2011-11-02 13:06:18 +0100621 }
622
623 strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
624 (*tun)->devname[IFNAMSIZ - 1] = 0;
625
626 ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
627 return 0;
628
jjako0fe0df02004-09-17 11:30:40 +0000629#elif defined(__FreeBSD__) || defined (__APPLE__)
jjakoec89e9f2004-01-10 06:38:43 +0000630
Harald Weltebed35df2011-11-02 13:06:18 +0100631 /* Find suitable device */
632 for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
633 snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
Harald Weltebed35df2011-11-02 13:06:18 +0100634 if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
635 break;
636 if (errno != EBUSY)
637 break;
638 }
639 if ((*tun)->fd < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100640 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100641 "Can't find tunnel device");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200642 goto err_free;
Harald Weltebed35df2011-11-02 13:06:18 +0100643 }
jjakoec89e9f2004-01-10 06:38:43 +0000644
Harald Weltebed35df2011-11-02 13:06:18 +0100645 snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
Harald Welte81bc2ae2017-08-11 12:56:30 +0200646 (*tun)->devname[sizeof((*tun)->devname)-1] = 0;
jjako1f158642004-02-05 20:39:57 +0000647
Harald Weltebed35df2011-11-02 13:06:18 +0100648 /* The tun device we found might have "old" IP addresses allocated */
649 /* We need to delete those. This problem is not present on Linux */
jjako1f158642004-02-05 20:39:57 +0000650
Harald Weltebed35df2011-11-02 13:06:18 +0100651 memset(&areq, 0, sizeof(areq));
jjako1f158642004-02-05 20:39:57 +0000652
Harald Weltebed35df2011-11-02 13:06:18 +0100653 /* Set up interface name */
654 strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
655 areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
jjako1f158642004-02-05 20:39:57 +0000656
Harald Weltebed35df2011-11-02 13:06:18 +0100657 /* Create a channel to the NET kernel. */
658 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100659 SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
Harald Welte9e6dfa02017-08-12 15:06:19 +0200660 goto err_close;
Harald Weltebed35df2011-11-02 13:06:18 +0100661 }
jjako1f158642004-02-05 20:39:57 +0000662
Harald Weltebed35df2011-11-02 13:06:18 +0100663 /* Delete any IP addresses until SIOCDIFADDR fails */
664 while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
665
666 close(fd);
667 return 0;
jjako409b8552004-02-04 22:57:41 +0000668#endif
669
Harald Welte9e6dfa02017-08-12 15:06:19 +0200670err_close:
671 close((*tun)->fd);
672err_free:
673 free(*tun);
674 *tun = NULL;
675 return -1;
jjako52c24142002-12-16 13:33:51 +0000676}
677
jjakoa7cd2492003-04-11 09:40:12 +0000678int tun_free(struct tun_t *tun)
jjako52c24142002-12-16 13:33:51 +0000679{
jjako163b4552004-12-30 15:33:58 +0000680
Harald Weltebed35df2011-11-02 13:06:18 +0100681 if (tun->routes) {
682 tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
683 }
jjako163b4552004-12-30 15:33:58 +0000684
Harald Weltebed35df2011-11-02 13:06:18 +0100685 if (close(tun->fd)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100686 SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100687 }
jjakoa7cd2492003-04-11 09:40:12 +0000688
Harald Weltebed35df2011-11-02 13:06:18 +0100689 /* TODO: For solaris we need to unlink streams */
jjakoec89e9f2004-01-10 06:38:43 +0000690
Harald Weltebed35df2011-11-02 13:06:18 +0100691 free(tun);
692 return 0;
jjako52c24142002-12-16 13:33:51 +0000693}
694
Harald Weltebed35df2011-11-02 13:06:18 +0100695int tun_set_cb_ind(struct tun_t *this,
696 int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
697{
698 this->cb_ind = cb_ind;
699 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000700}
701
jjakoa7cd2492003-04-11 09:40:12 +0000702int tun_decaps(struct tun_t *this)
jjako52c24142002-12-16 13:33:51 +0000703{
Harald Weltebed35df2011-11-02 13:06:18 +0100704 unsigned char buffer[PACKET_MAX];
705 int status;
jjako52c24142002-12-16 13:33:51 +0000706
Harald Weltebed35df2011-11-02 13:06:18 +0100707 if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100708 SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
Harald Weltebed35df2011-11-02 13:06:18 +0100709 return -1;
710 }
711
712 if (this->cb_ind)
713 return this->cb_ind(this, buffer, status);
714
715 return 0;
jjako52c24142002-12-16 13:33:51 +0000716}
717
718int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
719{
Harald Weltebed35df2011-11-02 13:06:18 +0100720 return write(tun->fd, pack, len);
jjakoa7cd2492003-04-11 09:40:12 +0000721}
722
Harald Weltebed35df2011-11-02 13:06:18 +0100723int tun_runscript(struct tun_t *tun, char *script)
724{
jjakoa7cd2492003-04-11 09:40:12 +0000725
Harald Weltebed35df2011-11-02 13:06:18 +0100726 char buf[TUN_SCRIPTSIZE];
727 char snet[TUN_ADDRSIZE];
728 char smask[TUN_ADDRSIZE];
729 int rc;
730
731 strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
732 snet[sizeof(snet) - 1] = 0;
733 strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
734 smask[sizeof(smask) - 1] = 0;
735
736 /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
737 snprintf(buf, sizeof(buf), "%s %s %s %s",
738 script, tun->devname, snet, smask);
739 buf[sizeof(buf) - 1] = 0;
740 rc = system(buf);
741 if (rc == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100742 SYS_ERR(DTUN, LOGL_ERROR, errno,
Harald Weltebed35df2011-11-02 13:06:18 +0100743 "Error executing command %s", buf);
744 return -1;
745 }
746 return 0;
jjako52c24142002-12-16 13:33:51 +0000747}
Harald Weltef85fe972017-09-24 20:00:34 +0800748
749#include <ifaddrs.h>
750
Harald Welte4c7d2912017-11-08 15:19:17 +0900751/*! Obtain the local address of a network device
752 * \param[in] devname Target device owning the IP
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200753 * \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
754 * \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
755 * \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
756 * \returns The number of ips found following the criteria specified by flags, -1 on error.
757 *
758 * This function will fill prefix_list with up to prefix_size IPs following the
759 * criteria specified by flags parameter. It returns the number of IPs matching
760 * the criteria. As a result, the number returned can be bigger than
761 * prefix_size. It can be used with prefix_size=0 to get an estimate of the size
762 * needed for prefix_list.
763 */
Harald Welte4c7d2912017-11-08 15:19:17 +0900764int netdev_ip_local_get(const char *devname, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
Harald Weltef85fe972017-09-24 20:00:34 +0800765{
Harald Weltef85fe972017-09-24 20:00:34 +0800766 static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200767 struct ifaddrs *ifaddr, *ifa;
768 struct in46_addr netmask;
769 size_t count = 0;
770 bool is_ipv6_ll;
Harald Weltef85fe972017-09-24 20:00:34 +0800771
772 if (getifaddrs(&ifaddr) == -1) {
773 return -1;
774 }
775
776 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
Harald Weltef85fe972017-09-24 20:00:34 +0800777 if (ifa->ifa_addr == NULL)
778 continue;
779
Harald Welte4c7d2912017-11-08 15:19:17 +0900780 if (strcmp(ifa->ifa_name, devname))
Harald Weltef85fe972017-09-24 20:00:34 +0800781 continue;
782
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200783 if (ifa->ifa_addr->sa_family == AF_INET && (flags & IP_TYPE_IPv4)) {
784 struct sockaddr_in *sin4 = (struct sockaddr_in *) ifa->ifa_addr;
785 struct sockaddr_in *netmask4 = (struct sockaddr_in *) ifa->ifa_netmask;
Harald Weltef85fe972017-09-24 20:00:34 +0800786
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200787 if (count < prefix_size) {
788 netmask.len = sizeof(netmask4->sin_addr);
789 netmask.v4 = netmask4->sin_addr;
790 prefix_list[count].addr.len = sizeof(sin4->sin_addr);
791 prefix_list[count].addr.v4 = sin4->sin_addr;
792 prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
793 }
794 count++;
795 }
796
797 if (ifa->ifa_addr->sa_family == AF_INET6 && (flags & IP_TYPE_IPv6)) {
798 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
799 struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) ifa->ifa_netmask;
800
801 is_ipv6_ll = !memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix));
802 if ((flags & IP_TYPE_IPv6_NONLINK) && is_ipv6_ll)
803 continue;
804 if ((flags & IP_TYPE_IPv6_LINK) && !is_ipv6_ll)
805 continue;
806
807 if (count < prefix_size) {
808 netmask.len = sizeof(netmask6->sin6_addr);
809 netmask.v6 = netmask6->sin6_addr;
810 prefix_list[count].addr.len = sizeof(sin6->sin6_addr);
811 prefix_list[count].addr.v6 = sin6->sin6_addr;
812 prefix_list[count].prefixlen = in46a_netmasklen(&netmask);
813 }
814 count++;
815 }
Harald Weltef85fe972017-09-24 20:00:34 +0800816 }
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200817
Pau Espin Pedrol58c0da72017-10-12 16:42:46 +0200818 freeifaddrs(ifaddr);
Pau Espin Pedrola037e592017-10-16 14:41:37 +0200819 return count;
Harald Weltef85fe972017-09-24 20:00:34 +0800820}
Harald Welte4c7d2912017-11-08 15:19:17 +0900821
822/*! Obtain the local address of the tun device.
823 * \param[in] tun Target device owning the IP
824 * \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
825 * \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
826 * \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
827 * \returns The number of ips found following the criteria specified by flags, -1 on error.
828 *
829 * This function will fill prefix_list with up to prefix_size IPs following the
830 * criteria specified by flags parameter. It returns the number of IPs matching
831 * the criteria. As a result, the number returned can be bigger than
832 * prefix_size. It can be used with prefix_size=0 to get an estimate of the size
833 * needed for prefix_list.
834 */
835int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
836{
837 return netdev_ip_local_get(tun->devname, prefix_list, prefix_size, flags);
838}