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

Generated by: LCOV version 1.14