]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/srvrec.cc
add GetSrvRecord helper to apt-pkg/contrib/srvrec.{cc,h}
[apt.git] / apt-pkg / contrib / srvrec.cc
CommitLineData
f106fecc
MV
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3/* ######################################################################
4
5 SRV record support
6
7 ##################################################################### */
8 /*}}}*/
9#include <config.h>
10
11#include <netinet/in.h>
12#include <arpa/nameser.h>
13#include <resolv.h>
14
15#include <apt-pkg/error.h>
16#include "srvrec.h"
17
18bool GetSrvRecords(std::string name, std::vector<SrvRec> &Result)
19{
20 unsigned char answer[PACKETSZ];
21 int answer_len, compressed_name_len;
22 int answer_count;
23
24 if (res_init() != 0)
25 return _error->Errno("res_init", "Failed to init resolver");
26
27 answer_len = res_query(name.c_str(), C_IN, T_SRV, answer, sizeof(answer));
28 if (answer_len < (int)sizeof(HEADER))
29 return _error->Warning("Not enough data from res_query (%i)", answer_len);
30
31 // check the header
32 HEADER *header = (HEADER*)answer;
33 if (header->rcode != NOERROR)
34 return _error->Warning("res_query returned rcode %i", header->rcode);
35 answer_count = ntohs(header->ancount);
36 if (answer_count <= 0)
37 return _error->Warning("res_query returned no answers (%i) ", answer_count);
38
39 // skip the header
40 compressed_name_len = dn_skipname(answer+sizeof(HEADER), answer+answer_len);
41 if(compressed_name_len < 0)
42 return _error->Warning("dn_skipname failed %i", compressed_name_len);
43
44 // pt points to the first answer record, go over all of them now
45 unsigned char *pt = answer+sizeof(HEADER)+compressed_name_len+QFIXEDSZ;
46 while ((int)Result.size() < answer_count && pt < answer+answer_len)
47 {
48 SrvRec rec;
49 u_int16_t type, klass, priority, weight, port, dlen;
50 char buf[MAXDNAME];
51
52 compressed_name_len = dn_skipname(pt, answer+answer_len);
53 if (compressed_name_len < 0)
54 return _error->Warning("dn_skipname failed (2): %i",
55 compressed_name_len);
56 pt += compressed_name_len;
57 if (((answer+answer_len) - pt) < 16)
58 return _error->Warning("packet too short");
59
60 // extract the data out of the result buffer
61 #define extract_u16(target, p) target = *p++ << 8; target |= *p++;
62
63 extract_u16(type, pt);
64 if(type != T_SRV)
65 return _error->Warning("Unexpected type excepted %x != %x",
66 T_SRV, type);
67 extract_u16(klass, pt);
68 if(klass != C_IN)
69 return _error->Warning("Unexpected class excepted %x != %x",
70 C_IN, klass);
71 pt += 4; // ttl
72 extract_u16(dlen, pt);
73 extract_u16(priority, pt);
74 extract_u16(weight, pt);
75 extract_u16(port, pt);
76
77 #undef extract_u16
78
79 compressed_name_len = dn_expand(answer, answer+answer_len, pt, buf, sizeof(buf));
80 if(compressed_name_len < 0)
81 return _error->Warning("dn_expand failed %i", compressed_name_len);
82 pt += compressed_name_len;
83
84 // add it to our class
85 rec.priority = priority;
86 rec.weight = weight;
87 rec.port = port;
88 rec.target = buf;
89 Result.push_back(rec);
90 }
91
92 return true;
93}