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

Generated by: LCOV version 1.14