DTLS over UDP

This commit is contained in:
Gerhard Rieger 2020-12-30 19:46:42 +01:00
parent ff8de6c5cd
commit d1b809b4ab
14 changed files with 537 additions and 126 deletions

View file

@ -50,6 +50,15 @@ Corrections:
address if you want to avoid data loss. address if you want to avoid data loss.
Thanks to Chunmei Xu for reporting this issue and proving the patch. 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: Porting:
In gcc version 10 the default changed from -fcommon to -fno-common. In gcc version 10 the default changed from -fcommon to -fno-common.
Consequently, linking filan and procan failed with error Consequently, linking filan and procan failed with error

View file

@ -681,7 +681,7 @@ typedef int sig_atomic_t;
#endif #endif
/* sigset_t printing - not an exact solution yet */ /* sigset_t printing - not an exact solution yet */
#define F_sigset "0x%4lx" #define F_sigset "0x%06lx"
typedef unsigned long T_sigset; typedef unsigned long T_sigset;
/* default: socklen_t */ /* default: socklen_t */

View file

@ -466,6 +466,10 @@
#undef HAVE_TLSv1_2_client_method #undef HAVE_TLSv1_2_client_method
#undef HAVE_TLSv1_2_server_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 */ /* Define if you have the DTLSv1 client and server method functions */
#undef HAVE_DTLSv1_client_method #undef HAVE_DTLSv1_client_method
#undef HAVE_DTLSv1_server_method #undef HAVE_DTLSv1_server_method
@ -476,6 +480,10 @@
/* Define if you have the SSL_CTX_set_max_proto_version function/macro */ /* Define if you have the SSL_CTX_set_max_proto_version function/macro */
#undef HAVE_SSL_CTX_set_max_proto_version #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 */ /* Define if you have the EC_KEY type */
#undef HAVE_TYPE_EC_KEY #undef HAVE_TYPE_EC_KEY

View file

@ -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(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_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(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 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 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])) 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(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_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_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 fi # $WITH_OPENSSL_METHOD
AC_CHECK_FUNC(SSL_CTX_set_default_verify_paths, AC_DEFINE(HAVE_SSL_CTX_set_default_verify_paths)) AC_CHECK_FUNC(SSL_CTX_set_default_verify_paths, AC_DEFINE(HAVE_SSL_CTX_set_default_verify_paths))

View file

@ -487,6 +487,7 @@ label(ADDRESS_OPEN)dit(bf(tt(OPEN:<filename>)))
link(CREATE)(ADDRESS_CREAT), link(CREATE)(ADDRESS_CREAT),
link(GOPEN)(ADDRESS_GOPEN), link(GOPEN)(ADDRESS_GOPEN),
link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT) link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT)
label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL:<host>:<port>))) label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL:<host>:<port>)))
Tries to establish a SSL connection to <port> [link(TCP Tries to establish a SSL connection to <port> [link(TCP
service)(TYPE_TCP_SERVICE)] on service)(TYPE_TCP_SERVICE)] on
@ -502,7 +503,7 @@ label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL:<host>:<port>)))
<host> parameter or the value of the <host> parameter or the value of the
link(openssl-commonname)(OPTION_OPENSSL_COMMONNAME) option. link(openssl-commonname)(OPTION_OPENSSL_COMMONNAME) option.
Socat tries to match it against the certificates subject commonName, 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() 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() 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: Useful options:
@ -522,6 +523,7 @@ label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL:<host>:<port>)))
See also: See also:
link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN), link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN),
link(TCP)(ADDRESS_TCP_CONNECT) link(TCP)(ADDRESS_TCP_CONNECT)
label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:<port>))) label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:<port>)))
Listens on tcp <port> [link(TCP service)(TYPE_TCP_SERVICE)]. Listens on tcp <port> [link(TCP service)(TYPE_TCP_SERVICE)].
The IP version is 4 or the one specified with The IP version is 4 or the one specified with
@ -552,6 +554,71 @@ label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:<port>)))
See also: See also:
link(OPENSSL)(ADDRESS_OPENSSL_CONNECT), link(OPENSSL)(ADDRESS_OPENSSL_CONNECT),
link(TCP-LISTEN)(ADDRESS_TCP_LISTEN) link(TCP-LISTEN)(ADDRESS_TCP_LISTEN)
label(ADDRESS_OPENSSL_DTLS_CLIENT)dit(bf(tt(OPENSSL-DTLS-CLIENT:<host>:<port>)))
Tries to establish a DTLS connection to <port> [link(UDP
service)(TYPE_UDP_SERVICE)] on
<host> [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:<port>)))
Listens on UDP <port> [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:<filename>))) label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:<filename>)))
If link(<filename>)(TYPE_FILENAME) already exists, it is opened. If link(<filename>)(TYPE_FILENAME) already exists, it is opened.
If it does not exist, a named pipe is created and opened. Beginning with If it does not exist, a named pipe is created and opened. Beginning with

