Openssl s_server Exits Successfully Without Listening on the Network

I was testing out the certificate chain for a new certificate authority by having openssl s_server bind to a port and serve an HTML page.

The trouble was it wouldn’t actually bind to the port, but would instead spit out some session statistics, exit successfully and return to the command prompt without any error messages. What the hell?

$ openssl s_server -CAfile certs/chain.pem \
-key intermediate/private/www.example.com.key.pem \
-cert intermediate/certs/www.example.com.cert.pem \
-www
Enter pass phrase for intermediate/private/www.example.com.key.pem:
Using default temp DH parameters
ACCEPT
   0 items in the session cache
   0 client connects (SSL_connect())
   0 client renegotiates (SSL_connect())
   0 client connects that finished
   0 server accepts (SSL_accept())
   0 server renegotiates (SSL_accept())
   0 server accepts that finished
   0 session cache hits
   0 session cache misses
   0 session cache timeouts
   0 callback cache hits
   0 cache full overflows (128 allowed)
$

Going with a hunch, I ran it again with strace set to spit out any socket-related system calls (-esocket), and saw this:

$ strace -esocket openssl s_server -CAfile certs/chain.pem \
-key intermediate/private/www.example.com.key.pem \
-cert intermediate/certs/www.example.com.cert.pem \
-www
Enter pass phrase for intermediate/private/www.example.com.key.pem:
Using default temp DH parameters
ACCEPT
socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) = -1 EAFNOSUPPORT (Address family not supported by protocol)
   0 items in the session cache
   0 client connects (SSL_connect())
   0 client renegotiates (SSL_connect())
   0 client connects that finished
   0 server accepts (SSL_accept())
   0 server renegotiates (SSL_accept())
   0 server accepts that finished
   0 session cache hits
   0 session cache misses
   0 session cache timeouts
   0 callback cache hits
   0 cache full overflows (128 allowed)
+++ exited with 0 +++
$

Aha!! Address family not supported by protocol As I suspected, it was trying to bind to an IPv6 address (by calling AF_INET6), but​ my system doesn’t have IPv6 support built into the kernel!

$ grep CONFIG_IPV6 /usr/src/linux/.config
# CONFIG_IPV6 is not set
$

The fiendishly simple solution

To get it to work, all I had to do was add -4 onto the s_server argument list to force it to bind to an IPv4 address

$ openssl s_server -CAfile certs/chain.pem \
-key intermediate/private/www.example.com.key.pem \
-cert intermediate/certs/www.example.com.cert.pem \
-www \
-4
Enter pass phrase for intermediate/private/www.example.com.key.pem:
Using default temp DH parameters
ACCEPT

Success! :-D