Skip to content

Commit

Permalink
wip: announce
Browse files Browse the repository at this point in the history
  • Loading branch information
m-schmoock committed Oct 7, 2021
1 parent 81e7840 commit afd6e41
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 26 deletions.
4 changes: 4 additions & 0 deletions common/json_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ void json_add_address(struct json_stream *response, const char *fieldname,
json_add_string(response, "type", "torv3");
json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr));
json_add_num(response, "port", addr->port);
} else if (addr->type == ADDR_TYPE_DNS) {
json_add_string(response, "type", "dns");
json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr));
json_add_num(response, "port", addr->port);
}
json_object_end(response);
}
Expand Down
38 changes: 38 additions & 0 deletions common/wireaddr.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ bool fromwire_wireaddr(const u8 **cursor, size_t *max, struct wireaddr *addr)
case ADDR_TYPE_TOR_V3:
addr->addrlen = TOR_V3_ADDRLEN;
break;
case ADDR_TYPE_DNS:
addr->addrlen = fromwire_u8(cursor, max);
memset(&addr->addr, 0, sizeof(addr->addr));
addr->addr[addr->addrlen] = 0;
break;
default:
return false;
}
Expand All @@ -49,6 +54,8 @@ bool fromwire_wireaddr(const u8 **cursor, size_t *max, struct wireaddr *addr)
void towire_wireaddr(u8 **pptr, const struct wireaddr *addr)
{
towire_u8(pptr, addr->type);
if (addr->type == ADDR_TYPE_DNS)
towire_u8(pptr, addr->addrlen);
towire(pptr, addr->addr, addr->addrlen);
towire_u16(pptr, addr->port);
}
Expand Down Expand Up @@ -192,6 +199,7 @@ bool wireaddr_is_wildcard(const struct wireaddr *addr)
return memeqzero(addr->addr, addr->addrlen);
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_DNS:
return false;
}
abort();
Expand Down Expand Up @@ -239,6 +247,8 @@ char *fmt_wireaddr_without_port(const tal_t * ctx, const struct wireaddr *a)
case ADDR_TYPE_TOR_V3:
return tal_fmt(ctx, "%s.onion",
b32_encode(tmpctx, a->addr, a->addrlen));
case ADDR_TYPE_DNS:
return tal_fmt(ctx, "%s", a->addr);
}

