Skip to content

Add support for local socket connections #1323

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

Closed
wants to merge 3 commits into from
Closed
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
20 changes: 19 additions & 1 deletion common/wireaddr.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <wire/wire.h>

/* Returns false if we didn't parse it, and *cursor == NULL if malformed. */
Expand All @@ -22,6 +23,9 @@ bool fromwire_wireaddr(const u8 **cursor, size_t *max, struct wireaddr *addr)
case ADDR_TYPE_IPV6:
addr->addrlen = 16;
break;
case ADDR_TYPE_PADDING:
addr->addrlen = ((u8)*max) - 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely wrong! We can have things in the msg after the addr. The ADDR_TYPE_PADDING case needs to simply 'return true' (addrlen is 0, there's no port).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and set addr->addrlen = 0.

break;
default:
return false;
}
Expand All @@ -33,7 +37,7 @@ bool fromwire_wireaddr(const u8 **cursor, size_t *max, struct wireaddr *addr)

void towire_wireaddr(u8 **pptr, const struct wireaddr *addr)
{
if (!addr || addr->type == ADDR_TYPE_PADDING) {
if (!addr) {
towire_u8(pptr, ADDR_TYPE_PADDING);
return;
}
Expand Down Expand Up @@ -181,6 +185,20 @@ bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 defport,

memset(&addr->addr, 0, sizeof(addr->addr));

/* Addresses starting with '/' are local socket paths */
if (ip[0] == '/') {
/* Check if the path is too long */
if (strlen(ip) > sizeof(addr->addr)) {
goto finish;
}
addr->type = ADDR_TYPE_PADDING;
addr->addrlen = strlen(ip);
addr->port = 0;
memcpy(&addr->addr, ip, addr->addrlen);
res = true;
goto finish;
}

if (inet_pton(AF_INET, ip, &v4) == 1) {
addr->type = ADDR_TYPE_IPV4;
addr->addrlen = 4;
Expand Down
2 changes: 1 addition & 1 deletion common/wireaddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ enum wire_addr_type {
struct wireaddr {
enum wire_addr_type type;
u8 addrlen;
u8 addr[16];
u8 addr[108];
u16 port;
};

Expand Down
50 changes: 44 additions & 6 deletions gossipd/gossip.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <wire/gen_peer_wire.h>
#include <wire/wire_io.h>
Expand Down Expand Up @@ -1541,6 +1542,12 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon
BUILD_ASSERT(sizeof(s4->sin_addr) <= sizeof(addr.addr));
memcpy(addr.addr, &s4->sin_addr, addr.addrlen);
addr.port = ntohs(s4->sin_port);
} else if (s.ss_family == AF_UNIX) {
struct sockaddr_un *sun = (void *)&s;
addr.type = ADDR_TYPE_PADDING;
addr.addrlen = sizeof(sun->sun_path);
memcpy(addr.addr, &sun->sun_path, addr.addrlen);
addr.port = 0;
} else {
status_broken("Unknown socket type %i for incoming conn",
s.ss_family);
Expand All @@ -1552,12 +1559,13 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon
init_new_peer, daemon);
}

static void setup_listeners(struct daemon *daemon, u16 portnum)
static void setup_listeners(struct daemon *daemon, u16 portnum, const char *localsocket)
{
struct sockaddr_in addr;
struct sockaddr_in6 addr6;
struct sockaddr_un sun;
socklen_t len;
int fd1, fd2;
int fd1, fd2, fd3;

if (!portnum) {
status_info("Zero portnum, not listening for incoming");
Expand Down Expand Up @@ -1615,6 +1623,27 @@ static void setup_listeners(struct daemon *daemon, u16 portnum)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could not bind to a network address on port %u",
portnum);

/* Optional UNIX socket */
if (localsocket) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comes from the fromwire_gossipctl_init. In towire_gossipctl_init a NULL pointer is converted to a 0-length array on-the-wire, I am uncertain if a 0-length array on-the-wire will be converted by fromwire_gossipctl_init to a NULL pointer. I shall check later when I can get access to my hacking node.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issue here: turns out 0-length arrays on-the-wire are converted to NULL by fromwire_* functions, so ok.

memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, (char*)localsocket);

fd3 = make_listen_fd(AF_UNIX, &sun, sizeof(sun), false);
if (fd3 >= 0) {
len = sizeof(sun);
if (getsockname(fd3, (void *)&sun, &len) != 0) {
status_broken("Failed get UNIX sockname: %s",
strerror(errno));
close_noerr(fd3);
fd3 = -1;
} else {
status_trace("Creating UNIX socket listener");
io_new_listener(daemon, fd3, connection_in, daemon);
}
}
}
}

