52391aef78080c57bb65879288c88e8966d34b5d
[samba.git] / lib / addns / 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "dns.h"
25
26 DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
27                             uint16 q_type, uint16 q_class,
28                             struct dns_request **preq )
29 {
30         struct dns_request *req;
31         struct dns_question *q;
32         DNS_ERROR err;
33
34         if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request)) ||
35             !(req->questions = TALLOC_ARRAY(req, struct dns_question *, 1)) ||
36             !(req->questions[0] = talloc(req->questions,
37                                          struct dns_question))) {
38                 TALLOC_FREE(req);
39                 return ERROR_DNS_NO_MEMORY;
40         }
41
42         req->id = random();
43
44         req->num_questions = 1;
45         q = req->questions[0];
46
47         err = dns_domain_name_from_string(q, name, &q->name);
48         if (!ERR_DNS_IS_OK(err)) {
49                 TALLOC_FREE(req);
50                 return err;
51         }
52
53         q->q_type = q_type;
54         q->q_class = q_class;
55
56         *preq = req;
57         return ERROR_DNS_SUCCESS;
58 }
59
60 DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
61                              struct dns_update_request **preq )
62 {
63         struct dns_update_request *req;
64         struct dns_zone *z;
65         DNS_ERROR err;
66
67         if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_update_request)) ||
68             !(req->zones = TALLOC_ARRAY(req, struct dns_zone *, 1)) ||
69             !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
70                 TALLOC_FREE(req);
71                 return ERROR_DNS_NO_MEMORY;
72         }
73
74         req->id = random();
75         req->flags = 0x2800;    /* Dynamic update */
76
77         req->num_zones = 1;
78         z = req->zones[0];
79
80         err = dns_domain_name_from_string(z, name, &z->name);
81         if (!ERR_DNS_IS_OK(err)) {
82                 TALLOC_FREE(req);
83                 return err;
84         }
85
86         z->z_type = QTYPE_SOA;
87         z->z_class = DNS_CLASS_IN;
88
89         *preq = req;
90         return ERROR_DNS_SUCCESS;
91 }
92
93 DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
94                           uint16 type, uint16 r_class, uint32 ttl,
95                           uint16 data_length, uint8 *data,
96                           struct dns_rrec **prec)
97 {
98         struct dns_rrec *rec;
99         DNS_ERROR err;
100
101         if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
102                 return ERROR_DNS_NO_MEMORY;
103         }
104
105         err = dns_domain_name_from_string(rec, name, &rec->name);
106         if (!(ERR_DNS_IS_OK(err))) {
107                 TALLOC_FREE(rec);
108                 return err;
109         }
110
111         rec->type = type;
112         rec->r_class = r_class;
113         rec->ttl = ttl;
114         rec->data_length = data_length;
115         rec->data = talloc_move(rec, &data);
116
117         *prec = rec;
118         return ERROR_DNS_SUCCESS;
119 }
120
121 DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
122                               uint32 ttl, const struct sockaddr_storage *pss,
123                               struct dns_rrec **prec)
124 {
125         uint8 *data;
126         DNS_ERROR err;
127         struct in_addr ip;
128
129         if (pss->ss_family != AF_INET) {
130                 /* Silently ignore this. */
131                 return ERROR_DNS_SUCCESS;
132         }
133
134         ip = ((const struct sockaddr_in *)pss)->sin_addr;
135         if (!(data = (uint8 *)TALLOC_MEMDUP(mem_ctx, (const void *)&ip.s_addr,
136                                             sizeof(ip.s_addr)))) {
137                 return ERROR_DNS_NO_MEMORY;
138         }
139
140         err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
141                               sizeof(ip.s_addr), data, prec);
142
143         if (!ERR_DNS_IS_OK(err)) {
144                 TALLOC_FREE(data);
145         }
146
147         return err;
148 }
149
150 DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
151                                         const char *name,
152                                         const struct sockaddr_storage *ss,
153                                         struct dns_rrec **prec)
154 {
155         if (ss != NULL) {
156                 return dns_create_a_record(mem_ctx, name, 0, ss, prec);
157         }
158
159         return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
160                                NULL, prec);
161 }
162
163 DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
164                                             const char *name, uint32 type,
165                                             struct dns_rrec **prec)
166 {
167         return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
168                                0, NULL, prec);
169 }
170
171 DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
172                                    uint16 type, uint16 r_class,
173                                    struct dns_rrec **prec)
174 {
175         return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
176 }
177
178 DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
179                                  const char *algorithm_name, time_t inception,
180                                  time_t expiration, uint16 mode, uint16 error,
181                                  uint16 key_length, const uint8 *key,
182                                  struct dns_rrec **prec)
183 {
184         struct dns_buffer *buf;
185         struct dns_domain_name *algorithm;
186         DNS_ERROR err;
187
188         if (!(buf = dns_create_buffer(mem_ctx))) {
189                 return ERROR_DNS_NO_MEMORY;
190         }
191
192         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
193         if (!ERR_DNS_IS_OK(err)) goto error;
194
195         dns_marshall_domain_name(buf, algorithm);
196         dns_marshall_uint32(buf, inception);
197         dns_marshall_uint32(buf, expiration);
198         dns_marshall_uint16(buf, mode);
199         dns_marshall_uint16(buf, error);
200         dns_marshall_uint16(buf, key_length);
201         dns_marshall_buffer(buf, key, key_length);
202         dns_marshall_uint16(buf, 0); /* Other Size */
203
204         if (!ERR_DNS_IS_OK(buf->error)) {
205                 err = buf->error;
206                 goto error;
207         }
208
209         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
210                               buf->offset, buf->data, prec);
211
212  error:
213         TALLOC_FREE(buf);
214         return err;
215 }
216
217 DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
218                                      struct dns_tkey_record **ptkey)
219 {
220         struct dns_tkey_record *tkey;
221         struct dns_buffer buf;
222         uint32 tmp_inception, tmp_expiration;
223         
224         if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
225                 return ERROR_DNS_NO_MEMORY;
226         }
227
228         buf.data = rec->data;
229         buf.size = rec->data_length;
230         buf.offset = 0;
231         buf.error = ERROR_DNS_SUCCESS;
232
233         dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
234         dns_unmarshall_uint32(&buf, &tmp_inception);
235         dns_unmarshall_uint32(&buf, &tmp_expiration);
236         dns_unmarshall_uint16(&buf, &tkey->mode);
237         dns_unmarshall_uint16(&buf, &tkey->error);
238         dns_unmarshall_uint16(&buf, &tkey->key_length);
239
240         if (!ERR_DNS_IS_OK(buf.error)) goto error;
241
242         if (tkey->key_length) {
243                 if (!(tkey->key = TALLOC_ARRAY(tkey, uint8, tkey->key_length))) {
244                         buf.error = ERROR_DNS_NO_MEMORY;
245                         goto error;
246                 }
247         } else {
248                 tkey->key = NULL;
249         }
250
251         dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
252         if (!ERR_DNS_IS_OK(buf.error)) goto error;
253
254         tkey->inception = (time_t)tmp_inception;
255         tkey->expiration = (time_t)tmp_expiration;
256
257         *ptkey = tkey;
258         return ERROR_DNS_SUCCESS;
259
260  error:
261         TALLOC_FREE(tkey);
262         return buf.error;
263 }
264
265 DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
266                                  const char *algorithm_name,
267                                  time_t time_signed, uint16 fudge,
268                                  uint16 mac_length, const uint8 *mac,
269                                  uint16 original_id, uint16 error,
270                                  struct dns_rrec **prec)
271 {
272         struct dns_buffer *buf;
273         struct dns_domain_name *algorithm;
274         DNS_ERROR err;
275
276         if (!(buf = dns_create_buffer(mem_ctx))) {
277                 return ERROR_DNS_NO_MEMORY;
278         }
279
280         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
281         if (!ERR_DNS_IS_OK(err)) goto error;
282
283         dns_marshall_domain_name(buf, algorithm);
284         dns_marshall_uint16(buf, 0); /* time prefix */
285         dns_marshall_uint32(buf, time_signed);
286         dns_marshall_uint16(buf, fudge);
287         dns_marshall_uint16(buf, mac_length);
288         dns_marshall_buffer(buf, mac, mac_length);
289         dns_marshall_uint16(buf, original_id);
290         dns_marshall_uint16(buf, error);
291         dns_marshall_uint16(buf, 0); /* Other Size */
292
293         if (!ERR_DNS_IS_OK(buf->error)) {
294                 err = buf->error;
295                 goto error;
296         }
297
298         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
299                               buf->offset, buf->data, prec);
300
301  error:
302         TALLOC_FREE(buf);
303         return err;
304 }
305
306 DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
307                        uint16 *num_records, struct dns_rrec ***records)
308 {
309         struct dns_rrec **new_records;
310
311         if (!(new_records = talloc_realloc(mem_ctx, *records,
312                                                  struct dns_rrec *,
313                                                  (*num_records)+1))) {
314                 return ERROR_DNS_NO_MEMORY;
315         }
316
317         new_records[*num_records] = talloc_move(new_records, &rec);
318
319         *num_records += 1;
320         *records = new_records;
321         return ERROR_DNS_SUCCESS;
322 }
323
324 /*
325  * Create a request that probes a server whether the list of IP addresses
326  * provides meets our expectations
327  */
328
329 DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
330                            const char *host, int num_ips,
331                            const struct sockaddr_storage *sslist,
332                            struct dns_update_request **preq)
333 {
334         struct dns_update_request *req;
335         struct dns_rrec *rec;
336         DNS_ERROR err;
337         uint16 i;
338
339         err = dns_create_update(mem_ctx, zone, &req);
340         if (!ERR_DNS_IS_OK(err)) goto error;
341
342         err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
343         if (!ERR_DNS_IS_OK(err)) goto error;
344
345         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
346         if (!ERR_DNS_IS_OK(err)) goto error;
347
348         for (i=0; i<num_ips; i++) {
349                 err = dns_create_name_in_use_record(req, host,
350                                                     &sslist[i], &rec);
351                 if (!ERR_DNS_IS_OK(err)) goto error;
352
353                 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
354                 if (!ERR_DNS_IS_OK(err)) goto error;
355         }
356
357         *preq = req;
358         return ERROR_DNS_SUCCESS;
359
360  error:
361         TALLOC_FREE(req);
362         return err;
363 }
364                            
365 DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
366                                     const char *domainname,
367                                     const char *hostname,
368                                     const struct sockaddr_storage *ss_addrs,
369                                     size_t num_addrs,
370                                     struct dns_update_request **preq)
371 {
372         struct dns_update_request *req;
373         struct dns_rrec *rec;
374         DNS_ERROR err;
375         size_t i;
376
377         err = dns_create_update(mem_ctx, domainname, &req);
378         if (!ERR_DNS_IS_OK(err)) return err;
379
380         /*
381          * Use the same prereq as WinXP -- No CNAME records for this host.
382          */
383
384         err = dns_create_rrec(req, hostname, QTYPE_CNAME, DNS_CLASS_NONE,
385                               0, 0, NULL, &rec);
386         if (!ERR_DNS_IS_OK(err)) goto error;
387
388         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
389         if (!ERR_DNS_IS_OK(err)) goto error;
390
391         /*
392          * Delete any existing A records
393          */
394
395         err = dns_create_delete_record(req, hostname, QTYPE_A, DNS_CLASS_ANY,
396                                        &rec);
397         if (!ERR_DNS_IS_OK(err)) goto error;
398
399         err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
400         if (!ERR_DNS_IS_OK(err)) goto error;
401
402         /*
403          * .. and add our IPs
404          */
405
406         for ( i=0; i<num_addrs; i++ ) {
407                 err = dns_create_a_record(req, hostname, 3600, &ss_addrs[i], &rec);
408                 if (!ERR_DNS_IS_OK(err))
409                         goto error;
410
411                 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
412                 if (!ERR_DNS_IS_OK(err))
413                         goto error;
414         }
415
416         *preq = req;
417         return ERROR_DNS_SUCCESS;
418
419  error:
420         TALLOC_FREE(req);
421         return err;
422 }