LCOV - code coverage report
Current view: top level - dns/bind - bind_resolver.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 54 113 47.8 %
Date: 2026-11-09 02:10:49 Functions: 7 14 50.0 %
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/bind/bind.hpp>
       7             : #include <bind/bind_util.h>
       8             : #include <base/address_util.h>
       9             : #include <bind/bind_resolver.h>
      10             : 
      11             : using namespace boost::placeholders;
      12             : 
      13             : BindResolver *BindResolver::resolver_;
      14             : 
      15          17 : void BindResolver::Init(boost::asio::io_context &io,
      16             :                         const std::vector<DnsServer> &dns_servers,
      17             :                         uint16_t client_port, Callback cb, uint8_t dscp) {
      18          17 :     assert(resolver_ == NULL);
      19          17 :     resolver_ = new BindResolver(io, dns_servers, client_port, cb, dscp);
      20          17 : }
      21             : 
      22          17 : void BindResolver::Shutdown() {
      23          17 :     if (resolver_) {
      24          17 :         delete resolver_;
      25          17 :         resolver_ = NULL;
      26             :     }
      27          17 : }
      28             : 
      29          17 : BindResolver::BindResolver(boost::asio::io_context &io,
      30             :                            const std::vector<DnsServer> &dns_servers,
      31             :                            uint16_t client_port, Callback cb,
      32          17 :                            uint8_t dscp)
      33          17 :                : pkt_buf_(NULL), cb_(cb), sock_(io), dscp_value_(dscp) {
      34             : 
      35          17 :     boost::system::error_code ec;
      36          17 :     uint8_t size = (dns_servers.size() > max_dns_servers) ?
      37          17 :                     dns_servers.size() : max_dns_servers;
      38          17 :     dns_ep_.resize(size);
      39          34 :     for (unsigned int i = 0; i < dns_servers.size(); ++i) {
      40             :         boost::asio::ip::address dns_address(
      41          17 :             AddressFromString(dns_servers[i].ip_, &ec));
      42             :         boost::asio::ip::udp::endpoint *ep =
      43          17 :             new boost::asio::ip::udp::endpoint(dns_address, dns_servers[i].port_);
      44          17 :         assert (ec.value() == 0);
      45          17 :         dns_ep_[i] = ep;
      46             :     }
      47             : 
      48             :     boost::asio::ip::udp::endpoint local_ep(boost::asio::ip::address::
      49          34 :                                             from_string("0.0.0.0", ec),
      50          17 :                                             client_port);
      51          17 :     sock_.open(boost::asio::ip::udp::v4(), ec);
      52          17 :     assert(ec.value() == 0);
      53          17 :     sock_.bind(local_ep, ec);
      54          17 :     if (ec.value() != 0) {
      55          15 :         local_ep.port(0);
      56          15 :         sock_.bind(local_ep, ec);
      57          15 :         assert(ec.value() == 0);
      58             :     }
      59          17 :     if (dscp_value_) {
      60           0 :         SetDscpSocketOption();
      61             :     }
      62          17 :     AsyncRead();
      63          17 : }
      64             : 
      65           0 : void BindResolver::SetDscpSocketOption() {
      66             :     /* The dscp_value_ field is expected to have DSCP value between 0 and 63 ie
      67             :      * in the lower order 6 bits of a byte. However, setsockopt expects DSCP
      68             :      * value in upper 6 bits of a byte. Hence left shift the value by 2 digits
      69             :      * before passing it to setsockopt */
      70           0 :     uint8_t value = dscp_value_ << 2;
      71           0 :     int retval = setsockopt(sock_.native_handle(), IPPROTO_IP, IP_TOS,
      72             :                             reinterpret_cast<const char *>(&value), sizeof(value));
      73           0 :     if (retval < 0) {
      74           0 :         DNS_BIND_TRACE(DnsBindError, "Setting DSCP bits on socket failed for "
      75             :                        << dscp_value_ << " with errno " << strerror(errno));
      76             :     }
      77           0 : }
      78             : 
      79           0 : void BindResolver::SetDscpValue(uint8_t val) {
      80           0 :     dscp_value_ = val;
      81           0 :     SetDscpSocketOption();
      82           0 : }
      83             : 
      84           0 : uint8_t BindResolver::GetDscpValue() {
      85           0 :     uint8_t dscp = 0;
      86           0 :     unsigned int optlen = sizeof(dscp);
      87           0 :     int retval = getsockopt(sock_.native_handle(), IPPROTO_IP, IP_TOS,
      88             :                             reinterpret_cast<char *>(&dscp),
      89             :                             reinterpret_cast<socklen_t *>(&optlen));
      90           0 :     if (retval < 0) {
      91           0 :         DNS_BIND_TRACE(DnsBindError, "Getting DSCP bits on socket failed "
      92             :                        "with errno " << strerror(errno));
      93             :     }
      94           0 :     return dscp;
      95             : }
      96             : 
      97          34 : BindResolver::~BindResolver() {
      98          17 :     boost::system::error_code ec;
      99          17 :     sock_.cancel(ec);
     100          17 :     sock_.close(ec);
     101          51 :     for (unsigned int i = 0; i < dns_ep_.size(); ++i) {
     102          34 :         delete dns_ep_[i];
     103          34 :         dns_ep_[i] = NULL;
     104             :     }
     105          17 :     resolver_ = NULL;
     106          17 :     if (pkt_buf_) delete [] pkt_buf_;
     107          34 : }
     108             : 
     109           0 : void BindResolver::SetupResolver(const DnsServer &server, uint8_t idx) {
     110           0 :     if (idx >= max_dns_servers) {
     111           0 :         DNS_BIND_TRACE(DnsBindError, "BindResolver doesnt support more than " <<
     112             :                        max_dns_servers << " servers; ignoring request for " <<
     113             :                        idx);
     114           0 :         return;
     115             :     }
     116             : 
     117           0 :     if (idx < dns_ep_.size() && dns_ep_[idx]) {
     118           0 :         delete dns_ep_[idx];
     119           0 :         dns_ep_[idx] = NULL;
     120             :     }
     121             : 
     122           0 :     boost::system::error_code ec;
     123             :     boost::asio::ip::udp::endpoint *ep = new boost::asio::ip::udp::endpoint(
     124           0 :         AddressFromString(server.ip_, &ec), server.port_);
     125           0 :     assert (ec.value() == 0);
     126           0 :     dns_ep_[idx] = ep;
     127             : }
     128             : 
     129           0 : bool BindResolver::DnsSend(uint8_t *pkt, unsigned int dns_srv_index,
     130             :                            std::size_t len) {
     131           0 :     if (dns_srv_index < dns_ep_.size() && dns_ep_[dns_srv_index] && len > 0) {
     132           0 :         sock_.async_send_to(
     133           0 :               boost::asio::buffer(pkt, len), *dns_ep_[dns_srv_index],
     134           0 :               boost::bind(&BindResolver::DnsSendHandler, this,
     135             :                           boost::asio::placeholders::error,
     136             :                           boost::asio::placeholders::bytes_transferred, pkt));
     137           0 :         return true;
     138             :     } else {
     139           0 :         DNS_BIND_TRACE(DnsBindError, "Invalid server index: " << dns_srv_index
     140             :                        << ";");
     141           0 :         delete [] pkt;
     142           0 :         return false;
     143             :     }
     144             : }
     145             : 
     146           0 : bool BindResolver::DnsSend(uint8_t *pkt, boost::asio::ip::udp::endpoint ep,
     147             :                            std::size_t len) {
     148           0 :     if (len > 0) {
     149           0 :         sock_.async_send_to(
     150           0 :             boost::asio::buffer(pkt, len),ep,
     151           0 :             boost::bind(&BindResolver::DnsSendHandler, this,
     152             :                         boost::asio::placeholders::error,
     153             :                         boost::asio::placeholders::bytes_transferred, pkt));
     154           0 :         return true;
     155             :     } else {
     156           0 :         DNS_BIND_TRACE(DnsBindError, "Invalid length of packet: " << len
     157             :                        << ";");
     158           0 :         delete [] pkt;
     159           0 :         return false;
     160             :     }
     161             : }
     162             : 
     163           0 : void BindResolver::DnsSendHandler(const boost::system::error_code &error,
     164             :                                   std::size_t length, uint8_t *pkt) {
     165           0 :     if (error)
     166           0 :         DNS_BIND_TRACE(DnsBindError, "Error sending packet to DNS server : " <<
     167             :                        boost::system::system_error(error).what() << ";");
     168           0 :     delete [] pkt;
     169           0 : }
     170             : 
     171          17 : void BindResolver::AsyncRead() {
     172          17 :     pkt_buf_ = new uint8_t[max_pkt_size];
     173          17 :     sock_.async_receive(boost::asio::buffer(pkt_buf_, max_pkt_size),
     174          17 :                         boost::bind(&BindResolver::DnsRcvHandler, this,
     175             :                                     boost::asio::placeholders::error,
     176             :                                     boost::asio::placeholders::bytes_transferred));
     177          17 : }
     178             : 
     179           2 : void BindResolver::DnsRcvHandler(const boost::system::error_code &error,
     180             :                                  std::size_t length) {
     181           2 :     bool del = false;
     182           2 :     if (!error) {
     183           0 :         if (cb_)
     184           0 :             cb_(pkt_buf_, length);
     185             :         else
     186           0 :             del = true;
     187             :     } else {
     188           2 :         DNS_BIND_TRACE(DnsBindError, "Error receiving DNS response : " <<
     189             :                        boost::system::system_error(error).what() << ";");
     190           2 :         if (error.value() == boost::asio::error::operation_aborted) {
     191           2 :             return;
     192             :         }
     193           0 :         del = true;
     194             :     }
     195           0 :     if (del) delete [] pkt_buf_;
     196           0 :     pkt_buf_ = NULL;
     197           0 :     AsyncRead();
     198             : }

Generated by: LCOV version 1.14