1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup dnsdbupdate Dynamic update functions
36  *  @ingroup dnsdb
37  *  @brief
38  *
39  * @{
40  */
41 /*------------------------------------------------------------------------------
42  *
43  * USE INCLUDES */
44 #include "dnsdb/dnsdb-config.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47 
48 #include "dnsdb/dynupdate-message.h"
49 
50 #define DMSGPCKT_TAG 0x544b435047534d44
51 
52 // Disable detailled diff log even in debug builds
53 
54 #define DYNUPDATE_DIFF_DETAILLED_LOG 0
55 
56 #ifndef DYNUPDATE_DIFF_DETAILLED_LOG
57 #if DEBUG
58 #define DYNUPDATE_DIFF_DETAILLED_LOG 1
59 #else
60 #define DYNUPDATE_DIFF_DETAILLED_LOG 0
61 #endif
62 #endif
63 
64 ///////////////////////////////////////////////////////////////////////////////
65 
66 /**
67  * Initialises a simple update buffer
68  *
69  * @param dmsg
70  */
71 
72 void
dynupdate_message_init(dynupdate_message * dmsg,const u8 * origin,u16 rclass)73 dynupdate_message_init(dynupdate_message *dmsg, const u8 *origin, u16 rclass)
74 {
75     dmsg->size = MAX_U16;
76     MALLOC_OR_DIE(u8*, dmsg->packet, dmsg->size, DMSGPCKT_TAG);
77     // packet_writer_init is for valid messages.  For writing a new message use:
78     packet_writer_create(&dmsg->pw, dmsg->packet, dmsg->size);
79     dmsg->rclass = rclass;
80     message_header *hdr = (message_header*)dmsg->packet;
81 #if DEBUG
82     memset(dmsg->packet, 0xcc, dmsg->size);
83 #endif
84     ZEROMEMORY(hdr, DNS_HEADER_LENGTH);
85     hdr->opcode = OPCODE_UPDATE;
86     packet_writer_add_fqdn(&dmsg->pw, origin);
87     packet_writer_add_u16(&dmsg->pw, TYPE_SOA);
88     packet_writer_add_u16(&dmsg->pw, rclass);
89     hdr->qdcount = NU16(1);
90 }
91 
92 void
dynupdate_message_reset(dynupdate_message * dmsg,const u8 * origin,u16 rclass)93 dynupdate_message_reset(dynupdate_message *dmsg, const u8 *origin, u16 rclass)
94 {
95     // packet_writer_init is for valid messages.  For writing a new message use:
96     packet_writer_create(&dmsg->pw, dmsg->packet, dmsg->size);
97     dmsg->rclass = rclass;
98     message_header *hdr = (message_header*)dmsg->packet;
99 #if DEBUG
100     memset(dmsg->packet, 0xcc, dmsg->size);
101 #endif
102     ZEROMEMORY(hdr, DNS_HEADER_LENGTH);
103     hdr->opcode = OPCODE_UPDATE;
104     packet_writer_add_fqdn(&dmsg->pw, origin);
105     packet_writer_add_u16(&dmsg->pw, TYPE_SOA);
106     packet_writer_add_u16(&dmsg->pw, rclass);
107     hdr->qdcount = NU16(1);
108 }
109 
110 /**
111  * Releases resources.
112  *
113  * @param dmsg
114  */
115 
116 void
dynupdate_message_finalize(dynupdate_message * dmsg)117 dynupdate_message_finalize(dynupdate_message *dmsg)
118 {
119     //packet_writer_finalize(&dmsg->pw);
120     free(dmsg->packet);
121 }
122 
123 /**
124  * Sets a reader up for the buffer.
125  *
126  * @param dmsg
127  * @param purd
128  */
129 
130 void
dynupdate_message_set_reader(dynupdate_message * dmsg,packet_unpack_reader_data * purd)131 dynupdate_message_set_reader(dynupdate_message *dmsg, packet_unpack_reader_data *purd)
132 {
133     yassert(dmsg->pw.packet_offset >= DNS_HEADER_LENGTH);
134 
135     packet_reader_init(purd, dmsg->packet, dmsg->pw.packet_offset);
136 }
137 
138 /**
139  * Return the number of update records.
140  *
141  * @param dmsg
142  * @return
143  */
144 
145 u16
dynupdate_message_get_count(dynupdate_message * dmsg)146 dynupdate_message_get_count(dynupdate_message *dmsg)
147 {
148     message_header *hdr = (message_header*)dmsg->packet;
149     u16 count = ntohs(hdr->nscount);
150     return count;
151 }
152 
153 /**
154  * Adds a dnskey record to the buffer
155  *
156  * @param dmsg
157  * @param ttl
158  * @param key
159  * @return
160  */
161 
162 ya_result
dynupdate_message_add_dnskey(dynupdate_message * dmsg,s32 ttl,const dnssec_key * key)163 dynupdate_message_add_dnskey(dynupdate_message *dmsg, s32 ttl, const dnssec_key *key)
164 {
165     u32 rdata_size = key->vtbl->dnssec_key_rdatasize(key);
166     u32 remaining = packet_writer_get_remaining_capacity(&dmsg->pw);
167 
168     ya_result ret = BUFFER_WOULD_OVERFLOW;
169 
170     // the first 2 is assuming compression will take place
171     // which is as it should be since the messages are initialised with the fqdn of the zone
172 
173     if(remaining >= 2 + 2 + 2 + 4 + 2 + rdata_size)
174     {
175         if(ISOK(ret = packet_writer_add_fqdn(&dmsg->pw, &dmsg->packet[DNS_HEADER_LENGTH])))
176         {
177             packet_writer_add_u16(&dmsg->pw, TYPE_DNSKEY);
178             packet_writer_add_u16(&dmsg->pw, dmsg->rclass);
179             packet_writer_add_u32(&dmsg->pw, htonl(ttl));
180             packet_writer_add_u16(&dmsg->pw, htons(rdata_size));
181             key->vtbl->dnssec_key_writerdata(key, packet_writer_get_next_u8_ptr(&dmsg->pw), rdata_size);
182             packet_writer_forward(&dmsg->pw, rdata_size);
183             message_header *hdr = (message_header*)dmsg->packet;
184             hdr->nscount = htons(ntohs(hdr->nscount) + 1);
185         }
186     }
187 
188     return ret;
189 }
190 
191 /**
192  * Deletes a dnskey record to the buffer
193  *
194  * @param dmsg
195  * @param ttl
196  * @param key
197  * @return
198  */
199 
200 ya_result
dynupdate_message_del_dnskey(dynupdate_message * dmsg,const dnssec_key * key)201 dynupdate_message_del_dnskey(dynupdate_message *dmsg, const dnssec_key *key)
202 {
203     u32 rdata_size = key->vtbl->dnssec_key_rdatasize(key);
204     u32 remaining = packet_writer_get_remaining_capacity(&dmsg->pw);
205 
206     ya_result ret = BUFFER_WOULD_OVERFLOW;
207 
208     if(remaining >= 2 + 2 + 2 + 4 + 2 + rdata_size)
209     {
210         if(ISOK(ret = packet_writer_add_fqdn(&dmsg->pw, &dmsg->packet[DNS_HEADER_LENGTH])))
211         {
212             packet_writer_add_u16(&dmsg->pw, TYPE_DNSKEY);
213             packet_writer_add_u16(&dmsg->pw, CLASS_NONE);
214             packet_writer_add_u32(&dmsg->pw, 0);
215             packet_writer_add_u16(&dmsg->pw, htons(rdata_size));
216             key->vtbl->dnssec_key_writerdata(key, packet_writer_get_next_u8_ptr(&dmsg->pw), rdata_size);
217             packet_writer_forward(&dmsg->pw, rdata_size);
218             message_header *hdr = (message_header*)dmsg->packet;
219             hdr->nscount = htons(ntohs(hdr->nscount) + 1);
220         }
221     }
222 
223     return ret;
224 }
225 
226 /**
227  * Appends a "add RR" command to the buffer.
228  *
229  * @param dmsg
230  * @param fqdn
231  * @param rtype
232  * @param ttl
233  * @param rdata_size
234  * @param rdata
235  * @return
236  */
237 
238 ya_result
dynupdate_message_add_record(dynupdate_message * dmsg,const u8 * fqdn,u16 rtype,s32 ttl,u16 rdata_size,void * rdata)239 dynupdate_message_add_record(dynupdate_message *dmsg, const u8 *fqdn, u16 rtype, s32 ttl, u16 rdata_size, void *rdata)
240 {
241     ya_result ret;
242     if(ISOK(ret = packet_writer_add_record(&dmsg->pw, fqdn, rtype, dmsg->rclass, ttl, rdata, rdata_size)))
243     {
244         message_header *hdr = (message_header*)dmsg->packet;
245         hdr->nscount = htons(ntohs(hdr->nscount) + 1);
246     }
247     return ret;
248 }
249 
250 /**
251  * Appends a "delete RR" command to the buffer.
252  *
253  * @param dmsg
254  * @param fqdn
255  * @param rtype
256  * @param ttl
257  * @param rdata_size
258  * @param rdata
259  * @return
260  */
261 
262 ya_result
dynupdate_message_del_record(dynupdate_message * dmsg,const u8 * fqdn,u16 rtype,s32 ttl,u16 rdata_size,void * rdata)263 dynupdate_message_del_record(dynupdate_message *dmsg, const u8 *fqdn, u16 rtype, s32 ttl, u16 rdata_size, void *rdata)
264 {
265     ya_result ret;
266     if(ISOK(ret = packet_writer_add_record(&dmsg->pw, fqdn, rtype, TYPE_NONE, ttl, rdata, rdata_size)))
267     {
268         message_header *hdr = (message_header*)dmsg->packet;
269         hdr->nscount = htons(ntohs(hdr->nscount) + 1);
270     }
271     return ret;
272 }
273 
274 /**
275  *
276  * Appends a "delete RRSET" command to the buffer.
277  *
278  * @param dmsg
279  * @param fqdn
280  * @param rtype
281  * @return
282  */
283 
284 ya_result
dynupdate_message_del_record_set(dynupdate_message * dmsg,const u8 * fqdn,u16 rtype)285 dynupdate_message_del_record_set(dynupdate_message *dmsg, const u8 *fqdn, u16 rtype)
286 {
287     ya_result ret;
288     if(ISOK(ret = packet_writer_add_record(&dmsg->pw, fqdn, rtype, TYPE_ANY, 0, NULL, 0)))
289     {
290         message_header *hdr = (message_header*)dmsg->packet;
291         hdr->nscount = htons(ntohs(hdr->nscount) + 1);
292     }
293     return ret;
294 }
295 
296 /**
297  * Appends a "delete fqdn" command to the buffer.
298  *
299  * @param dmsg
300  * @param fqdn
301  * @return
302  */
303 
304 ya_result
dynupdate_message_del_fqdn(dynupdate_message * dmsg,const u8 * fqdn)305 dynupdate_message_del_fqdn(dynupdate_message *dmsg, const u8 *fqdn)
306 {
307     ya_result ret;
308     if(ISOK(ret = packet_writer_add_record(&dmsg->pw, fqdn, TYPE_ANY, TYPE_ANY, 0, NULL, 0)))
309     {
310         message_header *hdr = (message_header*)dmsg->packet;
311         hdr->nscount = htons(ntohs(hdr->nscount) + 1);
312     }
313     return ret;
314 }
315 
316