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 * Copyright (c) 2017-2021, Soner Tari <sonertari@gmail.com>.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "pxyconn.h"
31
32 #include "prototcp.h"
33 #include "protossl.h"
34 #include "protohttp.h"
35 #include "protopop3.h"
36 #include "protosmtp.h"
37 #include "protoautossl.h"
38 #include "protopassthrough.h"
39
40 #include "privsep.h"
41 #include "sys.h"
42 #include "log.h"
43 #include "attrib.h"
44 #include "proc.h"
45 #include "util.h"
46
47 #include <string.h>
48 #include <arpa/inet.h>
49 #include <sys/param.h>
50 #include <assert.h>
51
52 #include <event2/listener.h>
53
54 #ifdef __linux__
55 #include <glob.h>
56 #endif /* __linux__ */
57
58 #include <net/if_arp.h>
59 #include <sys/ioctl.h>
60 #include <sys/socket.h>
61 #if (__linux__ && HAVE_SYSCTL) || !__linux__
62 #include <sys/sysctl.h>
63 #endif
64 #include <net/route.h>
65 #include <netinet/if_ether.h>
66 #ifdef __OpenBSD__
67 #include <net/if_dl.h>
68 #endif /* __OpenBSD__ */
69
70 /*
71 * Maximum size of data to buffer per connection direction before
72 * temporarily stopping to read data from the other end.
73 */
74 #define OUTBUF_LIMIT (128*1024)
75
76 // getdtablecount() returns int, hence we don't use size_t here
77 int descriptor_table_size = 0;
78
79 // @attention The order of names should match the order in protocol enum
80 char *protocol_names[] = {
81 // ERROR = -1
82 "PASSTHROUGH", // = 0
83 "HTTP",
84 "HTTPS",
85 "POP3",
86 "POP3S",
87 "SMTP",
88 "SMTPS",
89 "AUTOSSL",
90 "TCP",
91 "SSL",
92 };
93
94 static protocol_t NONNULL(1)
pxy_setup_proto_child(pxy_conn_child_ctx_t * ctx)95 pxy_setup_proto_child(pxy_conn_child_ctx_t *ctx)
96 {
97 ctx->protoctx = malloc(sizeof(proto_child_ctx_t));
98 if (!ctx->protoctx) {
99 return PROTO_ERROR;
100 }
101 memset(ctx->protoctx, 0, sizeof(proto_child_ctx_t));
102
103 // Default to tcp
104 prototcp_setup_child(ctx);
105
106 protocol_t proto;
107 if (ctx->conn->spec->upgrade) {
108 proto = protoautossl_setup_child(ctx);
109 } else if (ctx->conn->spec->http) {
110 if (ctx->conn->spec->ssl) {
111 proto = protohttps_setup_child(ctx);
112 } else {
113 proto = protohttp_setup_child(ctx);
114 }
115 } else if (ctx->conn->spec->pop3) {
116 if (ctx->conn->spec->ssl) {
117 proto = (protossl_setup_child(ctx) != PROTO_ERROR) ? PROTO_POP3S : PROTO_ERROR;
118 } else {
119 proto = PROTO_POP3;
120 }
121 } else if (ctx->conn->spec->smtp) {
122 if (ctx->conn->spec->ssl) {
123 proto = (protossl_setup_child(ctx) != PROTO_ERROR) ? PROTO_SMTPS : PROTO_ERROR;
124 } else {
125 proto = PROTO_SMTP;
126 }
127 } else if (ctx->conn->spec->ssl) {
128 proto = protossl_setup_child(ctx);
129 } else {
130 proto = PROTO_TCP;
131 }
132
133 if (proto == PROTO_ERROR) {
134 free(ctx->protoctx);
135 }
136 return proto;
137 }
138
139 static pxy_conn_child_ctx_t * MALLOC NONNULL(2)
pxy_conn_ctx_new_child(evutil_socket_t fd,pxy_conn_ctx_t * ctx)140 pxy_conn_ctx_new_child(evutil_socket_t fd, pxy_conn_ctx_t *ctx)
141 {
142 assert(ctx != NULL);
143
144 log_finest_va("ENTER, fd=%d", fd);
145
146 pxy_conn_child_ctx_t *child_ctx = malloc(sizeof(pxy_conn_child_ctx_t));
147 if (!child_ctx) {
148 return NULL;
149 }
150 memset(child_ctx, 0, sizeof(pxy_conn_child_ctx_t));
151
152 child_ctx->type = CONN_TYPE_CHILD;
153 #ifdef DEBUG_PROXY
154 child_ctx->id = ctx->child_count++;
155 #endif /* DEBUG_PROXY */
156 child_ctx->conn = ctx;
157 child_ctx->fd = fd;
158
159 if (pxy_setup_proto_child(child_ctx) == PROTO_ERROR) {
160 free(child_ctx);
161 return NULL;
162 }
163 return child_ctx;
164 }
165
166 static void NONNULL(1)
pxy_conn_ctx_free_child(pxy_conn_child_ctx_t * ctx)167 pxy_conn_ctx_free_child(pxy_conn_child_ctx_t *ctx)
168 {
169 log_finest("ENTER");
170
171 // If the proto doesn't have special args, proto_free() callback is NULL
172 if (ctx->protoctx->proto_free) {
173 ctx->protoctx->proto_free(ctx);
174 }
175 free(ctx->protoctx);
176 free(ctx);
177 }
178
179 // This function cannot fail.
180 static void NONNULL(1)
pxy_conn_attach_child(pxy_conn_child_ctx_t * ctx)181 pxy_conn_attach_child(pxy_conn_child_ctx_t *ctx)
182 {
183 log_finest("Adding child conn");
184
185 // @attention Child connections use the parent's event bases, otherwise we would get multithreading issues
186 // Always keep thr load and conns list in sync
187 ctx->conn->thr->load++;
188 ctx->conn->thr->max_load = max(ctx->conn->thr->max_load, ctx->conn->thr->load);
189
190 // Prepend child to the children list of parent
191 ctx->next = ctx->conn->children;
192 ctx->conn->children = ctx;
193 if (ctx->next)
194 ctx->next->prev = ctx;
195 }
196
197 // This function cannot fail.
198 static void NONNULL(1)
pxy_conn_detach_child(pxy_conn_child_ctx_t * ctx)199 pxy_conn_detach_child(pxy_conn_child_ctx_t *ctx)
200 {
201 assert(ctx->conn != NULL);
202 assert(ctx->conn->children != NULL);
203
204 log_finest("Removing child conn");
205
206 ctx->conn->thr->load--;
207
208 if (ctx->prev) {
209 ctx->prev->next = ctx->next;
210 } else {
211 ctx->conn->children = ctx->next;
212 }
213 if (ctx->next)
214 ctx->next->prev = ctx->prev;
215
216 #ifdef DEBUG_PROXY
217 if (ctx->conn->children) {
218 if (ctx->id == ctx->conn->children->id) {
219 // This should never happen
220 log_fine("Found child in conn children, first");
221 assert(0);
222 } else {
223 pxy_conn_child_ctx_t *current = ctx->conn->children->next;
224 pxy_conn_child_ctx_t *previous = ctx->conn->children;
225 while (current != NULL && previous != NULL) {
226 if (ctx->id == current->id) {
227 // This should never happen
228 log_fine("Found child in conn children");
229 assert(0);
230 }
231 previous = current;
232 current = current->next;
233 }
234 log_finest("Cannot find child in conn children");
235 }
236 } else {
237 log_finest("Cannot find child in conn children, empty");
238 }
239 #endif /* DEBUG_PROXY */
240 }
241
242 static void
pxy_conn_free_child(pxy_conn_child_ctx_t * ctx)243 pxy_conn_free_child(pxy_conn_child_ctx_t *ctx)
244 {
245 assert(ctx->conn != NULL);
246
247 log_finest("ENTER");
248
249 // We always assign NULL to bevs after freeing them
250 if (ctx->src.bev) {
251 ctx->src.free(ctx->src.bev, ctx->conn);
252 ctx->src.bev = NULL;
253 } else if (!ctx->src.closed) {
254 log_fine("!src.closed, evutil_closesocket on NULL src.bev");
255
256 // @attention early in the conn setup, src fd may be open, although src.bev is NULL
257 evutil_closesocket(ctx->fd);
258 }
259
260 if (ctx->dst.bev) {
261 ctx->dst.free(ctx->dst.bev, ctx->conn);
262 ctx->dst.bev = NULL;
263 }
264
265 // Save conn and srvdst_xferred before freeing ctx
266 pxy_conn_ctx_t *conn = ctx->conn;
267 unsigned int srvdst_xferred = ctx->srvdst_xferred;
268
269 pxy_conn_detach_child(ctx);
270 pxy_conn_ctx_free_child(ctx);
271
272 // If there is no child left, free child_evcl asap by calling pxy_conn_free_children()
273 if (!conn->children) {
274 pxy_conn_free_children(conn);
275 }
276
277 // If this is the first child, NULL srvdst.bev, so we don't try to access it from this point on
278 if (srvdst_xferred) {
279 conn->srvdst.bev = NULL;
280 }
281 }
282
283 void
pxy_conn_term_child(pxy_conn_child_ctx_t * ctx)284 pxy_conn_term_child(pxy_conn_child_ctx_t *ctx)
285 {
286 log_finest("ENTER");
287 ctx->term = 1;
288 }
289
290 void
pxy_conn_free_children(pxy_conn_ctx_t * ctx)291 pxy_conn_free_children(pxy_conn_ctx_t *ctx)
292 {
293 log_finest("ENTER");
294
295 // @attention Free the child ctxs asap, we need their fds
296 while (ctx->children) {
297 pxy_conn_free_child(ctx->children);
298 }
299
300 // @attention Parent may be closing before there was any child at all nor was child_evcl ever created
301 if (ctx->child_evcl) {
302 log_finer_va("Freeing child_evcl, children fd=%d", ctx->children ? ctx->children->fd : -1);
303
304 // @attention child_evcl was created with LEV_OPT_CLOSE_ON_FREE, so do not close ctx->child_fd
305 evconnlistener_free(ctx->child_evcl);
306 ctx->child_evcl = NULL;
307 }
308 }
309
310 /*
311 * Does full clean-up of conn ctx.
312 * This is the conn handling thr version of a similar function
313 * proxy_conn_ctx_free(), which runs on thrmgr and does minimal
314 * clean-up.
315 */
316 void
pxy_conn_ctx_free(pxy_conn_ctx_t * ctx,int by_requestor)317 pxy_conn_ctx_free(pxy_conn_ctx_t *ctx, int by_requestor)
318 {
319 log_finest("ENTER");
320
321 if (WANT_CONTENT_LOG(ctx)) {
322 // Always try to close log files, even if content, pcap, or mirror logging is disabled by filter rules
323 // The log files may have been initialized and opened
324 // so, do not pass down the log_content, log_pcap, and log_mirror fields of ctx
325 if (log_content_close(&ctx->logctx, by_requestor) == -1) {
326 log_err_level_printf(LOG_WARNING, "Content log close failed\n");
327 }
328 }
329
330 #ifndef WITHOUT_USERAUTH
331 if (ctx->conn_opts->user_auth && ctx->srchost_str && ctx->user && ctx->ether) {
332 // Update userdb atime if idle time is more than 50% of user timeout, which is expected to reduce update frequency
333 unsigned int idletime = ctx->idletime + (time(NULL) - ctx->ctime);
334 if (idletime > (ctx->conn_opts->user_timeout / 2)) {
335 userdbkeys_t keys;
336 // Zero out for NULL termination
337 memset(&keys, 0, sizeof(userdbkeys_t));
338 // Leave room for NULL to make sure the strings are always NULL terminated
339 strncpy(keys.ip, ctx->srchost_str, sizeof(keys.ip) - 1);
340 strncpy(keys.user, ctx->user, sizeof(keys.user) - 1);
341 strncpy(keys.ether, ctx->ether, sizeof(keys.ether) - 1);
342
343 if (privsep_client_update_atime(ctx->clisock, &keys) == -1) {
344 log_finest_va("Error updating user atime: %s", sqlite3_errmsg(ctx->global->userdb));
345 } else {
346 log_finest("Successfully updated user atime");
347 }
348 } else {
349 log_finest_va("Will not update user atime, idletime=%u", idletime);
350 }
351 }
352 #endif /* !WITHOUT_USERAUTH */
353
354 pxy_thr_detach(ctx);
355
356 if (ctx->srchost_str) {
357 free(ctx->srchost_str);
358 }
359 if (ctx->srcport_str) {
360 free(ctx->srcport_str);
361 }
362 if (ctx->dsthost_str) {
363 free(ctx->dsthost_str);
364 }
365 if (ctx->dstport_str) {
366 free(ctx->dstport_str);
367 }
368 #ifdef HAVE_LOCAL_PROCINFO
369 if (ctx->lproc.exec_path) {
370 free(ctx->lproc.exec_path);
371 }
372 if (ctx->lproc.user) {
373 free(ctx->lproc.user);
374 }
375 if (ctx->lproc.group) {
376 free(ctx->lproc.group);
377 }
378 #endif /* HAVE_LOCAL_PROCINFO */
379 if (ctx->ev) {
380 event_free(ctx->ev);
381 }
382 if (ctx->sslproxy_header) {
383 free(ctx->sslproxy_header);
384 }
385 // If the proto doesn't have special args, proto_free() callback is NULL
386 if (ctx->protoctx->proto_free) {
387 ctx->protoctx->proto_free(ctx);
388 }
389 free(ctx->protoctx);
390
391 #ifndef WITHOUT_USERAUTH
392 if (ctx->user) {
393 free(ctx->user);
394 }
395 if (ctx->ether) {
396 free(ctx->ether);
397 }
398 if (ctx->desc) {
399 free(ctx->desc);
400 }
401 #endif /* !WITHOUT_USERAUTH */
402 free(ctx);
403 }
404
405 void
pxy_conn_free(pxy_conn_ctx_t * ctx,int by_requestor)406 pxy_conn_free(pxy_conn_ctx_t *ctx, int by_requestor)
407 {
408 log_finest("ENTER");
409
410 // We always assign NULL to bevs after freeing them
411 if (ctx->src.bev) {
412 ctx->src.free(ctx->src.bev, ctx);
413 ctx->src.bev = NULL;
414 } else if (!ctx->src.closed) {
415 log_fine("evutil_closesocket on NULL src.bev");
416 // @attention early in the conn setup, src fd may be open, although src.bev is NULL
417 evutil_closesocket(ctx->fd);
418 }
419
420 if (ctx->srvdst.bev) {
421 // In split mode, srvdst is used as dst, so it should be freed as dst below
422 // If srvdst has been xferred to the first child conn, the child should free it, not the parent
423 if (ctx->divert && !ctx->srvdst_xferred) {
424 ctx->srvdst.free(ctx->srvdst.bev, ctx);
425 } else /*if (!ctx->divert || ctx->srvdst_xferred)*/ {
426 // We reuse srvdst as dst or child dst, so srvdst == dst or child_dst.
427 // But if we don't NULL the callbacks of srvdst in split mode,
428 // we randomly but rarely get a second eof event for srvdst during conn termination (especially on arm64),
429 // which crashes us with signal 11 or 10, because the first eof event for dst frees the ctx.
430 // Note that we don't free anything here, but just disable callbacks and events.
431 // This does not seem to happen with srvdst_xferred, but just to be safe we do the same for it too.
432 // This seems to be an issue with libevent.
433 // @todo Why does libevent raise the same event again for an already disabled and freed conn end?
434 // Note again that srvdst == dst or child_dst here.
435
436 struct bufferevent *ubev = bufferevent_get_underlying(ctx->srvdst.bev);
437
438 bufferevent_setcb(ctx->srvdst.bev, NULL, NULL, NULL, NULL);
439 bufferevent_disable(ctx->srvdst.bev, EV_READ|EV_WRITE);
440
441 if (ubev) {
442 bufferevent_setcb(ubev, NULL, NULL, NULL, NULL);
443 bufferevent_disable(ubev, EV_READ|EV_WRITE);
444 }
445 }
446 ctx->srvdst.bev = NULL;
447 }
448
449 if (ctx->dst.bev) {
450 ctx->dst.free(ctx->dst.bev, ctx);
451 ctx->dst.bev = NULL;
452 }
453
454 pxy_conn_free_children(ctx);
455 pxy_conn_ctx_free(ctx, by_requestor);
456 }
457
458 void
pxy_conn_term(pxy_conn_ctx_t * ctx,int by_requestor)459 pxy_conn_term(pxy_conn_ctx_t *ctx, int by_requestor)
460 {
461 log_finest("ENTER");
462 ctx->term = 1;
463 ctx->term_requestor = by_requestor;
464 }
465
466 void
pxy_log_connect_nonhttp(pxy_conn_ctx_t * ctx)467 pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx)
468 {
469 if (!ctx->log_connect)
470 return;
471
472 char *msg;
473 #ifdef HAVE_LOCAL_PROCINFO
474 char *lpi = NULL;
475 #endif /* HAVE_LOCAL_PROCINFO */
476 int rv;
477
478 #ifdef HAVE_LOCAL_PROCINFO
479 if (ctx->global->lprocinfo) {
480 rv = asprintf(&lpi, "lproc:%i:%s:%s:%s",
481 ctx->lproc.pid,
482 STRORDASH(ctx->lproc.user),
483 STRORDASH(ctx->lproc.group),
484 STRORDASH(ctx->lproc.exec_path));
485 if ((rv < 0) || !lpi) {
486 ctx->enomem = 1;
487 goto out;
488 }
489 } else {
490 lpi = "";
491 }
492 #endif /* HAVE_LOCAL_PROCINFO */
493
494 /*
495 * The following ifdef's within asprintf arguments list generates
496 * warnings with -Wembedded-directive on some compilers.
497 * Not fixing the code in order to avoid more code duplication.
498 */
499
500 if (!ctx->src.ssl) {
501 rv = asprintf(&msg, "CONN: %s %s %s %s %s"
502 #ifdef HAVE_LOCAL_PROCINFO
503 " %s"
504 #endif /* HAVE_LOCAL_PROCINFO */
505 #ifndef WITHOUT_USERAUTH
506 " user:%s"
507 #endif /* !WITHOUT_USERAUTH */
508 "\n",
509 ctx->proto == PROTO_AUTOSSL ? "autossl" : (ctx->proto == PROTO_PASSTHROUGH ? "passthrough" : (ctx->proto == PROTO_POP3 ? "pop3" : (ctx->proto == PROTO_SMTP ? "smtp" : "tcp"))),
510 STRORDASH(ctx->srchost_str),
511 STRORDASH(ctx->srcport_str),
512 STRORDASH(ctx->dsthost_str),
513 STRORDASH(ctx->dstport_str)
514 #ifdef HAVE_LOCAL_PROCINFO
515 , lpi
516 #endif /* HAVE_LOCAL_PROCINFO */
517 #ifndef WITHOUT_USERAUTH
518 , STRORDASH(ctx->user)
519 #endif /* !WITHOUT_USERAUTH */
520 );
521 } else {
522 rv = asprintf(&msg, "CONN: %s %s %s %s %s "
523 "sni:%s names:%s "
524 "sproto:%s:%s dproto:%s:%s "
525 "origcrt:%s usedcrt:%s"
526 #ifdef HAVE_LOCAL_PROCINFO
527 " %s"
528 #endif /* HAVE_LOCAL_PROCINFO */
529 #ifndef WITHOUT_USERAUTH
530 " user:%s"
531 #endif /* !WITHOUT_USERAUTH */
532 "\n",
533 ctx->proto == PROTO_AUTOSSL ? "autossl" : (ctx->proto == PROTO_POP3S ? "pop3s" : (ctx->proto == PROTO_SMTPS ? "smtps" : "ssl")),
534 STRORDASH(ctx->srchost_str),
535 STRORDASH(ctx->srcport_str),
536 STRORDASH(ctx->dsthost_str),
537 STRORDASH(ctx->dstport_str),
538 STRORDASH(ctx->sslctx->sni),
539 STRORDASH(ctx->sslctx->ssl_names),
540 SSL_get_version(ctx->src.ssl),
541 SSL_get_cipher(ctx->src.ssl),
542 STRORDASH(ctx->sslctx->srvdst_ssl_version),
543 STRORDASH(ctx->sslctx->srvdst_ssl_cipher),
544 STRORDASH(ctx->sslctx->origcrtfpr),
545 STRORDASH(ctx->sslctx->usedcrtfpr)
546 #ifdef HAVE_LOCAL_PROCINFO
547 , lpi
548 #endif /* HAVE_LOCAL_PROCINFO */
549 #ifndef WITHOUT_USERAUTH
550 , STRORDASH(ctx->user)
551 #endif /* !WITHOUT_USERAUTH */
552 );
553 }
554 if ((rv < 0) || !msg) {
555 ctx->enomem = 1;
556 goto out;
557 }
558 if (!ctx->global->detach) {
559 log_err_printf("%s", msg);
560 } else if (ctx->global->statslog) {
561 if (log_conn(msg) == -1) {
562 log_err_level_printf(LOG_WARNING, "Conn logging failed\n");
563 }
564 }
565 if (ctx->global->connectlog) {
566 if (log_connect_print_free(msg) == -1) {
567 free(msg);
568 log_err_level_printf(LOG_WARNING, "Connection logging failed\n");
569 }
570 } else {
571 free(msg);
572 }
573 out:
574 #ifdef HAVE_LOCAL_PROCINFO
575 if (lpi && ctx->global->lprocinfo) {
576 free(lpi);
577 }
578 #endif /* HAVE_LOCAL_PROCINFO */
579 return;
580 }
581
582 static int NONNULL(1)
pxy_log_content_inbuf(pxy_conn_ctx_t * ctx,struct evbuffer * inbuf,int req)583 pxy_log_content_inbuf(pxy_conn_ctx_t *ctx, struct evbuffer *inbuf, int req)
584 {
585 if (!ctx->log_content && !ctx->log_pcap
586 #ifndef WITHOUT_MIRROR
587 && !ctx->log_mirror
588 #endif /* !WITHOUT_MIRROR */
589 ) {
590 return 0;
591 }
592
593 size_t sz = evbuffer_get_length(inbuf);
594 unsigned char *buf = malloc(sz);
595 if (!buf) {
596 ctx->enomem = 1;
597 return -1;
598 }
599 if (evbuffer_copyout(inbuf, buf, sz) == -1) {
600 free(buf);
601 return -1;
602 }
603 logbuf_t *lb = logbuf_new_alloc(sz, NULL);
604 if (!lb) {
605 free(buf);
606 ctx->enomem = 1;
607 return -1;
608 }
609 memcpy(lb->buf, buf, lb->sz);
610 free(buf);
611 if (log_content_submit(&ctx->logctx, lb, req, ctx->log_content, ctx->log_pcap
612 #ifndef WITHOUT_MIRROR
613 , ctx->log_mirror
614 #endif /* !WITHOUT_MIRROR */
615 ) == -1) {
616 logbuf_free(lb);
617 log_err_level_printf(LOG_WARNING, "Content log submission failed\n");
618 return -1;
619 }
620 return 0;
621 }
622
623 #ifdef HAVE_LOCAL_PROCINFO
624 int
pxy_prepare_logging_local_procinfo(pxy_conn_ctx_t * ctx)625 pxy_prepare_logging_local_procinfo(pxy_conn_ctx_t *ctx)
626 {
627 if (ctx->global->lprocinfo) {
628 /* fetch process info */
629 if (proc_pid_for_addr(&ctx->lproc.pid,
630 (struct sockaddr*)&ctx->lproc.srcaddr,
631 ctx->lproc.srcaddrlen) == 0 &&
632 ctx->lproc.pid != -1 &&
633 proc_get_info(ctx->lproc.pid,
634 &ctx->lproc.exec_path,
635 &ctx->lproc.uid,
636 &ctx->lproc.gid) == 0) {
637 /* fetch user/group names */
638 ctx->lproc.user = sys_user_str(
639 ctx->lproc.uid);
640 ctx->lproc.group = sys_group_str(
641 ctx->lproc.gid);
642 if (!ctx->lproc.user ||
643 !ctx->lproc.group) {
644 ctx->enomem = 1;
645 pxy_conn_term(ctx, 1);
646 return -1;
647 }
648 }
649 }
650 return 0;
651 }
652 #endif /* HAVE_LOCAL_PROCINFO */
653
654 static int
pxy_prepare_logging(pxy_conn_ctx_t * ctx)655 pxy_prepare_logging(pxy_conn_ctx_t *ctx)
656 {
657 /* prepare logging, part 2 */
658 #ifdef HAVE_LOCAL_PROCINFO
659 if (WANT_CONNECT_LOG(ctx) || WANT_CONTENT_LOG(ctx)) {
660 if (pxy_prepare_logging_local_procinfo(ctx) == -1) {
661 return -1;
662 }
663 }
664 #endif /* HAVE_LOCAL_PROCINFO */
665 if (WANT_CONTENT_LOG(ctx)) {
666 if (log_content_open(&ctx->logctx, ctx->global,
667 (struct sockaddr *)&ctx->srcaddr,
668 ctx->srcaddrlen,
669 (struct sockaddr *)&ctx->dstaddr,
670 ctx->dstaddrlen,
671 STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str),
672 STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
673 #ifdef HAVE_LOCAL_PROCINFO
674 ctx->lproc.exec_path,
675 ctx->lproc.user,
676 ctx->lproc.group,
677 #else /* HAVE_LOCAL_PROCINFO */
678 NULL, NULL, NULL,
679 #endif /* HAVE_LOCAL_PROCINFO */
680 ctx->log_content, ctx->log_pcap
681 #ifndef WITHOUT_MIRROR
682 , ctx->log_mirror
683 #endif /* !WITHOUT_MIRROR */
684 ) == -1) {
685 if (errno == ENOMEM)
686 ctx->enomem = 1;
687 pxy_conn_term(ctx, 1);
688 return -1;
689 }
690 }
691 return 0;
692 }
693
694 static void NONNULL(1,2)
pxy_log_dbg_connect_type(pxy_conn_ctx_t * ctx,pxy_conn_desc_t * this)695 pxy_log_dbg_connect_type(pxy_conn_ctx_t *ctx, pxy_conn_desc_t *this)
696 {
697 if (OPTS_DEBUG(ctx->global)) {
698 if (this->ssl) {
699 char *keystr;
700 /* for SSL, we get two connect events */
701 log_dbg_printf("%s connected to [%s]:%s %s %s\n",
702 protocol_names[ctx->proto],
703 STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
704 SSL_get_version(this->ssl), SSL_get_cipher(this->ssl));
705 keystr = ssl_ssl_masterkey_to_str(this->ssl);
706 if (keystr) {
707 log_dbg_print_free(keystr);
708 }
709 } else {
710 /* for TCP, we get only a dst connect event,
711 * since src was already connected from the
712 * beginning; mirror SSL debug output anyway
713 * in order not to confuse anyone who might be
714 * looking closely at the output */
715 log_dbg_printf("%s connected to [%s]:%s\n",
716 protocol_names[ctx->proto],
717 STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
718 log_dbg_printf("%s connected from [%s]:%s\n",
719 protocol_names[ctx->proto],
720 STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str));
721 }
722 }
723 }
724
725 void
pxy_log_connect_src(pxy_conn_ctx_t * ctx)726 pxy_log_connect_src(pxy_conn_ctx_t *ctx)
727 {
728 /* log connection if we don't analyze any headers */
729 if (!ctx->spec->http && WANT_CONNECT_LOG(ctx)) {
730 pxy_log_connect_nonhttp(ctx);
731 }
732
733 if (ctx->src.ssl && ctx->log_cert && ctx->global->certgendir) {
734 /* write SSL certificates to gendir */
735 protossl_srccert_write(ctx);
736 }
737
738 if (protossl_log_masterkey(ctx, &ctx->src) == -1) {
739 return;
740 }
741
742 pxy_log_dbg_connect_type(ctx, &ctx->src);
743 }
744
745 void
pxy_log_connect_srvdst(pxy_conn_ctx_t * ctx)746 pxy_log_connect_srvdst(pxy_conn_ctx_t *ctx)
747 {
748 // @attention srvdst.bev may be NULL, if its writecb fires first
749 if (ctx->srvdst.bev) {
750 /* log connection if we don't analyze any headers */
751 if (!ctx->srvdst.ssl && !ctx->spec->http && WANT_CONNECT_LOG(ctx)) {
752 pxy_log_connect_nonhttp(ctx);
753 }
754
755 if (protossl_log_masterkey(ctx, &ctx->srvdst) == -1) {
756 return;
757 }
758
759 pxy_log_dbg_connect_type(ctx, &ctx->srvdst);
760 }
761 }
762
763 static void
pxy_log_dbg_disconnect(pxy_conn_ctx_t * ctx)764 pxy_log_dbg_disconnect(pxy_conn_ctx_t *ctx)
765 {
766 /* we only get a single disconnect event here for both connections */
767 if (OPTS_DEBUG(ctx->global)) {
768 log_dbg_printf("%s disconnected to [%s]:%s, fd=%d\n",
769 protocol_names[ctx->proto],
770 STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str), ctx->fd);
771 log_dbg_printf("%s disconnected from [%s]:%s, fd=%d\n",
772 protocol_names[ctx->proto],
773 STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), ctx->fd);
774 }
775 }
776
777 static void
pxy_log_dbg_disconnect_child(pxy_conn_child_ctx_t * ctx)778 pxy_log_dbg_disconnect_child(pxy_conn_child_ctx_t *ctx)
779 {
780 /* we only get a single disconnect event here for both connections */
781 if (OPTS_DEBUG(ctx->conn->global)) {
782 log_dbg_printf("Child %s disconnected to [%s]:%s, child fd=%d, fd=%d\n",
783 protocol_names[ctx->conn->proto],
784 STRORDASH(ctx->conn->dsthost_str), STRORDASH(ctx->conn->dstport_str), ctx->fd, ctx->conn->fd);
785 log_dbg_printf("Child %s disconnected from [%s]:%s, child fd=%d, fd=%d\n",
786 protocol_names[ctx->conn->proto],
787 STRORDASH(ctx->conn->srchost_str), STRORDASH(ctx->conn->srcport_str), ctx->fd, ctx->conn->fd);
788 }
789 }
790
791 #ifdef DEBUG_PROXY
792 void
pxy_log_dbg_evbuf_info(pxy_conn_ctx_t * ctx,pxy_conn_desc_t * this,pxy_conn_desc_t * other)793 pxy_log_dbg_evbuf_info(pxy_conn_ctx_t *ctx, pxy_conn_desc_t *this, pxy_conn_desc_t *other)
794 {
795 // This function is used by child conns too, they pass ctx->conn instead of ctx
796 if (OPTS_DEBUG(ctx->global)) {
797 log_dbg_printf("evbuffer size at EOF: i:%zu o:%zu i:%zu o:%zu\n",
798 evbuffer_get_length(bufferevent_get_input(this->bev)),
799 evbuffer_get_length(bufferevent_get_output(this->bev)),
800 other->closed ? 0 : evbuffer_get_length(bufferevent_get_input(other->bev)),
801 other->closed ? 0 : evbuffer_get_length(bufferevent_get_output(other->bev)));
802 }
803 }
804 #endif /* DEBUG_PROXY */
805
806 unsigned char *
pxy_malloc_packet(size_t sz,pxy_conn_ctx_t * ctx)807 pxy_malloc_packet(size_t sz, pxy_conn_ctx_t *ctx)
808 {
809 unsigned char *packet = malloc(sz);
810 if (!packet) {
811 ctx->enomem = 1;
812 return NULL;
813 }
814 return packet;
815 }
816
817 #ifdef DEBUG_PROXY
818 char *bev_names[] = {
819 "src",
820 "dst",
821 "srvdst",
822 "NULL",
823 "UNKWN"
824 };
825
826 static char *
pxy_get_event_name(struct bufferevent * bev,pxy_conn_ctx_t * ctx)827 pxy_get_event_name(struct bufferevent *bev, pxy_conn_ctx_t *ctx)
828 {
829 if (bev == ctx->src.bev) {
830 return bev_names[0];
831 } else if (bev == ctx->dst.bev) {
832 return bev_names[1];
833 } else if (bev == ctx->srvdst.bev) {
834 return bev_names[2];
835 } else if (bev == NULL) {
836 log_fine("event_name=NULL");
837 return bev_names[3];
838 } else {
839 log_fine("event_name=UNKWN");
840 return bev_names[4];
841 }
842 }
843 #endif /* DEBUG_PROXY */
844
845 void
pxy_try_set_watermark(struct bufferevent * bev,pxy_conn_ctx_t * ctx,struct bufferevent * other)846 pxy_try_set_watermark(struct bufferevent *bev, pxy_conn_ctx_t *ctx, struct bufferevent *other)
847 {
848 if (evbuffer_get_length(bufferevent_get_output(other)) >= OUTBUF_LIMIT) {
849 log_fine_va("%s", pxy_get_event_name(bev, ctx));
850
851 /* temporarily disable data source;
852 * set an appropriate watermark. */
853 bufferevent_setwatermark(other, EV_WRITE, OUTBUF_LIMIT/2, OUTBUF_LIMIT);
854 bufferevent_disable(bev, EV_READ);
855 ctx->thr->set_watermarks++;
856 }
857 }
858
859 void
pxy_try_unset_watermark(struct bufferevent * bev,pxy_conn_ctx_t * ctx,pxy_conn_desc_t * other)860 pxy_try_unset_watermark(struct bufferevent *bev, pxy_conn_ctx_t *ctx, pxy_conn_desc_t *other)
861 {
862 if (other->bev && !(bufferevent_get_enabled(other->bev) & EV_READ)) {
863 log_fine_va("%s", pxy_get_event_name(bev, ctx));
864
865 /* data source temporarily disabled;
866 * re-enable and reset watermark to 0. */
867 bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
868 bufferevent_enable(other->bev, EV_READ);
869 ctx->thr->unset_watermarks++;
870 }
871 }
872
873 void
pxy_discard_inbuf(struct bufferevent * bev)874 pxy_discard_inbuf(struct bufferevent *bev)
875 {
876 struct evbuffer *inbuf = bufferevent_get_input(bev);
877 size_t inbuf_size = evbuffer_get_length(inbuf);
878
879 log_dbg_printf("Warning: Drained %zu bytes (conn closed)\n", inbuf_size);
880 evbuffer_drain(inbuf, inbuf_size);
881 }
882
883 #ifdef DEBUG_PROXY
884 static void
pxy_insert_sslproxy_header(pxy_conn_ctx_t * ctx,unsigned char * packet,size_t * packet_size)885 pxy_insert_sslproxy_header(pxy_conn_ctx_t *ctx, unsigned char *packet, size_t *packet_size)
886 {
887 log_finer("ENTER");
888
889 // @attention Cannot use string manipulation functions; we are dealing with binary arrays here, not NULL-terminated strings
890 memmove(packet + ctx->sslproxy_header_len + 2, packet, *packet_size);
891 memcpy(packet, ctx->sslproxy_header, ctx->sslproxy_header_len);
892 memcpy(packet + ctx->sslproxy_header_len, "\r\n", 2);
893 *packet_size += ctx->sslproxy_header_len + 2;
894 ctx->sent_sslproxy_header = 1;
895 }
896 #endif /* DEBUG_PROXY */
897
898 int
pxy_try_prepend_sslproxy_header(pxy_conn_ctx_t * ctx,struct evbuffer * inbuf,struct evbuffer * outbuf)899 pxy_try_prepend_sslproxy_header(pxy_conn_ctx_t *ctx, struct evbuffer *inbuf, struct evbuffer *outbuf)
900 {
901 log_finer("ENTER");
902
903 if (ctx->divert && !ctx->sent_sslproxy_header) {
904 #ifdef DEBUG_PROXY
905 size_t packet_size = evbuffer_get_length(inbuf);
906 // +2 for \r\n
907 unsigned char *packet = pxy_malloc_packet(packet_size + ctx->sslproxy_header_len + 2, ctx);
908 if (!packet) {
909 return -1;
910 }
911
912 evbuffer_remove(inbuf, packet, packet_size);
913
914 log_finest_va("ORIG packet, size=%zu:\n%.*s", packet_size, (int)packet_size, packet);
915
916 pxy_insert_sslproxy_header(ctx, packet, &packet_size);
917 evbuffer_add(outbuf, packet, packet_size);
918
919 log_finest_va("NEW packet, size=%zu:\n%.*s", packet_size, (int)packet_size, packet);
920
921 free(packet);
922 }
923 else {
924 evbuffer_add_buffer(outbuf, inbuf);
925 }
926 #else /* DEBUG_PROXY */
927 evbuffer_add_printf(outbuf, "%s\r\n", ctx->sslproxy_header);
928 ctx->sent_sslproxy_header = 1;
929 }
930 evbuffer_add_buffer(outbuf, inbuf);
931 #endif /* !DEBUG_PROXY */
932 return 0;
933 }
934
935 void
pxy_try_remove_sslproxy_header(pxy_conn_child_ctx_t * ctx,unsigned char * packet,size_t * packet_size)936 pxy_try_remove_sslproxy_header(pxy_conn_child_ctx_t *ctx, unsigned char *packet, size_t *packet_size)
937 {
938 // @attention Cannot use string manipulation functions; we are dealing with binary arrays here, not NULL-terminated strings
939 unsigned char *pos = memmem(packet, *packet_size, ctx->conn->sslproxy_header, ctx->conn->sslproxy_header_len);
940 if (pos) {
941 log_finer("REMOVE");
942 memmove(pos, pos + ctx->conn->sslproxy_header_len + 2, *packet_size - (pos - packet) - (ctx->conn->sslproxy_header_len + 2));
943 *packet_size -= ctx->conn->sslproxy_header_len + 2;
944 ctx->removed_sslproxy_header = 1;
945 }
946 }
947
948 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
949 #define getdtablecount() 0
950
951 /*
952 * Copied from:
953 * opensmtpd-201801101641p1/openbsd-compat/imsg.c
954 *
955 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
956 *
957 * Permission to use, copy, modify, and distribute this software for any
958 * purpose with or without fee is hereby granted, provided that the above
959 * copyright notice and this permission notice appear in all copies.
960 *
961 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
962 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
963 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
964 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
965 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
966 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
967 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
968 */
969 static int
available_fds(unsigned int n)970 available_fds(unsigned int n)
971 {
972 unsigned int i;
973 int ret, fds[256];
974
975 if (n > (sizeof(fds)/sizeof(fds[0])))
976 return -1;
977
978 ret = 0;
979 for (i = 0; i < n; i++) {
980 fds[i] = -1;
981 if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
982 ret = -1;
983 break;
984 }
985 }
986
987 for (i = 0; i < n && fds[i] >= 0; i++)
988 close(fds[i]);
989
990 return ret;
991 }
992 #endif /* __APPLE__ || __FreeBSD__ */
993
994 #ifdef __linux__
995 /*
996 * Copied from:
997 * https://github.com/tmux/tmux/blob/master/compat/getdtablecount.c
998 *
999 * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
1000 *
1001 * Permission to use, copy, modify, and distribute this software for any
1002 * purpose with or without fee is hereby granted, provided that the above
1003 * copyright notice and this permission notice appear in all copies.
1004 *
1005 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1006 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1007 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1008 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1009 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
1010 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
1011 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1012 */
1013 int
getdtablecount()1014 getdtablecount()
1015 {
1016 char path[PATH_MAX];
1017 glob_t g;
1018 int n = 0;
1019
1020 if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0) {
1021 log_err_level_printf(LOG_CRIT, "snprintf overflow\n");
1022 return 0;
1023 }
1024 if (glob(path, 0, NULL, &g) == 0)
1025 n = g.gl_pathc;
1026 globfree(&g);
1027 return n;
1028 }
1029 #endif /* __linux__ */
1030
1031 /*
1032 * Check if we are out of file descriptors to close the conn, or else libevent will crash us
1033 * @attention We cannot guess the number of children in a connection at conn setup time. So, FD_RESERVE is just a ball park figure.
1034 * But what if a connection passes the check below, but eventually tries to create more children than FD_RESERVE allows for? This will crash us the same.
1035 * Beware, this applies to all current conns, not just the last connection setup.
1036 * For example, 20x conns pass the check below before creating any children, at which point we reach the last FD_RESERVE fds,
1037 * then they all start creating children, which crashes us again.
1038 * So, no matter how large an FD_RESERVE we choose, there will always be a risk of running out of fds, if we check the number of fds during parent conn setup only.
1039 * If we are left with less than FD_RESERVE fds, we should not create more children than FD_RESERVE allows for either.
1040 * Therefore, we check if we are out of fds in pxy_listener_acceptcb_child() and close the conn there too.
1041 * @attention These checks are expected to slow us further down, but it is critical to avoid a crash in case we run out of fds.
1042 */
1043 static int
check_fd_usage(pxy_conn_ctx_t * ctx)1044 check_fd_usage(
1045 #ifdef DEBUG_PROXY
1046 pxy_conn_ctx_t *ctx
1047 #endif /* DEBUG_PROXY */
1048 )
1049 {
1050 int dtable_count = getdtablecount();
1051
1052 log_finer_va("descriptor_table_size=%d, dtablecount=%d, reserve=%d", descriptor_table_size, dtable_count, FD_RESERVE);
1053
1054 if (dtable_count + FD_RESERVE >= descriptor_table_size) {
1055 goto out;
1056 }
1057
1058 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
1059 if (available_fds(FD_RESERVE) == -1) {
1060 goto out;
1061 }
1062 #endif /* __APPLE__ || __FreeBSD__ */
1063
1064 return 0;
1065 out:
1066 errno = EMFILE;
1067 log_err_level_printf(LOG_CRIT, "Out of file descriptors\n");
1068 return -1;
1069 }
1070
1071 /*
1072 * Callback for accept events on the socket listener bufferevent.
1073 */
1074 static void
pxy_listener_acceptcb_child(UNUSED struct evconnlistener * listener,evutil_socket_t fd,UNUSED struct sockaddr * peeraddr,UNUSED int peeraddrlen,void * arg)1075 pxy_listener_acceptcb_child(UNUSED struct evconnlistener *listener, evutil_socket_t fd,
1076 UNUSED struct sockaddr *peeraddr, UNUSED int peeraddrlen, void *arg)
1077 {
1078 pxy_conn_ctx_t *ctx = arg;
1079
1080 ctx->atime = time(NULL);
1081
1082 #ifdef DEBUG_PROXY
1083 log_finest_va("ENTER, fd=%d, ctx->child_fd=%d", fd, ctx->child_fd);
1084
1085 char *host, *port;
1086 if (sys_sockaddr_str(peeraddr, peeraddrlen, &host, &port) == 0) {
1087 log_finest_va("peer addr=[%s]:%s, fd=%d", host, port, fd);
1088 free(host);
1089 free(port);
1090 }
1091 #endif /* DEBUG_PROXY */
1092
1093 if (!ctx->dstaddrlen) {
1094 log_err_level_printf(LOG_CRIT, "Child no target address; aborting connection\n");
1095 evutil_closesocket(fd);
1096 pxy_conn_term(ctx, 1);
1097 goto out;
1098 }
1099
1100 if (check_fd_usage(
1101 #ifdef DEBUG_PROXY
1102 ctx
1103 #endif /* DEBUG_PROXY */
1104 ) == -1) {
1105 evutil_closesocket(fd);
1106 pxy_conn_term(ctx, 1);
1107 goto out;
1108 }
1109
1110 pxy_conn_child_ctx_t *child_ctx = pxy_conn_ctx_new_child(fd, ctx);
1111 if (!child_ctx) {
1112 log_err_level_printf(LOG_CRIT, "Error allocating memory\n");
1113 evutil_closesocket(fd);
1114 pxy_conn_term(ctx, 1);
1115 goto out;
1116 }
1117
1118 pxy_conn_attach_child(child_ctx);
1119
1120 // @attention Do not enable src events here yet, they will be enabled after dst connects
1121 if (prototcp_setup_src_child(child_ctx) == -1) {
1122 goto out;
1123 }
1124
1125 // @attention fd (child_ctx->fd) is different from child event listener fd (ctx->child_fd)
1126 ctx->thr->max_fd = max(ctx->thr->max_fd, child_ctx->fd);
1127 ctx->child_src_fd = child_ctx->fd;
1128
1129 /* create server-side socket and eventbuffer */
1130 // Children rely on the findings of parent
1131 child_ctx->protoctx->connectcb(child_ctx);
1132
1133 if (ctx->term || ctx->enomem) {
1134 goto out;
1135 }
1136
1137 if (OPTS_DEBUG(ctx->global)) {
1138 log_dbg_printf("Child connecting to [%s]:%s\n", STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
1139 }
1140
1141 /* initiate connection, except for the first child conn which uses the parent's srvdst as dst */
1142 if (child_ctx->dst.bev != ctx->srvdst.bev) {
1143 if (bufferevent_socket_connect(child_ctx->dst.bev, (struct sockaddr *)&ctx->dstaddr, ctx->dstaddrlen) == -1) {
1144 pxy_conn_term(ctx, 1);
1145 goto out;
1146 }
1147 }
1148
1149 child_ctx->dst_fd = bufferevent_getfd(child_ctx->dst.bev);
1150 ctx->child_dst_fd = child_ctx->dst_fd;
1151 ctx->thr->max_fd = max(ctx->thr->max_fd, child_ctx->dst_fd);
1152 // Do not return here, but continue and check term/enomem flags below
1153 out:
1154 // @attention Do not use child_ctx->conn here, child_ctx may be uninitialized
1155 // @attention Call pxy_conn_free() directly, not pxy_conn_term() here
1156 // This is our last chance to close and free the conn
1157 if (ctx->term || ctx->enomem) {
1158 pxy_conn_free(ctx, ctx->term ? ctx->term_requestor : 1);
1159 }
1160 }
1161
1162 static int WUNRES NONNULL(1)
pxy_opensock_child(pxy_conn_ctx_t * ctx)1163 pxy_opensock_child(pxy_conn_ctx_t *ctx)
1164 {
1165 evutil_socket_t fd = socket(ctx->spec->return_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
1166 if (fd == -1) {
1167 log_err_level_printf(LOG_CRIT, "Error from socket(): %s (%i)\n", strerror(errno), errno);
1168 log_fine_va("Error from socket(): %s (%i)", strerror(errno), errno);
1169 evutil_closesocket(fd);
1170 return -1;
1171 }
1172
1173 if (evutil_make_socket_nonblocking(fd) == -1) {
1174 log_err_level_printf(LOG_CRIT, "Error making socket nonblocking: %s (%i)\n", strerror(errno), errno);
1175 log_fine_va("Error making socket nonblocking: %s (%i)", strerror(errno), errno);
1176 evutil_closesocket(fd);
1177 return -1;
1178 }
1179
1180 int on = 1;
1181 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on)) == -1) {
1182 log_err_level_printf(LOG_CRIT, "Error from setsockopt(SO_KEEPALIVE): %s (%i)\n", strerror(errno), errno);
1183 log_fine_va("Error from setsockopt(SO_KEEPALIVE): %s (%i)", strerror(errno), errno);
1184 evutil_closesocket(fd);
1185 return -1;
1186 }
1187
1188 if (evutil_make_listen_socket_reuseable(fd) == -1) {
1189 log_err_level_printf(LOG_CRIT, "Error from setsockopt(SO_REUSABLE): %s (%i)\n", strerror(errno), errno);
1190 log_fine_va("Error from setsockopt(SO_REUSABLE): %s (%i)", strerror(errno), errno);
1191 evutil_closesocket(fd);
1192 return -1;
1193 }
1194
1195 if (bind(fd, (struct sockaddr *)&ctx->spec->return_addr, ctx->spec->return_addrlen) == -1) {
1196 log_err_level_printf(LOG_CRIT, "Error from bind(): %s (%i)\n", strerror(errno), errno);
1197 log_fine_va("Error from bind(): %s (%i)", strerror(errno), errno);
1198 evutil_closesocket(fd);
1199 return -1;
1200 }
1201 return fd;
1202 }
1203
1204 int
pxy_setup_child_listener(pxy_conn_ctx_t * ctx)1205 pxy_setup_child_listener(pxy_conn_ctx_t *ctx)
1206 {
1207 if (!ctx->divert) {
1208 // split mode
1209 return 0;
1210 }
1211
1212 // @attention Defer child setup and evcl creation until after parent init is complete, otherwise (1) causes multithreading issues (proxy_listener_acceptcb is
1213 // running on a different thread from the conn, and we only have thrmgr mutex), and (2) we need to clean up less upon errors.
1214 // Child evcls use the evbase of the parent thread, otherwise we would get multithreading issues.
1215 // We don't need a privsep call to open a socket for child listener,
1216 // because listener port of child conns are assigned by the system, hence are from non-privileged range above 1024
1217 ctx->child_fd = pxy_opensock_child(ctx);
1218 if (ctx->child_fd < 0) {
1219 log_err_level_printf(LOG_CRIT, "Error opening child socket: %s (%i)\n", strerror(errno), errno);
1220 log_fine_va("Error opening child socket: %s (%i)", strerror(errno), errno);
1221 pxy_conn_term(ctx, 1);
1222 return -1;
1223 }
1224 ctx->thr->max_fd = max(ctx->thr->max_fd, ctx->child_fd);
1225
1226 // @attention Do not pass NULL as user-supplied pointer
1227 struct evconnlistener *child_evcl = evconnlistener_new(ctx->thr->evbase, pxy_listener_acceptcb_child, ctx, LEV_OPT_CLOSE_ON_FREE, 1024, ctx->child_fd);
1228 if (!child_evcl) {
1229 log_err_level_printf(LOG_CRIT, "Error creating child evconnlistener: %s\n", strerror(errno));
1230 log_fine_va("Error creating child evconnlistener: %s", strerror(errno));
1231
1232 // @attention Close child fd separately, because child evcl does not exist yet, hence fd would not be closed by calling pxy_conn_free()
1233 evutil_closesocket(ctx->child_fd);
1234 pxy_conn_term(ctx, 1);
1235 return -1;
1236 }
1237 ctx->child_evcl = child_evcl;
1238
1239 evconnlistener_set_error_cb(child_evcl, proxy_listener_errorcb);
1240
1241 log_finer_va("Finished setting up child listener, child_fd=%d", ctx->child_fd);
1242
1243 struct sockaddr_in child_listener_addr;
1244 socklen_t child_listener_len = sizeof(child_listener_addr);
1245
1246 if (getsockname(ctx->child_fd, (struct sockaddr *)&child_listener_addr, &child_listener_len) < 0) {
1247 log_err_level_printf(LOG_CRIT, "Error in getsockname: %s\n", strerror(errno));
1248 // @attention Do not close the child fd here, because child evcl exists now, hence pxy_conn_free() will close it while freeing child_evcl
1249 pxy_conn_term(ctx, 1);
1250 return -1;
1251 }
1252
1253 // @todo Children are assumed to be listening on an IPv4 address, should we support IPv6 children?
1254 char addr[INET_ADDRSTRLEN];
1255 if (!inet_ntop(AF_INET, &child_listener_addr.sin_addr, addr, INET_ADDRSTRLEN)) {
1256 pxy_conn_term(ctx, 1);
1257 return -1;
1258 }
1259
1260 // Port may be 4 or 5 chars long
1261 unsigned int port = ntohs(child_listener_addr.sin_port);
1262 size_t port_len = port < 10000 ? 4 : 5;
1263
1264 #ifndef WITHOUT_USERAUTH
1265 int user_len = 0;
1266 if (ctx->conn_opts->user_auth && ctx->user) {
1267 // +1 for comma
1268 user_len = strlen(ctx->user) + 1;
1269 }
1270 #endif /* !WITHOUT_USERAUTH */
1271
1272 // SSLproxy: [127.0.0.1]:34649,[192.168.3.24]:47286,[74.125.206.108]:465,s,soner
1273 // SSLproxy: + + [ + addr + ] + : + p + , + [ + srchost_str + ] + : + srcport_str + , + [ + dsthost_str + ] + : + dstport_str + , + s + , + user
1274 // SSLPROXY_KEY_LEN + 1 + 1 + strlen(addr) + 1 + 1 + port_len + 1 + 1 + strlen(ctx->srchost_str) + 1 + 1 + strlen(ctx->srcport_str) + 1 + 1 + strlen(ctx->dsthost_str) + 1 + 1 + strlen(ctx->dstport_str) + 1 + 1 + user_len
1275 ctx->sslproxy_header_len = SSLPROXY_KEY_LEN + strlen(addr) + port_len + strlen(ctx->srchost_str) + strlen(ctx->srcport_str) + strlen(ctx->dsthost_str) + strlen(ctx->dstport_str) + 14
1276 #ifndef WITHOUT_USERAUTH
1277 + user_len
1278 #endif /* !WITHOUT_USERAUTH */
1279 ;
1280
1281 // +1 for NULL
1282 ctx->sslproxy_header = malloc(ctx->sslproxy_header_len + 1);
1283 if (!ctx->sslproxy_header) {
1284 pxy_conn_term(ctx, 1);
1285 return -1;
1286 }
1287
1288 // printf(3): "snprintf() will write at most size-1 of the characters (the size'th character then gets the terminating NULL)"
1289 // So, +1 for NULL
1290 if (snprintf(ctx->sslproxy_header, ctx->sslproxy_header_len + 1, "%s [%s]:%u,[%s]:%s,[%s]:%s,%s"
1291 #ifndef WITHOUT_USERAUTH
1292 "%s%s"
1293 #endif /* !WITHOUT_USERAUTH */
1294 ,
1295 SSLPROXY_KEY, addr, port, STRORNONE(ctx->srchost_str), STRORNONE(ctx->srcport_str),
1296 STRORNONE(ctx->dsthost_str), STRORNONE(ctx->dstport_str), ctx->spec->ssl ? "s":"p"
1297 #ifndef WITHOUT_USERAUTH
1298 , user_len ? "," : "", user_len ? ctx->user : ""
1299 #endif /* !WITHOUT_USERAUTH */
1300 ) < 0) {
1301 // ctx->sslproxy_header is freed by pxy_conn_ctx_free()
1302 pxy_conn_term(ctx, 1);
1303 return -1;
1304 }
1305 log_finer_va("sslproxy_header= %s", ctx->sslproxy_header);
1306 return 0;
1307 }
1308
1309 int
pxy_try_close_conn_end(pxy_conn_desc_t * conn_end,pxy_conn_ctx_t * ctx)1310 pxy_try_close_conn_end(pxy_conn_desc_t *conn_end, pxy_conn_ctx_t *ctx)
1311 {
1312 /* if the other end is still open and doesn't have data
1313 * to send, close it, otherwise its writecb will close
1314 * it after writing what's left in the output buffer */
1315 if (evbuffer_get_length(bufferevent_get_output(conn_end->bev)) == 0) {
1316 log_finest("evbuffer_get_length(outbuf) == 0, terminate conn");
1317 conn_end->free(conn_end->bev, ctx);
1318 conn_end->bev = NULL;
1319 conn_end->closed = 1;
1320 return 1;
1321 }
1322 return 0;
1323 }
1324
1325 void
pxy_try_disconnect(pxy_conn_ctx_t * ctx,pxy_conn_desc_t * this,pxy_conn_desc_t * other,int is_requestor)1326 pxy_try_disconnect(pxy_conn_ctx_t *ctx, pxy_conn_desc_t *this, pxy_conn_desc_t *other, int is_requestor)
1327 {
1328 this->closed = 1;
1329 this->free(this->bev, ctx);
1330 this->bev = NULL;
1331 if (other->closed) {
1332 log_finest("other->closed, terminate conn");
1333 // Uses only ctx to log disconnect, never any of the bevs
1334 pxy_log_dbg_disconnect(ctx);
1335 pxy_conn_term(ctx, is_requestor);
1336 }
1337 }
1338
1339 void
pxy_try_disconnect_child(pxy_conn_child_ctx_t * ctx,pxy_conn_desc_t * this,pxy_conn_desc_t * other)1340 pxy_try_disconnect_child(pxy_conn_child_ctx_t *ctx, pxy_conn_desc_t *this, pxy_conn_desc_t *other)
1341 {
1342 this->closed = 1;
1343 this->free(this->bev, ctx->conn);
1344 this->bev = NULL;
1345 if (other->closed) {
1346 log_finest("other->closed, terminate conn");
1347 // Uses only ctx to log disconnect, never any of the bevs
1348 pxy_log_dbg_disconnect_child(ctx);
1349 pxy_conn_term_child(ctx);
1350 }
1351 }
1352
1353 int
pxy_try_consume_last_input(struct bufferevent * bev,pxy_conn_ctx_t * ctx)1354 pxy_try_consume_last_input(struct bufferevent *bev, pxy_conn_ctx_t *ctx)
1355 {
1356 /* if there is data pending in the closed connection,
1357 * handle it here, otherwise it will be lost. */
1358 if (evbuffer_get_length(bufferevent_get_input(bev))) {
1359 log_fine("evbuffer_get_length(inbuf) > 0, terminate conn");
1360
1361 if (pxy_bev_readcb_preexec_logging_and_stats(bev, ctx) == -1) {
1362 return -1;
1363 }
1364 ctx->protoctx->bev_readcb(bev, ctx);
1365 }
1366 return 0;
1367 }
1368
1369 int
pxy_try_consume_last_input_child(struct bufferevent * bev,pxy_conn_child_ctx_t * ctx)1370 pxy_try_consume_last_input_child(struct bufferevent *bev, pxy_conn_child_ctx_t *ctx)
1371 {
1372 /* if there is data pending in the closed connection,
1373 * handle it here, otherwise it will be lost. */
1374 if (evbuffer_get_length(bufferevent_get_input(bev))) {
1375 log_fine("evbuffer_get_length(inbuf) > 0, terminate conn");
1376
1377 if (pxy_bev_readcb_preexec_logging_and_stats_child(bev, ctx) == -1) {
1378 return -1;
1379 }
1380 ctx->protoctx->bev_readcb(bev, ctx);
1381 }
1382 return 0;
1383 }
1384
1385 static int NONNULL(1)
pxy_set_dstaddr(pxy_conn_ctx_t * ctx)1386 pxy_set_dstaddr(pxy_conn_ctx_t *ctx)
1387 {
1388 if (sys_sockaddr_str((struct sockaddr *)&ctx->dstaddr, ctx->dstaddrlen, &ctx->dsthost_str, &ctx->dstport_str) != 0) {
1389 // sys_sockaddr_str() may fail due to either malloc() or getnameinfo()
1390 ctx->enomem = 1;
1391 pxy_conn_term(ctx, 1);
1392 return -1;
1393 }
1394 return 0;
1395 }
1396
1397 int
pxy_bev_readcb_preexec_logging_and_stats(struct bufferevent * bev,pxy_conn_ctx_t * ctx)1398 pxy_bev_readcb_preexec_logging_and_stats(struct bufferevent *bev, pxy_conn_ctx_t *ctx)
1399 {
1400 if (bev == ctx->src.bev || bev == ctx->dst.bev) {
1401 struct evbuffer *inbuf = bufferevent_get_input(bev);
1402 size_t inbuf_size = evbuffer_get_length(inbuf);
1403
1404 if (bev == ctx->src.bev) {
1405 ctx->thr->intif_in_bytes += inbuf_size;
1406 } else {
1407 ctx->thr->intif_out_bytes += inbuf_size;
1408 }
1409
1410 if (WANT_CONTENT_LOG(ctx->conn)) {
1411 // HTTP content logging at this point may record certain header lines twice, if we have not seen all headers yet
1412 return pxy_log_content_inbuf(ctx, inbuf, (bev == ctx->src.bev));
1413 }
1414 }
1415 return 0;
1416 }
1417
1418 /*
1419 * Callback for read events on the up- and downstream connection bufferevents.
1420 * Called when there is data ready in the input evbuffer.
1421 */
1422 void
pxy_bev_readcb(struct bufferevent * bev,void * arg)1423 pxy_bev_readcb(struct bufferevent *bev, void *arg)
1424 {
1425 pxy_conn_ctx_t *ctx = arg;
1426
1427 if (pxy_bev_readcb_preexec_logging_and_stats(bev, ctx) == -1) {
1428 goto out;
1429 }
1430
1431 if (!ctx->connected) {
1432 log_err_level(LOG_CRIT, "readcb called when not connected - aborting");
1433 log_exceptcb();
1434 return;
1435 }
1436
1437 ctx->atime = time(NULL);
1438 ctx->protoctx->bev_readcb(bev, ctx);
1439
1440 out:
1441 if (ctx->term || ctx->enomem) {
1442 pxy_conn_free(ctx, ctx->term ? ctx->term_requestor : (bev == ctx->src.bev));
1443 }
1444 }
1445
1446 int
pxy_bev_readcb_preexec_logging_and_stats_child(struct bufferevent * bev,pxy_conn_child_ctx_t * ctx)1447 pxy_bev_readcb_preexec_logging_and_stats_child(struct bufferevent *bev, pxy_conn_child_ctx_t *ctx)
1448 {
1449 struct evbuffer *inbuf = bufferevent_get_input(bev);
1450 size_t inbuf_size = evbuffer_get_length(inbuf);
1451
1452 if (bev == ctx->src.bev) {
1453 ctx->conn->thr->extif_out_bytes += inbuf_size;
1454 } else {
1455 ctx->conn->thr->extif_in_bytes += inbuf_size;
1456 }
1457
1458 if (WANT_CONTENT_LOG(ctx->conn)) {
1459 return pxy_log_content_inbuf(ctx->conn, inbuf, (bev == ctx->src.bev));
1460 }
1461 return 0;
1462 }
1463
1464 void
pxy_bev_readcb_child(struct bufferevent * bev,void * arg)1465 pxy_bev_readcb_child(struct bufferevent *bev, void *arg)
1466 {
1467 pxy_conn_child_ctx_t *ctx = arg;
1468
1469 if (pxy_bev_readcb_preexec_logging_and_stats_child(bev, ctx) == -1) {
1470 goto out;
1471 }
1472
1473 if (!ctx->connected) {
1474 log_err_level(LOG_CRIT, "readcb called when not connected - aborting");
1475 log_exceptcb();
1476 return;
1477 }
1478
1479 ctx->conn->atime = time(NULL);
1480 ctx->protoctx->bev_readcb(bev, ctx);
1481
1482 out:
1483 if (ctx->conn->term || ctx->conn->enomem) {
1484 pxy_conn_free(ctx->conn, ctx->conn->term ? ctx->conn->term_requestor : (bev == ctx->src.bev));
1485 return;
1486 }
1487
1488 if (ctx->term) {
1489 pxy_conn_free_child(ctx);
1490 }
1491 }
1492
1493 /*
1494 * Callback for write events on the up- and downstream connection bufferevents.
1495 * Called when either all data from the output evbuffer has been written,
1496 * or if the outbuf is only half full again after having been full.
1497 */
1498 void
pxy_bev_writecb(struct bufferevent * bev,void * arg)1499 pxy_bev_writecb(struct bufferevent *bev, void *arg)
1500 {
1501 pxy_conn_ctx_t *ctx = arg;
1502
1503 ctx->atime = time(NULL);
1504 ctx->protoctx->bev_writecb(bev, ctx);
1505
1506 if (ctx->term || ctx->enomem) {
1507 pxy_conn_free(ctx, ctx->term ? ctx->term_requestor : (bev == ctx->src.bev));
1508 }
1509 }
1510
1511 void
pxy_bev_writecb_child(struct bufferevent * bev,void * arg)1512 pxy_bev_writecb_child(struct bufferevent *bev, void *arg)
1513 {
1514 pxy_conn_child_ctx_t *ctx = arg;
1515
1516 ctx->conn->atime = time(NULL);
1517 ctx->protoctx->bev_writecb(bev, ctx);
1518
1519 if (ctx->conn->term || ctx->conn->enomem) {
1520 pxy_conn_free(ctx->conn, ctx->conn->term ? ctx->conn->term_requestor : (bev == ctx->src.bev));
1521 return;
1522 }
1523
1524 if (ctx->term) {
1525 pxy_conn_free_child(ctx);
1526 }
1527 }
1528
1529 static int NONNULL(1,3)
pxy_bev_eventcb_postexec_logging_and_stats(struct bufferevent * bev,short events,pxy_conn_ctx_t * ctx)1530 pxy_bev_eventcb_postexec_logging_and_stats(struct bufferevent *bev, short events, pxy_conn_ctx_t *ctx)
1531 {
1532 if (ctx->term || ctx->enomem) {
1533 return -1;
1534 }
1535
1536 if (events & BEV_EVENT_CONNECTED) {
1537 // Passthrough proto does its own connect logging
1538 if (ctx->proto != PROTO_PASSTHROUGH) {
1539 if (bev == ctx->src.bev) {
1540 // @todo When do we reach here? If proto is autossl? Otherwise, src is connected in acceptcb.
1541 pxy_log_connect_src(ctx);
1542 } else if (ctx->connected) {
1543 if (pxy_prepare_logging(ctx) == -1) {
1544 return -1;
1545 }
1546 // Doesn't log connect if proto is http, http proto does its own connect logging
1547 pxy_log_connect_srvdst(ctx);
1548 }
1549 }
1550
1551 if (bev == ctx->srvdst.bev) {
1552 ctx->thr->max_load = max(ctx->thr->max_load, ctx->thr->load);
1553 ctx->thr->max_fd = max(ctx->thr->max_fd, ctx->fd);
1554
1555 // src and other fd stats are collected in acceptcb functions
1556 ctx->srvdst_fd = bufferevent_getfd(ctx->srvdst.bev);
1557 ctx->thr->max_fd = max(ctx->thr->max_fd, ctx->srvdst_fd);
1558
1559 // Passthrough proto may have a NULL dst.bev
1560 if (ctx->dst.bev) {
1561 ctx->dst_fd = bufferevent_getfd(ctx->dst.bev);
1562 ctx->thr->max_fd = max(ctx->thr->max_fd, ctx->dst_fd);
1563 }
1564 }
1565 }
1566 return 0;
1567 }
1568
1569 /*
1570 * Callback for meta events on the up- and downstream connection bufferevents.
1571 * Called when EOF has been reached, a connection has been made, and on errors.
1572 */
1573 void
pxy_bev_eventcb(struct bufferevent * bev,short events,void * arg)1574 pxy_bev_eventcb(struct bufferevent *bev, short events, void *arg)
1575 {
1576 pxy_conn_ctx_t *ctx = arg;
1577
1578 ctx->atime = time(NULL);
1579
1580 if (events & BEV_EVENT_ERROR) {
1581 log_err_printf("Client-side BEV_EVENT_ERROR\n");
1582 ctx->thr->errors++;
1583 }
1584
1585 ctx->protoctx->bev_eventcb(bev, events, arg);
1586
1587 pxy_bev_eventcb_postexec_logging_and_stats(bev, events, ctx);
1588
1589 // Logging functions may set term or enomem too
1590 // EOF eventcb may call readcb possibly causing enomem
1591 if (ctx->term || ctx->enomem) {
1592 pxy_conn_free(ctx, ctx->term ? ctx->term_requestor : (bev == ctx->src.bev));
1593 }
1594 }
1595
1596 void
pxy_bev_eventcb_postexec_stats_child(short events,pxy_conn_child_ctx_t * ctx)1597 pxy_bev_eventcb_postexec_stats_child(short events, pxy_conn_child_ctx_t *ctx)
1598 {
1599 if (events & BEV_EVENT_CONNECTED) {
1600 ctx->conn->thr->max_fd = max(ctx->conn->thr->max_fd, max(bufferevent_getfd(ctx->src.bev), bufferevent_getfd(ctx->dst.bev)));
1601 }
1602 }
1603
1604 void
pxy_bev_eventcb_child(struct bufferevent * bev,short events,void * arg)1605 pxy_bev_eventcb_child(struct bufferevent *bev, short events, void *arg)
1606 {
1607 pxy_conn_child_ctx_t *ctx = arg;
1608
1609 ctx->conn->atime = time(NULL);
1610
1611 if (events & BEV_EVENT_ERROR) {
1612 log_err_printf("Server-side BEV_EVENT_ERROR\n");
1613 ctx->conn->thr->errors++;
1614 }
1615
1616 // All child conns including this one will be freed if this child engages passthrough mode
1617 // So save the vars used after eventcb call
1618 pxy_conn_ctx_t *conn = ctx->conn;
1619 unsigned int term_requestor = bev == ctx->src.bev;
1620
1621 ctx->protoctx->bev_eventcb(bev, events, arg);
1622
1623 // EOF eventcb may call readcb possibly causing enomem
1624 if (conn->term || conn->enomem) {
1625 pxy_conn_free(conn, conn->term ? conn->term_requestor : term_requestor);
1626 return;
1627 }
1628
1629 if (conn->children) {
1630 if (ctx->term) {
1631 pxy_conn_free_child(ctx);
1632 return;
1633 }
1634
1635 pxy_bev_eventcb_postexec_stats_child(events, ctx);
1636 }
1637 }
1638
1639 static filter_action_t * NONNULL(1,2)
pxy_conn_filter_match_ip(pxy_conn_ctx_t * ctx,filter_list_t * list)1640 pxy_conn_filter_match_ip(pxy_conn_ctx_t *ctx, filter_list_t *list)
1641 {
1642 filter_site_t *site = filter_site_find(list->ip_btree, list->ip_acm, list->ip_all, ctx->dsthost_str);
1643 if (!site)
1644 return NULL;
1645
1646 log_fine_va("Found site (line=%d): %s for %s:%s, %s:%s", site->action.line_num, site->site,
1647 STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
1648
1649 // Port spec determines the precedence of a site rule, unless the rule does not have any port
1650 if (!site->port_btree && !site->port_acm && (site->action.precedence < ctx->filter_precedence)) {
1651 log_finest_va("Rule precedence lower than conn filter precedence %d < %d (line=%d): %s, %s", site->action.precedence, ctx->filter_precedence, site->action.line_num, site->site, ctx->dsthost_str);
1652 return NULL;
1653 }
1654
1655 #ifdef DEBUG_PROXY
1656 if (site->all_sites)
1657 log_finest_va("Match all dst (line=%d): %s, %s", site->action.line_num, site->site, ctx->dsthost_str);
1658 else if (site->exact)
1659 log_finest_va("Match exact with dst (line=%d): %s, %s", site->action.line_num, site->site, ctx->dsthost_str);
1660 else
1661 log_finest_va("Match substring in dst (line=%d): %s, %s", site->action.line_num, site->site, ctx->dsthost_str);
1662 #endif /* DEBUG_PROXY */
1663
1664 filter_action_t *port_action = pxy_conn_filter_port(ctx, site);
1665 if (port_action)
1666 return port_action;
1667
1668 return &site->action;
1669 }
1670
1671 static filter_action_t * NONNULL(1,2)
pxy_conn_dsthost_filter(pxy_conn_ctx_t * ctx,filter_list_t * list)1672 pxy_conn_dsthost_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
1673 {
1674 if (ctx->dsthost_str) {
1675 filter_action_t *action;
1676 if ((action = pxy_conn_filter_match_ip(ctx, list)))
1677 return pxy_conn_set_filter_action(action, NULL
1678 #ifdef DEBUG_PROXY
1679 , ctx, ctx->dsthost_str, NULL
1680 #endif /* DEBUG_PROXY */
1681 );
1682
1683 log_finest_va("No filter match with ip: %s:%s, %s:%s",
1684 STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
1685 }
1686 return NULL;
1687 }
1688
1689 int
pxy_conn_apply_filter(pxy_conn_ctx_t * ctx,unsigned int defer_action)1690 pxy_conn_apply_filter(pxy_conn_ctx_t *ctx, unsigned int defer_action)
1691 {
1692 int rv = 0;
1693 filter_action_t *a;
1694 if ((a = pxy_conn_filter(ctx, pxy_conn_dsthost_filter))) {
1695 unsigned int action = pxy_conn_translate_filter_action(ctx, a);
1696
1697 ctx->filter_precedence = action & FILTER_PRECEDENCE;
1698
1699 // If we reach here, the matching filtering rule must have a higher precedence
1700 // Override any deferred action, if the current rule action is not match
1701 // Match action cannot override other filter actions
1702
1703 if (action & FILTER_ACTION_DIVERT) {
1704 ctx->deferred_action = FILTER_ACTION_NONE;
1705 ctx->divert = 1;
1706 }
1707 else if (action & FILTER_ACTION_SPLIT) {
1708 ctx->deferred_action = FILTER_ACTION_NONE;
1709 ctx->divert = 0;
1710 }
1711 else if (action & FILTER_ACTION_PASS) {
1712 if (defer_action & FILTER_ACTION_PASS) {
1713 log_fine("Deferring pass action");
1714 ctx->deferred_action = FILTER_ACTION_PASS;
1715 }
1716 else {
1717 ctx->deferred_action = FILTER_ACTION_NONE;
1718 protopassthrough_engage(ctx);
1719 ctx->pass = 1;
1720 rv = 1;
1721 }
1722 }
1723 else if (action & FILTER_ACTION_BLOCK) {
1724 if (defer_action & FILTER_ACTION_BLOCK) {
1725 // This block action should override any deferred pass action,
1726 // because the current rule must have a higher precedence
1727 log_fine("Deferring block action");
1728 ctx->deferred_action = FILTER_ACTION_BLOCK;
1729 }
1730 else {
1731 pxy_conn_term(ctx, 1);
1732 rv = 1;
1733 }
1734 }
1735 //else { /* FILTER_ACTION_MATCH */ }
1736
1737 // Filtering rules at higher precedence can enable/disable logging
1738 if (action & FILTER_LOG_CONNECT)
1739 ctx->log_connect = 1;
1740 else if (action & FILTER_LOG_NOCONNECT)
1741 ctx->log_connect = 0;
1742 if (action & FILTER_LOG_MASTER)
1743 ctx->log_master = 1;
1744 else if (action & FILTER_LOG_NOMASTER)
1745 ctx->log_master = 0;
1746 if (action & FILTER_LOG_CERT)
1747 ctx->log_cert = 1;
1748 else if (action & FILTER_LOG_NOCERT)
1749 ctx->log_cert = 0;
1750 if (action & FILTER_LOG_CONTENT)
1751 ctx->log_content = 1;
1752 else if (action & FILTER_LOG_NOCONTENT)
1753 ctx->log_content = 0;
1754 if (action & FILTER_LOG_PCAP)
1755 ctx->log_pcap = 1;
1756 else if (action & FILTER_LOG_NOPCAP)
1757 ctx->log_pcap = 0;
1758 #ifndef WITHOUT_MIRROR
1759 if (action & FILTER_LOG_MIRROR)
1760 ctx->log_mirror = 1;
1761 else if (action & FILTER_LOG_NOMIRROR)
1762 ctx->log_mirror = 0;
1763 #endif /* !WITHOUT_MIRROR */
1764
1765 if (a->conn_opts)
1766 ctx->conn_opts = a->conn_opts;
1767 }
1768 return rv;
1769 }
1770
1771 /*
1772 * Complete the connection. This gets called after finding out where to
1773 * connect to.
1774 */
1775 void
pxy_conn_connect(pxy_conn_ctx_t * ctx)1776 pxy_conn_connect(pxy_conn_ctx_t *ctx)
1777 {
1778 log_finest("ENTER");
1779
1780 if (!ctx->dstaddrlen) {
1781 log_err_level_printf(LOG_CRIT, "No target address; aborting connection\n");
1782 evutil_closesocket(ctx->fd);
1783 pxy_conn_ctx_free(ctx, 1);
1784 return;
1785 }
1786
1787 // This function may be called more than once for the same conn
1788 // So, set the dstaddr only once
1789 if (!ctx->dsthost_str && (pxy_set_dstaddr(ctx) == -1)) {
1790 return;
1791 }
1792
1793 // Apply dstip filter now, so we can replace the SSL/TLS configuration of the conn with the one in the matching filtering rule
1794 // It does not matter if this function is called more than once for the same conn
1795 // Defer any pass action until srvdst connected
1796 // Defer any block action until HTTP filter application or the first src readcb of non-http proto
1797 if (pxy_conn_apply_filter(ctx, FILTER_ACTION_PASS | FILTER_ACTION_BLOCK)) {
1798 // We never reach here, since we defer pass and block actions
1799 return;
1800 }
1801
1802 if (OPTS_DEBUG(ctx->global)) {
1803 log_dbg_printf("Connecting to [%s]:%s\n", ctx->dsthost_str, ctx->dstport_str);
1804 }
1805
1806 if (ctx->protoctx->connectcb(ctx) == -1) {
1807 // The return value of -1 from connectcb indicates that there was a fatal error before event callbacks were set, so we can terminate the connection.
1808 // Otherwise, it is up to the event callbacks to terminate the connection.
1809 if (ctx->term || ctx->enomem) {
1810 pxy_conn_free(ctx, ctx->term ? ctx->term_requestor : 1);
1811 return;
1812 }
1813 }
1814
1815 if (bufferevent_socket_connect(ctx->srvdst.bev, (struct sockaddr *)&ctx->dstaddr, ctx->dstaddrlen) == -1) {
1816 log_err_level(LOG_CRIT, "bufferevent_socket_connect for srvdst failed");
1817 pxy_conn_free(ctx, ctx->term ? ctx->term_requestor : 1);
1818 }
1819 }
1820
1821 #ifndef WITHOUT_USERAUTH
1822 #if defined(__OpenBSD__) || defined(__linux__)
1823 int
pxy_is_listuser(userlist_t * list,const char * user,pxy_conn_ctx_t * ctx,const char * listname)1824 pxy_is_listuser(userlist_t *list, const char *user
1825 #ifdef DEBUG_PROXY
1826 , pxy_conn_ctx_t *ctx, const char *listname
1827 #endif /* DEBUG_PROXY */
1828 )
1829 {
1830 while (list) {
1831 if (equal(user, list->user)) {
1832 log_finest_va("User %s in %s", user, listname);
1833 return 1;
1834 }
1835 list = list->next;
1836 }
1837 return 0;
1838 }
1839
1840 void
pxy_classify_user(pxy_conn_ctx_t * ctx)1841 pxy_classify_user(pxy_conn_ctx_t *ctx)
1842 {
1843 if (ctx->spec->opts->passusers && pxy_is_listuser(ctx->spec->opts->passusers, ctx->user
1844 #ifdef DEBUG_PROXY
1845 , ctx, "PassUsers"
1846 #endif /* DEBUG_PROXY */
1847 )) {
1848 log_fine_va("User %s in PassUsers; engaging passthrough mode", ctx->user);
1849 protopassthrough_engage(ctx);
1850 } else if (ctx->spec->opts->divertusers && !pxy_is_listuser(ctx->spec->opts->divertusers, ctx->user
1851 #ifdef DEBUG_PROXY
1852 , ctx, "DivertUsers"
1853 #endif /* DEBUG_PROXY */
1854 )) {
1855 log_fine_va("User %s not in DivertUsers; terminating connection", ctx->user);
1856 pxy_conn_term(ctx, 1);
1857 }
1858 }
1859
1860 static void
identify_user(UNUSED evutil_socket_t fd,UNUSED short what,void * arg)1861 identify_user(UNUSED evutil_socket_t fd, UNUSED short what, void *arg)
1862 {
1863 pxy_conn_ctx_t *ctx = arg;
1864
1865 log_finest("ENTER");
1866
1867 if (ctx->ev) {
1868 event_free(ctx->ev);
1869 ctx->ev = NULL;
1870 }
1871
1872 if (ctx->identify_user_count++ >= 50) {
1873 log_finest("Cannot get conn user");
1874 goto redirect;
1875 } else {
1876 int rc;
1877
1878 // @todo Do we really need to reset the stmt, as we always reset while returning?
1879 sqlite3_reset(ctx->thr->get_user);
1880 sqlite3_bind_text(ctx->thr->get_user, 1, ctx->srchost_str, -1, NULL);
1881 rc = sqlite3_step(ctx->thr->get_user);
1882
1883 // Retry in case we cannot acquire db file or database: SQLITE_BUSY or SQLITE_LOCKED respectively
1884 if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) {
1885 log_finest_va("User db busy or locked, retrying, count=%d", ctx->identify_user_count);
1886
1887 // Do not forget to reset sqlite stmt, or else the userdb may remain busy/locked
1888 sqlite3_reset(ctx->thr->get_user);
1889
1890 ctx->ev = event_new(ctx->thr->evbase, -1, 0, identify_user, ctx);
1891 if (!ctx->ev)
1892 goto memout;
1893 struct timeval retry_delay = {0, 100};
1894 if (event_add(ctx->ev, &retry_delay) == -1)
1895 goto memout;
1896 return;
1897 } else if (rc == SQLITE_DONE) {
1898 log_finest("Conn has no user");
1899 goto redirect;
1900 } else if (rc == SQLITE_ROW) {
1901 char *ether = (char *)sqlite3_column_text(ctx->thr->get_user, 1);
1902 if (strncasecmp(ether, ctx->ether, 17)) {
1903 log_finest_va("Ethernet addresses do not match, db=%s, arp cache=%s", ether, ctx->ether);
1904 goto redirect;
1905 }
1906
1907 log_finest_va("Passed ethernet address test, %s", ether);
1908
1909 ctx->idletime = time(NULL) - sqlite3_column_int(ctx->thr->get_user, 2);
1910 if (ctx->idletime > ctx->conn_opts->user_timeout) {
1911 log_finest_va("User entry timed out, idletime=%u", ctx->idletime);
1912 goto redirect;
1913 }
1914
1915 log_finest_va("Passed timeout test, idletime=%u", ctx->idletime);
1916
1917 ctx->user = strdup((char *)sqlite3_column_text(ctx->thr->get_user, 0));
1918 // Desc is needed for filtering
1919 ctx->desc = strdup((char *)sqlite3_column_text(ctx->thr->get_user, 3));
1920 if (!ctx->user || !ctx->desc) {
1921 goto memout;
1922 }
1923
1924 log_finest_va("Conn user=%s, desc=%s", ctx->user, ctx->desc);
1925
1926 ctx->protoctx->classify_usercb(ctx);
1927 }
1928 }
1929 log_finest("Passed user identification");
1930 redirect:
1931 sqlite3_reset(ctx->thr->get_user);
1932
1933 if (ctx->ev) {
1934 event_free(ctx->ev);
1935 ctx->ev = NULL;
1936 }
1937 return;
1938
1939 memout:
1940 log_err_level_printf(LOG_CRIT, "Aborting connection user identification!\n");
1941 pxy_conn_term(ctx, 1);
1942 }
1943 #endif /* __OpenBSD__ || __linux__ */
1944
1945 #ifdef __linux__
1946 // Assume proc filesystem support
1947 #define ARP_CACHE "/proc/net/arp"
1948
1949 /*
1950 * We do not care about multiple matches or expiration status of arp cache entries on Linux.
1951 */
1952 static int NONNULL(1)
get_client_ether(pxy_conn_ctx_t * ctx)1953 get_client_ether(pxy_conn_ctx_t *ctx)
1954 {
1955 int rv = 0;
1956
1957 FILE *arp_cache = fopen(ARP_CACHE, "r");
1958 if (!arp_cache) {
1959 log_err_level_printf(LOG_CRIT, "Failed to open arp cache: \"" ARP_CACHE "\"\n");
1960 return -1;
1961 }
1962
1963 // Skip the first line, which contains the header
1964 char header[1024];
1965 if (!fgets(header, sizeof(header), arp_cache)) {
1966 log_err_level_printf(LOG_CRIT, "Failed to skip arp cache header\n");
1967 rv = -1;
1968 goto out;
1969 }
1970
1971 char ip[46], ether[18];
1972 //192.168.0.1 0x1 0x2 00:50:56:2c:bf:e0 * enp3s0f1
1973 while (fscanf(arp_cache, "%45s %*s %*s %17s %*s %*s", ip, ether) == 2) {
1974 if (!strncasecmp(ip, ctx->srchost_str, 45)) {
1975 log_finest_va("Arp entry for %s: %s", ip, ether);
1976 ctx->ether = strdup(ether);
1977 rv = 1;
1978 goto out;
1979 }
1980 }
1981 out:
1982 fclose(arp_cache);
1983 return rv;
1984 }
1985 #endif /* __linux__ */
1986
1987 #ifdef __OpenBSD__
1988 /*
1989 * This is a modified version of the same function from OpenBSD sources,
1990 * which has a 3-clause BSD license.
1991 */
1992 static char *
ether_str(struct sockaddr_dl * sdl)1993 ether_str(struct sockaddr_dl *sdl)
1994 {
1995 char hbuf[NI_MAXHOST];
1996 u_char *cp;
1997
1998 if (sdl->sdl_alen) {
1999 cp = (u_char *)LLADDR(sdl);
2000 snprintf(hbuf, sizeof(hbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
2001 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
2002 return strdup(hbuf);
2003 } else {
2004 return NULL;
2005 }
2006 }
2007
2008 /*
2009 * This is a modified version of a similar function from OpenBSD sources,
2010 * which has a 3-clause BSD license.
2011 */
2012 static int NONNULL(2)
get_client_ether(in_addr_t addr,pxy_conn_ctx_t * ctx)2013 get_client_ether(in_addr_t addr, pxy_conn_ctx_t *ctx)
2014 {
2015 int mib[7];
2016 size_t needed;
2017 char *lim, *buf = NULL, *next;
2018 struct rt_msghdr *rtm;
2019 struct sockaddr_inarp *sin;
2020 struct sockaddr_dl *sdl;
2021 int found_entry = 0;
2022 int rdomain = getrtable();
2023
2024 mib[0] = CTL_NET;
2025 mib[1] = PF_ROUTE;
2026 mib[2] = 0;
2027 mib[3] = AF_INET;
2028 mib[4] = NET_RT_FLAGS;
2029 mib[5] = RTF_LLINFO;
2030 mib[6] = rdomain;
2031 while (1) {
2032 if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) {
2033 log_err_level_printf(LOG_WARNING, "route-sysctl-estimate\n");
2034 }
2035 if (needed == 0) {
2036 return found_entry;
2037 }
2038 if ((buf = realloc(buf, needed)) == NULL) {
2039 return -1;
2040 }
2041 if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) {
2042 if (errno == ENOMEM)
2043 continue;
2044 log_finest("actual retrieval of routing table");
2045 }
2046 lim = buf + needed;
2047 break;
2048 }
2049
2050 int expired = 0;
2051 int incomplete = 0;
2052 for (next = buf; next < lim; next += rtm->rtm_msglen) {
2053 rtm = (struct rt_msghdr *)next;
2054 if (rtm->rtm_version != RTM_VERSION)
2055 continue;
2056 sin = (struct sockaddr_inarp *)(next + rtm->rtm_hdrlen);
2057 sdl = (struct sockaddr_dl *)(sin + 1);
2058 if (addr) {
2059 if (addr != sin->sin_addr.s_addr)
2060 continue;
2061 found_entry++;
2062 }
2063
2064 char *expire = NULL;
2065 if (rtm->rtm_flags & (RTF_PERMANENT_ARP | RTF_LOCAL)) {
2066 expire = "permanent";
2067 } else if (rtm->rtm_rmx.rmx_expire == 0) {
2068 expire = "static";
2069 } else if (rtm->rtm_rmx.rmx_expire > time(NULL)) {
2070 expire = "active";
2071 } else {
2072 expire = "expired";
2073 expired++;
2074 }
2075
2076 char *ether = ether_str(sdl);
2077 if (ether) {
2078 // Record the first unexpired complete entry
2079 if (!ctx->ether && (found_entry - expired) == 1) {
2080 log_finest_va("Arp entry for %s: %s", inet_ntoa(sin->sin_addr), ether);
2081 // Dup before assignment because we free local var ether below
2082 ctx->ether = strdup(ether);
2083 // Do not care about multiple matches, return immediately
2084 free(ether);
2085 goto out;
2086 }
2087 } else {
2088 incomplete++;
2089 }
2090
2091 log_finest_va("Arp entry %u for %s: %s (%s)", found_entry, inet_ntoa(sin->sin_addr), ether ? ether : "incomplete", expire);
2092
2093 if (ether) {
2094 free(ether);
2095 }
2096 }
2097 out:
2098 free(buf);
2099 return found_entry - expired - incomplete;
2100 }
2101 #endif /* __OpenBSD__ */
2102
2103 void
pxy_userauth(pxy_conn_ctx_t * ctx)2104 pxy_userauth(pxy_conn_ctx_t *ctx)
2105 {
2106 if (ctx->conn_opts->user_auth && !ctx->user) {
2107 #if defined(__OpenBSD__) || defined(__linux__)
2108 int ec = get_client_ether(
2109 #if defined(__OpenBSD__)
2110 ((struct sockaddr_in *)&ctx->srcaddr)->sin_addr.s_addr,
2111 #endif /* __OpenBSD__ */
2112 ctx);
2113 if (ec == 1) {
2114 identify_user(-1, 0, ctx);
2115 return;
2116 } else if (ec == 0) {
2117 log_err_level_printf(LOG_CRIT, "Cannot find ethernet address of client IP address\n");
2118 } else if (ec > 1) {
2119 // get_client_ether() does not return multiple matches, but keep this in case a future version does
2120 log_err_level_printf(LOG_CRIT, "Multiple ethernet addresses for the same client IP address\n");
2121 } else {
2122 // ec == -1
2123 log_err_level_printf(LOG_CRIT, "Aborting connection setup (out of memory)!\n");
2124 }
2125 #endif /* __OpenBSD__ || __linux__ */
2126 log_err_level_printf(LOG_CRIT, "Aborting connection setup (user auth)!\n");
2127 pxy_conn_term(ctx, 1);
2128 }
2129 }
2130 #endif /* !WITHOUT_USERAUTH */
2131
2132 int
pxy_conn_apply_deferred_block_action(pxy_conn_ctx_t * ctx)2133 pxy_conn_apply_deferred_block_action(pxy_conn_ctx_t *ctx)
2134 {
2135 if (ctx->deferred_action & FILTER_ACTION_BLOCK) {
2136 log_fine("Applying deferred block action");
2137 pxy_conn_term(ctx, 1);
2138 return 1;
2139 }
2140 return 0;
2141 }
2142
2143 unsigned int
pxy_conn_translate_filter_action(pxy_conn_ctx_t * ctx,filter_action_t * a)2144 pxy_conn_translate_filter_action(pxy_conn_ctx_t *ctx, filter_action_t *a)
2145 {
2146 unsigned int action = FILTER_ACTION_NONE;
2147
2148 if (a->divert) {
2149 action = FILTER_ACTION_DIVERT;
2150 }
2151 else if (a->split) {
2152 action = FILTER_ACTION_SPLIT;
2153 }
2154 else if (a->pass) {
2155 // Ignore pass action if already in passthrough mode
2156 if (!ctx->pass) {
2157 action = FILTER_ACTION_PASS;
2158 }
2159 }
2160 else if (a->block) {
2161 action = FILTER_ACTION_BLOCK;
2162 }
2163 else if (a->match) {
2164 action = FILTER_ACTION_MATCH;
2165 }
2166
2167 // Multiple log actions can be defined, hence no 'else'
2168 // 0: don't change, 1: disable, 2: enable
2169 if (a->log_connect) {
2170 action |= (a->log_connect % 2) ? FILTER_LOG_NOCONNECT : FILTER_LOG_CONNECT;
2171 }
2172 if (a->log_master) {
2173 action |= (a->log_master % 2) ? FILTER_LOG_NOMASTER : FILTER_LOG_MASTER;
2174 }
2175 if (a->log_cert) {
2176 action |= (a->log_cert % 2) ? FILTER_LOG_NOCERT : FILTER_LOG_CERT;
2177 }
2178 if (a->log_content) {
2179 action |= (a->log_content % 2) ? FILTER_LOG_NOCONTENT : FILTER_LOG_CONTENT;
2180 }
2181 if (a->log_pcap) {
2182 action |= (a->log_pcap % 2) ? FILTER_LOG_NOPCAP : FILTER_LOG_PCAP;
2183 }
2184 #ifndef WITHOUT_MIRROR
2185 if (a->log_mirror) {
2186 action |= (a->log_mirror % 2) ? FILTER_LOG_NOMIRROR : FILTER_LOG_MIRROR;
2187 }
2188 #endif /* !WITHOUT_MIRROR */
2189
2190 action |= a->precedence;
2191
2192 return action;
2193 }
2194
2195 filter_action_t *
pxy_conn_set_filter_action(filter_action_t * a1,filter_action_t * a2,pxy_conn_ctx_t * ctx,char * s1,char * s2)2196 pxy_conn_set_filter_action(filter_action_t *a1, filter_action_t *a2
2197 #ifdef DEBUG_PROXY
2198 , pxy_conn_ctx_t *ctx, char *s1, char *s2
2199 #endif /* DEBUG_PROXY */
2200 )
2201 {
2202 filter_action_t *a;
2203 #ifdef DEBUG_PROXY
2204 char *site;
2205 #endif /* DEBUG_PROXY */
2206
2207 // a1 has precedence over a2, unless a2's precedence is higher
2208 if (!a1 || (a1 && a2 && (a1->precedence < a2->precedence))) {
2209 a = a2;
2210 #ifdef DEBUG_PROXY
2211 site = s2;
2212 if (a1 && a2 && (a1->precedence < a2->precedence))
2213 log_finest_va("Rule 2 has higher precedence than rule 1: %d > %d (line=%d, %d), %s, %s", a2->precedence, a1->precedence, a2->line_num, a1->line_num, s2, s1);
2214 #endif /* DEBUG_PROXY */
2215 } else {
2216 a = a1;
2217 #ifdef DEBUG_PROXY
2218 site = s1;
2219 #endif /* DEBUG_PROXY */
2220 }
2221
2222 #ifdef DEBUG_PROXY
2223 if (a->divert) {
2224 log_fine_va("Filter divert action for %s, precedence %d (line=%d)", site, a->precedence, a->line_num);
2225 }
2226 else if (a->split) {
2227 log_fine_va("Filter split action for %s, precedence %d (line=%d)", site, a->precedence, a->line_num);
2228 }
2229 else if (a->pass) {
2230 // Ignore pass action if already in passthrough mode
2231 if (!ctx->pass) {
2232 log_fine_va("Filter pass action for %s, precedence %d (line=%d)", site, a->precedence, a->line_num);
2233 }
2234 }
2235 else if (a->block) {
2236 log_fine_va("Filter block action for %s, precedence %d (line=%d)", site, a->precedence, a->line_num);
2237 }
2238 else if (a->match) {
2239 log_fine_va("Filter match action for %s, precedence %d (line=%d)", site, a->precedence, a->line_num);
2240 }
2241
2242 // Multiple log actions can be defined, hence no 'else'
2243 // 0: don't change, 1: disable, 2: enable
2244 if (a->log_connect) {
2245 log_fine_va("Filter %s connect log for %s, precedence %d (line=%d)", a->log_connect % 2 ? "disable" : "enable", site, a->precedence, a->line_num);
2246 }
2247 if (a->log_master) {
2248 log_fine_va("Filter %s master log for %s, precedence %d (line=%d)", a->log_master % 2 ? "disable" : "enable", site, a->precedence, a->line_num);
2249 }
2250 if (a->log_cert) {
2251 log_fine_va("Filter %s cert log for %s, precedence %d (line=%d)", a->log_cert % 2 ? "disable" : "enable", site, a->precedence, a->line_num);
2252 }
2253 if (a->log_content) {
2254 log_fine_va("Filter %s content log for %s, precedence %d (line=%d)", a->log_content % 2 ? "disable" : "enable", site, a->precedence, a->line_num);
2255 }
2256 if (a->log_pcap) {
2257 log_fine_va("Filter %s pcap log for %s, precedence %d (line=%d)", a->log_pcap % 2 ? "disable" : "enable", site, a->precedence, a->line_num);
2258 }
2259 #ifndef WITHOUT_MIRROR
2260 if (a->log_mirror) {
2261 log_fine_va("Filter %s mirror log for %s, precedence %d (line=%d)", a->log_mirror % 2 ? "disable" : "enable", site, a->precedence, a->line_num);
2262 }
2263 #endif /* !WITHOUT_MIRROR */
2264 #endif /* DEBUG_PROXY */
2265 return a;
2266 }
2267
2268 static int NONNULL(1,2)
pxy_conn_filter_match_port(pxy_conn_ctx_t * ctx,filter_port_t * port)2269 pxy_conn_filter_match_port(pxy_conn_ctx_t *ctx, filter_port_t *port)
2270 {
2271 if (port->action.precedence < ctx->filter_precedence) {
2272 log_finest_va("Rule port precedence lower than conn filter precedence %d < %d (line=%d): %s, %s", port->action.precedence, ctx->filter_precedence, port->action.line_num, port->port, ctx->dsthost_str);
2273 return 0;
2274 }
2275
2276 #ifdef DEBUG_PROXY
2277 if (port->all_ports)
2278 log_finest_va("Match all dst ports (line=%d): %s, %s", port->action.line_num, port->port, ctx->dstport_str);
2279 else if (port->exact)
2280 log_finest_va("Match exact with dst port (line=%d): %s, %s", port->action.line_num, port->port, ctx->dstport_str);
2281 else
2282 log_finest_va("Match substring in dst port (line=%d): %s, %s", port->action.line_num, port->port, ctx->dstport_str);
2283 #endif /* DEBUG_PROXY */
2284
2285 return 1;
2286 }
2287
2288 filter_action_t *
pxy_conn_filter_port(pxy_conn_ctx_t * ctx,filter_site_t * site)2289 pxy_conn_filter_port(pxy_conn_ctx_t *ctx, filter_site_t *site)
2290 {
2291 filter_port_t *port = filter_port_find(site, ctx->dstport_str);
2292 if (port) {
2293 log_fine_va("Found port (line=%d): %s for %s:%s, %s:%s", port->action.line_num, port->port,
2294 STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
2295 if (pxy_conn_filter_match_port(ctx, port))
2296 return &port->action;
2297 }
2298 else
2299 log_finest_va("No filter match with port: %s:%s, %s:%s",
2300 STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
2301
2302 return NULL;
2303 }
2304
2305 #ifndef WITHOUT_USERAUTH
2306 static filter_action_t *
pxy_conn_filter_user(pxy_conn_ctx_t * ctx,proto_filter_func_t filtercb,filter_user_t * user)2307 pxy_conn_filter_user(pxy_conn_ctx_t *ctx, proto_filter_func_t filtercb, filter_user_t *user)
2308 {
2309 filter_action_t * action = NULL;
2310 if (user) {
2311 if (ctx->desc) {
2312 log_finest_va("Searching user keyword exact: %s, %s", ctx->user, ctx->desc);
2313 filter_desc_t *keyword = filter_desc_exact_match(user->desc_btree, ctx->desc);
2314 if (keyword && (action = filtercb(ctx, keyword->list))) {
2315 return action;
2316 }
2317
2318 log_finest_va("Searching user keyword substring: %s, %s", ctx->user, ctx->desc);
2319 keyword = filter_desc_substring_match(user->desc_acm, ctx->desc);
2320 if (keyword && (action = filtercb(ctx, keyword->list))) {
2321 return action;
2322 }
2323 }
2324 if ((action = filtercb(ctx, user->list))) {
2325 return action;
2326 }
2327 }
2328 return action;
2329 }
2330 #endif /* !WITHOUT_USERAUTH */
2331
2332 filter_action_t *
pxy_conn_filter(pxy_conn_ctx_t * ctx,proto_filter_func_t filtercb)2333 pxy_conn_filter(pxy_conn_ctx_t *ctx, proto_filter_func_t filtercb)
2334 {
2335 filter_action_t * action = NULL;
2336
2337 filter_t *filter = ctx->spec->opts->filter;
2338 if (filter) {
2339 #ifndef WITHOUT_USERAUTH
2340 if (ctx->user) {
2341 log_finest_va("Searching user exact: %s", ctx->user);
2342 filter_user_t *user = filter_user_exact_match(filter->user_btree, ctx->user);
2343 if ((action = pxy_conn_filter_user(ctx, filtercb, user)))
2344 return action;
2345
2346 log_finest_va("Searching user substring: %s", ctx->user);
2347 user = filter_user_substring_match(filter->user_acm, ctx->user);
2348 if ((action = pxy_conn_filter_user(ctx, filtercb, user)))
2349 return action;
2350
2351 if (ctx->desc) {
2352 log_finest_va("Searching keyword exact: %s", ctx->desc);
2353 filter_desc_t *keyword = filter_desc_exact_match(filter->desc_btree, ctx->desc);
2354 if (keyword && (action = filtercb(ctx, keyword->list))) {
2355 return action;
2356 }
2357
2358 log_finest_va("Searching keyword substring: %s, %s", ctx->user, ctx->desc);
2359 keyword = filter_desc_substring_match(filter->desc_acm, ctx->desc);
2360 if (keyword && (action = filtercb(ctx, keyword->list))) {
2361 return action;
2362 }
2363 }
2364
2365 log_finest("Searching all_user");
2366 if (filter->all_user && (action = filtercb(ctx, filter->all_user))) {
2367 return action;
2368 }
2369 }
2370 #endif /* !WITHOUT_USERAUTH */
2371 if (ctx->srchost_str) {
2372 log_finest_va("Searching ip exact: %s", ctx->srchost_str);
2373 filter_ip_t *ip = filter_ip_exact_match(filter->ip_btree, ctx->srchost_str);
2374 if (ip && (action = filtercb(ctx, ip->list))) {
2375 return action;
2376 }
2377
2378 log_finest_va("Searching ip substring: %s", ctx->srchost_str);
2379 ip = filter_ip_substring_match(filter->ip_acm, ctx->srchost_str);
2380 if (ip && (action = filtercb(ctx, ip->list))) {
2381 return action;
2382 }
2383 }
2384
2385 log_finest("Searching all");
2386 if (filter->all && (action = filtercb(ctx, filter->all))) {
2387 return action;
2388 }
2389 }
2390 return action;
2391 }
2392
2393 int
pxy_conn_init(pxy_conn_ctx_t * ctx)2394 pxy_conn_init(pxy_conn_ctx_t *ctx)
2395 {
2396 log_finest("ENTER");
2397
2398 pxy_thr_attach(ctx);
2399
2400 ctx->ctime = time(NULL);
2401 ctx->atime = ctx->ctime;
2402
2403 if (check_fd_usage(
2404 #ifdef DEBUG_PROXY
2405 ctx
2406 #endif /* DEBUG_PROXY */
2407 ) == -1) {
2408 goto out;
2409 }
2410
2411 ctx->af = ctx->srcaddr.ss_family;
2412
2413 /* determine original destination of connection */
2414 if (ctx->spec->natlookup) {
2415 /* NAT engine lookup */
2416 ctx->dstaddrlen = sizeof(struct sockaddr_storage);
2417 if (ctx->spec->natlookup((struct sockaddr *)&ctx->dstaddr, &ctx->dstaddrlen, ctx->fd, (struct sockaddr *)&ctx->srcaddr, ctx->srcaddrlen) == -1) {
2418 log_err_printf("Connection not found in NAT state table, aborting connection\n");
2419 goto out;
2420 }
2421 } else if (ctx->spec->connect_addrlen > 0) {
2422 /* static forwarding */
2423 ctx->dstaddrlen = ctx->spec->connect_addrlen;
2424 memcpy(&ctx->dstaddr, &ctx->spec->connect_addr, ctx->dstaddrlen);
2425 } else {
2426 /* SNI mode */
2427 if (!ctx->spec->ssl) {
2428 /* if this happens, the proxyspec parser is broken */
2429 log_err_printf("SNI mode used for non-SSL connection; aborting connection\n");
2430 goto out;
2431 }
2432 }
2433
2434 if (sys_sockaddr_str((struct sockaddr *)&ctx->srcaddr, ctx->srcaddrlen, &ctx->srchost_str, &ctx->srcport_str) != 0) {
2435 log_err_level_printf(LOG_CRIT, "Aborting connection setup (out of memory)!\n");
2436 goto out;
2437 }
2438 log_finest_va("srcaddr= [%s]:%s", ctx->srchost_str, ctx->srcport_str);
2439 return 0;
2440 out:
2441 evutil_closesocket(ctx->fd);
2442 pxy_conn_ctx_free(ctx, 1);
2443 return -1;
2444 }
2445
2446 /* vim: set noet ft=c: */
2447