Blame otp-0009-epmd-support-IPv6-node-registration.patch

John Eckersberg da1dfd
From: Michael Santos <michael.santos@gmail.com>
John Eckersberg da1dfd
Date: Sun, 18 Oct 2015 16:20:37 -0400
John Eckersberg da1dfd
Subject: [PATCH] epmd: support IPv6 node registration
John Eckersberg da1dfd
John Eckersberg da1dfd
Allow IPv6 nodes to register with and query epmd. On systems with
John Eckersberg da1dfd
IPv6 support:
John Eckersberg da1dfd
John Eckersberg da1dfd
* epmd listens on both the IPv4 and IPv6 ANY or loopback sockets
John Eckersberg da1dfd
John Eckersberg da1dfd
* the epmd cli client connects to epmd over the IPv6 loopback
John Eckersberg da1dfd
John Eckersberg da1dfd
* distributed nodes started with "-proto_dist inet6_tcp" will register
John Eckersberg da1dfd
  with epmd over IPv6
John Eckersberg da1dfd
John Eckersberg da1dfd
To work on IPv6 capable systems that have IPv6 support disabled,
John Eckersberg da1dfd
epmd ignores errors opening the socket if the protocol is not
John Eckersberg da1dfd
supported. Similarly, the epmd client will fall back to IPv4 if the IPv6
John Eckersberg da1dfd
socket is not available.
John Eckersberg da1dfd
John Eckersberg da1dfd
The interaction between IPv4 and IPv6 sockets depends on the platform:
John Eckersberg da1dfd
John Eckersberg da1dfd
* FreeBSD allows multiple "specific" sockets to bind the same port (such
John Eckersberg da1dfd
  as 2 sockets listening to the same port on ANY and the loopback).
John Eckersberg da1dfd
  Binding port 4369 to IPv4 and IPv6 sockets simulataneously is allowed.
John Eckersberg da1dfd
John Eckersberg da1dfd
* Linux does not allow the same port to be bound by different sockets.
John Eckersberg da1dfd
  Setting the IPV6_V6ONLY socket option is required.
John Eckersberg da1dfd
John Eckersberg da1dfd
* Windows
John Eckersberg da1dfd
John Eckersberg da1dfd
  The behaviour differs depending on the version of Windows:
John Eckersberg da1dfd
John Eckersberg da1dfd
  http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
John Eckersberg da1dfd
John Eckersberg da1dfd
  According to the site, sockets on Windows XP with Service Pack 1 (SP1)
John Eckersberg da1dfd
  and Windows Server 2003 will only listen on either IPv4 or IPv6, so
John Eckersberg da1dfd
  creating two sockets is required to service IPv4 and IPv6 traffic on
John Eckersberg da1dfd
  the same port. The IPV6_V6ONLY socket option is not supported.
John Eckersberg da1dfd
John Eckersberg da1dfd
  For Windows Vista and later, a single socket can handle IPv4 and IPv6
John Eckersberg da1dfd
  traffic for the same port. The IPV6_V6ONLY socket option is supported
John Eckersberg da1dfd
  and is enabled for IPv6 sockets by default.
John Eckersberg da1dfd
John Eckersberg da1dfd
diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml
John Eckersberg da1dfd
index 28fcc8f..7f61804 100644
John Eckersberg da1dfd
--- a/erts/doc/src/epmd.xml
John Eckersberg da1dfd
+++ b/erts/doc/src/epmd.xml
John Eckersberg da1dfd
@@ -37,7 +37,7 @@
John Eckersberg da1dfd
   <comsummary>
John Eckersberg da1dfd
   

Erlang Port Mapper Daemon

John Eckersberg da1dfd
   <taglist>
John Eckersberg da1dfd
-  <tag><c></c></tag>
John Eckersberg da1dfd
+  <tag><c></c></tag>
John Eckersberg da1dfd
   <item>
John Eckersberg da1dfd
   

Starts the port mapper daemon

John Eckersberg da1dfd
   </item>
John Eckersberg da1dfd
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
John Eckersberg da1dfd
index ec4a0de..cdf8aef 100644
John Eckersberg da1dfd
--- a/erts/doc/src/erl.xml
John Eckersberg da1dfd
+++ b/erts/doc/src/erl.xml
John Eckersberg da1dfd
@@ -382,6 +382,28 @@
John Eckersberg da1dfd
           similar to <c></c>. See
John Eckersberg da1dfd
           <seealso marker="kernel:code">code(3)</seealso>.

John Eckersberg da1dfd
       </item>
John Eckersberg da1dfd
+      <tag><c></c></tag>
John Eckersberg da1dfd
+      <item>
John Eckersberg da1dfd
+        

Specify a protocol for Erlang distribution.

John Eckersberg da1dfd
+	    <taglist>
John Eckersberg da1dfd
+	      <tag><c>inet_tcp</c></tag>
John Eckersberg da1dfd
+              <item>
John Eckersberg da1dfd
+                  

TCP over IPv4 (the default)

John Eckersberg da1dfd
+              </item>
John Eckersberg da1dfd
+	      <tag><c>inet_tls</c></tag>
John Eckersberg da1dfd
+              <item>
John Eckersberg da1dfd
+                  

distribution over TLS/SSL

