Added option http-version

This commit is contained in:
Gerhard Rieger 2023-06-17 21:30:37 +02:00
parent 9f632ec651
commit 454a499401
9 changed files with 116 additions and 22 deletions

View file

@ -20,6 +20,11 @@ Features:
Added option ipv6-join-source-group. Added option ipv6-join-source-group.
Thanks to Martin Buck and David Schweizer for sending patches. Thanks to Martin Buck and David Schweizer for sending patches.
Added option http-version to PROXY-CONNECT address to support servers
that are not able to handle HTTP version 1.0
Test: PROXY_HTTPVERSION
Feature inspired by Robin Palotai.
Corrections: Corrections:
When a sub process (EXEC, SYSTEM) terminated with exit code other than When a sub process (EXEC, SYSTEM) terminated with exit code other than
0, its last sent data might have been lost depending on timing of read/ 0, its last sent data might have been lost depending on timing of read/

View file

@ -2421,6 +2421,10 @@ Options that can be provided with HTTP type addresses. The only HTTP address
currently implemented is link(proxy-connect)(ADDRESS_PROXY_CONNECT). currently implemented is link(proxy-connect)(ADDRESS_PROXY_CONNECT).
startdit() startdit()
label(OPTION_HTTP_VERSION)dit(bf(tt(http-version=<string>)))
Changes the default "1.0" that is sent to the server in the initial HTTP
request. Currently it has not other effect, in particular it does not
provide any means to send a Host header.
label(OPTION_PROXYPORT)dit(bf(tt(proxyport=<TCP service>))) label(OPTION_PROXYPORT)dit(bf(tt(proxyport=<TCP service>)))
Overrides the default HTTP proxy port 8080 with Overrides the default HTTP proxy port 8080 with
link(<TCP service>)(TYPE_TCP_SERVICE). link(<TCP service>)(TYPE_TCP_SERVICE).

View file

@ -7,8 +7,8 @@
# accepts and answers correct HTTP CONNECT requests on stdio, and tries to # accepts and answers correct HTTP CONNECT requests on stdio, and tries to
# establish the connection to the given server. # establish the connection to the given server.
# it is required for socats test.sh # it is required for socats test.sh
# for TCP, use this script as: # for TCP, use this script like:
# socat tcp-l:8080,reuseaddr,fork exec:"proxy.sh",nofork # socat TCP-L:8080,reuseaddr,fork EXEC:"proxy.sh",nofork
# 20130622 GR allow hostnames, not only IP addresses # 20130622 GR allow hostnames, not only IP addresses

View file

@ -7,7 +7,9 @@
# accepts and answers correct HTTP CONNECT requests, but then just echoes data. # accepts and answers correct HTTP CONNECT requests, but then just echoes data.
# it is required for test.sh # it is required for test.sh
# for TCP, use this script as: # for TCP, use this script as:
# socat tcp-l:8080,reuseaddr,crlf system:"proxyecho.sh" # socat TCP-L:8080,reuseaddr,crlf SYSTEM:"proxyecho.sh"
# 20230423 GR Added option -V to require particular HTTP version
if type socat >/dev/null 2>&1; then if type socat >/dev/null 2>&1; then
SOCAT=socat SOCAT=socat
@ -24,11 +26,12 @@ HP-UX|OSF1)
;; ;;
esac esac
SPACES=" " SPACES=" " REQVER=1.0
while [ -n "$1" ]; do while [ -n "$1" ]; do
case "$1" in case "$1" in
-w) n="$2"; while [ "$n" -gt 0 ]; do SPACES="$SPACES "; n=$((n-1)); done -w) n="$2"; while [ "$n" -gt 0 ]; do SPACES="$SPACES "; n=$((n-1)); done
shift ;; shift ;;
-V) shift; REQVER="$1" ;;
#-s) STAT="$2"; shift ;; #-s) STAT="$2"; shift ;;
esac esac
shift shift
@ -36,14 +39,18 @@ done
# read and parse HTTP request # read and parse HTTP request
read l read l
if echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/1.[01]$' >/dev/null if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/[1-3].[0-9]$' >/dev/null
then then
: go on below
else
echo "HTTP/1.0${SPACES}500 Bad Request" echo "HTTP/1.0${SPACES}500 Bad Request"
echo echo
exit exit
fi fi
if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/'"$REQVER"'$' >/dev/null
then
echo "HTTP/1.0${SPACES}426 Upgrade Required"
echo
exit
fi
# read more headers until empty line # read more headers until empty line
while [ -n "$l" ]; do while [ -n "$l" ]; do
@ -51,7 +58,7 @@ while [ -n "$l" ]; do
done done
# send status # send status
echo "HTTP/1.0${SPACES}200 OK" echo "HTTP/$REQVER${SPACES}200 OK"
# send empty line # send empty line
echo echo

