Skip to content

Commit

Permalink
Add support for SRV DNS record type.
Browse files Browse the repository at this point in the history
Service Record type returns the hostname and port number of
servers providing a specified service.

0 1 80 api.rubygems.org.

Add testcase.

Change-Id: I2b8abde3fc6932f31af435e7182a6703ed4919d2
Closes-Bug:1577680
  • Loading branch information
nipak committed May 19, 2016
1 parent 8a12266 commit 26d3954
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/dns/bind/bind_util.cc
Expand Up @@ -17,6 +17,7 @@ DnsTypeMap g_dns_type_map = map_list_of<std::string, uint16_t>
("MX", 0x0F)
("TXT", 0x10)
("AAAA", 0x1C)
("SRV", 0x21)
("ANY", 0xFF);

DnsTypeNumMap g_dns_type_num_map = map_list_of<uint16_t, std::string>
Expand All @@ -28,6 +29,7 @@ DnsTypeNumMap g_dns_type_num_map = map_list_of<uint16_t, std::string>
(DNS_MX_RECORD, "MX")
(DNS_TXT_RECORD, "TXT")
(DNS_AAAA_RECORD, "AAAA")
(DNS_SRV_RECORD, "SRV")
(DNS_TYPE_ANY, "ANY");

DnsTypeNumMap g_dns_class_num_map = map_list_of<uint16_t, std::string>
Expand Down Expand Up @@ -192,6 +194,19 @@ uint8_t *BindUtil::AddData(uint8_t *ptr, const DnsItem &item,
ptr = WriteShort(ptr, item.priority);
ptr = AddName(ptr, item.data, item.data_plen, item.data_offset, length);
length += 2 + 2;
} else if (item.type == DNS_SRV_RECORD) {
uint16_t data_len = 6 + DataLength(item.srv.hn_plen, item.srv.hn_offset,
item.srv.hostname.size());
ptr = WriteShort(ptr, data_len);
ptr = WriteShort(ptr, item.srv.priority);
ptr = WriteShort(ptr, item.srv.weight);
ptr = WriteShort(ptr, item.srv.port);
ptr = AddName(ptr, item.srv.hostname, item.srv.hn_plen,
item.srv.hn_offset, length);
length += 2 + 6;
} else {
DNS_BIND_TRACE(DnsBindError,
"Unsupported record type in response : " << item.type);
}

return ptr;
Expand Down Expand Up @@ -319,6 +334,15 @@ bool BindUtil::ReadData(uint8_t *dns, uint16_t dnslen, int *remlen,
if (ReadShort(dns, dnslen, remlen, item.priority) == false)
return false;
return ReadName(dns, dnslen, remlen, item.data, item.data_plen, item.data_offset);
} else if (item.type == DNS_SRV_RECORD) {
if (ReadShort(dns, dnslen, remlen, item.srv.priority) == false)
return false;
if (ReadShort(dns, dnslen, remlen, item.srv.weight) == false)
return false;
if (ReadShort(dns, dnslen, remlen, item.srv.port) == false)
return false;
return ReadName(dns, dnslen, remlen, item.srv.hostname,
item.srv.hn_plen, item.srv.hn_offset);
}

DNS_BIND_TRACE(DnsBindError,
Expand Down
14 changes: 14 additions & 0 deletions src/dns/bind/bind_util.h
Expand Up @@ -40,6 +40,7 @@ do { \
#define DNS_MX_RECORD 0x0F
#define DNS_TXT_RECORD 0x10
#define DNS_AAAA_RECORD 0x1C
#define DNS_SRV_RECORD 0x21
#define DNS_TYPE_ANY 0x00ff

// DNS return codes
Expand Down Expand Up @@ -131,6 +132,18 @@ struct DnsSOAData {
}
};

// Data format in an SRV record
struct DnsSRVData {
uint16_t priority;
uint16_t weight;
uint16_t port;
std::string hostname;
uint16_t hn_plen; // length of the prefix in hostname that is unique
uint16_t hn_offset; // offset from where rest of hostname name exists

DnsSRVData() : hn_plen(0), hn_offset(0) {}
};

struct DnsItem {
uint16_t eclass;
uint16_t type;
Expand All @@ -144,6 +157,7 @@ struct DnsItem {
std::string name;
std::string data;
DnsSOAData soa;
DnsSRVData srv;

DnsItem() : eclass(1), type(0), ttl(0), priority(0), offset(0),
name_plen(0), name_offset(0), data_plen(0), data_offset(0), soa() {}
Expand Down
43 changes: 43 additions & 0 deletions src/dns/test/dns_bind_test.cc
Expand Up @@ -1057,6 +1057,49 @@ TEST_F(DnsBindTest, DnsUpdateErrorParse) {
EXPECT_FALSE(BindUtil::ParseDnsUpdate(buf, len, data));
}

// Check the parsing of a DNS SRV Response
TEST_F(DnsBindTest, DnsResponseSRVParse) {
uint8_t buf[1024];
int count = 1;
DnsItems ans_in, auth_in, add_in;

DnsItem item;
item.eclass = DNS_CLASS_IN;
item.type = DNS_SRV_RECORD;
item.ttl = 100;
item.name = "_rubygems._tcp.rubygems.org";
item.srv.priority = 0;
item.srv.weight = 1;
item.srv.port = 80;
item.srv.hostname = "api.rubygems.org";
ans_in.push_back(item);

dnshdr *dns = (dnshdr *) buf;
BindUtil::BuildDnsHeader(dns, 0x0102, DNS_QUERY_RESPONSE, DNS_OPCODE_QUERY,
0, 0, 0, 0);
dns->ques_rrcount = htons(count);
dns->ans_rrcount = htons(count);
dns->auth_rrcount = 0;
dns->add_rrcount = 0;

uint16_t len = sizeof(dnshdr);
uint8_t *ptr = (uint8_t *) (dns + 1);
for (int i = 0; i < count; i++)
ptr = BindUtil::AddQuestionSection(ptr, "_rubygems._tcp.rubygems.org",
DNS_SRV_RECORD, DNS_CLASS_IN, len);
for (DnsItems::iterator it = ans_in.begin(); it != ans_in.end(); it++)
ptr = BindUtil::AddAnswerSection(ptr, *it, len);

uint16_t xid;
dns_flags flags;
DnsItems ques, ans, auth, add;
EXPECT_TRUE(BindUtil::ParseDnsResponse(buf, len, xid, flags,
ques, ans, auth, add));
EXPECT_TRUE(ans == ans_in);
}



} // namespace

int main(int argc, char **argv) {
Expand Down

0 comments on commit 26d3954

Please sign in to comment.