1 /* 2 * proxy-bio.c - BIO layer for SOCKS4a/5 proxy connections 3 * 4 * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 * 8 * This file implements a SOCKS4a/SOCKS5 "filter" BIO. In SSL terminology, a BIO 9 * is a stackable IO filter, kind of like sysv streams. These filters are 10 * inserted into a stream to cause it to run SOCKS over whatever transport is 11 * being used. Most commonly, this would be: 12 * SSL BIO (filter) -> SOCKS BIO (filter) -> connect BIO (source/sink) 13 * This configuration represents doing an SSL connection through a SOCKS proxy, 14 * which is itself connected to in plaintext. You might also do: 15 * SSL BIO -> SOCKS BIO -> SSL BIO -> connect BIO 16 * This is an SSL connection through a SOCKS proxy which is itself reached over 17 * SSL. 18 */ 19 20 #include "config.h" 21 22 #include <arpa/inet.h> 23 #include <assert.h> 24 #ifndef __USE_MISC 25 #define __USE_MISC 26 #endif 27 #ifndef __USE_POSIX 28 #define __USE_POSIX 29 #endif 30 #include <netdb.h> 31 32 #include <stdint.h> 33 34 #ifndef HAVE_STRNLEN 35 #include "src/common/strnlen.h" 36 #endif 37 38 #include "src/proxy-bio.h" 39 40 int socks4a_connect (BIO *b); 41 int socks5_connect (BIO *b); 42 int http_connect (BIO *b); 43 44 int proxy_new (BIO *b) 45 { 46 struct proxy_ctx *ctx = (struct proxy_ctx *) malloc (sizeof *ctx); 47 if (!ctx) 48 return 0; 49 ctx->connected = 0; 50 ctx->connect = NULL; 51 ctx->host = NULL; 52 ctx->port = 0; 53 b->init = 1; 54 b->flags = 0; 55 b->ptr = ctx; 56 return 1; 57 } 58 59 int proxy_free (BIO *b) 60 { 61 struct proxy_ctx *c; 62 if (!b || !b->ptr) 63 return 1; 64 c = (struct proxy_ctx *) b->ptr; 65 if (c->host) 66 free (c->host); 67 c->host = NULL; 68 b->ptr = NULL; 69 free (c); 70 return 1; 71 } 72 73 int socks4a_connect (BIO *b) 74 { 75 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 76 int r; 77 unsigned char buf[NI_MAXHOST + 16]; 78 uint16_t port_n = htons (ctx->port); 79 size_t sz = 0; 80 verb ("V: proxy4: connecting %s:%d", ctx->host, ctx->port); 81 /* 82 * Packet layout: 83 * 1b: Version (must be 0x04) 84 * 1b: command (0x01 is connect) 85 * 2b: port number, big-endian 86 * 4b: 0x00, 0x00, 0x00, 0x01 (bogus IPv4 addr) 87 * 1b: 0x00 (empty 'userid' field) 88 * nb: hostname, null-terminated 89 */ 90 buf[0] = 0x04; 91 buf[1] = 0x01; 92 sz += 2; 93 memcpy (buf + 2, &port_n, sizeof (port_n)); 94 sz += sizeof (port_n); 95 buf[4] = 0x00; 96 buf[5] = 0x00; 97 buf[6] = 0x00; 98 buf[7] = 0x01; 99 sz += 4; 100 buf[8] = 0x00; 101 sz += 1; 102 103 memcpy (buf + sz, ctx->host, strlen (ctx->host) + 1); 104 sz += strlen (ctx->host) + 1; 105 r = BIO_write (b->next_bio, buf, sz); 106 if ( -1 == r ) 107 return -1; 108 if ( (size_t) r != sz) 109 return 0; 110 /* server reply: 1 + 1 + 2 + 4 */ 111 r = BIO_read (b->next_bio, buf, 8); 112 if ( -1 == r ) 113 return -1; 114 if ( (size_t) r != 8) 115 return 0; 116 if (buf[1] == 0x5a) 117 { 118 verb ("V: proxy4: connected"); 119 ctx->connected = 1; 120 return 1; 121 } 122 return 0; 123 } 124 125 int socks5_connect (BIO *b) 126 { 127 unsigned char buf[NI_MAXHOST + 16]; 128 int r; 129 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 130 uint16_t port_n = htons (ctx->port); 131 size_t sz = 0; 132 /* the length for SOCKS addresses is only one byte. */ 133 if (strnlen (ctx->host, UINT8_MAX + 1) == UINT8_MAX + 1) 134 return 0; 135 verb ("V: proxy5: connecting %s:%d", ctx->host, ctx->port); 136 /* 137 * Hello packet layout: 138 * 1b: Version 139 * 1b: auth methods 140 * nb: method types 141 * 142 * We support only one method (no auth, 0x00). Others listed in RFC 143 * 1928. 144 */ 145 buf[0] = 0x05; 146 buf[1] = 0x01; 147 buf[2] = 0x00; 148 r = BIO_write (b->next_bio, buf, 3); 149 if (r != 3) 150 return 0; 151 r = BIO_read (b->next_bio, buf, 2); 152 if (r != 2) 153 return 0; 154 if (buf[0] != 0x05 || buf[1] != 0x00) 155 { 156 verb ("V: proxy5: auth error %02x %02x", buf[0], buf[1]); 157 return 0; 158 } 159 /* 160 * Connect packet layout: 161 * 1b: version 162 * 1b: command (0x01 is connect) 163 * 1b: reserved, 0x00 164 * 1b: addr type (0x03 is domain name) 165 * nb: addr len (1b) + addr bytes, no null termination 166 * 2b: port, network byte order 167 */ 168 buf[0] = 0x05; 169 buf[1] = 0x01; 170 buf[2] = 0x00; 171 buf[3] = 0x03; 172 buf[4] = strlen (ctx->host); 173 sz += 5; 174 memcpy (buf + 5, ctx->host, strlen (ctx->host)); 175 sz += strlen (ctx->host); 176 memcpy (buf + sz, &port_n, sizeof (port_n)); 177 sz += sizeof (port_n); 178 r = BIO_write (b->next_bio, buf, sz); 179 if ( -1 == r ) 180 return -1; 181 if ( (size_t) r != sz) 182 return 0; 183 /* 184 * Server's response: 185 * 1b: version 186 * 1b: status (0x00 is okay) 187 * 1b: reserved, 0x00 188 * 1b: addr type (0x03 is domain name, 0x01 ipv4) 189 * nb: addr len (1b) + addr bytes, no null termination 190 * 2b: port, network byte order 191 */ 192 /* grab up through the addr type */ 193 r = BIO_read (b->next_bio, buf, 4); 194 if ( -1 == r ) 195 return -1; 196 if (r != 4) 197 return 0; 198 if (buf[0] != 0x05 || buf[1] != 0x00) 199 { 200 verb ("V: proxy5: connect error %02x %02x", buf[0], buf[1]); 201 return 0; 202 } 203 if (buf[3] == 0x03) 204 { 205 unsigned int len; 206 r = BIO_read (b->next_bio, buf + 4, 1); 207 if (r != 1) 208 return 0; 209 /* host (buf[4] bytes) + port (2 bytes) */ 210 len = buf[4] + 2; 211 while (len) 212 { 213 r = BIO_read (b->next_bio, buf + 5, min (len, sizeof (buf))); 214 if (r <= 0) 215 return 0; 216 len -= min (len, r); 217 } 218 } 219 else if (buf[3] == 0x01) 220 { 221 /* 4 bytes ipv4 addr, 2 bytes port */ 222 r = BIO_read (b->next_bio, buf + 4, 6); 223 if (r != 6) 224 return 0; 225 } 226 verb ("V: proxy5: connected"); 227 ctx->connected = 1; 228 return 1; 229 } 230 231 /* SSL socket BIOs don't support BIO_gets, so... */ 232 int sock_gets (BIO *b, char *buf, size_t sz) 233 { 234 char c; 235 while (BIO_read (b, &c, 1) > 0 && sz > 1) 236 { 237 *buf++ = c; 238 sz--; 239 if (c == '\n') 240 { 241 *buf = '\0'; 242 return 0; 243 } 244 } 245 return 1; 246 } 247 248 int http_connect (BIO *b) 249 { 250 int r; 251 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 252 char buf[4096]; 253 int retcode; 254 snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.1\r\n", 255 ctx->host, ctx->port); 256 r = BIO_write (b->next_bio, buf, strlen (buf)); 257 if ( -1 == r ) 258 return -1; 259 if ( (size_t) r != strlen(buf)) 260 return 0; 261 /* required by RFC 2616 14.23 */ 262 snprintf (buf, sizeof (buf), "Host: %s:%d\r\n", ctx->host, ctx->port); 263 r = BIO_write (b->next_bio, buf, strlen (buf)); 264 if ( -1 == r ) 265 return -1; 266 if ( (size_t) r != strlen(buf)) 267 return 0; 268 strcpy (buf, "\r\n"); 269 r = BIO_write (b->next_bio, buf, strlen (buf)); 270 if ( -1 == r ) 271 return -1; 272 if ( (size_t) r != strlen(buf)) 273 return 0; 274 r = sock_gets (b->next_bio, buf, sizeof (buf)); 275 if (r) 276 return 0; 277 /* use %*s to ignore the version */ 278 if (sscanf (buf, "HTTP/%*s %d", &retcode) != 1) 279 return 0; 280 if (retcode < 200 || retcode > 299) 281 return 0; 282 while (! (r = sock_gets (b->next_bio, buf, sizeof (buf)))) 283 { 284 if (!strcmp (buf, "\r\n")) 285 { 286 /* Done with the header */ 287 ctx->connected = 1; 288 return 1; 289 } 290 } 291 return 0; 292 } 293 294 int proxy_write (BIO *b, const char *buf, int sz) 295 { 296 int r; 297 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 298 299 assert (buf); 300 if (sz <= 0) 301 return 0; 302 if (!b->next_bio) 303 return 0; 304 if (!ctx->connected) 305 { 306 assert (ctx->connect); 307 if (!ctx->connect (b)) 308 return 0; 309 } 310 r = BIO_write (b->next_bio, buf, sz); 311 BIO_clear_retry_flags (b); 312 BIO_copy_next_retry (b); 313 return r; 314 } 315 316 int proxy_read (BIO *b, char *buf, int sz) 317 { 318 int r; 319 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 320 321 assert (buf); 322 if (!b->next_bio) 323 return 0; 324 if (!ctx->connected) 325 { 326 assert (ctx->connect); 327 if (!ctx->connect (b)) 328 return 0; 329 } 330 r = BIO_read (b->next_bio, buf, sz); 331 BIO_clear_retry_flags (b); 332 BIO_copy_next_retry (b); 333 return r; 334 } 335 336 long proxy_ctrl (BIO *b, int cmd, long num, void *ptr) 337 { 338 long ret; 339 struct proxy_ctx *ctx; 340 if (!b->next_bio) 341 return 0; 342 ctx = (struct proxy_ctx *) b->ptr; 343 assert (ctx); 344 switch (cmd) 345 { 346 case BIO_C_DO_STATE_MACHINE: 347 BIO_clear_retry_flags (b); 348 ret = BIO_ctrl (b->next_bio, cmd, num, ptr); 349 BIO_copy_next_retry (b); 350 break; 351 #if defined(BIO_CTRL_DUP) 352 case BIO_CTRL_DUP: 353 ret = 0; 354 break; 355 #endif /* BIO_CTRL_DUP */ 356 default: 357 ret = BIO_ctrl (b->next_bio, cmd, num, ptr); 358 } 359 return ret; 360 } 361 362 int proxy_gets (BIO *b, char *buf, int size) 363 { 364 return BIO_gets (b->next_bio, buf, size); 365 } 366 367 int proxy_puts (BIO *b, const char *str) 368 { 369 return BIO_puts (b->next_bio, str); 370 } 371 372 long proxy_callback_ctrl (BIO *b, int cmd, bio_info_cb fp) 373 { 374 if (!b->next_bio) 375 return 0; 376 return BIO_callback_ctrl (b->next_bio, cmd, fp); 377 } 378 379 BIO_METHOD proxy_methods = 380 { 381 BIO_TYPE_MEM, 382 "proxy", 383 proxy_write, 384 proxy_read, 385 proxy_puts, 386 proxy_gets, 387 proxy_ctrl, 388 proxy_new, 389 proxy_free, 390 proxy_callback_ctrl, 391 }; 392 393 BIO_METHOD *BIO_f_proxy() 394 { 395 return &proxy_methods; 396 } 397 398 /* API starts here */ 399 400 BIO API *BIO_new_proxy() 401 { 402 return BIO_new (BIO_f_proxy()); 403 } 404 405 int API BIO_proxy_set_type (BIO *b, const char *type) 406 { 407 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 408 if (!strcmp (type, "socks5")) 409 ctx->connect = socks5_connect; 410 else if (!strcmp (type, "socks4a")) 411 ctx->connect = socks4a_connect; 412 else if (!strcmp (type, "http")) 413 ctx->connect = http_connect; 414 else 415 return 1; 416 return 0; 417 } 418 419 int API BIO_proxy_set_host (BIO *b, const char *host) 420 { 421 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 422 if (strnlen (host, NI_MAXHOST) == NI_MAXHOST) 423 return 1; 424 ctx->host = strdup (host); 425 return 0; 426 } 427 428 void API BIO_proxy_set_port (BIO *b, uint16_t port) 429 { 430 struct proxy_ctx *ctx = (struct proxy_ctx *) b->ptr; 431 ctx->port = port; 432 } 433