John Eckersberg da1dfd
+              </item>
John Eckersberg da1dfd
+	      <tag><c>inet6_tcp</c></tag>
John Eckersberg da1dfd
+              <item>
John Eckersberg da1dfd
+                  

TCP over IPv6

John Eckersberg da1dfd
+              </item>
John Eckersberg da1dfd
+        </taglist>
John Eckersberg da1dfd
+        

For example, to start up IPv6 distributed nodes:

John Eckersberg da1dfd
+
John Eckersberg da1dfd
+% <input>erl -name test@ipv6node.example.com -proto_dist inet6_tcp</input>
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+      </item>
John Eckersberg da1dfd
       <tag><c></c></tag>
John Eckersberg da1dfd
       <item>
John Eckersberg da1dfd
         

Starts Erlang with a remote shell connected to <c></c>.

John Eckersberg da1dfd
diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
John Eckersberg da1dfd
index 63ec18d..5513cb2 100644
John Eckersberg da1dfd
--- a/erts/epmd/src/epmd.c
John Eckersberg da1dfd
+++ b/erts/epmd/src/epmd.c
John Eckersberg da1dfd
@@ -343,7 +343,7 @@ static void run_daemon(EpmdVars *g)
John Eckersberg da1dfd
     for (fd = 0; fd < g->max_conn ; fd++) /* close all files ... */
John Eckersberg da1dfd
         close(fd);
John Eckersberg da1dfd
     /* Syslog on linux will try to write to whatever if we dont
John Eckersberg da1dfd
-       inform it of that the log is closed. */
John Eckersberg da1dfd
+       inform it that the log is closed. */
John Eckersberg da1dfd
     closelog();
John Eckersberg da1dfd
 
John Eckersberg da1dfd
     /* These shouldn't be needed but for safety... */
John Eckersberg da1dfd
diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
John Eckersberg da1dfd
index a8fe865..6fc05e1 100644
John Eckersberg da1dfd
--- a/erts/epmd/src/epmd_cli.c
John Eckersberg da1dfd
+++ b/erts/epmd/src/epmd_cli.c
John Eckersberg da1dfd
@@ -136,19 +136,33 @@ void epmd_call(EpmdVars *g,int what)
John Eckersberg da1dfd
 static int conn_to_epmd(EpmdVars *g)
John Eckersberg da1dfd
 {
John Eckersberg da1dfd
     struct EPMD_SOCKADDR_IN address;
John Eckersberg da1dfd
+    size_t salen = 0;
John Eckersberg da1dfd
     int connect_sock;
John Eckersberg da1dfd
-    
John Eckersberg da1dfd
-    connect_sock = socket(FAMILY, SOCK_STREAM, 0);
John Eckersberg da1dfd
-    if (connect_sock<0)
John Eckersberg da1dfd
-	goto error;
John Eckersberg da1dfd
+    unsigned short sport = g->port;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+    SET_ADDR6(address, in6addr_loopback, sport);
John Eckersberg da1dfd
+    salen = sizeof(struct sockaddr_in6);
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+    connect_sock = socket(AF_INET6, SOCK_STREAM, 0);
John Eckersberg da1dfd
+    if (connect_sock>=0) {
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+    if (connect(connect_sock, (struct sockaddr*)&address, salen) == 0)
John Eckersberg da1dfd
+	return connect_sock;
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-    { /* store port number in unsigned short */
John Eckersberg da1dfd
-      unsigned short sport = g->port;
John Eckersberg da1dfd
-      SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport);
John Eckersberg da1dfd
+    close(connect_sock);
John Eckersberg da1dfd
     }
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+    SET_ADDR(address, htonl(INADDR_LOOPBACK), sport);
John Eckersberg da1dfd
+    salen = sizeof(struct sockaddr_in);
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-    if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0) 
John Eckersberg da1dfd
+    connect_sock = socket(AF_INET, SOCK_STREAM, 0);
John Eckersberg da1dfd
+    if (connect_sock<0)
John Eckersberg da1dfd
 	goto error;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+    if (connect(connect_sock, (struct sockaddr*)&address, salen) < 0)
John Eckersberg da1dfd
+	goto error;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
     return connect_sock;
John Eckersberg da1dfd
 
John Eckersberg da1dfd
  error:
John Eckersberg da1dfd
diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
John Eckersberg da1dfd
index 26100af..8f44c2a 100644
John Eckersberg da1dfd
--- a/erts/epmd/src/epmd_int.h
John Eckersberg da1dfd
+++ b/erts/epmd/src/epmd_int.h
John Eckersberg da1dfd
@@ -55,6 +55,7 @@
John Eckersberg da1dfd
 #  ifndef WINDOWS_H_INCLUDES_WINSOCK2_H
John Eckersberg da1dfd
 #    include <winsock2.h>
John Eckersberg da1dfd
 #  endif
John Eckersberg da1dfd
+#  include <ws2tcpip.h>
John Eckersberg da1dfd
 #  include <windows.h>
John Eckersberg da1dfd
 #  include <process.h>
John Eckersberg da1dfd
 #endif
John Eckersberg da1dfd
@@ -130,6 +131,12 @@
John Eckersberg da1dfd
 #  include <systemd/sd-daemon.h>
John Eckersberg da1dfd
 #endif /* HAVE_SYSTEMD_DAEMON */
