LCOV - code coverage report
Current view: top level - dns/bind - bind_util.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 459 655 70.1 %
Date: 2026-06-11 01:56:02 Functions: 38 47 80.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <boost/algorithm/string/join.hpp>
       6             : #include <boost/assign/list_of.hpp>
       7             : #include <boost/regex.hpp>
       8             : #include <bind/bind_util.h>
       9             : 
      10             : using namespace boost::assign;
      11             : SandeshTraceBufferPtr DnsBindTraceBuf(SandeshTraceBufferCreate("DnsBind", 2000));
      12             : 
      13             : DnsTypeMap g_dns_type_map = map_list_of<std::string, uint16_t>
      14             :                                 ("A", 1)
      15             :                                 ("NS", 2)
      16             :                                 ("CNAME", 5)
      17             :                                 ("SOA", 6)
      18             :                                 ("PTR", 0x0C)
      19             :                                 ("MX", 0x0F)
      20             :                                 ("TXT", 0x10)
      21             :                                 ("AAAA", 0x1C)
      22             :                                 ("SRV", 0x21)
      23             :                                 ("ANY", 0xFF);
      24             : 
      25             : DnsTypeNumMap g_dns_type_num_map = map_list_of<uint16_t, std::string>
      26             :                                 (DNS_A_RECORD, "A")
      27             :                                 (DNS_NS_RECORD, "NS")
      28             :                                 (DNS_CNAME_RECORD, "CNAME")
      29             :                                 (DNS_TYPE_SOA, "SOA")
      30             :                                 (DNS_PTR_RECORD, "PTR")
      31             :                                 (DNS_MX_RECORD, "MX")
      32             :                                 (DNS_TXT_RECORD, "TXT")
      33             :                                 (DNS_AAAA_RECORD, "AAAA")
      34             :                                 (DNS_SRV_RECORD, "SRV")
      35             :                                 (DNS_TYPE_ANY, "ANY");
      36             : 
      37             : DnsTypeNumMap g_dns_class_num_map = map_list_of<uint16_t, std::string>
      38             :                                 (DNS_CLASS_IN, "IN")
      39             :                                 (DNS_CLASS_NONE, "None")
      40             :                                 (DNS_CLASS_ANY, "Any");
      41             : 
      42             : DnsResponseMap g_dns_response_map = map_list_of<uint16_t, std::string>
      43             :                                 (0, "No error")
      44             :                                 (1, "Format error")
      45             :                                 (2, "Server failure")
      46             :                                 (3, "Non-existent domain")
      47             :                                 (4, "Not implemented")
      48             :                                 (5, "Query refused")
      49             :                                 (6, "Name exists when it should not")
      50             :                                 (7, "RR Set Exists when it should not")
      51             :                                 (8, "RR Set that should exist does not")
      52             :                                 (9, "Not Authorized")
      53             :                                 (10, "Name not contained in zone")
      54             :                                 (16, "Bad OPT Version")
      55             :                                 (17, "Key not recognized")
      56             :                                 (18, "Signature out of time window")
      57             :                                 (19, "Bad TKEY Mode")
      58             :                                 (20, "Duplicate key name")
      59             :                                 (21, "Algorithm not supported")
      60             :                                 (22, "Bad truncation")
      61             :                                 (4095, "Invalid response code");
      62             : 
      63           0 : std::string DnsItem::ToString() const {
      64           0 :     return BindUtil::DnsClass(eclass) + "/" +
      65           0 :            BindUtil::DnsType(type) + "/" + name + "/" + data + ";";
      66             : }
      67             : 
      68          64 : bool Subnet::operator< (const Subnet &rhs) const {
      69          64 :     if (prefix.is_v4()) {
      70          62 :         if (rhs.prefix.is_v4()) {
      71          62 :             Ip4Address me = prefix.to_v4(),
      72          62 :                        they = rhs.prefix.to_v4();
      73          62 :             if (me != they) {
      74          26 :                 return me < they;
      75             :             }
      76          36 :             return plen < rhs.plen;
      77             :         } else {
      78             :             // IPv4 goes before IPv6 and garbage
      79           0 :             return true;
      80             :         }
      81           2 :     } else if (prefix.is_v6()) {
      82           2 :         if (rhs.prefix.is_v6()) {
      83           0 :             Ip6Address me = prefix.to_v6(),
      84           0 :                        they = rhs.prefix.to_v6();
      85           0 :             if (me != they)
      86           0 :                 return me < they;
      87           0 :             return plen < rhs.plen;
      88             :         } else {
      89             :             // IPv4 goes before IPv6, IPv6 goes before garbage
      90           2 :             return !rhs.prefix.is_v4();
      91             :         }
      92             :     } else {
      93             :         // Garbage always sorts towards the end
      94           0 :         return false;
      95             :     }
      96             : }
      97             : 
      98          12 : bool Subnet::Contains(const IpAddress &addr) const {
      99          12 :     if (prefix.is_v4() && addr.is_v4()) {
     100           4 :         return IsIp4SubnetMember(addr.to_v4(), prefix.to_v4(), plen);
     101           8 :     } else if (prefix.is_v6() && addr.is_v6()) {
     102           4 :         return IsIp6SubnetMember(addr.to_v6(), prefix.to_v6(), plen);
     103             :     } else {
     104           4 :         return false;
     105             :     }
     106             : }
     107             : 
     108         354 : void Subnet::GetReverseZones(ZoneList &zones) const {
     109         354 :     BindUtil::GetReverseZoneList(prefix, plen, zones);
     110         354 : }
     111             : 
     112          41 : uint16_t BindUtil::DnsClass(const std::string &cl) {
     113          41 :     if (cl == "IN")
     114          41 :         return DNS_CLASS_IN;
     115           0 :     return DNS_CLASS_ANY;
     116             : }
     117             : 
     118           1 : std::string BindUtil::DnsClass(uint16_t cl) {
     119           1 :     DnsTypeNumIter iter = g_dns_class_num_map.find(cl);
     120           1 :     if (iter == g_dns_class_num_map.end())
     121           1 :         return integerToString(cl);
     122           0 :     return iter->second;
     123             : }
     124             : 
     125          41 : uint16_t BindUtil::DnsType(const std::string &tp) {
     126          41 :     DnsTypeIter iter = g_dns_type_map.find(tp);
     127          41 :     if (iter == g_dns_type_map.end())
     128           0 :         return -1;
     129          41 :     return iter->second;
     130             : }
     131             : 
     132          48 : std::string BindUtil::DnsType(uint16_t tp) {
     133          48 :     DnsTypeNumIter iter = g_dns_type_num_map.find(tp);
     134          48 :     if (iter == g_dns_type_num_map.end())
     135           0 :         return integerToString(tp);
     136          48 :     return iter->second;
     137             : }
     138             : 
     139           0 : const std::string &BindUtil::DnsResponseCode(uint16_t code) {
     140           0 :     DnsResponseIter iter = g_dns_response_map.find(code);
     141           0 :     if (iter == g_dns_response_map.end())
     142           0 :         return DnsResponseCode(4095);
     143           0 :     return iter->second;
     144             : }
     145             : 
     146          38 : uint8_t *BindUtil::AddName(uint8_t *ptr, const std::string &addr,
     147             :                            uint16_t plen, uint16_t offset, uint16_t &length) {
     148          38 :     std::size_t size = addr.size();
     149          38 :     std::size_t cur_pos = 0;
     150          38 :     std::size_t prev_pos = 0;
     151         151 :     while (cur_pos < size && cur_pos != std::string::npos) {
     152         113 :         if (offset && !plen) {
     153           0 :             ptr = WriteShort(ptr, offset);
     154           0 :             length += 2;
     155           0 :             return ptr;
     156             :         }
     157             :         std::size_t len;
     158         113 :         cur_pos = addr.find('.', prev_pos);
     159         113 :         if (cur_pos == std::string::npos)
     160          37 :             len = size - prev_pos;
     161             :         else
     162          76 :             len = cur_pos - prev_pos;
     163             : 
     164         113 :         *ptr = len;
     165         113 :         memcpy(ptr + 1, addr.substr(prev_pos, len).data(), len);
     166         113 :         ptr += len + 1;
     167         113 :         plen = (plen > len) ? plen - len - 1 : 0;
     168             : 
     169         113 :         prev_pos = cur_pos + 1;
     170         113 :         length += len + 1;
     171             :     }
     172          38 :     ptr = WriteByte(ptr, 0);
     173          38 :     length++;
     174             : 
     175          38 :     return ptr;
     176             : }
     177             : 
     178          20 : uint8_t *BindUtil::AddQuestionSection(uint8_t *ptr, const std::string &name,
     179             :                                       uint16_t type, uint16_t cl,
     180             :                                       uint16_t &length) {
     181          20 :     ptr = AddName(ptr, name, 0, 0, length);
     182          20 :     ptr = WriteShort(ptr, type);
     183          20 :     ptr = WriteShort(ptr, cl);
     184          20 :     length += 4;
     185             : 
     186          20 :     return ptr;
     187             : }
     188             : 
     189          16 : uint8_t *BindUtil::AddData(uint8_t *ptr, const DnsItem &item,
     190             :                            uint16_t &length) {
     191          16 :     boost::system::error_code ec;
     192             : 
     193          16 :     if (item.type == DNS_A_RECORD) {
     194          10 :         ptr = WriteShort(ptr, 4);
     195          10 :         ptr = WriteWord(ptr, boost::asio::ip::address_v4::from_string(
     196          10 :                              item.data, ec).to_ulong());
     197          10 :         length += 2 + 4;
     198           6 :     } else if (item.type == DNS_AAAA_RECORD) {
     199           0 :         ptr = WriteShort(ptr, 16);
     200             :         boost::asio::ip::address_v6 addr =
     201           0 :                 boost::asio::ip::address_v6::from_string(item.data, ec);
     202           0 :         if (ec.value()) {
     203           0 :             memset(ptr, 0, 16);
     204             :         } else {
     205           0 :             memcpy(ptr, addr.to_bytes().data(), 16);
     206             :         }
     207           0 :         ptr += 16;
     208           0 :         length += 2 + 16;
     209           6 :     } else if(item.type == DNS_TYPE_SOA) {
     210           1 :         uint16_t data_len = DataLength(item.soa.ns_plen, item.soa.ns_offset,
     211           1 :                                        item.soa.primary_ns.size()) +
     212           1 :                             DataLength(item.soa.mailbox_plen,
     213           1 :                                        item.soa.mailbox_offset,
     214           1 :                                        item.soa.mailbox.size()) + 20;
     215           1 :         ptr = WriteShort(ptr, data_len);
     216           2 :         ptr = AddName(ptr, item.soa.primary_ns, item.soa.ns_plen,
     217           1 :                       item.soa.ns_offset, length);
     218           2 :         ptr = AddName(ptr, item.soa.mailbox, item.soa.mailbox_plen,
     219           1 :                       item.soa.mailbox_offset, length);
     220           1 :         ptr = WriteWord(ptr, item.soa.serial);
     221           1 :         ptr = WriteWord(ptr, item.soa.refresh);
     222           1 :         ptr = WriteWord(ptr, item.soa.retry);
     223           1 :         ptr = WriteWord(ptr, item.soa.expiry);
     224           1 :         ptr = WriteWord(ptr, item.soa.ttl);
     225           1 :         length += 2 + 20;
     226           5 :     } else if(item.type == DNS_PTR_RECORD ||
     227           5 :               item.type == DNS_CNAME_RECORD ||
     228           5 :               item.type == DNS_NS_RECORD) {
     229           3 :         uint16_t data_len = DataLength(item.data_plen, item.data_offset,
     230           3 :                                        item.data.size());
     231           3 :         ptr = WriteShort(ptr, data_len);
     232           3 :         ptr = AddName(ptr, item.data, item.data_plen, item.data_offset, length);
     233           3 :         length += 2;
     234           5 :     } else if (item.type == DNS_MX_RECORD) {
     235           0 :         uint16_t data_len = 2 + DataLength(item.data_plen, item.data_offset,
     236           0 :                                            item.data.size());
     237           0 :         ptr = WriteShort(ptr, data_len);
     238             :         // An MX record has 16 bit preference followed by host name
     239           0 :         ptr = WriteShort(ptr, item.priority);
     240           0 :         ptr = AddName(ptr, item.data, item.data_plen, item.data_offset, length);
     241           0 :         length += 2 + 2;
     242           2 :     } else if (item.type == DNS_SRV_RECORD) {
     243           1 :         uint16_t data_len = 6 + DataLength(item.srv.hn_plen, item.srv.hn_offset,
     244           1 :                                            item.srv.hostname.size());
     245           1 :         ptr = WriteShort(ptr, data_len);
     246           1 :         ptr = WriteShort(ptr, item.srv.priority);
     247           1 :         ptr = WriteShort(ptr, item.srv.weight);
     248           1 :         ptr = WriteShort(ptr, item.srv.port);
     249           2 :         ptr = AddName(ptr, item.srv.hostname, item.srv.hn_plen,
     250           1 :                       item.srv.hn_offset, length);
     251           1 :         length += 2 + 6;
     252             :     } else {
     253             :         // TXT and other record types are handled here.
     254             :         // TODO: In case a record type has domain name and name is compressed
     255             :         // in the message that is being read, it may lead to problem if the
     256             :         // offset in the message we send doesnt match with the offset in the
     257             :         // message that is received. Each such message has to be handled
     258             :         // as a different case here.
     259           1 :         uint16_t size = item.data.size();
     260           1 :         ptr = WriteShort(ptr, size);
     261           1 :         if (size) {
     262           1 :             memcpy(ptr, item.data.c_str(), size);
     263           1 :             ptr += size;
     264             :         }
     265           1 :         length += 2 + size;
     266             :     }
     267             : 
     268          16 :     return ptr;
     269             : }
     270             : 
     271          12 : uint8_t *BindUtil::AddAnswerSection(uint8_t *ptr, const DnsItem &item,
     272             :                                     uint16_t &length) {
     273          12 :     ptr = AddName(ptr, item.name, item.name_plen, item.name_offset, length);
     274          12 :     ptr = WriteShort(ptr, item.type);
     275          12 :     ptr = WriteShort(ptr, item.eclass);
     276          12 :     ptr = WriteWord(ptr, item.ttl);
     277          12 :     length += 2 + 2 + 4;
     278          12 :     ptr = AddData(ptr, item, length);
     279             : 
     280          12 :     return ptr;
     281             : }
     282             : 
     283           0 : uint8_t *BindUtil::AddAdditionalSection(uint8_t *ptr, const std::string name,
     284             :                                         uint16_t type, uint16_t cl,
     285             :                                         uint32_t ttl, const std::string &data,
     286             :                                         uint16_t &length) {
     287           0 :     ptr = AddQuestionSection(ptr, name, type, cl, length);
     288           0 :     ptr = WriteWord(ptr, ttl);
     289           0 :     ptr = WriteShort(ptr, data.size() + 1);
     290             : 
     291             :     // adding the domain name as it is, without replacing '.' with length
     292           0 :     ptr = WriteByte(ptr, data.size());
     293           0 :     memcpy(ptr, data.data(), data.size());
     294           0 :     ptr += data.size();
     295           0 :     length += 4 + 2 + 1 + data.size();
     296             : 
     297           0 :     return ptr;
     298             : }
     299             : 
     300           4 : uint8_t *BindUtil::AddUpdate(uint8_t *ptr, const DnsItem &item,
     301             :                              uint16_t cl, uint32_t ttl, uint16_t &length) {
     302           4 :     ptr = AddQuestionSection(ptr, item.name, item.type, cl, length);
     303           4 :     ptr = WriteWord(ptr, ttl);
     304           4 :     length += 4;
     305           4 :     ptr = AddData(ptr, item, length);
     306             : 
     307           4 :     return ptr;
     308             : }
     309             : 
     310          41 : bool BindUtil::ReadName(uint8_t *dns, uint16_t dnslen, int *remlen,
     311             :                         std::string &name, uint16_t &plen, uint16_t &offset) {
     312          41 :     if (*remlen <= 0) {
     313           3 :         return false;
     314             :     }
     315             : 
     316          38 :     uint8_t *ptr = dns + (dnslen - *remlen);
     317          38 :     std::size_t len = *ptr;
     318         151 :     while (len) {
     319         113 :         if ((len & 0xC0) == 0xC0) {
     320           0 :             plen = name.size() ? name.size() - 1 : 0;
     321           0 :             if (ReadShort(dns, dnslen, remlen, offset) == false)
     322           0 :                 return false;
     323           0 :             int offset_remlen = dnslen - (offset & ~0xC000);
     324             :             uint16_t dummy;
     325           0 :             return ReadName(dns, dnslen, &offset_remlen, name, dummy, dummy);
     326             :         } else {
     327         113 :             *remlen -= (len + 1);
     328         113 :             if (*remlen < 0) {
     329           0 :                 return false;
     330             :             }
     331         113 :             name.append((char *)ptr+1, len);
     332         113 :             ptr += len + 1;
     333         113 :             len = *ptr;
     334         113 :             if (len)
     335          76 :                 name.append(".");
     336             :         }
     337             :     }
     338             : 
     339          38 :     *remlen -= 1;
     340          38 :     return true;
     341             : }
     342             : 
     343          16 : bool BindUtil::ReadData(uint8_t *dns, uint16_t dnslen, int *remlen,
     344             :                         DnsItem &item) {
     345             :     uint16_t length;
     346          16 :     if (ReadShort(dns, dnslen, remlen, length) == false)
     347           0 :         return false;
     348             : 
     349          16 :     boost::system::error_code ec;
     350          16 :     if (item.type == DNS_A_RECORD) {
     351             :         uint32_t ip;
     352          10 :         if (ReadWord(dns, dnslen, remlen, ip) == false)
     353           0 :             return false;
     354          10 :         boost::asio::ip::address_v4 addr(ip);
     355          10 :         item.data = addr.to_string(ec);
     356          10 :         return true;
     357           6 :     } else if(item.type == DNS_AAAA_RECORD) {
     358           0 :         if (*remlen < 16) {
     359           0 :             return false;
     360             :         }
     361           0 :         uint8_t *ptr = dns + (dnslen - *remlen);
     362             :         boost::asio::ip::address_v6::bytes_type ip;
     363           0 :         memcpy(&ip[0], ptr, 16);
     364           0 :         boost::asio::ip::address_v6 addr(ip);
     365           0 :         item.data = addr.to_string(ec);
     366           0 :         *remlen -= 16;
     367           0 :         return true;
     368           6 :     } else if(item.type == DNS_TYPE_SOA) {
     369           2 :         if (ReadName(dns, dnslen, remlen, item.soa.primary_ns,
     370           1 :                      item.soa.ns_plen, item.soa.ns_offset) == false)
     371           0 :             return false;
     372           2 :         if (ReadName(dns, dnslen, remlen, item.soa.mailbox,
     373           1 :                      item.soa.mailbox_plen, item.soa.mailbox_offset) == false)
     374           0 :             return false;
     375           1 :         if (ReadWord(dns, dnslen, remlen, item.soa.serial) == false)
     376           0 :             return false;
     377           1 :         if (ReadWord(dns, dnslen, remlen, item.soa.refresh) == false)
     378           0 :             return false;
     379           1 :         if (ReadWord(dns, dnslen, remlen, item.soa.retry) == false)
     380           0 :             return false;
     381           1 :         if (ReadWord(dns, dnslen, remlen, item.soa.expiry) == false)
     382           0 :             return false;
     383           1 :         return ReadWord(dns, dnslen, remlen, item.soa.ttl);
     384           5 :     } else if(item.type == DNS_PTR_RECORD ||
     385           5 :               item.type == DNS_CNAME_RECORD ||
     386           5 :               item.type == DNS_NS_RECORD) {
     387           3 :         return ReadName(dns, dnslen, remlen, item.data, item.data_plen, item.data_offset);
     388           2 :     } else if(item.type == DNS_MX_RECORD) {
     389           0 :         if (ReadShort(dns, dnslen, remlen, item.priority) == false)
     390           0 :             return false;
     391           0 :         return ReadName(dns, dnslen, remlen, item.data, item.data_plen, item.data_offset);
     392           2 :     } else if (item.type == DNS_SRV_RECORD) {
     393           1 :         if (ReadShort(dns, dnslen, remlen, item.srv.priority) == false)
     394           0 :             return false;
     395           1 :         if (ReadShort(dns, dnslen, remlen, item.srv.weight) == false)
     396           0 :             return false;
     397           1 :         if (ReadShort(dns, dnslen, remlen, item.srv.port) == false)
     398           0 :             return false;
     399           2 :         return ReadName(dns, dnslen, remlen, item.srv.hostname,
     400           1 :                         item.srv.hn_plen, item.srv.hn_offset);
     401             :     } else {
     402             :         // TXT and other record types are handled here.
     403             :         // TODO: In case a record type has domain name and name is compressed
     404             :         // in the message that is being read, it may lead to problem if the
     405             :         // offset in the message we send doesnt match with the offset in the
     406             :         // message that is received. Each such message has to be handled
     407             :         // as a different case here.
     408           1 :         if (*remlen < length) {
     409           0 :             return false;
     410             :         }
     411           1 :         uint8_t *ptr = dns + (dnslen - *remlen);
     412           1 :         item.data.assign((const char *)ptr, length);
     413           1 :         *remlen -= length;
     414           1 :         return true;
     415             :     }
     416             : 
     417             :     DNS_BIND_TRACE(DnsBindError,
     418             :                    "Unsupported data type in DNS response : " << item.type);
     419             :     return false;
     420             : }
     421             : 
     422          28 : bool BindUtil::ReadQuestionEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
     423             :                                  DnsItem &item) {
     424          56 :     if (ReadName(dns, dnslen, remlen, item.name, item.name_plen,
     425          28 :                  item.name_offset) == false)
     426           2 :         return false;
     427             : 
     428          26 :     if (ReadShort(dns, dnslen, remlen, item.type) == false)
     429           0 :         return false;
     430             : 
     431          26 :     return ReadShort(dns, dnslen, remlen, item.eclass);
     432             : }
     433             : 
     434          13 : bool BindUtil::ReadAnswerEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
     435             :                                DnsItem &item) {
     436          13 :     if (ReadQuestionEntry(dns, dnslen, remlen, item) == false)
     437           1 :         return false;
     438             : 
     439          12 :     if (ReadWord(dns, dnslen, remlen, item.ttl) == false)
     440           0 :         return false;
     441             : 
     442          12 :     return ReadData(dns, dnslen, remlen, item);
     443             : }
     444             : 
     445           3 : bool BindUtil::ParseDnsQuery(uint8_t *dns, uint16_t dnslen, uint16_t *parsed_length,
     446             :                              DnsItems &items) {
     447           3 :     uint16_t xid = 0;
     448           3 :     *parsed_length = 0;
     449           3 :     if (dnslen <= sizeof(dnshdr)) {
     450           1 :         DNS_BIND_TRACE(DnsBindError,
     451             :                        "Invalid DNS Query with header missing - dropping it");
     452           1 :         return false;
     453             :     }
     454             : 
     455           2 :     dnshdr *hdr = (dnshdr *) dns;
     456           2 :     xid = ntohs(hdr->xid);
     457           2 :     uint16_t ques_rrcount = ntohs(hdr->ques_rrcount);
     458             : 
     459           2 :     int remlen = dnslen - sizeof(dnshdr);
     460           8 :     for (unsigned int i = 0; i < ques_rrcount; ++i) {
     461           7 :         DnsItem item;
     462           7 :         item.offset = (dnslen - remlen) | 0xC000;
     463           7 :         if (ReadQuestionEntry(dns, dnslen, &remlen, item) == false) {
     464           1 :             DNS_BIND_TRACE(DnsBindError, "DNS Query Parse error in question "
     465             :                            "section - xid : " << xid << " - dropping it");
     466           1 :             return false;
     467             :         }
     468           6 :         items.push_back(item);
     469           7 :     }
     470             : 
     471           1 :     *parsed_length = dnslen - remlen;
     472           1 :     return true;
     473             : 
     474             : }
     475             : 
     476           4 : bool BindUtil::ParseDnsResponse(uint8_t *dns, uint16_t dnslen, uint16_t &xid,
     477             :                                 dns_flags &flags, DnsItems &ques, DnsItems &ans,
     478             :                                 DnsItems &auth, DnsItems &add) {
     479           4 :     if (dnslen < sizeof(dnshdr)) {
     480           0 :         DNS_BIND_TRACE(DnsBindError,
     481             :                        "Invalid DNS Response with header missing - dropping it");
     482           0 :         return false;
     483             :     }
     484             : 
     485           4 :     dnshdr *hdr = (dnshdr *) dns;
     486           4 :     xid = ntohs(hdr->xid);
     487           4 :     flags = hdr->flags;
     488             : 
     489           4 :     uint16_t ques_rrcount = ntohs(hdr->ques_rrcount);
     490           4 :     uint16_t ans_rrcount = ntohs(hdr->ans_rrcount);
     491           4 :     uint16_t auth_rrcount = ntohs(hdr->auth_rrcount);
     492           4 :     uint16_t add_rrcount = ntohs(hdr->add_rrcount);
     493             : 
     494           4 :     int remlen = dnslen - sizeof(dnshdr);
     495           4 :     std::string errmsg;
     496             : 
     497             :     // question section
     498          12 :     for (unsigned int i = 0; i < ques_rrcount; ++i) {
     499           8 :         DnsItem item;
     500           8 :         if (ReadQuestionEntry(dns, dnslen, &remlen, item) == false) {
     501           0 :             errmsg = "Parse error in question section";
     502           0 :             goto error;
     503             :         }
     504           8 :         ques.push_back(item);
     505           8 :     }
     506             : 
     507             :     // answer section
     508          12 :     for (unsigned int i = 0; i < ans_rrcount; ++i) {
     509           9 :         DnsItem item;
     510           9 :         if (ReadAnswerEntry(dns, dnslen, &remlen, item) == false) {
     511           1 :             errmsg = "Parse error in answer section";
     512           1 :             goto error;
     513             :         }
     514           8 :         ans.push_back(item);
     515           9 :     }
     516             : 
     517             :     // authority section
     518           6 :     for (unsigned int i = 0; i < auth_rrcount; ++i) {
     519           3 :         DnsItem item;
     520           3 :         if (ReadAnswerEntry(dns, dnslen, &remlen, item) == false) {
     521           0 :             errmsg = "Parse error in authority section";
     522           0 :             goto error;
     523             :         }
     524           3 :         auth.push_back(item);
     525           3 :     }
     526             : 
     527             :     // additional section
     528           4 :     for (unsigned int i = 0; i < add_rrcount; ++i) {
     529           1 :         DnsItem item;
     530           1 :         if (ReadAnswerEntry(dns, dnslen, &remlen, item) == false) {
     531           0 :             errmsg = "Parse error in additional section";
     532           0 :             goto error;
     533             :         }
     534           1 :         add.push_back(item);
     535           1 :     }
     536             : 
     537           3 :     return true;
     538             : 
     539           1 : error:
     540           1 :     DNS_BIND_TRACE(DnsBindError,
     541             :                    "Invalid DNS response : " << errmsg <<
     542             :                    " xid : " << xid << " - dropping it");
     543           1 :     return false;
     544           4 : }
     545             : 
     546           2 : bool BindUtil::ParseDnsUpdate(uint8_t *dns, uint16_t dnslen,
     547             :                               DnsUpdateData &data) {
     548           2 :     if (dnslen <= sizeof(dnshdr)) {
     549           0 :         DNS_BIND_TRACE(DnsBindError, "Invalid DNS Update with header missing "
     550             :                        "- dropping it");
     551           0 :         return false;
     552             :     }
     553             : 
     554           2 :     dnshdr *hdr = (dnshdr *) dns;
     555           2 :     uint16_t zone_count = ntohs(hdr->ques_rrcount);
     556           2 :     uint16_t prereq_count = ntohs(hdr->ans_rrcount);
     557           2 :     uint16_t update_count = ntohs(hdr->auth_rrcount);
     558           2 :     uint16_t xid = ntohs(hdr->xid);
     559             : 
     560           2 :     if (zone_count != 1) {
     561           0 :         DNS_BIND_TRACE(DnsBindError,
     562             :                        "Invalid zone count in Update request : " << zone_count);
     563           0 :         return false;
     564             :     }
     565             : 
     566           2 :     if (prereq_count != 0) {
     567             :         // Not supporting pre-requisites now
     568           0 :         DNS_BIND_TRACE(DnsBindError, "Update has pre-requisites, " <<
     569             :                        "which is not supported; dropping the request");
     570           0 :         return false;
     571             :     }
     572             : 
     573           2 :     int remlen = dnslen - sizeof(dnshdr);
     574           2 :     std::string errmsg;
     575             : 
     576             :     // Read zone
     577             :     uint16_t zone_type, zone_class, plen, offset;
     578           2 :     if (ReadName(dns, dnslen, &remlen, data.zone, plen, offset) == false ||
     579           4 :         ReadShort(dns, dnslen, &remlen, zone_type) == false ||
     580           2 :         ReadShort(dns, dnslen, &remlen, zone_class) == false) {
     581           0 :         errmsg = "Parse error in reading zone";
     582           0 :         goto error;
     583             :     }
     584             : 
     585             :     // Read Updates
     586           6 :     for (unsigned int i = 0; i < update_count; ++i) {
     587           5 :         DnsItem item;
     588           5 :         if (ReadName(dns, dnslen, &remlen, item.name, plen, offset) == false ||
     589           4 :             ReadShort(dns, dnslen, &remlen, item.type) == false ||
     590           4 :             ReadShort(dns, dnslen, &remlen, item.eclass) == false ||
     591          13 :             ReadWord(dns, dnslen, &remlen, item.ttl) == false ||
     592           4 :             ReadData(dns, dnslen, &remlen, item) == false) {
     593           1 :             errmsg = "Parse error";
     594           1 :             goto error;
     595             :         }
     596           4 :         data.items.push_back(item);
     597           5 :     }
     598             : 
     599           1 :     return true;
     600             : 
     601           1 : error:
     602           1 :     DNS_BIND_TRACE(DnsBindError,
     603             :                    "Invalid DNS Update : " << errmsg <<
     604             :                    " xid : " << xid << " - dropping it");
     605           1 :     return false;
     606           2 : }
     607             : 
     608           9 : void BindUtil::BuildDnsHeader(dnshdr *dns, uint16_t xid, DnsReq req,
     609             :                               DnsOpcode op, bool rd, bool ra, uint8_t ret,
     610             :                               uint16_t ques_count) {
     611           9 :     dns->xid = htons(xid);
     612           9 :     dns->flags.req = req;
     613           9 :     dns->flags.op = op;
     614           9 :     dns->flags.auth = 0;
     615           9 :     dns->flags.trunc = 0;
     616           9 :     dns->flags.rd = rd;
     617           9 :     dns->flags.ra = ra;
     618           9 :     dns->flags.res = 0;
     619           9 :     dns->flags.ad = 0;
     620           9 :     dns->flags.cd = 0;
     621           9 :     dns->flags.ret = ret;
     622           9 :     dns->ques_rrcount = htons(ques_count);
     623           9 :     dns->ans_rrcount = 0;
     624           9 :     dns->auth_rrcount = 0;
     625           9 :     dns->add_rrcount = 0;
     626           9 : }
     627             : 
     628           0 : int BindUtil::BuildDnsQuery(uint8_t *buf, uint16_t xid,
     629             :                             const std::string &domain,
     630             :                             const DnsItems &items) {
     631           0 :     dnshdr *dns = (dnshdr *) buf;
     632           0 :     BuildDnsHeader(dns, xid, DNS_QUERY_REQUEST, DNS_OPCODE_QUERY,
     633           0 :                    1, 0, 0, items.size());
     634             : 
     635             :     // TODO : can be optimised to reuse any names using offsets
     636           0 :     uint16_t len = sizeof(dnshdr);
     637           0 :     uint8_t *ques = (uint8_t *) (dns + 1);
     638           0 :     for (DnsItems::const_iterator it = items.begin(); it != items.end(); ++it) {
     639           0 :         ques = AddQuestionSection(ques, (*it).name, (*it).type,
     640           0 :                                   (*it).eclass, len);
     641             :     }
     642             : 
     643           0 :     if (!domain.empty()) {
     644           0 :         dns->add_rrcount = htons(1);
     645           0 :         std::string view = "view=" + domain;
     646           0 :         ques = AddAdditionalSection(ques, "view", DNS_TXT_RECORD, DNS_CLASS_IN,
     647             :                                     0, view, len);
     648           0 :     }
     649             : 
     650           0 :     return len;
     651             : }
     652             : 
     653           0 : int BindUtil::BuildDnsUpdate(uint8_t *buf, Operation op, uint16_t xid,
     654             :                              const std::string &domain,
     655             :                              const std::string &zone,
     656             :                              const DnsItems &items) {
     657           0 :     dnshdr *dns = (dnshdr *) buf;
     658           0 :     BuildDnsHeader(dns, xid, DNS_QUERY_REQUEST, DNS_OPCODE_UPDATE, 0, 0, 0, 1);
     659             :     // dns->ques_rrcount = htons(1);          // Number of zones
     660             :     // dns->ans_rrcount = 0;                  // Number of Prerequisites
     661           0 :     dns->auth_rrcount = htons(items.size());  // Number of Updates
     662           0 :     dns->add_rrcount = htons(1);              // Number of Additional RRs
     663             : 
     664             :     // Add zone
     665           0 :     uint16_t len = sizeof(dnshdr);
     666           0 :     uint8_t *ptr = (uint8_t *) (dns + 1);
     667           0 :     ptr = AddQuestionSection(ptr, zone, DNS_TYPE_SOA, DNS_CLASS_IN, len);
     668             : 
     669             :     // Add Updates
     670           0 :     switch (op) {
     671           0 :         case ADD_UPDATE:
     672             :         case CHANGE_UPDATE:
     673           0 :             for (DnsItems::const_iterator it = items.begin();
     674           0 :                  it != items.end(); ++it) {
     675           0 :                 ptr = AddUpdate(ptr, *it, (*it).eclass, (*it).ttl, len);
     676             :             }
     677           0 :             break;
     678             : 
     679           0 :         case DELETE_UPDATE:
     680           0 :             for (DnsItems::const_iterator it = items.begin();
     681           0 :                  it != items.end(); ++it) {
     682           0 :                 ptr = AddUpdate(ptr, *it, DNS_CLASS_NONE, 0, len);
     683             :             }
     684           0 :             break;
     685             : 
     686           0 :         default:
     687           0 :             assert(0);
     688             :     }
     689             : 
     690             :     // Add Additional RRs
     691           0 :     std::string view = "view=" + domain;
     692           0 :     ptr = AddAdditionalSection(ptr, "view", DNS_TXT_RECORD, DNS_CLASS_IN,
     693             :                                 0, view, len);
     694             : 
     695           0 :     return len;
     696             : }
     697             : 
     698         469 : bool BindUtil::IsReverseZoneV4(const std::string &name) {
     699             :     // According to the docs, boost::regex is thread-safe. Compile once then.
     700             :     static boost::regex in_addr_arpa("(?:[0-9]+\\.){1,4}in-addr\\.arpa\\.?",
     701         469 :                                      boost::regex::perl | boost::regex::icase);
     702         469 :     return boost::regex_match(name, in_addr_arpa);
     703             : }
     704             : 
     705         176 : bool BindUtil::IsReverseZoneV6(const std::string &name) {
     706             :     static boost::regex ip6_arpa("(?:[0-9a-f]\\.){1,32}ip6\\.arpa\\.?",
     707         176 :                                  boost::regex::perl | boost::regex::icase);
     708         176 :     return boost::regex_match(name, ip6_arpa);
     709             : }
     710             : 
     711         464 : bool BindUtil::IsReverseZone(const std::string &name) {
     712         464 :     return BindUtil::IsReverseZoneV4(name) || BindUtil::IsReverseZoneV6(name);
     713             : }
     714             : 
     715          10 : bool BindUtil::IsIP(const std::string &name, IpAddress &addr) {
     716          10 :     boost::system::error_code ec;
     717          10 :     addr = boost::asio::ip::address::from_string(name, ec);
     718          10 :     return !ec.value();
     719             : }
     720             : 
     721         180 : inline uint8_t BindUtil::GetNibble(const Ip6Address::bytes_type &addr, size_t bit)
     722             : {
     723         180 :     assert((bit >> 3) < 16);
     724         180 :     uint8_t buf = addr[bit >> 3];
     725         180 :     return ((bit & 0x7) ? (buf & 0xF) : (buf >> 4));
     726             : }
     727             : 
     728             : // Takes nibbles up to (but not necessarily including) plen and builds
     729             : // ip6.arpa zone name suffix for them. The caller is responsible for
     730             : // prefixing it with remaining plen bits when plen is not a multiply of 4.
     731          11 : std::string BindUtil::BuildIp6ArpaSuffix(const Ip6Address::bytes_type &addr,
     732             :                                          uint32_t plen) {
     733          11 :     std::vector<std::string> items;
     734             :     uint8_t buf;
     735             : 
     736         187 :     for (size_t i = 0; i < (plen >> 2); i++) {
     737         176 :         buf = GetNibble(addr, i << 2);
     738         176 :         std::stringstream str;
     739         176 :         str << std::hex << static_cast<unsigned int>(buf);
     740         176 :         items.push_back(str.str());
     741         176 :     }
     742             : 
     743          11 :     std::reverse(items.begin(), items.end());
     744          11 :     items.push_back("ip6.arpa");
     745          22 :     return boost::algorithm::join(items, ".");
     746          11 : }
     747             : 
     748             : // Get list of reverse zones, given a subnet
     749         344 : void BindUtil::GetReverseZoneList(const Ip4Address &mask, uint32_t plen,
     750             :                                   ZoneList &zones) {
     751         344 :     uint32_t addr = mask.to_ulong();
     752         344 :     std::string zone_name = "in-addr.arpa.";
     753        1262 :     while (plen >= 8) {
     754         918 :         std::stringstream str;
     755         918 :         str << (addr >> 24);
     756         918 :         zone_name = str.str() + "." + zone_name;
     757         918 :         addr = addr << 8;
     758         918 :         plen -= 8;
     759         918 :     }
     760         344 :     if (plen == 0) {
     761             :         // when prefix len is a multiple of 8, add only one reverse zone
     762         200 :         zones.push_back(zone_name);
     763         200 :         return;
     764             :     }
     765         608 :     for (int j = 0; j <= (0xFF >> plen); j++) {
     766             :         // when prefix len is not a multiple of 8, add reverse zones for all
     767             :         // addresses upto the nearest 8 byte boundary for the prefix len. For
     768             :         // example, a /22 prefix results in 4 reverse zones.
     769         464 :         uint32_t last = (addr >> 24) + j;
     770         464 :         std::stringstream str;
     771         464 :         str << last;
     772         928 :         std::string rev_zone_name = str.str() + "." + zone_name;
     773         464 :         zones.push_back(rev_zone_name);
     774         464 :     }
     775         344 : }
     776             : 
     777          10 : void BindUtil::GetReverseZoneList(const Ip6Address &mask, uint32_t plen,
     778             :                                   ZoneList &zones) {
     779          10 :     Ip6Address::bytes_type addr = mask.to_bytes();
     780          10 :     std::string zone_name;
     781             :     uint8_t buf;
     782             : 
     783          10 :     if (!plen || plen > 128)
     784           0 :         return;
     785             : 
     786          10 :     zone_name = BindUtil::BuildIp6ArpaSuffix(addr, plen) + ".";
     787             : 
     788          10 :     uint32_t bits_rem = plen & 0x3;
     789             :     // Prefix doesn't end on nibble boundary
     790          10 :     if (bits_rem) {
     791           4 :         buf = BindUtil::GetNibble(addr, plen - bits_rem);
     792          36 :         for (int j = 0; j <= (0xF >> bits_rem); j++) {
     793          32 :             std::stringstream str;
     794          32 :             str << std::hex << static_cast<unsigned int>(buf + j)
     795          32 :                 << "." << zone_name;
     796          32 :             zones.push_back(str.str());
     797          32 :         }
     798             :     } else {
     799           6 :         zones.push_back(zone_name);
     800             :     }
     801          10 : }
     802             : 
     803         354 : void BindUtil::GetReverseZoneList(const IpAddress &mask, uint32_t plen,
     804             :                         ZoneList &zones) {
     805         354 :     if (mask.is_v4()) {
     806         344 :         GetReverseZoneList(mask.to_v4(), plen, zones);
     807          10 :     } else if (mask.is_v6()) {
     808          10 :         GetReverseZoneList(mask.to_v6(), plen, zones);
     809             :     }
     810         354 : }
     811             : 
     812           1 : void BindUtil::GetReverseZone(const Ip4Address &ip, uint32_t plen,
     813             :                               std::string &zone) {
     814           1 :     uint32_t addr = ip.to_ulong();
     815           1 :     zone = "in-addr.arpa";
     816           4 :     while (plen >= 8) {
     817           3 :         std::stringstream str;
     818           3 :         str << (addr >> 24);
     819           3 :         zone = str.str() + "." + zone;
     820           3 :         addr = addr << 8;
     821           3 :         plen -= 8;
     822           3 :     }
     823           1 :     if (plen == 0) {
     824           1 :         return;
     825             :     }
     826             :     // when prefix len is not a multiple of 8, add extra byte from the addr
     827           0 :     std::stringstream str;
     828           0 :     str << (addr >> 24);
     829           0 :     zone = str.str() + "." + zone;
     830           0 : }
     831             : 
     832           1 : void BindUtil::GetReverseZone(const Ip6Address &ip, uint32_t plen,
     833             :                               std::string &zone) {
     834           1 :     Ip6Address::bytes_type addr = ip.to_bytes();
     835             :     uint8_t buf;
     836             : 
     837           1 :     if (!plen || plen > 128)
     838           0 :         return;
     839             : 
     840           1 :     zone = BindUtil::BuildIp6ArpaSuffix(addr, plen);
     841             : 
     842           1 :     uint32_t bits_rem = plen & 0x3;
     843             :     // Add the trailing nibble
     844           1 :     if (bits_rem) {
     845           0 :         buf = BindUtil::GetNibble(addr, plen - bits_rem);
     846           0 :         std::stringstream str;
     847           0 :         str << std::hex << static_cast<unsigned int>(buf) << "." << zone;
     848           0 :         zone = str.str();
     849           0 :     }
     850             : }
     851             : 
     852           2 : void BindUtil::GetReverseZone(const IpAddress &addr, uint32_t plen,
     853             :                               std::string &zone) {
     854           2 :     if (addr.is_v4()) {
     855           1 :         GetReverseZone(addr.to_v4(), plen, zone);
     856           1 :     } else if (addr.is_v6()) {
     857           1 :         GetReverseZone(addr.to_v6(), plen, zone);
     858             :     }
     859           2 : }
     860             : 
     861           5 : bool BindUtil::GetAddrFromPtrName(std::string &ptr_name, Ip4Address &ip) {
     862           5 :     uint32_t addr = 0;
     863             :     uint8_t dot;
     864             :     uint32_t num;
     865           5 :     if (!BindUtil::IsReverseZoneV4(ptr_name))
     866           0 :         return false;
     867           5 :     std::stringstream str(ptr_name);
     868           5 :     if (str.peek() == '.')
     869           0 :         str >> dot;
     870           5 :     int count = 0;
     871          25 :     while (count < 4) {
     872          20 :         if (str.peek() == 'i')
     873           0 :             break;
     874          20 :         str >> num;
     875          20 :         str >> dot;
     876          20 :         addr |= (num << (8 * count));
     877          20 :         count++;
     878             :     }
     879           5 :     while (count++ < 4)
     880           0 :         addr = addr << 8;
     881           5 :     ip = Ip4Address(addr);
     882           5 :     return true;
     883           5 : }
     884             : 
     885           5 : bool BindUtil::GetAddrFromPtrName(std::string &ptr_name, Ip6Address &ip) {
     886             :     Ip6Address::bytes_type addr;
     887           5 :     BOOST_ASSERT(addr.size() == 16);
     888             : 
     889             :     typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
     890             :     typedef boost::array<uint8_t, 32> nibbles;
     891             : 
     892           5 :     if (!BindUtil::IsReverseZoneV6(ptr_name))
     893           0 :         return false;
     894             : 
     895           5 :     tokenizer tok(ptr_name, boost::char_separator<char>("."));
     896             :     nibbles nib;
     897             : 
     898           5 :     tokenizer::const_iterator tok_it = tok.begin();
     899           5 :     nibbles::iterator nib_it = nib.begin();
     900         165 :     for (; tok_it != tok.end() && nib_it != nib.end(); ++tok_it, ++nib_it) {
     901         160 :         std::stringstream str(*tok_it);
     902             :         unsigned int buf;
     903             : 
     904             :         // found ip6.arpa
     905         160 :         if (!(str >> std::hex >> buf))
     906           0 :             break;
     907             : 
     908         160 :         *nib_it = static_cast<uint8_t>(buf);
     909         160 :     }
     910             : 
     911           5 :     std::fill(addr.begin(), addr.end(), 0);
     912             : 
     913           5 :     std::reverse_iterator<nibbles::const_iterator> r_nib_it(nib_it);
     914           5 :     Ip6Address::bytes_type::iterator addr_it = addr.begin();
     915             : 
     916             :     // the most significant nibble is #0 thus always even
     917           5 :     bool odd_nib = false;
     918             :     // we should never get past addr.end() as nib.size() is 2 * 16
     919         165 :     for (; r_nib_it != nib.rend(); ++r_nib_it) {
     920         160 :         if (odd_nib) {
     921          80 :             *addr_it |= (*r_nib_it & 0xF);
     922          80 :             ++addr_it;
     923             :         } else {
     924          80 :             *addr_it |= (*r_nib_it << 4);
     925             :         }
     926         160 :         odd_nib = !odd_nib;
     927             :     }
     928             : 
     929           5 :     ip = Ip6Address(addr);
     930           5 :     return true;
     931           5 : }
     932             : 
     933          10 : bool BindUtil::GetAddrFromPtrName(std::string &ptr_name,
     934             :                                   IpAddress &ip) {
     935          10 :     std::string name = boost::to_lower_copy(ptr_name);
     936             :     std::size_t pos;
     937             : 
     938          10 :     pos = name.find(".in-addr.arpa");
     939          10 :     if (pos != std::string::npos) {
     940           5 :         Ip4Address out;
     941           5 :         bool success = BindUtil::GetAddrFromPtrName(ptr_name, out);
     942           5 :         if (success)
     943           5 :             ip = out;
     944           5 :         return success;
     945             :     }
     946             : 
     947           5 :     pos = name.find(".ip6.arpa");
     948           5 :     if (pos != std::string::npos) {
     949           5 :         Ip6Address out;
     950           5 :         bool success = BindUtil::GetAddrFromPtrName(ptr_name, out);
     951           5 :         if (success)
     952           5 :             ip = out;
     953           5 :         return success;
     954             :     }
     955             : 
     956           0 :     return false;
     957          10 : }
     958             : 
     959           0 : std::string BindUtil::GetPtrNameFromAddr(const Ip4Address &ip) {
     960           0 :     std::stringstream str;
     961           0 :     for (int i = 0; i < 4; i++) {
     962           0 :         str << ((ip.to_ulong() >> (i * 8)) & 0xFF) << ".";
     963             :     }
     964           0 :     str << "in-addr.arpa";
     965           0 :     return str.str();
     966           0 : }
     967             : 
     968           0 : std::string BindUtil::GetPtrNameFromAddr(const Ip6Address &ip6) {
     969           0 :     std::stringstream str;
     970             :     // we start with nibble #31 which is always odd
     971           0 :     bool odd_nibble = true;
     972             : 
     973           0 :     Ip6Address::bytes_type addr = ip6.to_bytes();
     974           0 :     Ip6Address::bytes_type::reverse_iterator it = addr.rbegin();
     975           0 :     while (it != addr.rend()) {
     976             :         unsigned int buf;
     977           0 :         if (odd_nibble) {
     978           0 :             buf = (*it & 0xF);
     979             :         } else {
     980           0 :             buf = (*it >> 4);
     981           0 :             ++it;
     982             :         }
     983           0 :         str << std::hex << buf << '.';
     984           0 :         odd_nibble = !odd_nibble;
     985             :     }
     986           0 :     str << "ip6.arpa";
     987             : 
     988           0 :     return str.str();
     989           0 : }
     990             : 
     991          41 : std::string BindUtil::GetFQDN(const std::string &name, const std::string &domain,
     992             :                               const std::string &match) {
     993          41 :     if (name.find(match, 0) == std::string::npos)
     994          82 :         return name + "." + domain;
     995             :     else
     996           0 :         return name;
     997             : }
     998             : 
     999          60 : bool BindUtil::HasSpecialChars(const std::string &name) {
    1000         599 :     for (unsigned int i = 0; i < name.size(); ++i) {
    1001         539 :         uint8_t c = name[i];
    1002         577 :         if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
    1003          83 :               (c >= '0' && c <= '9') || (c == '-') || (c == '.')))
    1004           0 :             return true;
    1005             :     }
    1006          60 :     return false;
    1007             : }
    1008             : 
    1009         930 : void BindUtil::RemoveSpecialChars(std::string &name) {
    1010        8906 :     for (unsigned int i = 0; i < name.size(); ++i) {
    1011        7976 :         uint8_t c = name[i];
    1012        8191 :         if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
    1013        1163 :               (c >= '0' && c <= '9') || (c == '-') || (c == '.')))
    1014           0 :             name[i] = '-';
    1015             :     }
    1016         930 : }
    1017             : 
    1018           0 : void DnsNameEncoder::AddName(std::string &name, uint16_t curr_msg_offset,
    1019             :                              uint16_t &name_plen, uint16_t &name_offset) {
    1020           0 :     name_plen = 0;
    1021           0 :     name_offset = 0;
    1022           0 :     std::size_t pos = 0;
    1023           0 :     while (pos < name.size()) {
    1024           0 :         std::string str = name.substr(pos);
    1025           0 :         if(IsPresent(str, name_offset)) {
    1026           0 :             name_plen = pos ? pos - 1 : 0;
    1027           0 :             break;
    1028             :         }
    1029             : 
    1030           0 :         pos = name.find('.', pos + 1);
    1031           0 :         if (pos == std::string::npos)
    1032           0 :             break;
    1033           0 :         pos++;
    1034           0 :     }
    1035           0 :     if (pos > 0)
    1036           0 :         names_.push_back(Name(name, curr_msg_offset));
    1037           0 : }
    1038             : 
    1039           0 : bool DnsNameEncoder::IsPresent(std::string &name, uint16_t &name_offset) {
    1040           0 :     for (unsigned int i = 0; i < names_.size(); i++) {
    1041           0 :         if (names_[i].name == name) {
    1042           0 :             name_offset = names_[i].offset;
    1043           0 :             return true;
    1044             :         }
    1045             :     }
    1046           0 :     return false;
    1047             : }

Generated by: LCOV version 1.14