s4-rpc: dnsserver: Fix enumeration of IPv4 and IPv6 addresses
authorGuenter Kukkukk <linux@kukkukk.com>
Fri, 21 Nov 2014 15:57:45 +0000 (16:57 +0100)
committerAmitay Isaacs <amitay@samba.org>
Wed, 26 Nov 2014 02:44:06 +0000 (03:44 +0100)
In the initial implementation only IPv4 addresses were supported.

Add IPv6 (and mixed IPv4/IPv6) support and all further needed conversion
routines to support w2k, dotnet, longhorn clients.

Signed-off-by: Guenter Kukkukk <linux@kukkukk.com>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
Autobuild-User(master): Amitay Isaacs <amitay@samba.org>
Autobuild-Date(master): Wed Nov 26 03:44:07 CET 2014 on sn-devel-104

source4/rpc_server/dnsserver/dcerpc_dnsserver.c
source4/rpc_server/dnsserver/dnsdata.c
source4/rpc_server/dnsserver/dnsserver.h
source4/rpc_server/dnsserver/dnsutils.c

index 5162ab027e3392ef194999c4f6958902aeaf0db5..be315001ee2cd9d0eb42ce068277e2e5fab62522 100644 (file)
@@ -202,8 +202,10 @@ static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
                        r->ServerInfoW2K->fDsAvailable = serverinfo->fDsAvailable;
                        r->ServerInfoW2K->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
                        r->ServerInfoW2K->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
-                       r->ServerInfoW2K->aipServerAddrs = ip4_array_copy(mem_ctx, serverinfo->aipServerAddrs);
-                       r->ServerInfoW2K->aipListenAddrs = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+                       r->ServerInfoW2K->aipServerAddrs = dns_addr_array_to_ip4_array(mem_ctx,
+                                                                                      serverinfo->aipServerAddrs);
+                       r->ServerInfoW2K->aipListenAddrs = dns_addr_array_to_ip4_array(mem_ctx,
+                                                                                      serverinfo->aipListenAddrs);
                        r->ServerInfoW2K->aipForwarders = ip4_array_copy(mem_ctx, serverinfo->aipForwarders);
                        r->ServerInfoW2K->dwLogLevel = serverinfo->dwLogLevel;
                        r->ServerInfoW2K->dwDebugLevel = serverinfo->dwDebugLevel;
@@ -244,8 +246,10 @@ static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
                        r->ServerInfoDotNet->fDsAvailable = serverinfo->fDsAvailable;
                        r->ServerInfoDotNet->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
                        r->ServerInfoDotNet->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
-                       r->ServerInfoDotNet->aipServerAddrs = ip4_array_copy(mem_ctx, serverinfo->aipServerAddrs);
-                       r->ServerInfoDotNet->aipListenAddrs = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+                       r->ServerInfoDotNet->aipServerAddrs = dns_addr_array_to_ip4_array(mem_ctx,
+                                                                                         serverinfo->aipServerAddrs);
+                       r->ServerInfoDotNet->aipListenAddrs = dns_addr_array_to_ip4_array(mem_ctx,
+                                                                                         serverinfo->aipListenAddrs);
                        r->ServerInfoDotNet->aipForwarders = ip4_array_copy(mem_ctx, serverinfo->aipForwarders);
                        r->ServerInfoDotNet->aipLogFilter = ip4_array_copy(mem_ctx, serverinfo->aipLogFilter);
                        r->ServerInfoDotNet->pwszLogFilePath = talloc_strdup(mem_ctx, serverinfo->pwszLogFilePath);
@@ -299,8 +303,8 @@ static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
                        r->ServerInfo->fDsAvailable = serverinfo->fDsAvailable;
                        r->ServerInfo->pszServerName = talloc_strdup(mem_ctx, serverinfo->pszServerName);
                        r->ServerInfo->pszDsContainer = talloc_strdup(mem_ctx, serverinfo->pszDsContainer);
