当前位置: 首页 > news >正文

WFP DNS 域名解析

原文:【WFP】域名过滤-编程技术-看雪-安全社区|安全招聘|kanxue.com

看到原文就试试,结果域名解析一直有问题。概念及原理请参考原文。就修改了一版。

直接上代码

//dns_parse.h
typedef struct _DNS_HEADER {UINT16 id;               // 会话IDUINT16 flags;            // 标志位(包含响应/查询标志)UINT16 qdcount;          // 问题数UINT16 ancount;          // 回答数UINT16 nscount;          // 权威记录数UINT16 arcount;          // 附加记录数
} DNS_HEADER, *PDNS_HEADER;USHORT UTIL_htons(USHORT hostshort)
{PUCHAR pBuffer;USHORT nResult;nResult = 0;pBuffer = (PUCHAR)&hostshort;nResult = ((pBuffer[0] << 8) & 0xFF00) | (pBuffer[1] & 0x00FF);return(nResult);
}/*UTIL_ntohs把网络字节顺序转换成主机字节顺序*/
USHORT UTIL_ntohs(USHORT netshort)
{return(UTIL_htons(netshort));
}
//callouts.h#ifndef  _CALLOUTS
#define  _CALLOUTSNTSTATUS  callouts_init(PDEVICE_OBJECT deviceObject);
void callouts_free();#endif // 
//callouts.h#include "stdinc.h"
#include "callouts.h"#define FLOW_ESTABLISHED_CALLOUT_DESCRIPTION L"Ethan Flow Established Callout"
#define FLOW_ESTABLISHED_CALLOUT_NAME L"Flow Established Callout"#define STREAM_CALLOUT_DESCRIPTION L"Ethan Stream Callout"
#define STREAM_CALLOUT_NAME L"Stream Callout"#define SUBLAYER_NAME L"Ethan Sublayer"
#define RECV_SUBLAYER_NAME L"Ethan Recv Sublayer"#define PROVIDER_NAME L"Ethan Provider"enum CALLOUT_GUIDS
{CG_DATAGRAM_DATA_CALLOUT_V4,CG_DATAGRAM_DATA_CALLOUT_V6,CG_MAX
};static GUID		g_sublayerGuid;
static GUID		g_recvSublayerGuid;
static GUID		g_recvProtSublayerGuid;
static GUID		g_ipSublayerGuid;
static GUID		g_calloutGuids[CG_MAX];
static UINT32	g_calloutIds[CG_MAX];
static HANDLE	g_engineHandle = NULL;
static GUID		g_providerGuid;
static BOOLEAN	g_blockRST = TRUE;
static BOOLEAN	g_blockUnexpectedRecvDisconnects = TRUE;
static BOOLEAN	g_fastRecvDisconnectOnFinWithData = TRUE;
static BOOLEAN	g_bypassConnectRedirectWithoutActionWrite = TRUE;static BOOLEAN	g_initialized = FALSE;VOID callouts_udpCallout(IN const FWPS_INCOMING_VALUES* inFixedValues,IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues,IN VOID* packet,IN const void* classifyContext,IN const FWPS_FILTER* filter,IN UINT64 flowContext,OUT FWPS_CLASSIFY_OUT* classifyOut);NTSTATUS callouts_udpNotify(IN  FWPS_CALLOUT_NOTIFY_TYPE         notifyType,IN  const GUID*             filterKey,IN  const FWPS_FILTER*     filter);struct NF_CALLOUT
{FWPS_CALLOUT_CLASSIFY_FN classifyFunction;FWPS_CALLOUT_NOTIFY_FN notifyFunction;FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteFunction;GUID const* calloutKey;UINT32 flags;UINT32* calloutId;
} g_callouts[] = {{(FWPS_CALLOUT_CLASSIFY_FN)callouts_udpCallout,(FWPS_CALLOUT_NOTIFY_FN)callouts_udpNotify,NULL,&g_calloutGuids[CG_DATAGRAM_DATA_CALLOUT_V4],0, // No flags&g_calloutIds[CG_DATAGRAM_DATA_CALLOUT_V4]},{(FWPS_CALLOUT_CLASSIFY_FN)callouts_udpCallout,(FWPS_CALLOUT_NOTIFY_FN)callouts_udpNotify,NULL,&g_calloutGuids[CG_DATAGRAM_DATA_CALLOUT_V6],0, // No flags&g_calloutIds[CG_DATAGRAM_DATA_CALLOUT_V6]} };// 最大递归解析深度,防止压缩指针死循环
#define DNS_MAX_RECURSION 10// 递归解析域名函数
// 解析DNS域名函数声明
BOOLEAN ParseDnsName(const UINT8* packetData,SIZE_T packetLength,const UINT8* dnsData,           // 当前解析指针(包内偏移)SIZE_T dnsDataLength,           // 剩余长度CHAR* domainBuffer,             // 输出缓冲区SIZE_T bufferSize,SIZE_T* parsedLength,           // 返回本次解析消耗的长度(含压缩跳转)int recursionDepth              // 当前递归深度
)
{if (recursionDepth > DNS_MAX_RECURSION)return FALSE;SIZE_T domainNameLen = 0;SIZE_T localParsedLen = 0; // 本次调用消耗的长度(非递归跳转部分)const UINT8* packetEnd = packetData + packetLength;const UINT8* currentPtr = dnsData;while (dnsDataLength > 0){UINT8 labelLen = *currentPtr;// 压缩指针处理 (两个高位bit是11)if ((labelLen & 0xC0) == 0xC0){if (dnsDataLength < 2)return FALSE;// 计算指针偏移UINT16 offset = ((labelLen & 0x3F) << 8) | *(currentPtr + 1);if (offset >= packetLength)return FALSE;// 递归解析压缩指针指向的域名部分SIZE_T unused = 0;BOOLEAN ret = ParseDnsName(packetData, packetLength, packetData + offset, packetLength - offset,domainBuffer + domainNameLen, bufferSize - domainNameLen, &unused, recursionDepth + 1);if (!ret)return FALSE;// 压缩指针终止后,当前层只消耗2字节localParsedLen += 2;*parsedLength = localParsedLen;return TRUE;}else if (labelLen == 0){// 域名结束localParsedLen += 1;*parsedLength = localParsedLen;if (domainNameLen < bufferSize)domainBuffer[domainNameLen] = '\0';else if (bufferSize > 0)domainBuffer[bufferSize - 1] = '\0';return TRUE;}else{// 普通标签长度检查if (labelLen > 63 || labelLen + 1 > dnsDataLength)return FALSE;if (domainNameLen + labelLen + 1 >= bufferSize)  // +1 for '.' or '\0'return FALSE;// 添加分隔点if (domainNameLen > 0){domainBuffer[domainNameLen++] = '.';}// 复制标签内容RtlCopyMemory(domainBuffer + domainNameLen, currentPtr + 1, labelLen);domainNameLen += labelLen;// 前进指针currentPtr += labelLen + 1;dnsDataLength -= labelLen + 1;localParsedLen += labelLen + 1;}}return FALSE;
}// 主函数入口,传入完整UDP包和偏移,输出域名
BOOLEAN ParseDnsQuery(const UINT8* packetData,SIZE_T packetLength,size_t udpHeaderLen,CHAR* domainBuffer,SIZE_T bufferSize
)
{if (packetLength < udpHeaderLen + sizeof(DNS_HEADER))return FALSE;const UINT8* dnsStart = packetData + udpHeaderLen;SIZE_T dnsDataLength = packetLength - udpHeaderLen;PDNS_HEADER dnsHeader = (PDNS_HEADER)dnsStart;// 正确判断:响应包的 flags 最高位为 1(0x8000),查询包为 0UINT16 flags = UTIL_ntohs(dnsHeader->flags);  // 网络字节序转主机字节序if ((flags & 0x8000) != 0)  // 是响应包则跳过(只处理查询包)return FALSE;// 从DNS头后面开始解析域名const UINT8* namePtr = dnsStart + sizeof(DNS_HEADER);SIZE_T nameDataLen = dnsDataLength - sizeof(DNS_HEADER);SIZE_T parsedLen = 0;BOOLEAN ret = ParseDnsName(packetData, packetLength, namePtr, nameDataLen, domainBuffer, bufferSize, &parsedLen, 0);if (ret){KdPrint((DPREFIX "域名: %s \n", domainBuffer));     }return ret;
}VOID callouts_udpCallout(IN const FWPS_INCOMING_VALUES* inFixedValues,IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues,IN VOID* layerData,IN const void* classifyContext,IN const FWPS_FILTER* filter,IN UINT64 flowContext,OUT FWPS_CLASSIFY_OUT* classifyOut)
{UNREFERENCED_PARAMETER(classifyContext);UNREFERENCED_PARAMETER(filter);UNREFERENCED_PARAMETER(flowContext);// 初始允许classifyOut->actionType = FWP_ACTION_PERMIT;if (layerData == NULL) return;if (inFixedValues->layerId != FWPS_LAYER_DATAGRAM_DATA_V4 &&inFixedValues->layerId != FWPS_LAYER_DATAGRAM_DATA_V6) {return;}// 后续使用正确的字段获取端口(IPv6的端口字段不同)UINT16 remotePort;if (inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4) {remotePort = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_PORT].value.uint16;}else {remotePort = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_PORT].value.uint16;}if (remotePort != 53) return; // 只关心 DNS 请求UINT8 direction;if (inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4) {direction = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint8;}else {  // IPv6direction = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_DIRECTION].value.uint8;}if (direction != FWP_DIRECTION_OUTBOUND) {return;  // 只处理出站查询}ULONG UdpHeaderLength = 0;BOOL isOutBound = FALSE;PNET_BUFFER pNetBuffer = NET_BUFFER_LIST_FIRST_NB((PNET_BUFFER_LIST)layerData);if (pNetBuffer == NULL){return;}ULONG UdpContentLength = NET_BUFFER_DATA_LENGTH(pNetBuffer);if (UdpContentLength == 0){return;}if (direction == FWP_DIRECTION_OUTBOUND){UdpHeaderLength = inMetaValues->transportHeaderSize;if (UdpHeaderLength == 0 || UdpContentLength < UdpHeaderLength) {return;}UdpContentLength -= UdpHeaderLength;isOutBound = TRUE;}else{return;}PVOID UdpContent = ExAllocatePoolWithTag(NonPagedPool, UdpContentLength + UdpHeaderLength, 'dnsT');if (UdpContent == NULL){return;}PVOID ndisBuffer = NdisGetDataBuffer(pNetBuffer, UdpContentLength + UdpHeaderLength, UdpContent, 1, 0);if (ndisBuffer == NULL) {ExFreePoolWithTag(UdpContent, 'dnsT');  // 释放内存return;}CHAR domain[256] = { 0 };if (ParseDnsQuery(UdpContent, UdpContentLength + UdpHeaderLength, UdpHeaderLength, domain, sizeof(domain))) {if (strstr(domain, "baidu.com") != 0) {classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;KdPrint((DPREFIX "拦截: %s \n", domain));}}ExFreePoolWithTag(UdpContent, 'dnsT');}NTSTATUS callouts_udpNotify(IN  FWPS_CALLOUT_NOTIFY_TYPE         notifyType,IN  const GUID*             filterKey,IN  const FWPS_FILTER*     filter)
{UNREFERENCED_PARAMETER(notifyType);UNREFERENCED_PARAMETER(filterKey);UNREFERENCED_PARAMETER(filter);switch (notifyType){case FWPS_CALLOUT_NOTIFY_ADD_FILTER:KdPrint((DPREFIX"Filter Added to UDP layer.\n"));break;case FWPS_CALLOUT_NOTIFY_DELETE_FILTER:KdPrint((DPREFIX"Filter Deleted from UDP layer.\n"));break;}return STATUS_SUCCESS;
}void
callouts_unregisterCallouts()
{NTSTATUS status;int i;for (i = 0; i < CG_MAX; i++){status = FwpsCalloutUnregisterByKey(&g_calloutGuids[i]);if (!NT_SUCCESS(status)){ASSERT(0);}}
}NTSTATUS  callouts_registerCallout(void* deviceObject,FWPS_CALLOUT_CLASSIFY_FN  classifyFunction,FWPS_CALLOUT_NOTIFY_FN notifyFunction,FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN  flowDeleteFunction,GUID const* calloutKey,UINT32  flags,UINT32* calloutId) 
{FWPS_CALLOUT sCallout;NTSTATUS status = STATUS_SUCCESS;memset(&sCallout,0,sizeof(sCallout));sCallout.calloutKey = *calloutKey;sCallout.flags = flags;sCallout.classifyFn = classifyFunction;sCallout.notifyFn = notifyFunction;sCallout.flowDeleteFn = flowDeleteFunction;status = FwpsCalloutRegister(deviceObject,(FWPS_CALLOUT*)&sCallout,calloutId);return status;
}NTSTATUS callouts_registerCallouts(void* deviceObject)
{NTSTATUS status = STATUS_SUCCESS;int i;status = FwpmTransactionBegin(g_engineHandle, 0);if (!NT_SUCCESS(status)){FwpmEngineClose(g_engineHandle);g_engineHandle = NULL;return status;}for (;;){for (i = 0; i < sizeof(g_callouts) / sizeof(g_callouts[0]); i++){status = callouts_registerCallout(deviceObject,g_callouts[i].classifyFunction,g_callouts[i].notifyFunction,g_callouts[i].flowDeleteFunction,g_callouts[i].calloutKey,g_callouts[i].flags,g_callouts[i].calloutId);if (!NT_SUCCESS(status)){break;}}if (!NT_SUCCESS(status)){break;}status = FwpmTransactionCommit(g_engineHandle);if (!NT_SUCCESS(status)){break;}break;}if (!NT_SUCCESS(status)){FwpmTransactionAbort(g_engineHandle);FwpmEngineClose(g_engineHandle);g_engineHandle = NULL;}return status;
}NTSTATUS
callouts_addUdpFlowEstablishedFilter(const GUID * calloutKey, const GUID * layer, FWPM_SUBLAYER * subLayer)
{FWPM_CALLOUT callout;FWPM_DISPLAY_DATA displayData;FWPM_FILTER filter;FWPM_FILTER_CONDITION filterConditions[1];NTSTATUS status;for (;;){RtlZeroMemory(&callout, sizeof(FWPM_CALLOUT));displayData.description = FLOW_ESTABLISHED_CALLOUT_DESCRIPTION;displayData.name = FLOW_ESTABLISHED_CALLOUT_NAME;callout.calloutKey = *calloutKey;callout.displayData = displayData;callout.applicableLayer = *layer;callout.flags = 0;status = FwpmCalloutAdd(g_engineHandle, &callout, NULL, NULL);if (!NT_SUCCESS(status)){break;}RtlZeroMemory(&filter, sizeof(FWPM_FILTER));filter.layerKey = *layer;filter.displayData.name = FLOW_ESTABLISHED_CALLOUT_NAME;filter.displayData.description = FLOW_ESTABLISHED_CALLOUT_NAME;filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;filter.action.calloutKey = *calloutKey;filter.filterCondition = filterConditions;filter.subLayerKey = subLayer->subLayerKey;filter.weight.type = FWP_EMPTY; // auto-weight.filter.numFilterConditions = 1;RtlZeroMemory(filterConditions, sizeof(filterConditions));filterConditions[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;filterConditions[0].matchType = FWP_MATCH_EQUAL;filterConditions[0].conditionValue.type = FWP_UINT8;filterConditions[0].conditionValue.uint8 = IPPROTO_UDP;status = FwpmFilterAdd(g_engineHandle,&filter,NULL,NULL);if (!NT_SUCCESS(status)){break;}break;}return status;
}NTSTATUS
callouts_addFilters()
{FWPM_SUBLAYER subLayer;NTSTATUS status;USHORT subLayerWeight;FWPM_SUBLAYER * pUdpSubLayer = NULL;subLayerWeight = 1;status = FwpmTransactionBegin(g_engineHandle, 0);if (!NT_SUCCESS(status)){return status;}for (;;){RtlZeroMemory(&subLayer, sizeof(FWPM_SUBLAYER));subLayer.subLayerKey = g_sublayerGuid;subLayer.displayData.name = SUBLAYER_NAME;subLayer.displayData.description = SUBLAYER_NAME;subLayer.flags = 0;subLayer.weight = 0x100;status = FwpmSubLayerAdd(g_engineHandle, &subLayer, NULL);if (!NT_SUCCESS(status)){break;}pUdpSubLayer = &subLayer;status = callouts_addUdpFlowEstablishedFilter(&g_calloutGuids[CG_DATAGRAM_DATA_CALLOUT_V4],&FWPM_LAYER_DATAGRAM_DATA_V4,pUdpSubLayer);if (!NT_SUCCESS(status)){break;}status = callouts_addUdpFlowEstablishedFilter(&g_calloutGuids[CG_DATAGRAM_DATA_CALLOUT_V6],&FWPM_LAYER_DATAGRAM_DATA_V6,pUdpSubLayer);if (!NT_SUCCESS(status)){break;}status = FwpmTransactionCommit(g_engineHandle);if (!NT_SUCCESS(status)){break;}break;}if (!NT_SUCCESS(status)){FwpmTransactionAbort(g_engineHandle);}return status;
}NTSTATUS  callouts_init(PDEVICE_OBJECT deviceObject)
{NTSTATUS status = STATUS_SUCCESS;DWORD dwStatus;FWPM_SESSION session = { 0 };int i;if (g_initialized)return STATUS_SUCCESS;ExUuidCreate(&g_providerGuid);ExUuidCreate(&g_sublayerGuid);ExUuidCreate(&g_recvSublayerGuid);ExUuidCreate(&g_recvProtSublayerGuid);for (i = 0; i < CG_MAX; i++){ExUuidCreate(&g_calloutGuids[i]);}session.flags = FWPM_SESSION_FLAG_DYNAMIC;status = FwpmEngineOpen(NULL,RPC_C_AUTHN_WINNT,NULL,&session,&g_engineHandle);if (!NT_SUCCESS(status)){KdPrint((DPREFIX"FwpmEngineOpen failed, status=%x\n", status));return status;}for (;;){FWPM_PROVIDER provider;RtlZeroMemory(&provider, sizeof(provider));provider.displayData.description = PROVIDER_NAME;provider.displayData.name = PROVIDER_NAME;provider.providerKey = g_providerGuid;dwStatus = FwpmProviderAdd(g_engineHandle, &provider, NULL);if (dwStatus != 0){KdPrint((DPREFIX"FwpmProviderAdd failed, status=%x\n", dwStatus));status = STATUS_UNSUCCESSFUL;break;}status = callouts_registerCallouts(deviceObject);if (!NT_SUCCESS(status)){KdPrint((DPREFIX"callouts_registerCallouts failed, status=%x\n", status));break;}status = callouts_addFilters();if (!NT_SUCCESS(status)){KdPrint((DPREFIX"callouts_addFilters failed, status=%x\n", status));break;}break;}g_initialized = TRUE;if (!NT_SUCCESS(status)){callouts_free();}return status;
}
void callouts_free()
{KdPrint((DPREFIX"callouts_free\n"));if (!g_initialized)return;g_initialized = FALSE;callouts_unregisterCallouts();FwpmSubLayerDeleteByKey(g_engineHandle, &g_sublayerGuid);FwpmSubLayerDeleteByKey(g_engineHandle, &g_recvSublayerGuid);FwpmSubLayerDeleteByKey(g_engineHandle, &g_recvProtSublayerGuid);FwpmSubLayerDeleteByKey(g_engineHandle, &g_ipSublayerGuid);FwpmProviderContextDeleteByKey(g_engineHandle, &g_providerGuid);if (g_engineHandle){FwpmEngineClose(g_engineHandle);g_engineHandle = NULL;}
}

http://www.dtcms.com/a/320246.html

相关文章:

  • 深入理解C++模板进阶:非类型参数、特化与分离编译
  • Linux节点创建API与路径对应关系
  • AI日报0807 | GPT-5或今晚1点来袭:四大版本全曝光
  • 什么是 TDengine IDMP?
  • Disruptor 消费者核心:BatchEventProcessor解析
  • 告别复杂配置!cpolar让Prometheus监控突破网络限制
  • 【42】【OpenCV C++】 计算图像某一列像素方差 或 某一行像素的方差;
  • 嵌入式开发硬件——单片机
  • 【列出指定时间段内所有的下单产品】
  • 数据结构(循环顺序队列)
  • RAGAS:检索增强生成系统的无参考评估框架与技术解析
  • 2025年华数杯C题超详细解题思路
  • 哈希表原理与实现全解析
  • 天道20金句
  • Moses工具的配置和小语种平行语料训练SMT完整实现
  • 大模型 Transformer模型(上)
  • Java集合的遍历方式(全解析)
  • 力扣经典算法篇-46-阶乘后的零(正向步长遍历,逆向步长遍历)
  • BGP笔记整理
  • Maven高级:继承与聚合实战指南
  • RS485转Profibus网关在QDNA钠离子分析仪与300PLC通信中的应用解析
  • 【OCCT+ImGUI系列】013-碰撞检测-包围盒Bnd_Box
  • 【入门级-C++程序设计:9、函数与递归-函数定义与调用、形参与实参】
  • RESTful 服务概述:从理念到实践的全面解析
  • Coze开放平台综合文档指南
  • 达梦包含OR条件的SQL特定优化----INJECT-HINT优化方法
  • 最新完整内、外期货量化交易系统C#源码可售
  • 【C#补全计划:类和对象(九)】接口
  • redis--黑马点评--用户签到模块详解
  • dubbo源码之编解码逻辑