Browse Source

Initial TOR v2/v3 support.

This is a rebased and combined patch for Tor support.  It is extensively
reworked in the following patches, but the basis remains Saibato's work,
so it seemed fairest to begin with this.

Minor changes:
1. Use --announce-addr instead of --tor-external.
2. I also reverted some whitespace and unrelated changes from the patch.
3. Removed unnecessary ';' after } in functions.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Saibato 7 years ago
committed by Rusty Russell
parent
commit
877f63e99e
  1. 1
      channeld/Makefile
  2. 1
      closingd/Makefile
  3. 2
      common/Makefile
  4. 63
      common/base32.c
  5. 10
      common/base32.h
  6. 13
      common/test/run-ip_port_parsing.c
  7. 254
      common/tor.c
  8. 14
      common/tor.h
  9. 72
      common/wireaddr.c
  10. 13
      common/wireaddr.h
  11. 146
      doc/TOR.md
  12. 2
      gossipd/Makefile
  13. 238
      gossipd/gossip.c
  14. 2
      gossipd/gossip_wire.csv
  15. 3
      gossipd/netaddress.c
  16. 2
      lightningd/Makefile
  17. 6
      lightningd/gossip_control.c
  18. 8
      lightningd/json.c
  19. 13
      lightningd/lightningd.c
  20. 12
      lightningd/lightningd.h
  21. 49
      lightningd/options.c
  22. 4
      lightningd/test/run-find_my_path.c
  23. 1
      openingd/Makefile
  24. 1
      wallet/test/Makefile

1
channeld/Makefile

@ -33,6 +33,7 @@ ALL_GEN_HEADERS += $(LIGHTNINGD_CHANNEL_HEADERS_GEN)
# Common source we use. # Common source we use.
CHANNELD_COMMON_OBJS := \ CHANNELD_COMMON_OBJS := \
common/base32.o \
common/bip32.o \ common/bip32.o \
common/channel_config.o \ common/channel_config.o \
common/crypto_state.o \ common/crypto_state.o \

1
closingd/Makefile

@ -42,6 +42,7 @@ $(LIGHTNINGD_CLOSING_OBJS): $(LIGHTNINGD_HEADERS)
# Common source we use. # Common source we use.
CLOSINGD_COMMON_OBJS := \ CLOSINGD_COMMON_OBJS := \
common/base32.o \
common/close_tx.o \ common/close_tx.o \
common/crypto_state.o \ common/crypto_state.o \
common/crypto_sync.o \ common/crypto_sync.o \

2
common/Makefile

@ -1,4 +1,5 @@
COMMON_SRC_NOGEN := \ COMMON_SRC_NOGEN := \
common/base32.c \
common/bech32.c \ common/bech32.c \
common/bech32_util.c \ common/bech32_util.c \
common/bip32.c \ common/bip32.c \
@ -41,6 +42,7 @@ COMMON_SRC_NOGEN := \
common/timeout.c \ common/timeout.c \
common/type_to_string.c \ common/type_to_string.c \
common/utils.c \ common/utils.c \
common/tor.c \
common/utxo.c \ common/utxo.c \
common/version.c \ common/version.c \
common/wallet_tx.c \ common/wallet_tx.c \

63
common/base32.c

@ -0,0 +1,63 @@
#include <common/base32.h>
#include <sys/types.h>
/* This is a rework of what i found on the Net about base32
*
* so Orum (shallot) and Markus Gutschke (Google.inc) should be mentioned here
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define BASE32DATA "abcdefghijklmnopqrstuvwxyz234567"
char *b32_encode(char *dst, u8 * src, u8 ver)
{
u16 byte = 0, poff = 0;
for (; byte < ((ver == 2) ? 16 : 56); poff += 5) {
if (poff > 7) {
poff -= 8;
src++;
}
dst[byte++] =
BASE32DATA[(htobe16(*(u16 *) src) >> (11 - poff)) & (u16)
0x001F];
}
dst[byte] = 0;
return dst;
}
//FIXME quiknditry
void b32_decode(u8 * dst, u8 * src, u8 ver)
{
int rem = 0;
int i;
u8 *p = src;
int buf;
u8 ch;
for (i = 0; i < ((ver == 2) ? 16 : 56); p++) {
ch = *p;
buf <<= 5;
if ((ch >= 'a' && ch <= 'z')) {
ch = (ch & 0x1F) - 1;
} else if (ch != '.') {
ch -= '2' - 0x1A;
} else return;
buf = buf | ch;
rem = rem + 5;
if (rem >= 8) {
dst[i++] = buf >> (rem - 8);
rem -= 8;
}
}
}

10
common/base32.h

@ -0,0 +1,10 @@
#ifndef LIGHTNING_COMMON_BASE32_H
#define LIGHTNING_COMMON_BASE32_H
#include "config.h"
#include <ccan/short_types/short_types.h>
char *b32_encode(char *dst, u8 * src, u8 ver);
void b32_decode(u8 * dst, u8 * src, u8 ver);
#endif /* LIGHTNING_COMMON_BASE32_H */

13
common/test/run-ip_port_parsing.c

@ -1,3 +1,4 @@
#include "../common/base32.c"
#include "../common/wireaddr.c" #include "../common/wireaddr.c"
#include <stdio.h> #include <stdio.h>
@ -102,6 +103,18 @@ int main(void)
assert(parse_wireaddr("[::ffff:127.0.0.1]:49150", &addr, 1, NULL)); assert(parse_wireaddr("[::ffff:127.0.0.1]:49150", &addr, 1, NULL));
assert(addr.port == 49150); assert(addr.port == 49150);
assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion:49150", &addr, 1, NULL));
assert(addr.port == 49150);
assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion", &addr, 1, NULL));
assert(addr.port == 1);
assert(parse_wireaddr("odpzvneidqdf5hdq.onion:49150", &addr, 1, NULL));
assert(addr.port == 49150);
assert(parse_wireaddr("odpzvneidqdf5hdq.onion.onion", &addr, 1, NULL));
assert(addr.port == 1);
tal_free(tmpctx); tal_free(tmpctx);
return 0; return 0;
} }

254
common/tor.c

