Forward port the app-head changes for dc name cache into 3.0.
authorJeremy Allison <jra@samba.org>
Fri, 13 Jun 2003 21:03:15 +0000 (21:03 +0000)
committerJeremy Allison <jra@samba.org>
Fri, 13 Jun 2003 21:03:15 +0000 (21:03 +0000)
Jeremy.
(This used to be commit 8bcc3116a22ce11b55a35f3363230f54bc5735fc)

source3/auth/auth_domain.c
source3/libsmb/namecache.c
source3/libsmb/namequery.c
source3/libsmb/namequery_dc.c
source3/nsswitch/winbindd_cm.c

index 2991684280546b794ede64d5a9432ea183d11afc..f1575e43b0a093f3e036f1fa368bb4c7b21a316a 100644 (file)
@@ -276,7 +276,7 @@ static NTSTATUS find_connect_dc(struct cli_state **cli,
        struct in_addr dc_ip;
        fstring srv_name;
 
-       if (!rpc_find_dc(domain, srv_name, &dc_ip)) {
+       if (!get_dc_name(domain, srv_name, &dc_ip)) {
                DEBUG(0,("find_connect_dc: Failed to find an DCs for %s\n", lp_workgroup()));
                return NT_STATUS_NO_LOGON_SERVERS;
        }
index d3541b7719d9a991ea030c89406f0415936d96e6..7a0eb5212aa0faf3893aa716a387d2148253f64d 100644 (file)
@@ -143,10 +143,19 @@ BOOL namecache_store(const char *name, int name_type,
         * out of action for the entire cache timeout time!
         */
 
+#if 0
+               /*
+                * I don't think we need to do this. We are
+                * checking at a higher level for failed DC
+                * connections. JRA.
+                */
+
        if (name_type == 0x1b || name_type == 0x1c)
                expiry = time(NULL) + 10;
        else
                expiry = time(NULL) + lp_name_cache_timeout();
+#endif
+       expiry = time(NULL) + lp_name_cache_timeout();
 
        /*
         * Generate string representation of ip addresses list
@@ -201,7 +210,9 @@ BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
 
        if (!gencache_get(key, &value, &timeout)) {
                DEBUG(5, ("no entry for %s#%02X found.\n", name, name_type));
+               gencache_del(key);
                SAFE_FREE(key);
+               SAFE_FREE(value);                
                return False;
        } else {
                DEBUG(5, ("name %s#%02X found.\n", name, name_type));
@@ -252,3 +263,75 @@ void namecache_flush(void)
        DEBUG(5, ("Namecache flushed\n"));
 }
 
+/* Construct a name status record key. */
+
+static char *namecache_status_record_key(const char *name, int name_type1,
+                               int name_type2, struct in_addr keyip)
+{
+       char *keystr;
+
+       asprintf(&keystr, "NBT/%s#%02X.%02X.%s",
+                       strupper_static(name), name_type1, name_type2, inet_ntoa(keyip));
+       return keystr;
+}
+
+/* Store a name status record. */
+
+BOOL namecache_status_store(const char *keyname, int keyname_type,
+               int name_type, struct in_addr keyip,
+               const char *srvname)
+{
+       char *key;
+       time_t expiry;
+       BOOL ret;
+
+       if (!gencache_init())
+               return False;
+
+       key = namecache_status_record_key(keyname, keyname_type, name_type, keyip);
+       if (!key)
+               return False;
+
+       expiry = time(NULL) + lp_name_cache_timeout();
+       ret = gencache_set(key, srvname, expiry);
+
+       if (ret)
+               DEBUG(5, ("namecache_status_store: entry %s -> %s\n", key, srvname ));
+       else
+               DEBUG(5, ("namecache_status_store: entry %s store failed.\n", key ));
+
+       SAFE_FREE(key);
+       return ret;
+}
+
+/* Fetch a name status record. */
+
+BOOL namecache_status_fetch(const char *keyname, int keyname_type,
+                       int name_type, struct in_addr keyip, char *srvname_out)
+{
+       char *key = NULL;
+       char *value = NULL;
+       time_t timeout;
+
+       if (!gencache_init())
+               return False;
+
+       key = namecache_status_record_key(keyname, keyname_type, name_type, keyip);
+       if (!key)
+               return False;
+
+       if (!gencache_get(key, &value, &timeout)) {
+               DEBUG(5, ("namecache_status_fetch: no entry for %s found.\n", key));
+               gencache_del(key);
+               SAFE_FREE(key);
+               SAFE_FREE(value);
+               return False;
+       } else {
+               DEBUG(5, ("namecache_status_fetch: key %s -> %s\n", key, value ));
+       }
+
+       strlcpy(srvname_out, value, 16);
+       SAFE_FREE(key);
+       SAFE_FREE(value);
+       return True;
+}
index 18ce5e4bd9b3ea1e74c2f579b55df522e324deef..7f343033d6a4c0c7f1d37882e76088465d08c9a0 100644 (file)
@@ -25,8 +25,9 @@
 BOOL global_in_nmbd = False;
 
 /****************************************************************************
-generate a random trn_id
+ Generate a random trn_id.
 ****************************************************************************/
+
 static int generate_trn_id(void)
 {
        static int trn_id;
@@ -40,10 +41,10 @@ static int generate_trn_id(void)
        return trn_id % (unsigned)0x7FFF;
 }
 
-
 /****************************************************************************
- parse a node status response into an array of structures
+ Parse a node status response into an array of structures.
 ****************************************************************************/
+
 static struct node_status *parse_node_status(char *p, int *num_names)
 {
        struct node_status *ret;
@@ -51,7 +52,8 @@ static struct node_status *parse_node_status(char *p, int *num_names)
 
        *num_names = CVAL(p,0);
 
-       if (*num_names == 0) return NULL;
+       if (*num_names == 0)
+               return NULL;
 
        ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));
        if (!ret) return NULL;
@@ -71,9 +73,10 @@ static struct node_status *parse_node_status(char *p, int *num_names)
 
 
 /****************************************************************************
-do a NBT node status query on an open socket and return an array of
-structures holding the returned names or NULL if the query failed
+ Do a NBT node status query on an open socket and return an array of
+ structures holding the returned names or NULL if the query failed.
 **************************************************************************/
+
 struct node_status *node_status_query(int fd,struct nmb_name *name,
                                      struct in_addr to_ip, int *num_names)
 {
@@ -155,11 +158,9 @@ struct node_status *node_status_query(int fd,struct nmb_name *name,
        return NULL;
 }
 
-
 /****************************************************************************
-find the first type XX name in a node status reply - used for finding
-a servers name given its IP
-return the matched name in *name
+ Find the first type XX name in a node status reply - used for finding
+ a servers name given its IP. Return the matched name in *name.
 **************************************************************************/
 
 BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr to_ip, char *name)
@@ -178,6 +179,11 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
        DEBUG(10, ("name_status_find: looking up %s#%02x at %s\n", q_name, 
                   q_type, inet_ntoa(to_ip)));
 
+       /* Check the cache first. */
+
+       if (namecache_status_fetch(q_name, q_type, type, to_ip, name))
+               return True;
+
        sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);
        if (sock == -1)
                goto done;
@@ -197,6 +203,10 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
                goto done;
 
        pull_ascii(name, status[i].name, 16, 15, STR_TERMINATE);
+
+       /* Store the result in the cache. */
+       namecache_status_store(q_name, q_type, type, to_ip, name);
+
        result = True;
 
  done:
@@ -205,17 +215,17 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
        DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not "));
 
        if (result)
-               DEBUGADD(10, (", ip address is %s", inet_ntoa(to_ip)));
+               DEBUGADD(10, (", name %s ip address is %s", name, inet_ntoa(to_ip)));
 
        DEBUG(10, ("\n"));      
 
        return result;
 }
 
