1 /* SIE DNS dedupe nmsg message module */
2
3 /*
4 * Copyright (c) 2010-2012 by Farsight Security, Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 /* Import. */
20
21 #include <string.h>
22 #include <time.h>
23
24 #include "defs.h"
25 #include "dnsdedupe.pb-c.h"
26
27 /* Exported via module context. */
28
29 static NMSG_MSGMOD_FIELD_PRINTER(dns_name_print);
30 static NMSG_MSGMOD_FIELD_PRINTER(dns_type_print);
31 static NMSG_MSGMOD_FIELD_PRINTER(dns_class_print);
32 static NMSG_MSGMOD_FIELD_PRINTER(dns_rdata_print);
33 static NMSG_MSGMOD_FIELD_PRINTER(dns_message_print);
34 static NMSG_MSGMOD_FIELD_PRINTER(time_print);
35
36 static NMSG_MSGMOD_FIELD_FORMATTER(dns_name_format);
37 static NMSG_MSGMOD_FIELD_FORMATTER(dns_type_format);
38 static NMSG_MSGMOD_FIELD_FORMATTER(dns_class_format);
39 static NMSG_MSGMOD_FIELD_FORMATTER(dns_rdata_format);
40 static NMSG_MSGMOD_FIELD_FORMATTER(dns_message_format);
41 static NMSG_MSGMOD_FIELD_FORMATTER(time_format);
42
43 static NMSG_MSGMOD_FIELD_PARSER(dns_name_parse);
44 static NMSG_MSGMOD_FIELD_PARSER(dns_type_parse);
45 static NMSG_MSGMOD_FIELD_PARSER(dns_class_parse);
46 static NMSG_MSGMOD_FIELD_PARSER(dns_rdata_parse);
47 static NMSG_MSGMOD_FIELD_PARSER(dns_message_parse);
48 static NMSG_MSGMOD_FIELD_PARSER(time_parse);
49
50 /* Data. */
51
52 struct nmsg_msgmod_field dnsdedupe_fields[] = {
53 {
54 .type = nmsg_msgmod_ft_enum,
55 .name = "type"
56 },
57 {
58 .type = nmsg_msgmod_ft_uint32,
59 .name = "count"
60 },
61 {
62 .type = nmsg_msgmod_ft_uint32,
63 .name = "time_first",
64 .print = time_print,
65 .format = time_format,
66 .parse = time_parse
67 },
68 {
69 .type = nmsg_msgmod_ft_uint32,
70 .name = "time_last",
71 .print = time_print,
72 .format = time_format,
73 .parse = time_parse
74 },
75 {
76 .type = nmsg_msgmod_ft_uint32,
77 .name = "zone_time_first",
78 .print = time_print,
79 .format = time_format,
80 .parse = time_parse
81 },
82 {
83 .type = nmsg_msgmod_ft_uint32,
84 .name = "zone_time_last",
85 .print = time_print,
86 .format = time_format,
87 .parse = time_parse
88 },
89 {
90 .type = nmsg_msgmod_ft_ip,
91 .name = "response_ip",
92 },
93 {
94 .type = nmsg_msgmod_ft_bytes,
95 .name = "bailiwick",
96 .print = dns_name_print,
97 .format = dns_name_format,
98 .parse = dns_name_parse
99 },
100 {
101 .type = nmsg_msgmod_ft_bytes,
102 .name = "rrname",
103 .print = dns_name_print,
104 .format = dns_name_format,
105 .parse = dns_name_parse
106 },
107 {
108 .type = nmsg_msgmod_ft_uint16,
109 .name = "rrclass",
110 .print = dns_class_print,
111 .format = dns_class_format,
112 .parse = dns_class_parse
113 },
114 {
115 .type = nmsg_msgmod_ft_uint16,
116 .name = "rrtype",
117 .print = dns_type_print,
118 .format = dns_type_format,
119 .parse = dns_type_parse
120 },
121 {
122 .type = nmsg_msgmod_ft_uint32,
123 .name = "rrttl",
124 },
125 {
126 .type = nmsg_msgmod_ft_bytes,
127 .name = "rdata",
128 .flags = NMSG_MSGMOD_FIELD_REPEATED,
129 .print = dns_rdata_print,
130 .format = dns_rdata_format,
131 .parse = dns_rdata_parse
132 },
133 {
134 .type = nmsg_msgmod_ft_bytes,
135 .name = "response",
136 .print = dns_message_print,
137 .format = dns_message_format,
138 .parse = dns_message_parse
139 },
140 NMSG_MSGMOD_FIELD_END
141 };
142
143 /* Export. */
144
145 struct nmsg_msgmod_plugin nmsg_msgmod_ctx = {
146 NMSG_MSGMOD_REQUIRED_INIT,
147 .vendor = NMSG_VENDOR_SIE,
148 .msgtype = { NMSG_VENDOR_SIE_DNSDEDUPE_ID, NMSG_VENDOR_SIE_DNSDEDUPE_NAME },
149
150 .pbdescr = &nmsg__sie__dns_dedupe__descriptor,
151 .fields = dnsdedupe_fields
152 };
153
154 /* Private. */
155
156 static nmsg_res
time_print(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)157 time_print(nmsg_message_t msg,
158 struct nmsg_msgmod_field *field,
159 void *ptr,
160 struct nmsg_strbuf *sb,
161 const char *endline)
162 {
163 (void)msg; /* unused parameter */
164 nmsg_res res = nmsg_res_failure;
165 time_t t;
166 struct tm gm;
167
168 t = *((uint32_t *) ptr);
169
170 if (gmtime_r(&t, &gm) != NULL) {
171 res = nmsg_strbuf_append(sb, "%s: %d-%02d-%02d %02d:%02d:%02d%s",
172 field->name,
173 1900 + gm.tm_year,
174 1 + gm.tm_mon,
175 gm.tm_mday,
176 gm.tm_hour,
177 gm.tm_min,
178 gm.tm_sec,
179 endline);
180 }
181
182 return (res);
183 }
184
185 static nmsg_res
time_format(nmsg_message_t m,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)186 time_format(nmsg_message_t m,
187 struct nmsg_msgmod_field *field,
188 void *ptr,
189 struct nmsg_strbuf *sb,
190 const char *endline)
191 {
192 (void)m; /* unused parameter */
193 (void)field; /* unused parameter */
194 (void)endline; /* unused parameter */
195 nmsg_res res = nmsg_res_failure;
196 time_t t;
197 struct tm gm;
198
199 t = *((uint32_t *) ptr);
200
201 if (gmtime_r(&t, &gm) != NULL) {
202 res = nmsg_strbuf_append(sb, "%d-%02d-%02d %02d:%02d:%02d",
203 1900 + gm.tm_year,
204 1 + gm.tm_mon,
205 gm.tm_mday,
206 gm.tm_hour,
207 gm.tm_min,
208 gm.tm_sec);
209 }
210
211 return (res);
212 }
213
214 static nmsg_res
time_parse(nmsg_message_t m,struct nmsg_msgmod_field * field,const char * value,void ** ptr,size_t * len,const char * endline)215 time_parse(nmsg_message_t m,
216 struct nmsg_msgmod_field *field,
217 const char *value,
218 void **ptr,
219 size_t *len,
220 const char *endline)
221 {
222 (void)m; /* unused parameter */
223 (void)field; /* unused parameter */
224 (void)endline; /* unused parameter */
225 time_t * t;
226 struct tm gm;
227
228 if (!strptime(value, "%Y-%m-%d %T", &gm)) {
229 return (nmsg_res_parse_error);
230 }
231
232 t = malloc(sizeof(*t));
233 *t = timegm(&gm);
234
235 *ptr = t;
236 *len = sizeof(*t);
237
238 return (nmsg_res_success);
239 }
240
241 static nmsg_res
dns_name_print(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)242 dns_name_print(nmsg_message_t msg,
243 struct nmsg_msgmod_field *field,
244 void *ptr,
245 struct nmsg_strbuf *sb,
246 const char *endline)
247 {
248 (void)msg; /* unused parameter */
249 ProtobufCBinaryData *rrname = ptr;
250 char name[WDNS_PRESLEN_NAME];
251 nmsg_res res = nmsg_res_success;
252
253 if (rrname->data != NULL &&
254 rrname->len > 0 &&
255 rrname->len <= WDNS_MAXLEN_NAME)
256 {
257 wdns_domain_to_str(rrname->data, rrname->len, name);
258 res = nmsg_strbuf_append(sb, "%s: %s%s", field->name,
259 name, endline);
260 }
261 return (res);
262 }
263
264 static nmsg_res
dns_name_format(nmsg_message_t m,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)265 dns_name_format(nmsg_message_t m,
266 struct nmsg_msgmod_field *field,
267 void *ptr,
268 struct nmsg_strbuf *sb,
269 const char *endline)
270 {
271 (void)m; /* unused parameter */
272 (void)field; /* unused parameter */
273 (void)endline; /* unused parameter */
274 ProtobufCBinaryData *rrname = ptr;
275 char name[WDNS_PRESLEN_NAME];
276 nmsg_res res = nmsg_res_success;
277
278 if (rrname->data != NULL &&
279 rrname->len > 0 &&
280 rrname->len <= WDNS_MAXLEN_NAME)
281 {
282 wdns_domain_to_str(rrname->data, rrname->len, name);
283 res = nmsg_strbuf_append(sb, "%s", name);
284 }
285 return (res);
286 }
287
288 static nmsg_res
dns_name_parse(nmsg_message_t m,struct nmsg_msgmod_field * field,const char * value,void ** ptr,size_t * len,const char * endline)289 dns_name_parse(nmsg_message_t m,
290 struct nmsg_msgmod_field *field,
291 const char *value,
292 void **ptr,
293 size_t *len,
294 const char *endline)
295 {
296 (void)m; /* unused parameter */
297 (void)field; /* unused parameter */
298 (void)endline; /* unused parameter */
299 wdns_res res;
300 wdns_name_t *name;
301
302 name = malloc(sizeof(*name));
303 if (name == NULL) {
304 return (nmsg_res_memfail);
305 }
306
307 res = wdns_str_to_name_case(value, name);
308 if (res != wdns_res_success) {
309 free(name);
310 return (nmsg_res_parse_error);
311 }
312
313 *ptr = name->data;
314 *len = name->len;
315
316 free(name);
317
318 return (nmsg_res_success);
319 }
320
321 static nmsg_res
dns_type_print(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)322 dns_type_print(nmsg_message_t msg,
323 struct nmsg_msgmod_field *field,
324 void *ptr,
325 struct nmsg_strbuf *sb,
326 const char *endline)
327 {
328 (void)msg; /* unused parameter */
329 uint16_t rrtype;
330 const char *s;
331 nmsg_res res = nmsg_res_success;
332
333 memcpy(&rrtype, ptr, sizeof(rrtype));
334 s = wdns_rrtype_to_str(rrtype);
335 res = nmsg_strbuf_append(sb, "%s: %s (%u)%s",
336 field->name,
337 s ? s : "<UNKNOWN>",
338 rrtype, endline);
339 return (res);
340 }
341
342 static nmsg_res
dns_type_format(nmsg_message_t m,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)343 dns_type_format(nmsg_message_t m,
344 struct nmsg_msgmod_field *field,
345 void *ptr,
346 struct nmsg_strbuf *sb,
347 const char *endline)
348 {
349 (void)m; /* unused parameter */
350 (void)field; /* unused parameter */
351 (void)endline; /* unused parameter */
352 uint16_t rrtype;
353 const char *s;
354 nmsg_res res = nmsg_res_success;
355
356 memcpy(&rrtype, ptr, sizeof(rrtype));
357 s = wdns_rrtype_to_str(rrtype);
358 res = nmsg_strbuf_append(sb, "%s", s ? s : "<UNKNOWN>");
359 return (res);
360 }
361
362 static nmsg_res
dns_type_parse(nmsg_message_t msg,struct nmsg_msgmod_field * field,const char * value,void ** ptr,size_t * len,const char * endline)363 dns_type_parse(nmsg_message_t msg,
364 struct nmsg_msgmod_field *field,
365 const char *value,
366 void **ptr,
367 size_t *len,
368 const char *endline)
369 {
370 (void)msg; /* unused parameter */
371 (void)field; /* unused parameter */
372 (void)endline; /* unused parameter */
373 uint16_t *rrtype;
374
375 rrtype = malloc(sizeof(*rrtype));
376 if (rrtype == NULL) {
377 return (nmsg_res_memfail);
378 }
379
380 *rrtype = wdns_str_to_rrtype(value);
381 if (*rrtype == 0) {
382 free(rrtype);
383 return (nmsg_res_parse_error);
384 }
385
386 *ptr = rrtype;
387 *len = sizeof(*rrtype);
388
389 return (nmsg_res_success);
390 }
391
392 static nmsg_res
dns_class_print(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)393 dns_class_print(nmsg_message_t msg,
394 struct nmsg_msgmod_field *field,
395 void *ptr,
396 struct nmsg_strbuf *sb,
397 const char *endline)
398 {
399 (void)msg; /* unused parameter */
400 uint16_t rrclass;
401 const char *s;
402 nmsg_res res = nmsg_res_success;
403
404 memcpy(&rrclass, ptr, sizeof(rrclass));
405 s = wdns_rrclass_to_str(rrclass);
406 res = nmsg_strbuf_append(sb, "%s: %s (%u)%s",
407 field->name,
408 s ? s : "<UNKNOWN>",
409 rrclass, endline);
410 return (res);
411 }
412
413 static nmsg_res
dns_class_format(nmsg_message_t m,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)414 dns_class_format(nmsg_message_t m,
415 struct nmsg_msgmod_field *field,
416 void *ptr,
417 struct nmsg_strbuf *sb,
418 const char *endline)
419 {
420 (void)m; /* unused parameter */
421 (void)field; /* unused parameter */
422 (void)endline; /* unused parameter */
423 uint16_t rrclass;
424 const char *s;
425 nmsg_res res = nmsg_res_success;
426
427 memcpy(&rrclass, ptr, sizeof(rrclass));
428 s = wdns_rrclass_to_str(rrclass);
429 res = nmsg_strbuf_append(sb, "%s", s ? s : "<UNKNOWN>");
430 return (res);
431 }
432
433 static nmsg_res
dns_class_parse(nmsg_message_t m,struct nmsg_msgmod_field * field,const char * value,void ** ptr,size_t * len,const char * endline)434 dns_class_parse(nmsg_message_t m,
435 struct nmsg_msgmod_field *field,
436 const char *value,
437 void **ptr,
438 size_t *len,
439 const char *endline)
440 {
441 (void)m; /* unused parameter */
442 (void)field; /* unused parameter */
443 (void)endline; /* unused parameter */
444 uint16_t *rrclass;
445
446 rrclass = malloc(sizeof(*rrclass));
447 if (rrclass == NULL) {
448 return (nmsg_res_memfail);
449 }
450
451 *rrclass = wdns_str_to_rrclass(value);
452 *rrclass = WDNS_CLASS_IN;
453 if (*rrclass == 0) {
454 free(rrclass);
455 return (nmsg_res_parse_error);
456 }
457
458 *ptr = rrclass;
459 *len = sizeof(*rrclass);
460
461 return (nmsg_res_success);
462 }
463
464 static nmsg_res
dns_rdata_print(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)465 dns_rdata_print(nmsg_message_t msg,
466 struct nmsg_msgmod_field *field,
467 void *ptr,
468 struct nmsg_strbuf *sb,
469 const char *endline)
470 {
471 (void)field; /* unused parameter */
472 ProtobufCBinaryData *rdata = ptr;
473 nmsg_res res;
474 char *buf;
475 uint32_t *rrtype, *rrclass;
476 size_t len;
477
478 res = nmsg_message_get_field(msg, "rrtype", 0, (void**) &rrtype, &len);
479 if (res != nmsg_res_success) {
480 return (nmsg_res_failure);
481 }
482 if (len != sizeof(uint32_t)) {
483 return (nmsg_res_failure);
484 }
485
486 res = nmsg_message_get_field(msg, "rrclass", 0, (void**) &rrclass, &len);
487 if (res != nmsg_res_success) {
488 return (nmsg_res_failure);
489 }
490 if (len != sizeof(uint32_t)) {
491 return (nmsg_res_failure);
492 }
493
494 buf = wdns_rdata_to_str(rdata->data, rdata->len, *rrtype, *rrclass);
495 if (buf == NULL)
496 return (nmsg_res_memfail);
497
498 res = nmsg_strbuf_append(sb, "rdata: %s%s", buf, endline);
499 free(buf);
500 return (res);
501 }
502
503 static nmsg_res
dns_rdata_format(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)504 dns_rdata_format(nmsg_message_t msg,
505 struct nmsg_msgmod_field *field,
506 void *ptr,
507 struct nmsg_strbuf *sb,
508 const char *endline)
509 {
510 (void)field; /* unused parameter */
511 (void)endline; /* unused parameter */
512 ProtobufCBinaryData *rdata = ptr;
513 nmsg_res res;
514 char *buf;
515 uint32_t *rrtype, *rrclass;
516 size_t len;
517
518 res = nmsg_message_get_field(msg, "rrtype", 0, (void**) &rrtype, &len);
519 if (res != nmsg_res_success) {
520 return (nmsg_res_failure);
521 }
522 if (len != sizeof(uint32_t)) {
523 return (nmsg_res_failure);
524 }
525
526 res = nmsg_message_get_field(msg, "rrclass", 0, (void**) &rrclass, &len);
527 if (res != nmsg_res_success) {
528 return (nmsg_res_failure);
529 }
530 if (len != sizeof(uint32_t)) {
531 return (nmsg_res_failure);
532 }
533
534 buf = wdns_rdata_to_str(rdata->data, rdata->len, *rrtype, *rrclass);
535 if (buf == NULL)
536 return (nmsg_res_memfail);
537
538 res = nmsg_strbuf_append(sb, "%s", buf);
539 free(buf);
540 return (res);
541 }
542
543 static nmsg_res
dns_rdata_parse(nmsg_message_t m,struct nmsg_msgmod_field * field,const char * value,void ** ptr,size_t * len,const char * endline)544 dns_rdata_parse(nmsg_message_t m,
545 struct nmsg_msgmod_field *field,
546 const char *value,
547 void **ptr,
548 size_t *len,
549 const char *endline)
550 {
551 (void)field; /* unused parameter */
552 (void)endline; /* unused parameter */
553 nmsg_res res;
554 wdns_res w_res;
555 uint32_t *rrtype, *rrclass;
556 size_t f_len;
557
558 res = nmsg_message_get_field(m, "rrtype", 0, (void**) &rrtype, &f_len);
559 if (res != nmsg_res_success) {
560 return (nmsg_res_failure);
561 }
562 if (f_len != sizeof(uint32_t)) {
563 return (nmsg_res_failure);
564 }
565
566 res = nmsg_message_get_field(m, "rrclass", 0, (void**) &rrclass, &f_len);
567 if (res != nmsg_res_success) {
568 return (nmsg_res_failure);
569 }
570 if (f_len != sizeof(uint32_t)) {
571 return (nmsg_res_failure);
572 }
573
574 w_res = wdns_str_to_rdata(value, *rrtype, *rrclass, (uint8_t**)ptr, len);
575 if (w_res == wdns_res_parse_error) {
576 return (nmsg_res_parse_error);
577 } else if (w_res != wdns_res_success) {
578 return (nmsg_res_failure);
579 }
580
581 return (nmsg_res_success);
582 }
583
584 static nmsg_res
dns_message_print(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)585 dns_message_print(nmsg_message_t msg,
586 struct nmsg_msgmod_field *field,
587 void *ptr,
588 struct nmsg_strbuf *sb,
589 const char *endline)
590 {
591 (void)ptr; /* unused parameter */
592 nmsg_res res;
593 uint8_t *payload;
594 size_t payload_len;
595
596 res = nmsg_message_get_field(msg, field->name, 0, (void **) &payload, &payload_len);
597 if (res == nmsg_res_success) {
598 wdns_message_t dns;
599 wdns_res wres;
600
601 wres = wdns_parse_message(&dns, payload, payload_len);
602 if (wres == wdns_res_success) {
603 char *s;
604
605 s = wdns_message_to_str(&dns);
606 if (s != NULL) {
607 nmsg_strbuf_append(sb, "%s: [%zd octets]%s%s---%s",
608 field->name, payload_len, endline, s, endline);
609 free(s);
610 wdns_clear_message(&dns);
611 return (nmsg_res_success);
612 }
613 wdns_clear_message(&dns);
614 }
615 }
616 nmsg_strbuf_append(sb, "%s: <PARSE ERROR>%s", field->name, endline);
617 return (nmsg_res_success);
618 }
619
620 static nmsg_res
dns_message_format(nmsg_message_t msg,struct nmsg_msgmod_field * field,void * ptr,struct nmsg_strbuf * sb,const char * endline)621 dns_message_format(nmsg_message_t msg,
622 struct nmsg_msgmod_field *field,
623 void *ptr,
624 struct nmsg_strbuf *sb,
625 const char *endline)
626 {
627 (void)ptr; /* unused parameter */
628 (void)endline; /* unused parameter */
629 nmsg_res res;
630 uint8_t *payload;
631 size_t payload_len;
632
633 res = nmsg_message_get_field(msg, field->name, 0, (void **) &payload, &payload_len);
634 if (res == nmsg_res_success) {
635 wdns_message_t dns;
636 wdns_res wres;
637
638 wres = wdns_parse_message(&dns, payload, payload_len);
639 if (wres == wdns_res_success) {
640 char *s;
641
642 s = wdns_message_to_str(&dns);
643 if (s != NULL) {
644 nmsg_strbuf_append(sb, "%s", s);
645 free(s);
646 wdns_clear_message(&dns);
647 return (nmsg_res_success);
648 }
649 wdns_clear_message(&dns);
650 }
651 }
652 nmsg_strbuf_append(sb, "<PARSE ERROR>");
653 return (nmsg_res_success);
654 }
655
656 static nmsg_res
dns_message_parse(nmsg_message_t m,struct nmsg_msgmod_field * field,const char * value,void ** ptr,size_t * len,const char * endline)657 dns_message_parse(nmsg_message_t m,
658 struct nmsg_msgmod_field *field,
659 const char *value,
660 void **ptr,
661 size_t *len,
662 const char *endline)
663 {
664 (void)m; /* unused parameter */
665 (void)field; /* unused parameter */
666 (void)value; /* unused parameter */
667 (void)ptr; /* unused parameter */
668 (void)len; /* unused parameter */
669 (void)endline; /* unused parameter */
670 return (nmsg_res_notimpl);
671 }
672