hex = tal_hexstr(ctx, a->addr, a->addrlen);
Expand Down Expand Up @@ -730,6 +740,8 @@ struct addrinfo *wireaddr_to_addrinfo(const tal_t *ctx,
struct addrinfo *ai = talz(ctx, struct addrinfo);
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct addrinfo hints, *ais, *aii;
int gai_err;

ai->ai_socktype = SOCK_STREAM;

Expand All @@ -748,6 +760,31 @@ struct addrinfo *wireaddr_to_addrinfo(const tal_t *ctx,
ai->ai_addrlen = sizeof(*sin6);
ai->ai_addr = (struct sockaddr *)sin6;
return ai;
case ADDR_TYPE_DNS:
/* Resolve with getaddrinfo */
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
gai_err = getaddrinfo((char *)wireaddr->addr,
tal_fmt(tmpctx, "%d", wireaddr->port),
&hints, &ais);
if (gai_err != 0) {
// TODO: handle errors
// *err_msg = gai_strerror(gai_err);
break;
}
for (aii = ais; aii; aii = aii->ai_next) {
if (aii->ai_family == AF_INET6 || aii->ai_family == AF_INET) {
memcpy(&ai, aii, sizeof(struct addrinfo));
freeaddrinfo(ais);
return ai;
}
}
freeaddrinfo(ais);
// TODO: handle no suitable ai_family found
break;
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
break;
Expand Down Expand Up @@ -801,6 +838,7 @@ bool all_tor_addresses(const struct wireaddr_internal *wireaddr)
switch (wireaddr[i].u.wireaddr.type) {
case ADDR_TYPE_IPV4:
case ADDR_TYPE_IPV6:
case ADDR_TYPE_DNS:
return false;
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
Expand Down
8 changes: 5 additions & 3 deletions common/wireaddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,24 @@ struct sockaddr_un;
* onion service addresses; Encodes:
* `[32:32_byte_ed25519_pubkey] || [2:checksum] || [1:version]`,
* where `checksum = sha3(".onion checksum" | pubkey || version)[:2]`
* * `5`: DNS hostname; data = `[byte:len][len*byte:hostname][u16:port]` (length up to 258)
*/

#define TOR_V2_ADDRLEN 10
#define TOR_V3_ADDRLEN 35
#define LARGEST_ADDRLEN TOR_V3_ADDRLEN
#define DNS_ADDRLEN 255
#define LARGEST_ADDRLEN DNS_ADDRLEN
#define TOR_V3_BLOBLEN 64
#define STATIC_TOR_MAGIC_STRING "gen-default-toraddress"

enum wire_addr_type {
ADDR_TYPE_IPV4 = 1,
ADDR_TYPE_IPV6 = 2,
ADDR_TYPE_TOR_V2 = 3,
ADDR_TYPE_TOR_V3 = 4
ADDR_TYPE_TOR_V3 = 4,
ADDR_TYPE_DNS = 5
};

/* Structure now fit for tor support */
struct wireaddr {
enum wire_addr_type type;
u8 addrlen;
Expand Down
6 changes: 6 additions & 0 deletions connectd/connectd.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,9 @@ static void try_connect_one_addr(struct connecting *connect)
case ADDR_TYPE_IPV6:
af = AF_INET6;
break;
case ADDR_TYPE_DNS:
// TODO: resolve with getaddrinfo and set af
break;
}
}

Expand Down Expand Up @@ -990,6 +993,7 @@ static bool handle_wireaddr_listen(struct daemon *daemon,
return false;
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_DNS:
break;
}
status_failed(STATUS_FAIL_INTERNAL_ERROR,
Expand Down Expand Up @@ -1409,6 +1413,8 @@ static void add_seed_addrs(struct wireaddr_internal **addrs,
NULL, broken_reply, NULL);
if (new_addrs) {
for (size_t j = 0; j < tal_count(new_addrs); j++) {
if (new_addrs[j].type == ADDR_TYPE_DNS)
continue;
struct wireaddr_internal a;
a.itype = ADDR_INTERNAL_WIREADDR;
a.u.wireaddr = new_addrs[j];
Expand Down
1 change: 1 addition & 0 deletions connectd/netaddress.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ bool guess_address(struct wireaddr *addr)
}
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_DNS:
status_broken("Cannot guess address type %u", addr->type);
break;
}
Expand Down
1 change: 1 addition & 0 deletions contrib/pyln-spec/bolt7/pyln/spec/bolt7/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@
onion service addresses; Encodes:
`[32:32_byte_ed25519_pubkey] || [2:checksum] || [1:version]`, where
`checksum = sha3(".onion checksum" | pubkey || version)[:2]`.
* `5`: DNS hostname; data = `[byte:len][len*byte:hostname][u16:port]` (length up to 258)
### Requirements
Expand Down
4 changes: 4 additions & 0 deletions devtools/gossipwith.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,10 @@ int main(int argc, char *argv[])
case ADDR_TYPE_IPV6:
af = AF_INET6;
break;
case ADDR_TYPE_DNS:
/* DNS names should have been resolved
* by parse_wireaddr_internal */
assert(false);
}
ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr);
}
Expand Down
4 changes: 2 additions & 2 deletions doc/lightning-getinfo.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ On success, an object is returned, containing:
- **network** (string): represents the type of network on the node are working (e.g: `bitcoin`, `testnet`, or `regtest`)
- **fees_collected_msat** (msat): Total routing fees collected by this node
- **address** (array of objects, optional): The addresses we announce to the world:
- **type** (string): Type of connection (one of "ipv4", "ipv6", "torv2", "torv3")
- **type** (string): Type of connection (one of "ipv4", "ipv6", "torv2", "torv3", "dns")
- **address** (string): address in expected format for **type**
- **port** (u16): port number
- **binding** (array of objects, optional): The addresses we are listening on:
Expand Down Expand Up @@ -115,4 +115,4 @@ RESOURCES
---------

Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:a41fb9bb8e6e61bec105ff250584ae019dda93d4f97bfff53bc86d57ab6e8607)
[comment]: # ( SHA256STAMP:ab2b63c6b0a09a6955759eab780b8197048b5aacb01c5c680371b2ade718fb1c)
10 changes: 5 additions & 5 deletions doc/lightning-listnodes.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ If **last_timestamp** is present:
- **color** (hex): The favorite RGB color this node advertized (always 6 characters)
- **features** (hex): BOLT #9 features bitmap this node advertized
- **addresses** (array of objects): The addresses this node advertized:
- **type** (string): Type of connection (one of "ipv4", "ipv6", "torv2", "torv3")
- **type** (string): Type of connection (one of "ipv4", "ipv6", "torv2", "torv3", "dns")
- **address** (string): address in expected format for *type*
- **port** (u16): port number

Expand All @@ -50,9 +50,9 @@ If **option_will_fund** is present:
- **compact_lease** (hex): the lease as represented in the node_announcement

[comment]: # (GENERATE-FROM-SCHEMA-END)

On failure, one of the following error codes may be returned:

- -32602: Error in given parameters.

EXAMPLE JSON RESPONSE
Expand Down Expand Up @@ -87,10 +87,10 @@ Vincenzo Palazzo <<vincenzo.palazzo@protonmail.com>> wrote the initial version o
SEE ALSO
--------

FIXME:
FIXME:

