s4-dns: Added DCERPC dns server for DNS management
[Samba/gebeck_regimport.git] / source4 / rpc_server / dnsserver / dnsdata.c
blob486290dd9b5f87513293b8914bc478c58b7eb2af
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;
95 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
96 struct DNS_ADDR_ARRAY *addr)
98 struct DNS_ADDR_ARRAY *ret;
100 if (!addr) {
101 return NULL;
104 ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY);
105 if (!ret) {
106 return ret;
109 ret->MaxCount = addr->MaxCount;
110 ret->AddrCount = addr->AddrCount;
111 ret->Family = addr->Family;
112 if (addr->AddrCount > 0) {
113 ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount);
114 if (ret->AddrArray) {
115 memcpy(ret->AddrArray, addr->AddrArray,
116 sizeof(struct DNS_ADDR) * addr->AddrCount);
117 } else {
118 talloc_free(ret);
119 return NULL;
122 return ret;
126 int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components)
128 char *str = NULL, *ptr, **list;
129 int count = 0;
131 str = talloc_strdup(tmp_ctx, name);
132 if (!str) {
133 goto failed;
136 list = talloc_zero_array(tmp_ctx, char *, 0);
137 if (!list) {
138 goto failed;
141 ptr = strtok(str, ".");
142 while (ptr != NULL) {
143 count++;
144 list = talloc_realloc(tmp_ctx, list, char *, count);
145 if (!list) {
146 goto failed;
148 list[count-1] = talloc_strdup(tmp_ctx, ptr);
149 if (list[count-1] == NULL) {
150 goto failed;
152 ptr = strtok(NULL, ".");
155 talloc_free(str);
157 *components = list;
158 return count;
160 failed:
161 if (str) {
162 talloc_free(str);
164 return -1;
168 char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name)
170 char **nlist, **zlist;
171 char *prefix;
172 int ncount, zcount, i, match;
175 * If node_name is "@", return the zone_name
176 * If node_name is ".", return NULL
177 * If there is no '.' in node_name, return the node_name as is.
179 * If node_name does not have zone_name in it, return the node_name as is.
181 * If node_name has additional components as compared to zone_name
182 * return only the additional components as a prefix.
185 if (strcmp(node_name, "@") == 0) {
186 prefix = talloc_strdup(tmp_ctx, zone_name);
187 } else if (strcmp(node_name, ".") == 0) {
188 prefix = NULL;
189 } else if (strchr(node_name, '.') == NULL) {
190 prefix = talloc_strdup(tmp_ctx, node_name);
191 } else {
192 zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist);
193 ncount = dns_split_name_components(tmp_ctx, node_name, &nlist);
194 if (zcount < 0 || ncount < 0) {
195 return NULL;
198 if (ncount < zcount) {
199 prefix = talloc_strdup(tmp_ctx, node_name);
200 } else {
201 match = 0;
202 for (i=1; i<=zcount; i++) {
203 if (strcmp(nlist[ncount-i], zlist[zcount-i]) != 0) {
204 break;
206 match++;
209 if (match == ncount) {
210 prefix = talloc_strdup(tmp_ctx, zone_name);
211 } else {
212 prefix = talloc_strdup(tmp_ctx, nlist[0]);
213 if (prefix != NULL) {
214 for (i=1; i<ncount-match; i++) {
215 prefix = talloc_asprintf_append(prefix, ".%s", nlist[i]);
216 if (prefix == NULL) {
217 break;
224 talloc_free(zlist);
225 talloc_free(nlist);
228 return prefix;
232 void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp,
233 struct DNS_RPC_RECORD *dns)
235 int len;
237 ZERO_STRUCTP(dns);
239 dns->wDataLength = dnsp->wDataLength;
240 dns->wType = dnsp->wType;
241 dns->dwFlags = dnsp->rank;
242 dns->dwSerial = dnsp->dwSerial;
243 dns->dwTtlSeconds = dnsp->dwTtlSeconds;
244 dns->dwTimeStamp = dnsp->dwTimeStamp;
246 switch (dnsp->wType) {
248 case DNS_TYPE_TOMBSTONE:
249 dns->data.timestamp = dnsp->data.timestamp;
250 break;
252 case DNS_TYPE_A:
253 dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4);
254 break;
256 case DNS_TYPE_NS:
257 len = strlen(dnsp->data.ns);
258 if (dnsp->data.ns[len-1] == '.') {
259 dns->data.name.len = len;
260 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns);
261 } else {
262 dns->data.name.len = len+1;
263 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns);
265 break;
267 case DNS_TYPE_CNAME:
268 len = strlen(dnsp->data.cname);
269 if (dnsp->data.cname[len-1] == '.') {
270 dns->data.name.len = len;
271 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname);
272 } else {
273 dns->data.name.len = len+1;
274 dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname);
276 break;
278 case DNS_TYPE_SOA:
279 dns->data.soa.dwSerialNo = dnsp->data.soa.serial;
280 dns->data.soa.dwRefresh = dnsp->data.soa.refresh;
281 dns->data.soa.dwRetry = dnsp->data.soa.retry;
282 dns->data.soa.dwExpire = dnsp->data.soa.expire;
283 dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum;
285 len = strlen(dnsp->data.soa.mname);
286 if (dnsp->data.soa.mname[len-1] == '.') {
287 dns->data.soa.NamePrimaryServer.len = len;
288 dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname);
289 } else {
290 dns->data.soa.NamePrimaryServer.len = len+1;
291 dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname);
294 len = strlen(dnsp->data.soa.rname);
295 if (dnsp->data.soa.rname[len-1] == '.') {
296 dns->data.soa.ZoneAdministratorEmail.len = len;
297 dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname);
298 } else {
299 dns->data.soa.ZoneAdministratorEmail.len = len+1;
300 dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname);
302 break;
304 case DNS_TYPE_PTR:
305 dns->data.ptr.len = strlen(dnsp->data.ptr);
306 dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr);
307 break;
309 case DNS_TYPE_MX:
310 dns->data.mx.wPreference = dnsp->data.mx.wPriority;
311 len = strlen(dnsp->data.mx.nameTarget);
312 if (dnsp->data.mx.nameTarget[len-1] == '.') {
313 dns->data.mx.nameExchange.len = len;
314 dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget);
315 } else {
316 dns->data.mx.nameExchange.len = len+1;
317 dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget);
319 break;
321 case DNS_TYPE_TXT:
322 dns->data.name.len = strlen(dnsp->data.txt);
323 dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.txt);
324 break;
326 case DNS_TYPE_AAAA:
327 dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6);
328 break;
330 case DNS_TYPE_SRV:
331 dns->data.srv.wPriority = dnsp->data.srv.wPriority;
332 dns->data.srv.wWeight = dnsp->data.srv.wWeight;
333 dns->data.srv.wPort = dnsp->data.srv.wPort;
334 len = strlen(dnsp->data.srv.nameTarget);
335 if (dnsp->data.srv.nameTarget[len-1] == '.') {
336 dns->data.srv.nameTarget.len = len;
337 dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget);
338 } else {
339 dns->data.srv.nameTarget.len = len+1;
340 dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget);
342 break;
344 default:
345 memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA));
346 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType));
352 struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns)
354 int len;
355 struct dnsp_DnssrvRpcRecord *dnsp;
357 dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
358 if (dnsp == NULL) {
359 return NULL;
362 dnsp->wDataLength = dns->wDataLength;
363 dnsp->wType = dns->wType;
364 dnsp->version = 5;
365 dnsp->rank = dns->dwFlags & 0x000000FF;
366 dnsp->dwSerial = dns->dwSerial;
367 dnsp->dwTtlSeconds = dns->dwTtlSeconds;
368 dnsp->dwTimeStamp = dns->dwTimeStamp;
370 switch (dns->wType) {
372 case DNS_TYPE_TOMBSTONE:
373 dnsp->data.timestamp = dns->data.timestamp;
374 break;
376 case DNS_TYPE_A:
377 dnsp->data.ipv4 = talloc_strdup(mem_ctx, dns->data.ipv4);
378 break;
380 case DNS_TYPE_NS:
381 len = dns->data.name.len;
382 if (dns->data.name.str[len-1] == '.') {
383 dnsp->data.ns = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
384 } else {
385 dnsp->data.ns = talloc_strdup(mem_ctx, dns->data.name.str);
387 break;
389 case DNS_TYPE_CNAME:
390 len = dns->data.name.len;
391 if (dns->data.name.str[len-1] == '.') {
392 dnsp->data.cname = talloc_strndup(mem_ctx, dns->data.name.str, len-1);
393 } else {
394 dnsp->data.cname = talloc_strdup(mem_ctx, dns->data.name.str);
396 break;
398 case DNS_TYPE_SOA:
399 dnsp->data.soa.serial = dns->data.soa.dwSerialNo;
400 dnsp->data.soa.refresh = dns->data.soa.dwRefresh;
401 dnsp->data.soa.retry = dns->data.soa.dwRetry;
402 dnsp->data.soa.expire = dns->data.soa.dwExpire;
403 dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl;
405 len = dns->data.soa.NamePrimaryServer.len;
406 if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') {
407 dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str);
408 } else {
409 dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1);
412 len = dns->data.soa.ZoneAdministratorEmail.len;
413 if (dns->data.soa.ZoneAdministratorEmail.str[len-1] == '.') {
414 dnsp->data.soa.rname = talloc_strndup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str, len-1);
415 } else {
416 dnsp->data.soa.rname = talloc_strdup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str);
418 break;
420 case DNS_TYPE_PTR:
421 dnsp->data.ptr = talloc_strdup(mem_ctx, dns->data.ptr.str);
422 break;
424 case DNS_TYPE_MX:
425 dnsp->data.mx.wPriority = dns->data.mx.wPreference;
426 len = dns->data.mx.nameExchange.len;
427 if (dns->data.mx.nameExchange.str[len-1] == '.') {
428 dnsp->data.mx.nameTarget = talloc_strndup(mem_ctx, dns->data.mx.nameExchange.str, len-1);
429 } else {
430 dnsp->data.mx.nameTarget = talloc_strdup(mem_ctx, dns->data.mx.nameExchange.str);
432 break;
434 case DNS_TYPE_TXT:
435 dnsp->data.txt = talloc_strdup(mem_ctx, dns->data.name.str);
436 break;
438 case DNS_TYPE_AAAA:
439 dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6);
440 break;
442 case DNS_TYPE_SRV:
443 dnsp->data.srv.wPriority = dns->data.srv.wPriority;
444 dnsp->data.srv.wWeight = dns->data.srv.wWeight;
445 dnsp->data.srv.wPort = dns->data.srv.wPort;
447 len = dns->data.srv.nameTarget.len;
448 if (dns->data.srv.nameTarget.str[len-1] == '.') {
449 dnsp->data.srv.nameTarget = talloc_strndup(mem_ctx, dns->data.srv.nameTarget.str, len-1);
450 } else {
451 dnsp->data.srv.nameTarget = talloc_strdup(mem_ctx, dns->data.srv.nameTarget.str);
453 break;
455 default:
456 memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData));
457 DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType));
461 return dnsp;
465 static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count)
467 int i;
468 char **ptr = *add_names;
469 int count = *add_count;
471 for (i=0; i<count; i++) {
472 if (strcmp(ptr[i], name) == 0) {
473 return;
477 ptr = talloc_realloc(mem_ctx, ptr, char *, count+1);
478 if (ptr == NULL) {
479 return;
482 ptr[count] = talloc_strdup(mem_ctx, name);
483 if (ptr[count] == NULL) {
484 return;
487 *add_names = ptr;
488 *add_count = count+1;
492 static void dns_find_additional_names(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *rec, char ***add_names, int *add_count)
494 if (add_names == NULL) {
495 return;
498 switch (rec->wType) {
500 case DNS_TYPE_NS:
501 _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count);
502 break;
504 case DNS_TYPE_CNAME:
505 _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count);
506 break;
508 case DNS_TYPE_SOA:
509 _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count);
510 break;
512 case DNS_TYPE_MX:
513 _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count);
514 break;
516 case DNS_TYPE_SRV:
517 _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count);
518 break;
520 default:
521 break;
526 WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx,
527 struct dnsserver_zone *z,
528 enum dns_record_type record_type,
529 unsigned int select_flag,
530 const char *branch_name,
531 struct ldb_message *msg,
532 struct DNS_RPC_RECORDS_ARRAY *recs,
533 char ***add_names,
534 int *add_count)
536 const char *nodename;
537 struct ldb_message_element *el;
538 int i, j;
539 bool found, node_is_rootzone;
541 /* Check if we already have created record for the branch */
542 found = false;
543 if (branch_name == NULL) {
544 i = 0;
545 if (recs->count > 0) {
546 found = true;
548 } else {
549 for (i=0; i<recs->count; i++) {
550 if (strcmp(branch_name, recs->rec[i].dnsNodeName.str) == 0) {
551 found = true;
552 break;
557 /* If not, add empty record */
558 if (!found) {
559 if (recs->count == 0) {
560 recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS);
561 } else {
562 recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1);
564 if (recs->rec == NULL) {
565 return WERR_NOMEM;
567 i = recs->count;
568 recs->rec[i].wLength = 0;
569 recs->rec[i].wRecordCount = 0;
570 recs->rec[i].dwChildCount = 0;
572 /* The base records returned with empty name */
573 /* Children records returned with names */
574 if (branch_name == NULL) {
575 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, "");
576 recs->rec[i].dnsNodeName.len = 0;
577 } else {
578 recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name);
579 recs->rec[i].dnsNodeName.len = strlen(branch_name);
581 recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0);
582 recs->count++;
585 /* Allow empty records */
586 if (msg == NULL) {
587 return WERR_OK;
590 nodename = ldb_msg_find_attr_as_string(msg, "name", NULL);
592 if (strcmp(nodename, "@") == 0) {
593 node_is_rootzone = true;
594 } else {
595 node_is_rootzone = false;
597 /* child record */
598 if (branch_name != NULL) {
599 if (branch_name[strlen(branch_name)-1] != '.'
600 && strcmp(nodename, branch_name) != 0) {
601 recs->rec[i].dwChildCount++;
602 return WERR_OK;
607 el = ldb_msg_find_element(msg, "dnsRecord");
608 if (el == NULL || el->values == 0) {
609 DEBUG(0, ("dnsserver: Missing dnsRecord for %s\n", ldb_dn_get_linearized(msg->dn)));
610 return WERR_OK;
613 /* branch level record */
614 for (j=0; j<el->num_values; j++) {
615 struct dnsp_DnssrvRpcRecord dnsp_rec;
616 struct DNS_RPC_RECORD *dns_rec;
617 enum ndr_err_code ndr_err;
619 ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec,
620 (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
621 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
622 DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn)));
623 return WERR_INTERNAL_DB_ERROR;
626 /* Match the records based on search criteria */
627 if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) {
628 found = false;
630 if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) {
631 if (dnsp_rec.rank == DNS_RANK_ZONE) {
632 found = true;
635 if (select_flag & DNS_RPC_VIEW_CACHE_DATA) {
636 if (dnsp_rec.rank == DNS_RANK_ZONE) {
637 found = true;
640 if (select_flag & DNS_RPC_VIEW_GLUE_DATA) {
641 if (dnsp_rec.rank == DNS_RANK_NS_GLUE) {
642 found = true;
645 if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) {
646 if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) {
647 found = true;
651 if (found) {
652 recs->rec[i].records = talloc_realloc(recs,
653 recs->rec[i].records,
654 struct DNS_RPC_RECORD,
655 recs->rec[i].wRecordCount+1);
656 if (recs->rec[i].records == NULL) {
657 return WERR_NOMEM;
660 dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount];
661 dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec);
663 /* Fix record flags */
664 if (node_is_rootzone) {
665 dns_rec->dwFlags |= (DNS_RPC_FLAG_ZONE_ROOT | DNS_RPC_FLAG_AUTH_ZONE_ROOT);
668 if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) {
669 dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT;
672 recs->rec[i].wRecordCount++;
674 dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count);
679 return WERR_OK;
683 int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2,
684 char *search_name)
686 const char *name1, *name2;
687 const char *ptr1, *ptr2;
689 name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
690 name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
691 if (name1 == NULL || name2 == NULL) {
692 return 0;
695 /* '@' record and the search_name record gets preference */
696 if (name1[0] == '@') {
697 return -1;
699 if (search_name && strcmp(name1, search_name) == 0) {
700 return -1;
703 if (name2[0] == '@') {
704 return 1;
706 if (search_name && strcmp(name2, search_name) == 0) {
707 return 1;
710 ptr1 = strrchr(name1, '.');
711 if (ptr1 == NULL) {
712 ptr1 = name1;
713 } else {
714 ptr1 = &ptr1[1];
717 ptr2 = strrchr(name2, '.');
718 if (ptr2 == NULL) {
719 ptr2 = name2;
720 } else {
721 ptr2 = &ptr2[1];
724 return strcasecmp(ptr1, ptr2);
728 bool dns_name_equal(const char *name1, const char *name2)
730 size_t len1 = strlen(name1);
731 size_t len2 = strlen(name2);
733 if (name1[len1-1] == '.') len1--;
734 if (name2[len2-1] == '.') len2--;
735 if (len1 != len2) {
736 return false;
738 return strncasecmp(name1, name2, len1) == 0;
742 bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2)
744 if (rec1->wType != rec2->wType) {
745 return false;
748 switch(rec1->wType) {
749 case DNS_TYPE_TOMBSTONE:
750 return true;
752 case DNS_TYPE_A:
753 return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0;
755 case DNS_TYPE_NS:
756 return dns_name_equal(rec1->data.ns, rec1->data.ns);
758 case DNS_TYPE_CNAME:
759 return dns_name_equal(rec1->data.cname, rec1->data.cname);
761 case DNS_TYPE_SOA:
762 return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) == 0 &&
763 dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) == 0 &&
764 rec1->data.soa.serial == rec2->data.soa.serial &&
765 rec1->data.soa.refresh == rec2->data.soa.refresh &&
766 rec1->data.soa.retry == rec2->data.soa.retry &&
767 rec1->data.soa.expire == rec2->data.soa.expire &&
768 rec1->data.soa.minimum == rec2->data.soa.minimum;
770 case DNS_TYPE_PTR:
771 return strcmp(rec1->data.ptr, rec2->data.ptr) == 0;
773 case DNS_TYPE_MX:
774 return rec1->data.mx.wPriority == rec2->data.srv.wPriority &&
775 dns_name_equal(rec1->data.mx.nameTarget, rec2->data.srv.nameTarget);
777 case DNS_TYPE_TXT:
778 return strcmp(rec1->data.txt, rec2->data.txt) == 0;
780 case DNS_TYPE_AAAA:
781 return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0;
783 case DNS_TYPE_SRV:
784 return rec1->data.srv.wPriority == rec2->data.srv.wPriority &&
785 rec1->data.srv.wWeight == rec2->data.srv.wWeight &&
786 rec1->data.srv.wPort == rec2->data.srv.wPort &&
787 dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget);
789 default:
790 DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType));
791 break;
794 return false;