89
test.sh
View file

@ -4128,26 +4128,30 @@ te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
newport tcp4 # provide free port number in $PORT newport tcp4 # provide free port number in $PORT
#CMD2="$TRACE $SOCAT $opts tcp-l:$PORT,crlf SYSTEM:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" #CMD2="$TRACE $SOCAT $opts TCP-L:$PORT,crlf SYSTEM:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\""
CMD2="$TRACE $SOCAT $opts tcp4-l:$PORT,reuseaddr,crlf exec:\"/usr/bin/env bash proxyecho.sh -w 2\"" CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,reuseaddr,crlf EXEC:\"/usr/bin/env bash proxyecho.sh -w 2\""
CMD="$TRACE $SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT" CMD1="$TRACE $SOCAT $opts - PROXY:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &" eval "$CMD0 2>\"${te}1\" &"
pid=$! # background process id pid=$! # background process id
waittcp4port $PORT 1 waittcp4port $PORT 1
echo "$da" |$CMD >"$tf" 2>"${te}2" echo "$da" |$CMD1 >"$tf" 2>"${te}0"
if ! echo "$da" |diff - "$tf" >"$tdiff"; then if ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n" $PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD2 &" echo "$CMD0 &"
echo "$CMD" cat "${te}0" >&2
cat "${te}1" echo "$CMD1"
cat "${te}2" cat "${te}1" >&2
echo "diff:"
cat "$tdiff" cat "$tdiff"
numFAIL=$((numFAIL+1)) numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N" listFAIL="$listFAIL $N"
else else
$PRINTF "$OK\n" $PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
if [ "$debug" ]; then cat "${te}0" >&2; fi
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
if [ "$debug" ]; then cat "${te}1" >&2; fi
numOK=$((numOK+1)) numOK=$((numOK+1))
fi fi
kill $pid 2>/dev/null kill $pid 2>/dev/null
@ -15153,6 +15157,71 @@ fi # NUMCOND
esac esac
N=$((N+1)) N=$((N+1))
# Test the http-version of the PROXY-CONNECT address
NAME=PROXY_HTTPVERSION
case "$TESTS" in
*%$N%*|*%functions%*|*%proxy%*|*%$NAME%*)
TEST="$NAME: PROXY-CONNECT with option http-version"
if ! eval $NUMCOND; then :;
elif ! $(type proxyecho.sh >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}proxyecho.sh not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! F=$(testfeats IP4 TCP LISTEN EXEC STDIO PROXY); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! A=$(testaddrs TCP4-LISTEN EXEC STDIO PROXY-CONNECT); then
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! o=$(testoptions so-reuseaddr crlf pf proxyport http-version) >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! runsip4 >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
ts="$td/test$N.sh"
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="$TRACE $SOCAT $opts TCP4-L:$PORT,reuseaddr,crlf EXEC:\"/usr/bin/env bash proxyecho.sh -V 1.1\""
CMD1="$TRACE $SOCAT $opts - PROXY:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT,http-version=1.1"
printf "test $F_n $TEST... " $N
eval "$CMD0 2>\"${te}1\" &"
pid=$! # background process id
waittcp4port $PORT 1
echo "$da" |$CMD1 >"$tf" 2>"${te}0"
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD0 &" >&2
cat "${te}0"
echo "$CMD1" >&2
cat "${te}1"
echo "diff:"
cat "$tdiff"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
else
$PRINTF "$OK\n"
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
if [ "$debug" ]; then cat "${te}0" >&2; fi
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
if [ "$debug" ]; then cat "${te}1" >&2; fi
numOK=$((numOK+1))
fi
kill $pid 2>/dev/null
wait
fi ;; # NUMCOND, feats
esac
PORT=$((PORT+1))
# end of common tests # end of common tests
################################################################################## ##################################################################################

View file

