Some paranoia checks
[Samba/gebeck_regimport.git] / source3 / libaddns / dnsrecord.c
blobcb8a7c1a950fd354160337addfa7d367c795c31d
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>
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
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.
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.
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/>.
24 #include "dns.h"
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 )
30 struct dns_request *req;
31 struct dns_question *q;
32 DNS_ERROR err;
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;
42 req->id = random();
44 req->num_questions = 1;
45 q = req->questions[0];
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;
53 q->q_type = q_type;
54 q->q_class = q_class;
56 *preq = req;
57 return ERROR_DNS_SUCCESS;
60 DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
61 struct dns_update_request **preq )
63 struct dns_update_request *req;
64 struct dns_zone *z;
65 DNS_ERROR err;
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;
74 req->id = random();
75 req->flags = 0x2800; /* Dynamic update */
77 req->num_zones = 1;
78 z = req->zones[0];
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;
86 z->z_type = QTYPE_SOA;
87 z->z_class = DNS_CLASS_IN;
89 *preq = req;
90 return ERROR_DNS_SUCCESS;
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)
98 struct dns_rrec *rec;
99 DNS_ERROR err;
101 if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
102 return ERROR_DNS_NO_MEMORY;
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;
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);
117 *prec = rec;
118 return ERROR_DNS_SUCCESS;
121 DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
122 uint32 ttl, struct in_addr ip,
123 struct dns_rrec **prec)
125 uint8 *data;
126 DNS_ERROR err;
128 if (!(data = (uint8 *)TALLOC_MEMDUP(mem_ctx, (const void *)&ip.s_addr,
129 sizeof(ip.s_addr)))) {
130 return ERROR_DNS_NO_MEMORY;
133 err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
134 sizeof(ip.s_addr), data, prec);
136 if (!ERR_DNS_IS_OK(err)) {
137 TALLOC_FREE(data);
140 return err;
143 DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
144 const char *name,
145 const struct in_addr *ip,
146 struct dns_rrec **prec)
148 if (ip != NULL) {
149 return dns_create_a_record(mem_ctx, name, 0, *ip, prec);
152 return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
153 NULL, prec);
156 DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
157 const char *name, uint32 type,
158 struct dns_rrec **prec)
160 return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
161 0, NULL, prec);
164 DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
165 uint16 type, uint16 r_class,
166 struct dns_rrec **prec)
168 return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
171 DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
172 const char *algorithm_name, time_t inception,
173 time_t expiration, uint16 mode, uint16 error,
174 uint16 key_length, const uint8 *key,
175 struct dns_rrec **prec)
177 struct dns_buffer *buf;
178 struct dns_domain_name *algorithm;
179 DNS_ERROR err;
181 if (!(buf = dns_create_buffer(mem_ctx))) {
182 return ERROR_DNS_NO_MEMORY;
185 err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
186 if (!ERR_DNS_IS_OK(err)) goto error;
188 dns_marshall_domain_name(buf, algorithm);
189 dns_marshall_uint32(buf, inception);
190 dns_marshall_uint32(buf, expiration);
191 dns_marshall_uint16(buf, mode);
192 dns_marshall_uint16(buf, error);
193 dns_marshall_uint16(buf, key_length);
194 dns_marshall_buffer(buf, key, key_length);
195 dns_marshall_uint16(buf, 0); /* Other Size */
197 if (!ERR_DNS_IS_OK(buf->error)) {
198 err = buf->error;
199 goto error;
202 err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
203 buf->offset, buf->data, prec);
205 error:
206 TALLOC_FREE(buf);
207 return err;
210 DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
211 struct dns_tkey_record **ptkey)
213 struct dns_tkey_record *tkey;
214 struct dns_buffer buf;
215 uint32 tmp_inception, tmp_expiration;
217 if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
218 return ERROR_DNS_NO_MEMORY;
221 buf.data = rec->data;
222 buf.size = rec->data_length;
223 buf.offset = 0;
224 buf.error = ERROR_DNS_SUCCESS;
226 dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
227 dns_unmarshall_uint32(&buf, &tmp_inception);
228 dns_unmarshall_uint32(&buf, &tmp_expiration);
229 dns_unmarshall_uint16(&buf, &tkey->mode);
230 dns_unmarshall_uint16(&buf, &tkey->error);
231 dns_unmarshall_uint16(&buf, &tkey->key_length);
233 if (!ERR_DNS_IS_OK(buf.error)) goto error;
235 if (tkey->key_length) {
236 if (!(tkey->key = TALLOC_ARRAY(tkey, uint8, tkey->key_length))) {
237 buf.error = ERROR_DNS_NO_MEMORY;
238 goto error;
240 } else {
241 tkey->key = NULL;
244 dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
245 if (!ERR_DNS_IS_OK(buf.error)) goto error;
247 tkey->inception = (time_t)tmp_inception;
248 tkey->expiration = (time_t)tmp_expiration;
250 *ptkey = tkey;
251 return ERROR_DNS_SUCCESS;
253 error:
254 TALLOC_FREE(tkey);
255 return buf.error;
258 DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
259 const char *algorithm_name,
260 time_t time_signed, uint16 fudge,
261 uint16 mac_length, const uint8 *mac,
262 uint16 original_id, uint16 error,
263 struct dns_rrec **prec)
265 struct dns_buffer *buf;
266 struct dns_domain_name *algorithm;
267 DNS_ERROR err;
269 if (!(buf = dns_create_buffer(mem_ctx))) {
270 return ERROR_DNS_NO_MEMORY;
273 err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
274 if (!ERR_DNS_IS_OK(err)) goto error;
276 dns_marshall_domain_name(buf, algorithm);
277 dns_marshall_uint16(buf, 0); /* time prefix */
278 dns_marshall_uint32(buf, time_signed);
279 dns_marshall_uint16(buf, fudge);
280 dns_marshall_uint16(buf, mac_length);
281 dns_marshall_buffer(buf, mac, mac_length);
282 dns_marshall_uint16(buf, original_id);
283 dns_marshall_uint16(buf, error);
284 dns_marshall_uint16(buf, 0); /* Other Size */
286 if (!ERR_DNS_IS_OK(buf->error)) {
287 err = buf->error;
288 goto error;
291 err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
292 buf->offset, buf->data, prec);
294 error:
295 TALLOC_FREE(buf);
296 return err;
299 DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
300 uint16 *num_records, struct dns_rrec ***records)
302 struct dns_rrec **new_records;
304 if (!(new_records = TALLOC_REALLOC_ARRAY(mem_ctx, *records,
305 struct dns_rrec *,
306 (*num_records)+1))) {
307 return ERROR_DNS_NO_MEMORY;
310 new_records[*num_records] = talloc_move(new_records, &rec);
312 *num_records += 1;
313 *records = new_records;
314 return ERROR_DNS_SUCCESS;
318 * Create a request that probes a server whether the list of IP addresses
319 * provides meets our expectations
322 DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
323 const char *host, int num_ips,
324 const struct in_addr *iplist,
325 struct dns_update_request **preq)
327 struct dns_update_request *req;
328 struct dns_rrec *rec;
329 DNS_ERROR err;
330 uint16 i;
332 err = dns_create_update(mem_ctx, zone, &req);
333 if (!ERR_DNS_IS_OK(err)) goto error;
335 err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
336 if (!ERR_DNS_IS_OK(err)) goto error;
338 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
339 if (!ERR_DNS_IS_OK(err)) goto error;
341 for (i=0; i<num_ips; i++) {
342 err = dns_create_name_in_use_record(req, host,
343 &iplist[i], &rec);
344 if (!ERR_DNS_IS_OK(err)) goto error;
346 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
347 if (!ERR_DNS_IS_OK(err)) goto error;
350 *preq = req;
351 return ERROR_DNS_SUCCESS;
353 error:
354 TALLOC_FREE(req);
355 return err;
358 DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
359 const char *domainname,
360 const char *hostname,
361 const struct in_addr *ip_addrs,
362 size_t num_addrs,
363 struct dns_update_request **preq)
365 struct dns_update_request *req;
366 struct dns_rrec *rec;
367 DNS_ERROR err;
368 size_t i;
370 err = dns_create_update(mem_ctx, domainname, &req);
371 if (!ERR_DNS_IS_OK(err)) return err;
374 * The zone must be used at all
377 err = dns_create_rrec(req, domainname, QTYPE_ANY, DNS_CLASS_ANY,
378 0, 0, NULL, &rec);
379 if (!ERR_DNS_IS_OK(err)) goto error;
381 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
382 if (!ERR_DNS_IS_OK(err)) goto error;
385 * Delete any existing A records
388 err = dns_create_delete_record(req, hostname, QTYPE_A, DNS_CLASS_ANY,
389 &rec);
390 if (!ERR_DNS_IS_OK(err)) goto error;
392 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
393 if (!ERR_DNS_IS_OK(err)) goto error;
396 * .. and add our IPs
399 for ( i=0; i<num_addrs; i++ ) {
400 err = dns_create_a_record(req, hostname, 3600, ip_addrs[i], &rec);
401 if (!ERR_DNS_IS_OK(err))
402 goto error;
404 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
405 if (!ERR_DNS_IS_OK(err))
406 goto error;
409 *preq = req;
410 return ERROR_DNS_SUCCESS;
412 error:
413 TALLOC_FREE(req);
414 return err;