-                       r->ServerInfo->aipServerAddrs = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipServerAddrs);
-                       r->ServerInfo->aipListenAddrs = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipListenAddrs);
+                       r->ServerInfo->aipServerAddrs = serverinfo->aipServerAddrs;
+                       r->ServerInfo->aipListenAddrs = serverinfo->aipListenAddrs;
                        r->ServerInfo->aipForwarders = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipForwarders);
                        r->ServerInfo->aipLogFilter = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipLogFilter);
                        r->ServerInfo->pwszLogFilePath = talloc_strdup(mem_ctx, serverinfo->pwszLogFilePath);
@@ -700,9 +704,9 @@ static WERROR dnsserver_query_server(struct dnsserver_state *dsstate,
                is_addresses = 1;
        } else if (strcasecmp(operation, "ListenAddresses") == 0) {
                if (client_version == DNS_CLIENT_VERSION_LONGHORN) {
-                       answer_addrarray = ip4_array_to_dns_addr_array(mem_ctx, serverinfo->aipListenAddrs);
+                       answer_addrarray = serverinfo->aipListenAddrs;
                } else {
-                       answer_iparray = ip4_array_copy(mem_ctx, serverinfo->aipListenAddrs);
+                       answer_iparray = dns_addr_array_to_ip4_array(mem_ctx, serverinfo->aipListenAddrs);
                }
                is_addresses = 1;
        } else if (strcasecmp(operation, "BreakOnReceiveFrom") == 0) {
index 2461a4bd026a922114cf5addee886c5666095096..067654ad2c62f25493441889337048204a7edb31 100644 (file)
@@ -91,6 +91,62 @@ struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx,
        return ret;
 }
 
+struct IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
+                                             struct DNS_ADDR_ARRAY *ip)
+{
+       struct IP4_ARRAY *ret;
+       int i, count, curr;
+
+       if (ip == NULL) {
+               return NULL;
+       }
+       /* We must only return IPv4 addresses.
+          The passed DNS_ADDR_ARRAY may contain:
+          - only ipv4 addresses
+          - only ipv6 addresses
+          - a mixture of both
+          - an empty array
+       */
+       ret = talloc_zero(mem_ctx, struct IP4_ARRAY);
+       if (!ret) {
+               return ret;
+       }
+       if (ip->AddrCount == 0 || ip->Family == AF_INET6) {
+               ret->AddrCount = 0;
+               return ret;
+       }
+       /* Now only ipv4 addresses or a mixture are left */
+       count = 0;
+       for (i = 0; i < ip->AddrCount; i++) {
+               if (ip->AddrArray[i].MaxSa[0] == 0x02) {
+                       /* Is ipv4 */
+                       count++;
+               }
+       }
+       if (count == 0) {
+               /* should not happen */
+               ret->AddrCount = 0;
+               return ret;
+       }
+       ret->AddrArray = talloc_zero_array(mem_ctx, uint32_t, count);
+       if (ret->AddrArray) {
+               curr = 0;
+               for (i = 0; i < ip->AddrCount; i++) {
+                       if (ip->AddrArray[i].MaxSa[0] == 0x02) {
+                               /* Is ipv4 */
+                               memcpy(&ret->AddrArray[curr],
+                                      &ip->AddrArray[i].MaxSa[4],
+                                      sizeof(uint32_t));
+                               curr++;
+                       }
+               }
+       } else {
+               talloc_free(ret);
+               return NULL;
+       }
+       ret->AddrCount = curr;
+       return ret;
+}
 
 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx,
                                                struct DNS_ADDR_ARRAY *addr)
