s4-rpc: dnsserver: Fix enumeration of IPv4 and IPv6 addresses
[Samba.git] / source4 / rpc_server / dnsserver / dnsdata.c
blob067654ad2c62f25493441889337048204a7edb31
1 /*
2 Unix SMB/CIFS implementation.
4 DNS Server
6 Copyright (C) Amitay Isaacs 2011
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "dnsserver.h"
24 #include "lib/replace/system/network.h"
25 #include "librpc/gen_ndr/ndr_dnsp.h"
26 #include "librpc/gen_ndr/ndr_dnsserver.h"
29 struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4)
31 struct IP4_ARRAY *ret;
33 if (!ip4) {
34 return NULL;
37 ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
38 if (!ret) {
39 return ret;
42 ret->AddrCount = ip4->AddrCount;
43 if (ip4->AddrCount > 0) {
44 ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount);
45 if (ret->AddrArray) {
46 memcpy(ret->AddrArray, ip4->AddrArray,
47 sizeof(unsigned int) * ip4->AddrCount);
48 } else {
49 talloc_free(ret);
50 return NULL;
53 return ret;
57 struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
58 struct IP4_ARRAY *ip4)
60 struct DNS_ADDR_ARRAY *ret;
61 int i;
63 if (!ip4) {
64 return NULL;
67 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
68 if (!ret) {
69 return ret;
72 ret->MaxCount = ip4->AddrCount;
73 ret->AddrCount = ip4->AddrCount;
74 ret->Family = AF_INET;
75 if (ip4->AddrCount > 0) {
76 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount);
77 if (ret->AddrArray) {
78 for (i=0; i<ip4->AddrCount; i++) {
79 ret->AddrArray[i].MaxSa[0] = 0x02;
80 ret->AddrArray[i].MaxSa[3] = 53;
81 memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray,
82 sizeof(unsigned int));
83 ret->AddrArray[i].DnsAddrUserDword[0] = 6;
86 } else {
87 talloc_free(ret);
88 return NULL;
91 return ret;
94 struct IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
95 struct DNS_ADDR_ARRAY *ip)
97 struct IP4_ARRAY *ret;
98 int i, count, curr;
100 if (ip == NULL) {
101 return NULL;
103 /* We must only return IPv4 addresses.
104 The passed DNS_ADDR_ARRAY may contain:
105 - only ipv4 addresses
106 - only ipv6 addresses
107 - a mixture of both
108 - an empty array
110 ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
111 if (!ret) {
112 return ret;
114 if (ip->AddrCount == 0 || ip->Family == AF_INET6) {
115 ret->AddrCount = 0;
116 return ret;
118 /* Now only ipv4 addresses or a mixture are left */
119 count = 0;
120 for (i = 0; i < ip->AddrCount; i++) {
121 if (ip->AddrArray[i].MaxSa[0] == 0x02) {
122 /* Is ipv4 */
123 count++;
126 if (count == 0) {
127 /* should not happen */
128 ret->AddrCount = 0;
129 return ret;
131 ret->AddrArray = talloc_zero_array(mem_ctx, uint32_t, count);
132 if (ret->AddrArray) {
133 curr = 0;
134 for (i = 0; i < ip->AddrCount; i++) {
135 if (ip->AddrArray[i].MaxSa[0] == 0x02) {
136 /* Is ipv4 */
137 memcpy(&ret->AddrArray[curr],
138 &ip->AddrArray[i].MaxSa[4],
139 sizeof(uint32_t));
140 curr++;
143 } else {
144 talloc_free(ret);
145 return NULL;
147 ret->AddrCount = curr;
148 return ret;
151 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
152 struct DNS_ADDR_ARRAY *addr)
154 struct DNS_ADDR_ARRAY *ret;
156 if (!addr) {
157 return NULL;
160 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
161 if (!ret) {
162 return ret;
165 ret->MaxCount = addr->MaxCount;
166 ret->AddrCount = addr->AddrCount;
167 ret->Family = addr->Family;
168 if (addr->AddrCount > 0) {
169 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
170 if (ret->AddrArray) {
171 memcpy(ret->AddrArray, addr->AddrArray,
172 sizeof(struct DNS_ADDR) * addr->AddrCount);
173 } else {
174 talloc_free(ret);
175 return NULL;
178 return ret;
182 int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
184 char *str = NULL, *ptr, **list;
185 int count = 0;
187 if (name == NULL) {
188 return 0;
191 str = talloc_strdup(tmp_ctx, name);
192 if (!str) {
193 goto failed;
196 list = talloc_zero_array(tmp_ctx, char *, 0);
197 if (!list) {
198 goto failed;
201 ptr = strtok(str, ".");
202 while (ptr != NULL) {
203 count++;
204 list = talloc_realloc(tmp_ctx, list, char *, count);
205 if (!list) {
206 goto failed;
208 list[count-1] = talloc_strdup(tmp_ctx, ptr);
209 if (list[count-1] == NULL) {
210 goto failed;
212 ptr = strtok(NULL, ".");
215 talloc_free(str);
217 *components = list;
218 return count;
220 failed:
221 if (str) {
222 talloc_free(str);
224 return -1;
228 char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
230 char **nlist, **zlist;
231 char *prefix;
232 int ncount, zcount, i, match;
235 * If node_name is "@", return the zone_name
236 * If node_name is ".", return NULL
237 * If there is no '.' in node_name, return the node_name as is.
239 * If node_name does not have zone_name in it, return the node_name as is.
241 * If node_name has additional components as compared to zone_name
242 * return only the additional components as a prefix.
245 if (strcmp(node_name, "@") == 0) {
246 prefix = talloc_strdup(tmp_ctx, zone_name);
247 } else if (strcmp(node_name, ".") == 0) {
248 prefix = NULL;
249 } else if (strchr(node_name, '.') == NULL) {
250 prefix = talloc_strdup(tmp_ctx, node_name);
251 } else {
252 zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
253 ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
254 if (zcount < 0 || ncount < 0) {
255 return NULL;
258 if (ncount < zcount) {
259 prefix = talloc_strdup(tmp_ctx, node_name);
260 } else {
261 match = 0;
262 for (i=1; i<=zcount; i++) {
263 if (strcasecmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
264 break;
266 match++;
269 if (match == ncount) {
270 prefix = talloc_strdup(tmp_ctx, zone_name);
271 } else {
272 prefix = talloc_strdup(tmp_ctx, nlist[0]);
273 if (prefix != NULL) {
274 for (i=1; i<ncount-match; i++) {
275 prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
276 if (prefix == NULL) {
277 break;
284 talloc_free(zlist);
285 talloc_free(nlist);
288 return prefix;
292 void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
293 struct DNS_RPC_RECORD *dns)
295 int i, len;
297 ZERO_STRUCTP(dns);
299 dns->wDataLength = dnsp->wDataLength;
300 dns->wType = dnsp->wType;
301 dns->dwFlags = dnsp->rank;
302 dns->dwSerial = dnsp->dwSerial;
303 dns->dwTtlSeconds = dnsp->dwTtlSeconds;
304 dns->dwTimeStamp = dnsp->dwTimeStamp;
306 switch (dnsp->wType) {
308 case DNS_TYPE_TOMBSTONE:
309 dns->data.timestamp = dnsp->data.timestamp;
310 break;
312 case DNS_TYPE_A:
313 dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
314 break;
316 case DNS_TYPE_NS:
317 len = strlen(dnsp->data.ns);
318 if (dnsp->data.ns[len-1] == '.') {
319 dns->data.name.len = len;
320 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
321 } else {
322 dns->data.name.len = len+1;
323 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
325 break;
327 case DNS_TYPE_CNAME:
328 len = strlen(dnsp->data.cname);
329 if (dnsp->data.cname[len-1] == '.') {
330 dns->data.name.len = len;
331 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
332 } else {
333 dns->data.name.len = len+1;
334 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
336 break;
338 case DNS_TYPE_SOA:
339 dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
340 dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
341 dns->data.soa.dwRetry = dnsp->data.soa.retry;
342 dns->data.soa.dwExpire = dnsp->data.soa.expire;
343 dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
345 len = strlen(dnsp->data.soa.mname);
346 if (dnsp->data.soa.mname[len-1] == '.') {
347 dns->data.soa.NamePrimaryServer.len = len;
348 dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
349 } else {
350 dns->data.soa.NamePrimaryServer.len = len+1;
351 dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
354 len = strlen(dnsp->data.soa.rname);
355 if (dnsp->data.soa.rname[len-1] == '.') {
356 dns->data.soa.ZoneAdministratorEmail.len = len;
357 dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
358 } else {
359 dns->data.soa.ZoneAdministratorEmail.len = len+1;
360 dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
362 break;
364 case DNS_TYPE_PTR:
365 dns->data.ptr.len = strlen(dnsp->data.ptr);
366 dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
367 break;
369 case DNS_TYPE_MX:
370 dns->data.mx.wPreference = dnsp->data.mx.wPriority;
371 len = strlen(dnsp->data.mx.nameTarget);
372 if (dnsp->data.mx.nameTarget[len-1] == '.') {
373 dns->data.mx.nameExchange.len = len;
374 dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
375 } else {
376 dns->data.mx.nameExchange.len = len+1;
377 dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
379 break;
381 case DNS_TYPE_TXT:
382 dns->data.txt.count = dnsp->data.txt.count;
383 dns->data.txt.str = talloc_array(mem_ctx, struct DNS_RPC_NAME, dnsp->data.txt.count);
384 for (i=0; i<dnsp->data.txt.count; i++) {
385 dns->data.txt.str[i].str = talloc_strdup(mem_ctx, dnsp->data.txt.str[i]);
386 dns->data.txt.str[i].len = strlen(dnsp->data.txt.str[i]);
388 break;
390 case DNS_TYPE_AAAA:
391 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
392 break;
394 case DNS_TYPE_SRV:
395 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
396 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
397 dns->data.srv.wPort = dnsp->data.srv.wPort;
398 len = strlen(dnsp->data.srv.nameTarget);
399 if (dnsp->data.srv.nameTarget[len-1] == '.') {
400 dns->data.srv.nameTarget.len = len;
401 dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
402 } else {
403 dns->data.srv.nameTarget.len = len+1;
404 dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
406 break;
408 default:
409 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
410 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
416 struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns)
418 int i, len;
419 struct dnsp_DnssrvRpcRecord *dnsp;
421 dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
422 if (dnsp == NULL) {
423 return NULL;
426 dnsp->wDataLength = dns->wDataLength;
427 dnsp->wType = dns->wType;
428 dnsp->version = 5;
429 dnsp->rank = dns->dwFlags & 0x000000FF;
430 dnsp->dwSerial = dns->dwSerial;
431 dnsp->dwTtlSeconds = dns->dwTtlSeconds;
432 dnsp->dwTimeStamp = dns->dwTimeStamp;
434 switch (dns->wType) {
436 case DNS_TYPE_TOMBSTONE:
437 dnsp->data.timestamp = dns->data.timestamp;
438 break;
440 case DNS_TYPE_A:
441 dnsp->data.ipv4 = talloc_strdup(mem_ctx, dns->data.ipv4);
442 break;
444 case DNS_TYPE_NS:
445 len = dns->data.name.len;
446 if (dns->data.name.str[len-1] == '.') {
447 dnsp->data.ns = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
448 } else {
449 dnsp->data.ns = talloc_strdup(mem_ctx, dns->data.name.str);
451 break;
453 case DNS_TYPE_CNAME:
454 len = dns->data.name.len;
455 if (dns->data.name.str[len-1] == '.') {
456 dnsp->data.cname = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
457 } else {
458 dnsp->data.cname = talloc_strdup(mem_ctx, dns->data.name.str);
460 break;
462 case DNS_TYPE_SOA:
463 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
464 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
465 dnsp->data.soa.retry = dns->data.soa.dwRetry;
466 dnsp->data.soa.expire = dns->data.soa.dwExpire;
467 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
469 len = dns->data.soa.NamePrimaryServer.len;
470 if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') {
471 dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1);
472 } else {
473 dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
476 len = dns->data.soa.ZoneAdministratorEmail.len;
477 if (dns->data.soa.ZoneAdministratorEmail.str[len-1] == '.') {
478 dnsp->data.soa.rname = talloc_strndup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str, len-1);
479 } else {
480 dnsp->data.soa.rname = talloc_strdup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str);
482 break;
484 case DNS_TYPE_PTR:
485 dnsp->data.ptr = talloc_strdup(mem_ctx, dns->data.ptr.str);
486 break;
488 case DNS_TYPE_MX:
489 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
490 len = dns->data.mx.nameExchange.len;
491 if (dns->data.mx.nameExchange.str[len-1] == '.') {
492 dnsp->data.mx.nameTarget = talloc_strndup(mem_ctx, dns->data.mx.nameExchange.str, len-1);
493 } else {
494 dnsp->data.mx.nameTarget = talloc_strdup(mem_ctx, dns->data.mx.nameExchange.str);
496 break;
498 case DNS_TYPE_TXT:
499 dnsp->data.txt.count = dns->data.txt.count;
500 dnsp->data.txt.str = talloc_array(mem_ctx, const char *, dns->data.txt.count);
501 for (i=0; i<dns->data.txt.count; i++) {
502 dnsp->data.txt.str[i] = talloc_strdup(mem_ctx, dns->data.txt.str[i].str);
504 break;
506 case DNS_TYPE_AAAA:
507 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
508 break;
510 case DNS_TYPE_SRV:
511 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
512 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
513 dnsp->data.srv.wPort = dns->data.srv.wPort;
515 len = dns->data.srv.nameTarget.len;
516 if (dns->data.srv.nameTarget.str[len-1] == '.') {
517 dnsp->data.srv.nameTarget = talloc_strndup(mem_ctx, dns->data.srv.nameTarget.str, len-1);
518 } else {
519 dnsp->data.srv.nameTarget = talloc_strdup(mem_ctx, dns->data.srv.nameTarget.str);
521 break;
523 default:
524 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
525 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
529 return dnsp;
533 /* Intialize tree with given name as the root */
534 static struct dns_tree *dns_tree_init(TALLOC_CTX *mem_ctx, const char *name, void *data)
536 struct dns_tree *tree;
538 tree = talloc_zero(mem_ctx, struct dns_tree);
539 if (tree == NULL) {
540 return NULL;
543 tree->name = talloc_strdup(tree, name);
544 if (tree->name == NULL) {
545 talloc_free(tree);
546 return NULL;
549 tree->data = data;
551 return tree;
555 /* Add a child one level below */
556 static struct dns_tree *dns_tree_add(struct dns_tree *tree, const char *name, void *data)
558 struct dns_tree *node;
560 node = talloc_zero(tree, struct dns_tree);
561 if (node == NULL) {
562 return NULL;
565 node->name = talloc_strdup(tree, name);
566 if (node->name == NULL) {
567 talloc_free(node);
568 return NULL;
570 node->level = tree->level + 1;
571 node->num_children = 0;
572 node->children = NULL;
573 node->data = data;
575 if (tree->num_children == 0) {
576 tree->children = talloc_zero(tree, struct dns_tree *);
577 } else {
578 tree->children = talloc_realloc(tree, tree->children, struct dns_tree *,
579 tree->num_children+1);
581 if (tree->children == NULL) {
582 talloc_free(node);
583 return NULL;
585 tree->children[tree->num_children] = node;
586 tree->num_children++;
588 return node;
591 /* Find a node that matches the name components */
592 static struct dns_tree *dns_tree_find(struct dns_tree *tree, int ncount, char **nlist, int *match_count)
594 struct dns_tree *node, *next;
595 int i, j, start;
597 *match_count = -1;
599 if (strcmp(tree->name, "@") == 0) {
600 start = 0;
601 } else {
602 if (strcasecmp(tree->name, nlist[ncount-1]) != 0) {
603 return NULL;
605 start = 1;
606 *match_count = 0;
609 node = tree;
610 for (i=start; i<ncount; i++) {
611 if (node->num_children == 0) {
612 break;
614 next = NULL;
615 for (j=0; j<node->num_children; j++) {
616 if (strcasecmp(nlist[(ncount-1)-i], node->children[j]->name) == 0) {
617 next = node->children[j];
618 *match_count = i;
619 break;
622 if (next == NULL) {
623 break;
624 } else {
625 node = next;
629 return node;
632 /* Build a 2-level tree for resulting dns names */
633 struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ldb_result *res)
635 struct dns_tree *root, *base, *tree, *node;
636 const char *ptr;
637 int rootcount, ncount;
638 char **nlist;
639 int i, level, match_count;
641 rootcount = dns_split_name_components(mem_ctx, name, &nlist);
642 if (rootcount <= 0) {
643 return NULL;
646 root = dns_tree_init(mem_ctx, nlist[rootcount-1], NULL);
647 if (root == NULL) {
648 return NULL;
651 tree = root;
652 for (i=rootcount-2; i>=0; i--) {
653 tree = dns_tree_add(tree, nlist[i], NULL);
654 if (tree == NULL) {
655 goto failed;
659 base = tree;
661 /* Add all names in the result in a tree */
662 for (i=0; i<res->count; i++) {
663 ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL);
665 if (strcmp(ptr, "@") == 0) {
666 base->data = res->msgs[i];
667 continue;
668 } else if (strcasecmp(ptr, name) == 0) {
669 base->data = res->msgs[i];
670 continue;
673 ncount = dns_split_name_components(root, ptr, &nlist);
674 if (ncount < 0) {
675 goto failed;
678 /* Find matching node */
679 tree = dns_tree_find(root, ncount, nlist, &match_count);
680 if (tree == NULL) {
681 goto failed;
684 /* If the node is on leaf, then add record data */
685 if (match_count+1 == ncount) {
686 tree->data = res->msgs[i];
689 /* Add missing name components */
690 for (level=match_count+1; level<ncount; level++) {
691 if (tree->level == rootcount+1) {
692 break;
694 if (level == ncount-1) {
695 node = dns_tree_add(tree, nlist[(ncount-1)-level], res->msgs[i]);
696 } else {
697 node = dns_tree_add(tree, nlist[(ncount-1)-level], NULL);
699 if (node == NULL) {
700 goto failed;
702 tree = node;
705 talloc_free(nlist);
708 /* Mark the base record, so it can be found easily */
709 base->level = -1;
711 return root;
713 failed:
714 talloc_free(root);
715 return NULL;
719 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
721 int i;
722 char **ptr = *add_names;
723 int count = *add_count;
725 for (i=0; i<count; i++) {
726 if (strcasecmp(ptr[i], name) == 0) {
727 return;
731 ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
732 if (ptr == NULL) {
733 return;
736 ptr[count] = talloc_strdup(mem_ctx, name);
737 if (ptr[count] == NULL) {
738 return;
741 *add_names = ptr;
742 *add_count = count+1;
746 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
748 if (add_names == NULL) {
749 return;
752 switch (rec->wType) {
754 case DNS_TYPE_NS:
755 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
756 break;
758 case DNS_TYPE_CNAME:
759 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
760 break;
762 case DNS_TYPE_SOA:
763 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
764 break;
766 case DNS_TYPE_MX:
767 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
768 break;
770 case DNS_TYPE_SRV:
771 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
772 break;
774 default:
775 break;
780 WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
781 struct dnsserver_zone *z,
782 enum dns_record_type record_type,
783 unsigned int select_flag,
784 const char *branch_name,
785 struct ldb_message *msg,
786 int num_children,
787 struct DNS_RPC_RECORDS_ARRAY *recs,
788 char ***add_names,
789 int *add_count)
791 struct ldb_message_element *el;
792 const char *ptr;
793 int i, j;
794 bool found;
796 if (recs->count == 0) {
797 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
798 } else {
799 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
801 if (recs->rec == NULL) {
802 return WERR_NOMEM;
804 i = recs->count;
805 recs->rec[i].wLength = 0;
806 recs->rec[i].wRecordCount = 0;
807 recs->rec[i].dwChildCount = num_children;
808 recs->rec[i].dwFlags = 0;
810 /* The base records returned with empty name */
811 /* Children records returned with names */
812 if (branch_name == NULL) {
813 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
814 recs->rec[i].dnsNodeName.len = 0;
815 } else {
816 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
817 recs->rec[i].dnsNodeName.len = strlen(branch_name);
819 recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
820 recs->count++;
822 /* Allow empty records */
823 if (msg == NULL) {
824 return WERR_OK;
827 /* Do not return RR records, if the node has children */
828 if (branch_name != NULL && num_children > 0) {
829 return WERR_OK;
832 ptr = ldb_msg_find_attr_as_string(msg, "name", NULL);
833 el = ldb_msg_find_element(msg, "dnsRecord");
834 if (el == NULL || el->values == 0) {
835 return WERR_OK;
838 /* Add RR records */
839 for (j=0; j<el->num_values; j++) {
840 struct dnsp_DnssrvRpcRecord dnsp_rec;
841 struct DNS_RPC_RECORD *dns_rec;
842 enum ndr_err_code ndr_err;
844 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
845 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
846 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
847 DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
848 return WERR_INTERNAL_DB_ERROR;
851 /* Match the records based on search criteria */
852 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
853 found = false;
855 if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
856 if (dnsp_rec.rank == DNS_RANK_ZONE) {
857 found = true;
858 } else if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
860 * If branch_name is NULL, we're
861 * explicitly asked to also return
862 * DNS_RANK_NS_GLUE records
864 if (branch_name == NULL) {
865 found = true;
869 if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
870 if (dnsp_rec.rank == DNS_RANK_ZONE) {
871 found = true;
874 if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
875 if (dnsp_rec.rank == DNS_RANK_GLUE) {
876 found = true;
879 if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
880 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
881 found = true;
885 if (found) {
886 recs->rec[i].records = talloc_realloc(recs,
887 recs->rec[i].records,
888 struct DNS_RPC_RECORD,
889 recs->rec[i].wRecordCount+1);
890 if (recs->rec[i].records == NULL) {
891 return WERR_NOMEM;
894 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
895 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
897 /* Fix record flags */
898 if (strcmp(ptr, "@") == 0) {
899 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
901 if (dnsp_rec.rank == DNS_RANK_ZONE) {
902 dns_rec->dwFlags |= DNS_RPC_FLAG_AUTH_ZONE_ROOT;
906 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
907 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
910 recs->rec[i].wRecordCount++;
912 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
917 return WERR_OK;
921 int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
922 char *search_name)
924 const char *name1, *name2;
925 const char *ptr1, *ptr2;
927 name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
928 name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
929 if (name1 == NULL || name2 == NULL) {
930 return 0;
933 /* '@' record and the search_name record gets preference */
934 if (name1[0] == '@') {
935 return -1;
937 if (search_name && strcasecmp(name1, search_name) == 0) {
938 return -1;
941 if (name2[0] == '@') {
942 return 1;
944 if (search_name && strcasecmp(name2, search_name) == 0) {
945 return 1;
948 /* Compare the last components of names.
949 * If search_name is not NULL, compare the second last components of names */
950 ptr1 = strrchr(name1, '.');
951 if (ptr1 == NULL) {
952 ptr1 = name1;
953 } else {
954 if (search_name && strcasecmp(ptr1+1, search_name) == 0) {
955 ptr1--;
956 while (ptr1 != name1) {
957 ptr1--;
958 if (*ptr1 == '.') {
959 break;
963 if (*ptr1 == '.') {
964 ptr1 = &ptr1[1];
968 ptr2 = strrchr(name2, '.');
969 if (ptr2 == NULL) {
970 ptr2 = name2;
971 } else {
972 if (search_name && strcasecmp(ptr2+1, search_name) == 0) {
973 ptr2--;
974 while (ptr2 != name2) {
975 ptr2--;
976 if (*ptr2 == '.') {
977 break;
981 if (*ptr2 == '.') {
982 ptr2 = &ptr2[1];
986 return strcasecmp(ptr1, ptr2);
990 bool dns_name_equal(const char *name1, const char *name2)
992 size_t len1 = strlen(name1);
993 size_t len2 = strlen(name2);
995 if (name1[len1-1] == '.') len1--;
996 if (name2[len2-1] == '.') len2--;
997 if (len1 != len2) {
998 return false;
1000 return strncasecmp(name1, name2, len1) == 0;
1004 bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
1006 bool status;
1007 int i;
1009 if (rec1->wType != rec2->wType) {
1010 return false;
1013 switch(rec1->wType) {
1014 case DNS_TYPE_TOMBSTONE:
1015 return true;
1017 case DNS_TYPE_A:
1018 return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
1020 case DNS_TYPE_NS:
1021 return dns_name_equal(rec1->data.ns, rec2->data.ns);
1023 case DNS_TYPE_CNAME:
1024 return dns_name_equal(rec1->data.cname, rec2->data.cname);
1026 case DNS_TYPE_SOA:
1027 return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) &&
1028 dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) &&
1029 rec1->data.soa.serial == rec2->data.soa.serial &&
1030 rec1->data.soa.refresh == rec2->data.soa.refresh &&
1031 rec1->data.soa.retry == rec2->data.soa.retry &&
1032 rec1->data.soa.expire == rec2->data.soa.expire &&
1033 rec1->data.soa.minimum == rec2->data.soa.minimum;
1035 case DNS_TYPE_PTR:
1036 return dns_name_equal(rec1->data.ptr, rec2->data.ptr);
1038 case DNS_TYPE_MX:
1039 return rec1->data.mx.wPriority == rec2->data.mx.wPriority &&
1040 dns_name_equal(rec1->data.mx.nameTarget, rec2->data.mx.nameTarget);
1042 case DNS_TYPE_TXT:
1043 if (rec1->data.txt.count != rec2->data.txt.count) {
1044 return false;
1046 status = true;
1047 for (i=0; i<rec1->data.txt.count; i++) {
1048 status = status && (strcmp(rec1->data.txt.str[i],
1049 rec2->data.txt.str[i]) == 0);
1051 return status;
1053 case DNS_TYPE_AAAA:
1054 return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
1056 case DNS_TYPE_SRV:
1057 return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
1058 rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
1059 rec1->data.srv.wPort == rec2->data.srv.wPort &&
1060 dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
1062 default:
1063 DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
1064 break;
1067 return false;