@ -27,6 +27,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
const struct optdesc opt_proxyport = { "proxyport", NULL, OPT_PROXYPORT, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_proxyport = { "proxyport", NULL, OPT_PROXYPORT, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
const struct optdesc opt_http_version = { "http-version", NULL, OPT_HTTP_VERSION, GROUP_HTTP, PH_LATE, TYPE_STRING, 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_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 = { "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 optdesc opt_proxy_authorization_file = { "proxy-authorization-file", "proxyauthfile", OPT_PROXY_AUTHORIZATION_FILE, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
@ -239,6 +240,7 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr); retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr);
retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve); retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve);
retropt_string(opts, OPT_HTTP_VERSION, &proxyvars->version);
retropt_string(opts, OPT_PROXY_AUTHORIZATION, &proxyvars->authstring); retropt_string(opts, OPT_PROXY_AUTHORIZATION, &proxyvars->authstring);
retropt_string(opts, OPT_PROXY_AUTHORIZATION_FILE, &proxyvars->authfile); retropt_string(opts, OPT_PROXY_AUTHORIZATION_FILE, &proxyvars->authfile);
@ -331,8 +333,11 @@ int _xioopen_proxy_connect(struct single *xfd,
ssize_t sresult; ssize_t sresult;
/* generate proxy request header - points to final target */ /* generate proxy request header - points to final target */
rv = snprintf(request, CONNLEN, "CONNECT %s:%u HTTP/1.0\r\n", if (proxyvars->version == NULL) {
proxyvars->targetaddr, proxyvars->targetport); proxyvars->version = "1.0";
}
rv = snprintf(request, CONNLEN, "CONNECT %s:%u HTTP/%s\r\n",
proxyvars->targetaddr, proxyvars->targetport, proxyvars->version);
if (rv >= CONNLEN || rv < 0) { if (rv >= CONNLEN || rv < 0) {
Error("_xioopen_proxy_connect(): PROXY CONNECT buffer too small"); Error("_xioopen_proxy_connect(): PROXY CONNECT buffer too small");
return -1; return -1;

View file

@ -8,6 +8,7 @@
struct proxyvars { struct proxyvars {
bool ignorecr; bool ignorecr;
char *version;
bool doresolve; bool doresolve;
char *authstring; char *authstring;
char *authfile; char *authfile;
@ -17,6 +18,7 @@ struct proxyvars {
extern const struct optdesc opt_proxyport; extern const struct optdesc opt_proxyport;
extern const struct optdesc opt_ignorecr; extern const struct optdesc opt_ignorecr;
extern const struct optdesc opt_http_version;
extern const struct optdesc opt_proxy_resolve; extern const struct optdesc opt_proxy_resolve;
extern const struct optdesc opt_proxy_authorization; extern const struct optdesc opt_proxy_authorization;
extern const struct optdesc opt_proxy_authorization_file; extern const struct optdesc opt_proxy_authorization_file;

View file

@ -613,6 +613,7 @@ const struct optname optionnames[] = {
#if WITH_LIBWRAP && defined(HAVE_HOSTS_DENY_TABLE) #if WITH_LIBWRAP && defined(HAVE_HOSTS_DENY_TABLE)
IF_IPAPP ("hosts-deny", &opt_tcpwrap_hosts_deny_table) IF_IPAPP ("hosts-deny", &opt_tcpwrap_hosts_deny_table)
#endif #endif
IF_PROXY ("http-version", &opt_http_version)
IF_TERMIOS("hup", &opt_hupcl) IF_TERMIOS("hup", &opt_hupcl)
IF_TERMIOS("hupcl", &opt_hupcl) IF_TERMIOS("hupcl", &opt_hupcl)
#ifdef I_POP #ifdef I_POP

View file

@ -337,6 +337,7 @@ enum e_optcode {
OPT_GROUP_EARLY, OPT_GROUP_EARLY,
OPT_GROUP_LATE, OPT_GROUP_LATE,
OPT_HISTORY_FILE, /* readline history file */ OPT_HISTORY_FILE, /* readline history file */
OPT_HTTP_VERSION,
OPT_HUPCL, /* termios.c_cflag */ OPT_HUPCL, /* termios.c_cflag */
OPT_ICANON, /* termios.c_lflag */ OPT_ICANON, /* termios.c_lflag */
OPT_ICRNL, /* termios.c_iflag */ OPT_ICRNL, /* termios.c_iflag */