View file

@ -35,6 +35,26 @@ int sycSSL_library_init(void) {
return result; 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 #if HAVE_SSLv2_client_method
const SSL_METHOD *sycSSLv2_client_method(void) { const SSL_METHOD *sycSSLv2_client_method(void) {
const SSL_METHOD *result; const SSL_METHOD *result;
@ -151,6 +171,26 @@ const SSL_METHOD *sycTLSv1_2_server_method(void) {
} }
#endif #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 #if HAVE_DTLSv1_client_method
const SSL_METHOD *sycDTLSv1_client_method(void) { const SSL_METHOD *sycDTLSv1_client_method(void) {
const SSL_METHOD *result; const SSL_METHOD *result;
@ -171,6 +211,26 @@ const SSL_METHOD *sycDTLSv1_server_method(void) {
} }
#endif #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 *sycSSL_CTX_new(const SSL_METHOD *method) {
SSL_CTX *result; SSL_CTX *result;
Debug1("SSL_CTX_new(%p)", method); Debug1("SSL_CTX_new(%p)", method);

View file

@ -10,6 +10,8 @@
void sycSSL_load_error_strings(void); void sycSSL_load_error_strings(void);
int sycSSL_library_init(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_client_method(void);
const SSL_METHOD *sycSSLv2_server_method(void); const SSL_METHOD *sycSSLv2_server_method(void);
const SSL_METHOD *sycSSLv3_client_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_1_server_method(void);
const SSL_METHOD *sycTLSv1_2_client_method(void); const SSL_METHOD *sycTLSv1_2_client_method(void);
const SSL_METHOD *sycTLSv1_2_server_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_client_method(void);
const SSL_METHOD *sycDTLSv1_server_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_CTX *sycSSL_CTX_new(const SSL_METHOD *method);
SSL *sycSSL_new(SSL_CTX *ctx); SSL *sycSSL_new(SSL_CTX *ctx);
int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, 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_load_error_strings() SSL_load_error_strings()
#define sycSSL_library_init() SSL_library_init() #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_client_method() SSLv2_client_method()
#define sycSSLv2_server_method() SSLv2_server_method() #define sycSSLv2_server_method() SSLv2_server_method()
#define sycSSLv3_client_method() SSLv3_client_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_1_server_method() TLSv1_1_server_method()
#define sycTLSv1_2_client_method() TLSv1_2_client_method() #define sycTLSv1_2_client_method() TLSv1_2_client_method()
#define sycTLSv1_2_server_method() TLSv1_2_server_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_client_method() DTLSv1_client_method()
#define sycDTLSv1_server_method() DTLSv1_server_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_CTX_new(m) SSL_CTX_new(m)
#define sycSSL_new(c) SSL_new(c) #define sycSSL_new(c) SSL_new(c)
#define sycSSL_CTX_load_verify_locations(c,f,p) SSL_CTX_load_verify_locations(c,f,p) #define sycSSL_CTX_load_verify_locations(c,f,p) SSL_CTX_load_verify_locations(c,f,p)

View file

@ -960,8 +960,14 @@ int Sigaction(int signum, const struct sigaction *act,
int Sigprocmask(int how, const sigset_t *set, sigset_t *oset) { int Sigprocmask(int how, const sigset_t *set, sigset_t *oset) {
int retval; 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); retval = sigprocmask(how, set, oset);
if (oset)
Debug2("sigprocmask() -> {,, "F_sigset"} %d", *(T_sigset *)oset, retval);
else
Debug1("sigprocmask() -> %d", retval); Debug1("sigprocmask() -> %d", retval);
return retval; return retval;
} }

149
test.sh
View file

@ -12907,7 +12907,7 @@ N=$((N+1))
# tests of various SSL methods; from TLS1.3 this method is not avail in OpenSSL: # tests of various SSL methods; from TLS1.3 this method is not avail in OpenSSL:
OPENSSL_METHODS_OBSOLETE="SSL3 SSL23" 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. # the OPENSSL_METHOD_DTLS1 test hangs sometimes, probably depending on the openssl version.
OPENSSL_VERSION="$(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 else
$CMD0 >/dev/null 2>"${te}0" & $CMD0 >/dev/null 2>"${te}0" &
pid0=$! pid0=$!
waittcp4port $PORT 1 if [[ "$method" =~ DTLS* ]]; then
waitudp4port $PORT 1
else
waittcp4port $PORT 1
fi
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
rc1=$? rc1=$?
kill $pid0 2>/dev/null; wait kill $pid0 2>/dev/null; wait
@ -13924,6 +13928,147 @@ esac
N=$((N+1)) 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 # here come tests that might affect your systems integrity. Put normal tests

View file

@ -14,6 +14,7 @@
#include "xio-fd.h" #include "xio-fd.h"
#include "xio-socket.h" /* _xioopen_connect() */ #include "xio-socket.h" /* _xioopen_connect() */
#include "xio-listen.h" #include "xio-listen.h"
#include "xio-udp.h"
#include "xio-ipapp.h" #include "xio-ipapp.h"
#include "xio-openssl.h" #include "xio-openssl.h"
@ -58,7 +59,7 @@ static int openssl_delete_cert_info(void);
/* description record for ssl connect */ /* 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 "openssl", /* keyword for selecting this address type in xioopen calls
(canonical or main name) */ (canonical or main name) */
3, /* data flow directions this address supports on API layer: 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. 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 */ You might have to specify a new group in xioopts.h */
0, /* an integer passed to xioopen_openssl; makes it possible to 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. */ address types. */
0, /* like previous argument */ 0, /* like previous argument */
0 /* like previous arguments, but pointer type. 0 /* like previous arguments, but pointer type.
@ -79,7 +80,7 @@ const struct addrdesc addr_openssl = {
#if WITH_LISTEN #if WITH_LISTEN
/* description record for ssl 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 "openssl-listen", /* keyword for selecting this address type in xioopen calls
(canonical or main name) */ (canonical or main name) */
3, /* data flow directions this address supports on API layer: 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. 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 */ You might have to specify a new group in xioopts.h */
0, /* an integer passed to xioopen_openssl_listen; makes it possible to 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. */ address types. */
0, /* like previous argument */ 0, /* like previous argument */
0 /* like previous arguments, but pointer type. 0 /* like previous arguments, but pointer type.
@ -99,6 +100,9 @@ const struct addrdesc addr_openssl_listen = {
} ; } ;
#endif /* WITH_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(":<host>:<port>") } ;
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(":<port>") } ;
/* both client and server */ /* both client and server */
const struct optdesc opt_openssl_cipherlist = { "openssl-cipherlist", "ciphers", OPT_OPENSSL_CIPHERLIST, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_openssl_cipherlist = { "openssl-cipherlist", "ciphers", OPT_OPENSSL_CIPHERLIST, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC };
#if WITH_OPENSSL_METHOD #if WITH_OPENSSL_METHOD
@ -188,7 +192,7 @@ static int
xiofile_t *xxfd, /* a xio file descriptor structure, xiofile_t *xxfd, /* a xio file descriptor structure,
already allocated */ already allocated */
unsigned groups, /* the matching address groups... */ unsigned groups, /* the matching address groups... */
int dummy1, /* first transparent integer value from int protogrp, /* first transparent integer value from
addr_openssl */ addr_openssl */
int dummy2, /* second transparent integer value from int dummy2, /* second transparent integer value from
addr_openssl */ addr_openssl */
@ -199,8 +203,9 @@ static int
struct opt *opts0 = NULL; struct opt *opts0 = NULL;
const char *hostname, *portname; const char *hostname, *portname;
int pf = PF_UNSPEC; int pf = PF_UNSPEC;
int ipproto = IPPROTO_TCP; bool use_dtls = (protogrp != 0);
int socktype = SOCK_STREAM; int socktype = SOCK_STREAM;
int ipproto = IPPROTO_TCP;
bool dofork = false; bool dofork = false;
union sockaddr_union us_sa, *us = &us_sa; union sockaddr_union us_sa, *us = &us_sa;
union sockaddr_union them_sa, *them = &them_sa; union sockaddr_union them_sa, *them = &them_sa;
@ -248,9 +253,16 @@ static int
} }
result = 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 (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 = result =
_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[1],
@ -428,7 +440,7 @@ static int
xiofile_t *xxfd, /* a xio file descriptor structure, xiofile_t *xxfd, /* a xio file descriptor structure,
already allocated */ already allocated */
unsigned groups, /* the matching address groups... */ unsigned groups, /* the matching address groups... */
int dummy1, /* first transparent integer value from int protogrp, /* first transparent integer value from
addr_openssl */ addr_openssl */
int dummy2, /* second transparent integer value from int dummy2, /* second transparent integer value from
addr_openssl */ addr_openssl */
@ -441,6 +453,7 @@ static int
union sockaddr_union us_sa, *us = &us_sa; union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa); socklen_t uslen = sizeof(us_sa);
int pf; int pf;
bool use_dtls = (protogrp != 0);
int socktype = SOCK_STREAM; int socktype = SOCK_STREAM;
int ipproto = IPPROTO_TCP; int ipproto = IPPROTO_TCP;
/*! lowport? */ /*! lowport? */
@ -486,9 +499,16 @@ static int
applyopts(-1, opts, PH_EARLY); applyopts(-1, opts, PH_EARLY);
result = 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 (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, if (_xioopen_ipapp_listen_prepare(opts, &opts0, portname, &pf, ipproto,
xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[1],
xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts[0],
@ -497,7 +517,7 @@ static int
return STAT_NORETRY; return STAT_NORETRY;
} }
xfd->addr = &addr_openssl_listen; xfd->addr = &xioaddr_openssl_listen;
xfd->dtype = XIODATA_OPENSSL; xfd->dtype = XIODATA_OPENSSL;
while (true) { /* loop over failed attempts */ while (true) { /* loop over failed attempts */
@ -509,17 +529,22 @@ static int
#endif /* WITH_RETRY */ #endif /* WITH_RETRY */
level = E_ERROR; level = E_ERROR;
/* tcp listen; this can fork() for us; it only returns on error or on /* this can fork() for us; it only returns on error or on
successful establishment of tcp connection */ successful establishment of connection */
if (ipproto == IPPROTO_TCP) {
result = _xioopen_listen(xfd, xioflags, result = _xioopen_listen(xfd, xioflags,
(struct sockaddr *)us, uslen, (struct sockaddr *)us, uslen,
opts, pf, socktype, IPPROTO_TCP, opts, pf, socktype, ipproto,
#if WITH_RETRY #if WITH_RETRY
(xfd->retry||xfd->forever)?E_INFO:E_ERROR (xfd->retry||xfd->forever)?E_INFO:E_ERROR
#else #else
E_ERROR E_ERROR
#endif /* WITH_RETRY */ #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 */ /*! not sure if we should try again on retry/forever */
switch (result) { switch (result) {
case STAT_OK: break; case STAT_OK: break;
@ -838,7 +863,8 @@ int
bool server, /* SSL client: false */ bool server, /* SSL client: false */
bool *opt_ver, bool *opt_ver,
const char *opt_cert, const char *opt_cert,
SSL_CTX **ctxp) SSL_CTX **ctxp,
bool *use_dtls) /* checked,overwritten with true if DTLS-method */
{ {
SSL_CTX *ctx; SSL_CTX *ctx;
bool opt_fips = false; bool opt_fips = false;
@ -857,7 +883,9 @@ int
unsigned long err; unsigned long err;
int result; int result;
xfd->addr = &addr_openssl; //*ipproto = IPPROTO_TCP;
xfd->addr = &xioaddr_openssl;
xfd->dtype = XIODATA_OPENSSL; xfd->dtype = XIODATA_OPENSSL;
retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips); retropt_bool(opts, OPT_OPENSSL_FIPS, &opt_fips);
@ -926,15 +954,21 @@ int
method = sycTLSv1_2_client_method(); method = sycTLSv1_2_client_method();
#endif #endif
#if HAVE_DTLSv1_client_method #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(); 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 #endif
} else { } else {
Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str); Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str);
} }
} else { } else if (!*use_dtls) {
#if HAVE_TLS_client_method #if HAVE_TLS_client_method
method = TLS_client_method(); method = sycTLS_client_method();
#elif HAVE_SSLv23_client_method #elif HAVE_SSLv23_client_method
method = sycSSLv23_client_method(); method = sycSSLv23_client_method();
#elif HAVE_TLSv1_2_client_method #elif HAVE_TLSv1_2_client_method
@ -948,8 +982,19 @@ int
#elif HAVE_SSLv2_client_method #elif HAVE_SSLv2_client_method
method = sycSSLv2_client_method(); method = sycSSLv2_client_method();
#else #else
# error "OpenSSL does not seem to provide client methods" # error "OpenSSL does not seem to provide SSL/TLS client methods"
#endif #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 */ { } else /* server */ {
if (me_str != 0) { if (me_str != 0) {
@ -980,15 +1025,21 @@ int
method = sycTLSv1_2_server_method(); method = sycTLSv1_2_server_method();
#endif #endif
#if HAVE_DTLSv1_server_method #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(); 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 #endif
} else { } else {
Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str); Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str);
} }
} else { } else if (!*use_dtls) {
#if HAVE_TLS_server_method #if HAVE_TLS_server_method
method = TLS_server_method(); method = sycTLS_server_method();
#elif HAVE_SSLv23_server_method #elif HAVE_SSLv23_server_method
method = sycSSLv23_server_method(); method = sycSSLv23_server_method();
#elif HAVE_TLSv1_2_server_method #elif HAVE_TLSv1_2_server_method
@ -1002,8 +1053,19 @@ int
#elif HAVE_SSLv2_server_method #elif HAVE_SSLv2_server_method
method = sycSSLv2_server_method(); method = sycSSLv2_server_method();
#else #else
# error "OpenSSL does not seem to provide client methods" # error "OpenSSL does not seem to provide SSL/TLS server methods"
#endif #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;
} }
} }

