C/C++ 提取DNS请求/响应数据包之中的 Quesion 内容

2024-06-20 08:36

本文主要是介绍C/C++ 提取DNS请求/响应数据包之中的 Quesion 内容,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

它主要是提取DNS数据包之中查询问题的信息,如:问题类型、问题类别、问题内容(域/IP),我们如果想要对于某个DNS数据包需要进行遥测的时,或者进行NS缓存生命周期管理,那么就需要类似这样的函数实现了。

例子:

                uint16_t queries_type = 0;uint16_t queries_clazz = 0;ppp::string domain = ppp::net::native::dns::ExtractHostY((Byte*)packet, packet_length,[&queries_type, &queries_clazz](ppp::net::native::dns::dns_hdr* h, ppp::string& domain, uint16_t type, uint16_t clazz) noexcept -> bool {queries_type = type;queries_clazz = clazz;return true;});

源声明:

#pragma pack(push, 1)struct dns_hdr {uint16_t                                                                usTransID;         // 标识符uint16_t                                                                usFlags;           // 各种标志位uint16_t                                                                usQuestionCount;   // Question字段个数 uint16_t                                                                usAnswerCount;     // Answer字段个数uint16_t                                                                usAuthorityCount;  // Authority字段个数uint16_t                                                                usAdditionalCount; // Additional字段个数};
#pragma pack(pop)static constexpr int MAX_DOMAINNAME_LEN                                     = 255; /* MAX: 253 +. ≈ 254 BYTE or 254 CHAR+. ≈ 255 BYTE */static constexpr int DNS_PORT                                               = PPP_DNS_SYS_PORT;static constexpr int DNS_TYPE_SIZE                                          = 2;static constexpr int DNS_CLASS_SIZE                                         = 2;static constexpr int DNS_TTL_SIZE                                           = 4;static constexpr int DNS_DATALEN_SIZE                                       = 2;static constexpr int DNS_TYPE_A                                             = 0x0001; //1 a host addressstatic constexpr int DNS_TYPE_AAAA                                          = 0x001c; //1 a host addressstatic constexpr int DNS_TYPE_CNAME                                         = 0x0005; //5 the canonical name for an aliasstatic constexpr int DNS_CLASS_IN                                           = 0x0001;static constexpr int DNS_PACKET_MAX_SIZE                                    = (sizeof(struct dns_hdr) + MAX_DOMAINNAME_LEN + DNS_TYPE_SIZE + DNS_CLASS_SIZE);ppp::string                                                                 ExtractHost(const Byte*                                                             szPacketStartPos, int                                                                     nPacketLength) noexcept;ppp::string                                                                 ExtractHostX(const Byte*                                                             szPacketStartPos, int                                                                     nPacketLength, const ppp::function<bool(dns_hdr*)>&                                    fPredicateB) noexcept;ppp::string                                                                 ExtractHostY(const Byte*                                                             szPacketStartPos, int                                                                     nPacketLength, const ppp::function<bool(dns_hdr*, ppp::string&, uint16_t, uint16_t)>&  fPredicateE) noexcept;ppp::string                                                                 ExtractHostZ(const Byte*                                                             szPacketStartPos, int                                                                     nPacketLength, const ppp::function<bool(dns_hdr*)>&                                    fPredicateB, const ppp::function<bool(dns_hdr*, ppp::string&, uint16_t, uint16_t)>&  fPredicateE) noexcept;

