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

Generated by: LCOV version 1.14