View file

@ -10,8 +10,10 @@
#define SSLIO_BASE 0x53530000 /* "SSxx" */ #define SSLIO_BASE 0x53530000 /* "SSxx" */
#define SSLIO_MASK 0xffff0000 #define SSLIO_MASK 0xffff0000
extern const struct addrdesc addr_openssl; extern const struct addrdesc xioaddr_openssl;
extern const struct addrdesc addr_openssl_listen; 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_cipherlist;
extern const struct optdesc opt_openssl_method; extern const struct optdesc opt_openssl_method;
@ -36,7 +38,7 @@ extern const struct optdesc opt_openssl_commonname;
extern int extern int
_xioopen_openssl_prepare(struct opt *opts, struct single *xfd, _xioopen_openssl_prepare(struct opt *opts, struct single *xfd,
bool server, bool *opt_ver, const char *opt_cert, bool server, bool *opt_ver, const char *opt_cert,
SSL_CTX **ctx); SSL_CTX **ctx, bool *use_dtls);
extern int extern int
_xioopen_openssl_connect(struct single *xfd, bool opt_ver, _xioopen_openssl_connect(struct single *xfd, bool opt_ver,
const char *opt_commonname, const char *opt_commonname,

191
xio-udp.c
View file

@ -74,16 +74,11 @@ const struct addrdesc addr_udp6_recv = { "udp6-recv", 1, xioopen_udp_re
#endif /* WITH_IP6 */ #endif /* WITH_IP6 */
/* we expect the form: port */ int _xioopen_ipdgram_listen(struct single *sfd,
int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, int xioflags, union sockaddr_union *us, socklen_t uslen,
int xioflags, xiofile_t *fd, struct opt *opts, int pf, int socktype, int ipproto) {
unsigned groups, int pf, int ipproto,
int protname) {
const char *portname = argv[1];
union sockaddr_union us;
union sockaddr_union themunion; union sockaddr_union themunion;
union sockaddr_union *them = &themunion; union sockaddr_union *them = &themunion;
int socktype = SOCK_DGRAM;
struct pollfd readfd; struct pollfd readfd;
bool dofork = false; bool dofork = false;
int maxchildren = 0; int maxchildren = 0;
@ -91,49 +86,9 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
char *rangename; char *rangename;
char infobuff[256]; char infobuff[256];
unsigned char buff1[1]; unsigned char buff1[1];
socklen_t uslen;
socklen_t themlen; socklen_t themlen;
int result; 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); retropt_bool(opts, OPT_FORK, &dofork);
if (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 WITH_IP4 /*|| WITH_IP6*/
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { 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); free(rangename);
return STAT_NORETRY; return STAT_NORETRY;
} }
free(rangename); free(rangename);
fd->stream.para.socket.dorange = true; sfd->para.socket.dorange = true;
} }
#endif #endif
#if WITH_LIBWRAP #if WITH_LIBWRAP
xio_retropt_tcpwrap(&fd->stream, opts); xio_retropt_tcpwrap(sfd, opts);
#endif /* WITH_LIBWRAP */ #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) { >= 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) { if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */ 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 _sockname;
union sockaddr_union *la = &_sockname; /* local address */ 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; return STAT_RETRYLATER;
} }
doreuseaddr |= (retropt_int(opts, OPT_SO_REUSEADDR, &reuseaddr) >= 0); 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 (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)) opt_so_reuseaddr.minor, &reuseaddr, sizeof(reuseaddr))
< 0) { < 0) {
Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s", 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), opt_so_reuseaddr.minor, reuseaddr, sizeof(reuseaddr),
strerror(errno)); strerror(errno));
} }
} }
applyopts_cloexec(fd->stream.fd, opts); applyopts_cloexec(sfd->fd, opts);
applyopts(fd->stream.fd, opts, PH_PREBIND); applyopts(sfd->fd, opts, PH_PREBIND);
applyopts(fd->stream.fd, opts, PH_BIND); applyopts(sfd->fd, opts, PH_BIND);
if (Bind(fd->stream.fd, &us.soa, uslen) < 0) { if (Bind(sfd->fd, &us->soa, uslen) < 0) {
Error4("bind(%d, {%s}, "F_socklen"): %s", fd->stream.fd, Error4("bind(%d, {%s}, "F_socklen"): %s", sfd->fd,
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)), sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno)); uslen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/* under some circumstances bind() fills sockaddr with interesting info. */ /* 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", Error4("getsockname(%d, %p, {%d}): %s",
fd->stream.fd, &us.soa, uslen, strerror(errno)); sfd->fd, &us->soa, uslen, strerror(errno));
} }
applyopts(fd->stream.fd, opts, PH_PASTBIND); applyopts(sfd->fd, opts, PH_PASTBIND);
if (ipproto == IPPROTO_UDP) {
Notice1("listening on UDP %s", Notice1("listening on UDP %s",
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)));
readfd.fd = fd->stream.fd; } else {
Notice2("listening on PROTO%d %s", ipproto,
sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)));
}
readfd.fd = sfd->fd;
readfd.events = POLLIN|POLLERR; readfd.events = POLLIN|POLLERR;
while (xiopoll(&readfd, 1, NULL) < 0) { while (xiopoll(&readfd, 1, NULL) < 0) {
if (errno != EINTR) break; 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); themlen = socket_init(pf, them);
do { do {
result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK, result = Recvfrom(sfd->fd, buff1, 1, MSG_PEEK,
&them->soa, &themlen); &them->soa, &themlen);
} while (result < 0 && errno == EINTR); } while (result < 0 && errno == EINTR);
if (result < 0) { if (result < 0) {
Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_socklen"}): %s", 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)), sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
return STAT_RETRYLATER; 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", Notice1("accepting UDP connection from %s",
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff))); 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 */ /* drop packet */
char buff[512]; char buff[512];
Recv(fd->stream.fd, buff, sizeof(buff), 0); /* drop packet */ Recv(sfd->fd, buff, sizeof(buff), 0); /* drop packet */
Close(fd->stream.fd); Close(sfd->fd);
continue; continue;
} }
Info1("permitting UDP connection from %s", 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() */ /* server: continue loop with socket()+recvfrom() */
/* when we dont close this we get awkward behaviour on Linux 2.4: /* when we dont close this we get awkward behaviour on Linux 2.4:
recvfrom gives 0 bytes with invalid socket address */ recvfrom gives 0 bytes with invalid socket address */
if (Close(fd->stream.fd) < 0) { if (Close(sfd->fd) < 0) {
Info2("close(%d): %s", fd->stream.fd, strerror(errno)); Info2("close(%d): %s", sfd->fd, strerror(errno));
} }
while (maxchildren) { while (maxchildren) {
@ -279,35 +243,88 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
continue; continue;
} }
break; break;
} } /* end of the big while loop */
applyopts(fd->stream.fd, opts, PH_CONNECT); applyopts(sfd->fd, opts, PH_CONNECT);
if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) { if ((result = Connect(sfd->fd, &them->soa, themlen)) < 0) {
Error4("connect(%d, {%s}, "F_socklen"): %s", Error4("connect(%d, {%s}, "F_socklen"): %s",
fd->stream.fd, sfd->fd,
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)), sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno)); themlen, strerror(errno));
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
/* set the env vars describing the local and remote sockets */ /* 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", 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); xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP);
fd->stream.howtoend = END_SHUTDOWN; sfd->howtoend = END_SHUTDOWN;
applyopts_fchown(fd->stream.fd, opts); applyopts_fchown(sfd->fd, opts);
applyopts(fd->stream.fd, opts, PH_LATE); applyopts(sfd->fd, opts, PH_LATE);
if ((result = _xio_openlate(&fd->stream, opts)) < 0) if ((result = _xio_openlate(sfd, opts)) < 0)
return result; return result;
return 0; 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 static
int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts, int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts,

View file

@ -24,6 +24,10 @@ extern const struct addrdesc addr_udp6_datagram;
extern const struct addrdesc addr_udp6_recvfrom; extern const struct addrdesc addr_udp6_recvfrom;
extern const struct addrdesc addr_udp6_recv; 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, extern int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
int rw, xiofile_t *fd, int rw, xiofile_t *fd,
unsigned groups, int af, int ipproto, unsigned groups, int af, int ipproto,

View file

@ -41,6 +41,17 @@ const struct addrname addressnames[] = {
{ "datagram", &xioaddr_socket_datagram }, { "datagram", &xioaddr_socket_datagram },
{ "dgram", &xioaddr_socket_datagram }, { "dgram", &xioaddr_socket_datagram },
#endif #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 #if WITH_PIPE
{ "echo", &addr_pipe }, { "echo", &addr_pipe },
#endif #endif
@ -122,10 +133,14 @@ const struct addrname addressnames[] = {
{ "open", &addr_open }, { "open", &addr_open },
#endif #endif
#if WITH_OPENSSL #if WITH_OPENSSL
{ "openssl", &addr_openssl }, { "openssl", &xioaddr_openssl },
{ "openssl-connect", &addr_openssl }, { "openssl-connect", &xioaddr_openssl },
{ "openssl-dtls-client", &xioaddr_openssl_dtls_client },
{ "openssl-dtls-connect", &xioaddr_openssl_dtls_client },
#if WITH_LISTEN #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
#endif #endif
#if WITH_PIPE #if WITH_PIPE
@ -186,9 +201,9 @@ const struct addrname addressnames[] = {
{ "socks4a", &addr_socks4a_connect }, { "socks4a", &addr_socks4a_connect },
#endif #endif
#if WITH_OPENSSL #if WITH_OPENSSL
{ "ssl", &addr_openssl }, { "ssl", &xioaddr_openssl },
#if WITH_LISTEN #if WITH_LISTEN
{ "ssl-l", &addr_openssl_listen }, { "ssl-l", &xioaddr_openssl_listen },
#endif #endif
#endif #endif
#if WITH_STDIO #if WITH_STDIO