John Eckersberg da1dfd
 
John Eckersberg da1dfd
+#if defined(HAVE_IN6) && defined(AF_INET6)
John Eckersberg da1dfd
+#if !defined(__WIN32__)
John Eckersberg da1dfd
+#  define EPMD6
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+
John Eckersberg da1dfd
 /* ************************************************************************ */
John Eckersberg da1dfd
 /* Replace some functions by others by making the function name a macro */
John Eckersberg da1dfd
 
John Eckersberg da1dfd
@@ -183,33 +190,53 @@
John Eckersberg da1dfd
 /* ************************************************************************ */
John Eckersberg da1dfd
 /* Macros that let us use IPv6                                              */
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6)
John Eckersberg da1dfd
+#if HAVE_IN6
John Eckersberg da1dfd
+#  if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY
John Eckersberg da1dfd
+#    if HAVE_DECL_IN6ADDR_ANY_INIT
John Eckersberg da1dfd
+static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } };
John Eckersberg da1dfd
+#    else
John Eckersberg da1dfd
+static const struct in6_addr in6addr_any =
John Eckersberg da1dfd
+    { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
John Eckersberg da1dfd
+#    endif /* HAVE_IN6ADDR_ANY_INIT */
John Eckersberg da1dfd
+#  endif /* ! HAVE_DECL_IN6ADDR_ANY */
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#  if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK
John Eckersberg da1dfd
+#    if HAVE_DECL_IN6ADDR_LOOPBACK_INIT
John Eckersberg da1dfd
+static const struct in6_addr in6addr_loopback =
John Eckersberg da1dfd
+    { { IN6ADDR_LOOPBACK_INIT } };
John Eckersberg da1dfd
+#    else
John Eckersberg da1dfd
+static const struct in6_addr in6addr_loopback =
John Eckersberg da1dfd
+    { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
John Eckersberg da1dfd
+#    endif /* HAVE_IN6ADDR_LOOPBACK_INIT */
John Eckersberg da1dfd
+#  endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */
John Eckersberg da1dfd
+#endif /* HAVE_IN6 */
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-#define EPMD_SOCKADDR_IN sockaddr_in6
John Eckersberg da1dfd
-#define EPMD_IN_ADDR in6_addr
John Eckersberg da1dfd
-#define EPMD_S_ADDR s6_addr
John Eckersberg da1dfd
-#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr
John Eckersberg da1dfd
-#define EPMD_ADDR_ANY in6addr_any.s6_addr
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#define EPMD_SOCKADDR_IN sockaddr_storage
John Eckersberg da1dfd
 #define FAMILY AF_INET6
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-#define SET_ADDR(dst, addr, port) do { \
John Eckersberg da1dfd
-    memset((char*)&(dst), 0, sizeof(dst)); \
John Eckersberg da1dfd
-    memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \
John Eckersberg da1dfd
-    (dst).sin6_family = AF_INET6; \
John Eckersberg da1dfd
-    (dst).sin6_flowinfo = 0; \
John Eckersberg da1dfd
-    (dst).sin6_port = htons(port); \
John Eckersberg da1dfd
+#define SET_ADDR6(dst, addr, port) do { \
John Eckersberg da1dfd
+    struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(dst); \
John Eckersberg da1dfd
+    memset(sa, 0, sizeof(dst)); \
John Eckersberg da1dfd
+    sa->sin6_family = AF_INET6; \
John Eckersberg da1dfd
+    sa->sin6_addr = (addr); \
John Eckersberg da1dfd
+    sa->sin6_port = htons(port); \
John Eckersberg da1dfd
  } while(0)
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-#define IS_ADDR_LOOPBACK(addr) \
John Eckersberg da1dfd
-    (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0)
John Eckersberg da1dfd
+#define SET_ADDR(dst, addr, port) do { \
John Eckersberg da1dfd
+    struct sockaddr_in *sa = (struct sockaddr_in *)&(dst); \
John Eckersberg da1dfd
+    memset(sa, 0, sizeof(dst)); \
John Eckersberg da1dfd
+    sa->sin_family = AF_INET; \
John Eckersberg da1dfd
+    sa->sin_addr.s_addr = (addr); \
John Eckersberg da1dfd
+    sa->sin_port = htons(port); \
John Eckersberg da1dfd
+ } while(0)
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 #else /* Not IP v6 */
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 #define EPMD_SOCKADDR_IN sockaddr_in
John Eckersberg da1dfd
-#define EPMD_IN_ADDR in_addr
John Eckersberg da1dfd
-#define EPMD_S_ADDR s_addr
John Eckersberg da1dfd
-#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK)
John Eckersberg da1dfd
-#define EPMD_ADDR_ANY htonl(INADDR_ANY)
John Eckersberg da1dfd
 #define FAMILY AF_INET
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 #define SET_ADDR(dst, addr, port) do { \
John Eckersberg da1dfd
@@ -219,8 +246,6 @@
John Eckersberg da1dfd
     (dst).sin_port = htons(port); \