@ -0,0 +1,254 @@
#include <arpa/inet.h>
#include <assert.h>
#include <ccan/err/err.h>
#include <ccan/io/io.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/tor.h>
#include <common/type_to_string.h>
#include <common/utils.h>
#include <common/wireaddr.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <wire/wire.h>
#define MAX_TOR_COOKIE_LEN 32
#define MAX_TOR_SERVICE_READBUFFER_LEN 255
#define MAX_TOR_ONION_V2_ADDR_LEN 16
#define MAX_TOR_ONION_V3_ADDR_LEN 56
static bool return_from_service_call;
struct tor_service_reaching {
struct lightningd *ld;
u8 buffer[MAX_TOR_SERVICE_READBUFFER_LEN];
char *cookie[MAX_TOR_COOKIE_LEN];
u8 *p;
bool noauth;
size_t hlen;
};
static struct io_plan *io_tor_connect_close(struct io_conn *conn)
{
err(1, "Cannot create TOR service address");
return_from_service_call = true;
return io_close(conn);
}
static struct io_plan *io_tor_connect_create_onion_finished(struct io_conn
*conn, struct
tor_service_reaching
*reach)
{
char *temp_char;
if (reach->hlen == MAX_TOR_ONION_V2_ADDR_LEN) {
size_t n = tal_count(reach->ld->proposed_wireaddr);
tal_resize(&reach->ld->proposed_wireaddr, n + 1);
tal_resize(&reach->ld->proposed_listen_announce, n+1);
reach->ld->proposed_listen_announce[n] = ADDR_ANNOUNCE;
temp_char = tal_fmt(tmpctx, "%.56s.onion", reach->buffer);
parse_wireaddr_internal(temp_char,
&reach->ld->proposed_wireaddr[n],
reach->ld->portnum, false, NULL);
return_from_service_call = true;
return io_close(conn);
}
/*on the other hand we can stay connected until ln finish to keep onion alive and then vanish */
//because when we run with Detach flag as we now do every start of LN creates a new addr while the old
//stays valid until reboot this might not be desired so we can also drop Detach and use the
//read_partial to keep it open until LN drops
//FIXME: SAIBATO we might not want to close this conn
//return io_read_partial(conn, reach->p, 1 ,&reach->hlen, io_tor_connect_create_onion_finished, reach);
return io_tor_connect_close(conn);
}
static struct io_plan *io_tor_connect_after_create_onion(struct io_conn *conn, struct
tor_service_reaching
*reach)
{
reach->p = reach->p + reach->hlen;
if (!strstr((char *)reach->buffer, "ServiceID=")) {
if (reach->hlen == 0)
return io_tor_connect_close(conn);
return io_read_partial(conn, reach->p, 1, &reach->hlen,
io_tor_connect_after_create_onion,
reach);
} else {
memset(reach->buffer, 0, sizeof(reach->buffer));
return io_read_partial(conn, reach->buffer,
MAX_TOR_ONION_V2_ADDR_LEN, &reach->hlen,
io_tor_connect_create_onion_finished,
reach);
}
}
//V3 tor after 3.3.3.aplha FIXME: TODO SAIBATO
//sprintf((char *)reach->buffer,"ADD_ONION NEW:ED25519-V3 Port=9735,127.0.0.1:9735\r\n");
static struct io_plan *io_tor_connect_make_onion(struct io_conn *conn, struct tor_service_reaching
*reach)
{
if (strstr((char *)reach->buffer, "250 OK") == NULL)
return io_tor_connect_close(conn);
sprintf((char *)reach->buffer,
"ADD_ONION NEW:RSA1024 Port=%d,127.0.0.1:%d Flags=DiscardPK,Detach\r\n",
reach->ld->portnum, reach->ld->portnum);
reach->hlen = strlen((char *)reach->buffer);
reach->p = reach->buffer;
return io_write(conn, reach->buffer, reach->hlen,
io_tor_connect_after_create_onion, reach);
}
static struct io_plan *io_tor_connect_after_authenticate(struct io_conn *conn, struct
tor_service_reaching
*reach)
{
return io_read(conn, reach->buffer, 7, io_tor_connect_make_onion,
reach);
}
static struct io_plan *io_tor_connect_authenticate(struct io_conn *conn, struct
tor_service_reaching
*reach)
{
sprintf((char *)reach->buffer, "AUTHENTICATE %s\r\n",
(char *)reach->cookie);
if (reach->noauth)
sprintf((char *)reach->buffer, "AUTHENTICATE\r\n");
reach->hlen = strlen((char *)reach->buffer);
return io_write(conn, reach->buffer, reach->hlen,
io_tor_connect_after_authenticate, reach);
}
static struct io_plan *io_tor_connect_after_answer_pi(struct io_conn *conn, struct
tor_service_reaching
*reach)
{
char *p = tal(reach, char);
char *p2 = tal(reach, char);
u8 *buf = tal_arrz(reach, u8, MAX_TOR_COOKIE_LEN);
reach->noauth = false;
if (strstr((char *)reach->buffer, "NULL"))
reach->noauth = true;
else if (strstr((char *)reach->buffer, "HASHEDPASSWORD")
&& (strlen(reach->ld->tor_service_password))) {
reach->noauth = false;
sprintf((char *)reach->cookie, "\"%s\"",
reach->ld->tor_service_password);
} else if ((p = strstr((char *)reach->buffer, "COOKIEFILE="))) {
assert(strlen(p) > 12);
p2 = strstr((char *)(p + 12), "\"");
assert(p2 != NULL);
*(char *)(p + (strlen(p) - strlen(p2))) = 0;
int fd = open((char *)(p + 12), O_RDONLY);
if (fd < 0)
return io_tor_connect_close(conn);
if (!read(fd, buf, MAX_TOR_COOKIE_LEN)) {
close(fd);
return io_tor_connect_close(conn);
} else
close(fd);
hex_encode(buf, 32, (char *)reach->cookie, 80);
reach->noauth = false;
} else
return io_tor_connect_close(conn);
return io_tor_connect_authenticate(conn, reach);
}
static struct io_plan *io_tor_connect_after_protocolinfo(struct io_conn *conn, struct
tor_service_reaching
*reach)
{
memset(reach->buffer, 0, MAX_TOR_SERVICE_READBUFFER_LEN);
return io_read_partial(conn, reach->buffer,
MAX_TOR_SERVICE_READBUFFER_LEN - 1, &reach->hlen,
&io_tor_connect_after_answer_pi, reach);
}
static struct io_plan *io_tor_connect_after_resp_to_connect(struct io_conn
*conn, struct
tor_service_reaching
*reach)
{
sprintf((char *)reach->buffer, "PROTOCOLINFO 1\r\n");
reach->hlen = strlen((char *)reach->buffer);
return io_write(conn, reach->buffer, reach->hlen,
io_tor_connect_after_protocolinfo, reach);
}
static struct io_plan *tor_connect_finish(struct io_conn *conn,
struct tor_service_reaching *reach)
{
return io_tor_connect_after_resp_to_connect(conn, reach);
}
static struct io_plan *tor_conn_init(struct io_conn *conn,
struct lightningd *ld)
{
struct addrinfo *ai_tor = tal(ld, struct addrinfo);
struct tor_service_reaching *reach =
tal(ld, struct tor_service_reaching);
reach->ld = ld;
getaddrinfo(fmt_wireaddr_without_port(ld, ld->tor_serviceaddrs),
tal_fmt(ld, "%d", ld->tor_serviceaddrs->port), NULL,
&ai_tor);
return io_connect(conn, ai_tor, &tor_connect_finish, reach);
}
bool create_tor_hidden_service_conn(struct lightningd * ld)
{
int fd;
struct io_conn *conn;
return_from_service_call = false;
fd = socket(AF_INET, SOCK_STREAM, 0);
conn = io_new_conn(NULL, fd, &tor_conn_init, ld);
if (!conn) {
return_from_service_call = true;
err(1, "Cannot create new TOR connection");
}
return true;
}
bool do_we_use_tor_addr(const struct wireaddr * wireaddr)
{
for (int i = 0; i < tal_count(wireaddr); i++) {
if ((wireaddr[i].type == ADDR_TYPE_TOR_V2)
|| (wireaddr[i].type == ADDR_TYPE_TOR_V3))
return true;
}
return false;
}
bool check_return_from_service_call(void)
{
return return_from_service_call;
}

