Added cygwin support (client only)

This commit is contained in:
Friedrich Schöller 2013-05-13 23:31:27 +02:00
parent 1b2370143d
commit 01a65b13e3
6 changed files with 393 additions and 28 deletions

View File

@ -20,6 +20,9 @@ c)
LINUX)
echo $FLAGS -DHAVE_LINUX_IF_TUN_H
;;
CYGWIN*)
echo $FLAGS -DWIN32
;;
*)
echo $FLAGS
;;
@ -43,10 +46,12 @@ dev)
echo src/tun_dev_generic.c
fi
;;
CYGWIN*)
echo src/tun_dev_cygwin.c
;;
*)
echo src/tun_dev_generic.c
;;
esac
;;
esac

View File

@ -170,6 +170,10 @@ int main(int argc, char *argv[])
if (userName != NULL)
{
#ifdef WIN32
syslog(LOG_ERR, "dropping privileges is not supported on Windows");
return 1;
#endif
passwd *pw = getpwnam(userName);
if (pw != NULL)

View File

@ -36,6 +36,8 @@ using namespace std;
Tun::Tun(const char *device, int mtu)
{
char cmdline[512];
this->mtu = mtu;
if (device != NULL)
@ -52,10 +54,15 @@ Tun::Tun(const char *device, int mtu)
syslog(LOG_INFO, "opened tunnel device: %s", this->device);
char cmdline[512];
#ifdef WIN32
snprintf(cmdline, sizeof(cmdline), "netsh interface ipv4 set subinterface \"%s\" mtu=%d", this->device, mtu);
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device mtu");
#else
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s mtu %u", this->device, mtu);
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device mtu");
#endif
}
Tun::~Tun()
@ -69,16 +76,23 @@ void Tun::setIp(uint32_t ip, uint32_t destIp, bool includeSubnet)
string ips = Utility::formatIp(ip);
string destIps = Utility::formatIp(destIp);
#ifdef LINUX
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s netmask 255.255.255.0", device, ips.c_str());
#else
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s %s netmask 255.255.255.255", device, ips.c_str(), destIps.c_str());
#endif
#ifdef WIN32
snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address name=\"%s\" "
"static %s 255.255.255.0", device, ips.c_str());
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device ip address");
if (!tun_set_ip(fd, ip, ip & 0xffffff00, 0xffffff00))
syslog(LOG_ERR, "could not set tun device driver ip address: %s", tun_last_error());
#elif LINUX
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s netmask 255.255.255.0", device, ips.c_str());
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device ip address");
#else
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s %s netmask 255.255.255.255", device, ips.c_str(), destIps.c_str());
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device ip address");
#ifndef LINUX
if (includeSubnet)
{
snprintf(cmdline, sizeof(cmdline), "/sbin/route add %s/24 %s", destIps.c_str(), destIps.c_str());

View File

@ -1,28 +1,43 @@
/*
VTun - Virtual Tunnel over TCP/IP network.
Copyright (C) 1998-2000 Maxim Krasnyansky <max_mk@yahoo.com>
VTun has been derived from VPPP package by Maxim Krasnyansky.
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
/*
* Hans - IP over ICMP
* Copyright (C) 2013 Friedrich Schöller <hans@schoeller.se>
* 1998-2000 Maxim Krasnyansky <max_mk@yahoo.com>
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#define VTUN_DEV_LEN 20
#include <stdint.h>
#include <stdbool.h>
#define VTUN_DEV_LEN 100
#ifdef __cplusplus
extern "C" {
#endif
extern "C"
{
int tun_open(char *dev);
int tun_close(int fd, char *dev);
int tun_write(int fd, char *buf, int len);
int tun_read(int fd, char *buf, int len);
const char *tun_last_error();
#ifdef WIN32
bool tun_set_ip(int fd, uint32_t local, uint32_t network, uint32_t netmask);
#endif
#ifdef __cplusplus
}
#endif

325
src/tun_dev_cygwin.c Normal file
View File

@ -0,0 +1,325 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2013 Friedrich Schöller <hans@schoeller.se>
* 2002-2005 Ivo Timmermans,
* 2002-2011 Guus Sliepen <guus@tinc-vpn.org>
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "tun_dev.h"
#include <unistd.h>
#include <stdbool.h>
#include <syslog.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <w32api/windows.h>
#include <w32api/winioctl.h>
#define TAP_WIN_CONTROL_CODE(request,method) CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED)
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
#define SYSDEVICEDIR "\\Device\\"
#define USERDEVICEDIR "\\DosDevices\\Global\\"
#define TAP_WIN_SUFFIX ".tap"
struct adapter_info
{
int reader_read_fd, reader_write_fd;
HANDLE reader_thread;
HANDLE adapter_handle;
};
#define ERROR_BUFFER_SIZE 1024
char error_buffer[ERROR_BUFFER_SIZE];
static void error(char *format, ...)
{
va_list vl;
va_start(vl, format);
vsnprintf(error_buffer, ERROR_BUFFER_SIZE, format, vl);
va_end(vl);
}
static void noerror(void)
{
*error_buffer = 0;
}
static const char *winerror(int err)
{
static char buf[1024], *ptr;
ptr = buf + sprintf(buf, "(%d) ", err);
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), ptr, sizeof(buf) - (ptr - buf), NULL)) {
strcpy(ptr, "(unable to format errormessage)");
};
if((ptr = strchr(buf, '\r')))
*ptr = '\0';
return buf;
}
static struct adapter_info *get_adapter_info_from_fd(int fd)
{
static struct adapter_info single_adapter_info = {
.reader_read_fd = -1,
.reader_write_fd = -1,
.reader_thread = INVALID_HANDLE_VALUE,
.adapter_handle = INVALID_HANDLE_VALUE
};
return &single_adapter_info;
}
static HANDLE open_tap_adapter(char *name)
{
HKEY connections_key, adapter_key;
int adapter_index, error_code;
char regpath[1024];
char adapter_id[VTUN_DEV_LEN];
char adapter_path[1024];
char adapter_name[1024];
HANDLE adapter_handle = INVALID_HANDLE_VALUE;
DWORD len;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &connections_key) != ERROR_SUCCESS)
{
error("opening registry: %s", winerror(GetLastError()));
return INVALID_HANDLE_VALUE;
}
for (adapter_index = 0; ; adapter_index++)
{
len = sizeof(adapter_id);
if (RegEnumKeyEx(connections_key, adapter_index, adapter_id, &len, 0, 0, 0, NULL) != ERROR_SUCCESS)
break;
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapter_id);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &adapter_key) != ERROR_SUCCESS)
continue;
len = sizeof(adapter_name);
if (RegQueryValueEx(adapter_key, "Name", 0, 0, adapter_name, &len) != ERROR_SUCCESS)
{
RegCloseKey(adapter_key);
continue;
}
RegCloseKey(adapter_key);
if (name && name[0] && strcmp(name, adapter_name) && strcmp(name, adapter_id))
continue;
snprintf(adapter_path, sizeof(adapter_path), USERMODEDEVICEDIR "%s" TAP_WIN_SUFFIX, adapter_id);
adapter_handle = CreateFile(adapter_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if (adapter_handle != INVALID_HANDLE_VALUE)
break;
}
RegCloseKey(connections_key);
if (adapter_handle == INVALID_HANDLE_VALUE)
{
error("could not open tap adapter");
return INVALID_HANDLE_VALUE;
}
strncpy(name, adapter_name, VTUN_DEV_LEN);
noerror();
return adapter_handle;
}
static __stdcall DWORD reader_thread(LPVOID ptr)
{
struct adapter_info *adapter_info = ptr;
char buf[0xffff]; // TODO: MTU
OVERLAPPED overlapped;
DWORD len;
int wait_result;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = CreateEvent(NULL, true, false, NULL);
while (true)
{
if (!ReadFile(adapter_info->adapter_handle, buf, sizeof(buf), &len, &overlapped))
{
if (GetLastError() != ERROR_IO_PENDING)
{
syslog(LOG_ERR, "error reading tap: %s", winerror(GetLastError()));
return 1;
}
wait_result = WaitForSingleObjectEx(overlapped.hEvent, INFINITE, true); // or false?
if (wait_result == WAIT_IO_COMPLETION)
{
printf("hui?\n");
continue;
}
if (wait_result != WAIT_OBJECT_0)
{
syslog(LOG_ERR, "error waiting for tap adapter: %s", winerror(GetLastError()));
return 1;
}
if (!GetOverlappedResult(adapter_info->adapter_handle, &overlapped, &len, true))
{
syslog(LOG_ERR, "error waiting for operation to complete: %s", winerror(GetLastError()));
return 1;
}
}
// printf("success: %d\n", len);
write(adapter_info->reader_write_fd, buf, len);
}
}
int tun_open(char *dev)
{
struct adapter_info *adapter_info;
int socket_pair[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, socket_pair))
{
error("creating socket pair: %s", strerror(errno));
return -1;
}
adapter_info = get_adapter_info_from_fd(socket_pair[0]);
adapter_info->reader_read_fd = socket_pair[0];
adapter_info->reader_write_fd = socket_pair[1];
adapter_info->adapter_handle = open_tap_adapter(dev);
if (adapter_info->adapter_handle == INVALID_HANDLE_VALUE)
{
tun_close(adapter_info->reader_read_fd, NULL);
return -1;
}
adapter_info->reader_thread = CreateThread(NULL, 0, reader_thread, adapter_info, 0, NULL);
if (adapter_info->reader_thread == INVALID_HANDLE_VALUE)
{
error("reader thread creation: %s", winerror(GetLastError()));
tun_close(adapter_info->reader_read_fd, NULL);
return -1;
}
return adapter_info->reader_read_fd;
}
int tun_close(int fd, char *dev)
{
struct adapter_info *adapter_info = get_adapter_info_from_fd(fd);
if (adapter_info->reader_thread != INVALID_HANDLE_VALUE)
{
TerminateThread(adapter_info->reader_thread, 0);
adapter_info->reader_thread = INVALID_HANDLE_VALUE;
}
close(adapter_info->reader_read_fd);
adapter_info->reader_read_fd = -1;
close(adapter_info->reader_write_fd);
adapter_info->reader_write_fd = -1;
if (adapter_info->adapter_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(adapter_info->adapter_handle);
adapter_info->adapter_handle = INVALID_HANDLE_VALUE;
}
return 0;
}
int tun_write(int fd, char *buf, int len)
{
struct adapter_info *adapter_info = get_adapter_info_from_fd(fd);
OVERLAPPED overlapped;
DWORD written;
memset(&overlapped, 0, sizeof(overlapped));
if (!WriteFile(adapter_info->adapter_handle, buf, len, &written, &overlapped))
{
error("tap write: %s", winerror(GetLastError()));
return -1;
}
return written;
}
int tun_read(int fd, char *buf, int len)
{
len = read(fd, buf, len);
if (len == -1)
error("reader read: %s", strerror(errno));
return len;
}
const char *tun_last_error()
{
return error_buffer;
}
bool tun_set_ip(int fd, uint32_t local, uint32_t network, uint32_t netmask)
{
struct adapter_info *adapter_info = get_adapter_info_from_fd(fd);
uint32_t addresses[3];
DWORD status;
DWORD len;
addresses[0] = htonl(local);
addresses[1] = htonl(network);
addresses[2] = htonl(netmask);
if (!DeviceIoControl(adapter_info->adapter_handle, TAP_WIN_IOCTL_CONFIG_TUN,
&addresses, sizeof(addresses), &addresses, sizeof(addresses), &len, NULL))
{
error("configuring tap addresses", winerror(GetLastError()));
return false;
}
status = true;
if (!DeviceIoControl(adapter_info->adapter_handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
&status, sizeof(status), &status, sizeof(status), &len, NULL))
{
error("enabling tap device: %s", winerror(GetLastError()));
return false;
}
noerror();
return true;
}

View File

@ -185,6 +185,7 @@ void Worker::run()
void Worker::dropPrivileges()
{
#ifndef WIN32
if (uid <= 0 || privilegesDropped)
return;
@ -197,4 +198,5 @@ void Worker::dropPrivileges()
throw Exception("setuid", true);
privilegesDropped = true;
#endif
}