[erlang-patches] [PATCH] epmd: support IPv6 node registration

Patrik Nyblom pan@REDACTED
Tue Feb 19 18:08:47 CET 2013


On 02/18/2013 12:28 PM, Fredrik wrote:
> This happens only on windows I should add to the context also..
>
> BR Fredrik
> On 02/18/2013 12:00 PM, Fredrik wrote:
For unknown reasons, you need to drop support for win2k to get 
IPPROTO_IPV6 from the windows headers. Either we can up the command line 
-D_WIN32_WINVER to 0x0501 (Windows XP) or you can set (#define it) in 
epmd_int.h before including winsock2.h.
...
#ifdef _WIN32_WINVER
#undef _WIN32_WINVER
#endif
#define _WIN32_WINVER 0x0501
...
But that will probably be the end of any (theoretical) windows 2000 
support. We don't support Win 2000 officially, so I think it will be a 
non-issue. Others might disagree though :)

/Patrik

>> Hello,
>> Your patch does not seem to build:
>>
>> epmd_srv.c(332) : error C2065: 'IPPROTO_IPV6' : undeclared identifier
>> epmd_srv.c(332) : warning C4133: 'function' : incompatible types - 
>> from 'int *' to 'const char *'
>>
>>
>> Could you please have a look at this problem?
>>
>> On 02/17/2013 12:23 AM, Michael Santos wrote:
>>> Allow IPv6 nodes to register with and query epmd. On systems with
>>> IPv6 support:
>>>
>>> * epmd listens on the IPv4 and IPv6 ANY or loopback sockets
>>>
>>> * the epmd cli client connects to epmd using the IPv6 loopback
>>>
>>> * distributed nodes started with "-proto_dist inet6_tcp" will register
>>>    with epmd over IPv6
>>> ---
>>>   erts/doc/src/epmd.xml             |    2 +-
>>>   erts/doc/src/erl.xml              |   22 +++++
>>>   erts/epmd/src/epmd.c              |    6 +-
>>>   erts/epmd/src/epmd_cli.c          |   11 ++-
>>>   erts/epmd/src/epmd_int.h          |   59 ++++++++----
>>>   erts/epmd/src/epmd_srv.c          |  184 
>>> +++++++++++++++++++++++++------------
>>>   erts/epmd/test/epmd_SUITE.erl     |   33 ++++++-
>>>   lib/kernel/src/erl_epmd.erl       |   18 ++--
>>>   lib/kernel/src/inet6_tcp_dist.erl |    2 +-
>>>   9 files changed, 244 insertions(+), 93 deletions(-)
>>>
>>> diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml
>>> index 3e70054..3c9313e 100644
>>> --- a/erts/doc/src/epmd.xml
>>> +++ b/erts/doc/src/epmd.xml
>>> @@ -36,7 +36,7 @@
>>> <comsummary>
>>> <p>Erlang Port Mapper Daemon</p>
>>> <taglist>
>>> -<tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-port No] 
>>> [-daemon] [-relaxed_command_check]]]></c></tag>
>>> +<tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-address 
>>> Addresses] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag>
>>> <item>
>>> <p>Starts the port mapper daemon</p>
>>> </item>
>>> diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
>>> index f354d68..aebf4ff 100644
>>> --- a/erts/doc/src/erl.xml
>>> +++ b/erts/doc/src/erl.xml
>>> @@ -381,6 +381,28 @@
>>>             similar to<c><![CDATA[code:add_pathsz/1]]></c>. See
>>> <seealso marker="kernel:code">code(3)</seealso>.</p>
>>> </item>
>>> +<tag><c><![CDATA[-proto_dist Proto]]></c></tag>
>>> +<item>
>>> +<p>Specify a protocol for Erlang distribution.</p>
>>> + <taglist>
>>> + <tag><c>inet_tcp</c></tag>
>>> +<item>
>>> +<p>TCP over IPv4 (the default)</p>
>>> +</item>
>>> + <tag><c>inet_ssl</c></tag>
>>> +<item>
>>> +<p>distribution over SSL</p>
>>> +</item>
>>> + <tag><c>inet6_tcp</c></tag>
>>> +<item>
>>> +<p>TCP over IPv6</p>
>>> +</item>
>>> +</taglist>
>>> +<p>For example, to start up IPv6 distributed nodes:</p>
>>> +<pre>
>>> +%<input>erl -name test@REDACTED -proto_dist 
>>> inet6_tcp</input>
>>> +</pre>
>>> +</item>
>>> <tag><c><![CDATA[-remsh Node]]></c></tag>
>>> <item>
>>> <p>Starts Erlang with a remote shell connected 
>>> to<c><![CDATA[Node]]></c>.</p>
>>> diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
>>> index 94bb74c..0789cc3 100644
>>> --- a/erts/epmd/src/epmd.c
>>> +++ b/erts/epmd/src/epmd.c
>>> @@ -335,10 +335,10 @@ static void run_daemon(EpmdVars *g)
>>>       for (fd = 0; fd<  g->max_conn ; fd++) /* close all files ... */
>>>           close(fd);
>>>       /* Syslog on linux will try to write to whatever if we dont
>>> -       inform it of that the log is closed. */
>>> +       inform it that the log is closed. */
>>>       closelog();
>>>
>>> -    /* These chouldn't be needed but for safety... */
>>> +    /* These shouldn't be needed but for safety... */
>>>
>>>       open("/dev/null", O_RDONLY); /* Order is important! */
>>>       open("/dev/null", O_WRONLY);
>>> @@ -379,7 +379,7 @@ static void run_daemon(EpmdVars *g)
>>>       close(1);
>>>       close(2);
>>>
>>> -    /* These chouldn't be needed but for safety... */
>>> +    /* These shouldn't be needed but for safety... */
>>>
>>>       open("nul", O_RDONLY);
>>>       open("nul", O_WRONLY);
>>> diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
>>> index 8817bde..a0dd890 100644
>>> --- a/erts/epmd/src/epmd_cli.c
>>> +++ b/erts/epmd/src/epmd_cli.c
>>> @@ -135,6 +135,7 @@ void epmd_call(EpmdVars *g,int what)
>>>   static int conn_to_epmd(EpmdVars *g)
>>>   {
>>>       struct EPMD_SOCKADDR_IN address;
>>> +    size_t salen = 0;
>>>       int connect_sock;
>>>
>>>       connect_sock = socket(FAMILY, SOCK_STREAM, 0);
>>> @@ -143,10 +144,16 @@ static int conn_to_epmd(EpmdVars *g)
>>>
>>>       { /* store port number in unsigned short */
>>>         unsigned short sport = g->port;
>>> -      SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport);
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +      SET_ADDR6(address, in6addr_loopback, sport);
>>> +      salen = sizeof(struct sockaddr_in6);
>>> +#else
>>> +      SET_ADDR(address, htonl(INADDR_LOOPBACK), sport);
>>> +      salen = sizeof(struct sockaddr_in);
>>> +#endif
>>>       }
>>>
>>> -    if (connect(connect_sock, (struct sockaddr*)&address, sizeof 
>>> address)<  0)
>>> +    if (connect(connect_sock, (struct sockaddr*)&address, salen)<  0)
>>>       goto error;
>>>       return connect_sock;
>>>
>>> diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
>>> index ac354dc..b16c137 100644
>>> --- a/erts/epmd/src/epmd_int.h
>>> +++ b/erts/epmd/src/epmd_int.h
>>> @@ -49,6 +49,7 @@
>>>   #  ifndef WINDOWS_H_INCLUDES_WINSOCK2_H
>>>   #    include<winsock2.h>
>>>   #  endif
>>> +#  include<ws2tcpip.h>
>>>   #  include<windows.h>
>>>   #  include<process.h>
>>>   #endif
>>> @@ -165,33 +166,53 @@
>>>   /* 
>>> ************************************************************************ 
>>> */
>>>   /* Macros that let us use 
>>> IPv6                                              */
>>>
>>> -#if defined(HAVE_IN6)&&  defined(AF_INET6)&& defined(EPMD6)
>>> +#if HAVE_IN6
>>> +#  if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY
>>> +#    if HAVE_DECL_IN6ADDR_ANY_INIT
>>> +static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } };
>>> +#    else
>>> +static const struct in6_addr in6addr_any =
>>> +    { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
>>> +#    endif /* HAVE_IN6ADDR_ANY_INIT */
>>> +#  endif /* ! HAVE_DECL_IN6ADDR_ANY */
>>> +
>>> +#  if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK
>>> +#    if HAVE_DECL_IN6ADDR_LOOPBACK_INIT
>>> +static const struct in6_addr in6addr_loopback =
>>> +    { { IN6ADDR_LOOPBACK_INIT } };
>>> +#    else
>>> +static const struct in6_addr in6addr_loopback =
>>> +    { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
>>> +#    endif /* HAVE_IN6ADDR_LOOPBACK_INIT */
>>> +#  endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */
>>> +#endif /* HAVE_IN6 */
>>> +
>>> +#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == 
>>> htonl(INADDR_LOOPBACK))
>>> +
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>>
>>> -#define EPMD_SOCKADDR_IN sockaddr_in6
>>> -#define EPMD_IN_ADDR in6_addr
>>> -#define EPMD_S_ADDR s6_addr
>>> -#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr
>>> -#define EPMD_ADDR_ANY in6addr_any.s6_addr
>>> +#define EPMD_SOCKADDR_IN sockaddr_storage
>>>   #define FAMILY AF_INET6
>>>
>>> -#define SET_ADDR(dst, addr, port) do { \
>>> -    memset((char*)&(dst), 0, sizeof(dst)); \
>>> -    memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \
>>> -    (dst).sin6_family = AF_INET6; \
>>> -    (dst).sin6_flowinfo = 0; \
>>> -    (dst).sin6_port = htons(port); \
>>> +#define SET_ADDR6(dst, addr, port) do { \
>>> +    struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(dst); \
>>> +    memset(sa, 0, sizeof(dst)); \
>>> +    sa->sin6_family = AF_INET6; \
>>> +    sa->sin6_addr = (addr); \
>>> +    sa->sin6_port = htons(port); \
>>>    } while(0)
>>>
>>> -#define IS_ADDR_LOOPBACK(addr) \
>>> -    (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0)
>>> +#define SET_ADDR(dst, addr, port) do { \
>>> +    struct sockaddr_in *sa = (struct sockaddr_in *)&(dst); \
>>> +    memset(sa, 0, sizeof(dst)); \
>>> +    sa->sin_family = AF_INET; \
>>> +    sa->sin_addr.s_addr = (addr); \
>>> +    sa->sin_port = htons(port); \
>>> + } while(0)
>>>
>>>   #else /* Not IP v6 */
>>>
>>>   #define EPMD_SOCKADDR_IN sockaddr_in
>>> -#define EPMD_IN_ADDR in_addr
>>> -#define EPMD_S_ADDR s_addr
>>> -#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK)
>>> -#define EPMD_ADDR_ANY htonl(INADDR_ANY)
>>>   #define FAMILY AF_INET
>>>
>>>   #define SET_ADDR(dst, addr, port) do { \
>>> @@ -201,8 +222,6 @@
>>>       (dst).sin_port = htons(port); \
>>>    } while(0)
>>>
>>> -#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == 
>>> htonl(INADDR_LOOPBACK))
>>> -
>>>   #endif /* Not IP v6 */
>>>
>>>   /* 
>>> ************************************************************************ 
>>> */
>>> diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
>>> index 90df7cc..1c34f5f 100644
>>> --- a/erts/epmd/src/epmd_srv.c
>>> +++ b/erts/epmd/src/epmd_srv.c
>>> @@ -70,6 +70,7 @@ static time_t current_time(EpmdVars*);
>>>
>>>   static Connection *conn_init(EpmdVars*);
>>>   static int conn_open(EpmdVars*,int);
>>> +static int conn_local_peer_check(EpmdVars*, int);
>>>   static int conn_close_fd(EpmdVars*,int);
>>>
>>>   static void node_init(EpmdVars*);
>>> @@ -200,7 +201,7 @@ void run(EpmdVars *g)
>>>   {
>>>     struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS];
>>>     int listensock[MAX_LISTEN_SOCKETS];
>>> -  int num_sockets;
>>> +  int num_sockets = 0;
>>>     int i;
>>>     int opt;
>>>     unsigned short sport = g->port;
>>> @@ -213,64 +214,82 @@ void run(EpmdVars *g)
>>>     if (g->addresses != NULL&&  /* String contains non-separator 
>>> characters if: */
>>>         g->addresses[strspn(g->addresses," ,")] != '\000')
>>>       {
>>> -      char *tmp;
>>> -      char *token;
>>> -      int loopback_ok = 0;
>>> +      char *tmp = NULL;
>>> +      char *token = NULL;
>>> +
>>> +      /* Always listen on the loopback. */
>>> + SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_LOOPBACK),sport);
>>> +      num_sockets++;
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> + SET_ADDR6(iserv_addr[num_sockets],in6addr_loopback,sport);
>>> +      num_sockets++;
>>> +#endif
>>>
>>> -      if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL)
>>> +      if ((tmp = strdup(g->addresses)) == NULL)
>>>       {
>>>         dbg_perror(g,"cannot allocate memory");
>>>         epmd_cleanup_exit(g,1);
>>>       }
>>> -      strcpy(tmp,g->addresses);
>>>
>>> -      for(token = strtok(tmp,", "), num_sockets = 0;
>>> +      for(token = strtok(tmp,", ");
>>>         token != NULL;
>>> -      token = strtok(NULL,", "), num_sockets++)
>>> +      token = strtok(NULL,", "))
>>>       {
>>> -      struct EPMD_IN_ADDR addr;
>>> -#ifdef HAVE_INET_PTON
>>> -      int ret;
>>> +      struct in_addr addr;
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +      struct in6_addr addr6;
>>> +      struct sockaddr_storage *sa =&iserv_addr[num_sockets];
>>>
>>> -      if ((ret = inet_pton(FAMILY,token,&addr)) == -1)
>>> +      if (inet_pton(AF_INET,token,&addr) == 1)
>>>           {
>>> -          dbg_perror(g,"cannot convert IP address to network format");
>>> -          epmd_cleanup_exit(g,1);
>>> + SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
>>> +        }
>>> +      else if (inet_pton(AF_INET6,token,&addr6) == 1)
>>> +        {
>>> +          SET_ADDR6(iserv_addr[num_sockets],addr6,sport);
>>> +        }
>>> +      else
>>> +#else
>>> +      if ((addr.s_addr = inet_addr(token)) != INADDR_NONE)
>>> +        {
>>> + SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
>>>           }
>>> -      else if (ret == 0)
>>> -#elif !defined(EPMD6)
>>> -      if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE)
>>> +      else
>>>   #endif
>>>           {
>>>             dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token);
>>>             epmd_cleanup_exit(g,1);
>>>           }
>>>
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +      if (sa->ss_family == AF_INET6&& IN6_IS_ADDR_LOOPBACK(&addr6))
>>> +          continue;
>>> +
>>> +      if (sa->ss_family == AF_INET)
>>> +#endif
>>>         if (IS_ADDR_LOOPBACK(addr))
>>> -        loopback_ok = 1;
>>> +        continue;
>>>
>>> -      if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1)
>>> +      num_sockets++;
>>> +
>>> +      if (num_sockets>= MAX_LISTEN_SOCKETS)
>>>           {
>>>             dbg_tty_printf(g,0,"cannot listen on more than %d IP 
>>> addresses",
>>>                    MAX_LISTEN_SOCKETS);
>>>             epmd_cleanup_exit(g,1);
>>>           }
>>> -
>>> - SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport);
>>>       }
>>>
>>>         free(tmp);
>>> -
>>> -      if (!loopback_ok)
>>> -    {
>>> - SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport);
>>> -      num_sockets++;
>>> -    }
>>>       }
>>>     else
>>>       {
>>> -      SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport);
>>> -      num_sockets = 1;
>>> + SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_ANY),sport);
>>> +      num_sockets++;
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +      SET_ADDR6(iserv_addr[num_sockets],in6addr_any,sport);
>>> +      num_sockets++;
>>> +#endif
>>>       }
>>>
>>>   #if !defined(__WIN32__)
>>> @@ -291,13 +310,33 @@ void run(EpmdVars *g)
>>>
>>>     for (i = 0; i<  num_sockets; i++)
>>>       {
>>> -      if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0))< 0)
>>> +      struct sockaddr *sa = (struct sockaddr *)&iserv_addr[i];
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +      size_t salen = (sa->sa_family == AF_INET6 ?
>>> +              sizeof(struct sockaddr_in6) :
>>> +              sizeof(struct sockaddr_in));
>>> +#else
>>> +      size_t salen = sizeof(struct sockaddr_in);
>>> +#endif
>>> +
>>> +      if ((listensock[i] = socket(sa->sa_family,SOCK_STREAM,0))<  0)
>>>       {
>>>         dbg_perror(g,"error opening stream socket");
>>>         epmd_cleanup_exit(g,1);
>>>       }
>>>         g->listenfd[i] = listensock[i];
>>> -
>>> +
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +      opt = 1;
>>> +      if (sa->sa_family == AF_INET6&&
>>> + setsockopt(listensock[i],IPPROTO_IPV6,IPV6_V6ONLY,&opt,
>>> +              sizeof(opt))<0)
>>> +    {
>>> +      dbg_perror(g,"can't set IPv6 only socket option");
>>> +      epmd_cleanup_exit(g,1);
>>> +    }
>>> +#endif
>>> +
>>>         /*
>>>          * Note that we must not enable the SO_REUSEADDR on Windows,
>>>          * because addresses will be reused even if they are still 
>>> in use.
>>> @@ -329,8 +368,7 @@ void run(EpmdVars *g)
>>>       dbg_perror(g,"failed to set non-blocking mode of listening 
>>> socket %d",
>>>              listensock[i]);
>>>
>>> -      if (bind(listensock[i], (struct sockaddr*)&iserv_addr[i],
>>> -      sizeof(iserv_addr[i]))<  0)
>>> +      if (bind(listensock[i], (struct sockaddr*)&iserv_addr[i], 
>>> salen)<  0)
>>>       {
>>>         if (errno == EADDRINUSE)
>>>           {
>>> @@ -952,15 +990,6 @@ static int conn_open(EpmdVars *g,int fd)
>>>
>>>     for (i = 0; i<  g->max_conn; i++) {
>>>       if (g->conn[i].open == EPMD_FALSE) {
>>> -      struct sockaddr_in si;
>>> -      struct sockaddr_in di;
>>> -#ifdef HAVE_SOCKLEN_T
>>> -      socklen_t st;
>>> -#else
>>> -      int st;
>>> -#endif
>>> -      st = sizeof(si);
>>> -
>>>         g->active_conn++;
>>>         s =&g->conn[i];
>>>
>>> @@ -971,20 +1000,7 @@ static int conn_open(EpmdVars *g,int fd)
>>>         s->open = EPMD_TRUE;
>>>         s->keep = EPMD_FALSE;
>>>
>>> -      /* Determine if connection is from localhost */
>>> -      if (getpeername(s->fd,(struct sockaddr*)&si,&st) ||
>>> -      st<  sizeof(si)) {
>>> -      /* Failure to get peername is regarded as non local host */
>>> -      s->local_peer = EPMD_FALSE;
>>> -      } else {
>>> -      /* Only 127.x.x.x and connections from the host's IP address
>>> -         allowed, no false positives */
>>> -      s->local_peer =
>>> -          (((((unsigned) ntohl(si.sin_addr.s_addr))& 0xFF000000U) ==
>>> -           0x7F000000U) ||
>>> -           (getsockname(s->fd,(struct sockaddr*)&di,&st) ?
>>> -           EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr));
>>> -      }
>>> +      s->local_peer = conn_local_peer_check(g, s->fd);
>>>         dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" :
>>>                "Non-local peer connected");
>>>
>>> @@ -992,7 +1008,7 @@ static int conn_open(EpmdVars *g,int fd)
>>>         s->got  = 0;
>>>         s->mod_time = current_time(g); /* Note activity */
>>>
>>> -      s->buf = (char *)malloc(INBUF_SIZE);
>>> +      s->buf = malloc(INBUF_SIZE);
>>>
>>>         if (s->buf == NULL) {
>>>       dbg_printf(g,0,"epmd: Insufficient memory");
>>> @@ -1010,6 +1026,60 @@ static int conn_open(EpmdVars *g,int fd)
>>>     return EPMD_FALSE;
>>>   }
>>>
>>> +static int conn_local_peer_check(EpmdVars *g, int fd)
>>> +{
>>> +  struct EPMD_SOCKADDR_IN si;
>>> +  struct EPMD_SOCKADDR_IN di;
>>> +
>>> +  struct sockaddr_in *si4 = (struct sockaddr_in *)&si;
>>> +  struct sockaddr_in *di4 = (struct sockaddr_in *)&di;
>>> +
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&si;
>>> +  struct sockaddr_in6 *di6 = (struct sockaddr_in6 *)&di;
>>> +#endif
>>> +
>>> +#ifdef HAVE_SOCKLEN_T
>>> +  socklen_t st;
>>> +#else
>>> +  int st;
>>> +#endif
>>> +
>>> +  st = sizeof(si);
>>> +
>>> +  /* Determine if connection is from localhost */
>>> +  if (getpeername(fd,(struct sockaddr*)&si,&st) ||
>>> +      st>  sizeof(si)) {
>>> +      /* Failure to get peername is regarded as non local host */
>>> +      return EPMD_FALSE;
>>> +  }
>>> +
>>> +  /* Only 127.x.x.x and connections from the host's IP address
>>> +     allowed, no false positives */
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +  if (si.ss_family == AF_INET6&& 
>>> IN6_IS_ADDR_LOOPBACK(&(si6->sin6_addr)))
>>> +      return EPMD_TRUE;
>>> +
>>> +  if (si.ss_family == AF_INET)
>>> +#endif
>>> +  if ((((unsigned) ntohl(si4->sin_addr.s_addr))& 0xFF000000U) ==
>>> +      0x7F000000U)
>>> +      return EPMD_TRUE;
>>> +
>>> +  if (getsockname(fd,(struct sockaddr*)&di,&st))
>>> +      return EPMD_FALSE;
>>> +
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +  if (si.ss_family == AF_INET6)
>>> +      return IN6_ARE_ADDR_EQUAL(&(si6->sin6_addr),&(di6->sin6_addr));
>>> +  if (si.ss_family == AF_INET)
>>> +#endif
>>> +  return si4->sin_addr.s_addr == di4->sin_addr.s_addr;
>>> +#if defined(HAVE_IN6)&&  defined(AF_INET6)
>>> +  return EPMD_FALSE;
>>> +#endif
>>> +}
>>> +
>>>   static int conn_close_fd(EpmdVars *g,int fd)
>>>   {
>>>     int i;
>>> diff --git a/erts/epmd/test/epmd_SUITE.erl 
>>> b/erts/epmd/test/epmd_SUITE.erl
>>> index cc24a55..ddfe5ab 100644
>>> --- a/erts/epmd/test/epmd_SUITE.erl
>>> +++ b/erts/epmd/test/epmd_SUITE.erl
>>> @@ -42,6 +42,7 @@
>>>   -export(
>>>      [
>>>       register_name/1,
>>> +    register_name_ipv6/1,
>>>       register_names_1/1,
>>>       register_names_2/1,
>>>       register_duplicate_name/1,
>>> @@ -108,7 +109,8 @@
>>>   suite() ->  [{ct_hooks,[ts_install_cth]}].
>>>
>>>   all() ->
>>> -    [register_name, register_names_1, register_names_2,
>>> +    [register_name, register_name_ipv6,
>>> +     register_names_1, register_names_2,
>>>        register_duplicate_name, unicode_name, long_unicode_name,
>>>        get_port_nr, slow_get_port_nr,
>>>        unregister_others_name_1, unregister_others_name_2,
>>> @@ -165,6 +167,24 @@ register_name(Config) when is_list(Config) ->
>>>       ?line ok = close(Sock),            % Unregister
>>>       ok.
>>>
>>> +register_name_ipv6(doc) ->
>>> +    ["Register a name over IPv6"];
>>> +register_name_ipv6(suite) ->
>>> +    [];
>>> +register_name_ipv6(Config) when is_list(Config) ->
>>> +    % Test if the host has an IPv6 loopback address
>>> +    Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]),
>>> +    case Res of
>>> +    {ok,LSock} ->
>>> +        gen_tcp:close(LSock),
>>> +        ?line ok = epmdrun(),
>>> +        ?line {ok,Sock} = register_node6("foobar6"),
>>> +        ?line ok = close(Sock),         % Unregister
>>> +        ok;
>>> +    _Error ->
>>> +        {skip, "Host does not have an IPv6 loopback address"}
>>> +    end.
>>> +
>>>   register_names_1(doc) ->
>>>       ["Register and unregister two nodes"];
>>>   register_names_1(suite) ->
>>> @@ -238,13 +258,18 @@ register_node(Name) ->
>>>   register_node(Name,Port) ->
>>>       register_node_v2(Port,$M,0,5,5,Name,"").
>>>
>>> +register_node6(Name) ->
>>> + register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,"").
>>> +
>>>   register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
>>> +    register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, 
>>> Name, Extra).
>>> +register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, 
>>> Extra) ->
>>>       Utf8Name = unicode:characters_to_binary(Name),
>>>       Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot,
>>>          put16(HVsn), put16(LVsn),
>>>          put16(size(Utf8Name)), binary_to_list(Utf8Name),
>>>          size16(Extra), Extra],
>>> -    case send_req(Req) of
>>> +    case send_req(Req, Addr) of
>>>       {ok,Sock} ->
>>>       case recv(Sock,4) of
>>>           {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} ->
>>> @@ -1129,7 +1154,9 @@ send_direct(Sock, Bytes) ->
>>>       end.
>>>
>>>   send_req(Req) ->
>>> -    case connect() of
>>> +    send_req(Req, "localhost").
>>> +send_req(Req, Addr) ->
>>> +    case connect(Addr) of
>>>       {ok,Sock} ->
>>>       case send(Sock, [size16(Req), Req]) of
>>>           ok ->
>>> diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
>>> index 91af49f..21a3dec 100644
>>> --- a/lib/kernel/src/erl_epmd.erl
>>> +++ b/lib/kernel/src/erl_epmd.erl
>>> @@ -31,7 +31,7 @@
>>>   %% External exports
>>>   -export([start/0, start_link/0, stop/0, port_please/2,
>>>        port_please/3, names/0, names/1,
>>> -     register_node/2, open/0, open/1, open/2]).
>>> +     register_node/2, register_node/3, open/0, open/1, open/2]).
>>>
>>>   %% gen_server callbacks
>>>   -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
>>> @@ -106,7 +106,9 @@ names1(HostName) ->
>>>
>>>
>>>   register_node(Name, PortNo) ->
>>> -    gen_server:call(erl_epmd, {register, Name, PortNo}, infinity).
>>> +    register_node(Name, PortNo, inet).
>>> +register_node(Name, PortNo, Family) ->
>>> +    gen_server:call(erl_epmd, {register, Name, PortNo, Family}, 
>>> infinity).
>>>
>>> %%%----------------------------------------------------------------------
>>>   %%% Callback functions from gen_server
>>> @@ -124,10 +126,10 @@ init(_) ->
>>>   -spec handle_call(calls(), term(), state()) ->
>>>           {'reply', term(), state()} | {'stop', 'shutdown', 'ok', 
>>> state()}.
>>>
>>> -handle_call({register, Name, PortNo}, _From, State) ->
>>> +handle_call({register, Name, PortNo, Family}, _From, State) ->
>>>       case State#state.socket of
>>>       P when P<  0 ->
>>> -        case do_register_node(Name, PortNo) of
>>> +        case do_register_node(Name, PortNo, Family) of
>>>           {alive, Socket, Creation} ->
>>>           S = State#state{socket = Socket,
>>>                       port_no = PortNo,
>>> @@ -210,8 +212,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when 
>>> ?ip6(A,B,C,D,E,F,G,H) ->
>>>   close(Socket) ->
>>>       gen_tcp:close(Socket).
>>>
>>> -do_register_node(NodeName, TcpPort) ->
>>> -    case open() of
>>> +do_register_node(NodeName, TcpPort, Family) ->
>>> +    Localhost = case Family of
>>> +        inet ->  open({127,0,0,1});
>>> +        inet6 ->  open({0,0,0,0,0,0,0,1})
>>> +    end,
>>> +    case Localhost of
>>>       {ok, Socket} ->
>>>       Name = to_string(NodeName),
>>>           Extra = "",
>>> diff --git a/lib/kernel/src/inet6_tcp_dist.erl 
>>> b/lib/kernel/src/inet6_tcp_dist.erl
>>> index 2315a56..bba4d87 100644
>>> --- a/lib/kernel/src/inet6_tcp_dist.erl
>>> +++ b/lib/kernel/src/inet6_tcp_dist.erl
>>> @@ -71,7 +71,7 @@ listen(Name) ->
>>>           {ok, Socket} ->
>>>               TcpAddress = get_tcp_address(Socket),
>>>               {_,Port} = TcpAddress#net_address.address,
>>> -            case erl_epmd:register_node(Name, Port) of
>>> +            case erl_epmd:register_node(Name, Port, inet6) of
>>>                   {ok, Creation} ->
>>>                       {ok, {Socket, TcpAddress, Creation}};
>>>                   Error ->
>>
>>
>
>




More information about the erlang-patches mailing list