Make use of the CIPE driver. Woohoo, tinc for Windows!

This commit is contained in:
Guus Sliepen 2003-07-15 16:27:39 +00:00
parent d26a4af456
commit 4c52febc57

View file

@ -1,127 +1,313 @@
/* /*
device.c -- Stub for 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.7 2003/07/12 17:41:47 guus Exp $ $Id: device.c,v 1.1.2.8 2003/07/15 16:27:39 guus Exp $
*/ */
#include "config.h" #include "config.h"
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <stdbool.h>
#include <sys/types.h> #include <errno.h>
#include <sys/stat.h> #include <sys/types.h>
#include <fcntl.h> #include <sys/stat.h>
#include <unistd.h> #include <signal.h>
#include <string.h> #include <fcntl.h>
#include <unistd.h>
#include <utils.h> #include <string.h>
#include "conf.h" #include <w32api/windows.h>
#include "net.h" #include <w32api/winioctl.h>
#include "logger.h"
// #include <utils.h>
#include "system.h" #include "conf.h"
#include "net.h"
int device_fd = -1; #include "logger.h"
int device_type; #include "route.h"
char *device;
char *interface; #include "system.h"
char *device_info;
/* Definitions from CIPE */
int device_total_in = 0;
int device_total_out = 0; #define NETCARD_REG_KEY_2000 "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NETCARD_REG_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"
int setup_device(void) #define REG_SERVICE_KEY "SYSTEM\\CurrentControlSet\\Services"
{
struct ifreq ifr; #define USERMODEDEVICEDIR "\\\\.\\"
#define SYSDEVICEDIR "\\Device\\"
cp(); #define USERDEVICEDIR "\\??\\"
#define TAPSUFFIX ".tap"
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = DEFAULT_DEVICE; #define PRODUCT_STRING "DKW Heavy Industries VPN Adapter."
#define CIPE_SERVICE_NAME "CIPE_Daemon"
if(!get_config_string(lookup_config(config_tree, "Interface"), &interface)) #define CIPE_DRIVER_NAME "CIPE"
interface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
#define CIPE_NDIS_MAJOR_VERSION 4
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) { #define CIPE_NDIS_MINOR_VERSION 0
logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
return -1; #ifndef CIPE_DRIVER_MAJOR_VERSION
} # define CIPE_DRIVER_MAJOR_VERSION 2
#endif
device_info = _("Stub device for Cygwin environment");
#ifndef CIPE_DRIVER_MINOR_VERSION
logger(LOG_INFO, _("%s is a %s"), device, device_info); # define CIPE_DRIVER_MINOR_VERSION 1
#endif
return 0;
} #ifndef CIPE_MAC_ROOT_ADDRESS
# define CIPE_MAC_ROOT_ADDRESS "8:0:58:0:0:1"
void close_device(void) #endif
{
cp(); #define CIPE_CONTROL_CODE(request,method) CTL_CODE (FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
close(device_fd); #define CIPE_IOCTL_GET_LASTMAC CIPE_CONTROL_CODE (0, METHOD_BUFFERED)
} #define CIPE_IOCTL_GET_MAC CIPE_CONTROL_CODE (1, METHOD_BUFFERED)
#define CIPE_IOCTL_SET_STATISTICS CIPE_CONTROL_CODE (2, METHOD_BUFFERED)
int read_packet(vpn_packet_t *packet)
{ /* Windows 2000 */
int lenin; #define OSTYPE 5
cp(); int device_fd = -1;
char *device = NULL;
if((lenin = read(device_fd, packet->data, MTU)) <= 0) { char *iface = NULL;
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, char *device_info = NULL;
device, strerror(errno));
return -1; int device_total_in = 0;
} int device_total_out = 0;
packet->len = lenin; HANDLE handle;
device_total_in += packet->len; pid_t reader_pid;
int sp[2];
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
device_info); int setup_device(void)
{
return 0; HKEY key, key2, adapterkey;
} int i;
int write_packet(vpn_packet_t *packet) char adapterid[1024];
{ char manufacturer[1024];
cp(); char productname[1024];
char adaptername[1024];
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"), char tapname[1024];
packet->len, device_info); char gelukt = 0;
long len;
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device, FILETIME filetime;
strerror(errno)); bool found = false;
return -1;
} cp();
device_total_out += packet->len; get_config_string(lookup_config(config_tree, "Device"), &device);
return 0; /* 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)) {
void dump_device_stats(void) logger(LOG_ERR, _("Unable to read registry"));
{ return -1;
cp(); }
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device); for (i = 0; ; i++) {
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in); len = sizeof(adapterid);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out); if(RegEnumKeyEx (key, i, adapterid, &len, 0, 0, 0, &filetime))
} break;
/* Find out more about this adapter */
if(RegOpenKeyEx (key, adapterid, 0, KEY_READ, &adapterkey)) {
logger(LOG_ERR, _("Unable to read registry"));
return -1;
}
len = sizeof(productname);
if(RegQueryValueEx(adapterkey, "ProductName", 0, 0, productname, &len))
goto skip;
len = sizeof(manufacturer);
if(RegQueryValueEx(adapterkey, "Manufacturer", 0, 0, manufacturer, &len))
goto skip;
if(!strcmp(productname, "CIPE") && !strcmp(manufacturer, "DKWHeavyIndustries")) {
if(device && strcmp(adapterid, device))
continue;
if(!device)
device = xstrdup(adapterid);
found = true;
break;
}
skip:
RegCloseKey (adapterkey);
}
if(!found) {
logger(LOG_ERR, _("No CIPE adapters found!"));
return -1;
}
/* Get adapter name */
len = sizeof(adaptername);
RegQueryValueEx(adapterkey, (OSTYPE > 4 ? "NetCfgInstanceId" : "ServiceName"), 0, 0, adaptername, &len);
/* FIXME? cipsrvr checks if the device is in use at this point */
/* Try to open the corresponding tap device */
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adaptername);
/* 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.
Furthermore I don't really know how to do it the "Windows" way. */
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "socketpair", strerror(errno));
return -1;
}
reader_pid = fork();
if(reader_pid == -1) {
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "fork", strerror(errno));
return -1;
}
if(!reader_pid) {
/* The child opens the tap device for reading, blocking.
It passes everything it reads to the socket. */
char buf[MTU];
int lenin;
handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
if(handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, _("Could not open CIPE tap device for reading!"));
buf[0] = 0;
write(sp[1], buf, 1);
exit(1);
}
logger(LOG_DEBUG, _("Tap reader forked and running."));
/* Notify success */
buf[0] = 1;
write(sp[1], buf, 1);
/* Pass packets */
for(;;) {
ReadFile (handle, buf, MTU, &lenin, NULL);
write(sp[1], buf, lenin);
}
}
/* The parent opens the tap device for writing. */
handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
if(handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, _("Could not open CIPE tap device for writing!"));
return -1;
}
device_fd = sp[0];
/* Get MAC address from tap device */
if(routing_mode == RMODE_ROUTER) {
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 -1;
}
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 0;
}
void close_device(void)
{
cp();
close(sp[0]);
close(sp[1]);
CloseHandle(handle);
kill(reader_pid, SIGKILL);
}
int 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 -1;
}
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 0;
}
int 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 -1;
}
device_total_out += packet->len;
return 0;
}
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);
}