Browse Source
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
24 changed files with 921 additions and 9 deletions
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -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 */ |
@ -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; |
||||
|
} |
@ -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 */ |
@ -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 |
||||
|
|
||||
|
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 6.
|
Loading…
Reference in new issue