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: 51 96 53.1 %
Date: 2026-06-08 02:02:55 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             :  */
       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 data;
     161             :     DnsSOAData soa;
     162             :     DnsSRVData srv;
     163             : 
     164         549 :     DnsItem() : eclass(1), type(0), ttl(0), priority(0), offset(0),
     165         549 :     name_plen(0), name_offset(0), data_plen(0), data_offset(0), soa() {}
     166             : 
     167             :     std::string ToString() const;
     168             : 
     169          77 :     bool operator ==(const DnsItem &rhs) const {
     170         153 :         if (eclass == rhs.eclass && type == rhs.type &&
     171         230 :             name == rhs.name && data == rhs.data && soa == rhs.soa && source_name == rhs.source_name)
     172          32 :             return true;
     173          45 :         return false;
     174             :     }
     175             : 
     176           0 :     bool IsDelete() const {
     177           0 :         if (ttl == 0 && (eclass == DNS_CLASS_ANY || eclass == DNS_CLASS_NONE))
     178           0 :             return true;
     179           0 :         return false;
     180             :     }
     181             : 
     182           0 :     bool MatchDelete(const DnsItem &rhs) const {
     183           0 :         if ((rhs.eclass == DNS_CLASS_ANY || rhs.eclass == DNS_CLASS_NONE) &&
     184           0 :             (rhs.type == DNS_TYPE_ANY || type == rhs.type) &&
     185           0 :             (name == rhs.name) &&
     186           0 :             (rhs.data.size() == 0 || data == rhs.data) &&
     187           0 :             (source_name == rhs.source_name))
     188           0 :             return true;
     189           0 :         return false;
     190             :     }
     191             : };
     192             : 
     193             : typedef std::list<DnsItem> DnsItems;
     194           0 : static inline std::string DnsItemsToString(DnsItems &items) {
     195           0 :     std::string str;
     196           0 :     for (DnsItems::iterator it = items.begin();
     197           0 :          !items.empty() && it != items.end(); ++it) {
     198           0 :         str += (*it).ToString();
     199             :     }
     200           0 :     return str;
     201           0 : }
     202             : 
     203             : struct DnsUpdateData {
     204             :     typedef boost::function<void(DnsItem &)> DeleteCallback;
     205             : 
     206             :     std::string virtual_dns;
     207             :     std::string zone;
     208             :     mutable DnsItems items;
     209             : 
     210          23 :     DnsUpdateData() {}
     211             :     DnsUpdateData(const std::string &vdns, const std::string &z)
     212             :                 : virtual_dns(vdns), zone(z) {}
     213             : 
     214             :     struct Compare {
     215           0 :         bool operator() (DnsUpdateData *const &lhs, DnsUpdateData *const &rhs) const {
     216           0 :             if (!lhs || !rhs)
     217           0 :                 return false;
     218           0 :             if (lhs->virtual_dns != rhs->virtual_dns)
     219           0 :                 return lhs->virtual_dns < rhs->virtual_dns;
     220           0 :             return lhs->zone < rhs->zone;
     221             :         }
     222             :     };
     223             : 
     224           0 :     bool AddItem(DnsItem &item, bool replace = false) const {
     225           0 :         for (DnsItems::iterator it = items.begin(); it != items.end(); ++it) {
     226           0 :             if (item == *it) {
     227           0 :                 if (replace)
     228           0 :                     *it = item;
     229           0 :                 return false;
     230             :             }
     231             :         }
     232           0 :         items.push_back(item);
     233           0 :         return true;
     234             :     }
     235             : 
     236           0 :     bool DelItem(DnsItem &item) const {
     237           0 :         bool change = false;
     238           0 :         for (DnsItems::iterator it = items.begin(); it != items.end();) {
     239           0 :             if ((*it).MatchDelete(item)) {
     240           0 :                 items.erase(it++);
     241           0 :                 change = true;
     242             :             } else {
     243           0 :                 ++it;
     244             :             }
     245             :         }
     246           0 :         return change;
     247             :     }
     248             : };
     249             : 
     250             : typedef std::vector<std::string> ZoneList;
     251             : 
     252             : struct Subnet {
     253             :     IpAddress prefix;
     254             :     uint32_t plen;
     255             :     uint8_t flags;
     256             : 
     257             :     enum DnsConfigFlags {
     258             :         DeleteMarked = 1 << 0,
     259             :     };
     260             : 
     261          10 :     Subnet() : plen(0), flags(0) {}
     262          43 :     Subnet(std::string addr, uint32_t len) : plen(len), flags(0) {
     263          43 :         boost::system::error_code ec;
     264          43 :         prefix = boost::asio::ip::address::from_string(addr, ec);
     265          43 :     }
     266             : 
     267             :     bool operator< (const Subnet &rhs) const;
     268             : 
     269           4 :     void MarkDelete() { flags |= DeleteMarked; }
     270         283 :     bool IsDeleted() const { return (flags & DeleteMarked); }
     271             :     void ClearDelete() { flags &= ~DeleteMarked; }
     272             : 
     273             :     void GetReverseZones(ZoneList &zones) const;
     274             : 
     275             :     bool Contains(const IpAddress &addr) const;
     276             : };
     277             : 
     278             : typedef std::vector<Subnet> Subnets;
     279             : 
     280             : class BindUtil {
     281             : public:
     282             :     enum Operation {
     283             :         ADD_UPDATE,
     284             :         CHANGE_UPDATE,
     285             :         DELETE_UPDATE
     286             :     };
     287             : 
     288             :     static uint16_t DnsClass(const std::string &cl);
     289             :     static std::string DnsClass(uint16_t cl);
     290             :     static uint16_t DnsType(const std::string &tp);
     291             :     static std::string DnsType(uint16_t tp);
     292             :     static const std::string &DnsResponseCode(uint16_t code);
     293             :     static uint8_t *AddName(uint8_t *ptr, const std::string &addr,
     294             :                             uint16_t plen, uint16_t offset, uint16_t &length);
     295             :     static bool ParseDnsQuery(uint8_t *dns, uint16_t dnslen,
     296             :                               uint16_t *parsed_length, DnsItems &items);
     297             :     static bool ParseDnsResponse(uint8_t *dns, uint16_t dnslen, uint16_t &xid,
     298             :                                  dns_flags &flags, DnsItems &ques,
     299             :                                  DnsItems &ans, DnsItems &auth, DnsItems &add);
     300             :     static bool ParseDnsUpdate(uint8_t *dns, uint16_t dnslen,
     301             :                                DnsUpdateData &data);
     302             :     static int BuildDnsQuery(uint8_t *buf, uint16_t xid,
     303             :                              const std::string &domain,
     304             :                              const DnsItems &items);
     305             :     static int BuildDnsUpdate(uint8_t *buf, Operation op, uint16_t xid,
     306             :                               const std::string &domain,
     307             :                               const std::string &zone,
     308             :                               const DnsItems &items);
     309             :     static uint8_t *AddQuestionSection(uint8_t *ptr, const std::string &name,
     310             :                                        uint16_t type, uint16_t cl,
     311             :                                        uint16_t &length);
     312             :     static uint8_t *AddAnswerSection(uint8_t *ptr, const DnsItem &item,
     313             :                                      uint16_t &length);
     314             :     static uint8_t *AddUpdate(uint8_t *ptr, const DnsItem &item,
     315             :                              uint16_t cl, uint32_t ttl, uint16_t &length);
     316             :     static void BuildDnsHeader(dnshdr *dns, uint16_t xid, DnsReq req,
     317             :                                DnsOpcode op, bool rd, bool ra, uint8_t ret,
     318             :                                uint16_t ques_count);
     319             : 
     320           6 :     static inline uint16_t DataLength(uint16_t plen, uint16_t offset,
     321             :                                       uint16_t size) {
     322           6 :         return (offset ? (plen ? plen + 2 + 1 : 2) : (size ? size + 2 : 1));
     323             :     }
     324             :     static bool IsIP(const std::string &name, IpAddress &addr);
     325             :     static bool IsReverseZone(const std::string &name);
     326             :     static void GetReverseZoneList(const IpAddress &mask, uint32_t plen,
     327             :                                    ZoneList &zones);
     328             :     // DnsProto::SendUpdateDnsEntry() needs the following two methods...
     329             :     static void GetReverseZone(const Ip4Address &addr, uint32_t plen,
     330             :                                std::string &zone);
     331             :     static void GetReverseZone(const Ip6Address &addr, uint32_t plen,
     332             :                                std::string &zone);
     333             :     static void GetReverseZone(const IpAddress &addr, uint32_t plen,
     334             :                                std::string &zone);
     335             :     static bool GetAddrFromPtrName(std::string &ptr_name, IpAddress &mask);
     336             :     // ...and these two as well.
     337             :     static std::string GetPtrNameFromAddr(const Ip4Address &ip);
     338             :     static std::string GetPtrNameFromAddr(const Ip6Address &ip6);
     339             :     static std::string GetFQDN(const std::string &name, const std::string &domain,
     340             :                                const std::string &match);
     341             :     static bool HasSpecialChars(const std::string &name);
     342             :     static void RemoveSpecialChars(std::string &name);
     343             : private:
     344             : 
     345             :     static inline bool ReadByte(uint8_t *dns, uint16_t dnslen, int *remlen,
     346             :                                 uint8_t &value) {
     347             :         if (*remlen < 1) {
     348             :             return false;
     349             :         }
     350             :         uint8_t *ptr = dns + (dnslen - *remlen);
     351             :         *remlen -= 1;
     352             :         value = *(uint8_t *) ptr;
     353             :         return true;
     354             :     }
     355             : 
     356          83 :     static inline bool ReadShort(uint8_t *dns, uint16_t dnslen, int *remlen,
     357             :                                  uint16_t &value) {
     358          83 :         if (*remlen < 2) {
     359           0 :             return false;
     360             :         }
     361          83 :         uint8_t *ptr = dns + (dnslen - *remlen);
     362          83 :         *remlen -= 2;
     363          83 :         value = ntohs(*(uint16_t *) ptr);
     364          83 :         return true;
     365             :     }
     366             : 
     367          31 :     static inline bool ReadWord(uint8_t *dns, uint16_t dnslen, int *remlen,
     368             :                                 uint32_t &value) {
     369          31 :         if (*remlen < 4) {
     370           0 :             return false;
     371             :         }
     372          31 :         uint8_t *ptr = dns + (dnslen - *remlen);
     373          31 :         *remlen -= 4;
     374          31 :         value = ntohl(*(uint32_t *) ptr);
     375          31 :         return true;
     376             :     }
     377             : 
     378          38 :     static inline uint8_t *WriteByte(uint8_t *ptr, uint8_t value) {
     379          38 :         *(uint8_t *) ptr = value;
     380          38 :         ptr += 1;
     381             : 
     382          38 :         return ptr;
     383             :     }
     384             : 
     385          83 :     static inline uint8_t *WriteShort(uint8_t *ptr, uint16_t value) {
     386          83 :         *(uint16_t *) ptr = htons(value);
     387          83 :         ptr += 2;
     388             : 
     389          83 :         return ptr;
     390             :     }
     391             : 
     392          31 :     static inline uint8_t *WriteWord(uint8_t *ptr, uint32_t value) {
     393          31 :         *(uint32_t *) ptr = htonl(value);
     394          31 :         ptr += 4;
     395             : 
     396          31 :         return ptr;
     397             :     }
     398             :     static uint8_t *AddData(uint8_t *ptr, const DnsItem &item,
     399             :                             uint16_t &length);
     400             :     static uint8_t *AddAdditionalSection(uint8_t *ptr, const std::string name,
     401             :                                          uint16_t type, uint16_t cl,
     402             :                                          uint32_t ttl, const std::string &data,
     403             :                                          uint16_t &length);
     404             :     static bool ReadName(uint8_t *dns, uint16_t dnslen, int *remlen,
     405             :                          std::string &name, uint16_t &plen, uint16_t &offset);
     406             :     static bool ReadData(uint8_t *dns, uint16_t dnslen, int *remlen,
     407             :                          DnsItem &item);
     408             :     static bool ReadQuestionEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
     409             :                                   DnsItem &item);
     410             :     static bool ReadAnswerEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
     411             :                                 DnsItem &item);
     412             :     static bool IsReverseZoneV4(const std::string &name);
     413             :     static bool IsReverseZoneV6(const std::string &name);
     414             :     static void GetReverseZoneList(const Ip4Address &mask, uint32_t plen,
     415             :                                    ZoneList &zones);
     416             :     static void GetReverseZoneList(const Ip6Address &mask, uint32_t plen,
     417             :                                    ZoneList &zones);
     418             :     static bool GetAddrFromPtrName(std::string &ptr_name,
     419             :                                    Ip4Address &ip);
     420             :     static bool GetAddrFromPtrName(std::string &ptr_name,
     421             :                                    Ip6Address &ip);
     422             :     static uint8_t GetNibble(const Ip6Address::bytes_type &addr,
     423             :                              size_t bit);
     424             :     static std::string BuildIp6ArpaSuffix(const Ip6Address::bytes_type &addr,
     425             :                                           uint32_t plen);
     426             : };
     427             : 
     428             : // Identify the offsets for names in a DNS message
     429             : class DnsNameEncoder {
     430             : public:
     431             :     struct Name {
     432             :         std::string name;
     433             :         uint16_t offset;
     434           0 :         Name(std::string &n, uint16_t oset) : name(n), offset(oset) {}
     435             :     };
     436             : 
     437          30 :     DnsNameEncoder() {};
     438          30 :     virtual ~DnsNameEncoder() {};
     439             :     void AddName(std::string &name, uint16_t curr_msg_offset,
     440             :                  uint16_t &name_plen, uint16_t &name_offset);
     441             : 
     442             : private:
     443             :     bool IsPresent(std::string &name, uint16_t &name_offset);
     444             : 
     445             :     std::vector<Name> names_;
     446             :     DISALLOW_COPY_AND_ASSIGN(DnsNameEncoder);
     447             : };
     448             : 
     449             : #endif // __bind_util_h__

Generated by: LCOV version 1.14