本文主要是介绍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 内容的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!