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 1098 : DnsSOAData() : ns_plen(0), ns_offset(0), mailbox_plen(0), mailbox_offset(0),
126 549 : 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 549 : 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 vm_uuid;
161 : std::string data;
162 : DnsSOAData soa;
163 : DnsSRVData srv;
164 :
165 549 : DnsItem() : eclass(1), type(0), ttl(0), priority(0), offset(0),
166 549 : name_plen(0), name_offset(0), data_plen(0), data_offset(0), soa() {}
167 :
168 : std::string ToString() const;
169 :
170 77 : bool operator ==(const DnsItem &rhs) const {
171 153 : if (eclass == rhs.eclass && type == rhs.type &&
172 144 : name == rhs.name && data == rhs.data && soa == rhs.soa &&
173 188 : source_name == rhs.source_name && vm_uuid == rhs.vm_uuid)
174 32 : return true;
175 45 : return false;
176 : }
177 :
178 0 : bool IsDelete() const {
179 0 : if (ttl == 0 && (eclass == DNS_CLASS_ANY || eclass == DNS_CLASS_NONE))
180 0 : return true;
181 0 : return false;
182 : }
183 :
184 0 : bool MatchDelete(const DnsItem &rhs) const {
185 0 : if ((rhs.eclass == DNS_CLASS_ANY || rhs.eclass == DNS_CLASS_NONE) &&
186 0 : (rhs.type == DNS_TYPE_ANY || type == rhs.type) &&
187 0 : (name == rhs.name) &&
188 0 : (rhs.data.size() == 0 || data == rhs.data) &&
189 0 : (source_name == rhs.source_name) &&
190 : // Same ownership rule as DnsManager::ProcessAgentUpdate(): the
191 : // vm_uuid is compared only when both sides carry one. A stored
192 : // item published without a vm_uuid must stay removable by a
193 : // delete that carries one, else the record is stranded in named.
194 0 : (rhs.vm_uuid.empty() || vm_uuid.empty() ||
195 0 : vm_uuid == rhs.vm_uuid))
196 0 : return true;
197 0 : return false;
198 : }
199 : };
200 :
201 : typedef std::list<DnsItem> DnsItems;
202 0 : static inline std::string DnsItemsToString(DnsItems &items) {
203 0 : std::string str;
204 0 : for (DnsItems::iterator it = items.begin();
205 0 : !items.empty() && it != items.end(); ++it) {
206 0 : str += (*it).ToString();
207 : }
208 0 : return str;
209 0 : }
210 :
211 : struct DnsUpdateData {
212 : typedef boost::function<void(DnsItem &)> DeleteCallback;
213 :
214 : std::string virtual_dns;
215 : std::string zone;
216 : mutable DnsItems items;
217 :
218 23 : DnsUpdateData() {}
219 : DnsUpdateData(const std::string &vdns, const std::string &z)
220 : : virtual_dns(vdns), zone(z) {}
221 :
222 : struct Compare {
223 0 : bool operator() (DnsUpdateData *const &lhs, DnsUpdateData *const &rhs) const {
224 0 : if (!lhs || !rhs)
225 0 : return false;
226 0 : if (lhs->virtual_dns != rhs->virtual_dns)
227 0 : return lhs->virtual_dns < rhs->virtual_dns;
228 0 : return lhs->zone < rhs->zone;
229 : }
230 : };
231 :
232 0 : bool AddItem(DnsItem &item, bool replace = false) const {
233 0 : for (DnsItems::iterator it = items.begin(); it != items.end(); ++it) {
234 0 : if (item == *it) {
235 0 : if (replace)
236 0 : *it = item;
237 0 : return false;
238 : }
239 : }
240 0 : items.push_back(item);
241 0 : return true;
242 : }
243 :
244 0 : bool DelItem(DnsItem &item) const {
245 0 : bool change = false;
246 0 : for (DnsItems::iterator it = items.begin(); it != items.end();) {
247 0 : if ((*it).MatchDelete(item)) {
248 0 : items.erase(it++);
249 0 : change = true;
250 : } else {
251 0 : ++it;
252 : }
253 : }
254 0 : return change;
255 : }
256 : };
257 :
258 : typedef std::vector<std::string> ZoneList;
259 :
260 : struct Subnet {
261 : IpAddress prefix;
262 : uint32_t plen;
263 : uint8_t flags;
264 :
265 : enum DnsConfigFlags {
266 : DeleteMarked = 1 << 0,
267 : };
268 :
269 10 : Subnet() : plen(0), flags(0) {}
270 43 : Subnet(std::string addr, uint32_t len) : plen(len), flags(0) {
271 43 : boost::system::error_code ec;
272 43 : prefix = boost::asio::ip::address::from_string(addr, ec);
273 43 : }
274 :
275 : bool operator< (const Subnet &rhs) const;
276 :
277 4 : void MarkDelete() { flags |= DeleteMarked; }
278 283 : bool IsDeleted() const { return (flags & DeleteMarked); }
279 : void ClearDelete() { flags &= ~DeleteMarked; }
280 :
281 : void GetReverseZones(ZoneList &zones) const;
282 :
283 : bool Contains(const IpAddress &addr) const;
284 : };
285 :
286 : typedef std::vector<Subnet> Subnets;
287 :
288 : class BindUtil {
289 : public:
290 : enum Operation {
291 : ADD_UPDATE,
292 : CHANGE_UPDATE,
293 : DELETE_UPDATE
294 : };
295 :
296 : static uint16_t DnsClass(const std::string &cl);
297 : static std::string DnsClass(uint16_t cl);
298 : static uint16_t DnsType(const std::string &tp);
299 : static std::string DnsType(uint16_t tp);
300 : static const std::string &DnsResponseCode(uint16_t code);
301 : static uint8_t *AddName(uint8_t *ptr, const std::string &addr,
302 : uint16_t plen, uint16_t offset, uint16_t &length);
303 : static bool ParseDnsQuery(uint8_t *dns, uint16_t dnslen,
304 : uint16_t *parsed_length, DnsItems &items);
305 : static bool ParseDnsResponse(uint8_t *dns, uint16_t dnslen, uint16_t &xid,
306 : dns_flags &flags, DnsItems &ques,
307 : DnsItems &ans, DnsItems &auth, DnsItems &add);
308 : static bool ParseDnsUpdate(uint8_t *dns, uint16_t dnslen,
309 : DnsUpdateData &data);
310 : static int BuildDnsQuery(uint8_t *buf, uint16_t xid,
311 : const std::string &domain,
312 : const DnsItems &items);
313 : static int BuildDnsUpdate(uint8_t *buf, Operation op, uint16_t xid,
314 : const std::string &domain,
315 : const std::string &zone,
316 : const DnsItems &items);
317 : static uint8_t *AddQuestionSection(uint8_t *ptr, const std::string &name,
318 : uint16_t type, uint16_t cl,
319 : uint16_t &length);
320 : static uint8_t *AddAnswerSection(uint8_t *ptr, const DnsItem &item,
321 : uint16_t &length);
322 : static uint8_t *AddUpdate(uint8_t *ptr, const DnsItem &item,
323 : uint16_t cl, uint32_t ttl, uint16_t &length);
324 : static void BuildDnsHeader(dnshdr *dns, uint16_t xid, DnsReq req,
325 : DnsOpcode op, bool rd, bool ra, uint8_t ret,
326 : uint16_t ques_count);
327 :
328 6 : static inline uint16_t DataLength(uint16_t plen, uint16_t offset,
329 : uint16_t size) {
330 6 : return (offset ? (plen ? plen + 2 + 1 : 2) : (size ? size + 2 : 1));
331 : }
332 : static bool IsIP(const std::string &name, IpAddress &addr);
333 : static bool IsReverseZone(const std::string &name);
334 : static void GetReverseZoneList(const IpAddress &mask, uint32_t plen,
335 : ZoneList &zones);
336 : // DnsProto::SendUpdateDnsEntry() needs the following two methods...
337 : static void GetReverseZone(const Ip4Address &addr, uint32_t plen,
338 : std::string &zone);
339 : static void GetReverseZone(const Ip6Address &addr, uint32_t plen,
340 : std::string &zone);
341 : static void GetReverseZone(const IpAddress &addr, uint32_t plen,
342 : std::string &zone);
343 : static bool GetAddrFromPtrName(std::string &ptr_name, IpAddress &mask);
344 : // ...and these two as well.
345 : static std::string GetPtrNameFromAddr(const Ip4Address &ip);
346 : static std::string GetPtrNameFromAddr(const Ip6Address &ip6);
347 : static std::string GetFQDN(const std::string &name, const std::string &domain,
348 : const std::string &match);
349 : static bool HasSpecialChars(const std::string &name);
350 : static void RemoveSpecialChars(std::string &name);
351 : private:
352 :
353 : static inline bool ReadByte(uint8_t *dns, uint16_t dnslen, int *remlen,
354 : uint8_t &value) {
355 : if (*remlen < 1) {
356 : return false;
357 : }
358 : uint8_t *ptr = dns + (dnslen - *remlen);
359 : *remlen -= 1;
360 : value = *(uint8_t *) ptr;
361 : return true;
362 : }
363 :
364 83 : static inline bool ReadShort(uint8_t *dns, uint16_t dnslen, int *remlen,
365 : uint16_t &value) {
366 83 : if (*remlen < 2) {
367 0 : return false;
368 : }
369 83 : uint8_t *ptr = dns + (dnslen - *remlen);
370 83 : *remlen -= 2;
371 83 : value = ntohs(*(uint16_t *) ptr);
372 83 : return true;
373 : }
374 :
375 31 : static inline bool ReadWord(uint8_t *dns, uint16_t dnslen, int *remlen,
376 : uint32_t &value) {
377 31 : if (*remlen < 4) {
378 0 : return false;
379 : }
380 31 : uint8_t *ptr = dns + (dnslen - *remlen);
381 31 : *remlen -= 4;
382 31 : value = ntohl(*(uint32_t *) ptr);
383 31 : return true;
384 : }
385 :
386 38 : static inline uint8_t *WriteByte(uint8_t *ptr, uint8_t value) {
387 38 : *(uint8_t *) ptr = value;
388 38 : ptr += 1;
389 :
390 38 : return ptr;
391 : }
392 :
393 83 : static inline uint8_t *WriteShort(uint8_t *ptr, uint16_t value) {
394 83 : *(uint16_t *) ptr = htons(value);
395 83 : ptr += 2;
396 :
397 83 : return ptr;
398 : }
399 :
400 31 : static inline uint8_t *WriteWord(uint8_t *ptr, uint32_t value) {
401 31 : *(uint32_t *) ptr = htonl(value);
402 31 : ptr += 4;
403 :
404 31 : return ptr;
405 : }
406 : static uint8_t *AddData(uint8_t *ptr, const DnsItem &item,
407 : uint16_t &length);
408 : static uint8_t *AddAdditionalSection(uint8_t *ptr, const std::string name,
409 : uint16_t type, uint16_t cl,
410 : uint32_t ttl, const std::string &data,
411 : uint16_t &length);
412 : static bool ReadName(uint8_t *dns, uint16_t dnslen, int *remlen,
413 : std::string &name, uint16_t &plen, uint16_t &offset);
414 : static bool ReadData(uint8_t *dns, uint16_t dnslen, int *remlen,
415 : DnsItem &item);
416 : static bool ReadQuestionEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
417 : DnsItem &item);
418 : static bool ReadAnswerEntry(uint8_t *dns, uint16_t dnslen, int *remlen,
419 : DnsItem &item);
420 : static bool IsReverseZoneV4(const std::string &name);
421 : static bool IsReverseZoneV6(const std::string &name);
422 : static void GetReverseZoneList(const Ip4Address &mask, uint32_t plen,
423 : ZoneList &zones);
424 : static void GetReverseZoneList(const Ip6Address &mask, uint32_t plen,
425 : ZoneList &zones);
426 : static bool GetAddrFromPtrName(std::string &ptr_name,
427 : Ip4Address &ip);
428 : static bool GetAddrFromPtrName(std::string &ptr_name,
429 : Ip6Address &ip);
430 : static uint8_t GetNibble(const Ip6Address::bytes_type &addr,
431 : size_t bit);
432 : static std::string BuildIp6ArpaSuffix(const Ip6Address::bytes_type &addr,
433 : uint32_t plen);
434 : };
435 :
436 : // Identify the offsets for names in a DNS message
437 : class DnsNameEncoder {
438 : public:
439 : struct Name {
440 : std::string name;
441 : uint16_t offset;
442 0 : Name(std::string &n, uint16_t oset) : name(n), offset(oset) {}
443 : };
444 :
445 0 : DnsNameEncoder() {};
446 0 : virtual ~DnsNameEncoder() {};
447 : void AddName(std::string &name, uint16_t curr_msg_offset,
448 : uint16_t &name_plen, uint16_t &name_offset);
449 :
450 : private:
451 : bool IsPresent(std::string &name, uint16_t &name_offset);
452 :
453 : std::vector<Name> names_;
454 : DISALLOW_COPY_AND_ASSIGN(DnsNameEncoder);
455 : };
456 :
457 : #endif // __bind_util_h__
|