index e3db0b2e1ce9161e3220af096fe880d002b8b029..cfe6d4e81a394c2ad4891b51f887ff83d863d8c0 100644 (file)
@@ -46,8 +46,8 @@ struct dnsserver_serverinfo {
        char *          pszDomainDirectoryPartition;
        char *          pszForestDirectoryPartition;
 
-       struct IP4_ARRAY * aipServerAddrs;
-       struct IP4_ARRAY * aipListenAddrs;
+       struct DNS_ADDR_ARRAY * aipServerAddrs;
+       struct DNS_ADDR_ARRAY * aipListenAddrs;
        struct IP4_ARRAY * aipForwarders;
 
        struct IP4_ARRAY * aipLogFilter;
@@ -179,6 +179,8 @@ struct dns_tree {
 
 struct IP4_ARRAY *ip4_array_copy(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4);
 struct DNS_ADDR_ARRAY *ip4_array_to_dns_addr_array(TALLOC_CTX *mem_ctx, struct IP4_ARRAY *ip4);
+struct IP4_ARRAY *dns_addr_array_to_ip4_array(TALLOC_CTX *mem_ctx,
+                                             struct DNS_ADDR_ARRAY *ip);
 struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx, struct DNS_ADDR_ARRAY *addr);
 
 int dns_split_name_components(TALLOC_CTX *mem_ctx, const char *name, char ***components);
@@ -217,7 +219,6 @@ struct ldb_dn *dnsserver_name_to_dn(TALLOC_CTX *mem_ctx, struct dnsserver_zone *
                                        const char *name);
 uint32_t dnsserver_zone_to_request_filter(const char *zone);
 
-
 /* Database functions from dnsdb.c */
 
 struct dnsserver_partition *dnsserver_db_enumerate_partitions(TALLOC_CTX *mem_ctx,
index 9f956460f99a421153010e184f7e3ddc1975e50a..72b47f72b4fdfb9f6e0e52b8ed3341e32497a992 100644 (file)
 #include "rpc_server/common/common.h"
 #include "dsdb/samdb/samdb.h"
 #include "lib/socket/netif.h"
+#include "lib/util/util_net.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++) {
+               ipstr = iface_list_n_ip(ifaces, i);
+               if (is_ipaddress_v4(ipstr)) {
+                       have_ipv4 = true;
+                       dns_addr_array->AddrArray[i].MaxSa[0] = 0x02;
+                       inet_pton(AF_INET, ipstr,
+                                 &dns_addr_array->AddrArray[i].MaxSa[4]);
+               } else {
+                       have_ipv6 = true;
+                       dns_addr_array->AddrArray[i].MaxSa[0] = 0x17;
+                       inet_pton(AF_INET6, ipstr,
+                                 &dns_addr_array->AddrArray[i].MaxSa[8]);
+               }
+       }
+
+       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,
@@ -33,8 +104,6 @@ struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx,
        struct dnsserver_serverinfo *serverinfo;
        struct dcerpc_server_info *dinfo;
        struct ldb_dn *domain_dn, *forest_dn;
-       struct interface *ifaces;
-       int num_interfaces, i;
 
        serverinfo = talloc_zero(mem_ctx, struct dnsserver_serverinfo);
        if (serverinfo == NULL) {
@@ -80,31 +149,14 @@ struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx,
        serverinfo->pszForestDirectoryPartition = talloc_asprintf(mem_ctx,
                                                        "DC=ForestDnsZones,%s",
                                                        ldb_dn_get_linearized(forest_dn));
-
-       load_interface_list(mem_ctx, lp_ctx, &ifaces);
-       num_interfaces = iface_list_count(ifaces);
-
-       serverinfo->aipServerAddrs = talloc_zero(mem_ctx, struct IP4_ARRAY);
-
-       if (serverinfo->aipServerAddrs) {
-               serverinfo->aipServerAddrs->AddrCount = num_interfaces;
-               if (num_interfaces > 0) {
-                       serverinfo->aipServerAddrs->AddrArray = talloc_zero_array(mem_ctx,
-                                                                       unsigned int,
-                                                                       num_interfaces);
-                       if (serverinfo->aipServerAddrs->AddrArray) {
-                               for (i=0; i<num_interfaces; i++) {
-                                       serverinfo->aipServerAddrs->AddrArray[i] = inet_addr(iface_list_n_ip(ifaces, i));
-                               }
-                       } else {
-                               serverinfo->aipServerAddrs->AddrCount = 0;
-                       }
-               }
-       }
-       talloc_free(ifaces);
-
-       /* Assume listen addresses are same as server addresses */
-       serverinfo->aipListenAddrs = serverinfo->aipServerAddrs;
+       /* 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;