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 address
                static constexpr int DNS_TYPE_AAAA                                          = 0x001c; //1 a host address
                static constexpr int DNS_TYPE_CNAME                                         = 0x0005; //5 the canonical name for an alias
                static 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 + Label
                        if ((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();
                }

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值