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 <config.h>
16 : :
17 : : #include <stdint.h>
18 : :
19 : : #include <cassert>
20 : :
21 : : #include <boost/lexical_cast.hpp>
22 : :
23 : : #include <exceptions/exceptions.h>
24 : :
25 : : #include <dns/edns.h>
26 : : #include <dns/exceptions.h>
27 : : #include <dns/message.h>
28 : : #include <dns/messagerenderer.h>
29 : : #include <dns/name.h>
30 : : #include <dns/rdata.h>
31 : : #include <dns/rdataclass.h>
32 : : #include <dns/rrclass.h>
33 : : #include <dns/rrttl.h>
34 : : #include <dns/rrtype.h>
35 : :
36 : : using namespace std;
37 : : using namespace boost;
38 : : using namespace isc::dns::rdata;
39 : : using namespace isc::util;
40 : :
41 : : namespace isc {
42 : : namespace dns {
43 : :
44 : : namespace {
45 : : // This diagram shows the wire-format representation of the TTL field of
46 : : // OPT RR and its relationship with implementation specific parameters.
47 : : //
48 : : // 0 7 15 31
49 : : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 : : // | EXTENDED-RCODE| VERSION |D| Z |
51 : : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 : : // <= VERSION_SHIFT (16 bits)
53 : : // <= EXTRCODE_SHIFT (24 bits)
54 : : //EXTFLAG_DO:0 0 0 ....................... 0 1 0 0 0 0.....................0
55 : : //VER_MASK: 0 0 0 ........0 1 1 1 1 1 1 1 1 0 0 ..........................0
56 : :
57 : : const unsigned int VERSION_SHIFT = 16;
58 : : const unsigned int EXTRCODE_SHIFT = 24;
59 : : const uint32_t VERSION_MASK = 0x00ff0000;
60 : : const uint32_t EXTFLAG_DO = 0x00008000;
61 : : }
62 : :
63 : 129 : EDNS::EDNS(const uint8_t version) :
64 : : version_(version),
65 : : udp_size_(Message::DEFAULT_MAX_UDPSIZE),
66 : 129 : dnssec_aware_(false)
67 : : {
68 [ + + ]: 129 : if (version_ > SUPPORTED_VERSION) {
69 [ + - ]: 6 : isc_throw(isc::InvalidParameter,
70 : : "failed to construct EDNS: unsupported version: " <<
71 : : static_cast<unsigned int>(version_));
72 : : }
73 : 127 : }
74 : :
75 : 72 : EDNS::EDNS(const Name& name, const RRClass& rrclass, const RRType& rrtype,
76 : : const RRTTL& ttl, const Rdata&) :
77 : 72 : version_((ttl.getValue() & VERSION_MASK) >> VERSION_SHIFT)
78 : : {
79 [ + + ]: 72 : if (rrtype != RRType::OPT()) {
80 [ + - ][ + - ]: 4 : isc_throw(isc::InvalidParameter,
81 : : "EDNS is being created with incompatible RR type: "
82 : : << rrtype);
83 : : }
84 : :
85 [ + + ]: 70 : if (version_ > EDNS::SUPPORTED_VERSION) {
86 [ + - ]: 21 : isc_throw(DNSMessageBADVERS, "unsupported EDNS version: " <<
87 : : static_cast<unsigned int>(version_));
88 : : }
89 : :
90 [ + + ]: 126 : if (name != Name::ROOT_NAME()) {
91 [ + - ][ + - ]: 6 : isc_throw(DNSMessageFORMERR, "invalid owner name for EDNS OPT RR: " <<
92 : : name);
93 : : }
94 : :
95 : 60 : dnssec_aware_ = ((ttl.getValue() & EXTFLAG_DO) != 0);
96 : 60 : udp_size_ = rrclass.getCode();
97 : 60 : }
98 : :
99 : : string
100 : 24 : EDNS::toText() const {
101 : 24 : string ret = "; EDNS: version: ";
102 : :
103 : 24 : ret += lexical_cast<string>(static_cast<int>(getVersion()));
104 : : ret += ", flags:";
105 [ + + ]: 24 : if (getDNSSECAwareness()) {
106 : : ret += " do";
107 : : }
108 : 24 : ret += "; udp: " + lexical_cast<string>(getUDPSize()) + "\n";
109 : :
110 : 24 : return (ret);
111 : : }
112 : :
113 : : namespace {
114 : : /// Helper function to define unified implementation for the public versions
115 : : /// of toWire().
116 : : template <typename Output>
117 : : int
118 : 143 : toWireCommon(Output& output, const uint8_t version,
119 : : const uint16_t udp_size, const bool dnssec_aware,
120 : : const uint8_t extended_rcode)
121 : : {
122 : : // Render EDNS OPT RR
123 : 143 : uint32_t extrcode_flags = extended_rcode << EXTRCODE_SHIFT;
124 : 143 : extrcode_flags |= (version << VERSION_SHIFT) & VERSION_MASK;
125 [ - + ][ + + ]: 143 : if (dnssec_aware) {
126 : 19 : extrcode_flags |= EXTFLAG_DO;
127 : : }
128 : :
129 : : // Construct an RRset corresponding to the EDNS.
130 : : // We don't support any options for now, so the OPT RR can be empty.
131 : : RRsetPtr edns_rrset(new RRset(Name::ROOT_NAME(), RRClass(udp_size),
132 [ + - ][ + - ]: 143 : RRType::OPT(), RRTTL(extrcode_flags)));
133 [ + - ][ + - ]: 143 : edns_rrset->addRdata(ConstRdataPtr(new generic::OPT()));
[ + - + - ]
[ + - ][ + - ]
134 : :
135 [ + - ][ + - ]: 143 : edns_rrset->toWire(output);
136 : :
137 : 143 : return (1);
138 : : }
139 : : }
140 : :
141 : : unsigned int
142 : 143 : EDNS::toWire(AbstractMessageRenderer& renderer,
143 : : const uint8_t extended_rcode) const
144 : : {
145 : : // If adding the OPT RR would exceed the size limit, don't do it.
146 : : // 11 = len(".") + type(2byte) + class(2byte) + TTL(4byte) + RDLEN(2byte)
147 : : // (RDATA is empty in this simple implementation)
148 [ + + ]: 143 : if (renderer.getLength() + 11 > renderer.getLengthLimit()) {
149 : : return (0);
150 : : }
151 : :
152 : : return (toWireCommon(renderer, version_, udp_size_, dnssec_aware_,
153 : 143 : extended_rcode));
154 : : }
155 : :
156 : : unsigned int
157 : 2 : EDNS::toWire(isc::util::OutputBuffer& buffer,
158 : : const uint8_t extended_rcode) const
159 : : {
160 : : return (toWireCommon(buffer, version_, udp_size_, dnssec_aware_,
161 : 2 : extended_rcode));
162 : : }
163 : :
164 : : EDNS*
165 : 60 : createEDNSFromRR(const Name& name, const RRClass& rrclass,
166 : : const RRType& rrtype, const RRTTL& ttl,
167 : : const Rdata& rdata,
168 : : uint8_t& extended_rcode)
169 : : {
170 : : // Create a new EDNS object first for exception guarantee.
171 [ + + ]: 60 : EDNS* edns = new EDNS(name, rrclass, rrtype, ttl, rdata);
172 : :
173 : : // At this point we can update extended_rcode safely.
174 : 51 : extended_rcode = ttl.getValue() >> EXTRCODE_SHIFT;
175 : :
176 : 51 : return (edns);
177 : : }
178 : :
179 : : ostream&
180 : 1 : operator<<(std::ostream& os, const EDNS& edns) {
181 [ + - ]: 1 : os << edns.toText();
182 : 1 : return (os);
183 : : }
184 : :
185 : : } // end of namespace dns
186 : 137 : } // end of namespace isc
|