📄 skyeye_net_tap.c
字号:
/*
* TAP-Win32 -- A kernel driver to provide virtual tap device functionality
* on Windows. Originally derived from the CIPE-Win32
* project by Damion K. Wilson, with extensive modifications by
* James Yonan.
*
* All source code which derives from the CIPE-Win32 project is
* Copyright (C) Damion K. Wilson, 2003, and is released under the
* GPL version 2 (see below).
*
* All other source code is Copyright (C) James Yonan, 2003-2004,
* and is released under the GPL version 2 (see below).
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "arch/arm/common/armdefs.h"
#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>
#include <SDL/SDL_mutex.h>
#undef WORD
#include <stdio.h>
#include <windows.h>
#include <ddk/ntapi.h>
#include <ddk/winddk.h>
#include <ddk/ntddk.h>
#define TAP_CONTROL_CODE(request,method) \
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED)
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED)
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED)
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED)
// Legacy TAP IOCTLs
#define OLD_TAP_CONTROL_CODE(request,method) \
CTL_CODE (FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
#define OLD_TAP_IOCTL_GET_VERSION OLD_TAP_CONTROL_CODE (3, METHOD_BUFFERED)
//=================
// Registry keys
//=================
#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}"
//======================
// Filesystem prefixes
//======================
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
#define SYSDEVICEDIR "\\Device\\"
#define USERDEVICEDIR "\\DosDevices\\Global\\"
#define TAPSUFFIX ".tap"
#define BUFFER_SIZE 65536
#define READ_SIZE 16384
#define ERRORMSG_SIZE 1024
#define printm(s...) printf("[TAP-WIN32]: "s)
#define bool int
#define true 1
#define false 0
HANDLE mFile;
unsigned char mBuf[BUFFER_SIZE];
DWORD mBuflen;
OVERLAPPED mOverlapped;
#define TAP_WIN32_MIN_MAJOR 7
#define TAP_WIN32_MIN_MINOR 1
static void GetErrorString(char *out, DWORD error)
{
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) out,
ERRORMSG_SIZE,
NULL);
}
static bool is_tap_win32_dev(const char *guid)
{
HKEY netcard_key;
LONG status;
DWORD len;
int i = 0;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &netcard_key);
if (status != ERROR_SUCCESS) {
printm("Error opening registry key: %s\n", ADAPTER_KEY);
return false;
}
while (true) {
char enum_name[256];
char unit_string[256];
HKEY unit_key;
char component_id_string[] = "ComponentId";
char component_id[256];
char net_cfg_instance_id_string[] = "NetCfgInstanceId";
char net_cfg_instance_id[256];
DWORD data_type;
len = sizeof (enum_name);
status = RegEnumKeyEx(netcard_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
if (status == ERROR_NO_MORE_ITEMS)
break;
else if (status != ERROR_SUCCESS) {
printm("Error enumerating registry subkeys of key: %s\n",
ADAPTER_KEY);
return false;
}
snprintf(unit_string, sizeof(unit_string), "%s\\%s", ADAPTER_KEY, enum_name);
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key);
if (status != ERROR_SUCCESS) {
printm("Error opening registry key: %s\n", unit_string);
return false;
} else {
len = sizeof (component_id);
status = RegQueryValueEx(unit_key, component_id_string, NULL, &data_type, (BYTE *)component_id, &len);
if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
len = sizeof (net_cfg_instance_id);
status = RegQueryValueEx(unit_key, net_cfg_instance_id_string, NULL, &data_type, (BYTE *)net_cfg_instance_id, &len);
if (status == ERROR_SUCCESS && data_type == REG_SZ) {
if (!strncmp(component_id, "tap", 3)
&& !strcmp(net_cfg_instance_id, guid)) {
RegCloseKey(unit_key);
RegCloseKey(netcard_key);
return true;
}
}
}
RegCloseKey(unit_key);
}
++i;
}
RegCloseKey(netcard_key);
return false;
}
static int get_device_guid(char *name, int name_size, char *actual_name, int actual_name_size)
{
LONG status;
HKEY control_net_key;
DWORD len;
int i = 0;
bool stop = false;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &control_net_key);
if (status != ERROR_SUCCESS) {
printm("Error opening registry key: %s", NETWORK_CONNECTIONS_KEY);
return 1;
}
while (!stop) {
char enum_name[256];
char connection_string[256];
HKEY connection_key;
char name_data[256];
DWORD name_type;
const char name_string[] = "Name";
len = sizeof (enum_name);
status = RegEnumKeyEx(control_net_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
if (status == ERROR_NO_MORE_ITEMS)
break;
else if (status != ERROR_SUCCESS) {
printm("Error enumerating registry subkeys of key: %s", NETWORK_CONNECTIONS_KEY);
return 1;
}
snprintf(connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name);
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connection_key);
if (status == ERROR_SUCCESS) {
len = sizeof (name_data);
status = RegQueryValueEx(connection_key, name_string, NULL, &name_type, (BYTE *)name_data, &len);
if (status != ERROR_SUCCESS || name_type != REG_SZ) {
printm("Error opening registry key: %s\\%s\\%s", NETWORK_CONNECTIONS_KEY, connection_string, name_string);
return 1;
} else {
if (is_tap_win32_dev(enum_name)) {
printm("Found TAP device named '%s'\n", name_data);
snprintf(name, name_size, "%s", enum_name);
if (actual_name)
ht_snprintf(actual_name, actual_name_size, "%s", name_data);
stop = true;
}
}
RegCloseKey(connection_key);
}
++i;
}
RegCloseKey(control_net_key);
if (!stop)
return 1;
return 0;
}
bool tap_set_status(ULONG status)
{
DWORD len = 0;
bool ret;
ret = DeviceIoControl(mFile, TAP_IOCTL_SET_MEDIA_STATUS,
&status, sizeof (status),
&status, sizeof (status), &len, NULL);
if (!ret) {
char errmsg[ERRORMSG_SIZE];
GetErrorString(errmsg, GetLastError());
printm("Failed: %s\n", errmsg);
}
return ret;
}
int initDevice()
{
char device_path[256];
char device_guid[0x100];
int rc;
HANDLE handle = NULL;
printm("Enumerating TAP devices...\n");
rc = get_device_guid(device_guid, sizeof device_guid, NULL, 0);
if (rc != 0) {
printm("Could not locate any installed TAP-WIN32 devices.");
}
//Open Windows TAP-Win32 adapter
snprintf(device_path, sizeof device_path, "%s%s%s",
USERMODEDEVICEDIR,
device_guid,
TAPSUFFIX);
handle = CreateFile(
device_path,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0);
if (handle == INVALID_HANDLE_VALUE || handle == NULL) {
printm("Opening TAP connection failed");
}
mFile = handle;
mOverlapped.Offset = 0;
mOverlapped.OffsetHigh = 0;
mOverlapped.hEvent = CreateEvent(NULL, TRUE, false, NULL);
//check TAP driver version against our minimum supported version
{
ULONG info[3];
ULONG len;
info[0] = info[1] = info[2] = 0;
if (DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
&info, sizeof (info),
&info, sizeof (info), &len, NULL)) {
printm("Driver Version %d.%d\n",
(int) info[0],
(int) info[1]);
} else {
if (DeviceIoControl(handle, OLD_TAP_IOCTL_GET_VERSION,
&info, sizeof (info),
&info, sizeof (info), &len, NULL)) {
printm("Driver Version %d.%d %s.\n",
(int) info[0],
(int) info[1],
(info[2] ? "(DEBUG) " : ""));
} else {
char errmsg[ERRORMSG_SIZE];
GetErrorString(errmsg, GetLastError());
printm("Could not get driver version info: %s\n", errmsg);
}
}
if (!(info[0] > TAP_WIN32_MIN_MAJOR || (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR))) {
printm("ERROR: This version of PearPC requires a TAP-Win32 driver that is at least version %d.%d\n"
"Please install an updated version from http://prdownloads.sourceforge.net/openvpn/openvpn-2.0_beta2-install.exe\n",
TAP_WIN32_MIN_MAJOR,
TAP_WIN32_MIN_MINOR);
}
}
//connect our virtual cat5 cable to the TAP device
if (!tap_set_status(TRUE)) {
if (CloseHandle(handle) != 1) {
printm("Error closing handle.\n");
}
printm("Setting Media Status to connected failed (handle is %d)\n", handle);
}
return 0;
}
int shutdownDevice()
{
printm("Setting Media Status to disconnected.\n");
if (!tap_set_status(false)) {
printm("Error disconnecting media.\n");
}
printm("Closing TAP-WIN32 handle.\n");
CloseHandle(mFile);
mFile = INVALID_HANDLE_VALUE;
return 0;
}
int recvPacket(void *buf, int size)
{
if (mBuflen > size) {
// no partial packets. drop it.
mBuflen = 0;
return 0;
}
memcpy(buf, mBuf, mBuflen);
int ret = mBuflen;
mBuflen = 0;
return ret;
}
int waitRecvPacket()
{
DWORD status;
mOverlapped.Offset = 0;
mOverlapped.OffsetHigh = 0;
ResetEvent(mOverlapped.hEvent);
status = ReadFile(mFile, mBuf, READ_SIZE, &mBuflen, &mOverlapped);
if (!status) {
DWORD e = GetLastError();
if (e == ERROR_IO_PENDING) {
WaitForSingleObject(mOverlapped.hEvent, INFINITE);
if (!GetOverlappedResult(mFile, &mOverlapped, &mBuflen, FALSE)) {
printm("You should never see this error\n");
}
} else {
char errmsg[ERRORMSG_SIZE];
GetErrorString(errmsg, e);
printm("Bad read error: %s\n", errmsg);
return EIO;
}
}
return 0;
}
int sendPacket(void *buf, int size)
{
DWORD written;
BOOL ret;
OVERLAPPED wrov = {0};
ret = WriteFile(mFile, buf, size, &written, &wrov);
if (!ret) {
char errmsg[ERRORMSG_SIZE];
GetErrorString(errmsg, GetLastError());
printm("Sending of %d bytes failed (%d bytes sent): %s\n", size, written, errmsg);
}
return written;
}
static SDL_sem * net_sem = NULL;
static int net_readed = 0;
int net_thread(void * par)
{
int n = 0;
while(1)
{
if(SDL_SemWait(net_sem) != -1)
{
if( net_readed == 0)
{
n = waitRecvPacket();
if(n == 0)
{
net_readed = 1;
}
}
SDL_SemPost(net_sem);
}
}
}
int
tap_open (struct net_device *net_dev)
{
initDevice();
static first_run = 1;
if(first_run == 1)
{
first_run = 0;
net_sem = SDL_CreateSemaphore(1);
SDL_CreateThread(net_thread, NULL);
}
return 0;
}
int
tap_close (struct net_device *net_dev)
{
printf("Setting Media Status to disconnected.\n");
printf("we are not expecting this !!!\n");
shutdownDevice();
return 0;
}
int
tap_read (struct net_device *net_dev, void *buf, size_t count)
{
int n = 0;
if (SDL_SemTryWait(net_sem)==0)
{
if(net_readed == 1)
{
n = recvPacket(buf,count);
net_readed = 0;
}
SDL_SemPost(net_sem);
}
return n;
}
int
tap_write (struct net_device *net_dev, void *buf, size_t count)
{
int n = sendPacket(buf, count);
return n;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -