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/>.
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 */
60 unsigned short checksum
;
65 unsigned char ll_type
;
66 unsigned char ll_length
;
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];
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;
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
)
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
);
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
);
128 len
= sizeof (componentId
);
129 status
= RegQueryValueEx (key
, "ComponentId", NULL
, NULL
, (BYTE
*) componentId
, &len
);
131 if (status
== ERROR_SUCCESS
&& !strcmp (componentId
, TAP_COMPONENT_ID
)) {
133 RegQueryValueEx (key
, "NetCfgInstanceId", NULL
, NULL
, (BYTE
*) deviceID
, &len
);
139 RegCloseKey (adapterKey
);
141 if (deviceID
[0] == 0)
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
)
152 status
= RegQueryValueEx (key
, "Name", NULL
, NULL
, (BYTE
*) deviceName
, &len
);
156 if (status
!= ERROR_SUCCESS
)
162 static int tundev_arch_alloc ()
165 char deviceName
[256];
167 unsigned long len
= 0;
170 if (findTapDevice (deviceId
, sizeof (deviceId
), deviceName
, sizeof (deviceName
))) {
171 printf ("ERROR -> Can't find TAP device !\n");
175 dev
= strdup (deviceName
);
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
);
194 /* set device status to UP */
195 DeviceIoControl (fd
, TAP_IOCTL_SET_MEDIA_STATUS
, &status
, sizeof (status
),
196 &status
, sizeof (status
), &len
, NULL
);
199 o_read
.OffsetHigh
= 0;
201 o_write
.OffsetHigh
= 0;
203 printf ("> TAP -> OK\n");
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
) )
215 read_in_progress
= 0;
220 if (ReadFile (fd
, data_thr
, DEFAULT_MTU
, &read_result
, &o_read
))
223 int i
= GetLastError ();
225 if (i
== ERROR_IO_PENDING
)
226 read_in_progress
= 1;
228 printf ("error %d on iface read\n", i
);
233 unsigned short checksum16_ones (unsigned sum
, const void *_buf
, int len
)
235 const unsigned short *buf
= _buf
;
240 if (sum
& 0x80000000)
241 sum
= (sum
& 0xffff) + (sum
>> 16);
247 unsigned char temp
[2];
249 temp
[0] = *(unsigned char *) buf
;
252 sum
+= *(unsigned short *) temp
;
256 sum
= (sum
& 0xffff) + (sum
>> 16);
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
;
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
);
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);
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
)
302 /* build a new packet */
303 char packet
[sizeof (struct proto_ipv6_t
) + sizeof (struct proto_ndp_t
) + 1];
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
)
348 int ret
= tundev_arch_recv ();
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");
362 if (!ndp_reply ((char *) ip
))
365 tunnel_send ((char *) ip
, ret
- sizeof (struct proto_eth_t
));
371 int tundev_arch_poll ()
373 /* replaced by thread */
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 */
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
406 if (!GetOverlappedResult (fd
, &o_write
, &len
, TRUE
))
407 printf ("ERROR -> writing iface failed with %d", (int) GetLastError ());
414 const char *inet_ntop (int af
, const void *src
, char *dst
, socklen_t cnt
)
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
);
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
);
440 int tundev_arch_setup ()
443 int r
= system ("ipv6 install > NUL");
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: ");
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: ");
467 int tundev_arch_init ()
469 if (tundev_arch_alloc () == -1)
473 HANDLE h
= CreateThread (NULL
, 0, (LPTHREAD_START_ROUTINE
) tundev_recv_thread
, 0, 0, &pID
);
476 printf ("ERROR -> receiver thread failed\n");