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
49void* 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
75void* 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
95void* 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
123void* 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
151void* 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
173char* 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