John Eckersberg da1dfd
  } while(0)
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
John Eckersberg da1dfd
-
John Eckersberg da1dfd
 #endif /* Not IP v6 */
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 /* ************************************************************************ */
John Eckersberg da1dfd
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
John Eckersberg da1dfd
index 8c8d730..28a2968 100644
John Eckersberg da1dfd
--- a/erts/epmd/src/epmd_srv.c
John Eckersberg da1dfd
+++ b/erts/epmd/src/epmd_srv.c
John Eckersberg da1dfd
@@ -76,6 +76,7 @@ static time_t current_time(EpmdVars*);
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 static Connection *conn_init(EpmdVars*);
John Eckersberg da1dfd
 static int conn_open(EpmdVars*,int);
John Eckersberg da1dfd
+static int conn_local_peer_check(EpmdVars*, int);
John Eckersberg da1dfd
 static int conn_close_fd(EpmdVars*,int);
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 static void node_init(EpmdVars*);
John Eckersberg da1dfd
@@ -206,10 +207,11 @@ void run(EpmdVars *g)
John Eckersberg da1dfd
 {
John Eckersberg da1dfd
   struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS];
John Eckersberg da1dfd
   int listensock[MAX_LISTEN_SOCKETS];
John Eckersberg da1dfd
-  int num_sockets;
John Eckersberg da1dfd
+  int num_sockets = 0;
John Eckersberg da1dfd
   int i;
John Eckersberg da1dfd
   int opt;
John Eckersberg da1dfd
   unsigned short sport = g->port;
John Eckersberg da1dfd
+  int bound = 0;
John Eckersberg da1dfd
 
John Eckersberg da1dfd
   node_init(g);
John Eckersberg da1dfd
   g->conn = conn_init(g);
John Eckersberg da1dfd
@@ -252,64 +254,82 @@ void run(EpmdVars *g)
John Eckersberg da1dfd
   if (g->addresses != NULL && /* String contains non-separator characters if: */
John Eckersberg da1dfd
       g->addresses[strspn(g->addresses," ,")] != '\000')
John Eckersberg da1dfd
     {
John Eckersberg da1dfd
-      char *tmp;
John Eckersberg da1dfd
-      char *token;
John Eckersberg da1dfd
-      int loopback_ok = 0;
John Eckersberg da1dfd
+      char *tmp = NULL;
John Eckersberg da1dfd
+      char *token = NULL;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+      /* Always listen on the loopback. */
John Eckersberg da1dfd
+      SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_LOOPBACK),sport);
John Eckersberg da1dfd
+      num_sockets++;
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+      SET_ADDR6(iserv_addr[num_sockets],in6addr_loopback,sport);
John Eckersberg da1dfd
+      num_sockets++;
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-      if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL)
John Eckersberg da1dfd
+	  if ((tmp = strdup(g->addresses)) == NULL)
John Eckersberg da1dfd
 	{
John Eckersberg da1dfd
 	  dbg_perror(g,"cannot allocate memory");
John Eckersberg da1dfd
 	  epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
 	}
John Eckersberg da1dfd
-      strcpy(tmp,g->addresses);
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-      for(token = strtok(tmp,", "), num_sockets = 0;
John Eckersberg da1dfd
+      for(token = strtok(tmp,", ");
John Eckersberg da1dfd
 	  token != NULL;
John Eckersberg da1dfd
-	  token = strtok(NULL,", "), num_sockets++)
John Eckersberg da1dfd
+	  token = strtok(NULL,", "))
John Eckersberg da1dfd
 	{
John Eckersberg da1dfd
-	  struct EPMD_IN_ADDR addr;
John Eckersberg da1dfd
-#ifdef HAVE_INET_PTON
John Eckersberg da1dfd
-	  int ret;
John Eckersberg da1dfd
+	  struct in_addr addr;
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+	  struct in6_addr addr6;
John Eckersberg da1dfd
+	  struct sockaddr_storage *sa = &iserv_addr[num_sockets];
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-	  if ((ret = inet_pton(FAMILY,token,&addr)) == -1)
John Eckersberg da1dfd
+	  if (inet_pton(AF_INET6,token,&addr6) == 1)
John Eckersberg da1dfd
 	    {
John Eckersberg da1dfd
-	      dbg_perror(g,"cannot convert IP address to network format");
John Eckersberg da1dfd
-	      epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
+	      SET_ADDR6(iserv_addr[num_sockets],addr6,sport);
John Eckersberg da1dfd
+	    }
John Eckersberg da1dfd
+	  else if (inet_pton(AF_INET,token,&addr) == 1)
John Eckersberg da1dfd
+	    {
John Eckersberg da1dfd
+	      SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
John Eckersberg da1dfd
+	    }
John Eckersberg da1dfd
+	  else
John Eckersberg da1dfd
+#else
John Eckersberg da1dfd
+	  if ((addr.s_addr = inet_addr(token)) != INADDR_NONE)
John Eckersberg da1dfd
+	    {
John Eckersberg da1dfd
+	      SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
John Eckersberg da1dfd
 	    }
John Eckersberg da1dfd
-	  else if (ret == 0)
John Eckersberg da1dfd
-#elif !defined(EPMD6)
John Eckersberg da1dfd
-	  if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE)
John Eckersberg da1dfd
+	  else
John Eckersberg da1dfd
 #endif
John Eckersberg da1dfd
 	    {
John Eckersberg da1dfd
 	      dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token);
John Eckersberg da1dfd
 	      epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
 	    }
