dnscap/src/dnscap.c
Daniel Baumann ce06587ac5
Merging upstream version 2.3.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-04-24 13:53:01 +02:00

250 lines
7.9 KiB
C

/* dnscap - DNS capture utility
*
* By Paul Vixie (ISC) and Duane Wessels (Measurement Factory), 2007.
*/
/*
* Copyright (c) 2016-2025 OARC, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "dnscap.h"
#include "args.h"
#include "bpft.h"
#include "pcaps.h"
#include "dumper.h"
#include "daemon.h"
#include "log.h"
#include "sig.h"
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_CONF_H) && defined(HAVE_OPENSSL_ERR_H) && defined(HAVE_OPENSSL_EVP_H)
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#define INIT_OPENSSL 1
#endif
plugin_list plugins;
const char* ProgramName = "amnesia";
int dumptrace = 0;
int flush = FALSE;
vlan_list vlans_excl;
vlan_list vlans_incl;
unsigned msg_wanted = MSG_QUERY;
unsigned dir_wanted = DIR_INITIATE | DIR_RESPONSE;
unsigned end_hide = 0U;
unsigned err_wanted = ERR_NO | ERR_YES; /* accept all by default */
tcpstate_list tcpstates;
int tcpstate_count = 0;
endpoint_list initiators, not_initiators;
endpoint_list responders, not_responders;
endpoint_list drop_responders; /* drops only responses from these hosts */
myregex_list myregexes;
mypcap_list mypcaps;
mypcap_ptr pcap_offline = NULL;
const char* dump_base = NULL;
char* dump_suffix = 0;
char* extra_bpf = NULL;
enum dump_type dump_type = nowhere;
enum dump_state dump_state = dumper_closed;
const char* kick_cmd = NULL;
unsigned limit_seconds = 0U;
time_t next_interval = 0;
unsigned limit_packets = 0U;
size_t limit_pcapfilesize = 0U;
pcap_t* pcap_dead;
pcap_dumper_t* dumper;
FILE* dumper_fp = 0;
time_t dumpstart;
size_t msgcount = 0;
size_t capturedbytes = 0;
char * dumpname, *dumpnamepart;
char* bpft;
unsigned dns_port = DNS_PORT;
int promisc = TRUE;
int monitor_mode = FALSE;
int immediate_mode = FALSE;
int background = FALSE;
char errbuf[PCAP_ERRBUF_SIZE];
int wantgzip = 0;
int wantfrags = FALSE;
int wanticmp = FALSE;
int wanttcp = FALSE;
int preso = FALSE;
#ifdef USE_SECCOMP
int use_seccomp = FALSE;
#endif
int main_exit = FALSE;
int alarm_set = FALSE;
time_t start_time = 0;
time_t stop_time = 0;
int print_pcap_stats = FALSE;
uint64_t pcap_drops = 0;
my_bpftimeval last_ts = { 0, 0 };
unsigned long long mem_limit = (unsigned)MEM_MAX; /* process memory limit */
int mem_limit_set = 1; /* TODO: Should be configurable */
const char DROPTOUSER[] = "nobody";
pcap_thread_t pcap_thread = PCAP_THREAD_T_INIT;
int only_offline_pcaps = FALSE;
int dont_drop_privileges = FALSE;
options_t options = OPTIONS_T_DEFAULTS;
ldns_rr_type match_qtype = 0, nmatch_qtype = 0;
int main(int argc, char* argv[])
{
struct plugin* p;
struct timeval now;
#ifdef INIT_OPENSSL
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
OPENSSL_config(0);
#endif
#endif
parse_args(argc, argv);
gettimeofday(&now, 0);
if (!only_offline_pcaps && start_time) {
if (now.tv_sec < start_time) {
char when[100];
struct tm tm;
gmtime_r(&start_time, &tm);
strftime(when, sizeof when, "%F %T", &tm);
fprintf(stderr, "Sleeping for %" PRI_tv_sec " seconds until %s UTC\n",
start_time - now.tv_sec, when);
sleep(start_time - now.tv_sec);
fprintf(stderr, "Awake.\n");
}
}
prepare_bpft();
open_pcaps();
if (dump_type == to_stdout) {
if (dumper_open(now)) {
fprintf(stderr, "%s: dumper_open() to stdout failed\n", ProgramName);
exit(1);
}
}
INIT_LIST(tcpstates);
if (!dont_drop_privileges && !only_offline_pcaps) {
drop_privileges();
}
for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
if (p->start)
if (0 != (*p->start)(logerr)) {
logerr("%s_start returned non-zero", p->name);
exit(1);
}
}
if (dump_type == nowhere)
dumpstart = time(NULL);
if (background)
daemonize();
#if HAVE_PTHREAD
/*
* Defer signal setup until we have dropped privileges and daemonized,
* otherwise signals might not reach us because different threads
* are running under different users/access
*/
{
sigset_t set;
int err;
pthread_t thread;
sigfillset(&set);
if ((err = pthread_sigmask(SIG_BLOCK, &set, 0))) {
logerr("pthread_sigmask: %s", strerror(err));
exit(1);
}
sigemptyset(&set);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGALRM);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGQUIT);
if ((err = pthread_create(&thread, 0, &sigthread, (void*)&set))) {
logerr("pthread_create: %s", strerror(err));
exit(1);
}
}
#else
{
sigset_t set;
sigfillset(&set);
sigdelset(&set, SIGHUP);
sigdelset(&set, SIGINT);
sigdelset(&set, SIGALRM);
sigdelset(&set, SIGTERM);
sigdelset(&set, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &set, 0)) {
logerr("sigprocmask: %s", strerror(errno));
exit(1);
}
}
setsig(SIGHUP, TRUE);
setsig(SIGINT, TRUE);
setsig(SIGALRM, FALSE);
setsig(SIGTERM, TRUE);
setsig(SIGQUIT, TRUE);
#endif
while (!main_exit)
poll_pcaps();
/* close PCAPs after dumper_close() to have statistics still available during dumper_close() */
if (dumper_opened == dump_state)
(void)dumper_close(last_ts);
close_pcaps();
for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
if (p->stop)
(*p->stop)();
}
options_free(&options);
#ifdef INIT_OPENSSL
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
#endif
return 0;
}