Refresh existing patches.
[debian/iodine.git] / src / tun.c
1 /*
2  * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
3  * 2006-2009 Bjorn Andersson <flex@kryo.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <stdint.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #ifndef IFCONFIGPATH
29 #define IFCONFIGPATH "PATH=/sbin:/bin "
30 #endif
31
32 #ifdef WINDOWS32
33 #include "windows.h"
34 #include <winioctl.h>
35
36 static HANDLE dev_handle;
37 static struct tun_data data;
38
39 static void get_name(char *ifname, int namelen, char *dev_name);
40
41 #define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
42 #define TAP_IOCTL_CONFIG_TUN       TAP_CONTROL_CODE(10, METHOD_BUFFERED)
43 #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
44
45 #define TAP_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
46 #define NETWORK_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
47 #define TAP_DEVICE_SPACE "\\\\.\\Global\\"
48 #define TAP_VERSION_ID_0801 "tap0801"
49 #define TAP_VERSION_ID_0901 "tap0901"
50 #define KEY_COMPONENT_ID "ComponentId"
51 #define NET_CFG_INST_ID "NetCfgInstanceId"
52 #else
53 #include <err.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
56
57 #define TUN_MAX_TRY 50
58 #endif
59
60 #include "tun.h"
61 #include "common.h"
62
63 static char if_name[250];
64
65 #ifdef LINUX
66
67 #include <sys/ioctl.h>
68 #include <net/if.h>
69 #include <linux/if_tun.h>
70
71 int
72 open_tun(const char *tun_device)
73 {
74         int i;
75         int tun_fd;
76         struct ifreq ifreq;
77 #ifdef ANDROID
78         char *tunnel = "/dev/tun";
79 #else
80         char *tunnel = "/dev/net/tun";
81 #endif
82
83         if ((tun_fd = open(tunnel, O_RDWR)) < 0) {
84                 warn("open_tun: %s: %s", tunnel, strerror(errno));
85                 return -1;
86         }
87
88         memset(&ifreq, 0, sizeof(ifreq));
89
90         ifreq.ifr_flags = IFF_TUN;
91
92         if (tun_device != NULL) {
93                 strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
94                 ifreq.ifr_name[IFNAMSIZ-1] = '\0';
95                 strncpy(if_name, tun_device, sizeof(if_name));
96                 if_name[sizeof(if_name)-1] = '\0';
97
98                 if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
99                         fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
100                         fd_set_close_on_exec(tun_fd);
101                         return tun_fd;
102                 }
103
104                 if (errno != EBUSY) {
105                         warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
106                         return -1;
107                 }
108         } else {
109                 for (i = 0; i < TUN_MAX_TRY; i++) {
110                         snprintf(ifreq.ifr_name, IFNAMSIZ, "dns%d", i);
111
112                         if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
113                                 fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
114                                 snprintf(if_name, sizeof(if_name), "dns%d", i);
115                                 fd_set_close_on_exec(tun_fd);
116                                 return tun_fd;
117                         }
118
119                         if (errno != EBUSY) {
120                                 warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
121                                 return -1;
122                         }
123                 }
124
125                 warn("open_tun: Couldn't set interface name");
126         }
127         warn("error when opening tun");
128         return -1;
129 }
130
131 #elif WINDOWS32
132
133 static void
134 get_device(char *device, int device_len, const char *wanted_dev)
135 {
136         LONG status;
137         HKEY adapter_key;
138         int index;
139
140         index = 0;
141         status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapter_key);
142
143         if (status != ERROR_SUCCESS) {
144                 warnx("Error opening registry key " TAP_ADAPTER_KEY );
145                 return;
146         }
147
148         while (TRUE) {
149                 char name[256];
150                 char unit[256];
151                 char component[256];
152
153                 char cid_string[256] = KEY_COMPONENT_ID;
154                 HKEY device_key;
155                 DWORD datatype;
156                 DWORD len;
157
158                 /* Iterate through all adapter of this kind */
159                 len = sizeof(name);
160                 status = RegEnumKeyEx(adapter_key, index, name, &len, NULL, NULL, NULL, NULL);
161                 if (status == ERROR_NO_MORE_ITEMS) {
162                         break;
163                 } else if (status != ERROR_SUCCESS) {
164                         warnx("Error enumerating subkeys of registry key " TAP_ADAPTER_KEY );
165                         break;
166                 }
167
168                 snprintf(unit, sizeof(unit), TAP_ADAPTER_KEY "\\%s", name);
169                 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit, 0, KEY_READ, &device_key);
170                 if (status != ERROR_SUCCESS) {
171                         warnx("Error opening registry key %s", unit);
172                         goto next;
173                 }
174
175                 /* Check component id */
176                 len = sizeof(component);
177                 status = RegQueryValueEx(device_key, cid_string, NULL, &datatype, (LPBYTE)component, &len);
178                 if (status != ERROR_SUCCESS || datatype != REG_SZ) {
179                         goto next;
180                 }
181                 if (strncmp(TAP_VERSION_ID_0801, component, strlen(TAP_VERSION_ID_0801)) == 0 ||
182                         strncmp(TAP_VERSION_ID_0901, component, strlen(TAP_VERSION_ID_0901)) == 0) {
183                         /* We found a TAP32 device, get its NetCfgInstanceId */
184                         char iid_string[256] = NET_CFG_INST_ID;
185
186                         status = RegQueryValueEx(device_key, iid_string, NULL, &datatype, (LPBYTE) device, (DWORD *) &device_len);
187                         if (status != ERROR_SUCCESS || datatype != REG_SZ) {
188                                 warnx("Error reading registry key %s\\%s on TAP device", unit, iid_string);
189                         } else {
190                                 /* Done getting GUID of TAP device,
191                                  * now check if the name is the requested one */
192                                 if (wanted_dev) {
193                                         char name[250];
194                                         get_name(name, sizeof(name), device);
195                                         if (strncmp(name, wanted_dev, strlen(wanted_dev))) {
196                                                 /* Skip if name mismatch */
197                                                 goto next;
198                                         }
199                                 }
200                                 /* Get the if name */
201                                 get_name(if_name, sizeof(if_name), device);
202                                 RegCloseKey(device_key);
203                                 return;
204                         }
205                 }
206 next:
207                 RegCloseKey(device_key);
208                 index++;
209         }
210         RegCloseKey(adapter_key);
211 }
212
213 static void
214 get_name(char *ifname, int namelen, char *dev_name)
215 {
216         char path[256];
217         char name_str[256] = "Name";
218         LONG status;
219         HKEY conn_key;
220         DWORD len;
221         DWORD datatype;
222
223         memset(ifname, 0, namelen);
224
225         snprintf(path, sizeof(path), NETWORK_KEY "\\%s\\Connection", dev_name);
226         status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &conn_key);
227         if (status != ERROR_SUCCESS) {
228                 fprintf(stderr, "Could not look up name of interface %s: error opening key\n", dev_name);
229                 RegCloseKey(conn_key);
230                 return;
231         }
232         len = namelen;
233         status = RegQueryValueEx(conn_key, name_str, NULL, &datatype, (LPBYTE)ifname, &len);
234         if (status != ERROR_SUCCESS || datatype != REG_SZ) {
235                 fprintf(stderr, "Could not look up name of interface %s: error reading value\n", dev_name);
236                 RegCloseKey(conn_key);
237                 return;
238         }
239         RegCloseKey(conn_key);
240 }
241
242 DWORD WINAPI tun_reader(LPVOID arg)
243 {
244         struct tun_data *tun = arg;
245         char buf[64*1024];
246         int len;
247         int res;
248         OVERLAPPED olpd;
249         int sock;
250
251         sock = open_dns_from_host("127.0.0.1", 0, AF_INET, 0);
252
253         olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
254
255         while(TRUE) {
256                 olpd.Offset = 0;
257                 olpd.OffsetHigh = 0;
258                 res = ReadFile(tun->tun, buf, sizeof(buf), (LPDWORD) &len, &olpd);
259                 if (!res) {
260                         WaitForSingleObject(olpd.hEvent, INFINITE);
261                         res = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE);
262                         res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr),
263                                 tun->addrlen);
264                 }
265         }
266
267         return 0;
268 }
269
270 int
271 open_tun(const char *tun_device)
272 {
273         char adapter[256];
274         char tapfile[512];
275         int tunfd;
276         struct sockaddr_storage localsock;
277         int localsock_len;
278
279         memset(adapter, 0, sizeof(adapter));
280         memset(if_name, 0, sizeof(if_name));
281         get_device(adapter, sizeof(adapter), tun_device);
282
283         if (strlen(adapter) == 0 || strlen(if_name) == 0) {
284                 if (tun_device) {
285                         warnx("No TAP adapters found. Try without -d.");
286                 } else {
287                         warnx("No TAP adapters found. Version 0801 and 0901 are supported.");
288                 }
289                 return -1;
290         }
291
292         fprintf(stderr, "Opening device %s\n", if_name);
293         snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter);
294         dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
295         if (dev_handle == INVALID_HANDLE_VALUE) {
296                 warnx("Could not open device!");
297                 return -1;
298         }
299
300         /* Use a UDP connection to forward packets from tun,
301          * so we can still use select() in main code.
302          * A thread does blocking reads on tun device and
303          * sends data as udp to this socket */
304
305         localsock_len = get_addr("127.0.0.1", 55353, AF_INET, 0, &localsock);
306         tunfd = open_dns(&localsock, localsock_len);
307
308         data.tun = dev_handle;
309         memcpy(&(data.addr), &localsock, localsock_len);
310         data.addrlen = localsock_len;
311         CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);
312
313         return tunfd;
314 }
315
316 #else /* BSD and friends */
317
318 int
319 open_tun(const char *tun_device)
320 {
321         int i;
322         int tun_fd;
323         char tun_name[50];
324
325         if (tun_device != NULL) {
326                 snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
327                 strncpy(if_name, tun_device, sizeof(if_name));
328                 if_name[sizeof(if_name)-1] = '\0';
329
330                 if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
331                         warn("open_tun: %s: %s", tun_name, strerror(errno));
332                         return -1;
333                 }
334
335                 fprintf(stderr, "Opened %s\n", tun_name);
336                 fd_set_close_on_exec(tun_fd);
337                 return tun_fd;
338         } else {
339                 for (i = 0; i < TUN_MAX_TRY; i++) {
340                         snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i);
341
342                         if ((tun_fd = open(tun_name, O_RDWR)) >= 0) {
343                                 fprintf(stderr, "Opened %s\n", tun_name);
344                                 snprintf(if_name, sizeof(if_name), "tun%d", i);
345                                 fd_set_close_on_exec(tun_fd);
346                                 return tun_fd;
347                         }
348
349                         if (errno == ENOENT)
350                                 break;
351                 }
352
353                 warn("open_tun: Failed to open tunneling device");
354         }
355
356         return -1;
357 }
358
359 #endif
360
361 void
362 close_tun(int tun_fd)
363 {
364         if (tun_fd >= 0)
365                 close(tun_fd);
366 }
367
368 #ifdef WINDOWS32
369 int
370 write_tun(int tun_fd, char *data, size_t len)
371 {
372         DWORD written;
373         DWORD res;
374         OVERLAPPED olpd;
375
376         data += 4;
377         len -= 4;
378
379         olpd.Offset = 0;
380         olpd.OffsetHigh = 0;
381         olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
382         res = WriteFile(dev_handle, data, len, &written, &olpd);
383         if (!res && GetLastError() == ERROR_IO_PENDING) {
384                 WaitForSingleObject(olpd.hEvent, INFINITE);
385                 res = GetOverlappedResult(dev_handle, &olpd, &written, FALSE);
386                 if (written != len) {
387                         return -1;
388                 }
389         }
390         return 0;
391 }
392
393 ssize_t
394 read_tun(int tun_fd, char *buf, size_t len)
395 {
396         int bytes;
397         memset(buf, 0, 4);
398
399         bytes = recv(tun_fd, buf + 4, len - 4, 0);
400         if (bytes < 0) {
401                 return bytes;
402         } else {
403                 return bytes + 4;
404         }
405 }
406 #else
407 int
408 write_tun(int tun_fd, char *data, size_t len)
409 {
410 #if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
411         data += 4;
412         len -= 4;
413 #else /* !FREEBSD/DARWIN */
414 #ifdef LINUX
415         data[0] = 0x00;
416         data[1] = 0x00;
417         data[2] = 0x08;
418         data[3] = 0x00;
419 #else /* OPENBSD */
420         data[0] = 0x00;
421         data[1] = 0x00;
422         data[2] = 0x00;
423         data[3] = 0x02;
424 #endif /* !LINUX */
425 #endif /* FREEBSD */
426
427         if (write(tun_fd, data, len) != len) {
428                 warn("write_tun");
429                 return 1;
430         }
431         return 0;
432 }
433
434 ssize_t
435 read_tun(int tun_fd, char *buf, size_t len)
436 {
437 #if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
438         /* FreeBSD/Darwin/NetBSD has no header */
439         int bytes;
440         memset(buf, 0, 4);
441
442         bytes = read(tun_fd, buf + 4, len - 4);
443         if (bytes < 0) {
444                 return bytes;
445         } else {
446                 return bytes + 4;
447         }
448 #else /* !FREEBSD */
449         return read(tun_fd, buf, len);
450 #endif /* !FREEBSD */
451 }
452 #endif
453
454 int
455 tun_setip(const char *ip, const char *other_ip, int netbits)
456 {
457         char cmdline[512];
458         int netmask;
459         struct in_addr net;
460         int i;
461 #ifndef LINUX
462         int r;
463 #endif
464 #ifdef WINDOWS32
465         DWORD status;
466         DWORD ipdata[3];
467         struct in_addr addr;
468         DWORD len;
469 #else
470         const char *display_ip;
471 #ifndef LINUX
472         struct in_addr netip;
473 #endif
474 #endif
475
476         netmask = 0;
477         for (i = 0; i < netbits; i++) {
478                 netmask = (netmask << 1) | 1;
479         }
480         netmask <<= (32 - netbits);
481         net.s_addr = htonl(netmask);
482
483         if (inet_addr(ip) == INADDR_NONE) {
484                 fprintf(stderr, "Invalid IP: %s!\n", ip);
485                 return 1;
486         }
487 #ifndef WINDOWS32
488 # ifdef FREEBSD
489         display_ip = other_ip; /* FreeBSD wants other IP as second IP */
490 # else
491         display_ip = ip;
492 # endif
493         snprintf(cmdline, sizeof(cmdline),
494                         IFCONFIGPATH "ifconfig %s %s %s netmask %s",
495                         if_name,
496                         ip,
497                         display_ip,
498                         inet_ntoa(net));
499
500         fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
501 #ifndef LINUX
502         netip.s_addr = inet_addr(ip);
503         netip.s_addr = netip.s_addr & net.s_addr;
504         r = system(cmdline);
505         if(r != 0) {
506                 return r;
507         } else {
508
509                 snprintf(cmdline, sizeof(cmdline),
510                                 "/sbin/route add %s/%d %s",
511                                 inet_ntoa(netip), netbits, ip);
512         }
513         fprintf(stderr, "Adding route %s/%d to %s\n", inet_ntoa(netip), netbits, ip);
514 #endif
515         return system(cmdline);
516 #else /* WINDOWS32 */
517
518         /* Set device as connected */
519         fprintf(stderr, "Enabling interface '%s'\n", if_name);
520         status = 1;
521         r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status,
522                 sizeof(status), &status, sizeof(status), &len, NULL);
523         if (!r) {
524                 fprintf(stderr, "Failed to enable interface\n");
525                 return -1;
526         }
527
528         if (inet_aton(ip, &addr)) {
529                 ipdata[0] = (DWORD) addr.s_addr;   /* local ip addr */
530                 ipdata[1] = net.s_addr & ipdata[0]; /* network addr */
531                 ipdata[2] = (DWORD) net.s_addr;    /* netmask */
532         } else {
533                 return -1;
534         }
535
536         /* Tell ip/networkaddr/netmask to device for arp use */
537         r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata,
538                 sizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL);
539         if (!r) {
540                 fprintf(stderr, "Failed to set interface in TUN mode\n");
541                 return -1;
542         }
543
544         /* use netsh to set ip address */
545         fprintf(stderr, "Setting IP of interface '%s' to %s (can take a few seconds)...\n", if_name, ip);
546         snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address \"%s\" static %s %s",
547                 if_name, ip, inet_ntoa(net));
548         return system(cmdline);
549 #endif
550 }
551
552 int
553 tun_setmtu(const unsigned mtu)
554 {
555 #ifndef WINDOWS32
556         char cmdline[512];
557
558         if (mtu > 200 && mtu <= 1500) {
559                 snprintf(cmdline, sizeof(cmdline),
560                                 IFCONFIGPATH "ifconfig %s mtu %u",
561                                 if_name,
562                                 mtu);
563
564                 fprintf(stderr, "Setting MTU of %s to %u\n", if_name, mtu);
565                 return system(cmdline);
566         } else {
567                 warn("MTU out of range: %u\n", mtu);
568         }
569
570         return 1;
571 #else /* WINDOWS32 */
572
573         return 0;
574 #endif
575 }
576