John Eckersberg da1dfd
 
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+	  if (sa->ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&addr6))
John Eckersberg da1dfd
+	      continue;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+	  if (sa->ss_family == AF_INET)
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
 	  if (IS_ADDR_LOOPBACK(addr))
John Eckersberg da1dfd
-	    loopback_ok = 1;
John Eckersberg da1dfd
+	    continue;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+	  num_sockets++;
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-	  if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1)
John Eckersberg da1dfd
+	  if (num_sockets >= MAX_LISTEN_SOCKETS)
John Eckersberg da1dfd
 	    {
John Eckersberg da1dfd
 	      dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses",
John Eckersberg da1dfd
 			     MAX_LISTEN_SOCKETS);
John Eckersberg da1dfd
 	      epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
 	    }
John Eckersberg da1dfd
-
John Eckersberg da1dfd
-	  SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport);
John Eckersberg da1dfd
 	}
John Eckersberg da1dfd
 
John Eckersberg da1dfd
       free(tmp);
John Eckersberg da1dfd
-
John Eckersberg da1dfd
-      if (!loopback_ok)
John Eckersberg da1dfd
-	{
John Eckersberg da1dfd
-	  SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport);
John Eckersberg da1dfd
-	  num_sockets++;
John Eckersberg da1dfd
-	}
John Eckersberg da1dfd
     }
John Eckersberg da1dfd
   else
John Eckersberg da1dfd
     {
John Eckersberg da1dfd
-      SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport);
John Eckersberg da1dfd
-      num_sockets = 1;
John Eckersberg da1dfd
+      SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_ANY),sport);
John Eckersberg da1dfd
+      num_sockets++;
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+      SET_ADDR6(iserv_addr[num_sockets],in6addr_any,sport);
John Eckersberg da1dfd
+      num_sockets++;
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
     }
John Eckersberg da1dfd
 #ifdef HAVE_SYSTEMD_DAEMON
John Eckersberg da1dfd
     }
John Eckersberg da1dfd
@@ -340,13 +360,39 @@ void run(EpmdVars *g)
John Eckersberg da1dfd
 #endif /* HAVE_SYSTEMD_DAEMON */
John Eckersberg da1dfd
   for (i = 0; i < num_sockets; i++)
John Eckersberg da1dfd
     {
John Eckersberg da1dfd
-      if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0)
John Eckersberg da1dfd
+      struct sockaddr *sa = (struct sockaddr *)&iserv_addr[i];
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+      size_t salen = (sa->sa_family == AF_INET6 ?
John Eckersberg da1dfd
+              sizeof(struct sockaddr_in6) :
John Eckersberg da1dfd
+              sizeof(struct sockaddr_in));
John Eckersberg da1dfd
+#else
John Eckersberg da1dfd
+      size_t salen = sizeof(struct sockaddr_in);
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+      if ((listensock[i] = socket(sa->sa_family,SOCK_STREAM,0)) < 0)
John Eckersberg da1dfd
 	{
John Eckersberg da1dfd
-	  dbg_perror(g,"error opening stream socket");
John Eckersberg da1dfd
-	  epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
+	  switch (errno) {
John Eckersberg da1dfd
+	      case EAFNOSUPPORT:
John Eckersberg da1dfd
+	      case EPROTONOSUPPORT:
John Eckersberg da1dfd
+	          continue;
John Eckersberg da1dfd
+	      default:
John Eckersberg da1dfd
+	          dbg_perror(g,"error opening stream socket");
John Eckersberg da1dfd
+	          epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
+	  }
John Eckersberg da1dfd
 	}
John Eckersberg da1dfd
       g->listenfd[i] = listensock[i];
