suricata
app-layer-dns-udp.c
Go to the documentation of this file.
1 /* Copyright (C) 2017 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "suricata-common.h"
19 #include "suricata.h"
20 
21 #include "app-layer-protos.h"
22 #include "app-layer-detect-proto.h"
23 #include "app-layer-parser.h"
24 #include "app-layer-dns-common.h"
25 
26 #include "util-unittest.h"
27 
28 #include "app-layer-dns-udp.h"
29 #include "rust-dns-dns-gen.h"
30 
31 #ifdef UNITTESTS
32 static void RustDNSUDPParserRegisterTests(void);
33 #endif
34 
35 static int RustDNSUDPParseRequest(Flow *f, void *state,
36  AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len,
37  void *local_data, const uint8_t flags)
38 {
39  return rs_dns_parse_request(f, state, pstate, input, input_len,
40  local_data);
41 }
42 
43 static int RustDNSUDPParseResponse(Flow *f, void *state,
44  AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len,
45  void *local_data, const uint8_t flags)
46 {
47  return rs_dns_parse_response(f, state, pstate, input, input_len,
48  local_data);
49 }
50 
51 static uint16_t DNSUDPProbe(Flow *f, uint8_t direction,
52  const uint8_t *input, uint32_t len, uint8_t *rdir)
53 {
54  if (len == 0 || len < sizeof(DNSHeader)) {
55  return ALPROTO_UNKNOWN;
56  }
57 
58  // Validate and return ALPROTO_FAILED if needed.
59  if (!rs_dns_probe(input, len, rdir)) {
60  return ALPROTO_FAILED;
61  }
62 
63  return ALPROTO_DNS;
64 }
65 
66 static int RustDNSGetAlstateProgress(void *tx, uint8_t direction)
67 {
68  return rs_dns_tx_get_alstate_progress(tx, direction);
69 }
70 
71 static uint64_t RustDNSGetTxCnt(void *alstate)
72 {
73  return rs_dns_state_get_tx_count(alstate);
74 }
75 
76 static void *RustDNSGetTx(void *alstate, uint64_t tx_id)
77 {
78  return rs_dns_state_get_tx(alstate, tx_id);
79 }
80 
81 static void RustDNSSetTxLogged(void *alstate, void *tx, LoggerId logged)
82 {
83  rs_dns_tx_set_logged(alstate, tx, logged);
84 }
85 
86 static LoggerId RustDNSGetTxLogged(void *alstate, void *tx)
87 {
88  return rs_dns_tx_get_logged(alstate, tx);
89 }
90 
91 static void RustDNSStateTransactionFree(void *state, uint64_t tx_id)
92 {
93  rs_dns_state_tx_free(state, tx_id);
94 }
95 
96 static DetectEngineState *RustDNSGetTxDetectState(void *tx)
97 {
98  return rs_dns_state_get_tx_detect_state(tx);
99 }
100 
101 static int RustDNSSetTxDetectState(void *tx, DetectEngineState *s)
102 {
103  rs_dns_state_set_tx_detect_state(tx, s);
104  return 0;
105 }
106 
107 static void RustDNSSetDetectFlags(void *tx, uint8_t dir, uint64_t flags)
108 {
109  rs_dns_tx_set_detect_flags(tx, dir, flags);
110 }
111 
112 static uint64_t RustDNSGetDetectFlags(void *tx, uint8_t dir)
113 {
114  return rs_dns_tx_get_detect_flags(tx, dir);
115 }
116 
117 static AppLayerDecoderEvents *RustDNSGetEvents(void *tx)
118 {
119  return rs_dns_state_get_events(tx);
120 }
121 
123 {
124  const char *proto_name = "dns";
125 
126  /** DNS */
127  if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
129 
130  if (RunmodeIsUnittests()) {
131  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53", ALPROTO_DNS, 0,
132  sizeof(DNSHeader), STREAM_TOSERVER, DNSUDPProbe,
133  DNSUDPProbe);
134  } else {
135  int have_cfg = AppLayerProtoDetectPPParseConfPorts("udp",
136  IPPROTO_UDP, proto_name, ALPROTO_DNS, 0, sizeof(DNSHeader),
137  DNSUDPProbe, DNSUDPProbe);
138 
139  /* If no config, enable on port 53. */
140  if (!have_cfg) {
141 #ifndef AFLFUZZ_APPLAYER
142  SCLogConfig("no DNS UDP config found, "
143  "enabling DNS detection on port 53.");
144 #endif
145  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53", ALPROTO_DNS,
146  0, sizeof(DNSHeader), STREAM_TOSERVER,
147  DNSUDPProbe, DNSUDPProbe);
148  }
149  }
150  } else {
151  SCLogConfig("Protocol detection and parser disabled for %s protocol.",
152  proto_name);
153  return;
154  }
155 
156  if (AppLayerParserConfParserEnabled("udp", proto_name)) {
158  RustDNSUDPParseRequest);
160  RustDNSUDPParseResponse);
162  rs_dns_state_new, rs_dns_state_free);
164  RustDNSStateTransactionFree);
166  RustDNSGetEvents);
168  RustDNSGetTxDetectState, RustDNSSetTxDetectState);
170  RustDNSGetDetectFlags, RustDNSSetDetectFlags);
171 
172  AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS, RustDNSGetTx);
174  RustDNSGetTxCnt);
176  RustDNSGetTxLogged, RustDNSSetTxLogged);
178  RustDNSGetAlstateProgress);
179 
181  rs_dns_state_progress_completion_status);
182 
185 
186  } else {
187  SCLogConfig("Parsed disabled for %s protocol. Protocol detection"
188  "still on.", proto_name);
189  }
190 #ifdef UNITTESTS
192  RustDNSUDPParserRegisterTests);
193 #endif
194 }
195 
196 #ifdef UNITTESTS
197 
198 #include "util-unittest-helper.h"
199 
200 static int RustDNSUDPParserTest01 (void)
201 {
202  /* query: abcdefghijk.com
203  * TTL: 86400
204  * serial 20130422 refresh 28800 retry 7200 exp 604800 min ttl 86400
205  * ns, hostmaster */
206  uint8_t buf[] = { 0x00, 0x3c, 0x85, 0x00, 0x00, 0x01, 0x00, 0x00,
207  0x00, 0x01, 0x00, 0x00, 0x0b, 0x61, 0x62, 0x63,
208  0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
209  0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x0f, 0x00,
210  0x01, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x01,
211  0x51, 0x80, 0x00, 0x25, 0x02, 0x6e, 0x73, 0x00,
212  0x0a, 0x68, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x73,
213  0x74, 0x65, 0x72, 0xc0, 0x2f, 0x01, 0x33, 0x2a,
214  0x76, 0x00, 0x00, 0x70, 0x80, 0x00, 0x00, 0x1c,
215  0x20, 0x00, 0x09, 0x3a, 0x80, 0x00, 0x01, 0x51,
216  0x80};
217  size_t buflen = sizeof(buf);
218  Flow *f = NULL;
219 
220  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
221  FAIL_IF_NULL(f);
222  f->proto = IPPROTO_UDP;
223  f->alproto = ALPROTO_DNS;
224  f->alstate = rs_dns_state_new();
225  FAIL_IF_NULL(f->alstate);
226 
227  FAIL_IF_NOT(RustDNSUDPParseResponse(f, f->alstate, NULL, buf, buflen,
228  NULL, STREAM_START));
229 
230  UTHFreeFlow(f);
231  PASS;
232 }
233 
234 static int RustDNSUDPParserTest02 (void)
235 {
236  uint8_t buf[] = {
237  0x6D,0x08,0x84,0x80,0x00,0x01,0x00,0x08,0x00,0x00,0x00,0x01,0x03,0x57,0x57,0x57,
238  0x04,0x54,0x54,0x54,0x54,0x03,0x56,0x56,0x56,0x03,0x63,0x6F,0x6D,0x02,0x79,0x79,
239  0x00,0x00,0x01,0x00,0x01,0xC0,0x0C,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,
240  0x02,0xC0,0x0C,0xC0,0x31,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,
241  0x31,0xC0,0x3F,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x3F,0xC0,
242  0x4D,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x4D,0xC0,0x5B,0x00,
243  0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x5B,0xC0,0x69,0x00,0x05,0x00,
244  0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x69,0xC0,0x77,0x00,0x05,0x00,0x01,0x00,
245  0x00,0x0E,0x10,0x00,0x02,0xC0,0x77,0xC0,0x85,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,
246  0x10,0x00,0x02,0xC0,0x85,0x00,0x00,0x29,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
247  };
248  size_t buflen = sizeof(buf);
249  Flow *f = NULL;
250 
251  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
252  FAIL_IF_NULL(f);
253  f->proto = IPPROTO_UDP;
254  f->alproto = ALPROTO_DNS;
255  f->alstate = rs_dns_state_new();
256  FAIL_IF_NULL(f->alstate);
257 
258  FAIL_IF_NOT(RustDNSUDPParseResponse(f, f->alstate, NULL, buf, buflen,
259  NULL, STREAM_START));
260 
261  UTHFreeFlow(f);
262  PASS;
263 }
264 
265 static int RustDNSUDPParserTest03 (void)
266 {
267  uint8_t buf[] = {
268  0x6F,0xB4,0x84,0x80,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x03,0x57,0x57,0x77,
269  0x0B,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x03,0x55,0x55,0x55,
270  0x02,0x79,0x79,0x00,0x00,0x01,0x00,0x01,0xC0,0x0C,0x00,0x05,0x00,0x01,0x00,0x00,
271  0x0E,0x10,0x00,0x02,0xC0,0x10,0xC0,0x34,0x00,0x01,0x00,0x01,0x00,0x00,0x0E,0x10,
272  0x00,0x04,0xC3,0xEA,0x04,0x19,0xC0,0x34,0x00,0x02,0x00,0x01,0x00,0x00,0x0E,0x10,
273  0x00,0x0A,0x03,0x6E,0x73,0x31,0x03,0x61,0x67,0x62,0xC0,0x20,0xC0,0x46,0x00,0x02,
274  0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x06,0x03,0x6E,0x73,0x32,0xC0,0x56,0xC0,0x52,
275  0x00,0x01,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x04,0xC3,0xEA,0x04,0x0A,0xC0,0x68,
276  0x00,0x01,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x04,0xC3,0xEA,0x05,0x14,0x00,0x00,
277  0x29,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00
278  };
279  size_t buflen = sizeof(buf);
280  Flow *f = NULL;
281 
282  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
283  FAIL_IF_NULL(f);
284  f->proto = IPPROTO_UDP;
285  f->alproto = ALPROTO_DNS;
286  f->alstate = rs_dns_state_new();
287  FAIL_IF_NULL(f->alstate);
288 
289  FAIL_IF_NOT(RustDNSUDPParseResponse(f, f->alstate, NULL, buf, buflen,
290  NULL, STREAM_START));
291 
292  UTHFreeFlow(f);
293  PASS;
294 }
295 
296 /** \test TXT records in answer */
297 static int RustDNSUDPParserTest04 (void)
298 {
299  uint8_t buf[] = {
300  0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41,
301  0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72,
302  0x76,0x06,0x74,0x75,0x6e,0x6e,0x65,0x6c,0x03,0x63,0x6f,0x6d,0x00,0x00,0x10,0x00,
303  0x01,
304  /* answer record start */
305  0xc0,0x0c,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x22,
306  /* txt record starts: */
307  0x20, /* <txt len 32 */ 0x41,0x68,0x76,0x4d,0x41,0x41,0x4f,0x31,0x6b,0x41,0x46,
308  0x45,0x35,0x54,0x45,0x39,0x51,0x54,0x6a,0x46,0x46,0x4e,0x30,0x39,0x52,0x4e,0x31,
309  0x6c,0x59,0x53,0x44,0x6b,0x00, /* <txt len 0 */ 0xc0,0x1d,0x00,0x02,0x00,0x01,
310  0x00,0x09,0x3a,0x80,0x00,0x09,0x06,0x69,0x6f,0x64,0x69,0x6e,0x65,0xc0,0x21,0xc0,
311  0x6b,0x00,0x01,0x00,0x01,0x00,0x09,0x3a,0x80,0x00,0x04,0x0a,0x1e,0x1c,0x5f
312  };
313  size_t buflen = sizeof(buf);
314  Flow *f = NULL;
315 
316  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
317  FAIL_IF_NULL(f);
318  f->proto = IPPROTO_UDP;
319  f->alproto = ALPROTO_DNS;
320  f->alstate = rs_dns_state_new();
321  FAIL_IF_NULL(f->alstate);
322 
323  FAIL_IF_NOT(RustDNSUDPParseResponse(f, f->alstate, NULL, buf, buflen,
324  NULL, STREAM_START));
325 
326  UTHFreeFlow(f);
327  PASS;
328 }
329 
330 /** \test TXT records in answer, bad txtlen */
331 static int RustDNSUDPParserTest05 (void)
332 {
333  uint8_t buf[] = {
334  0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41,
335  0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72,
336  0x76,0x06,0x74,0x75,0x6e,0x6e,0x65,0x6c,0x03,0x63,0x6f,0x6d,0x00,0x00,0x10,0x00,
337  0x01,
338  /* answer record start */
339  0xc0,0x0c,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x22,
340  /* txt record starts: */
341  0x40, /* <txt len 64 */ 0x41,0x68,0x76,0x4d,0x41,0x41,0x4f,0x31,0x6b,0x41,0x46,
342  0x45,0x35,0x54,0x45,0x39,0x51,0x54,0x6a,0x46,0x46,0x4e,0x30,0x39,0x52,0x4e,0x31,
343  0x6c,0x59,0x53,0x44,0x6b,0x00, /* <txt len 0 */ 0xc0,0x1d,0x00,0x02,0x00,0x01,
344  0x00,0x09,0x3a,0x80,0x00,0x09,0x06,0x69,0x6f,0x64,0x69,0x6e,0x65,0xc0,0x21,0xc0,
345  0x6b,0x00,0x01,0x00,0x01,0x00,0x09,0x3a,0x80,0x00,0x04,0x0a,0x1e,0x1c,0x5f
346  };
347  size_t buflen = sizeof(buf);
348  Flow *f = NULL;
349 
350  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
351  FAIL_IF_NULL(f);
352  f->proto = IPPROTO_UDP;
353  f->alproto = ALPROTO_DNS;
354  f->alstate = rs_dns_state_new();
355  FAIL_IF_NULL(f->alstate);
356 
357  FAIL_IF(RustDNSUDPParseResponse(f, f->alstate, NULL, buf, buflen,
358  NULL, STREAM_START) != -1);
359 
360  UTHFreeFlow(f);
361  PASS;
362 }
363 
364 static void RustDNSUDPParserRegisterTests(void)
365 {
366  UtRegisterTest("RustDNSUDPParserTest01", RustDNSUDPParserTest01);
367  UtRegisterTest("RustDNSUDPParserTest02", RustDNSUDPParserTest02);
368  UtRegisterTest("RustDNSUDPParserTest03", RustDNSUDPParserTest03);
369  UtRegisterTest("RustDNSUDPParserTest04", RustDNSUDPParserTest04);
370  UtRegisterTest("RustDNSUDPParserTest05", RustDNSUDPParserTest05);
371 }
372 
373 #endif
uint16_t flags
void AppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2)
register parser at a port
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
uint8_t proto
Definition: flow.h:344
LoggerId
void DNSAppLayerRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto)
int logged
#define PASS
Pass the test.
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
void AppLayerParserRegisterDetectFlagsFuncs(uint8_t ipproto, AppProto alproto, uint64_t(*GetTxDetectFlags)(void *tx, uint8_t dir), void(*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t))
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, AppLayerDecoderEvents *(*StateGetEvents)(void *))
void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
void * alstate
Definition: flow.h:438
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests and when...
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Data structure to store app layer decoder events.
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc)
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define STREAM_TOCLIENT
Definition: stream.h:32
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
int RunmodeIsUnittests(void)
Definition: suricata.c:267
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
uint16_t tx_id
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
#define STREAM_START
Definition: stream.h:29
#define STREAM_TOSERVER
Definition: stream.h:31
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
uint8_t len
AppProto alproto
application level protocol
Definition: flow.h:409
void RegisterDNSUDPParsers(void)
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
Flow data structure.
Definition: flow.h:325
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
void UTHFreeFlow(Flow *flow)
void DNSAppLayerRegisterGetEventInfo(uint8_t ipproto, AppProto alproto)
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))