diff --git a/CHANGES b/CHANGES index 11e2c32..0fc1d95 100644 --- a/CHANGES +++ b/CHANGES @@ -164,6 +164,12 @@ New features: Test: UDP_DATAGRAM_SOURCEPORT Feature inspired by Hans Bueckler for SSDP inquiry (for UPnP) + New option proxy-authorization-file reads PROXY-CONNECT credentials + from file and makes it possible to hide this data from the process + table. + Test: PROXYAUTHFILE + Thanks to Charles Stephens for sending an initial patch. + ####################### V 1.7.3.4: Corrections: diff --git a/doc/socat.yo b/doc/socat.yo index e906839..5bbab58 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -2343,13 +2343,17 @@ label(OPTION_IGNORECR)dit(bf(tt(ignorecr))) server violates this standard, socat might not understand its answer. This option directs socat to interprete NL as line terminator and to ignore CR in the answer. Nevertheless, socat sends CR+NL to the proxy. -label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxyauth=:))) +label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxy-authorization=:))) Provide "basic" authentication to the proxy server. The argument to the - option is used with a "Proxy-Authorization: Base" header in base64 encoded + option is used with a "Proxy-Authorization: Basic" header in base64 encoded form.nl() Note: username and password are visible for every user on the local machine in the process list; username and password are transferred to the proxy server unencrypted (base64 encoded) and might be sniffed. +label(OPTION_PROXY_AUTHORIZATION_FILE)dit(bf(tt(proxy-authorization-file=))) + Like option link(proxy-authorization)(OPTION_PROXY_AUTHORIZATION), but the + credentials are read from the file and therefore not visible in the process + list.nl() label(OPTION_PROXY_RESOLVE)dit(bf(tt(resolve))) Per default, socat sends to the proxy a CONNECT request containing the target hostname. With this option, socat resolves the hostname locally and diff --git a/test.sh b/test.sh index 25affe9..9cfa9e3 100755 --- a/test.sh +++ b/test.sh @@ -14521,6 +14521,73 @@ PORT=$((PORT+1)) N=$((N+1)) +# Test the proxy-authorization-file option +NAME=PROXYAUTHFILE +case "$TESTS" in +*%$N%*|*%functions%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: proxy-authorization-file option" +if ! eval $NUMCOND; then :; +elif ! testfeats proxy >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! testoptions proxy-authorization-file >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}Option proxy-authorization-file not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +else +ta="$td/test$N.auth" +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" +CMD0="{ echo -e \"HTTP/1.0 200 OK\\n\"; sleep 2; } |$TRACE $SOCAT $opts - TCP4-L:$PORT,$REUSEADDR,crlf" +CMD1="$TRACE $SOCAT $opts FILE:/dev/null PROXY-CONNECT:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT,proxy-authorization-file=$ta" +printf "test $F_n $TEST... " $N +echo "user:s3cr3t" >$ta +eval "$CMD0 >${tf}0 2>${te}0 &" +pid0=$! # background process id +waittcp4port $PORT 1 +$CMD1 >"${tf}1" 2>"${te}1" +rc1=$? +kill $pid0 2>/dev/null +wait $pid0 +if [ $rc1 -ne 0 ]; then + $PRINTF "$FAILED\n" + echo "$CMD0 &" >&2 + cat "${te}0" >&2 + echo "$CMD1" >&2 + cat "${te}1" >&2 + cat "${tf}0" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +elif ! grep -q '^Proxy-authorization: Basic dXNlcjpzM2NyM3QK$' ${tf}0; then + $PRINTF "$FAILED:\n" + echo "$CMD0 &" >&2 + cat "${te}0" >&2 + echo "$CMD1" >&2 + cat "${te}1" >&2 + cat "${tf}0" >&2 + echo "Authorization string not in client request" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + numOK=$((numOK+1)) +fi +kill $pid 2>/dev/null +wait +fi ;; # NUMCOND, feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + ################################################################################## #================================================================================= # here come tests that might affect your systems integrity. Put normal tests diff --git a/xio-proxy.c b/xio-proxy.c index 6e780a6..67a9d8c 100644 --- a/xio-proxy.c +++ b/xio-proxy.c @@ -29,6 +29,7 @@ const struct optdesc opt_proxyport = { "proxyport", NULL, OPT_PROXYPORT, GROUP_H const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_proxy_resolve = { "proxy-resolve", "resolve", OPT_PROXY_RESOLVE, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_proxy_authorization = { "proxy-authorization", "proxyauth", OPT_PROXY_AUTHORIZATION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_proxy_authorization_file = { "proxy-authorization-file", "proxyauthfile", OPT_PROXY_AUTHORIZATION_FILE, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC }; const struct addrdesc addr_proxy_connect = { "proxy", 3, xioopen_proxy_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_HTTP|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":::") }; @@ -239,6 +240,50 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr); retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve); retropt_string(opts, OPT_PROXY_AUTHORIZATION, &proxyvars->authstring); + retropt_string(opts, OPT_PROXY_AUTHORIZATION_FILE, &proxyvars->authfile); + + if (proxyvars->authfile) { + int authfd; + off_t length; + ssize_t bytes; + + /* if we have a file containing authentication credentials and they were also + provided on the command line, something is misspecified */ + if (proxyvars->authstring) { + Error("Only one of options proxy-authorization and proxy-authorization-file allowed"); + return STAT_NORETRY; + } + authfd = Open(proxyvars->authfile, O_RDONLY, 0); + if (authfd < 0) { + Error2("open(\"%s\", O_RDONLY): %s", proxyvars->authfile, strerror(errno)); + return STAT_NORETRY; + } + /* go to the end of our proxy auth file to + figure out how long our proxy auth is */ + if ((length = Lseek(authfd, 0, SEEK_END)) < 0) { + Error2("lseek(<%s>, 0, SEEK_END): %s", + proxyvars->authfile, strerror(errno)); + return STAT_RETRYLATER; + } + proxyvars->authstring = Malloc(length+1); + /* go back to the beginning */ + Lseek(authfd, 0, SEEK_SET); + /* read our proxy info from the file */ + if ((bytes = Read(authfd, proxyvars->authstring, (size_t) length)) < 0) { + Error3("read(<%s>, , "F_Zu"): %s", proxyvars->authfile, length, strerror(errno)); + free(proxyvars->authstring); + Close(authfd); + return STAT_NORETRY; + } + if (bytes < length) { + Error3("read(<%s>, , "F_Zu"): got only "F_Zu" bytes", + proxyvars->authfile, length, bytes); + Close(authfd); + return STAT_NORETRY; + } + proxyvars->authstring[bytes] = '\0'; /* string termination */ + Close(authfd); + } if (proxyvars->doresolve) { /* currently we only resolve to IPv4 addresses. This is in accordance to diff --git a/xio-proxy.h b/xio-proxy.h index 85729aa..be68ccb 100644 --- a/xio-proxy.h +++ b/xio-proxy.h @@ -10,6 +10,7 @@ struct proxyvars { bool ignorecr; bool doresolve; char *authstring; + char *authfile; char *targetaddr; /* name/address of host, in malloced string */ uint16_t targetport; } ; @@ -18,6 +19,7 @@ extern const struct optdesc opt_proxyport; extern const struct optdesc opt_ignorecr; extern const struct optdesc opt_proxy_resolve; extern const struct optdesc opt_proxy_authorization; +extern const struct optdesc opt_proxy_authorization_file; extern const struct addrdesc addr_proxy_connect; diff --git a/xioopts.c b/xioopts.c index d3c7748..7e41d1e 100644 --- a/xioopts.c +++ b/xioopts.c @@ -1254,8 +1254,10 @@ const struct optname optionnames[] = { #endif IF_PROXY ("proxy-auth", &opt_proxy_authorization) IF_PROXY ("proxy-authorization", &opt_proxy_authorization) + IF_PROXY ("proxy-authorization-file", &opt_proxy_authorization_file) IF_PROXY ("proxy-resolve", &opt_proxy_resolve) IF_PROXY ("proxyauth", &opt_proxy_authorization) + IF_PROXY ("proxyauthfile", &opt_proxy_authorization_file) IF_PROXY ("proxyport", &opt_proxyport) #ifdef ECHOPRT IF_TERMIOS("prterase", &opt_echoprt) diff --git a/xioopts.h b/xioopts.h index 9b4d573..425960f 100644 --- a/xioopts.h +++ b/xioopts.h @@ -573,6 +573,7 @@ enum e_optcode { OPT_PROTOCOL_FAMILY, /* 1=PF_UNIX, 2=PF_INET, 10=PF_INET6 */ OPT_PROXYPORT, OPT_PROXY_AUTHORIZATION, + OPT_PROXY_AUTHORIZATION_FILE, OPT_PROXY_RESOLVE, #if HAVE_DEV_PTMX || HAVE_DEV_PTC OPT_PTMX,