源实现:

                static bool ExtractName(char* szEncodedStr, uint16_t* pusEncodedStrLen, char* szDotStr, uint16_t nDotStrSize, char* szPacketStartPos, char* szPacketEndPos, char** ppDecodePos) noexcept{if (NULL == szEncodedStr || NULL == pusEncodedStrLen || NULL == szDotStr || szEncodedStr >= szPacketEndPos){return false;}char*& pDecodePos = *ppDecodePos;pDecodePos = szEncodedStr;uint16_t usPlainStrLen = 0;uint8_t nLabelDataLen = 0;*pusEncodedStrLen = 0;while ((nLabelDataLen = *pDecodePos) != 0x00){// Normal Format,LabelDataLen + Labelif ((nLabelDataLen & 0xc0) == 0) {if ((usPlainStrLen + nLabelDataLen + 1) > nDotStrSize || (pDecodePos + nLabelDataLen + 1) >= szPacketEndPos){return false;}memcpy(szDotStr + usPlainStrLen, pDecodePos + 1, nLabelDataLen);memcpy(szDotStr + usPlainStrLen + nLabelDataLen, ".", 1);pDecodePos += (nLabelDataLen + 1);usPlainStrLen += (nLabelDataLen + 1);*pusEncodedStrLen += (nLabelDataLen + 1);}else  {// Message compression format is 11000000 00000000, consisting of two bytes. // The first two bits are the jump flag, and the last 14 bits are the offset of the jump。if (NULL == szPacketStartPos){return false;}uint16_t usJumpPos = ntohs(*(uint16_t*)(pDecodePos)) & 0x3fff;uint16_t nEncodeStrLen = 0;if (!ExtractName(szPacketStartPos + usJumpPos, &nEncodeStrLen, szDotStr + usPlainStrLen, nDotStrSize - usPlainStrLen, szPacketStartPos, szPacketEndPos, ppDecodePos)){return false;}else{*pusEncodedStrLen += 2;return true;}}}++pDecodePos;szDotStr[usPlainStrLen - 1] = '\0';*pusEncodedStrLen += 1;return true;}static bool ExtractHost_DefaultPredicateB(dns_hdr* h) noexcept{uint16_t usFlags = htons(h->usFlags) & htons(DNS_TYPE_A);return usFlags != 0;}ppp::string ExtractHost(const Byte* szPacketStartPos, int nPacketLength) noexcept{ppp::function<bool(dns_hdr*)> predicate = ExtractHost_DefaultPredicateB;return ExtractHostX(szPacketStartPos, nPacketLength, predicate);}ppp::string ExtractHostX(const Byte* szPacketStartPos, int nPacketLength, const ppp::function<bool(dns_hdr*)>& fPredicateB) noexcept{ppp::function<bool(dns_hdr*, ppp::string&, uint16_t, uint16_t)> fPredicateE =[](dns_hdr* h, ppp::string& domain, uint16_t type, uint16_t clazz) noexcept -> bool{return true;};return ExtractHostZ(szPacketStartPos, nPacketLength, fPredicateB, fPredicateE);}ppp::string ExtractHostY(const Byte* szPacketStartPos, int nPacketLength, const ppp::function<bool(dns_hdr*, ppp::string&, uint16_t, uint16_t)>& fPredicateE) noexcept{ppp::function<bool(dns_hdr*)> fPredicateB = ExtractHost_DefaultPredicateB;return ExtractHostZ(szPacketStartPos, nPacketLength, fPredicateB, fPredicateE);}ppp::string ExtractHostZ(const Byte*                                        szPacketStartPos, int                                                                     nPacketLength, const ppp::function<bool(dns_hdr*)>&                                    fPredicateB, const ppp::function<bool(dns_hdr*, ppp::string&, uint16_t, uint16_t)>&  fPredicateE) noexcept{static constexpr int MAX_DOMAINNAME_LEN_STR = MAX_DOMAINNAME_LEN + 1;if (NULL == fPredicateB || NULL == fPredicateE){return ppp::string();}struct dns_hdr* pDNSHeader = (struct dns_hdr*)szPacketStartPos;if (NULL == pDNSHeader || nPacketLength < sizeof(pDNSHeader)){return ppp::string();}if (!fPredicateB(pDNSHeader)){return ppp::string();}int nQuestionCount = htons(pDNSHeader->usQuestionCount);if (nQuestionCount < 1){return ppp::string();}std::shared_ptr<Byte> pioBuffers = make_shared_alloc<Byte>(MAX_DOMAINNAME_LEN_STR);if (NULL == pioBuffers) {return ppp::string();}uint16_t pusEncodedStrLen = 0;char* pDecodePos = NULL;char* szDomainDotStr = (char*)pioBuffers.get();if (!ExtractName((char*)(pDNSHeader + 1), &pusEncodedStrLen, szDomainDotStr,(uint16_t)MAX_DOMAINNAME_LEN_STR, (char*)szPacketStartPos, (char*)szPacketStartPos + nPacketLength, &pDecodePos)){return ppp::string();}while (pusEncodedStrLen > 0 && szDomainDotStr[pusEncodedStrLen - 1] == '\x0'){pusEncodedStrLen--;}if (pusEncodedStrLen == 0){return ppp::string();}uint16_t* pusDecodePos = (uint16_t*)pDecodePos;uint16_t usQueriesType = ntohs(pusDecodePos[0]);uint16_t usQueriesClass = ntohs(pusDecodePos[1]);ppp::string strDomianStr(szDomainDotStr, pusEncodedStrLen);if (!fPredicateE(pDNSHeader, strDomianStr, usQueriesType, usQueriesClass)){return ppp::string();}return strDomianStr.data();}

这篇关于C/C++ 提取DNS请求/响应数据包之中的 Quesion 内容的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1077634

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u

C++11中的包装器实战案例

《C++11中的包装器实战案例》本文给大家介绍C++11中的包装器实战案例,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录引言1.std::function1.1.什么是std::function1.2.核心用法1.2.1.包装普通函数1.2.

C++多线程开发环境配置方法

《C++多线程开发环境配置方法》文章详细介绍了如何在Windows上安装MinGW-w64和VSCode,并配置环境变量和编译任务,使用VSCode创建一个C++多线程测试项目,并通过配置tasks.... 目录下载安装 MinGW-w64下载安装VS code创建测试项目配置编译任务创建 tasks.js

C++ 多态性实战之何时使用 virtual 和 override的问题解析

《C++多态性实战之何时使用virtual和override的问题解析》在面向对象编程中,多态是一个核心概念,很多开发者在遇到override编译错误时,不清楚是否需要将基类函数声明为virt... 目录C++ 多态性实战:何时使用 virtual 和 override?引言问题场景判断是否需要多态的三个关

Java轻松实现在Excel中插入、提取或删除文本框

《Java轻松实现在Excel中插入、提取或删除文本框》在日常的Java开发中,我们经常需要与Excel文件打交道,当涉及到Excel中的文本框时,许多开发者可能会感到棘手,下面我们就来看看如何使用J... 目录Java操作Excel文本框的实战指南1. 插入Excel文本框2. 提取Excel文本框内容3