Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

epmd: add option to bind to network interface on Linux #1353

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions erts/doc/src/epmd.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,22 @@
<c><![CDATA[ERL_EPMD_PORT]]></c>; see section <seealso
marker="#environment_variables">Environment Variables</seealso>.</p>
</item>
<tag><c><![CDATA[-interface Name]]></c></tag>
<item>
<p>Bind this instance of <c>epmd</c> listen socket to the specified
interface. This can also be set using environment variable
<c><![CDATA[ERL_EPMD_INTERFACE]]></c>; see section <seealso
marker="#environment_variables">Environment Variables</seealso>.</p>
<p>This option uses the Linux-specific socket option
<c>SO_BINDTODEVICE</c>, such as in Linux kernel 2.0.30 or later,
and therefore only exists when the runtime system
is compiled for such an operating system.</p>
<p>epmd also needs elevated privileges, either running as superuser or
(for Linux) having capability <c>CAP_NET_RAW</c>.</p>
<p>The primary use case for this option is to bind epmd into a
<url href="http://www.kernel.org/doc/Documentation/networking/vrf.txt">Linux VRF instance</url>.
</p>
</item>
<tag><c><![CDATA[-d | -debug]]></c></tag>
<item>
<p>Enables debug output. The more <c>-d</c> flags specified, the more
Expand Down Expand Up @@ -273,6 +289,12 @@
independent clusters of nodes, to co-exist on the same host.
All nodes in a cluster must use the same <c>epmd</c> port number.</p>
</item>
<tag><c><![CDATA[ERL_EPMD_INTERFACE]]></c></tag>
<item>
<p>If set, <c>epmd</c> will bind it sockets to that interface (Linux only).
See <seealso marker="#daemon_flags">Option -interface</seealso> for
additional restrictions.</p>
</item>
<tag><c><![CDATA[ERL_EPMD_RELAXED_COMMAND_CHECK]]></c></tag>
<item>
<p>If set before start, the <c>epmd</c> daemon behaves
Expand Down
24 changes: 23 additions & 1 deletion erts/epmd/src/epmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ static void usage(EpmdVars *);
static void run_daemon(EpmdVars*);
static char* get_addresses(void);
static int get_port_no(void);
#if defined(SO_BINDTODEVICE)
static char* get_interface(void);
#endif
static int check_relaxed(void);
#ifdef __WIN32__
static int has_console(void);
Expand Down Expand Up @@ -163,6 +166,9 @@ int main(int argc, char** argv)

g->addresses = get_addresses();
g->port = get_port_no();
#if defined(SO_BINDTODEVICE)
g->interface = get_interface();
#endif
g->debug = 0;

g->silent = 0;
Expand Down Expand Up @@ -227,6 +233,13 @@ int main(int argc, char** argv)
((g->port = atoi(argv[1])) == 0))
usage(g);
argv += 2; argc -= 2;
#if defined(SO_BINDTODEVICE)
} else if (strcmp(argv[0], "-interface") == 0) {
if (argc == 1)
usage(g);
g->interface = argv[1];
argv += 2; argc -= 2;
#endif
} else if (strcmp(argv[0], "-names") == 0) {
if (argc == 1)
epmd_call(g, EPMD_NAMES_REQ);
Expand Down Expand Up @@ -423,6 +436,10 @@ static void usage(EpmdVars *g)
fprintf(stderr, " -port No\n");
fprintf(stderr, " Let epmd listen to another port than default %d\n",
EPMD_PORT_NO);
#if defined(SO_BINDTODEVICE)
fprintf(stderr, " -interface Name\n");
fprintf(stderr, " Bind epmd's socket to the specified interface\n");
#endif
fprintf(stderr, " -d\n");
fprintf(stderr, " -debug\n");
fprintf(stderr, " Enable debugging. This will give a log to\n");
Expand Down Expand Up @@ -614,4 +631,9 @@ static int check_relaxed(void)
char* port_str = getenv("ERL_EPMD_RELAXED_COMMAND_CHECK");
return (port_str != NULL) ? 1 : 0;
}

#if defined(SO_BINDTODEVICE)
static char* get_interface(void)
{
return getenv("ERL_EPMD_INTERFACE");
}
#endif
16 changes: 16 additions & 0 deletions erts/epmd/src/epmd_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ static int conn_to_epmd(EpmdVars *g)
connect_sock = socket(AF_INET6, SOCK_STREAM, 0);
if (connect_sock>=0) {

#if defined(SO_BINDTODEVICE)
if (g->interface && g->interface[0]) {
if (setsockopt(connect_sock, SOL_SOCKET, SO_BINDTODEVICE, g->interface,
strlen(g->interface) + 1) < 0)
goto error;
}
#endif

if (connect(connect_sock, (struct sockaddr*)&address, salen) == 0)
return connect_sock;

Expand All @@ -160,6 +168,14 @@ static int conn_to_epmd(EpmdVars *g)
if (connect_sock<0)
goto error;

#if defined(SO_BINDTODEVICE)
if (g->interface && g->interface[0]) {
if (setsockopt(connect_sock, SOL_SOCKET, SO_BINDTODEVICE, g->interface,
strlen(g->interface) + 1) < 0)
goto error;
}
#endif

if (connect(connect_sock, (struct sockaddr*)&address, salen) < 0)
goto error;

Expand Down
3 changes: 3 additions & 0 deletions erts/epmd/src/epmd_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ typedef struct {
fd_set orig_read_mask;
int listenfd[MAX_LISTEN_SOCKETS];
char *addresses;
#if defined(SO_BINDTODEVICE)
char *interface;
#endif
char **argv;
#ifdef HAVE_SYSTEMD_DAEMON
int is_systemd;
Expand Down
11 changes: 11 additions & 0 deletions erts/epmd/src/epmd_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,17 @@ void run(EpmdVars *g)
}
#endif

#if defined(SO_BINDTODEVICE)
if (g->interface && g->interface[0]) {
if (setsockopt(listensock[i], SOL_SOCKET, SO_BINDTODEVICE,
g->interface, strlen(g->interface) + 1) < 0)
{
dbg_perror(g,"can't bind to interface");
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.
Expand Down