2019-02-08 16:37:02 +00:00
# include "tor_ctl.h"
2020-02-24 16:22:22 +00:00
# include "timer.h"
struct os_connect {
char host [ 256 ] ;
char port [ 6 ] ;
char url [ 512 ] ;
} ;
enum DONAR_TIMER_DECISION on_os_connect_timeout ( struct evt_core_ctx * ctx , void * user_data ) {
struct os_connect * oc = user_data ;
struct evt_core_fdinfo newfdinfo ;
struct evt_core_cat newcat ;
newfdinfo . cat = & newcat ;
newfdinfo . url = oc - > url ;
int fd = create_tcp_client ( oc - > host , oc - > port ) ;
if ( fd < = 0 ) return DONAR_TIMER_CONTINUE ;
newfdinfo . fd = fd ;
newfdinfo . cat - > name = " torctl-server-success " ;
struct evt_core_fdinfo * reg = evt_core_add_fd ( ctx , & newfdinfo ) ;
printf ( " [%s][torctl] onion service %s up (cat: %s, fd: %d) \n " , current_human_datetime ( ) , reg - > url , reg - > cat - > name , reg - > fd ) ;
free ( oc ) ;
return DONAR_TIMER_STOP ;
}
2019-02-08 16:37:02 +00:00
int tor_ctl_connect ( struct tor_ctl * ctx , char * addr , char * service ) {
int sock = create_tcp_client ( addr , service ) ;
int sock2 = dup ( sock ) ;
ctx - > rsock = NULL ;
ctx - > wsock = NULL ;
ctx - > rsock = fdopen ( sock , " r " ) ;
if ( ctx - > rsock = = NULL ) {
return - 1 ;
}
setbuf ( ctx - > rsock , NULL ) ;
ctx - > wsock = fdopen ( sock2 , " w " ) ;
if ( ctx - > wsock = = NULL ) {
return - 1 ;
}
setbuf ( ctx - > wsock , NULL ) ;
fprintf ( ctx - > wsock , " authenticate \" \" \n " ) ;
int error_code = 0 ;
fscanf ( ctx - > rsock , " %d " , & error_code ) ;
if ( error_code ! = 250 ) {
tor_ctl_close ( ctx ) ;
return - 1 ;
}
fscanf ( ctx - > rsock , " OK " ) ;
return 0 ;
}
2020-01-20 22:35:02 +00:00
void tor_ctl_list_onions ( struct tor_ctl * ctx ) {
fprintf ( ctx - > wsock , " getinfo onions/current \n " ) ;
char delimiter , buffer [ 1024 ] = { 0 } ;
fscanf ( ctx - > rsock , " 250%c " , & delimiter ) ;
if ( delimiter = = ' - ' ) {
fscanf ( ctx - > rsock , " onions/current=%s " , buffer ) ;
if ( strlen ( buffer ) > 0 ) printf ( " key: %s \n " , buffer ) ;
} else if ( delimiter = = ' + ' ) {
fscanf ( ctx - > rsock , " onions/current= " ) ;
while ( 1 ) {
fgets ( buffer , 1024 , ctx - > rsock ) ;
if ( strcmp ( buffer , " 250 OK \r \n " ) = = 0 ) break ;
if ( strcmp ( buffer , " . \r \n " ) = = 0 ) continue ;
printf ( " line: %s " , buffer ) ;
}
} else {
printf ( " deli:%c \n " , delimiter ) ;
}
}
2020-02-01 22:33:45 +00:00
int tor_ctl_add_onion ( struct tor_ctl * ctx , struct tor_os_str * tos , uint16_t * port , uint64_t port_per_os , enum TOR_ONION_FLAGS flags ) {
2019-02-08 16:37:02 +00:00
int err = 0 ;
2019-02-11 08:53:00 +00:00
char buffer1 [ 1024 ] = { 0 } ;
char buffer2 [ 1024 ] = { 0 } ;
2019-02-08 16:37:02 +00:00
int to_create = tos - > size - tos - > filled ;
/* Add onion services loaded from file */
for ( int i = 0 ; i < tos - > filled ; i + + ) {
2020-02-01 22:33:45 +00:00
fprintf ( ctx - > wsock , " add_onion %s " , tos - > keys [ i ] . priv ) ;
for ( int j = 0 ; j < port_per_os ; j + + ) {
2020-02-27 15:41:52 +00:00
fprintf ( ctx - > wsock , " Port=%d,%s:%d " , port [ i * port_per_os + j ] , ctx - > os_endpoint , port [ i * port_per_os + j ] ) ;
2020-02-01 22:33:45 +00:00
}
if ( flags = = TOR_ONION_FLAG_NONE ) fprintf ( ctx - > wsock , " \n " ) ;
2019-09-04 15:24:51 +00:00
else {
2020-02-01 22:33:45 +00:00
fprintf ( ctx - > wsock , " Flags= " ) ;
if ( flags & TOR_ONION_FLAG_NON_ANONYMOUS ) fprintf ( ctx - > wsock , " NonAnonymous, " ) ;
2019-09-04 15:24:51 +00:00
fprintf ( ctx - > wsock , " \n " ) ;
}
2019-02-08 16:37:02 +00:00
fscanf ( ctx - > rsock , " %d " , & err ) ;
2019-02-08 17:17:42 +00:00
if ( err ! = 250 ) {
printf ( " err: %d \n " , err ) ;
return - 1 ;
}
2019-02-11 09:25:27 +00:00
fscanf ( ctx - > rsock , " -ServiceID=%s \n " , buffer1 ) ;
2019-02-11 08:53:00 +00:00
printf ( " Added onion service %s.onion from file \n " , buffer1 ) ;
2019-02-08 16:37:02 +00:00
fscanf ( ctx - > rsock , " 250 OK " ) ;
}
/* Complete by creating new onion services */
for ( int i = tos - > filled ; i < tos - > size ; i + + ) {
2020-02-01 22:33:45 +00:00
fprintf ( ctx - > wsock , " add_onion NEW:ED25519-V3 " ) ;
for ( int j = 0 ; j < port_per_os ; j + + ) {
2020-02-27 15:41:52 +00:00
fprintf ( ctx - > wsock , " Port=%d,%s:%d " , port [ i * port_per_os + j ] , ctx - > os_endpoint , port [ i * port_per_os + j ] ) ;
2020-02-01 22:33:45 +00:00
}
if ( flags = = TOR_ONION_FLAG_NONE ) fprintf ( ctx - > wsock , " \n " ) ;
2019-09-04 14:40:02 +00:00
else {
2020-02-01 22:33:45 +00:00
fprintf ( ctx - > wsock , " Flags= " ) ;
if ( flags & TOR_ONION_FLAG_NON_ANONYMOUS ) fprintf ( ctx - > wsock , " NonAnonymous, " ) ;
2019-09-04 14:40:02 +00:00
fprintf ( ctx - > wsock , " \n " ) ;
}
2020-02-01 22:33:45 +00:00
2019-03-06 16:46:12 +00:00
//fprintf(ctx->wsock, "add_onion NEW:RSA1024 Port=%d\n", port[i]);
2019-02-08 16:37:02 +00:00
2020-02-24 12:42:35 +00:00
err = 0 ;
2019-02-08 16:37:02 +00:00
fscanf ( ctx - > rsock , " %d " , & err ) ;
2020-02-24 12:42:35 +00:00
if ( err ! = 250 ) {
fprintf ( stderr , " Got error %d instead of 250 \n " , err ) ;
return - 2 ;
}
2019-02-11 08:53:00 +00:00
err = fscanf ( ctx - > rsock , " -ServiceID=%s \n " , buffer1 ) ;
2019-02-08 16:37:02 +00:00
if ( err < = 0 ) return - 3 ;
2019-02-11 08:53:00 +00:00
printf ( " Created onion service %s.onion \n " , buffer1 ) ;
err = fscanf ( ctx - > rsock , " 250-PrivateKey=%s \n " , buffer2 ) ;
2019-02-08 16:37:02 +00:00
if ( err < = 0 ) return - 4 ;
2019-02-11 08:53:00 +00:00
//printf("Onion service private key: %s\n", buffer);
if ( tor_os_append ( tos , buffer1 , buffer2 ) ! = 0 ) return - 5 ;
2019-02-08 16:37:02 +00:00
err = fscanf ( ctx - > rsock , " 250 OK " ) ;
if ( err < 0 ) return - 6 ;
}
if ( to_create > 0 ) {
tor_os_persist ( tos ) ;
}
return 0 ;
}
void tor_ctl_close ( struct tor_ctl * ctx ) {
fclose ( ctx - > rsock ) ;
fclose ( ctx - > wsock ) ;
}
2020-02-24 12:42:35 +00:00
int on_torctl_server_auth_read ( struct evt_core_ctx * ctx , struct evt_core_fdinfo * fdinfo ) {
char * expected = " authenticate \" \" \n " ;
size_t to_read = strlen ( expected ) ;
char buffer [ 128 ] = { 0 } ;
ssize_t nread = recv ( fdinfo - > fd , buffer , to_read , MSG_PEEK ) ;
if ( nread = = - 1 & & errno = = EAGAIN ) return EVT_CORE_FD_EXHAUSTED ;
if ( nread ! = to_read ) return EVT_CORE_FD_EXHAUSTED ;
recv ( fdinfo - > fd , buffer , to_read , 0 ) ;
if ( strstr ( buffer , " authenticate " ) = = NULL ) {
fprintf ( stderr , " Unable to find string 'authenticate' in receveived command: '%s' \n " , buffer ) ;
exit ( EXIT_FAILURE ) ;
}
evt_core_mv_fd2 ( ctx , fdinfo , " torctl-server-auth-write " ) ;
return EVT_CORE_FD_EXHAUSTED ;
}
int on_torctl_server_auth_write ( struct evt_core_ctx * ctx , struct evt_core_fdinfo * fdinfo ) {
char * response = " 250 OK \r \n " ;
ssize_t nwrite = send ( fdinfo - > fd , response , sizeof ( response ) , 0 ) ;
if ( nwrite ! = sizeof ( response ) ) {
perror ( " @FIXME: Unproper handling of sockets in torctl_server_auth_write. " ) ;
exit ( EXIT_FAILURE ) ;
}
evt_core_mv_fd2 ( ctx , fdinfo , " torctl-server-add-onion-read " ) ;
return EVT_CORE_FD_EXHAUSTED ;
}
int on_torctl_server_add_onion_read ( struct evt_core_ctx * ctx , struct evt_core_fdinfo * fdinfo ) {
char buffer [ 1024 ] = { 0 } ;
2020-02-24 14:59:22 +00:00
char * strtok_ptr , * str_target , * token ;
2020-02-24 16:22:22 +00:00
int i , port1 ;
char * service_id = " iu7aeep42k5ky3fwcfag5el2raelfcwuilsstqhcz3c6bmxilr2nuayd.onion " ; //@FIXME hardcoded url
2020-02-24 12:42:35 +00:00
ssize_t nread = recv ( fdinfo - > fd , buffer , sizeof ( buffer ) , MSG_PEEK ) ;
if ( nread = = - 1 & & errno = = EAGAIN ) return EVT_CORE_FD_EXHAUSTED ;
if ( nread = = - 1 ) {
perror ( " an error occured... " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( buffer [ nread - 1 ] ! = ' \n ' ) return EVT_CORE_FD_EXHAUSTED ;
nread = recv ( fdinfo - > fd , buffer , sizeof ( buffer ) , 0 ) ;
printf ( " [%s][torctl] Received command: %s \n " , current_human_datetime ( ) , buffer ) ;
2020-02-24 14:59:22 +00:00
for ( i = 0 , str_target = buffer ; ; str_target = NULL , i + + ) {
token = strtok_r ( str_target , " " , & strtok_ptr ) ;
if ( i = = 0 & & ( token = = NULL | | strcmp ( token , " add_onion " ) ! = 0 ) ) {
fprintf ( stderr , " wrong command. expected 'add_onion' but got '%s' \n " , token ) ;
exit ( EXIT_FAILURE ) ;
}
if ( i = = 1 & & token = = NULL ) {
fprintf ( stderr , " command add_onion requires at least one parameter, specifying key algo \n " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( i < 2 ) continue ;
if ( token = = NULL ) break ;
2020-02-24 16:22:22 +00:00
struct os_connect * oc = malloc ( sizeof ( struct os_connect ) ) ;
int captured = sscanf ( token , " Port=%d,%[^:]:%s " , & port1 , oc - > host , oc - > port ) ;
if ( captured ! = 3 ) {
free ( oc ) ;
continue ;
}
2020-02-24 14:59:22 +00:00
2020-02-24 16:22:22 +00:00
sprintf ( oc - > url , " torctl:%s:%d " , service_id , port1 ) ;
printf ( " [%s][torctl] will create onion service %s:%d <-> %s:%s in background (%s) \n " , current_human_datetime ( ) , service_id , port1 , oc - > host , oc - > port , oc - > url ) ;
set_timeout ( ctx , 100 , oc , on_os_connect_timeout ) ;
2020-02-24 14:59:22 +00:00
}
2020-02-24 12:42:35 +00:00
evt_core_mv_fd2 ( ctx , fdinfo , " torctl-server-add-onion-write " ) ;
return EVT_CORE_FD_EXHAUSTED ;
}
int on_torctl_server_add_onion_write ( struct evt_core_ctx * ctx , struct evt_core_fdinfo * fdinfo ) {
2020-02-24 16:22:22 +00:00
//@FIXME hardcoded response
2020-02-24 12:42:35 +00:00
char * answer = " 250-ServiceID=iu7aeep42k5ky3fwcfag5el2raelfcwuilsstqhcz3c6bmxilr2nuayd \r \n 250-PrivateKey=ED25519-V3:ULk3Q/TFqngKCDDzeM93YC80IDOjz13PKTx718UjE0Svf+u/QZmN9EHzUCqCa1ZkNAXSQJIzcOVeJ8OL8Zg5Xg== \r \n 250 OK \r \n " ;
ssize_t nwrite ;
nwrite = send ( fdinfo - > fd , answer , strlen ( answer ) , 0 ) ;
if ( nwrite ! = strlen ( answer ) ) goto error ;
printf ( " [%s][torctl] Sent add-onion reply \n " , current_human_datetime ( ) ) ;
evt_core_mv_fd2 ( ctx , fdinfo , " torctl-server-add-onion-read " ) ;
return EVT_CORE_FD_EXHAUSTED ;
error :
2020-02-24 15:20:15 +00:00
perror ( " @FIXME: unproper handling of non blocking sockets, you have been bitten in torctl_server_add_onion_write \n " ) ;
2020-02-24 12:42:35 +00:00
exit ( EXIT_FAILURE ) ;
}
void tor_ctl_server_init ( struct evt_core_ctx * ctx ) {
struct evt_core_cat template = { 0 } ;
template . cb = on_torctl_server_auth_read ;
template . err_cb = NULL ;
template . name = " torctl-server-auth-read " ;
template . flags = EPOLLIN | EPOLLET ;
evt_core_add_cat ( ctx , & template ) ;
template . cb = on_torctl_server_auth_write ;
template . err_cb = NULL ;
template . name = " torctl-server-auth-write " ;
template . flags = EPOLLOUT | EPOLLET ;
evt_core_add_cat ( ctx , & template ) ;
template . cb = on_torctl_server_add_onion_read ;
template . err_cb = NULL ;
template . name = " torctl-server-add-onion-read " ;
template . flags = EPOLLIN | EPOLLET ;
evt_core_add_cat ( ctx , & template ) ;
template . cb = on_torctl_server_add_onion_write ;
template . err_cb = NULL ;
template . name = " torctl-server-add-onion-write " ;
template . flags = EPOLLOUT | EPOLLET ;
evt_core_add_cat ( ctx , & template ) ;
}
void tor_ctl_server_handle ( struct evt_core_ctx * ctx , int fd ) {
struct evt_core_fdinfo * reg_fdinfo ;
struct evt_core_fdinfo fdinfo ;
struct evt_core_cat cat ;
char url [ 256 ] ;
fdinfo . cat = & cat ;
fdinfo . cat - > name = " torctl-server-auth-read " ;
fdinfo . fd = fd ;
fdinfo . other = NULL ;
fdinfo . free_other = NULL ;
sprintf ( url , " tor-ctl-server:%d " , fd ) ;
fdinfo . url = url ;
reg_fdinfo = evt_core_add_fd ( ctx , & fdinfo ) ;
}