/* dnscap - DNS capture utility * * By Paul Vixie (ISC) and Duane Wessels (Measurement Factory), 2007. */ /* * Copyright (c) 2016-2023, 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 #include #include #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; time_t dumpstart; unsigned msgcount; 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 %d seconds until %s UTC\n", (int)(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; }