mirror of
https://github.com/samba-team/samba.git
synced 2025-02-23 09:57:40 +03:00
Forward port the app-head changes for dc name cache into 3.0.
Jeremy. (This used to be commit 8bcc3116a22ce11b55a35f3363230f54bc5735fc)
This commit is contained in:
parent
3d0d8f609d
commit
292a51eda1
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user