From 8df2ed42cc4662bd385ea34169ebd3bcd4d8bc17 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Tue, 27 Sep 2011 16:53:45 +1000 Subject: s4-dns: Added DCERPC dns server for DNS management dnsserver.h - typedefs and prototypes dnsserver.c - RPC API and implementation methods dnsdb.c - samdb operations dnsdata.c - functions to manipulate dns structures dnsutils.c - function for serverinfo and zoneinfo structures Signed-off-by: Andrew Tridgell --- source4/rpc_server/dnsserver/dnsdata.c | 795 +++++++++++++++++++++++++++++++++ 1 file changed, 795 insertions(+) create mode 100644 source4/rpc_server/dnsserver/dnsdata.c (limited to 'source4/rpc_server/dnsserver/dnsdata.c') diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c new file mode 100644 index 0000000000..486290dd9b --- /dev/null +++ b/source4/rpc_server/dnsserver/dnsdata.c @@ -0,0 +1,795 @@ +/* + Unix SMB/CIFS implementation. + + DNS Server + + Copyright (C) Amitay Isaacs 2011 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "dnsserver.h" +#include "lib/replace/system/network.h" +#include "librpc/gen_ndr/ndr_dnsp.h" +#include "librpc/gen_ndr/ndr_dnsserver.h" + + +struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4) +{ + struct IP4_ARRAY *ret; + + if (!ip4) { + return NULL; + } + + ret = talloc_zero(mem_ctx, struct IP4_ARRAY); + if (!ret) { + return ret; + } + + ret->AddrCount = ip4->AddrCount; + if (ip4->AddrCount > 0) { + ret->AddrArray = talloc_zero_array(mem_ctx, unsigned int, ip4->AddrCount); + if (ret->AddrArray) { + memcpy(ret->AddrArray, ip4->AddrArray, + sizeof(unsigned int) * ip4->AddrCount); + } else { + talloc_free(ret); + return NULL; + } + } + return ret; +} + + +struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx, + struct IP4_ARRAY *ip4) +{ + struct DNS_ADDR_ARRAY *ret; + int i; + + if (!ip4) { + return NULL; + } + + ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY); + if (!ret) { + return ret; + } + + ret->MaxCount = ip4->AddrCount; + ret->AddrCount = ip4->AddrCount; + ret->Family = AF_INET; + if (ip4->AddrCount > 0) { + ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, ip4->AddrCount); + if (ret->AddrArray) { + for (i=0; iAddrCount; i++) { + ret->AddrArray[i].MaxSa[0] = 0x02; + ret->AddrArray[i].MaxSa[3] = 53; + memcpy(&ret->AddrArray[i].MaxSa[4], ip4->AddrArray, + sizeof(unsigned int)); + ret->AddrArray[i].DnsAddrUserDword[0] = 6; + } + + } else { + talloc_free(ret); + return NULL; + } + } + return ret; +} + + +struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx, + struct DNS_ADDR_ARRAY *addr) +{ + struct DNS_ADDR_ARRAY *ret; + + if (!addr) { + return NULL; + } + + ret = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY); + if (!ret) { + return ret; + } + + ret->MaxCount = addr->MaxCount; + ret->AddrCount = addr->AddrCount; + ret->Family = addr->Family; + if (addr->AddrCount > 0) { + ret->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, addr->AddrCount); + if (ret->AddrArray) { + memcpy(ret->AddrArray, addr->AddrArray, + sizeof(struct DNS_ADDR) * addr->AddrCount); + } else { + talloc_free(ret); + return NULL; + } + } + return ret; +} + + +int dns_split_name_components(TALLOC_CTX *tmp_ctx, const char *name, char ***components) +{ + char *str = NULL, *ptr, **list; + int count = 0; + + str = talloc_strdup(tmp_ctx, name); + if (!str) { + goto failed; + } + + list = talloc_zero_array(tmp_ctx, char *, 0); + if (!list) { + goto failed; + } + + ptr = strtok(str, "."); + while (ptr != NULL) { + count++; + list = talloc_realloc(tmp_ctx, list, char *, count); + if (!list) { + goto failed; + } + list[count-1] = talloc_strdup(tmp_ctx, ptr); + if (list[count-1] == NULL) { + goto failed; + } + ptr = strtok(NULL, "."); + } + + talloc_free(str); + + *components = list; + return count; + +failed: + if (str) { + talloc_free(str); + } + return -1; +} + + +char *dns_split_node_name(TALLOC_CTX *tmp_ctx, const char *node_name, const char *zone_name) +{ + char **nlist, **zlist; + char *prefix; + int ncount, zcount, i, match; + + /* + * If node_name is "@", return the zone_name + * If node_name is ".", return NULL + * If there is no '.' in node_name, return the node_name as is. + * + * If node_name does not have zone_name in it, return the node_name as is. + * + * If node_name has additional components as compared to zone_name + * return only the additional components as a prefix. + * + */ + if (strcmp(node_name, "@") == 0) { + prefix = talloc_strdup(tmp_ctx, zone_name); + } else if (strcmp(node_name, ".") == 0) { + prefix = NULL; + } else if (strchr(node_name, '.') == NULL) { + prefix = talloc_strdup(tmp_ctx, node_name); + } else { + zcount = dns_split_name_components(tmp_ctx, zone_name, &zlist); + ncount = dns_split_name_components(tmp_ctx, node_name, &nlist); + if (zcount < 0 || ncount < 0) { + return NULL; + } + + if (ncount < zcount) { + prefix = talloc_strdup(tmp_ctx, node_name); + } else { + match = 0; + for (i=1; i<=zcount; i++) { + if (strcmp(nlist[ncount-i], zlist[zcount-i]) != 0) { + break; + } + match++; + } + + if (match == ncount) { + prefix = talloc_strdup(tmp_ctx, zone_name); + } else { + prefix = talloc_strdup(tmp_ctx, nlist[0]); + if (prefix != NULL) { + for (i=1; iwDataLength = dnsp->wDataLength; + dns->wType = dnsp->wType; + dns->dwFlags = dnsp->rank; + dns->dwSerial = dnsp->dwSerial; + dns->dwTtlSeconds = dnsp->dwTtlSeconds; + dns->dwTimeStamp = dnsp->dwTimeStamp; + + switch (dnsp->wType) { + + case DNS_TYPE_TOMBSTONE: + dns->data.timestamp = dnsp->data.timestamp; + break; + + case DNS_TYPE_A: + dns->data.ipv4 = talloc_strdup(mem_ctx, dnsp->data.ipv4); + break; + + case DNS_TYPE_NS: + len = strlen(dnsp->data.ns); + if (dnsp->data.ns[len-1] == '.') { + dns->data.name.len = len; + dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.ns); + } else { + dns->data.name.len = len+1; + dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.ns); + } + break; + + case DNS_TYPE_CNAME: + len = strlen(dnsp->data.cname); + if (dnsp->data.cname[len-1] == '.') { + dns->data.name.len = len; + dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.cname); + } else { + dns->data.name.len = len+1; + dns->data.name.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.cname); + } + break; + + case DNS_TYPE_SOA: + dns->data.soa.dwSerialNo = dnsp->data.soa.serial; + dns->data.soa.dwRefresh = dnsp->data.soa.refresh; + dns->data.soa.dwRetry = dnsp->data.soa.retry; + dns->data.soa.dwExpire = dnsp->data.soa.expire; + dns->data.soa.dwMinimumTtl = dnsp->data.soa.minimum; + + len = strlen(dnsp->data.soa.mname); + if (dnsp->data.soa.mname[len-1] == '.') { + dns->data.soa.NamePrimaryServer.len = len; + dns->data.soa.NamePrimaryServer.str = talloc_strdup(mem_ctx, dnsp->data.soa.mname); + } else { + dns->data.soa.NamePrimaryServer.len = len+1; + dns->data.soa.NamePrimaryServer.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.mname); + } + + len = strlen(dnsp->data.soa.rname); + if (dnsp->data.soa.rname[len-1] == '.') { + dns->data.soa.ZoneAdministratorEmail.len = len; + dns->data.soa.ZoneAdministratorEmail.str = talloc_strdup(mem_ctx, dnsp->data.soa.rname); + } else { + dns->data.soa.ZoneAdministratorEmail.len = len+1; + dns->data.soa.ZoneAdministratorEmail.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.soa.rname); + } + break; + + case DNS_TYPE_PTR: + dns->data.ptr.len = strlen(dnsp->data.ptr); + dns->data.ptr.str = talloc_strdup(mem_ctx, dnsp->data.ptr); + break; + + case DNS_TYPE_MX: + dns->data.mx.wPreference = dnsp->data.mx.wPriority; + len = strlen(dnsp->data.mx.nameTarget); + if (dnsp->data.mx.nameTarget[len-1] == '.') { + dns->data.mx.nameExchange.len = len; + dns->data.mx.nameExchange.str = talloc_strdup(mem_ctx, dnsp->data.mx.nameTarget); + } else { + dns->data.mx.nameExchange.len = len+1; + dns->data.mx.nameExchange.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.mx.nameTarget); + } + break; + + case DNS_TYPE_TXT: + dns->data.name.len = strlen(dnsp->data.txt); + dns->data.name.str = talloc_strdup(mem_ctx, dnsp->data.txt); + break; + + case DNS_TYPE_AAAA: + dns->data.ipv6 = talloc_strdup(mem_ctx, dnsp->data.ipv6); + break; + + case DNS_TYPE_SRV: + dns->data.srv.wPriority = dnsp->data.srv.wPriority; + dns->data.srv.wWeight = dnsp->data.srv.wWeight; + dns->data.srv.wPort = dnsp->data.srv.wPort; + len = strlen(dnsp->data.srv.nameTarget); + if (dnsp->data.srv.nameTarget[len-1] == '.') { + dns->data.srv.nameTarget.len = len; + dns->data.srv.nameTarget.str = talloc_strdup(mem_ctx, dnsp->data.srv.nameTarget); + } else { + dns->data.srv.nameTarget.len = len+1; + dns->data.srv.nameTarget.str = talloc_asprintf(mem_ctx, "%s.", dnsp->data.srv.nameTarget); + } + break; + + default: + memcpy(&dns->data, &dnsp->data, sizeof(union DNS_RPC_DATA)); + DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dnsp->wType)); + } + +} + + +struct dnsp_DnssrvRpcRecord *dns_to_dnsp_copy(TALLOC_CTX *mem_ctx, struct DNS_RPC_RECORD *dns) +{ + int len; + struct dnsp_DnssrvRpcRecord *dnsp; + + dnsp = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord); + if (dnsp == NULL) { + return NULL; + } + + dnsp->wDataLength = dns->wDataLength; + dnsp->wType = dns->wType; + dnsp->version = 5; + dnsp->rank = dns->dwFlags & 0x000000FF; + dnsp->dwSerial = dns->dwSerial; + dnsp->dwTtlSeconds = dns->dwTtlSeconds; + dnsp->dwTimeStamp = dns->dwTimeStamp; + + switch (dns->wType) { + + case DNS_TYPE_TOMBSTONE: + dnsp->data.timestamp = dns->data.timestamp; + break; + + case DNS_TYPE_A: + dnsp->data.ipv4 = talloc_strdup(mem_ctx, dns->data.ipv4); + break; + + case DNS_TYPE_NS: + len = dns->data.name.len; + if (dns->data.name.str[len-1] == '.') { + dnsp->data.ns = talloc_strndup(mem_ctx, dns->data.name.str, len-1); + } else { + dnsp->data.ns = talloc_strdup(mem_ctx, dns->data.name.str); + } + break; + + case DNS_TYPE_CNAME: + len = dns->data.name.len; + if (dns->data.name.str[len-1] == '.') { + dnsp->data.cname = talloc_strndup(mem_ctx, dns->data.name.str, len-1); + } else { + dnsp->data.cname = talloc_strdup(mem_ctx, dns->data.name.str); + } + break; + + case DNS_TYPE_SOA: + dnsp->data.soa.serial = dns->data.soa.dwSerialNo; + dnsp->data.soa.refresh = dns->data.soa.dwRefresh; + dnsp->data.soa.retry = dns->data.soa.dwRetry; + dnsp->data.soa.expire = dns->data.soa.dwExpire; + dnsp->data.soa.minimum = dns->data.soa.dwMinimumTtl; + + len = dns->data.soa.NamePrimaryServer.len; + if (dns->data.soa.NamePrimaryServer.str[len-1] == '.') { + dnsp->data.soa.mname = talloc_strdup(mem_ctx, dns->data.soa.NamePrimaryServer.str); + } else { + dnsp->data.soa.mname = talloc_strndup(mem_ctx, dns->data.soa.NamePrimaryServer.str, len-1); + } + + len = dns->data.soa.ZoneAdministratorEmail.len; + if (dns->data.soa.ZoneAdministratorEmail.str[len-1] == '.') { + dnsp->data.soa.rname = talloc_strndup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str, len-1); + } else { + dnsp->data.soa.rname = talloc_strdup(mem_ctx, dns->data.soa.ZoneAdministratorEmail.str); + } + break; + + case DNS_TYPE_PTR: + dnsp->data.ptr = talloc_strdup(mem_ctx, dns->data.ptr.str); + break; + + case DNS_TYPE_MX: + dnsp->data.mx.wPriority = dns->data.mx.wPreference; + len = dns->data.mx.nameExchange.len; + if (dns->data.mx.nameExchange.str[len-1] == '.') { + dnsp->data.mx.nameTarget = talloc_strndup(mem_ctx, dns->data.mx.nameExchange.str, len-1); + } else { + dnsp->data.mx.nameTarget = talloc_strdup(mem_ctx, dns->data.mx.nameExchange.str); + } + break; + + case DNS_TYPE_TXT: + dnsp->data.txt = talloc_strdup(mem_ctx, dns->data.name.str); + break; + + case DNS_TYPE_AAAA: + dnsp->data.ipv6 = talloc_strdup(mem_ctx, dns->data.ipv6); + break; + + case DNS_TYPE_SRV: + dnsp->data.srv.wPriority = dns->data.srv.wPriority; + dnsp->data.srv.wWeight = dns->data.srv.wWeight; + dnsp->data.srv.wPort = dns->data.srv.wPort; + + len = dns->data.srv.nameTarget.len; + if (dns->data.srv.nameTarget.str[len-1] == '.') { + dnsp->data.srv.nameTarget = talloc_strndup(mem_ctx, dns->data.srv.nameTarget.str, len-1); + } else { + dnsp->data.srv.nameTarget = talloc_strdup(mem_ctx, dns->data.srv.nameTarget.str); + } + break; + + default: + memcpy(&dnsp->data, &dns->data, sizeof(union dnsRecordData)); + DEBUG(0, ("dnsserver: Found Unhandled DNS record type=%d", dns->wType)); + + } + + return dnsp; +} + + +static void _dns_add_name(TALLOC_CTX *mem_ctx, const char *name, char ***add_names, int *add_count) +{ + int i; + char **ptr = *add_names; + int count = *add_count; + + for (i=0; iwType) { + + case DNS_TYPE_NS: + _dns_add_name(mem_ctx, rec->data.ns, add_names, add_count); + break; + + case DNS_TYPE_CNAME: + _dns_add_name(mem_ctx, rec->data.cname, add_names, add_count); + break; + + case DNS_TYPE_SOA: + _dns_add_name(mem_ctx, rec->data.soa.mname, add_names, add_count); + break; + + case DNS_TYPE_MX: + _dns_add_name(mem_ctx, rec->data.mx.nameTarget, add_names, add_count); + break; + + case DNS_TYPE_SRV: + _dns_add_name(mem_ctx, rec->data.srv.nameTarget, add_names, add_count); + break; + + default: + break; + } +} + + +WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx, + struct dnsserver_zone *z, + enum dns_record_type record_type, + unsigned int select_flag, + const char *branch_name, + struct ldb_message *msg, + struct DNS_RPC_RECORDS_ARRAY *recs, + char ***add_names, + int *add_count) +{ + const char *nodename; + struct ldb_message_element *el; + int i, j; + bool found, node_is_rootzone; + + /* Check if we already have created record for the branch */ + found = false; + if (branch_name == NULL) { + i = 0; + if (recs->count > 0) { + found = true; + } + } else { + for (i=0; icount; i++) { + if (strcmp(branch_name, recs->rec[i].dnsNodeName.str) == 0) { + found = true; + break; + } + } + } + + /* If not, add empty record */ + if (!found) { + if (recs->count == 0) { + recs->rec = talloc_zero(recs, struct DNS_RPC_RECORDS); + } else { + recs->rec = talloc_realloc(recs, recs->rec, struct DNS_RPC_RECORDS, recs->count+1); + } + if (recs->rec == NULL) { + return WERR_NOMEM; + } + i = recs->count; + recs->rec[i].wLength = 0; + recs->rec[i].wRecordCount = 0; + recs->rec[i].dwChildCount = 0; + + /* The base records returned with empty name */ + /* Children records returned with names */ + if (branch_name == NULL) { + recs->rec[i].dnsNodeName.str = talloc_strdup(recs, ""); + recs->rec[i].dnsNodeName.len = 0; + } else { + recs->rec[i].dnsNodeName.str = talloc_strdup(recs, branch_name); + recs->rec[i].dnsNodeName.len = strlen(branch_name); + } + recs->rec[i].records = talloc_zero_array(recs, struct DNS_RPC_RECORD, 0); + recs->count++; + } + + /* Allow empty records */ + if (msg == NULL) { + return WERR_OK; + } + + nodename = ldb_msg_find_attr_as_string(msg, "name", NULL); + + if (strcmp(nodename, "@") == 0) { + node_is_rootzone = true; + } else { + node_is_rootzone = false; + + /* child record */ + if (branch_name != NULL) { + if (branch_name[strlen(branch_name)-1] != '.' + && strcmp(nodename, branch_name) != 0) { + recs->rec[i].dwChildCount++; + return WERR_OK; + } + } + } + + el = ldb_msg_find_element(msg, "dnsRecord"); + if (el == NULL || el->values == 0) { + DEBUG(0, ("dnsserver: Missing dnsRecord for %s\n", ldb_dn_get_linearized(msg->dn))); + return WERR_OK; + } + + /* branch level record */ + for (j=0; jnum_values; j++) { + struct dnsp_DnssrvRpcRecord dnsp_rec; + struct DNS_RPC_RECORD *dns_rec; + enum ndr_err_code ndr_err; + + ndr_err = ndr_pull_struct_blob(&el->values[j], mem_ctx, &dnsp_rec, + (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("dnsserver: Unable to parse dns record (%s)", ldb_dn_get_linearized(msg->dn))); + return WERR_INTERNAL_DB_ERROR; + } + + /* Match the records based on search criteria */ + if (record_type == DNS_TYPE_ALL || dnsp_rec.wType == record_type) { + found = false; + + if (select_flag & DNS_RPC_VIEW_AUTHORITY_DATA) { + if (dnsp_rec.rank == DNS_RANK_ZONE) { + found = true; + } + } + if (select_flag & DNS_RPC_VIEW_CACHE_DATA) { + if (dnsp_rec.rank == DNS_RANK_ZONE) { + found = true; + } + } + if (select_flag & DNS_RPC_VIEW_GLUE_DATA) { + if (dnsp_rec.rank == DNS_RANK_NS_GLUE) { + found = true; + } + } + if (select_flag & DNS_RPC_VIEW_ROOT_HINT_DATA) { + if (dnsp_rec.rank == DNS_RANK_ROOT_HINT) { + found = true; + } + } + + if (found) { + recs->rec[i].records = talloc_realloc(recs, + recs->rec[i].records, + struct DNS_RPC_RECORD, + recs->rec[i].wRecordCount+1); + if (recs->rec[i].records == NULL) { + return WERR_NOMEM; + } + + dns_rec = &recs->rec[i].records[recs->rec[i].wRecordCount]; + dnsp_to_dns_copy(recs, &dnsp_rec, dns_rec); + + /* Fix record flags */ + if (node_is_rootzone) { + dns_rec->dwFlags |= (DNS_RPC_FLAG_ZONE_ROOT | DNS_RPC_FLAG_AUTH_ZONE_ROOT); + } + + if (dns_rec->dwFlags == DNS_RANK_NS_GLUE) { + dns_rec->dwFlags |= DNS_RPC_FLAG_ZONE_ROOT; + } + + recs->rec[i].wRecordCount++; + + dns_find_additional_names(mem_ctx, &dnsp_rec, add_names, add_count); + } + } + } + + return WERR_OK; +} + + +int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2, + char *search_name) +{ + const char *name1, *name2; + const char *ptr1, *ptr2; + + name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL); + name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL); + if (name1 == NULL || name2 == NULL) { + return 0; + } + + /* '@' record and the search_name record gets preference */ + if (name1[0] == '@') { + return -1; + } + if (search_name && strcmp(name1, search_name) == 0) { + return -1; + } + + if (name2[0] == '@') { + return 1; + } + if (search_name && strcmp(name2, search_name) == 0) { + return 1; + } + + ptr1 = strrchr(name1, '.'); + if (ptr1 == NULL) { + ptr1 = name1; + } else { + ptr1 = &ptr1[1]; + } + + ptr2 = strrchr(name2, '.'); + if (ptr2 == NULL) { + ptr2 = name2; + } else { + ptr2 = &ptr2[1]; + } + + return strcasecmp(ptr1, ptr2); +} + + +bool dns_name_equal(const char *name1, const char *name2) +{ + size_t len1 = strlen(name1); + size_t len2 = strlen(name2); + + if (name1[len1-1] == '.') len1--; + if (name2[len2-1] == '.') len2--; + if (len1 != len2) { + return false; + } + return strncasecmp(name1, name2, len1) == 0; +} + + +bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2) +{ + if (rec1->wType != rec2->wType) { + return false; + } + + switch(rec1->wType) { + case DNS_TYPE_TOMBSTONE: + return true; + + case DNS_TYPE_A: + return strcmp(rec1->data.ipv4, rec2->data.ipv4) == 0; + + case DNS_TYPE_NS: + return dns_name_equal(rec1->data.ns, rec1->data.ns); + + case DNS_TYPE_CNAME: + return dns_name_equal(rec1->data.cname, rec1->data.cname); + + case DNS_TYPE_SOA: + return dns_name_equal(rec1->data.soa.mname, rec2->data.soa.mname) == 0 && + dns_name_equal(rec1->data.soa.rname, rec2->data.soa.rname) == 0 && + rec1->data.soa.serial == rec2->data.soa.serial && + rec1->data.soa.refresh == rec2->data.soa.refresh && + rec1->data.soa.retry == rec2->data.soa.retry && + rec1->data.soa.expire == rec2->data.soa.expire && + rec1->data.soa.minimum == rec2->data.soa.minimum; + + case DNS_TYPE_PTR: + return strcmp(rec1->data.ptr, rec2->data.ptr) == 0; + + case DNS_TYPE_MX: + return rec1->data.mx.wPriority == rec2->data.srv.wPriority && + dns_name_equal(rec1->data.mx.nameTarget, rec2->data.srv.nameTarget); + + case DNS_TYPE_TXT: + return strcmp(rec1->data.txt, rec2->data.txt) == 0; + + case DNS_TYPE_AAAA: + return strcmp(rec1->data.ipv6, rec2->data.ipv6) == 0; + + case DNS_TYPE_SRV: + return rec1->data.srv.wPriority == rec2->data.srv.wPriority && + rec1->data.srv.wWeight == rec2->data.srv.wWeight && + rec1->data.srv.wPort == rec2->data.srv.wPort && + dns_name_equal(rec1->data.srv.nameTarget, rec2->data.srv.nameTarget); + + default: + DEBUG(0, ("dnsserver: unhandled record type %u", rec1->wType)); + break; + } + + return false; +} -- cgit