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