使用 WFP 在 ALE_CONNECT_REDIRECT_V4 层重定向每个应用的 DNS 请求
Redirect per-app DNS requests at the ALE_CONNECT_REDIRECT_V4 layer using WFP
我正在尝试使用 WFP(Windows 过滤平台)在每个应用程序的基础上重定向 DNS 请求。我想重定向到 public DNS 服务器 - 而不是本地代理。我在 ALE_CONNECT_REDIRECT_V4
层有一个标注驱动程序。当我在这一层跟踪 DNS 请求时,我可以看到它们正常运行。
但是,当我将 DNS 服务器 ip(使用 INETADDR_SET_ADDRESS
)重写到另一个 public 服务器,例如 1.1.1.1
(我只重写到 public 服务器,而不是本地代理)我看到重写的 DNS 请求留在 wireshark 上,并且它们的响应也成功进入——但我正在重写其 DNS 的应用程序没有收到这些 DNS 响应——它无法解析主机名。
我已禁用 DNS 缓存,以便 DNS 请求直接来自应用程序,而不是 svchost.exe 进程。
这是为什么?我是否还必须以某种方式挂接传入数据包并将 DNS 服务器恢复到应用程序期望的服务器?我很茫然。
在亲自尝试之后,是的,对于通过 UDP 的 DNS 流量,您必须拦截入站数据报并使用 clone-drop-reinject 方法修改源地址。 TCP 上的 DNS 流量不受影响,因为它是基于连接的协议,而 UDP 是无连接的。
完整的最小工作驱动程序代码:https://pastebin.com/tCHqNnJH
相关摘录:
void UpdateIpv4HeaderChecksum(PIPV4_HEADER IpHeader, UINT32 IpHeaderSize)
{
UINT32 Checksum = 0;
UINT32 WordCount = IpHeaderSize / sizeof(UINT16);
UINT16* Header = (UINT16*)IpHeader;
IpHeader->Checksum = 0;
for (UINT8 WordIndex = 0; WordIndex < WordCount; WordIndex++)
{
Checksum += Header[WordIndex];
}
Checksum = (Checksum & 0x0000ffff) + (Checksum >> 16);
Checksum += (Checksum >> 16);
IpHeader->Checksum = (UINT16)~Checksum;
}
void NTAPI DriverDatagramDataInjectComplete(
_In_ void* context,
_Inout_ NET_BUFFER_LIST* netBufferList,
_In_ BOOLEAN dispatchLevel
)
{
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(dispatchLevel);
if (!NT_SUCCESS(netBufferList->Status))
{
DoTraceMessage(Default, "DriverDatagramDataInjectComplete() Status=%!STATUS!", netBufferList->Status);
}
FwpsFreeCloneNetBufferList(netBufferList, 0);
}
void NTAPI DriverDatagramDataClassify(
_In_ const FWPS_INCOMING_VALUES* inFixedValues,
_In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
_Inout_opt_ void* layerData,
_In_opt_ const void* classifyContext,
_In_ const FWPS_FILTER* filter,
_In_ UINT64 flowContext,
_Inout_ FWPS_CLASSIFY_OUT* classifyOut
)
{
UNREFERENCED_PARAMETER(layerData);
UNREFERENCED_PARAMETER(classifyContext);
UNREFERENCED_PARAMETER(filter);
UNREFERENCED_PARAMETER(flowContext);
UINT32 RemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32;
UINT16 RemotePort = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_PORT].value.uint16;
IF_INDEX InterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;
IF_INDEX SubInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;
FWP_DIRECTION Direction = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32;
FWPS_PACKET_INJECTION_STATE PacketInjectionState = FwpsQueryPacketInjectionState(g_InjectionHandle, layerData, NULL);
classifyOut->actionType = FWP_ACTION_PERMIT;
classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
if ((Direction == FWP_DIRECTION_INBOUND) && (PacketInjectionState == FWPS_PACKET_NOT_INJECTED) && (RemotePort == DNS_PORT) && (RemoteAddress == DNS_HOST_REDIRECT))
{
UINT32 IpHeaderSize = inMetaValues->ipHeaderSize;
UINT32 TransportHeaderSize = inMetaValues->transportHeaderSize;
PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB((PNET_BUFFER_LIST)layerData);
NdisRetreatNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, 0, NULL);
PNET_BUFFER_LIST NetBufferList = NULL;
NTSTATUS Status = FwpsAllocateCloneNetBufferList(layerData, NULL, NULL, 0, &NetBufferList);
if (!NT_SUCCESS(Status))
{
DoTraceMessage(Default, "FwpsAllocateCloneNetBufferList() Status=%!STATUS!", Status);
}
NdisAdvanceNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, FALSE, NULL);
if (!NetBufferList)
{
return;
}
DoTraceMessage(Default, "Modify DNS response");
NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
PIPV4_HEADER IpHeader = NdisGetDataBuffer(NetBuffer, sizeof(IPV4_HEADER), NULL, 1, 0);
IpHeader->SourceAddress = DNS_HOST_ORIGINAL;
UpdateIpv4HeaderChecksum(IpHeader, sizeof(IPV4_HEADER));
Status = FwpsInjectTransportReceiveAsync(g_InjectionHandle, NULL, NULL, 0, AF_INET, inMetaValues->compartmentId, InterfaceIndex, SubInterfaceIndex, NetBufferList, DriverDatagramDataInjectComplete, NULL);
if (!NT_SUCCESS(Status))
{
DoTraceMessage(Default, "FwpsInjectTransportReceiveAsync() Status=%!STATUS!", Status);
FwpsFreeCloneNetBufferList(NetBufferList, 0);
}
classifyOut->actionType = FWP_ACTION_BLOCK;
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
}
}
我正在尝试使用 WFP(Windows 过滤平台)在每个应用程序的基础上重定向 DNS 请求。我想重定向到 public DNS 服务器 - 而不是本地代理。我在 ALE_CONNECT_REDIRECT_V4
层有一个标注驱动程序。当我在这一层跟踪 DNS 请求时,我可以看到它们正常运行。
但是,当我将 DNS 服务器 ip(使用 INETADDR_SET_ADDRESS
)重写到另一个 public 服务器,例如 1.1.1.1
(我只重写到 public 服务器,而不是本地代理)我看到重写的 DNS 请求留在 wireshark 上,并且它们的响应也成功进入——但我正在重写其 DNS 的应用程序没有收到这些 DNS 响应——它无法解析主机名。
我已禁用 DNS 缓存,以便 DNS 请求直接来自应用程序,而不是 svchost.exe 进程。
这是为什么?我是否还必须以某种方式挂接传入数据包并将 DNS 服务器恢复到应用程序期望的服务器?我很茫然。
在亲自尝试之后,是的,对于通过 UDP 的 DNS 流量,您必须拦截入站数据报并使用 clone-drop-reinject 方法修改源地址。 TCP 上的 DNS 流量不受影响,因为它是基于连接的协议,而 UDP 是无连接的。
完整的最小工作驱动程序代码:https://pastebin.com/tCHqNnJH
相关摘录:
void UpdateIpv4HeaderChecksum(PIPV4_HEADER IpHeader, UINT32 IpHeaderSize)
{
UINT32 Checksum = 0;
UINT32 WordCount = IpHeaderSize / sizeof(UINT16);
UINT16* Header = (UINT16*)IpHeader;
IpHeader->Checksum = 0;
for (UINT8 WordIndex = 0; WordIndex < WordCount; WordIndex++)
{
Checksum += Header[WordIndex];
}
Checksum = (Checksum & 0x0000ffff) + (Checksum >> 16);
Checksum += (Checksum >> 16);
IpHeader->Checksum = (UINT16)~Checksum;
}
void NTAPI DriverDatagramDataInjectComplete(
_In_ void* context,
_Inout_ NET_BUFFER_LIST* netBufferList,
_In_ BOOLEAN dispatchLevel
)
{
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(dispatchLevel);
if (!NT_SUCCESS(netBufferList->Status))
{
DoTraceMessage(Default, "DriverDatagramDataInjectComplete() Status=%!STATUS!", netBufferList->Status);
}
FwpsFreeCloneNetBufferList(netBufferList, 0);
}
void NTAPI DriverDatagramDataClassify(
_In_ const FWPS_INCOMING_VALUES* inFixedValues,
_In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
_Inout_opt_ void* layerData,
_In_opt_ const void* classifyContext,
_In_ const FWPS_FILTER* filter,
_In_ UINT64 flowContext,
_Inout_ FWPS_CLASSIFY_OUT* classifyOut
)
{
UNREFERENCED_PARAMETER(layerData);
UNREFERENCED_PARAMETER(classifyContext);
UNREFERENCED_PARAMETER(filter);
UNREFERENCED_PARAMETER(flowContext);
UINT32 RemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32;
UINT16 RemotePort = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_PORT].value.uint16;
IF_INDEX InterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;
IF_INDEX SubInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;
FWP_DIRECTION Direction = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32;
FWPS_PACKET_INJECTION_STATE PacketInjectionState = FwpsQueryPacketInjectionState(g_InjectionHandle, layerData, NULL);
classifyOut->actionType = FWP_ACTION_PERMIT;
classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
if ((Direction == FWP_DIRECTION_INBOUND) && (PacketInjectionState == FWPS_PACKET_NOT_INJECTED) && (RemotePort == DNS_PORT) && (RemoteAddress == DNS_HOST_REDIRECT))
{
UINT32 IpHeaderSize = inMetaValues->ipHeaderSize;
UINT32 TransportHeaderSize = inMetaValues->transportHeaderSize;
PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB((PNET_BUFFER_LIST)layerData);
NdisRetreatNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, 0, NULL);
PNET_BUFFER_LIST NetBufferList = NULL;
NTSTATUS Status = FwpsAllocateCloneNetBufferList(layerData, NULL, NULL, 0, &NetBufferList);
if (!NT_SUCCESS(Status))
{
DoTraceMessage(Default, "FwpsAllocateCloneNetBufferList() Status=%!STATUS!", Status);
}
NdisAdvanceNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, FALSE, NULL);
if (!NetBufferList)
{
return;
}
DoTraceMessage(Default, "Modify DNS response");
NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
PIPV4_HEADER IpHeader = NdisGetDataBuffer(NetBuffer, sizeof(IPV4_HEADER), NULL, 1, 0);
IpHeader->SourceAddress = DNS_HOST_ORIGINAL;
UpdateIpv4HeaderChecksum(IpHeader, sizeof(IPV4_HEADER));
Status = FwpsInjectTransportReceiveAsync(g_InjectionHandle, NULL, NULL, 0, AF_INET, inMetaValues->compartmentId, InterfaceIndex, SubInterfaceIndex, NetBufferList, DriverDatagramDataInjectComplete, NULL);
if (!NT_SUCCESS(Status))
{
DoTraceMessage(Default, "FwpsInjectTransportReceiveAsync() Status=%!STATUS!", Status);
FwpsFreeCloneNetBufferList(NetBufferList, 0);
}
classifyOut->actionType = FWP_ACTION_BLOCK;
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
}
}