diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | doc/assuan.texi | 7 | ||||
-rw-r--r-- | src/assuan-socket.c | 28 | ||||
-rw-r--r-- | tests/socks5.c | 34 |
4 files changed, 65 insertions, 7 deletions
@@ -4,6 +4,9 @@ Noteworthy changes in version 2.4.2 (unreleased) [C7/A7/R_] * The nPth version of the connect system hook does now wrap the call with npth_unprotec/npth_protect to avoid blocking during a connect. + * Add feature to assuan_sock_connect_byname to test for SOCKS5 + availability. + Noteworthy changes in version 2.4.1 (2015-11-23) [C7/A7/R1] ------------------------------------------------ diff --git a/doc/assuan.texi b/doc/assuan.texi index 131ffc1..aae3de7 100644 --- a/doc/assuan.texi +++ b/doc/assuan.texi @@ -1995,7 +1995,12 @@ current implementation requires that @var{flags} has either new TCP STREAM socket is returned; on error @code{ASSUAN_INVALID_FD} and ERRNO set. If @var{credentials} is not @code{NULL}, it is a string used for password based SOCKS authentication. Username and -password are separated by a colon. @var{reserved} should be 0. +password are separated by a colon. @var{reserved} should be 0. To +test whether the proxy is available @var{host} and @var{port} may be +given as NULL/0: If the proxy is available the function returns a +valid socket which is in the state after credentials sub-negotiation. +The caller now knows that the SOCKS proxy is available and has been +authenticated; normally the caller closes the socket then. @end deftypefun diff --git a/src/assuan-socket.c b/src/assuan-socket.c index bb0e610..d5e4ee4 100644 --- a/src/assuan-socket.c +++ b/src/assuan-socket.c @@ -814,6 +814,13 @@ socks5_connect (assuan_context_t ctx, assuan_fd_t sock, } } + if (hostname && !*hostname && !hostport) + { + /* Empty hostname given. Stop right here to allow the caller to + do the actual proxy request. */ + return 0; + } + /* Send request details (rfc-1928, 4). */ buffer[0] = 5; /* VER */ buffer[1] = 1; /* CMD = CONNECT */ @@ -1059,11 +1066,13 @@ _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd, /* Connect to HOST specified as host name on PORT. The current implementation requires that either the flags ASSUAN_SOCK_SOCKS or - ASSUAN_SOCK_TOR are give in FLAGS. On success a new socket is + ASSUAN_SOCK_TOR are given in FLAGS. On success a new socket is returned; on error ASSUAN_INVALID_FD is returned and ERRNO set. If CREDENTIALS is not NULL, it is a string used for password based - authentication. Username and password are separated by a - colon. RESERVED must be 0. */ + authentication. Username and password are separated by a colon. + RESERVED must be 0. By passing HOST and PORT as 0 the function can + be used to check for proxy availability: If the proxy is available + a socket will be returned which the caller should then close. */ assuan_fd_t _assuan_sock_connect_byname (assuan_context_t ctx, const char *host, unsigned short port, int reserved, @@ -1082,12 +1091,23 @@ _assuan_sock_connect_byname (assuan_context_t ctx, const char *host, return ASSUAN_INVALID_FD; } + if (host && !*host) + { + /* Error out early on an empty host name. See below. */ + gpg_err_set_errno (EINVAL); + return ASSUAN_INVALID_FD; + } + fd = _assuan_sock_new (ctx, AF_INET, SOCK_STREAM, 0); if (fd == ASSUAN_INVALID_FD) return fd; + /* For HOST being NULL we pass an empty string which indicates to + socks5_connect to stop midway during the proxy negotiation. Note + that we can't pass NULL directly as this indicates IP address + mode to the called function. */ if (socks5_connect (ctx, fd, socksport, - credentials, host, port, NULL, 0)) + credentials, host? host:"", port, NULL, 0)) { int save_errno = errno; assuan_sock_close (fd); diff --git a/tests/socks5.c b/tests/socks5.c index 7ab0438..b3754b8 100644 --- a/tests/socks5.c +++ b/tests/socks5.c @@ -53,6 +53,7 @@ main (int argc, char **argv) int only_v6 = 0; int only_v4 = 0; int use_tor = 0; + int opt_have_proxy = 0; int disable_socks = 0; int opt_byname = 0; const char *user = NULL; @@ -87,6 +88,7 @@ main (int argc, char **argv) " --inet6-only Use only IPv6\n" " --inet4-only Use only IPv4\n" " --disable-socks Connect w/o SOCKS\n" + " --have-proxy Check whether the proxy is available\n" " --byname Use assuan_sock_connect_byname\n" " --user STRING Use STRING as user for authentication\n" " --pass STRING Use STRING as password for authentication\n" @@ -128,6 +130,11 @@ main (int argc, char **argv) opt_byname = 1; argc--; argv++; } + else if (!strcmp (*argv, "--have-proxy")) + { + opt_have_proxy = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--user")) { argc--; argv++; @@ -153,7 +160,7 @@ main (int argc, char **argv) } } - if (argc != 2) + if (argc != 2 && !opt_have_proxy) { fputs ("usage: socks5 HOST PORT\n", stderr); exit (1); @@ -175,7 +182,30 @@ main (int argc, char **argv) use_tor? "TOR": "SOCKS", gpg_strerror (err)); } - if (opt_byname) + if (opt_have_proxy) + { + char *cred; + + if (user || pass) + cred = xstrconcat (user?user:"", ":", pass, NULL); + else + cred = NULL; + + sock = assuan_sock_connect_byname + (NULL, 0, 0, cred, use_tor? ASSUAN_SOCK_TOR : ASSUAN_SOCK_SOCKS); + if (sock == ASSUAN_INVALID_FD) + { + err = gpg_error_from_syserror (); + log_error ("SOCKS proxy is not available (%s)\n", gpg_strerror (err)); + exit (1); + } + xfree (cred); + assuan_sock_close (sock); + if (verbose) + log_info ("SOCKS proxy available\n"); + exit (0); + } + else if (opt_byname) { unsigned short port; char *cred; |