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 "log.h"
30
31 #include "logger.h"
32 #include "sys.h"
33 #include "attrib.h"
34 #include "privsep.h"
35 #include "defaults.h"
36 #include "logpkt.h"
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <syslog.h>
46 #include <assert.h>
47 #include <sys/stat.h>
48 #include <netinet/in.h>
49
50 /*
51 * Centralized logging code multiplexing thread access to the logger based
52 * logging in separate threads. Some log types are switchable to different
53 * backends, such as syslog and stderr.
54 */
55
56
57 /*
58 * Common code for all logs.
59 */
60 static proxy_ctx_t *proxy_ctx = NULL;
61
62 // @attention The order of names should match the numbering in LOG_DBG_MODE_* macros
63 char *log_dbg_mode_names[] = {
64 "NONE", // = 0
65 "ERROR",
66 "FINE",
67 "FINER",
68 "FINEST",
69 };
70
71 void
log_exceptcb(void)72 log_exceptcb(void)
73 {
74 log_err_level_printf(LOG_CRIT, "Error %d on logger: %s\n", errno, strerror(errno));
75 /* Do not break the event loop if out of fds:
76 * Bad file descriptor (9) or Message too long (40) */
77 if (errno == 9 || errno == 40) {
78 return;
79 }
80 if (proxy_ctx) {
81 proxy_loopbreak(proxy_ctx, -1);
82 proxy_ctx = NULL;
83 }
84 }
85
86 /*
87 * Error log.
88 * Switchable between stderr and syslog.
89 * Uses logger thread.
90 */
91
92 static logger_t *err_log = NULL;
93 static int err_shortcut_logger = 0;
94 static int err_mode = LOG_ERR_MODE_STDERR;
95
96 static ssize_t
log_err_writecb(int level,UNUSED void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)97 log_err_writecb(int level, UNUSED void *fh, UNUSED unsigned long ctl,
98 const void *buf, size_t sz)
99 {
100 switch (err_mode) {
101 case LOG_ERR_MODE_STDERR:
102 return fwrite(buf, sz - 1, 1, stderr);
103 case LOG_ERR_MODE_SYSLOG:
104 syslog(LOG_DAEMON|level, "%s", (const char *)buf);
105 return sz;
106 }
107 return -1;
108 }
109
110 int
log_err_printf(const char * fmt,...)111 log_err_printf(const char *fmt, ...)
112 {
113 va_list ap;
114 char *buf;
115 int rv;
116
117 va_start(ap, fmt);
118 rv = vasprintf(&buf, fmt, ap);
119 va_end(ap);
120 if (rv < 0)
121 return -1;
122 if (err_shortcut_logger) {
123 return logger_write_freebuf(err_log, LOG_ERR, NULL, 0,
124 buf, strlen(buf) + 1);
125 } else {
126 log_err_writecb(LOG_ERR, NULL, 0, (unsigned char*)buf, strlen(buf) + 1);
127 free(buf);
128 }
129 return 0;
130 }
131
132 int
log_err_level_printf(int level,const char * fmt,...)133 log_err_level_printf(int level, const char *fmt, ...)
134 {
135 va_list ap;
136 char *buf;
137 int rv;
138
139 va_start(ap, fmt);
140 rv = vasprintf(&buf, fmt, ap);
141 va_end(ap);
142 if (rv < 0)
143 return -1;
144 if (err_shortcut_logger) {
145 return logger_write_freebuf(err_log, level, NULL, 0,
146 buf, strlen(buf) + 1);
147 } else {
148 log_err_writecb(level, NULL, 0, (unsigned char*)buf, strlen(buf) + 1);
149 free(buf);
150 }
151 return 0;
152 }
153
154 void
log_err_mode(int mode)155 log_err_mode(int mode)
156 {
157 err_mode = mode;
158 }
159
160
161 /*
162 * Debug log. Redirects logging to error log.
163 * Switchable between error log or no logging.
164 * Uses the error log logger thread.
165 */
166
167 static int dbg_mode = LOG_DBG_MODE_NONE;
168
169 int
log_dbg_write_free(void * buf,size_t sz)170 log_dbg_write_free(void *buf, size_t sz)
171 {
172 if (dbg_mode == LOG_DBG_MODE_NONE)
173 return 0;
174
175 if (err_shortcut_logger) {
176 return logger_write_freebuf(err_log, LOG_DEBUG, NULL, 0, buf, sz);
177 } else {
178 log_err_writecb(LOG_DEBUG, NULL, 0, buf, sz);
179 free(buf);
180 }
181 return 0;
182 }
183
184 int
log_dbg_print_free(char * s)185 log_dbg_print_free(char *s)
186 {
187 return log_dbg_write_free(s, strlen(s) + 1);
188 }
189
190 int
log_dbg_printf(const char * fmt,...)191 log_dbg_printf(const char *fmt, ...)
192 {
193 va_list ap;
194 char *buf;
195 int rv;
196
197 if (dbg_mode == LOG_DBG_MODE_NONE)
198 return 0;
199
200 va_start(ap, fmt);
201 rv = vasprintf(&buf, fmt, ap);
202 va_end(ap);
203 if (rv < 0)
204 return -1;
205 return log_dbg_print_free(buf);
206 }
207
208 int
log_dbg_level_printf(int level,const char * function,int thrid,long long unsigned int id,evutil_socket_t fd,evutil_socket_t child_fd,const char * fmt,...)209 log_dbg_level_printf(int level, const char *function, int thrid, long long unsigned int id, evutil_socket_t fd, evutil_socket_t child_fd, const char *fmt, ...)
210 {
211 va_list ap;
212 char *buf;
213 int rv;
214
215 if (dbg_mode == LOG_DBG_MODE_NONE || dbg_mode < level)
216 return 0;
217
218 va_start(ap, fmt);
219 rv = vasprintf(&buf, fmt, ap);
220 va_end(ap);
221 if (rv < 0)
222 return -1;
223
224 char *logbuf;
225 // The *_main and *_main_va macros always pass 0 as fd, and the other macros fd > 0
226 if (fd) {
227 rv = asprintf(&logbuf, "[%s] [%d.%llu fd=%d cfd=%d] %s: %s\n", log_dbg_mode_names[level], thrid, id, fd, child_fd, function, buf);
228 } else {
229 rv = asprintf(&logbuf, "[%s] %s: %s\n", log_dbg_mode_names[level], function, buf);
230 }
231 free(buf);
232 if (rv < 0)
233 return -1;
234 return log_dbg_print_free(logbuf);
235 }
236
237 void
log_dbg_mode(int mode)238 log_dbg_mode(int mode)
239 {
240 dbg_mode = mode;
241 }
242
243 /*
244 * Master key log. Logs master keys in SSLKEYLOGFILE format.
245 * Uses a logger thread.
246 */
247
248 logger_t *masterkey_log = NULL;
249 static int masterkey_fd = -1;
250 static char *masterkey_fn = NULL;
251 static int masterkey_clisock = -1;
252
253 static int
log_masterkey_preinit(const char * logfile)254 log_masterkey_preinit(const char *logfile)
255 {
256 masterkey_fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, DFLT_FILEMODE);
257 if (masterkey_fd == -1) {
258 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
259 logfile, strerror(errno), errno);
260 return -1;
261 }
262 masterkey_fn = strdup(logfile);
263 if (!masterkey_fn) {
264 close(masterkey_fd);
265 masterkey_fd = -1;
266 return -1;
267 }
268 return 0;
269 }
270
271 static int
log_masterkey_reopencb(void)272 log_masterkey_reopencb(void)
273 {
274 close(masterkey_fd);
275 masterkey_fd = privsep_client_openfile(masterkey_clisock,
276 masterkey_fn,
277 0);
278 if (masterkey_fd == -1) {
279 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s\n",
280 masterkey_fn, strerror(errno));
281 free(masterkey_fn);
282 masterkey_fn = NULL;
283 return -1;
284 }
285 return 0;
286 }
287
288 /*
289 * Do the actual write to the open master key log file descriptor.
290 */
291 static ssize_t
log_masterkey_writecb(UNUSED int level,UNUSED void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)292 log_masterkey_writecb(UNUSED int level, UNUSED void *fh, UNUSED unsigned long ctl,
293 const void *buf, size_t sz)
294 {
295 if (write(masterkey_fd, buf, sz) == -1) {
296 log_err_level_printf(LOG_CRIT, "Warning: Failed to write to masterkey log:"
297 " %s\n", strerror(errno));
298 return -1;
299 }
300 return sz;
301 }
302
303 static void
log_masterkey_fini(void)304 log_masterkey_fini(void)
305 {
306 close(masterkey_fd);
307 }
308
309 /*
310 * Connection log. Logs a one-liner to a file-based connection log.
311 * Uses a logger thread.
312 */
313
314 logger_t *connect_log = NULL;
315 static int connect_fd = -1;
316 static char *connect_fn = NULL;
317 static int connect_clisock = -1;
318
319 static int
log_connect_preinit(const char * logfile)320 log_connect_preinit(const char *logfile)
321 {
322 connect_fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, DFLT_FILEMODE);
323 if (connect_fd == -1) {
324 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
325 logfile, strerror(errno), errno);
326 return -1;
327 }
328 connect_fn = strdup(logfile);
329 if (!connect_fn) {
330 close(connect_fd);
331 connect_fd = -1;
332 return -1;
333 }
334 return 0;
335 }
336
337 static int
log_connect_reopencb(void)338 log_connect_reopencb(void)
339 {
340 close(connect_fd);
341 connect_fd = privsep_client_openfile(connect_clisock,
342 connect_fn,
343 0);
344 if (connect_fd == -1) {
345 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s\n",
346 connect_fn, strerror(errno));
347 free(connect_fn);
348 connect_fn = NULL;
349 return -1;
350 }
351 return 0;
352 }
353
354 /*
355 * Do the actual write to the open connection log file descriptor.
356 * We prepend a timestamp here, which means that timestamps are slightly
357 * delayed from the time of actual logging. Since we only have second
358 * resolution that should not make any difference.
359 */
360 static ssize_t
log_connect_writecb(UNUSED int level,UNUSED void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)361 log_connect_writecb(UNUSED int level, UNUSED void *fh, UNUSED unsigned long ctl,
362 const void *buf, size_t sz)
363 {
364 char timebuf[32];
365 time_t epoch;
366 struct tm *utc;
367 size_t n;
368
369 time(&epoch);
370 utc = gmtime(&epoch);
371 n = strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S UTC ", utc);
372 if (n == 0) {
373 log_err_level_printf(LOG_CRIT, "Error from strftime(): buffer too small\n");
374 return -1;
375 }
376 if ((write(connect_fd, timebuf, n) == -1) ||
377 (write(connect_fd, buf, sz) == -1)) {
378 log_err_level_printf(LOG_CRIT, "Failed to write to connect log: %s\n",
379 strerror(errno));
380 return -1;
381 }
382 return sz;
383 }
384
385 static void
log_connect_fini(void)386 log_connect_fini(void)
387 {
388 close(connect_fd);
389 }
390
391 static int
log_info(int facility,const char * buf)392 log_info(int facility, const char *buf)
393 {
394 size_t sz = strlen(buf) + 1;
395 switch (err_mode) {
396 case LOG_ERR_MODE_STDERR:
397 return fwrite(buf, sz - 1, 1, stderr);
398 case LOG_ERR_MODE_SYSLOG:
399 syslog(facility|LOG_INFO, "%s", (const char *)buf);
400 return sz;
401 }
402 return -1;
403 }
404
405 int
log_stats(const char * buf)406 log_stats(const char *buf)
407 {
408 return log_info(LOG_LOCAL0, buf);
409 }
410
411 int
log_conn(const char * buf)412 log_conn(const char *buf)
413 {
414 return log_info(LOG_LOCAL1, buf);
415 }
416
417 /*
418 * Content log.
419 * Logs connection content to either a single file or a directory containing
420 * per-connection logs.
421 * Uses a logger thread; the actual logging happens in a separate thread.
422 * To ensure ordering of requests (open, write, ..., close), logging for a
423 * single connection must happen from a single thread.
424 * This is guaranteed by the current pxythr architecture.
425 */
426
427 #define PREPFLAG_REQUEST 1
428 #define PREPFLAG_EOF 2
429
430 typedef struct log_content_file_ctx {
431 union {
432 struct {
433 char *header_req;
434 char *header_resp;
435 } single;
436 struct {
437 int fd;
438 char *filename;
439 } dir;
440 struct {
441 int fd;
442 char *filename;
443 } spec;
444 } u;
445 } log_content_file_ctx_t;
446
447 typedef struct log_content_pcap_ctx {
448 union {
449 struct {
450 int fd;
451 char *filename;
452 } dir;
453 struct {
454 int fd;
455 char *filename;
456 } spec;
457 } u;
458 logpkt_ctx_t state;
459 } log_content_pcap_ctx_t;
460
461 #ifndef WITHOUT_MIRROR
462 typedef struct log_content_mirror_ctx {
463 logpkt_ctx_t state;
464 } log_content_mirror_ctx_t;
465 #endif /* !WITHOUT_MIRROR */
466
467 static int content_file_clisock = -1;
468 static logger_t *content_file_log = NULL;
469 static int content_pcap_clisock = -1;
470 static logger_t *content_pcap_log = NULL;
471 static uint8_t content_pcap_src_ether[ETHER_ADDR_LEN] = {
472 0x02, 0x00, 0x00, 0x11, 0x11, 0x11};
473 static uint8_t content_pcap_dst_ether[ETHER_ADDR_LEN] = {
474 0x02, 0x00, 0x00, 0x22, 0x22, 0x22};
475 #ifndef WITHOUT_MIRROR
476 static logger_t *content_mirror_log = NULL;
477 static libnet_t *content_mirror_libnet = NULL;
478 static size_t content_mirror_mtu = 0;
479 static uint8_t content_mirror_src_ether[ETHER_ADDR_LEN];
480 static uint8_t content_mirror_dst_ether[ETHER_ADDR_LEN];
481 #endif /* !WITHOUT_MIRROR */
482
483 /*
484 * Split a pathname into static LHS (including final slashes) and dynamic RHS.
485 * Returns -1 on error, 0 on success.
486 * On success, fills in lhs and rhs with newly allocated buffers that must
487 * be freed by the caller.
488 */
489 int
log_content_split_pathspec(const char * path,char ** lhs,char ** rhs)490 log_content_split_pathspec(const char *path, char **lhs, char **rhs)
491 {
492 const char *p, *q, *r;
493
494 p = strchr(path, '%');
495 /* at first % or EOS */
496
497 /* skip % if next char is % (and implicitly not \0) */
498 while (p && p[1] == '%') {
499 p = strchr(p + 2, '%');
500 }
501 /* at first % that is not %%, or at EOS */
502
503 if (!p || !p[1]) {
504 /* EOS: no % that is not %% in path */
505 p = path + strlen(path);
506 }
507 /* at first hot % or at '\0' */
508
509 /* find last / before % */
510 for (r = q = strchr(path, '/'); q && (q < p); q = strchr(q + 1, '/')) {
511 r = q;
512 }
513 if (!(p = r)) {
514 /* no / found, use dummy ./ as LHS */
515 *lhs = strdup("./");
516 if (!*lhs)
517 return -1;
518 *rhs = strdup(path);
519 if (!*rhs) {
520 free(*lhs);
521 return -1;
522 }
523 return 0;
524 }
525 /* at last / terminating the static part of path */
526
527 p++; /* skip / */
528 *lhs = malloc(p - path + 1 /* for terminating null */);
529 if (!*lhs)
530 return -1;
531 memcpy(*lhs, path, p - path);
532 (*lhs)[p - path] = '\0';
533 *rhs = strdup(p);
534 if (!*rhs) {
535 free(*lhs);
536 return -1;
537 }
538
539 return 0;
540 }
541
542 /*
543 * Generate a log path based on the given log spec.
544 * Returns an allocated buffer which must be freed by caller, or NULL on error.
545 */
546 #define PATH_BUF_INC 1024
547 static char * MALLOC NONNULL(1,2,3)
log_content_format_pathspec(const char * logspec,char * srchost,char * srcport,char * dsthost,char * dstport,char * exec_path,char * user,char * group)548 log_content_format_pathspec(const char *logspec,
549 char *srchost, char *srcport,
550 char *dsthost, char *dstport,
551 char *exec_path, char *user, char *group)
552 {
553 /* set up buffer to hold our generated file path */
554 size_t path_buflen = PATH_BUF_INC;
555 char *path_buf = malloc(path_buflen);
556 if (path_buf == NULL) {
557 log_err_level_printf(LOG_CRIT, "Failed to allocate path buffer\n");
558 return NULL;
559 }
560
561 /* initialize the buffer as an empty C string */
562 path_buf[0] = '\0';
563
564 /* iterate over format specifiers */
565 size_t path_len = 0;
566 for (const char *p = logspec; *p != '\0'; p++) {
567 const char *elem = NULL;
568 size_t elem_len = 0;
569
570 const char iso8601[] = "%Y%m%dT%H%M%SZ";
571 char timebuf[24]; /* sized for ISO 8601 format */
572 char addrbuf[INET6_ADDRSTRLEN + 8]; /* [host]:port */
573
574 /* parse the format string and generate the next path element */
575 switch (*p) {
576 case '%':
577 p++;
578 /* handle format specifiers. */
579 switch (*p) {
580 case '\0':
581 /* unexpected eof; backtrack and discard
582 * invalid format spec */
583 p--;
584 elem_len = 0;
585 break;
586 case '%':
587 elem = p;
588 elem_len = 1;
589 break;
590 case 'd':
591 if (snprintf(addrbuf, sizeof(addrbuf),
592 "%s,%s", dsthost, dstport) < 0) {
593 addrbuf[0] = '?';
594 addrbuf[1] = '\0';
595 }
596 elem = addrbuf;
597 elem_len = strlen(addrbuf);
598 break;
599 case 'D':
600 elem = dsthost;
601 elem_len = strlen(dsthost);
602 break;
603 case 'p':
604 elem = dstport;
605 elem_len = strlen(dstport);
606 break;
607 case 's':
608 if (snprintf(addrbuf, sizeof(addrbuf),
609 "%s,%s", srchost, srcport) < 0) {
610 addrbuf[0] = '?';
611 addrbuf[1] = '\0';
612 }
613 elem = addrbuf;
614 elem_len = strlen(addrbuf);
615 break;
616 case 'S':
617 elem = srchost;
618 elem_len = strlen(srchost);
619 break;
620 case 'q':
621 elem = srcport;
622 elem_len = strlen(srcport);
623 break;
624 case 'x':
625 if (exec_path) {
626 char *match = exec_path;
627 while ((match = strchr(match, '/')) != NULL) {
628 match++;
629 elem = match;
630 }
631 elem_len = elem ? strlen(elem) : 0;
632 } else {
633 elem_len = 0;
634 }
635 break;
636 case 'X':
637 elem = exec_path;
638 elem_len = exec_path ? strlen(exec_path) : 0;
639 break;
640 case 'u':
641 elem = user;
642 elem_len = user ? strlen(user) : 0;
643 break;
644 case 'g':
645 elem = group;
646 elem_len = group ? strlen(group) : 0;
647 break;
648 case 'T': {
649 time_t epoch;
650 struct tm *utc;
651
652 time(&epoch);
653 utc = gmtime(&epoch);
654 strftime(timebuf, sizeof(timebuf), iso8601, utc);
655
656 elem = timebuf;
657 elem_len = sizeof(timebuf);
658 break;
659 }}
660 break;
661 default:
662 elem = p;
663 elem_len = 1;
664 break;
665 }
666
667 if (elem_len > 0) {
668 /* growing the buffer to fit elem_len + terminating \0 */
669 if (path_buflen - path_len < elem_len + 1) {
670 /* Grow in PATH_BUF_INC chunks.
671 * Note that the use of `PATH_BUF_INC' provides
672 * our guaranteed space for a trailing '\0' */
673 path_buflen += elem_len + PATH_BUF_INC;
674 char *newbuf = realloc(path_buf, path_buflen);
675 if (newbuf == NULL) {
676 log_err_level_printf(LOG_CRIT, "Failed to reallocate"
677 " path buffer\n");
678 free(path_buf);
679 return NULL;
680 }
681 path_buf = newbuf;
682 }
683
684 strncat(path_buf, elem, elem_len);
685 path_len += elem_len;
686 }
687 }
688
689 /* apply terminating NUL */
690 assert(path_buflen > path_len);
691 path_buf[path_len] = '\0';
692 return path_buf;
693 }
694 #undef PATH_BUF_INC
695
696 /*
697 * log_content_ctx_t is preallocated by the caller (part of connection ctx).
698 */
699 int
log_content_open(log_content_ctx_t * ctx,global_t * global,const struct sockaddr * srcaddr,socklen_t srcaddrlen,const struct sockaddr * dstaddr,socklen_t dstaddrlen,char * srchost,char * srcport,char * dsthost,char * dstport,char * exec_path,char * user,char * group,int log_content,int log_pcap,int log_mirror)700 log_content_open(log_content_ctx_t *ctx, global_t *global,
701 const struct sockaddr *srcaddr, socklen_t srcaddrlen,
702 const struct sockaddr *dstaddr, socklen_t dstaddrlen,
703 char *srchost, char *srcport,
704 char *dsthost, char *dstport,
705 char *exec_path, char *user, char *group,
706 int log_content, int log_pcap
707 #ifndef WITHOUT_MIRROR
708 , int log_mirror
709 #endif /* !WITHOUT_MIRROR */
710 )
711 {
712 char timebuf[24];
713 time_t epoch;
714 struct tm *utc;
715 char *dsthost_clean = NULL;
716 char *srchost_clean = NULL;
717
718 if (ctx->file || ctx->pcap
719 #ifndef WITHOUT_MIRROR
720 || ctx->mirror
721 #endif /* !WITHOUT_MIRROR */
722 )
723 return 0; /* does this actually happen? */
724
725 if (!log_content && !log_pcap
726 #ifndef WITHOUT_MIRROR
727 && !log_mirror
728 #endif /* !WITHOUT_MIRROR */
729 ) {
730 return 0;
731 }
732
733 if ((log_content && (global->contentlog_isdir || global->contentlog_isspec)) ||
734 (log_pcap && (global->pcaplog_isdir || global->pcaplog_isspec))) {
735 if (global->contentlog_isdir || global->pcaplog_isdir) {
736 if (time(&epoch) == -1) {
737 log_err_level_printf(LOG_CRIT, "Failed to get time\n");
738 goto errout;
739 }
740 if ((utc = gmtime(&epoch)) == NULL) {
741 log_err_level_printf(LOG_CRIT, "Failed to convert time:"
742 " %s (%i)\n",
743 strerror(errno), errno);
744 goto errout;
745 }
746 if (!strftime(timebuf, sizeof(timebuf),
747 "%Y%m%dT%H%M%SZ", utc)) {
748 log_err_level_printf(LOG_CRIT, "Failed to format time:"
749 " %s (%i)\n",
750 strerror(errno), errno);
751 goto errout;
752 }
753 }
754
755 srchost_clean = sys_ip46str_sanitize(srchost);
756 if (!srchost_clean) {
757 log_err_level_printf(LOG_CRIT, "Failed to sanitize srchost\n");
758 goto errout;
759 }
760 dsthost_clean = sys_ip46str_sanitize(dsthost);
761 if (!dsthost_clean) {
762 log_err_level_printf(LOG_CRIT, "Failed to sanitize dsthost\n");
763 free(srchost_clean);
764 goto errout;
765 }
766 }
767
768 if (log_content && global->contentlog) {
769 ctx->file = malloc(sizeof(log_content_file_ctx_t));
770 if (!ctx->file)
771 goto errout;
772 memset(ctx->file, 0, sizeof(log_content_file_ctx_t));
773
774 if (global->contentlog_isdir) {
775 /* per-connection-file content log (-S) */
776 if (asprintf(&ctx->file->u.dir.filename,
777 "%s/%s-%s,%s-%s,%s.log",
778 global->contentlog, timebuf,
779 srchost_clean, srcport,
780 dsthost_clean, dstport) < 0) {
781 log_err_level_printf(LOG_CRIT, "Failed to format filename:"
782 " %s (%i)\n",
783 strerror(errno), errno);
784 goto errout;
785 }
786 } else if (global->contentlog_isspec) {
787 /* per-connection-file content log with logspec (-F) */
788 ctx->file->u.spec.filename =
789 log_content_format_pathspec(global->contentlog,
790 srchost_clean,
791 srcport,
792 dsthost_clean,
793 dstport,
794 exec_path,
795 user, group);
796 if (!ctx->file->u.spec.filename) {
797 goto errout;
798 }
799 } else {
800 /* single-file content log (-L) */
801 if (asprintf(&ctx->file->u.single.header_req,
802 "[%s]:%s -> [%s]:%s",
803 srchost, srcport, dsthost, dstport) < 0) {
804 goto errout;
805 }
806 if (asprintf(&ctx->file->u.single.header_resp,
807 "[%s]:%s -> [%s]:%s",
808 dsthost, dstport, srchost, srcport) < 0) {
809 free(ctx->file->u.single.header_req);
810 goto errout;
811 }
812 }
813 }
814
815 if (log_pcap && global->pcaplog) {
816 ctx->pcap = malloc(sizeof(log_content_pcap_ctx_t));
817 if (!ctx->pcap)
818 goto errout;
819 memset(ctx->pcap, 0, sizeof(log_content_pcap_ctx_t));
820
821 logpkt_ctx_init(&ctx->pcap->state, NULL, 0,
822 content_pcap_src_ether, content_pcap_dst_ether,
823 srcaddr, srcaddrlen, dstaddr, dstaddrlen);
824
825 if (global->pcaplog_isdir) {
826 /* per-connection-file pcap log (-Y) */
827 if (asprintf(&ctx->pcap->u.dir.filename,
828 "%s/%s-%s,%s-%s,%s.pcap",
829 global->pcaplog, timebuf,
830 srchost_clean, srcport,
831 dsthost_clean, dstport) < 0) {
832 log_err_level_printf(LOG_CRIT, "Failed to format filename:"
833 " %s (%i)\n",
834 strerror(errno), errno);
835 goto errout;
836 }
837 } else if (global->pcaplog_isspec) {
838 /* per-connection-file pcap log with logspec (-y) */
839 ctx->pcap->u.spec.filename =
840 log_content_format_pathspec(global->pcaplog,
841 srchost_clean,
842 srcport,
843 dsthost_clean,
844 dstport,
845 exec_path,
846 user, group);
847 if (!ctx->pcap->u.spec.filename) {
848 goto errout;
849 }
850 }
851 }
852
853 #ifndef WITHOUT_MIRROR
854 if (log_mirror && global->mirrorif) {
855 ctx->mirror = malloc(sizeof(log_content_mirror_ctx_t));
856 if (!ctx->mirror)
857 goto errout;
858 memset(ctx->mirror, 0, sizeof(log_content_mirror_ctx_t));
859
860 logpkt_ctx_init(&ctx->mirror->state,
861 content_mirror_libnet,
862 content_mirror_mtu,
863 content_mirror_src_ether,
864 content_mirror_dst_ether,
865 srcaddr, srcaddrlen, dstaddr, dstaddrlen);
866 }
867 #endif /* !WITHOUT_MIRROR */
868
869 /* submit open events */
870 if (log_content && ctx->file) {
871 if (logger_open(content_file_log, ctx->file) == -1)
872 goto errout;
873 }
874 if (log_pcap && ctx->pcap) {
875 if (logger_open(content_pcap_log, ctx->pcap) == -1)
876 goto errout;
877 }
878 #ifndef WITHOUT_MIRROR
879 if (log_mirror && ctx->mirror) {
880 if (logger_open(content_mirror_log, ctx->mirror) == -1)
881 goto errout;
882 }
883 #endif /* !WITHOUT_MIRROR */
884
885 if (srchost_clean)
886 free(srchost_clean);
887 if (dsthost_clean)
888 free(dsthost_clean);
889 return 0;
890
891 errout:
892 if (srchost_clean)
893 free(srchost_clean);
894 if (dsthost_clean)
895 free(dsthost_clean);
896 if (ctx->file)
897 free(ctx->file);
898 if (ctx->pcap) {
899 free(ctx->pcap);
900 }
901 #ifndef WITHOUT_MIRROR
902 if (ctx->mirror) {
903 free(ctx->mirror);
904 }
905 #endif /* !WITHOUT_MIRROR */
906 memset(ctx, 0, sizeof(log_content_ctx_t));
907 return -1;
908 }
909
910 /*
911 * On failure, lb is not freed.
912 */
913 int
log_content_submit(log_content_ctx_t * ctx,logbuf_t * lb,int is_request,int log_content,int log_pcap,int log_mirror)914 log_content_submit(log_content_ctx_t *ctx, logbuf_t *lb, int is_request, int log_content, int log_pcap
915 #ifndef WITHOUT_MIRROR
916 , int log_mirror
917 #endif /* !WITHOUT_MIRROR */
918 )
919 {
920 unsigned long prepflags = 0;
921 logbuf_t *lbpcap, *lbmirror;
922
923 if (is_request)
924 prepflags |= PREPFLAG_REQUEST;
925
926 lb = logbuf_make_contiguous(lb);
927 if (!lb)
928 return -1;
929
930 lbpcap = lbmirror = lb;
931 if (log_content && content_file_log) {
932 if (log_pcap && content_pcap_log) {
933 lbpcap = logbuf_new_deepcopy(lb, 1);
934 if (!lbpcap)
935 goto errout;
936 }
937 #ifndef WITHOUT_MIRROR
938 if (log_mirror && content_mirror_log) {
939 lbmirror = logbuf_new_deepcopy(lb, 1);
940 if (!lbmirror)
941 goto errout;
942 }
943 } else if (log_pcap && content_pcap_log && log_mirror && content_mirror_log) {
944 lbmirror = logbuf_new_deepcopy(lb, 1);
945 if (!lbmirror)
946 goto errout;
947 #endif /* !WITHOUT_MIRROR */
948 }
949
950 if (log_pcap && content_pcap_log) {
951 if (logger_submit(content_pcap_log, ctx->pcap,
952 prepflags, lbpcap) == -1) {
953 goto errout;
954 }
955 lbpcap = NULL;
956 }
957 #ifndef WITHOUT_MIRROR
958 if (log_mirror && content_mirror_log) {
959 if (logger_submit(content_mirror_log, ctx->mirror,
960 prepflags, lbmirror) == -1) {
961 goto errout;
962 }
963 lbmirror = NULL;
964 }
965 #endif /* !WITHOUT_MIRROR */
966 if (log_content && content_file_log) {
967 if (logger_submit(content_file_log, ctx->file,
968 prepflags, lb) == -1) {
969 return -1;
970 }
971 }
972 return 0;
973 errout:
974 if (lbpcap && lbpcap != lb)
975 logbuf_free(lbpcap);
976 if (lbmirror && lbmirror != lb)
977 logbuf_free(lbmirror);
978 return -1;
979 }
980
981 int
log_content_close(log_content_ctx_t * ctx,int by_requestor)982 log_content_close(log_content_ctx_t *ctx, int by_requestor)
983 {
984 unsigned long prepflags = PREPFLAG_EOF;
985 unsigned long ctl;
986
987 if (by_requestor) {
988 prepflags |= PREPFLAG_REQUEST;
989 ctl = LBFLAG_IS_REQ;
990 } else {
991 ctl = LBFLAG_IS_RESP;
992 }
993
994 /* We call submit an empty log buffer in order to give the content log
995 * a chance to insert an EOF footer to be logged before actually
996 * closing the file. The logger_close() call will actually close the
997 * log. Some logs prefer to use the close callback for logging the
998 * close event to the log. */
999 if (content_file_log && ctx->file) {
1000 if (logger_submit(content_file_log, ctx->file,
1001 prepflags, NULL) == -1) {
1002 return -1;
1003 }
1004 if (logger_close(content_file_log, ctx->file, ctl) == -1) {
1005 return -1;
1006 }
1007 ctx->file = NULL;
1008 }
1009 if (content_pcap_log && ctx->pcap) {
1010 if (logger_submit(content_pcap_log, ctx->pcap,
1011 prepflags, NULL) == -1) {
1012 return -1;
1013 }
1014 if (logger_close(content_pcap_log, ctx->pcap, ctl) == -1) {
1015 return -1;
1016 }
1017 ctx->pcap = NULL;
1018 }
1019 #ifndef WITHOUT_MIRROR
1020 if (content_mirror_log && ctx->mirror) {
1021 if (logger_submit(content_mirror_log, ctx->mirror,
1022 prepflags, NULL) == -1) {
1023 return -1;
1024 }
1025 if (logger_close(content_mirror_log, ctx->mirror, ctl) == -1) {
1026 return -1;
1027 }
1028 ctx->mirror = NULL;
1029 }
1030 #endif /* !WITHOUT_MIRROR */
1031 return 0;
1032 }
1033
1034 /*
1035 * Log-type specific code.
1036 *
1037 * The init/fini functions are executed globally in the main thread.
1038 * Callback functions are executed in the logger thread.
1039 */
1040
1041 static int
log_content_file_dir_opencb(void * fh)1042 log_content_file_dir_opencb(void *fh)
1043 {
1044 log_content_file_ctx_t *ctx = fh;
1045
1046 if ((ctx->u.dir.fd = privsep_client_openfile(content_file_clisock,
1047 ctx->u.dir.filename,
1048 0)) == -1) {
1049 log_err_level_printf(LOG_CRIT, "Opening logdir file '%s' failed: %s (%i)\n",
1050 ctx->u.dir.filename,
1051 strerror(errno), errno);
1052 return -1;
1053 }
1054 return 0;
1055 }
1056
1057 static void
log_content_file_dir_closecb(void * fh,UNUSED unsigned long ctl)1058 log_content_file_dir_closecb(void *fh, UNUSED unsigned long ctl)
1059 {
1060 log_content_file_ctx_t *ctx = fh;
1061
1062 if (ctx->u.dir.filename)
1063 free(ctx->u.dir.filename);
1064 if (ctx->u.dir.fd != 1)
1065 close(ctx->u.dir.fd);
1066 free(ctx);
1067 }
1068
1069 static ssize_t
log_content_file_dir_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1070 log_content_file_dir_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1071 const void *buf, size_t sz)
1072 {
1073 log_content_file_ctx_t *ctx = fh;
1074
1075 if (write(ctx->u.dir.fd, buf, sz) == -1) {
1076 log_err_level_printf(LOG_CRIT, "Failed to write to content log: %s\n",
1077 strerror(errno));
1078 return -1;
1079 }
1080 return sz;
1081 }
1082
1083 static int
log_content_file_spec_opencb(void * fh)1084 log_content_file_spec_opencb(void *fh)
1085 {
1086 log_content_file_ctx_t *ctx = fh;
1087
1088 if ((ctx->u.spec.fd = privsep_client_openfile(content_file_clisock,
1089 ctx->u.spec.filename,
1090 1)) == -1) {
1091 log_err_level_printf(LOG_CRIT, "Opening logspec file '%s' failed: %s (%i)\n",
1092 ctx->u.spec.filename, strerror(errno), errno);
1093 return -1;
1094 }
1095 return 0;
1096 }
1097
1098 static void
log_content_file_spec_closecb(void * fh,UNUSED unsigned long ctl)1099 log_content_file_spec_closecb(void *fh, UNUSED unsigned long ctl)
1100 {
1101 log_content_file_ctx_t *ctx = fh;
1102
1103 if (ctx->u.spec.filename)
1104 free(ctx->u.spec.filename);
1105 if (ctx->u.spec.fd != -1)
1106 close(ctx->u.spec.fd);
1107 free(ctx);
1108 }
1109
1110 static ssize_t
log_content_file_spec_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1111 log_content_file_spec_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1112 const void *buf, size_t sz)
1113 {
1114 log_content_file_ctx_t *ctx = fh;
1115
1116 if (write(ctx->u.spec.fd, buf, sz) == -1) {
1117 log_err_level_printf(LOG_CRIT, "Failed to write to content log: %s\n",
1118 strerror(errno));
1119 return -1;
1120 }
1121 return sz;
1122 }
1123
1124 static int content_file_single_fd = -1;
1125 static char *content_file_single_fn = NULL;
1126
1127 static int
log_content_file_single_preinit(const char * logfile)1128 log_content_file_single_preinit(const char *logfile)
1129 {
1130 content_file_single_fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT,
1131 DFLT_FILEMODE);
1132 if (content_file_single_fd == -1) {
1133 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1134 logfile, strerror(errno), errno);
1135 return -1;
1136 }
1137 content_file_single_fn = strdup(logfile);
1138 if (!content_file_single_fn) {
1139 close(content_file_single_fd);
1140 content_file_single_fd = -1;
1141 return -1;
1142 }
1143 return 0;
1144 }
1145
1146 static void
log_content_file_single_fini(void)1147 log_content_file_single_fini(void)
1148 {
1149 if (content_file_single_fn) {
1150 free(content_file_single_fn);
1151 content_file_single_fn = NULL;
1152 }
1153 if (content_file_single_fd != -1) {
1154 close(content_file_single_fd);
1155 content_file_single_fd = -1;
1156 }
1157 }
1158
1159 static int
log_content_file_single_reopencb(void)1160 log_content_file_single_reopencb(void)
1161 {
1162 close(content_file_single_fd);
1163 content_file_single_fd = privsep_client_openfile(content_file_clisock,
1164 content_file_single_fn,
1165 0);
1166 if (content_file_single_fd == -1) {
1167 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1168 content_file_single_fn, strerror(errno), errno);
1169 return -1;
1170 }
1171 return 0;
1172 }
1173
1174 static void
log_content_file_single_closecb(void * fh,UNUSED unsigned long ctl)1175 log_content_file_single_closecb(void *fh, UNUSED unsigned long ctl)
1176 {
1177 log_content_file_ctx_t *ctx = fh;
1178
1179 if (ctx->u.single.header_req) {
1180 free(ctx->u.single.header_req);
1181 }
1182 if (ctx->u.single.header_resp) {
1183 free(ctx->u.single.header_resp);
1184 }
1185 free(ctx);
1186 }
1187
1188 static ssize_t
log_content_file_single_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1189 log_content_file_single_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1190 const void *buf, size_t sz)
1191 {
1192 UNUSED log_content_file_ctx_t *ctx = fh;
1193
1194 if (write(content_file_single_fd, buf, sz) == -1) {
1195 log_err_level_printf(LOG_CRIT, "Failed to write to content log: %s\n",
1196 strerror(errno));
1197 return -1;
1198 }
1199 return sz;
1200 }
1201
1202 static logbuf_t *
log_content_file_single_prepcb(void * fh,unsigned long prepflags,logbuf_t * lb)1203 log_content_file_single_prepcb(void *fh, unsigned long prepflags,
1204 logbuf_t *lb)
1205 {
1206 log_content_file_ctx_t *ctx = fh;
1207 int is_request = !!(prepflags & PREPFLAG_REQUEST);
1208 logbuf_t *head;
1209 time_t epoch;
1210 struct tm *utc;
1211 char *header;
1212
1213 if (!(header = is_request ? ctx->u.single.header_req
1214 : ctx->u.single.header_resp))
1215 goto out;
1216
1217 /* prepend size tag or EOF, and newline */
1218 if (prepflags & PREPFLAG_EOF) {
1219 head = logbuf_new_printf(NULL, " (EOF)\n");
1220 } else {
1221 head = logbuf_new_printf(lb, " (%zu):\n", logbuf_size(lb));
1222 }
1223 if (!head) {
1224 log_err_level_printf(LOG_CRIT, "Failed to allocate memory\n");
1225 logbuf_free(lb);
1226 return NULL;
1227 }
1228 lb = head;
1229
1230 /* prepend header */
1231 head = logbuf_new_copy(header, strlen(header), lb);
1232 if (!head) {
1233 log_err_level_printf(LOG_CRIT, "Failed to allocate memory\n");
1234 logbuf_free(lb);
1235 return NULL;
1236 }
1237 lb = head;
1238
1239 /* prepend timestamp */
1240 head = logbuf_new_alloc(32, lb);
1241 if (!head) {
1242 log_err_level_printf(LOG_CRIT, "Failed to allocate memory\n");
1243 logbuf_free(lb);
1244 return NULL;
1245 }
1246 lb = head;
1247 time(&epoch);
1248 utc = gmtime(&epoch);
1249 lb->sz = strftime((char*)lb->buf, lb->sz, "%Y-%m-%d %H:%M:%S UTC ",
1250 utc);
1251
1252 out:
1253 return lb;
1254 }
1255
1256 /*
1257 * Pcap writer for -X/-Y/-y options.
1258 */
1259 static int content_pcap_fd = -1;
1260 static char *content_pcap_fn = NULL;
1261
1262 /*
1263 * Initialize pcap content logging. For single-file mode, pcapfile is the
1264 * path to the file. For dir/spec modes, pcapfile is NULL.
1265 */
1266 static int
log_content_pcap_preinit(const char * pcapfile)1267 log_content_pcap_preinit(const char *pcapfile)
1268 {
1269 if (!pcapfile)
1270 return 0;
1271
1272 /* single file pcap mode */
1273
1274 content_pcap_fd = open(pcapfile, O_RDWR|O_CREAT, DFLT_FILEMODE);
1275 if (content_pcap_fd == -1) {
1276 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1277 pcapfile, strerror(errno), errno);
1278 return -1;
1279 }
1280 if (logpkt_pcap_open_fd(content_pcap_fd) == -1) {
1281 log_err_level_printf(LOG_CRIT, "Failed to prepare '%s' for PCAP writing"
1282 ": %s (%i)\n",
1283 pcapfile, strerror(errno), errno);
1284 close(content_pcap_fd);
1285 content_pcap_fd = -1;
1286 return -1;
1287 }
1288 content_pcap_fn = strdup(pcapfile);
1289 if (!content_pcap_fn) {
1290 close(content_pcap_fd);
1291 content_pcap_fd = -1;
1292 return -1;
1293 }
1294 return 0;
1295 }
1296
1297 static void
log_content_pcap_fini(void)1298 log_content_pcap_fini(void)
1299 {
1300 if (content_pcap_fn) {
1301 free(content_pcap_fn);
1302 content_pcap_fn = NULL;
1303 }
1304 if (content_pcap_fd != -1) {
1305 close(content_pcap_fd);
1306 content_pcap_fd = -1;
1307 }
1308 }
1309
1310 static int
log_content_pcap_reopencb(void)1311 log_content_pcap_reopencb(void) {
1312 close(content_pcap_fd);
1313 content_pcap_fd = privsep_client_openfile(content_pcap_clisock,
1314 content_pcap_fn,
1315 0);
1316 if (content_pcap_fd == -1) {
1317 log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1318 content_pcap_fn, strerror(errno), errno);
1319 return -1;
1320 }
1321 if (logpkt_pcap_open_fd(content_pcap_fd) == -1) {
1322 log_err_level_printf(LOG_CRIT, "Failed to prepare '%s' for PCAP writing"
1323 ": %s (%i)\n",
1324 content_pcap_fn, strerror(errno), errno);
1325 close(content_pcap_fd);
1326 content_pcap_fd = -1;
1327 return -1;
1328 }
1329 return 0;
1330 }
1331
1332 static void
log_content_pcap_closecb_base(void * fh,unsigned long ctl,int fd)1333 log_content_pcap_closecb_base(void *fh, unsigned long ctl, int fd) {
1334 log_content_pcap_ctx_t *ctx = fh;
1335 int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1336 : LOGPKT_RESPONSE;
1337
1338 logpkt_write_close(&ctx->state, fd, direction);
1339 }
1340
1341 static void
log_content_pcap_closecb(void * fh,unsigned long ctl)1342 log_content_pcap_closecb(void *fh, unsigned long ctl) {
1343 log_content_pcap_ctx_t *ctx = fh;
1344 log_content_pcap_closecb_base(fh, ctl, content_pcap_fd);
1345 free(ctx);
1346 }
1347
1348 static ssize_t
log_content_pcap_writecb_base(void * fh,unsigned long ctl,const void * buf,size_t sz,int fd)1349 log_content_pcap_writecb_base(void *fh, unsigned long ctl,
1350 const void *buf, size_t sz, int fd) {
1351 log_content_pcap_ctx_t *ctx = fh;
1352 int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1353 : LOGPKT_RESPONSE;
1354
1355 if (logpkt_write_payload(&ctx->state, fd, direction, buf, sz) == -1)
1356 goto errout;
1357
1358 return sz;
1359 errout:
1360 log_err_level_printf(LOG_CRIT, "Failed to write to pcap log: %s (%i)\n",
1361 strerror(errno), errno);
1362 return -1;
1363 }
1364
1365 static ssize_t
log_content_pcap_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1366 log_content_pcap_writecb(UNUSED int level, void *fh, unsigned long ctl,
1367 const void *buf, size_t sz) {
1368 return log_content_pcap_writecb_base(fh, ctl, buf, sz, content_pcap_fd);
1369 }
1370
1371 static int
log_content_pcap_dir_opencb(void * fh)1372 log_content_pcap_dir_opencb(void *fh)
1373 {
1374 log_content_pcap_ctx_t *ctx = fh;
1375
1376 if ((ctx->u.dir.fd = privsep_client_openfile(content_pcap_clisock,
1377 ctx->u.dir.filename,
1378 0)) == -1) {
1379 log_err_level_printf(LOG_CRIT, "Opening pcapdir file '%s' failed: %s (%i)\n",
1380 ctx->u.dir.filename, strerror(errno), errno);
1381 return -1;
1382 }
1383 return logpkt_pcap_open_fd(ctx->u.dir.fd);
1384 }
1385
1386 static void
log_content_pcap_dir_closecb(void * fh,unsigned long ctl)1387 log_content_pcap_dir_closecb(void *fh, unsigned long ctl)
1388 {
1389 log_content_pcap_ctx_t *ctx = fh;
1390 log_content_pcap_closecb_base(fh, ctl, ctx->u.dir.fd);
1391 if (ctx->u.dir.filename)
1392 free(ctx->u.dir.filename);
1393 if (ctx->u.dir.fd != -1)
1394 close(ctx->u.dir.fd);
1395 free(ctx);
1396 }
1397
1398 static ssize_t
log_content_pcap_dir_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1399 log_content_pcap_dir_writecb(UNUSED int level, void *fh, unsigned long ctl,
1400 const void *buf, size_t sz)
1401 {
1402 log_content_pcap_ctx_t *ctx = fh;
1403 return log_content_pcap_writecb_base(fh, ctl, buf, sz, ctx->u.dir.fd);
1404 }
1405
1406 static int
log_content_pcap_spec_opencb(void * fh)1407 log_content_pcap_spec_opencb(void *fh)
1408 {
1409 log_content_pcap_ctx_t *ctx = fh;
1410
1411 if ((ctx->u.spec.fd = privsep_client_openfile(content_pcap_clisock,
1412 ctx->u.spec.filename,
1413 1)) == -1) {
1414 log_err_level_printf(LOG_CRIT, "Opening pcapspec file '%s' failed: %s (%i)\n",
1415 ctx->u.spec.filename, strerror(errno), errno);
1416 return -1;
1417 }
1418 return logpkt_pcap_open_fd(ctx->u.spec.fd);
1419 }
1420
1421 static void
log_content_pcap_spec_closecb(void * fh,unsigned long ctl)1422 log_content_pcap_spec_closecb(void *fh, unsigned long ctl)
1423 {
1424 log_content_pcap_ctx_t *ctx = fh;
1425 log_content_pcap_closecb_base(fh, ctl, ctx->u.spec.fd);
1426 if (ctx->u.spec.filename)
1427 free(ctx->u.spec.filename);
1428 if (ctx->u.spec.fd != -1)
1429 close(ctx->u.spec.fd);
1430 free(ctx);
1431 }
1432
1433 static ssize_t
log_content_pcap_spec_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1434 log_content_pcap_spec_writecb(UNUSED int level, void *fh, unsigned long ctl,
1435 const void *buf, size_t sz)
1436 {
1437 log_content_pcap_ctx_t *ctx = fh;
1438 return log_content_pcap_writecb_base(fh, ctl, buf, sz, ctx->u.spec.fd);
1439 }
1440
1441 static logbuf_t *
log_content_pcap_prepcb(UNUSED void * fh,unsigned long prepflags,logbuf_t * lb)1442 log_content_pcap_prepcb(UNUSED void *fh, unsigned long prepflags,
1443 logbuf_t *lb) {
1444 /* log_content_pcap_ctx_t *ctx = fh; */
1445 if (prepflags & PREPFLAG_EOF)
1446 return lb;
1447 logbuf_ctl_set(lb, (prepflags & PREPFLAG_REQUEST) ? LBFLAG_IS_REQ
1448 : LBFLAG_IS_RESP);
1449 return lb;
1450 }
1451
1452 /*
1453 * Mirror writer for -T/-I options.
1454 */
1455
1456 #ifndef WITHOUT_MIRROR
1457 static int
log_content_mirror_preinit(const char * ifname,const char * targetip)1458 log_content_mirror_preinit(const char *ifname, const char *targetip) {
1459 char errbuf[LIBNET_ERRBUF_SIZE];
1460
1461 /* cast to char* needed on OpenBSD */
1462 content_mirror_libnet = libnet_init(LIBNET_LINK, (char *)ifname,
1463 errbuf);
1464 if (content_mirror_libnet == NULL) {
1465 log_err_level_printf(LOG_CRIT, "Failed to init mirror libnet: %s\n", errbuf);
1466 return -1;
1467 }
1468 libnet_seed_prand(content_mirror_libnet);
1469
1470 content_mirror_mtu = sys_get_mtu(ifname);
1471 if (content_mirror_mtu == 0) {
1472 log_err_level_printf(LOG_CRIT, "Failed to lookup MTU of interface %s\n",
1473 ifname);
1474 return -1;
1475 }
1476
1477 if (logpkt_ether_lookup(content_mirror_libnet,
1478 content_mirror_src_ether,
1479 content_mirror_dst_ether,
1480 targetip, ifname) == -1) {
1481 log_err_level_printf(LOG_CRIT, "Failed to lookup target ether\n");
1482 libnet_destroy(content_mirror_libnet);
1483 return -1;
1484 }
1485
1486 return 0;
1487 }
1488
1489 static void
log_content_mirror_fini(void)1490 log_content_mirror_fini(void)
1491 {
1492 if (content_mirror_libnet) {
1493 libnet_destroy(content_mirror_libnet);
1494 }
1495 }
1496
1497 static void
log_content_mirror_closecb(void * fh,unsigned long ctl)1498 log_content_mirror_closecb(void *fh, unsigned long ctl) {
1499 log_content_mirror_ctx_t *ctx = fh;
1500 int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1501 : LOGPKT_RESPONSE;
1502
1503 logpkt_write_close(&ctx->state, -1, direction);
1504 free(ctx);
1505 }
1506
1507 static ssize_t
log_content_mirror_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1508 log_content_mirror_writecb(UNUSED int level, void *fh, unsigned long ctl,
1509 const void *buf, size_t sz) {
1510 log_content_mirror_ctx_t *ctx = fh;
1511 int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1512 : LOGPKT_RESPONSE;
1513
1514 if (logpkt_write_payload(&ctx->state, -1, direction, buf, sz) == -1)
1515 goto errout;
1516 return sz;
1517
1518 errout:
1519 log_err_level_printf(LOG_CRIT, "Failed to write to mirror log: %s (%i)\n",
1520 strerror(errno), errno);
1521 return -1;
1522 }
1523
1524 static logbuf_t *
log_content_mirror_prepcb(UNUSED void * fh,unsigned long prepflags,logbuf_t * lb)1525 log_content_mirror_prepcb(UNUSED void *fh, unsigned long prepflags,
1526 logbuf_t *lb) {
1527 /* log_content_mirror_ctx_t *ctx = fh; */
1528 if (prepflags & PREPFLAG_EOF)
1529 return lb;
1530 logbuf_ctl_set(lb, (prepflags & PREPFLAG_REQUEST) ? LBFLAG_IS_REQ
1531 : LBFLAG_IS_RESP);
1532 return lb;
1533 }
1534 #endif /* !WITHOUT_MIRROR */
1535
1536 /*
1537 * Certificate writer for -w/-W options.
1538 */
1539 static logger_t *cert_log = NULL;
1540 static int cert_clisock = -1; /* privsep client socket for cert logger */
1541
1542 int
log_cert_submit(const char * fn,X509 * crt)1543 log_cert_submit(const char *fn, X509 *crt)
1544 {
1545 void *fh;
1546 logbuf_t *lb;
1547 char *pem;
1548
1549 if (!(fh = strdup(fn)))
1550 goto errout1;
1551 if (!(pem = ssl_x509_to_pem(crt)))
1552 goto errout2;
1553 if (!(lb = logbuf_new(0, pem, strlen(pem), NULL)))
1554 goto errout3;
1555 return logger_submit(cert_log, fh, 0, lb);
1556 errout3:
1557 free(pem);
1558 errout2:
1559 free(fh);
1560 errout1:
1561 return -1;
1562 }
1563
1564 static ssize_t
log_cert_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1565 log_cert_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1566 const void *buf, size_t sz)
1567 {
1568 char *fn = fh;
1569 int fd;
1570
1571 if ((fd = privsep_client_certfile(cert_clisock, fn)) == -1) {
1572 if (errno != EEXIST) {
1573 log_err_level_printf(LOG_CRIT, "Failed to open '%s': %s (%i)\n",
1574 fn, strerror(errno), errno);
1575 return -1;
1576 }
1577 return sz;
1578 }
1579 if (write(fd, buf, sz) == -1) {
1580 log_err_level_printf(LOG_CRIT, "Failed to write to '%s': %s (%i)\n",
1581 fn, strerror(errno), errno);
1582 close(fd);
1583 return -1;
1584 }
1585 close(fd);
1586 return sz;
1587 }
1588
1589
1590 /*
1591 * Initialization and destruction.
1592 */
1593
1594 /*
1595 * Log pre-init: open all log files but don't start any threads, since we may
1596 * fork() after pre-initialization.
1597 * Return -1 on errors, 0 otherwise.
1598 */
1599 int
log_preinit(global_t * global)1600 log_preinit(global_t *global)
1601 {
1602 logger_reopen_func_t reopencb;
1603 logger_open_func_t opencb;
1604 logger_close_func_t closecb;
1605 logger_write_func_t writecb;
1606 logger_prep_func_t prepcb;
1607
1608 if (global->contentlog) {
1609 if (global->contentlog_isdir) {
1610 reopencb = NULL;
1611 opencb = log_content_file_dir_opencb;
1612 closecb = log_content_file_dir_closecb;
1613 writecb = log_content_file_dir_writecb;
1614 prepcb = NULL;
1615 } else if (global->contentlog_isspec) {
1616 reopencb = NULL;
1617 opencb = log_content_file_spec_opencb;
1618 closecb = log_content_file_spec_closecb;
1619 writecb = log_content_file_spec_writecb;
1620 prepcb = NULL;
1621 } else {
1622 if (log_content_file_single_preinit(global->contentlog) == -1)
1623 goto out;
1624 reopencb = log_content_file_single_reopencb;
1625 opencb = NULL;
1626 closecb = log_content_file_single_closecb;
1627 writecb = log_content_file_single_writecb;
1628 prepcb = log_content_file_single_prepcb;
1629 }
1630 if (!(content_file_log = logger_new(reopencb, opencb, closecb,
1631 writecb, prepcb,
1632 log_exceptcb))) {
1633 log_content_file_single_fini();
1634 goto out;
1635 }
1636 }
1637 if (global->pcaplog) {
1638 if (log_content_pcap_preinit((global->pcaplog_isdir ||
1639 global->pcaplog_isspec) ?
1640 NULL :
1641 global->pcaplog) == -1)
1642 goto out;
1643 if (global->pcaplog_isdir) {
1644 reopencb = NULL;
1645 opencb = log_content_pcap_dir_opencb;
1646 closecb = log_content_pcap_dir_closecb;
1647 writecb = log_content_pcap_dir_writecb;
1648 prepcb = log_content_pcap_prepcb;
1649 } else if (global->pcaplog_isspec) {
1650 reopencb = NULL;
1651 opencb = log_content_pcap_spec_opencb;
1652 closecb = log_content_pcap_spec_closecb;
1653 writecb = log_content_pcap_spec_writecb;
1654 prepcb = log_content_pcap_prepcb;
1655 } else {
1656 reopencb = log_content_pcap_reopencb;
1657 opencb = NULL;
1658 closecb = log_content_pcap_closecb;
1659 writecb = log_content_pcap_writecb;
1660 prepcb = log_content_pcap_prepcb;
1661 }
1662 if (!(content_pcap_log = logger_new(reopencb, opencb, closecb,
1663 writecb, prepcb,
1664 log_exceptcb))) {
1665 log_content_pcap_fini();
1666 goto out;
1667 }
1668 }
1669 #ifndef WITHOUT_MIRROR
1670 if (global->mirrorif) {
1671 if (log_content_mirror_preinit(global->mirrorif,
1672 global->mirrortarget) == -1)
1673 goto out;
1674 reopencb = NULL;
1675 opencb = NULL;
1676 closecb = log_content_mirror_closecb;
1677 writecb = log_content_mirror_writecb;
1678 prepcb = log_content_mirror_prepcb;
1679 if (!(content_mirror_log = logger_new(reopencb, opencb, closecb,
1680 writecb, prepcb,
1681 log_exceptcb))) {
1682 log_content_mirror_fini();
1683 goto out;
1684 }
1685 }
1686 #endif /* !WITHOUT_MIRROR */
1687 if (global->connectlog) {
1688 if (log_connect_preinit(global->connectlog) == -1)
1689 goto out;
1690 if (!(connect_log = logger_new(log_connect_reopencb,
1691 NULL, NULL,
1692 log_connect_writecb, NULL,
1693 log_exceptcb))) {
1694 log_connect_fini();
1695 goto out;
1696 }
1697 }
1698 if (global->masterkeylog) {
1699 if (log_masterkey_preinit(global->masterkeylog) == -1)
1700 goto out;
1701 if (!(masterkey_log = logger_new(log_masterkey_reopencb,
1702 NULL, NULL,
1703 log_masterkey_writecb, NULL,
1704 log_exceptcb))) {
1705 log_masterkey_fini();
1706 goto out;
1707 }
1708 }
1709 if (global->certgendir) {
1710 if (!(cert_log = logger_new(NULL, NULL, NULL, log_cert_writecb,
1711 NULL, log_exceptcb)))
1712 goto out;
1713 }
1714 if (!(err_log = logger_new(NULL, NULL, NULL, log_err_writecb, NULL,
1715 log_exceptcb)))
1716 goto out;
1717 return 0;
1718
1719 out:
1720 if (connect_log) {
1721 log_connect_fini();
1722 logger_free(connect_log);
1723 }
1724 if (content_file_log) {
1725 log_content_file_single_fini();
1726 logger_free(content_file_log);
1727 }
1728 if (content_pcap_log) {
1729 log_content_pcap_fini();
1730 logger_free(content_pcap_log);
1731 }
1732 #ifndef WITHOUT_MIRROR
1733 if (content_mirror_log) {
1734 log_content_mirror_fini();
1735 logger_free(content_mirror_log);
1736 }
1737 #endif /* !WITHOUT_MIRROR */
1738 if (cert_log) {
1739 logger_free(cert_log);
1740 }
1741 if (masterkey_log) {
1742 log_masterkey_fini();
1743 logger_free(masterkey_log);
1744 }
1745 return -1;
1746 }
1747
1748 /*
1749 * Close all file descriptors opened by log_preinit; used in privsep parent.
1750 * Only undo content, connect and masterkey logs, leave error and debug log
1751 * functional.
1752 */
1753 void
log_preinit_undo(void)1754 log_preinit_undo(void)
1755 {
1756 if (connect_log) {
1757 log_connect_fini();
1758 logger_free(connect_log);
1759 }
1760 if (content_file_log) {
1761 log_content_file_single_fini();
1762 logger_free(content_file_log);
1763 }
1764 if (content_pcap_log) {
1765 log_content_pcap_fini();
1766 logger_free(content_pcap_log);
1767 }
1768 #ifndef WITHOUT_MIRROR
1769 if (content_mirror_log) {
1770 log_content_mirror_fini();
1771 logger_free(content_mirror_log);
1772 }
1773 #endif /* !WITHOUT_MIRROR */
1774 if (masterkey_log) {
1775 log_masterkey_fini();
1776 logger_free(masterkey_log);
1777 }
1778 }
1779
1780 /*
1781 * Log post-init: start logging threads.
1782 * Return -1 on errors, 0 otherwise.
1783 */
1784 int
log_init(global_t * global,proxy_ctx_t * ctx,int clisock[5])1785 log_init(global_t *global, proxy_ctx_t *ctx, int clisock[5])
1786 {
1787 proxy_ctx = ctx;
1788 if (err_log)
1789 if (logger_start(err_log) == -1)
1790 return -1;
1791 if (!global->debug) {
1792 err_shortcut_logger = 1;
1793 }
1794
1795 if (masterkey_log) {
1796 masterkey_clisock = clisock[0];
1797 if (logger_start(masterkey_log) == -1)
1798 return -1;
1799 } else {
1800 privsep_client_close(clisock[0]);
1801 }
1802
1803 if (connect_log) {
1804 connect_clisock = clisock[1];
1805 if (logger_start(connect_log) == -1)
1806 return -1;
1807 } else {
1808 privsep_client_close(clisock[1]);
1809 }
1810
1811 if (content_file_log) {
1812 content_file_clisock = clisock[2];
1813 if (logger_start(content_file_log) == -1)
1814 return -1;
1815 } else {
1816 privsep_client_close(clisock[2]);
1817 }
1818
1819 if (content_pcap_log) {
1820 content_pcap_clisock = clisock[3];
1821 if (logger_start(content_pcap_log) == -1)
1822 return -1;
1823 } else {
1824 privsep_client_close(clisock[3]);
1825 }
1826
1827 #ifndef WITHOUT_MIRROR
1828 if (content_mirror_log) {
1829 if (logger_start(content_mirror_log) == -1)
1830 return -1;
1831 }
1832 #endif /* !WITHOUT_MIRROR */
1833
1834 if (cert_log) {
1835 cert_clisock = clisock[4];
1836 if (logger_start(cert_log) == -1)
1837 return -1;
1838 } else {
1839 privsep_client_close(clisock[4]);
1840 }
1841 return 0;
1842 }
1843
1844 /*
1845 * Drain and cleanup. Tell all loggers to leave, then join all logger threads,
1846 * and finally free resources and close log files.
1847 */
1848 void
log_fini(void)1849 log_fini(void)
1850 {
1851 /* switch back to direct logging so we can still log errors while
1852 * tearing down the logging infrastructure */
1853 err_shortcut_logger = 1;
1854
1855 if (cert_log)
1856 logger_leave(cert_log);
1857 if (masterkey_log)
1858 logger_leave(masterkey_log);
1859 #ifndef WITHOUT_MIRROR
1860 if (content_mirror_log)
1861 logger_leave(content_mirror_log);
1862 #endif /* !WITHOUT_MIRROR */
1863 if (content_pcap_log)
1864 logger_leave(content_pcap_log);
1865 if (content_file_log)
1866 logger_leave(content_file_log);
1867 if (connect_log)
1868 logger_leave(connect_log);
1869 if (err_log)
1870 logger_leave(err_log);
1871
1872 if (cert_log)
1873 logger_join(cert_log);
1874 if (masterkey_log)
1875 logger_join(masterkey_log);
1876 #ifndef WITHOUT_MIRROR
1877 if (content_mirror_log)
1878 logger_join(content_mirror_log);
1879 #endif /* !WITHOUT_MIRROR */
1880 if (content_pcap_log)
1881 logger_join(content_pcap_log);
1882 if (content_file_log)
1883 logger_join(content_file_log);
1884 if (connect_log)
1885 logger_join(connect_log);
1886 if (err_log)
1887 logger_join(err_log);
1888
1889 if (cert_log)
1890 logger_free(cert_log);
1891 if (masterkey_log)
1892 logger_free(masterkey_log);
1893 #ifndef WITHOUT_MIRROR
1894 if (content_mirror_log)
1895 logger_free(content_mirror_log);
1896 #endif /* !WITHOUT_MIRROR */
1897 if (content_pcap_log)
1898 logger_free(content_pcap_log);
1899 if (content_file_log)
1900 logger_free(content_file_log);
1901 if (connect_log)
1902 logger_free(connect_log);
1903 if (err_log)
1904 logger_free(err_log);
1905
1906 if (masterkey_log)
1907 log_masterkey_fini();
1908 #ifndef WITHOUT_MIRROR
1909 if (content_mirror_log)
1910 log_content_mirror_fini();
1911 #endif /* !WITHOUT_MIRROR */
1912 if (content_pcap_log)
1913 log_content_pcap_fini();
1914 if (content_file_log)
1915 log_content_file_single_fini();
1916 if (connect_log)
1917 log_connect_fini();
1918
1919 if (masterkey_clisock != -1)
1920 privsep_client_close(masterkey_clisock);
1921 if (cert_clisock != -1)
1922 privsep_client_close(cert_clisock);
1923 if (content_file_clisock != -1)
1924 privsep_client_close(content_file_clisock);
1925 if (content_pcap_clisock != -1)
1926 privsep_client_close(content_pcap_clisock);
1927 if (connect_clisock != -1)
1928 privsep_client_close(connect_clisock);
1929 }
1930
1931 int
log_reopen(void)1932 log_reopen(void)
1933 {
1934 int rv = 0;
1935
1936 if (masterkey_log)
1937 if (logger_reopen(masterkey_log) == -1)
1938 rv = -1;
1939 if (content_pcap_log)
1940 if (logger_reopen(content_pcap_log) == -1)
1941 rv = -1;
1942 if (content_file_log)
1943 if (logger_reopen(content_file_log) == -1)
1944 rv = -1;
1945 if (connect_log)
1946 if (logger_reopen(connect_log) == -1)
1947 rv = -1;
1948
1949 return rv;
1950 }
1951
1952 /* vim: set noet ft=c: */
1953