John Eckersberg da1dfd
-  
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#if HAVE_DECL_IPV6_V6ONLY
John Eckersberg da1dfd
+      opt = 1;
John Eckersberg da1dfd
+      if (sa->sa_family == AF_INET6 &&
John Eckersberg da1dfd
+          setsockopt(listensock[i],IPPROTO_IPV6,IPV6_V6ONLY,&opt,
John Eckersberg da1dfd
+              sizeof(opt)) <0)
John Eckersberg da1dfd
+	{
John Eckersberg da1dfd
+	  dbg_perror(g,"can't set IPv6 only socket option");
John Eckersberg da1dfd
+	  epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
+	}
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+
John Eckersberg da1dfd
       /*
John Eckersberg da1dfd
        * Note that we must not enable the SO_REUSEADDR on Windows,
John Eckersberg da1dfd
        * because addresses will be reused even if they are still in use.
John Eckersberg da1dfd
@@ -378,8 +424,7 @@ void run(EpmdVars *g)
John Eckersberg da1dfd
 	dbg_perror(g,"failed to set non-blocking mode of listening socket %d",
John Eckersberg da1dfd
 		   listensock[i]);
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-      if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i],
John Eckersberg da1dfd
-	  sizeof(iserv_addr[i])) < 0)
John Eckersberg da1dfd
+      if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], salen) < 0)
John Eckersberg da1dfd
 	{
John Eckersberg da1dfd
 	  if (errno == EADDRINUSE)
John Eckersberg da1dfd
 	    {
John Eckersberg da1dfd
@@ -394,12 +439,18 @@ void run(EpmdVars *g)
John Eckersberg da1dfd
 	    }
John Eckersberg da1dfd
 	}
John Eckersberg da1dfd
 
John Eckersberg da1dfd
+      bound++;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
       if(listen(listensock[i], SOMAXCONN) < 0) {
John Eckersberg da1dfd
           dbg_perror(g,"failed to listen on socket");
John Eckersberg da1dfd
           epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
       }
John Eckersberg da1dfd
       select_fd_set(g, listensock[i]);
John Eckersberg da1dfd
     }
John Eckersberg da1dfd
+  if (bound == 0) {
John Eckersberg da1dfd
+      dbg_perror(g,"unable to bind any address");
John Eckersberg da1dfd
+      epmd_cleanup_exit(g,1);
John Eckersberg da1dfd
+  }
John Eckersberg da1dfd
 #ifdef HAVE_SYSTEMD_DAEMON
John Eckersberg da1dfd
     }
John Eckersberg da1dfd
     sd_notifyf(0, "READY=1\n"
John Eckersberg da1dfd
@@ -1007,15 +1058,6 @@ static int conn_open(EpmdVars *g,int fd)
John Eckersberg da1dfd
 
John Eckersberg da1dfd
   for (i = 0; i < g->max_conn; i++) {
John Eckersberg da1dfd
     if (g->conn[i].open == EPMD_FALSE) {
John Eckersberg da1dfd
-      struct sockaddr_in si;
John Eckersberg da1dfd
-      struct sockaddr_in di;
John Eckersberg da1dfd
-#ifdef HAVE_SOCKLEN_T
John Eckersberg da1dfd
-      socklen_t st;
John Eckersberg da1dfd
-#else
John Eckersberg da1dfd
-      int st;
John Eckersberg da1dfd
-#endif
John Eckersberg da1dfd
-      st = sizeof(si);
John Eckersberg da1dfd
-
John Eckersberg da1dfd
       g->active_conn++;
John Eckersberg da1dfd
       s = &g->conn[i];
John Eckersberg da1dfd
      
John Eckersberg da1dfd
@@ -1026,20 +1068,7 @@ static int conn_open(EpmdVars *g,int fd)
John Eckersberg da1dfd
       s->open = EPMD_TRUE;
John Eckersberg da1dfd
       s->keep = EPMD_FALSE;
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-      /* Determine if connection is from localhost */
John Eckersberg da1dfd
-      if (getpeername(s->fd,(struct sockaddr*) &si,&st) ||
John Eckersberg da1dfd
-	  st < sizeof(si)) {
John Eckersberg da1dfd
-	  /* Failure to get peername is regarded as non local host */
John Eckersberg da1dfd
-	  s->local_peer = EPMD_FALSE;
John Eckersberg da1dfd
-      } else {
John Eckersberg da1dfd
-	  /* Only 127.x.x.x and connections from the host's IP address
John Eckersberg da1dfd
-	     allowed, no false positives */
John Eckersberg da1dfd
-	  s->local_peer =
John Eckersberg da1dfd
-	      (((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) ==
John Eckersberg da1dfd
-	       0x7F000000U) ||
John Eckersberg da1dfd
-	       (getsockname(s->fd,(struct sockaddr*) &di,&st) ?
John Eckersberg da1dfd
-	       EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr));
John Eckersberg da1dfd
-      }
John Eckersberg da1dfd
+      s->local_peer = conn_local_peer_check(g, s->fd);
John Eckersberg da1dfd
       dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" :
John Eckersberg da1dfd
 		     "Non-local peer connected");
John Eckersberg da1dfd
 
John Eckersberg da1dfd
@@ -1047,7 +1076,7 @@ static int conn_open(EpmdVars *g,int fd)
John Eckersberg da1dfd
       s->got  = 0;
John Eckersberg da1dfd
       s->mod_time = current_time(g); /* Note activity */
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-      s->buf = (char *)malloc(INBUF_SIZE);
John Eckersberg da1dfd
+      s->buf = malloc(INBUF_SIZE);
John Eckersberg da1dfd
 
John Eckersberg da1dfd
       if (s->buf == NULL) {
John Eckersberg da1dfd
 	dbg_printf(g,0,"epmd: Insufficient memory");
John Eckersberg da1dfd
@@ -1065,6 +1094,60 @@ static int conn_open(EpmdVars *g,int fd)
John Eckersberg da1dfd
   return EPMD_FALSE;
John Eckersberg da1dfd
 }
John Eckersberg da1dfd
 
