U: 更新WinDivert函数封装并调整参数类型,增强错误处理和稳定性
A: 添加SafeRecv等安全调用封装,优化数据包接收逻辑 A: 提供Win32错误代码的详细解析打印 U: 更新数据包解析函数的实现,调整pDataLen类型 A: 新增PacketHeaders的ToString方法,用于调试输出 U: 重构PacketSniffer,优化IPv4/IPv6数据包解析及日志输出
This commit is contained in:
1 parent
ad2514e044
commit
2ba20f8e8a
3 files changed
+438
-103
No files matched your search
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
public static class PacketSniffer
|
||||
{
|
||||
public static void Start()
|
||||
public static void Start1()
|
||||
{
|
||||
Console.WriteLine($"进入 12313 ");
|
||||
var handle = WinDivert.Open("true", WinDivert.WINDIVERT_LAYER_NETWORK, 0, WinDivert.WINDIVERT_FLAG_SNIFF);
|
||||
@@ -29,61 +29,199 @@ public static class PacketSniffer
|
||||
}
|
||||
}
|
||||
|
||||
void ParsePacketAndLog(byte[] buffer, uint length, WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
if (buffer == null || length == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// IPv4 数据包的最小长度为 20 字节
|
||||
if (length >= 20)
|
||||
void ParsePacketAndLog(byte[] buffer, uint length, WinDivert.WINDIVERT_ADDRESS addr)
|
||||
{
|
||||
// 检查版本 (IPv4 = 4, 位于第一个字节的高 4 位)
|
||||
int version = (buffer[0] >> 4) & 0xF;
|
||||
|
||||
if (version == 4) // IPv4
|
||||
Console.WriteLine($"length: {length}");
|
||||
if (buffer == null || length == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
int headerLength = (buffer[0] & 0xF) * 4; // IHL * 4 = 字节数
|
||||
byte protocol = buffer[9]; // 协议字段
|
||||
|
||||
// 源 IP 和目标 IP
|
||||
uint srcIp = (uint)((buffer[12]) | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24));
|
||||
uint dstIp = (uint)((buffer[16]) | (buffer[17] << 8) | (buffer[18] << 16) | (buffer[19] << 24));
|
||||
|
||||
string srcIpStr = $"{buffer[12]}.{buffer[13]}.{buffer[14]}.{buffer[15]}";
|
||||
string dstIpStr = $"{buffer[16]}.{buffer[17]}.{buffer[18]}.{buffer[19]}";
|
||||
|
||||
Console.WriteLine($"IPv4: Src={srcIpStr}, Dst={dstIpStr}, Protocol={protocol}");
|
||||
|
||||
// 如果有足够的数据,解析 TCP 或 UDP
|
||||
if (length >= (uint)(headerLength + 4) && (protocol == 6 || protocol == 17))
|
||||
// IPv4 数据包的最小长度为 20 字节
|
||||
if (length >= 20)
|
||||
{
|
||||
// 获取端口 (TCP 和 UDP 的前 4 字节都是源端口和目标端口)
|
||||
int offset = headerLength;
|
||||
ushort srcPort = (ushort)((buffer[offset] << 8) | buffer[offset + 1]);
|
||||
ushort dstPort = (ushort)((buffer[offset + 2] << 8) | buffer[offset + 3]);
|
||||
|
||||
if (protocol == 6) // TCP
|
||||
// 检查版本 (IPv4 = 4, 位于第一个字节的高 4 位)
|
||||
int version = (buffer[0] >> 4) & 0xF;
|
||||
|
||||
if (version == 4) // IPv4
|
||||
{
|
||||
Console.WriteLine($"TCP: SrcPort={srcPort}, DstPort={dstPort}");
|
||||
int headerLength = (buffer[0] & 0xF) * 4; // IHL * 4 = 字节数
|
||||
byte protocol = buffer[9]; // 协议字段
|
||||
|
||||
// 源 IP 和目标 IP
|
||||
uint srcIp = (uint)((buffer[12]) | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24));
|
||||
uint dstIp = (uint)((buffer[16]) | (buffer[17] << 8) | (buffer[18] << 16) | (buffer[19] << 24));
|
||||
|
||||
string srcIpStr = $"{buffer[12]}.{buffer[13]}.{buffer[14]}.{buffer[15]}";
|
||||
string dstIpStr = $"{buffer[16]}.{buffer[17]}.{buffer[18]}.{buffer[19]}";
|
||||
|
||||
Console.WriteLine($"IPv4: Src={srcIpStr}, Dst={dstIpStr}, Protocol={protocol}");
|
||||
|
||||
// 如果有足够的数据,解析 TCP 或 UDP
|
||||
if (length >= (uint)(headerLength + 4) && (protocol == 6 || protocol == 17))
|
||||
{
|
||||
// 获取端口 (TCP 和 UDP 的前 4 字节都是源端口和目标端口)
|
||||
int offset = headerLength;
|
||||
ushort srcPort = (ushort)((buffer[offset] << 8) | buffer[offset + 1]);
|
||||
ushort dstPort = (ushort)((buffer[offset + 2] << 8) | buffer[offset + 3]);
|
||||
|
||||
if (protocol == 6) // TCP
|
||||
{
|
||||
Console.WriteLine($"TCP: SrcPort={srcPort}, DstPort={dstPort}");
|
||||
}
|
||||
else if (protocol == 17) // UDP
|
||||
{
|
||||
Console.WriteLine($"UDP: SrcPort={srcPort}, DstPort={dstPort}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (protocol == 17) // UDP
|
||||
else if (version == 6 && length >= 40) // IPv6 (头部固定 40 字节)
|
||||
{
|
||||
Console.WriteLine($"UDP: SrcPort={srcPort}, DstPort={dstPort}");
|
||||
// IPv6 解析代码...
|
||||
// 这里略过,需要时可以添加
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (version == 6 && length >= 40) // IPv6 (头部固定 40 字节)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// IPv6 解析代码...
|
||||
// 这里略过,需要时可以添加
|
||||
Console.WriteLine($"解析数据包时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
Console.WriteLine($"解析数据包时出错: {ex.Message}");
|
||||
Console.WriteLine("WinDivert调试工具启动...");
|
||||
|
||||
// 检查是否以管理员身份运行
|
||||
bool isAdmin = new System.Security.Principal.WindowsPrincipal(
|
||||
System.Security.Principal.WindowsIdentity.GetCurrent()
|
||||
).IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
|
||||
|
||||
if (!isAdmin)
|
||||
{
|
||||
Console.WriteLine("错误: 此程序需要管理员权限才能使用WinDivert!");
|
||||
Console.WriteLine("请右键点击程序,选择'以管理员身份运行'然后重试。");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("步骤1: 尝试打开WinDivert...");
|
||||
|
||||
// 最简单的过滤器
|
||||
string filter = "true";
|
||||
IntPtr handle =
|
||||
WinDivert.WinDivertOpen(filter, WinDivert.WINDIVERT_LAYER_NETWORK, 0, WinDivert.WINDIVERT_FLAG_SNIFF);
|
||||
|
||||
// 检查句柄是否有效
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
Console.WriteLine($"错误: 无法打开WinDivert,错误码: {errorCode}");
|
||||
PrintWin32Error(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("成功: WinDivert句柄已打开");
|
||||
|
||||
// 尝试接收一个数据包
|
||||
Console.WriteLine("\n步骤2: 尝试接收数据包...");
|
||||
|
||||
// 为数据包分配缓冲区
|
||||
byte[] buffer = new byte[65535]; // 最大以太网帧大小
|
||||
|
||||
// 设置接收地址结构
|
||||
WinDivert.WINDIVERT_ADDRESS addr = new WinDivert.WINDIVERT_ADDRESS
|
||||
{
|
||||
Reserved = new byte[8] // 确保Reserved被初始化
|
||||
};
|
||||
|
||||
// 接收数据包
|
||||
uint readLen = 0;
|
||||
|
||||
// 尝试直接使用基本的Recv函数
|
||||
Console.WriteLine("尝试WinDivertRecv...");
|
||||
bool recvResult = WinDivert.WinDivertRecv(handle, buffer, (uint)buffer.Length, ref addr, ref readLen);
|
||||
|
||||
if (!recvResult)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
Console.WriteLine($"错误: WinDivertRecv失败,错误码: {errorCode}");
|
||||
PrintWin32Error(errorCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"成功: 接收到数据包,大小: {readLen} 字节");
|
||||
|
||||
// 打印数据包的前16个字节
|
||||
string hexData = BitConverter.ToString(buffer, 0, Math.Min((int)readLen, 16));
|
||||
Console.WriteLine($"数据包前16字节: {hexData}");
|
||||
}
|
||||
|
||||
// 重置并尝试使用Ex版本
|
||||
readLen = 0;
|
||||
addr = new WinDivert.WINDIVERT_ADDRESS { Reserved = new byte[8] };
|
||||
|
||||
Console.WriteLine("\n尝试WinDivertRecvEx...");
|
||||
bool recvExResult =
|
||||
WinDivert.WinDivertRecvEx(handle, buffer, (uint)buffer.Length, 0, ref addr, ref readLen, IntPtr.Zero);
|
||||
|
||||
if (!recvExResult)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
Console.WriteLine($"错误: WinDivertRecvEx失败,错误码: {errorCode}");
|
||||
PrintWin32Error(errorCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"成功: 接收到数据包,大小: {readLen} 字节");
|
||||
|
||||
// 打印数据包的前16个字节
|
||||
string hexData = BitConverter.ToString(buffer, 0, Math.Min((int)readLen, 16));
|
||||
Console.WriteLine($"数据包前16字节: {hexData}");
|
||||
}
|
||||
|
||||
// 最后关闭句柄
|
||||
WinDivert.WinDivertClose(handle);
|
||||
Console.WriteLine("\nWinDivert句柄已关闭");
|
||||
|
||||
Console.WriteLine("\n调试信息收集完成。请检查以上输出以确定问题所在。");
|
||||
}
|
||||
|
||||
// 辅助函数:打印Win32错误信息
|
||||
private static void PrintWin32Error(int errorCode)
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 5:
|
||||
Console.WriteLine("访问被拒绝。请确认程序以管理员权限运行。");
|
||||
break;
|
||||
case 87:
|
||||
Console.WriteLine("参数错误。过滤器语法可能不正确。");
|
||||
break;
|
||||
case 123:
|
||||
Console.WriteLine("文件名、目录名或卷标语法不正确。请检查WinDivert.dll是否位于正确的路径。");
|
||||
break;
|
||||
case 126:
|
||||
Console.WriteLine("找不到指定的模块。无法找到WinDivert.dll文件。");
|
||||
break;
|
||||
case 193:
|
||||
Console.WriteLine("不是有效的Win32应用程序。WinDivert.dll可能是错误的版本(32位/64位)。");
|
||||
break;
|
||||
case 997:
|
||||
Console.WriteLine("正在进行重叠操作。WinDivert可能需要异步调用。");
|
||||
break;
|
||||
case 995:
|
||||
Console.WriteLine("由于线程退出或应用程序请求,已中止I/O操作。");
|
||||
break;
|
||||
case 998:
|
||||
Console.WriteLine("无效访问WinDivert。请检查是否有另一个进程正在使用相同的过滤器。");
|
||||
break;
|
||||
case 1450:
|
||||
Console.WriteLine("系统资源不足,无法完成请求的服务。");
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"未知错误。Windows错误码: {errorCode}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} }
|
||||
}
|
||||
@@ -71,21 +71,39 @@ public static class WinDivert
|
||||
/// <summary>
|
||||
/// WinDivert 地址结构
|
||||
/// </summary>
|
||||
// [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 byte Flags; // 标志
|
||||
public byte Reserved1; // 保留
|
||||
public uint IfIdx; // 接口索引
|
||||
public uint SubIfIdx; // 子接口索引
|
||||
public byte Direction; // 方向
|
||||
public byte Reserved2; // 保留
|
||||
public ulong Reserved3; // 保留
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IPv4 头结构
|
||||
/// </summary>
|
||||
@@ -178,30 +196,30 @@ public static class WinDivert
|
||||
|
||||
#region 原生 API 导入
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
[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)]
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
|
||||
public static extern bool WinDivertRecv(
|
||||
IntPtr handle,
|
||||
byte[] pPacket,
|
||||
[Out] byte[] pPacket,
|
||||
uint packetLen,
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
ref uint readLen);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
|
||||
public static extern bool WinDivertRecvEx(
|
||||
IntPtr handle,
|
||||
byte[] pPacket,
|
||||
[Out] byte[] pPacket,
|
||||
uint packetLen,
|
||||
uint flags,
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
ref uint readLen,
|
||||
IntPtr overlapped);
|
||||
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(
|
||||
@@ -221,10 +239,31 @@ public static class WinDivert
|
||||
ref uint writeLen,
|
||||
IntPtr overlapped);
|
||||
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
[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,
|
||||
@@ -244,31 +283,93 @@ public static class WinDivert
|
||||
ref WINDIVERT_ADDRESS pAddr,
|
||||
uint flags);
|
||||
|
||||
// [DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
// public static extern bool WinDivertHelperParsePacket(
|
||||
// byte[] pPacket,
|
||||
// uint packetLen,
|
||||
// ref IntPtr ppIpHdr,
|
||||
// ref IntPtr ppIpv6Hdr,
|
||||
// ref IntPtr ppIcmpHdr,
|
||||
// ref IntPtr ppIcmpv6Hdr,
|
||||
// ref IntPtr ppTcpHdr,
|
||||
// ref IntPtr ppUdpHdr,
|
||||
// ref IntPtr ppData,
|
||||
// ref uint pDataLen);
|
||||
[DllImport("WinDivert.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool WinDivertHelperParsePacket(
|
||||
[In] byte[] pPacket,
|
||||
byte[] pPacket,
|
||||
uint packetLen,
|
||||
[Out] out IntPtr ppIpHdr,
|
||||
[Out] out IntPtr ppIpv6Hdr,
|
||||
[Out] out IntPtr ppIcmpHdr,
|
||||
[Out] out IntPtr ppIcmpv6Hdr,
|
||||
[Out] out IntPtr ppTcpHdr,
|
||||
[Out] out IntPtr ppUdpHdr,
|
||||
[Out] out IntPtr ppData,
|
||||
[Out] out uint pDataLen);
|
||||
|
||||
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,
|
||||
@@ -322,8 +423,20 @@ public static class WinDivert
|
||||
/// <param name="addr">地址结构</param>
|
||||
/// <param name="readLen">实际读取长度</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool Recv(IntPtr handle, byte[] buffer, uint len, ref WINDIVERT_ADDRESS addr, ref uint readLen) =>
|
||||
WinDivertRecv(handle, buffer, len, ref addr, ref readLen);
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扩展接收数据包
|
||||
@@ -336,9 +449,27 @@ public static class WinDivert
|
||||
/// <param name="readLen">实际读取长度</param>
|
||||
/// <param name="overlapped">重叠 I/O 结构</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool RecvEx(IntPtr handle, byte[] buffer, uint len, uint flags, ref WINDIVERT_ADDRESS addr,
|
||||
ref uint readLen, IntPtr overlapped) =>
|
||||
WinDivertRecvEx(handle, buffer, len, flags, ref addr, ref readLen, overlapped);
|
||||
// 更安全的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 // 非异步调用
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据包
|
||||
@@ -407,7 +538,7 @@ public static class WinDivert
|
||||
WinDivertHelperCalcChecksums(buffer, len, ref addr, flags);
|
||||
|
||||
/// <summary>
|
||||
/// 解析数据包
|
||||
/// 解析数据包【传递至此的 buffer 必须是新的!必须是空的!不能是用过的!】
|
||||
/// </summary>
|
||||
/// <param name="buffer">数据缓冲区</param>
|
||||
/// <param name="len">缓冲区长度</param>
|
||||
@@ -420,11 +551,32 @@ public static class WinDivert
|
||||
/// <param name="ppData">数据指针</param>
|
||||
/// <param name="pDataLen">数据长度</param>
|
||||
/// <returns>是否成功</returns>
|
||||
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 uint pDataLen) =>
|
||||
WinDivertHelperParsePacket(buffer, len, out ppIpHdr, out ppIpv6Hdr, out ppIcmpHdr, out ppIcmpv6Hdr,
|
||||
out ppTcpHdr, out ppUdpHdr, out ppData, out pDataLen);
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析 IPv4 地址
|
||||
@@ -488,7 +640,7 @@ public static class WinDivert
|
||||
WinDivertHelperCheckFilter(filter, layer, errorStr, errorStrLen);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PacketHeaders
|
||||
{
|
||||
@@ -507,5 +659,4 @@ public static class WinDivert
|
||||
[In] byte[] pPacket,
|
||||
uint packetLen,
|
||||
ref PacketHeaders headers);
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class WinDivertController : IDisposable
|
||||
{
|
||||
private IntPtr _handle;
|
||||
private bool _disposed = false;
|
||||
|
||||
public IntPtr Handle => _handle;
|
||||
/// <summary>
|
||||
/// 获取句柄是否有效
|
||||
/// </summary>
|
||||
@@ -50,10 +50,29 @@ public class WinDivertController : IDisposable
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
_handle = WinDivert.Open(filter, layer, priority, flags);
|
||||
|
||||
_handle = WinDivert.WinDivertOpen(filter, layer, priority, flags);
|
||||
|
||||
if (_handle == IntPtr.Zero)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
Console.WriteLine($"WinDivert打开失败,错误码: {errorCode}");
|
||||
}
|
||||
|
||||
return IsValid;
|
||||
}
|
||||
public bool TryGetPacket(out byte[] packet, out WinDivert.WINDIVERT_ADDRESS address)
|
||||
{
|
||||
packet = null;
|
||||
address = new WinDivert.WINDIVERT_ADDRESS { Reserved = new byte[8] };
|
||||
|
||||
if (!IsValid) return false;
|
||||
|
||||
byte[] buffer = new byte[65535]; // 足够大的缓冲区
|
||||
|
||||
// 使用我们的SafeRecv函数处理异常大小问题
|
||||
return WinDivert.SafeRecv(_handle, buffer, ref address, out packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 WinDivert 句柄
|
||||
@@ -83,6 +102,7 @@ public class WinDivertController : IDisposable
|
||||
uint readLen = 0;
|
||||
if (WinDivert.Recv(_handle, buffer, (uint)buffer.Length, ref addr, ref readLen))
|
||||
{
|
||||
Console.WriteLine($"Receive: {readLen}");
|
||||
return readLen;
|
||||
}
|
||||
|
||||
@@ -215,7 +235,7 @@ public class WinDivertController : IDisposable
|
||||
IntPtr ppTcpHdr = IntPtr.Zero;
|
||||
IntPtr ppUdpHdr = IntPtr.Zero;
|
||||
IntPtr ppData = IntPtr.Zero;
|
||||
uint pDataLen = 0;
|
||||
ushort pDataLen = 0;
|
||||
|
||||
bool success = WinDivert.ParsePacket(packet, (uint)packet.Length, ref ppIpHdr, ref ppIpv6Hdr,
|
||||
ref ppIcmpHdr, ref ppIcmpv6Hdr, ref ppTcpHdr, ref ppUdpHdr, ref ppData, ref pDataLen);
|
||||
@@ -478,7 +498,6 @@ public class WinDivertController : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 数据包头信息
|
||||
/// </summary>
|
||||
@@ -558,4 +577,31 @@ public class PacketHeaders
|
||||
/// 数据长度
|
||||
/// </summary>
|
||||
public uint DataLength { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("PacketHeaders {");
|
||||
sb.AppendLine($" Success: {Success},");
|
||||
sb.AppendLine($" HasIpHeader: {HasIpHeader},");
|
||||
sb.AppendLine($" HasIpv6Header: {HasIpv6Header},");
|
||||
sb.AppendLine($" HasTcpHeader: {HasTcpHeader},");
|
||||
sb.AppendLine($" HasUdpHeader: {HasUdpHeader},");
|
||||
sb.AppendLine($" HasIcmpHeader: {HasIcmpHeader},");
|
||||
sb.AppendLine($" HasIcmpv6Header: {HasIcmpv6Header},");
|
||||
|
||||
sb.AppendLine($" IpHeader: {(HasIpHeader ? IpHeader.ToString() : "N/A")},");
|
||||
sb.AppendLine($" Ipv6Header: {(HasIpv6Header ? Ipv6Header.ToString() : "N/A")},");
|
||||
sb.AppendLine($" TcpHeader: {(HasTcpHeader ? TcpHeader.ToString() : "N/A")},");
|
||||
sb.AppendLine($" UdpHeader: {(HasUdpHeader ? UdpHeader.ToString() : "N/A")},");
|
||||
sb.AppendLine($" IcmpHeader: {(HasIcmpHeader ? IcmpHeader.ToString() : "N/A")},");
|
||||
sb.AppendLine($" Icmpv6Header: {(HasIcmpv6Header ? Icmpv6Header.ToString() : "N/A")},");
|
||||
|
||||
sb.AppendLine($" DataLength: {DataLength},");
|
||||
sb.AppendLine(
|
||||
$" Data: {(Data != null ? BitConverter.ToString(Data, 0, (int)Math.Min(Data.Length, 32)) + (Data.Length > 32 ? "..." : "") : "null")}");
|
||||
sb.AppendLine("}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user