Added prefer_ipv4 bool parameter to resolve_name().
authorJeremy Allison <jra@samba.org>
Tue, 28 Jul 2009 18:51:58 +0000 (11:51 -0700)
committerJeremy Allison <jra@samba.org>
Tue, 28 Jul 2009 18:51:58 +0000 (11:51 -0700)
W2K3 DC's can have IPv6 addresses but won't serve
krb5/ldap or cldap on those addresses. Make sure when
we're asking for DC's we prefer IPv4.
If you have an IPv6-only network this prioritizing code
will be a no-op. And if you have a mixed network then you
need to prioritize IPv4 due to W2K3 DC's.
Jeremy.

15 files changed:
source3/auth/auth_server.c
source3/include/proto.h
source3/libads/ldap.c
source3/libsmb/libsmb_dir.c
source3/libsmb/namequery.c
source3/libsmb/passchange.c
source3/rpc_client/cli_pipe.c
source3/rpc_server/srv_spoolss_nt.c
source3/smbd/reply.c
source3/torture/torture.c
source3/utils/net_ads.c
source3/utils/net_lookup.c
source3/utils/net_util.c
source3/utils/smbfilter.c
source3/winbindd/winbindd_cm.c

index 466c4bf129ffa7932d8f1bab03a77307a8c5acc1..287b50b080ff437edc11b69a9c22c6e38634da82 100644 (file)
@@ -60,7 +60,7 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
                }
                strupper_m(desthost);
 
-               if(!resolve_name( desthost, &dest_ss, 0x20)) {
+               if(!resolve_name( desthost, &dest_ss, 0x20, false)) {
                        DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
                        continue;
                }
index f7fedc7e5212177cc5d4f2eb7eaa4c1456e0858d..fc009145f08a60280d453edc69d749d8202f4e28 100644 (file)
@@ -3132,7 +3132,8 @@ NTSTATUS internal_resolve_name(const char *name,
                                const char *resolve_order);
 bool resolve_name(const char *name,
                struct sockaddr_storage *return_ss,
-               int name_type);
+               int name_type,
+               bool prefer_ipv4);
 NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
                const char *name,
                int name_type,
