LCOV - code coverage report
Current view: top level - dns/bind - bind_util.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 50 99 50.5 %
Date: 2026-10-19 02:12:28 Functions: 16 26 61.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef __bind_util_h__
       6             : #define __bind_util_h__
       7             : 
       8             : #include <iostream>
       9             : #include <stdint.h>
      10             : #include <vector>
      11             : #include <boost/asio.hpp>
      12             : 
      13             : #include "sandesh/sandesh_trace.h"
      14             : #include "bind/bind_types.h"
      15             : #include "bind/xmpp_dns_agent.h"
      16             : 
      17             : #include "base/address.h"
      18             : #include "base/address_util.h"
      19             : 
      20             : extern SandeshTraceBufferPtr DnsBindTraceBuf;
      21             : #define DNS_BIND_TRACE(obj, arg)                                              \
      22             : do {                                                                          \
      23             :     std::ostringstream _str;                                                  \
      24             :     _str << arg;                                                              \
      25             :     obj::TraceMsg(DnsBindTraceBuf, __FILE__, __LINE__, _str.str());           \
      26             : } while (false)                                                               \
      27             : 
      28             : #define DNS_SERVER_PORT 53
      29             : 
      30             : // DNS Class
      31             : #define DNS_CLASS_IN   1
      32             : #define DNS_CLASS_ANY  0x00ff
      33             : #define DNS_CLASS_NONE 0x00fe
      34             : 
      35             : // DNS record types
      36             : #define DNS_A_RECORD     1
      37             : #define DNS_NS_RECORD    2
      38             : #define DNS_CNAME_RECORD 5
      39             : #define DNS_TYPE_SOA     6
      40             : #define DNS_PTR_RECORD   0x0C
      41             : #define DNS_MX_RECORD    0x0F
      42             : #define DNS_TXT_RECORD   0x10
      43             : #define DNS_AAAA_RECORD  0x1C
      44             : #define DNS_SRV_RECORD   0x21
      45             : #define DNS_TYPE_ANY     0x00ff
      46             : 
      47             : // DNS return codes
      48             : #define DNS_ERR_NO_ERROR     0
      49             : #define DNS_ERR_FORMAT_ERROR 1
      50             : #define DNS_ERR_SERVER_FAIL  2
      51             : #define DNS_ERR_NO_SUCH_NAME 3
      52             : #define DNS_ERR_NO_IMPLEMENT 4
      53             : #define DNS_ERR_NOT_AUTH     9
      54             : 
      55             : enum DnsReq {
      56             :     DNS_QUERY_REQUEST = 0x0,
      57             :     DNS_QUERY_RESPONSE = 0x1,
      58             : };
      59             : 
      60             : enum DnsOpcode {
      61             :     DNS_OPCODE_QUERY = 0x0,
      62             :     DNS_OPCODE_STATUS = 0x2,
      63             :     DNS_OPCODE_NOTIFY = 0x04,
      64             :     DNS_OPCODE_UPDATE = 0x05,
      65             : };
      66             : 
      67             : typedef std::map<std::string, uint16_t> DnsTypeMap;
      68             : typedef std::map<std::string, uint16_t>::const_iterator DnsTypeIter;
      69             : typedef std::map<uint16_t, std::string> DnsTypeNumMap;
      70             : typedef std::map<uint16_t, std::string>::const_iterator DnsTypeNumIter;
      71             : typedef std::map<uint16_t, std::string> DnsResponseMap;
      72             : typedef std::map<uint16_t, std::string>::const_iterator DnsResponseIter;
      73             : 
      74             : struct dns_flags {
      75             : #if __BYTE_ORDER == __LITTLE_ENDIAN
      76             :     uint8_t rd:1;          // recursion desired
      77             :     uint8_t trunc:1;       // truncated
      78             :     uint8_t auth:1;        // authoritative answer
      79             :     uint8_t op:4;          // opcode
      80             :     uint8_t req:1;         // request / response
      81             :     uint8_t ret:4;         // return code
      82             :     uint8_t cd:1;          // checking disabled
      83             :     uint8_t ad:1;          // answer authenticated
      84             :     uint8_t res:1;         // reserved
      85             :     uint8_t ra:1;          // recursion available
      86             : #elif __BYTE_ORDER == __BIG_ENDIAN
      87             :     uint8_t req:1;
      88             :     uint8_t op:4;
      89             :     uint8_t auth:1;
      90             :     uint8_t trunc:1;
      91             :     uint8_t rd:1;
      92             :     uint8_t ra:1;
      93             :     uint8_t res:1;
      94             :     uint8_t ad:1;
      95             :     uint8_t cd:1;
      96             :     uint8_t ret:4;
      97             : #else
      98             : #error "Adjust your <bits/endian.h> defines"
      99             : #endif
     100             : };
     101             : 
     102             : struct dnshdr {
     103             :     uint16_t xid;
     104             :     dns_flags flags;
     105             :     uint16_t ques_rrcount; // question RR count
     106             :     uint16_t ans_rrcount;  // answer RR count
     107             :     uint16_t auth_rrcount; // authority RR count
     108             :     uint16_t add_rrcount;  // additional RR count
     109             : };
     110             : 
     111             : // Data format in an SOA record
     112             : struct DnsSOAData {
     113             :     std::string primary_ns; // primary name server
     114             :     std::string mailbox;    // responsible authority's mailbox
     115             :     uint16_t ns_plen;       // length of the prefix in primary_ns that is unique
     116             :     uint16_t ns_offset;     // offset from where rest of primary_ns name exists
     117             :     uint16_t mailbox_plen;
     118             :     uint16_t mailbox_offset;
     119             :     uint32_t serial;        // serial number
     120             :     uint32_t refresh;       // refresh interval in seconds
     121             :     uint32_t retry;         // retry interval in seconds
     122             :     uint32_t expiry;        // expiration limit in seconds
     123             :     uint32_t ttl;           // minimum ttl in seconds
     124             : 
     125        1098 :     DnsSOAData() : ns_plen(0), ns_offset(0), mailbox_plen(0), mailbox_offset(0),
     126         549 :                    serial(0), refresh(0), retry(0), expiry(0), ttl(0) {}
     127          34 :     bool operator ==(const DnsSOAData &rhs) const {
     128          68 :         if (primary_ns == rhs.primary_ns && mailbox == rhs.mailbox &&
     129          34 :             serial == rhs.serial && refresh == rhs.refresh &&
     130          68 :             retry == rhs.retry && expiry == rhs.expiry && ttl == rhs.ttl)
     131          34 :             return true;
     132           0 :         return false;
     133             :     }
     134             : };
     135             : 
     136             : // Data format in an SRV record
     137             : struct DnsSRVData {
     138             :     uint16_t priority;
     139             :     uint16_t weight;
     140             :     uint16_t port;
     141             :     std::string hostname;
     142             :     uint16_t hn_plen;       // length of the prefix in hostname that is unique
     143             :     uint16_t hn_offset;     // offset from where rest of hostname name exists
     144             : 
     145         549 :     DnsSRVData() : hn_plen(0), hn_offset(0) {}
     146             : };
     147             : 
     148             : struct DnsItem {
     149             :     uint16_t eclass;
     150             :     uint16_t type;
     151             :     uint32_t ttl;
     152             :     uint16_t priority;
     153             :     uint16_t offset;      // offset of the name in the read request from the VM
     154             :     uint16_t name_plen;   // length of the prefix in name that is unique
     155             :     uint16_t name_offset; // offset from where rest of name exists
     156             :     uint16_t data_plen;   // length of the prefix in data that is unique
     157             :     uint16_t data_offset; // offset from where rest of data exists
     158             :     std::string name;
     159             :     std::string source_name;
     160             :     std::string vm_uuid;
     161             :     std::string data;
     162             :     DnsSOAData soa;
     163             :     DnsSRVData srv;
     164             : 
     165         549 :     DnsItem() : eclass(1), type(0), ttl(0), priority(0), offset(0),
     166         549 :     name_plen(0), name_offset(0), data_plen(0), data_offset(0), soa() {}
     167             : 
     168             :     std::string ToString() const;
     169             : 
     170          77 :     bool operator ==(const DnsItem &rhs) const {
     171         153 :         if (eclass == rhs.eclass && type == rhs.type &&
     172         144 :             name == rhs.name && data == rhs.data && soa == rhs.soa &&
     173         188 :             source_name == rhs.source_name && vm_uuid == rhs.vm_uuid)
     174          32 :             return true;
     175          45 :         return false;
     176             :     }
     177             : 
     178           0 :     bool IsDelete() const {
     179           0 :         if (ttl == 0 && (eclass == DNS_CLASS_ANY || eclass == DNS_CLASS_NONE))
     180           0 :             return true;
     181           0 :         return false;
     182             :     }
     183             : 
     184           0 :     bool MatchDelete(const DnsItem &rhs) const {
     185           0 :         if ((rhs.eclass == DNS_CLASS_ANY || rhs.eclass == DNS_CLASS_NONE) &&
     186           0 :             (rhs.type == DNS_TYPE_ANY || type == rhs.type) &&
     187           0 :             (name == rhs.name) &&
     188           0 :             (rhs.data.size() == 0 || data == rhs.data) &&
     189           0 :             (source_name == rhs.source_name) &&
     190             :             // Same ownership rule as DnsManager::ProcessAgentUpdate(): the
     191             :             // vm_uuid is compared only when both sides carry one. A stored
     192             :             // item published without a vm_uuid must stay removable by a
     193             :             // delete that carries one, else the record is stranded in named.
     194           0 :             (rhs.vm_uuid.empty() || vm_uuid.empty() ||
     195           0 :              vm_uuid == rhs.vm_uuid))
     196           0 :             return true;
     197           0 :         return false;
     198             :     }
     199             : };
     200             : 
     201             : typedef std::list<DnsItem> DnsItems;
     202           0 : static inline std::string DnsItemsToString(DnsItems &items) {
     203           0 :     std::string str;
     204           0 :     for (DnsItems::iterator it = items.begin();
     205           0 :          !items.empty() && it != items.end(); ++it) {
     206           0 :         str += (*it).ToString();
     207             :     }
     208           0 :     return str;
     209           0 : }
     210             : 
     211             : struct DnsUpdateData {
     212             :     typedef boost::function<void(DnsItem &)> DeleteCallback;
     213             : 
     214             :     std::string virtual_dns;
     215             :     std::string zone;
     216             :     mutable DnsItems items;
     217             : 
     218          23 :     DnsUpdateData() {}
     219             :     DnsUpdateData(const std::string &vdns, const std::string &z)
     220             :                 : virtual_dns(vdns), zone(z) {}
     221             : 
     222             :     struct Compare {
     223           0 :         bool operator() (DnsUpdateData *const &lhs, DnsUpdateData *const &rhs) const {
     224           0 :             if (!lhs || !rhs)
     225           0 :                 return false;
     226           0 :             if (lhs->virtual_dns != rhs->virtual_dns)
     227           0 :                 return lhs->virtual_dns < rhs->virtual_dns;
     228           0 :             return lhs->zone < rhs->zone;
     229             :         }
     230             :     };
     231             : 
     232           0 :     bool AddItem(DnsItem &item, bool replace = false) const {
     233           0 :         for (DnsItems::iterator it = items.begin(); it != items.end(); ++it) {
     234           0 :             if (item == *it) {
     235           0 :                 if (replace)
     236           0 :                     *it = item;
     237           0 :                 return false;
     238             :             }
     239             :         }
     240           0 :         items.push_back(item);
     241           0 :         return true;
     242             :     }
     243             : 
     244           0 :     bool DelItem(DnsItem &item) const {
     245           0 :         bool change = false;
     246           0 :         for (DnsItems::iterator it = items.begin(); it != items.end();) {
     247           0 :             if ((*it).MatchDelete(item)) {
     248           0 :                 items.erase(it++);
     249           0 :                 change = true;
     250             :             } else {
     251           0 :                 ++it;
     252             :             }
     253             :         }
     254           0 :         return change;
     255             :     }
     256             : };
     257             : 
     258             : typedef std::vector<std::string> ZoneList;
     259             : 
     260             : struct Subnet {
     261             :     IpAddress prefix;
     262             :     uint32_t plen;
     263             :     uint8_t flags;
     264             : 
     265             :     enum DnsConfigFlags {
     266             :         DeleteMarked = 1 << 0,
     267             :     };
     268             : 
     269          10 :     Subnet() : plen(0), flags(0) {}
     270          43 :     Subnet(std::string addr, uint32_t len) : plen(len), flags(0) {
     271          43 :         boost::system::error_code ec;
     272          43 :         prefix = boost::asio::ip::address::from_string(addr, ec);
     273          43 :     }
     274             : 
     275             :     bool operator< (const Subnet &rhs) const;
     276             : 
     277           4 :     void MarkDelete() { flags |= DeleteMarked; }
     278         283 :     bool IsDeleted() const { return (flags & DeleteMarked); }
     279             :     void ClearDelete() { flags &= ~DeleteMarked; }
     280             : 
     281             :     void GetReverseZones(ZoneList &zones) const;
     282             : 
     283             :     bool Contains(const IpAddress &addr) const;
     284             : };
     285             : 
     286             : typedef std::vector<Subnet> Subnets;
     287             : 
     288             : class BindUtil {
     289             : public:
     290             :     enum Operation {
     291             :         ADD_UPDATE,
     292             :         CHANGE_UPDATE,
     293             :         DELETE_UPDATE
     294             :     };
     295             : 
     296             :     static uint16_t DnsClass(const std::string &cl);
     297             :     static std::string DnsClass(uint16_t cl);
     298             :     static uint16_t DnsType(const std::string &tp);
     299             :     static std::string DnsType(uint16_t tp);
     300             :     static const std::string &DnsResponseCode(uint16_t code);
     301             :     static uint8_t *AddName(uint8_t *ptr, const std::string &addr,
     302             :                             uint16_t plen, uint16_t offset, uint16_t &length);
     303             :     static bool ParseDnsQuery(uint8_t *dns, uint16_t dnslen,
     304             :                               uint16_t *parsed_length, DnsItems &items);
     305             :     static bool ParseDnsResponse(uint8_t *dns, uint16_t dnslen, uint16_t &xid,
     306             :                                  dns_flags &flags, DnsItems &ques,
     307             :                                  DnsItems &ans, DnsItems &auth, DnsItems &add);
     308             :     static bool ParseDnsUpdate(uint8_t *dns, uint16_t dnslen,
     309             :                                DnsUpdateData &data);
     310             :     static int BuildDnsQuery(uint8_t *buf, uint16_t xid,
     311             :                              const std::string &domain,
     312             :                              const DnsItems &items);
     313             :     static int BuildDnsUpdate(uint8_t *buf, Operation op, uint16_t xid,
     314             :                               const std::string &domain,
     315             :                               const std::string &zone,
     316             :                               const DnsItems &items);
     317             :     static uint8_t *AddQuestionSection(uint8_t *ptr, const std::string &name,
     318             :                                        uint16_t type, uint16_t cl,
     319             :                                        uint16_t &length);
     320             :     static uint8_t *AddAnswerSection(uint8_t *ptr, const DnsItem &item,
     321             :                                      uint16_t &length);
     322             :     static uint8_t *AddUpdate(uint8_t *ptr, const DnsItem &item,
     323             :                              uint16_t cl, uint32_t ttl, uint16_t &length);
     324             :     static void BuildDnsHeader(dnshdr *dns, uint16_t xid, DnsReq req,
     325             :                                DnsOpcode op, bool rd, bool ra, uint8_t ret,
     326             :                                uint16_t ques_count);
     327             : 
     328           6 :     static inline uint16_t DataLength(uint16_t plen, uint16_t offset,
     329             :                                       uint16_t size) {
     330           6 :         return (offset ? (plen ? plen + 2 + 1 : 2) : (size ? size + 2 : 1));
     331             :     }
     332             :     static bool IsIP(const std::string &name, IpAddress &addr);
     333             :     static bool IsReverseZone(const std::string &name);
     334             :     static void GetReverseZoneList(const IpAddress &mask, uint32_t plen,
     335             :                                    ZoneList &zones);
     336             :     // DnsProto::SendUpdateDnsEntry() needs the following two methods...
     337             :     static void GetReverseZone(const Ip4Address &addr, uint32_t plen,
     338             :                                std::string &zone);
     339             :     static void GetReverseZone(const Ip6Address &addr, uint32_t plen,
     340             :                                std::string &zone);
     341             :     static void GetReverseZone(const IpAddress &addr, uint32_t plen,
     342             :                                std::string &zone);
     343             :     static bool GetAddrFromPtrName(std::string &ptr_name, IpAddress &mask);
     344             :     // ...and these two as well.
     345             :     static std::string GetPtrNameFromAddr(const Ip4Address &ip);
     346             :     static std::string GetPtrNameFromAddr(const Ip6Address &ip6);
     347             :     static std::string GetFQDN(const std::string &name, const std::string &domain,
     348             :                                const std::string &match);
     349             :     static bool HasSpecialChars(const std::string &name);
     350             :     static void RemoveSpecialChars(std::string &name);
     351             : private:
     352             : 
     353             :     static inline bool ReadByte(uint8_t *dns, uint16_t dnslen, int *remlen,
     354             :                                 uint8_t &value) {
     355             :         if (*remlen < 1) {
     356             :             return false;
     357             :         }
     358             :         uint8_t *ptr = dns + (dnslen - *remlen);
     359             :         *remlen -= 1;
     360             :         value = *(uint8_t *) ptr;
     361             :         return true;
     362             :     }
     363             : 
     364          83 :     static inline bool ReadShort(uint8_t *dns, uint16_t dnslen, int *remlen,
     365             :                                  uint16_t &value) {
     366          83 :         if (*remlen < 2) {
     367           0 :             return false;
     368             :         }
     369          83 :         uint8_t *ptr = dns + (dnslen - *remlen);
     370          83 :         *remlen -= 2;
     371          83 :         value = ntohs(*(uint16_t *) ptr);
     372          83 :         return true;
     373             :     }
     374             : 
     375          31 :     static inline bool ReadWord(uint8_t *dns, uint16_t dnslen, int *remlen,
     376             :                                 uint32_t &value) {
     377          31 :         if (*remlen < 4) {
     378           0 :             return false;
     379             :         }
     380          31 :         uint8_t *ptr = dns + (dnslen - *remlen);
     381          31 :         *remlen -= 4;
     382          31 :         value = ntohl(*(uint32_t *) ptr);
     383          31 :         return true;
     384             :     }
     385             : 
     386          38 :     static inline uint8_t *WriteByte(uint8_t *ptr, uint8_t value) {
     387          38 :         *(uint8_t *) ptr = value;
     388          38 :         ptr += 1;
     389             : 
     390          38 :         return ptr;
     391             :     }
     392             : 
     393          83 :     static inline uint8_t *WriteShort(uint8_t *ptr, uint16_t value) {
     394          83 :         *(uint16_t *) ptr = htons(value);
     395          83 :         ptr += 2;
     396             : 
     397          83 :         return ptr;
     398             :     }
     399             : 
     400          31 :     static inline uint8_t *WriteWord(uint8_t *ptr, uint32_t value) {
     401          31 :         *(uint32_t *) ptr = htonl(value);
     402          31 :         ptr += 4;
     403             : 
     404          31 :         return ptr;
     405             :     }
     406             :     static uint8_t *AddData(uint8_t *ptr, const DnsItem &item,
     407             :                             uint16_t &length);
     408             :     static uint8_t *AddAdditionalSection(uint8_t *ptr, const std::string name,
     409             :                                          uint16_t type, uint16_t cl,
     410             :                                          uint32_t ttl, const std::string &data,
     411             :                                          uint16_t &length);
     412             :     static bool ReadName(uint8_t *dns, uint16_t dnslen, int *remlen,
     413             :                          std::string &name, uint16_t &plen, uint16_t &offset);
     414             :     static bool ReadData(uint8_t *dns, uint16_t dnslen, int *remlen,
     415             :                          DnsItem &item);
     416             :     static bool ReadQuestionEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
     417             :                                   DnsItem &item);
     418             :     static bool ReadAnswerEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
     419             :                                 DnsItem &item);
     420             :     static bool IsReverseZoneV4(const std::string &name);
     421             :     static bool IsReverseZoneV6(const std::string &name);
     422             :     static void GetReverseZoneList(const Ip4Address &mask, uint32_t plen,
     423             :                                    ZoneList &zones);
     424             :     static void GetReverseZoneList(const Ip6Address &mask, uint32_t plen,
     425             :                                    ZoneList &zones);
     426             :     static bool GetAddrFromPtrName(std::string &ptr_name,
     427             :                                    Ip4Address &ip);
     428             :     static bool GetAddrFromPtrName(std::string &ptr_name,
     429             :                                    Ip6Address &ip);
     430             :     static uint8_t GetNibble(const Ip6Address::bytes_type &addr,
     431             :                              size_t bit);
     432             :     static std::string BuildIp6ArpaSuffix(const Ip6Address::bytes_type &addr,
     433             :                                           uint32_t plen);
     434             : };
     435             : 
     436             : // Identify the offsets for names in a DNS message
     437             : class DnsNameEncoder {
     438             : public:
     439             :     struct Name {
     440             :         std::string name;
     441             :         uint16_t offset;
     442           0 :         Name(std::string &n, uint16_t oset) : name(n), offset(oset) {}
     443             :     };
     444             : 
     445           0 :     DnsNameEncoder() {};
     446           0 :     virtual ~DnsNameEncoder() {};
     447             :     void AddName(std::string &name, uint16_t curr_msg_offset,
     448             :                  uint16_t &name_plen, uint16_t &name_offset);
     449             : 
     450             : private:
     451             :     bool IsPresent(std::string &name, uint16_t &name_offset);
     452             : 
     453             :     std::vector<Name> names_;
     454             :     DISALLOW_COPY_AND_ASSIGN(DnsNameEncoder);
     455             : };
     456             : 
     457             : #endif // __bind_util_h__

Generated by: LCOV version 1.14