From d1b809b4aba3ce349c3e76d3d5a6bcc27bbfbc56 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Wed, 30 Dec 2020 19:46:42 +0100 Subject: [PATCH] DTLS over UDP --- CHANGES | 9 +++ compat.h | 2 +- config.h.in | 8 +++ configure.ac | 4 ++ doc/socat.yo | 69 ++++++++++++++++++++- sslcls.c | 60 ++++++++++++++++++ sslcls.h | 12 ++++ sycls.c | 10 ++- test.sh | 149 ++++++++++++++++++++++++++++++++++++++++++++- xio-openssl.c | 110 +++++++++++++++++++++++++-------- xio-openssl.h | 8 ++- xio-udp.c | 193 ++++++++++++++++++++++++++++++++-------------------------- xio-udp.h | 4 ++ xioopen.c | 25 ++++++-- 14 files changed, 537 insertions(+), 126 deletions(-) diff --git a/CHANGES b/CHANGES index 781ac09..3f02506 100644 --- a/CHANGES +++ b/CHANGES @@ -50,6 +50,15 @@ Corrections: address if you want to avoid data loss. Thanks to Chunmei Xu for reporting this issue and proving the patch. + Socats DTLS implementation has been reworked and appears to work now + reasonably over UDP. + New addresses: OPENSSL-DTLS-SERVER (DTLS-L), + OPENSSL-DTLS-CLIENT (DTLS) + Tests: OPENSSL_DTLS_CLIENT OPENSSL_DTLS_SERVER + OPENSSL_METHOD_DTLS1 OPENSSL_METHOD_DTLS1.2 + Thanks to Brandon Carpenter, Qing Wan, and Pavel Nakonechnyi for + sending patches. + Porting: In gcc version 10 the default changed from -fcommon to -fno-common. Consequently, linking filan and procan failed with error diff --git a/compat.h b/compat.h index 963f87f..99a78ae 100644 --- a/compat.h +++ b/compat.h @@ -681,7 +681,7 @@ typedef int sig_atomic_t; #endif /* sigset_t printing - not an exact solution yet */ -#define F_sigset "0x%4lx" +#define F_sigset "0x%06lx" typedef unsigned long T_sigset; /* default: socklen_t */ diff --git a/config.h.in b/config.h.in index d77f86f..c4fb579 100644 --- a/config.h.in +++ b/config.h.in @@ -466,6 +466,10 @@ #undef HAVE_TLSv1_2_client_method #undef HAVE_TLSv1_2_server_method +/* Define if you have the DTLS client and server method functions */ +#undef HAVE_DTLS_client_method +#undef HAVE_DTLS_server_method + /* Define if you have the DTLSv1 client and server method functions */ #undef HAVE_DTLSv1_client_method #undef HAVE_DTLSv1_server_method @@ -476,6 +480,10 @@ /* Define if you have the SSL_CTX_set_max_proto_version function/macro */ #undef HAVE_SSL_CTX_set_max_proto_version +/* Define if you have the DTLSv1_2 client and server method functions */ +#undef HAVE_DTLSv1_2_client_method +#undef HAVE_DTLSv1_2_server_method + /* Define if you have the EC_KEY type */ #undef HAVE_TYPE_EC_KEY diff --git a/configure.ac b/configure.ac index 5233248..8e3045e 100644 --- a/configure.ac +++ b/configure.ac @@ -1454,6 +1454,8 @@ AC_CHECK_FUNC(SSL_CTX_set_min_proto_version, AC_DEFINE(HAVE_SSL_CTX_set_min_prot AC_CHECK_FUNC(SSL_CTX_set_max_proto_version, AC_DEFINE(HAVE_SSL_CTX_set_max_proto_version)) AC_CHECK_FUNC(TLS_client_method, AC_DEFINE(HAVE_TLS_client_method) ac_cv_have_tls_client_method=yes, AC_CHECK_LIB(crypt, TLS_client_method, [LIBS=-lcrypt $LIBS])) AC_CHECK_FUNC(TLS_server_method, AC_DEFINE(HAVE_TLS_server_method) ac_cv_have_tls_server_method=yes, AC_CHECK_LIB(crypt, TLS_server_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(DTLS_client_method, AC_DEFINE(HAVE_DTLS_client_method), AC_CHECK_LIB(crypt, DTLS_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(DTLS_server_method, AC_DEFINE(HAVE_DTLS_server_method), AC_CHECK_LIB(crypt, DTLS_server_method, [LIBS=-lcrypt $LIBS])) if test -n "$WITH_OPENSSL_METHOD" -o -z "$ac_cv_have_tls_client_method" -o -z "$ac_cv_have_tls_server_method" ; then dnl Search for SSLv2_client_method, SSLv2_server_method AC_CHECK_FUNC(SSLv2_client_method, AC_DEFINE(HAVE_SSLv2_client_method), AC_CHECK_LIB(crypt, SSLv2_client_method, [LIBS=-lcrypt $LIBS])) @@ -1471,6 +1473,8 @@ AC_CHECK_FUNC(TLSv1_2_client_method, AC_DEFINE(HAVE_TLSv1_2_client_method), AC_C AC_CHECK_FUNC(TLSv1_2_server_method, AC_DEFINE(HAVE_TLSv1_2_server_method), AC_CHECK_LIB(crypt, TLSv1_2_server_method, [LIBS=-lcrypt $LIBS])) AC_CHECK_FUNC(DTLSv1_client_method, AC_DEFINE(HAVE_DTLSv1_client_method), AC_CHECK_LIB(crypt, DTLSv1_client_method, [LIBS=-lcrypt $LIBS])) AC_CHECK_FUNC(DTLSv1_server_method, AC_DEFINE(HAVE_DTLSv1_server_method), AC_CHECK_LIB(crypt, DTLSv1_server_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(DTLSv1_2_client_method, AC_DEFINE(HAVE_DTLSv1_2_client_method), AC_CHECK_LIB(crypt, DTLSv1_2_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(DTLSv1_2_server_method, AC_DEFINE(HAVE_DTLSv1_2_server_method), AC_CHECK_LIB(crypt, DTLSv1_2_server_method, [LIBS=-lcrypt $LIBS])) fi # $WITH_OPENSSL_METHOD AC_CHECK_FUNC(SSL_CTX_set_default_verify_paths, AC_DEFINE(HAVE_SSL_CTX_set_default_verify_paths)) diff --git a/doc/socat.yo b/doc/socat.yo index 391b010..88508f4 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -487,6 +487,7 @@ label(ADDRESS_OPEN)dit(bf(tt(OPEN:))) link(CREATE)(ADDRESS_CREAT), link(GOPEN)(ADDRESS_GOPEN), link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT) + label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL::))) Tries to establish a SSL connection to [link(TCP service)(TYPE_TCP_SERVICE)] on @@ -502,7 +503,7 @@ label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL::))) parameter or the value of the link(openssl-commonname)(OPTION_OPENSSL_COMMONNAME) option. Socat tries to match it against the certificates subject commonName, - and the certifications extension subjectAltName DNS names. Wildcards in the + and the certificates extension subjectAltName DNS names. Wildcards in the certificate are supported.nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(OPENSSL)(GROUP_OPENSSL),link(RETRY)(GROUP_RETRY) nl() Useful options: @@ -522,6 +523,7 @@ label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL::))) See also: link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN), link(TCP)(ADDRESS_TCP_CONNECT) + label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:))) Listens on tcp [link(TCP service)(TYPE_TCP_SERVICE)]. The IP version is 4 or the one specified with @@ -552,6 +554,71 @@ label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:))) See also: link(OPENSSL)(ADDRESS_OPENSSL_CONNECT), link(TCP-LISTEN)(ADDRESS_TCP_LISTEN) + +label(ADDRESS_OPENSSL_DTLS_CLIENT)dit(bf(tt(OPENSSL-DTLS-CLIENT::))) + Tries to establish a DTLS connection to [link(UDP + service)(TYPE_UDP_SERVICE)] on + [link(IP address)(TYPE_IP_ADDRESS)] using UDP/IP version 4 or 6 + depending on address specification, name resolution, or option + link(pf)(OPTION_PROTOCOL_FAMILY).nl() + Socat() checks the peer certificates subjectAltName or commonName against the addresses + option link(openssl-commonname)(OPTION_OPENSSL_COMMONNAME) or the host name. + Wildcards in the certificate are supported.nl() + Use socat() option link(-b)(option_b) to make datagrams small enough to fit with overhead + on the network. Use option link(-T)(option_T) to prevent indefinite hanging when peer went down quietly.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),COMMENT(link(UDP)(GROUP_UDP),)link(OPENSSL)(GROUP_OPENSSL),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(cipher)(OPTION_OPENSSL_CIPHERLIST), + link(verify)(OPTION_OPENSSL_VERIFY), + link(commonname)(OPTION_OPENSSL_COMMONNAME), + link(cafile)(OPTION_OPENSSL_CAFILE), + link(capath)(OPTION_OPENSSL_CAPATH), + link(certificate)(OPTION_OPENSSL_CERTIFICATE), + link(key)(OPTION_OPENSSL_KEY), + link(compress)(OPTION_OPENSSL_COMPRESS), + link(bind)(OPTION_BIND), + link(pf)(OPTION_PROTOCOL_FAMILY), + link(sourceport)(OPTION_SOURCEPORT), + link(retry)(OPTION_RETRY)nl() + See also: + link(OPENSSL-DTLS-SERVER)(ADDRESS_OPENSSL_DTLS_SERVER), + link(OPENSSL-CONNECT)(ADDRESS_OPENSSL_CONNECT), + link(UDP-CONNECT)(ADDRESS_UDP_CONNECT) + +label(ADDRESS_OPENSSL_DTLS_SERVER)dit(bf(tt(OPENSSL-DTLS-SERVER:))) + Listens on UDP [link(UDP service)(TYPE_UDP_SERVICE)]. + The IP version is 4 or the one specified with + link(pf)(OPTION_PROTOCOL_FAMILY). When a + connection is accepted, this address behaves as DTLS server.nl() + Note: You probably want to use the link(certificate)(OPTION_OPENSSL_CERTIFICATE) option with this address.nl() + NOTE: The client certificate is only checked for validity against + link(cafile)(OPTION_OPENSSL_CAFILE) or link(capath)(OPTION_OPENSSL_CAPATH), + but not for match with the client's name or its IP address! + Use socat() option link(-b)(option_b) to make datagrams small enough to fit with overhead on the network. + Use option link(-T)(option_T) to prevent indefinite hanging when peer went down quietly.nl() + Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),COMMENT(link(UDP)(GROUP_UDP),)link(LISTEN)(GROUP_LISTEN),link(OPENSSL)(GROUP_OPENSSL),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(RETRY)(GROUP_RETRY) nl() + Useful options: + link(pf)(OPTION_PROTOCOL_FAMILY), + link(cipher)(OPTION_OPENSSL_CIPHERLIST), + link(verify)(OPTION_OPENSSL_VERIFY), + link(commonname)(OPTION_OPENSSL_COMMONNAME), + link(cafile)(OPTION_OPENSSL_CAFILE), + link(capath)(OPTION_OPENSSL_CAPATH), + link(certificate)(OPTION_OPENSSL_CERTIFICATE), + link(key)(OPTION_OPENSSL_KEY), + link(compress)(OPTION_OPENSSL_COMPRESS), + link(fork)(OPTION_FORK), + link(bind)(OPTION_BIND), + link(range)(OPTION_RANGE), + link(tcpwrap)(OPTION_TCPWRAPPERS), + link(su)(OPTION_SUBSTUSER), + link(reuseaddr)(OPTION_REUSEADDR), + link(retry)(OPTION_RETRY)nl() + See also: + link(OPENSSL-DTLS-CLIENT)(ADDRESS_OPENSSL_DTLS_CLIENT), + link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN), + link(UDP-LISTEN)(ADDRESS_UDP_LISTEN) + label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:))) If link()(TYPE_FILENAME) already exists, it is opened. If it does not exist, a named pipe is created and opened. Beginning with diff --git a/sslcls.c b/sslcls.c index f9ce389..48943fe 100644 --- a/sslcls.c +++ b/sslcls.c @@ -35,6 +35,26 @@ int sycSSL_library_init(void) { return result; } +#if HAVE_TLS_client_method +const SSL_METHOD *sycTLS_client_method(void) { + const SSL_METHOD *result; + Debug("TLS_client_method()"); + result = TLS_client_method(); + Debug1("TLS_client_method() -> %p", result); + return result; +} +#endif + +#if HAVE_TLS_server_method +const SSL_METHOD *sycTLS_server_method(void) { + const SSL_METHOD *result; + Debug("TLS_server_method()"); + result = TLS_server_method(); + Debug1("TLS_server_method() -> %p", result); + return result; +} +#endif + #if HAVE_SSLv2_client_method const SSL_METHOD *sycSSLv2_client_method(void) { const SSL_METHOD *result; @@ -151,6 +171,26 @@ const SSL_METHOD *sycTLSv1_2_server_method(void) { } #endif +#if HAVE_DTLS_client_method +const SSL_METHOD *sycDTLS_client_method(void) { + const SSL_METHOD *result; + Debug("DTLS_client_method()"); + result = DTLS_client_method(); + Debug1("DTLS_client_method() -> %p", result); + return result; +} +#endif + +#if HAVE_DTLS_server_method +const SSL_METHOD *sycDTLS_server_method(void) { + const SSL_METHOD *result; + Debug("DTLS_server_method()"); + result = DTLS_server_method(); + Debug1("DTLS_server_method() -> %p", result); + return result; +} +#endif + #if HAVE_DTLSv1_client_method const SSL_METHOD *sycDTLSv1_client_method(void) { const SSL_METHOD *result; @@ -171,6 +211,26 @@ const SSL_METHOD *sycDTLSv1_server_method(void) { } #endif +#if HAVE_DTLSv1_2_client_method +const SSL_METHOD *sycDTLSv1_2_client_method(void) { + const SSL_METHOD *result; + Debug("DTLSv1_2_client_method()"); + result = DTLSv1_2_client_method(); + Debug1("DTLSv1_2_client_method() -> %p", result); + return result; +} +#endif + +#if HAVE_DTLSv1_2_server_method +const SSL_METHOD *sycDTLSv1_2_server_method(void) { + const SSL_METHOD *result; + Debug("DTLSv1_2_server_method()"); + result = DTLSv1_2_server_method(); + Debug1("DTLSv1_2_server_method() -> %p", result); + return result; +} +#endif + SSL_CTX *sycSSL_CTX_new(const SSL_METHOD *method) { SSL_CTX *result; Debug1("SSL_CTX_new(%p)", method); diff --git a/sslcls.h b/sslcls.h index 7c3e226..c4c2d7d 100644 --- a/sslcls.h +++ b/sslcls.h @@ -10,6 +10,8 @@ void sycSSL_load_error_strings(void); int sycSSL_library_init(void); +const SSL_METHOD *sycTLS_client_method(void); +const SSL_METHOD *sycTLS_server_method(void); const SSL_METHOD *sycSSLv2_client_method(void); const SSL_METHOD *sycSSLv2_server_method(void); const SSL_METHOD *sycSSLv3_client_method(void); @@ -22,8 +24,12 @@ const SSL_METHOD *sycTLSv1_1_client_method(void); const SSL_METHOD *sycTLSv1_1_server_method(void); const SSL_METHOD *sycTLSv1_2_client_method(void); const SSL_METHOD *sycTLSv1_2_server_method(void); +const SSL_METHOD *sycDTLS_client_method(void); +const SSL_METHOD *sycDTLS_server_method(void); const SSL_METHOD *sycDTLSv1_client_method(void); const SSL_METHOD *sycDTLSv1_server_method(void); +const SSL_METHOD *sycDTLSv1_2_client_method(void); +const SSL_METHOD *sycDTLSv1_2_server_method(void); SSL_CTX *sycSSL_CTX_new(const SSL_METHOD *method); SSL *sycSSL_new(SSL_CTX *ctx); int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, @@ -69,6 +75,8 @@ const char *sycSSL_COMP_get_name(const COMP_METHOD *comp); #define sycSSL_load_error_strings() SSL_load_error_strings() #define sycSSL_library_init() SSL_library_init() +#define sycTLS_client_method() TLS_client_method() +#define sycTLS_server_method() TLS_server_method() #define sycSSLv2_client_method() SSLv2_client_method() #define sycSSLv2_server_method() SSLv2_server_method() #define sycSSLv3_client_method() SSLv3_client_method() @@ -81,8 +89,12 @@ const char *sycSSL_COMP_get_name(const COMP_METHOD *comp); #define sycTLSv1_1_server_method() TLSv1_1_server_method() #define sycTLSv1_2_client_method() TLSv1_2_client_method() #define sycTLSv1_2_server_method() TLSv1_2_server_method() +#define sycDTLS_client_method() DTLS_client_method() +#define sycDTLS_server_method() DTLS_server_method() #define sycDTLSv1_client_method() DTLSv1_client_method() #define sycDTLSv1_server_method() DTLSv1_server_method() +#define sycDTLSv1_2_client_method() DTLSv1_2_client_method() +#define sycDTLSv1_2_server_method() DTLSv1_2_server_method() #define sycSSL_CTX_new(m) SSL_CTX_new(m) #define sycSSL_new(c) SSL_new(c) #define sycSSL_CTX_load_verify_locations(c,f,p) SSL_CTX_load_verify_locations(c,f,p) diff --git a/sycls.c b/sycls.c index e22f9fb..3eb1378 100644 --- a/sycls.c +++ b/sycls.c @@ -960,9 +960,15 @@ int Sigaction(int signum, const struct sigaction *act, int Sigprocmask(int how, const sigset_t *set, sigset_t *oset) { int retval; - Debug3("sigprocmask(%d, %p, %p)", how, set, oset); + if (set) + Debug3("sigprocmask(%d, "F_sigset", %p)", how, *(T_sigset *)set, oset); + else + Debug2("sigprocmask(%d, NULL, %p)", how, oset); retval = sigprocmask(how, set, oset); - Debug1("sigprocmask() -> %d", retval); + if (oset) + Debug2("sigprocmask() -> {,, "F_sigset"} %d", *(T_sigset *)oset, retval); + else + Debug1("sigprocmask() -> %d", retval); return retval; } diff --git a/test.sh b/test.sh index 541a1d9..434d912 100755 --- a/test.sh +++ b/test.sh @@ -12907,7 +12907,7 @@ N=$((N+1)) # tests of various SSL methods; from TLS1.3 this method is not avail in OpenSSL: OPENSSL_METHODS_OBSOLETE="SSL3 SSL23" -OPENSSL_METHODS_EXPECTED="TLS1 TLS1.1 TLS1.2 DTLS1" +OPENSSL_METHODS_EXPECTED="TLS1 TLS1.1 TLS1.2 DTLS1 DTLS1.2" # the OPENSSL_METHOD_DTLS1 test hangs sometimes, probably depending on the openssl version. OPENSSL_VERSION="$(openssl version)" @@ -13015,7 +13015,11 @@ if [ "$method" = DTLS1 -a "$(echo -e "$OPENSSL_VERSION\n1.0.2" |sort |tail -n 1) else $CMD0 >/dev/null 2>"${te}0" & pid0=$! -waittcp4port $PORT 1 +if [[ "$method" =~ DTLS* ]]; then + waitudp4port $PORT 1 +else + waittcp4port $PORT 1 +fi echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait @@ -13924,6 +13928,147 @@ esac N=$((N+1)) +# test the DTLS client feature +NAME=OPENSSL_DTLS_CLIENT +case "$TESTS" in +*%$N%*|*%functions%*|*%openssl%*|*%dtls%*|*%udp%*|*%udp4%*|*%ip4%*|*%$NAME%*) +TEST="$NAME: OpenSSL DTLS client" +# Run openssl s_server in DTLS mode, wrapped into a simple Socat echoing command. +# Start a Socat DTLS client, send data to server and check if reply is received. +if ! eval $NUMCOND; then :; +elif ! a=$(testfeats ip4 udp openssl); then + $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! a=$(testaddrs openssl-dtls-client); then + $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${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" +elif ! type openssl >/dev/null 2>&1; then + $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not found${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +else +gentestcert testsrv +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +#set -vx +da="test$N $(date) $RANDOM" +S_SERVER_4= +if openssl s_server -help 2>&1 | grep -q ' -4 '; then + S_SERVER_4="-4" +fi +if openssl s_server -help 2>&1 | grep -q ' -dtls '; then + S_SERVER_DTLS=-dtls +else + S_SERVER_DTLS=-dtls1 +fi +if openssl s_server -help 2>&1 | grep -q ' -no-ign_eof '; then + S_SERVER_NO_IGN_EOF=-no-ign_eof +else + S_SERVER_NO_IGN_EOF= +fi +CMD1="$TRACE openssl s_server $S_SERVER_4 $S_SERVER_DTLS -accept $PORT -quiet $S_SERVER_NO_IGN_EOF -cert testsrv.pem" +CMD="$TRACE $SOCAT $opts -T 1 - OPENSSL-DTLS-CLIENT:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" +printf "test $F_n $TEST... " $N +( sleep 2; echo "$da"; sleep 1 ) |$CMD1 2>"${te}1" & +pid1=$! # background process id +waitudp4port $PORT +$CMD >$tf 2>"$te" +kill $pid1 2>/dev/null; wait 2>/dev/null +if ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: $TRACE $SOCAT:\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +else + $PRINTF "$OK\n" + if [ -n "$debug" ]; then cat "${te}1" "$te"; fi + numOK=$((numOK+1)) +fi +fi ;; # NUMCOND, feats +esac +PORT=$((PORT+1)) +N=$((N+1)) +set +vx + +# test the DTLS server feature +NAME=OPENSSL_DTLS_SERVER +case "$TESTS" in +*%$N%*|*%functions%*|*%openssl%*|*%dtls%*|*%udp%*|*%udp4%*|*%ip4%*|*%socket%*|*%$NAME%*) +TEST="$NAME: OpenSSL DTLS server" +# Run a socat OpenSSL DTLS server with echo function +# Start an OpenSSL s_client, send data and check if repley is received. +if ! eval $NUMCOND; then :; +elif ! a=$(testfeats ip4 udp openssl) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! a=$(testaddrs openssl-dtls-server); then + $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${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" +elif ! type openssl >/dev/null 2>&1; then + $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not found${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif [[ $(openssl version |awk '{print($2);}') =~ 0.9.8[a-c] ]]; then + $PRINTF "test $F_n $TEST... ${YELLOW}openssl s_client might hang${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +else +gentestcert testsrv +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +if openssl s_server -help 2>&1 | grep -q ' -dtls '; then + S_SERVER_DTLS=-dtls +else + S_SERVER_DTLS=-dtls1 +fi +CMD1="$TRACE $SOCAT $opts OPENSSL-DTLS-SERVER:$PORT,$REUSEADDR,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" +CMD="openssl s_client -host $LOCALHOST -port $PORT $S_SERVER_DTLS" +printf "test $F_n $TEST... " $N +$CMD1 >/dev/null 2>"${te}1" & +pid1=$! +waitudp4port $PORT 1 +( echo "$da"; sleep 0.1 ) |$CMD 2>"$te" |grep "$da" >"$tf" +rc=$? +kill $pid1 2>/dev/null; wait +if echo "$da" |diff - $tf >"$tdiff"; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD1 &" + cat "${te}1" + echo "$CMD" + cat "$te" + cat "$tdiff" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +fi +fi # NUMCOND + ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + ################################################################################## #================================================================================= # here come tests that might affect your systems integrity. Put normal tests diff --git a/xio-openssl.c b/xio-openssl.c index 118f335..78369d7 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -14,6 +14,7 @@ #include "xio-fd.h" #include "xio-socket.h" /* _xioopen_connect() */ #include "xio-listen.h" +#include "xio-udp.h" #include "xio-ipapp.h" #include "xio-openssl.h" @@ -58,7 +59,7 @@ static int openssl_delete_cert_info(void); /* description record for ssl connect */ -const struct addrdesc addr_openssl = { +const struct addrdesc xioaddr_openssl = { "openssl", /* keyword for selecting this address type in xioopen calls (canonical or main name) */ 3, /* data flow directions this address supports on API layer: @@ -67,7 +68,7 @@ const struct addrdesc addr_openssl = { GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to. You might have to specify a new group in xioopts.h */ 0, /* an integer passed to xioopen_openssl; makes it possible to - use the same xioopen_openssl function for slightly different + use the xioopen_openssl_connect function for slightly different address types. */ 0, /* like previous argument */ 0 /* like previous arguments, but pointer type. @@ -79,7 +80,7 @@ const struct addrdesc addr_openssl = { #if WITH_LISTEN /* description record for ssl listen */ -const struct addrdesc addr_openssl_listen = { +const struct addrdesc xioaddr_openssl_listen = { "openssl-listen", /* keyword for selecting this address type in xioopen calls (canonical or main name) */ 3, /* data flow directions this address supports on API layer: @@ -88,7 +89,7 @@ const struct addrdesc addr_openssl_listen = { GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_OPENSSL|GROUP_RETRY, /* bitwise OR of address groups this address belongs to. You might have to specify a new group in xioopts.h */ 0, /* an integer passed to xioopen_openssl_listen; makes it possible to - use the same xioopen_openssl_listen function for slightly different + use the xioopen_openssl_listen function for slightly different address types. */ 0, /* like previous argument */ 0 /* like previous arguments, but pointer type. @@ -99,6 +100,9 @@ const struct addrdesc addr_openssl_listen = { } ; #endif /* WITH_LISTEN */ +const struct addrdesc xioaddr_openssl_dtls_client = { "openssl-dtls-client", 3, xioopen_openssl_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_CHILD|GROUP_OPENSSL|GROUP_RETRY, 1, 0, 0 HELP("::") } ; +const struct addrdesc xioaddr_openssl_dtls_server = { "openssl-dtls-server", 3, xioopen_openssl_listen, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_UDP|GROUP_LISTEN|GROUP_CHILD|GROUP_RANGE|GROUP_OPENSSL|GROUP_RETRY, 1, 0, 0 HELP(":") } ; + /* both client and server */ const struct optdesc opt_openssl_cipherlist = { "openssl-cipherlist", "ciphers", OPT_OPENSSL_CIPHERLIST, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC }; #if WITH_OPENSSL_METHOD @@ -188,7 +192,7 @@ static int xiofile_t *xxfd, /* a xio file descriptor structure, already allocated */ unsigned groups, /* the matching address groups... */ - int dummy1, /* first transparent integer value from + int protogrp, /* first transparent integer value from addr_openssl */ int dummy2, /* second transparent integer value from addr_openssl */ @@ -199,8 +203,9 @@ static int struct opt *opts0 = NULL; const char *hostname, *portname; int pf = PF_UNSPEC; - int ipproto = IPPROTO_TCP; + bool use_dtls = (protogrp != 0); int socktype = SOCK_STREAM; + int ipproto = IPPROTO_TCP; bool dofork = false; union sockaddr_union us_sa, *us = &us_sa; union sockaddr_union them_sa, *them = &them_sa; @@ -248,9 +253,16 @@ static int } result = - _xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx); + _xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx, (bool *)&use_dtls); if (result != STAT_OK) return STAT_NORETRY; + if (use_dtls) { + socktype = SOCK_DGRAM; + ipproto = IPPROTO_UDP; + } + retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); + result = _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, xfd->para.socket.ip.res_opts[1], @@ -428,7 +440,7 @@ static int xiofile_t *xxfd, /* a xio file descriptor structure, already allocated */ unsigned groups, /* the matching address groups... */ - int dummy1, /* first transparent integer value from + int protogrp, /* first transparent integer value from addr_openssl */ int dummy2, /* second transparent integer value from addr_openssl */ @@ -441,6 +453,7 @@ static int union sockaddr_union us_sa, *us = &us_sa; socklen_t uslen = sizeof(us_sa); int pf; + bool use_dtls = (protogrp != 0); int socktype = SOCK_STREAM; int ipproto = IPPROTO_TCP; /*! lowport? */ @@ -486,9 +499,16 @@ static int applyopts(-1, opts, PH_EARLY); result = - _xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert, &ctx); + _xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert, &ctx, &use_dtls); if (result != STAT_OK) return STAT_NORETRY; + if (use_dtls) { + socktype = SOCK_DGRAM; + ipproto = IPPROTO_UDP; + } + retropt_int(opts, OPT_SO_TYPE, &socktype); + retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); + if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], @@ -497,7 +517,7 @@ static int return STAT_NORETRY; } - xfd->addr = &addr_openssl_listen; + xfd->addr = &xioaddr_openssl_listen; xfd->dtype = XIODATA_OPENSSL; while (true) { /* loop over failed attempts */ @@ -509,17 +529,22 @@ static int #endif /* WITH_RETRY */ level = E_ERROR; - /* tcp listen; this can fork() for us; it only returns on error or on - successful establishment of tcp connection */ - result = _xioopen_listen(xfd, xioflags, + /* this can fork() for us; it only returns on error or on + successful establishment of connection */ + if (ipproto == IPPROTO_TCP) { + result = _xioopen_listen(xfd, xioflags, (struct sockaddr *)us, uslen, - opts, pf, socktype, IPPROTO_TCP, + opts, pf, socktype, ipproto, #if WITH_RETRY (xfd->retry||xfd->forever)?E_INFO:E_ERROR #else E_ERROR #endif /* WITH_RETRY */ ); + } else { + result = _xioopen_ipdgram_listen(xfd, xioflags, + us, uslen, opts, pf, socktype, ipproto); + } /*! not sure if we should try again on retry/forever */ switch (result) { case STAT_OK: break; @@ -838,7 +863,8 @@ int bool server, /* SSL client: false */ bool *opt_ver, const char *opt_cert, - SSL_CTX **ctxp) + SSL_CTX **ctxp, + bool *use_dtls) /* checked,overwritten with true if DTLS-method */ { SSL_CTX *ctx; bool opt_fips = false; @@ -857,7 +883,9 @@ int unsigned long err; int result; - xfd->addr = &addr_openssl; + //*ipproto = IPPROTO_TCP; + + xfd->addr = &xioaddr_openssl; xfd->dtype = XIODATA_OPENSSL; retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips); @@ -926,15 +954,21 @@ int method = sycTLSv1_2_client_method(); #endif #if HAVE_DTLSv1_client_method - } else if (!strcasecmp(me_str, "DTLS") || !strcasecmp(me_str, "DTLS1")) { + } else if (!strcasecmp(me_str, "DTLS1") || !strcasecmp(me_str, "DTLS1.0")) { method = sycDTLSv1_client_method(); + *use_dtls = true; +#endif +#if HAVE_DTLSv1_2_client_method + } else if (!strcasecmp(me_str, "DTLS1.2")) { + method = sycDTLSv1_2_client_method(); + *use_dtls = true; #endif } else { Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str); } - } else { + } else if (!*use_dtls) { #if HAVE_TLS_client_method - method = TLS_client_method(); + method = sycTLS_client_method(); #elif HAVE_SSLv23_client_method method = sycSSLv23_client_method(); #elif HAVE_TLSv1_2_client_method @@ -948,8 +982,19 @@ int #elif HAVE_SSLv2_client_method method = sycSSLv2_client_method(); #else -# error "OpenSSL does not seem to provide client methods" +# error "OpenSSL does not seem to provide SSL/TLS client methods" +#endif + } else { +#if HAVE_DTLS_client_method + method = sycDTLS_client_method(); +#elif HAVE_DTLSv1_2_client_method + method = sycDTLSv1_2_client_method(); +#elif HAVE_DTLSv1_client_method + method = sycDTLSv1_client_method(); +#else +# error "OpenSSL does not seem to provide DTLS client methods" #endif + *use_dtls = true; } } else /* server */ { if (me_str != 0) { @@ -980,15 +1025,21 @@ int method = sycTLSv1_2_server_method(); #endif #if HAVE_DTLSv1_server_method - } else if (!strcasecmp(me_str, "DTLS") || !strcasecmp(me_str, "DTLS1")) { + } else if (!strcasecmp(me_str, "DTLS1") || !strcasecmp(me_str, "DTLS1.0")) { method = sycDTLSv1_server_method(); + *use_dtls = true; +#endif +#if HAVE_DTLSv1_2_server_method + } else if (!strcasecmp(me_str, "DTLS1.2")) { + method = sycDTLSv1_2_server_method(); + *use_dtls = true; #endif } else { Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str); } - } else { + } else if (!*use_dtls) { #if HAVE_TLS_server_method - method = TLS_server_method(); + method = sycTLS_server_method(); #elif HAVE_SSLv23_server_method method = sycSSLv23_server_method(); #elif HAVE_TLSv1_2_server_method @@ -1002,8 +1053,19 @@ int #elif HAVE_SSLv2_server_method method = sycSSLv2_server_method(); #else -# error "OpenSSL does not seem to provide client methods" +# error "OpenSSL does not seem to provide SSL/TLS server methods" +#endif + } else { +#if HAVE_DTLS_server_method + method = sycDTLS_server_method(); +#elif HAVE_DTLSv1_2_server_method + method = sycDTLSv1_2_server_method(); +#elif HAVE_DTLSv1_server_method + method = sycDTLSv1_server_method(); +#else +# error "OpenSSL does not seem to provide DTLS server methods" #endif + *use_dtls = true; } } diff --git a/xio-openssl.h b/xio-openssl.h index dae65f9..a6ca357 100644 --- a/xio-openssl.h +++ b/xio-openssl.h @@ -10,8 +10,10 @@ #define SSLIO_BASE 0x53530000 /* "SSxx" */ #define SSLIO_MASK 0xffff0000 -extern const struct addrdesc addr_openssl; -extern const struct addrdesc addr_openssl_listen; +extern const struct addrdesc xioaddr_openssl; +extern const struct addrdesc xioaddr_openssl_listen; +extern const struct addrdesc xioaddr_openssl_dtls_client; +extern const struct addrdesc xioaddr_openssl_dtls_server; extern const struct optdesc opt_openssl_cipherlist; extern const struct optdesc opt_openssl_method; @@ -36,7 +38,7 @@ extern const struct optdesc opt_openssl_commonname; extern int _xioopen_openssl_prepare(struct opt *opts, struct single *xfd, bool server, bool *opt_ver, const char *opt_cert, - SSL_CTX **ctx); + SSL_CTX **ctx, bool *use_dtls); extern int _xioopen_openssl_connect(struct single *xfd, bool opt_ver, const char *opt_commonname, diff --git a/xio-udp.c b/xio-udp.c index 0d027eb..ff5fb6c 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -74,16 +74,11 @@ const struct addrdesc addr_udp6_recv = { "udp6-recv", 1, xioopen_udp_re #endif /* WITH_IP6 */ -/* we expect the form: port */ -int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, - int xioflags, xiofile_t *fd, - unsigned groups, int pf, int ipproto, - int protname) { - const char *portname = argv[1]; - union sockaddr_union us; +int _xioopen_ipdgram_listen(struct single *sfd, + int xioflags, union sockaddr_union *us, socklen_t uslen, + struct opt *opts, int pf, int socktype, int ipproto) { union sockaddr_union themunion; union sockaddr_union *them = &themunion; - int socktype = SOCK_DGRAM; struct pollfd readfd; bool dofork = false; int maxchildren = 0; @@ -91,49 +86,9 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, char *rangename; char infobuff[256]; unsigned char buff1[1]; - socklen_t uslen; socklen_t themlen; int result; - if (argc != 2) { - Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); - } - - if (pf == PF_UNSPEC) { -#if WITH_IP4 && WITH_IP6 - pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; -#elif WITH_IP6 - pf = PF_INET6; -#else - pf = PF_INET; -#endif - } - - retropt_socket_pf(opts, &pf); - - if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; - applyopts(-1, opts, PH_INIT); - - uslen = socket_init(pf, &us); - retropt_bind(opts, pf, socktype, IPPROTO_UDP, - (struct sockaddr *)&us, &uslen, 1, - fd->stream.para.socket.ip.res_opts[1], - fd->stream.para.socket.ip.res_opts[0]); - - if (false) { - ; -#if WITH_IP4 - } else if (pf == PF_INET) { - us.ip4.sin_port = parseport(portname, ipproto); -#endif -#if WITH_IP6 - } else if (pf == PF_INET6) { - us.ip6.sin6_port = parseport(portname, ipproto); -#endif - } else { - Error1("xioopen_ipdgram_listen(): unknown address family %d", pf); - } - retropt_bool(opts, OPT_FORK, &dofork); if (dofork) { @@ -152,24 +107,24 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &fd->stream.para.socket.range) < 0) { + if (xioparserange(rangename, pf, &sfd->para.socket.range) < 0) { free(rangename); return STAT_NORETRY; } free(rangename); - fd->stream.para.socket.dorange = true; + sfd->para.socket.dorange = true; } #endif #if WITH_LIBWRAP - xio_retropt_tcpwrap(&fd->stream, opts); + xio_retropt_tcpwrap(sfd, opts); #endif /* WITH_LIBWRAP */ - if (retropt_ushort(opts, OPT_SOURCEPORT, &fd->stream.para.socket.ip.sourceport) + if (retropt_ushort(opts, OPT_SOURCEPORT, &sfd->para.socket.ip.sourceport) >= 0) { - fd->stream.para.socket.ip.dosourceport = true; + sfd->para.socket.ip.dosourceport = true; } - retropt_bool(opts, OPT_LOWPORT, &fd->stream.para.socket.ip.lowport); + retropt_bool(opts, OPT_LOWPORT, &sfd->para.socket.ip.lowport); if (dofork) { xiosetchilddied(); /* set SIGCHLD handler */ @@ -184,40 +139,46 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, union sockaddr_union _sockname; union sockaddr_union *la = &_sockname; /* local address */ - if ((fd->stream.fd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) { + if ((sfd->fd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) { return STAT_RETRYLATER; } doreuseaddr |= (retropt_int(opts, OPT_SO_REUSEADDR, &reuseaddr) >= 0); - applyopts(fd->stream.fd, opts, PH_PASTSOCKET); + applyopts(sfd->fd, opts, PH_PASTSOCKET); if (doreuseaddr) { - if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major, + if (Setsockopt(sfd->fd, opt_so_reuseaddr.major, opt_so_reuseaddr.minor, &reuseaddr, sizeof(reuseaddr)) < 0) { Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s", - fd->stream.fd, opt_so_reuseaddr.major, + sfd->fd, opt_so_reuseaddr.major, opt_so_reuseaddr.minor, reuseaddr, sizeof(reuseaddr), strerror(errno)); } } - applyopts_cloexec(fd->stream.fd, opts); - applyopts(fd->stream.fd, opts, PH_PREBIND); - applyopts(fd->stream.fd, opts, PH_BIND); - if (Bind(fd->stream.fd, &us.soa, uslen) < 0) { - Error4("bind(%d, {%s}, "F_socklen"): %s", fd->stream.fd, - sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)), + applyopts_cloexec(sfd->fd, opts); + applyopts(sfd->fd, opts, PH_PREBIND); + applyopts(sfd->fd, opts, PH_BIND); + if (Bind(sfd->fd, &us->soa, uslen) < 0) { + Error4("bind(%d, {%s}, "F_socklen"): %s", sfd->fd, + sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)), uslen, strerror(errno)); return STAT_RETRYLATER; } /* under some circumstances bind() fills sockaddr with interesting info. */ - if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) { + if (Getsockname(sfd->fd, &us->soa, &uslen) < 0) { Error4("getsockname(%d, %p, {%d}): %s", - fd->stream.fd, &us.soa, uslen, strerror(errno)); + sfd->fd, &us->soa, uslen, strerror(errno)); + } + applyopts(sfd->fd, opts, PH_PASTBIND); + + if (ipproto == IPPROTO_UDP) { + Notice1("listening on UDP %s", + sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff))); + } else { + Notice2("listening on PROTO%d %s", ipproto, + sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff))); } - applyopts(fd->stream.fd, opts, PH_PASTBIND); - Notice1("listening on UDP %s", - sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); - readfd.fd = fd->stream.fd; + readfd.fd = sfd->fd; readfd.events = POLLIN|POLLERR; while (xiopoll(&readfd, 1, NULL) < 0) { if (errno != EINTR) break; @@ -225,12 +186,12 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, themlen = socket_init(pf, them); do { - result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK, + result = Recvfrom(sfd->fd, buff1, 1, MSG_PEEK, &them->soa, &themlen); } while (result < 0 && errno == EINTR); if (result < 0) { Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_socklen"}): %s", - fd->stream.fd, buff1, + sfd->fd, buff1, sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), themlen, strerror(errno)); return STAT_RETRYLATER; @@ -239,11 +200,14 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, Notice1("accepting UDP connection from %s", sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff))); - if (xiocheckpeer(&fd->stream, them, la) < 0) { + if (xiocheckpeer(sfd, them, la) < 0) { + Notice1("forbidding UDP connection from %s", + sockaddr_info(&them->soa, themlen, + infobuff, sizeof(infobuff))); /* drop packet */ char buff[512]; - Recv(fd->stream.fd, buff, sizeof(buff), 0); /* drop packet */ - Close(fd->stream.fd); + Recv(sfd->fd, buff, sizeof(buff), 0); /* drop packet */ + Close(sfd->fd); continue; } Info1("permitting UDP connection from %s", @@ -264,8 +228,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, /* server: continue loop with socket()+recvfrom() */ /* when we dont close this we get awkward behaviour on Linux 2.4: recvfrom gives 0 bytes with invalid socket address */ - if (Close(fd->stream.fd) < 0) { - Info2("close(%d): %s", fd->stream.fd, strerror(errno)); + if (Close(sfd->fd) < 0) { + Info2("close(%d): %s", sfd->fd, strerror(errno)); } while (maxchildren) { @@ -279,35 +243,88 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, continue; } break; - } + } /* end of the big while loop */ - applyopts(fd->stream.fd, opts, PH_CONNECT); - if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) { + applyopts(sfd->fd, opts, PH_CONNECT); + if ((result = Connect(sfd->fd, &them->soa, themlen)) < 0) { Error4("connect(%d, {%s}, "F_socklen"): %s", - fd->stream.fd, + sfd->fd, sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), themlen, strerror(errno)); return STAT_RETRYLATER; } /* set the env vars describing the local and remote sockets */ - if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) { + if (Getsockname(sfd->fd, &us->soa, &uslen) < 0) { Warn4("getsockname(%d, %p, {%d}): %s", - fd->stream.fd, &us.soa, uslen, strerror(errno)); + sfd->fd, &us->soa, uslen, strerror(errno)); } - xiosetsockaddrenv("SOCK", &us, uslen, IPPROTO_UDP); + xiosetsockaddrenv("SOCK", us, uslen, IPPROTO_UDP); xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP); - fd->stream.howtoend = END_SHUTDOWN; - applyopts_fchown(fd->stream.fd, opts); - applyopts(fd->stream.fd, opts, PH_LATE); + sfd->howtoend = END_SHUTDOWN; + applyopts_fchown(sfd->fd, opts); + applyopts(sfd->fd, opts, PH_LATE); - if ((result = _xio_openlate(&fd->stream, opts)) < 0) + if ((result = _xio_openlate(sfd, opts)) < 0) return result; return 0; } +/* we expect the form: port */ +int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, + int xioflags, xiofile_t *fd, + unsigned groups, int pf, int ipproto, + int protname) { + const char *portname = argv[1]; + union sockaddr_union us; + int socktype = SOCK_DGRAM; + socklen_t uslen; + + if (argc != 2) { + Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); + } + + if (pf == PF_UNSPEC) { +#if WITH_IP4 && WITH_IP6 + pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; +#elif WITH_IP6 + pf = PF_INET6; +#else + pf = PF_INET; +#endif + } + + retropt_socket_pf(opts, &pf); + retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); + + if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1; + applyopts(-1, opts, PH_INIT); + + uslen = socket_init(pf, &us); + retropt_bind(opts, pf, socktype, ipproto, + (struct sockaddr *)&us, &uslen, 1, + fd->stream.para.socket.ip.res_opts[1], + fd->stream.para.socket.ip.res_opts[0]); + + if (false) { + ; +#if WITH_IP4 + } else if (pf == PF_INET) { + us.ip4.sin_port = parseport(portname, ipproto); +#endif +#if WITH_IP6 + } else if (pf == PF_INET6) { + us.ip6.sin6_port = parseport(portname, ipproto); +#endif + } else { + Error1("xioopen_ipdgram_listen(): unknown address family %d", pf); + } + + return _xioopen_ipdgram_listen(&fd->stream, xioflags, &us, uslen, + opts, pf, socktype, ipproto); +} static int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, diff --git a/xio-udp.h b/xio-udp.h index d8d1471..fd9d028 100644 --- a/xio-udp.h +++ b/xio-udp.h @@ -24,6 +24,10 @@ extern const struct addrdesc addr_udp6_datagram; extern const struct addrdesc addr_udp6_recvfrom; extern const struct addrdesc addr_udp6_recv; +extern int _xioopen_ipdgram_listen(struct single *sfd, + int xioflags, union sockaddr_union *us, socklen_t uslen, + struct opt *opts, int pf, int socktype, int ipproto); + extern int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, int rw, xiofile_t *fd, unsigned groups, int af, int ipproto, diff --git a/xioopen.c b/xioopen.c index dbef43a..883f684 100644 --- a/xioopen.c +++ b/xioopen.c @@ -41,6 +41,17 @@ const struct addrname addressnames[] = { { "datagram", &xioaddr_socket_datagram }, { "dgram", &xioaddr_socket_datagram }, #endif +#if WITH_OPENSSL + { "dtls", &xioaddr_openssl_dtls_client }, + { "dtls-c", &xioaddr_openssl_dtls_client }, + { "dtls-client", &xioaddr_openssl_dtls_client }, + { "dtls-connect", &xioaddr_openssl_dtls_client }, +#if WITH_LISTEN + { "dtls-l", &xioaddr_openssl_dtls_server }, + { "dtls-listen", &xioaddr_openssl_dtls_server }, + { "dtls-server", &xioaddr_openssl_dtls_server }, +#endif +#endif #if WITH_PIPE { "echo", &addr_pipe }, #endif @@ -122,10 +133,14 @@ const struct addrname addressnames[] = { { "open", &addr_open }, #endif #if WITH_OPENSSL - { "openssl", &addr_openssl }, - { "openssl-connect", &addr_openssl }, + { "openssl", &xioaddr_openssl }, + { "openssl-connect", &xioaddr_openssl }, + { "openssl-dtls-client", &xioaddr_openssl_dtls_client }, + { "openssl-dtls-connect", &xioaddr_openssl_dtls_client }, #if WITH_LISTEN - { "openssl-listen", &addr_openssl_listen }, + { "openssl-dtls-listen", &xioaddr_openssl_dtls_server }, + { "openssl-dtls-server", &xioaddr_openssl_dtls_server }, + { "openssl-listen", &xioaddr_openssl_listen }, #endif #endif #if WITH_PIPE @@ -186,9 +201,9 @@ const struct addrname addressnames[] = { { "socks4a", &addr_socks4a_connect }, #endif #if WITH_OPENSSL - { "ssl", &addr_openssl }, + { "ssl", &xioaddr_openssl }, #if WITH_LISTEN - { "ssl-l", &addr_openssl_listen }, + { "ssl-l", &xioaddr_openssl_listen }, #endif #endif #if WITH_STDIO -- 2.11.4.GIT