Skip to content

Add support for local socket connections#1323

Closed
icota wants to merge 3 commits into
ElementsProject:masterfrom
icota:offline-payments
Closed

Add support for local socket connections#1323
icota wants to merge 3 commits into
ElementsProject:masterfrom
icota:offline-payments

Conversation

@icota
Copy link
Copy Markdown
Contributor

@icota icota commented Apr 4, 2018

This is a flexible way to connect two instances of c-lightning via means other than the official ones. Run one side with --localsocket=lightning-listener and the other simply connects to the full socket path.

In practice two c-lightning instances are run on separate machines with glue code connecting to sockets and forwarding data between them.

I use this to make a lightning connection (on an otherwise disconnected device) via NFC, but can be made to support bluetooth, infrared, sound or even smoke signals, anything really. Use case would be communicating with always-connected payment terminals with a mobile device that might not be.

This is way out of lightning spec but it doesn't seem to hurt anything. Let me know know what you think!

Comment thread common/wireaddr.h Outdated
ADDR_TYPE_PADDING = 0,
ADDR_TYPE_IPV4 = 1,
ADDR_TYPE_IPV6 = 2,
ADDR_TYPE_LOCAL_SOCKET = 5
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am hesitant to put this in struct wireaddr as this is also used in BOLT standard-compliant node_announcement that get broadcast as node gossip.

At minimum the numbering should not be directly after the BOLT-defined ones.

It might be better to bring up this possible use case in lightning-dev mailing list.

Alternatively we could skip this address type when sending gossip announcements.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, it makes no sense at all to broadcast these. It hadn't occurred to me. I will look into alternatives.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think there's much value in adding local sockets to the BOLTs but I settled on a MIME type (application/lightning) and an application id (LIGHTNING) for NFC payments. I'll bring this up on the ML when I get the time since I'm not sure how to proceed on standardising these.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If we never broadcast these there is no need to bring it up on the mailinglist, but, I am uncertain if we should be using struct wireaddr then, or some other mechanism. Intent, as I understand it, is that struct wireaddr, is for standard broadcastable messages. @rustyrussell @cdecker opinions?

Comment thread lightningd/options.c

}

static char *opt_add_localsocket(const char *arg, struct lightningd *ld)
Copy link
Copy Markdown
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();
}

@rustyrussell
Copy link
Copy Markdown
Contributor

It's cute to see these in the local address listings, but the consequences of putting it in struct wireaddr are probably not worth dealing with.

Just add a '--local-socket' option perhaps? And set addr->type to ADDR_TYPE_PADDING.

@icota
Copy link
Copy Markdown
Contributor Author

icota commented Apr 5, 2018

@rustyrussell There is the --localsocket option when we start the daemon, to make it listen. Did you mean a JSON option when connecting?

@icota icota force-pushed the offline-payments branch from c1fe67d to 61cece6 Compare April 6, 2018 09:32
@icota
Copy link
Copy Markdown
Contributor Author

icota commented Apr 6, 2018

New code avoids changes to struct_wireaddr opting to just use ADDR_TYPE_PADDING. It's less code and doesn't broadcast.

check-source fails at shellcheck and check fails at test-blockchaintrack. I don't think either of those are my fault. I guess I'm missing something to run these tests correctly.

@ZmnSCPxj
Copy link
Copy Markdown
Contributor

ZmnSCPxj commented Apr 6, 2018

CI is fine so I suppose it is OK. You can install shellcheck, most distros seem to have it. test_blockchaintrack is known flaky and rerunning it should be OK.

Now reviewing code, please wait...

Comment thread gossipd/gossip.c
portnum);

/* Optional UNIX socket */
if (localsocket) {
Copy link
Copy Markdown
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
Copy Markdown
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.

Comment thread gossipd/gossip.c Outdated
io_new_conn(reach, fd, conn_init, reach);
}

static void try_connect_local_socket(struct daemon *daemon, const struct pubkey *id, const struct addrhint *a)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Might conflict with ongoing changes in #1322, that is higher priority than this I think, so please monitor that PR when it gets merged in and see if this gets conflicted (maybe not a text-level conflict but some of the functions this try_connect_local_socket calls might change their signatures and exact behavior). The first thing I can think of is that reach->succeeded has been removed in #1322, but please see that PR more for other changes that might affect this code.

ZmnSCPxj
ZmnSCPxj previously approved these changes Apr 6, 2018
@ZmnSCPxj
Copy link
Copy Markdown
Contributor

ZmnSCPxj commented Apr 6, 2018

ACK 61cece6

