1 /* dnscap - DNS capture utility
2 *
3 * By Paul Vixie (ISC) and Duane Wessels (Measurement Factory), 2007.
4 */
5
6 /*
7 * Copyright (c) 2016-2021, OARC, Inc.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * 3. Neither the name of the copyright holder nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include "config.h"
41
42 #include "dnscap.h"
43 #include "args.h"
44 #include "bpft.h"
45 #include "pcaps.h"
46 #include "dumper.h"
47 #include "daemon.h"
48 #include "log.h"
49 #include "sig.h"
50
51 #if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_CONF_H) && defined(HAVE_OPENSSL_ERR_H) && defined(HAVE_OPENSSL_EVP_H)
52 #include <openssl/conf.h>
53 #include <openssl/evp.h>
54 #include <openssl/err.h>
55 #define INIT_OPENSSL 1
56 #endif
57
58 plugin_list plugins;
59 const char* ProgramName = "amnesia";
60 int dumptrace = 0;
61 int flush = FALSE;
62 vlan_list vlans_excl;
63 vlan_list vlans_incl;
64 unsigned msg_wanted = MSG_QUERY;
65 unsigned dir_wanted = DIR_INITIATE | DIR_RESPONSE;
66 unsigned end_hide = 0U;
67 unsigned err_wanted = ERR_NO | ERR_YES; /* accept all by default */
68 tcpstate_list tcpstates;
69 int tcpstate_count = 0;
70 endpoint_list initiators, not_initiators;
71 endpoint_list responders, not_responders;
72 endpoint_list drop_responders; /* drops only responses from these hosts */
73 myregex_list myregexes;
74 mypcap_list mypcaps;
75 mypcap_ptr pcap_offline = NULL;
76 const char* dump_base = NULL;
77 char* dump_suffix = 0;
78 char* extra_bpf = NULL;
79 enum dump_type dump_type = nowhere;
80 enum dump_state dump_state = dumper_closed;
81 const char* kick_cmd = NULL;
82 unsigned limit_seconds = 0U;
83 time_t next_interval = 0;
84 unsigned limit_packets = 0U;
85 size_t limit_pcapfilesize = 0U;
86 pcap_t* pcap_dead;
87 pcap_dumper_t* dumper;
88 time_t dumpstart;
89 unsigned msgcount;
90 size_t capturedbytes = 0;
91 char * dumpname, *dumpnamepart;
92 char* bpft;
93 unsigned dns_port = DNS_PORT;
94 int promisc = TRUE;
95 int monitor_mode = FALSE;
96 int immediate_mode = FALSE;
97 int background = FALSE;
98 char errbuf[PCAP_ERRBUF_SIZE];
99 int wantgzip = 0;
100 int wantfrags = FALSE;
101 int wanticmp = FALSE;
102 int wanttcp = FALSE;
103 int preso = FALSE;
104 #ifdef USE_SECCOMP
105 int use_seccomp = FALSE;
106 #endif
107 int main_exit = FALSE;
108 int alarm_set = FALSE;
109 time_t start_time = 0;
110 time_t stop_time = 0;
111 int print_pcap_stats = FALSE;
112 uint64_t pcap_drops = 0;
113 my_bpftimeval last_ts = { 0, 0 };
114 unsigned long long mem_limit = (unsigned)MEM_MAX; /* process memory limit */
115 int mem_limit_set = 1; /* TODO: Should be configurable */
116 const char DROPTOUSER[] = "nobody";
117 pcap_thread_t pcap_thread = PCAP_THREAD_T_INIT;
118 int only_offline_pcaps = FALSE;
119 int dont_drop_privileges = FALSE;
120 options_t options = OPTIONS_T_DEFAULTS;
121
122 ldns_rr_type match_qtype = 0, nmatch_qtype = 0;
123
main(int argc,char * argv[])124 int main(int argc, char* argv[])
125 {
126 struct plugin* p;
127 struct timeval now;
128
129 #ifdef INIT_OPENSSL
130 ERR_load_crypto_strings();
131 OpenSSL_add_all_algorithms();
132 #if OPENSSL_VERSION_NUMBER < 0x10100000L
133 OPENSSL_config(0);
134 #endif
135 #endif
136
137 parse_args(argc, argv);
138 gettimeofday(&now, 0);
139 if (!only_offline_pcaps && start_time) {
140 if (now.tv_sec < start_time) {
141 char when[100];
142 struct tm tm;
143 gmtime_r(&start_time, &tm);
144 strftime(when, sizeof when, "%F %T", &tm);
145 fprintf(stderr, "Sleeping for %d seconds until %s UTC\n",
146 (int)(start_time - now.tv_sec), when);
147 sleep(start_time - now.tv_sec);
148 fprintf(stderr, "Awake.\n");
149 }
150 }
151 prepare_bpft();
152 open_pcaps();
153 if (dump_type == to_stdout) {
154 if (dumper_open(now)) {
155 fprintf(stderr, "%s: dumper_open() to stdout failed\n", ProgramName);
156 exit(1);
157 }
158 }
159 INIT_LIST(tcpstates);
160
161 if (!dont_drop_privileges && !only_offline_pcaps) {
162 drop_privileges();
163 }
164
165 for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
166 if (p->start)
167 if (0 != (*p->start)(logerr)) {
168 logerr("%s_start returned non-zero", p->name);
169 exit(1);
170 }
171 }
172 if (dump_type == nowhere)
173 dumpstart = time(NULL);
174 if (background)
175 daemonize();
176
177 #if HAVE_PTHREAD
178 /*
179 * Defer signal setup until we have dropped privileges and daemonized,
180 * otherwise signals might not reach us because different threads
181 * are running under different users/access
182 */
183 {
184 sigset_t set;
185 int err;
186 pthread_t thread;
187
188 sigfillset(&set);
189 if ((err = pthread_sigmask(SIG_BLOCK, &set, 0))) {
190 logerr("pthread_sigmask: %s", strerror(err));
191 exit(1);
192 }
193
194 sigemptyset(&set);
195 sigaddset(&set, SIGHUP);
196 sigaddset(&set, SIGINT);
197 sigaddset(&set, SIGALRM);
198 sigaddset(&set, SIGTERM);
199 sigaddset(&set, SIGQUIT);
200
201 if ((err = pthread_create(&thread, 0, &sigthread, (void*)&set))) {
202 logerr("pthread_create: %s", strerror(err));
203 exit(1);
204 }
205 }
206 #else
207 {
208 sigset_t set;
209
210 sigfillset(&set);
211 sigdelset(&set, SIGHUP);
212 sigdelset(&set, SIGINT);
213 sigdelset(&set, SIGALRM);
214 sigdelset(&set, SIGTERM);
215 sigdelset(&set, SIGQUIT);
216
217 if (sigprocmask(SIG_BLOCK, &set, 0)) {
218 logerr("sigprocmask: %s", strerror(errno));
219 exit(1);
220 }
221 }
222
223 setsig(SIGHUP, TRUE);
224 setsig(SIGINT, TRUE);
225 setsig(SIGALRM, FALSE);
226 setsig(SIGTERM, TRUE);
227 setsig(SIGQUIT, TRUE);
228 #endif
229
230 while (!main_exit)
231 poll_pcaps();
232 /* close PCAPs after dumper_close() to have statistics still available during dumper_close() */
233 if (dumper_opened == dump_state)
234 (void)dumper_close(last_ts);
235 close_pcaps();
236 for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
237 if (p->stop)
238 (*p->stop)();
239 }
240 options_free(&options);
241
242 #ifdef INIT_OPENSSL
243 EVP_cleanup();
244 CRYPTO_cleanup_all_ex_data();
245 ERR_free_strings();
246 #endif
247
248 return 0;
249 }
250