-
 /*
   comparison function used by sort_ip_list
 */
+
 int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
 {
        int max_bits1=0, max_bits2=0;
@@ -248,6 +258,7 @@ int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
   are at the top. This prevents the problem where a WINS server returns an IP that
   is not reachable from our subnet as the first match
 */
+
 static void sort_ip_list(struct in_addr *iplist, int count)
 {
        if (count <= 1) {
@@ -257,13 +268,13 @@ static void sort_ip_list(struct in_addr *iplist, int count)
        qsort(iplist, count, sizeof(struct in_addr), QSORT_CAST ip_compare);    
 }
 
-
 /****************************************************************************
  Do a netbios name query to find someones IP.
  Returns an array of IP addresses or NULL if none.
  *count will be set to the number of addresses returned.
  *timed_out is set if we failed by timing out
 ****************************************************************************/
+
 struct in_addr *name_query(int fd,const char *name,int name_type, 
                           BOOL bcast,BOOL recurse,
                           struct in_addr to_ip, int *count, int *flags,
@@ -611,6 +622,7 @@ BOOL name_resolve_bcast(const char *name, int name_type,
 /********************************************************
  Resolve via "wins" method.
 *********************************************************/
+
 BOOL resolve_wins(const char *name, int name_type,
                  struct in_addr **return_iplist, int *return_count)
 {
@@ -1377,4 +1389,3 @@ BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count, int *
        
        return internal_resolve_name(domain, 0x1C, ip_list, count);
 }
-
index e98b728963ebe415b50a42e19755c89f3080412b..c162e340279c095f0e8172b6f1d523f5930521a9 100644 (file)
@@ -156,12 +156,11 @@ void flush_negative_conn_cache( void )
 }
 
 /****************************************************************************
- Utility function to return the name of a DC using RPC. The name is 
- guaranteed to be valid since we have already done a name_status_find on it 
- and we have checked our negative connection cache
+ Utility function to return the name of a DC. The name is guaranteed to be 
+ valid since we have already done a name_status_find on it 
  ***************************************************************************/
-BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
+
+BOOL get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
 {
        struct in_addr *ip_list = NULL, dc_ip, exclude_ip;
        int count, i;
@@ -177,10 +176,12 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
           
        if ( use_pdc_only && get_pdc_ip(domain, &dc_ip) ) 
        {
-               DEBUG(10,("rpc_find_dc: Atempting to lookup PDC to avoid sam sync delays\n"));
+               DEBUG(10,("get_dc_name: Atempting to lookup PDC to avoid sam sync delays\n"));
                
-               if (name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name)) {
-                       /* makre we we haven't tried this on previously and failed */
+               /* check the connection cache and perform the node status 
+                  lookup only if the IP is not found to be bad */
+
+               if (name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name) ) {
                        result = check_negative_conn_cache( domain, srv_name );
                        if ( NT_STATUS_IS_OK(result) )
                                goto done;
@@ -205,11 +206,71 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
                }
        }
 
-       /* Pick a nice close server, but only if the list was not ordered */
-       if (!list_ordered && (count > 1) ) {
-               qsort(ip_list, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
+       if ( !list_ordered ) 
+       {
+               /* 
+                * Pick a nice close server. Look for DC on local net 
+                * (assuming we don't have a list of preferred DC's)
+                */
+                
+               for (i = 0; i < count; i++) {
+                       if (is_zero_ip(ip_list[i]))
+                               continue;
+
+                       if ( !is_local_net(ip_list[i]) )
+                               continue;
+               
+                       if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
+                               result = check_negative_conn_cache( domain, srv_name );
+                               if ( NT_STATUS_IS_OK(result) ) {
+                                       dc_ip = ip_list[i];
+                                       goto done;
+                               }
+                       }
+               
+                       zero_ip(&ip_list[i]);
+               }
+
+               /*
+                * Try looking in the name status cache for an
+                * entry we already have. We know that already
+                * resolved ok.
+                */
+
+               for (i = 0; i < count; i++) {
+                       if (is_zero_ip(ip_list[i]))
+                               continue;
+
+                       if (namecache_status_fetch(domain, 0x1c, 0x20,
+                                               ip_list[i], srv_name)) {
+                               result = check_negative_conn_cache( domain, srv_name );
+                               if ( NT_STATUS_IS_OK(result) ) {
+                                       dc_ip = ip_list[i];
+                                       goto done;
+                               }
+                       }
+               }
+               
+               /*
+                * Secondly try and contact a random PDC/BDC.
+                */
+
+               i = (sys_random() % count);
+
+               if ( !is_zero_ip(ip_list[i]) ) {
+                       if ( name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
+                               result = check_negative_conn_cache( domain, srv_name );
+                               if ( NT_STATUS_IS_OK(result) ) {
+                                       dc_ip = ip_list[i];
+                                       goto done;
+                               }
+                       }
+                       zero_ip(&ip_list[i]); /* Tried and failed. */
+               }
        }
 
+       /* Finally return first DC that we can contact */
+
        for (i = 0; i < count; i++) {
                if (is_zero_ip(ip_list[i]))
                        continue;
@@ -220,20 +281,21 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
                                dc_ip = ip_list[i];
                                goto done;
                        }
-               }
+               }               
        }
 
-
        SAFE_FREE(ip_list);
 
-       return False;
-done:
+       /* No-one to talk to )-: */
+       return False;           /* Boo-hoo */
+       
+ done:
        /* We have the netbios name and IP address of a domain controller.
           Ideally we should sent a SAMLOGON request to determine whether
           the DC is alive and kicking.  If we can catch a dead DC before
           performing a cli_connect() we can avoid a 30-second timeout. */
 
-       DEBUG(3, ("rpc_find_dc: Returning DC %s (%s) for domain %s\n", srv_name,
+       DEBUG(3, ("get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
                  inet_ntoa(dc_ip), domain));
 
        *ip_out = dc_ip;
@@ -242,4 +304,3 @@ done:
 
        return True;
 }
-
index 381cdaaa20f258bfe7390830ca5b4644e566075e..0ba9ab8266504b234c9e76fd732a19ebf6261319 100644 (file)
@@ -51,9 +51,6 @@
      - I'm pretty annoyed by all the make_nmb_name() stuff.  It should be
        moved down into another function.
 
-     - There needs to be a utility function in libsmb/namequery.c that does
-       cm_get_dc_name() 
-
      - Take care when destroying cli_structs as they can be shared between
        various sam handles.
 
@@ -132,8 +129,6 @@ static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr
        return True;
 }
 
-
-
 static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
 {
        static struct get_dc_name_cache *get_dc_name_cache;
@@ -196,7 +191,7 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr
 
        if (!ret) {
                /* fall back on rpc methods if the ADS methods fail */
-               ret = rpc_find_dc(domain, srv_name, &dc_ip);
+               ret = get_dc_name(domain, srv_name, &dc_ip);
        }
 
        if (!ret)