1*d7b4a113Ssthen /*
2*d7b4a113Ssthen  * dnstap/dnstap_fstrm.c - Frame Streams protocol for dnstap
3*d7b4a113Ssthen  *
4*d7b4a113Ssthen  * Copyright (c) 2020, NLnet Labs. All rights reserved.
5*d7b4a113Ssthen  *
6*d7b4a113Ssthen  * This software is open source.
7*d7b4a113Ssthen  *
8*d7b4a113Ssthen  * Redistribution and use in source and binary forms, with or without
9*d7b4a113Ssthen  * modification, are permitted provided that the following conditions
10*d7b4a113Ssthen  * are met:
11*d7b4a113Ssthen  *
12*d7b4a113Ssthen  * Redistributions of source code must retain the above copyright notice,
13*d7b4a113Ssthen  * this list of conditions and the following disclaimer.
14*d7b4a113Ssthen  *
15*d7b4a113Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16*d7b4a113Ssthen  * this list of conditions and the following disclaimer in the documentation
17*d7b4a113Ssthen  * and/or other materials provided with the distribution.
18*d7b4a113Ssthen  *
19*d7b4a113Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20*d7b4a113Ssthen  * be used to endorse or promote products derived from this software without
21*d7b4a113Ssthen  * specific prior written permission.
22*d7b4a113Ssthen  *
23*d7b4a113Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*d7b4a113Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*d7b4a113Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26*d7b4a113Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27*d7b4a113Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*d7b4a113Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29*d7b4a113Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30*d7b4a113Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*d7b4a113Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*d7b4a113Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*d7b4a113Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*d7b4a113Ssthen  *
35*d7b4a113Ssthen  */
36*d7b4a113Ssthen 
37*d7b4a113Ssthen /**
38*d7b4a113Ssthen  * \file
39*d7b4a113Ssthen  *
40*d7b4a113Ssthen  * Definitions for the Frame Streams data transport protocol for
41*d7b4a113Ssthen  * dnstap message logs.
42*d7b4a113Ssthen  */
43*d7b4a113Ssthen 
44*d7b4a113Ssthen #include "config.h"
45*d7b4a113Ssthen #include "dnstap/dnstap_fstrm.h"
46*d7b4a113Ssthen #include "sldns/sbuffer.h"
47*d7b4a113Ssthen #include "sldns/wire2str.h"
48*d7b4a113Ssthen 
fstrm_create_control_frame_start(char * contenttype,size_t * len)49*d7b4a113Ssthen void* fstrm_create_control_frame_start(char* contenttype, size_t* len)
50*d7b4a113Ssthen {
51*d7b4a113Ssthen 	uint32_t* control;
52*d7b4a113Ssthen 	size_t n;
53*d7b4a113Ssthen 	/* start framestream message:
54*d7b4a113Ssthen 	 * 4byte 0: control indicator.
55*d7b4a113Ssthen 	 * 4byte bigendian: length of control frame
56*d7b4a113Ssthen 	 * 4byte bigendian: type START
57*d7b4a113Ssthen 	 * 4byte bigendian: option: content-type
58*d7b4a113Ssthen 	 * 4byte bigendian: length of string
59*d7b4a113Ssthen 	 * string of content type (dnstap)
60*d7b4a113Ssthen 	 */
61*d7b4a113Ssthen 	n = 4+4+4+4+4+strlen(contenttype);
62*d7b4a113Ssthen 	control = malloc(n);
63*d7b4a113Ssthen 	if(!control)
64*d7b4a113Ssthen 		return NULL;
65*d7b4a113Ssthen 	control[0] = 0;
66*d7b4a113Ssthen 	control[1] = htonl(4+4+4+strlen(contenttype));
67*d7b4a113Ssthen 	control[2] = htonl(FSTRM_CONTROL_FRAME_START);
68*d7b4a113Ssthen 	control[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE);
69*d7b4a113Ssthen 	control[4] = htonl(strlen(contenttype));
70*d7b4a113Ssthen 	memmove(&control[5], contenttype, strlen(contenttype));
71*d7b4a113Ssthen 	*len = n;
72*d7b4a113Ssthen 	return control;
73*d7b4a113Ssthen }
74*d7b4a113Ssthen 
fstrm_create_control_frame_stop(size_t * len)75*d7b4a113Ssthen void* fstrm_create_control_frame_stop(size_t* len)
76*d7b4a113Ssthen {
77*d7b4a113Ssthen 	uint32_t* control;
78*d7b4a113Ssthen 	size_t n;
79*d7b4a113Ssthen 	/* stop framestream message:
80*d7b4a113Ssthen 	 * 4byte 0: control indicator.
81*d7b4a113Ssthen 	 * 4byte bigendian: length of control frame
82*d7b4a113Ssthen 	 * 4byte bigendian: type STOP
83*d7b4a113Ssthen 	 */
84*d7b4a113Ssthen 	n = 4+4+4;
85*d7b4a113Ssthen 	control = malloc(n);
86*d7b4a113Ssthen 	if(!control)
87*d7b4a113Ssthen 		return NULL;
88*d7b4a113Ssthen 	control[0] = 0;
89*d7b4a113Ssthen 	control[1] = htonl(4);
90*d7b4a113Ssthen 	control[2] = htonl(FSTRM_CONTROL_FRAME_STOP);
91*d7b4a113Ssthen 	*len = n;
92*d7b4a113Ssthen 	return control;
93*d7b4a113Ssthen }
94*d7b4a113Ssthen 
fstrm_create_control_frame_ready(char * contenttype,size_t * len)95*d7b4a113Ssthen void* fstrm_create_control_frame_ready(char* contenttype, size_t* len)
96*d7b4a113Ssthen {
97*d7b4a113Ssthen 	uint32_t* control;
98*d7b4a113Ssthen 	size_t n;
99*d7b4a113Ssthen 	/* start bidirectional stream:
100*d7b4a113Ssthen 	 * 4 bytes 0 escape
101*d7b4a113Ssthen 	 * 4 bytes bigendian length of frame
102*d7b4a113Ssthen 	 * 4 bytes bigendian type READY
103*d7b4a113Ssthen 	 * 4 bytes bigendian frame option content type
104*d7b4a113Ssthen 	 * 4 bytes bigendian length of string
105*d7b4a113Ssthen 	 * string of content type.
106*d7b4a113Ssthen 	 */
107*d7b4a113Ssthen 	/* len includes the escape and framelength */
108*d7b4a113Ssthen 	n = 4+4+4+4+4+strlen(contenttype);
109*d7b4a113Ssthen 	control = malloc(n);
110*d7b4a113Ssthen 	if(!control) {
111*d7b4a113Ssthen 		return NULL;
112*d7b4a113Ssthen 	}
113*d7b4a113Ssthen 	control[0] = 0;
114*d7b4a113Ssthen 	control[1] = htonl(4+4+4+strlen(contenttype));
115*d7b4a113Ssthen 	control[2] = htonl(FSTRM_CONTROL_FRAME_READY);
116*d7b4a113Ssthen 	control[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE);
117*d7b4a113Ssthen 	control[4] = htonl(strlen(contenttype));
118*d7b4a113Ssthen 	memmove(&control[5], contenttype, strlen(contenttype));
119*d7b4a113Ssthen 	*len = n;
120*d7b4a113Ssthen 	return control;
121*d7b4a113Ssthen }
122*d7b4a113Ssthen 
fstrm_create_control_frame_accept(char * contenttype,size_t * len)123*d7b4a113Ssthen void* fstrm_create_control_frame_accept(char* contenttype, size_t* len)
124*d7b4a113Ssthen {
125*d7b4a113Ssthen 	uint32_t* control;
126*d7b4a113Ssthen 	size_t n;
127*d7b4a113Ssthen 	/* control frame on reply:
128*d7b4a113Ssthen 	 * 4 bytes 0 escape
129*d7b4a113Ssthen 	 * 4 bytes bigendian length of frame
130*d7b4a113Ssthen 	 * 4 bytes bigendian type ACCEPT
131*d7b4a113Ssthen 	 * 4 bytes bigendian frame option content type
132*d7b4a113Ssthen 	 * 4 bytes bigendian length of string
133*d7b4a113Ssthen 	 * string of content type.
134*d7b4a113Ssthen 	 */
135*d7b4a113Ssthen 	/* len includes the escape and framelength */
136*d7b4a113Ssthen 	n = 4+4+4+4+4+strlen(contenttype);
137*d7b4a113Ssthen 	control = malloc(n);
138*d7b4a113Ssthen 	if(!control) {
139*d7b4a113Ssthen 		return NULL;
140*d7b4a113Ssthen 	}
141*d7b4a113Ssthen 	control[0] = 0;
142*d7b4a113Ssthen 	control[1] = htonl(4+4+4+strlen(contenttype));
143*d7b4a113Ssthen 	control[2] = htonl(FSTRM_CONTROL_FRAME_ACCEPT);
144*d7b4a113Ssthen 	control[3] = htonl(FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE);
145*d7b4a113Ssthen 	control[4] = htonl(strlen(contenttype));
146*d7b4a113Ssthen 	memmove(&control[5], contenttype, strlen(contenttype));
147*d7b4a113Ssthen 	*len = n;
148*d7b4a113Ssthen 	return control;
149*d7b4a113Ssthen }
150*d7b4a113Ssthen 
fstrm_create_control_frame_finish(size_t * len)151*d7b4a113Ssthen void* fstrm_create_control_frame_finish(size_t* len)
152*d7b4a113Ssthen {
153*d7b4a113Ssthen 	uint32_t* control;
154*d7b4a113Ssthen 	size_t n;
155*d7b4a113Ssthen 	/* control frame on reply:
156*d7b4a113Ssthen 	 * 4 bytes 0 escape
157*d7b4a113Ssthen 	 * 4 bytes bigendian length of frame
158*d7b4a113Ssthen 	 * 4 bytes bigendian type FINISH
159*d7b4a113Ssthen 	 */
160*d7b4a113Ssthen 	/* len includes the escape and framelength */
161*d7b4a113Ssthen 	n = 4+4+4;
162*d7b4a113Ssthen 	control = malloc(n);
163*d7b4a113Ssthen 	if(!control) {
164*d7b4a113Ssthen 		return NULL;
165*d7b4a113Ssthen 	}
166*d7b4a113Ssthen 	control[0] = 0;
167*d7b4a113Ssthen 	control[1] = htonl(4);
168*d7b4a113Ssthen 	control[2] = htonl(FSTRM_CONTROL_FRAME_FINISH);
169*d7b4a113Ssthen 	*len = n;
170*d7b4a113Ssthen 	return control;
171*d7b4a113Ssthen }
172*d7b4a113Ssthen 
fstrm_describe_control(void * pkt,size_t len)173*d7b4a113Ssthen char* fstrm_describe_control(void* pkt, size_t len)
174*d7b4a113Ssthen {
175*d7b4a113Ssthen 	uint32_t frametype = 0;
176*d7b4a113Ssthen 	char buf[512];
177*d7b4a113Ssthen 	char* str = buf;
178*d7b4a113Ssthen 	size_t remain, slen = sizeof(buf);
179*d7b4a113Ssthen 	uint8_t* pos;
180*d7b4a113Ssthen 
181*d7b4a113Ssthen 	buf[0]=0;
182*d7b4a113Ssthen 	if(len < 4) {
183*d7b4a113Ssthen 		snprintf(buf, sizeof(buf), "malformed control frame, "
184*d7b4a113Ssthen 			"too short, len=%u", (unsigned int)len);
185*d7b4a113Ssthen 		return strdup(buf);
186*d7b4a113Ssthen 	}
187*d7b4a113Ssthen 	frametype = sldns_read_uint32(pkt);
188*d7b4a113Ssthen 	if(frametype == FSTRM_CONTROL_FRAME_ACCEPT) {
189*d7b4a113Ssthen 		(void)sldns_str_print(&str, &slen, "accept");
190*d7b4a113Ssthen 	} else if(frametype == FSTRM_CONTROL_FRAME_START) {
191*d7b4a113Ssthen 		(void)sldns_str_print(&str, &slen, "start");
192*d7b4a113Ssthen 	} else if(frametype == FSTRM_CONTROL_FRAME_STOP) {
193*d7b4a113Ssthen 		(void)sldns_str_print(&str, &slen, "stop");
194*d7b4a113Ssthen 	} else if(frametype == FSTRM_CONTROL_FRAME_READY) {
195*d7b4a113Ssthen 		(void)sldns_str_print(&str, &slen, "ready");
196*d7b4a113Ssthen 	} else if(frametype == FSTRM_CONTROL_FRAME_FINISH) {
197*d7b4a113Ssthen 		(void)sldns_str_print(&str, &slen, "finish");
198*d7b4a113Ssthen 	} else {
199*d7b4a113Ssthen 		(void)sldns_str_print(&str, &slen, "type%d", (int)frametype);
200*d7b4a113Ssthen 	}
201*d7b4a113Ssthen 
202*d7b4a113Ssthen 	/* show the content type options */
203*d7b4a113Ssthen 	pos = pkt + 4;
204*d7b4a113Ssthen 	remain = len - 4;
205*d7b4a113Ssthen 	while(remain >= 8) {
206*d7b4a113Ssthen 		uint32_t field_type = sldns_read_uint32(pos);
207*d7b4a113Ssthen 		uint32_t field_len = sldns_read_uint32(pos+4);
208*d7b4a113Ssthen 		if(remain < field_len) {
209*d7b4a113Ssthen 			(void)sldns_str_print(&str, &slen, "malformed_field");
210*d7b4a113Ssthen 			break;
211*d7b4a113Ssthen 		}
212*d7b4a113Ssthen 		if(field_type == FSTRM_CONTROL_FIELD_TYPE_CONTENT_TYPE) {
213*d7b4a113Ssthen 			char tempf[512];
214*d7b4a113Ssthen 			(void)sldns_str_print(&str, &slen, " content-type(");
215*d7b4a113Ssthen 			if(field_len < sizeof(tempf)-1) {
216*d7b4a113Ssthen 				memmove(tempf, pos+8, field_len);
217*d7b4a113Ssthen 				tempf[field_len] = 0;
218*d7b4a113Ssthen 				(void)sldns_str_print(&str, &slen, "%s", tempf);
219*d7b4a113Ssthen 			} else {
220*d7b4a113Ssthen 				(void)sldns_str_print(&str, &slen, "<error-too-long>");
221*d7b4a113Ssthen 			}
222*d7b4a113Ssthen 			(void)sldns_str_print(&str, &slen, ")");
223*d7b4a113Ssthen 		} else {
224*d7b4a113Ssthen 			(void)sldns_str_print(&str, &slen,
225*d7b4a113Ssthen 				" field(type %u, length %u)",
226*d7b4a113Ssthen 				(unsigned int)field_type,
227*d7b4a113Ssthen 				(unsigned int)field_len);
228*d7b4a113Ssthen 		}
229*d7b4a113Ssthen 		pos += 8 + field_len;
230*d7b4a113Ssthen 		remain -= (8 + field_len);
231*d7b4a113Ssthen 	}
232*d7b4a113Ssthen 	if(remain > 0)
233*d7b4a113Ssthen 		(void)sldns_str_print(&str, &slen, " trailing-bytes"
234*d7b4a113Ssthen 			"(length %u)", (unsigned int)remain);
235*d7b4a113Ssthen 	return strdup(buf);
236*d7b4a113Ssthen }
237