1 #include <ccan/io/io.h>
2 #include <ccan/tal/str/str.h>
3 #include <common/status.h>
4 #include <common/utils.h>
5 #include <connectd/connectd.h>
6 #include <connectd/tor.h>
7 #include <errno.h>
8 #include <inttypes.h>
9 #include <netinet/in.h>
10 
11 #define SOCKS_NOAUTH		0
12 #define SOCKS_ERROR 	 0xff
13 #define SOCKS_CONNECT		1
14 #define SOCKS_TYP_IPV4		1
15 #define SOCKS_DOMAIN		3
16 #define SOCKS_TYP_IPV6		4
17 #define SOCKS_V5            5
18 
19 #define MAX_SIZE_OF_SOCKS5_REQ_OR_RESP 255
20 #define SIZE_OF_RESPONSE 		4
21 #define SIZE_OF_REQUEST 		3
22 #define SIZE_OF_IPV4_RESPONSE 	6
23 #define SIZE_OF_IPV6_RESPONSE 	18
24 #define SOCK_REQ_METH_LEN		3
25 #define SOCK_REQ_V5_LEN			5
26 #define SOCK_REQ_V5_HEADER_LEN	7
27 
28 /* some crufts can not forward ipv6 */
29 #undef BIND_FIRST_TO_IPV6
30 
31 struct connecting_socks {
32 	u8 buffer[MAX_SIZE_OF_SOCKS5_REQ_OR_RESP];
33 	size_t hlen;
34 	in_port_t port;
35 	char *host;
36 	struct connecting *connect;
37 };
38 
socks5strerror(const tal_t * ctx,u8 code)39 static const char* socks5strerror(const tal_t *ctx, u8 code)
40 {
41 	/* Error codes defined in https://tools.ietf.org/html/rfc1928#section-6 */
42 	switch (code) {
43 	case 0:
44 		return tal_strdup(ctx, "success");
45 	case 1:
46 		return tal_strdup(ctx, "general SOCKS server failure");
47 	case 2:
48 		return tal_strdup(ctx, "connection not allowed by ruleset");
49 	case 3:
50 		return tal_strdup(ctx, "network unreachable");
51 	case 4:
52 		return tal_strdup(ctx, "host unreachable");
53 	case 5:
54 		return tal_strdup(ctx, "connection refused");
55 	case 6:
56 		return tal_strdup(ctx, "TTL expired");
57 	case 7:
58 		return tal_strdup(ctx, "command not supported");
59 	case 8:
60 		return tal_strdup(ctx, "address type not supported");
61 	}
62 	return tal_fmt(ctx, "unknown error: %" PRIu8, code);
63 }
64 
connect_finish2(struct io_conn * conn,struct connecting_socks * connect)65 static struct io_plan *connect_finish2(struct io_conn *conn,
66 				       struct connecting_socks *connect)
67 {
68 	status_io(LOG_IO_IN, NULL, "proxy",
69 		  connect->buffer + SIZE_OF_RESPONSE + SIZE_OF_IPV4_RESPONSE,
70 		  SIZE_OF_IPV6_RESPONSE - SIZE_OF_IPV4_RESPONSE);
71 	status_debug("Now try LN connect out for host %s", connect->host);
72 	return connection_out(conn, connect->connect);
73 }
74 
connect_finish(struct io_conn * conn,struct connecting_socks * connect)75 static struct io_plan *connect_finish(struct io_conn *conn,
76 				      struct connecting_socks *connect)
77 {
78 	status_io(LOG_IO_IN, NULL, "proxy",
79 		  connect->buffer, SIZE_OF_IPV4_RESPONSE + SIZE_OF_RESPONSE);
80 
81 	/* buffer[1] contains the reply status code and 0 means "success",
82 	 * see https://tools.ietf.org/html/rfc1928#section-6
83 	 */
84 	if ( connect->buffer[1] == '\0') {
85 		if ( connect->buffer[3] == SOCKS_TYP_IPV6) {
86 			/* Read rest of response */
87 			return io_read(conn,
88 				       connect->buffer + SIZE_OF_RESPONSE +
89 				       SIZE_OF_IPV4_RESPONSE,
90 				       SIZE_OF_IPV6_RESPONSE -
91 				       SIZE_OF_IPV4_RESPONSE,
92 				       &connect_finish2, connect);
93 
94 		} else if ( connect->buffer[3] == SOCKS_TYP_IPV4) {
95 			status_debug("Now try LN connect out for host %s",
96 				     connect->host);
97 			return connection_out(conn, connect->connect);
98 		} else {
99 			const char *msg = tal_fmt(tmpctx,
100 			     "Tor connect out for host %s error invalid "
101 			     "type return: %0x", connect->host,
102 			     connect->buffer[3]);
103 			status_debug("%s", msg);
104 			add_errors_to_error_list(connect->connect, msg);
105 
106 			errno = ECONNREFUSED;
107 			return io_close(conn);
108 		}
109 	} else {
110 		const char *msg = tal_fmt(tmpctx,
111 			     "Error connecting to %s: Tor server reply: %s",
112 			     connect->host,
113 			     socks5strerror(tmpctx, connect->buffer[1]));
114 		status_debug("%s", msg);
115 		add_errors_to_error_list(connect->connect, msg);
116 
117 		errno = ECONNREFUSED;
118 		return io_close(conn);
119 	}
120 }
121 
122 /* called when TOR responds */
connect_out(struct io_conn * conn,struct connecting_socks * connect)123 static struct io_plan *connect_out(struct io_conn *conn,
124 				   struct connecting_socks *connect)
125 {
126 	return io_read(conn, connect->buffer,
127 		       SIZE_OF_IPV4_RESPONSE + SIZE_OF_RESPONSE,
128 		       &connect_finish, connect);
129 
130 }
131 
io_tor_connect_after_resp_to_connect(struct io_conn * conn,struct connecting_socks * connect)132 static struct io_plan *io_tor_connect_after_resp_to_connect(struct io_conn
133 							    *conn,
134 							    struct
135 							    connecting_socks
136 							    *connect)
137 {
138 	status_io(LOG_IO_IN, NULL, "proxy", connect->buffer, 2);
139 
140 	if (connect->buffer[1] == SOCKS_ERROR) {
141 		/* The Tor socks5 server did not like any of our authentication
142 		 * methods and we provided only "no auth".
143 		 */
144 		const char *msg = tal_fmt(tmpctx,
145 			     "Connected out for %s error: authentication required",
146 			     connect->host);
147 		status_debug("%s", msg);
148 		add_errors_to_error_list(connect->connect, msg);
149 
150 		errno = ECONNREFUSED;
151 		return io_close(conn);
152 	}
153 	if (connect->buffer[1] == '\0') {
154 		/* make the V5 request */
155 		connect->hlen = strlen(connect->host);
156 		connect->buffer[0] = SOCKS_V5;
157 		connect->buffer[1] = SOCKS_CONNECT;
158 		connect->buffer[2] = 0;
159 		connect->buffer[3] = SOCKS_DOMAIN;
160 		connect->buffer[4] = connect->hlen;
161 
162 		memcpy(connect->buffer + SOCK_REQ_V5_LEN, connect->host, connect->hlen);
163 		memcpy(connect->buffer + SOCK_REQ_V5_LEN + strlen(connect->host),
164 				&(connect->port), sizeof connect->port);
165 
166 		status_io(LOG_IO_OUT, NULL, "proxy", connect->buffer,
167 				SOCK_REQ_V5_HEADER_LEN + connect->hlen);
168 		return io_write(conn, connect->buffer,
169 				SOCK_REQ_V5_HEADER_LEN + connect->hlen,
170 				connect_out, connect);
171 	} else {
172 			const char *msg = tal_fmt(tmpctx,
173 				"Connected out for %s error: unexpected connect answer %0x from the tor socks5 proxy",
174 				connect->host,
175 				connect->buffer[1]);
176 			status_debug("%s", msg);
177 			add_errors_to_error_list(connect->connect, msg);
178 
179 		errno = ECONNREFUSED;
180 		return io_close(conn);
181 	}
182 }
183 
io_tor_connect_after_req_to_connect(struct io_conn * conn,struct connecting_socks * connect)184 static struct io_plan *io_tor_connect_after_req_to_connect(struct io_conn *conn,
185 							   struct connecting_socks
186 							   *connect)
187 {
188 	return io_read(conn, connect->buffer, 2,
189 		       &io_tor_connect_after_resp_to_connect, connect);
190 }
191 
io_tor_connect_do_req(struct io_conn * conn,struct connecting_socks * connect)192 static struct io_plan *io_tor_connect_do_req(struct io_conn *conn,
193 					     struct connecting_socks *connect)
194 {
195 	/* make the init request */
196 	connect->buffer[0] = SOCKS_V5;
197 	connect->buffer[1] = 1;
198 	connect->buffer[2] = SOCKS_NOAUTH;
199 
200 	status_io(LOG_IO_OUT, NULL, "proxy", connect->buffer, SOCK_REQ_METH_LEN);
201 	return io_write(conn, connect->buffer, SOCK_REQ_METH_LEN,
202 			&io_tor_connect_after_req_to_connect, connect);
203 }
204 
205 /* called when we want to connect to TOR SOCKS5 */
io_tor_connect(struct io_conn * conn,const struct addrinfo * tor_proxyaddr,const char * host,u16 port,struct connecting * connect)206 struct io_plan *io_tor_connect(struct io_conn *conn,
207 			       const struct addrinfo *tor_proxyaddr,
208 			       const char *host, u16 port,
209 			       struct connecting *connect)
210 {
211 	struct connecting_socks *connect_tor = tal(connect,
212 						   struct connecting_socks);
213 
214 	connect_tor->port = htons(port);
215 	connect_tor->host = tal_strdup(connect_tor, host);
216 	connect_tor->connect = connect;
217 
218 	return io_connect(conn, tor_proxyaddr,
219 			  &io_tor_connect_do_req, connect_tor);
220 }
221