2 * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include <sys/types.h>
35 #define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
36 #define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE(10, METHOD_BUFFERED)
37 #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
39 #define TAP_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
40 #define TAP_DEVICE_SPACE "\\\\.\\Global\\"
41 #define TAP_VERSION_ID_0801 "tap0801"
42 #define TAP_VERSION_ID_0901 "tap0901"
43 #define KEY_COMPONENT_ID "ComponentId"
44 #define NET_CFG_INST_ID "NetCfgInstanceId"
47 #include <arpa/inet.h>
48 #include <netinet/in.h>
50 #define TUN_MAX_TRY 50
61 #include <sys/ioctl.h>
63 #include <linux/if_tun.h>
66 open_tun(const char *tun_device)
71 char *tunnel = "/dev/net/tun";
73 if ((tun_fd = open(tunnel, O_RDWR)) < 0) {
74 warn("open_tun: %s: %s", tunnel, strerror(errno));
78 memset(&ifreq, 0, sizeof(ifreq));
80 ifreq.ifr_flags = IFF_TUN;
82 if (tun_device != NULL) {
83 strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
84 ifreq.ifr_name[IFNAMSIZ-1] = '\0';
85 strncpy(if_name, tun_device, sizeof(if_name));
86 if_name[sizeof(if_name)-1] = '\0';
88 if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
89 fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
94 warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
98 for (i = 0; i < TUN_MAX_TRY; i++) {
99 snprintf(ifreq.ifr_name, IFNAMSIZ, "dns%d", i);
101 if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
102 fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
103 snprintf(if_name, sizeof(if_name), "dns%d", i);
107 if (errno != EBUSY) {
108 warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
113 warn("open_tun: Couldn't set interface name");
121 open_tun(const char *tun_device)
127 if (tun_device != NULL) {
128 snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
129 strncpy(if_name, tun_device, sizeof(if_name));
130 if_name[sizeof(if_name)-1] = '\0';
132 if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
133 warn("open_tun: %s: %s", tun_name, strerror(errno));
137 fprintf(stderr, "Opened %s\n", tun_name);
140 for (i = 0; i < TUN_MAX_TRY; i++) {
141 snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i);
143 if ((tun_fd = open(tun_name, O_RDWR)) >= 0) {
144 fprintf(stderr, "Opened %s\n", tun_name);
145 snprintf(if_name, sizeof(if_name), "tun%d", i);
153 warn("open_tun: Failed to open tunneling device");
160 #else /* WINDOWS32 */
162 get_device(char *device, int device_len)
169 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapter_key);
171 if (status != ERROR_SUCCESS) {
172 warnx("Error opening registry key " TAP_ADAPTER_KEY );
181 char cid_string[256] = KEY_COMPONENT_ID;
186 /* Iterate through all adapter of this kind */
188 status = RegEnumKeyEx(adapter_key, index, name, &len, NULL, NULL, NULL, NULL);
189 if (status == ERROR_NO_MORE_ITEMS) {
191 } else if (status != ERROR_SUCCESS) {
192 warnx("Error enumerating subkeys of registry key " TAP_ADAPTER_KEY );
196 snprintf(unit, sizeof(unit), TAP_ADAPTER_KEY "\\%s", name);
197 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit, 0, KEY_READ, &device_key);
198 if (status != ERROR_SUCCESS) {
199 warnx("Error opening registry key %s", unit);
203 /* Check component id */
204 len = sizeof(component);
205 status = RegQueryValueEx(device_key, cid_string, NULL, &datatype, (LPBYTE)component, &len);
206 if (status != ERROR_SUCCESS || datatype != REG_SZ) {
209 if (strncmp(TAP_VERSION_ID_0801, component, strlen(TAP_VERSION_ID_0801)) == 0 ||
210 strncmp(TAP_VERSION_ID_0901, component, strlen(TAP_VERSION_ID_0901)) == 0) {
211 /* We found a TAP32 device, get its NetCfgInstanceId */
212 char iid_string[256] = NET_CFG_INST_ID;
214 status = RegQueryValueEx(device_key, iid_string, NULL, &datatype, (LPBYTE) device, (DWORD *) &device_len);
215 if (status != ERROR_SUCCESS || datatype != REG_SZ) {
216 warnx("Error reading registry key %s\\%s on TAP device", unit, iid_string);
218 /* Done getting name of TAP device */
219 RegCloseKey(device_key);
224 RegCloseKey(device_key);
227 RegCloseKey(adapter_key);
230 DWORD WINAPI tun_reader(LPVOID arg)
232 struct tun_data *tun = arg;
239 sock = open_dns(0, INADDR_ANY);
241 olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
246 res = ReadFile(tun->tun, buf, sizeof(buf), (LPDWORD) &len, &olpd);
248 WaitForSingleObject(olpd.hEvent, INFINITE);
249 res = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE);
250 res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr),
251 sizeof(struct sockaddr_in));
259 open_tun(const char *tun_device)
266 memset(adapter, 0, sizeof(adapter));
267 get_device(adapter, sizeof(adapter));
269 if (strlen(adapter) == 0) {
270 warnx("No TAP adapters found. See README-win32.txt for help.\n");
274 snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter);
275 fprintf(stderr, "Opening device %s\n", tapfile);
276 dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
277 if (dev_handle == INVALID_HANDLE_VALUE) {
281 /* TODO get name of interface */
282 strncpy(if_name, "dns", MIN(4, sizeof(if_name)));
284 /* Use a UDP connection to forward packets from tun,
285 * so we can still use select() in main code.
286 * A thread does blocking reads on tun device and
287 * sends data as udp to this socket */
289 local = htonl(0x7f000001); /* 127.0.0.1 */
290 tunfd = open_dns(55353, local);
292 data.tun = dev_handle;
293 memset(&(data.addr), 0, sizeof(data.addr));
294 data.addr.sin_family = AF_INET;
295 data.addr.sin_port = htons(55353);
296 data.addr.sin_addr.s_addr = local;
297 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);
304 close_tun(int tun_fd)
311 write_tun(int tun_fd, char *data, size_t len)
313 #if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
316 #else /* !FREEBSD/DARWIN */
331 if (write(tun_fd, data, len) != len) {
335 #else /* WINDOWS32 */
343 olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
344 res = WriteFile(dev_handle, data, len, &written, &olpd);
345 if (!res && GetLastError() == ERROR_IO_PENDING) {
346 WaitForSingleObject(olpd.hEvent, INFINITE);
347 res = GetOverlappedResult(dev_handle, &olpd, &written, FALSE);
348 if (written != len) {
358 read_tun(int tun_fd, char *buf, size_t len)
360 #if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
361 /* FreeBSD/Darwin/NetBSD has no header */
363 bytes = recv(tun_fd, buf + 4, len, 0);
370 return read(tun_fd, buf, len);
371 #endif /* !FREEBSD */
375 tun_setip(const char *ip, int netbits)
392 for (i = 0; i < netbits; i++) {
393 netmask = (netmask << 1) | 1;
395 netmask <<= (32 - netbits);
396 net.s_addr = htonl(netmask);
398 if (inet_addr(ip) == INADDR_NONE) {
399 fprintf(stderr, "Invalid IP: %s!\n", ip);
403 snprintf(cmdline, sizeof(cmdline),
404 "/sbin/ifconfig %s %s %s netmask %s",
410 fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
416 snprintf(cmdline, sizeof(cmdline),
417 "/sbin/route add %s/%d %s",
420 fprintf(stderr, "Adding route %s/%d to %s\n", ip, netbits, ip);
422 return system(cmdline);
423 #else /* WINDOWS32 */
425 /* Set device as connected */
426 fprintf(stderr, "Enabling interface '%s'\n", if_name);
428 r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status,
429 sizeof(status), &status, sizeof(status), &len, NULL);
431 fprintf(stderr, "Failed to enable interface\n");
435 if (inet_aton(ip, &addr)) {
436 ipdata[0] = (DWORD) addr.s_addr; /* local ip addr */
437 ipdata[1] = net.s_addr & ipdata[0]; /* network addr */
438 ipdata[2] = (DWORD) net.s_addr; /* netmask */
443 /* Tell ip/networkaddr/netmask to device for arp use */
444 r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata,
445 sizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL);
447 fprintf(stderr, "Failed to set interface in TUN mode\n");
451 /* use netsh to set ip address */
452 fprintf(stderr, "Setting IP of interface '%s' to %s (can take a few seconds)...\n", if_name, ip);
453 snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address \"%s\" static %s %s",
454 if_name, ip, inet_ntoa(net));
455 return system(cmdline);
460 tun_setmtu(const unsigned mtu)
465 if (mtu > 200 && mtu <= 1500) {
466 snprintf(cmdline, sizeof(cmdline),
467 "/sbin/ifconfig %s mtu %u",
471 fprintf(stderr, "Setting MTU of %s to %u\n", if_name, mtu);
472 return system(cmdline);
474 warn("MTU out of range: %u\n", mtu);
478 #else /* WINDOWS32 */