#include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 /* some crufts can not forward ipv6*/ #undef BIND_FIRST_TO_IPV6 struct reaching_socks { u8 buffer[MAX_SIZE_OF_SOCKS5_REQ_OR_RESP]; size_t hlen; in_port_t port; char *host; struct reaching *reach; }; static struct io_plan *connect_finish2(struct io_conn *conn, struct reaching_socks *reach) { status_trace("Now try LN connect out for host %s", reach->host); return connection_out(conn, reach->reach); } static struct io_plan *connect_finish(struct io_conn *conn, struct reaching_socks *reach) { if ( reach->buffer[1] == '\0') { if ( reach->buffer[3] == SOCKS_TYP_IPV6) { return io_read(conn, (reach->buffer + SIZE_OF_RESPONSE - SIZE_OF_IPV4_RESPONSE), SIZE_OF_IPV6_RESPONSE - SIZE_OF_RESPONSE - SIZE_OF_IPV4_RESPONSE, &connect_finish2, reach); } else if ( reach->buffer[3] == SOCKS_TYP_IPV4) { status_trace("Now try LN connect out for host %s", reach->host); return connection_out(conn, reach->reach); } else { status_trace ("Tor connect out for host %s error invalid type return ", reach->host); return io_close(conn); } } else { status_trace("Tor connect out for host %s error: %x ", reach->host, reach->buffer[1]); return io_close(conn); } } static struct io_plan *connect_out(struct io_conn *conn, struct reaching_socks *reach) { return io_read(conn, reach->buffer, SIZE_OF_IPV4_RESPONSE + SIZE_OF_RESPONSE, &connect_finish, reach); } /* called when TOR responds */ static struct io_plan *io_tor_connect_after_req_host(struct io_conn *conn, struct reaching_socks *reach) { if (reach->buffer[0] == '0') { status_trace("Connected out over tor for %s failed", reach->host); return io_close(conn); } return connect_out(conn, reach); } static struct io_plan *io_tor_connect_after_resp_to_connect(struct io_conn *conn, struct reaching_socks *reach) { if (reach->buffer[1] == SOCKS_ERROR) { status_trace("Connected out for %s error", reach->host); return io_close(conn); } /* make the V5 request */ reach->hlen = strlen(reach->host); reach->buffer[0] = SOCKS_V5; reach->buffer[1] = SOCKS_CONNECT; reach->buffer[2] = 0; reach->buffer[3] = SOCKS_DOMAIN; reach->buffer[4] = reach->hlen; memcpy(reach->buffer + SOCK_REQ_V5_LEN, reach->host, reach->hlen); memcpy(reach->buffer + SOCK_REQ_V5_LEN + strlen(reach->host), &(reach->port), sizeof reach->port); return io_write(conn, reach->buffer, SOCK_REQ_V5_HEADER_LEN + reach->hlen, io_tor_connect_after_req_host, reach); } static struct io_plan *io_tor_connect_after_req_to_connect(struct io_conn *conn, struct reaching_socks *reach) { return io_read(conn, reach->buffer, 2, &io_tor_connect_after_resp_to_connect, reach); } static struct io_plan *io_tor_connect_do_req(struct io_conn *conn, struct reaching_socks *reach) { /* make the init request */ reach->buffer[0] = SOCKS_V5; reach->buffer[1] = 1; reach->buffer[2] = SOCKS_NOAUTH; return io_write(conn, reach->buffer, SOCK_REQ_METH_LEN, &io_tor_connect_after_req_to_connect, reach); } // called when we want to connect to TOR SOCKS5 struct io_plan *io_tor_connect(struct io_conn *conn, const struct wireaddr *tor_proxyaddrs, const struct wireaddr *addr, struct reaching *reach) { struct addrinfo *ai_tor = tal(reach, struct addrinfo); char *port_addr = tal(reach, char); struct io_plan *plan; struct reaching_socks *reach_tor = tal(reach, struct reaching_socks); reach_tor->port = htons(addr->port); port_addr = tal_fmt(reach, "%u", tor_proxyaddrs->port); getaddrinfo((char *) fmt_wireaddr_without_port(tmpctx, tor_proxyaddrs), port_addr, NULL, &ai_tor); status_trace("Tor proxyaddr : %s", fmt_wireaddr(reach, tor_proxyaddrs)); reach_tor->host = tal_strdup(reach, ""); if (addr->type == ADDR_TYPE_TOR_V3) reach_tor->host = tal_fmt(reach, "%.62s", fmt_wireaddr_without_port(tmpctx, addr)); else if (addr->type == ADDR_TYPE_TOR_V2) reach_tor->host = tal_fmt(reach, "%.22s", fmt_wireaddr_without_port(tmpctx, addr)); else if (addr->type == ADDR_TYPE_IPV4) reach_tor->host = tal_fmt(reach, "%s", fmt_wireaddr_without_port(tmpctx, addr)); else if (addr->type == ADDR_TYPE_IPV6) reach_tor->host = tal_fmt(reach, "%s", fmt_wireaddr_without_port(tmpctx, addr)); reach_tor->reach = reach; plan = io_connect(conn, ai_tor, &io_tor_connect_do_req, reach_tor); return plan; } 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; }