@ -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 ;
}