14
common/tor.h

@ -0,0 +1,14 @@
#ifndef LIGHTNING_COMMON_TOR_H
#define LIGHTNING_COMMON_TOR_H
#include "config.h"
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <lightningd/lightningd.h>
#include <stdbool.h>
#include <stdlib.h>
bool check_return_from_service_call(void);
bool parse_tor_wireaddr(const char *arg,u8 *ip_ld,u16 *port_ld);
bool create_tor_hidden_service_conn(struct lightningd *);
bool do_we_use_tor_addr(const struct wireaddr *wireaddrs);
#endif /* LIGHTNING_COMMON_TOR_H */

72
common/wireaddr.c

@ -1,14 +1,20 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <assert.h> #include <assert.h>
#include <ccan/build_assert/build_assert.h> #include <ccan/build_assert/build_assert.h>
#include <ccan/io/io.h>
#include <ccan/mem/mem.h> #include <ccan/mem/mem.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
#include <common/base32.h>
#include <common/type_to_string.h> #include <common/type_to_string.h>
#include <common/utils.h> #include <common/utils.h>
#include <common/wireaddr.h> #include <common/wireaddr.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#include <wire/wire.h> #include <wire/wire.h>
/* Returns false if we didn't parse it, and *cursor == NULL if malformed. */ /* Returns false if we didn't parse it, and *cursor == NULL if malformed. */
@ -23,6 +29,12 @@ bool fromwire_wireaddr(const u8 **cursor, size_t *max, struct wireaddr *addr)
case ADDR_TYPE_IPV6: case ADDR_TYPE_IPV6:
addr->addrlen = 16; addr->addrlen = 16;
break; break;
case ADDR_TYPE_TOR_V2:
addr->addrlen = TOR_V2_ADDRLEN;
break;
case ADDR_TYPE_TOR_V3:
addr->addrlen = TOR_V3_ADDRLEN;
break;
default: default:
return false; return false;
} }
@ -96,7 +108,7 @@ bool fromwire_wireaddr_internal(const u8 **cursor, size_t *max,
char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a) char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a)
{ {
char addrstr[INET6_ADDRSTRLEN]; char addrstr[FQDN_ADDRLEN];
char *ret, *hex; char *ret, *hex;
switch (a->type) { switch (a->type) {
@ -108,6 +120,12 @@ char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a)
if (!inet_ntop(AF_INET6, a->addr, addrstr, INET6_ADDRSTRLEN)) if (!inet_ntop(AF_INET6, a->addr, addrstr, INET6_ADDRSTRLEN))
return "Unprintable-ipv6-address"; return "Unprintable-ipv6-address";
return tal_fmt(ctx, "[%s]:%u", addrstr, a->port); return tal_fmt(ctx, "[%s]:%u", addrstr, a->port);
case ADDR_TYPE_TOR_V2:
return tal_fmt(ctx, "%s.onion:%u",
b32_encode(addrstr, (u8 *) a->addr, 2), a->port);
case ADDR_TYPE_TOR_V3:
return tal_fmt(ctx, "%s.onion:%u",
b32_encode(addrstr, (u8 *) a->addr, 3), a->port);
case ADDR_TYPE_PADDING: case ADDR_TYPE_PADDING:
break; break;
} }
@ -170,6 +188,8 @@ bool wireaddr_is_wildcard(const struct wireaddr *addr)
case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV4:
return memeqzero(addr->addr, addr->addrlen); return memeqzero(addr->addr, addr->addrlen);
case ADDR_TYPE_PADDING: case ADDR_TYPE_PADDING:
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
return false; return false;
} }
abort(); abort();
@ -190,6 +210,36 @@ char *fmt_wireaddr_internal(const tal_t *ctx,
} }
REGISTER_TYPE_TO_STRING(wireaddr_internal, fmt_wireaddr_internal); REGISTER_TYPE_TO_STRING(wireaddr_internal, fmt_wireaddr_internal);
char *fmt_wireaddr_without_port(const tal_t * ctx, const struct wireaddr *a)
{
char addrstr[FQDN_ADDRLEN];
char *ret, *hex;
switch (a->type) {
case ADDR_TYPE_IPV4:
if (!inet_ntop(AF_INET, a->addr, addrstr, INET_ADDRSTRLEN))
return "Unprintable-ipv4-address";
return tal_fmt(ctx, "%s", addrstr);
case ADDR_TYPE_IPV6:
if (!inet_ntop(AF_INET6, a->addr, addrstr, INET6_ADDRSTRLEN))
return "Unprintable-ipv6-address";
return tal_fmt(ctx, "[%s]", addrstr);
case ADDR_TYPE_TOR_V2:
return tal_fmt(ctx, "%.16s.onion",
b32_encode(addrstr, (u8 *) a->addr, 2));
case ADDR_TYPE_TOR_V3:
return tal_fmt(ctx, "%.56s.onion",
b32_encode(addrstr, (u8 *) a->addr, 3));
case ADDR_TYPE_PADDING:
break;
}
hex = tal_hexstr(ctx, a->addr, a->addrlen);
ret = tal_fmt(ctx, "Unknown type %u %s", a->type, hex);
tal_free(hex);
return ret;
}
/* Valid forms: /* Valid forms:
* *
* [anything]:<number> * [anything]:<number>
@ -244,8 +294,28 @@ bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname,
struct addrinfo *addrinfo; struct addrinfo *addrinfo;
struct addrinfo hints; struct addrinfo hints;
int gai_err; int gai_err;
u8 tor_dec_bytes[TOR_V3_ADDRLEN];
bool res = false; bool res = false;
/* Don't do lookup on onion addresses. */
if (strends(hostname, ".onion")) {
if (strlen(hostname) < 25) { //FIXME bool is_V2_or_V3_TOR(addr);
addr->type = ADDR_TYPE_TOR_V2;
addr->addrlen = TOR_V2_ADDRLEN;
addr->port = port;
b32_decode((u8 *) tor_dec_bytes, (u8 *)hostname, 2);
memcpy(&addr->addr, tor_dec_bytes, addr->addrlen);
return true;
} else {
addr->type = ADDR_TYPE_TOR_V3;
addr->addrlen = TOR_V3_ADDRLEN;
addr->port = port;
b32_decode((u8 *) tor_dec_bytes, (u8 *)hostname, 3);
memcpy(&addr->addr, tor_dec_bytes, addr->addrlen);
return true;
}
}
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;

