1 /*-
2 * SSLsplit - transparent SSL/TLS interception
3 * https://www.roe.ch/SSLsplit
4 *
5 * Copyright (c) 2009-2019, Daniel Roethlisberger <daniel@roe.ch>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "proxy.h"
30
31 #include "prototcp.h"
32 #include "privsep.h"
33 #include "pxythrmgr.h"
34 #include "pxyconn.h"
35 #include "opts.h"
36 #include "log.h"
37 #include "attrib.h"
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <signal.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <errno.h>
47
48 #include <event2/event.h>
49 #include <event2/listener.h>
50 #include <event2/bufferevent.h>
51 #include <event2/bufferevent_ssl.h>
52 #include <event2/buffer.h>
53 #include <event2/thread.h>
54
55 /*
56 * Proxy engine, built around libevent 2.x.
57 */
58
59 static int signals[] = { SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1 };
60
61 struct proxy_ctx {
62 pxy_thrmgr_ctx_t *thrmgr;
63 struct event_base *evbase;
64 struct event *sev[sizeof(signals)/sizeof(int)];
65 struct proxy_listener_ctx *lctx;
66 opts_t *opts;
67 };
68
69 static proxy_listener_ctx_t * MALLOC
proxy_listener_ctx_new(pxy_thrmgr_ctx_t * thrmgr,proxyspec_t * spec,opts_t * opts)70 proxy_listener_ctx_new(pxy_thrmgr_ctx_t *thrmgr, proxyspec_t *spec,
71 opts_t *opts)
72 {
73 proxy_listener_ctx_t *ctx = malloc(sizeof(proxy_listener_ctx_t));
74 if (!ctx)
75 return NULL;
76 memset(ctx, 0, sizeof(proxy_listener_ctx_t));
77 ctx->thrmgr = thrmgr;
78 ctx->spec = spec;
79 ctx->opts = opts;
80 return ctx;
81 }
82
83 static void NONNULL(1)
proxy_listener_ctx_free(proxy_listener_ctx_t * ctx)84 proxy_listener_ctx_free(proxy_listener_ctx_t *ctx)
85 {
86 if (ctx->evcl) {
87 evconnlistener_free(ctx->evcl);
88 }
89 if (ctx->next) {
90 proxy_listener_ctx_free(ctx->next);
91 }
92 free(ctx);
93 }
94
95 static protocol_t NONNULL(1)
proxy_setup_proto(pxy_conn_ctx_t * ctx)96 proxy_setup_proto(pxy_conn_ctx_t *ctx)
97 {
98 ctx->protoctx = malloc(sizeof(proto_ctx_t));
99 if (!ctx->protoctx) {
100 return PROTO_ERROR;
101 }
102 memset(ctx->protoctx, 0, sizeof(proto_ctx_t));
103
104 protocol_t proto = prototcp_setup(ctx);
105
106 if (proto == PROTO_ERROR) {
107 free(ctx->protoctx);
108 }
109 return proto;
110 }
111
112 static pxy_conn_ctx_t * MALLOC NONNULL(2,3)
proxy_conn_ctx_new(evutil_socket_t fd,pxy_thrmgr_ctx_t * thrmgr,opts_t * opts)113 proxy_conn_ctx_new(evutil_socket_t fd,
114 pxy_thrmgr_ctx_t *thrmgr, opts_t *opts)
115 {
116 log_finest_main_va("ENTER, fd=%d", fd);
117
118 pxy_conn_ctx_t *ctx = malloc(sizeof(pxy_conn_ctx_t));
119 if (!ctx) {
120 return NULL;
121 }
122 memset(ctx, 0, sizeof(pxy_conn_ctx_t));
123
124 #ifdef DEBUG_PROXY
125 ctx->id = thrmgr->conn_count++;
126 #endif /* DEBUG_PROXY */
127 ctx->fd = fd;
128 ctx->thrmgr = thrmgr;
129
130 ctx->proto = proxy_setup_proto(ctx);
131 if (ctx->proto == PROTO_ERROR) {
132 free(ctx);
133 return NULL;
134 }
135
136 ctx->opts = opts;
137
138 log_finest("Created new conn");
139 return ctx;
140 }
141
142 /*
143 * Does minimal clean-up, called on error by proxy_listener_acceptcb() only.
144 * We call this function instead of pxy_conn_ctx_free(), because
145 * proxy_listener_acceptcb() runs on thrmgr, whereas pxy_conn_ctx_free()
146 * runs on conn handling thr. This is necessary to prevent multithreading issues.
147 */
148 static void NONNULL(1)
proxy_conn_ctx_free(pxy_conn_ctx_t * ctx)149 proxy_conn_ctx_free(pxy_conn_ctx_t *ctx)
150 {
151 log_finest("ENTER");
152
153 if (ctx->ev) {
154 event_free(ctx->ev);
155 }
156 free(ctx->protoctx);
157 free(ctx);
158 }
159
160 /*
161 * Callback for accept events on the socket listener bufferevent.
162 * Called when a new incoming connection has been accepted.
163 * Initiates the connection to the server. The incoming connection
164 * from the client is not being activated until we have a successful
165 * connection to the server, because we need the server's certificate
166 * in order to set up the SSL session to the client.
167 * For consistency, plain TCP works the same way, even if we could
168 * start reading from the client while waiting on the connection to
169 * the server to connect.
170 */
171 static void
proxy_listener_acceptcb(UNUSED struct evconnlistener * listener,evutil_socket_t fd,struct sockaddr * peeraddr,int peeraddrlen,void * arg)172 proxy_listener_acceptcb(UNUSED struct evconnlistener *listener,
173 evutil_socket_t fd,
174 struct sockaddr *peeraddr, int peeraddrlen,
175 void *arg)
176 {
177 proxy_listener_ctx_t *lctx = arg;
178 log_finest_main_va("ENTER, fd=%d", fd);
179
180 /* create per connection state */
181 pxy_conn_ctx_t *ctx = proxy_conn_ctx_new(fd, lctx->thrmgr, lctx->opts);
182 if (!ctx) {
183 log_err_level_printf(LOG_CRIT, "Error allocating memory\n");
184 evutil_closesocket(fd);
185 return;
186 }
187
188 // Choose the conn handling thr
189 pxy_thrmgr_assign_thr(ctx);
190
191 ctx->srcaddrlen = peeraddrlen;
192 memcpy(&ctx->srcaddr, peeraddr, ctx->srcaddrlen);
193
194 // Switch from thrmgr to connection handling thread, i.e. change the event base, asap
195 // This prevents possible multithreading issues between thrmgr and conn handling threads
196 ctx->ev = event_new(ctx->thr->evbase, -1, 0, prototcp_connect, ctx);
197 if (!ctx->ev) {
198 log_err_level(LOG_CRIT, "Error creating connect event, aborting connection");
199 goto out;
200 }
201 // The only purpose of this event is to change the event base, so it is a one-shot event
202 if (event_add(ctx->ev, NULL) == -1)
203 goto out;
204 event_active(ctx->ev, 0, 0);
205 return;
206 out:
207 evutil_closesocket(fd);
208 proxy_conn_ctx_free(ctx);
209 }
210
211 /*
212 * Callback for error events on the socket listener bufferevent.
213 */
214 void
proxy_listener_errorcb(struct evconnlistener * listener,UNUSED void * arg)215 proxy_listener_errorcb(struct evconnlistener *listener, UNUSED void *arg)
216 {
217 struct event_base *evbase = evconnlistener_get_base(listener);
218 int err = EVUTIL_SOCKET_ERROR();
219 log_err_level_printf(LOG_CRIT, "Error %d on listener: %s\n", err,
220 evutil_socket_error_to_string(err));
221 /* Do not break the event loop if out of fds:
222 * Too many open files (24) */
223 if (err == 24) {
224 return;
225 }
226 event_base_loopbreak(evbase);
227 }
228
229 /*
230 * Dump a description of an evbase to debugging code.
231 */
232 static void
proxy_debug_base(const struct event_base * ev_base)233 proxy_debug_base(const struct event_base *ev_base)
234 {
235 log_dbg_printf("Using libevent backend '%s'\n",
236 event_base_get_method(ev_base));
237
238 enum event_method_feature f;
239 f = event_base_get_features(ev_base);
240 log_dbg_printf("Event base supports: edge %s, O(1) %s, anyfd %s\n",
241 ((f & EV_FEATURE_ET) ? "yes" : "no"),
242 ((f & EV_FEATURE_O1) ? "yes" : "no"),
243 ((f & EV_FEATURE_FDS) ? "yes" : "no"));
244 }
245
246 /*
247 * Set up the listener for a single proxyspec and add it to evbase.
248 * Returns the proxy_listener_ctx_t pointer if successful, NULL otherwise.
249 */
250 static proxy_listener_ctx_t *
proxy_listener_setup(struct event_base * evbase,pxy_thrmgr_ctx_t * thrmgr,proxyspec_t * spec,opts_t * opts,evutil_socket_t clisock)251 proxy_listener_setup(struct event_base *evbase, pxy_thrmgr_ctx_t *thrmgr,
252 proxyspec_t *spec, opts_t *opts, evutil_socket_t clisock)
253 {
254 log_finest_main("ENTER");
255
256 int fd;
257 if ((fd = privsep_client_opensock(clisock, spec)) == -1) {
258 log_err_level_printf(LOG_CRIT, "Error opening socket: %s (%i)\n",
259 strerror(errno), errno);
260 return NULL;
261 }
262
263 proxy_listener_ctx_t *lctx = proxy_listener_ctx_new(thrmgr, spec, opts);
264 if (!lctx) {
265 log_err_level_printf(LOG_CRIT, "Error creating listener context\n");
266 evutil_closesocket(fd);
267 return NULL;
268 }
269
270 // @attention Do not pass NULL as user-supplied pointer
271 lctx->evcl = evconnlistener_new(evbase, proxy_listener_acceptcb,
272 lctx, LEV_OPT_CLOSE_ON_FREE, 1024, fd);
273 if (!lctx->evcl) {
274 log_err_level_printf(LOG_CRIT, "Error creating evconnlistener: %s\n",
275 strerror(errno));
276 proxy_listener_ctx_free(lctx);
277 evutil_closesocket(fd);
278 return NULL;
279 }
280 evconnlistener_set_error_cb(lctx->evcl, proxy_listener_errorcb);
281 return lctx;
282 }
283
284 /*
285 * Signal handler for SIGTERM, SIGQUIT, SIGINT, SIGHUP, SIGPIPE and SIGUSR1.
286 */
287 static void
proxy_signal_cb(evutil_socket_t fd,UNUSED short what,void * arg)288 proxy_signal_cb(evutil_socket_t fd, UNUSED short what, void *arg)
289 {
290 proxy_ctx_t *ctx = arg;
291
292 if (OPTS_DEBUG(ctx->opts)) {
293 log_dbg_printf("Received signal %i\n", fd);
294 }
295
296 switch(fd) {
297 case SIGTERM:
298 case SIGQUIT:
299 case SIGINT:
300 proxy_loopbreak(ctx);
301 break;
302 case SIGHUP:
303 case SIGUSR1:
304 if (log_reopen() == -1) {
305 log_err_level_printf(LOG_WARNING, "Failed to reopen logs\n");
306 } else {
307 log_dbg_printf("Reopened log files\n");
308 }
309 break;
310 case SIGPIPE:
311 log_err_level_printf(LOG_WARNING, "Received SIGPIPE; ignoring.\n");
312 break;
313 default:
314 log_err_level_printf(LOG_WARNING, "Received unexpected signal %i\n", fd);
315 break;
316 }
317 }
318
319 /*
320 * Set up the core event loop.
321 * Socket clisock is the privsep client socket used for binding to ports.
322 * Returns ctx on success, or NULL on error.
323 */
324 proxy_ctx_t *
proxy_new(opts_t * opts,int clisock)325 proxy_new(opts_t *opts, int clisock)
326 {
327 proxy_listener_ctx_t *head;
328 proxy_ctx_t *ctx;
329
330 /* adds locking, only required if accessed from separate threads */
331 evthread_use_pthreads();
332
333 #ifndef PURIFY
334 if (OPTS_DEBUG(opts)) {
335 event_enable_debug_mode();
336 }
337 #endif /* PURIFY */
338
339 ctx = malloc(sizeof(proxy_ctx_t));
340 if (!ctx) {
341 log_err_level_printf(LOG_CRIT, "Error allocating memory\n");
342 goto leave0;
343 }
344 memset(ctx, 0, sizeof(proxy_ctx_t));
345
346 ctx->opts = opts;
347 ctx->evbase = event_base_new();
348 if (!ctx->evbase) {
349 log_err_level_printf(LOG_CRIT, "Error getting event base\n");
350 goto leave1;
351 }
352
353 if (OPTS_DEBUG(opts)) {
354 proxy_debug_base(ctx->evbase);
355 }
356
357 ctx->thrmgr = pxy_thrmgr_new(opts);
358 if (!ctx->thrmgr) {
359 log_err_level_printf(LOG_CRIT, "Error creating thread manager\n");
360 goto leave1b;
361 }
362
363 head = ctx->lctx = NULL;
364 for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) {
365 head = proxy_listener_setup(ctx->evbase, ctx->thrmgr,
366 spec, opts, clisock);
367 if (!head)
368 goto leave2;
369 head->next = ctx->lctx;
370 ctx->lctx = head;
371
372 char *specstr = proxyspec_str(spec);
373 if (!specstr) {
374 fprintf(stderr, "out of memory\n");
375 exit(EXIT_FAILURE);
376 }
377 log_dbg_printf("proxy_listener_setup: %s\n", specstr);
378 free(specstr);
379 }
380
381 for (size_t i = 0; i < (sizeof(signals) / sizeof(int)); i++) {
382 ctx->sev[i] = evsignal_new(ctx->evbase, signals[i],
383 proxy_signal_cb, ctx);
384 if (!ctx->sev[i])
385 goto leave3;
386 evsignal_add(ctx->sev[i], NULL);
387 }
388
389 privsep_client_close(clisock);
390 return ctx;
391
392 leave3:
393 for (size_t i = 0; i < (sizeof(ctx->sev) / sizeof(ctx->sev[0])); i++) {
394 if (ctx->sev[i]) {
395 event_free(ctx->sev[i]);
396 }
397 }
398 leave2:
399 if (ctx->lctx) {
400 proxy_listener_ctx_free(ctx->lctx);
401 }
402 pxy_thrmgr_free(ctx->thrmgr);
403 leave1b:
404 event_base_free(ctx->evbase);
405 leave1:
406 free(ctx);
407 leave0:
408 return NULL;
409 }
410
411 /*
412 * Run the event loop. Returns when the event loop is canceled by a signal
413 * or on failure.
414 */
415 void
proxy_run(proxy_ctx_t * ctx)416 proxy_run(proxy_ctx_t *ctx)
417 {
418 if (ctx->opts->detach) {
419 event_reinit(ctx->evbase);
420 }
421 #ifndef PURIFY
422 if (OPTS_DEBUG(ctx->opts)) {
423 event_base_dump_events(ctx->evbase, stderr);
424 }
425 #endif /* PURIFY */
426 if (pxy_thrmgr_run(ctx->thrmgr) == -1) {
427 log_err_level_printf(LOG_CRIT, "Failed to start thread manager\n");
428 return;
429 }
430 if (OPTS_DEBUG(ctx->opts)) {
431 log_dbg_printf("Starting main event loop.\n");
432 }
433 event_base_dispatch(ctx->evbase);
434 if (OPTS_DEBUG(ctx->opts)) {
435 log_dbg_printf("Main event loop stopped.\n");
436 }
437 }
438
439 /*
440 * Break the loop of the proxy, causing the proxy_run to return.
441 */
442 void
proxy_loopbreak(proxy_ctx_t * ctx)443 proxy_loopbreak(proxy_ctx_t *ctx)
444 {
445 event_base_loopbreak(ctx->evbase);
446 }
447
448 /*
449 * Free the proxy data structures.
450 */
451 void
proxy_free(proxy_ctx_t * ctx)452 proxy_free(proxy_ctx_t *ctx)
453 {
454 if (ctx->lctx) {
455 proxy_listener_ctx_free(ctx->lctx);
456 }
457 for (size_t i = 0; i < (sizeof(ctx->sev) / sizeof(ctx->sev[0])); i++) {
458 if (ctx->sev[i]) {
459 event_free(ctx->sev[i]);
460 }
461 }
462 if (ctx->thrmgr) {
463 pxy_thrmgr_free(ctx->thrmgr);
464 }
465 if (ctx->evbase) {
466 event_base_free(ctx->evbase);
467 }
468 free(ctx);
469 }
470
471 /* vim: set noet ft=c: */
472