r21217: Just found a system that does not define in_addr_t but only struct
[sfrench/samba-autobuild/.git] / source / libaddns / dnsrecord.c
1 /*
2   Linux DNS client library implementation
3   Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
4   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
5
6      ** NOTE! The following LGPL license applies to the libaddns
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
10   This library is free software; you can redistribute it and/or
11   modify it under the terms of the GNU Lesser General Public
12   License as published by the Free Software Foundation; either
13   version 2.1 of the License, or (at your option) any later version.
14
15   This library is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public
21   License along with this library; if not, write to the Free Software
22   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
23   02110-1301  USA
24 */
25
26 #include "dns.h"
27
28 DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
29                             uint16 q_type, uint16 q_class,
30                             struct dns_request **preq )
31 {
32         struct dns_request *req;
33         struct dns_question *q;
34         DNS_ERROR err;
35
36         if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request)) ||
37             !(req->questions = TALLOC_ARRAY(req, struct dns_question *, 1)) ||
38             !(req->questions[0] = talloc(req->questions,
39                                          struct dns_question))) {
40                 TALLOC_FREE(req);
41                 return ERROR_DNS_NO_MEMORY;
42         }
43
44         req->id = random();
45
46         req->num_questions = 1;
47         q = req->questions[0];
48
49         err = dns_domain_name_from_string(q, name, &q->name);
50         if (!ERR_DNS_IS_OK(err)) {
51                 TALLOC_FREE(req);
52                 return err;
53         }
54
55         q->q_type = q_type;
56         q->q_class = q_class;
57
58         *preq = req;
59         return ERROR_DNS_SUCCESS;
60 }
61
62 DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
63                              struct dns_update_request **preq )
64 {
65         struct dns_update_request *req;
66         struct dns_zone *z;
67         DNS_ERROR err;
68
69         if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_update_request)) ||
70             !(req->zones = TALLOC_ARRAY(req, struct dns_zone *, 1)) ||
71             !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
72                 TALLOC_FREE(req);
73                 return ERROR_DNS_NO_MEMORY;
74         }
75
76         req->id = random();
77         req->flags = 0x2800;    /* Dynamic update */
78
79         req->num_zones = 1;
80         z = req->zones[0];
81
82         err = dns_domain_name_from_string(z, name, &z->name);
83         if (!ERR_DNS_IS_OK(err)) {
84                 TALLOC_FREE(req);
85                 return err;
86         }
87
88         z->z_type = QTYPE_SOA;
89         z->z_class = DNS_CLASS_IN;
90
91         *preq = req;
92         return ERROR_DNS_SUCCESS;
93 }
94
95 DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
96                           uint16 type, uint16 r_class, uint32 ttl,
97                           uint16 data_length, uint8 *data,
98                           struct dns_rrec **prec)
99 {
100         struct dns_rrec *rec;
101         DNS_ERROR err;
102
103         if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
104                 return ERROR_DNS_NO_MEMORY;
105         }
106
107         err = dns_domain_name_from_string(rec, name, &rec->name);
108         if (!(ERR_DNS_IS_OK(err))) {
109                 TALLOC_FREE(rec);
110                 return err;
111         }
112
113         rec->type = type;
114         rec->r_class = r_class;
115         rec->ttl = ttl;
116         rec->data_length = data_length;
117         rec->data = talloc_move(rec, &data);
118
119         *prec = rec;
120         return ERROR_DNS_SUCCESS;
121 }
122
123 DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
124                               uint32 ttl, struct in_addr ip,
125                               struct dns_rrec **prec)
126 {
127         uint8 *data;
128         DNS_ERROR err;
129
130         if (!(data = (uint8 *)TALLOC_MEMDUP(mem_ctx, (const void *)&ip.s_addr,
131                                             sizeof(ip.s_addr)))) {
132                 return ERROR_DNS_NO_MEMORY;
133         }
134
135         err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
136                               sizeof(ip.s_addr), data, prec);
137
138         if (!ERR_DNS_IS_OK(err)) {
139                 TALLOC_FREE(data);
140         }
141
142         return err;
143 }
144
145 DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
146                                         const char *name,
147                                         const struct in_addr *ip,
148                                         struct dns_rrec **prec)
149 {
150         if (ip != NULL) {
151                 return dns_create_a_record(mem_ctx, name, 0, *ip, prec);
152         }
153
154         return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
155                                NULL, prec);
156 }
157
158 DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
159                                             const char *name, uint32 type,
160                                             struct dns_rrec **prec)
161 {
162         return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
163                                0, NULL, prec);
164 }
165
166 DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
167                                    uint16 type, uint16 r_class,
168                                    struct dns_rrec **prec)
169 {
170         return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
171 }
172
173 DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
174                                  const char *algorithm_name, time_t inception,
175                                  time_t expiration, uint16 mode, uint16 error,
176                                  uint16 key_length, const uint8 *key,
177                                  struct dns_rrec **prec)
178 {
179         struct dns_buffer *buf;
180         struct dns_domain_name *algorithm;
181         DNS_ERROR err;
182
183         if (!(buf = dns_create_buffer(mem_ctx))) {
184                 return ERROR_DNS_NO_MEMORY;
185         }
186
187         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
188         if (!ERR_DNS_IS_OK(err)) goto error;
189
190         dns_marshall_domain_name(buf, algorithm);
191         dns_marshall_uint32(buf, inception);
192         dns_marshall_uint32(buf, expiration);
193         dns_marshall_uint16(buf, mode);
194         dns_marshall_uint16(buf, error);
195         dns_marshall_uint16(buf, key_length);
196         dns_marshall_buffer(buf, key, key_length);
197         dns_marshall_uint16(buf, 0); /* Other Size */
198
199         if (!ERR_DNS_IS_OK(buf->error)) {
200                 err = buf->error;
201                 goto error;
202         }
203
204         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
205                               buf->offset, buf->data, prec);
206
207  error:
208         TALLOC_FREE(buf);
209         return err;
210 }
211
212 DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
213                                      struct dns_tkey_record **ptkey)
214 {
215         struct dns_tkey_record *tkey;
216         struct dns_buffer buf;
217         uint32 tmp_inception, tmp_expiration;
218         
219         if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
220                 return ERROR_DNS_NO_MEMORY;
221         }
222
223         buf.data = rec->data;
224         buf.size = rec->data_length;
225         buf.offset = 0;
226         buf.error = ERROR_DNS_SUCCESS;
227
228         dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
229         dns_unmarshall_uint32(&buf, &tmp_inception);
230         dns_unmarshall_uint32(&buf, &tmp_expiration);
231         dns_unmarshall_uint16(&buf, &tkey->mode);
232         dns_unmarshall_uint16(&buf, &tkey->error);
233         dns_unmarshall_uint16(&buf, &tkey->key_length);
234
235         if (!ERR_DNS_IS_OK(buf.error)) goto error;
236
237         if (!(tkey->key = TALLOC_ARRAY(tkey, uint8, tkey->key_length))) {
238                 buf.error = ERROR_DNS_NO_MEMORY;
239                 goto error;
240         }
241
242         dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
243         if (!ERR_DNS_IS_OK(buf.error)) goto error;
244
245         tkey->inception = (time_t)tmp_inception;
246         tkey->expiration = (time_t)tmp_expiration;
247
248         *ptkey = tkey;
249         return ERROR_DNS_SUCCESS;
250
251  error:
252         TALLOC_FREE(tkey);
253         return buf.error;
254 }
255
256 DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
257                                  const char *algorithm_name,
258                                  time_t time_signed, uint16 fudge,
259                                  uint16 mac_length, const uint8 *mac,
260                                  uint16 original_id, uint16 error,
261                                  struct dns_rrec **prec)
262 {
263         struct dns_buffer *buf;
264         struct dns_domain_name *algorithm;
265         DNS_ERROR err;
266
267         if (!(buf = dns_create_buffer(mem_ctx))) {
268                 return ERROR_DNS_NO_MEMORY;
269         }
270
271         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
272         if (!ERR_DNS_IS_OK(err)) goto error;
273
274         dns_marshall_domain_name(buf, algorithm);
275         dns_marshall_uint16(buf, 0); /* time prefix */
276         dns_marshall_uint32(buf, time_signed);
277         dns_marshall_uint16(buf, fudge);
278         dns_marshall_uint16(buf, mac_length);
279         dns_marshall_buffer(buf, mac, mac_length);
280         dns_marshall_uint16(buf, original_id);
281         dns_marshall_uint16(buf, error);
282         dns_marshall_uint16(buf, 0); /* Other Size */
283
284         if (!ERR_DNS_IS_OK(buf->error)) {
285                 err = buf->error;
286                 goto error;
287         }
288
289         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
290                               buf->offset, buf->data, prec);
291
292  error:
293         TALLOC_FREE(buf);
294         return err;
295 }
296
297 DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
298                        uint16 *num_records, struct dns_rrec ***records)
299 {
300         struct dns_rrec **new_records;
301
302         if (!(new_records = TALLOC_REALLOC_ARRAY(mem_ctx, *records,
303                                                  struct dns_rrec *,
304                                                  (*num_records)+1))) {
305                 return ERROR_DNS_NO_MEMORY;
306         }
307
308         new_records[*num_records] = talloc_move(new_records, &rec);
309
310         *num_records += 1;
311         *records = new_records;
312         return ERROR_DNS_SUCCESS;
313 }
314
315 /*
316  * Create a request that probes a server whether the list of IP addresses
317  * provides meets our expectations
318  */
319
320 DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
321                            const char *host, int num_ips,
322                            const struct in_addr *iplist,
323                            struct dns_update_request **preq)
324 {
325         struct dns_update_request *req;
326         struct dns_rrec *rec;
327         DNS_ERROR err;
328         uint16 i;
329
330         err = dns_create_update(mem_ctx, zone, &req);
331         if (!ERR_DNS_IS_OK(err)) goto error;
332
333         err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
334         if (!ERR_DNS_IS_OK(err)) goto error;
335
336         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
337         if (!ERR_DNS_IS_OK(err)) goto error;
338
339         for (i=0; i<num_ips; i++) {
340                 err = dns_create_name_in_use_record(req, host,
341                                                     &iplist[i], &rec);
342                 if (!ERR_DNS_IS_OK(err)) goto error;
343
344                 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
345                 if (!ERR_DNS_IS_OK(err)) goto error;
346         }
347
348         *preq = req;
349         return ERROR_DNS_SUCCESS;
350
351  error:
352         TALLOC_FREE(req);
353         return err;
354 }
355                            
356 DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
357                                     const char *domainname,
358                                     const char *hostname,
359                                     const struct in_addr *ip_addrs,
360                                     size_t num_addrs,
361                                     struct dns_update_request **preq)
362 {
363         struct dns_update_request *req;
364         struct dns_rrec *rec;
365         DNS_ERROR err;
366         size_t i;       
367
368         err = dns_create_update(mem_ctx, domainname, &req);
369         if (!ERR_DNS_IS_OK(err)) return err;
370
371         /*
372          * The zone must be used at all
373          */
374
375         err = dns_create_rrec(req, domainname, QTYPE_ANY, DNS_CLASS_ANY,
376                               0, 0, NULL, &rec);
377         if (!ERR_DNS_IS_OK(err)) goto error;
378
379         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
380         if (!ERR_DNS_IS_OK(err)) goto error;
381
382         /*
383          * Delete any existing A records
384          */
385
386         err = dns_create_delete_record(req, hostname, QTYPE_A, DNS_CLASS_ANY,
387                                        &rec);
388         if (!ERR_DNS_IS_OK(err)) goto error;
389         
390         err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
391         if (!ERR_DNS_IS_OK(err)) goto error;
392
393         /*
394          * .. and add our IPs
395          */
396
397         for ( i=0; i<num_addrs; i++ ) {         
398                 err = dns_create_a_record(req, hostname, 3600, ip_addrs[i], &rec);
399                 if (!ERR_DNS_IS_OK(err)) 
400                         goto error;
401
402                 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
403                 if (!ERR_DNS_IS_OK(err)) 
404                         goto error;
405         }       
406
407         *preq = req;
408         return ERROR_DNS_SUCCESS;
409
410  error:
411         TALLOC_FREE(req);
412         return err;
413 }