LCOV - code coverage report
Current view: top level - vnsw/agent/services - dns_handler.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 750 0.0 %
Date: 2026-06-18 01:51:13 Functions: 0 38 0.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 <stdint.h>
       6             : #include "base/os.h"
       7             : #include "vr_defs.h"
       8             : #include "base/address_util.h"
       9             : #include "oper/interface_common.h"
      10             : #include "services/dns_proto.h"
      11             : #include "services/dhcp_proto.h"
      12             : #include "bind/bind_resolver.h"
      13             : #include "cmn/agent_cmn.h"
      14             : #include "controller/controller_dns.h"
      15             : #include "base/timer.h"
      16             : #include "oper/operdb_init.h"
      17             : #include "oper/global_vrouter.h"
      18             : #include "oper/vn.h"
      19             : 
      20           0 : DnsHandler::DnsHandler(Agent *agent, boost::shared_ptr<PktInfo> info,
      21           0 :                        boost::asio::io_context &io)
      22           0 :     : ProtoHandler(agent, info, io), resp_ptr_(NULL), dns_resp_size_(0),
      23           0 :       xid_(-1), action_(NONE), rkey_(NULL),
      24           0 :       query_name_update_(false), pend_req_(0), default_method_(false),
      25           0 :       curr_index_(0) {
      26           0 :     dns_ = (dnshdr *) pkt_info_->data;
      27           0 : }
      28             : 
      29           0 : DnsHandler::~DnsHandler() {
      30           0 :     for (ResolvList::iterator it = resolv_list_.begin();
      31           0 :          it != resolv_list_.end(); ++it) {
      32           0 :         delete *it;
      33             :     }
      34           0 :     if (rkey_) {
      35           0 :         delete rkey_;
      36             :     }
      37             : 
      38           0 :     uint8_t count = 0;
      39           0 :     while (count < dns_resolvers_.size()) {
      40           0 :         if (dns_resolvers_[count]) {
      41           0 :             dns_resolvers_[count]->timer_->Cancel();
      42           0 :             TimerManager::DeleteTimer(dns_resolvers_[count]->timer_);
      43           0 :             delete dns_resolvers_[count];
      44             :         }
      45           0 :         count++;
      46             :     }
      47           0 :     count = 0;
      48           0 :     while (count < def_dns_resolvers_.size()) {
      49           0 :         if (def_dns_resolvers_[count]) {
      50           0 :             def_dns_resolvers_[count]->timer_->Cancel();
      51           0 :             TimerManager::DeleteTimer(def_dns_resolvers_[count]->timer_);
      52           0 :             delete def_dns_resolvers_[count];
      53             :         }
      54           0 :         count++;
      55             :     }
      56             : 
      57           0 :     dns_resolvers_.clear();
      58           0 :     def_dns_resolvers_.clear();
      59           0 : }
      60             : 
      61             : 
      62           0 : void DnsHandler::BuildDnsResolvers() {
      63             : 
      64           0 :     uint8_t count = 0;
      65           0 :     uint8_t resolvers_count = Agent::GetInstance()->GetDnslist().size();
      66           0 :     dns_resolvers_.resize(resolvers_count);
      67             : 
      68           0 :     std::vector<string>dns_servers;
      69           0 :     while (count < resolvers_count) {
      70             : 
      71           0 :         boost::split(dns_servers, Agent::GetInstance()->GetDnslist()[count],
      72           0 :                      boost::is_any_of(":"));
      73           0 :         DnsResolverInfo *resolver = new DnsResolverInfo();
      74             : 
      75           0 :         boost::system::error_code ec;
      76           0 :         resolver->ep_.address(AddressFromString(dns_servers[0], &ec));
      77           0 :         assert(ec.value() == 0);
      78           0 :         uint16_t dns_port = DNS_SERVER_PORT;
      79           0 :         if (dns_servers.size() > 1)
      80           0 :             dns_port = strtoul(dns_servers[1].c_str(), NULL, 10);
      81           0 :         resolver->ep_.port(dns_port);
      82           0 :         resolver->retries_ = 0;
      83           0 :         std::stringstream ss;
      84           0 :         ss << "DnsHandlerTimer " << count;
      85           0 :         resolver->timer_ = TimerManager::CreateTimer(
      86           0 :                 *(agent()->event_manager()->io_service()), ss.str(),
      87             :                 TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
      88             :                 PktHandler::DNS);
      89           0 :         dns_resolvers_[count] = resolver;
      90             : 
      91           0 :         count++;
      92           0 :     }
      93           0 : }
      94             : 
      95           0 : void DnsHandler::BuildDefaultDnsResolvers() {
      96           0 :     uint8_t count = 0;
      97           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
      98           0 :     std::vector<IpAddress> const &def_slist = dns_proto->GetDefaultServerList();
      99           0 :     def_dns_resolvers_.resize(def_slist.size());
     100           0 :     while (count < def_slist.size()) {
     101           0 :         DnsResolverInfo *resolver = new DnsResolverInfo();
     102             : 
     103           0 :         resolver->ep_.address(def_slist[count]);
     104           0 :         resolver->ep_.port(DNS_SERVER_PORT);
     105           0 :         resolver->retries_ = 0;
     106           0 :         std::stringstream ss;
     107           0 :         ss << "DefDnsHandlerTimer " << count;
     108           0 :         resolver->timer_ = TimerManager::CreateTimer(
     109           0 :             *(agent()->event_manager()->io_service()), ss.str(),
     110             :             TaskScheduler::GetInstance()->GetTaskId("Agent::Services"),
     111             :             PktHandler::DNS);
     112           0 :         def_dns_resolvers_[count] = resolver;
     113           0 :         count++;
     114           0 :     }
     115           0 : }
     116             : 
     117           0 : bool DnsHandler::Run() {
     118           0 :     switch(pkt_info_->type) {
     119           0 :         case PktType::MESSAGE:
     120           0 :             return HandleMessage();
     121             : 
     122           0 :        default:
     123           0 :             return HandleRequest();
     124             :     }
     125             : }
     126             : 
     127           0 : bool DnsHandler::HandleRequest() {
     128           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     129           0 :     dns_proto->IncrStatsReq();
     130             : 
     131           0 :     uint16_t ret = DNS_ERR_NO_ERROR;
     132             :     const Interface *itf =
     133           0 :         agent()->interface_table()->FindInterface(GetInterfaceIndex());
     134           0 :     if (!itf || (itf->type() != Interface::VM_INTERFACE) ||
     135           0 :         dns_->flags.req) {
     136           0 :         dns_proto->IncrStatsDrop();
     137           0 :         DNS_BIND_TRACE(DnsBindError, "Received Invalid DNS request - dropping"
     138             :                        << "; itf = " << itf << "; flags.req = "
     139             :                        << dns_->flags.req << "; src addr = "
     140             :                        << pkt_info_->ip->ip_src.s_addr <<";");
     141           0 :         return true;
     142             :     }
     143             : 
     144           0 :     const VmInterface *vmitf = static_cast<const VmInterface *>(itf);
     145           0 :     if (!vmitf->layer3_forwarding()) {
     146           0 :         DNS_BIND_TRACE(DnsBindError, "DNS request on VM port with disabled"
     147             :                        "ipv4 service: " << itf);
     148           0 :         dns_proto->IncrStatsDrop();
     149           0 :         return true;
     150             :     }
     151             :     // Handle requests (req == 0), queries (op code == 0), updates, non auth
     152           0 :     if ((dns_->flags.op && dns_->flags.op != DNS_OPCODE_UPDATE) ||
     153           0 :         (dns_->flags.cd)) {
     154           0 :         DNS_BIND_TRACE(DnsBindError, "Unimplemented DNS request"
     155             :                        << "; flags.op = " << dns_->flags.op << "; flags.cd = "
     156             :                        << dns_->flags.cd << ";");
     157           0 :         ret = DNS_ERR_NO_IMPLEMENT;
     158           0 :         goto error;
     159             :     }
     160             : 
     161           0 :     if (!vmitf->vn() ||
     162           0 :         (pkt_info_->ip_saddr.is_v4() &&
     163           0 :          !vmitf->vn()->GetIpamData(vmitf->primary_ip_addr(),
     164           0 :                                    &ipam_name_, &ipam_type_)) ||
     165           0 :         (pkt_info_->ip_saddr.is_v6() &&
     166           0 :          !vmitf->vn()->GetIpamData(vmitf->primary_ip6_addr(),
     167             :                                    &ipam_name_, &ipam_type_))) {
     168           0 :         DNS_BIND_TRACE(DnsBindError, "Unable to find Ipam data; interface = "
     169             :                        << vmitf->name());
     170           0 :         ret = DNS_ERR_SERVER_FAIL;
     171           0 :         goto error;
     172             :     }
     173             : 
     174           0 :     if (ipam_type_.ipam_dns_method == "default-dns-server" ||
     175           0 :         ipam_type_.ipam_dns_method == "") {
     176           0 :         BuildDefaultDnsResolvers();
     177           0 :         if (dns_->flags.op == DNS_OPCODE_UPDATE) {
     178           0 :             DNS_BIND_TRACE(DnsBindError, "Default DNS request : Update received, ignoring");
     179           0 :             ret = DNS_ERR_NO_IMPLEMENT;
     180           0 :             goto error;
     181             :         }
     182           0 :         GetDomainName(vmitf, &domain_name_);
     183           0 :         default_method_ = true;
     184           0 :         return HandleDefaultDnsRequest(vmitf);
     185           0 :     } else if (ipam_type_.ipam_dns_method == "virtual-dns-server") {
     186           0 :         BuildDnsResolvers();
     187           0 :         if (!agent()->domain_config_table()->GetVDns(ipam_type_.ipam_dns_server.
     188           0 :             virtual_dns_server_name, &vdns_type_)) {
     189           0 :             DNS_BIND_TRACE(DnsBindError, "Unable to find domain; interface = "
     190             :                            << vmitf->vm_name());
     191           0 :             ret = DNS_ERR_SERVER_FAIL;
     192           0 :             goto error;
     193             :         }
     194           0 :         domain_name_ = vdns_type_.domain_name;
     195           0 :         default_method_ = false;
     196           0 :         return HandleVirtualDnsRequest(vmitf);
     197           0 :     } else if (ipam_type_.ipam_dns_method == "none") {
     198           0 :         DNS_BIND_TRACE(DnsBindError, "No DNS support for the VM : "
     199             :                         << "ipam_dns_method set to none, ignoring request");
     200           0 :         ret = DNS_ERR_SERVER_FAIL;
     201           0 :         goto error;
     202             :     }
     203             : 
     204           0 :     ret = DNS_ERR_SERVER_FAIL;
     205           0 : error:
     206           0 :     BindUtil::BuildDnsHeader(dns_, ntohs(dns_->xid), DNS_QUERY_RESPONSE,
     207             :                              DNS_OPCODE_QUERY, 0, 1, ret,
     208           0 :                              ntohs(dns_->ques_rrcount));
     209           0 :     SendDnsResponse();
     210           0 :     return true;
     211             : }
     212             : 
     213           0 : bool DnsHandler::HandleDefaultDnsRequest(const VmInterface *vmitf) {
     214           0 :     std::scoped_lock lock(mutex_);
     215           0 :     uint16_t ret = DNS_ERR_NO_ERROR;
     216           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     217           0 :     rkey_ = new QueryKey(vmitf, dns_->xid);
     218           0 :     if (dns_proto->IsVmRequestDuplicate(rkey_)) {
     219           0 :         DNS_BIND_TRACE(DnsBindTrace,
     220             :                        "Retry DNS query from VM - dropping; interface = "
     221             :                        << vmitf->vm_name() << " xid = " << dns_->xid);
     222           0 :         dns_proto->IncrStatsRetransmitReq();
     223           0 :         return true;
     224             :     }
     225           0 :     dns_proto->AddVmRequest(rkey_);
     226             : 
     227           0 :     if (BindUtil::ParseDnsQuery((uint8_t *)dns_,
     228           0 :                                 pkt_info_->GetUdpPayloadLength(),
     229           0 :                                 &dns_resp_size_, items_) == false) {
     230           0 :         DNS_BIND_TRACE(DnsBindTrace, "Default DNS query parsing failed; "
     231             :                        "interface = " << vmitf->vm_name() << " xid = " <<
     232             :                        dns_->xid);
     233           0 :         return true;
     234             :     }
     235             : 
     236           0 :     resp_ptr_ = (uint8_t *)dns_ + dns_resp_size_;
     237           0 :     BindUtil::BuildDnsHeader(dns_, ntohs(dns_->xid), DNS_QUERY_RESPONSE,
     238             :                              DNS_OPCODE_QUERY, 0, 1, DNS_ERR_NO_ERROR,
     239           0 :                              ntohs(dns_->ques_rrcount));
     240           0 :     ResolveAllLinkLocalRequests();
     241           0 :     if (!items_.size()) {
     242             :         // no pending resolution, send response
     243           0 :         dns_->ans_rrcount = htons(dns_->ans_rrcount);
     244           0 :         DefaultDnsSendResponse();
     245           0 :         dns_proto->DelVmRequest(rkey_);
     246           0 :         return true;
     247             :     }
     248             : 
     249           0 :     if (!def_dns_resolvers_.size()) {
     250           0 :         DNS_BIND_TRACE(DnsBindTrace, "No DNS resolvers for Default DNS query"
     251             :                        " with xid = " << dns_->xid << ";interface = "
     252             :                        << vmitf->vm_name());
     253           0 :         ret = DNS_ERR_SERVER_FAIL;
     254           0 :         goto fail;
     255             :     }
     256             : 
     257           0 :     DNS_BIND_TRACE(DnsBindTrace, "Default DNS query received; "
     258             :                    "interface = " << vmitf->vm_name() << " xid = " <<
     259             :                    dns_->xid << " " << DnsItemsToString(items_));
     260             : 
     261           0 :     action_ = DnsHandler::DNS_QUERY;
     262           0 :     curr_index_ = 0;
     263           0 :     if (SendToDefaultServer()) {
     264           0 :         return false;
     265             :     }
     266             : 
     267           0 :     DNS_BIND_TRACE(DnsBindTrace, "Unable to send DNS query to resolvers;"
     268             :                    " xid = " << dns_->xid << "; interface = "
     269             :                    << vmitf->vm_name());
     270           0 :     ret = DNS_ERR_SERVER_FAIL;
     271           0 : fail:
     272           0 :     BindUtil::BuildDnsHeader(dns_, ntohs(dns_->xid), DNS_QUERY_RESPONSE,
     273             :                              DNS_OPCODE_QUERY, 0, 1, ret,
     274           0 :                              ntohs(dns_->ques_rrcount));
     275           0 :     SendDnsResponse();
     276           0 :     dns_proto->DelVmRequest(rkey_);
     277           0 :     return true;
     278           0 : }
     279             : 
     280           0 : void DnsHandler::DefaultDnsSendResponse() {
     281           0 :     agent()->GetDnsProto()->DelVmRequest(rkey_);
     282           0 :     if (dns_->flags.ret) {
     283           0 :         DNS_BIND_TRACE(DnsBindError, "Query failed : " <<
     284             :                        BindUtil::DnsResponseCode(dns_->flags.ret) <<
     285             :                        " xid = " << dns_->xid << " " <<
     286             :                        DnsItemsToString(items_) <<
     287             :                        DnsItemsToString(linklocal_items_));
     288             :     } else {
     289           0 :         DNS_BIND_TRACE(DnsBindTrace, "Query successful : xid = " <<
     290             :                        dns_->xid << " " << DnsItemsToString(items_) <<
     291             :                        DnsItemsToString(linklocal_items_));
     292             :     }
     293           0 :     SendDnsResponse();
     294           0 : }
     295             : 
     296           0 : bool DnsHandler::HandleVirtualDnsRequest(const VmInterface *vmitf) {
     297           0 :     rkey_ = new QueryKey(vmitf, dns_->xid);
     298           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     299           0 :     if (dns_proto->IsVmRequestDuplicate(rkey_)) {
     300           0 :         DNS_BIND_TRACE(DnsBindTrace,
     301             :                        "Retry DNS query from VM - dropping; interface = " <<
     302             :                        vmitf->vm_name() << " xid = " << dns_->xid << " " <<
     303             :                        DnsItemsToString(items_) <<
     304             :                        DnsItemsToString(linklocal_items_));
     305           0 :         dns_proto->IncrStatsRetransmitReq();
     306           0 :         return true;
     307             :     }
     308           0 :     dns_proto->AddVmRequest(rkey_);
     309             : 
     310           0 :     BindUtil::RemoveSpecialChars(ipam_type_.ipam_dns_server.
     311           0 :                                  virtual_dns_server_name);
     312             : 
     313           0 :     uint16_t ret = DNS_ERR_NO_ERROR;
     314           0 :     switch (dns_->flags.op) {
     315           0 :         case DNS_OPCODE_QUERY: {
     316           0 :             if (BindUtil::ParseDnsQuery((uint8_t *)dns_,
     317           0 :                                         pkt_info_->GetUdpPayloadLength(),
     318           0 :                                         &dns_resp_size_, items_) == false) {
     319           0 :                 DNS_BIND_TRACE(DnsBindTrace, "vDNS query parsing failed; "
     320             :                                "interface = " << vmitf->vm_name() << " xid = " <<
     321             :                                dns_->xid);
     322           0 :                 break;
     323             :             }
     324           0 :             resp_ptr_ = (uint8_t *)dns_ + dns_resp_size_;
     325           0 :             BindUtil::BuildDnsHeader(dns_, ntohs(dns_->xid), DNS_QUERY_RESPONSE,
     326             :                                      DNS_OPCODE_QUERY, 0, 1, ret,
     327           0 :                                      ntohs(dns_->ques_rrcount));
     328             :             // Check for linklocal service name resolution
     329           0 :             ResolveAllLinkLocalRequests();
     330           0 :             if (!items_.size()) {
     331             :                 // no pending resolution, send response
     332           0 :                 dns_->ans_rrcount = htons(dns_->ans_rrcount);
     333           0 :                 SendDnsResponse();
     334           0 :                 break;
     335             :             }
     336           0 :             UpdateQueryNames();
     337             : 
     338           0 :             uint8_t count = 0;
     339           0 :             bool query_success = false;
     340             : 
     341           0 :             action_ = DnsHandler::DNS_QUERY;
     342           0 :             while (count < dns_resolvers_.size()) {
     343           0 :                 if (dns_resolvers_[count]) {
     344           0 :                     uint16_t xid = dns_proto->GetTransId();
     345           0 :                     if (SendDnsQuery(dns_resolvers_[count], xid) == true) {
     346           0 :                         dns_proto->AddDnsQueryIndex(xid, count);
     347           0 :                         query_success = true;
     348             :                     }
     349             :                 }
     350           0 :                 count++;
     351             :             }
     352           0 :             if (query_success) {
     353             :                 // atleast one query sent succesful, do not delete request yet.
     354           0 :                 return false;
     355             :             }
     356           0 :             break;
     357             :         }
     358             : 
     359           0 :         case DNS_OPCODE_UPDATE: {
     360           0 :             if (vdns_type_.dynamic_records_from_client) {
     361           0 :                 DnsUpdateData *update_data = new DnsUpdateData();
     362             :                 DnsProto::DnsUpdateIpc *update =
     363             :                     new DnsProto::DnsUpdateIpc(DnsAgentXmpp::Update,
     364           0 :                                                update_data, vmitf, false);
     365           0 :                 if (BindUtil::ParseDnsUpdate((uint8_t *)dns_,
     366           0 :                                              pkt_info_->GetUdpPayloadLength(),
     367             :                                              *update_data)) {
     368             :                     update_data->virtual_dns = ipam_type_.ipam_dns_server.
     369           0 :                                                virtual_dns_server_name;
     370           0 :                     Update(update);
     371             :                 } else {
     372           0 :                     delete update;
     373           0 :                     ret = DNS_ERR_NO_IMPLEMENT;
     374             :                 }
     375             :             } else {
     376           0 :                 DNS_BIND_TRACE(DnsBindTrace, "Client not allowed to update "
     377             :                 "dynamic records : " << vmitf->vm_name() << " ;Ignoring "
     378             :                 "update for " << DnsItemsToString(items_));
     379           0 :                 ret = DNS_ERR_NOT_AUTH;
     380             :             }
     381           0 :             BindUtil::BuildDnsHeader(dns_, ntohs(dns_->xid), DNS_QUERY_RESPONSE,
     382             :                                      DNS_OPCODE_UPDATE, 0, 1, ret,
     383           0 :                                      ntohs(dns_->ques_rrcount));
     384           0 :             SendDnsResponse();
     385           0 :             break;
     386             :         }
     387             : 
     388           0 :         default: {
     389           0 :             DNS_BIND_TRACE(DnsBindTrace, "Unsupported op : " << dns_->flags.op
     390             :                            << "from vm : " << vmitf->vm_name());
     391           0 :             break;
     392             :         }
     393             :     }
     394             : 
     395           0 :     dns_proto->DelVmRequest(rkey_);
     396           0 :     return true;
     397             : }
     398             : 
     399           0 : bool DnsHandler::SendDnsQuery(DnsResolverInfo *resolver,
     400             :                               uint16_t xid) {
     401           0 :     uint8_t *pkt = NULL;
     402           0 :     std::size_t len = 0;
     403           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     404           0 :     bool in_progress = dns_proto->IsDnsQueryInProgress(xid);
     405           0 :     if (in_progress) {
     406           0 :         if (resolver->retries_ >= dns_proto->max_retries()) {
     407           0 :             DNS_BIND_TRACE(DnsBindTrace,
     408             :                            "Max retries reached for query; xid = " << xid <<
     409             :                            " " << DnsItemsToString(items_));
     410           0 :             goto cleanup;
     411             :         } else {
     412           0 :             resolver->retries_++;
     413             :         }
     414             :     } else {
     415           0 :         dns_proto->AddDnsQuery(xid, this);
     416             :     }
     417             : 
     418           0 :     pkt = new uint8_t[BindResolver::max_pkt_size];
     419           0 :     if (!default_method_) {
     420           0 :         len = BindUtil::BuildDnsQuery(pkt, xid,
     421           0 :                   ipam_type_.ipam_dns_server.virtual_dns_server_name, items_);
     422             :     } else {
     423           0 :         len = BindUtil::BuildDnsQuery(pkt, xid, "", items_);
     424             :     }
     425           0 :     if (BindResolver::Resolver()->DnsSend(pkt, resolver->ep_, len)) {
     426           0 :         DNS_BIND_TRACE(DnsBindTrace, "DNS query sent to named server : " <<
     427             :                        resolver->ep_.address().to_string() << "; xid =" <<
     428             :                        xid << " " << DnsItemsToString(items_));
     429           0 :         resolver->timer_->Cancel();
     430           0 :         resolver->timer_->Start(dns_proto->timeout(),
     431             :             boost::bind(&DnsHandler::TimerExpiry, this, xid));
     432           0 :         return true;
     433             :     }
     434             : 
     435           0 : cleanup:
     436           0 :     dns_proto->IncrStatsDrop();
     437           0 :     dns_proto->DelDnsQuery(xid);
     438           0 :     dns_proto->DelDnsQueryIndex(xid);
     439           0 :     return false;
     440             : }
     441             : 
     442             : // Check the request against configured link local services and
     443             : // update DnsItems, if found
     444           0 : bool DnsHandler::ResolveLinkLocalRequest(DnsItems::iterator &item,
     445             :                                          DnsItems *linklocal_items) const {
     446           0 :     GlobalVrouter *global_vrouter = agent_->oper_db()->global_vrouter();
     447             : 
     448           0 :     switch (item->type) {
     449             : 
     450           0 :     case DNS_A_RECORD: {
     451           0 :         std::string base_name;
     452           0 :         GetBaseName(item->name, &base_name);
     453           0 :         std::set<IpAddress> service_ips;
     454           0 :         if (global_vrouter->FindLinkLocalService(item->name, &service_ips) ||
     455           0 :             (!base_name.empty() &&
     456           0 :              global_vrouter->FindLinkLocalService(base_name, &service_ips))) {
     457           0 :             for (std::set<IpAddress>::iterator it = service_ips.begin();
     458           0 :                  it != service_ips.end(); ++it) {
     459           0 :                 item->data = it->to_string();
     460           0 :                 linklocal_items->push_back(*item);
     461             :             }
     462             :         }
     463           0 :         break;
     464           0 :     }
     465             : 
     466           0 :     case DNS_PTR_RECORD: {
     467           0 :         std::set<std::string> service_names;
     468           0 :         boost::asio::ip::address addr;
     469           0 :         if (!BindUtil::GetAddrFromPtrName(item->name, addr) ||
     470           0 :             !addr.is_v4()) {
     471             :             // TODO: Support link-local services on IPv6 links.
     472           0 :             break;
     473             :         }
     474           0 :         if (global_vrouter->FindLinkLocalService(
     475           0 :                 addr.to_v4(), &service_names)) {
     476           0 :             for (std::set<std::string>::iterator it = service_names.begin();
     477           0 :                  it != service_names.end(); ++it) {
     478           0 :                 item->data = *it;
     479           0 :                 linklocal_items->push_back(*item);
     480             :             }
     481             :         }
     482           0 :         break;
     483           0 :     }
     484             : 
     485           0 :     case DNS_AAAA_RECORD:
     486           0 :         break;
     487             : 
     488           0 :     default:
     489           0 :         break;
     490             : 
     491             :     }
     492             : 
     493           0 :     return (linklocal_items->size() > 0);
     494             : }
     495             : 
     496             : // Resolve link local service name requests locally
     497           0 : bool DnsHandler::ResolveAllLinkLocalRequests() {
     498           0 :     bool linklocal_request = false;
     499           0 :     for (DnsItems::iterator it = items_.begin(); it != items_.end(); ) {
     500           0 :         DnsItems linklocal_items;
     501           0 :         if (ResolveLinkLocalRequest(it, &linklocal_items)) {
     502           0 :             linklocal_request = true;
     503           0 :             for (DnsItems::iterator llit = linklocal_items.begin();
     504           0 :                  llit != linklocal_items.end(); ++llit) {
     505           0 :                 resp_ptr_ = BindUtil::AddAnswerSection(resp_ptr_, *llit,
     506           0 :                                                        dns_resp_size_);
     507           0 :                 dns_->ans_rrcount++;
     508             :             }
     509             :             // storing the link local items in a different list
     510           0 :             linklocal_items_.splice(linklocal_items_.begin(), linklocal_items);
     511           0 :             items_.erase(it++);
     512             :         } else {
     513           0 :             it++;
     514             :         }
     515           0 :     }
     516           0 :     return linklocal_request;
     517             : }
     518             : 
     519           0 : bool DnsHandler::HandleMessage() {
     520           0 :     switch (pkt_info_->ipc->cmd) {
     521           0 :         case DnsProto::DNS_DEFAULT_RESPONSE:
     522           0 :             return HandleDefaultDnsResponse();
     523             : 
     524           0 :         case DnsProto::DNS_BIND_RESPONSE:
     525           0 :             return HandleBindResponse();
     526             : 
     527           0 :         case DnsProto::DNS_TIMER_EXPIRED:
     528           0 :             return HandleRetryExpiry();
     529             : 
     530           0 :         case DnsProto::DNS_XMPP_SEND_UPDATE:
     531           0 :             return HandleUpdate();
     532             : 
     533           0 :         case DnsProto::DNS_XMPP_MODIFY_VDNS:
     534           0 :             return HandleModifyVdns();
     535             : 
     536           0 :         case DnsProto::DNS_XMPP_UPDATE_RESPONSE:
     537           0 :             return HandleUpdateResponse();
     538             : 
     539           0 :         case DnsProto::DNS_XMPP_SEND_UPDATE_ALL:
     540           0 :             return UpdateAll();
     541             : 
     542           0 :         default:
     543           0 :             DNS_BIND_TRACE(DnsBindError, "Invalid internal DNS message : " <<
     544             :                            pkt_info_->ipc->cmd);
     545           0 :             return true;
     546             :     }
     547             : }
     548             : 
     549           0 : bool DnsHandler::HandleDefaultDnsResponse() {
     550           0 :     DnsProto::DnsIpc *ipc = static_cast<DnsProto::DnsIpc *>(pkt_info_->ipc);
     551           0 :     ipc->handler->DefaultDnsSendResponse();
     552           0 :     delete ipc;
     553           0 :     return true;
     554             : }
     555             : 
     556           0 : bool DnsHandler::HandleBindResponse() {
     557           0 :     DnsProto::DnsIpc *ipc = static_cast<DnsProto::DnsIpc *>(pkt_info_->ipc);
     558           0 :     uint16_t xid = ntohs(*(uint16_t *)ipc->resp);
     559           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     560           0 :     DnsHandler *handler = dns_proto->GetDnsQueryHandler(xid);
     561           0 :     bool valid_response = false;
     562           0 :     if (handler) {
     563             :         dns_flags flags;
     564           0 :         DnsItems ques, ans, auth, add;
     565           0 :         if (BindUtil::ParseDnsResponse(ipc->resp, ipc->length, xid, flags,
     566             :                                        ques, ans, auth, add)) {
     567           0 :             switch(handler->action_) {
     568           0 :                 case DnsHandler::DNS_QUERY:
     569           0 :                     if (flags.ret) {
     570           0 :                         DNS_BIND_TRACE(DnsBindError, "Query failed : " <<
     571             :                                        BindUtil::DnsResponseCode(flags.ret) <<
     572             :                                        " xid = " << xid << " " <<
     573             :                                        DnsItemsToString(items_) <<
     574             :                                        DnsItemsToString(linklocal_items_));
     575             :                     } else {
     576           0 :                         valid_response = true;
     577           0 :                         handler->Resolve(flags, ques, ans, auth, add);
     578           0 :                         DNS_BIND_TRACE(DnsBindTrace,
     579             :                                        "Query successful : xid = " <<
     580             :                                        xid << " " << DnsItemsToString(ans) <<
     581             :                                        DnsItemsToString(linklocal_items_));
     582             :                     }
     583           0 :                     break;
     584             : 
     585           0 :                 default:
     586           0 :                     DNS_BIND_TRACE(DnsBindTrace,
     587             :                                    "Invalid DNS action: xid = " << xid);
     588           0 :                     break;
     589             :             }
     590             :         } else {
     591           0 :             DNS_BIND_TRACE(DnsBindTrace,
     592             :                            "Received invalid BIND response: xid = " << xid);
     593             :         }
     594             : 
     595           0 :         dns_proto->DelDnsQuery(xid);
     596           0 :         dns_proto->DelDnsQueryIndex(xid);
     597             : 
     598           0 :         if (valid_response) {
     599           0 :             dns_proto->DelDnsQueryHandler(handler);
     600             :             /* Delete Request on first valid Response from named Server */
     601           0 :             dns_proto->DelVmRequest(handler->rkey_);
     602           0 :             delete handler;
     603             :         } else {
     604           0 :             if (!handler->DefaultMethodInUse()) {
     605           0 :                 if (!dns_proto->IsDnsHandlerInUse(handler)) {
     606           0 :                     HandleInvalidBindResponse(handler, flags, ques, ans, auth,
     607             :                                               add, xid);
     608             :                 }
     609             :             } else {
     610           0 :                 if (NeedRetryForNextServer(flags.ret)) {
     611             :                     /* Try sending query to next available server */
     612           0 :                     handler->IncrCurrIndex();
     613           0 :                     if (!handler->SendToDefaultServer()) {
     614             :                         /* Sending query to next server failed, send invalid
     615             :                          * response to client
     616             :                          */
     617           0 :                         HandleInvalidBindResponse(handler, flags, ques, ans,
     618             :                                                   auth, add, xid);
     619             :                     }
     620             :                 } else {
     621             :                     /* Retry is not required, send invalid response to client */
     622           0 :                     HandleInvalidBindResponse(handler, flags, ques, ans, auth,
     623             :                                               add, xid);
     624             :                 }
     625             :             }
     626             :         }
     627           0 :     } else {
     628           0 :         DNS_BIND_TRACE(DnsBindError, "Invalid or Response ignored xid " << xid <<
     629             :                        " received from DNS server - dropping");
     630           0 :         dns_proto->DelDnsQueryIndex(xid);
     631             :     }
     632             : 
     633           0 :     delete ipc;
     634           0 :     return true;
     635             : }
     636             : 
     637           0 : void DnsHandler::HandleInvalidBindResponse(DnsHandler *handler, dns_flags flags,
     638             :                                            const DnsItems &ques, DnsItems &ans,
     639             :                                            DnsItems &auth, DnsItems &add,
     640             :                                            uint16_t xid) {
     641           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     642           0 :     if (flags.ret) {
     643             :         /* Send last invalid response to requesting VM */
     644           0 :         handler->Resolve(flags, ques, ans, auth, add);
     645           0 :         DNS_BIND_TRACE(DnsBindTrace,
     646             :                        "Send invalid BIND response: xid = " << xid);
     647             :     } else {
     648           0 :         DNS_BIND_TRACE(DnsBindTrace,
     649             :                        "No response sent: xid = " << xid);
     650             :     }
     651             :     /* Delete Request on last invalid Response from named Server */
     652           0 :     dns_proto->DelVmRequest(handler->rkey_);
     653           0 :     delete handler;
     654           0 : }
     655             : 
     656           0 : bool DnsHandler::NeedRetryForNextServer(uint16_t code) {
     657             :    /*
     658             :     * Try next server for following response codes: server_failure(2),
     659             :     * Non-existent domain(3), Not implemented(4), Query refused(5),
     660             :     * Not Authorized(9)
     661             :     */
     662           0 :    if ((code > 1 && code < 6) || code == 9) {
     663           0 :        return true;
     664             :    }
     665           0 :    return false;
     666             : }
     667             : 
     668           0 : bool DnsHandler::SendToDefaultServer() {
     669           0 :     if (curr_index() > last_index()) {
     670           0 :         return false;
     671             :     }
     672           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     673           0 :     uint16_t xid = dns_proto->GetTransId();
     674             :     DnsResolverInfo *resolver;
     675           0 :     while (curr_index() <= last_index()) {
     676           0 :        resolver = def_dns_resolvers_[curr_index()];
     677           0 :        if (!SendDnsQuery(resolver, xid)) {
     678           0 :            IncrCurrIndex();
     679             :        } else {
     680             :            /* Query sent succesfully */
     681           0 :            return true;
     682             :        }
     683             :     }
     684           0 :     return false;
     685             : }
     686             : 
     687           0 : bool DnsHandler::HandleRetryExpiry() {
     688           0 :     DnsProto::DnsIpc *ipc = static_cast<DnsProto::DnsIpc *>(pkt_info_->ipc);
     689           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     690           0 :     uint16_t xid = ipc->xid;
     691           0 :     DnsHandler *handler = dns_proto->GetDnsQueryHandler(xid);
     692           0 :     if (handler) {
     693             :         DnsResolverInfo *resolver;
     694           0 :         if (handler->DefaultMethodInUse()) {
     695           0 :             resolver = handler->def_dns_resolvers_[handler->curr_index()];
     696           0 :             if (!handler->SendDnsQuery(resolver, xid)) {
     697             :                 // Try sending query to next available server
     698           0 :                 handler->IncrCurrIndex();
     699           0 :                 if (!handler->SendToDefaultServer()) {
     700           0 :                     dns_proto->DelVmRequest(handler->rkey_);
     701           0 :                     delete handler;
     702             :                 }
     703             :             }
     704             :         } else {
     705           0 :             uint16_t idx = dns_proto->GetDnsQueryServerIndex(ipc->xid);
     706           0 :             resolver = handler->dns_resolvers_[idx];
     707           0 :             if (!handler->SendDnsQuery(resolver, xid)) {
     708           0 :                 if (!dns_proto->IsDnsHandlerInUse(handler)) {
     709           0 :                     dns_proto->DelVmRequest(handler->rkey_);
     710           0 :                     delete handler;
     711             :                 }
     712             :             }
     713             :         }
     714             :     }
     715           0 :     delete ipc;
     716           0 :     return true;
     717             : }
     718             : 
     719           0 : bool DnsHandler::HandleUpdateResponse() {
     720             :     DnsProto::DnsUpdateIpc *ipc =
     721           0 :         static_cast<DnsProto::DnsUpdateIpc *>(pkt_info_->ipc);
     722           0 :     delete ipc;
     723           0 :     return true;
     724             : }
     725             : 
     726           0 : bool DnsHandler::HandleUpdate() {
     727             :     DnsProto::DnsUpdateIpc *ipc =
     728           0 :         static_cast<DnsProto::DnsUpdateIpc *>(pkt_info_->ipc);
     729           0 :     if (!ipc->xmpp_data) {
     730           0 :         DelUpdate(ipc);
     731             :     } else {
     732           0 :         Update(ipc);
     733             :     }
     734           0 :     return true;
     735             : }
     736             : 
     737           0 : bool DnsHandler::HandleModifyVdns() {
     738             :     DnsProto::DnsUpdateIpc *ipc =
     739           0 :         static_cast<DnsProto::DnsUpdateIpc *>(pkt_info_->ipc);
     740           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
     741           0 :     std::vector<DnsProto::DnsUpdateIpc *> change_list;
     742           0 :     const DnsProto::DnsUpdateSet &update_set = dns_proto->update_set();
     743           0 :     for (DnsProto::DnsUpdateSet::const_iterator it = update_set.begin();
     744           0 :          it != update_set.end(); ++it) {
     745           0 :         if ((ipc->itf &&
     746           0 :              ((*it)->itf != ipc->itf || (*it)->floatingIp != ipc->floatingIp)) ||
     747           0 :             !((*it)->xmpp_data) || (*it)->xmpp_data->virtual_dns != ipc->old_vdns)
     748           0 :             continue;
     749             : 
     750           0 :         change_list.push_back(*it);
     751             :         // if the server ttl changes, we only readd with the new values
     752           0 :         if (!ipc->itf && ipc->new_vdns == ipc->old_vdns)
     753           0 :             continue;
     754             : 
     755           0 :         for (DnsItems::iterator item = (*it)->xmpp_data->items.begin();
     756           0 :              item != (*it)->xmpp_data->items.end(); ++item) {
     757             :             // in case of delete, set the class to NONE and ttl to 0
     758           0 :             (*item).eclass = DNS_CLASS_NONE;
     759           0 :             (*item).ttl = 0;
     760             :         }
     761           0 :         for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
     762           0 :             AgentDnsXmppChannel *channel = agent()->dns_xmpp_channel(i);
     763           0 :             SendXmppUpdate(channel, (*it)->xmpp_data);
     764             :         }
     765             :     }
     766           0 :     for (unsigned int i = 0; i < change_list.size(); i++) {
     767           0 :         dns_proto->DelUpdateRequest(change_list[i]);
     768           0 :         if (ipc->new_vdns.empty())
     769           0 :             delete change_list[i];
     770             :     }
     771           0 :     if (ipc->new_vdns.empty())
     772           0 :         goto done;
     773           0 :     for (unsigned int i = 0; i < change_list.size(); i++) {
     774           0 :         change_list[i]->xmpp_data->virtual_dns = ipc->new_vdns;
     775           0 :         std::string &zone = change_list[i]->xmpp_data->zone;
     776           0 :         if (zone.find(".in-addr.arpa") == std::string::npos &&
     777           0 :             zone.find(".ip6.arpa") == std::string::npos)
     778           0 :             zone = ipc->new_domain;
     779           0 :         for (DnsItems::iterator item = change_list[i]->xmpp_data->items.begin();
     780           0 :              item != change_list[i]->xmpp_data->items.end(); ++item) {
     781           0 :             (*item).eclass = DNS_CLASS_IN;
     782           0 :             (*item).ttl = ipc->ttl;
     783             :         }
     784           0 :         Update(change_list[i]);
     785             :     }
     786             : 
     787           0 : done:
     788           0 :     delete ipc;
     789           0 :     return true;
     790           0 : }
     791             : 
     792           0 : bool DnsHandler::UpdateAll() {
     793             :     DnsProto::DnsUpdateAllIpc *ipc =
     794           0 :         static_cast<DnsProto::DnsUpdateAllIpc *>(pkt_info_->ipc);
     795             :     const DnsProto::DnsUpdateSet &update_set =
     796           0 :         agent()->GetDnsProto()->update_set();
     797           0 :     for (DnsProto::DnsUpdateSet::const_iterator it = update_set.begin();
     798           0 :          it != update_set.end(); ++it) {
     799           0 :         SendXmppUpdate(ipc->channel, (*it)->xmpp_data);
     800             :     }
     801             : 
     802           0 :     delete ipc;
     803           0 :     return true;
     804             : }
     805             : 
     806           0 : void DnsHandler::SendXmppUpdate(AgentDnsXmppChannel *channel,
     807             :                                 DnsUpdateData *xmpp_data) {
     808           0 :     if (channel && agent_->is_dns_xmpp_channel(channel)) {
     809             :         // Split the request in case we have more data items
     810           0 :         DnsItems done, store;
     811           0 :         DnsItems::iterator first, last;
     812             : 
     813           0 :         uint32_t size = xmpp_data->items.size();
     814           0 :         store.swap(xmpp_data->items);
     815           0 :         for (uint32_t i = 0; i <= size / max_items_per_xmpp_msg; i++) {
     816           0 :             if (!store.size())
     817           0 :                 break;
     818             : 
     819           0 :             first = last = store.begin();
     820           0 :             if (store.size() > max_items_per_xmpp_msg)
     821           0 :                 std::advance(last, max_items_per_xmpp_msg);
     822             :             else
     823           0 :                 last = store.end();
     824           0 :             xmpp_data->items.splice(xmpp_data->items.begin(), store, first, last);
     825             : 
     826             :             uint8_t data[DnsAgentXmpp::max_dns_xmpp_msg_len];
     827           0 :             xid_ = agent()->GetDnsProto()->GetTransId();
     828           0 :             std::size_t len = 0;
     829           0 :             if ((len = DnsAgentXmpp::DnsAgentXmppEncode(channel->GetXmppChannel(),
     830             :                                                         DnsAgentXmpp::Update,
     831           0 :                                                         xid_, 0, xmpp_data,
     832           0 :                                                         data)) > 0) {
     833           0 :                 channel->SendMsg(data, len);
     834             :             }
     835             : 
     836           0 :             done.splice(done.end(), xmpp_data->items, xmpp_data->items.begin(),
     837           0 :                         xmpp_data->items.end());
     838             :         }
     839           0 :         xmpp_data->items.swap(done);
     840           0 :     }
     841           0 : }
     842             : 
     843             : void
     844           0 : DnsHandler::Resolve(dns_flags flags, const DnsItems &ques, DnsItems &ans,
     845             :                     DnsItems &auth, DnsItems &add) {
     846           0 :     for (DnsItems::iterator it = ans.begin(); it != ans.end(); ++it) {
     847           0 :         bool name_update_required = true;
     848             :         // Do not update dns response msg offset, for default dns case
     849           0 :         if (!DefaultMethodInUse()) {
     850             :             // find the matching entry in the request
     851           0 :             for (DnsItems::const_iterator item = items_.begin();
     852           0 :                 item != items_.end(); ++item) {
     853           0 :                 if (it->name == item->name && it->eclass == item->eclass) {
     854           0 :                     it->name_plen = item->name_plen;
     855           0 :                     it->name_offset = item->offset;
     856           0 :                     name_update_required = false;
     857           0 :                     break;
     858             :                 }
     859             :             }
     860             :         }
     861           0 :         UpdateOffsets(*it, name_update_required);
     862           0 :         resp_ptr_ = BindUtil::AddAnswerSection(resp_ptr_, *it, dns_resp_size_);
     863           0 :         dns_->ans_rrcount++;
     864             :     }
     865             : 
     866           0 :     for (DnsItems::iterator it = auth.begin(); it != auth.end(); ++it) {
     867           0 :         UpdateOffsets(*it, true);
     868           0 :         UpdateGWAddress(*it);
     869           0 :         resp_ptr_ = BindUtil::AddAnswerSection(resp_ptr_, *it, dns_resp_size_);
     870           0 :         dns_->auth_rrcount++;
     871             :     }
     872             : 
     873           0 :     for (DnsItems::iterator it = add.begin(); it != add.end(); ++it) {
     874           0 :         UpdateOffsets(*it, true);
     875           0 :         UpdateGWAddress(*it);
     876           0 :         resp_ptr_ = BindUtil::AddAnswerSection(resp_ptr_, *it, dns_resp_size_);
     877           0 :         dns_->add_rrcount++;
     878             :     }
     879             : 
     880           0 :     dns_->flags.ret = flags.ret;
     881           0 :     dns_->flags.auth = flags.auth;
     882           0 :     dns_->flags.ad = flags.ad;
     883           0 :     dns_->flags.ra = flags.ra;
     884           0 :     dns_->ans_rrcount = htons(dns_->ans_rrcount);
     885           0 :     dns_->auth_rrcount = htons(dns_->auth_rrcount);
     886           0 :     dns_->add_rrcount = htons(dns_->add_rrcount);
     887           0 :     SendDnsResponse();
     888           0 : }
     889             : 
     890           0 : void DnsHandler::SendDnsResponse() {
     891           0 :     PktInfo in_pkt_info = *pkt_info_.get();
     892             : 
     893           0 :     uint16_t buff_len = in_pkt_info.packet_buffer()->buffer_len();
     894           0 :     pkt_info_->AllocPacketBuffer(agent(), PktHandler::DNS, buff_len, 0);
     895           0 :     char *buff = (char *)pkt_info_->packet_buffer()->data();
     896           0 :     memset(buff, 0, buff_len);
     897           0 :     pkt_info_->vrf = in_pkt_info.vrf;
     898             : 
     899           0 :     uint16_t eth_type = ETHERTYPE_IP;
     900           0 :     if (in_pkt_info.ip == NULL)
     901           0 :         eth_type = ETHERTYPE_IPV6;
     902             : 
     903           0 :     MacAddress dest_mac(in_pkt_info.eth->ether_shost);
     904           0 :     pkt_info_->eth = (struct ether_header *)(buff);
     905           0 :     uint16_t eth_len = 0;
     906           0 :     eth_len += EthHdr(buff, buff_len, in_pkt_info.GetAgentHdr().ifindex,
     907             :                       agent()->vhost_interface()->mac(), dest_mac, eth_type);
     908             : 
     909           0 :     uint16_t data_len = dns_resp_size_;
     910             :     // fill in the response
     911           0 :     if (in_pkt_info.ip) {
     912             :         // IPv4 request
     913           0 :         in_addr_t src_ip = in_pkt_info.ip->ip_dst.s_addr;
     914           0 :         in_addr_t dest_ip = in_pkt_info.ip->ip_src.s_addr;
     915             : 
     916           0 :         pkt_info_->ip = (struct ip *)(buff + eth_len);
     917           0 :         pkt_info_->transp.udp = (struct udphdr *)
     918           0 :             ((uint8_t *)pkt_info_->ip + sizeof(struct ip));
     919             : 
     920           0 :         data_len += sizeof(udphdr);
     921           0 :         UdpHdr(data_len, src_ip, DNS_SERVER_PORT,
     922           0 :                dest_ip, ntohs(in_pkt_info.transp.udp->uh_sport));
     923           0 :         data_len += sizeof(struct ip);
     924           0 :         IpHdr(data_len, src_ip, dest_ip, IPPROTO_UDP,
     925             :               DEFAULT_IP_ID, DEFAULT_IP_TTL);
     926             : 
     927             :     } else {
     928             :         // IPv6 request
     929           0 :         Ip6Address src_ip = in_pkt_info.ip_daddr.to_v6();
     930           0 :         Ip6Address dest_ip = in_pkt_info.ip_saddr.to_v6();
     931             : 
     932           0 :         pkt_info_->ip6 = (struct ip6_hdr *)(buff + eth_len);
     933           0 :         pkt_info_->transp.udp = (struct udphdr *)
     934           0 :             ((uint8_t *)pkt_info_->ip6 + sizeof(struct ip6_hdr));
     935             : 
     936           0 :         data_len += sizeof(udphdr);
     937           0 :         UdpHdr(data_len, src_ip.to_bytes().data(),
     938           0 :                DNS_SERVER_PORT, dest_ip.to_bytes().data(),
     939           0 :                ntohs(in_pkt_info.transp.udp->uh_sport), IPPROTO_UDP);
     940             : 
     941           0 :         data_len += sizeof(struct ip6_hdr);
     942           0 :         Ip6Hdr(pkt_info_->ip6, data_len, IPPROTO_UDP, 64,
     943           0 :                src_ip.to_bytes().data(), dest_ip.to_bytes().data());
     944             :     }
     945             : 
     946           0 :     memcpy(((char *)pkt_info_->transp.udp + sizeof(udphdr)),
     947           0 :            ((char *)in_pkt_info.transp.udp + sizeof(udphdr)),
     948           0 :            dns_resp_size_);
     949             : 
     950           0 :     dns_resp_size_ += data_len + eth_len;
     951           0 :     pkt_info_->set_len(dns_resp_size_);
     952             : 
     953             :     PacketInterfaceKey key(
     954           0 :         boost::uuids::nil_uuid(), agent()->pkt_interface_name());
     955           0 :     Interface *pkt_itf = static_cast<Interface *>
     956           0 :                          (agent()->interface_table()->FindActiveEntry(&key));
     957           0 :     if (pkt_itf) {
     958           0 :         UpdateStats();
     959             :         uint32_t interface =
     960           0 :             (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
     961           0 :             pkt_info_->agent_hdr.cmd_param : GetInterfaceIndex();
     962             :         uint16_t command =
     963           0 :             (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
     964           0 :             (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH;
     965           0 :         Send(interface, pkt_info_->vrf, command, PktHandler::DNS);
     966             :     } else {
     967           0 :         agent()->GetDnsProto()->IncrStatsDrop();
     968             :     }
     969           0 : }
     970             : 
     971           0 : void DnsHandler::UpdateQueryNames() {
     972           0 :     for (DnsItems::iterator it = items_.begin(); it != items_.end(); ++it) {
     973             :         // do not append domain for empty string (request to root ns)
     974           0 :         if (it->name.size() == 0) {
     975           0 :             return;
     976             :         }
     977             : 
     978             :         // do not append domain in case of NS query
     979           0 :         if (it->type == DNS_NS_RECORD) {
     980           0 :             return;
     981             :         }
     982             : 
     983           0 :         if (it->name.find('.', 0) == std::string::npos) {
     984           0 :             it->name.append(".");
     985           0 :             it->name.append(vdns_type_.domain_name);
     986           0 :             query_name_update_ = true;
     987             :         }
     988             :     }
     989             : }
     990             : 
     991             : // In case we added domain name to the queries, the response to the VM
     992             : // should not have the domain name. Update the offsets in the DnsItems
     993             : // accordingly.
     994           0 : void DnsHandler::UpdateOffsets(DnsItem &item, bool name_update_required) {
     995           0 :     if (!query_name_update_)
     996           0 :         return;
     997             : 
     998           0 :     uint16_t msg_offset = (resp_ptr_ - (uint8_t *)dns_) | 0xC000;
     999           0 :     if (name_update_required) {
    1000           0 :         name_encoder_.AddName(item.name, msg_offset, item.name_plen,
    1001           0 :                               item.name_offset);
    1002             :     }
    1003           0 :     msg_offset += BindUtil::DataLength(item.name_plen, item.name_offset,
    1004           0 :                                        item.name.size()) + 10;
    1005           0 :     if (item.type == DNS_TYPE_SOA) {
    1006           0 :         name_encoder_.AddName(item.soa.primary_ns, msg_offset, item.soa.ns_plen,
    1007           0 :                               item.soa.ns_offset);
    1008           0 :         msg_offset += BindUtil::DataLength(item.soa.ns_plen, item.soa.ns_offset,
    1009           0 :                                            item.soa.primary_ns.size());
    1010           0 :         name_encoder_.AddName(item.soa.mailbox, msg_offset,
    1011           0 :                               item.soa.mailbox_plen, item.soa.mailbox_offset);
    1012             :     } else {
    1013           0 :         name_encoder_.AddName(item.data, msg_offset,
    1014           0 :                               item.data_plen, item.data_offset);
    1015             :     }
    1016             : }
    1017             : 
    1018           0 : void DnsHandler::UpdateGWAddress(DnsItem &item) {
    1019           0 :     boost::system::error_code ec;
    1020           0 :     if ((item.type == DNS_A_RECORD || item.type == DNS_AAAA_RECORD) &&
    1021           0 :         (item.data == agent()->dns_server(0) ||
    1022           0 :          item.data == agent()->dns_server(1))) {
    1023           0 :         item.data = pkt_info_->ip_daddr.to_string(ec);
    1024             :     }
    1025           0 : }
    1026             : 
    1027           0 : void DnsHandler::Update(InterTaskMsg *msg) {
    1028           0 :     DnsProto::DnsUpdateIpc *update = static_cast<DnsProto::DnsUpdateIpc *>(msg);
    1029           0 :     bool free_update = true;
    1030           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
    1031           0 :     DnsProto::DnsUpdateIpc *update_req = dns_proto->FindUpdateRequest(update);
    1032           0 :     if (update_req) {
    1033           0 :         DnsUpdateData *data = update_req->xmpp_data;
    1034           0 :         for (DnsItems::iterator item = update->xmpp_data->items.begin();
    1035           0 :              item != update->xmpp_data->items.end();) {
    1036           0 :             if ((*item).IsDelete()) {
    1037           0 :                 if (!data->DelItem(*item))
    1038           0 :                     update->xmpp_data->items.erase(item++);
    1039             :                 else
    1040           0 :                     ++item;
    1041             :             } else {
    1042           0 :                 if (!data->AddItem(*item))
    1043           0 :                     update->xmpp_data->items.erase(item++);
    1044             :                 else
    1045           0 :                     ++item;
    1046             :             }
    1047             :         }
    1048           0 :         if (!data->items.size()) {
    1049           0 :             dns_proto->DelUpdateRequest(update_req);
    1050           0 :             delete update_req;
    1051             :         }
    1052           0 :         if (!update->xmpp_data->items.size())
    1053           0 :             goto done;
    1054             :     } else {
    1055           0 :         dns_proto->AddUpdateRequest(update);
    1056           0 :         free_update = false;
    1057             :     }
    1058             : 
    1059           0 :     for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
    1060           0 :         AgentDnsXmppChannel *channel = agent()->dns_xmpp_channel(i);
    1061           0 :         SendXmppUpdate(channel, update->xmpp_data);
    1062             :     }
    1063             : 
    1064           0 : done:
    1065           0 :     if (free_update)
    1066           0 :         delete update;
    1067           0 : }
    1068             : 
    1069           0 : void DnsHandler::DelUpdate(InterTaskMsg *msg) {
    1070           0 :     DnsProto::DnsUpdateIpc *update = static_cast<DnsProto::DnsUpdateIpc *>(msg);
    1071           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
    1072           0 :     DnsProto::DnsUpdateIpc *update_req = dns_proto->FindUpdateRequest(update);
    1073           0 :     while (update_req) {
    1074           0 :         for (DnsItems::iterator item = update_req->xmpp_data->items.begin();
    1075           0 :              item != update_req->xmpp_data->items.end(); ++item) {
    1076             :             // in case of delete, set the class to NONE and ttl to 0
    1077           0 :             (*item).eclass = DNS_CLASS_NONE;
    1078           0 :             (*item).ttl = 0;
    1079             :         }
    1080           0 :         for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
    1081             :             AgentDnsXmppChannel *channel =
    1082           0 :                         agent()->dns_xmpp_channel(i);
    1083           0 :             SendXmppUpdate(channel, update_req->xmpp_data);
    1084             :         }
    1085           0 :         dns_proto->DelUpdateRequest(update_req);
    1086           0 :         delete update_req;
    1087           0 :         update_req = dns_proto->FindUpdateRequest(update);
    1088             :     }
    1089           0 :     delete update;
    1090           0 : }
    1091             : 
    1092           0 : void DnsHandler::UpdateStats() {
    1093           0 :     DnsProto *dns_proto = agent()->GetDnsProto();
    1094           0 :     switch (dns_->flags.ret) {
    1095           0 :         case DNS_ERR_NO_ERROR:
    1096           0 :             dns_proto->IncrStatsRes();
    1097           0 :             break;
    1098             : 
    1099           0 :         case DNS_ERR_NO_IMPLEMENT:
    1100           0 :             dns_proto->IncrStatsUnsupp();
    1101           0 :             break;
    1102             : 
    1103           0 :         case DNS_ERR_FORMAT_ERROR:
    1104             :         case DNS_ERR_NO_SUCH_NAME:
    1105             :         case DNS_ERR_SERVER_FAIL:
    1106             :         case DNS_ERR_NOT_AUTH:
    1107             :         default:
    1108           0 :             dns_proto->IncrStatsFail();
    1109           0 :             break;
    1110             :     }
    1111           0 : }
    1112             : 
    1113           0 : bool DnsHandler::TimerExpiry(uint16_t xid) {
    1114           0 :     agent()->GetDnsProto()->SendDnsIpc(DnsProto::DNS_TIMER_EXPIRED, xid,
    1115             :                                        NULL, NULL);
    1116           0 :     return false;
    1117             : }
    1118             : 
    1119           0 : void DnsHandler::GetDomainName(const VmInterface *vm_itf,
    1120             :                                std::string *domain_name) const {
    1121           0 :     std::vector<autogen::DhcpOptionType> options;
    1122           0 :     if (vm_itf->GetInterfaceDhcpOptions(&options)) {
    1123           0 :         if (GetDomainNameFromDhcp(options, domain_name))
    1124           0 :             return;
    1125             :     }
    1126             : 
    1127           0 :     if (pkt_info_->ip_saddr.is_v4()) {
    1128           0 :         if (vm_itf->GetSubnetDhcpOptions(&options, false) ||
    1129           0 :             vm_itf->GetIpamDhcpOptions(&options, false)) {
    1130           0 :             GetDomainNameFromDhcp(options, domain_name);
    1131           0 :             return;
    1132             :         }
    1133             :     }
    1134             : 
    1135           0 :     if (pkt_info_->ip_saddr.is_v6()) {
    1136           0 :         if (vm_itf->GetSubnetDhcpOptions(&options, true) ||
    1137           0 :             vm_itf->GetIpamDhcpOptions(&options, true)) {
    1138           0 :             GetDomainNameFromDhcp(options, domain_name);
    1139           0 :             return;
    1140             :         }
    1141             :     }
    1142           0 : }
    1143             : 
    1144           0 : bool DnsHandler::GetDomainNameFromDhcp(
    1145             :                     std::vector<autogen::DhcpOptionType> &options,
    1146             :                     std::string *domain_name) const {
    1147           0 :     for (unsigned int i = 0; i < options.size(); ++i) {
    1148             :         uint32_t option_type;
    1149           0 :         std::stringstream str(options[i].dhcp_option_name);
    1150           0 :         str >> option_type;
    1151           0 :         if (option_type == DHCP_OPTION_DOMAIN_NAME) {
    1152           0 :             *domain_name = options[i].dhcp_option_value;
    1153           0 :             return true;
    1154             :         }
    1155           0 :     }
    1156           0 :     return false;
    1157             : }
    1158             : 
    1159             : // remove domain name suffix from given name, if present
    1160           0 : void DnsHandler::GetBaseName(const std::string &name, std::string *base) const {
    1161           0 :     if (domain_name_.empty())
    1162           0 :         return;
    1163             : 
    1164           0 :     std::size_t pos = name.find(domain_name_, 1);
    1165           0 :     while (pos != std::string::npos) {
    1166           0 :         std::string base_name = name.substr(0, pos - 1);
    1167           0 :         if (name == base_name + "." + domain_name_ ||
    1168           0 :             name == base_name + "." + domain_name_ + ".") {
    1169           0 :             *base = base_name;
    1170           0 :             return;
    1171             :         }
    1172           0 :         pos = name.find(domain_name_, pos + 1);
    1173           0 :     }
    1174             : }
    1175             : 
    1176           0 : std::string DnsHandler::DnsItemsToString(DnsItems &items) const {
    1177           0 :     std::string str;
    1178           0 :     for (DnsItems::const_iterator it = items.begin(); it != items.end(); ++it) {
    1179           0 :         str.append(it->ToString());
    1180           0 :         str.append(" ");
    1181             :     }
    1182           0 :     return str;
    1183           0 : }

Generated by: LCOV version 1.14