/* Parse an incoming gossip init message and assign config variables
Expand Down Expand Up @@ -1653,11 +1682,12 @@ static struct io_plan *gossip_activate(struct daemon_conn *master,
const u8 *msg)
{
u16 port;
u8* localsocket;

if (!fromwire_gossipctl_activate(msg, &port))
if (!fromwire_gossipctl_activate(msg, msg, &port, &localsocket))
master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg);

setup_listeners(daemon, port);
setup_listeners(daemon, port, (const char*)localsocket);

/* OK, we're ready! */
daemon_conn_send(&daemon->master,
Expand Down Expand Up @@ -1762,6 +1792,7 @@ static struct io_plan *conn_init(struct io_conn *conn, struct reaching *reach)
struct addrinfo ai;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_un sun;

/* FIXME: make generic */
ai.ai_flags = 0;
Expand Down Expand Up @@ -1789,8 +1820,12 @@ static struct io_plan *conn_init(struct io_conn *conn, struct reaching *reach)
ai.ai_addr = (struct sockaddr *)&sin6;
break;
case ADDR_TYPE_PADDING:
/* Shouldn't happen. */
return io_close(conn);
ai.ai_family = AF_UNIX;
sun.sun_family = AF_UNIX;
memcpy(&sun.sun_path, reach->addr.addr, sizeof(sun.sun_path));
ai.ai_addrlen = sizeof(sun);
ai.ai_addr = (struct sockaddr *)&sun;
break;
}

io_set_finish(conn, connect_failed, reach);
Expand Down Expand Up @@ -1915,6 +1950,9 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id,
case ADDR_TYPE_IPV6:
fd = socket(AF_INET6, SOCK_STREAM, 0);
break;
case ADDR_TYPE_PADDING:
fd = socket(AF_UNIX, SOCK_STREAM, 0);
break;
default:
fd = -1;
errno = EPROTONOSUPPORT;
Expand Down
2 changes: 2 additions & 0 deletions gossipd/gossip_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ gossipctl_init,,no_reconnect,bool
gossipctl_activate,3025
# If non-zero, port to listen on.
gossipctl_activate,,port,u16
gossipctl_activate,,lslen,u16
gossipctl_activate,,localsocket,lslen*u8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use 'wirestring' here, which is much nicer, and removes cast (it's actually a char*, but wirestring is the name for purposes of the csv).


# Gossipd->master, I am ready.
gossipctl_activate_reply,3125
Expand Down
2 changes: 1 addition & 1 deletion lightningd/gossip_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ static void gossip_activate_done(struct subd *gossip UNUSED,

void gossip_activate(struct lightningd *ld)
{
const u8 *msg = towire_gossipctl_activate(NULL, ld->portnum);
const u8 *msg = towire_gossipctl_activate(NULL, ld->portnum, ld->localsocket_filename);
subd_req(ld->gossip, ld->gossip, take(msg), -1, 0,
gossip_activate_done, NULL);

Expand Down
3 changes: 3 additions & 0 deletions lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ int main(int argc, char *argv[])
if (!ld->daemon_dir)
errx(1, "Could not find daemons");

/* Don't accept local connections by default */
ld->localsocket_filename = NULL;

register_opts(ld);

/* Handle options and config; move to .lightningd */
Expand Down
3 changes: 3 additions & 0 deletions lightningd/lightningd.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ struct lightningd {
char *config_dir;
char *rpc_filename;

/* Local socket for incoming connections */
u8 *localsocket_filename;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

char *?


/* Configuration settings. */
struct config config;

Expand Down
18 changes: 18 additions & 0 deletions lightningd/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,19 @@ static char *opt_add_ipaddr(const char *arg, struct lightningd *ld)

}

static char *opt_add_localsocket(const char *arg, struct lightningd *ld)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listconfigs is crashing in CI, probably due to not handling this case properly in add_config function.

} else {
/* Insert more decodes here! */
abort();
}

{
assert(arg != NULL);

ld->localsocket_filename = tal_free(ld->localsocket_filename);

if (strlen(arg) > 108)
return tal_fmt(NULL, "Local socket path '%s' is over 108 characters", arg);
ld->localsocket_filename = tal_arrz(ld, u8, strlen(arg));
strncpy((char*)ld->localsocket_filename, arg, strlen(arg));
return NULL;
}

static void opt_show_u64(char buf[OPT_SHOW_LEN], const u64 *u)
{
snprintf(buf, OPT_SHOW_LEN, "%"PRIu64, *u);
Expand Down Expand Up @@ -319,6 +332,9 @@ static void config_register_opts(struct lightningd *ld)
opt_register_arg("--ipaddr", opt_add_ipaddr, NULL,
ld,
"Set the IP address (v4 or v6) to announce to the network for incoming connections");
opt_register_arg("--local-socket", opt_add_localsocket, NULL,
ld,
"Set a local socket for incoming connections");
opt_register_noarg("--offline", opt_set_offline, ld,
"Start in offline-mode (do not automatically reconnect and do not accept incoming connections");

Expand Down Expand Up @@ -859,6 +875,8 @@ static void add_config(struct lightningd *ld,
answer = tal_hexstr(name0, ld->rgb, 3);
} else if (opt->cb_arg == (void *)opt_set_alias) {
answer = (const char *)ld->alias;
} else if (opt->cb_arg == (void *)opt_add_localsocket) {
answer = (const char *)ld->localsocket_filename;
} else if (opt->cb_arg == (void *)arg_log_to_file) {
answer = ld->logfile;
} else if (opt->cb_arg == (void *)opt_set_fee_rates) {
Expand Down