Use an absolute path to ensure that we can always regenerate tables.c
[Samba/bb.git] / source3 / libaddns / dnsrecord.c
blob559c2644d44a1ef3d5fb37b4797184d80e446cd0
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, const struct sockaddr_storage *pss,
123 struct dns_rrec **prec)
125 uint8 *data;
126 DNS_ERROR err;
127 struct in_addr ip;
129 if (pss->ss_family != AF_INET) {
130 /* Silently ignore this. */
131 return ERROR_DNS_SUCCESS;
134 ip = ((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;
140 err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
141 sizeof(ip.s_addr), data, prec);
143 if (!ERR_DNS_IS_OK(err)) {
144 TALLOC_FREE(data);
147 return err;
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)
155 if (ss != NULL) {
156 return dns_create_a_record(mem_ctx, name, 0, ss, prec);
159 return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
160 NULL, prec);
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)
167 return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
168 0, NULL, prec);
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)
175 return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
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)
184 struct dns_buffer *buf;
185 struct dns_domain_name *algorithm;
186 DNS_ERROR err;
188 if (!(buf = dns_create_buffer(mem_ctx))) {
189 return ERROR_DNS_NO_MEMORY;
192 err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
193 if (!ERR_DNS_IS_OK(err)) goto error;
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 */
204 if (!ERR_DNS_IS_OK(buf->error)) {
205 err = buf->error;
206 goto error;
209 err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
210 buf->offset, buf->data, prec);
212 error:
213 TALLOC_FREE(buf);
214 return err;
217 DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
218 struct dns_tkey_record **ptkey)
220 struct dns_tkey_record *tkey;
221 struct dns_buffer buf;
222 uint32 tmp_inception, tmp_expiration;
224 if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
225 return ERROR_DNS_NO_MEMORY;
228 buf.data = rec->data;
229 buf.size = rec->data_length;
230 buf.offset = 0;
231 buf.error = ERROR_DNS_SUCCESS;
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);
240 if (!ERR_DNS_IS_OK(buf.error)) goto error;
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;
247 } else {
248 tkey->key = NULL;
251 dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
252 if (!ERR_DNS_IS_OK(buf.error)) goto error;
254 tkey->inception = (time_t)tmp_inception;
255 tkey->expiration = (time_t)tmp_expiration;
257 *ptkey = tkey;
258 return ERROR_DNS_SUCCESS;
260 error:
261 TALLOC_FREE(tkey);
262 return buf.error;
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)
272 struct dns_buffer *buf;
273 struct dns_domain_name *algorithm;
274 DNS_ERROR err;
276 if (!(buf = dns_create_buffer(mem_ctx))) {
277 return ERROR_DNS_NO_MEMORY;
280 err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
281 if (!ERR_DNS_IS_OK(err)) goto error;
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 */
293 if (!ERR_DNS_IS_OK(buf->error)) {
294 err = buf->error;
295 goto error;
298 err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
299 buf->offset, buf->data, prec);
301 error:
302 TALLOC_FREE(buf);
303 return err;
306 DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
307 uint16 *num_records, struct dns_rrec ***records)
309 struct dns_rrec **new_records;
311 if (!(new_records = TALLOC_REALLOC_ARRAY(mem_ctx, *records,
312 struct dns_rrec *,
313 (*num_records)+1))) {
314 return ERROR_DNS_NO_MEMORY;
317 new_records[*num_records] = talloc_move(new_records, &rec);
319 *num_records += 1;
320 *records = new_records;
321 return ERROR_DNS_SUCCESS;
325 * Create a request that probes a server whether the list of IP addresses
326 * provides meets our expectations
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)
334 struct dns_update_request *req;
335 struct dns_rrec *rec;
336 DNS_ERROR err;
337 uint16 i;
339 err = dns_create_update(mem_ctx, zone, &req);
340 if (!ERR_DNS_IS_OK(err)) goto error;
342 err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
343 if (!ERR_DNS_IS_OK(err)) goto error;
345 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
346 if (!ERR_DNS_IS_OK(err)) goto error;
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;
353 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
354 if (!ERR_DNS_IS_OK(err)) goto error;
357 *preq = req;
358 return ERROR_DNS_SUCCESS;
360 error:
361 TALLOC_FREE(req);
362 return err;
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)
372 struct dns_update_request *req;
373 struct dns_rrec *rec;
374 DNS_ERROR err;
375 size_t i;
377 err = dns_create_update(mem_ctx, domainname, &req);
378 if (!ERR_DNS_IS_OK(err)) return err;
381 * Use the same prereq as WinXP -- No CNAME records for this host.
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;
388 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
389 if (!ERR_DNS_IS_OK(err)) goto error;
392 * Delete any existing A records
395 err = dns_create_delete_record(req, hostname, QTYPE_A, DNS_CLASS_ANY,
396 &rec);
397 if (!ERR_DNS_IS_OK(err)) goto error;
399 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
400 if (!ERR_DNS_IS_OK(err)) goto error;
403 * .. and add our IPs
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;
411 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
412 if (!ERR_DNS_IS_OK(err))
413 goto error;
416 *preq = req;
417 return ERROR_DNS_SUCCESS;
419 error:
420 TALLOC_FREE(req);
421 return err;