New revision of the Tunnel6 client with improvements and routed prefix support
[tunnel6.git] / client / src / tun / win.c
blob481ace43c6118168456845a1105d23cf7320a406
1 /*
2 * tunnel6
3 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef __WIN32__
22 #include <windows.h>
23 #include <objbase.h>
24 #include <winioctl.h>
25 #include <ws2tcpip.h>
26 #include <stdio.h>
27 #include "ipv6.h"
28 #include "tunnel.h"
29 #include "packet.h"
30 #include "defaults.h"
33 * Thanks for OpenVPN to TAP-WIN32
34 * Thanks for CloudVPN, respectively P2PVPN
35 * Without them this code could'nt exist
38 /* Registry IDs of TAP device */
39 #define TAP_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
40 #define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
42 /* Driver name of the TUN/TAP required by tunnel6 */
43 #define TAP_COMPONENT_ID "tap0901"
45 #define USERMODEDEVICEDIR "\\\\.\\Global\\"
46 #define TAPSUFFIX ".tap"
48 #define TAP_CONTROL_CODE(request,method) CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
50 #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
52 /* NDP Neighbour packet type */
53 #define NDP_TYPE_NBSOL 135
54 #define NDP_TYPE_NBADV 136
56 /* NDP protool header */
57 struct proto_ndp_t {
58 unsigned char type;
59 unsigned char code;
60 unsigned short checksum;
61 unsigned flags;
62 ipv6_addr_t target;
64 /* ICMPv6 options */
65 unsigned char ll_type;
66 unsigned char ll_length;
67 mac_addr_t ll_mac;
70 /* pseudo-header for icmp6 checksum */
71 typedef struct proto_ipv6_pseudo_t {
72 unsigned short ip_source[8];
73 unsigned short ip_dest[8];
74 unsigned pl_len;
75 unsigned zero:24;
76 unsigned char next_head;
77 } proto_ipv6_pseudo_t;
79 static HANDLE fd; /* FD of TUN/TAP device */
80 static OVERLAPPED o_read, o_write;
82 static int read_in_progress = 0;
83 static DWORD read_result = 0;
85 /* data buffers */
86 static char buf_prealloc[DEFAULT_MTU + 64];
87 static char data[DEFAULT_MTU + 64];
88 static char data_thr[DEFAULT_MTU + 64];
90 static char *dev; /* System name of the device */
92 int tundev_arch_send (char *packet, unsigned len);
94 extern ipv6_addr_t tunip;
95 extern ipv6_addr_t tungw;
97 static int findTapDevice (char *deviceID, int deviceIDLen, char *deviceName, int deviceNameLen)
99 HKEY adapterKey;
100 int i;
101 LONG status;
102 DWORD len;
103 char keyI[1024];
104 char keyName[1024];
105 HKEY key;
107 status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapterKey);
109 if (status != ERROR_SUCCESS) {
110 printf ("Could not open key '%s'!\n", TAP_ADAPTER_KEY);
111 return 1;
114 strncpy (deviceID, "", deviceIDLen);
116 for (i = 0; !deviceID[0] && RegEnumKey (adapterKey, i, keyI, sizeof (keyI)) == ERROR_SUCCESS; i++) {
117 char componentId[256];
119 snprintf (keyName, sizeof (keyName), "%s\\%s", TAP_ADAPTER_KEY, keyI);
121 status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
123 if (status != ERROR_SUCCESS) {
124 printf ("Could not open key '%s'!\n", keyName);
125 return 1;
128 len = sizeof (componentId);
129 status = RegQueryValueEx (key, "ComponentId", NULL, NULL, (BYTE *) componentId, &len);
131 if (status == ERROR_SUCCESS && !strcmp (componentId, TAP_COMPONENT_ID)) {
132 len = deviceIDLen;
133 RegQueryValueEx (key, "NetCfgInstanceId", NULL, NULL, (BYTE *) deviceID, &len);
136 RegCloseKey (key);
139 RegCloseKey (adapterKey);
141 if (deviceID[0] == 0)
142 return 1;
144 snprintf (keyName, sizeof (keyName), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, deviceID);
146 status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
148 if (status != ERROR_SUCCESS)
149 return 1;
151 len = deviceNameLen;
152 status = RegQueryValueEx (key, "Name", NULL, NULL, (BYTE *) deviceName, &len);
154 RegCloseKey (key);
156 if (status != ERROR_SUCCESS)
157 return 1;
159 return 0;
162 static int tundev_arch_alloc ()
164 char deviceId[256];
165 char deviceName[256];
166 char tapPath[256];
167 unsigned long len = 0;
168 int status;
170 if (findTapDevice (deviceId, sizeof (deviceId), deviceName, sizeof (deviceName))) {
171 printf ("ERROR -> Can't find TAP device !\n");
172 return -1;
175 dev = strdup (deviceName);
177 if (!dev)
178 return -1;
180 printf ("Device: '%s'\n", deviceName);
182 snprintf (tapPath, sizeof (tapPath), "%s%s%s", USERMODEDEVICEDIR, deviceId, TAPSUFFIX);
184 fd = CreateFile (tapPath, GENERIC_READ | GENERIC_WRITE, 0, 0,
185 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
187 if (fd == INVALID_HANDLE_VALUE) {
188 printf ("Could not open `%s'!\n", tapPath);
189 return -1;
192 status = TRUE;
194 /* set device status to UP */
195 DeviceIoControl (fd, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof (status),
196 &status, sizeof (status), &len, NULL);
198 o_read.Offset = 0;
199 o_read.OffsetHigh = 0;
200 o_write.Offset = 0;
201 o_write.OffsetHigh = 0;
203 printf ("> TAP -> OK\n");
205 return 0;
208 /* receive packet from TAP device */
209 int tundev_arch_recv ()
211 if (read_in_progress) {
212 if (!GetOverlappedResult (fd, &o_read, &read_result, FALSE) )
213 return -1;
215 read_in_progress = 0;
217 return read_result;
220 if (ReadFile (fd, data_thr, DEFAULT_MTU, &read_result, &o_read))
221 return read_result;
223 int i = GetLastError ();
225 if (i == ERROR_IO_PENDING)
226 read_in_progress = 1;
227 else
228 printf ("error %d on iface read\n", i);
230 return -1;
233 unsigned short checksum16_ones (unsigned sum, const void *_buf, int len)
235 const unsigned short *buf = _buf;
237 while (len >= 2) {
238 sum += *buf ++;
240 if (sum & 0x80000000)
241 sum = (sum & 0xffff) + (sum >> 16);
243 len -= 2;
246 if (len) {
247 unsigned char temp[2];
249 temp[0] = *(unsigned char *) buf;
250 temp[1] = 0;
252 sum += *(unsigned short *) temp;
255 while (sum >> 16)
256 sum = (sum & 0xffff) + (sum >> 16);
258 return sum;
261 unsigned short checksum16 (void *_buf, int len)
263 return ~checksum16_ones (0, _buf, len);
266 /* calculate packet checksum */
267 unsigned short checksum16_ipv6 (unsigned short ip_source[8], unsigned short ip_dest[8], char *buf, unsigned len, unsigned char proto)
269 char *buf_pseudo = (char *) &buf_prealloc;
271 if (!buf_pseudo)
272 return 0;
274 proto_ipv6_pseudo_t *pseudo = (proto_ipv6_pseudo_t *) buf_pseudo;
276 memcpy (pseudo->ip_source, ip_source, 16);
277 memcpy (pseudo->ip_dest, ip_dest, 16);
279 pseudo->pl_len = htonl (len);
280 pseudo->zero = 0x0;
281 pseudo->next_head = proto;
283 memcpy (buf_pseudo+40, buf, len);
285 buf_pseudo[len+40] = '\0';
287 unsigned short ret = checksum16 (buf_pseudo, len+40);
289 return ret;
292 /* send neighbour advertisement - we lie about existing address :-B */
293 int ndp_reply (char *buf)
295 struct proto_ipv6_t *ip = (struct proto_ipv6_t *) buf;
296 struct proto_ndp_t *ndp = (struct proto_ndp_t *) ((char *) buf + sizeof (struct proto_ipv6_t));
298 /* check for neighbour solicitation packet */
299 if (ndp->type != NDP_TYPE_NBSOL)
300 return -1;
302 /* build a new packet */
303 char packet[sizeof (struct proto_ipv6_t) + sizeof (struct proto_ndp_t) + 1];
305 /* IPv6 layer */
306 struct proto_ipv6_t *packet_ip = (struct proto_ipv6_t *) ((char *) &packet);
308 packet_ip->ver = 0x60;
309 packet_ip->tclass = 0x0;
310 packet_ip->flabel = 0x0;
311 packet_ip->pl_len = htons (32);
312 packet_ip->nhead = IPV6_TYPE_ICMPv6;
313 packet_ip->hop = 0xff;
314 memcpy (packet_ip->src, (void *) ndp->target, sizeof (ipv6_addr_t));
315 memcpy (packet_ip->dest, (void *) ip->src, sizeof (ipv6_addr_t));
317 /* ICMPv6 - NDP layer */
318 struct proto_ndp_t *packet_ndp = (struct proto_ndp_t *) ((char *) &packet + sizeof (struct proto_ipv6_t));
320 packet_ndp->type = NDP_TYPE_NBADV;
321 packet_ndp->code = 0;
322 packet_ndp->flags = htonl (0xe0);
323 memcpy (packet_ndp->target, (void *) ndp->target, sizeof (ipv6_addr_t));
325 packet_ndp->ll_type = 2;
326 packet_ndp->ll_length = 1;
328 /* fake MAC address */
329 packet_ndp->ll_mac[0] = 0x00;
330 packet_ndp->ll_mac[1] = 0xff;
331 packet_ndp->ll_mac[2] = 0x25;
332 packet_ndp->ll_mac[3] = 0x02;
333 packet_ndp->ll_mac[4] = 0x19;
334 packet_ndp->ll_mac[5] = 0x78;
336 packet_ndp->checksum = 0x0;
338 /* calculate checksum */
339 packet_ndp->checksum = checksum16_ipv6 (packet_ip->src, packet_ip->dest, (char *) packet_ndp, sizeof (struct proto_ndp_t), IPV6_TYPE_ICMPv6);
341 /* send RAW packet */
342 return tundev_arch_send (packet, sizeof (struct proto_ipv6_t) + sizeof (struct proto_ndp_t));
345 DWORD WINAPI tundev_recv_thread (LPVOID arg)
347 for (;;) {
348 int ret = tundev_arch_recv ();
350 if (ret < 1) {
351 Sleep (1);
352 continue;
355 struct proto_ipv6_t *ip = (struct proto_ipv6_t *) ((char *) &data_thr + sizeof (struct proto_eth_t));
357 if (!ipv6_cmp (ip->src, tunip)) {
358 // printf ("WARNING -> This is not our packet\n");
359 continue;
362 if (!ndp_reply ((char *) ip))
363 continue;
365 tunnel_send ((char *) ip, ret - sizeof (struct proto_eth_t));
368 return 0;
371 int tundev_arch_poll ()
373 /* replaced by thread */
374 return 0;
377 int tundev_arch_send (char *packet, unsigned len)
379 struct proto_eth_t *eth = (struct proto_eth_t *) &data;
381 /* build IPv6 multicast packet */
382 eth->dest[0] = 0x33;
383 eth->dest[1] = 0x33;
384 eth->dest[2] = 0xff;
385 eth->dest[3] = 0x00;
386 eth->dest[4] = 0x00;
387 eth->dest[5] = 0x02;
389 eth->src[0] = 0x00;
390 eth->src[1] = 0xff;
391 eth->src[2] = 0x53;
392 eth->src[3] = 0x52;
393 eth->src[4] = 0x27;
394 eth->src[5] = 0x68;
396 eth->type = PACKET_TYPE_IPV6;
398 memcpy (data+sizeof (struct proto_eth_t), packet, len);
400 if (!WriteFile (fd, data, sizeof (struct proto_eth_t) + len, 0, &o_write)) {
401 /*we need to wait for operation to complete,
402 because if there was any overlapping, memory corruption
403 would happen. */
404 DWORD len = 0;
406 if (!GetOverlappedResult (fd, &o_write, &len, TRUE))
407 printf ("ERROR -> writing iface failed with %d", (int) GetLastError ());
410 return 0;
413 #ifndef inet_ntop
414 const char *inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
416 if (af == AF_INET) {
417 struct sockaddr_in in;
418 memset (&in, 0, sizeof (in));
419 in.sin_family = AF_INET;
420 memcpy (&in.sin_addr, src, sizeof (struct in_addr));
421 getnameinfo ((struct sockaddr *) &in, sizeof (struct
422 sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
424 return dst;
425 } else if (af == AF_INET6) {
426 struct sockaddr_in6 in;
427 memset(&in, 0, sizeof (in));
428 in.sin6_family = AF_INET6;
429 memcpy (&in.sin6_addr, src, sizeof (struct in_addr6));
430 getnameinfo ((struct sockaddr *) &in, sizeof (struct
431 sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
433 return dst;
436 return 0;
438 #endif
440 int tundev_arch_setup ()
442 /* needed for XP */
443 int r = system ("ipv6 install > NUL");
445 char ipv6[64];
446 inet_ntop (AF_INET6, &tunip, ipv6, 64);
448 sprintf (data, "netsh interface ipv6 add address \"%s\" %s > NUL", dev, ipv6);
449 printf ("> Setting new interface address: ");
450 r = system (data);
452 if (!r)
453 printf ("OK\n");
455 inet_ntop (AF_INET6, &tungw, ipv6, 64);
457 sprintf (data, "netsh interface ipv6 add route ::/0 \"%s\" %s > NUL", dev, ipv6);
458 printf ("> Setting new interface gateway: ");
459 r = system (data);
461 if (!r)
462 printf ("OK\n");
464 return 0;
467 int tundev_arch_init ()
469 if (tundev_arch_alloc () == -1)
470 return -1;
472 DWORD pID;
473 HANDLE h = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) tundev_recv_thread, 0, 0, &pID);
475 if (!h) {
476 printf ("ERROR -> receiver thread failed\n");
477 return -1;
480 return 0;
482 #endif