13
common/wireaddr.h

@ -3,6 +3,7 @@
#include "config.h" #include "config.h"
#include <ccan/short_types/short_types.h> #include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h> #include <ccan/tal/tal.h>
#include <lightningd/lightningd.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -30,18 +31,23 @@ struct sockaddr_un;
* where `checksum = sha3(".onion checksum" | pubkey || version)[:2]` * where `checksum = sha3(".onion checksum" | pubkey || version)[:2]`
*/ */
#define TOR_V2_ADDRLEN 12
#define TOR_V3_ADDRLEN 37
#define FQDN_ADDRLEN 255
enum wire_addr_type { enum wire_addr_type {
ADDR_TYPE_PADDING = 0, ADDR_TYPE_PADDING = 0,
ADDR_TYPE_IPV4 = 1, ADDR_TYPE_IPV4 = 1,
ADDR_TYPE_IPV6 = 2, ADDR_TYPE_IPV6 = 2,
ADDR_TYPE_TOR_V2 = 3,
ADDR_TYPE_TOR_V3 = 4
}; };
/* FIXME(cdecker) Extend this once we have defined how TOR addresses /* Structure now fit for tor support */
* should look like */
struct wireaddr { struct wireaddr {
enum wire_addr_type type; enum wire_addr_type type;
u8 addrlen; u8 addrlen;
u8 addr[16]; u8 addr[TOR_V3_ADDRLEN]; //or FQDN_ADDRLEN ?
u16 port; u16 port;
}; };
@ -64,6 +70,7 @@ void towire_addr_listen_announce(u8 **pptr, enum addr_listen_announce ala);
bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 port, const char **err_msg); bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 port, const char **err_msg);
char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a); char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a);
char *fmt_wireaddr_without_port(const tal_t *ctx, const struct wireaddr *a);
bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname, bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname,
const u16 port, const char **err_msg); const u16 port, const char **err_msg);

146
doc/TOR.md

@ -0,0 +1,146 @@
HOWTO USE TOR WITH C-LIGHTNING
what do we support
1 c-lightning has a public IP address and no TOR hidden service address,
but can connect to an onion address via a TOR socks 5 proxy.
2 c-lightning has a public IP address and a fixed TOR hidden service address that is persistent
so that external users can connect to this node.
3 c-lightning has a public IP address and not fixed TOR service address that (changes at each restart
and that vanish at restart of tor)
so that external users can connect to this node by TOR and IP
4 c-lightning has no public IP address, but has a fixed TOR hidden service address that is persistent
so that external users can connect to this node.
5 c-lightning has no public IP address, and has no fixed TOR hidden service address
(changes at each restart and vanish at restart of tor) to make it harder to track this node.
6 c-lightning has a public IP address and a fixed TOR V3 service address and a TOR V2 service address
that (changes at each restart and that vanish at restart of tor)
so that external users can connect to this node by TOR V2 and V3 and IP
7 c-lightning has nop public IP address and a fixed TOR V3 service address and fixed TOR V2 service address
a 3rd V2 address that (changes at each restart and that vanish at restart of tor)
so that external users can connect to this node by TOR V2 and V3 and a random V2 until next tor release then also (V3 randomly)
8 c-lightning has a public IP address and no TOR hidden service address,
but can connect to any V4/6 ip address via a IPV4/6 socks 5 proxy.
to use tor you have to have tor installed an running.
i.e.
sudo apt install tor
/etc/init.d/tor start
if new to tor you might not change the default setting
# The safe default with minimal harassment (See tor FAQ)
ExitPolicy reject *:* # no exits allowed
this does not effect c-ln connect listen etc.
it will only prevent that you become a full exitpoint
Only enable this if you are sure about the implications.
if you want an auto service created
edit the torconfig file /etc/tor/torrc
set
ControlPort 9051
CookieAuthentication 1
CookieAuthFileGroupReadable 1
or create a password with
cmdline
tor --hash-password yourepassword
this returns an line like
16:533E3963988E038560A8C4EE6BBEE8DB106B38F9C8A7F81FE38D2A3B1F
put this in the /etc/tor/torrc file
i.e.
HashedControlPassword 16:533E3963988E038560A8C4EE6BBEE8DB106B38F9C8A7F81FE38D2A3B1F
save
and
/etc/init.d/tor restart
then you can use c-lightning with following options
--tor-service-password=yourpassword to access the tor service at 9051
--proxy=127.0.0.1:9050 : set the Tor proxy to use
or the password for the service if cookiefile is not accessable
--tor-auto-listen true : try to generate an temp V2 onion addr
NOTE if --tor-proxy set all traffic will be rooted over the proxy
if --addr is not specified only the auto generated onion addr will be used for your node.
you can also set a fixed onion addr by option
--addr=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion (V2 or V3 is allowed)
this addr can be created by
HiddenServiceDir /var/lib/tor/bitcoin-service_v2/
HiddenServiceVersion 2
HiddenServicePort 8333 127.0.0.1:8333
HiddenServiceDir /var/lib/tor/other_hidden_service_v3/
HiddenServiceVersion 3
HiddenServicePort 9735 127.0.0.1:9735
in /etc/tor/torrc
the addr for
the --addr option
you find after /etc/init.d/tor restart
i.e.
in /var/lib/tor/other_hidden_service_v3/hostname
to see your onion addr use
cli/lightning-cli getinfo
some examples:
sudo lightningd/lightningd --network=testnet --addr=127.0.0.1 --port=1234
--proxy=127.0.0.1:9050 --tor-auto-listen true --tor-service=127.0.0.1:9051
this will try to generate an V2 auto hidden-service by reading the tor cookie and
also create local ipaddr at port 1234
so the node is accessableby connect peerid xxxxxxxxxxxxxxxx.onion 1234
or local by connect ID 127.0.0.1 1234
lightningd/lightningd --network=testnet --port=1234
--proxy=127.0.0.1:9050 --tor-service-password testpassword --tor-auto-listen true --tor-service=127.0.0.1:9051
this will try to generate an V2 auto temp hidden-service addr by using the password to access tor service api
so the node accessable by connect peerid xxxxxxxxxxxxxxxxxxx.onion 1234
lightningd/lightningd --network=testnet --port=1234
--proxy=127.0.0.1:9050 --addr=xxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion --port 1234
this will use the hidden-service set by /etc/tor/torrc and use the hidden service
so the node is accessable by connect peerid xxxxxxxxxxxxxxxxxxxxxxxx.onion 1234
or
lightningd/lightningd --network=testnet --port=1234
--proxy=127.0.0.1:9050 --addr=xxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion --port 1234
this will use the hidden-service set by /etc/tor/torrc and use the hidden service
so the node is only accessable by connect peerid xxxxxxxxxxxxxxxxxxxxxxxonion 1234
for connects you can use
i.e cli/lightning-cli connect peerID xxxxxxxxxxxxxxxxxxxxxxx.onion 1234

2
gossipd/Makefile

