File: libsres-implementation-notes

package info (click to toggle)
dnssec-tools 1.13-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 16,064 kB
  • sloc: perl: 44,399; ansic: 31,547; cpp: 21,306; sh: 15,813; xml: 2,113; makefile: 1,390; pascal: 836; python: 290; csh: 11
file content (197 lines) | stat: -rw-r--r-- 8,266 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# Copyright 2004-2012 SPARTA, Inc.  All rights reserved.
# See the COPYING file included with the dnssec-tools package for details.


			     DNSSEC-Tools
			Is your domain secure?


DNSSEC-aware Resolver library
-----------------------------

A library that is capable of sending queries to, and receiving answers
from a DNSSEC-aware name server.


Overview 
--------

This library provides the resolver component of the "validating resolver"
(see libval_implementation_notes for details on the validator component). 
It provides the interfaces necessary for the validator to fetch answers from
a DNSSEC-aware name server. 

Most of the implementation of the resolver component and some for the 
validator library was re-used from an older implementation of the secure 
resolver library developed at Tislabs. The older implementation was
built as per the older RFC 2535 DNSSEC specifications and modifications 
were made so that our library was conformant to the newer specifications 
and also contained other feature improvements.  The choice to split
the secure resolver functionality into two libraries was made in order to 
decouple these two distinct roles. Given a well documented interface between 
these two components it could then be possible to plug the
validator component with applications that contain their own native 
implementation of the resolver functionality.

The resolver library does not itself perform any recursion. This design 
choice was made reduce the complexity within the resolver and keep it
as DNSSEC-agnostic as possible (DNSSEC-relevant information may be present in
the additional section of the referrals). The library still needs to be 
'DNSSEC-aware' in that queries that it sends must have the DO bit 
(and consequently EDNS0) and CD bits set to permit all DNSSEC-relevant 
resource records to be returned in different sections of the DNS response. 

The resolver library is built to support both synchronous as well as 
asynchronous queries to the DNS. Asynchronous queries are a useful 
optimization feature in some instances, where it is possible to 
parallize other time-consuming operations while the query is in transit.

The following interfaces are exported by the libsres library (more 
details may be found in the libsres manual page):

int query_send( const char      *name,
            const u_int16_t     type,
            const u_int16_t     class,
            struct name_server  *nslist,
            int                 edns0_size,
            int                 *trans_id);

int response_recv(int           *trans_id,
            struct name_server  **respondent,
            u_int8_t            **response,
            u_int32_t           *response_length);

int get ( const char            *name_n,
            const u_int16_t     type_h,
            const u_int16_t     class_h,
            struct name_server  *nslist,
            int                 edns0_size,
            struct name_server  **respondent,
            u_int8_t            **response,
            u_int32_t           *response_length);

int clone_ns(struct name_server **cloned_ns, struct name_server *ns);

int clone_ns_list(struct name_server **ns_list,
                        struct name_server *orig_ns_list);

void free_name_server (struct name_server **ns);

void free_name_servers (struct name_server **ns);

query_send() and response_recv() provide the asynchronous query/response 
interface to the libsres library. A synchronous interface to the 
query/response mechanism can be implemented using the above interfaces 
as shown below:

if (SR_UNSET == (ret_val = query_send(name, type, class, 
        				nslist, EDNS_UDP_SIZE, &trans_id))) {
	do {
		ret_val = response_recv(&trans_id, server, 
						response, response_length);
	} while (ret_val == SR_NO_ANSWER_YET);
}

The above code segment forms the essence of the get() interface.

The response_recv() function never blocks. The validator must constantly
poll the resolver to see if any data has arrived.

The clone_ns (clone_ns_list) interface can be used to make a copy of an
existing name server structure (name server list). The free_name_server(s)
methods can be used to free up memory allocated within the name_server
structure.

Other symbols exported by the libsres library include the following: 
        nametoclass, nametotype,
        ns_name_ntop, ns_name_pton, ns_name_unpack ns_parse_ttl,
        p_class, p_section p_type
The above are helper functions that have been directly imported from 
the BIND library. p_type has been enhanced so that the DNSSEC RR types 
(such as DNSKEY, RRSIG, NSEC, NSEC3, DLV) are also recognized.

The libsres libarary perfoms some basic header checking on the 
data that it receives from the name server before sending it on to
the application that initiated the query. The rcodes normally returned 
by the name server are passed back as return values to the get() and 
response_recv() methods. Only two non-error rcodes exist -- 
the no error RCODE itself and the NXDOMAIN response. The NXDOMAIN 
response is considered as "no error" when there are only SOA or NSEC 
records in the authority section (proof of non-existence).

The query transmission framework
--------------------------------

The brief algorithm is as given below. This logic is invoked each time a 
call is made to the res_io_accept method().

1. while there are more name servers to query
	1.1. Send the query to the first name server and wait for ns.ns_retrans
             seconds
	1.2. If there is no response, send the query to the next name server and
	     increment the delay for the first name server by its current
             ns_retrans 
	1.3. If the number of retries for a name server has exceeded ns.ns_retry
             stop attempting to re-send this query to this name servers. 
	1.4. Keep adding name servers in a staggered fashion while re-trying
             queries to existing name servers.
2. wait for a response or for all requests to time out

If res_io_method() is called within a loop (such as the case in get()), the 
pattern of (re)transmissions is roughly ( for _res.retries = 4, 
_res.delay = 5, three servers, one address each):

         0  5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 (seconds)
Svr 1 :  1  2     3           4                Give up
Svr 2 :     1  2     3           4                Give up
Svr 3 :        1  2     3           4                Give up

All pending queries are destroyed once an answer is obtained. From
the application's standpoint the answer may still not be complete 
(for example, RRSIGs may be missing), in which case it may wish to 
retry a different set of name servers or query separately for missing data. 


Resolver Current Status
-----------------------

This library provides very basic functionality for name resolution. 
The data structures and interfaces exported to applications are still 
in a state of flux.  

The following enhancements still need to be made:

1. Clean up the interface between the resolver and the validator.

2. The current design requires the validator to constantly poll the resolver
for data. Since the calls are non-blocking, this process may have some 
demands on CPU cycles. A better approach would be for the validator to 
never have to poll the resolver for data once a query is issued; 
instead, the resolver should invoke some callback function to hand over 
any data back to the validator or to any other program that requested 
such data.  

3. Most zones are served by multiple name servers. Only the answer returned
by the first name server is used. The resolver needs to keep track of 
the response times for different name servers so that future queries to the
same zone can be made on a preferential basis to name servers that have the
best response time.

4. The measures outlined in draft-ietf-dnsext-forgery-resilience must be
followed.

5. Support for TSIG

6. Detection of multiple responses for a given query



Acknowledgements
----------------

Most of the code in the libsres library was derived from an earlier 
implementation of the secure resolver library written by 
Ed Lewis at Tislabs. 

libsres has some reliance on BIND code (although these are mostly 
helper routines) and some other libbind artifacts.