1 /*
2  * Copyright (c) 2009-2011 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /**
28  *
29  * Adapter API.
30  */
31 
32 #include "config.h"
33 #include "adapter/adapi.h"
34 #include "duration.h"
35 #include "log.h"
36 #include "status.h"
37 #include "util.h"
38 #include "signer/zone.h"
39 
40 #include <ldns/ldns.h>
41 
42 static const char* adapi_str = "adapter";
43 
44 
45 /**
46  * Get the inbound serial.
47  *
48  */
49 uint32_t
adapi_get_serial(zone_type * zone)50 adapi_get_serial(zone_type* zone)
51 {
52     if (!zone || !zone->db) {
53         return 0;
54     }
55     return zone->db->inbserial;
56 }
57 
58 
59 /**
60  * Set the inbound serial.
61  *
62  */
63 void
adapi_set_serial(zone_type * zone,uint32_t serial)64 adapi_set_serial(zone_type* zone, uint32_t serial)
65 {
66     if (!zone || !zone->db) {
67         return;
68     }
69     zone->db->inbserial = serial;
70 }
71 
72 
73 /**
74  * Get origin.
75  *
76  */
77 ldns_rdf*
adapi_get_origin(zone_type * zone)78 adapi_get_origin(zone_type* zone)
79 {
80     if (!zone) {
81         return NULL;
82     }
83     return zone->apex;
84 }
85 
86 
87 /**
88  * Get ttl.
89  *
90  */
91 uint32_t
adapi_get_ttl(zone_type * zone)92 adapi_get_ttl(zone_type* zone)
93 {
94     if (!zone) {
95         return 0;
96     }
97     return zone->default_ttl;
98 }
99 
100 
101 /*
102  * Do full zone transaction.
103  *
104  */
105 void
adapi_trans_full(zone_type * zone,unsigned more_coming)106 adapi_trans_full(zone_type* zone, unsigned more_coming)
107 {
108     time_t start = 0;
109     time_t end = 0;
110     uint32_t num_added = 0;
111     if (!zone || !zone->db) {
112         return;
113     }
114     namedb_diff(zone->db, 0, more_coming);
115 
116     if (zone->stats) {
117         pthread_mutex_lock(&zone->stats->stats_lock);
118         zone->stats->nsec_time = 0;
119         zone->stats->nsec_count = 0;
120         pthread_mutex_unlock(&zone->stats->stats_lock);
121     }
122     start = time(NULL);
123     /* nsecify(3) */
124     namedb_nsecify(zone->db, &num_added);
125     end = time(NULL);
126     if (zone->stats) {
127         pthread_mutex_lock(&zone->stats->stats_lock);
128         if (!zone->stats->start_time) {
129             zone->stats->start_time = start;
130         }
131         zone->stats->nsec_time = (end-start);
132         zone->stats->nsec_count = num_added;
133         pthread_mutex_unlock(&zone->stats->stats_lock);
134     }
135 }
136 
137 
138 /*
139  * Do incremental zone transaction.
140  *
141  */
142 void
adapi_trans_diff(zone_type * zone,unsigned more_coming)143 adapi_trans_diff(zone_type* zone, unsigned more_coming)
144 {
145     time_t start = 0;
146     time_t end = 0;
147     uint32_t num_added = 0;
148     if (!zone || !zone->db) {
149         return;
150     }
151     namedb_diff(zone->db, 1, more_coming);
152 
153    if (zone->stats) {
154         pthread_mutex_lock(&zone->stats->stats_lock);
155         zone->stats->nsec_time = 0;
156         zone->stats->nsec_count = 0;
157         pthread_mutex_unlock(&zone->stats->stats_lock);
158     }
159     start = time(NULL);
160     /* nsecify(3) */
161     namedb_nsecify(zone->db, &num_added);
162     end = time(NULL);
163     if (zone->stats) {
164         pthread_mutex_lock(&zone->stats->stats_lock);
165         if (!zone->stats->start_time) {
166             zone->stats->start_time = start;
167         }
168         zone->stats->nsec_time = (end-start);
169         zone->stats->nsec_count = num_added;
170         pthread_mutex_unlock(&zone->stats->stats_lock);
171     }
172 }
173 
174 
175 /**
176  * Process SOA.
177  *
178  */
179 static ods_status
adapi_process_soa(zone_type * zone,ldns_rr * rr,int add,int backup)180 adapi_process_soa(zone_type* zone, ldns_rr* rr, int add, int backup)
181 {
182     uint32_t tmp = 0;
183     ldns_rdf* soa_rdata = NULL;
184     ods_status status = ODS_STATUS_OK;
185 
186     ods_log_assert(rr);
187     ods_log_assert(zone);
188     ods_log_assert(zone->name);
189     ods_log_assert(zone->signconf);
190 
191     if (backup) {
192         /* no need to do processing */
193         return ODS_STATUS_OK;
194     }
195     if (zone->signconf->soa_ttl) {
196         tmp = (uint32_t) duration2time(zone->signconf->soa_ttl);
197         ods_log_verbose("[%s] zone %s set soa ttl to %u",
198             adapi_str, zone->name, tmp);
199         ldns_rr_set_ttl(rr, tmp);
200     }
201     if (zone->signconf->soa_min) {
202         tmp = (uint32_t) duration2time(zone->signconf->soa_min);
203         ods_log_verbose("[%s] zone %s set soa minimum to %u",
204             adapi_str, zone->name, tmp);
205         soa_rdata = ldns_rr_set_rdf(rr,
206             ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp),
207             SE_SOA_RDATA_MINIMUM);
208         if (soa_rdata) {
209             ldns_rdf_deep_free(soa_rdata);
210             soa_rdata = NULL;
211         } else {
212             ods_log_error("[%s] unable to %s soa to zone %s: failed to replace "
213                 "soa minimum rdata", adapi_str, add?"add":"delete",
214                 zone->name);
215             return ODS_STATUS_ASSERT_ERR;
216         }
217     }
218     if (!add) {
219         /* we are done */
220         return ODS_STATUS_OK;
221     }
222     tmp = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
223     status = namedb_update_serial(zone->db, zone->name,
224         zone->signconf->soa_serial, tmp);
225     if (status != ODS_STATUS_OK) {
226         ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
227             "soa serial rdata (%s)", adapi_str, zone->name,
228             ods_status2str(status));
229         if (status == ODS_STATUS_CONFLICT_ERR) {
230             ods_log_error("[%s] If this is the result of a key rollover, "
231                 "please increment the serial in the unsigned zone %s",
232                 adapi_str, zone->name);
233         }
234         return status;
235     }
236     ods_log_verbose("[%s] zone %s set soa serial to %u", adapi_str,
237         zone->name, zone->db->intserial);
238     soa_rdata = ldns_rr_set_rdf(rr, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
239         zone->db->intserial), SE_SOA_RDATA_SERIAL);
240     if (soa_rdata) {
241         ldns_rdf_deep_free(soa_rdata);
242         soa_rdata = NULL;
243     } else {
244         ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
245             "soa serial rdata", adapi_str, zone->name);
246         return ODS_STATUS_ERR;
247     }
248     zone->db->serial_updated = 1;
249     return ODS_STATUS_OK;
250 }
251 
252 
253 /**
254  * Process DNSKEY.
255  *
256  */
257 static void
adapi_process_dnskey(zone_type * zone,ldns_rr * rr)258 adapi_process_dnskey(zone_type* zone, ldns_rr* rr)
259 {
260     uint32_t tmp = 0;
261     ods_log_assert(rr);
262     ods_log_assert(zone);
263     ods_log_assert(zone->name);
264     ods_log_assert(zone->signconf);
265     tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
266     ods_log_verbose("[%s] zone %s set dnskey ttl to %u",
267         adapi_str, zone->name, tmp);
268     ldns_rr_set_ttl(rr, tmp);
269 }
270 
271 
272 /**
273  * Process RR.
274  *
275  */
276 static ods_status
adapi_process_rr(zone_type * zone,ldns_rr * rr,int add,int backup)277 adapi_process_rr(zone_type* zone, ldns_rr* rr, int add, int backup)
278 {
279     ods_status status = ODS_STATUS_OK;
280     uint32_t tmp = 0;
281     ods_log_assert(rr);
282     ods_log_assert(zone);
283     ods_log_assert(zone->name);
284     ods_log_assert(zone->db);
285     ods_log_assert(zone->signconf);
286     /* We only support IN class */
287     if (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) {
288         ods_log_warning("[%s] only class in is supported, changing class "
289             "to in", adapi_str);
290         ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
291     }
292     /* RR processing */
293     if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
294         if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) {
295             ods_log_error("[%s] unable to %s rr to zone: soa record has "
296                 "invalid owner name", adapi_str, add?"add":"delete");
297             return ODS_STATUS_ERR;
298         }
299         status = adapi_process_soa(zone, rr, add, backup);
300         if (status != ODS_STATUS_OK) {
301             ods_log_error("[%s] unable to %s rr: failed to process soa "
302                 "record", adapi_str, add?"add":"delete");
303             return status;
304         }
305     } else {
306         if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex) &&
307             !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->apex)) {
308             ods_log_warning("[%s] zone %s contains out-of-zone data, "
309                 "skipping", adapi_str, zone->name);
310             return ODS_STATUS_UNCHANGED;
311         } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY) {
312             adapi_process_dnskey(zone, rr);
313         } else if (util_is_dnssec_rr(rr) && !backup) {
314             ods_log_warning("[%s] zone %s contains dnssec data (type=%u), "
315                 "skipping", adapi_str, zone->name,
316                 (unsigned) ldns_rr_get_type(rr));
317             return ODS_STATUS_UNCHANGED;
318         } else if (zone->signconf->max_zone_ttl) {
319             /* Convert MaxZoneTTL */
320             tmp = (uint32_t) duration2time(zone->signconf->max_zone_ttl);
321         }
322     }
323     /* //MaxZoneTTL. Only set for RRtype != SOA && RRtype != DNSKEY */
324     if (tmp && tmp < ldns_rr_ttl(rr)) {
325         char* str = ldns_rdf2str(ldns_rr_owner(rr));
326         if (str) {
327             str[(strlen(str))-1] = '\0';
328             /* replace tabs with white space */
329             for (int i = 0; i < strlen(str); i++) {
330                 if (str[i] == '\t') {
331                     str[i] = ' ';
332                 }
333             }
334             ods_log_warning("[%s] TTL %u exceeds MaxZoneTTL %u for rrset "
335                 "<%s,%s>", adapi_str, ldns_rr_ttl(rr), tmp, str,
336                 rrset_type2str(ldns_rr_get_type(rr)));
337             LDNS_FREE(str);
338         }
339     }
340 
341     /* TODO: DNAME and CNAME checks */
342     /* TODO: NS and DS checks */
343 
344     if (add) {
345         return zone_add_rr(zone, rr, 1);
346     } else {
347         return zone_del_rr(zone, rr, 1);
348     }
349     /* not reached */
350     return ODS_STATUS_ERR;
351 }
352 
353 
354 /**
355  * Add RR.
356  *
357  */
358 ods_status
adapi_add_rr(zone_type * zone,ldns_rr * rr,int backup)359 adapi_add_rr(zone_type* zone, ldns_rr* rr, int backup)
360 {
361     return adapi_process_rr(zone, rr, 1, backup);
362 }
363 
364 
365 /**
366  * Delete RR.
367  *
368  */
369 ods_status
adapi_del_rr(zone_type * zone,ldns_rr * rr,int backup)370 adapi_del_rr(zone_type* zone, ldns_rr* rr, int backup)
371 {
372     return adapi_process_rr(zone, rr, 0, backup);
373 }
374 
375 
376 /**
377  * Print zone.
378  *
379  */
380 ods_status
adapi_printzone(FILE * fd,zone_type * zone)381 adapi_printzone(FILE* fd, zone_type* zone)
382 {
383     ods_status status = ODS_STATUS_OK;
384     if (!fd || !zone || !zone->db) {
385         ods_log_error("[%s] unable to print zone: file descriptor, zone or "
386             "name database missing", adapi_str);
387         return ODS_STATUS_ASSERT_ERR;
388     }
389     namedb_export(fd, zone->db, &status);
390     return status;
391 }
392 
393 
394 /**
395  * Print axfr.
396  *
397  */
398 ods_status
adapi_printaxfr(FILE * fd,zone_type * zone)399 adapi_printaxfr(FILE* fd, zone_type* zone)
400 {
401     rrset_type* rrset = NULL;
402     ods_status status = ODS_STATUS_OK;
403     if (!fd || !zone || !zone->db) {
404         ods_log_error("[%s] unable to print axfr: file descriptor, zone or "
405             "name database missing", adapi_str);
406         return ODS_STATUS_ASSERT_ERR;
407     }
408     namedb_export(fd, zone->db, &status);
409     if (status == ODS_STATUS_OK) {
410         rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
411         ods_log_assert(rrset);
412         rrset_print(fd, rrset, 1, &status);
413     }
414     return status;
415 }
416 
417 
418 /**
419  * Print ixfr.
420  *
421  */
422 ods_status
adapi_printixfr(FILE * fd,zone_type * zone)423 adapi_printixfr(FILE* fd, zone_type* zone)
424 {
425     rrset_type* rrset = NULL;
426     ods_status status = ODS_STATUS_OK;
427     if (!fd || !zone || !zone->db || !zone->ixfr) {
428         ods_log_error("[%s] unable to print ixfr: file descriptor, zone or "
429             "name database missing", adapi_str);
430         return ODS_STATUS_ASSERT_ERR;
431     }
432     if (!zone->db->is_initialized) {
433         /* no ixfr yet */
434         return ODS_STATUS_OK;
435     }
436     rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
437     ods_log_assert(rrset);
438     rrset_print(fd, rrset, 1, &status);
439     if (status != ODS_STATUS_OK) {
440         return status;
441     }
442     pthread_mutex_lock(&zone->ixfr->ixfr_lock);
443     if (ixfr_print(fd, zone->ixfr)) {
444         zone->adoutbound->error = 1;
445     }
446     pthread_mutex_unlock(&zone->ixfr->ixfr_lock);
447     rrset_print(fd, rrset, 1, &status);
448     return status;
449 }
450