@ -37,6 +37,7 @@ LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_GOSSIP_HEADERS)
# Common source we use. # Common source we use.
GOSSIPD_COMMON_OBJS := \ GOSSIPD_COMMON_OBJS := \
common/base32.o \
common/bech32.o \ common/bech32.o \
common/bech32_util.o \ common/bech32_util.o \
common/bip32.o \ common/bip32.o \
@ -55,6 +56,7 @@ GOSSIPD_COMMON_OBJS := \
common/status_wire.o \ common/status_wire.o \
common/subdaemon.o \ common/subdaemon.o \
common/timeout.o \ common/timeout.o \
common/tor.o \
common/type_to_string.o \ common/type_to_string.o \
common/utils.o \ common/utils.o \
common/utxo.o \ common/utxo.o \

238
gossipd/gossip.c

@ -24,6 +24,7 @@
#include <common/status.h> #include <common/status.h>
#include <common/subdaemon.h> #include <common/subdaemon.h>
#include <common/timeout.h> #include <common/timeout.h>
#include <common/tor.h>
#include <common/type_to_string.h> #include <common/type_to_string.h>
#include <common/utils.h> #include <common/utils.h>
#include <common/version.h> #include <common/version.h>
@ -53,6 +54,176 @@
#include <wire/wire_io.h> #include <wire/wire_io.h>
#include <wire/wire_sync.h> #include <wire/wire_sync.h>
#define GOSSIP_MAX_REACH_ATTEMPTS 10
#define SOCKS_NOAUTH 0
#define SOCKS_ERROR 0xff
#define SOCKS_CONNECT 1
#define SOCKS_TYP_IPV4 1
#define SOCKS_DOMAIN 3
#define SOCKS_TYP_IPV6 4
#define SOCKS_V5 5
#define MAX_SIZE_OF_SOCKS5_REQ_OR_RESP 255
#define SIZE_OF_RESPONSE 4
#define SIZE_OF_REQUEST 3
#define SIZE_OF_IPV4_RESPONSE 6
#define SIZE_OF_IPV6_RESPONSE 18
#define SOCK_REQ_METH_LEN 3
#define SOCK_REQ_V5_LEN 5
#define SOCK_REQ_V5_HEADER_LEN 7
/* some crufts can not forward ipv6*/
#undef BIND_FIRST_TO_IPV6
struct reaching_socks {
u8 buffer[MAX_SIZE_OF_SOCKS5_REQ_OR_RESP];
size_t hlen;
in_port_t port;
char *host;
struct reaching *reach;
};
static struct io_plan *connect_finish(struct io_conn *,
struct reaching_socks *);
static struct io_plan *connect_finish2(struct io_conn *,
struct reaching_socks *);
static struct io_plan *connect_out(struct io_conn *, struct reaching_socks *);
static struct io_plan *io_tor_connect_after_req_to_connect(struct io_conn *,
struct reaching_socks
*);
static struct io_plan *io_tor_connect_after_req_host(struct io_conn *,
struct reaching_socks *);
static struct io_plan *io_tor_connect_do_req(struct io_conn *,
struct reaching_socks *);
static struct io_plan *connect_out(struct io_conn *, struct reaching_socks *);
static struct io_plan *io_tor_connect_do_req(struct io_conn *,
struct reaching_socks *);
static struct io_plan *io_tor_connect_after_resp_to_connect(struct io_conn
*conn,
struct
reaching_socks *);
static struct io_plan *io_tor_connect(struct io_conn *, struct reaching *);
static struct io_plan *io_tor_connect_after_resp_to_connect(struct io_conn
*conn,
struct
reaching_socks
*reach)
{
if (reach->buffer[1] == SOCKS_ERROR) {
status_trace("Connected out for %s error", reach->host);
return io_close(conn);
}
/* make the V5 request */
reach->hlen = strlen(reach->host);
reach->buffer[0] = SOCKS_V5;
reach->buffer[1] = SOCKS_CONNECT;
reach->buffer[2] = 0;
reach->buffer[3] = SOCKS_DOMAIN;
reach->buffer[4] = reach->hlen;
memcpy(reach->buffer + SOCK_REQ_V5_LEN, reach->host, reach->hlen);
memcpy(reach->buffer + SOCK_REQ_V5_LEN + strlen(reach->host),
&(reach->port), sizeof reach->port);
return io_write(conn, reach->buffer,
SOCK_REQ_V5_HEADER_LEN + reach->hlen,
io_tor_connect_after_req_host, reach);
}
static struct io_plan *io_tor_connect_after_req_to_connect(struct io_conn *conn,
struct reaching_socks
*reach)
{
return io_read(conn, reach->buffer, 2,
&io_tor_connect_after_resp_to_connect, reach);
}
static struct io_plan *io_tor_connect_do_req(struct io_conn *conn,
struct reaching_socks *reach)
{
/* make the init request */
reach->buffer[0] = SOCKS_V5;
reach->buffer[1] = 1;
reach->buffer[2] = SOCKS_NOAUTH;
return io_write(conn, reach->buffer, SOCK_REQ_METH_LEN,
&io_tor_connect_after_req_to_connect, reach);
}
static struct io_plan *connection_out(struct io_conn *conn,
struct reaching *reach);
static struct io_plan *connect_finish2(struct io_conn *conn,
struct reaching_socks *reach)
{
status_trace("Now try LN connect out for host %s", reach->host);
return connection_out(conn, reach->reach);
}
static struct io_plan *connect_finish(struct io_conn *conn,
struct reaching_socks *reach)
{
if ( reach->buffer[1] == '\0') {
if ( reach->buffer[3] == SOCKS_TYP_IPV6) {
return io_read(conn,
(reach->buffer + SIZE_OF_RESPONSE -
SIZE_OF_IPV4_RESPONSE),
SIZE_OF_IPV6_RESPONSE -
SIZE_OF_RESPONSE - SIZE_OF_IPV4_RESPONSE,
&connect_finish2, reach);
} else if ( reach->buffer[3] == SOCKS_TYP_IPV4) {
status_trace("Now try LN connect out for host %s",
reach->host);
return connection_out(conn, reach->reach);
} else {
status_trace
("Tor connect out for host %s error invalid type return ",
reach->host);
return io_close(conn);
}
} else {
status_trace("Tor connect out for host %s error: %x ",
reach->host, reach->buffer[1]);
return io_close(conn);
}
}
static struct io_plan *connect_out(struct io_conn *conn,
struct reaching_socks *reach)
{
return io_read(conn, reach->buffer,
SIZE_OF_IPV4_RESPONSE + SIZE_OF_RESPONSE,
&connect_finish, reach);
}
/* called when TOR responds */
static struct io_plan *io_tor_connect_after_req_host(struct io_conn *conn,
struct reaching_socks
*reach)
{
if (reach->buffer[0] == '0') {
status_trace("Connected out over tor for %s failed",
reach->host);
return io_close(conn);
}
return connect_out(conn, reach);
}
#define HSM_FD 3 #define HSM_FD 3
#define INITIAL_WAIT_SECONDS 1 #define INITIAL_WAIT_SECONDS 1
@ -142,6 +313,9 @@ struct daemon {
/* Automatically reconnect. */ /* Automatically reconnect. */
bool reconnect; bool reconnect;
struct wireaddr *tor_proxyaddrs;
bool use_tor_proxy_always;
}; };
/* Peers we're trying to reach. */ /* Peers we're trying to reach. */
@ -230,6 +404,49 @@ static bool send_peer_with_fds(struct peer *peer, const u8 *msg);
static void wake_pkt_out(struct peer *peer); static void wake_pkt_out(struct peer *peer);
static void retry_important(struct important_peerid *imp); static void retry_important(struct important_peerid *imp);
// called when we want to connect to TOR SOCKS5
static struct io_plan *io_tor_connect(struct io_conn *conn,
struct reaching *reach)
{
struct addrinfo *ai_tor = tal(reach, struct addrinfo);
char *port_addr = tal(reach, char);
struct io_plan *plan;
struct reaching_socks *reach_tor = tal(reach, struct reaching_socks);
assert(reach->addr.itype == ADDR_INTERNAL_WIREADDR);
reach_tor->port = htons(reach->addr.u.wireaddr.port);
port_addr = tal_fmt(reach, "%u", reach->daemon->tor_proxyaddrs->port);
getaddrinfo((char *)
fmt_wireaddr_without_port(tmpctx,
reach->daemon->tor_proxyaddrs),
port_addr, NULL, &ai_tor);
status_trace("Tor proxyaddr : %s",
fmt_wireaddr(reach, reach->daemon->tor_proxyaddrs));
reach_tor->host = tal_strdup(reach, "");
if ((reach->addr.u.wireaddr.type) == ADDR_TYPE_TOR_V3)
reach_tor->host =
tal_fmt(reach, "%.62s",
fmt_wireaddr_without_port(tmpctx, &reach->addr.u.wireaddr));
else if ((reach->addr.u.wireaddr.type) == ADDR_TYPE_TOR_V2)
reach_tor->host =
tal_fmt(reach, "%.22s",
fmt_wireaddr_without_port(tmpctx, &reach->addr.u.wireaddr));
else if ((reach->addr.u.wireaddr.type) == ADDR_TYPE_IPV4)
reach_tor->host =
tal_fmt(reach, "%s",
fmt_wireaddr_without_port(tmpctx, &reach->addr.u.wireaddr));
else if ((reach->addr.u.wireaddr.type) == ADDR_TYPE_IPV6)
reach_tor->host =
tal_fmt(reach, "%s",
fmt_wireaddr_without_port(tmpctx, &reach->addr.u.wireaddr));
reach_tor->reach = reach;
plan = io_connect(conn, ai_tor, &io_tor_connect_do_req, reach_tor);
return plan;
}
static void destroy_peer(struct peer *peer) static void destroy_peer(struct peer *peer)
{ {
struct important_peerid *imp; struct important_peerid *imp;
@ -1605,6 +1822,8 @@ static bool handle_wireaddr_listen(struct daemon *daemon,
} }
return false; return false;
case ADDR_TYPE_PADDING: case ADDR_TYPE_PADDING:
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
break; break;
} }
status_failed(STATUS_FAIL_INTERNAL_ERROR, status_failed(STATUS_FAIL_INTERNAL_ERROR,
@ -1730,6 +1949,7 @@ static struct io_plan *gossip_init(struct daemon_conn *master,
struct bitcoin_blkid chain_hash; struct bitcoin_blkid chain_hash;
u32 update_channel_interval; u32 update_channel_interval;
bool dev_allow_localhost; bool dev_allow_localhost;
daemon->tor_proxyaddrs = tal_arrz(daemon, struct wireaddr, 1);
if (!fromwire_gossipctl_init( if (!fromwire_gossipctl_init(
daemon, msg, &daemon->broadcast_interval, &chain_hash, daemon, msg, &daemon->broadcast_interval, &chain_hash,
@ -1737,6 +1957,7 @@ static struct io_plan *gossip_init(struct daemon_conn *master,
&daemon->localfeatures, &daemon->proposed_wireaddr, &daemon->localfeatures, &daemon->proposed_wireaddr,
&daemon->proposed_listen_announce, daemon->rgb, &daemon->proposed_listen_announce, daemon->rgb,
daemon->alias, &update_channel_interval, &daemon->reconnect, daemon->alias, &update_channel_interval, &daemon->reconnect,
daemon->tor_proxyaddrs, &daemon->use_tor_proxy_always,
&dev_allow_localhost)) { &dev_allow_localhost)) {
master_badmsg(WIRE_GOSSIPCTL_INIT, msg); master_badmsg(WIRE_GOSSIPCTL_INIT, msg);
} }
@ -1876,6 +2097,7 @@ static struct io_plan *conn_init(struct io_conn *conn, struct reaching *reach)
struct sockaddr_in sin; struct sockaddr_in sin;
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
struct sockaddr_un sun; struct sockaddr_un sun;
bool use_tor = false;
/* FIXME: make generic */ /* FIXME: make generic */
ai.ai_flags = 0; ai.ai_flags = 0;
@ -1909,12 +2131,26 @@ static struct io_plan *conn_init(struct io_conn *conn, struct reaching *reach)
ai.ai_addrlen = sizeof(sin6); ai.ai_addrlen = sizeof(sin6);
ai.ai_addr = (struct sockaddr *)&sin6; ai.ai_addr = (struct sockaddr *)&sin6;
break; break;
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
use_tor = true;
break;
case ADDR_TYPE_PADDING: case ADDR_TYPE_PADDING:
/* Shouldn't happen. */ /* Shouldn't happen. */
return io_close(conn); return io_close(conn);
} }
if (!use_tor && reach->daemon->tor_proxyaddrs->port > 0) {
/* We dont use tor proxy if we only have ip */
if (reach->daemon->use_tor_proxy_always
|| do_we_use_tor_addr(reach->daemon->announcable))
use_tor = true;
}
} }
io_set_finish(conn, connect_failed, reach); io_set_finish(conn, connect_failed, reach);
if (use_tor)
return io_tor_connect(conn, reach);
return io_connect(conn, &ai, connection_out, reach); return io_connect(conn, &ai, connection_out, reach);
} }
@ -2046,6 +2282,8 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id,
"Can't reach ALLPROTO"); "Can't reach ALLPROTO");
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
switch (a->addr.u.wireaddr.type) { switch (a->addr.u.wireaddr.type) {
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV4:
af = AF_INET; af = AF_INET;
break; break;

2
gossipd/gossip_wire.csv

@ -18,6 +18,8 @@ gossipctl_init,,rgb,3*u8
gossipctl_init,,alias,32*u8 gossipctl_init,,alias,32*u8
gossipctl_init,,update_channel_interval,u32 gossipctl_init,,update_channel_interval,u32
gossipctl_init,,reconnect,bool gossipctl_init,,reconnect,bool
gossipctl_init,,tor_proxyaddrs,struct wireaddr
gossipctl_init,,use_tor_proxy_always,bool
gossipctl_init,,dev_allow_localhost,bool gossipctl_init,,dev_allow_localhost,bool
# Activate the gossip daemon, so others can connect. # Activate the gossip daemon, so others can connect.

Can't render this file because it has a wrong number of fields in line 6.

3
gossipd/netaddress.c

@ -259,7 +259,10 @@ bool guess_address(struct wireaddr *addr)
memcpy(addr->addr, &sin6.sin6_addr, addr->addrlen); memcpy(addr->addr, &sin6.sin6_addr, addr->addrlen);
return ret; return ret;
} }
case ADDR_TYPE_TOR_V2:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_PADDING: case ADDR_TYPE_PADDING:
status_broken("Cannot guess address type %u", addr->type);
break; break;
} }
abort(); abort();

