1 /*
2  * proxy-bio-unittest.c - proxy-bio unit tests
3  * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #if defined(__linux__)
9 #include <alloca.h>
10 #endif
11 
12 #include "src/proxy-bio.h"
13 #include "src/test-bio.h"
14 #include "src/test_harness.h"
15 #include "src/tlsdate.h"
16 
FIXTURE(test_bio)17 FIXTURE (test_bio)
18 {
19   BIO *test;
20 };
21 
FIXTURE_SETUP(test_bio)22 FIXTURE_SETUP (test_bio)
23 {
24   self->test = BIO_new_test();
25   ASSERT_NE (NULL, self->test);
26 }
27 
FIXTURE_TEARDOWN(test_bio)28 FIXTURE_TEARDOWN (test_bio)
29 {
30   BIO_free (self->test);
31 }
32 
proxy_bio(BIO * test,const char * type)33 BIO *proxy_bio (BIO *test, const char *type)
34 {
35   BIO *proxy = BIO_new_proxy();
36   BIO_proxy_set_type (proxy, type);
37   BIO_proxy_set_host (proxy, kTestHost);
38   BIO_proxy_set_port (proxy, TEST_PORT);
39   BIO_push (proxy, test);
40   return proxy;
41 }
42 
need_out_bytes(BIO * test,const unsigned char * out,size_t sz)43 int need_out_bytes (BIO *test, const unsigned char *out, size_t sz)
44 {
45   unsigned char *buf = malloc (sz);
46   size_t i;
47   int result;
48   if (!buf)
49     return 1;
50   if (BIO_test_output_left (test) <  sz)
51     {
52       fprintf (TH_LOG_STREAM, "not enough output: %d < %d\n",
53                (int) BIO_test_output_left (test), (int) sz);
54       free (buf);
55       return 2;
56     }
57   if (BIO_test_get_output (test, buf, sz) != sz)
58     {
59       free (buf);
60       return 3;
61     }
62   if (memcmp (buf, out, sz))
63     {
64       for (i = 0; i < sz; i++)
65         {
66           if (buf[i] != out[i])
67             fprintf (TH_LOG_STREAM,
68                      "mismatch %d %02x %02x\n", (int) i,
69                      buf[i], out[i]);
70         }
71     }
72   result = memcmp (buf, out, sz);
73   free (buf);
74   return result;
75 }
76 
need_out_byte(BIO * test,unsigned char out)77 int need_out_byte (BIO *test, unsigned char out)
78 {
79   unsigned char c;
80   if (BIO_test_output_left (test) < 1)
81     return 1;
82   if (BIO_test_get_output (test, &c, 1) != 1)
83     return 2;
84   return c != out;
85 }
86 
get_bytes(BIO * test,unsigned char * buf,size_t sz)87 int get_bytes (BIO *test, unsigned char *buf, size_t sz)
88 {
89   return BIO_test_get_output (test, buf, sz);
90 }
91 
put_bytes(BIO * test,const unsigned char * buf,size_t sz)92 void put_bytes (BIO *test, const unsigned char *buf, size_t sz)
93 {
94   BIO_test_add_input (test, buf, sz);
95 }
96 
put_byte(BIO * test,char c)97 void put_byte (BIO *test, char c)
98 {
99   BIO_test_add_input (test, (unsigned char *) &c, 1);
100 }
101 
102 unsigned const char kSocks4ARequest[] =
103 {
104   0x04, /* socks4 */
105   0x01, /* tcp stream */
106   (TEST_PORT & 0xff00) >> 8,
107   TEST_PORT & 0xff,
108   0x00, 0x00, 0x00, 0x01, /* bogus IP */
109   0x00, /* userid */
110   TEST_HOST, 0x00 /* null-terminated host */
111 };
112 
TEST_F(test_bio,socks4a_success)113 TEST_F (test_bio, socks4a_success)
114 {
115   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
116   unsigned const char kReply[] =
117   {
118     0x00, /* null byte */
119     0x5a, /* success */
120     (TEST_PORT & 0xff00) >> 8,  /* port high */
121     TEST_PORT & 0xff, /* port low */
122     0x00, 0x00, 0x00, 0x00  /* bogus IP */
123   };
124   BIO *proxy = proxy_bio (self->test, "socks4a");
125   put_bytes (self->test, kReply, sizeof (kReply));
126   EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
127   EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest,
128                                 sizeof (kSocks4ARequest)));
129   EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
130                                 sizeof (kTestInput)));
131   EXPECT_EQ (0U, BIO_test_output_left (self->test));
132 }
133 
TEST_F(test_bio,socks4a_fail)134 TEST_F (test_bio, socks4a_fail)
135 {
136   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
137   unsigned const char kReply[] =
138   {
139     0x00, /* null byte */
140     0x5b, /* fail */
141     (TEST_PORT & 0xff00) >> 8,  /* port high */
142     TEST_PORT & 0xff, /* port low */
143     0x00, 0x00, 0x00, 0x00  /* bogus IP */
144   };
145   BIO *proxy = proxy_bio (self->test, "socks4a");
146   put_bytes (self->test, kReply, sizeof (kReply));
147   EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
148   EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest,
149                                 sizeof (kSocks4ARequest)));
150   /* We shouldn't have written any payload */
151   EXPECT_EQ (0U, BIO_test_output_left (self->test));
152 }
153 
154 unsigned const char kSocks5AuthRequest[] =
155 {
156   0x05, /* socks5 */
157   0x01, /* one auth method */
158   0x00  /* no auth */
159 };
160 
161 unsigned const char kSocks5AuthReply[] =
162 {
163   0x05, /* socks5 */
164   0x00, /* no auth */
165 };
166 
167 unsigned const char kSocks5ConnectRequest[] =
168 {
169   0x05, /* socks5 */
170   0x01, /* tcp stream */
171   0x00, /* reserved 0x00 */
172   0x03, /* domain name */
173   TEST_HOST_SIZE, /* hostname with length prefix */
174   TEST_HOST,
175   (TEST_PORT & 0xff00) >> 8,
176   TEST_PORT & 0xff
177 };
178 
179 unsigned const char kSocks5ConnectReply[] =
180 {
181   0x05, /* socks5 */
182   0x00, /* success */
183   0x00, /* reserved 0x00 */
184   0x03, /* domain name */
185   TEST_HOST_SIZE, /* hostname with length prefix */
186   TEST_HOST,
187   (TEST_PORT & 0xff00) >> 8,
188   TEST_PORT & 0xff
189 };
190 
TEST_F(test_bio,socks5_success)191 TEST_F (test_bio, socks5_success)
192 {
193   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
194   BIO *proxy = proxy_bio (self->test, "socks5");
195   put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply));
196   put_bytes (self->test, kSocks5ConnectReply, sizeof (kSocks5ConnectReply));
197   EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
198   EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
199                                 sizeof (kSocks5AuthRequest)));
200   EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest,
201                                 sizeof (kSocks5ConnectRequest)));
202   EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
203                                 sizeof (kTestInput)));
204   EXPECT_EQ (0U, BIO_test_output_left (self->test));
205 }
206 
TEST_F(test_bio,socks5_auth_fail)207 TEST_F (test_bio, socks5_auth_fail)
208 {
209   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
210   unsigned const char kAuthFail[] =
211   {
212     0x05,
213     0xff,
214   };
215   BIO *proxy = proxy_bio (self->test, "socks5");
216   put_bytes (self->test, kAuthFail, sizeof (kAuthFail));
217   EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
218   EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
219                                 sizeof (kSocks5AuthRequest)));
220   EXPECT_EQ (0U, BIO_test_output_left (self->test));
221 }
222 
TEST_F(test_bio,socks5_connect_fail)223 TEST_F (test_bio, socks5_connect_fail)
224 {
225   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
226   unsigned const char kConnectFail[] =
227   {
228     0x05,
229     0x01,
230     0x00,
231     0x03,
232     TEST_HOST_SIZE,
233     TEST_HOST,
234     (TEST_PORT & 0xff00) >> 8,
235     TEST_PORT & 0xff
236   };
237   BIO *proxy = proxy_bio (self->test, "socks5");
238   put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply));
239   put_bytes (self->test, kConnectFail, sizeof (kConnectFail));
240   EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
241   EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
242                                 sizeof (kSocks5AuthRequest)));
243   EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest,
244                                 sizeof (kSocks5ConnectRequest)));
245   EXPECT_EQ (0U, BIO_test_output_left (self->test));
246 }
247 
TEST_F(test_bio,http_success)248 TEST_F (test_bio, http_success)
249 {
250   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
251   BIO *proxy = proxy_bio (self->test, "http");
252   char kConnectRequest[1024];
253   char kConnectResponse[] = "HTTP/1.0 200 OK\r\n"
254                             "Uninteresting-Header: foobar\r\n"
255                             "Another-Header: lol\r\n"
256                             "\r\n";
257   snprintf (kConnectRequest, sizeof (kConnectRequest),
258             "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
259             kTestHost, TEST_PORT, kTestHost, TEST_PORT);
260   put_bytes (self->test, (unsigned char *) kConnectResponse,
261              strlen (kConnectResponse));
262   EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
263   EXPECT_EQ (0, need_out_bytes (self->test,
264                                 (unsigned char *) kConnectRequest,
265                                 strlen (kConnectRequest)));
266   EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
267                                 sizeof (kTestInput)));
268   EXPECT_EQ (0U, BIO_test_output_left (self->test));
269 }
270 
TEST_F(test_bio,http_error)271 TEST_F (test_bio, http_error)
272 {
273   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
274   BIO *proxy = proxy_bio (self->test, "http");
275   char kConnectRequest[1024];
276   char kConnectResponse[] = "HTTP/1.0 403 NO U\r\n"
277                             "Uninteresting-Header: foobar\r\n"
278                             "Another-Header: lol\r\n"
279                             "\r\n";
280   snprintf (kConnectRequest, sizeof (kConnectRequest),
281             "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
282             kTestHost, TEST_PORT, kTestHost, TEST_PORT);
283   put_bytes (self->test, (unsigned char *) kConnectResponse,
284              strlen (kConnectResponse));
285   EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
286   EXPECT_EQ (0, need_out_bytes (self->test,
287                                 (unsigned char *) kConnectRequest,
288                                 strlen (kConnectRequest)));
289   EXPECT_EQ (0U, BIO_test_output_left (self->test));
290 }
291 
292 TEST_HARNESS_MAIN
293