Package: erlang
Version: 11.b.2-4
Severity: wishlist
Tags: patch

Included patch adds support for IPv6 to the ssl application.
After applying the patch, you need to run autoconf and autoheader in the
erts subdir.


-- System Information:
Debian Release: 4.0
  APT prefers testing
  APT policy: (750, 'testing'), (671, 'stable'), (500, 'testing'), (300, 
'unstable'), (1, 'experimental')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.18-3-k7
Locale: LANG=sv_SE.UTF-8, LC_CTYPE=sv_SE.UTF-8 (charmap=UTF-8)
diff -ur erlang-11.b.2.orig/erts/configure.in erlang-11.b.2/erts/configure.in
--- erlang-11.b.2.orig/erts/configure.in	2007-03-04 17:46:34.000000000 +0100
+++ erlang-11.b.2/erts/configure.in	2007-03-04 12:42:33.000000000 +0100
@@ -1051,6 +1051,8 @@
 dnl inet_gethost with ipv6 support.
 AC_CHECK_FUNCS([getipnodebyname getipnodebyaddr gethostbyname2])
 AC_CHECK_TYPES([struct in6_addr],,,[#include<netdb.h>])
+AC_CHECK_FUNCS([getnameinfo inet_pton])
+AC_CHECK_TYPES([struct sockaddr_storage],,,[#include <netinet/in.h>])
 
 AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \
 		pread pwrite writev memmove strerror strerror_r strncasecmp \
diff -ur erlang-11.b.2.orig/lib/ssl/c_src/esock.c erlang-11.b.2/lib/ssl/c_src/esock.c
--- erlang-11.b.2.orig/lib/ssl/c_src/esock.c	2006-05-03 10:18:31.000000000 +0200
+++ erlang-11.b.2/lib/ssl/c_src/esock.c	2007-03-04 17:39:41.000000000 +0100
@@ -130,6 +130,11 @@
 #define INADDR_NONE 0xffffffff  /* Should be in <netinet/in.h>.  */
 #endif
 
+#if defined(HAVE_STRUCT_SOCKADDR_STORAGE) && defined(HAVE_GETNAMEINFO) && \
+    defined(HAVE_INET_PTON)
+# define USE_IPV6
+#endif
+
 #include "esock.h"
 #include "debuglog.h"
 #include "esock_utils.h"
@@ -175,6 +180,15 @@
 static void print_connections(void);
 static int check_num_sock_fds(FD fd); 
 static void safe_close(FD fd);
+
+#if defined(USE_IPV6)
+static FD do_connect6(char *lipstring, int lport, char *fipstring, int fport);
+static FD do_listen6(char *ipstring, int lport, int backlog, int *aport);
+static int ss_getport(const struct sockaddr *sa, socklen_t size);
+static int reply_sockaddr(int cmd, int fd, const struct sockaddr *sa,
+			  socklen_t size);
+#endif
+
 static Connection *new_connection(int state, FD fd);
 static Connection *get_connection(FD fd);
 static void remove_connection(Connection *conn);
@@ -362,7 +376,11 @@
     char *protocol_vsn, *cipher;
     unsigned char *cert, *bin;
     int certlen, binlen;
+#if defined(USE_IPV6)
+    struct sockaddr_storage iserv_addr;
+#else
     struct sockaddr_in iserv_addr;
+#endif
     int sret = 1;
     Connection *cp, *cpnext, *newcp;
     Proxy *pp;
@@ -439,7 +457,12 @@
 			/* Add to pending proxy connections */
 			SET_NONBLOCKING(proxysock);
 			pp = new_proxy(proxysock);
+#if defined(USE_IPV6)
+			pp->peer_port =
+			    ss_getport((struct sockaddr *)&iserv_addr, length);
+#else
 			pp->peer_port = ntohs(iserv_addr.sin_port);
+#endif
 			DEBUGF(("-----------------------------------\n"));
 			DEBUGF(("[PROXY_LISTEN_SOCK] conn accepted: "
 				"proxyfd = %d, "
@@ -494,9 +517,14 @@
 			 * reply  = {cmd(1), fd(4), port(2), 
 			 * 	    ipstring(N), 0(1)}
 			 */
+#if defined(USE_IPV6)
+			reply_sockaddr(ESOCK_GETPEERNAME_REP, fd,
+				       (struct sockaddr*)&iserv_addr, length);
+#else
 			reply(ESOCK_GETPEERNAME_REP, "42s", fd, 
 			      ntohs(iserv_addr.sin_port), 
 			      inet_ntoa(iserv_addr.sin_addr));
+#endif
 		    }
 		    break;
 
@@ -520,9 +548,14 @@
 			 * reply  = {cmd(1), fd(4), port(2), 
 			 * 	    ipstring(N), 0(1)}
 			 */
+#if defined(USE_IPV6)
+			reply_sockaddr(ESOCK_GETSOCKNAME_REP, fd,
+				       (struct sockaddr*)&iserv_addr, length);
+#else
 			reply(ESOCK_GETSOCKNAME_REP, "42s", fd, 
 			      ntohs(iserv_addr.sin_port),
 			      inet_ntoa(iserv_addr.sin_addr));
+#endif
 		    }
 		    break;
 
@@ -698,8 +731,7 @@
 		    }
 		    DEBUGF(("-> PASSIVE_LISTENING (fd = %d)\n", listensock));
 		    /* Publish listensock */
-		    reply(ESOCK_LISTEN_REP, "442", intref, listensock,
-			  ntohs(iserv_addr.sin_port));
+		    reply(ESOCK_LISTEN_REP, "442", intref, listensock, lport);
 		    break;
 
 		case ESOCK_ACCEPT_CMD:
@@ -1481,6 +1513,11 @@
     struct sockaddr_in sock_addr;
     long inaddr;
     FD fd;
+
+#if defined(USE_IPV6)
+    if (strchr(fipstring, ':'))
+	return do_connect6(lipstring, lport, fipstring, fport);
+#endif
    
     if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
 	DEBUGF(("Error calling socket()\n"));
@@ -1538,9 +1575,14 @@
     static int one = 1;		/* Type must be int, not long */
     struct sockaddr_in sock_addr;
     long inaddr;
-    int length;
+    unsigned int length;
     FD fd;
     
+#if defined(USE_IPV6)
+    if (strchr(ipstring, ':'))
+	return do_listen6(ipstring, lport, backlog, aport);
+#endif
+
     if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
 	DEBUGF(("Error calling socket()\n"));
 	return fd;
@@ -1596,6 +1638,145 @@
     return fd;
 }
 
+#if defined(USE_IPV6)
+static FD do_connect6(char *lipstring, int lport, char *fipstring, int fport)
+{
+    struct sockaddr_in6 sock_addr;
+    FD fd;
+
+    if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_FD) {
+	DEBUGF(("Error calling socket()\n"));
+	return fd;
+    }
+    if (check_num_sock_fds(fd) < 0) 
+	return INVALID_FD;
+    DEBUGF(("  fd = %d\n", fd));
+
+    memset(&sock_addr, 0, sizeof(sock_addr));
+    /* local */
+    if (inet_pton(AF_INET6, lipstring, &sock_addr.sin6_addr) <= 0) {
+	DEBUGF(("Error in inet_pton(): lipstring = %s\n", lipstring));
+	safe_close(fd);
+	sock_set_errno(ERRNO_ADDRNOTAVAIL);
+	return INVALID_FD;
+    }
+    sock_addr.sin6_family = AF_INET6;
+    sock_addr.sin6_port = htons(lport);
+    if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+	DEBUGF(("Error in bind()\n"));
+	safe_close(fd);
+	/* XXX Set error code for bind error */
+	return INVALID_FD;
+    }
+
+    /* foreign */
+    memset(&sock_addr, 0, sizeof(sock_addr));
+    if (inet_pton(AF_INET6, fipstring, &sock_addr.sin6_addr) <= 0) {
+	DEBUGF(("Error in inet_pton(): fipstring = %s\n", fipstring));
+	safe_close(fd);
+	sock_set_errno(ERRNO_ADDRNOTAVAIL);
+	return INVALID_FD;
+    }
+    sock_addr.sin6_family = AF_INET6;
+    sock_addr.sin6_port = htons(fport);
+
+    SET_NONBLOCKING(fd);
+
+    if(connect(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
+	if (sock_errno() != ERRNO_PROGRESS && /* UNIX */
+	    sock_errno() != ERRNO_BLOCK) { /* WIN32 */
+	    DEBUGF(("Error in connect()\n"));
+	    safe_close(fd);
+	    return INVALID_FD;
+	}
+    }
+    return fd;
+}
+
+static FD do_listen6(char *ipstring, int lport, int backlog, int *aport)
+{
+    static int one = 1;		/* Type must be int, not long */
+    struct sockaddr_in6 sock_addr;
+    socklen_t length;
+    FD fd;
+    
+    if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_FD) {
+	DEBUGF(("Error calling socket()\n"));
+	return fd;
+    }
+    if (check_num_sock_fds(fd) < 0) 
+	return INVALID_FD;
+    DEBUGF(("  fd = %d\n", fd));
+    memset(&sock_addr, 0, sizeof(sock_addr));
+    if (inet_pton(AF_INET6, ipstring, &sock_addr.sin6_addr) <= 0) {
+	DEBUGF(("Error in inet_pton(): ipstring = %s\n", ipstring));
+	safe_close(fd);
+	sock_set_errno(ERRNO_ADDRNOTAVAIL);
+	return INVALID_FD;
+    }
+    sock_addr.sin6_family = AF_INET6;
+    sock_addr.sin6_port = htons(lport);
+
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
+
+    if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+	DEBUGF(("Error in bind()\n"));
+	safe_close(fd);
+	return INVALID_FD;
+    }
+    if (listen(fd, backlog) < 0) {
+	DEBUGF(("Error in listen()\n"));
+	safe_close(fd);
+	return INVALID_FD;
+    }
+    /* find out assigned local port number */
+    length = sizeof(sock_addr);
+    if (getsockname(fd, (struct sockaddr *)&sock_addr, &length) < 0) {
+	DEBUGF(("Error in getsockname()\n"));
+	safe_close(fd);
+	return INVALID_FD;
+    }
+    if (aport)
+	*aport = ntohs(sock_addr.sin6_port);
+    return fd;
+}
+
+static int reply_sockaddr(int cmd, int fd, const struct sockaddr *sa,
+			  socklen_t size)
+{
+    char addr[INET6_ADDRSTRLEN+1] = "";
+    char port[10] = "";
+    int res;
+
+    res = getnameinfo(sa, size,
+		      addr, sizeof(addr), port, sizeof(port),
+		      NI_NUMERICHOST | NI_NUMERICSERV);
+    if (res) {
+	if (res != EAI_SYSTEM) {
+	    sock_set_errno(ERRNO_INVAL);
+	}
+	return reply(cmd, "4s", fd, psx_errstr());
+    } else {
+	return reply(cmd, "42s", fd, atoi(port), addr);
+    }
+}
+
+static int ss_getport(const struct sockaddr *sa, socklen_t size)
+{
+    char port[10] = "";
+    int res;
+
+    res = getnameinfo(sa, size,
+		      NULL, 0, port, sizeof(port), NI_NUMERICSERV);
+    if (res) {
+	return -1;
+    } else {
+	return atoi(port);
+    }
+}
+#endif
+
+
 static Connection *new_connection(int state, FD fd)
 {
     Connection *cp;
diff -ur erlang-11.b.2.orig/lib/ssl/src/ssl_broker.erl erlang-11.b.2/lib/ssl/src/ssl_broker.erl
--- erlang-11.b.2.orig/lib/ssl/src/ssl_broker.erl	2006-05-03 10:18:30.000000000 +0200
+++ erlang-11.b.2/lib/ssl/src/ssl_broker.erl	2007-03-04 12:42:33.000000000 +0100
@@ -441,7 +441,7 @@
     debug(St, "peername: client = ~w~n", [Client]),
     Reply = case ssl_server:peername(St#st.fd) of
 		{ok, {Address, Port}} ->
-		    {ok, At} = inet_parse:ipv4_address(Address),
+		    {ok, At} = inet_parse:address(Address),
 		    {ok, {At, Port}};
 		Error ->
 		    Error
@@ -498,7 +498,7 @@
     debug(St, "sockname: client = ~w~n", [Client]),
     Reply = case ssl_server:sockname(St#st.fd) of
 		{ok, {Address, Port}} ->
-		    {ok, At} = inet_parse:ipv4_address(Address),
+		    {ok, At} = inet_parse:address(Address),
 		    {ok, {At, Port}};
 		Error ->
 		    Error
@@ -661,7 +661,8 @@
     SSLOpts = get_ssl_opts(Opts),
     FlagStr =mk_ssl_optstr(SSLOpts),
     BackLog = get_backlog(LOpts),
-    IP = get_ip(LOpts),
+    Family = get_family(Opts),
+    IP = get_ip(LOpts, Family),
     case ssl_server:listen_prim(ServerName, IP, Port, FlagStr, BackLog) of
 	{ok, ListenFd, _Port0} ->
 	    ThisSocket = #sslsocket{fd = ListenFd, pid = self()},
@@ -684,10 +685,11 @@
     COpts = get_tcp_connect_opts(Opts),
     SSLOpts = get_ssl_opts(Opts),
     FlagStr = mk_ssl_optstr(SSLOpts),
-    case inet:getaddr(FAddress, inet) of
+    Family = get_family(Opts),
+    case inet:getaddr(FAddress, Family) of
 	{ok, FIP} ->
 	    %% Timeout is gen_server timeout - hence catch
-	    LIP = get_ip(COpts),
+	    LIP = get_ip(COpts, Family),
 	    LPort = get_port(COpts),
 	    case (catch ssl_server:connect_prim(ServerName, 
 						LIP, LPort, FIP, FPort, 
@@ -945,8 +947,13 @@
 get_backlog(Opts) ->
     get_tagged_opt(backlog, Opts, ?DEF_BACKLOG).
 
-get_ip(Opts) ->
-    get_tagged_opt(ip, Opts, {0, 0, 0, 0}).
+get_ip(Opts, Family) ->
+    DefaultIp =
+	case Family of
+	    inet -> {0, 0, 0, 0};
+	    inet6 -> {0, 0, 0, 0, 0, 0, 0, 0}
+	end,
+    get_tagged_opt(ip, Opts, DefaultIp).
 
 get_port(Opts) ->
     get_tagged_opt(port, Opts, 0).
@@ -954,6 +961,9 @@
 get_nodelay(Opts) ->
     get_tagged_opt(nodelay, Opts, empty).
 
+get_family(Opts) ->
+    get_tagged_opt(family, transform_opts(Opts), inet).
+
 %%
 %% add_default_*_opts(Opts) -> NOpts
 %%
@@ -1002,6 +1012,8 @@
 transform_opt(binary) -> 		[{mode, binary}];
 transform_opt(list) -> 			[{mode, list}];
 transform_opt({packet, raw}) ->		[{packet, 0}];
+transform_opt(inet) ->			[{family, inet}];
+transform_opt(inet6) ->			[{family, inet6}];
 transform_opt(raw) -> 			[];
 transform_opt(Opt) -> 			[Opt].
 
@@ -1009,10 +1021,10 @@
 %% only.
 
 is_connect_opt(Opt) ->
-    is_tcp_connect_opt(Opt) or is_ssl_opt(Opt).
+    is_tcp_connect_opt(Opt) or is_ssl_opt(Opt) or is_family_opt(Opt).
 
 is_listen_opt(Opt) ->
-    is_tcp_listen_opt(Opt) or is_ssl_opt(Opt).
+    is_tcp_listen_opt(Opt) or is_ssl_opt(Opt) or is_family_opt(Opt).
 
 is_tcp_accept_opt(Opt) ->
     is_tcp_gen_opt(Opt).
@@ -1064,6 +1076,10 @@
 is_ssl_opt({cachetimeout, Timeout}) when Timeout >= 0 -> true;
 is_ssl_opt(_Opt) -> false.
 
+is_family_opt({family, inet}) -> true;
+is_family_opt({family, inet6}) -> true;
+is_family_opt(_Opt) -> false.
+
 %% Various types
 is_string(String) when is_list(String) ->
     lists:all(fun (C) when is_integer(C), 0 =< C, C =< 255 -> true; 
@@ -1074,11 +1090,20 @@
 
 is_ip_address(Addr) when is_tuple(Addr), size(Addr) == 4 ->
     is_string(tuple_to_list(Addr));
+is_ip_address(Addr) when is_tuple(Addr), size(Addr) == 8 ->
+    is_ip6_string(tuple_to_list(Addr));
 is_ip_address(Addr) when is_list(Addr) ->
     is_string(Addr);
 is_ip_address(_) ->
     false.
 
+is_ip6_string(String) when is_list(String) ->
+    lists:all(fun (C) when is_integer(C), 0 =< C, C =< 65535 -> true; 
+		  (_C) -> false end, 
+	      String);
+is_ip6_string(_) ->
+    false.
+
 get_tagged_opt(Tag, Opts, Default) ->
     case lists:keysearch(Tag, 1, Opts) of
 	{value, {_, Value}} ->
diff -ur erlang-11.b.2.orig/lib/ssl/src/ssl_prim.erl erlang-11.b.2/lib/ssl/src/ssl_prim.erl
--- erlang-11.b.2.orig/lib/ssl/src/ssl_prim.erl	2006-05-03 10:19:24.000000000 +0200
+++ erlang-11.b.2/lib/ssl/src/ssl_prim.erl	2007-03-04 12:42:33.000000000 +0100
@@ -107,7 +107,7 @@
 peername(St) when record(St, st), St#st.status =:= open  ->
     case ssl_server:peername_prim(ssl_server_prim, St#st.fd) of
 	{ok, {Address, Port}} ->
-	    {ok, At} = inet_parse:ipv4_address(Address),
+	    {ok, At} = inet_parse:address(Address),
 	    {ok, {At, Port}};
 	Error ->
 	    Error
@@ -119,7 +119,7 @@
 sockname(St) when record(St, st), St#st.status =:= open  ->
     case ssl_server:sockname_prim(ssl_server_prim, St#st.fd) of
 	{ok, {Address, Port}} ->
-	    {ok, At} = inet_parse:ipv4_address(Address),
+	    {ok, At} = inet_parse:address(Address),
 	    {ok, {At, Port}};
 	Error ->
 	    Error
diff -ur erlang-11.b.2.orig/lib/ssl/src/ssl_server.erl erlang-11.b.2/lib/ssl/src/ssl_server.erl
--- erlang-11.b.2.orig/lib/ssl/src/ssl_server.erl	2006-05-03 10:18:31.000000000 +0200
+++ erlang-11.b.2/lib/ssl/src/ssl_server.erl	2007-03-04 12:42:33.000000000 +0100
@@ -1227,7 +1227,10 @@
 
 ip_to_string({A,B,C,D}) ->
     [integer_to_list(A),$.,integer_to_list(B),$.,
-     integer_to_list(C),$.,integer_to_list(D)].
+     integer_to_list(C),$.,integer_to_list(D)];
+
+ip_to_string(Addr) when is_tuple(Addr), size(Addr) == 8 ->
+    inet_parse:ntoa(Addr).
 
 debug(St, Format, Args) ->
     debug1(St#st.debug, Format, Args).

Reply via email to