2
lightningd/Makefile

@ -14,6 +14,7 @@ default: lightningd-all
# Common source we use. # Common source we use.
LIGHTNINGD_COMMON_OBJS := \ LIGHTNINGD_COMMON_OBJS := \
common/base32.o \
common/bech32.o \ common/bech32.o \
common/bech32_util.o \ common/bech32_util.o \
common/bip32.o \ common/bip32.o \
@ -43,6 +44,7 @@ LIGHTNINGD_COMMON_OBJS := \
common/type_to_string.o \ common/type_to_string.o \
common/utils.o \ common/utils.o \
common/utxo.o \ common/utxo.o \
common/tor.o \
common/version.o \ common/version.o \
common/wallet_tx.o \ common/wallet_tx.o \
common/wire_error.o \ common/wire_error.o \

6
lightningd/gossip_control.c

@ -209,8 +209,9 @@ void gossip_init(struct lightningd *ld)
if (!ld->gossip) if (!ld->gossip)
err(1, "Could not subdaemon gossip"); err(1, "Could not subdaemon gossip");
/* If no addr specified, hand wildcard to gossipd */ /* If no addr (not even Tor auto) specified, hand wildcard to gossipd */
if (tal_count(wireaddrs) == 0 && ld->autolisten) { if (tal_count(wireaddrs) == 0 && ld->autolisten
&& !ld->config.tor_enable_auto_hidden_service) {
wireaddrs = tal_arrz(tmpctx, struct wireaddr_internal, 1); wireaddrs = tal_arrz(tmpctx, struct wireaddr_internal, 1);
listen_announce = tal_arr(tmpctx, enum addr_listen_announce, 1); listen_announce = tal_arr(tmpctx, enum addr_listen_announce, 1);
wireaddrs->itype = ADDR_INTERNAL_ALLPROTO; wireaddrs->itype = ADDR_INTERNAL_ALLPROTO;
@ -225,6 +226,7 @@ void gossip_init(struct lightningd *ld)
get_offered_local_features(tmpctx), wireaddrs, get_offered_local_features(tmpctx), wireaddrs,
listen_announce, ld->rgb, listen_announce, ld->rgb,
ld->alias, ld->config.channel_update_interval, ld->reconnect, ld->alias, ld->config.channel_update_interval, ld->reconnect,
ld->tor_proxyaddrs, ld->use_tor_proxy_always,
allow_localhost); allow_localhost);
subd_send_msg(ld->gossip, msg); subd_send_msg(ld->gossip, msg);
} }

