More generic handling of tap device under Windows.

This commit is contained in:
Guus Sliepen 2003-07-28 21:54:03 +00:00
parent 83263b7446
commit c15e8a96bf
2 changed files with 516 additions and 607 deletions
src
cygwin
mingw

View file

@ -1,303 +1,291 @@
/* /*
device.c -- Interaction with CIPE driver in a Cygwin environment device.c -- Interaction with CIPE driver in a Cygwin environment
Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>, Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>,
2002-2003 Guus Sliepen <guus@sliepen.eu.org> 2002-2003 Guus Sliepen <guus@sliepen.eu.org>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c,v 1.1.2.10 2003/07/22 20:55:20 guus Exp $ $Id: device.c,v 1.1.2.11 2003/07/28 21:54:03 guus Exp $
*/ */
#include "system.h" #include "system.h"
#include <w32api/windows.h> #include <w32api/windows.h>
#include <w32api/winioctl.h> #include <w32api/winioctl.h>
#include "conf.h" #include "conf.h"
#include "logger.h" #include "logger.h"
#include "net.h" #include "net.h"
#include "route.h" #include "route.h"
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
/* Definitions from CIPE */ #define NETCARD_REG_KEY_2000 "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NETCARD_REG_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"
#define NETCARD_REG_KEY_2000 "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" #define REG_SERVICE_KEY "SYSTEM\\CurrentControlSet\\Services"
#define NETCARD_REG_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards" #define REG_CONTROL_NET "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define REG_SERVICE_KEY "SYSTEM\\CurrentControlSet\\Services"
#define USERMODEDEVICEDIR "\\\\.\\"
#define USERMODEDEVICEDIR "\\\\.\\" #define SYSDEVICEDIR "\\Device\\"
#define SYSDEVICEDIR "\\Device\\" #define USERDEVICEDIR "\\??\\"
#define USERDEVICEDIR "\\??\\" #define TAPSUFFIX ".tap"
#define TAPSUFFIX ".tap"
#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
#define PRODUCT_STRING "DKW Heavy Industries VPN Adapter."
#define CIPE_SERVICE_NAME "CIPE_Daemon" #define TAP_IOCTL_GET_LASTMAC TAP_CONTROL_CODE(0, METHOD_BUFFERED)
#define CIPE_DRIVER_NAME "CIPE" #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
#define TAP_IOCTL_SET_STATISTICS TAP_CONTROL_CODE(2, METHOD_BUFFERED)
#define CIPE_NDIS_MAJOR_VERSION 4
#define CIPE_NDIS_MINOR_VERSION 0 /* FIXME: This only works for Windows 2000 */
#define OSTYPE 5
#ifndef CIPE_DRIVER_MAJOR_VERSION
# define CIPE_DRIVER_MAJOR_VERSION 2 int device_fd = -1;
#endif char *device = NULL;
char *iface = NULL;
#ifndef CIPE_DRIVER_MINOR_VERSION char *device_info = NULL;
# define CIPE_DRIVER_MINOR_VERSION 1
#endif int device_total_in = 0;
int device_total_out = 0;
#ifndef CIPE_MAC_ROOT_ADDRESS
# define CIPE_MAC_ROOT_ADDRESS "8:0:58:0:0:1" HANDLE handle;
#endif
pid_t reader_pid;
#define CIPE_CONTROL_CODE(request,method) CTL_CODE (FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS) int sp[2];
#define CIPE_IOCTL_GET_LASTMAC CIPE_CONTROL_CODE (0, METHOD_BUFFERED) bool setup_device(void)
#define CIPE_IOCTL_GET_MAC CIPE_CONTROL_CODE (1, METHOD_BUFFERED) {
#define CIPE_IOCTL_SET_STATISTICS CIPE_CONTROL_CODE (2, METHOD_BUFFERED) HKEY key, key2;
int i;
/* Windows 2000 */
#define OSTYPE 5 char regpath[1024];
char adapterid[1024];
int device_fd = -1; char adaptername[1024];
char *device = NULL; char tapname[1024];
char *iface = NULL; char gelukt = 0;
char *device_info = NULL; long len;
int device_total_in = 0; bool found = false;
int device_total_out = 0;
cp();
HANDLE handle;
get_config_string(lookup_config(config_tree, "Device"), &device);
pid_t reader_pid; get_config_string(lookup_config(config_tree, "Interface"), &iface);
int sp[2];
/* Open registry and look for network adapters */
bool setup_device(void)
{ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_NET, 0, KEY_READ, &key)) {
HKEY key, key2, adapterkey; logger(LOG_ERR, _("Unable to read registry"));
int i; return false;
}
char adapterid[1024];
char manufacturer[1024]; for (i = 0; ; i++) {
char productname[1024]; len = sizeof(adapterid);
char adaptername[1024]; if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
char tapname[1024]; break;
char gelukt = 0;
long len; if(device) {
if(!strcmp(device, adapterid)) {
FILETIME filetime; found = true;
bool found = false; break;
} else
cp(); continue;
}
get_config_string(lookup_config(config_tree, "Device"), &device);
/* Find out more about this adapter */
/* Open registry and look for network adapters */
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", REG_CONTROL_NET, adapterid);
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, (OSTYPE > 4 ? NETCARD_REG_KEY_2000 : NETCARD_REG_KEY), 0, KEY_READ, &key)) {
logger(LOG_ERR, _("Unable to read registry")); if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) {
return false; logger(LOG_ERR, _("Unable to read registry"));
} return false;
}
for (i = 0; ; i++) {
len = sizeof(adapterid); len = sizeof(adaptername);
if(RegEnumKeyEx (key, i, adapterid, &len, 0, 0, 0, &filetime)) RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
break;
if(iface) {
/* Find out more about this adapter */ if(!strcmp(iface, adaptername)) {
found = true;
if(RegOpenKeyEx (key, adapterid, 0, KEY_READ, &adapterkey)) { break;
logger(LOG_ERR, _("Unable to read registry")); } else
return false; continue;
} }
len = sizeof(productname); snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
if(RegQueryValueEx(adapterkey, "ProductName", 0, 0, productname, &len)) handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
goto skip; if(handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
len = sizeof(manufacturer); found = true;
if(RegQueryValueEx(adapterkey, "Manufacturer", 0, 0, manufacturer, &len)) break;
goto skip; }
}
if(!strcmp(productname, "CIPE") && !strcmp(manufacturer, "DKWHeavyIndustries")) {
if(device && strcmp(adapterid, device)) if(!found) {
continue; logger(LOG_ERR, _("No Windows tap device found!"));
if(!device) return false;
device = xstrdup(adapterid); }
found = true;
break; device = adapterid;
} iface = adaptername;
skip: snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
RegCloseKey (adapterkey);
} /* Now we are going to open this device twice: once for reading and once for writing.
We do this because apparently it isn't possible to check for activity in the select() loop.
if(!found) { Furthermore I don't really know how to do it the "Windows" way. */
logger(LOG_ERR, _("No CIPE adapters found!"));
return false; if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
} logger(LOG_DEBUG, _("System call `%s' failed: %s"), "socketpair", strerror(errno));
return false;
/* Get adapter name */ }
len = sizeof(adaptername); /* The parent opens the tap device for writing. */
RegQueryValueEx(adapterkey, (OSTYPE > 4 ? "NetCfgInstanceId" : "ServiceName"), 0, 0, adaptername, &len);
handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
/* FIXME? cipsrvr checks if the device is in use at this point */
if(handle == INVALID_HANDLE_VALUE) {
/* Try to open the corresponding tap device */ logger(LOG_ERR, _("Could not open CIPE tap device for writing!"));
return false;
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adaptername); }
/* Now we are going to open this device twice: once for reading and once for writing. device_fd = sp[0];
We do this because apparently it isn't possible to check for activity in the select() loop.
Furthermore I don't really know how to do it the "Windows" way. */ /* Get MAC address from tap device */
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) { if(DeviceIoControl(device_fd, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "socketpair", strerror(errno)); logger(LOG_ERR, _("Could not get MAC address from Windows tap device!"));
return false; return false;
} }
reader_pid = fork(); if(routing_mode == RMODE_ROUTER) {
overwrite_mac = 1;
if(reader_pid == -1) { }
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "fork", strerror(errno));
return false; /* Now we start the child */
}
reader_pid = fork();
if(!reader_pid) {
/* The child opens the tap device for reading, blocking. if(reader_pid == -1) {
It passes everything it reads to the socket. */ logger(LOG_DEBUG, _("System call `%s' failed: %s"), "fork", strerror(errno));
return false;
char buf[MTU]; }
int lenin;
if(!reader_pid) {
handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0); /* The child opens the tap device for reading, blocking.
It passes everything it reads to the socket. */
if(handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, _("Could not open CIPE tap device for reading!")); char buf[MTU];
buf[0] = 0; int lenin;
write(sp[1], buf, 1);
exit(1); handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
}
if(handle == INVALID_HANDLE_VALUE) {
logger(LOG_DEBUG, _("Tap reader forked and running.")); logger(LOG_ERR, _("Could not open CIPE tap device for reading!"));
buf[0] = 0;
/* Notify success */ write(sp[1], buf, 1);
exit(1);
buf[0] = 1; }
write(sp[1], buf, 1);
logger(LOG_DEBUG, _("Tap reader forked and running."));
/* Pass packets */
/* Notify success */
for(;;) {
ReadFile (handle, buf, MTU, &lenin, NULL); buf[0] = 1;
write(sp[1], buf, lenin); write(sp[1], buf, 1);
}
} /* Pass packets */
/* The parent opens the tap device for writing. */ for(;;) {
ReadFile (handle, buf, MTU, &lenin, NULL);
handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0); write(sp[1], buf, lenin);
}
if(handle == INVALID_HANDLE_VALUE) { }
logger(LOG_ERR, _("Could not open CIPE tap device for writing!"));
return false; read(device_fd, &gelukt, 1);
} if(gelukt != 1) {
logger(LOG_DEBUG, "Tap reader failed!");
device_fd = sp[0]; return false;
}
/* Get MAC address from tap device */
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
if(routing_mode == RMODE_ROUTER) { iface = device;
DeviceIoControl (handle, CIPE_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0);
overwrite_mac = 1; device_info = _("Windows tap device");
}
logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info);
read(device_fd, &gelukt, 1);
if(gelukt != 1) { return false;
logger(LOG_DEBUG, "Tap reader failed!"); }
return false;
} void close_device(void)
{
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) cp();
iface = device;
close(sp[0]);
device_info = _("Cygwin CIPE device"); close(sp[1]);
CloseHandle(handle);
logger(LOG_INFO, _("%s is a %s"), device, device_info);
kill(reader_pid, SIGKILL);
return false; }
}
bool read_packet(vpn_packet_t *packet)
void close_device(void) {
{ int lenin;
cp();
cp();
close(sp[0]);
close(sp[1]); if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
CloseHandle(handle); logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
device, strerror(errno));
kill(reader_pid, SIGKILL); return false;
} }
bool read_packet(vpn_packet_t *packet) packet->len = lenin;
{
int lenin; device_total_in += packet->len;
cp(); ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
device_info);
if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, return true;
device, strerror(errno)); }
return false;
} bool write_packet(vpn_packet_t *packet)
{
packet->len = lenin; int lenout;
device_total_in += packet->len; cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len, ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
device_info); packet->len, device_info);
return true; if(!WriteFile (handle, packet->data, packet->len, &lenout, NULL)) {
} logger(LOG_ERR, "Error while writing to %s %s", device_info, device);
return false;
bool write_packet(vpn_packet_t *packet) }
{
int lenout; device_total_out += packet->len;
cp(); return true;
}
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
packet->len, device_info); void dump_device_stats(void)
{
if(!WriteFile (handle, packet->data, packet->len, &lenout, NULL)) { cp();
logger(LOG_ERR, "Error while writing to %s %s", device_info, device);
return false; logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
} logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
device_total_out += packet->len; }
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
}

