lnsocket

A minimal C library for connecting to the lightning network
git clone git://jb55.com/lnsocket
Log | Files | Refs | Submodules | README | LICENSE

commit b2debd2504fababe70f0d3e4995fb2a90694b7f7
parent 5080a331b88fcd3fc85938c89df5fe27af956e2e
Author: Luca Vaccaro <me@lvaccaro.com>
Date:   Mon,  4 Jul 2022 10:04:57 +0200

add tor proxy support to connect on onion endpoint

Closes #6

Signed-off-by: Luca Vaccaro <me@lvaccaro.com>

Diffstat:
Mlnsocket.c | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mlnsocket.h | 1+
2 files changed, 103 insertions(+), 9 deletions(-)

diff --git a/lnsocket.c b/lnsocket.c @@ -11,6 +11,8 @@ #include <errno.h> #include <unistd.h> #include <fcntl.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include <secp256k1.h> #include <secp256k1_ecdh.h> @@ -31,6 +33,25 @@ #define MSGBUF_MEM (65536*2) #define ERROR_MEM 4096 #define DEFAULT_TIMEOUT 3000 +#define DEFAULT_TOR_TIMEOUT 10000 + +// Tor socks define +#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 int push_error(struct lnsocket *lnsocket, const char *err); @@ -539,7 +560,55 @@ const char *parse_port(char *host) return NULL; } -int lnsocket_connect_with(struct lnsocket *ln, const char *node_id, const char *host, int timeout_ms) +int lnsocket_handshake_with_tor(struct lnsocket *ln, const char *host, const char *port) +{ + // make the init request + u8 request[SIZE_OF_REQUEST] = { SOCKS_V5, 0x01, SOCKS_NOAUTH }; + if (write(ln->socket, request, sizeof(request)) != sizeof(request)) { + return note_error(&ln->errs, "Failed writing request: %s", + strerror(errno)); + } + + // read proxy response + u8 hdr[2]; + if (!read(ln->socket, hdr, 2)) + return note_error(&ln->errs,"Failed reading header"); + + if (hdr[1] == SOCKS_ERROR) + return note_error(&ln->errs,"Failed proxy authentication required"); + + // make the V5 request + size_t hlen = strlen(host); + u16 uport = htons(atoi(port)); + + u8 buffer[SOCK_REQ_V5_HEADER_LEN + hlen]; + buffer[0] = SOCKS_V5; + buffer[1] = SOCKS_CONNECT; + buffer[2] = 0; + buffer[3] = SOCKS_DOMAIN; + buffer[4] = hlen; + memcpy(buffer + SOCK_REQ_V5_LEN, host, hlen); + memcpy(buffer + SOCK_REQ_V5_LEN + hlen, &uport, sizeof(uport)); + + if (write(ln->socket, buffer, sizeof(buffer)) != sizeof(buffer)) { + return note_error(&ln->errs,"Failed writing buffer: %s", strerror(errno)); + } + + // read completion + u8 inbuffer[SIZE_OF_IPV4_RESPONSE + SIZE_OF_RESPONSE]; + if (!read_all(ln->socket, inbuffer, sizeof(inbuffer))) + return note_error(&ln->errs,"Failed reading inbuffer: %s", strerror(errno)); + if (inbuffer[1] != '\0') + return note_error(&ln->errs,"Failed proxy connection: %d", inbuffer[1]); + if (inbuffer[3] == SOCKS_TYP_IPV6) + return note_error(&ln->errs,"Failed ipv6 not supported yet"); + if (inbuffer[3] != SOCKS_TYP_IPV4) + return note_error(&ln->errs,"Failed only ipv4 supported"); + + return 1; +} + +int lnsocket_connect_with(struct lnsocket *ln, const char *node_id, const char *host, const char *tor_proxy, int timeout_ms) { int ret; struct addrinfo *addrs = NULL; @@ -566,11 +635,6 @@ int lnsocket_connect_with(struct lnsocket *ln, const char *node_id, const char * if (!pubkey_from_node_id(ln->secp, &their_id, &their_node_id)) return note_error(&ln->errs, "failed to convert node_id to pubkey"); - // parse ip into addrinfo - const char *port = parse_port(onlyhost); - if ((ret = getaddrinfo(onlyhost, port ? port : "9735", NULL, &addrs)) || !addrs) - return note_error(&ln->errs, "%s", gai_strerror(ret)); - // create our network socket for comms if (!(ln->socket = socket(AF_INET, SOCK_STREAM, 0))) return note_error(&ln->errs, "creating socket failed"); @@ -580,8 +644,25 @@ int lnsocket_connect_with(struct lnsocket *ln, const char *node_id, const char * if (!io_fd_block(ln->socket, 0)) return note_error(&ln->errs, "failed setting socket to non-blocking"); - // connect to the node! - connect(ln->socket, addrs->ai_addr, addrs->ai_addrlen); + if (tor_proxy != NULL) { + // connect to the tor proxy! + char proxyhost[strlen(tor_proxy)+1]; + strncpy(proxyhost, tor_proxy, sizeof(proxyhost)); + const char *port = parse_port(proxyhost); + struct sockaddr_in proxy_server; + proxy_server.sin_family = AF_INET; + proxy_server.sin_addr.s_addr = inet_addr(proxyhost); + proxy_server.sin_port = htons(port ? atoi(port) : 9050); + if (!connect(ln->socket, (struct sockaddr*) &proxy_server, sizeof(proxy_server))) + return note_error(&ln->errs, "Failed to connect"); + } else { + // parse ip into addrinfo + const char *port = parse_port(onlyhost); + if ((ret = getaddrinfo(onlyhost, port ? port : "9735", NULL, &addrs)) || !addrs) + return note_error(&ln->errs, "%s", gai_strerror(ret)); + // connect to the node! + connect(ln->socket, addrs->ai_addr, addrs->ai_addrlen); + } if (!io_fd_block(ln->socket, 1)) return note_error(&ln->errs, "failed setting socket to blocking"); @@ -593,6 +674,13 @@ int lnsocket_connect_with(struct lnsocket *ln, const char *node_id, const char * return note_error(&ln->errs, "connection timeout"); } + if (tor_proxy != NULL) { + // connect to the node through tor proxy + const char *port = parse_port(onlyhost); + if (!lnsocket_handshake_with_tor(ln, onlyhost, port ? port : "9735")) + return note_error(&ln->errs, "failed handshake with tor proxy"); + } + // prepare some data for ACT1 new_handshake(ln->secp, &ln->handshake, &their_id); @@ -605,7 +693,12 @@ int lnsocket_connect_with(struct lnsocket *ln, const char *node_id, const char * int lnsocket_connect(struct lnsocket *ln, const char *node_id, const char *host) { - return lnsocket_connect_with(ln, node_id, host, DEFAULT_TIMEOUT); + return lnsocket_connect_with(ln, node_id, host, NULL, DEFAULT_TIMEOUT); +} + +int lnsocket_connect_tor(struct lnsocket *ln, const char *node_id, const char *host, const char *tor_proxy) +{ + return lnsocket_connect_with(ln, node_id, host, tor_proxy, DEFAULT_TOR_TIMEOUT); } int lnsocket_fd(struct lnsocket *ln, int *fd) diff --git a/lnsocket.h b/lnsocket.h @@ -76,6 +76,7 @@ int lnsocket_make_init_msg(unsigned char *buf, int buflen, const unsigned char * int lnsocket_perform_init(struct lnsocket *ln); int lnsocket_connect(struct lnsocket *, const char *node_id, const char *host); +int lnsocket_connect_tor(struct lnsocket *, const char *node_id, const char *host, const char *tor_proxy); int lnsocket_fd(struct lnsocket *, int *fd); int lnsocket_write(struct lnsocket *, const unsigned char *msg, unsigned short msg_len);