namespace WinDivertNet.WinDivertWrapper;
using System;
using System.Runtime.InteropServices;
using System.Text;
///
/// WinDivert 的 C# 封装类
///
public static class WinDivert
{
#region 常量定义
// 层级常量
public const uint WINDIVERT_LAYER_NETWORK = 0;
public const uint WINDIVERT_LAYER_NETWORK_FORWARD = 1;
public const uint WINDIVERT_LAYER_FLOW = 2;
public const uint WINDIVERT_LAYER_SOCKET = 3;
public const uint WINDIVERT_LAYER_REFLECT = 4;
// 标志常量
public const ulong WINDIVERT_FLAG_SNIFF = 1;
public const ulong WINDIVERT_FLAG_DROP = 2;
public const ulong WINDIVERT_FLAG_RECV_ONLY = 4;
public const ulong WINDIVERT_FLAG_SEND_ONLY = 8;
public const ulong WINDIVERT_FLAG_NO_INSTALL = 16;
public const ulong WINDIVERT_FLAG_FRAGMENTS = 32;
public const ulong WINDIVERT_FLAG_RECV_PARTIAL = 64;
public const ulong WINDIVERT_FLAG_SEND_PARTIAL = 128;
// 事件常量
public const byte WINDIVERT_EVENT_NETWORK_PACKET = 0;
public const byte WINDIVERT_EVENT_FLOW_ESTABLISHED = 1;
public const byte WINDIVERT_EVENT_FLOW_DELETED = 2;
public const byte WINDIVERT_EVENT_SOCKET_BIND = 3;
public const byte WINDIVERT_EVENT_SOCKET_CONNECT = 4;
public const byte WINDIVERT_EVENT_SOCKET_LISTEN = 5;
public const byte WINDIVERT_EVENT_SOCKET_ACCEPT = 6;
public const byte WINDIVERT_EVENT_REFLECT_OPEN = 7;
public const byte WINDIVERT_EVENT_REFLECT_CLOSE = 8;
// 方向常量
public const byte WINDIVERT_DIRECTION_OUTBOUND = 0;
public const byte WINDIVERT_DIRECTION_INBOUND = 1;
// 参数常量
public const int WINDIVERT_PARAM_QUEUE_LENGTH = 0;
public const int WINDIVERT_PARAM_QUEUE_TIME = 1;
public const int WINDIVERT_PARAM_QUEUE_SIZE = 2;
public const int WINDIVERT_PARAM_VERSION_MAJOR = 3;
public const int WINDIVERT_PARAM_VERSION_MINOR = 4;
// 校验和常量
public const uint WINDIVERT_HELPER_NO_REPLACE = 0;
public const uint WINDIVERT_HELPER_NO_ICMPV6 = 0;
public const uint WINDIVERT_HELPER_NO_ICMP = 0;
public const uint WINDIVERT_HELPER_NO_TCP = 0;
public const uint WINDIVERT_HELPER_NO_UDP = 0;
public const uint WINDIVERT_HELPER_NO_IP = 0;
public const uint WINDIVERT_HELPER_NO_IPV6 = 0;
// 优先级范围
public const short WINDIVERT_PRIORITY_HIGHEST = 30000;
public const short WINDIVERT_PRIORITY_LOWEST = -30000;
public const short WINDIVERT_PRIORITY_DEFAULT = 0;
#endregion
#region 结构体定义
///
/// WinDivert 地址结构
///
// [StructLayout(LayoutKind.Sequential)]
// public struct WINDIVERT_ADDRESS
// {
// public long Timestamp; // 时间戳
// public byte Layer; // 层级
// public byte Event; // 事件
// public byte Flags; // 标志
// public byte Reserved1; // 保留
// public uint IfIdx; // 接口索引
// public uint SubIfIdx; // 子接口索引
// public byte Direction; // 方向
// public byte Reserved2; // 保留
// public ulong Reserved3; // 保留
// }
// 确保结构体布局正确 - 使用StructLayout和FieldOffset
// 完全匹配WinDivert 2.0版本的结构体定义
[StructLayout(LayoutKind.Sequential)]
public struct WINDIVERT_ADDRESS
{
public long Timestamp;
public byte Layer;
public byte Event;
public ushort Flags;
public uint IfIdx;
public uint SubIfIdx;
// 注意:在WinDivert 2.0中,Reserved字段是64位(8字节)对齐的
// 所以我们使用固定大小的字节数组
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Reserved;
}
///
/// IPv4 头结构
///
[StructLayout(LayoutKind.Sequential)]
public struct WINDIVERT_IPHDR
{
public byte HdrLength4; // 组合字段: 版本 (4 bits) + 头长度 (4 bits)
public byte TOS; // 服务类型
public ushort Length; // 总长度
public ushort Id; // 标识
public ushort FragOff0; // 组合字段: 标志 (3 bits) + 分片偏移 (13 bits)
public byte TTL; // 生存时间
public byte Protocol; // 协议
public ushort Checksum; // 检验和
public uint SrcAddr; // 源地址
public uint DstAddr; // 目标地址
}
///
/// IPv6 头结构
///
[StructLayout(LayoutKind.Sequential)]
public struct WINDIVERT_IPV6HDR
{
public uint FlowLabel0; // 组合字段: 版本 (4 bits) + 通信类 (8 bits) + 流标签 (20 bits)
public ushort Length; // 有效载荷长度
public byte NextHdr; // 下一个头
public byte HopLimit; // 跳数限制
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] SrcAddr; // 源地址
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] DstAddr; // 目标地址
}
///
/// TCP 头结构
///
[StructLayout(LayoutKind.Sequential)]
public struct WINDIVERT_TCPHDR
{
public ushort SrcPort; // 源端口
public ushort DstPort; // 目标端口
public uint SeqNum; // 序列号
public uint AckNum; // 确认号
public ushort Reserved10; // 组合字段: 数据偏移 (4 bits) + 保留 (6 bits) + 标志 (6 bits)
public ushort Window; // 窗口大小
public ushort Checksum; // 检验和
public ushort UrgPtr; // 紧急指针
}
///
/// UDP 头结构
///
[StructLayout(LayoutKind.Sequential)]
public struct WINDIVERT_UDPHDR
{
public ushort SrcPort; // 源端口
public ushort DstPort; // 目标端口
public ushort Length; // 长度
public ushort Checksum; // 检验和
}
///
/// ICMP 头结构
///
[StructLayout(LayoutKind.Sequential)]
public struct WINDIVERT_ICMPHDR
{
public byte Type; // 类型
public byte Code; // 代码
public ushort Checksum; // 检验和
public uint Body; // 消息体
}
///
/// ICMPv6 头结构
///
[StructLayout(LayoutKind.Sequential)]
public struct WINDIVERT_ICMPV6HDR
{
public byte Type; // 类型
public byte Code; // 代码
public ushort Checksum; // 检验和
public uint Body; // 消息体
}
#endregion
#region 原生 API 导入
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern IntPtr WinDivertOpen(
[MarshalAs(UnmanagedType.LPStr)] string filter,
uint layer,
short priority,
ulong flags);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool WinDivertRecv(
IntPtr handle,
[Out] byte[] pPacket,
uint packetLen,
ref WINDIVERT_ADDRESS pAddr,
ref uint readLen);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool WinDivertRecvEx(
IntPtr handle,
[Out] byte[] pPacket,
uint packetLen,
uint recvFlags,
[In, Out] ref WINDIVERT_ADDRESS pAddr,
[In, Out] ref uint readLen,
IntPtr lpOverlapped);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertSend(
IntPtr handle,
byte[] pPacket,
uint packetLen,
ref WINDIVERT_ADDRESS pAddr,
ref uint writeLen);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertSendEx(
IntPtr handle,
byte[] pPacket,
uint packetLen,
uint flags,
ref WINDIVERT_ADDRESS pAddr,
ref uint writeLen,
IntPtr overlapped);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool WinDivertClose(
IntPtr handle);
// 获取错误信息的帮助函数
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint WinDivertHelperNtohs(ushort value);
// 获取WinDivert特定错误
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr WinDivertHelperFormatFilter(
[MarshalAs(UnmanagedType.LPStr)] string filter,
WinDivertFormatFlags formatFlags,
IntPtr buffer,
uint bufferLen);
// 用于格式化过滤器的标志
[Flags]
public enum WinDivertFormatFlags : uint
{
Normal = 0,
NoNumbers = 1,
Aliases = 2,
}
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertSetParam(
IntPtr handle,
int param,
ulong value);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertGetParam(
IntPtr handle,
int param,
ref ulong value);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint WinDivertHelperCalcChecksums(
byte[] pPacket,
uint packetLen,
ref WINDIVERT_ADDRESS pAddr,
uint flags);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertHelperParsePacket(
byte[] pPacket,
uint packetLen,
out IntPtr ppIpHdr,
out IntPtr ppIpv6Hdr,
out IntPtr ppIcmpHdr,
out IntPtr ppIcmpv6Hdr,
out IntPtr ppTcpHdr,
out IntPtr ppUdpHdr,
out IntPtr ppData,
out ushort pDataLen
);
// 安全包装 - 处理异常大小问题
public static bool SafeRecv(IntPtr handle, byte[] buffer, ref WINDIVERT_ADDRESS addr, out byte[] packet)
{
packet = null;
// 确保结构体正确初始化
if (addr.Reserved == null)
{
addr.Reserved = new byte[8];
}
uint readLen = 0;
// 使用基础函数调用
bool result = WinDivertRecv(handle, buffer, (uint)buffer.Length, ref addr, ref readLen);
if (!result) return false;
// *** 关键修复:处理异常大小 ***
// 通过数据包的第一个字节验证它是IPv4还是IPv6数据包
if (buffer.Length > 0)
{
byte version = (byte)(buffer[0] >> 4);
// IPv4数据包版本是4,IPv6是6
if (version == 4 || version == 6)
{
// 检查IP头部中的长度字段
// 对于IPv4,长度在字节3-4中;对于IPv6,长度在字节5-6中
ushort ipLength;
if (version == 4 && buffer.Length >= 4)
{
ipLength = (ushort)((buffer[2] << 8) | buffer[3]);
// IPv4报头最小20字节,最大65535字节
if (ipLength >= 20 && ipLength <= 65535)
{
readLen = ipLength;
}
else if (buffer.Length >= 20) // 如果长度字段无效,至少读取IPv4头
{
readLen = 1500; // 使用标准以太网MTU大小
}
}
else if (version == 6 && buffer.Length >= 6)
{
ipLength = (ushort)((buffer[4] << 8) | buffer[5]);
// IPv6报头固定40字节,加上有效载荷
if (ipLength + 40 <= 65535)
{
readLen = (uint)(ipLength + 40);
}
else if (buffer.Length >= 40) // 如果长度字段无效,至少读取IPv6头
{
readLen = 1500; // 使用标准以太网MTU大小
}
}
}
// 如果仍然出现异常大小,强制使用安全值
if (readLen > 9000 || readLen == 0)
{
// 设置为安全的默认值(标准以太网MTU)
readLen = 1500;
}
}
// 只提取有效数据
packet = new byte[readLen];
Array.Copy(buffer, packet, readLen);
return true;
}
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertHelperParseIPv4Address(
[MarshalAs(UnmanagedType.LPStr)] string str,
ref uint pAddr);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertHelperParseIPv6Address(
[MarshalAs(UnmanagedType.LPStr)] string str,
byte[] pAddr);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertHelperFormatIPv4Address(
uint addr,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer,
uint bufLen);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertHelperFormatIPv6Address(
byte[] addr,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer,
uint bufLen);
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertHelperCheckFilter(
[MarshalAs(UnmanagedType.LPStr)] string filter,
uint layer,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder errorStr,
uint errorStrLen);
#endregion
#region 辅助方法
///
/// 打开 WinDivert 句柄
///
/// 过滤器表达式
/// 层级
/// 优先级
/// 标志
/// WinDivert 句柄
public static IntPtr Open(string filter, uint layer, short priority, ulong flags) =>
WinDivertOpen(filter, layer, priority, flags);
///
/// 接收数据包
///
/// WinDivert 句柄
/// 数据缓冲区
/// 缓冲区长度
/// 地址结构
/// 实际读取长度
/// 是否成功
public static bool Recv(IntPtr handle, byte[] buffer, uint bufferLength, ref WINDIVERT_ADDRESS addr,
ref uint readLen)
{
// 明确初始化readLen为0
readLen = 0;
// 确保WINDIVERT_ADDRESS结构体初始化正确
if (addr.Reserved == null)
{
addr.Reserved = new byte[8];
}
return WinDivertRecv(handle, buffer, bufferLength, ref addr, ref readLen);
}
///
/// 扩展接收数据包
///
/// WinDivert 句柄
/// 数据缓冲区
/// 缓冲区长度
/// 标志
/// 地址结构
/// 实际读取长度
/// 重叠 I/O 结构
/// 是否成功
// 更安全的Recv包装
public static bool RecvEx(IntPtr handle, byte[] buffer, ref WINDIVERT_ADDRESS addr, ref uint readLen)
{
// 确保结构体正确初始化
if (addr.Reserved == null)
addr.Reserved = new byte[8];
// 清零readLen
readLen = 0;
// 使用Ex版本,提供更多控制和稳定性
return WinDivertRecvEx(
handle,
buffer,
(uint)buffer.Length,
0, // 默认接收标志
ref addr,
ref readLen,
IntPtr.Zero // 非异步调用
);
}
///
/// 发送数据包
///
/// WinDivert 句柄
/// 数据缓冲区
/// 缓冲区长度
/// 地址结构
/// 实际写入长度
/// 是否成功
public static bool Send(IntPtr handle, byte[] buffer, uint len, ref WINDIVERT_ADDRESS addr, ref uint writeLen) =>
WinDivertSend(handle, buffer, len, ref addr, ref writeLen);
///
/// 扩展发送数据包
///
/// WinDivert 句柄
/// 数据缓冲区
/// 缓冲区长度
/// 标志
/// 地址结构
/// 实际写入长度
/// 重叠 I/O 结构
/// 是否成功
public static bool SendEx(IntPtr handle, byte[] buffer, uint len, uint flags, ref WINDIVERT_ADDRESS addr,
ref uint writeLen, IntPtr overlapped) =>
WinDivertSendEx(handle, buffer, len, flags, ref addr, ref writeLen, overlapped);
///
/// 关闭 WinDivert 句柄
///
/// WinDivert 句柄
/// 是否成功
public static bool Close(IntPtr handle) =>
WinDivertClose(handle);
///
/// 设置参数
///
/// WinDivert 句柄
/// 参数类型
/// 参数值
/// 是否成功
public static bool SetParam(IntPtr handle, int param, ulong value) =>
WinDivertSetParam(handle, param, value);
///
/// 获取参数
///
/// WinDivert 句柄
/// 参数类型
/// 参数值
/// 是否成功
public static bool GetParam(IntPtr handle, int param, ref ulong value) =>
WinDivertGetParam(handle, param, ref value);
///
/// 计算校验和
///
/// 数据缓冲区
/// 缓冲区长度
/// 地址结构
/// 标志
/// 校验和结果
public static uint CalcChecksums(byte[] buffer, uint len, ref WINDIVERT_ADDRESS addr, uint flags) =>
WinDivertHelperCalcChecksums(buffer, len, ref addr, flags);
///
/// 解析数据包【传递至此的 buffer 必须是新的!必须是空的!不能是用过的!】
///
/// 数据缓冲区
/// 缓冲区长度
/// IPv4 头指针
/// IPv6 头指针
/// ICMP 头指针
/// ICMPv6 头指针
/// TCP 头指针
/// UDP 头指针
/// 数据指针
/// 数据长度
/// 是否成功
public static bool ParsePacket(
byte[] buffer,
uint len,
ref IntPtr ppIpHdr,
ref IntPtr ppIpv6Hdr,
ref IntPtr ppIcmpHdr,
ref IntPtr ppIcmpv6Hdr,
ref IntPtr ppTcpHdr,
ref IntPtr ppUdpHdr,
ref IntPtr ppData,
ref ushort pDataLen
)
{
return WinDivertHelperParsePacket(
buffer,
len,
out ppIpHdr,
out ppIpv6Hdr,
out ppIcmpHdr,
out ppIcmpv6Hdr,
out ppTcpHdr,
out ppUdpHdr,
out ppData,
out pDataLen
);
}
///
/// 解析 IPv4 地址
///
/// IP 地址字符串
/// 地址结果
/// 是否成功
public static bool ParseIPv4Address(string str, ref uint pAddr) =>
WinDivertHelperParseIPv4Address(str, ref pAddr);
///
/// 解析 IPv6 地址
///
/// IP 地址字符串
/// 地址结果
/// 是否成功
public static bool ParseIPv6Address(string str, byte[] pAddr) =>
WinDivertHelperParseIPv6Address(str, pAddr);
///
/// 格式化 IPv4 地址
///
/// IP 地址
/// 格式化后的字符串
public static string FormatIPv4Address(uint addr)
{
StringBuilder buffer = new StringBuilder(16);
if (WinDivertHelperFormatIPv4Address(addr, buffer, 16))
{
return buffer.ToString();
}
return string.Empty;
}
///
/// 格式化 IPv6 地址
///
/// IP 地址
/// 格式化后的字符串
public static string FormatIPv6Address(byte[] addr)
{
StringBuilder buffer = new StringBuilder(46);
if (WinDivertHelperFormatIPv6Address(addr, buffer, 46))
{
return buffer.ToString();
}
return string.Empty;
}
///
/// 检查过滤器语法
///
/// 过滤器表达式
/// 层级
/// 错误信息
/// 错误信息长度
/// 是否有效
public static bool CheckFilter(string filter, uint layer, StringBuilder errorStr, uint errorStrLen) =>
WinDivertHelperCheckFilter(filter, layer, errorStr, errorStrLen);
#endregion
[StructLayout(LayoutKind.Sequential)]
public struct PacketHeaders
{
public IntPtr IpHdr;
public IntPtr Ipv6Hdr;
public IntPtr IcmpHdr;
public IntPtr Icmpv6Hdr;
public IntPtr TcpHdr;
public IntPtr UdpHdr;
public IntPtr Data;
public uint DataLen;
}
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool WinDivertHelperParsePacketEx(
[In] byte[] pPacket,
uint packetLen,
ref PacketHeaders headers);
}