Note however that #1322 changes code that this PR depends on, so we should take care. I somewhat prefer that we get #1322 merged first, then adapt this PR to it, but anyway adapting is needed at some point.

@icota
Copy link
Copy Markdown
Contributor Author

icota commented Apr 6, 2018

Thanks @ZmnSCPxj! No big deal if you merge #1322 first, this one is smaller so easier to adapt

@cdecker
Copy link
Copy Markdown
Member

cdecker commented Apr 15, 2018

Holding this PR back a bit further since #1322 is rather high priority and I don't want to delay by introducing conflicts. Just wanted to acknowledge that we haven't forgotten about this excellent change @icota 😉

@ZmnSCPxj
Copy link
Copy Markdown
Contributor

@icota could you please rebase? #1322 has been merged.

@ZmnSCPxj ZmnSCPxj dismissed their stale review April 27, 2018 14:13

Needs rebase, #1322 probably strongly affects this PR

@icota icota force-pushed the offline-payments branch from 61cece6 to 373fcef Compare April 29, 2018 15:54
@icota
Copy link
Copy Markdown
Contributor Author

icota commented Apr 29, 2018

Rebased, waiting to see if CI is happy

Copy link
Copy Markdown
Contributor

@ZmnSCPxj ZmnSCPxj left a comment

Choose a reason for hiding this comment

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

Mostly request to change in gossipd/gossip_wire.csv. Also suggestion for localsocket arg of setup_listeners.

Comment thread gossipd/gossip.c Outdated
}

static void setup_listeners(struct daemon *daemon, u16 portnum)
static void setup_listeners(struct daemon *daemon, u16 portnum, u8 *localsocket)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

localsocket is only ever read in this function, and is effectively an input string. Maybe better to write as const char * and move the type conversion from u8* to char * to caller of setup_listeners. Or at least const u8* in the argslist.

Comment thread gossipd/gossip_wire.csv Outdated
# Gossipd->master, I am ready.
gossipctl_init_reply,3100

gossipctl_init,,lslen,u16
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this not be with the gossipctl_init fields before gossipctl_init_reply? Clearer that way.

@ZmnSCPxj
Copy link
Copy Markdown
Contributor

ZmnSCPxj commented Apr 30, 2018

Sorry @icota but a new commit in #1440 also conflicts with this: specifically the second commit by @rustyrussell moves setup of listeners to after the activate message, so the localsocket argument in init needs to be moved to the new activate.

@icota icota force-pushed the offline-payments branch from 373fcef to 4ae3aaa Compare April 30, 2018 12:11
@icota
Copy link
Copy Markdown
Contributor Author

icota commented Apr 30, 2018

No worries @ZmnSCPxj, local sockets are kind of a niche application so obviously important stuff needs to go in first. I've rebased yet again.

@ZmnSCPxj
Copy link
Copy Markdown
Contributor

ACK 4ae3aaa

@icota
Copy link
Copy Markdown
Contributor Author

icota commented May 1, 2018

make check fails at test_pay_disconnect which doesn't seem to be related at all:

Traceback (most recent call last):
  File "tests/test_lightningd.py", line 4280, in test_pay_disconnect
    l1.daemon.wait_for_log(r'Peer permanent failure in CHANNELD_NORMAL: lightning_channeld: received ERROR channel .*: update_fee 150000 outside range 4250-75000')

@ZmnSCPxj
Copy link
Copy Markdown
Contributor

ZmnSCPxj commented May 1, 2018

Kicked CI, hopefully it is a temporary thing.

Comment thread common/wireaddr.c
addr->type = ADDR_TYPE_PADDING;
addr->addrlen = strlen(ip);
addr->port = 9999;
memcpy(&addr->addr, ip, addr->addrlen);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this missing an addrlen < sizeof(addr->addr) check?

Comment thread gossipd/gossip.c Outdated
addr.type = ADDR_TYPE_PADDING;
addr.addrlen = sizeof(sun->sun_path);
memcpy(addr.addr, &sun->sun_path, addr.addrlen);
addr.port = 9999;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think 0 as magic value might be better here, just in case we use the port somewhere.

@cdecker
Copy link
Copy Markdown
Member

cdecker commented May 1, 2018

Just two last nits, happy to merge this soon ^^

@icota icota force-pushed the offline-payments branch from 4ae3aaa to 44af32a Compare May 1, 2018 19:10
@icota
Copy link
Copy Markdown
Contributor Author

icota commented May 1, 2018

I've amended the code, I'm thinking this might be the day 🤞

@icota
Copy link
Copy Markdown
Contributor Author

