summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-12-12 09:42:58 -0800
committerJeremy Allison <jra@samba.org>2007-12-12 09:42:58 -0800
commite3e16928c057b35b66bc814a507fc79b9e02084c (patch)
tree40ddc22a9e766042c634fbf7de87797e69ed2dfc
parentd818a93d073f5c15ffbb3b769348d25e49bc9848 (diff)
downloadsamba-e3e16928c057b35b66bc814a507fc79b9e02084c.tar.gz
samba-e3e16928c057b35b66bc814a507fc79b9e02084c.tar.bz2
samba-e3e16928c057b35b66bc814a507fc79b9e02084c.zip
Allow cliconnect to loop through multiple ip addresses
for a server. We should have been doing this for a while, but it's more critical with IPv6. Original patch fixed up by James. Jeremy. (This used to be commit 5c7f7629a97ef0929e00e52f1fae4386c984000b)
-rw-r--r--source3/libsmb/cliconnect.c72
-rw-r--r--source3/libsmb/namequery.c81
2 files changed, 130 insertions, 23 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index fdf7491d80..45c202090e 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -1424,7 +1424,11 @@ NTSTATUS cli_connect(struct cli_state *cli,
{
int name_type = 0x20;
- char *p;
+ TALLOC_CTX *frame = talloc_stackframe();
+ unsigned int num_addrs = 0;
+ unsigned int i = 0;
+ struct sockaddr_storage *ss_arr = NULL;
+ char *p = NULL;
/* reasonable default hostname */
if (!host) {
@@ -1440,44 +1444,66 @@ NTSTATUS cli_connect(struct cli_state *cli,
}
if (!dest_ss || is_zero_addr(dest_ss)) {
- if (!resolve_name(cli->desthost, &cli->dest_ss, name_type)) {
+ NTSTATUS status =resolve_name_list(frame,
+ cli->desthost,
+ name_type,
+ &ss_arr,
+ &num_addrs);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
return NT_STATUS_BAD_NETWORK_NAME;
}
- if (dest_ss) {
- *dest_ss = cli->dest_ss;
- }
} else {
- cli->dest_ss = *dest_ss;
+ num_addrs = 1;
+ ss_arr = TALLOC_P(frame, struct sockaddr_storage);
+ if (!ss_arr) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ *ss_arr = *dest_ss;
}
- if (getenv("LIBSMB_PROG")) {
- cli->fd = sock_exec(getenv("LIBSMB_PROG"));
- } else {
- /* try 445 first, then 139 */
- uint16_t port = cli->port?cli->port:445;
- cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
- port, cli->timeout);
- if (cli->fd == -1 && cli->port == 0) {
- port = 139;
+ for (i = 0; i < num_addrs; i++) {
+ cli->dest_ss = ss_arr[i];
+ if (getenv("LIBSMB_PROG")) {
+ cli->fd = sock_exec(getenv("LIBSMB_PROG"));
+ } else {
+ /* try 445 first, then 139 */
+ uint16_t port = cli->port?cli->port:445;
cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
port, cli->timeout);
+ if (cli->fd == -1 && cli->port == 0) {
+ port = 139;
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ss,
+ port, cli->timeout);
+ }
+ if (cli->fd != -1) {
+ cli->port = port;
+ }
}
- if (cli->fd != -1) {
- cli->port = port;
+ if (cli->fd == -1) {
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
+ DEBUG(2,("Error connecting to %s (%s)\n",
+ dest_ss?addr:host,strerror(errno)));
+ } else {
+ /* Exit from loop on first connection. */
+ break;
}
}
+
if (cli->fd == -1) {
- char addr[INET6_ADDRSTRLEN];
- if (dest_ss) {
- print_sockaddr(addr, sizeof(addr), dest_ss);
- }
- DEBUG(1,("Error connecting to %s (%s)\n",
- dest_ss?addr:host,strerror(errno)));
+ TALLOC_FREE(frame);
return map_nt_error_from_unix(errno);
}
+ if (dest_ss) {
+ *dest_ss = cli->dest_ss;
+ }
+
set_socket_options(cli->fd, lp_socket_options());
+ TALLOC_FREE(frame);
return NT_STATUS_OK;
}
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 819147d48f..853fe979b7 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -1654,6 +1654,87 @@ bool resolve_name(const char *name,
}
/********************************************************
+ Internal interface to resolve a name into a list of IP addresses.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+*********************************************************/
+
+NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
+ const char *name,
+ int name_type,
+ struct sockaddr_storage **return_ss_arr,
+ unsigned int *p_num_entries)
+{
+ struct ip_service *ss_list = NULL;
+ char *sitename = NULL;
+ int count = 0;
+ int i;
+ unsigned int num_entries;
+ NTSTATUS status;
+
+ *p_num_entries = 0;
+ *return_ss_arr = NULL;
+
+ if (is_ipaddress(name)) {
+ *return_ss_arr = TALLOC_P(ctx, struct sockaddr_storage);
+ if (!*return_ss_arr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ if (!interpret_string_addr(*return_ss_arr, name, AI_NUMERICHOST)) {
+ TALLOC_FREE(*return_ss_arr);
+ return NT_STATUS_BAD_NETWORK_NAME;
+ }
+ *p_num_entries = 1;
+ return NT_STATUS_OK;
+ }
+
+ sitename = sitename_fetch(lp_realm()); /* wild guess */
+
+ status = internal_resolve_name(name, name_type, sitename,
+ &ss_list, &count,
+ lp_name_resolve_order());
+ SAFE_FREE(sitename);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* only return valid addresses for TCP connections */
+ for (i=0, num_entries = 0; i<count; i++) {
+ if (!is_zero_addr(&ss_list[i].ss) &&
+ !is_broadcast_addr(&ss_list[i].ss)) {
+ num_entries++;
+ }
+ }
+ if (num_entries == 0) {
+ SAFE_FREE(ss_list);
+ return NT_STATUS_BAD_NETWORK_NAME;
+ }
+
+ *return_ss_arr = TALLOC_ARRAY(ctx,
+ struct sockaddr_storage,
+ num_entries);
+ if (!(*return_ss_arr)) {
+ SAFE_FREE(ss_list);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0, num_entries = 0; i<count; i++) {
+ if (!is_zero_addr(&ss_list[i].ss) &&
+ !is_broadcast_addr(&ss_list[i].ss)) {
+ (*return_ss_arr)[num_entries++] = ss_list[i].ss;
+ }
+ }
+
+ status = NT_STATUS_OK;
+ *p_num_entries = num_entries;
+
+ SAFE_FREE(ss_list);
+ return NT_STATUS_OK;
+}
+
+/********************************************************
Find the IP address of the master browser or DMB for a workgroup.
*********************************************************/