View file

@ -1,304 +1,225 @@
/* /*
device.c -- Interaction with CIPE driver in a MinGW environment device.c -- Interaction with CIPE driver in a MinGW environment
Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>, Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>,
2002-2003 Guus Sliepen <guus@sliepen.eu.org> 2002-2003 Guus Sliepen <guus@sliepen.eu.org>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c,v 1.1.2.2 2003/07/22 20:55:21 guus Exp $ $Id: device.c,v 1.1.2.3 2003/07/28 21:54:03 guus Exp $
*/ */
#error "Device driver for MinGW environment not written yet!" #include "system.h"
#include "system.h" #include <windows.h>
#include <winioctl.h>
#include <winioctl.h>
#include "conf.h"
#include "conf.h" #include "logger.h"
#include "logger.h" #include "net.h"
#include "net.h" #include "route.h"
#include "route.h" #include "utils.h"
#include "utils.h" #include "xalloc.h"
#include "xalloc.h"
#define NETCARD_REG_KEY_2000 "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
/* Definitions from CIPE */ #define NETCARD_REG_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"
#define REG_SERVICE_KEY "SYSTEM\\CurrentControlSet\\Services"
#define NETCARD_REG_KEY_2000 "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" #define REG_CONTROL_NET "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NETCARD_REG_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"
#define REG_SERVICE_KEY "SYSTEM\\CurrentControlSet\\Services" #define USERMODEDEVICEDIR "\\\\.\\"
#define SYSDEVICEDIR "\\Device\\"
#define USERMODEDEVICEDIR "\\\\.\\" #define USERDEVICEDIR "\\??\\"
#define SYSDEVICEDIR "\\Device\\" #define TAPSUFFIX ".tap"
#define USERDEVICEDIR "\\??\\"
#define TAPSUFFIX ".tap" #define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
#define PRODUCT_STRING "DKW Heavy Industries VPN Adapter." #define TAP_IOCTL_GET_LASTMAC TAP_CONTROL_CODE(0, METHOD_BUFFERED)
#define CIPE_SERVICE_NAME "CIPE_Daemon" #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
#define CIPE_DRIVER_NAME "CIPE" #define TAP_IOCTL_SET_STATISTICS TAP_CONTROL_CODE(2, METHOD_BUFFERED)
#define CIPE_NDIS_MAJOR_VERSION 4 /* FIXME: This only works for Windows 2000 */
#define CIPE_NDIS_MINOR_VERSION 0 #define OSTYPE 5
#ifndef CIPE_DRIVER_MAJOR_VERSION HANDLE device_fd = INVALID_HANDLE_VALUE;
# define CIPE_DRIVER_MAJOR_VERSION 2 char *device = NULL;
#endif char *iface = NULL;
char *device_info = NULL;
#ifndef CIPE_DRIVER_MINOR_VERSION
# define CIPE_DRIVER_MINOR_VERSION 1 int device_total_in = 0;
#endif int device_total_out = 0;
#ifndef CIPE_MAC_ROOT_ADDRESS bool setup_device(void)
# define CIPE_MAC_ROOT_ADDRESS "8:0:58:0:0:1" {
#endif HKEY key, key2;
int i;
#define CIPE_CONTROL_CODE(request,method) CTL_CODE (FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
char regpath[1024];
#define CIPE_IOCTL_GET_LASTMAC CIPE_CONTROL_CODE (0, METHOD_BUFFERED) char adapterid[1024];
#define CIPE_IOCTL_GET_MAC CIPE_CONTROL_CODE (1, METHOD_BUFFERED) char adaptername[1024];
#define CIPE_IOCTL_SET_STATISTICS CIPE_CONTROL_CODE (2, METHOD_BUFFERED) char tapname[1024];
char gelukt = 0;
/* Windows 2000 */ long len;
#define OSTYPE 5
bool found = false;
int device_fd = -1;
char *device = NULL; cp();
char *iface = NULL;
char *device_info = NULL; get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
int device_total_in = 0;
int device_total_out = 0; /* Open registry and look for network adapters */
HANDLE handle; if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_NET, 0, KEY_READ, &key)) {
logger(LOG_ERR, _("Unable to read registry"));
pid_t reader_pid; return false;
int sp[2]; }
bool setup_device(void) for (i = 0; ; i++) {
{ len = sizeof(adapterid);
HKEY key, key2, adapterkey; if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
int i; break;
char adapterid[1024]; if(device) {
char manufacturer[1024]; if(!strcmp(device, adapterid)) {
char productname[1024]; found = true;
char adaptername[1024]; break;
char tapname[1024]; } else
char gelukt = 0; continue;
long len; }
FILETIME filetime; /* Find out more about this adapter */
bool found = false;
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", REG_CONTROL_NET, adapterid);
cp();
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) {
get_config_string(lookup_config(config_tree, "Device"), &device); logger(LOG_ERR, _("Unable to read registry"));
return false;
/* Open registry and look for network adapters */ }
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, (OSTYPE > 4 ? NETCARD_REG_KEY_2000 : NETCARD_REG_KEY), 0, KEY_READ, &key)) { len = sizeof(adaptername);
logger(LOG_ERR, _("Unable to read registry")); RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
return false;
} if(iface) {
if(!strcmp(iface, adaptername)) {
for (i = 0; ; i++) { found = true;
len = sizeof(adapterid); break;
if(RegEnumKeyEx (key, i, adapterid, &len, 0, 0, 0, &filetime)) } else
break; continue;
}
/* Find out more about this adapter */
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
if(RegOpenKeyEx (key, adapterid, 0, KEY_READ, &adapterkey)) { device_fd = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
logger(LOG_ERR, _("Unable to read registry")); if(device_fd != INVALID_HANDLE_VALUE) {
return false; found = true;
} break;
}
len = sizeof(productname); }
if(RegQueryValueEx(adapterkey, "ProductName", 0, 0, productname, &len))
goto skip; if(!found) {
logger(LOG_ERR, _("No Windows tap device found!"));
len = sizeof(manufacturer); return false;
if(RegQueryValueEx(adapterkey, "Manufacturer", 0, 0, manufacturer, &len)) }
goto skip;
device = adapterid;
if(!strcmp(productname, "CIPE") && !strcmp(manufacturer, "DKWHeavyIndustries")) { iface = adaptername;
if(device && strcmp(adapterid, device))
continue; /* Try to open the corresponding tap device */
if(!device)
device = xstrdup(adapterid); if(device_fd == INVALID_HANDLE_VALUE) {
found = true; snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
break; device_fd = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
} }
skip: if(device_fd == INVALID_HANDLE_VALUE) {
RegCloseKey (adapterkey); logger(LOG_ERR, _("%s (%s) is no a usable Windows tap device!"), device, iface);
} return false;
}
if(!found) {
logger(LOG_ERR, _("No CIPE adapters found!")); /* Get MAC address from tap device */
return false;
} if(DeviceIoControl(device_fd, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
logger(LOG_ERR, _("Could not get MAC address from Windows tap device!"));
/* Get adapter name */ return false;
}
len = sizeof(adaptername);
RegQueryValueEx(adapterkey, (OSTYPE > 4 ? "NetCfgInstanceId" : "ServiceName"), 0, 0, adaptername, &len); if(routing_mode == RMODE_ROUTER) {
overwrite_mac = 1;
/* FIXME? cipsrvr checks if the device is in use at this point */ }
/* Try to open the corresponding tap device */ if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = device;
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adaptername);
device_info = _("Windows tap device");
/* Now we are going to open this device twice: once for reading and once for writing.
We do this because apparently it isn't possible to check for activity in the select() loop. logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info);
Furthermore I don't really know how to do it the "Windows" way. */
return true;
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) { }
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "socketpair", strerror(errno));
return false; void close_device(void)
} {
cp();
reader_pid = fork();
CloseHandle(device_fd);
if(reader_pid == -1) { }
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "fork", strerror(errno));
return false; bool read_packet(vpn_packet_t *packet)
} {
int lenin;
if(!reader_pid) {
/* The child opens the tap device for reading, blocking. cp();
It passes everything it reads to the socket. */
if(!ReadFile(device_fd, packet->data, MTU, &lenin, NULL)) {
char buf[MTU]; logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
int lenin; device, strerror(errno));
return false;
handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0); }
if(handle == INVALID_HANDLE_VALUE) { packet->len = lenin;
logger(LOG_ERR, _("Could not open CIPE tap device for reading!"));
buf[0] = 0; device_total_in += packet->len;
write(sp[1], buf, 1);
exit(1); ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
} device_info);
logger(LOG_DEBUG, _("Tap reader forked and running.")); return true;
}
/* Notify success */
bool write_packet(vpn_packet_t *packet)
buf[0] = 1; {
write(sp[1], buf, 1); int lenout;
/* Pass packets */ cp();
for(;;) { ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
ReadFile (handle, buf, MTU, &lenin, NULL); packet->len, device_info);
write(sp[1], buf, lenin);
} if(!WriteFile(device_fd, packet->data, packet->len, &lenout, NULL)) {
} logger(LOG_ERR, "Error while writing to %s %s", device_info, device);
return false;
/* The parent opens the tap device for writing. */ }
handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0); device_total_out += packet->len;
if(handle == INVALID_HANDLE_VALUE) { return true;
logger(LOG_ERR, _("Could not open CIPE tap device for writing!")); }
return false;
} void dump_device_stats(void)
{
device_fd = sp[0]; cp();
/* Get MAC address from tap device */ logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
if(routing_mode == RMODE_ROUTER) { logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
DeviceIoControl (handle, CIPE_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0); }
overwrite_mac = 1;
}
read(device_fd, &gelukt, 1);
if(gelukt != 1) {
logger(LOG_DEBUG, "Tap reader failed!");
return false;
}
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = device;
device_info = _("Cygwin CIPE device");
logger(LOG_INFO, _("%s is a %s"), device, device_info);
return true;
}
void close_device(void)
{
cp();
close(sp[0]);
close(sp[1]);
CloseHandle(handle);
kill(reader_pid, SIGKILL);
}
bool read_packet(vpn_packet_t *packet)
{
int lenin;
cp();
if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
device, strerror(errno));
return false;
}
packet->len = lenin;
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
device_info);
return true;
}
bool write_packet(vpn_packet_t *packet)
{
int lenout;
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
packet->len, device_info);
if(!WriteFile (handle, packet->data, packet->len, &lenout, NULL)) {
logger(LOG_ERR, "Error while writing to %s %s", device_info, device);
return false;
}
device_total_out += packet->len;
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
}