1 /*
2 * proxy-polarssl.c - Net stack layer for SOCKS4a/5 proxy connections
3 *
4 * Based on proxy-bio.c - Original copyright (c) 2012 The Chromium OS Authors.
5 *
6 * This file was adapted by Paul Bakker <p.j.bakker@offspark.com>
7 * All rights reserved.
8 *
9 * Use of this source code is governed by a BSD-style license that can be
10 * found in the LICENSE file.
11 *
12 * This file implements a SOCKS4a/SOCKS5 net layer as used by PolarSSL.
13 */
14
15 #include "config.h"
16
17 #include <arpa/inet.h>
18 #include <assert.h>
19 #ifndef __USE_MISC
20 #define __USE_MISC
21 #endif
22 #ifndef __USE_POSIX
23 #define __USE_POSIX
24 #endif
25 #include <netdb.h>
26 #include <stdint.h>
27 #include <stdio.h>
28
29 #ifndef HAVE_STRNLEN
30 #include "src/common/strnlen.h"
31 #endif
32
33 #include "src/proxy-polarssl.h"
34 #include "src/util.h"
35
socks4a_connect(proxy_polarssl_ctx * ctx)36 int socks4a_connect(proxy_polarssl_ctx *ctx)
37 {
38 int r;
39 unsigned char buf[NI_MAXHOST + 16];
40 uint16_t port_n;
41 size_t sz = 0;
42
43 if (!ctx)
44 return 0;
45
46 verb("V: proxy4: connecting %s:%d", ctx->host, ctx->port);
47
48 port_n = htons(ctx->port);
49
50 /*
51 * Packet layout:
52 * 1b: Version (must be 0x04)
53 * 1b: command (0x01 is connect)
54 * 2b: port number, big-endian
55 * 4b: 0x00, 0x00, 0x00, 0x01 (bogus IPv4 addr)
56 * 1b: 0x00 (empty 'userid' field)
57 * nb: hostname, null-terminated
58 */
59 buf[0] = 0x04;
60 buf[1] = 0x01;
61 sz += 2;
62
63 memcpy(buf + 2, &port_n, sizeof(port_n));
64 sz += sizeof(port_n);
65
66 buf[4] = 0x00;
67 buf[5] = 0x00;
68 buf[6] = 0x00;
69 buf[7] = 0x01;
70 sz += 4;
71
72 buf[8] = 0x00;
73 sz += 1;
74
75 memcpy(buf + sz, ctx->host, strlen(ctx->host) + 1);
76 sz += strlen(ctx->host) + 1;
77
78 r = ctx->f_send(ctx->p_send, buf, sz);
79 if (r != sz)
80 return 0;
81
82 /* server reply: 1 + 1 + 2 + 4 */
83 r = ctx->f_recv(ctx->p_recv, buf, 8);
84 if (r != 8)
85 return 0;
86
87 if (buf[1] == 0x5a) {
88 verb("V: proxy4: connected");
89 ctx->connected = 1;
90 return 1;
91 }
92 return 0;
93 }
94
socks5_connect(proxy_polarssl_ctx * ctx)95 int socks5_connect(proxy_polarssl_ctx *ctx)
96 {
97 unsigned char buf[NI_MAXHOST + 16];
98 int r;
99 uint16_t port_n;
100 size_t sz = 0;
101
102 if (!ctx)
103 return 0;
104
105 /* the length for SOCKS addresses is only one byte. */
106 if (strnlen(ctx->host, UINT8_MAX + 1) == UINT8_MAX + 1)
107 return 0;
108
109 verb("V: proxy5: connecting %s:%d", ctx->host, ctx->port);
110
111 port_n = htons(ctx->port);
112
113 /*
114 * Hello packet layout:
115 * 1b: Version
116 * 1b: auth methods
117 * nb: method types
118 *
119 * We support only one method (no auth, 0x00). Others listed in RFC
120 * 1928.
121 */
122 buf[0] = 0x05;
123 buf[1] = 0x01;
124 buf[2] = 0x00;
125
126 r = ctx->f_send(ctx->p_send, buf, 3);
127 if (r != 3)
128 return 0;
129
130 r = ctx->f_recv(ctx->p_recv, buf, 2);
131 if (r != 2)
132 return 0;
133
134 if (buf[0] != 0x05 || buf[1] != 0x00) {
135 verb("V: proxy5: auth error %02x %02x", buf[0], buf[1]);
136 return 0;
137 }
138
139 /*
140 * Connect packet layout:
141 * 1b: version
142 * 1b: command (0x01 is connect)
143 * 1b: reserved, 0x00
144 * 1b: addr type (0x03 is domain name)
145 * nb: addr len (1b) + addr bytes, no null termination
146 * 2b: port, network byte order
147 */
148 buf[0] = 0x05;
149 buf[1] = 0x01;
150 buf[2] = 0x00;
151 buf[3] = 0x03;
152 buf[4] = strlen(ctx->host);
153 sz += 5;
154 memcpy(buf + 5, ctx->host, strlen(ctx->host));
155 sz += strlen(ctx->host);
156 memcpy(buf + sz, &port_n, sizeof(port_n));
157 sz += sizeof(port_n);
158
159 r = ctx->f_send(ctx->p_send, buf, sz);
160 if (r != sz)
161 return 0;
162
163 /*
164 * Server's response:
165 * 1b: version
166 * 1b: status (0x00 is okay)
167 * 1b: reserved, 0x00
168 * 1b: addr type (0x03 is domain name, 0x01 ipv4)
169 * nb: addr len (1b) + addr bytes, no null termination
170 * 2b: port, network byte order
171 */
172
173 /* grab up through the addr type */
174 r = ctx->f_recv(ctx->p_recv, buf, 4);
175 if (r != 4)
176 return 0;
177
178 if (buf[0] != 0x05 || buf[1] != 0x00) {
179 verb("V: proxy5: connect error %02x %02x", buf[0], buf[1]);
180 return 0;
181 }
182
183 if (buf[3] == 0x03) {
184 unsigned int len;
185 r = ctx->f_recv(ctx->p_recv, buf + 4, 1);
186 if (r != 1)
187 return 0;
188 /* host (buf[4] bytes) + port (2 bytes) */
189 len = buf[4] + 2;
190 while (len) {
191 r = ctx->f_recv(ctx->p_recv, buf + 5, min(len, sizeof(buf)));
192 if (r <= 0)
193 return 0;
194 len -= min(len, r);
195 }
196 } else if (buf[3] == 0x01) {
197 /* 4 bytes ipv4 addr, 2 bytes port */
198 r = ctx->f_recv(ctx->p_recv, buf + 4, 6);
199 if (r != 6)
200 return 0;
201 }
202
203 verb("V: proxy5: connected");
204 ctx->connected = 1;
205 return 1;
206 }
207
208 /* SSL socket BIOs don't support BIO_gets, so... */
sock_gets(proxy_polarssl_ctx * ctx,char * buf,size_t sz)209 int sock_gets(proxy_polarssl_ctx *ctx, char *buf, size_t sz)
210 {
211 unsigned char c;
212 while (ctx->f_recv(ctx->p_recv, &c, 1) > 0 && sz > 1) {
213 *buf++ = c;
214 sz--;
215 if (c == '\n') {
216 *buf = '\0';
217 return 0;
218 }
219 }
220 return 1;
221 }
222
http_connect(proxy_polarssl_ctx * ctx)223 int http_connect(proxy_polarssl_ctx *ctx)
224 {
225 int r;
226 char buf[4096];
227 int retcode;
228
229 snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n",
230 ctx->host, ctx->port);
231 r = ctx->f_send(ctx->p_send, (unsigned char *) buf, strlen(buf));
232 if (r != strlen(buf))
233 return 0;
234 /* required by RFC 2616 14.23 */
235 snprintf(buf, sizeof(buf), "Host: %s:%d\r\n", ctx->host, ctx->port);
236 r = ctx->f_send(ctx->p_send, (unsigned char *) buf, strlen(buf));
237 if (r != strlen(buf))
238 return 0;
239 strcpy(buf, "\r\n");
240 r = ctx->f_send(ctx->p_send, (unsigned char *) buf, strlen(buf));
241 if (r != strlen(buf))
242 return 0;
243
244 r = sock_gets(ctx, buf, sizeof(buf));
245 if (r)
246 return 0;
247 /* use %*s to ignore the version */
248 if (sscanf(buf, "HTTP/%*s %d", &retcode) != 1)
249 return 0;
250
251 if (retcode < 200 || retcode > 299)
252 return 0;
253 while (!(r = sock_gets(ctx, buf, sizeof(buf)))) {
254 if (!strcmp(buf, "\r\n")) {
255 /* Done with the header */
256 ctx->connected = 1;
257 return 1;
258 }
259 }
260 return 0;
261 }
262
proxy_polarssl_init(proxy_polarssl_ctx * ctx)263 int API proxy_polarssl_init(proxy_polarssl_ctx *ctx)
264 {
265 if (!ctx)
266 return 0;
267
268 memset(ctx, 0, sizeof(proxy_polarssl_ctx));
269 return 1;
270 }
271
proxy_polarssl_set_bio(proxy_polarssl_ctx * ctx,int (* f_recv)(void *,unsigned char *,size_t),void * p_recv,int (* f_send)(void *,const unsigned char *,size_t),void * p_send)272 void API proxy_polarssl_set_bio(proxy_polarssl_ctx *ctx,
273 int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
274 int (*f_send)(void *, const unsigned char *, size_t), void *p_send)
275 {
276 if (!ctx)
277 return;
278
279 ctx->f_recv = f_recv;
280 ctx->p_recv = p_recv;
281 ctx->f_send = f_send;
282 ctx->p_send = p_send;
283 }
284
proxy_polarssl_free(proxy_polarssl_ctx * ctx)285 int API proxy_polarssl_free(proxy_polarssl_ctx *ctx)
286 {
287 if (!ctx)
288 return 0;
289
290 if (ctx->host)
291 {
292 free(ctx->host);
293 ctx->host = NULL;
294 }
295
296 return 1;
297 }
298
proxy_polarssl_set_scheme(proxy_polarssl_ctx * ctx,const char * scheme)299 int API proxy_polarssl_set_scheme(proxy_polarssl_ctx *ctx, const char *scheme)
300 {
301 if (!strcmp(scheme, "socks5"))
302 ctx->f_connect = socks5_connect;
303 else if (!strcmp(scheme, "socks4"))
304 ctx->f_connect = socks4a_connect;
305 else if (!strcmp(scheme, "http"))
306 ctx->f_connect = http_connect;
307 else
308 return 1;
309 return 0;
310 }
311
proxy_polarssl_set_host(proxy_polarssl_ctx * ctx,const char * host)312 int API proxy_polarssl_set_host(proxy_polarssl_ctx *ctx, const char *host)
313 {
314 if (strnlen(host, NI_MAXHOST) == NI_MAXHOST)
315 return 1;
316 ctx->host = strdup(host);
317 return 0;
318 }
319
proxy_polarssl_set_port(proxy_polarssl_ctx * ctx,uint16_t port)320 void API proxy_polarssl_set_port(proxy_polarssl_ctx *ctx, uint16_t port)
321 {
322 ctx->port = port;
323 }
324
proxy_polarssl_recv(void * ctx,unsigned char * data,size_t len)325 int API proxy_polarssl_recv(void *ctx, unsigned char *data, size_t len)
326 {
327 proxy_polarssl_ctx *proxy = (proxy_polarssl_ctx *) ctx;
328 int r;
329
330 if (!ctx)
331 return -1;
332
333 if (!proxy->connected)
334 {
335 r = proxy->f_connect(ctx);
336 if (r)
337 return (r);
338 }
339
340 return proxy->f_recv(proxy->p_recv, data, len);
341 }
342
343
proxy_polarssl_send(void * ctx,const unsigned char * data,size_t len)344 int API proxy_polarssl_send(void *ctx, const unsigned char *data, size_t len)
345 {
346 proxy_polarssl_ctx *proxy = (proxy_polarssl_ctx *) ctx;
347 int r;
348
349 if (!ctx)
350 return -1;
351
352 if (!proxy->connected)
353 {
354 r = proxy->f_connect(ctx);
355 if (r)
356 return (r);
357 }
358
359 return proxy->f_send(proxy->p_send, data, len);
360 }
361