Merged IPv6 support in the NET module
diff --git a/ChangeLog b/ChangeLog
index 2ff3694..3eadbcc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,7 @@
(POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
* Support for Curve25519
* Support for ECDH-RSA and ECDH-ECDSA key exchanges and ciphersuites
+ * Support for IPv6 in the NET module
Changes
* gen_prime() speedup
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index 970212f..7bbef55 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -101,6 +101,16 @@
* Comment if your system does not support time functions
*/
#define POLARSSL_HAVE_TIME
+
+/**
+ * \def POLARSSL_HAVE_IPV6
+ *
+ * System supports the basic socket interface for IPv6 (RFC 3493),
+ * specifically getaddrinfo(), freeaddrinfo() and struct sockaddr_storage.
+ *
+ * Comment if your system does not support the IPv6 socket interface
+ */
+#define POLARSSL_HAVE_IPV6
/* \} name SECTION: System support */
/**
diff --git a/include/polarssl/net.h b/include/polarssl/net.h
index 88302ac..22698b4 100644
--- a/include/polarssl/net.h
+++ b/include/polarssl/net.h
@@ -82,9 +82,10 @@
* \param bind_fd Relevant socket
* \param client_fd Will contain the connected client socket
* \param client_ip Will contain the client IP address
+ * Must be at least 4 bytes, or 16 if IPv6 is supported
*
* \return 0 if successful, POLARSSL_ERR_NET_ACCEPT_FAILED, or
- * POLARSSL_ERR_NET_WOULD_BLOCK is bind_fd was set to
+ * POLARSSL_ERR_NET_WANT_READ is bind_fd was set to
* non-blocking and accept() is blocking.
*/
int net_accept( int bind_fd, int *client_fd, void *client_ip );
diff --git a/library/net.c b/library/net.c
index be2785d..19f699d 100644
--- a/library/net.c
+++ b/library/net.c
@@ -81,6 +81,11 @@
#include <stdlib.h>
#include <stdio.h>
+#if defined(_MSC_VER) && !defined snprintf && !defined(EFIX64) && \
+ !defined(EFI32)
+#define snprintf _snprintf
+#endif
+
#if defined(POLARSSL_HAVE_TIME)
#include <time.h>
#endif
@@ -115,16 +120,12 @@
#define net_htonl(n) POLARSSL_HTONL(n)
/*
- * Initiate a TCP connection with host:port
+ * Prepare for using the sockets interface
*/
-int net_connect( int *fd, const char *host, int port )
+static void net_prepare( void )
{
- struct sockaddr_in server_addr;
- struct hostent *server_host;
-
#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
!defined(EFI32)
-
WSADATA wsaData;
if( wsa_init_done == 0 )
@@ -139,6 +140,64 @@
signal( SIGPIPE, SIG_IGN );
#endif
#endif
+}
+
+/*
+ * Initiate a TCP connection with host:port
+ */
+int net_connect( int *fd, const char *host, int port )
+{
+#if defined(POLARSSL_HAVE_IPV6)
+ int ret = POLARSSL_ERR_NET_UNKNOWN_HOST;
+ struct addrinfo hints, *addr_list, *cur;
+ char port_str[6];
+
+ net_prepare();
+
+ /* getaddrinfo expects port as a string */
+ memset( port_str, 0, sizeof( port_str ) );
+ snprintf( port_str, sizeof( port_str ), "%d", port );
+
+ /* Do name resolution with both IPv6 and IPv4, but only TCP */
+ memset( &hints, 0, sizeof( hints ) );
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ if( getaddrinfo( host, port_str, &hints, &addr_list ) != 0 )
+ return( POLARSSL_ERR_NET_UNKNOWN_HOST );
+
+ /* Try the sockaddrs until a connection succeeds */
+ for( cur = addr_list; cur != NULL; cur = cur->ai_next )
+ {
+ *fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
+ if( *fd < 0 )
+ {
+ ret = POLARSSL_ERR_NET_SOCKET_FAILED;
+ continue;
+ }
+
+ if( connect( *fd, cur->ai_addr, cur->ai_addrlen ) == 0 )
+ {
+ ret = 0;
+ break;
+ }
+
+ close( *fd );
+ ret = POLARSSL_ERR_NET_CONNECT_FAILED;
+ }
+
+ freeaddrinfo( addr_list );
+
+ return( ret );
+
+#else
+ /* Legacy IPv4-only version */
+
+ struct sockaddr_in server_addr;
+ struct hostent *server_host;
+
+ net_prepare();
if( ( server_host = gethostbyname( host ) ) == NULL )
return( POLARSSL_ERR_NET_UNKNOWN_HOST );
@@ -161,6 +220,7 @@
}
return( 0 );
+#endif /* POLARSSL_HAVE_IPV6 */
}
/*
@@ -168,25 +228,72 @@
*/
int net_bind( int *fd, const char *bind_ip, int port )
{
+#if defined(POLARSSL_HAVE_IPV6)
+ int n, ret = POLARSSL_ERR_NET_UNKNOWN_HOST;
+ struct addrinfo hints, *addr_list, *cur;
+ char port_str[6];
+
+ net_prepare();
+
+ /* getaddrinfo expects port as a string */
+ memset( port_str, 0, sizeof( port_str ) );
+ snprintf( port_str, sizeof( port_str ), "%d", port );
+
+ /* Bind to IPv6 and/or IPv4, but only in TCP */
+ memset( &hints, 0, sizeof( hints ) );
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ if( bind_ip == NULL )
+ hints.ai_flags = AI_PASSIVE;
+
+ if( getaddrinfo( bind_ip, port_str, &hints, &addr_list ) != 0 )
+ return( POLARSSL_ERR_NET_UNKNOWN_HOST );
+
+ /* Try the sockaddrs until a binding succeeds */
+ for( cur = addr_list; cur != NULL; cur = cur->ai_next )
+ {
+ *fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
+ if( *fd < 0 )
+ {
+ ret = POLARSSL_ERR_NET_SOCKET_FAILED;
+ continue;
+ }
+
+ n = 1;
+ setsockopt( *fd, SOL_SOCKET, SO_REUSEADDR,
+ (const char *) &n, sizeof( n ) );
+
+ if( bind( *fd, cur->ai_addr, cur->ai_addrlen ) != 0 )
+ {
+ close( *fd );
+ ret = POLARSSL_ERR_NET_BIND_FAILED;
+ continue;
+ }
+
+ if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 )
+ {
+ close( *fd );
+ ret = POLARSSL_ERR_NET_LISTEN_FAILED;
+ continue;
+ }
+
+ /* I we ever get there, it's a success */
+ ret = 0;
+ break;
+ }
+
+ freeaddrinfo( addr_list );
+
+ return( ret );
+
+#else
+ /* Legacy IPv4-only version */
+
int n, c[4];
struct sockaddr_in server_addr;
-#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \
- !defined(EFI32)
- WSADATA wsaData;
-
- if( wsa_init_done == 0 )
- {
- if( WSAStartup( MAKEWORD(2,0), &wsaData ) == SOCKET_ERROR )
- return( POLARSSL_ERR_NET_SOCKET_FAILED );
-
- wsa_init_done = 1;
- }
-#else
-#if !defined(EFIX64) && !defined(EFI32)
- signal( SIGPIPE, SIG_IGN );
-#endif
-#endif
+ net_prepare();
if( ( *fd = (int) socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 )
return( POLARSSL_ERR_NET_SOCKET_FAILED );
@@ -230,6 +337,7 @@
}
return( 0 );
+#endif /* POLARSSL_HAVE_IPV6 */
}
/*
@@ -260,7 +368,11 @@
*/
int net_accept( int bind_fd, int *client_fd, void *client_ip )
{
+#if defined(POLARSSL_HAVE_IPV6)
+ struct sockaddr_storage client_addr;
+#else
struct sockaddr_in client_addr;
+#endif
#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \
defined(_SOCKLEN_T_DECLARED)
@@ -281,8 +393,25 @@
}
if( client_ip != NULL )
+ {
+#if defined(POLARSSL_HAVE_IPV6)
+ if( client_addr.ss_family == AF_INET )
+ {
+ struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;
+ memcpy( client_ip, &addr4->sin_addr.s_addr,
+ sizeof( addr4->sin_addr.s_addr ) );
+ }
+ else
+ {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr;
+ memcpy( client_ip, &addr6->sin6_addr.s6_addr,
+ sizeof( addr6->sin6_addr.s6_addr ) );
+ }
+#else
memcpy( client_ip, &client_addr.sin_addr.s_addr,
sizeof( client_addr.sin_addr.s_addr ) );
+#endif /* POLARSSL_HAVE_IPV6 */
+ }
return( 0 );
}
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 96cbb49..7233dff 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -49,6 +49,7 @@
#include "polarssl/memory.h"
#endif
+#define DFL_SERVER_ADDR NULL
#define DFL_SERVER_PORT 4433
#define DFL_DEBUG_LEVEL 0
#define DFL_CA_FILE ""
@@ -91,6 +92,7 @@
*/
struct options
{
+ const char *server_addr; /* address on which the ssl service runs */
int server_port; /* port on which the ssl service runs */
int debug_level; /* level of debugging */
const char *ca_file; /* the file with the CA certificate(s) */
@@ -172,6 +174,7 @@
#define USAGE \
"\n usage: ssl_server2 param=<>...\n" \
"\n acceptable parameters:\n" \
+ " server_addr=%%d default: (all interfaces)\n" \
" server_port=%%d default: 4433\n" \
" debug_level=%%d default: 0 (disabled)\n" \
USAGE_IO \
@@ -281,6 +284,7 @@
goto exit;
}
+ opt.server_addr = DFL_SERVER_ADDR;
opt.server_port = DFL_SERVER_PORT;
opt.debug_level = DFL_DEBUG_LEVEL;
opt.ca_file = DFL_CA_FILE;
@@ -313,6 +317,8 @@
if( opt.server_port < 1 || opt.server_port > 65535 )
goto usage;
}
+ else if( strcmp( p, "server_addr" ) == 0 )
+ opt.server_addr = q;
else if( strcmp( p, "debug_level" ) == 0 )
{
opt.debug_level = atoi( q );
@@ -678,7 +684,8 @@
printf( " . Bind on tcp://localhost:%-4d/ ...", opt.server_port );
fflush( stdout );
- if( ( ret = net_bind( &listen_fd, NULL, opt.server_port ) ) != 0 )
+ if( ( ret = net_bind( &listen_fd, opt.server_addr,
+ opt.server_port ) ) != 0 )
{
printf( " failed\n ! net_bind returned -0x%x\n\n", -ret );
goto exit;
diff --git a/tests/compat.sh b/tests/compat.sh
index 36f241b..ecc2e58 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -354,8 +354,8 @@
kill $PROCESS_ID
wait $PROCESS_ID 2>/dev/null
-log "../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE > /dev/null"
-../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE > /dev/null &
+log "../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE > /dev/null"
+../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE > /dev/null &
PROCESS_ID=$!
sleep 1
@@ -390,8 +390,8 @@
kill $PROCESS_ID
wait $PROCESS_ID 2>/dev/null
-log "../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE"
-../programs/ssl/ssl_server2 $P_SERVER_ARGS force_version=$MODE > /dev/null &
+log "../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE"
+../programs/ssl/ssl_server2 server_addr=0.0.0.0 $P_SERVER_ARGS force_version=$MODE > /dev/null &
PROCESS_ID=$!
sleep 1