Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #ifndef __bind_util_h__
6 : #define __bind_util_h__
7 :
8 : #include <iostream>
9 : #include <stdint.h>
10 : #include <vector>
11 : #include <boost/asio.hpp>
12 :
13 : #include "sandesh/sandesh_trace.h"
14 : #include "bind/bind_types.h"
15 : #include "bind/xmpp_dns_agent.h"
16 :
17 : #include "base/address.h"
18 : #include "base/address_util.h"
19 :
20 : extern SandeshTraceBufferPtr DnsBindTraceBuf;
21 : #define DNS_BIND_TRACE(obj, arg) \
22 : do { \
23 : std::ostringstream _str; \
24 : _str << arg; \
25 : obj::TraceMsg(DnsBindTraceBuf, __FILE__, __LINE__, _str.str()); \
26 : } while (false) \
27 :
28 : #define DNS_SERVER_PORT 53
29 :
30 : // DNS Class
31 : #define DNS_CLASS_IN 1
32 : #define DNS_CLASS_ANY 0x00ff
33 : #define DNS_CLASS_NONE 0x00fe
34 :
35 : // DNS record types
36 : #define DNS_A_RECORD 1
37 : #define DNS_NS_RECORD 2
38 : #define DNS_CNAME_RECORD 5
39 : #define DNS_TYPE_SOA 6
40 : #define DNS_PTR_RECORD 0x0C
41 : #define DNS_MX_RECORD 0x0F
42 : #define DNS_TXT_RECORD 0x10
43 : #define DNS_AAAA_RECORD 0x1C
44 : #define DNS_SRV_RECORD 0x21
45 : #define DNS_TYPE_ANY 0x00ff
46 :
47 : // DNS return codes
48 : #define DNS_ERR_NO_ERROR 0
49 : #define DNS_ERR_FORMAT_ERROR 1
50 : #define DNS_ERR_SERVER_FAIL 2
51 : #define DNS_ERR_NO_SUCH_NAME 3
52 : #define DNS_ERR_NO_IMPLEMENT 4
53 : #define DNS_ERR_NOT_AUTH 9
54 :
55 : enum DnsReq {
56 : DNS_QUERY_REQUEST = 0x0,
57 : DNS_QUERY_RESPONSE = 0x1,
58 : };
59 :
60 : enum DnsOpcode {
61 : DNS_OPCODE_QUERY = 0x0,
62 : DNS_OPCODE_STATUS = 0x2,
63 : DNS_OPCODE_NOTIFY = 0x04,
64 : DNS_OPCODE_UPDATE = 0x05,
65 : };
66 :
67 : typedef std::map<std::string, uint16_t> DnsTypeMap;
68 : typedef std::map<std::string, uint16_t>::const_iterator DnsTypeIter;
69 : typedef std::map<uint16_t, std::string> DnsTypeNumMap;
70 : typedef std::map<uint16_t, std::string>::const_iterator DnsTypeNumIter;
71 : typedef std::map<uint16_t, std::string> DnsResponseMap;
72 : typedef std::map<uint16_t, std::string>::const_iterator DnsResponseIter;
73 :
74 : struct dns_flags {
75 : #if __BYTE_ORDER == __LITTLE_ENDIAN
76 : uint8_t rd:1; // recursion desired
77 : uint8_t trunc:1; // truncated
78 : uint8_t auth:1; // authoritative answer
79 : uint8_t op:4; // opcode
80 : uint8_t req:1; // request / response
81 : uint8_t ret:4; // return code
82 : uint8_t cd:1; // checking disabled
83 : uint8_t ad:1; // answer authenticated
84 : uint8_t res:1; // reserved
85 : uint8_t ra:1; // recursion available
86 : #elif __BYTE_ORDER == __BIG_ENDIAN
87 : uint8_t req:1;
88 : uint8_t op:4;
89 : uint8_t auth:1;
90 : uint8_t trunc:1;
91 : uint8_t rd:1;
92 : uint8_t ra:1;
93 : uint8_t res:1;
94 : uint8_t ad:1;
95 : uint8_t cd:1;
96 : uint8_t ret:4;
97 : #else
98 : #error "Adjust your <bits/endian.h> defines"
99 : #endif
100 : };
101 :
102 : struct dnshdr {
103 : uint16_t xid;
104 : dns_flags flags;
105 : uint16_t ques_rrcount; // question RR count
106 : uint16_t ans_rrcount; // answer RR count
107 : uint16_t auth_rrcount; // authority RR count
108 : uint16_t add_rrcount; // additional RR count
109 : };
110 :
111 : // Data format in an SOA record
112 : struct DnsSOAData {
113 : std::string primary_ns; // primary name server
114 : std::string mailbox; // responsible authority's mailbox
115 : uint16_t ns_plen; // length of the prefix in primary_ns that is unique
116 : uint16_t ns_offset; // offset from where rest of primary_ns name exists
117 : uint16_t mailbox_plen;
118 : uint16_t mailbox_offset;
119 : uint32_t serial; // serial number
120 : uint32_t refresh; // refresh interval in seconds
121 : uint32_t retry; // retry interval in seconds
122 : uint32_t expiry; // expiration limit in seconds
123 : uint32_t ttl; // minimum ttl in seconds
124 :
125 1102 : DnsSOAData() : ns_plen(0), ns_offset(0), mailbox_plen(0), mailbox_offset(0),
126 551 : serial(0), refresh(0), retry(0), expiry(0), ttl(0) {}
127 34 : bool operator ==(const DnsSOAData &rhs) const {
128 68 : if (primary_ns == rhs.primary_ns && mailbox == rhs.mailbox &&
129 34 : serial == rhs.serial && refresh == rhs.refresh &&
130 68 : retry == rhs.retry && expiry == rhs.expiry && ttl == rhs.ttl)
131 34 : return true;
132 0 : return false;
133 : }
134 : };
135 :
136 : // Data format in an SRV record
137 : struct DnsSRVData {
138 : uint16_t priority;
139 : uint16_t weight;
140 : uint16_t port;
141 : std::string hostname;
142 : uint16_t hn_plen; // length of the prefix in hostname that is unique
143 : uint16_t hn_offset; // offset from where rest of hostname name exists
144 :
145 551 : DnsSRVData() : hn_plen(0), hn_offset(0) {}
146 : };
147 :
148 : struct DnsItem {
149 : uint16_t eclass;
150 : uint16_t type;
151 : uint32_t ttl;
152 : uint16_t priority;
153 : uint16_t offset; // offset of the name in the read request from the VM
154 : uint16_t name_plen; // length of the prefix in name that is unique
155 : uint16_t name_offset; // offset from where rest of name exists
156 : uint16_t data_plen; // length of the prefix in data that is unique
157 : uint16_t data_offset; // offset from where rest of data exists
158 : std::string name;
159 : std::string source_name;
160 : std::string data;
161 : DnsSOAData soa;
162 : DnsSRVData srv;
163 :
164 551 : DnsItem() : eclass(1), type(0), ttl(0), priority(0), offset(0),
165 551 : name_plen(0), name_offset(0), data_plen(0), data_offset(0), soa() {}
166 :
167 : std::string ToString() const;
168 :
169 77 : bool operator ==(const DnsItem &rhs) const {
170 153 : if (eclass == rhs.eclass && type == rhs.type &&
171 230 : name == rhs.name && data == rhs.data && soa == rhs.soa && source_name == rhs.source_name)
172 32 : return true;
173 45 : return false;
174 : }
175 :
176 0 : bool IsDelete() const {
177 0 : if (ttl == 0 && (eclass == DNS_CLASS_ANY || eclass == DNS_CLASS_NONE))
178 0 : return true;
179 0 : return false;
180 : }
181 :
182 0 : bool MatchDelete(const DnsItem &rhs) const {
183 0 : if ((rhs.eclass == DNS_CLASS_ANY || rhs.eclass == DNS_CLASS_NONE) &&
184 0 : (rhs.type == DNS_TYPE_ANY || type == rhs.type) &&
185 0 : (name == rhs.name) &&
186 0 : (rhs.data.size() == 0 || data == rhs.data) &&
187 0 : (source_name == rhs.source_name))
188 0 : return true;
189 0 : return false;
190 : }
191 : };
192 :
193 : typedef std::list<DnsItem> DnsItems;
194 0 : static inline std::string DnsItemsToString(DnsItems &items) {
195 0 : std::string str;
196 0 : for (DnsItems::iterator it = items.begin();
197 0 : !items.empty() && it != items.end(); ++it) {
198 0 : str += (*it).ToString();
199 : }
200 0 : return str;
201 0 : }
202 :
203 : struct DnsUpdateData {
204 : typedef boost::function<void(DnsItem &)> DeleteCallback;
205 :
206 : std::string virtual_dns;
207 : std::string zone;
208 : mutable DnsItems items;
209 :
210 23 : DnsUpdateData() {}
211 : DnsUpdateData(const std::string &vdns, const std::string &z)
212 : : virtual_dns(vdns), zone(z) {}
213 :
214 : struct Compare {
215 0 : bool operator() (DnsUpdateData *const &lhs, DnsUpdateData *const &rhs) const {
216 0 : if (!lhs || !rhs)
217 0 : return false;
218 0 : if (lhs->virtual_dns != rhs->virtual_dns)
219 0 : return lhs->virtual_dns < rhs->virtual_dns;
220 0 : return lhs->zone < rhs->zone;
221 : }
222 : };
223 :
224 0 : bool AddItem(DnsItem &item, bool replace = false) const {
225 0 : for (DnsItems::iterator it = items.begin(); it != items.end(); ++it) {
226 0 : if (item == *it) {
227 0 : if (replace)
228 0 : *it = item;
229 0 : return false;
230 : }
231 : }
232 0 : items.push_back(item);
233 0 : return true;
234 : }
235 :
236 0 : bool DelItem(DnsItem &item) const {
237 0 : bool change = false;
238 0 : for (DnsItems::iterator it = items.begin(); it != items.end();) {
239 0 : if ((*it).MatchDelete(item)) {
240 0 : items.erase(it++);
241 0 : change = true;
242 : } else {
243 0 : ++it;
244 : }
245 : }
246 0 : return change;
247 : }
248 : };
249 :
250 : typedef std::vector<std::string> ZoneList;
251 :
252 : struct Subnet {
253 : IpAddress prefix;
254 : uint32_t plen;
255 : uint8_t flags;
256 :
257 : enum DnsConfigFlags {
258 : DeleteMarked = 1 << 0,
259 : };
260 :
261 10 : Subnet() : plen(0), flags(0) {}
262 43 : Subnet(std::string addr, uint32_t len) : plen(len), flags(0) {
263 43 : boost::system::error_code ec;
264 43 : prefix = boost::asio::ip::address::from_string(addr, ec);
265 43 : }
266 :
267 : bool operator< (const Subnet &rhs) const;
268 :
269 4 : void MarkDelete() { flags |= DeleteMarked; }
270 283 : bool IsDeleted() const { return (flags & DeleteMarked); }
271 : void ClearDelete() { flags &= ~DeleteMarked; }
272 :
273 : void GetReverseZones(ZoneList &zones) const;
274 :
275 : bool Contains(const IpAddress &addr) const;
276 : };
277 :
278 : typedef std::vector<Subnet> Subnets;
279 :
280 : class BindUtil {
281 : public:
282 : enum Operation {
283 : ADD_UPDATE,
284 : CHANGE_UPDATE,
285 : DELETE_UPDATE
286 : };
287 :
288 : static uint16_t DnsClass(const std::string &cl);
289 : static std::string DnsClass(uint16_t cl);
290 : static uint16_t DnsType(const std::string &tp);
291 : static std::string DnsType(uint16_t tp);
292 : static const std::string &DnsResponseCode(uint16_t code);
293 : static uint8_t *AddName(uint8_t *ptr, const std::string &addr,
294 : uint16_t plen, uint16_t offset, uint16_t &length);
295 : static bool ParseDnsQuery(uint8_t *dns, uint16_t dnslen,
296 : uint16_t *parsed_length, DnsItems &items);
297 : static bool ParseDnsResponse(uint8_t *dns, uint16_t dnslen, uint16_t &xid,
298 : dns_flags &flags, DnsItems &ques,
299 : DnsItems &ans, DnsItems &auth, DnsItems &add);
300 : static bool ParseDnsUpdate(uint8_t *dns, uint16_t dnslen,
301 : DnsUpdateData &data);
302 : static int BuildDnsQuery(uint8_t *buf, uint16_t xid,
303 : const std::string &domain,
304 : const DnsItems &items);
305 : static int BuildDnsUpdate(uint8_t *buf, Operation op, uint16_t xid,
306 : const std::string &domain,
307 : const std::string &zone,
308 : const DnsItems &items);
309 : static uint8_t *AddQuestionSection(uint8_t *ptr, const std::string &name,
310 : uint16_t type, uint16_t cl,
311 : uint16_t &length);
312 : static uint8_t *AddAnswerSection(uint8_t *ptr, const DnsItem &item,
313 : uint16_t &length);
314 : static uint8_t *AddUpdate(uint8_t *ptr, const DnsItem &item,
315 : uint16_t cl, uint32_t ttl, uint16_t &length);
316 : static void BuildDnsHeader(dnshdr *dns, uint16_t xid, DnsReq req,
317 : DnsOpcode op, bool rd, bool ra, uint8_t ret,
318 : uint16_t ques_count);
319 :
320 6 : static inline uint16_t DataLength(uint16_t plen, uint16_t offset,
321 : uint16_t size) {
322 6 : return (offset ? (plen ? plen + 2 + 1 : 2) : (size ? size + 2 : 1));
323 : }
324 : static bool IsIP(const std::string &name, IpAddress &addr);
325 : static bool IsReverseZone(const std::string &name);
326 : static void GetReverseZoneList(const IpAddress &mask, uint32_t plen,
327 : ZoneList &zones);
328 : // DnsProto::SendUpdateDnsEntry() needs the following two methods...
329 : static void GetReverseZone(const Ip4Address &addr, uint32_t plen,
330 : std::string &zone);
331 : static void GetReverseZone(const Ip6Address &addr, uint32_t plen,
332 : std::string &zone);
333 : static void GetReverseZone(const IpAddress &addr, uint32_t plen,
334 : std::string &zone);
335 : static bool GetAddrFromPtrName(std::string &ptr_name, IpAddress &mask);
336 : // ...and these two as well.
337 : static std::string GetPtrNameFromAddr(const Ip4Address &ip);
338 : static std::string GetPtrNameFromAddr(const Ip6Address &ip6);
339 : static std::string GetFQDN(const std::string &name, const std::string &domain,
340 : const std::string &match);
341 : static bool HasSpecialChars(const std::string &name);
342 : static void RemoveSpecialChars(std::string &name);
343 : private:
344 :
345 : static inline bool ReadByte(uint8_t *dns, uint16_t dnslen, int *remlen,
346 : uint8_t &value) {
347 : if (*remlen < 1) {
348 : return false;
349 : }
350 : uint8_t *ptr = dns + (dnslen - *remlen);
351 : *remlen -= 1;
352 : value = *(uint8_t *) ptr;
353 : return true;
354 : }
355 :
356 83 : static inline bool ReadShort(uint8_t *dns, uint16_t dnslen, int *remlen,
357 : uint16_t &value) {
358 83 : if (*remlen < 2) {
359 0 : return false;
360 : }
361 83 : uint8_t *ptr = dns + (dnslen - *remlen);
362 83 : *remlen -= 2;
363 83 : value = ntohs(*(uint16_t *) ptr);
364 83 : return true;
365 : }
366 :
367 31 : static inline bool ReadWord(uint8_t *dns, uint16_t dnslen, int *remlen,
368 : uint32_t &value) {
369 31 : if (*remlen < 4) {
370 0 : return false;
371 : }
372 31 : uint8_t *ptr = dns + (dnslen - *remlen);
373 31 : *remlen -= 4;
374 31 : value = ntohl(*(uint32_t *) ptr);
375 31 : return true;
376 : }
377 :
378 38 : static inline uint8_t *WriteByte(uint8_t *ptr, uint8_t value) {
379 38 : *(uint8_t *) ptr = value;
380 38 : ptr += 1;
381 :
382 38 : return ptr;
383 : }
384 :
385 83 : static inline uint8_t *WriteShort(uint8_t *ptr, uint16_t value) {
386 83 : *(uint16_t *) ptr = htons(value);
387 83 : ptr += 2;
388 :
389 83 : return ptr;
390 : }
391 :
392 31 : static inline uint8_t *WriteWord(uint8_t *ptr, uint32_t value) {
393 31 : *(uint32_t *) ptr = htonl(value);
394 31 : ptr += 4;
395 :
396 31 : return ptr;
397 : }
398 : static uint8_t *AddData(uint8_t *ptr, const DnsItem &item,
399 : uint16_t &length);
400 : static uint8_t *AddAdditionalSection(uint8_t *ptr, const std::string name,
401 : uint16_t type, uint16_t cl,
402 : uint32_t ttl, const std::string &data,
403 : uint16_t &length);
404 : static bool ReadName(uint8_t *dns, uint16_t dnslen, int *remlen,
405 : std::string &name, uint16_t &plen, uint16_t &offset);
406 : static bool ReadData(uint8_t *dns, uint16_t dnslen, int *remlen,
407 : DnsItem &item);
408 : static bool ReadQuestionEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
409 : DnsItem &item);
410 : static bool ReadAnswerEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
411 : DnsItem &item);
412 : static bool IsReverseZoneV4(const std::string &name);
413 : static bool IsReverseZoneV6(const std::string &name);
414 : static void GetReverseZoneList(const Ip4Address &mask, uint32_t plen,
415 : ZoneList &zones);
416 : static void GetReverseZoneList(const Ip6Address &mask, uint32_t plen,
417 : ZoneList &zones);
418 : static bool GetAddrFromPtrName(std::string &ptr_name,
419 : Ip4Address &ip);
420 : static bool GetAddrFromPtrName(std::string &ptr_name,
421 : Ip6Address &ip);
422 : static uint8_t GetNibble(const Ip6Address::bytes_type &addr,
423 : size_t bit);
424 : static std::string BuildIp6ArpaSuffix(const Ip6Address::bytes_type &addr,
425 : uint32_t plen);
426 : };
427 :
428 : // Identify the offsets for names in a DNS message
429 : class DnsNameEncoder {
430 : public:
431 : struct Name {
432 : std::string name;
433 : uint16_t offset;
434 0 : Name(std::string &n, uint16_t oset) : name(n), offset(oset) {}
435 : };
436 :
437 0 : DnsNameEncoder() {};
438 0 : virtual ~DnsNameEncoder() {};
439 : void AddName(std::string &name, uint16_t curr_msg_offset,
440 : uint16_t &name_plen, uint16_t &name_offset);
441 :
442 : private:
443 : bool IsPresent(std::string &name, uint16_t &name_offset);
444 :
445 : std::vector<Name> names_;
446 : DISALLOW_COPY_AND_ASSIGN(DnsNameEncoder);
447 : };
448 :
449 : #endif // __bind_util_h__
|