8
lightningd/json.c

@ -139,6 +139,14 @@ void json_add_address(struct json_result *response, const char *fieldname,
json_add_string(response, "type", "ipv6"); json_add_string(response, "type", "ipv6");
json_add_string(response, "address", addrstr); json_add_string(response, "address", addrstr);
json_add_num(response, "port", addr->port); json_add_num(response, "port", addr->port);
} else if (addr->type == ADDR_TYPE_TOR_V2) {
json_add_string(response, "type", "torv2");
json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr));
json_add_num(response, "port", addr->port);
} else if (addr->type == ADDR_TYPE_TOR_V3) {
json_add_string(response, "type", "torv3");
json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr));
json_add_num(response, "port", addr->port);
} }
json_object_end(response); json_object_end(response);
} }

13
lightningd/lightningd.c

@ -21,6 +21,7 @@
#include <common/daemon.h> #include <common/daemon.h>
#include <common/memleak.h> #include <common/memleak.h>
#include <common/timeout.h> #include <common/timeout.h>
#include <common/tor.h>
#include <common/utils.h> #include <common/utils.h>
#include <common/version.h> #include <common/version.h>
#include <errno.h> #include <errno.h>
@ -83,7 +84,10 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
ld->pidfile = NULL; ld->pidfile = NULL;
ld->ini_autocleaninvoice_cycle = 0; ld->ini_autocleaninvoice_cycle = 0;
ld->ini_autocleaninvoice_expiredby = 86400; ld->ini_autocleaninvoice_expiredby = 86400;
ld->tor_service_password = tal_arrz(ld, char, 32);
ld->tor_proxyaddrs = tal_arrz(ld, struct wireaddr,1);
ld->tor_serviceaddrs = tal_arrz(ld, struct wireaddr,1);
ld->use_tor_proxy_always = false;
return ld; return ld;
} }
@ -312,6 +316,13 @@ int main(int argc, char *argv[])
/* Ignore SIGPIPE: we look at our write return values*/ /* Ignore SIGPIPE: we look at our write return values*/
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
/* tor support */
if (ld->config.tor_enable_auto_hidden_service) {
create_tor_hidden_service_conn(ld);
while (!check_return_from_service_call())
io_loop(NULL, NULL);
}
/* Make sure we can reach other daemons, and versions match. */ /* Make sure we can reach other daemons, and versions match. */
test_daemons(ld); test_daemons(ld);

12
lightningd/lightningd.h

