| /* |
| * proxy-bio-unittest.c - proxy-bio unit tests |
| * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #if defined(__linux__) |
| #include <alloca.h> |
| #endif |
| |
| #include "src/proxy-bio.h" |
| #include "src/test-bio.h" |
| #include "src/test_harness.h" |
| #include "src/tlsdate.h" |
| |
| FIXTURE (test_bio) |
| { |
| BIO *test; |
| }; |
| |
| FIXTURE_SETUP (test_bio) |
| { |
| self->test = BIO_new_test(); |
| ASSERT_NE (NULL, self->test); |
| } |
| |
| FIXTURE_TEARDOWN (test_bio) |
| { |
| BIO_free (self->test); |
| } |
| |
| BIO *proxy_bio (BIO *test, const char *type) |
| { |
| BIO *proxy = BIO_new_proxy(); |
| BIO_proxy_set_type (proxy, type); |
| BIO_proxy_set_host (proxy, kTestHost); |
| BIO_proxy_set_port (proxy, TEST_PORT); |
| BIO_push (proxy, test); |
| return proxy; |
| } |
| |
| int need_out_bytes (BIO *test, const unsigned char *out, size_t sz) |
| { |
| unsigned char *buf = malloc (sz); |
| size_t i; |
| int result; |
| if (!buf) |
| return 1; |
| if (BIO_test_output_left (test) < sz) |
| { |
| fprintf (TH_LOG_STREAM, "not enough output: %d < %d\n", |
| (int) BIO_test_output_left (test), (int) sz); |
| free (buf); |
| return 2; |
| } |
| if (BIO_test_get_output (test, buf, sz) != sz) |
| { |
| free (buf); |
| return 3; |
| } |
| if (memcmp (buf, out, sz)) |
| { |
| for (i = 0; i < sz; i++) |
| { |
| if (buf[i] != out[i]) |
| fprintf (TH_LOG_STREAM, |
| "mismatch %d %02x %02x\n", (int) i, |
| buf[i], out[i]); |
| } |
| } |
| result = memcmp (buf, out, sz); |
| free (buf); |
| return result; |
| } |
| |
| int need_out_byte (BIO *test, unsigned char out) |
| { |
| unsigned char c; |
| if (BIO_test_output_left (test) < 1) |
| return 1; |
| if (BIO_test_get_output (test, &c, 1) != 1) |
| return 2; |
| return c != out; |
| } |
| |
| int get_bytes (BIO *test, unsigned char *buf, size_t sz) |
| { |
| return BIO_test_get_output (test, buf, sz); |
| } |
| |
| void put_bytes (BIO *test, const unsigned char *buf, size_t sz) |
| { |
| BIO_test_add_input (test, buf, sz); |
| } |
| |
| void put_byte (BIO *test, char c) |
| { |
| BIO_test_add_input (test, (unsigned char *) &c, 1); |
| } |
| |
| unsigned const char kSocks4ARequest[] = |
| { |
| 0x04, /* socks4 */ |
| 0x01, /* tcp stream */ |
| (TEST_PORT & 0xff00) >> 8, |
| TEST_PORT & 0xff, |
| 0x00, 0x00, 0x00, 0x01, /* bogus IP */ |
| 0x00, /* userid */ |
| TEST_HOST, 0x00 /* null-terminated host */ |
| }; |
| |
| TEST_F (test_bio, socks4a_success) |
| { |
| unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef }; |
| unsigned const char kReply[] = |
| { |
| 0x00, /* null byte */ |
| 0x5a, /* success */ |
| (TEST_PORT & 0xff00) >> 8, /* port high */ |
| TEST_PORT & 0xff, /* port low */ |
| 0x00, 0x00, 0x00, 0x00 /* bogus IP */ |
| }; |
| BIO *proxy = proxy_bio (self->test, "socks4a"); |
| put_bytes (self->test, kReply, sizeof (kReply)); |
| EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest, |
| sizeof (kSocks4ARequest))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kTestInput, |
| sizeof (kTestInput))); |
| EXPECT_EQ (0U, BIO_test_output_left (self->test)); |
| } |
| |
| TEST_F (test_bio, socks4a_fail) |
| { |
| unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef }; |
| unsigned const char kReply[] = |
| { |
| 0x00, /* null byte */ |
| 0x5b, /* fail */ |
| (TEST_PORT & 0xff00) >> 8, /* port high */ |
| TEST_PORT & 0xff, /* port low */ |
| 0x00, 0x00, 0x00, 0x00 /* bogus IP */ |
| }; |
| BIO *proxy = proxy_bio (self->test, "socks4a"); |
| put_bytes (self->test, kReply, sizeof (kReply)); |
| EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest, |
| sizeof (kSocks4ARequest))); |
| /* We shouldn't have written any payload */ |
| EXPECT_EQ (0U, BIO_test_output_left (self->test)); |
| } |
| |
| unsigned const char kSocks5AuthRequest[] = |
| { |
| 0x05, /* socks5 */ |
| 0x01, /* one auth method */ |
| 0x00 /* no auth */ |
| }; |
| |
| unsigned const char kSocks5AuthReply[] = |
| { |
| 0x05, /* socks5 */ |
| 0x00, /* no auth */ |
| }; |
| |
| unsigned const char kSocks5ConnectRequest[] = |
| { |
| 0x05, /* socks5 */ |
| 0x01, /* tcp stream */ |
| 0x00, /* reserved 0x00 */ |
| 0x03, /* domain name */ |
| TEST_HOST_SIZE, /* hostname with length prefix */ |
| TEST_HOST, |
| (TEST_PORT & 0xff00) >> 8, |
| TEST_PORT & 0xff |
| }; |
| |
| unsigned const char kSocks5ConnectReply[] = |
| { |
| 0x05, /* socks5 */ |
| 0x00, /* success */ |
| 0x00, /* reserved 0x00 */ |
| 0x03, /* domain name */ |
| TEST_HOST_SIZE, /* hostname with length prefix */ |
| TEST_HOST, |
| (TEST_PORT & 0xff00) >> 8, |
| TEST_PORT & 0xff |
| }; |
| |
| TEST_F (test_bio, socks5_success) |
| { |
| unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef }; |
| BIO *proxy = proxy_bio (self->test, "socks5"); |
| put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply)); |
| put_bytes (self->test, kSocks5ConnectReply, sizeof (kSocks5ConnectReply)); |
| EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest, |
| sizeof (kSocks5AuthRequest))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest, |
| sizeof (kSocks5ConnectRequest))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kTestInput, |
| sizeof (kTestInput))); |
| EXPECT_EQ (0U, BIO_test_output_left (self->test)); |
| } |
| |
| TEST_F (test_bio, socks5_auth_fail) |
| { |
| unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef }; |
| unsigned const char kAuthFail[] = |
| { |
| 0x05, |
| 0xff, |
| }; |
| BIO *proxy = proxy_bio (self->test, "socks5"); |
| put_bytes (self->test, kAuthFail, sizeof (kAuthFail)); |
| EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest, |
| sizeof (kSocks5AuthRequest))); |
| EXPECT_EQ (0U, BIO_test_output_left (self->test)); |
| } |
| |
| TEST_F (test_bio, socks5_connect_fail) |
| { |
| unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef }; |
| unsigned const char kConnectFail[] = |
| { |
| 0x05, |
| 0x01, |
| 0x00, |
| 0x03, |
| TEST_HOST_SIZE, |
| TEST_HOST, |
| (TEST_PORT & 0xff00) >> 8, |
| TEST_PORT & 0xff |
| }; |
| BIO *proxy = proxy_bio (self->test, "socks5"); |
| put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply)); |
| put_bytes (self->test, kConnectFail, sizeof (kConnectFail)); |
| EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest, |
| sizeof (kSocks5AuthRequest))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest, |
| sizeof (kSocks5ConnectRequest))); |
| EXPECT_EQ (0U, BIO_test_output_left (self->test)); |
| } |
| |
| TEST_F (test_bio, http_success) |
| { |
| unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef }; |
| BIO *proxy = proxy_bio (self->test, "http"); |
| char kConnectRequest[1024]; |
| char kConnectResponse[] = "HTTP/1.0 200 OK\r\n" |
| "Uninteresting-Header: foobar\r\n" |
| "Another-Header: lol\r\n" |
| "\r\n"; |
| snprintf (kConnectRequest, sizeof (kConnectRequest), |
| "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n", |
| kTestHost, TEST_PORT, kTestHost, TEST_PORT); |
| put_bytes (self->test, (unsigned char *) kConnectResponse, |
| strlen (kConnectResponse)); |
| EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput))); |
| EXPECT_EQ (0, need_out_bytes (self->test, |
| (unsigned char *) kConnectRequest, |
| strlen (kConnectRequest))); |
| EXPECT_EQ (0, need_out_bytes (self->test, kTestInput, |
| sizeof (kTestInput))); |
| EXPECT_EQ (0U, BIO_test_output_left (self->test)); |
| } |
| |
| TEST_F (test_bio, http_error) |
| { |
| unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef }; |
| BIO *proxy = proxy_bio (self->test, "http"); |
| char kConnectRequest[1024]; |
| char kConnectResponse[] = "HTTP/1.0 403 NO U\r\n" |
| "Uninteresting-Header: foobar\r\n" |
| "Another-Header: lol\r\n" |
| "\r\n"; |
| snprintf (kConnectRequest, sizeof (kConnectRequest), |
| "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n", |
| kTestHost, TEST_PORT, kTestHost, TEST_PORT); |
| put_bytes (self->test, (unsigned char *) kConnectResponse, |
| strlen (kConnectResponse)); |
| EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput))); |
| EXPECT_EQ (0, need_out_bytes (self->test, |
| (unsigned char *) kConnectRequest, |
| strlen (kConnectRequest))); |
| EXPECT_EQ (0U, BIO_test_output_left (self->test)); |
| } |
| |
| TEST_HARNESS_MAIN |