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