@ -76,6 +76,12 @@ struct config {
/* Number of blocks to rescan from the current head, or absolute /* Number of blocks to rescan from the current head, or absolute
* blockheight if rescan >= 500'000 */ * blockheight if rescan >= 500'000 */
s32 rescan; s32 rescan;
/* tor support */
bool tor_enable_auto_hidden_service;
/* ipv6 bind disable */
bool no_ipv6_bind;
}; };
struct lightningd { struct lightningd {
@ -195,6 +201,12 @@ struct lightningd {
/* Things we've marked as not leaking. */ /* Things we've marked as not leaking. */
const void **notleaks; const void **notleaks;
#endif /* DEVELOPER */ #endif /* DEVELOPER */
/* tor support */
struct wireaddr *tor_proxyaddrs;
struct wireaddr *tor_serviceaddrs;
char *tor_service_password;
bool use_tor_proxy_always;
}; };
const struct chainparams *get_chainparams(const struct lightningd *ld); const struct chainparams *get_chainparams(const struct lightningd *ld);

49
lightningd/options.c

@ -12,6 +12,7 @@
#include <common/configdir.h> #include <common/configdir.h>
#include <common/json_escaped.h> #include <common/json_escaped.h>
#include <common/memleak.h> #include <common/memleak.h>
#include <common/tor.h>
#include <common/version.h> #include <common/version.h>
#include <common/wireaddr.h> #include <common/wireaddr.h>
#include <errno.h> #include <errno.h>
@ -295,6 +296,30 @@ static char *opt_set_offline(struct lightningd *ld)
return NULL; return NULL;
} }
static char *opt_add_torproxy_addr(const char *arg, struct lightningd *ld)
{
if (!parse_wireaddr(arg, ld->tor_proxyaddrs,9050,NULL)) {
return tal_fmt(NULL, "Unable to parse Tor proxy address '%s'", arg);
}
return NULL;
}
static char *opt_add_tor_service_addr(const char *arg, struct lightningd *ld)
{
if (!parse_wireaddr(arg, ld->tor_serviceaddrs,9051,NULL)) {
return tal_fmt(NULL, "Unable to parse Tor service address '%s'", arg);
}
return NULL;
}
static char *opt_add_tor_service_password(const char *arg, struct lightningd *ld)
{
ld->tor_service_password = tal_fmt(ld, "%.30s", arg);
return NULL;
}
static void config_register_opts(struct lightningd *ld) static void config_register_opts(struct lightningd *ld)
{ {
opt_register_noarg("--daemon", opt_set_bool, &ld->daemon, opt_register_noarg("--daemon", opt_set_bool, &ld->daemon,
@ -367,7 +392,7 @@ static void config_register_opts(struct lightningd *ld)
"Set an IP address (v4 or v6) to listen on, but not announce"); "Set an IP address (v4 or v6) to listen on, but not announce");
opt_register_arg("--announce-addr", opt_add_announce_addr, NULL, opt_register_arg("--announce-addr", opt_add_announce_addr, NULL,
ld, ld,
"Set an IP address (v4 or v6) to announce, but not listen on"); "Set an IP address (v4 or v6) or .onion v2/v3 to announce, but not listen on");
opt_register_noarg("--offline", opt_set_offline, ld, opt_register_noarg("--offline", opt_set_offline, ld,
"Start in offline-mode (do not automatically reconnect and do not accept incoming connections)"); "Start in offline-mode (do not automatically reconnect and do not accept incoming connections)");
@ -398,6 +423,16 @@ static void config_register_opts(struct lightningd *ld)
opt_set_u64, opt_show_u64, opt_set_u64, opt_show_u64,
&ld->ini_autocleaninvoice_cycle, &ld->ini_autocleaninvoice_cycle,
"If expired invoice autoclean enabled, invoices that have expired for at least this given seconds are cleaned"); "If expired invoice autoclean enabled, invoices that have expired for at least this given seconds are cleaned");
opt_register_arg("--proxy", opt_add_torproxy_addr, NULL,
ld,"Set a socks v5 proxy IP address and port");
opt_register_arg("--tor-service",opt_add_tor_service_addr, NULL,
ld,"Set a tor service api IP address and port");
opt_register_arg("--tor-service-password", opt_add_tor_service_password, NULL,
ld,"Set a Tor hidden service password");
opt_register_arg("--tor-auto-listen", opt_set_bool_arg, opt_show_bool,
&ld->config.tor_enable_auto_hidden_service , "Generate and use a temp auto hidden-service and show the onion address");
opt_register_arg("--always-use-tor-proxy", opt_set_bool_arg, opt_show_bool,
&ld->use_tor_proxy_always , "Use the Tor proxy always");
} }
#if DEVELOPER #if DEVELOPER
@ -474,6 +509,9 @@ static const struct config testnet_config = {
/* Rescan 5 hours of blocks on testnet, it's reorg happy */ /* Rescan 5 hours of blocks on testnet, it's reorg happy */
.rescan = 30, .rescan = 30,
/* tor support */
.tor_enable_auto_hidden_service = false
}; };
/* aka. "Dude, where's my coins?" */ /* aka. "Dude, where's my coins?" */
@ -538,6 +576,9 @@ static const struct config mainnet_config = {
/* Rescan 2.5 hours of blocks on startup, it's not so reorg happy */ /* Rescan 2.5 hours of blocks on startup, it's not so reorg happy */
.rescan = 15, .rescan = 15,
.tor_enable_auto_hidden_service = false
}; };
static void check_config(struct lightningd *ld) static void check_config(struct lightningd *ld)
@ -937,6 +978,12 @@ static void add_config(struct lightningd *ld,
ld->proposed_listen_announce, ld->proposed_listen_announce,
ADDR_ANNOUNCE); ADDR_ANNOUNCE);
return; return;
} else if (opt->cb_arg == (void *)opt_add_torproxy_addr) {
answer = fmt_wireaddr(name0, ld->tor_proxyaddrs);
} else if (opt->cb_arg == (void *)opt_add_tor_service_addr) {
answer = fmt_wireaddr(name0, ld->tor_serviceaddrs);
} else if (opt->cb_arg == (void *)opt_add_tor_service_password) {
answer = tal_fmt(name0, "%s", ld->tor_service_password);
#if DEVELOPER #if DEVELOPER
} else if (strstarts(name, "dev-")) { } else if (strstarts(name, "dev-")) {
/* Ignore dev settings */ /* Ignore dev settings */

4
lightningd/test/run-find_my_path.c

@ -1,6 +1,8 @@
#define main unused_main #define main unused_main
int unused_main(int argc, char *argv[]); int unused_main(int argc, char *argv[]);
#include "../../common/base32.c"
#include "../../common/wireaddr.c"
#include "../../common/tor.c"
#include "../lightningd.c" #include "../lightningd.c"
/* AUTOGENERATED MOCKS START */ /* AUTOGENERATED MOCKS START */

1
openingd/Makefile

@ -35,6 +35,7 @@ LIGHTNINGD_HEADERS_NOGEN += $(LIGHTNINGD_OPENING_HEADERS_NOGEN)
# Common source we use. # Common source we use.
OPENINGD_COMMON_OBJS := \ OPENINGD_COMMON_OBJS := \
common/base32.o \
common/bip32.o \ common/bip32.o \
common/channel_config.o \ common/channel_config.o \
common/crypto_state.o \ common/crypto_state.o \

1
wallet/test/Makefile

@ -3,6 +3,7 @@ WALLET_TEST_OBJS := $(WALLET_TEST_SRC:.c=.o)
WALLET_TEST_PROGRAMS := $(WALLET_TEST_OBJS:.o=) WALLET_TEST_PROGRAMS := $(WALLET_TEST_OBJS:.o=)
WALLET_TEST_COMMON_OBJS := \ WALLET_TEST_COMMON_OBJS := \
common/base32.o \
common/htlc_state.o \ common/htlc_state.o \
common/type_to_string.o \ common/type_to_string.o \
common/memleak.o \ common/memleak.o \

Loading…
Cancel
Save