icota commented May 1, 2018

Foiled by CI test_closing_different_fees 😢

Copy link
Copy Markdown
Contributor

@rustyrussell rustyrussell left a comment

Choose a reason for hiding this comment

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

That got ugly fast! You can't mess with how we unmarshal ADDR_TYPE_PADDING; it's in the spec as zero length.

This is internal-only between the main daemon and gossipd. Ugly as it is, I prefer that to be explicit, rather than using wireaddr for this. Otherwise we'll risk getting local file accesses because someone gossiped a socket addresses to us!

  1. Add a new message to gossipd 'towire_gossipctl_peer_addrhint_sockname' which takes a socket name; overloading the wireaddr to add local sockets gives me the creeps, since we also accept them from peers.

  2. Then 'struct addrhint' needs to change in gossipd, to add a 'char *sockname' and appropriate handling.

  3. Finally opt_add_addr needs enhancement, to put the socketname string somewhere if it starts with / (or, use a different option name).

Comment thread gossipd/gossip_wire.csv
# If non-zero, port to listen on.
gossipctl_activate,,port,u16
gossipctl_activate,,lslen,u16
gossipctl_activate,,localsocket,lslen*u8
Copy link
Copy Markdown
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).

Comment thread lightningd/lightningd.h
char *rpc_filename;

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

Choose a reason for hiding this comment

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

char *?

Comment thread common/wireaddr.c
addr->addrlen = 16;
break;
case ADDR_TYPE_PADDING:
addr->addrlen = ((u8)*max) - 2;
Copy link
Copy Markdown
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
Copy Markdown
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.

@rustyrussell
Copy link
Copy Markdown
Contributor

Actually, after more thought, you can just introduce a new 'wireaddr_or_socket' type, and wire that up in the various places...

@ZmnSCPxj
Copy link
Copy Markdown
Contributor

ZmnSCPxj commented May 2, 2018

Agree with the wireaddr_or_socket type idea, but maybe name to contactaddr?

struct contactaddr {
    enum contactaddr_type type;
    union {
        struct wireaddr wireaddr;
        char *localsocket;
    } u;
};

This would probably require special marshaling towire_ and fromwire_ code, though.

@rustyrussell
Copy link
Copy Markdown
Contributor

I have half a patch to do this properly. Give me 2 hours please, will push.

@rustyrussell
Copy link
Copy Markdown
Contributor

Yuck, this ended up quite invasive. There are some nasty places to fix, too.

I've got a very rough cut here:
https://github.com/rustyrussell/lightning/tree/guilt/pr-1323

It's a bit weird since it's built on this PR then ends up reworking much of it: it might be cleaner to combine into one logical sequence.

@ZmnSCPxj
Copy link
Copy Markdown
Contributor

ZmnSCPxj commented May 2, 2018

@rustyrussell your branch looks fine to me, although I mildly agree to combine to a better logical sequence. I would have moved the "single localsocket -> multiple wireaddr_or_sockname and make local sockets in a loop" conversion to its own commit (i.e. leave the localsocket in gossipctl_activate in the big wireaddr to wireaddr_or_sockname move).

rustyrussell added a commit to rustyrussell/lightning that referenced this pull request May 7, 2018
This replacement is a little menial, but it explicitly catches all
the places where we allow a local socket.  The actual implementation of
opening a AF_UNIX socket is almost hidden in the patch.

The detection of "valid address" is now more complex:

	p->addr.itype != ADDR_INTERNAL_WIREADDR || p->addr.u.wireaddr.type != ADDR_TYPE_PADDING

But most places we do this, we should audit: I'm pretty sure we can't
get an invalid address any more from gossipd (they may be in db, but
we should fix that too).

Closes: ElementsProject#1323
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
Copy link
Copy Markdown
Contributor

OK, This has been swallowed into the "crap, where did my time go!" PR #1450...

@cdecker cdecker closed this in 73cd009 May 7, 2018
NicolasDorier pushed a commit to NicolasDorier/lightning that referenced this pull request May 9, 2018
This replacement is a little menial, but it explicitly catches all
the places where we allow a local socket.  The actual implementation of
opening a AF_UNIX socket is almost hidden in the patch.

The detection of "valid address" is now more complex:

	p->addr.itype != ADDR_INTERNAL_WIREADDR || p->addr.u.wireaddr.type != ADDR_TYPE_PADDING

But most places we do this, we should audit: I'm pretty sure we can't
get an invalid address any more from gossipd (they may be in db, but
we should fix that too).

Closes: ElementsProject#1323
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants