Branch data Line data Source code
1 : : // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #include <algorithm>
16 : : #include <cctype>
17 : : #include <string>
18 : : #include <sstream>
19 : : #include <iomanip>
20 : : #include <ios>
21 : : #include <ostream>
22 : : #include <vector>
23 : :
24 : : #include <stdint.h>
25 : : #include <string.h>
26 : :
27 : : #include <boost/lexical_cast.hpp>
28 : : #include <boost/shared_ptr.hpp>
29 : :
30 : : #include <util/buffer.h>
31 : : #include <dns/name.h>
32 : : #include <dns/messagerenderer.h>
33 : : #include <dns/rdata.h>
34 : : #include <dns/rrparamregistry.h>
35 : : #include <dns/rrtype.h>
36 : :
37 : : using namespace std;
38 : : using namespace boost;
39 : : using namespace isc::util;
40 : :
41 : : namespace isc {
42 : : namespace dns {
43 : : namespace rdata {
44 : :
45 : : // XXX: we need to specify std:: for string to help doxygen match the
46 : : // function signature with that given in the header file.
47 : : RdataPtr
48 : 19767 : createRdata(const RRType& rrtype, const RRClass& rrclass,
49 : : const std::string& rdata_string)
50 : : {
51 : 19767 : return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass,
52 : 19767 : rdata_string));
53 : : }
54 : :
55 : : RdataPtr
56 : 1136 : createRdata(const RRType& rrtype, const RRClass& rrclass,
57 : : isc::util::InputBuffer& buffer, size_t len)
58 : : {
59 [ + + ]: 1136 : if (len > MAX_RDLENGTH) {
60 [ + - ]: 2 : isc_throw(InvalidRdataLength, "RDLENGTH too large");
61 : : }
62 : :
63 : 1135 : size_t old_pos = buffer.getPosition();
64 : :
65 : : RdataPtr rdata =
66 : 1135 : RRParamRegistry::getRegistry().createRdata(rrtype, rrclass, buffer,
67 : 1135 : len);
68 : :
69 [ + + ]: 1035 : if (buffer.getPosition() - old_pos != len) {
70 [ + - ][ + - ]: 88 : isc_throw(InvalidRdataLength, "RDLENGTH mismatch: " <<
[ + - ]
71 : : buffer.getPosition() - old_pos << " != " << len);
72 : : }
73 : :
74 : 1013 : return (rdata);
75 : : }
76 : :
77 : : RdataPtr
78 : 10365 : createRdata(const RRType& rrtype, const RRClass& rrclass, const Rdata& source)
79 : : {
80 : 10365 : return (RRParamRegistry::getRegistry().createRdata(rrtype, rrclass,
81 : 10365 : source));
82 : : }
83 : :
84 : : int
85 : 2454 : compareNames(const Name& n1, const Name& n2) {
86 : 2454 : size_t len1 = n1.getLength();
87 : 2454 : size_t len2 = n2.getLength();
88 : 2454 : size_t cmplen = min(len1, len2);
89 : :
90 [ + + ]: 44622 : for (size_t i = 0; i < cmplen; ++i) {
91 : 42200 : uint8_t c1 = tolower(n1.at(i));
92 : 42200 : uint8_t c2 = tolower(n2.at(i));
93 [ + + ]: 42200 : if (c1 < c2) {
94 : : return (-1);
95 [ + + ]: 42187 : } else if (c1 > c2) {
96 : : return (1);
97 : : }
98 : : }
99 : :
100 [ - + ][ # # ]: 2454 : return ((len1 == len2) ? 0 : (len1 < len2) ? -1 : 1);
101 : : }
102 : :
103 : : namespace generic {
104 [ + - ][ + - ]: 334 : struct GenericImpl {
105 [ + - ][ + - ]: 274 : GenericImpl(const vector<uint8_t>& data) : data_(data) {}
106 : : vector<uint8_t> data_;
107 : : };
108 : :
109 : 32 : Generic::Generic(isc::util::InputBuffer& buffer, size_t rdata_len) {
110 [ + + ]: 16 : if (rdata_len > MAX_RDLENGTH) {
111 [ + - ][ + - ]: 2 : isc_throw(InvalidRdataLength, "RDLENGTH too large");
112 : : }
113 : :
114 : 15 : vector<uint8_t> data(rdata_len);
115 [ + + ]: 15 : if (rdata_len > 0) {
116 : 14 : buffer.readData(&data[0], rdata_len);
117 : : }
118 : :
119 [ + - ]: 14 : impl_ = new GenericImpl(data);
120 : 14 : }
121 : :
122 : 546 : Generic::Generic(const string& rdata_string) {
123 [ + - + - ]: 546 : istringstream iss(rdata_string);
124 : 273 : string unknown_mark;
125 [ + - ]: 273 : iss >> unknown_mark;
126 [ + + ]: 273 : if (unknown_mark != "\\#") {
127 [ + - ][ + - ]: 8 : isc_throw(InvalidRdataText,
128 : : "Missing the special token (\\#) for generic RDATA encoding");
129 : : }
130 : :
131 : : // RDLENGTH: read into a string so that we can easily reject invalid tokens
132 : 269 : string rdlen_txt;
133 [ + - ]: 269 : iss >> rdlen_txt;
134 [ + - + - ]: 538 : istringstream iss_rdlen(rdlen_txt);
135 : : int32_t rdlen;
136 [ + - ]: 269 : iss_rdlen >> rdlen;
137 [ + + ]: 269 : if (iss_rdlen.rdstate() != ios::eofbit) {
138 [ + - ][ + - ]: 6 : isc_throw(InvalidRdataText,
139 : : "Invalid representation for a generic RDLENGTH");
140 : : }
141 [ + + ]: 266 : if (rdlen < 0 || rdlen > 0xffff) {
142 [ + - ][ + - ]: 4 : isc_throw(InvalidRdataLength, "RDATA length is out of range");
143 : : }
144 : : iss >> ws; // skip any white spaces
145 : :
146 : : // Hexadecimal encoding of RDATA: each segment must consist of an even
147 : : // number of hex digits.
148 : 264 : vector<uint8_t> data;
149 [ + + ][ + + ]: 524164 : while (!iss.eof() && data.size() < rdlen) {
[ + + ]
150 : : // extract two characters, which should compose a single byte of data.
151 : : char buf[2];
152 [ + - ]: 523902 : iss.read(buf, sizeof(buf));
153 [ + + ]: 523902 : if ((iss.rdstate() & (ios::badbit | ios::failbit)) != 0) {
154 [ + - ][ + - ]: 2 : isc_throw(InvalidRdataText,
155 : : "Invalid hex encoding of generic RDATA");
156 : : }
157 : :
158 : : // convert it to a single byte integer as a hex digit.
159 [ + - ][ + - ]: 1047802 : istringstream iss_byte(string(buf, sizeof(buf)));
[ + - ]
160 : : unsigned int ch;
161 : 523901 : iss_byte >> hex >> ch;
162 [ + + ]: 523901 : if (iss_byte.rdstate() != ios::eofbit) {
163 [ + - ][ + - ]: 2 : isc_throw(InvalidRdataText,
164 : : "Invalid hex encoding of generic RDATA");
165 : : }
166 : 523900 : data.push_back(ch);
167 : : iss >> ws; // skip spaces
168 : : }
169 : :
170 [ + + ]: 262 : if (!iss.eof()) {
171 [ + - ][ + - ]: 2 : isc_throw(InvalidRdataLength,
172 : : "RDLENGTH is too small for generic RDATA");
173 : : }
174 : :
175 [ + + ]: 261 : if (data.size() != rdlen) {
176 [ + - ][ + - ]: 2 : isc_throw(InvalidRdataLength,
177 : : "Generic RDATA code doesn't match RDLENGTH");
178 : : }
179 : :
180 [ + - ]: 260 : impl_ = new GenericImpl(data);
181 : 260 : }
182 : :
183 : 586 : Generic::~Generic() {
184 [ + - ]: 604 : delete impl_;
185 : 586 : }
186 : :
187 : 28 : Generic::Generic(const Generic& source) :
188 [ + - ]: 28 : Rdata(), impl_(new GenericImpl(*source.impl_))
189 : 28 : {}
190 : :
191 : : Generic&
192 : 3 : Generic::operator=(const Generic& source) {
193 [ + + ]: 3 : if (impl_ == source.impl_) {
194 : : return (*this);
195 : : }
196 : :
197 : 2 : GenericImpl* newimpl = new GenericImpl(*source.impl_);
198 [ + - ]: 4 : delete impl_;
199 : 2 : impl_ = newimpl;
200 : :
201 : 3 : return (*this);
202 : : }
203 : :
204 : : namespace {
205 : : class UnknownRdataDumper {
206 : : public:
207 : 6 : UnknownRdataDumper(ostringstream& oss) : oss_(&oss) {}
208 : : void operator()(const unsigned char d)
209 : : {
210 : 131326 : *oss_ << setw(2) << static_cast<unsigned int>(d);
211 : : }
212 : : private:
213 : : ostringstream* oss_;
214 : : };
215 : : }
216 : :
217 : : string
218 : 6 : Generic::toText() const {
219 : 12 : ostringstream oss;
220 : :
221 [ + - ][ + - ]: 12 : oss << "\\# " << impl_->data_.size() << " ";
222 : : oss.fill('0');
223 : 6 : oss << right << hex;
224 : 12 : for_each(impl_->data_.begin(), impl_->data_.end(), UnknownRdataDumper(oss));
225 : :
226 : 6 : return (oss.str());
227 : : }
228 : :
229 : : void
230 : 7 : Generic::toWire(isc::util::OutputBuffer& buffer) const {
231 : 7 : buffer.writeData(&impl_->data_[0], impl_->data_.size());
232 : 7 : }
233 : :
234 : : void
235 : 6 : Generic::toWire(AbstractMessageRenderer& renderer) const {
236 : 12 : renderer.writeData(&impl_->data_[0], impl_->data_.size());
237 : 6 : }
238 : :
239 : : namespace {
240 : : inline int
241 : : compare_internal(const GenericImpl& lhs, const GenericImpl& rhs) {
242 : 34 : size_t this_len = lhs.data_.size();
243 : 34 : size_t other_len = rhs.data_.size();
244 [ + + ]: 34 : size_t len = (this_len < other_len) ? this_len : other_len;
245 : : int cmp;
246 : :
247 : : // TODO: is there a need to check len - should we just assert?
248 : : // (Depends if it is possible for rdata to have zero length)
249 [ + + ][ + + ]: 34 : if ((len != 0) &&
[ + + ]
250 : : ((cmp = memcmp(&lhs.data_[0], &rhs.data_[0], len)) != 0)) {
251 : : return (cmp);
252 : : } else {
253 : : return ((this_len == other_len) ? 0 :
254 [ + + ][ + + ]: 30 : (this_len < other_len) ? -1 : 1);
255 : : }
256 : : }
257 : : }
258 : :
259 : : int
260 : 34 : Generic::compare(const Rdata& other) const {
261 [ + - ]: 34 : const Generic& other_rdata = dynamic_cast<const Generic&>(other);
262 : :
263 : 34 : return (compare_internal(*impl_, *other_rdata.impl_));
264 : : }
265 : :
266 : : std::ostream&
267 : 1 : operator<<(std::ostream& os, const Generic& rdata) {
268 [ + - ]: 1 : return (os << rdata.toText());
269 : : }
270 : : } // end of namespace generic
271 : :
272 : : } // end of namespace rdata
273 : : }
274 : 6 : }
|