Init commit to be able to create a tor static service on the fly.

We  want to have a static Tor service created from a blob bound to
our node on cmdline

Changelog-added: persistent Tor address support
Changelog-added: allow the Tor inbound service port differ from 9735

Signed-off-by: Saibato <saibato.naga@pm.me>

Add base64 encode/decode to common

We need this to encode the blob for the tor service

Signed-off-by: Saibato <saibato.naga@pm.me>
This commit is contained in:
Saibato
2019-11-15 09:44:22 +01:00
committed by Christian Decker
parent 99ff86f6fe
commit f6006f43a9
14 changed files with 385 additions and 44 deletions

View File

@@ -39,6 +39,7 @@ LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_CONNECT_HEADERS)
CONNECTD_COMMON_OBJS := \
common/amount.o \
common/base32.o \
common/base64.o \
common/bech32.o \
common/bech32_util.o \
common/bigsize.o \

View File

@@ -56,6 +56,7 @@
#include <netdb.h>
#include <netinet/in.h>
#include <secp256k1_ecdh.h>
#include <sodium.h>
#include <sodium/randombytes.h>
#include <stdarg.h>
#include <sys/socket.h>
@@ -149,7 +150,7 @@ struct daemon {
/* File descriptors to listen on once we're activated. */
struct listen_fd *listen_fds;
/* Allow to define the default behavior of tot services calls*/
/* Allow to define the default behavior of tor services calls*/
bool use_v3_autotor;
};
@@ -652,6 +653,10 @@ static struct io_plan *conn_init(struct io_conn *conn,
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to autotor address");
break;
case ADDR_INTERNAL_STATICTOR:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to statictor address");
break;
case ADDR_INTERNAL_FORPROXY:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to forproxy address");
@@ -688,6 +693,7 @@ static struct io_plan *conn_proxy_init(struct io_conn *conn,
case ADDR_INTERNAL_SOCKNAME:
case ADDR_INTERNAL_ALLPROTO:
case ADDR_INTERNAL_AUTOTOR:
case ADDR_INTERNAL_STATICTOR:
break;
}
@@ -731,6 +737,9 @@ static void try_connect_one_addr(struct connecting *connect)
case ADDR_INTERNAL_AUTOTOR:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect AUTOTOR");
case ADDR_INTERNAL_STATICTOR:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect STATICTOR");
case ADDR_INTERNAL_FORPROXY:
use_proxy = true;
break;
@@ -993,6 +1002,10 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
struct sockaddr_un addrun;
int fd;
struct wireaddr_internal *binding;
const u8 *blob = NULL;
struct secret random;
struct pubkey pb;
struct wireaddr *toraddr;
/* Start with empty arrays, for tal_arr_expand() */
binding = tal_arr(ctx, struct wireaddr_internal, 0);
@@ -1018,7 +1031,6 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
for (size_t i = 0; i < tal_count(proposed_wireaddr); i++) {
struct wireaddr_internal wa = proposed_wireaddr[i];
bool announce = (proposed_listen_announce[i] & ADDR_ANNOUNCE);
if (!(proposed_listen_announce[i] & ADDR_LISTEN))
continue;
@@ -1042,6 +1054,9 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
case ADDR_INTERNAL_AUTOTOR:
/* We handle these after we have all bindings. */
continue;
case ADDR_INTERNAL_STATICTOR:
/* We handle these after we have all bindings. */
continue;
/* Special case meaning IPv6 and IPv4 */
case ADDR_INTERNAL_ALLPROTO: {
bool ipv6_ok;
@@ -1102,25 +1117,63 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
for (size_t i = 0; i < tal_count(proposed_wireaddr); i++) {
if (!(proposed_listen_announce[i] & ADDR_LISTEN))
continue;
if (proposed_wireaddr[i].itype != ADDR_INTERNAL_AUTOTOR)
continue;
toraddr = tor_autoservice(tmpctx,
&proposed_wireaddr[i],
tor_password,
binding,
daemon->use_v3_autotor);
if (!(proposed_listen_announce[i] & ADDR_ANNOUNCE)) {
tor_autoservice(tmpctx,
&proposed_wireaddr[i].u.torservice,
tor_password,
binding,
daemon->use_v3_autotor);
continue;
};
add_announcable(announcable,
tor_autoservice(tmpctx,
&proposed_wireaddr[i].u.torservice,
tor_password,
binding,
daemon->use_v3_autotor));
add_announcable(announcable, toraddr);
}
/* Now we have bindings, set up any Tor static addresses: we will point
* it at the first bound IPv4 or IPv6 address we have. */
for (size_t i = 0; i < tal_count(proposed_wireaddr); i++) {
if (!(proposed_listen_announce[i] & ADDR_LISTEN))
continue;
if (proposed_wireaddr[i].itype != ADDR_INTERNAL_STATICTOR)
continue;
blob = proposed_wireaddr[i].u.torservice.blob;
if (tal_strreg(tmpctx, (char *)proposed_wireaddr[i].u.torservice.blob, STATIC_TOR_MAGIC_STRING)) {
if (pubkey_from_node_id(&pb, &daemon->id)) {
if (sodium_mlock(&random, sizeof(random)) != 0)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could not lock the random prf key memory.");
randombytes_buf((void * const)&random, 32);
/* generate static tor node address, take first 32 bytes from secret of node_id plus 32 random bytes from sodiom */
struct sha256 sha;
/* let's sha, that will clear ctx of hsm data */
sha256(&sha, hsm_do_ecdh(tmpctx, &pb), 32);
/* even if it's a secret pub derived, tor shall see only the single sha */
memcpy((void *)&blob[0], &sha, 32);
memcpy((void *)&blob[32], &random, 32);
/* clear our temp buffer, don't leak by extern libs core-dumps, our blob we/tal handle later */
sodium_munlock(&random, sizeof(random));
} else status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could not get the pub of our node id from hsm");
}
toraddr = tor_fixed_service(tmpctx,
&proposed_wireaddr[i],
tor_password,
blob,
find_local_address(binding),
0);
/* get rid of blob data on our side of tor and add jitter */
randombytes_buf((void * const)proposed_wireaddr[i].u.torservice.blob, TOR_V3_BLOBLEN);
if (!(proposed_listen_announce[i] & ADDR_ANNOUNCE)) {
continue;
};
add_announcable(announcable, toraddr);
}
/* Sort and uniquify. */
finalize_announcable(announcable);

View File

@@ -7,6 +7,7 @@
#include <ccan/str/hex/hex.h>
#include <ccan/tal/grab_file/grab_file.h>
#include <ccan/tal/str/str.h>
#include <common/base64.h>
#include <common/type_to_string.h>
#include <common/utils.h>
#include <common/wireaddr.h>
@@ -21,10 +22,6 @@
#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 void *buf_resize(struct membuf *mb, void *buf, size_t len)
{
@@ -45,6 +42,30 @@ static void tor_send_cmd(struct rbuf *rbuf, const char *cmd)
"Writing CRLF to Tor socket");
}
static char *tor_response_line_wfail(struct rbuf *rbuf)
{
char *line = NULL;
while ((line = rbuf_read_str(rbuf, '\n')) != NULL) {
status_io(LOG_IO_IN, NULL, "torcontrol", line, strlen(line));
/* Weird response */
if (!strstarts(line, "250") && !strstarts(line, "550"))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Tor returned '%s'", line);
/* Last line */
if (strstarts(line, "250 ") || strstarts(line, "550 "))
break;
return line + 4;
}
if (line)
return line + 4;
else
return NULL;
}
static char *tor_response_line(struct rbuf *rbuf)
{
char *line;
@@ -74,13 +95,14 @@ static void discard_remaining_response(struct rbuf *rbuf)
static struct wireaddr *make_onion(const tal_t *ctx,
struct rbuf *rbuf,
const struct wireaddr *local,
bool use_v3_autotor)
bool use_v3_autotor,
u16 port)
{
char *line;
struct wireaddr *onion;
/* Now that V3 is out of Beta default to V3 autoservice onions if version is above 0.4
*/
/* Now that V3 is out of Beta default to V3 autoservice onions if version is above 0.4
*/
tor_send_cmd(rbuf, "PROTOCOLINFO 1");
while ((line = tor_response_line(rbuf)) != NULL) {
@@ -101,13 +123,11 @@ static struct wireaddr *make_onion(const tal_t *ctx,
if (!use_v3_autotor) {
tor_send_cmd(rbuf,
tal_fmt(tmpctx, "ADD_ONION NEW:RSA1024 Port=%d,%s Flags=DiscardPK,Detach",
/* FIXME: We *could* allow user to set Tor port */
DEFAULT_PORT, fmt_wireaddr(tmpctx, local)));
port, fmt_wireaddr(tmpctx, local)));
} else {
tor_send_cmd(rbuf,
tal_fmt(tmpctx, "ADD_ONION NEW:ED25519-V3 Port=%d,%s Flags=DiscardPK,Detach",
/* FIXME: We *could* allow user to set Tor port */
DEFAULT_PORT, fmt_wireaddr(tmpctx, local)));
port, fmt_wireaddr(tmpctx, local)));
}
while ((line = tor_response_line(rbuf)) != NULL) {
@@ -122,10 +142,10 @@ static struct wireaddr *make_onion(const tal_t *ctx,
name = tal_fmt(tmpctx, "%s.onion", line);
onion = tal(ctx, struct wireaddr);
if (!parse_wireaddr(name, onion, DEFAULT_PORT, false, NULL))
if (!parse_wireaddr(name, onion, local->port, false, NULL))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Tor gave bad onion name '%s'", name);
status_info("New autotor service onion address: \"%s:%d\"", name, DEFAULT_PORT);
status_info("New autotor service onion address: \"%s:%d\" bound from extern port:%d", name, local->port, port);
discard_remaining_response(rbuf);
return onion;
}
@@ -133,6 +153,51 @@ static struct wireaddr *make_onion(const tal_t *ctx,
"Tor didn't give us a ServiceID");
}
static struct wireaddr *make_fixed_onion(const tal_t *ctx,
struct rbuf *rbuf,
const struct wireaddr *local, const u8 *blob, u16 port)
{
char *line;
struct wireaddr *onion;
char *blob64;
blob64 = b64_encode(tmpctx, blob, 64);
tor_send_cmd(rbuf,
tal_fmt(tmpctx, "ADD_ONION ED25519-V3:%s Port=%d,%s Flags=DiscardPK",
blob64, port, fmt_wireaddr(tmpctx, local)));
while ((line = tor_response_line_wfail(rbuf))) {
const char *name;
if (strstarts(line, "Onion address collision"))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Tor address in use");
if (!strstarts(line, "ServiceID="))
continue;
line += strlen("ServiceID=");
/* Strip the trailing CR */
if (strchr(line, '\r'))
*strchr(line, '\r') = '\0';
name = tal_fmt(tmpctx, "%s.onion", line);
onion = tal(ctx, struct wireaddr);
if (!parse_wireaddr(name, onion, local->port, false, NULL))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Tor gave bad onion name '%s'", name);
#ifdef SUPERVERBOSE
status_info("Static Tor service onion address: \"%s:%d,%s\"from blob %s base64 %s ",
name, port ,fmt_wireaddr(tmpctx, local), blob ,blob64);
#else
status_info("Static Tor service onion address: \"%s:%d,%s\" bound from extern port %d ",
name, port ,fmt_wireaddr(tmpctx, local), port);
#endif
discard_remaining_response(rbuf);
return onion;
}
return NULL;
}
/* https://gitweb.torproject.org/torspec.git/tree/control-spec.txt:
*
* MidReplyLine = StatusCode "-" ReplyLine
@@ -210,7 +275,7 @@ static void negotiate_auth(struct rbuf *rbuf, const char *tor_password)
}
/* We need to have a bound address we can tell Tor to connect to */
static const struct wireaddr *
const struct wireaddr *
find_local_address(const struct wireaddr_internal *bindings)
{
for (size_t i = 0; i < tal_count(bindings); i++) {
@@ -226,7 +291,7 @@ find_local_address(const struct wireaddr_internal *bindings)
}
struct wireaddr *tor_autoservice(const tal_t *ctx,
const struct wireaddr *tor_serviceaddr,
const struct wireaddr_internal *tor_serviceaddr,
const char *tor_password,
const struct wireaddr_internal *bindings,
const bool use_v3_autotor)
@@ -239,7 +304,7 @@ struct wireaddr *tor_autoservice(const tal_t *ctx,
char *buffer;
laddr = find_local_address(bindings);
ai_tor = wireaddr_to_addrinfo(tmpctx, tor_serviceaddr);
ai_tor = wireaddr_to_addrinfo(tmpctx, &tor_serviceaddr->u.torservice.address);
fd = socket(ai_tor->ai_family, SOCK_STREAM, 0);
if (fd < 0)
@@ -252,7 +317,7 @@ struct wireaddr *tor_autoservice(const tal_t *ctx,
rbuf_init(&rbuf, fd, buffer, tal_count(buffer), buf_resize);
negotiate_auth(&rbuf, tor_password);
onion = make_onion(ctx, &rbuf, laddr, use_v3_autotor);
onion = make_onion(ctx, &rbuf, laddr, use_v3_autotor, tor_serviceaddr->u.torservice.port);
/*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
@@ -263,3 +328,42 @@ struct wireaddr *tor_autoservice(const tal_t *ctx,
return onion;
}
struct wireaddr *tor_fixed_service(const tal_t *ctx,
const struct wireaddr_internal *tor_serviceaddr,
const char *tor_password,
const u8 *blob,
const struct wireaddr *bind,
const u8 index)
{
int fd;
const struct wireaddr *laddr;
struct wireaddr *onion;
struct addrinfo *ai_tor;
struct rbuf rbuf;
char *buffer;
laddr = bind;
ai_tor = wireaddr_to_addrinfo(tmpctx, &tor_serviceaddr->u.torservice.address);
fd = socket(ai_tor->ai_family, SOCK_STREAM, 0);
if (fd < 0)
err(1, "Creating stream socket for Tor");
if (connect(fd, ai_tor->ai_addr, ai_tor->ai_addrlen) != 0)
err(1, "Connecting stream socket to Tor service");
buffer = tal_arr(tmpctx, char, rbuf_good_size(fd));
rbuf_init(&rbuf, fd, buffer, tal_count(buffer), buf_resize);
negotiate_auth(&rbuf, tor_password);
onion = make_fixed_onion(ctx, &rbuf, laddr, blob, tor_serviceaddr->u.torservice.port);
/*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
* DO NOT CLOSE FD TO KEEP ADDRESS ALIVE AS WE DO NOT DETACH WITH STATIC ADDRESS
*/
return onion;
}

View File

@@ -7,9 +7,20 @@
#include <stdlib.h>
struct wireaddr *tor_autoservice(const tal_t *ctx,
const struct wireaddr *tor_serviceaddr,
const struct wireaddr_internal *tor_serviceaddr,
const char *tor_password,
const struct wireaddr_internal *bindings,
const bool use_v3_autotor);
struct wireaddr *tor_fixed_service(const tal_t *ctx,
const struct wireaddr_internal *tor_serviceaddr,
const char *tor_password,
const u8 *blob,
const struct wireaddr *bind,
const u8 index);
const struct wireaddr *
find_local_address(const struct wireaddr_internal *bindings);
#endif /* LIGHTNING_CONNECTD_TOR_AUTOSERVICE_H */