/* 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 "rpc_server/common/common.h" #include "dns_server/dnsserver_common.h" #include "dsdb/samdb/samdb.h" #include "lib/socket/netif.h" #include "lib/util/util_net.h" #include "dnsserver_common.h" static struct DNS_ADDR_ARRAY *fill_dns_addr_array(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, bool listen_only) { struct interface *ifaces; int num_interfaces, i; struct DNS_ADDR_ARRAY *dns_addr_array; const char *ipstr; bool have_ipv4, have_ipv6; uint16_t family; have_ipv4 = have_ipv6 = false; if (!listen_only) { /* Return all interfaces from kernel Not implemented! */ return NULL; } /* Only the used interfaces */ load_interface_list(mem_ctx, lp_ctx, &ifaces); num_interfaces = iface_list_count(ifaces); dns_addr_array = talloc_zero(mem_ctx, struct DNS_ADDR_ARRAY); if (dns_addr_array == NULL) { goto nomem; } dns_addr_array->MaxCount = num_interfaces; dns_addr_array->AddrCount = num_interfaces; if (num_interfaces == 0) { goto nomem; } dns_addr_array->AddrArray = talloc_zero_array(mem_ctx, struct DNS_ADDR, num_interfaces); if (!dns_addr_array->AddrArray) { TALLOC_FREE(dns_addr_array); goto nomem; } for (i = 0; i < num_interfaces; i++) { int ret; ipstr = iface_list_n_ip(ifaces, i); if (is_ipaddress_v4(ipstr)) { have_ipv4 = true; dns_addr_array->AddrArray[i].MaxSa[0] = 0x02; ret = inet_pton(AF_INET, ipstr, &dns_addr_array->AddrArray[i].MaxSa[4]); } else { have_ipv6 = true; dns_addr_array->AddrArray[i].MaxSa[0] = 0x17; ret = inet_pton(AF_INET6, ipstr, &dns_addr_array->AddrArray[i].MaxSa[8]); } if (ret != 1) { /*yep, 1 means success for inet_pton */ DBG_ERR("Interface %d address (%s) is invalid\n", i, ipstr); goto nomem; } } if (have_ipv4 && have_ipv6) { family = 0; /* mixed: MS-DNSP */ } else if (have_ipv4 && !have_ipv6) { family = AF_INET; } else { family = AF_INET6; } dns_addr_array->Family = family; nomem: talloc_free(ifaces); return dns_addr_array; } struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_context *samdb) { struct dnsserver_serverinfo *serverinfo; struct dcerpc_server_info *dinfo; struct ldb_dn *domain_dn, *forest_dn; serverinfo = talloc_zero(mem_ctx, struct dnsserver_serverinfo); if (serverinfo == NULL) { return NULL; } dinfo = lpcfg_dcerpc_server_info(mem_ctx, lp_ctx); if (dinfo) { serverinfo->dwVersion = (dinfo->version_build & 0x0000FFFF) << 16 | (dinfo->version_minor & 0x000000FF) << 8 | (dinfo->version_major & 0x000000FF); talloc_free(dinfo); } else { serverinfo->dwVersion = 0x0ECE0205; /* build, os_minor, os_major */; } serverinfo->fBootMethod = DNS_BOOT_METHOD_DIRECTORY; serverinfo->fAdminConfigured = 0; serverinfo->fAllowUpdate = 1; serverinfo->fDsAvailable = 1; serverinfo->pszServerName = talloc_asprintf(mem_ctx, "%s.%s", lpcfg_netbios_name(lp_ctx), lpcfg_dnsdomain(lp_ctx)); domain_dn = ldb_get_default_basedn(samdb); forest_dn = ldb_get_root_basedn(samdb); serverinfo->pszDsContainer = talloc_asprintf(mem_ctx, "CN=MicrosoftDNS,DC=DomainDnsZones,%s", ldb_dn_get_linearized(domain_dn)); serverinfo->dwDsForestVersion = dsdb_forest_functional_level(samdb); serverinfo->dwDsDomainVersion = dsdb_functional_level(samdb); serverinfo->dwDsDsaVersion = 4; /* need to do ldb search here */ serverinfo->pszDomainName = samdb_dn_to_dns_domain(mem_ctx, domain_dn); serverinfo->pszForestName = samdb_dn_to_dns_domain(mem_ctx, forest_dn); serverinfo->pszDomainDirectoryPartition = talloc_asprintf(mem_ctx, "DC=DomainDnsZones,%s", ldb_dn_get_linearized(domain_dn)); serverinfo->pszForestDirectoryPartition = talloc_asprintf(mem_ctx, "DC=ForestDnsZones,%s", ldb_dn_get_linearized(forest_dn)); /* IP addresses on which the DNS server listens for DNS requests */ serverinfo->aipListenAddrs = fill_dns_addr_array(mem_ctx, lp_ctx, true); /* All IP addresses available on the server * Not implemented! * Use same as listen addresses */ serverinfo->aipServerAddrs = serverinfo->aipListenAddrs; serverinfo->aipForwarders = NULL; serverinfo->aipLogFilter = NULL; serverinfo->pwszLogFilePath = NULL; serverinfo->dwLogLevel = 0; serverinfo->dwDebugLevel = 0; serverinfo->dwEventLogLevel = DNS_EVENT_LOG_INFORMATION_TYPE; serverinfo->dwLogFileMaxSize = 0; serverinfo->dwForwardTimeout = 3; /* seconds (default) */ serverinfo->dwRpcProtocol = 5; serverinfo->dwNameCheckFlag = DNS_ALLOW_MULTIBYTE_NAMES; serverinfo->cAddressAnswerLimit = 0; serverinfo->dwRecursionRetry = 3; /* seconds (default) */ serverinfo->dwRecursionTimeout = 8; /* seconds (default) */ serverinfo->dwMaxCacheTtl = 0x00015180; /* 1 day (default) */ serverinfo->dwDsPollingInterval = 0xB4; /* 3 minutes (default) */ serverinfo->dwLocalNetPriorityNetMask = 0x000000FF; serverinfo->dwScavengingInterval = lpcfg_parm_int( lp_ctx, NULL, "dnsserver", "ScavengingInterval", 24 * 7); serverinfo->dwDefaultRefreshInterval = lpcfg_parm_int( lp_ctx, NULL, "dnsserver", "DefaultRefreshInterval", 24 * 3); serverinfo->dwDefaultNoRefreshInterval = lpcfg_parm_int( lp_ctx, NULL, "dnsserver", "DefaultNoRefreshInterval", 24 * 3); serverinfo->dwLastScavengeTime = 0; serverinfo->fAutoReverseZones = 0; serverinfo->fAutoCacheUpdate = 0; serverinfo->fRecurseAfterForwarding = 0; serverinfo->fForwardDelegations = 1; serverinfo->fNoRecursion = 0; serverinfo->fSecureResponses = 0; serverinfo->fRoundRobin = 1; serverinfo->fLocalNetPriority = 0; serverinfo->fBindSecondaries = 0; serverinfo->fWriteAuthorityNs = 0; serverinfo->fStrictFileParsing = 0; serverinfo->fLooseWildcarding = 0 ; serverinfo->fDefaultAgingState = 0; return serverinfo; } struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone, struct dnsserver_serverinfo *serverinfo) { struct dnsserver_zoneinfo *zoneinfo; uint32_t fReverse; const char *revzone = "in-addr.arpa"; const char *revzone6 = "ip6.arpa"; int len1, len2; unsigned int i = 0; zoneinfo = talloc_zero(zone, struct dnsserver_zoneinfo); if (zoneinfo == NULL) { return NULL; } /* If the zone name ends with in-addr.arpa, it's reverse zone */ /* If the zone name ends with ip6.arpa, it's reverse zone (IPv6) */ fReverse = 0; len1 = strlen(zone->name); len2 = strlen(revzone); if (len1 > len2 && strcasecmp(&zone->name[len1-len2], revzone) == 0) { fReverse = 1; } else { len2 = strlen(revzone6); if (len1 > len2 && strcasecmp(&zone->name[len1-len2], revzone6) == 0) { fReverse = 1; } } zoneinfo->Version = 0x32; zoneinfo->Flags = DNS_RPC_ZONE_DSINTEGRATED; if (strcmp(zone->name, ".") == 0) { zoneinfo->dwZoneType = DNS_ZONE_TYPE_CACHE; zoneinfo->fAllowUpdate = DNS_ZONE_UPDATE_OFF; zoneinfo->fSecureSecondaries = DNS_ZONE_SECSECURE_NO_SECURITY; zoneinfo->fNotifyLevel = DNS_ZONE_NOTIFY_OFF; zoneinfo->dwNoRefreshInterval = 0; zoneinfo->dwRefreshInterval = 0; } else { zoneinfo->Flags |= DNS_RPC_ZONE_UPDATE_SECURE; zoneinfo->dwZoneType = DNS_ZONE_TYPE_PRIMARY; zoneinfo->fAllowUpdate = DNS_ZONE_UPDATE_SECURE; zoneinfo->fSecureSecondaries = DNS_ZONE_SECSECURE_NO_XFER; zoneinfo->fNotifyLevel = DNS_ZONE_NOTIFY_LIST_ONLY; zoneinfo->dwNoRefreshInterval = serverinfo->dwDefaultNoRefreshInterval; zoneinfo->dwRefreshInterval = serverinfo->dwDefaultRefreshInterval; } zoneinfo->fReverse = fReverse; zoneinfo->fPaused = 0; zoneinfo->fShutdown = 0; zoneinfo->fAutoCreated = 0; zoneinfo->fUseDatabase = 1; zoneinfo->pszDataFile = NULL; zoneinfo->aipMasters = NULL; zoneinfo->aipSecondaries = NULL; zoneinfo->aipNotify = NULL; zoneinfo->fUseWins = 0; zoneinfo->fUseNbstat = 0; zoneinfo->fAging = 0; zoneinfo->dwAvailForScavengeTime = 0; zoneinfo->aipScavengeServers = NULL; zoneinfo->dwForwarderTimeout = 0; zoneinfo->fForwarderSlave = 0; zoneinfo->aipLocalMasters = NULL; zoneinfo->pwszZoneDn = discard_const_p(char, ldb_dn_get_linearized(zone->zone_dn)); zoneinfo->dwLastSuccessfulSoaCheck = 0; zoneinfo->dwLastSuccessfulXfr = 0; zoneinfo->fQueuedForBackgroundLoad = 0; zoneinfo->fBackgroundLoadInProgress = 0; zoneinfo->fReadOnlyZone = 0; zoneinfo->dwLastXfrAttempt = 0; zoneinfo->dwLastXfrResult = 0; for(i=0; inum_props; i++){ bool valid_property; valid_property = dns_zoneinfo_load_zone_property( zoneinfo, &zone->tmp_props[i]); if (!valid_property) { TALLOC_FREE(zoneinfo); return NULL; } } return zoneinfo; } struct dnsserver_zone *dnsserver_find_zone(struct dnsserver_zone *zones, const char *zone_name) { struct dnsserver_zone *z = NULL; for (z = zones; z; z = z->next) { if (dns_name_equal(zone_name, z->name)) { break; } } return z; } struct ldb_dn *dnsserver_name_to_dn(TALLOC_CTX *mem_ctx, struct dnsserver_zone *z, const char *name) { struct ldb_dn *dn; bool ret; struct ldb_val name_val = data_blob_string_const(name); dn = ldb_dn_copy(mem_ctx, z->zone_dn); if (dn == NULL) { return NULL; } if (strcasecmp(name, z->name) == 0) { ret = ldb_dn_add_child_fmt(dn, "DC=@"); if (!ret) { talloc_free(dn); return NULL; } return dn; } ret = ldb_dn_add_child_val(dn, "DC", name_val); if (!ret) { talloc_free(dn); return NULL; } return dn; } uint32_t dnsserver_zone_to_request_filter(const char *zone_name) { uint32_t request_filter = 0; if (strcmp(zone_name, "..AllZones") == 0) { request_filter = DNS_ZONE_REQUEST_PRIMARY | DNS_ZONE_REQUEST_SECONDARY | DNS_ZONE_REQUEST_AUTO | DNS_ZONE_REQUEST_FORWARD | DNS_ZONE_REQUEST_REVERSE | DNS_ZONE_REQUEST_FORWARDER | DNS_ZONE_REQUEST_STUB | DNS_ZONE_REQUEST_DS | DNS_ZONE_REQUEST_NON_DS | DNS_ZONE_REQUEST_DOMAIN_DP | DNS_ZONE_REQUEST_FOREST_DP | DNS_ZONE_REQUEST_CUSTOM_DP | DNS_ZONE_REQUEST_LEGACY_DP; } else if (strcmp(zone_name, "..AllZonesAndCache") == 0) { request_filter = DNS_ZONE_REQUEST_PRIMARY | DNS_ZONE_REQUEST_SECONDARY | DNS_ZONE_REQUEST_CACHE | DNS_ZONE_REQUEST_AUTO | DNS_ZONE_REQUEST_FORWARD | DNS_ZONE_REQUEST_REVERSE | DNS_ZONE_REQUEST_FORWARDER | DNS_ZONE_REQUEST_STUB | DNS_ZONE_REQUEST_DS | DNS_ZONE_REQUEST_NON_DS | DNS_ZONE_REQUEST_DOMAIN_DP | DNS_ZONE_REQUEST_FOREST_DP | DNS_ZONE_REQUEST_CUSTOM_DP | DNS_ZONE_REQUEST_LEGACY_DP; } else if (strcmp(zone_name, "..AllPrimaryZones") == 0) { request_filter = DNS_ZONE_REQUEST_PRIMARY; } else if (strcmp(zone_name, "..AllSecondaryZones") == 0) { request_filter = DNS_ZONE_REQUEST_SECONDARY; } else if (strcmp(zone_name, "..AllForwardZones") == 0) { request_filter = DNS_ZONE_REQUEST_FORWARD; } else if (strcmp(zone_name, "..AllReverseZones") == 0) { request_filter = DNS_ZONE_REQUEST_REVERSE; } else if (strcmp(zone_name, "..AllDsZones") == 0) { request_filter = DNS_ZONE_REQUEST_DS; } else if (strcmp(zone_name, "..AllNonDsZones") == 0) { request_filter = DNS_ZONE_REQUEST_NON_DS; } else if (strcmp(zone_name, "..AllPrimaryReverseZones") == 0) { request_filter = DNS_ZONE_REQUEST_PRIMARY | DNS_ZONE_REQUEST_REVERSE; } else if (strcmp(zone_name, "..AllPrimaryForwardZones") == 0) { request_filter = DNS_ZONE_REQUEST_PRIMARY | DNS_ZONE_REQUEST_FORWARD; } else if (strcmp(zone_name, "..AllSecondaryReverseZones") == 0) { request_filter = DNS_ZONE_REQUEST_SECONDARY | DNS_ZONE_REQUEST_REVERSE; } else if (strcmp(zone_name, "..AllSecondaryForwardZones") == 0) { request_filter = DNS_ZONE_REQUEST_SECONDARY | DNS_ZONE_REQUEST_REVERSE; } return request_filter; }