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