Files
basil00_WinDivert/dll/windivert.c
T
basil00 e247f01c43 Remove automatic checksum calculation & legacy API
- As discussed in #37, the WINDIVERT_FLAG_NO_CHECKSUM behavior has become the
  default.  This means that outbound packets returned by WinDivertRecv() are
  no longer guaranteed to have valid checksums, thanks to TCP checksum
  offloading by the Windows TCP/IP stack.  The checksums can still be
  recovered by calling WinDivertHelperCalcChecksums() manually.
- Remove the old WinDivert1.0 legacy API, as nobody should still be using it.
2015-07-02 21:19:27 +08:00

976 lines
27 KiB
C

/*
* windivert.c
* (C) 2015, all rights reserved,
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <winsock2.h>
#include <windows.h>
#include <winioctl.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define WINDIVERTEXPORT
#include "windivert.h"
#include "windivert_device.h"
#define WINDIVERT_DRIVER_NAME L"WinDivert"
#define WINDIVERT_DRIVER32_SYS L"\\" WINDIVERT_DRIVER_NAME L"32.sys"
#define WINDIVERT_DRIVER64_SYS L"\\" WINDIVERT_DRIVER_NAME L"64.sys"
/*
* Definitions to remove (some) external dependencies:
*/
#define BYTESWAP16(x) \
((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
#define BYTESWAP32(x) \
((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | \
(((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000))
#define ntohs(x) BYTESWAP16(x)
#define htons(x) BYTESWAP16(x)
#define ntohl(x) BYTESWAP32(x)
#define htonl(x) BYTESWAP32(x)
static BOOLEAN WinDivertStrLen(const wchar_t *s, size_t maxlen,
size_t *lenptr);
static BOOLEAN WinDivertStrCpy(wchar_t *dst, size_t dstlen,
const wchar_t *src);
static BOOLEAN WinDivertAToI(const char *str, char **endptr, UINT32 *intptr);
static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr);
/*
* IPv4/IPv6 pseudo headers.
*/
typedef struct
{
UINT32 SrcAddr;
UINT32 DstAddr;
UINT8 Zero;
UINT8 Protocol;
UINT16 Length;
} WINDIVERT_PSEUDOHDR, *PWINDIVERT_PSEUDOHDR;
typedef struct
{
UINT32 SrcAddr[4];
UINT32 DstAddr[4];
UINT32 Length;
UINT32 Zero:24;
UINT32 NextHdr:8;
} WINDIVERT_PSEUDOV6HDR, *PWINDIVERT_PSEUDOV6HDR;
/*
* Misc.
*/
#ifndef UINT8_MAX
#define UINT8_MAX 0xFF
#endif
#ifndef UINT32_MAX
#define UINT32_MAX 0xFFFFFFFF
#endif
/*
* Prototypes.
*/
static BOOLEAN WinDivertUse32Bit(void);
static BOOLEAN WinDivertGetDriverFileName(LPWSTR sys_str);
static SC_HANDLE WinDivertDriverInstall(VOID);
static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen);
static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped);
static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len);
#ifdef WINDIVERT_DEBUG
static void WinDivertFilterDump(windivert_ioctl_filter_t filter, UINT16 len);
#endif
/*
* Include the helper API implementation.
*/
#include "windivert_helper.c"
/*
* Thread local.
*/
static DWORD windivert_tls_idx;
/*
* Current DLL hmodule.
*/
static HMODULE module = NULL;
/*
* Dll Entry
*/
extern BOOL APIENTRY WinDivertDllEntry(HANDLE module0, DWORD reason,
LPVOID reserved)
{
HANDLE event;
switch (reason)
{
case DLL_PROCESS_ATTACH:
module = module0;
if ((windivert_tls_idx = TlsAlloc()) == TLS_OUT_OF_INDEXES)
{
return FALSE;
}
// Fallthrough
case DLL_THREAD_ATTACH:
event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (event == NULL)
{
return FALSE;
}
TlsSetValue(windivert_tls_idx, (LPVOID)event);
break;
case DLL_PROCESS_DETACH:
event = (HANDLE)TlsGetValue(windivert_tls_idx);
if (event != (HANDLE)NULL)
{
CloseHandle(event);
}
TlsFree(windivert_tls_idx);
break;
case DLL_THREAD_DETACH:
event = (HANDLE)TlsGetValue(windivert_tls_idx);
if (event != (HANDLE)NULL)
{
CloseHandle(event);
}
break;
}
return TRUE;
}
/*
* Test if we should use the 32-bit or 64-bit driver.
*/
static BOOLEAN WinDivertUse32Bit(void)
{
BOOL is_wow64;
if (sizeof(void *) == sizeof(UINT64))
{
return FALSE;
}
if (!IsWow64Process(GetCurrentProcess(), &is_wow64))
{
// Just guess:
return FALSE;
}
return (is_wow64? FALSE: TRUE);
}
/*
* Locate the WinDivert driver files.
*/
static BOOLEAN WinDivertGetDriverFileName(LPWSTR sys_str)
{
size_t dir_len, sys_len;
BOOLEAN is_32bit;
is_32bit = WinDivertUse32Bit();
if (is_32bit)
{
if (!WinDivertStrLen(WINDIVERT_DRIVER32_SYS, MAX_PATH, &sys_len))
{
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
}
else
{
if (!WinDivertStrLen(WINDIVERT_DRIVER64_SYS, MAX_PATH, &sys_len))
{
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
}
dir_len = (size_t)GetModuleFileName(module, sys_str, MAX_PATH);
if (dir_len == 0)
{
return FALSE;
}
for (; dir_len > 0 && sys_str[dir_len] != L'\\'; dir_len--)
;
if (sys_str[dir_len] != L'\\' || dir_len + sys_len + 1 >= MAX_PATH)
{
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
if (!WinDivertStrCpy(sys_str + dir_len, MAX_PATH-dir_len-1,
(is_32bit? WINDIVERT_DRIVER32_SYS: WINDIVERT_DRIVER64_SYS)))
{
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
return TRUE;
}
/*
* Install the WinDivert driver.
*/
static SC_HANDLE WinDivertDriverInstall(VOID)
{
DWORD err, retries = 2;
SC_HANDLE manager = NULL, service = NULL;
wchar_t windivert_sys[MAX_PATH+1];
SERVICE_STATUS status;
// Open the service manager:
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager == NULL)
{
goto WinDivertDriverInstallExit;
}
// Check if the WinDivert service already exists; if so, start it.
WinDivertDriverInstallReTry:
service = OpenService(manager, WINDIVERT_DEVICE_NAME, SERVICE_ALL_ACCESS);
if (service != NULL)
{
goto WinDivertDriverInstallExit;
}
// Get driver file:
if (!WinDivertGetDriverFileName(windivert_sys))
{
goto WinDivertDriverInstallExit;
}
// Create the service:
service = CreateService(manager, WINDIVERT_DEVICE_NAME,
WINDIVERT_DEVICE_NAME, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, windivert_sys, NULL, NULL,
NULL, NULL, NULL);
if (service == NULL)
{
if (GetLastError() == ERROR_SERVICE_EXISTS)
{
if (retries != 0)
{
retries--;
goto WinDivertDriverInstallReTry;
}
}
goto WinDivertDriverInstallExit;
}
WinDivertDriverInstallExit:
if (service != NULL)
{
// Start the service:
if (!StartService(service, 0, NULL))
{
err = GetLastError();
if (err == ERROR_SERVICE_ALREADY_RUNNING)
{
SetLastError(0);
}
else
{
// Failed to start service; clean-up:
ControlService(service, SERVICE_CONTROL_STOP, &status);
DeleteService(service);
CloseServiceHandle(service);
service = NULL;
SetLastError(err);
}
}
}
err = GetLastError();
if (manager != NULL)
{
CloseServiceHandle(manager);
}
SetLastError(err);
return service;
}
/*
* Perform a DeviceIoControl.
*/
static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen)
{
OVERLAPPED overlapped;
DWORD iolen0;
HANDLE event;
event = (HANDLE)TlsGetValue(windivert_tls_idx);
if (event == (HANDLE)NULL)
{
event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (event == NULL)
{
return FALSE;
}
TlsSetValue(windivert_tls_idx, (LPVOID)event);
}
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = event;
if (!WinDivertIoControlEx(handle, code, arg8, arg, buf, len, iolen,
&overlapped))
{
if (GetLastError() != ERROR_IO_PENDING ||
!GetOverlappedResult(handle, &overlapped, &iolen0, TRUE))
{
return FALSE;
}
if (iolen != NULL)
{
*iolen = (UINT)iolen0;
}
}
return TRUE;
}
/*
* Perform an (overlapped) DeviceIoControl.
*/
static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped)
{
struct windivert_ioctl_s ioctl;
BOOL result;
DWORD iolen0;
ioctl.version = WINDIVERT_IOCTL_VERSION;
ioctl.magic = WINDIVERT_IOCTL_MAGIC;
ioctl.arg8 = arg8;
ioctl.arg = arg;
result = DeviceIoControl(handle, code, &ioctl, sizeof(ioctl), buf,
(DWORD)len, &iolen0, overlapped);
if (result && iolen != NULL)
{
*iolen = (UINT)iolen0;
}
return result;
}
/*
* Open a WinDivert handle.
*/
extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
INT16 priority, UINT64 flags)
{
struct windivert_ioctl_filter_s object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
DWORD err;
HANDLE handle;
SC_HANDLE service;
UINT32 priority32;
// Parameter checking.
if (!WINDIVERT_FLAGS_VALID(flags) || layer > WINDIVERT_LAYER_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
priority32 = WINDIVERT_PRIORITY(priority);
if (priority32 < WINDIVERT_PRIORITY_MIN ||
priority32 > WINDIVERT_PRIORITY_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
// Compile the filter:
if (!WinDivertCompileFilter(filter, layer, object, &obj_len))
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
#ifdef WINDIVERT_DEBUG
WinDivertFilterDump(object, obj_len);
#endif
// Attempt to open the WinDivert device:
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, INVALID_HANDLE_VALUE);
if (handle == INVALID_HANDLE_VALUE)
{
err = GetLastError();
if (err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND)
{
return INVALID_HANDLE_VALUE;
}
// Open failed because the device isn't installed; install it now.
SetLastError(0);
service = WinDivertDriverInstall();
if (service == NULL)
{
if (GetLastError() == 0)
{
SetLastError(ERROR_OPEN_FAILED);
}
return INVALID_HANDLE_VALUE;
}
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
INVALID_HANDLE_VALUE);
// Schedule the service to be deleted (once all handles are closed).
DeleteService(service);
CloseServiceHandle(service);
if (handle == INVALID_HANDLE_VALUE)
{
return INVALID_HANDLE_VALUE;
}
}
// Set the layer:
if (layer != WINDIVERT_LAYER_DEFAULT)
{
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_LAYER, 0,
(UINT64)layer, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
}
}
// Set the flags:
if (flags != 0)
{
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_FLAGS, 0,
(UINT64)flags, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
}
}
// Set the priority:
if (priority32 != WINDIVERT_PRIORITY_DEFAULT)
{
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PRIORITY, 0,
(UINT64)priority32, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
}
}
// Start the filter:
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_START_FILTER, 0, 0,
object, obj_len*sizeof(struct windivert_ioctl_filter_s), NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
}
// Success!
return handle;
}
/*
* Receive a WinDivert packet.
*/
extern BOOL WinDivertRecv(HANDLE handle, PVOID pPacket, UINT packetLen,
PWINDIVERT_ADDRESS addr, UINT *readlen)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV, 0, (UINT64)addr,
pPacket, packetLen, readlen);
}
/*
* Receive a WinDivert packet.
*/
extern BOOL WinDivertRecvEx(HANDLE handle, PVOID pPacket, UINT packetLen,
UINT64 flags, PWINDIVERT_ADDRESS addr, UINT *readlen,
LPOVERLAPPED overlapped)
{
if (flags != 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (overlapped == NULL)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV, 0,
(UINT64)addr, pPacket, packetLen, readlen);
}
else
{
return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_RECV, 0,
(UINT64)addr, pPacket, packetLen, readlen, overlapped);
}
}
/*
* Send a WinDivert packet.
*/
extern BOOL WinDivertSend(HANDLE handle, PVOID pPacket, UINT packetLen,
PWINDIVERT_ADDRESS addr, UINT *writelen)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, 0, (UINT64)addr,
pPacket, packetLen, writelen);
}
/*
* Send a WinDivert packet.
*/
extern BOOL WinDivertSendEx(HANDLE handle, PVOID pPacket, UINT packetLen,
UINT64 flags, PWINDIVERT_ADDRESS addr, UINT *writelen,
LPOVERLAPPED overlapped)
{
if (flags != 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (overlapped == NULL)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, 0,
(UINT64)addr, pPacket, packetLen, writelen);
}
else
{
return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_SEND, 0,
(UINT64)addr, pPacket, packetLen, writelen, overlapped);
}
}
/*
* Close a WinDivert handle.
*/
extern BOOL WinDivertClose(HANDLE handle)
{
return CloseHandle(handle);
}
/*
* Set a WinDivert parameter.
*/
extern BOOL WinDivertSetParam(HANDLE handle, WINDIVERT_PARAM param,
UINT64 value)
{
switch ((int)param)
{
case WINDIVERT_PARAM_QUEUE_LEN:
if (value < WINDIVERT_PARAM_QUEUE_LEN_MIN ||
value > WINDIVERT_PARAM_QUEUE_LEN_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
break;
case WINDIVERT_PARAM_QUEUE_TIME:
if (value < WINDIVERT_PARAM_QUEUE_TIME_MIN ||
value > WINDIVERT_PARAM_QUEUE_TIME_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PARAM, (UINT8)param,
value, NULL, 0, NULL);
}
/*
* Get a WinDivert parameter.
*/
extern BOOL WinDivertGetParam(HANDLE handle, WINDIVERT_PARAM param,
UINT64 *pValue)
{
switch ((int)param)
{
case WINDIVERT_PARAM_QUEUE_LEN: case WINDIVERT_PARAM_QUEUE_TIME:
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return WinDivertIoControl(handle, IOCTL_WINDIVERT_GET_PARAM, (UINT8)param,
0, pValue, sizeof(UINT64), NULL);
}
/*****************************************************************************/
/* REPLACEMENTS */
/*****************************************************************************/
static BOOLEAN WinDivertStrLen(const wchar_t *s, size_t maxlen,
size_t *lenptr)
{
size_t i;
for (i = 0; s[i]; i++)
{
if (i > maxlen)
{
return FALSE;
}
}
*lenptr = i;
return TRUE;
}
static BOOLEAN WinDivertStrCpy(wchar_t *dst, size_t dstlen, const wchar_t *src)
{
size_t i;
for (i = 0; src[i]; i++)
{
if (i > dstlen)
{
return FALSE;
}
dst[i] = src[i];
}
if (i > dstlen)
{
return FALSE;
}
dst[i] = src[i];
return TRUE;
}
static BOOLEAN WinDivertAToI(const char *str, char **endptr, UINT32 *intptr)
{
size_t i = 0;
UINT32 num = 0, num0;
if (str[i] == '\0')
{
return FALSE;
}
for (; str[i] && isdigit(str[i]); i++)
{
num0 = num;
num *= 10;
num += (UINT32)(str[i] - '0');
if (num0 > num)
{
return FALSE;
}
}
if (endptr != NULL)
{
*endptr = (char *)str + i;
}
*intptr = num;
return TRUE;
}
static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr)
{
size_t i = 0;
UINT32 num = 0, num0;
if (str[i] == '\0')
{
return FALSE;
}
if (str[i] == '0' && str[i+1] == 'x')
{
i += 2;
}
for (; str[i] && isxdigit(str[i]); i++)
{
num0 = num;
num *= 16;
if (isdigit(str[i]))
{
num += (UINT32)(str[i] - '0');
}
else
{
num += (UINT32)(tolower(str[i]) - 'a') + 0x0A;
}
if (num0 > num)
{
return FALSE;
}
}
if (endptr != NULL)
{
*endptr = (char *)str + i;
}
*intptr = num;
return TRUE;
}
/***************************************************************************/
/* DEBUGGING */
/***************************************************************************/
#ifdef WINDIVERT_DEBUG
/*
* Print a filter (debugging).
*/
static void WinDivertFilterDump(windivert_ioctl_filter_t filter, UINT16 len)
{
UINT16 i;
for (i = 0; i < len; i++)
{
printf("label_%u:\n\tif (", i);
switch (filter[i].field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
printf("zero ");
break;
case WINDIVERT_FILTER_FIELD_INBOUND:
printf("inbound ");
break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
printf("outbound ");
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
printf("ifIdx ");
break;
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
printf("subIfIdx ");
break;
case WINDIVERT_FILTER_FIELD_IP:
printf("ip ");
break;
case WINDIVERT_FILTER_FIELD_IPV6:
printf("ipv6 ");
break;
case WINDIVERT_FILTER_FIELD_ICMP:
printf("icmp ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
printf("icmpv6 ");
break;
case WINDIVERT_FILTER_FIELD_TCP:
printf("tcp ");
break;
case WINDIVERT_FILTER_FIELD_UDP:
printf("udp ");
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
printf("ip.HdrLength ");
break;
case WINDIVERT_FILTER_FIELD_IP_TOS:
printf("ip.TOS ");
break;
case WINDIVERT_FILTER_FIELD_IP_LENGTH:
printf("ip.Length ");
break;
case WINDIVERT_FILTER_FIELD_IP_ID:
printf("ip.Id ");
break;
case WINDIVERT_FILTER_FIELD_IP_DF:
printf("ip.DF ");
break;
case WINDIVERT_FILTER_FIELD_IP_MF:
printf("ip.MF ");
break;
case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
printf("ip.FragOff ");
break;
case WINDIVERT_FILTER_FIELD_IP_TTL:
printf("ip.TTL ");
break;
case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
printf("ip.Protocol ");
break;
case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
printf("ip.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
printf("ip.SrcAddr ");
break;
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
printf("ip.DstAddr ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
printf("ipv6.TrafficClass ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
printf("ipv6.FlowLabel ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
printf("ipv6.Length ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
printf("ipv6.NextHdr ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
printf("ipv6.HopLimit ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
printf("ipv6.SrcAddr ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
printf("ipv6.DstAddr ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
printf("icmp.Type ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_CODE:
printf("icmp.Code ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
printf("icmp.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_BODY:
printf("icmp.Body ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
printf("icmpv6.Type ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
printf("icmpv6.Code ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
printf("icmpv6.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
printf("icmpv6.Body ");
break;
case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
printf("tcp.SrcPort ");
break;
case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
printf("tcp.DstPort ");
break;
case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
printf("tcp.SeqNum ");
break;
case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
printf("tcp.AckNum ");
break;
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
printf("tcp.HdrLength ");
break;
case WINDIVERT_FILTER_FIELD_TCP_URG:
printf("tcp.Urg ");
break;
case WINDIVERT_FILTER_FIELD_TCP_ACK:
printf("tcp.Ack ");
break;
case WINDIVERT_FILTER_FIELD_TCP_PSH:
printf("tcp.Psh ");
break;
case WINDIVERT_FILTER_FIELD_TCP_RST:
printf("tcp.Rst ");
break;
case WINDIVERT_FILTER_FIELD_TCP_SYN:
printf("tcp.Syn ");
break;
case WINDIVERT_FILTER_FIELD_TCP_FIN:
printf("tcp.Fin ");
break;
case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
printf("tcp.Window ");
break;
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
printf("tcp.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
printf("tcp.UrgPtr ");
break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
printf("tcp.PayloadLength " );
break;
case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
printf("udp.SrcPort ");
break;
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
printf("udp.DstPort ");
break;
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
printf("udp.Length ");
break;
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
printf("udp.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
printf("udp.PayloadLength ");
break;
default:
printf("unknown.Field ");
break;
}
switch (filter[i].test)
{
case WINDIVERT_FILTER_TEST_EQ:
printf("== ");
break;
case WINDIVERT_FILTER_TEST_NEQ:
printf("!= ");
break;
case WINDIVERT_FILTER_TEST_LT:
printf("< ");
break;
case WINDIVERT_FILTER_TEST_LEQ:
printf("<= ");
break;
case WINDIVERT_FILTER_TEST_GT:
printf("> ");
break;
case WINDIVERT_FILTER_TEST_GEQ:
printf(">= ");
break;
default:
printf("?? ");
break;
}
printf("%u)\n", filter[i].arg[0]);
switch (filter[i].success)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
printf("\t\treturn ACCEPT;\n");
break;
case WINDIVERT_FILTER_RESULT_REJECT:
printf("\t\treturn REJECT;\n");
break;
default:
printf("\t\tgoto label_%u;\n", filter[i].success);
break;
}
printf("\telse\n");
switch (filter[i].failure)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
printf("\t\treturn ACCEPT;\n");
break;
case WINDIVERT_FILTER_RESULT_REJECT:
printf("\t\treturn REJECT;\n");
break;
default:
printf("\t\tgoto label_%u;\n", filter[i].failure);
break;
}
}
}
#endif /* WINDIVERT_DEBUG */