blob: bc0b3a64f7059643f398d86c76ce9c3bae44eb06 [file] [log] [blame]
Alexander Afanasyev2a655f72015-01-26 18:38:33 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shif748a4e2017-07-05 23:41:48 +00002/*
Davide Pesaventoe422f9e2022-06-03 01:30:23 -04003 * Copyright (c) 2014-2022, Regents of the University of California,
Alexander Afanasyev2a655f72015-01-26 18:38:33 -08004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
Junxiao Shif748a4e2017-07-05 23:41:48 +000026#include "dns-srv.hpp"
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080027
28#include <sys/types.h>
Davide Pesavento457f1352018-07-14 17:17:38 -040029#include <arpa/nameser.h>
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080030#include <netinet/in.h>
31#include <resolv.h>
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080032
33#ifdef __APPLE__
34#include <arpa/nameser_compat.h>
35#endif
36
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040037#include <ndn-cxx/util/backports.hpp>
38#include <ndn-cxx/util/exception.hpp>
39
Davide Pesaventoa997d292017-08-24 20:16:59 -040040#include <iostream>
41
Davide Pesavento457f1352018-07-14 17:17:38 -040042#include <boost/endian/conversion.hpp>
43
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040044namespace ndn::autoconfig {
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080045
Davide Pesavento457f1352018-07-14 17:17:38 -040046using namespace std::string_literals;
47
Junxiao Shif748a4e2017-07-05 23:41:48 +000048union QueryAnswer
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080049{
50 HEADER header;
51 uint8_t buf[NS_PACKETSZ];
52};
53
Junxiao Shif748a4e2017-07-05 23:41:48 +000054/** \brief Parse SRV record
55 * \return FaceUri of the hub from the SRV record
56 * \throw DnsSrvError if SRV record cannot be parsed
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080057 */
Junxiao Shif748a4e2017-07-05 23:41:48 +000058static std::string
59parseSrvRr(const QueryAnswer& queryAnswer, int answerSize)
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080060{
61 // The references of the next classes are:
62 // http://www.diablotin.com/librairie/networking/dnsbind/ch14_02.htm
63
64 struct rechdr
65 {
66 uint16_t type;
67 uint16_t iclass;
68 uint32_t ttl;
69 uint16_t length;
70 };
71
72 struct srv_t
73 {
74 uint16_t priority;
75 uint16_t weight;
76 uint16_t port;
77 uint8_t* target;
78 };
79
Davide Pesavento457f1352018-07-14 17:17:38 -040080 uint16_t ancount = queryAnswer.header.ancount;
81 if (boost::endian::big_to_native(ancount) == 0) {
Davide Pesavento19779d82019-02-14 13:40:04 -050082 NDN_THROW(DnsSrvError("SRV record cannot be parsed"));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080083 }
84
85 const uint8_t* blob = queryAnswer.buf + NS_HFIXEDSZ;
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080086 blob += dn_skipname(blob, queryAnswer.buf + answerSize) + NS_QFIXEDSZ;
87
88 char srvName[NS_MAXDNAME];
89 int serverNameSize = dn_expand(queryAnswer.buf, // message pointer
90 queryAnswer.buf + answerSize, // end of message
91 blob, // compressed server name
92 srvName, // expanded server name
93 NS_MAXDNAME);
94 if (serverNameSize <= 0) {
Davide Pesavento19779d82019-02-14 13:40:04 -050095 NDN_THROW(DnsSrvError("SRV record cannot be parsed (error decoding domain name)"));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080096 }
97
98 const srv_t* server = reinterpret_cast<const srv_t*>(&blob[sizeof(rechdr)]);
Davide Pesavento457f1352018-07-14 17:17:38 -040099 uint16_t port = boost::endian::big_to_native(server->port);
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800100
101 blob += serverNameSize + NS_HFIXEDSZ + NS_QFIXEDSZ;
102
103 char hostName[NS_MAXDNAME];
104 int hostNameSize = dn_expand(queryAnswer.buf, // message pointer
105 queryAnswer.buf + answerSize, // end of message
106 blob, // compressed host name
107 hostName, // expanded host name
108 NS_MAXDNAME);
109 if (hostNameSize <= 0) {
Davide Pesavento19779d82019-02-14 13:40:04 -0500110 NDN_THROW(DnsSrvError("SRV record cannot be parsed (error decoding host name)"));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800111 }
112
Davide Pesavento457f1352018-07-14 17:17:38 -0400113 return "udp://"s + hostName + ":" + to_string(port);
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800114}
115
Junxiao Shif748a4e2017-07-05 23:41:48 +0000116std::string
117querySrvRr(const std::string& fqdn)
118{
119 std::string srvDomain = "_ndn._udp." + fqdn;
120 std::cerr << "Sending DNS query for SRV record for " << srvDomain << std::endl;
121
122 res_init();
123
124 _res.retrans = 1;
125 _res.retry = 2;
126 _res.ndots = 10;
127
128 QueryAnswer queryAnswer;
129 int answerSize = res_query(srvDomain.data(),
130 ns_c_in,
131 ns_t_srv,
132 queryAnswer.buf,
133 sizeof(queryAnswer));
134 if (answerSize == 0) {
Davide Pesavento19779d82019-02-14 13:40:04 -0500135 NDN_THROW(DnsSrvError("No DNS SRV records found for " + srvDomain));
Junxiao Shif748a4e2017-07-05 23:41:48 +0000136 }
137 return parseSrvRr(queryAnswer, answerSize);
138}
139
140/**
141 * @brief Send DNS SRV request using search domain list
142 */
143std::string
144querySrvRrSearch()
145{
146 std::cerr << "Sending DNS query for SRV record for _ndn._udp" << std::endl;
147
148 QueryAnswer queryAnswer;
149
150 res_init();
151
152 _res.retrans = 1;
153 _res.retry = 2;
154 _res.ndots = 10;
155
156 int answerSize = res_search("_ndn._udp",
157 ns_c_in,
158 ns_t_srv,
159 queryAnswer.buf,
160 sizeof(queryAnswer));
161
162 if (answerSize == 0) {
Davide Pesavento19779d82019-02-14 13:40:04 -0500163 NDN_THROW(DnsSrvError("No DNS SRV records found for _ndn._udp"));
Junxiao Shif748a4e2017-07-05 23:41:48 +0000164 }
165
166 return parseSrvRr(queryAnswer, answerSize);
167}
168
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400169} // namespace ndn::autoconfig