1 /**
2  * @file mediator_json.c
3  *
4  * Contains most of the JSON-y functions.
5  *
6  ** ------------------------------------------------------------------------
7  ** Copyright (C) 2012-2017 Carnegie Mellon University. All Rights Reserved.
8  ** ------------------------------------------------------------------------
9  * Authors: Emily Sarneso <netsa-help@cert.org>
10  * ------------------------------------------------------------------------
11  * @OPENSOURCE_HEADER_START@
12  * Use of this (and related) source code is subject to the terms
13  * of the following licenses:
14  *
15  * GNU Public License (GPL) Rights pursuant to Version 2, June 1991
16  * Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
17  *
18  * NO WARRANTY
19  *
20  * ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
21  * PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
22  * PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
23  * "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
24  * KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
25  * LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
26  * MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
27  * OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
28  * SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
29  * TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
30  * WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
31  * LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
32  * CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
33  * CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
34  * DELIVERABLES UNDER THIS LICENSE.
35  *
36  * Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
37  * Mellon University, its trustees, officers, employees, and agents from
38  * all claims or demands made against them (and any related losses,
39  * expenses, or attorney's fees) arising out of, or relating to Licensee's
40  * and/or its sub licensees' negligent use or willful misuse of or
41  * negligent conduct or willful misconduct regarding the Software,
42  * facilities, or other rights or assistance granted by Carnegie Mellon
43  * University under this License, including, but not limited to, any
44  * claims of product liability, personal injury, death, damage to
45  * property, or violation of any laws or regulations.
46  *
47  * Carnegie Mellon University Software Engineering Institute authored
48  * documents are sponsored by the U.S. Department of Defense under
49  * Contract FA8721-05-C-0003. Carnegie Mellon University retains
50  * copyrights in all material produced under this contract. The U.S.
51  * Government retains a non-exclusive, royalty-free license to publish or
52  * reproduce these documents, or allow othersto do so, for U.S.
53  * Government purposes only pursuant to the copyright license under the
54  * contract clause at 252.227.7013.
55  *
56  *
57  * @OPENSOURCE_HEADER_END@
58  * -----------------------------------------------------------
59  */
60 
61 #include <mediator/mediator_ctx.h>
62 #include <mediator/mediator_util.h>
63 #include <mediator/mediator_inf.h>
64 #include "mediator_print.h"
65 #include "mediator_json.h"
66 
67 #define FBSTLNEXT(a, b) fbSubTemplateListGetNextPtr(a, b)
68 #define MD_REM_MSG(_buf_) (buf->buflen - (_buf_->cp - _buf_->buf))
69 
70 #define MD_WR_BDC(_ret_, _size_)             \
71     if (_ret_ < 0) return FALSE;             \
72     if ((size_t)_ret_ >= _size_) return FALSE;  \
73     _size_ -= _ret_;
74 
75 #define MD_CHECK_RET(_buf_, _ret_, _size_)    \
76     if (_ret_ < 0) return FALSE;              \
77     if ((size_t)_ret_ >= _size_) return FALSE;  \
78     _size_ -= _ret_;                          \
79     _buf_->cp += _ret_;
80 
81 #define MD_CHECK_RET0(_buf_, _ret_, _size_)    \
82     if (_ret_ < 0) return 0;                  \
83     if ((size_t)_ret_ >= _size_) return 0;    \
84     _size_ -= _ret_;                          \
85     _buf_->cp += _ret_;
86 
87 #define MD_APPEND_CHAR(_buf_, _ch_)           \
88     *(_buf_->cp) = _ch_;                      \
89     ++(_buf_->cp);
90 #define MD_APPEND_CHAR_CHECK(_rem_, _buf_, _ch_)        \
91     if (_rem_ > 1) {                           \
92         MD_APPEND_CHAR(_buf_, _ch_);           \
93         _rem_ -= 1;                            \
94     } else {                                   \
95         return FALSE;                          \
96     }
97 
98 
99 /* RFC 4627 -
100 Any character may be escaped.  If the character is in the Basic
101    Multilingual Plane (U+0000 through U+FFFF), then it may be
102    represented as a six-character sequence: a reverse solidus, followed
103    by the lowercase letter u, followed by four hexadecimal digits that
104    encode the character's code point.  The hexadecimal letters A though
105    F can be upper or lowercase.  So, for example, a string containing
106    only a single reverse solidus character may be represented as
107    "\u005C".
108 */
109 
mdJsonifyEscapeChars(mdBuf_t * mdbuf,size_t * rem,uint8_t * buf,size_t buflen)110 gboolean mdJsonifyEscapeChars(
111     mdBuf_t  *mdbuf,
112     size_t   *rem,
113     uint8_t  *buf,
114     size_t   buflen)
115 {
116     int i, ret;
117     uint8_t ch;
118 
119     for (i = 0; i < (int)buflen; i++) {
120         ch = buf[i];
121         if (ch == '\\') {
122             ret = snprintf(mdbuf->cp, *rem, "\\\\");
123         } else if (ch < 32 || ch >= 127) {
124             ret = snprintf(mdbuf->cp, *rem, "\\u%04x", ch);
125         } else if (ch == '"') {
126             ret = snprintf(mdbuf->cp, *rem, "\\%c", ch);
127         } else {
128             ret = snprintf(mdbuf->cp, *rem, "%c", ch);
129         }
130         MD_WR_BDC(ret, *rem);
131         mdbuf->cp += ret;
132     }
133 
134     return TRUE;
135 
136 }
137 
mdJsonifyDNSRRRecord(md_dns_rr_t * rec,mdBuf_t * buf)138 gboolean mdJsonifyDNSRRRecord(
139     md_dns_rr_t          *rec,
140     mdBuf_t            *buf)
141 {
142     size_t brem = MD_REM_MSG(buf);
143     size_t buftest;
144     uint64_t start_secs = rec->flowStartMilliseconds / 1000;
145     uint32_t start_rem = rec->flowStartMilliseconds % 1000;
146     char     sabuf[40];
147     char    testsip[16];
148     int ret;
149 
150     ret = snprintf(buf->cp, brem, "{\"dns\":{\"flowStartMilliseconds\":\"");
151     MD_CHECK_RET0(buf, ret, brem);
152 
153     memset(testsip, 0, sizeof(testsip));
154 
155     if (!md_util_time_buf_append(buf, &brem, start_secs, PRINT_TIME_FMT)) {
156         return 0;
157     }
158 
159     ret = snprintf(buf->cp, brem, ".%03u\",", start_rem);
160 
161     MD_CHECK_RET0(buf, ret, brem);
162 
163     if (rec->sourceIPv4Address == 0) {
164         if (memcmp(rec->sourceIPv6Address, testsip, sizeof(rec->sourceIPv6Address))) {
165             md_util_print_ip6_addr(sabuf, rec->sourceIPv6Address);
166             ret = snprintf(buf->cp, brem, "\"sourceIPv6Address\":\"%s\",", sabuf);
167             MD_CHECK_RET0(buf, ret, brem);
168             md_util_print_ip6_addr(sabuf, rec->destinationIPv6Address);
169             ret = snprintf(buf->cp, brem, "\"destinationIPv6Address\":\"%s\",", sabuf);
170             MD_CHECK_RET0(buf, ret, brem);
171         }
172     } else {
173         md_util_print_ip4_addr(sabuf, rec->sourceIPv4Address);
174         ret = snprintf(buf->cp, brem, "\"sourceIPv4Address\":\"%s\",", sabuf);
175         MD_CHECK_RET0(buf, ret, brem);
176         md_util_print_ip4_addr(sabuf, rec->destinationIPv4Address);
177         ret = snprintf(buf->cp, brem, "\"destinationIPv4Address\":\"%s\",", sabuf);
178         MD_CHECK_RET0(buf, ret, brem);
179 
180     }
181 
182     if (rec->protocolIdentifier) {
183         ret = snprintf(buf->cp, brem, "\"protocolIdentifier\":%d,", rec->protocolIdentifier);
184         MD_CHECK_RET0(buf, ret, brem);
185     }
186 
187     if (rec->vlanId) {
188         ret = snprintf(buf->cp, brem, "\"vlanId\":\"%u,", rec->vlanId);
189         MD_CHECK_RET0(buf, ret, brem);
190     }
191 
192     if (rec->sourceTransportPort) {
193         ret = snprintf(buf->cp, brem, "\"sourceTransportPort\":%d,", rec->sourceTransportPort);
194         MD_CHECK_RET0(buf, ret, brem);
195     }
196 
197     if (rec->destinationTransportPort) {
198         ret = snprintf(buf->cp,brem, "\"destinationTransportPort\":%d,", rec->destinationTransportPort);
199         MD_CHECK_RET0(buf, ret,brem);
200     }
201 
202     if (rec->yafFlowKeyHash) {
203         ret = snprintf(buf->cp,brem, "\"yafFlowKeyHash\":%u,", rec->yafFlowKeyHash);
204         MD_CHECK_RET0(buf, ret,brem);
205     }
206 
207     if (rec->observationDomainId) {
208         ret = snprintf(buf->cp, brem, "\"observationDomainId\":%u,", rec->observationDomainId);
209         MD_CHECK_RET0(buf, ret, brem);
210     }
211 
212     ret = snprintf(buf->cp, brem, "\"dnsRRSection\":%d,\"dnsNXDomain\":%d,",
213                    rec->dnsRRSection, rec->dnsNXDomain);
214     MD_CHECK_RET(buf, ret, brem);
215 
216     if (rec->dnsAuthoritative) {
217         ret = snprintf(buf->cp, brem, "\"dnsAuthoritative\":\"True\",");
218     } else {
219         ret = snprintf(buf->cp, brem, "\"dnsAuthoritative\":\"False\",");
220     }
221     MD_CHECK_RET(buf, ret, brem);
222 
223     ret = snprintf(buf->cp, brem, "\"dnsQRType\":%d, \"dnsTTL\":%u, "
224                    "\"dnsID\":%d,",
225                    rec->dnsQRType, rec->dnsTTL, rec->dnsID);
226 
227     MD_CHECK_RET(buf, ret, brem);
228 
229     if (rec->rrname.buf) {
230         ret = snprintf(buf->cp, brem, "\"dnsQName\":\"");
231         MD_CHECK_RET(buf, ret, brem);
232         mdJsonifyEscapeChars(buf, &brem, rec->rrname.buf, rec->rrname.len);
233         ret = snprintf(buf->cp, brem, "\",");
234         MD_CHECK_RET(buf, ret, brem);
235     } /* else - query may be for the root server which is NULL*/
236 
237     buftest = MD_REM_MSG(buf);
238 
239     if (rec->dnsQueryResponse == 0) {
240         /* query */
241         buf->cp -= 1;
242         brem += 1;
243         MD_APPEND_CHAR_CHECK(brem, buf, '}');
244         MD_APPEND_CHAR_CHECK(brem, buf, '}');
245         MD_APPEND_CHAR_CHECK(brem, buf, '\n');
246 
247         return TRUE;
248     }
249 
250     if (rec->dnsQRType == 1) {
251         uint32_t sip;
252         if (rec->rrdata.len) {
253             memcpy(&sip, rec->rrdata.buf, sizeof(uint32_t));
254             md_util_print_ip4_addr(sabuf, sip);
255             ret = snprintf(buf->cp, brem, "\"A\":\"%s\"", sabuf);
256             MD_CHECK_RET(buf, ret, brem);
257         }
258     } else if (rec->dnsQRType == 2) {
259         ret = snprintf(buf->cp, brem, "\"dnsNSDName\":\"");
260         MD_CHECK_RET(buf, ret, brem);
261         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
262                              rec->rrdata.len);
263         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
264 
265     } else if (rec->dnsQRType == 5) {
266         ret = snprintf(buf->cp, brem, "\"dnsCName\":\"");
267         MD_CHECK_RET(buf, ret, brem);
268         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
269                              rec->rrdata.len);
270         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
271     } else if (rec->dnsQRType == 12) {
272         ret = snprintf(buf->cp, brem, "\"dnsPTRDName\":\"");
273         MD_CHECK_RET(buf, ret, brem);
274         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
275                              rec->rrdata.len);
276         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
277     } else if (rec->dnsQRType == 15) {
278         ret = snprintf(buf->cp, brem, "\"dnsMXExchange\":\"");
279         MD_CHECK_RET(buf, ret, brem);
280         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
281                              rec->rrdata.len);
282         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
283     } else if (rec->dnsQRType == 28) {
284         uint8_t sip[16];
285         if (rec->rrdata.len) {
286             memcpy(sip, rec->rrdata.buf, sizeof(sip));
287             md_util_print_ip6_addr(sabuf, sip);
288             ret = snprintf(buf->cp, brem, "\"AAAA\":\"%s\"", sabuf);
289             MD_CHECK_RET(buf, ret, brem);
290         }
291     } else if (rec->dnsQRType == 16) {
292         ret = snprintf(buf->cp, brem, "\"dnsTXTData\":\"");
293         MD_CHECK_RET(buf, ret, brem);
294         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
295                              rec->rrdata.len);
296         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
297     } else if (rec->dnsQRType == 33) {
298         ret = snprintf(buf->cp, brem, "\"dnsSRVTarget\":\"");
299         MD_CHECK_RET(buf, ret, brem);
300         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
301                              rec->rrdata.len);
302         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
303     } else if (rec->dnsQRType == 6) {
304         ret = snprintf(buf->cp, brem, "\"dnsSOAMName\":\"");
305         MD_CHECK_RET(buf, ret, brem);
306         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
307                              rec->rrdata.len);
308         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
309     } else if (rec->dnsQRType == 46) {
310         ret = snprintf(buf->cp, brem, "\"dnsSigner\":\"");
311         MD_CHECK_RET(buf, ret, brem);
312         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
313                              rec->rrdata.len);
314         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
315     } else if (rec->dnsQRType == 47) {
316         ret = snprintf(buf->cp, brem, "\"dnsHashData\":\"");
317         MD_CHECK_RET(buf, ret, brem);
318         mdJsonifyEscapeChars(buf, &brem, rec->rrdata.buf,
319                              rec->rrdata.len);
320         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
321     }
322 
323     brem = MD_REM_MSG(buf);
324 
325     /* no rrname/rrdata */
326     if (brem == buftest) {
327         /* remove the comma at the end of dnsQName */
328         buf->cp -= 1;
329         brem += 1;
330     }
331 
332     MD_APPEND_CHAR_CHECK(brem, buf, '}');
333     MD_APPEND_CHAR_CHECK(brem, buf, '}');
334     MD_APPEND_CHAR_CHECK(brem, buf, '\n');
335     return TRUE;
336 
337 }
338 
339 
340 
mdJsonifyDNSRecord(yaf_dnsQR_t * dns,mdBuf_t * buf)341 gboolean mdJsonifyDNSRecord(
342     yaf_dnsQR_t     *dns,
343     mdBuf_t           *buf)
344 {
345     size_t brem = MD_REM_MSG(buf);
346     size_t buftest;
347     int ret;
348 
349     ret = snprintf(buf->cp, brem, "\"dnsRRSection\":%d,\"dnsNXDomain\":%d,",
350                    dns->dnsRRSection, dns->dnsNXDomain);
351     MD_CHECK_RET(buf, ret, brem);
352 
353     if (dns->dnsAuthoritative) {
354         ret = snprintf(buf->cp, brem, "\"dnsAuthoritative\":\"True\",");
355     } else {
356         ret = snprintf(buf->cp, brem, "\"dnsAuthoritative\":\"False\",");
357     }
358     MD_CHECK_RET(buf, ret, brem);
359 
360     ret = snprintf(buf->cp, brem, "\"dnsQRType\":%d, \"dnsTTL\":%u, \"dnsID\":%d,",
361                    dns->dnsQRType, dns->dnsTTL, dns->dnsID);
362 
363     MD_CHECK_RET(buf, ret, brem);
364 
365     if (dns->dnsQName.buf) {
366         ret = snprintf(buf->cp, brem, "\"dnsQName\":\"");
367         MD_CHECK_RET(buf, ret, brem);
368         mdJsonifyEscapeChars(buf, &brem, dns->dnsQName.buf, dns->dnsQName.len);
369         ret = snprintf(buf->cp, brem, "\",");
370         MD_CHECK_RET(buf, ret, brem);
371     } /* else - query may be for the root server which is NULL*/
372 
373     buftest = MD_REM_MSG(buf);
374 
375     if (dns->dnsQRType == 1) {
376         yaf_dnsA_t *aflow = NULL;
377         char ipaddr[20];
378         while ((aflow = (yaf_dnsA_t *)FBSTLNEXT(&(dns->dnsRRList), aflow))) {
379             if (aflow->sourceIPv4Address) {
380                 md_util_print_ip4_addr(ipaddr, aflow->sourceIPv4Address);
381                 ret = snprintf(buf->cp, brem, "\"A\":\"%s\"", ipaddr);
382                 MD_CHECK_RET(buf, ret, brem);
383             }
384         }
385     } else if (dns->dnsQRType == 2) {
386         yaf_dnsNS_t *ns = NULL;
387         while ((ns = (yaf_dnsNS_t *)FBSTLNEXT(&(dns->dnsRRList), ns))){
388             ret = snprintf(buf->cp, brem, "\"dnsNSDName\":\"");
389             MD_CHECK_RET(buf, ret, brem);
390             mdJsonifyEscapeChars(buf, &brem, ns->dnsNSDName.buf,
391                                       ns->dnsNSDName.len);
392             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
393         }
394 
395     } else if (dns->dnsQRType == 5) {
396         yaf_dns_CNAME_t *c = NULL;
397         while ((c = (yaf_dns_CNAME_t *)FBSTLNEXT(&(dns->dnsRRList), c)))
398         {
399             ret = snprintf(buf->cp, brem, "\"dnsCName\":\"");
400             MD_CHECK_RET(buf, ret, brem);
401             mdJsonifyEscapeChars(buf, &brem, c->dnsCName.buf,
402                                   c->dnsCName.len);
403             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
404         }
405     } else if (dns->dnsQRType == 12) {
406         yaf_dnsPTR_t *ptr = NULL;
407         while ((ptr = (yaf_dnsPTR_t *)FBSTLNEXT(&(dns->dnsRRList), ptr)))
408         {
409             ret = snprintf(buf->cp, brem, "\"dnsPTRDName\":\"");
410             MD_CHECK_RET(buf, ret, brem);
411             mdJsonifyEscapeChars(buf, &brem, ptr->dnsPTRDName.buf,
412                                       ptr->dnsPTRDName.len);
413             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
414         }
415     } else if (dns->dnsQRType == 15) {
416         yaf_dnsMX_t *mx = NULL;
417         while (( mx = (yaf_dnsMX_t *)FBSTLNEXT(&(dns->dnsRRList), mx)))
418         {
419             ret = snprintf(buf->cp, brem, "\"dnsMXExchange\":\"");
420             MD_CHECK_RET(buf, ret, brem);
421             mdJsonifyEscapeChars(buf, &brem, mx->dnsMXExchange.buf,
422                                   mx->dnsMXExchange.len);
423             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
424         }
425     } else if (dns->dnsQRType == 28) {
426         yaf_dnsAAAA_t *aa = NULL;
427         char ipaddr[40];
428         while ((aa = (yaf_dnsAAAA_t *)FBSTLNEXT(&(dns->dnsRRList), aa)))
429         {
430             md_util_print_ip6_addr(ipaddr,(uint8_t *)&(aa->sourceIPv6Address));
431             ret = snprintf(buf->cp, brem, "\"AAAA\":\"%s\"", ipaddr);
432             MD_CHECK_RET(buf, ret, brem);
433         }
434     } else if (dns->dnsQRType == 16) {
435         yaf_dnsTXT_t *txt = NULL;
436         while ((txt = (yaf_dnsTXT_t *)FBSTLNEXT(&(dns->dnsRRList), txt)))
437         {
438             ret = snprintf(buf->cp, brem, "\"dnsTXTData\":\"");
439             MD_CHECK_RET(buf, ret, brem);
440             mdJsonifyEscapeChars(buf, &brem, txt->dnsTXTData.buf,
441                                   txt->dnsTXTData.len);
442             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
443         }
444     } else if (dns->dnsQRType == 33) {
445         yaf_dnsSRV_t *srv = NULL;
446         while ((srv = (yaf_dnsSRV_t *)FBSTLNEXT(&(dns->dnsRRList), srv)))
447         {
448             ret = snprintf(buf->cp, brem, "\"dnsSRVTarget\":\"");
449             MD_CHECK_RET(buf, ret, brem);
450             mdJsonifyEscapeChars(buf, &brem,srv->dnsSRVTarget.buf,
451                                       srv->dnsSRVTarget.len);
452             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
453         }
454     } else if (dns->dnsQRType == 6) {
455         yaf_dnsSOA_t *soa = NULL;
456         while ((soa = (yaf_dnsSOA_t *)FBSTLNEXT(&(dns->dnsRRList), soa))) {
457             ret = snprintf(buf->cp, brem, "\"dnsSOAMName\":\"");
458             MD_CHECK_RET(buf, ret, brem);
459             mdJsonifyEscapeChars(buf, &brem,soa->dnsSOAMName.buf,
460                                       soa->dnsSOAMName.len);
461             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
462         }
463     } else if (dns->dnsQRType == 46) {
464         yaf_dnsRRSig_t *rr = NULL;
465         while ((rr = (yaf_dnsRRSig_t *)FBSTLNEXT(&(dns->dnsRRList), rr))) {
466             ret = snprintf(buf->cp, brem, "\"dnsSigner\":\"");
467             MD_CHECK_RET(buf, ret, brem);
468             mdJsonifyEscapeChars(buf, &brem, rr->dnsSigner.buf,
469                                       rr->dnsSigner.len);
470             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
471         }
472     } else if (dns->dnsQRType == 47) {
473         yaf_dnsNSEC_t *nsec = NULL;
474         while ((nsec = (yaf_dnsNSEC_t *)FBSTLNEXT(&(dns->dnsRRList), nsec)))
475         {
476             ret = snprintf(buf->cp, brem, "\"dnsHashData\":\"");
477             MD_CHECK_RET(buf, ret, brem);
478             mdJsonifyEscapeChars(buf, &brem, nsec->dnsHashData.buf,
479                                       nsec->dnsHashData.len);
480             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
481         }
482     }
483 
484     brem = MD_REM_MSG(buf);
485 
486     /* no rrname/rrdata */
487     if (brem == buftest) {
488         /* remove the comma at the end of dnsQName */
489         buf->cp -= 1;
490         brem += 1;
491     }
492 
493     return TRUE;
494 
495 }
496 
mdPrintJsonStats(yaf_stats_option_t * stats,char * name,FILE * lfp,GError ** err)497 size_t mdPrintJsonStats(
498     yaf_stats_option_t  *stats,
499     char            *name,
500     FILE            *lfp,
501     GError          **err)
502 {
503 
504     GString *str = NULL;
505     char ipaddr[20];
506     size_t rc;
507 
508     md_util_print_ip4_addr(ipaddr, stats->exporterIPv4Address);
509     str = g_string_new("");
510 
511     g_string_append(str, "{\"stats\":{");
512 
513     g_string_append_printf(str, "\"exportedFlowTotalCount\":%"PRIu64",",
514             stats->exportedFlowRecordTotalCount);
515     g_string_append_printf(str, "\"packetTotalCount\":%"PRIu64",",
516             stats->packetTotalCount);
517     g_string_append_printf(str, "\"droppedPacketTotalCount\":%"PRIu64",",
518             stats->droppedPacketTotalCount);
519     g_string_append_printf(str, "\"ignoredPacketTotalCount\":%"PRIu64",",
520             stats->ignoredPacketTotalCount);
521     g_string_append_printf(str, "\"expiredFragmentCount\":%u,",
522             stats->expiredFragmentCount);
523     g_string_append_printf(str, "\"assembledFragmentCount\":%u,",
524             stats->assembledFragmentCount);
525     g_string_append_printf(str, "\"flowTableFlushEvents\":%u,",
526             stats->flowTableFlushEvents);
527     g_string_append_printf(str, "\"flowTablePeakCount\":%u,",
528             stats->flowTablePeakCount);
529     g_string_append_printf(str, "\"exporterIPv4Address\":\"%s\",", ipaddr);
530     g_string_append_printf(str, "\"exportingProcessId\":%d,",
531             stats->exportingProcessId);
532     g_string_append_printf(str, "\"meanFlowRate\":%u,",
533             stats->meanFlowRate);
534     g_string_append_printf(str, "\"meanPacketRate\":%u,",
535             stats->meanPacketRate);
536     g_string_append_printf(str, "\"exporterName\":\"%s\"", name);
537 
538     g_string_append(str, "}}\n");
539 
540     rc = fwrite(str->str, 1, str->len, lfp);
541 
542     if (rc != str->len) {
543         g_set_error(err, MD_ERROR_DOMAIN, MD_ERROR_IO,
544                 "Error writing %d b ytes to file: %s\n",
545                 (unsigned int)str->len, strerror(errno));
546         return 0;
547     }
548 
549     g_string_free(str, TRUE);
550 
551     return rc;
552 }
553 
mdJsonifyDNSDedupRecord(FILE * fp,mdBuf_t * buf,uint8_t * rec,gboolean print_last,gboolean base64,GError ** err)554 int mdJsonifyDNSDedupRecord(
555     FILE        *fp,
556     mdBuf_t     *buf,
557     uint8_t     *rec,
558     gboolean    print_last,
559     gboolean    base64,
560     GError      **err)
561 {
562     size_t rc = 0;
563     char sabuf[40];
564     md_dns_t *record = (md_dns_t *)rec;
565     uint64_t start_secs = record->flowStartMilliseconds / 1000;
566     uint32_t start_rem = record->flowStartMilliseconds % 1000;
567     uint64_t end_secs = record->flowEndMilliseconds / 1000;
568     uint32_t end_rem = record->flowEndMilliseconds % 1000;
569     gchar *base1 = NULL;
570     size_t brem = MD_REM_MSG(buf);
571     gboolean encode = FALSE;
572     int ret;
573 
574     ret = snprintf(buf->cp, brem, "{\"dns\":{\"flowStartMilliseconds\":\"");
575     MD_CHECK_RET0(buf, ret, brem);
576 
577     if (!md_util_time_buf_append(buf, &brem, start_secs, PRINT_TIME_FMT)) {
578         return 0;
579     }
580 
581     ret = snprintf(buf->cp, brem, ".%03u\",", start_rem);
582 
583     MD_CHECK_RET0(buf, ret, brem);
584 
585     if (print_last) {
586         ret = snprintf(buf->cp, brem, "\"flowEndMilliseconds\":\"");
587         MD_CHECK_RET0(buf, ret, brem);
588 
589         if (!md_util_time_buf_append(buf, &brem, end_secs, PRINT_TIME_FMT)) {
590             return 0;
591         }
592 
593         ret = snprintf(buf->cp, brem, ".%03u\",", end_rem);
594         MD_CHECK_RET0(buf, ret, brem);
595     }
596 
597     ret = snprintf(buf->cp, brem, "\"dnsQRType\":%d,", record->rrtype);
598     MD_CHECK_RET0(buf, ret, brem);
599 
600     if (print_last) {
601         ret = snprintf(buf->cp, brem, "\"dnsHitCount\":%d,\"dnsTTL\":%d,",
602                        record->dnsHitCount, record->dnsTTL);
603         MD_CHECK_RET0(buf, ret, brem);
604     }
605 
606     if (record->rrname.len) {
607 
608         if (base64) {
609             base1 = g_base64_encode((const guchar *)record->rrname.buf,
610                     record->rrname.len-1);
611             ret = snprintf(buf->cp, brem, "\"dnsQName\":\"%s\",", base1);
612             MD_CHECK_RET0(buf, ret, brem);
613             g_free(base1);
614         } else {
615             ret = snprintf(buf->cp, brem, "\"dnsQName\":\"");
616             MD_CHECK_RET0(buf, ret, brem);
617             if (!mdJsonifyEscapeChars(buf, &brem, (uint8_t *)record->rrname.buf,
618                                     record->rrname.len-1)) {
619                 return 0;
620             }
621             if (brem > 2) {
622                 MD_APPEND_CHAR(buf, '\"');
623                 MD_APPEND_CHAR(buf, ',');
624             }
625         }
626     }
627 
628     if (record->rrtype == 1) {
629         if (record->sourceIPv4Address) {
630             md_util_print_ip4_addr(sabuf, record->sourceIPv4Address);
631             ret = snprintf(buf->cp, brem, "\"A\":\"%s\"", sabuf);
632             MD_CHECK_RET0(buf, ret, brem);
633         }
634     } else if (record->rrtype == 2) {
635         ret = snprintf(buf->cp, brem, "\"dnsNSDName\":\"");
636         MD_CHECK_RET(buf, ret, brem);
637         if (base64) {
638             encode = TRUE;
639         }  else {
640             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
641                                  record->rrdata.len);
642             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
643         }
644 
645     } else if (record->rrtype == 5) {
646         ret = snprintf(buf->cp, brem, "\"dnsCName\":\"");
647         MD_CHECK_RET(buf, ret, brem);
648         if (base64) {
649             encode = TRUE;
650         }  else {
651             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
652                                  record->rrdata.len);
653             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
654         }
655     } else if (record->rrtype == 12) {
656         ret = snprintf(buf->cp, brem, "\"dnsPTRDName\":\"");
657         MD_CHECK_RET(buf, ret, brem);
658         if (base64) {
659             encode = TRUE;
660         }  else {
661             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
662                                  record->rrdata.len);
663             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
664         }
665     } else if (record->rrtype == 15) {
666         ret = snprintf(buf->cp, brem, "\"dnsMXExchange\":\"");
667         MD_CHECK_RET(buf, ret, brem);
668         if (base64) {
669             encode = TRUE;
670         }  else {
671             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
672                                  record->rrdata.len);
673             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
674         }
675     } else if (record->rrtype == 28) {
676         md_util_print_ip6_addr(sabuf, record->rrdata.buf);
677         ret = snprintf(buf->cp, brem, "\"AAAA\":\"%s\"", sabuf);
678         MD_CHECK_RET0(buf, ret, brem);
679     } else if (record->rrtype == 16) {
680         ret = snprintf(buf->cp, brem, "\"dnsTXTData\":\"");
681         MD_CHECK_RET(buf, ret, brem);
682         if (base64) {
683             encode = TRUE;
684         }  else {
685             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
686                                  record->rrdata.len);
687             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
688         }
689     } else if (record->rrtype == 33) {
690         ret = snprintf(buf->cp, brem, "\"dnsSRVTarget\":\"");
691         MD_CHECK_RET(buf, ret, brem);
692         if (base64) {
693             encode = TRUE;
694         }  else {
695             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
696                                  record->rrdata.len);
697             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
698         }
699     } else if (record->rrtype == 6) {
700         ret = snprintf(buf->cp, brem, "\"dnsSOAMName\":\"");
701         MD_CHECK_RET(buf, ret, brem);
702         if (base64) {
703             encode = TRUE;
704         }  else {
705             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
706                                  record->rrdata.len);
707             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
708         }
709     } else if (record->rrtype == 46) {
710         ret = snprintf(buf->cp, brem, "\"dnsSigner\":\"");
711         MD_CHECK_RET(buf, ret, brem);
712         if (base64) {
713             encode = TRUE;
714         }  else {
715             mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
716                                  record->rrdata.len);
717             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
718         }
719     } else if (record->rrtype == 47) {
720         ret = snprintf(buf->cp, brem, "\"dnsHashData\":\"");
721         MD_CHECK_RET(buf, ret, brem);
722         mdJsonifyEscapeChars(buf, &brem, record->rrdata.buf,
723                              record->rrdata.len);
724         if (base64) {
725             encode = TRUE;
726         }  else {
727             MD_APPEND_CHAR_CHECK(brem, buf, '\"');
728         }
729     } else {
730         /* if we found no rrData then we need to snip the trailing comma from
731          * the previous field.
732          */
733         buf->cp -= 1;
734         brem += 1;
735     }
736 
737     if (base64 && encode) {
738         base1 = g_base64_encode((const guchar *)record->rrdata.buf,
739                                 record->rrdata.len-1);
740         ret = snprintf(buf->cp, brem, "%s\"", base1);
741         MD_CHECK_RET0(buf, ret, brem);
742         g_free(base1);
743     }
744 
745     if (record->mapname.len) {
746         MD_APPEND_CHAR_CHECK(brem, buf, ',');
747         ret = snprintf(buf->cp, brem, "\"observationDomainName\":\"");
748         MD_CHECK_RET0(buf, ret, brem);
749         if (!md_util_append_varfield(buf, &brem, &(record->mapname))) {
750             return 0;
751         }
752         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
753     }
754 
755     if (brem > 3) {
756         MD_APPEND_CHAR(buf, '}');
757         MD_APPEND_CHAR(buf, '}');
758         MD_APPEND_CHAR(buf, '\n');
759     } else { return 0; }
760 
761     rc = md_util_write_buffer(fp, buf, "", err);
762 
763     if (!rc) {
764         return -1;
765     }
766 
767     return rc;
768 }
769 
mdJsonifySSLDedupRecord(FILE * fp,mdBuf_t * buf,uint8_t * rec,GError ** err)770 int mdJsonifySSLDedupRecord(
771     FILE        *fp,
772     mdBuf_t     *buf,
773     uint8_t     *rec,
774     GError      **err)
775 {
776 
777     size_t rc = 0;
778     size_t brem = MD_REM_MSG(buf);
779     int ret;
780     md_ssl_t *ssl = (md_ssl_t *)rec;
781     uint64_t start_secs = ssl->flowStartMilliseconds / 1000;
782     uint32_t start_rem = ssl->flowStartMilliseconds % 1000;
783     uint64_t end_secs = ssl->flowEndMilliseconds / 1000;
784     uint32_t end_rem = ssl->flowEndMilliseconds % 1000;
785 
786     ret = snprintf(buf->cp, brem, "{\"ssl\":{\"firstSeen\":\"");
787     MD_CHECK_RET0(buf, ret, brem);
788 
789     if (!md_util_time_buf_append(buf, &brem, start_secs, PRINT_TIME_FMT)) {
790         return 0;
791     }
792     ret = snprintf(buf->cp, brem, ".%03u\",\"lastSeen\":\"", start_rem);
793     MD_CHECK_RET0(buf, ret, brem);
794 
795     if (!md_util_time_buf_append(buf, &brem, end_secs, PRINT_TIME_FMT)) {
796         return 0;
797     }
798 
799     ret = snprintf(buf->cp, brem,  ".%03u\",\"sslCertSerialNumber\":\"",
800                    end_rem);
801     MD_CHECK_RET0(buf, ret, brem);
802 
803     ret = md_util_hexdump_append_nospace(buf->cp, &brem,
804                                          ssl->sslCertSerialNumber.buf, ssl->sslCertSerialNumber.len);
805     if (!ret) {
806         return 0;
807     }
808     buf->cp += ret;
809 
810     if (ssl->mapname.len) {
811         ret = snprintf(buf->cp, brem, "\",\"observationDomainName\":\"");
812         MD_CHECK_RET0(buf, ret, brem);
813         if (!md_util_append_varfield(buf, &brem, &(ssl->mapname))) {
814             return 0;
815         }
816     }
817 
818     ret = snprintf(buf->cp, brem, "\",\"observedDataTotalCount\":%"PRIu64
819                    ",\"sslCertIssuerCommonName\":\"", ssl->observedDataTotalCount);
820     MD_CHECK_RET0(buf, ret, brem);
821 
822     if (!md_util_append_varfield(buf, &brem, &(ssl->sslCertIssuerCommonName))) {
823         return 0;
824     }
825 
826     ret = snprintf(buf->cp, brem, "\"}}\n");
827 
828     MD_CHECK_RET0(buf, ret, brem);
829 
830     rc = md_util_write_buffer(fp, buf, "", err);
831 
832     if (!rc) {
833         return -1;
834     }
835 
836     return rc;
837 }
838 
mdJsonifyDedupRecord(FILE * fp,mdBuf_t * buf,char * prefix,md_dedup_t * rec,GError ** err)839 int mdJsonifyDedupRecord(
840     FILE                *fp,
841     mdBuf_t             *buf,
842     char                *prefix,
843     md_dedup_t          *rec,
844     GError              **err)
845 {
846 
847     size_t rc = 0;
848     size_t brem = MD_REM_MSG(buf);
849     uint64_t start_secs = rec->monitoringIntervalStartMilliSeconds / 1000;
850     uint32_t start_rem = rec->monitoringIntervalStartMilliSeconds % 1000;
851     uint64_t end_secs = rec->monitoringIntervalEndMilliSeconds / 1000;
852     uint32_t end_rem = rec->monitoringIntervalEndMilliSeconds % 1000;
853     uint64_t flow_secs = rec->flowStartMilliseconds / 1000;
854     uint32_t flow_rem = rec->flowStartMilliseconds % 1000;
855     char     sabuf[40];
856     int      ret;
857 
858 
859 
860     ret = snprintf(buf->cp, brem, "{\"dedup\":{\"firstSeen\":\"");
861     MD_CHECK_RET0(buf, ret, brem);
862 
863     if (!md_util_time_buf_append(buf, &brem, start_secs, PRINT_TIME_FMT)) {
864         return 0;
865     }
866     ret = snprintf(buf->cp, brem, ".%03u\",\"lastSeen\":\"", start_rem);
867     MD_CHECK_RET0(buf, ret, brem);
868 
869     if (!md_util_time_buf_append(buf, &brem, end_secs, PRINT_TIME_FMT)) {
870         return 0;
871     }
872 
873     if (rec->sourceIPv4Address != rec->yafFlowKeyHash) {
874         if (rec->sourceIPv4Address == 0) {
875             ret = snprintf(buf->cp, brem, ".%03u\",\"sourceIPv6Address\":\"",
876                            end_rem);
877             MD_CHECK_RET0(buf, ret, brem);
878             md_util_print_ip6_addr(sabuf, rec->sourceIPv6Address);
879         } else {
880             ret = snprintf(buf->cp, brem, ".%03u\",\"sourceIPv4Address\":\"",
881                            end_rem);
882             MD_CHECK_RET0(buf, ret, brem);
883             md_util_print_ip4_addr(sabuf, rec->sourceIPv4Address);
884         }
885         ret = snprintf(buf->cp, brem, "%s\",\"yafFlowKeyHash\":%u,"
886                        "\"observedDataTotalCount\":%"PRIu64",",
887                        sabuf, rec->yafFlowKeyHash, rec->observedDataTotalCount);
888     } else {
889         /* deduped on hash, not IP so don't print IP */
890         ret = snprintf(buf->cp, brem, ".%03u\",\"yafFlowKeyHash\":%u,"
891                        "\"observedDataTotalCount\":%"PRIu64",",
892                        end_rem, rec->yafFlowKeyHash, rec->observedDataTotalCount);
893     }
894 
895     MD_CHECK_RET0(buf, ret, brem);
896 
897     /* flow's start time */
898     ret = snprintf(buf->cp, brem, "\"flowStartMilliseconds\":\"");
899     MD_CHECK_RET0(buf, ret, brem);
900 
901     if (!md_util_time_buf_append(buf, &brem, flow_secs, PRINT_TIME_FMT)) {
902         return 0;
903     }
904 
905     ret = snprintf(buf->cp, brem, ".%03u\",", flow_rem);
906     MD_CHECK_RET0(buf, ret, brem);
907 
908 
909     if (rec->mapname.len) {
910         ret = snprintf(buf->cp, brem, "\"observationDomainName\":\"");
911         MD_CHECK_RET0(buf, ret, brem);
912         if (!md_util_append_varfield(buf, &brem, &(rec->mapname))) {
913             return 0;
914         }
915         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
916         MD_APPEND_CHAR_CHECK(brem, buf, ',');
917     }
918 
919 
920     if (rec->observedData.len) {
921         ret = snprintf(buf->cp, brem, "\"%s\":\"", prefix);
922         MD_CHECK_RET0(buf, ret, brem);
923         if (!md_util_append_varfield(buf, &brem, &(rec->observedData))) {
924             return 0;
925         }
926         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
927     } else if (rec->sslCertSerialNumber1.len) {
928         ret = snprintf(buf->cp, brem, "\"sslCertificateChain\":[{\""
929                        "sslCertSerialNumber\":\"");
930         MD_CHECK_RET0(buf, ret, brem);
931         ret = md_util_hexdump_append_nospace(buf->cp, &brem, rec->sslCertSerialNumber1.buf,
932                                              rec->sslCertSerialNumber1.len);
933         if (!ret) {
934             return 0;
935         }
936         buf->cp += ret;
937         ret = snprintf(buf->cp, brem, "\", \"sslCertIssuerCommonName\":\"");
938         MD_CHECK_RET0(buf, ret, brem);
939         if (!md_util_append_varfield(buf, &brem, &(rec->sslCertIssuerCommonName1))) {
940             return 0;
941         }
942         MD_APPEND_CHAR_CHECK(brem, buf, '\"');
943         MD_APPEND_CHAR_CHECK(brem, buf, '}');
944         if (rec->sslCertSerialNumber2.len) {
945             ret = snprintf(buf->cp, brem, ",{\"sslCertSerialNumber\":\"");
946             MD_CHECK_RET0(buf, ret, brem);
947             ret = md_util_hexdump_append_nospace(buf->cp, &brem,
948                                                  rec->sslCertSerialNumber2.buf,
949                                                  rec->sslCertSerialNumber2.len);
950             if (!ret) {
951                 return 0;
952             }
953             buf->cp += ret;
954             ret = snprintf(buf->cp, brem, "\", \"sslCertIssuerCommonName\":\"");
955             MD_CHECK_RET0(buf, ret, brem);
956             if (!md_util_append_varfield(buf, &brem, &(rec->sslCertIssuerCommonName2))) {
957                 return 0;
958             }
959             ret = snprintf(buf->cp, brem, "\"}]");
960             MD_CHECK_RET0(buf, ret, brem);
961         } else {
962             MD_APPEND_CHAR_CHECK(brem, buf, ']');
963         }
964     }
965 
966     ret = snprintf(buf->cp, brem, "}}\n");
967     MD_CHECK_RET0(buf, ret, brem);
968 
969     rc = md_util_write_buffer(fp, buf, "", err);
970 
971     if (!rc) {
972         return -1;
973     }
974 
975     return rc;
976 }
977 
mdJsonifySSLCertBase64(mdBuf_t * buf,fbVarfield_t * cert)978 gboolean mdJsonifySSLCertBase64(
979     mdBuf_t             *buf,
980     fbVarfield_t        *cert)
981 {
982     size_t brem = MD_REM_MSG(buf);
983     gchar *base1 = NULL;
984     int ret;
985 
986     /* remove '},' */
987     buf->cp -= 2;
988     brem += 2;
989 
990     base1 = g_base64_encode((const guchar *)cert->buf,
991                             cert->len);
992 
993     ret = snprintf(buf->cp, brem, ",\"sslCertificate\":\"%s\"},", base1);
994     MD_CHECK_RET0(buf, ret, brem);
995 
996     if (base1) {
997         g_free(base1);
998     }
999 
1000     return TRUE;
1001 }
1002