return False;
}
- if ( !gencache_init() )
- return False;
-
key = saf_key( domain );
expire = time( NULL ) + lp_parm_int(-1, "saf","ttl", SAF_TTL);
return False;
}
- if ( !gencache_init() )
- return False;
-
key = saf_join_key( domain );
expire = time( NULL ) + lp_parm_int(-1, "saf","join ttl", SAFJOIN_TTL);
return False;
}
- if ( !gencache_init() )
- return False;
-
key = saf_join_key(domain);
ret = gencache_del(key);
SAFE_FREE(key);
return NULL;
}
- if ( !gencache_init() )
- return False;
-
key = saf_join_key( domain );
ret = gencache_get( key, &server, &timeout );
p.ip = ((const struct sockaddr_in *)to_ss)->sin_addr;
p.port = NMB_PORT;
- p.fd = fd;
+ p.recv_fd = -1;
+ p.send_fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
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;
}
}
DEBUG(10,("remove_duplicate_addrs2: "
"looking for duplicate address/port pairs\n"));
- /* one loop to remove duplicates */
+ /* One loop to set duplicates to a zero addr. */
for ( i=0; i<count; i++ ) {
if ( is_zero_addr((struct sockaddr *)&iplist[i].ss)) {
continue;
}
}
- /* one loop to clean up any holes we left */
- /* first ip should never be a zero_ip() */
- for (i = 0; i<count; ) {
- if (is_zero_addr((struct sockaddr *)&iplist[i].ss) ) {
- if (i != count-1) {
- memmove(&iplist[i], &iplist[i+1],
- (count - i - 1)*sizeof(iplist[i]));
+ /* Now remove any addresses set to zero above. */
+ for (i = 0; i < count; i++) {
+ while (i < count &&
+ is_zero_addr((struct sockaddr *)&iplist[i].ss)) {
+ if (count-i-1>0) {
+ memmove(&iplist[i],
+ &iplist[i+1],
+ (count-i-1)*sizeof(struct ip_service));
}
count--;
- continue;
}
- i++;
}
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.
p.ip = ((struct sockaddr_in *)to_ss)->sin_addr;
p.port = NMB_PORT;
- p.fd = fd;
+ p.recv_fd = -1;
+ p.send_fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
}
/********************************************************
- Start parsing the lmhosts file.
-*********************************************************/
-
-XFILE *startlmhosts(const char *fname)
-{
- XFILE *fp = x_fopen(fname,O_RDONLY, 0);
- if (!fp) {
- DEBUG(4,("startlmhosts: Can't open lmhosts file %s. "
- "Error was %s\n",
- fname, strerror(errno)));
- return NULL;
- }
- return fp;
-}
-
-/********************************************************
- Parse the next line in the lmhosts file.
-*********************************************************/
-
-bool getlmhostsent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, int *name_type,
- struct sockaddr_storage *pss)
-{
- char line[1024];
-
- *pp_name = NULL;
-
- while(!x_feof(fp) && !x_ferror(fp)) {
- char *ip = NULL;
- char *flags = NULL;
- char *extra = NULL;
- char *name = NULL;
- const char *ptr;
- char *ptr1 = NULL;
- int count = 0;
-
- *name_type = -1;
-
- if (!fgets_slash(line,sizeof(line),fp)) {
- continue;
- }
-
- if (*line == '#') {
- continue;
- }
-
- ptr = line;
-
- if (next_token_talloc(ctx, &ptr, &ip, NULL))
- ++count;
- if (next_token_talloc(ctx, &ptr, &name, NULL))
- ++count;
- if (next_token_talloc(ctx, &ptr, &flags, NULL))
- ++count;
- if (next_token_talloc(ctx, &ptr, &extra, NULL))
- ++count;
-
- if (count <= 0)
- continue;
-
- if (count > 0 && count < 2) {
- DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",
- line));
- continue;
- }
-
- if (count >= 4) {
- DEBUG(0,("getlmhostsent: too many columns "
- "in lmhosts file (obsolete syntax)\n"));
- continue;
- }
-
- if (!flags) {
- flags = talloc_strdup(ctx, "");
- if (!flags) {
- continue;
- }
- }
-
- DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n",
- ip, name, flags));
-
- if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
- DEBUG(0,("getlmhostsent: group flag "
- "in lmhosts ignored (obsolete)\n"));
- continue;
- }
-
- if (!interpret_string_addr(pss, ip, AI_NUMERICHOST)) {
- DEBUG(0,("getlmhostsent: invalid address "
- "%s.\n", ip));
- }
-
- /* Extra feature. If the name ends in '#XX',
- * where XX is a hex number, then only add that name type. */
- if((ptr1 = strchr_m(name, '#')) != NULL) {
- char *endptr;
- ptr1++;
-
- *name_type = (int)strtol(ptr1, &endptr, 16);
- if(!*ptr1 || (endptr == ptr1)) {
- DEBUG(0,("getlmhostsent: invalid name "
- "%s containing '#'.\n", name));
- continue;
- }
-
- *(--ptr1) = '\0'; /* Truncate at the '#' */
- }
-
- *pp_name = talloc_strdup(ctx, name);
- if (!*pp_name) {
- return false;
- }
- return true;
- }
-
- return false;
-}
-
-/********************************************************
- Finish parsing the lmhosts file.
-*********************************************************/
-
-void endlmhosts(XFILE *fp)
-{
- x_fclose(fp);
-}
-
-/********************************************************
- convert an array if struct sockaddr_storage to struct ip_service
+ Convert an array if struct sockaddr_storage to struct ip_service
return false on failure. Port is set to PORT_NONE;
+ pcount is [in/out] - it is the length of ss_list on input,
+ and the length of return_iplist on output as we remove any
+ zero addresses from ss_list.
*********************************************************/
static bool convert_ss2service(struct ip_service **return_iplist,
const struct sockaddr_storage *ss_list,
- int count)
+ int *pcount)
{
int i;
+ int orig_count = *pcount;
+ int real_count = 0;
- if ( count==0 || !ss_list )
+ if (orig_count==0 || !ss_list )
return False;
+ /* Filter out zero addrs. */
+ for ( i=0; i<orig_count; i++ ) {
+ if (is_zero_addr((struct sockaddr *)&ss_list[i])) {
+ continue;
+ }
+ real_count++;
+ }
+ if (real_count==0) {
+ return false;
+ }
+
/* copy the ip address; port will be PORT_NONE */
- if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, count)) ==
+ if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, real_count)) ==
NULL) {
DEBUG(0,("convert_ip2service: malloc failed "
- "for %d enetries!\n", count ));
+ "for %d enetries!\n", real_count ));
return False;
}
- for ( i=0; i<count; i++ ) {
- (*return_iplist)[i].ss = ss_list[i];
- (*return_iplist)[i].port = PORT_NONE;
+ for ( i=0, real_count = 0; i<orig_count; i++ ) {
+ if (is_zero_addr((struct sockaddr *)&ss_list[i])) {
+ continue;
+ }
+ (*return_iplist)[real_count].ss = ss_list[i];
+ (*return_iplist)[real_count].port = PORT_NONE;
+ real_count++;
}
+ *pcount = real_count;
return true;
}
success:
status = NT_STATUS_OK;
- if (!convert_ss2service(return_iplist, ss_list, *return_count) )
+ if (!convert_ss2service(return_iplist, ss_list, return_count) )
status = NT_STATUS_INVALID_PARAMETER;
SAFE_FREE(ss_list);
success:
status = NT_STATUS_OK;
- if (!convert_ss2service(return_iplist, ss_list, *return_count))
+ if (!convert_ss2service(return_iplist, ss_list, return_count))
status = NT_STATUS_INVALID_PARAMETER;
SAFE_FREE(ss_list);
ZERO_STRUCT(ss);
memcpy(&ss, res->ai_addr, res->ai_addrlen);
+ if (is_zero_addr((struct sockaddr *)&ss)) {
+ continue;
+ }
+
*return_count += 1;
*return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
struct ip_service **return_iplist,
int *return_count)
{
- int i, j;
+ int i;
NTSTATUS status;
TALLOC_CTX *ctx;
struct dns_rr_srv *dcs = NULL;
}
for (i=0;i<numdcs;i++) {
- numaddrs += MAX(dcs[i].num_ips,1);
+ if (!dcs[i].ss_s) {
+ numaddrs += 1;
+ } else {
+ numaddrs += dcs[i].num_ips;
+ }
}
if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) ==
/* now unroll the list of IP addresses */
*return_count = 0;
- i = 0;
- j = 0;
- while ( i < numdcs && (*return_count<numaddrs) ) {
- struct ip_service *r = &(*return_iplist)[*return_count];
-
- r->port = dcs[i].port;
-
- /* If we don't have an IP list for a name, lookup it up */
+ for (i = 0; i < numdcs; i++) {
+ /* If we don't have an IP list for a name, look it up */
if (!dcs[i].ss_s) {
- interpret_string_addr(&r->ss, dcs[i].hostname, 0);
- i++;
- j = 0;
- } else {
- /* use the IP addresses from the SRV sresponse */
-
- if ( j >= dcs[i].num_ips ) {
- i++;
- j = 0;
+ /* We need to get all IP addresses here. */
+ struct addrinfo *res = NULL;
+ struct addrinfo *p;
+ int extra_addrs = 0;
+
+ if (!interpret_string_addr_internal(&res,
+ dcs[i].hostname,
+ 0)) {
continue;
}
-
- r->ss = dcs[i].ss_s[j];
- j++;
- }
-
- /* make sure it is a valid IP. I considered checking the
- * negative connection cache, but this is the wrong place
- * for it. Maybe only as a hack. After think about it, if
- * all of the IP addresses returned from DNS are dead, what
- * hope does a netbios name lookup have ? The standard reason
- * for falling back to netbios lookups is that our DNS server
- * doesn't know anything about the DC's -- jerry */
-
- if (!is_zero_addr((struct sockaddr *)&r->ss)) {
- (*return_count)++;
+ /* Add in every IP from the lookup. How
+ many is that ? */
+ for (p = res; p; p = p->ai_next) {
+ if (is_zero_addr((struct sockaddr *)p->ai_addr)) {
+ continue;
+ }
+ extra_addrs++;
+ }
+ if (extra_addrs > 1) {
+ /* We need to expand the return_iplist array
+ as we only budgeted for one address. */
+ numaddrs += (extra_addrs-1);
+ *return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
+ struct ip_service,
+ numaddrs);
+ if (*return_iplist == NULL) {
+ if (res) {
+ freeaddrinfo(res);
+ }
+ talloc_destroy(ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ for (p = res; p; p = p->ai_next) {
+ (*return_iplist)[*return_count].port = dcs[i].port;
+ memcpy(&(*return_iplist)[*return_count].ss,
+ p->ai_addr,
+ p->ai_addrlen);
+ if (is_zero_addr((struct sockaddr *)&(*return_iplist)[*return_count].ss)) {
+ continue;
+ }
+ (*return_count)++;
+ /* Should never happen, but still... */
+ if (*return_count>=numaddrs) {
+ break;
+ }
+ }
+ if (res) {
+ freeaddrinfo(res);
+ }
+ } else {
+ /* use all the IP addresses from the SRV sresponse */
+ int j;
+ for (j = 0; j < dcs[i].num_ips; j++) {
+ (*return_iplist)[*return_count].port = dcs[i].port;
+ (*return_iplist)[*return_count].ss = dcs[i].ss_s[j];
+ if (is_zero_addr((struct sockaddr *)&(*return_iplist)[*return_count].ss)) {
+ continue;
+ }
+ (*return_count)++;
+ /* Should never happen, but still... */
+ if (*return_count>=numaddrs) {
+ break;
+ }
+ }
}
}
SAFE_FREE(*return_iplist);
return NT_STATUS_INVALID_PARAMETER;
}
+ if (is_zero_addr((struct sockaddr *)&(*return_iplist)->ss)) {
+ SAFE_FREE(*return_iplist);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
*return_count = 1;
return NT_STATUS_OK;
}
/* Check name cache */
if (namecache_fetch(name, name_type, return_iplist, return_count)) {
+ *return_count = remove_duplicate_addrs2(*return_iplist,
+ *return_count );
/* This could be a negative response */
if (*return_count > 0) {
return NT_STATUS_OK;
controllers including the PDC in iplist[1..n]. Iterating over
the iplist when the PDC is down will cause two sets of timeouts. */
- if ( *return_count ) {
- *return_count = remove_duplicate_addrs2(*return_iplist,
- *return_count );
- }
+ *return_count = remove_duplicate_addrs2(*return_iplist, *return_count );
/* Save in name cache */
if ( DEBUGLEVEL >= 100 ) {
}
}
- namecache_store(name, name_type, *return_count, *return_iplist);
+ if (*return_count) {
+ namecache_store(name, name_type, *return_count, *return_iplist);
+ }
/* Display some debugging info */
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;
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) &&
/* 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),
/* need to remove duplicates in the list if we have any
explicit password servers */
- if (local_count) {
- local_count = remove_duplicate_addrs2(return_iplist,
- local_count );
+ local_count = remove_duplicate_addrs2(return_iplist, 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 ) {