index 102fc83d0fc92048ab964a9c23537c9dd048ace0..bb8d43c96f5cbcefe319599908fb23ea45067b0a 100644 (file)
@@ -192,29 +192,42 @@ static bool ads_try_connect(ADS_STRUCT *ads, const char *server, bool gc)
 {
        char *srv;
        struct NETLOGON_SAM_LOGON_RESPONSE_EX cldap_reply;
-       TALLOC_CTX *mem_ctx = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
        bool ret = false;
 
        if (!server || !*server) {
+               TALLOC_FREE(frame);
                return False;
        }
 
-       DEBUG(5,("ads_try_connect: sending CLDAP request to %s (realm: %s)\n", 
-               server, ads->server.realm));
+       if (!is_ipaddress(server)) {
+               struct sockaddr_storage ss;
+               char addr[INET6_ADDRSTRLEN];
 
-       mem_ctx = talloc_init("ads_try_connect");
-       if (!mem_ctx) {
-               DEBUG(0,("out of memory\n"));
-               return false;
+               if (!resolve_name(server, &ss, 0x20, true)) {
+                       DEBUG(5,("ads_try_connect: unable to resolve name %s\n",
+                               server ));
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+               print_sockaddr(addr, sizeof(addr), &ss);
+               srv = talloc_strdup(frame, addr);
+       } else {
+               /* this copes with inet_ntoa brokenness */
+               srv = talloc_strdup(frame, server);
        }
 
-       /* this copes with inet_ntoa brokenness */
+       if (!srv) {
+               TALLOC_FREE(frame);
+               return false;
+       }
 
-       srv = SMB_STRDUP(server);
+       DEBUG(5,("ads_try_connect: sending CLDAP request to %s (realm: %s)\n", 
+               srv, ads->server.realm));
 
        ZERO_STRUCT( cldap_reply );
 
-       if ( !ads_cldap_netlogon_5(mem_ctx, srv, ads->server.realm, &cldap_reply ) ) {
+       if ( !ads_cldap_netlogon_5(frame, srv, ads->server.realm, &cldap_reply ) ) {
                DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", srv));
                ret = false;
                goto out;
@@ -267,10 +280,10 @@ static bool ads_try_connect(ADS_STRUCT *ads, const char *server, bool gc)
        sitename_store( cldap_reply.dns_domain, cldap_reply.client_site);
 
        ret = true;
+
  out:
-       SAFE_FREE(srv);
-       TALLOC_FREE(mem_ctx);
 
+       TALLOC_FREE(frame);
        return ret;
 }
 
index a3f63f204d2fa652df80080351079d365a49aefc..7a6632ae4eb6e6b0bb125bc6a67b118aa682ce07 100644 (file)
@@ -615,8 +615,8 @@ SMBC_opendir_ctx(SMBCCTX *context,
                          */
                        if (!srv &&
                             !is_ipaddress(server) &&
-                           (resolve_name(server, &rem_ss, 0x1d) ||   /* LMB */
-                             resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
+                           (resolve_name(server, &rem_ss, 0x1d, false) ||   /* LMB */
+                             resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
 
                                fstring buserver;
 
@@ -675,7 +675,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                        return NULL;
                                }
                        } else if (srv ||
-                                   (resolve_name(server, &rem_ss, 0x20))) {
+                                   (resolve_name(server, &rem_ss, 0x20, false))) {
 
                                 /*
                                  * If we hadn't found the server, get one now
index 05143270b9fd8ce2a9f9f8b35740092a1e6ca6d7..1a641ac79133334fe300ab861c863da633bc3d3e 100644 (file)
@@ -439,12 +439,12 @@ static int addr_compare(const struct sockaddr *ss1,
        int num_interfaces = iface_count();
        int i;
 
-       /* Sort IPv6 addresses first. */
+       /* Sort IPv4 addresses first. */
        if (ss1->sa_family != ss2->sa_family) {
                if (ss2->sa_family == AF_INET) {
-                       return -1;
-               } else {
                        return 1;
+               } else {
+                       return -1;
                }
        }
 
@@ -601,6 +601,38 @@ static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
        return count;
 }
 
+static bool prioritize_ipv4_list(struct ip_service *iplist, int count)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct ip_service *iplist_new = TALLOC_ARRAY(frame, struct ip_service, count);
+       int i, j;
+
+       if (iplist_new == NULL) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       j = 0;
+
+       /* Copy IPv4 first. */
+       for (i = 0; i < count; i++) {
+               if (iplist[i].ss.ss_family == AF_INET) {
+                       iplist_new[j++] = iplist[i];
+               }
+       }
+
+       /* Copy IPv6. */
+       for (i = 0; i < count; i++) {
+               if (iplist[i].ss.ss_family != AF_INET) {
+                       iplist_new[j++] = iplist[i];
+               }
+       }
+
+       memcpy(iplist, iplist_new, sizeof(struct ip_service)*count);
+       TALLOC_FREE(frame);
+       return true;
+}
+
 /****************************************************************************
  Do a netbios name query to find someones IP.
  Returns an array of IP addresses or NULL if none.
@@ -1664,7 +1696,8 @@ NTSTATUS internal_resolve_name(const char *name,
 
 bool resolve_name(const char *name,
                struct sockaddr_storage *return_ss,
-               int name_type)
+               int name_type,
+               bool prefer_ipv4)
 {
        struct ip_service *ss_list = NULL;
        char *sitename = NULL;
@@ -1681,6 +1714,19 @@ bool resolve_name(const char *name,
                                                  lp_name_resolve_order()))) {
                int i;
 
+               if (prefer_ipv4) {
+                       for (i=0; i<count; i++) {
+                               if (!is_zero_addr((struct sockaddr *)&ss_list[i].ss) &&
+                                               !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss) &&
+                                               (ss_list[i].ss.ss_family == AF_INET)) {
+                                       *return_ss = ss_list[i].ss;
+                                       SAFE_FREE(ss_list);
+                                       SAFE_FREE(sitename);
+                                       return True;
+                               }
+                       }
+               }
+
                /* only return valid addresses for TCP connections */
                for (i=0; i<count; i++) {
                        if (!is_zero_addr((struct sockaddr *)&ss_list[i].ss) &&
@@ -2056,7 +2102,7 @@ static NTSTATUS get_dc_list(const char *domain,
 
                /* explicit lookup; resolve_name() will
                 * handle names & IP addresses */
-               if (resolve_name( name, &name_ss, 0x20 )) {
+               if (resolve_name( name, &name_ss, 0x20, true )) {
                        char addr[INET6_ADDRSTRLEN];
                        print_sockaddr(addr,
                                        sizeof(addr),
@@ -2086,6 +2132,13 @@ static NTSTATUS get_dc_list(const char *domain,
                                local_count );
        }
 
+       /* For DC's we always prioritize IPv4 due to W2K3 not
+        * supporting LDAP, KRB5 or CLDAP over IPv6. */
+
+       if (local_count && return_iplist) {
+               prioritize_ipv4_list(return_iplist, local_count);
+       }
+
        if ( DEBUGLEVEL >= 4 ) {
                DEBUG(4,("get_dc_list: returning %d ip addresses "
                                "in an %sordered list\n",
index 7f0389f132dccbf216ec9d5d4162f807421450b4..bb70386990a6e59eeb36939c85f7d0d2e5582d11 100644 (file)
@@ -37,7 +37,7 @@ NTSTATUS remote_password_change(const char *remote_machine, const char *user_nam
 
        *err_str = NULL;
 
-       if(!resolve_name( remote_machine, &ss, 0x20)) {
+       if(!resolve_name( remote_machine, &ss, 0x20, false)) {
                if (asprintf(err_str, "Unable to find an IP address for machine "
                         "%s.\n", remote_machine) == -1) {
                        *err_str = NULL;
index c9f17c65ade4168d5b7319e0bfae69b25eb40f68..be375f1ba50cdca026c62e1893ac54c520634cd8 100644 (file)
@@ -3171,7 +3171,7 @@ static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
        result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
        result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
 
-       if (!resolve_name(host, &addr, 0)) {
+       if (!resolve_name(host, &addr, 0, false)) {
                status = NT_STATUS_NOT_FOUND;
                goto fail;
        }
index 9dc1a26e3b383e815ba8535c44b7910d390c04f0..d7bc2624c4e559bbdc70cc05b2d8fa6802cb2549 100644 (file)
@@ -2579,7 +2579,7 @@ static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
        struct sockaddr_storage rm_addr;
 
        if ( is_zero_addr((struct sockaddr *)client_ss) ) {
-               if ( !resolve_name( remote_machine, &rm_addr, 0x20) ) {
+               if ( !resolve_name( remote_machine, &rm_addr, 0x20, false) ) {
                        DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
                        return false;
                }
index b5882abe9f2c10107566408d609b4c56746dc2d6..77e122a90c95c86f8b084b29370d01091b937264 100644 (file)
@@ -466,7 +466,7 @@ static bool netbios_session_retarget(const char *name, int name_type)
                sscanf(p, "%x", &retarget_type);
        }
 
-       ret = resolve_name(retarget, &retarget_addr, retarget_type);
+       ret = resolve_name(retarget, &retarget_addr, retarget_type, false);
        if (!ret) {
                DEBUG(10, ("could not resolve %s\n", retarget));
                goto fail;
index 7185f1c2be84132bbccaf7d0af96c08f1365eda8..babcb1e7d0e0cfc6a0ba0418202fa4d4e32fd6c2 100644 (file)
@@ -5633,7 +5633,7 @@ static bool run_tldap(int dummy)
        struct tevent_req *req;
        char *basedn;
 
-       if (!resolve_name(host, &addr, 0)) {
+       if (!resolve_name(host, &addr, 0, false)) {
                d_printf("could not find host %s\n", host);
                return false;
        }
index 9ca52a87bc9c05ff7702418fc64245fdf691805c..4e27278154bbc4a64a3c1bb22826c319b77325e3 100644 (file)
@@ -1655,7 +1655,7 @@ static int net_ads_printer_publish(struct net_context *c, int argc, const char *
 
        /* Get printer data from SPOOLSS */
 
-       resolve_name(servername, &server_ss, 0x20);
+       resolve_name(servername, &server_ss, 0x20, false);
 
        nt_status = cli_full_connection(&cli, global_myname(), servername,
                                        &server_ss, 0,
index 66f673b8d32fc7dbbb760ca07666e11ba4773ac5..e770e3299f9ea70308009cdd5ca86a7eb94b68b2 100644 (file)
@@ -53,7 +53,7 @@ static int net_lookup_host(struct net_context *c, int argc, const char **argv)
                sscanf(++p,"%x",&name_type);
        }
 
-       if (!resolve_name(name, &ss, name_type)) {
+       if (!resolve_name(name, &ss, name_type, false)) {
                /* we deliberately use DEBUG() here to send it to stderr
                   so scripts aren't mucked up */
                DEBUG(0,("Didn't find %s#%02x\n", name, name_type));
@@ -72,7 +72,7 @@ static void print_ldap_srvlist(struct dns_rr_srv *dclist, int numdcs )
        int i;
 
        for ( i=0; i<numdcs; i++ ) {
-               if (resolve_name(dclist[i].hostname, &ss, 0x20) ) {
+               if (resolve_name(dclist[i].hostname, &ss, 0x20, true) ) {
                        char addr[INET6_ADDRSTRLEN];
                        print_sockaddr(addr, sizeof(addr), &ss);
 #ifdef HAVE_IPV6
index 8bf9aac6f260b9a7662931813f0ea9653281fd6d..383fea47cce391322c4e8b614631a79b17dbd457 100644 (file)
@@ -393,7 +393,7 @@ bool net_find_server(struct net_context *c,
                }
        } else if (*server_name) {
                /* resolve the IP address */
-               if (!resolve_name(*server_name, server_ss, 0x20))  {
+               if (!resolve_name(*server_name, server_ss, 0x20, false))  {
                        DEBUG(1,("Unable to resolve server name\n"));
                        return false;
                }
@@ -420,8 +420,8 @@ bool net_find_server(struct net_context *c,
                struct sockaddr_storage msbrow_ss;
                char addr[INET6_ADDRSTRLEN];
 
-               /*  if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */
-               if (!resolve_name(d, &msbrow_ss, 0x1B))  {
+               /*  if (!resolve_name(MSBROWSE, &msbrow_ip, 1, false)) */
+               if (!resolve_name(d, &msbrow_ss, 0x1B, false))  {
                        DEBUG(1,("Unable to resolve domain browser via name lookup\n"));
                        return false;
                }
@@ -431,7 +431,7 @@ bool net_find_server(struct net_context *c,
        } else if (flags & NET_FLAGS_MASTER) {
                struct sockaddr_storage brow_ss;
                char addr[INET6_ADDRSTRLEN];
-               if (!resolve_name(d, &brow_ss, 0x1D))  {
+               if (!resolve_name(d, &brow_ss, 0x1D, false))  {
                                /* go looking for workgroups */
                        DEBUG(1,("Unable to resolve master browser via name lookup\n"));
                        return false;
index 39a264011eed4cf90acd6d9ac47893f096d30711..83de0c4c37482662075a2007074bde51fdbee893 100644 (file)
@@ -232,7 +232,7 @@ static void start_filter(char *desthost)
                d_printf("listen failed\n");
        }
 
-       if (!resolve_name(desthost, &dest_ss, 0x20)) {
+       if (!resolve_name(desthost, &dest_ss, 0x20, false)) {
                d_printf("Unable to resolve host %s\n", desthost);
                exit(1);
        }
index a7c63ea71ee297fbfff7b4aa5a7cb46a90c20dd5..460c7738b39a5b25149a9c3e56716366a35533f9 100644 (file)
@@ -679,7 +679,7 @@ static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
 
        DEBUG(10,("rpccli_netr_GetAnyDCName returned %s\n", dcname));
 
-       if (!resolve_name(dcname, dc_ss, 0x20)) {
+       if (!resolve_name(dcname, dc_ss, 0x20, true)) {
                return False;
        }
 
@@ -1467,7 +1467,7 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
 
                if (*domain->dcname 
                        && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
-                       && (resolve_name(domain->dcname, &domain->dcaddr, 0x20)))
+                       && (resolve_name(domain->dcname, &domain->dcaddr, 0x20, true)))
                {
                        struct sockaddr_storage *addrs = NULL;
                        int num_addrs = 0;