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