Branch data Line data Source code
1 : : // Copyright (C) 2011 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 "glue_hints.h"
16 : :
17 : : #include <stdlib.h>
18 : :
19 : : #include <dns/rrset.h>
20 : : #include <dns/rdata.h>
21 : : #include <dns/rrtype.h>
22 : : #include <dns/rdataclass.h>
23 : :
24 : : #include <asiolink/io_address.h>
25 : : #include <nsas/nameserver_entry.h>
26 : :
27 : : using namespace isc::dns;
28 : : using namespace isc::nsas;
29 : :
30 : : // This is a simple implementation for finding glue
31 : : //
32 : : // It iterates over the AUTHORITY section of the given Message,
33 : : // and for each NS RR it iterates over the ADDITIONAL section to
34 : : // see if there are A or AAAA records.
35 : : //
36 : : // Of course, this could be done more efficiently. One option is to
37 : : // reverse this; check for A and AAAA records (since those will only
38 : : // be there if there actually is glue, while NS records will be present
39 : : // in any delegation). However, it may be even better to let the
40 : : // Response Classifier decide on glue, while it is validating the packet
41 : : //
42 : : // (er, TODO, so to speak. discuss.)
43 : :
44 : : // Helper functions
45 : : namespace {
46 : : // Add the contents of the given A or AAAA rrset to the given
47 : : // addressvector
48 : : //
49 : : // This creates an 'dummy' NameserverEntry value, because that
50 : : // is enforced by NameserverAddress. We may want to reconsider
51 : : // the need for that (perhaps we can change it so that if it is
52 : : // NULL, all NSAS-related calls to the NameserverAddress object
53 : : // become nops)
54 : : void
55 : 4 : addRRset(std::vector<NameserverAddress>& addresses,
56 : : const RRsetPtr rrset)
57 : : {
58 : 8 : const std::string ns_name = rrset->getName().toText();
59 [ + - ]: 4 : RdataIteratorPtr rdi = rrset->getRdataIterator();
60 [ + - ][ + + ]: 8 : while (!rdi->isLast()) {
61 [ + - ][ + - ]: 4 : AddressEntry entry(isc::asiolink::IOAddress(rdi->getCurrent().toText()));
[ + - ]
62 [ + - ][ + - ]: 8 : boost::shared_ptr<NameserverEntry> ns_entry(new NameserverEntry(ns_name, rrset->getClass()));
[ + - ]
63 : : NameserverAddress ns_address(ns_entry, entry, V4_ONLY);
64 : : addresses.push_back(ns_address);
65 [ + - ]: 4 : rdi->next();
66 : : }
67 : 4 : }
68 : : }
69 : :
70 : : namespace isc {
71 : : namespace nsas {
72 : :
73 : 2 : GlueHints::GlueHints(const std::string& zone_name,
74 : 0 : const isc::dns::Message& delegation_message)
75 : : {
76 [ + - ][ + - ]: 12 : for (RRsetIterator rssi = delegation_message.beginSection(Message::SECTION_AUTHORITY);
[ + - ][ + + ]
[ + - ]
77 [ + - ][ + - ]: 8 : rssi != delegation_message.endSection(Message::SECTION_AUTHORITY);
78 : : ++rssi) {
79 [ + - ][ + - ]: 6 : if ((*rssi)->getType() == RRType::NS() &&
[ + - ][ - + ]
[ + - ]
80 [ + - ][ + - ]: 4 : (*rssi)->getName().toText() == zone_name) {
[ + - ][ + - ]
81 [ + - ][ + - ]: 4 : addGlueForRRset(*rssi, delegation_message);
82 : : }
83 : : }
84 : 2 : }
85 : :
86 : :
87 : : bool
88 : 30 : GlueHints::hasGlue(AddressFamily family) const {
89 : 30 : return ((!addresses_v4.empty() && (family == ANY_OK || family == V4_ONLY)) ||
90 [ + + ][ - + ]: 30 : (!addresses_v6.empty() && (family == ANY_OK || family == V6_ONLY)));
[ - + ][ # # ]
91 : : }
92 : :
93 : : NameserverAddress
94 : 2 : GlueHints::getGlue(AddressFamily family) const {
95 : : // TODO: once we have a more general random lib, use that. Since
96 : : // this is simply glue, and we don't need a weighted selection,
97 : : // for now srandom should be good enough. Once #583 has been merged,
98 : : // (or better yet, once that one and the weighted random have gone
99 : : // together in a util lib), we can use that.
100 : 2 : int max = 0;
101 : 2 : size_t v4s = addresses_v4.size();
102 : 2 : size_t v6s = addresses_v6.size();
103 : :
104 [ + - ]: 2 : if (family == ANY_OK || family == V4_ONLY) {
105 : 2 : max += v4s;
106 : : }
107 [ + - ]: 2 : if (family == ANY_OK || family == V6_ONLY) {
108 : 2 : max += v6s;
109 : : }
110 : :
111 [ - + ]: 2 : assert(max > 0);
112 : 2 : long int selection = random() % max;
113 : :
114 [ + - ]: 2 : if (family == ANY_OK) {
115 [ + - ]: 2 : if (selection < v4s) {
116 : 2 : return addresses_v4[selection];
117 : : } else {
118 : 0 : return addresses_v6[selection-v4s];
119 : : }
120 [ # # ]: 0 : } else if (family == V4_ONLY) {
121 : 0 : return addresses_v4[selection];
122 [ # # ]: 0 : } else if (family == V6_ONLY) {
123 : 0 : return addresses_v6[selection];
124 : : } else {
125 : : // Unknown family
126 : 2 : assert(false);
127 : : // Some compilers want something returned anyway
128 : : return NameserverAddress();
129 : : }
130 : : }
131 : :
132 : : // Add the A and AAAA records from the given message for the given
133 : : // NS name to the relevant address vector
134 : : // (A rrsets are added to addresses_v4, AAAA rrsets are added to
135 : : // addresses_v6).
136 : : void
137 : 4 : GlueHints::addGlueForName(const Name& name, const Message& message)
138 : : {
139 [ + - ][ + - ]: 36 : for (RRsetIterator rssi = message.beginSection(Message::SECTION_ADDITIONAL);
[ + + ]
140 [ + - ][ + - ]: 24 : rssi != message.endSection(Message::SECTION_ADDITIONAL);
141 : : ++rssi) {
142 [ + - ][ + - ]: 16 : if ((*rssi)->getName() == name) {
[ + + ]
143 [ + - ][ + - ]: 4 : if ((*rssi)->getType() == RRType::A()) {
[ + - ]
144 [ + - ][ + - ]: 8 : addRRset(addresses_v4, *rssi);
145 [ # # ][ # # ]: 0 : } else if ((*rssi)->getType() == RRType::AAAA()) {
[ # # ]
146 [ # # ][ # # ]: 0 : addRRset(addresses_v6, *rssi);
147 : : }
148 : : }
149 : : }
150 : 4 : }
151 : :
152 : : // Add the glue for the given NS RRset in the message to the
153 : : // relevant vectors.
154 : : void
155 : 2 : GlueHints::addGlueForRRset(const RRsetPtr rrset, const Message& message)
156 : : {
157 : 2 : RdataIteratorPtr rdi = rrset->getRdataIterator();
158 [ + - ][ + + ]: 6 : while (!rdi->isLast()) {
159 : : isc::dns::Name name(dynamic_cast<const rdata::generic::NS&>(
160 [ + - ][ + - ]: 8 : rdi->getCurrent()).getNSName());
[ + - ]
161 [ + - ]: 4 : addGlueForName(name, message);
162 [ + - ]: 4 : rdi->next();
163 : : }
164 : 2 : }
165 : :
166 : :
167 : : } // namespace nsas
168 : 4 : } // namespace isc
|