John Eckersberg da1dfd
+static int conn_local_peer_check(EpmdVars *g, int fd)
John Eckersberg da1dfd
+{
John Eckersberg da1dfd
+  struct EPMD_SOCKADDR_IN si;
John Eckersberg da1dfd
+  struct EPMD_SOCKADDR_IN di;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+  struct sockaddr_in *si4 = (struct sockaddr_in *)&si;
John Eckersberg da1dfd
+  struct sockaddr_in *di4 = (struct sockaddr_in *)&di;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&si;
John Eckersberg da1dfd
+  struct sockaddr_in6 *di6 = (struct sockaddr_in6 *)&di;
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#ifdef HAVE_SOCKLEN_T
John Eckersberg da1dfd
+  socklen_t st;
John Eckersberg da1dfd
+#else
John Eckersberg da1dfd
+  int st;
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+  st = sizeof(si);
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+  /* Determine if connection is from localhost */
John Eckersberg da1dfd
+  if (getpeername(fd,(struct sockaddr*) &si,&st) ||
John Eckersberg da1dfd
+	  st > sizeof(si)) {
John Eckersberg da1dfd
+	  /* Failure to get peername is regarded as non local host */
John Eckersberg da1dfd
+	  return EPMD_FALSE;
John Eckersberg da1dfd
+  }
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+  /* Only 127.x.x.x and connections from the host's IP address
John Eckersberg da1dfd
+	 allowed, no false positives */
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+  if (si.ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(si6->sin6_addr)))
John Eckersberg da1dfd
+	  return EPMD_TRUE;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+  if (si.ss_family == AF_INET)
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+  if ((((unsigned) ntohl(si4->sin_addr.s_addr)) & 0xFF000000U) ==
John Eckersberg da1dfd
+	  0x7F000000U)
John Eckersberg da1dfd
+	  return EPMD_TRUE;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+  if (getsockname(fd,(struct sockaddr*) &di,&st))
John Eckersberg da1dfd
+	  return EPMD_FALSE;
John Eckersberg da1dfd
+
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+  if (si.ss_family == AF_INET6)
John Eckersberg da1dfd
+      return IN6_ARE_ADDR_EQUAL( &(si6->sin6_addr), &(di6->sin6_addr));
John Eckersberg da1dfd
+  if (si.ss_family == AF_INET)
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+  return si4->sin_addr.s_addr == di4->sin_addr.s_addr;
John Eckersberg da1dfd
+#if defined(EPMD6)
John Eckersberg da1dfd
+  return EPMD_FALSE;
John Eckersberg da1dfd
+#endif
John Eckersberg da1dfd
+}
John Eckersberg da1dfd
+
John Eckersberg da1dfd
 static int conn_close_fd(EpmdVars *g,int fd)
John Eckersberg da1dfd
 {
John Eckersberg da1dfd
   int i;
John Eckersberg da1dfd
diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl
John Eckersberg da1dfd
index e8bbfdb..f3c0ada 100644
John Eckersberg da1dfd
--- a/erts/epmd/test/epmd_SUITE.erl
John Eckersberg da1dfd
+++ b/erts/epmd/test/epmd_SUITE.erl
John Eckersberg da1dfd
@@ -43,6 +43,7 @@
John Eckersberg da1dfd
 -export(
John Eckersberg da1dfd
    [
John Eckersberg da1dfd
     register_name/1,
John Eckersberg da1dfd
+    register_name_ipv6/1,
John Eckersberg da1dfd
     register_names_1/1,
John Eckersberg da1dfd
     register_names_2/1,
John Eckersberg da1dfd
     register_duplicate_name/1,
John Eckersberg da1dfd
@@ -111,7 +112,8 @@
John Eckersberg da1dfd
 suite() -> [{ct_hooks,[ts_install_cth]}].
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 all() -> 
John Eckersberg da1dfd
-    [register_name, register_names_1, register_names_2,
John Eckersberg da1dfd
+    [register_name, register_name_ipv6,
John Eckersberg da1dfd
+     register_names_1, register_names_2,
John Eckersberg da1dfd
      register_duplicate_name, unicode_name, long_unicode_name,
John Eckersberg da1dfd
      get_port_nr, slow_get_port_nr,
John Eckersberg da1dfd
      unregister_others_name_1, unregister_others_name_2,
John Eckersberg da1dfd
@@ -169,6 +171,24 @@ register_name(Config) when is_list(Config) ->
John Eckersberg da1dfd
     ?line ok = close(Sock),			% Unregister
John Eckersberg da1dfd
     ok.
John Eckersberg da1dfd
 
John Eckersberg da1dfd
+register_name_ipv6(doc) ->
John Eckersberg da1dfd
+    ["Register a name over IPv6"];
John Eckersberg da1dfd
+register_name_ipv6(suite) ->
John Eckersberg da1dfd
+    [];
John Eckersberg da1dfd
+register_name_ipv6(Config) when is_list(Config) ->
John Eckersberg da1dfd
+    % Test if the host has an IPv6 loopback address
John Eckersberg da1dfd
+    Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]),
John Eckersberg da1dfd
+    case Res of
John Eckersberg da1dfd
+    {ok,LSock} ->
John Eckersberg da1dfd
+	    gen_tcp:close(LSock),
John Eckersberg da1dfd
+	    ?line ok = epmdrun(),
John Eckersberg da1dfd
+	    ?line {ok,Sock} = register_node6("foobar6"),
John Eckersberg da1dfd
+	    ?line ok = close(Sock),         % Unregister
John Eckersberg da1dfd
+	    ok;
John Eckersberg da1dfd
+    _Error ->
John Eckersberg da1dfd
+	    {skip, "Host does not have an IPv6 loopback address"}
John Eckersberg da1dfd
+    end.
John Eckersberg da1dfd
+
John Eckersberg da1dfd
 register_names_1(doc) ->
John Eckersberg da1dfd
     ["Register and unregister two nodes"];
John Eckersberg da1dfd
 register_names_1(suite) ->
John Eckersberg da1dfd
@@ -242,13 +262,18 @@ register_node(Name) ->
John Eckersberg da1dfd
 register_node(Name,Port) ->
John Eckersberg da1dfd
     register_node_v2(Port,$M,0,5,5,Name,"").
John Eckersberg da1dfd
 
John Eckersberg da1dfd
+register_node6(Name) ->
John Eckersberg da1dfd
+    register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,"").
John Eckersberg da1dfd
+
John Eckersberg da1dfd
 register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
John Eckersberg da1dfd
+    register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, Name, Extra).
John Eckersberg da1dfd
+register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
John Eckersberg da1dfd
     Utf8Name = unicode:characters_to_binary(Name),
John Eckersberg da1dfd
     Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot,
John Eckersberg da1dfd
 	   put16(HVsn), put16(LVsn),
John Eckersberg da1dfd
 	   put16(size(Utf8Name)), binary_to_list(Utf8Name),
John Eckersberg da1dfd
 	   size16(Extra), Extra],
