5 #include <boost/algorithm/string/join.hpp>
6 #include <boost/assign/list_of.hpp>
7 #include <boost/regex.hpp>
10 using namespace boost::assign;
46 (3,
"Non-existent domain")
47 (4,
"Not implemented")
49 (6,
"Name exists when it should not")
50 (7,
"RR Set Exists when it should not")
51 (8,
"RR Set that should exist does not")
53 (10,
"Name not contained in zone")
54 (16,
"Bad OPT Version")
55 (17,
"Key not recognized")
56 (18,
"Signature out of time window")
58 (20,
"Duplicate key name")
59 (21,
"Algorithm not supported")
60 (22,
"Bad truncation")
61 (4095,
"Invalid response code");
76 return plen < rhs.
plen;
81 }
else if (prefix.is_v6()) {
87 return plen < rhs.
plen;
90 return !rhs.
prefix.is_v4();
99 if (prefix.is_v4() && addr.is_v4()) {
101 }
else if (prefix.is_v6() && addr.is_v6()) {
142 return DnsResponseCode(4095);
147 uint16_t plen, uint16_t offset, uint16_t &length) {
148 std::size_t size = addr.size();
149 std::size_t cur_pos = 0;
150 std::size_t prev_pos = 0;
151 while (cur_pos < size && cur_pos != std::string::npos) {
152 if (offset && !plen) {
153 ptr = WriteShort(ptr, offset);
158 cur_pos = addr.find(
'.', prev_pos);
159 if (cur_pos == std::string::npos)
160 len = size - prev_pos;
162 len = cur_pos - prev_pos;
165 memcpy(ptr + 1, addr.substr(prev_pos, len).data(), len);
167 plen = (plen > len) ? plen - len - 1 : 0;
169 prev_pos = cur_pos + 1;
172 ptr = WriteByte(ptr, 0);
179 uint16_t
type, uint16_t cl,
181 ptr = AddName(ptr, name, 0, 0, length);
182 ptr = WriteShort(ptr, type);
183 ptr = WriteShort(ptr, cl);
191 boost::system::error_code ec;
194 ptr = WriteShort(ptr, 4);
195 ptr = WriteWord(ptr, boost::asio::ip::address_v4::from_string(
196 item.
data, ec).to_ulong());
199 ptr = WriteShort(ptr, 16);
200 boost::asio::ip::address_v6 addr =
201 boost::asio::ip::address_v6::from_string(item.
data, ec);
205 memcpy(ptr, addr.to_bytes().data(), 16);
215 ptr = WriteShort(ptr, data_len);
222 ptr = WriteWord(ptr, item.
soa.
retry);
224 ptr = WriteWord(ptr, item.
soa.
ttl);
231 ptr = WriteShort(ptr, data_len);
237 ptr = WriteShort(ptr, data_len);
239 ptr = WriteShort(ptr, item.
priority);
245 ptr = WriteShort(ptr, data_len);
248 ptr = WriteShort(ptr, item.
srv.
port);
259 uint16_t size = item.
data.size();
260 ptr = WriteShort(ptr, size);
262 memcpy(ptr, item.
data.c_str(), size);
274 ptr = WriteShort(ptr, item.
type);
275 ptr = WriteShort(ptr, item.
eclass);
276 ptr = WriteWord(ptr, item.
ttl);
278 ptr = AddData(ptr, item, length);
284 uint16_t
type, uint16_t cl,
285 uint32_t ttl,
const std::string &data,
287 ptr = AddQuestionSection(ptr, name, type, cl, length);
288 ptr = WriteWord(ptr, ttl);
289 ptr = WriteShort(ptr, data.size() + 1);
292 ptr = WriteByte(ptr, data.size());
293 memcpy(ptr, data.data(), data.size());
295 length += 4 + 2 + 1 + data.size();
301 uint16_t cl, uint32_t ttl, uint16_t &length) {
302 ptr = AddQuestionSection(ptr, item.
name, item.
type, cl, length);
303 ptr = WriteWord(ptr, ttl);
305 ptr = AddData(ptr, item, length);
311 std::string &name, uint16_t &plen, uint16_t &offset) {
316 uint8_t *ptr = dns + (dnslen - *remlen);
317 std::size_t len = *ptr;
319 if ((len & 0xC0) == 0xC0) {
320 plen = name.size() ? name.size() - 1 : 0;
321 if (ReadShort(dns, dnslen, remlen, offset) ==
false)
323 int offset_remlen = dnslen - (offset & ~0xC000);
325 return ReadName(dns, dnslen, &offset_remlen, name, dummy, dummy);
327 *remlen -= (len + 1);
331 name.append((
char *)ptr+1, len);
346 if (ReadShort(dns, dnslen, remlen, length) ==
false)
349 boost::system::error_code ec;
352 if (ReadWord(dns, dnslen, remlen, ip) ==
false)
354 boost::asio::ip::address_v4 addr(ip);
355 item.
data = addr.to_string(ec);
361 uint8_t *ptr = dns + (dnslen - *remlen);
362 boost::asio::ip::address_v6::bytes_type ip;
363 memcpy(&ip[0], ptr, 16);
364 boost::asio::ip::address_v6 addr(ip);
365 item.
data = addr.to_string(ec);
372 if (ReadName(dns, dnslen, remlen, item.
soa.
mailbox,
375 if (ReadWord(dns, dnslen, remlen, item.
soa.
serial) ==
false)
377 if (ReadWord(dns, dnslen, remlen, item.
soa.
refresh) ==
false)
379 if (ReadWord(dns, dnslen, remlen, item.
soa.
retry) ==
false)
381 if (ReadWord(dns, dnslen, remlen, item.
soa.
expiry) ==
false)
383 return ReadWord(dns, dnslen, remlen, item.
soa.
ttl);
389 if (ReadShort(dns, dnslen, remlen, item.
priority) ==
false)
393 if (ReadShort(dns, dnslen, remlen, item.
srv.
priority) ==
false)
395 if (ReadShort(dns, dnslen, remlen, item.
srv.
weight) ==
false)
397 if (ReadShort(dns, dnslen, remlen, item.
srv.
port) ==
false)
399 return ReadName(dns, dnslen, remlen, item.
srv.
hostname,
408 if (*remlen < length) {
411 uint8_t *ptr = dns + (dnslen - *remlen);
412 item.
data.assign((
const char *)ptr, length);
418 "Unsupported data type in DNS response : " << item.
type);
428 if (ReadShort(dns, dnslen, remlen, item.
type) ==
false)
431 return ReadShort(dns, dnslen, remlen, item.
eclass);
436 if (ReadQuestionEntry(dns, dnslen, remlen, item) ==
false)
439 if (ReadWord(dns, dnslen, remlen, item.
ttl) ==
false)
442 return ReadData(dns, dnslen, remlen, item);
449 if (dnslen <=
sizeof(
dnshdr)) {
451 "Invalid DNS Query with header missing - dropping it");
456 xid = ntohs(hdr->
xid);
459 int remlen = dnslen -
sizeof(
dnshdr);
460 for (
unsigned int i = 0; i < ques_rrcount; ++i) {
462 item.
offset = (dnslen - remlen) | 0xC000;
463 if (ReadQuestionEntry(dns, dnslen, &remlen, item) ==
false) {
465 "section - xid : " << xid <<
" - dropping it");
468 items.push_back(item);
471 *parsed_length = dnslen - remlen;
479 if (dnslen <
sizeof(
dnshdr)) {
481 "Invalid DNS Response with header missing - dropping it");
486 xid = ntohs(hdr->
xid);
494 int remlen = dnslen -
sizeof(
dnshdr);
498 for (
unsigned int i = 0; i < ques_rrcount; ++i) {
500 if (ReadQuestionEntry(dns, dnslen, &remlen, item) ==
false) {
501 errmsg =
"Parse error in question section";
504 ques.push_back(item);
508 for (
unsigned int i = 0; i < ans_rrcount; ++i) {
510 if (ReadAnswerEntry(dns, dnslen, &remlen, item) ==
false) {
511 errmsg =
"Parse error in answer section";
518 for (
unsigned int i = 0; i < auth_rrcount; ++i) {
520 if (ReadAnswerEntry(dns, dnslen, &remlen, item) ==
false) {
521 errmsg =
"Parse error in authority section";
524 auth.push_back(item);
528 for (
unsigned int i = 0; i < add_rrcount; ++i) {
530 if (ReadAnswerEntry(dns, dnslen, &remlen, item) ==
false) {
531 errmsg =
"Parse error in additional section";
541 "Invalid DNS response : " << errmsg <<
542 " xid : " << xid <<
" - dropping it");
548 if (dnslen <=
sizeof(
dnshdr)) {
549 DNS_BIND_TRACE(DnsBindError,
"Invalid DNS Update with header missing "
558 uint16_t xid = ntohs(hdr->
xid);
560 if (zone_count != 1) {
562 "Invalid zone count in Update request : " << zone_count);
566 if (prereq_count != 0) {
569 "which is not supported; dropping the request");
573 int remlen = dnslen -
sizeof(
dnshdr);
577 uint16_t zone_type, zone_class, plen, offset;
578 if (ReadName(dns, dnslen, &remlen, data.
zone, plen, offset) ==
false ||
579 ReadShort(dns, dnslen, &remlen, zone_type) ==
false ||
580 ReadShort(dns, dnslen, &remlen, zone_class) ==
false) {
581 errmsg =
"Parse error in reading zone";
586 for (
unsigned int i = 0; i < update_count; ++i) {
588 if (ReadName(dns, dnslen, &remlen, item.
name, plen, offset) ==
false ||
589 ReadShort(dns, dnslen, &remlen, item.
type) ==
false ||
590 ReadShort(dns, dnslen, &remlen, item.
eclass) ==
false ||
591 ReadWord(dns, dnslen, &remlen, item.
ttl) ==
false ||
592 ReadData(dns, dnslen, &remlen, item) ==
false) {
593 errmsg =
"Parse error";
596 data.
items.push_back(item);
603 "Invalid DNS Update : " << errmsg <<
604 " xid : " << xid <<
" - dropping it");
609 DnsOpcode op,
bool rd,
bool ra, uint8_t ret,
610 uint16_t ques_count) {
611 dns->
xid = htons(xid);
629 const std::string &domain,
633 1, 0, 0, items.size());
636 uint16_t len =
sizeof(
dnshdr);
637 uint8_t *ques = (uint8_t *) (dns + 1);
638 for (DnsItems::const_iterator it = items.begin(); it != items.end(); ++it) {
639 ques = AddQuestionSection(ques, (*it).name, (*it).type,
643 if (!domain.empty()) {
645 std::string view =
"view=" + domain;
654 const std::string &domain,
655 const std::string &zone,
665 uint16_t len =
sizeof(
dnshdr);
666 uint8_t *ptr = (uint8_t *) (dns + 1);
673 for (DnsItems::const_iterator it = items.begin();
674 it != items.end(); ++it) {
675 ptr = AddUpdate(ptr, *it, (*it).eclass, (*it).ttl, len);
680 for (DnsItems::const_iterator it = items.begin();
681 it != items.end(); ++it) {
691 std::string view =
"view=" + domain;
700 static boost::regex in_addr_arpa(
"(?:[0-9]+\\.){1,4}in-addr\\.arpa\\.?",
701 boost::regex::perl | boost::regex::icase);
706 static boost::regex ip6_arpa(
"(?:[0-9a-f]\\.){1,32}ip6\\.arpa\\.?",
707 boost::regex::perl | boost::regex::icase);
716 boost::system::error_code ec;
717 addr = boost::asio::ip::address::from_string(name, ec);
723 assert((bit >> 3) < 16);
724 uint8_t buf = addr[bit >> 3];
725 return ((bit & 0x7) ? (buf & 0xF) : (buf >> 4));
733 std::vector<std::string> items;
736 for (
size_t i = 0; i < (plen >> 2); i++) {
737 buf = GetNibble(addr, i << 2);
738 std::stringstream str;
739 str << std::hex << static_cast<unsigned int>(buf);
740 items.push_back(str.str());
743 std::reverse(items.begin(), items.end());
744 items.push_back(
"ip6.arpa");
745 return boost::algorithm::join(items,
".");
751 uint32_t addr = mask.to_ulong();
752 std::string zone_name =
"in-addr.arpa.";
754 std::stringstream str;
756 zone_name = str.str() +
"." + zone_name;
762 zones.push_back(zone_name);
765 for (
int j = 0; j <= (0xFF >> plen); j++) {
769 uint32_t last = (addr >> 24) + j;
770 std::stringstream str;
772 std::string rev_zone_name = str.str() +
"." + zone_name;
773 zones.push_back(rev_zone_name);
779 Ip6Address::bytes_type addr = mask.to_bytes();
780 std::string zone_name;
783 if (!plen || plen > 128)
788 uint32_t bits_rem = plen & 0x3;
792 for (
int j = 0; j <= (0xF >> bits_rem); j++) {
793 std::stringstream str;
794 str << std::hex << static_cast<unsigned int>(buf + j)
796 zones.push_back(str.str());
799 zones.push_back(zone_name);
806 GetReverseZoneList(mask.to_v4(), plen, zones);
807 }
else if (mask.is_v6()) {
808 GetReverseZoneList(mask.to_v6(), plen, zones);
814 uint32_t addr = ip.to_ulong();
815 zone =
"in-addr.arpa";
817 std::stringstream str;
819 zone = str.str() +
"." + zone;
827 std::stringstream str;
829 zone = str.str() +
"." + zone;
834 Ip6Address::bytes_type addr = ip.to_bytes();
837 if (!plen || plen > 128)
842 uint32_t bits_rem = plen & 0x3;
846 std::stringstream str;
847 str << std::hex << static_cast<unsigned int>(buf) <<
"." << zone;
855 GetReverseZone(addr.to_v4(), plen, zone);
856 }
else if (addr.is_v6()) {
857 GetReverseZone(addr.to_v6(), plen, zone);
867 std::stringstream str(ptr_name);
868 if (str.peek() ==
'.')
872 if (str.peek() ==
'i')
876 addr |= (num << (8 * count));
886 Ip6Address::bytes_type addr;
887 BOOST_ASSERT(addr.size() == 16);
889 typedef boost::tokenizer<boost::char_separator<char> >
tokenizer;
890 typedef boost::array<uint8_t, 32> nibbles;
895 tokenizer tok(ptr_name, boost::char_separator<char>(
"."));
898 tokenizer::const_iterator tok_it = tok.begin();
899 nibbles::iterator nib_it = nib.begin();
900 for (; tok_it != tok.end() && nib_it != nib.end(); ++tok_it, ++nib_it) {
901 std::stringstream str(*tok_it);
905 if (!(str >> std::hex >> buf))
908 *nib_it =
static_cast<uint8_t
>(buf);
911 std::fill(addr.begin(), addr.end(), 0);
913 std::reverse_iterator<nibbles::const_iterator> r_nib_it(nib_it);
914 Ip6Address::bytes_type::iterator addr_it = addr.begin();
917 bool odd_nib =
false;
919 for (; r_nib_it != nib.rend(); ++r_nib_it) {
921 *addr_it |= (*r_nib_it & 0xF);
924 *addr_it |= (*r_nib_it << 4);
935 std::string name = boost::to_lower_copy(ptr_name);
938 pos = name.find(
".in-addr.arpa");
939 if (pos != std::string::npos) {
947 pos = name.find(
".ip6.arpa");
948 if (pos != std::string::npos) {
960 std::stringstream str;
961 for (
int i = 0; i < 4; i++) {
962 str << ((ip.to_ulong() >> (i * 8)) & 0xFF) <<
".";
964 str <<
"in-addr.arpa";
969 std::stringstream str;
971 bool odd_nibble =
true;
973 Ip6Address::bytes_type addr = ip6.to_bytes();
974 Ip6Address::bytes_type::reverse_iterator it = addr.rbegin();
975 while (it != addr.rend()) {
983 str << std::hex << buf <<
'.';
984 odd_nibble = !odd_nibble;
992 const std::string &match) {
993 if (name.find(match, 0) == std::string::npos)
994 return name +
"." + domain;
1000 for (
unsigned int i = 0; i < name.size(); ++i) {
1001 uint8_t c = name[i];
1002 if (!((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
1003 (c >=
'0' && c <=
'9') || (c ==
'-') || (c ==
'.')))
1010 for (
unsigned int i = 0; i < name.size(); ++i) {
1011 uint8_t c = name[i];
1012 if (!((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
1013 (c >=
'0' && c <=
'9') || (c ==
'-') || (c ==
'.')))
1019 uint16_t &name_plen, uint16_t &name_offset) {
1022 std::size_t pos = 0;
1023 while (pos < name.size()) {
1024 std::string str = name.substr(pos);
1025 if(IsPresent(str, name_offset)) {
1026 name_plen = pos ? pos - 1 : 0;
1030 pos = name.find(
'.', pos + 1);
1031 if (pos == std::string::npos)
1036 names_.push_back(
Name(name, curr_msg_offset));
1040 for (
unsigned int i = 0; i < names_.size(); i++) {
1041 if (names_[i].name == name) {
1042 name_offset = names_[i].offset;
static uint8_t * AddQuestionSection(uint8_t *ptr, const std::string &name, uint16_t type, uint16_t cl, 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)
std::map< std::string, uint16_t >::const_iterator DnsTypeIter
std::map< uint16_t, std::string > DnsResponseMap
#define DNS_BIND_TRACE(obj, arg)
SandeshTraceBufferPtr DnsBindTraceBuf
std::map< uint16_t, std::string >::const_iterator DnsResponseIter
static int BuildDnsUpdate(uint8_t *buf, Operation op, uint16_t xid, const std::string &domain, const std::string &zone, const DnsItems &items)
std::map< std::string, uint16_t > DnsTypeMap
bool IsIp4SubnetMember(const Ip4Address &ip, const Ip4Address &prefix_ip, uint16_t plen)
static int BuildDnsQuery(uint8_t *buf, uint16_t xid, const std::string &domain, const DnsItems &items)
boost::asio::ip::address IpAddress
static uint8_t GetNibble(const Ip6Address::bytes_type &addr, size_t bit)
std::list< DnsItem > DnsItems
static uint8_t * AddAnswerSection(uint8_t *ptr, const DnsItem &item, uint16_t &length)
void AddName(std::string &name, uint16_t curr_msg_offset, uint16_t &name_plen, uint16_t &name_offset)
boost::shared_ptr< TraceBuffer< SandeshTrace > > SandeshTraceBufferPtr
std::map< uint16_t, std::string >::const_iterator DnsTypeNumIter
static const std::string & DnsResponseCode(uint16_t code)
void GetReverseZones(ZoneList &zones) const
static bool ReadQuestionEntry(uint8_t *dns, uint16_t dnslen, int *remlen, DnsItem &item)
static bool ParseDnsResponse(uint8_t *dns, uint16_t dnslen, uint16_t &xid, dns_flags &flags, DnsItems &ques, DnsItems &ans, DnsItems &auth, DnsItems &add)
static std::string GetFQDN(const std::string &name, const std::string &domain, const std::string &match)
static uint8_t * AddData(uint8_t *ptr, const DnsItem &item, uint16_t &length)
static void RemoveSpecialChars(std::string &name)
static uint8_t * AddUpdate(uint8_t *ptr, const DnsItem &item, uint16_t cl, uint32_t ttl, uint16_t &length)
static bool regex_match(const std::string &input, const regex ®ex)
static bool IsReverseZone(const std::string &name)
static bool ParseDnsUpdate(uint8_t *dns, uint16_t dnslen, DnsUpdateData &data)
static const std::string integerToString(const NumberType &num)
static bool ParseDnsQuery(uint8_t *dns, uint16_t dnslen, uint16_t *parsed_length, DnsItems &items)
boost::asio::ip::address_v6 Ip6Address
static uint8_t * AddName(uint8_t *ptr, const std::string &addr, uint16_t plen, uint16_t offset, uint16_t &length)
std::string ToString() const
static bool IsIP(const std::string &name, IpAddress &addr)
std::map< uint16_t, std::string > DnsTypeNumMap
static std::string GetPtrNameFromAddr(const Ip4Address &ip)
bool Contains(const IpAddress &addr) const
boost::tokenizer< boost::char_separator< char > > tokenizer
bool operator<(const Subnet &rhs) const
static bool ReadAnswerEntry(uint8_t *dns, uint16_t dnslen, int *remlen, DnsItem &item)
static uint16_t DnsClass(const std::string &cl)
boost::asio::ip::address_v4 Ip4Address
static bool IsReverseZoneV4(const std::string &name)
static bool GetAddrFromPtrName(std::string &ptr_name, IpAddress &mask)
static bool ReadName(uint8_t *dns, uint16_t dnslen, int *remlen, std::string &name, uint16_t &plen, uint16_t &offset)
static void BuildDnsHeader(dnshdr *dns, uint16_t xid, DnsReq req, DnsOpcode op, bool rd, bool ra, uint8_t ret, uint16_t ques_count)
static bool ReadData(uint8_t *dns, uint16_t dnslen, int *remlen, DnsItem &item)
static bool HasSpecialChars(const std::string &name)
static uint16_t DnsType(const std::string &tp)
DnsTypeNumMap g_dns_class_num_map
static void GetReverseZoneList(const IpAddress &mask, uint32_t plen, ZoneList &zones)
static void GetReverseZone(const Ip4Address &addr, uint32_t plen, std::string &zone)
bool IsIp6SubnetMember(const Ip6Address &ip, const Ip6Address &subnet, uint8_t plen)
static std::string BuildIp6ArpaSuffix(const Ip6Address::bytes_type &addr, uint32_t plen)
DnsResponseMap g_dns_response_map
DnsTypeMap g_dns_type_map
static bool IsReverseZoneV6(const std::string &name)
std::vector< std::string > ZoneList
bool IsPresent(std::string &name, uint16_t &name_offset)
SandeshTraceBufferPtr SandeshTraceBufferCreate(const std::string &buf_name, size_t buf_size, bool trace_enable=true)
DnsTypeNumMap g_dns_type_num_map