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