blob: 5bfa3d54f854677cae1582309f3018e0903c5c74 [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/*
3 * Copyright (c) 2014-2017, 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>
29#include <netinet/in.h>
30#include <resolv.h>
31#include <arpa/nameser.h>
32
33#ifdef __APPLE__
34#include <arpa/nameser_compat.h>
35#endif
36
37namespace ndn {
38namespace tools {
39namespace autoconfig {
40
Junxiao Shif748a4e2017-07-05 23:41:48 +000041union QueryAnswer
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080042{
43 HEADER header;
44 uint8_t buf[NS_PACKETSZ];
45};
46
Junxiao Shif748a4e2017-07-05 23:41:48 +000047/** \brief Parse SRV record
48 * \return FaceUri of the hub from the SRV record
49 * \throw DnsSrvError if SRV record cannot be parsed
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080050 */
Junxiao Shif748a4e2017-07-05 23:41:48 +000051static std::string
52parseSrvRr(const QueryAnswer& queryAnswer, int answerSize)
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080053{
54 // The references of the next classes are:
55 // http://www.diablotin.com/librairie/networking/dnsbind/ch14_02.htm
56
57 struct rechdr
58 {
59 uint16_t type;
60 uint16_t iclass;
61 uint32_t ttl;
62 uint16_t length;
63 };
64
65 struct srv_t
66 {
67 uint16_t priority;
68 uint16_t weight;
69 uint16_t port;
70 uint8_t* target;
71 };
72
73 if (ntohs(queryAnswer.header.ancount) == 0) {
Junxiao Shif748a4e2017-07-05 23:41:48 +000074 BOOST_THROW_EXCEPTION(DnsSrvError("SRV record cannot be parsed"));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080075 }
76
77 const uint8_t* blob = queryAnswer.buf + NS_HFIXEDSZ;
78
79 blob += dn_skipname(blob, queryAnswer.buf + answerSize) + NS_QFIXEDSZ;
80
81 char srvName[NS_MAXDNAME];
82 int serverNameSize = dn_expand(queryAnswer.buf, // message pointer
83 queryAnswer.buf + answerSize, // end of message
84 blob, // compressed server name
85 srvName, // expanded server name
86 NS_MAXDNAME);
87 if (serverNameSize <= 0) {
Junxiao Shif748a4e2017-07-05 23:41:48 +000088 BOOST_THROW_EXCEPTION(DnsSrvError("SRV record cannot be parsed (error decoding domain name)"));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -080089 }
90
91 const srv_t* server = reinterpret_cast<const srv_t*>(&blob[sizeof(rechdr)]);
92 uint16_t convertedPort = be16toh(server->port);
93
94 blob += serverNameSize + NS_HFIXEDSZ + NS_QFIXEDSZ;
95
96 char hostName[NS_MAXDNAME];
97 int hostNameSize = dn_expand(queryAnswer.buf, // message pointer
98 queryAnswer.buf + answerSize, // end of message
99 blob, // compressed host name
100 hostName, // expanded host name
101 NS_MAXDNAME);
102 if (hostNameSize <= 0) {
Junxiao Shif748a4e2017-07-05 23:41:48 +0000103 BOOST_THROW_EXCEPTION(DnsSrvError("SRV record cannot be parsed (error decoding host name)"));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800104 }
105
106 std::string uri = "udp://";
107 uri.append(hostName);
108 uri.append(":");
Davide Pesaventoec2a6982015-09-18 23:59:17 +0200109 uri.append(to_string(convertedPort));
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800110
111 return uri;
112}
113
Junxiao Shif748a4e2017-07-05 23:41:48 +0000114std::string
115querySrvRr(const std::string& fqdn)
116{
117 std::string srvDomain = "_ndn._udp." + fqdn;
118 std::cerr << "Sending DNS query for SRV record for " << srvDomain << std::endl;
119
120 res_init();
121
122 _res.retrans = 1;
123 _res.retry = 2;
124 _res.ndots = 10;
125
126 QueryAnswer queryAnswer;
127 int answerSize = res_query(srvDomain.data(),
128 ns_c_in,
129 ns_t_srv,
130 queryAnswer.buf,
131 sizeof(queryAnswer));
132 if (answerSize == 0) {
133 BOOST_THROW_EXCEPTION(DnsSrvError("No DNS SRV records found for " + srvDomain));
134 }
135 return parseSrvRr(queryAnswer, answerSize);
136}
137
138/**
139 * @brief Send DNS SRV request using search domain list
140 */
141std::string
142querySrvRrSearch()
143{
144 std::cerr << "Sending DNS query for SRV record for _ndn._udp" << std::endl;
145
146 QueryAnswer queryAnswer;
147
148 res_init();
149
150 _res.retrans = 1;
151 _res.retry = 2;
152 _res.ndots = 10;
153
154 int answerSize = res_search("_ndn._udp",
155 ns_c_in,
156 ns_t_srv,
157 queryAnswer.buf,
158 sizeof(queryAnswer));
159
160 if (answerSize == 0) {
161 BOOST_THROW_EXCEPTION(DnsSrvError("No DNS SRV records found for _ndn._udp"));
162 }
163
164 return parseSrvRr(queryAnswer, answerSize);
165}
166
Alexander Afanasyev2a655f72015-01-26 18:38:33 -0800167} // namespace autoconfig
168} // namespace tools
169} // namespace ndn