mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
DTLS over UDP
This commit is contained in:
parent
ff8de6c5cd
commit
d1b809b4ab
14 changed files with 537 additions and 126 deletions
9
CHANGES
9
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
|
||||
|
|
2
compat.h
2
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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
69
doc/socat.yo
69
doc/socat.yo
|
@ -487,6 +487,7 @@ label(ADDRESS_OPEN)dit(bf(tt(OPEN:<filename>)))
|
|||
link(CREATE)(ADDRESS_CREAT),
|
||||
link(GOPEN)(ADDRESS_GOPEN),
|
||||
link(UNIX-CONNECT)(ADDRESS_UNIX_CONNECT)
|
||||
|
||||
label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL:<host>:<port>)))
|
||||
Tries to establish a SSL connection to <port> [link(TCP
|
||||
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
|
||||
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:<host>:<port>)))
|
|||
See also:
|
||||
link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN),
|
||||
link(TCP)(ADDRESS_TCP_CONNECT)
|
||||
|
||||
label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:<port>)))
|
||||
Listens on tcp <port> [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:<port>)))
|
|||
See also:
|
||||
link(OPENSSL)(ADDRESS_OPENSSL_CONNECT),
|
||||
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>)))
|
||||
If link(<filename>)(TYPE_FILENAME) already exists, it is opened.
|
||||
If it does not exist, a named pipe is created and opened. Beginning with
|
||||
|
|
60
sslcls.c
60
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);
|
||||
|
|
12
sslcls.h
12
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)
|
||||
|
|
10
sycls.c
10
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;
|
||||
}
|
||||
|
||||
|
|
149
test.sh
149
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
|
||||
|
|
110
xio-openssl.c
110
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(":<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 */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
193
xio-udp.c
193
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(fd->stream.fd, opts, PH_PASTBIND);
|
||||
applyopts(sfd->fd, opts, PH_PASTBIND);
|
||||
|
||||
Notice1("listening on UDP %s",
|
||||
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
|
||||
readfd.fd = fd->stream.fd;
|
||||
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)));
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
|
|
25
xioopen.c
25
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
|
||||
|
|
Loading…
Reference in a new issue