1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer * dnssec.c
3825eb42bSJan Lentfer * Some DNSSEC helper function are defined here
4825eb42bSJan Lentfer * and tracing is done
5825eb42bSJan Lentfer * (c) 2005 NLnet Labs
6825eb42bSJan Lentfer *
7825eb42bSJan Lentfer * See the file LICENSE for the license
8825eb42bSJan Lentfer *
9825eb42bSJan Lentfer */
10825eb42bSJan Lentfer
11825eb42bSJan Lentfer #include "drill.h"
12825eb42bSJan Lentfer #include <ldns/ldns.h>
13825eb42bSJan Lentfer
14825eb42bSJan Lentfer /* get rr_type from a server from a server */
15825eb42bSJan Lentfer ldns_rr_list *
get_rr(ldns_resolver * res,ldns_rdf * zname,ldns_rr_type t,ldns_rr_class c)16825eb42bSJan Lentfer get_rr(ldns_resolver *res, ldns_rdf *zname, ldns_rr_type t, ldns_rr_class c)
17825eb42bSJan Lentfer {
18825eb42bSJan Lentfer /* query, retrieve, extract and return */
19825eb42bSJan Lentfer ldns_pkt *p;
20825eb42bSJan Lentfer ldns_rr_list *found;
21825eb42bSJan Lentfer
22825eb42bSJan Lentfer p = ldns_pkt_new();
23825eb42bSJan Lentfer found = NULL;
24825eb42bSJan Lentfer
25d1b2b5caSJohn Marino if (ldns_resolver_send(&p, res, zname, t, c, 0) == LDNS_STATUS_OK) {
26825eb42bSJan Lentfer found = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANY_NOQUESTION);
27825eb42bSJan Lentfer }
28d1b2b5caSJohn Marino ldns_pkt_free(p);
29825eb42bSJan Lentfer return found;
30825eb42bSJan Lentfer }
31825eb42bSJan Lentfer
32825eb42bSJan Lentfer void
drill_pkt_print(FILE * fd,ldns_resolver * r,ldns_pkt * p)33825eb42bSJan Lentfer drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p)
34825eb42bSJan Lentfer {
35825eb42bSJan Lentfer ldns_rr_list *new_nss;
36825eb42bSJan Lentfer ldns_rr_list *hostnames;
37d1b2b5caSJohn Marino char *answerfrom_str;
38825eb42bSJan Lentfer
39825eb42bSJan Lentfer if (verbosity < 5) {
40825eb42bSJan Lentfer return;
41825eb42bSJan Lentfer }
42825eb42bSJan Lentfer
43825eb42bSJan Lentfer hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
44825eb42bSJan Lentfer
45825eb42bSJan Lentfer new_nss = ldns_pkt_rr_list_by_type(p,
46825eb42bSJan Lentfer LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
47825eb42bSJan Lentfer ldns_rr_list_print(fd, new_nss);
48d1b2b5caSJohn Marino ldns_rr_list_deep_free(new_nss);
49825eb42bSJan Lentfer
50825eb42bSJan Lentfer fprintf(fd, ";; Received %d bytes from %s#%d(",
51825eb42bSJan Lentfer (int) ldns_pkt_size(p),
52825eb42bSJan Lentfer ldns_rdf2str(ldns_pkt_answerfrom(p)),
53825eb42bSJan Lentfer (int) ldns_resolver_port(r));
54825eb42bSJan Lentfer /* if we can resolve this print it, other print the ip again */
55825eb42bSJan Lentfer if (hostnames) {
56825eb42bSJan Lentfer ldns_rdf_print(fd,
57825eb42bSJan Lentfer ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
58825eb42bSJan Lentfer ldns_rr_list_deep_free(hostnames);
59825eb42bSJan Lentfer } else {
60d1b2b5caSJohn Marino answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
61d1b2b5caSJohn Marino if (answerfrom_str) {
62d1b2b5caSJohn Marino fprintf(fd, "%s", answerfrom_str);
63d1b2b5caSJohn Marino LDNS_FREE(answerfrom_str);
64d1b2b5caSJohn Marino }
65825eb42bSJan Lentfer }
66825eb42bSJan Lentfer fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
67825eb42bSJan Lentfer }
68825eb42bSJan Lentfer
69825eb42bSJan Lentfer void
drill_pkt_print_footer(FILE * fd,ldns_resolver * r,ldns_pkt * p)70825eb42bSJan Lentfer drill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p)
71825eb42bSJan Lentfer {
72825eb42bSJan Lentfer ldns_rr_list *hostnames;
73d1b2b5caSJohn Marino char *answerfrom_str;
74825eb42bSJan Lentfer
75825eb42bSJan Lentfer if (verbosity < 5) {
76825eb42bSJan Lentfer return;
77825eb42bSJan Lentfer }
78825eb42bSJan Lentfer
79825eb42bSJan Lentfer hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
80825eb42bSJan Lentfer
81825eb42bSJan Lentfer fprintf(fd, ";; Received %d bytes from %s#%d(",
82825eb42bSJan Lentfer (int) ldns_pkt_size(p),
83825eb42bSJan Lentfer ldns_rdf2str(ldns_pkt_answerfrom(p)),
84825eb42bSJan Lentfer (int) ldns_resolver_port(r));
85825eb42bSJan Lentfer /* if we can resolve this print it, other print the ip again */
86825eb42bSJan Lentfer if (hostnames) {
87825eb42bSJan Lentfer ldns_rdf_print(fd,
88825eb42bSJan Lentfer ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
89825eb42bSJan Lentfer ldns_rr_list_deep_free(hostnames);
90825eb42bSJan Lentfer } else {
91d1b2b5caSJohn Marino answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
92d1b2b5caSJohn Marino if (answerfrom_str) {
93d1b2b5caSJohn Marino fprintf(fd, "%s", answerfrom_str);
94d1b2b5caSJohn Marino LDNS_FREE(answerfrom_str);
95d1b2b5caSJohn Marino }
96825eb42bSJan Lentfer }
97825eb42bSJan Lentfer fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
98825eb42bSJan Lentfer }
99825eb42bSJan Lentfer /*
100825eb42bSJan Lentfer * generic function to get some RRset from a nameserver
101825eb42bSJan Lentfer * and possible some signatures too (that would be the day...)
102825eb42bSJan Lentfer */
103825eb42bSJan Lentfer ldns_pkt_type
get_dnssec_rr(ldns_pkt * p,ldns_rdf * name,ldns_rr_type t,ldns_rr_list ** rrlist,ldns_rr_list ** sig)104825eb42bSJan Lentfer get_dnssec_rr(ldns_pkt *p, ldns_rdf *name, ldns_rr_type t,
105825eb42bSJan Lentfer ldns_rr_list **rrlist, ldns_rr_list **sig)
106825eb42bSJan Lentfer {
107825eb42bSJan Lentfer ldns_pkt_type pt = LDNS_PACKET_UNKNOWN;
108825eb42bSJan Lentfer ldns_rr_list *sigs = NULL;
109825eb42bSJan Lentfer size_t i;
110825eb42bSJan Lentfer
111825eb42bSJan Lentfer if (!p) {
112825eb42bSJan Lentfer if (rrlist) {
113825eb42bSJan Lentfer *rrlist = NULL;
114825eb42bSJan Lentfer }
115825eb42bSJan Lentfer return LDNS_PACKET_UNKNOWN;
116825eb42bSJan Lentfer }
117825eb42bSJan Lentfer
118825eb42bSJan Lentfer pt = ldns_pkt_reply_type(p);
119825eb42bSJan Lentfer if (name) {
120d1b2b5caSJohn Marino if (rrlist) {
121d1b2b5caSJohn Marino *rrlist = ldns_pkt_rr_list_by_name_and_type(p, name, t,
122d1b2b5caSJohn Marino LDNS_SECTION_ANSWER);
123d1b2b5caSJohn Marino if (!*rrlist) {
124d1b2b5caSJohn Marino *rrlist = ldns_pkt_rr_list_by_name_and_type(
125d1b2b5caSJohn Marino p, name, t,
126d1b2b5caSJohn Marino LDNS_SECTION_AUTHORITY);
127825eb42bSJan Lentfer }
128d1b2b5caSJohn Marino }
129d1b2b5caSJohn Marino if (sig) {
130d1b2b5caSJohn Marino sigs = ldns_pkt_rr_list_by_name_and_type(p, name,
131d1b2b5caSJohn Marino LDNS_RR_TYPE_RRSIG,
132825eb42bSJan Lentfer LDNS_SECTION_ANSWER);
133825eb42bSJan Lentfer if (!sigs) {
134d1b2b5caSJohn Marino sigs = ldns_pkt_rr_list_by_name_and_type(
135d1b2b5caSJohn Marino p, name, LDNS_RR_TYPE_RRSIG,
136825eb42bSJan Lentfer LDNS_SECTION_AUTHORITY);
137825eb42bSJan Lentfer }
138d1b2b5caSJohn Marino }
139825eb42bSJan Lentfer } else {
140825eb42bSJan Lentfer /* A DS-referral - get the DS records if they are there */
141d1b2b5caSJohn Marino if (rrlist) {
142d1b2b5caSJohn Marino *rrlist = ldns_pkt_rr_list_by_type(
143d1b2b5caSJohn Marino p, t, LDNS_SECTION_AUTHORITY);
144d1b2b5caSJohn Marino }
145d1b2b5caSJohn Marino if (sig) {
146d1b2b5caSJohn Marino sigs = ldns_pkt_rr_list_by_type(p,
147d1b2b5caSJohn Marino LDNS_RR_TYPE_RRSIG,
148825eb42bSJan Lentfer LDNS_SECTION_AUTHORITY);
149825eb42bSJan Lentfer }
150d1b2b5caSJohn Marino }
151825eb42bSJan Lentfer if (sig) {
152825eb42bSJan Lentfer *sig = ldns_rr_list_new();
153825eb42bSJan Lentfer for (i = 0; i < ldns_rr_list_rr_count(sigs); i++) {
154825eb42bSJan Lentfer /* only add the sigs that cover this type */
155d1b2b5caSJohn Marino if (t == ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(
156d1b2b5caSJohn Marino ldns_rr_list_rr(sigs, i)))) {
157d1b2b5caSJohn Marino
158d1b2b5caSJohn Marino ldns_rr_list_push_rr(*sig,
159d1b2b5caSJohn Marino ldns_rr_clone(
160d1b2b5caSJohn Marino ldns_rr_list_rr(
161d1b2b5caSJohn Marino sigs, i)));
162825eb42bSJan Lentfer }
163825eb42bSJan Lentfer }
164825eb42bSJan Lentfer }
165825eb42bSJan Lentfer ldns_rr_list_deep_free(sigs);
166825eb42bSJan Lentfer
167825eb42bSJan Lentfer if (pt == LDNS_PACKET_NXDOMAIN || pt == LDNS_PACKET_NODATA) {
168825eb42bSJan Lentfer return pt;
169825eb42bSJan Lentfer } else {
170825eb42bSJan Lentfer return LDNS_PACKET_ANSWER;
171825eb42bSJan Lentfer }
172825eb42bSJan Lentfer }
173825eb42bSJan Lentfer
174825eb42bSJan Lentfer
175825eb42bSJan Lentfer ldns_status
ldns_verify_denial(ldns_pkt * pkt,ldns_rdf * name,ldns_rr_type type,ldns_rr_list ** nsec_rrs,ldns_rr_list ** nsec_rr_sigs)176825eb42bSJan Lentfer ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
177825eb42bSJan Lentfer {
178d1b2b5caSJohn Marino #ifdef HAVE_SSL
179825eb42bSJan Lentfer uint16_t nsec_i;
180825eb42bSJan Lentfer
181825eb42bSJan Lentfer ldns_rr_list *nsecs;
182825eb42bSJan Lentfer ldns_status result;
183*ee791febSAntonio Huete Jimenez const ldns_rr_descriptor *descriptor;
184825eb42bSJan Lentfer
185*ee791febSAntonio Huete Jimenez if (!pkt) {
186*ee791febSAntonio Huete Jimenez descriptor = ldns_rr_descript(type);
187*ee791febSAntonio Huete Jimenez
188*ee791febSAntonio Huete Jimenez printf("NETWORk ERROR! Cannot verify denial for: ");
189*ee791febSAntonio Huete Jimenez ldns_rdf_print(stdout, name);
190*ee791febSAntonio Huete Jimenez printf(" type ");
191*ee791febSAntonio Huete Jimenez if (descriptor && descriptor->_name)
192*ee791febSAntonio Huete Jimenez printf("%s", descriptor->_name);
193*ee791febSAntonio Huete Jimenez else
194*ee791febSAntonio Huete Jimenez printf("TYPE%u", type);
195*ee791febSAntonio Huete Jimenez return LDNS_STATUS_CRYPTO_NO_RRSIG;
196*ee791febSAntonio Huete Jimenez }
197825eb42bSJan Lentfer if (verbosity >= 5) {
198825eb42bSJan Lentfer printf("VERIFY DENIAL FROM:\n");
199825eb42bSJan Lentfer ldns_pkt_print(stdout, pkt);
200825eb42bSJan Lentfer }
201825eb42bSJan Lentfer
202825eb42bSJan Lentfer result = LDNS_STATUS_CRYPTO_NO_RRSIG;
203825eb42bSJan Lentfer /* Try to see if there are NSECS in the packet */
204825eb42bSJan Lentfer nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
205825eb42bSJan Lentfer if (nsecs) {
206825eb42bSJan Lentfer for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
207825eb42bSJan Lentfer /* there are four options:
208825eb42bSJan Lentfer * - name equals ownername and is covered by the type bitmap
209825eb42bSJan Lentfer * - name equals ownername but is not covered by the type bitmap
210825eb42bSJan Lentfer * - name falls within nsec coverage but is not equal to the owner name
211825eb42bSJan Lentfer * - name falls outside of nsec coverage
212825eb42bSJan Lentfer */
213825eb42bSJan Lentfer if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
214825eb42bSJan Lentfer /*
215825eb42bSJan Lentfer printf("CHECKING NSEC:\n");
216825eb42bSJan Lentfer ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
217825eb42bSJan Lentfer printf("DAWASEM\n");
218825eb42bSJan Lentfer */
219825eb42bSJan Lentfer if (ldns_nsec_bitmap_covers_type(
220825eb42bSJan Lentfer ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
221825eb42bSJan Lentfer nsec_i)),
222825eb42bSJan Lentfer type)) {
223825eb42bSJan Lentfer /* Error, according to the nsec this rrset is signed */
224825eb42bSJan Lentfer result = LDNS_STATUS_CRYPTO_NO_RRSIG;
225825eb42bSJan Lentfer } else {
226825eb42bSJan Lentfer /* ok nsec denies existence */
227825eb42bSJan Lentfer if (verbosity >= 3) {
228825eb42bSJan Lentfer printf(";; Existence of data set with this type denied by NSEC\n");
229825eb42bSJan Lentfer }
230825eb42bSJan Lentfer /*printf(";; Verifiably insecure.\n");*/
231825eb42bSJan Lentfer if (nsec_rrs && nsec_rr_sigs) {
232825eb42bSJan Lentfer (void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
233825eb42bSJan Lentfer }
234825eb42bSJan Lentfer ldns_rr_list_deep_free(nsecs);
235825eb42bSJan Lentfer return LDNS_STATUS_OK;
236825eb42bSJan Lentfer }
237825eb42bSJan Lentfer } else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
238825eb42bSJan Lentfer if (verbosity >= 3) {
239825eb42bSJan Lentfer printf(";; Existence of data set with this name denied by NSEC\n");
240825eb42bSJan Lentfer }
241825eb42bSJan Lentfer if (nsec_rrs && nsec_rr_sigs) {
242825eb42bSJan Lentfer (void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
243825eb42bSJan Lentfer }
244825eb42bSJan Lentfer ldns_rr_list_deep_free(nsecs);
245825eb42bSJan Lentfer return LDNS_STATUS_OK;
246825eb42bSJan Lentfer } else {
247825eb42bSJan Lentfer /* nsec has nothing to do with this data */
248825eb42bSJan Lentfer }
249825eb42bSJan Lentfer }
250825eb42bSJan Lentfer ldns_rr_list_deep_free(nsecs);
251ac996e71SJan Lentfer } else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
252ac996e71SJan Lentfer ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
253ac996e71SJan Lentfer ldns_rr* q = ldns_rr_new();
254b5dedccaSJan Lentfer ldns_rr* match = NULL;
255d1b2b5caSJohn Marino
256d1b2b5caSJohn Marino if(!sigs) {
257d1b2b5caSJohn Marino if (q) {
258d1b2b5caSJohn Marino ldns_rr_free(q);
259d1b2b5caSJohn Marino }
260d1b2b5caSJohn Marino ldns_rr_list_deep_free(nsecs);
261d1b2b5caSJohn Marino return LDNS_STATUS_MEM_ERR;
262d1b2b5caSJohn Marino }
263d1b2b5caSJohn Marino if(!q) {
264d1b2b5caSJohn Marino ldns_rr_list_deep_free(nsecs);
265d1b2b5caSJohn Marino ldns_rr_list_deep_free(sigs);
266d1b2b5caSJohn Marino return LDNS_STATUS_MEM_ERR;
267d1b2b5caSJohn Marino }
268ac996e71SJan Lentfer ldns_rr_set_question(q, 1);
269ac996e71SJan Lentfer ldns_rr_set_ttl(q, 0);
270ac996e71SJan Lentfer ldns_rr_set_owner(q, ldns_rdf_clone(name));
271d1b2b5caSJohn Marino if(!ldns_rr_owner(q)) {
272d1b2b5caSJohn Marino ldns_rr_free(q);
273d1b2b5caSJohn Marino ldns_rr_list_deep_free(sigs);
274d1b2b5caSJohn Marino ldns_rr_list_deep_free(nsecs);
275d1b2b5caSJohn Marino return LDNS_STATUS_MEM_ERR;
276d1b2b5caSJohn Marino }
277ac996e71SJan Lentfer ldns_rr_set_type(q, type);
278ac996e71SJan Lentfer
279b5dedccaSJan Lentfer /* result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0); */
280b5dedccaSJan Lentfer result = ldns_dnssec_verify_denial_nsec3_match(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0, &match);
281b5dedccaSJan Lentfer if (result == LDNS_STATUS_OK && match && nsec_rrs && nsec_rr_sigs) {
282b5dedccaSJan Lentfer (void) get_dnssec_rr(pkt, ldns_rr_owner(match), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
283b5dedccaSJan Lentfer }
284ac996e71SJan Lentfer ldns_rr_free(q);
285ac996e71SJan Lentfer ldns_rr_list_deep_free(nsecs);
286ac996e71SJan Lentfer ldns_rr_list_deep_free(sigs);
287825eb42bSJan Lentfer }
288825eb42bSJan Lentfer return result;
289d1b2b5caSJohn Marino #else
290d1b2b5caSJohn Marino (void)pkt;
291d1b2b5caSJohn Marino (void)name;
292d1b2b5caSJohn Marino (void)type;
293d1b2b5caSJohn Marino (void)nsec_rrs;
294d1b2b5caSJohn Marino (void)nsec_rr_sigs;
295d1b2b5caSJohn Marino return LDNS_STATUS_ERR;
296d1b2b5caSJohn Marino #endif /* HAVE_SSL */
297825eb42bSJan Lentfer }
298825eb42bSJan Lentfer
299825eb42bSJan Lentfer /* NSEC3 draft -07 */
300825eb42bSJan Lentfer /*return hash name match*/
301825eb42bSJan Lentfer ldns_rr *
ldns_nsec3_exact_match(ldns_rdf * qname,ldns_rr_type qtype,ldns_rr_list * nsec3s)302825eb42bSJan Lentfer ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
303825eb42bSJan Lentfer uint8_t algorithm;
304825eb42bSJan Lentfer uint32_t iterations;
305825eb42bSJan Lentfer uint8_t salt_length;
306825eb42bSJan Lentfer uint8_t *salt;
307825eb42bSJan Lentfer
308d1b2b5caSJohn Marino ldns_rdf *sname = NULL, *hashed_sname = NULL;
309825eb42bSJan Lentfer
310825eb42bSJan Lentfer size_t nsec_i;
311825eb42bSJan Lentfer ldns_rr *nsec;
312825eb42bSJan Lentfer ldns_rr *result = NULL;
313825eb42bSJan Lentfer
314825eb42bSJan Lentfer const ldns_rr_descriptor *descriptor;
315825eb42bSJan Lentfer
316d1b2b5caSJohn Marino ldns_rdf *zone_name = NULL;
317825eb42bSJan Lentfer
318825eb42bSJan Lentfer if (verbosity >= 4) {
319825eb42bSJan Lentfer printf(";; finding exact match for ");
320825eb42bSJan Lentfer descriptor = ldns_rr_descript(qtype);
321825eb42bSJan Lentfer if (descriptor && descriptor->_name) {
322825eb42bSJan Lentfer printf("%s ", descriptor->_name);
323825eb42bSJan Lentfer } else {
324825eb42bSJan Lentfer printf("TYPE%d ", qtype);
325825eb42bSJan Lentfer }
326825eb42bSJan Lentfer ldns_rdf_print(stdout, qname);
327825eb42bSJan Lentfer printf("\n");
328825eb42bSJan Lentfer }
329825eb42bSJan Lentfer
330825eb42bSJan Lentfer if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
331825eb42bSJan Lentfer if (verbosity >= 4) {
332825eb42bSJan Lentfer printf("no qname, nsec3s or list empty\n");
333825eb42bSJan Lentfer }
334825eb42bSJan Lentfer return NULL;
335825eb42bSJan Lentfer }
336825eb42bSJan Lentfer
337825eb42bSJan Lentfer nsec = ldns_rr_list_rr(nsec3s, 0);
338825eb42bSJan Lentfer algorithm = ldns_nsec3_algorithm(nsec);
339825eb42bSJan Lentfer salt_length = ldns_nsec3_salt_length(nsec);
340825eb42bSJan Lentfer salt = ldns_nsec3_salt_data(nsec);
341825eb42bSJan Lentfer iterations = ldns_nsec3_iterations(nsec);
342d1b2b5caSJohn Marino if (salt == NULL) {
343d1b2b5caSJohn Marino goto done;
344d1b2b5caSJohn Marino }
345825eb42bSJan Lentfer
346825eb42bSJan Lentfer sname = ldns_rdf_clone(qname);
347d1b2b5caSJohn Marino if (sname == NULL) {
348d1b2b5caSJohn Marino goto done;
349d1b2b5caSJohn Marino }
350825eb42bSJan Lentfer if (verbosity >= 4) {
351825eb42bSJan Lentfer printf(";; owner name hashes to: ");
352825eb42bSJan Lentfer }
353825eb42bSJan Lentfer hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
354d1b2b5caSJohn Marino if (hashed_sname == NULL) {
355d1b2b5caSJohn Marino goto done;
356d1b2b5caSJohn Marino }
357825eb42bSJan Lentfer zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
358d1b2b5caSJohn Marino if (zone_name == NULL) {
359d1b2b5caSJohn Marino goto done;
360d1b2b5caSJohn Marino }
361d1b2b5caSJohn Marino if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK) {
362d1b2b5caSJohn Marino goto done;
363d1b2b5caSJohn Marino };
364825eb42bSJan Lentfer
365825eb42bSJan Lentfer if (verbosity >= 4) {
366825eb42bSJan Lentfer ldns_rdf_print(stdout, hashed_sname);
367825eb42bSJan Lentfer printf("\n");
368825eb42bSJan Lentfer }
369825eb42bSJan Lentfer
370825eb42bSJan Lentfer for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
371825eb42bSJan Lentfer nsec = ldns_rr_list_rr(nsec3s, nsec_i);
372825eb42bSJan Lentfer
373825eb42bSJan Lentfer /* check values of iterations etc! */
374825eb42bSJan Lentfer
375825eb42bSJan Lentfer /* exact match? */
376825eb42bSJan Lentfer if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
377825eb42bSJan Lentfer result = nsec;
378825eb42bSJan Lentfer goto done;
379825eb42bSJan Lentfer }
380825eb42bSJan Lentfer
381825eb42bSJan Lentfer }
382825eb42bSJan Lentfer
383825eb42bSJan Lentfer done:
384825eb42bSJan Lentfer ldns_rdf_deep_free(zone_name);
385825eb42bSJan Lentfer ldns_rdf_deep_free(sname);
386825eb42bSJan Lentfer ldns_rdf_deep_free(hashed_sname);
387825eb42bSJan Lentfer LDNS_FREE(salt);
388825eb42bSJan Lentfer
389825eb42bSJan Lentfer if (verbosity >= 4) {
390825eb42bSJan Lentfer if (result) {
391825eb42bSJan Lentfer printf(";; Found.\n");
392825eb42bSJan Lentfer } else {
393825eb42bSJan Lentfer printf(";; Not foud.\n");
394825eb42bSJan Lentfer }
395825eb42bSJan Lentfer }
396825eb42bSJan Lentfer return result;
397825eb42bSJan Lentfer }
398825eb42bSJan Lentfer
399825eb42bSJan Lentfer /*return the owner name of the closest encloser for name from the list of rrs */
400825eb42bSJan Lentfer /* this is NOT the hash, but the original name! */
401825eb42bSJan Lentfer ldns_rdf *
ldns_nsec3_closest_encloser(ldns_rdf * qname,ldns_rr_type qtype,ldns_rr_list * nsec3s)402825eb42bSJan Lentfer ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
403825eb42bSJan Lentfer {
404825eb42bSJan Lentfer /* remember parameters, they must match */
405825eb42bSJan Lentfer uint8_t algorithm;
406825eb42bSJan Lentfer uint32_t iterations;
407825eb42bSJan Lentfer uint8_t salt_length;
408825eb42bSJan Lentfer uint8_t *salt;
409825eb42bSJan Lentfer
410d1b2b5caSJohn Marino ldns_rdf *sname = NULL, *hashed_sname = NULL, *tmp;
411825eb42bSJan Lentfer bool flag;
412825eb42bSJan Lentfer
413825eb42bSJan Lentfer bool exact_match_found;
414825eb42bSJan Lentfer bool in_range_found;
415825eb42bSJan Lentfer
416d1b2b5caSJohn Marino ldns_rdf *zone_name = NULL;
417825eb42bSJan Lentfer
418825eb42bSJan Lentfer size_t nsec_i;
419825eb42bSJan Lentfer ldns_rr *nsec;
420825eb42bSJan Lentfer ldns_rdf *result = NULL;
421825eb42bSJan Lentfer
422825eb42bSJan Lentfer if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
423825eb42bSJan Lentfer return NULL;
424825eb42bSJan Lentfer }
425825eb42bSJan Lentfer
426825eb42bSJan Lentfer if (verbosity >= 4) {
427825eb42bSJan Lentfer printf(";; finding closest encloser for type %d ", qtype);
428825eb42bSJan Lentfer ldns_rdf_print(stdout, qname);
429825eb42bSJan Lentfer printf("\n");
430825eb42bSJan Lentfer }
431825eb42bSJan Lentfer
432825eb42bSJan Lentfer nsec = ldns_rr_list_rr(nsec3s, 0);
433825eb42bSJan Lentfer algorithm = ldns_nsec3_algorithm(nsec);
434825eb42bSJan Lentfer salt_length = ldns_nsec3_salt_length(nsec);
435825eb42bSJan Lentfer salt = ldns_nsec3_salt_data(nsec);
436825eb42bSJan Lentfer iterations = ldns_nsec3_iterations(nsec);
437d1b2b5caSJohn Marino if (salt == NULL) {
438d1b2b5caSJohn Marino goto done;
439d1b2b5caSJohn Marino }
440825eb42bSJan Lentfer
441825eb42bSJan Lentfer sname = ldns_rdf_clone(qname);
442d1b2b5caSJohn Marino if (sname == NULL) {
443d1b2b5caSJohn Marino goto done;
444d1b2b5caSJohn Marino }
445825eb42bSJan Lentfer
446825eb42bSJan Lentfer flag = false;
447825eb42bSJan Lentfer
448825eb42bSJan Lentfer zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
449d1b2b5caSJohn Marino if (zone_name == NULL) {
450d1b2b5caSJohn Marino goto done;
451d1b2b5caSJohn Marino }
452825eb42bSJan Lentfer
453825eb42bSJan Lentfer /* algorithm from nsec3-07 8.3 */
454825eb42bSJan Lentfer while (ldns_dname_label_count(sname) > 0) {
455825eb42bSJan Lentfer exact_match_found = false;
456825eb42bSJan Lentfer in_range_found = false;
457825eb42bSJan Lentfer
458825eb42bSJan Lentfer if (verbosity >= 3) {
459825eb42bSJan Lentfer printf(";; ");
460825eb42bSJan Lentfer ldns_rdf_print(stdout, sname);
461825eb42bSJan Lentfer printf(" hashes to: ");
462825eb42bSJan Lentfer }
463825eb42bSJan Lentfer hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
464d1b2b5caSJohn Marino if (hashed_sname == NULL) {
465d1b2b5caSJohn Marino goto done;
466d1b2b5caSJohn Marino }
467825eb42bSJan Lentfer
468d1b2b5caSJohn Marino if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK){
469819dec71SDaniel Fojt ldns_rdf_deep_free(hashed_sname);
470d1b2b5caSJohn Marino goto done;
471d1b2b5caSJohn Marino }
472825eb42bSJan Lentfer
473825eb42bSJan Lentfer if (verbosity >= 3) {
474825eb42bSJan Lentfer ldns_rdf_print(stdout, hashed_sname);
475825eb42bSJan Lentfer printf("\n");
476825eb42bSJan Lentfer }
477825eb42bSJan Lentfer
478825eb42bSJan Lentfer for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
479825eb42bSJan Lentfer nsec = ldns_rr_list_rr(nsec3s, nsec_i);
480825eb42bSJan Lentfer
481825eb42bSJan Lentfer /* check values of iterations etc! */
482825eb42bSJan Lentfer
483825eb42bSJan Lentfer /* exact match? */
484825eb42bSJan Lentfer if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
485825eb42bSJan Lentfer if (verbosity >= 4) {
486825eb42bSJan Lentfer printf(";; exact match found\n");
487825eb42bSJan Lentfer }
488825eb42bSJan Lentfer exact_match_found = true;
489825eb42bSJan Lentfer } else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
490825eb42bSJan Lentfer if (verbosity >= 4) {
491825eb42bSJan Lentfer printf(";; in range of an nsec\n");
492825eb42bSJan Lentfer }
493825eb42bSJan Lentfer in_range_found = true;
494825eb42bSJan Lentfer }
495825eb42bSJan Lentfer
496825eb42bSJan Lentfer }
497825eb42bSJan Lentfer if (!exact_match_found && in_range_found) {
498825eb42bSJan Lentfer flag = true;
499825eb42bSJan Lentfer } else if (exact_match_found && flag) {
500825eb42bSJan Lentfer result = ldns_rdf_clone(sname);
501825eb42bSJan Lentfer } else if (exact_match_found && !flag) {
502825eb42bSJan Lentfer // error!
503825eb42bSJan Lentfer if (verbosity >= 4) {
504825eb42bSJan Lentfer printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
505825eb42bSJan Lentfer }
506825eb42bSJan Lentfer ldns_rdf_deep_free(hashed_sname);
507825eb42bSJan Lentfer goto done;
508825eb42bSJan Lentfer } else {
509825eb42bSJan Lentfer flag = false;
510825eb42bSJan Lentfer }
511825eb42bSJan Lentfer
512825eb42bSJan Lentfer ldns_rdf_deep_free(hashed_sname);
513825eb42bSJan Lentfer tmp = sname;
514825eb42bSJan Lentfer sname = ldns_dname_left_chop(sname);
515825eb42bSJan Lentfer ldns_rdf_deep_free(tmp);
516d1b2b5caSJohn Marino if (sname == NULL) {
517d1b2b5caSJohn Marino goto done;
518d1b2b5caSJohn Marino }
519825eb42bSJan Lentfer }
520825eb42bSJan Lentfer
521825eb42bSJan Lentfer done:
522825eb42bSJan Lentfer LDNS_FREE(salt);
523825eb42bSJan Lentfer ldns_rdf_deep_free(zone_name);
524825eb42bSJan Lentfer ldns_rdf_deep_free(sname);
525825eb42bSJan Lentfer
526825eb42bSJan Lentfer if (!result) {
527825eb42bSJan Lentfer if (verbosity >= 4) {
528825eb42bSJan Lentfer printf(";; no closest encloser found\n");
529825eb42bSJan Lentfer }
530825eb42bSJan Lentfer }
531825eb42bSJan Lentfer
532825eb42bSJan Lentfer /* todo checks from end of 6.2. here or in caller? */
533825eb42bSJan Lentfer return result;
534825eb42bSJan Lentfer }
535