John Eckersberg da1dfd
-    case send_req(Req) of
John Eckersberg da1dfd
+    case send_req(Req, Addr) of
John Eckersberg da1dfd
 	{ok,Sock} ->
John Eckersberg da1dfd
 	    case recv(Sock,4) of
John Eckersberg da1dfd
 		{ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} ->
John Eckersberg da1dfd
@@ -1151,7 +1176,9 @@ send_direct(Sock, Bytes) ->
John Eckersberg da1dfd
     end.
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 send_req(Req) ->
John Eckersberg da1dfd
-    case connect() of
John Eckersberg da1dfd
+    send_req(Req, "localhost").
John Eckersberg da1dfd
+send_req(Req, Addr) ->
John Eckersberg da1dfd
+    case connect(Addr) of
John Eckersberg da1dfd
 	{ok,Sock} ->
John Eckersberg da1dfd
 	    case send(Sock, [size16(Req), Req]) of
John Eckersberg da1dfd
 		ok ->
John Eckersberg da1dfd
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
John Eckersberg da1dfd
index 55ce9a7..c6202dd 100644
John Eckersberg da1dfd
--- a/lib/kernel/src/erl_epmd.erl
John Eckersberg da1dfd
+++ b/lib/kernel/src/erl_epmd.erl
John Eckersberg da1dfd
@@ -32,7 +32,7 @@
John Eckersberg da1dfd
 %% External exports
John Eckersberg da1dfd
 -export([start/0, start_link/0, stop/0, port_please/2, 
John Eckersberg da1dfd
 	 port_please/3, names/0, names/1,
John Eckersberg da1dfd
-	 register_node/2, open/0, open/1, open/2]).
John Eckersberg da1dfd
+	 register_node/2, register_node/3, open/0, open/1, open/2]).
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 %% gen_server callbacks
John Eckersberg da1dfd
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, 
John Eckersberg da1dfd
@@ -102,7 +102,9 @@ names(EpmdAddr) ->
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 register_node(Name, PortNo) ->
John Eckersberg da1dfd
-    gen_server:call(erl_epmd, {register, Name, PortNo}, infinity).
John Eckersberg da1dfd
+    register_node(Name, PortNo, inet).
John Eckersberg da1dfd
+register_node(Name, PortNo, Family) ->
John Eckersberg da1dfd
+    gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
John Eckersberg da1dfd
 
John Eckersberg da1dfd
 %%%----------------------------------------------------------------------
John Eckersberg da1dfd
 %%% Callback functions from gen_server
John Eckersberg da1dfd
@@ -120,10 +122,10 @@ init(_) ->
John Eckersberg da1dfd
 -spec handle_call(calls(), term(), state()) ->
John Eckersberg da1dfd
         {'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}.
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-handle_call({register, Name, PortNo}, _From, State) ->
John Eckersberg da1dfd
+handle_call({register, Name, PortNo, Family}, _From, State) ->
John Eckersberg da1dfd
     case State#state.socket of
John Eckersberg da1dfd
 	P when P < 0 ->
John Eckersberg da1dfd
-	    case do_register_node(Name, PortNo) of
John Eckersberg da1dfd
+	    case do_register_node(Name, PortNo, Family) of
John Eckersberg da1dfd
 		{alive, Socket, Creation} ->
John Eckersberg da1dfd
 		    S = State#state{socket = Socket,
John Eckersberg da1dfd
 				    port_no = PortNo,
John Eckersberg da1dfd
@@ -206,8 +208,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
John Eckersberg da1dfd
 close(Socket) ->
John Eckersberg da1dfd
     gen_tcp:close(Socket).
John Eckersberg da1dfd
 
John Eckersberg da1dfd
-do_register_node(NodeName, TcpPort) ->
John Eckersberg da1dfd
-    case open() of
John Eckersberg da1dfd
+do_register_node(NodeName, TcpPort, Family) ->
John Eckersberg da1dfd
+    Localhost = case Family of
John Eckersberg da1dfd
+        inet -> open({127,0,0,1});
John Eckersberg da1dfd
+        inet6 -> open({0,0,0,0,0,0,0,1})
John Eckersberg da1dfd
+    end,
John Eckersberg da1dfd
+    case Localhost of
John Eckersberg da1dfd
 	{ok, Socket} ->
John Eckersberg da1dfd
 	    Name = to_string(NodeName),
John Eckersberg da1dfd
 	    Extra = "",