RESOURCES
---------

Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:158477348efb51a8cf71a595b3d76dde545ab6824958c8a32d4b3dbbbe2c8121)
[comment]: # ( SHA256STAMP:6ec13dcde7efe4ec5e5ead8df1a7b8e2915c85b7600283afb5399bb79a5525db)
2 changes: 1 addition & 1 deletion doc/schemas/getinfo.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"properties": {
"type": {
"type": "string",
"enum": [ "ipv4", "ipv6", "torv2", "torv3" ],
"enum": [ "ipv4", "ipv6", "torv2", "torv3", "dns" ],
"description": "Type of connection"
},
"address": {
Expand Down
2 changes: 1 addition & 1 deletion doc/schemas/listnodes.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"properties": {
"type": {
"type": "string",
"enum": [ "ipv4", "ipv6", "torv2", "torv3" ],
"enum": [ "ipv4", "ipv6", "torv2", "torv3", "dns" ],
"description": "Type of connection"
},
"address": {
Expand Down
34 changes: 27 additions & 7 deletions lightningd/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,18 +188,38 @@ static char *opt_add_addr_withtype(const char *arg,
char const *err_msg;
struct wireaddr_internal wi;
bool dns_ok;
char *address;
u16 port;

assert(arg != NULL);
dns_ok = !ld->always_use_proxy && ld->config.use_dns;

if (!parse_wireaddr_internal(arg, &wi,
ld->portnum,
wildcard_ok, dns_ok, false,
deprecated_apis, &err_msg)) {
return tal_fmt(NULL, "Unable to parse address '%s': %s", arg, err_msg);
if (!separate_address_and_port(tmpctx, arg, &address, &port))
return tal_fmt(NULL, "Unable to parse address:port '%s'", arg);

if (is_ipaddr(address) || is_toraddr(address) || ala != ADDR_ANNOUNCE) {
if (!parse_wireaddr_internal(arg, &wi, ld->portnum,
wildcard_ok, dns_ok, false,
deprecated_apis, &err_msg)) {
return tal_fmt(NULL, "Unable to parse address '%s': %s", arg, err_msg);
}
tal_arr_expand(&ld->proposed_listen_announce, ala);
tal_arr_expand(&ld->proposed_wireaddr, wi);
}
tal_arr_expand(&ld->proposed_listen_announce, ala);
tal_arr_expand(&ld->proposed_wireaddr, wi);

/* Add ADDR_TYPE_DNS to announce DNS hostnames */
if (is_dnsaddr(address) && ala & ADDR_ANNOUNCE) {
memset(&wi, 0, sizeof(wi));
wi.itype = ADDR_INTERNAL_WIREADDR;
wi.u.wireaddr.type = ADDR_TYPE_DNS;
wi.u.wireaddr.addrlen = strlen(address);
strncpy((char * restrict)&wi.u.wireaddr.addr,
address, sizeof(wi.u.wireaddr.addr));
wi.u.wireaddr.port = port;
tal_arr_expand(&ld->proposed_listen_announce, ADDR_ANNOUNCE);
tal_arr_expand(&ld->proposed_wireaddr, wi);
}

return NULL;

}
Expand Down
35 changes: 28 additions & 7 deletions tests/test_gossip.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ def test_announce_address(node_factory, bitcoind):
"""Make sure our announcements are well formed."""

# We do not allow announcement of duplicates.
opts = {'announce-addr':
opts = {'disable-dns': None, 'announce-addr':
['4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad.onion',
'1.2.3.4:1234',
'localhost:1235',
'example.com:1236',
'::'],
'log-level': 'io',
'dev-allow-localhost': None}
Expand All @@ -125,12 +127,31 @@ def test_announce_address(node_factory, bitcoind):
l2.wait_channel_active(scid)

# We should see it send node announce with all addresses (257 = 0x0101)
# local ephemeral port is masked out.
l1.daemon.wait_for_log(r"\[OUT\] 0101.*47"
"010102030404d2"
"017f000001...."
"02000000000000000000000000000000002607"
"04e00533f3e8f2aedaa8969b3d0fa03a96e857bbb28064dca5e147e934244b9ba50230032607")
# Note: local ephemeral port is masked out.
# Note: Since we `disable-dns` it should not announce a resolved IPv4
# or IPv6 address for example.com
#
# Also expect the address descriptor types to be sorted!
# BOLT #7:
# - MUST place address descriptors in ascending order.
l1.daemon.wait_for_log(r"\[OUT\] 0101.*0063"
"010102030404d2" # IPv4 01 1.2.3.4:1234
"017f000001...." # IPv4 01 127.0.0.1:wxyz
"02000000000000000000000000000000002607" # IPv6 02 :::9735
"04e00533f3e8f2aedaa8969b3d0fa03a96e857bbb28064dca5e147e934244b9ba50230032607" # TORv3 04
"05096c6f63616c686f737404d3" # DNS 05 len localhost:1235
"050b6578616d706c652e636f6d04d4") # DNS 05 len example.com:1236

# Check other node can parse these
addresses = l2.rpc.listnodes()['nodes'][0]['addresses']
addresses_dns = [address for address in addresses if address['type'] == 'dns']
assert len(addresses) == 6
assert len(addresses_dns) == 2
assert addresses_dns[0]['address'] == 'localhost'
assert addresses_dns[0]['port'] == 1235
assert addresses_dns[1]['address'] == 'example.com'
assert addresses_dns[1]['port'] == 1236



@pytest.mark.developer("needs DEVELOPER=1")
Expand Down

0 comments on commit afd6e41

Please sign in to comment.