From eaabbb09ea74bb82a3c8593dc5014a6ff51062c6 Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Thu, 21 May 2020 20:47:59 -0700 Subject: [PATCH] add ppp-over-tls tests (with pppd as the reference peer implementation) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit These test OpenConnect's ability to communicate with the standard pppd using PPP-over-TLS, with a variety of PPP negotiation options: ± IPv4 ± IPv6 ± DNS and NBNS server negotiation ± PPP header protocol/address field compression ± Van Jacobson header compression (always rejected by OpenConnect) These tests use socat to create TLS socket pairs, connecting `openconnect --protocol=nullppp` to one end and `pppd` to the other. I tried and failed to combine socat and pppd invocations, but pppd seemingly cannot handle being wrapped by libsocket_wrapper.so (nor libuid_wrapper.so; it must run as root). `pppd sync` (non-HDLC framing) appears to have trouble reacting to incoming packets in this configuration, so OpenConnect has to invoke retry timers during negotiation. This seems to be a bug in pppd, rather than a flaw in OpenConnect's implementation of PPP. Added logging of the time that each run takes. Signed-off-by: Daniel Lenski --- configure.ac | 7 ++++ tests/Makefile.am | 4 ++ tests/common.sh | 22 +++++++++++ tests/ppp-over-tls | 98 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100755 tests/ppp-over-tls diff --git a/configure.ac b/configure.ac index 6133ae23..b8d97d54 100644 --- a/configure.ac +++ b/configure.ac @@ -644,6 +644,11 @@ AC_ARG_ENABLE([dsa-tests], [], [enable_dsa_tests=yes]) AM_CONDITIONAL(TEST_DSA, [test "$enable_dsa_tests" = "yes"]) +AC_ARG_ENABLE([ppp-tests], + AS_HELP_STRING([--enable-ppp-tests], [Enable PPP tests (which require socat and pppd, and must run as root)]), + [enable_ppp_tests=yes]) +AM_CONDITIONAL(TEST_PPP, [test "$enable_ppp_tests" = "yes"]) + AM_CONDITIONAL(OPENCONNECT_GNUTLS, [ test "$ssl_library" = "GnuTLS" ]) AM_CONDITIONAL(OPENCONNECT_OPENSSL, [ test "$ssl_library" = "OpenSSL" ]) AM_CONDITIONAL(OPENCONNECT_ESP, [ test "$esp" != "" ]) @@ -1157,6 +1162,8 @@ SUMMARY([Java bindings], [$with_java]) SUMMARY([Build docs], [$build_www]) SUMMARY([Unit tests], [$have_cwrap]) SUMMARY([Net namespace tests], [$have_netns]) +SUMMARY([DSA tests], [$enable_dsa_tests]) +SUMMARY([PPP tests], [$enable_ppp_tests]) SUMMARY([Insecure debugging], [$insecure_debugging]) SUMMARY([NSIS installer], [$build_nsis]) diff --git a/tests/Makefile.am b/tests/Makefile.am index 99d34482..5493e6ca 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -54,6 +54,10 @@ if HAVE_NETNS dist_check_SCRIPTS += dtls-psk sigterm endif +if TEST_PPP +dist_check_SCRIPTS += ppp-over-tls +endif + if HAVE_CWRAP dist_check_SCRIPTS += auth-username-pass auth-certificate auth-nonascii cert-fingerprint id-test obsolete-server-crypto pfs diff --git a/tests/common.sh b/tests/common.sh index 31c27cd0..96d52e5f 100644 --- a/tests/common.sh +++ b/tests/common.sh @@ -30,6 +30,8 @@ if test "${DISABLE_ASAN_BROKEN_TESTS}" = 1 && test "${PRELOAD}" = 1;then fi OCSERV=/usr/sbin/ocserv +PPPD=/usr/sbin/pppd +test $(id -u) -eq 0 && SUDO= || SUDO=sudo top_builddir=${top_builddir:-..} SOCKDIR="./sockwrap.$$.tmp" @@ -38,6 +40,7 @@ export SOCKET_WRAPPER_DIR=$SOCKDIR export SOCKET_WRAPPER_DEFAULT_IFACE=2 ADDRESS=127.0.0.$SOCKET_WRAPPER_DEFAULT_IFACE OPENCONNECT="${OPENCONNECT:-${top_builddir}/openconnect}"${EXEEXT} +LOGFILE="$SOCKDIR/log.$$.tmp" OCCTL_SOCKET="${OCCTL_SOCKET:-./occtl-comp-$$.socket}" certdir="${srcdir}/certs" @@ -66,6 +69,25 @@ launch_simple_sr_server() { LD_PRELOAD=libsocket_wrapper.so:libuid_wrapper.so UID_WRAPPER=1 UID_WRAPPER_ROOT=1 $OCSERV $* & } +launch_simple_pppd() { + CERT="$1" + KEY="$2" + shift 2 + LD_PRELOAD=libsocket_wrapper.so socat \ + PTY,rawer,b9600,link="$SOCKDIR/pppd.$$.pty" \ + OPENSSL-LISTEN:443,verify=0,cert="$CERT",key="$KEY" 2>&1 & + PID=$! + + sleep 3 # Wait for socat to create the PTY link + + # It would be preferable to invoke `pppd notty` directly using socat, but it seemingly cannot handle + # being wrapped by libsocket_wrapper.so. + # pppd's option parsing is notably brittle: it must have the actual PTY device node, not a symlink + $SUDO $PPPD $(readlink "$SOCKDIR/pppd.$$.pty") noauth local debug nodetach logfile "$LOGFILE" $* 2>&1 & + + # XX: Caller needs to use PID, rather than $! +} + wait_server() { trap "kill $1" 1 15 2 sleep 5 diff --git a/tests/ppp-over-tls b/tests/ppp-over-tls new file mode 100755 index 00000000..1556b8a8 --- /dev/null +++ b/tests/ppp-over-tls @@ -0,0 +1,98 @@ +#!/bin/sh +# +# Copyright © 2020 Daniel Lenski +# +# This file is part of openconnect. +# +# This is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see + +srcdir=${srcdir:-.} +top_builddir=${top_builddir:-..} + +. `dirname $0`/common.sh + +CERT=$certdir/server-cert.pem +KEY=$certdir/server-key.pem + +echo "Testing PPP ... " + +echo -n "Connecting to PPP peer (HDLC/RFC1662, IPv4+IPv6, DNS, extraneous VJ and CCP)... " +launch_simple_pppd $CERT $KEY 10.0.0.1:10.0.0.101 ms-dns 1.1.1.1 ms-dns 8.8.8.8 +ipv6 2>&1 +wait_server $PID +start=$(date +%s) +LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT -q --protocol=nullppp $ADDRESS:443 -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookie "hdlc" >/dev/null 2>&1 +took=$(( $(date +%s) - start )) +if grep -qF "rcvd [IPCP ConfAck " $LOGFILE && grep -qF "sent [IPCP ConfAck " $LOGFILE && grep -qF "rcvd [IPV6CP ConfAck " $LOGFILE && grep -qF "sent [IPV6CP ConfAck " $LOGFILE; then + echo "ok (took $took seconds)" +else + fail $PID "Did not negotiate IPCP and IP6CP successfully." +fi + +cleanup + +echo -n "Connecting to PPP peer (HDLC/RFC1662, IPv4+IPv6, DNS, extraneous VJ and CCP, no header compression)... " +launch_simple_pppd $CERT $KEY 10.0.0.1:10.0.0.101 ms-dns 1.1.1.1 ms-dns 8.8.8.8 +ipv6 nopcomp noaccomp 2>&1 +wait_server $PID +start=$(date +%s) +LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT -q --protocol=nullppp $ADDRESS:443 -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookie "hdlc" >/dev/null 2>&1 +took=$(( $(date +%s) - start )) +if grep -qF "rcvd [IPCP ConfAck " $LOGFILE && grep -qF "sent [IPCP ConfAck " $LOGFILE && grep -qF "rcvd [IPV6CP ConfAck " $LOGFILE && grep -qF "sent [IPV6CP ConfAck " $LOGFILE; then + echo "ok (took $took seconds)" +else + fail $PID "Did not negotiate IPCP and IP6CP successfully." +fi + +cleanup + +echo -n "Connecting to PPP peer (sync/no-HDLC, IPv4+IPv6, DNS, extraneous VJ and CCP)... " +launch_simple_pppd $CERT $KEY sync 10.0.0.1:10.0.0.101 ms-dns 1.1.1.1 ms-dns 8.8.8.8 +ipv6 2>&1 +wait_server $PID +start=$(date +%s) +LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT -q --protocol=nullppp $ADDRESS:443 -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 >/dev/null 2>&1 +took=$(( $(date +%s) - start )) +if grep -qF "rcvd [IPCP ConfAck " $LOGFILE && grep -qF "sent [IPCP ConfAck " $LOGFILE && grep -qF "rcvd [IPV6CP ConfAck " $LOGFILE && grep -qF "sent [IPV6CP ConfAck " $LOGFILE; then + echo "ok (took $took seconds)" +else + fail $PID "Did not negotiate IPCP and IP6CP successfully." +fi + +cleanup + +echo -n "Connecting to PPP peer (sync/no-HDLC, IPv4 only)... " +launch_simple_pppd $CERT $KEY sync novj noccp 10.0.0.1:10.0.0.101 noipv6 2>&1 +wait_server $PID +start=$(date +%s) +LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT -q --protocol=nullppp $ADDRESS:443 -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 >/dev/null 2>&1 +took=$(( $(date +%s) - start )) +if grep -qF "rcvd [IPCP ConfAck " $LOGFILE && grep -qF "sent [IPCP ConfAck " $LOGFILE; then + echo "ok (took $took seconds)" +else + fail $PID "Did not negotiate IPCP successfully." +fi + +echo -n "Connecting to PPP peer (sync/no-HDLC, IPv6 only)... " +launch_simple_pppd $CERT $KEY sync novj noccp noip +ipv6 2>&1 +wait_server $PID +start=$(date +%s) +LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT -q --protocol=nullppp $ADDRESS:443 -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 >/dev/null 2>&1 +took=$(( $(date +%s) - start )) +if grep -qF "rcvd [IPV6CP ConfAck " $LOGFILE && grep -qF "sent [IPV6CP ConfAck " $LOGFILE; then + echo "ok (took $took seconds)" +else + fail $PID "Did not negotiate IP6CP successfully." +fi + +cleanup + +exit 0 -- 2.49.0