1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #ifndef _DNSTAP_H
13 #define _DNSTAP_H
14 
15 /*****
16 ***** Module Info
17 *****/
18 
19 /*! \file
20  * \brief
21  * The dt (dnstap) module provides fast passive logging of DNS messages.
22  * Protocol Buffers.  The protobuf schema for Dnstap messages is in the
23  * file dnstap.proto, which is compiled to dnstap.pb-c.c and dnstap.pb-c.h.
24  */
25 
26 #include <inttypes.h>
27 #include <stdbool.h>
28 
29 #ifdef HAVE_DNSTAP
30 #include <fstrm.h>
31 
32 #include <protobuf-c/protobuf-c.h>
33 #else  /* ifdef HAVE_DNSTAP */
34 struct fstrm_iothr_options;
35 #endif /* HAVE_DNSTAP */
36 
37 #include <isc/log.h>
38 #include <isc/refcount.h>
39 #include <isc/region.h>
40 #include <isc/sockaddr.h>
41 #include <isc/time.h>
42 #include <isc/types.h>
43 
44 #include <dns/name.h>
45 #include <dns/rdataclass.h>
46 #include <dns/rdatatype.h>
47 #include <dns/types.h>
48 
49 /*%
50  * Dnstap message types:
51  *
52  * STUB QUERY: SQ
53  * STUB RESPONSE: SR
54  * CLIENT QUERY: CQ
55  * CLIENT RESPONSE: CR
56  * AUTH QUERY: AQ
57  * AUTH RESPONSE: AR
58  * RESOLVER QUERY: RQ
59  * RESOLVER RESPONSE: RR
60  * FORWARDER QUERY: FQ
61  * FORWARDER RESPONSE: FR
62  */
63 
64 #define DNS_DTTYPE_SQ 0x0001
65 #define DNS_DTTYPE_SR 0x0002
66 #define DNS_DTTYPE_CQ 0x0004
67 #define DNS_DTTYPE_CR 0x0008
68 #define DNS_DTTYPE_AQ 0x0010
69 #define DNS_DTTYPE_AR 0x0020
70 #define DNS_DTTYPE_RQ 0x0040
71 #define DNS_DTTYPE_RR 0x0080
72 #define DNS_DTTYPE_FQ 0x0100
73 #define DNS_DTTYPE_FR 0x0200
74 #define DNS_DTTYPE_TQ 0x0400
75 #define DNS_DTTYPE_TR 0x0800
76 #define DNS_DTTYPE_UQ 0x1000
77 #define DNS_DTTYPE_UR 0x2000
78 
79 #define DNS_DTTYPE_QUERY                                                 \
80 	(DNS_DTTYPE_SQ | DNS_DTTYPE_CQ | DNS_DTTYPE_AQ | DNS_DTTYPE_RQ | \
81 	 DNS_DTTYPE_FQ | DNS_DTTYPE_TQ | DNS_DTTYPE_UQ)
82 #define DNS_DTTYPE_RESPONSE                                              \
83 	(DNS_DTTYPE_SR | DNS_DTTYPE_CR | DNS_DTTYPE_AR | DNS_DTTYPE_RR | \
84 	 DNS_DTTYPE_FR | DNS_DTTYPE_TR | DNS_DTTYPE_UR)
85 #define DNS_DTTYPE_ALL (DNS_DTTYPE_QUERY | DNS_DTTYPE_RESPONSE)
86 
87 typedef enum {
88 	dns_dtmode_none = 0,
89 	dns_dtmode_file,
90 	dns_dtmode_unix
91 } dns_dtmode_t;
92 
93 typedef struct dns_dthandle dns_dthandle_t;
94 
95 #ifdef HAVE_DNSTAP
96 struct dns_dtdata {
97 	isc_mem_t *mctx;
98 
99 	void *frame;
100 
101 	bool		query;
102 	bool		tcp;
103 	dns_dtmsgtype_t type;
104 
105 	isc_time_t qtime;
106 	isc_time_t rtime;
107 
108 	isc_region_t qaddr;
109 	isc_region_t raddr;
110 
111 	uint32_t qport;
112 	uint32_t rport;
113 
114 	isc_region_t   msgdata;
115 	dns_message_t *msg;
116 
117 	char namebuf[DNS_NAME_FORMATSIZE];
118 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
119 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
120 };
121 #endif /* HAVE_DNSTAP */
122 
123 isc_result_t
124 dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path,
125 	      struct fstrm_iothr_options **foptp, isc_task_t *reopen_task,
126 	      dns_dtenv_t **envp);
127 /*%<
128  * Create and initialize the dnstap environment.
129  *
130  * There should be a single global dnstap environment for the server;
131  * copies of it will be attached to each view.
132  *
133  * Notes:
134  *
135  *\li	'path' refers to a UNIX domain socket by default. It may
136  *	optionally be prepended with "socket:" or "file:". If prepended
137  *	with "file:", then dnstap logs are sent to a file instead of a
138  *	socket.
139  *
140  *\li	'*foptp' set the options for fstrm_iothr_init(). '*foptp' must have
141  *	have had the number of input queues set and this should be set
142  *	to the number of worker threads.  Additionally the queue model
143  *	should also be set.  Other options may be set if desired.
144  *	If dns_dt_create succeeds the *foptp is set to NULL.
145  *
146  *\li	'reopen_task' needs to be set to the task in the context of which
147  *	dns_dt_reopen() will be called.  This is not an optional parameter:
148  *	using dns_dt_create() (which sets 'reopen_task' to NULL) is only
149  *	allowed in unit tests.
150  *
151  * Requires:
152  *
153  *\li	'mctx' is a valid memory context.
154  *
155  *\li	'path' is a valid C string.
156  *
157  *\li	'foptp' is non NULL.
158  *
159  *\li	envp != NULL && *envp == NULL
160  *
161  * Returns:
162  *
163  *\li	#ISC_R_SUCCESS
164  *\li	#ISC_R_NOMEMORY
165  *
166  *\li	Other errors are possible.
167  */
168 
169 isc_result_t
170 dns_dt_setupfile(dns_dtenv_t *env, uint64_t max_size, int rolls,
171 		 isc_log_rollsuffix_t suffix);
172 /*%<
173  * Sets up the dnstap logfile limits.
174  *
175  * 'max_size' is the size a log file may grow before it is rolled
176  *
177  * 'rolls' is the number of rolled files to retain.
178  *
179  * 'suffix' is the logfile suffix setting, increment or timestamp.
180  *
181  * Requires:
182  *
183  *\li	'env' is a valid dnstap environment.
184  *
185  * Returns:
186  *\li	#ISC_R_SUCCESS on success
187  *\li	#ISC_R_INVALIDFILE if dnstap is set to use a UNIX domain socket
188  */
189 
190 isc_result_t
191 dns_dt_reopen(dns_dtenv_t *env, int roll);
192 /*%<
193  * Reopens files established by dns_dt_create2().
194  *
195  * If 'roll' is non-negative and 'env->mode' is dns_dtmode_file,
196  * then the file is automatically rolled over before reopening.
197  * The value of 'roll' indicates the number of backup log files to
198  * keep.  If 'roll' is negative, or if 'env->mode' is dns_dtmode_unix,
199  * then the channel is simply reopened.
200  *
201  * Note: dns_dt_reopen() uses task-exclusive mode and must be run in the
202  * context of env->reopen_task.
203  *
204  * Requires:
205  *\li	'env' is a valid dnstap environment.
206  */
207 
208 isc_result_t
209 dns_dt_setidentity(dns_dtenv_t *env, const char *identity);
210 isc_result_t
211 dns_dt_setversion(dns_dtenv_t *env, const char *version);
212 /*%<
213  * Set the "identity" and "version" strings to be sent in dnstap messages.
214  *
215  * Requires:
216  *
217  *\li	'env' is a valid dnstap environment.
218  */
219 
220 void
221 dns_dt_attach(dns_dtenv_t *source, dns_dtenv_t **destp);
222 /*%<
223  * Attach '*destp' to 'source', incrementing the reference counter.
224  *
225  * Requires:
226  *
227  *\li	'source' is a valid dnstap environment.
228  *
229  *\li	'destp' is not NULL and '*destp' is NULL.
230  *
231  *\li	*destp is attached to source.
232  */
233 
234 void
235 dns_dt_detach(dns_dtenv_t **envp);
236 /*%<
237  * Detach '*envp', decrementing the reference counter.
238  *
239  * Requires:
240  *
241  *\li	'*envp' is a valid dnstap environment.
242  *
243  * Ensures:
244  *
245  *\li	'*envp' will be destroyed when the number of references reaches zero.
246  *
247  *\li	'*envp' is NULL.
248  */
249 
250 isc_result_t
251 dns_dt_getstats(dns_dtenv_t *env, isc_stats_t **statsp);
252 /*%<
253  * Attach to the stats struct if it exists.
254  *
255  * Requires:
256  *
257  *\li	'env' is a valid dnstap environment.
258  *
259  *\li	'statsp' is non NULL and '*statsp' is NULL.
260  *
261  * Returns:
262  *
263  *\li	ISC_R_SUCCESS
264  *
265  *\li	ISC_R_NOTFOUND
266  */
267 
268 void
269 dns_dt_send(dns_view_t *view, dns_dtmsgtype_t msgtype, isc_sockaddr_t *qaddr,
270 	    isc_sockaddr_t *dstaddr, bool tcp, isc_region_t *zone,
271 	    isc_time_t *qtime, isc_time_t *rtime, isc_buffer_t *buf);
272 /*%<
273  * Sends a dnstap message to the log, if 'msgtype' is one of the message
274  * types represented in 'view->dttypes'.
275  *
276  * Parameters are: 'qaddr' (query address, i.e, the address of the
277  * query initiator); 'raddr' (response address, i.e., the address of
278  * the query responder); 'tcp' (boolean indicating whether the transaction
279  * was over TCP); 'zone' (the authoritative zone or bailiwick, in
280  * uncompressed wire format), 'qtime' and 'rtime' (query and response
281  * times; if NULL, they are set to the current time); and 'buf' (the
282  * DNS message being logged, in wire format).
283  *
284  * Requires:
285  *
286  *\li	'view' is a valid view, and 'view->dtenv' is NULL or is a
287  *	valid dnstap environment.
288  */
289 
290 isc_result_t
291 dns_dt_parse(isc_mem_t *mctx, isc_region_t *src, dns_dtdata_t **destp);
292 /*%<
293  * Converts a raw dnstap frame in 'src' to a parsed dnstap data structure
294  * in '*destp'.
295  *
296  * Requires:
297  *\li	'src' is not NULL
298  *
299  *\li	'destp' is not NULL and '*destp' points to a valid buffer.
300  *
301  * Returns:
302  *\li	#ISC_R_SUCCESS on success
303  *
304  *\li	Other errors are possible.
305  */
306 
307 isc_result_t
308 dns_dt_datatotext(dns_dtdata_t *d, isc_buffer_t **dest);
309 /*%<
310  * Converts a parsed dnstap data structure 'd' to text, storing
311  * the result in the buffer 'dest'.  If 'dest' points to a dynamically
312  * allocated buffer, then it may be reallocated as needed.
313  *
314  * (XXX: add a 'long_form' option to generate a detailed listing of
315  * dnstap data instead * of a one-line summary.)
316  *
317  * Requires:
318  *\li	'd' is not NULL
319  *
320  *\li	'dest' is not NULL and '*dest' points to a valid buffer.
321  *
322  * Returns:
323  *\li	#ISC_R_SUCCESS on success
324  *\li	#ISC_R_NOSPACE if buffer is not dynamic and runs out of space
325  *\li	#ISC_R_NOMEMORY if buffer is dynamic but memory could not be allocated
326  *
327  *\li	Other errors are possible.
328  */
329 
330 void
331 dns_dtdata_free(dns_dtdata_t **dp);
332 /*%<
333  * Frees the specified dns_dtdata structure and all its members,
334  * and sets *dp to NULL.
335  */
336 
337 isc_result_t
338 dns_dt_open(const char *filename, dns_dtmode_t mode, isc_mem_t *mctx,
339 	    dns_dthandle_t **handlep);
340 /*%<
341  * Opens a dnstap framestream at 'filename' and stores a pointer to the
342  * reader object in a dns_dthandle_t structure.
343  *
344  * The caller is responsible for allocating the handle structure.
345  *
346  * (XXX: Currently only file readers are supported, not unix-domain socket
347  * readers.)
348  *
349  * Requires:
350  *
351  *\li	'filename' is not NULL.
352  *
353  *\li	'handlep' is not NULL and '*handlep' is NULL.
354  *
355  *\li	'*mctx' is not a valid memory context.
356  *
357  * Returns:
358  *
359  *\li	#ISC_R_SUCCESS on success
360  *\li	#ISC_R_NOTIMPLEMENTED if 'mode' is not dns_dtmode_file. (XXX)
361  *\li	#ISC_R_NOMEMORY if the fstrm library was unable to allocate a
362  *      reader or options structure
363  *\li	#ISC_R_FAILURE if 'filename' could not be opened.
364  *\li	#DNS_R_BADDNSTAP if 'filename' does not contain a dnstap
365  *      framestream.
366  */
367 
368 isc_result_t
369 dns_dt_getframe(dns_dthandle_t *handle, uint8_t **bufp, size_t *sizep);
370 /*%<
371  * Read a dnstap frame from the framstream reader in 'handle', storing
372  * a pointer to it in '*bufp' and its size in '*sizep'.
373  *
374  * Requires:
375  *
376  *\li	'handle' is not NULL
377  *\li	'bufp' is not NULL
378  *\li	'sizep' is not NULL
379  *
380  * Ensures:
381  * \li	if returning ISC_R_SUCCESS then '*bufp' is not NULL
382  *
383  * Returns:
384  *
385  *\li	#ISC_R_SUCCESS on success
386  *\li	#ISC_R_NOMORE at the end of the frame stream
387  *\li	#ISC_R_FAILURE for any other failure
388  */
389 
390 void
391 dns_dt_close(dns_dthandle_t **handlep);
392 /*%<
393  * Closes the dnstap file referenced by 'handle'.
394  *
395  * Requires:
396  *
397  *\li	'*handlep' is not NULL
398  */
399 
400 #endif /* _DNSTAP_H */
401