]>
Commit | Line | Data |
---|---|---|
a44a8d66 OM |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
22 | ||
23 | #include "protozero.hh" | |
454e9974 RG |
24 | |
25 | #ifndef DISABLE_PROTOBUF | |
87f46425 | 26 | #include "dnsparser.hh" |
a44a8d66 OM |
27 | |
28 | void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& ca) | |
29 | { | |
30 | if (ca.sin4.sin_family == AF_INET) { | |
ac10822e | 31 | d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr)); |
a44a8d66 OM |
32 | } |
33 | else if (ca.sin4.sin_family == AF_INET6) { | |
ac10822e | 34 | d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr)); |
a44a8d66 OM |
35 | } |
36 | } | |
37 | ||
38 | void pdns::ProtoZero::Message::encodeNetmask(const protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask) | |
39 | { | |
40 | if (!subnet.empty()) { | |
41 | ComboAddress ca(subnet.getNetwork()); | |
42 | ca.truncate(mask); | |
43 | if (ca.sin4.sin_family == AF_INET) { | |
ac10822e | 44 | d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr)); |
a44a8d66 OM |
45 | } |
46 | else if (ca.sin4.sin_family == AF_INET6) { | |
ac10822e | 47 | d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr)); |
a44a8d66 OM |
48 | } |
49 | } | |
50 | } | |
51 | ||
52 | void pdns::ProtoZero::Message::encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, const protozero::pbf_tag_type type, const DNSName& name) | |
53 | { | |
54 | // this will append the tag, mark the current position then reserve enough place to write the size | |
55 | protozero::pbf_writer pbf_name{pbf, type}; | |
56 | // we append the name to the buffer | |
57 | name.toString(buffer); | |
58 | // leaving the block will cause the sub writer to compute how much was written based on the new size and update the size accordingly | |
59 | } | |
60 | ||
cffd3a17 | 61 | void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, pdns::ProtoZero::Message::TransportProtocol proto, size_t len) |
a44a8d66 | 62 | { |
a44a8d66 OM |
63 | setMessageIdentity(uniqueId); |
64 | setSocketFamily(requestor.sin4.sin_family); | |
cffd3a17 | 65 | setSocketProtocol(proto); |
a44a8d66 OM |
66 | setFrom(requestor); |
67 | setTo(local); | |
68 | setInBytes(len); | |
69 | setTime(); | |
70 | setId(id); | |
71 | setQuestion(qname, qtype, qclass); | |
72 | setFromPort(requestor.getPort()); | |
73 | setToPort(local.getPort()); | |
74 | } | |
75 | ||
d58249ee | 76 | void pdns::ProtoZero::Message::setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass) |
a44a8d66 | 77 | { |
89addb82 | 78 | setType(pdns::ProtoZero::Message::MessageType::DNSResponseType); |
a44a8d66 OM |
79 | setQuestion(qname, qtype, qclass); |
80 | } | |
81 | ||
87f46425 | 82 | void pdns::ProtoZero::Message::addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME) |
a44a8d66 | 83 | { |
87f46425 | 84 | if (len < sizeof(struct dnsheader)) { |
a44a8d66 OM |
85 | return; |
86 | } | |
87 | ||
90686725 | 88 | const dnsheader_aligned dh(packet); |
87f46425 RG |
89 | |
90 | if (ntohs(dh->ancount) == 0) { | |
a44a8d66 OM |
91 | return; |
92 | } | |
93 | ||
87f46425 RG |
94 | if (ntohs(dh->qdcount) == 0) { |
95 | return; | |
a44a8d66 | 96 | } |
87f46425 | 97 | |
fa5a722b | 98 | PacketReader pr(std::string_view(packet, len)); |
87f46425 RG |
99 | |
100 | size_t idx = 0; | |
101 | DNSName rrname; | |
102 | uint16_t qdcount = ntohs(dh->qdcount); | |
103 | uint16_t ancount = ntohs(dh->ancount); | |
104 | uint16_t rrtype; | |
105 | uint16_t rrclass; | |
106 | string blob; | |
107 | struct dnsrecordheader ah; | |
108 | ||
109 | rrname = pr.getName(); | |
110 | rrtype = pr.get16BitInt(); | |
111 | rrclass = pr.get16BitInt(); | |
90ee15b3 RG |
112 | (void) rrtype; |
113 | (void) rrclass; | |
87f46425 RG |
114 | |
115 | /* consume remaining qd if any */ | |
116 | if (qdcount > 1) { | |
117 | for(idx = 1; idx < qdcount; idx++) { | |
118 | rrname = pr.getName(); | |
119 | rrtype = pr.get16BitInt(); | |
120 | rrclass = pr.get16BitInt(); | |
121 | (void) rrtype; | |
122 | (void) rrclass; | |
123 | } | |
a44a8d66 | 124 | } |
87f46425 RG |
125 | |
126 | /* parse AN */ | |
127 | for (idx = 0; idx < ancount; idx++) { | |
128 | rrname = pr.getName(); | |
129 | pr.getDnsrecordheader(ah); | |
130 | ||
131 | if (ah.d_type == QType::A || ah.d_type == QType::AAAA) { | |
132 | pr.xfrBlob(blob); | |
133 | ||
134 | addRR(rrname, ah.d_type, ah.d_class, ah.d_ttl, blob); | |
135 | ||
136 | } else if (ah.d_type == QType::CNAME && includeCNAME) { | |
89addb82 | 137 | protozero::pbf_writer pbf_rr{d_response, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::ResponseField::rrs)}; |
87f46425 | 138 | |
89addb82 RG |
139 | encodeDNSName(pbf_rr, d_buffer, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::name), rrname); |
140 | pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::type), ah.d_type); | |
141 | pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::class_), ah.d_class); | |
142 | pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::ttl), ah.d_ttl); | |
87f46425 RG |
143 | DNSName target; |
144 | pr.xfrName(target, true); | |
89addb82 | 145 | encodeDNSName(pbf_rr, d_buffer, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::rdata), target); |
87f46425 RG |
146 | } |
147 | else { | |
148 | pr.xfrBlob(blob); | |
149 | } | |
a44a8d66 | 150 | } |
a44a8d66 | 151 | } |
47a6825e | 152 | |
87f46425 | 153 | void pdns::ProtoZero::Message::addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob) |
47a6825e | 154 | { |
89addb82 RG |
155 | protozero::pbf_writer pbf_rr{d_response, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::ResponseField::rrs)}; |
156 | encodeDNSName(pbf_rr, d_buffer, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::name), name); | |
157 | pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::type), uType); | |
158 | pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::class_), uClass); | |
159 | pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::ttl), uTTL); | |
160 | pbf_rr.add_string(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::rdata), blob); | |
47a6825e | 161 | } |
454e9974 RG |
162 | |
163 | #endif /* DISABLE_PROTOBUF */ |