1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup streaming Streams
36 * @ingroup dnscore
37 * @brief
38 *
39 *
40 *
41 * @{
42 *
43 *----------------------------------------------------------------------------*/
44 #include "dnscore/dnscore-config.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47
48 #include <arpa/inet.h> /* or netinet/in.h */
49
50 #include "dnscore/input_stream.h"
51 #include "dnscore/rfc.h"
52 #include "dnscore/logger.h"
53
54 #include "dnscore/dnscore.h"
55
56 #define MODULE_MSG_HANDLE g_system_logger
57
58 ya_result
input_stream_read_fully(input_stream * stream,void * buffer_start,u32 len_start)59 input_stream_read_fully(input_stream *stream, void* buffer_start, u32 len_start)
60 {
61 input_stream_read_method* readfunc = stream->vtbl->read;
62 u32 len = len_start;
63 u8* buffer = (u8*)buffer_start;
64 ya_result ret;
65
66 while(len > 0)
67 {
68 if(FAIL(ret = readfunc(stream, buffer, len)))
69 {
70 return ret;
71 }
72
73 if(ret == 0) /* eof */
74 {
75 break;
76 }
77
78 buffer += ret;
79 len -= ret; // cppcheck: false positive
80 }
81
82 /* If we only read a partial it's wrong.
83 * If we were aked to read nothing it's ok.
84 * If we read nothing at all we were on EOF and its still ok
85 */
86
87 if(len > 0)
88 {
89 return UNABLE_TO_COMPLETE_FULL_READ;
90 }
91
92 return (ya_result)(buffer - (u8*)buffer_start);
93 }
94
95 ya_result
input_stream_skip_fully(input_stream * stream,u32 len_start)96 input_stream_skip_fully(input_stream *stream, u32 len_start)
97 {
98 input_stream_skip_method* skipfunc = stream->vtbl->skip;
99 u32 len = len_start;
100 ya_result ret;
101
102 while(len > 0)
103 {
104 if(FAIL(ret = skipfunc(stream, len)))
105 {
106 return ret;
107 }
108
109 if(ret == 0) /* eof */
110 {
111 break;
112 }
113
114 len -= ret; // cppcheck: false positive
115 }
116
117 /* If we only read a partial it's wrong.
118 * If we were aked to read nothing it's ok.
119 * If we read nothing at all we were on EOF and its still ok
120 */
121
122 if(len > 0)
123 {
124 return UNABLE_TO_COMPLETE_FULL_READ;
125 }
126
127 return len_start;
128 }
129
130 ya_result
input_stream_read_nu32(input_stream * stream,u32 * output)131 input_stream_read_nu32(input_stream *stream, u32 *output)
132 {
133 u32 data;
134 ya_result err;
135
136 if(ISOK(err = input_stream_read_fully(stream, &data, 4)))
137 {
138 *output = ntohl(data);
139 }
140
141 return err;
142 }
143
144 ya_result
input_stream_read_nu16(input_stream * stream,u16 * output)145 input_stream_read_nu16(input_stream *stream, u16 *output)
146 {
147 u16 data;
148 ya_result err;
149
150 if(ISOK(err = input_stream_read_fully(stream, &data, 2)))
151 {
152 *output = ntohs(data);
153 }
154
155 return err;
156 }
157
158 ya_result
input_stream_read_u32(input_stream * stream,u32 * output)159 input_stream_read_u32(input_stream *stream, u32 *output)
160 {
161 u32 data;
162 ya_result err;
163
164 if(ISOK(err = input_stream_read_fully(stream, &data, 4)))
165 {
166 *output = data;
167 }
168
169 return err;
170 }
171
172 ya_result
input_stream_read_s32(input_stream * stream,s32 * output)173 input_stream_read_s32(input_stream *stream, s32 *output)
174 {
175 u32 data;
176 ya_result err;
177
178 if(ISOK(err = input_stream_read_fully(stream, &data, 4)))
179 {
180 *output = data;
181 }
182
183 return err;
184 }
185
186 ya_result
input_stream_read_u16(input_stream * stream,u16 * output)187 input_stream_read_u16(input_stream *stream, u16 *output)
188 {
189 u16 data;
190 ya_result err;
191
192 if(ISOK(err = input_stream_read_fully(stream, &data, 2)))
193 {
194 *output = data;
195 }
196
197 return err;
198 }
199
200 union t32
201 {
202 u8 bytes[4];
203 u32 value;
204 };
205
206 ya_result
input_stream_read_pu32(input_stream * is,u32 * output)207 input_stream_read_pu32(input_stream* is, u32 *output)
208 {
209 ya_result ret;
210 u32 value = 0;
211 union t32 buffer;
212 buffer.value = 0;
213 ya_result n = 0;
214 u8 s = 0;
215
216 for(;;)
217 {
218 #if WORDS_BIGENDIAN
219 if(FAIL(ret = input_stream_read(is, &buffer.bytes[3], 1)))
220 {
221 return ret;
222 }
223 #else
224 if(FAIL(ret = input_stream_read(is, &buffer.bytes[0], 1)))
225 {
226 return ret;
227 }
228 #endif
229
230 value |= (buffer.value & 127) << s;
231
232 ++n;
233
234 if(buffer.value < 128)
235 {
236 *output = value;
237 return n;
238 }
239
240 s += 7;
241 }
242 }
243
244 union t64
245 {
246 u8 bytes[8];
247 u64 value;
248 };
249
250 ya_result
input_stream_read_pu64(input_stream * is,u64 * output)251 input_stream_read_pu64(input_stream* is, u64 *output)
252 {
253 ya_result ret;
254 u64 value = 0;
255 union t64 buffer;
256 buffer.value = 0;
257 ya_result n = 0;
258 u8 s = 0;
259
260 for(;;)
261 {
262 #if WORDS_BIGENDIAN
263 if(FAIL(ret = input_stream_read(is, &buffer.bytes[7], 1)))
264 {
265 return ret;
266 }
267 #else
268 if(FAIL(ret = input_stream_read(is, &buffer.bytes[0], 1)))
269 {
270 return ret;
271 }
272 #endif
273
274 value |= (buffer.value & 127) << s;
275
276 ++n;
277
278 if(buffer.value < 128)
279 {
280 *output = value;
281 return n;
282 }
283
284 s += 7;
285 }
286 }
287
288 ya_result
input_stream_read_dnsname(input_stream * stream,u8 * output_buffer)289 input_stream_read_dnsname(input_stream *stream, u8 *output_buffer)
290 {
291 u8 *output = output_buffer;
292 const u8 * const limit = &output_buffer[MAX_DOMAIN_LENGTH - 1]; /* -1 because the limit is computed after the terminator */
293
294 for(;;)
295 {
296 int n;
297
298 if(FAIL(n = input_stream_read_fully(stream, output, 1)))
299 {
300 return (output == output_buffer) ? 0 /* eof*/ : n;
301 }
302
303 if((n = *output++) == 0)
304 {
305 break;
306 }
307
308 if(n > MAX_LABEL_LENGTH)
309 {
310 return LABEL_TOO_LONG;
311 }
312
313 u8* tmp = output;
314
315 output += n;
316
317 if(output >= limit)
318 {
319 return DOMAIN_TOO_LONG;
320 }
321
322 if(FAIL(n = input_stream_read_fully(stream, tmp, n)))
323 {
324 return n;
325 }
326
327 /* 0x012a = 01 '*' = wildcard */
328
329 /*if(GET_U16_AT(tmp[-1]) != NU16(0x012a))*/
330 {
331 if(!dnslabel_locase_verify_charspace(&tmp[-1]))
332 {
333 return INVALID_CHARSET;
334 }
335 }
336 }
337
338 return (ya_result)(output - output_buffer);
339 }
340
341 ya_result
input_stream_read_rname(input_stream * stream,u8 * output_buffer)342 input_stream_read_rname(input_stream *stream, u8 *output_buffer)
343 {
344 u8 *output = output_buffer;
345 const u8 * const limit = &output_buffer[MAX_DOMAIN_LENGTH - 1]; /* -1 because the limit is computed after the terminator */
346
347 for(;;)
348 {
349 int n;
350
351 if(FAIL(n = input_stream_read_fully(stream, output, 1)))
352 {
353 return (output == output_buffer) ? 0 /* eof*/ : n;
354 }
355
356 if((n = *output++) == 0)
357 {
358 break;
359 }
360
361 if(n > MAX_LABEL_LENGTH)
362 {
363 return LABEL_TOO_LONG;
364 }
365
366 u8* tmp = output;
367
368 output += n;
369
370 if(output >= limit)
371 {
372 return DOMAIN_TOO_LONG;
373 }
374
375 if(FAIL(n = input_stream_read_fully(stream, tmp, n)))
376 {
377 return n;
378 }
379 }
380
381 return (ya_result)(output - output_buffer);
382 }
383
384 ya_result
input_stream_read_line(input_stream * stream,char * output_,int max_len)385 input_stream_read_line(input_stream *stream, char *output_, int max_len)
386 {
387 const char * const limit = &output_[max_len];
388 char *output = output_;
389
390 /*
391 * Cache the method
392 */
393
394 input_stream_read_method *read_method = stream->vtbl->read;
395
396 while(output < limit)
397 {
398 ya_result n = read_method(stream, (u8*)output, 1);
399
400 if(n <= 0)
401 {
402 if(n == 0)
403 {
404 n = ((ya_result)(output - output_));
405 }
406
407 return n;
408 }
409
410 if(*output++ == '\n')
411 {
412 return ((ya_result)(output - output_));
413 }
414 }
415
416 return max_len;
417 }
418
input_stream_void_read(input_stream * stream,void * in_buffer,u32 in_len)419 static ya_result input_stream_void_read(input_stream *stream, void* in_buffer,u32 in_len)
420 {
421 (void)stream;
422 (void)in_buffer;
423 (void)in_len;
424
425 log_err("tried to read a closed stream");
426 return INVALID_STATE_ERROR;
427 }
428
input_stream_void_skip(input_stream * stream,u32 byte_count)429 static ya_result input_stream_void_skip(input_stream *stream, u32 byte_count)
430 {
431 (void)stream;
432 (void)byte_count;
433
434 log_err("tried to skip a closed stream");
435 return INVALID_STATE_ERROR;
436 }
437
input_stream_void_close(input_stream * stream)438 static void input_stream_void_close(input_stream *stream)
439 {
440 (void)stream;
441
442 log_err("tried to close a closed stream");
443 #if DEBUG
444 logger_flush();
445 abort();
446 #endif
447 }
448
449 static const input_stream_vtbl void_input_stream_vtbl ={
450 input_stream_void_read,
451 input_stream_void_skip,
452 input_stream_void_close,
453 "void_input_stream",
454 };
455
456 /**
457 * This tools allows a safer misuse (and detection) of closed streams
458 * It sets the stream to a sink that warns abouts its usage and for which every call that can fail fails.
459 */
460
input_stream_set_void(input_stream * is)461 void input_stream_set_void(input_stream* is)
462 {
463 yassert(is != NULL);
464 is->data = NULL;
465 is->vtbl = &void_input_stream_vtbl;
466 }
467
input_stream_sink_read(input_stream * stream,void * in_buffer,u32 in_len)468 static ya_result input_stream_sink_read(input_stream *stream, void* in_buffer,u32 in_len)
469 {
470 (void)stream;
471 (void)in_buffer;
472 (void)in_len;
473 return -1;
474 }
475
input_stream_sink_skip(input_stream * stream,u32 byte_count)476 static ya_result input_stream_sink_skip(input_stream *stream, u32 byte_count)
477 {
478 (void)stream;
479 return byte_count;
480 }
481
input_stream_sink_close(input_stream * stream)482 static void input_stream_sink_close(input_stream *stream)
483 {
484 (void)stream;
485 }
486
487 static const input_stream_vtbl sink_input_stream_vtbl ={
488 input_stream_sink_read,
489 input_stream_sink_skip,
490 input_stream_sink_close,
491 "sink_input_stream",
492 };
493
494 /**
495 * Used to temporarily initialise a stream with a sink that can be closed safely.
496 * Typically used as pre-init so the stream can be closed even if the function
497 * setup failed before reaching stream initialisation.
498 *
499 * @param is
500 */
501
input_stream_set_sink(input_stream * is)502 void input_stream_set_sink(input_stream* is)
503 {
504 yassert(is != NULL);
505 is->data = NULL;
506 is->vtbl = &sink_input_stream_vtbl;
507 }
508
509 /** @} */
510