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 (at) 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 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 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... */ 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 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 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 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 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 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 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 320 void API proxy_polarssl_set_port(proxy_polarssl_ctx *ctx, uint16_t port) 321 { 322 ctx->port = port; 323 } 324 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 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