1 /*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <assert.h>
18 #include <poll.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "libknot/control/control.h"
25 #include "libknot/attribute.h"
26 #include "libknot/error.h"
27 #include "contrib/mempattern.h"
28 #include "contrib/net.h"
29 #include "contrib/sockaddr.h"
30 #include "contrib/string.h"
31 #include "contrib/ucw/mempool.h"
32 #include "contrib/wire_ctx.h"
33 
34 /*! Size of the input and output buffers. */
35 #ifndef CTL_BUFF_SIZE
36 #define CTL_BUFF_SIZE		(256 * 1024)
37 #endif
38 
39 /*! Listen backlog size. */
40 #define LISTEN_BACKLOG		5
41 
42 /*! Default socket operations timeout in milliseconds. */
43 #define DEFAULT_TIMEOUT		(5 * 1000)
44 
45 /*! The first data item code. */
46 #define DATA_CODE_OFFSET	16
47 
48 /*! Control context structure. */
49 struct knot_ctl {
50 	/*! Memory pool context. */
51 	knot_mm_t mm;
52 	/*! Network operations timeout. */
53 	int timeout;
54 	/*! Server listening socket. */
55 	int listen_sock;
56 	/*! Remote server/client socket. */
57 	int sock;
58 
59 	/*! The latter read data. */
60 	knot_ctl_data_t data;
61 
62 	/*! Write wire context. */
63 	wire_ctx_t wire_out;
64 	/*! Read wire context. */
65 	wire_ctx_t wire_in;
66 
67 	/*! Write buffer. */
68 	uint8_t buff_out[CTL_BUFF_SIZE];
69 	/*! Read buffer. */
70 	uint8_t buff_in[CTL_BUFF_SIZE];
71 };
72 
type_to_code(knot_ctl_type_t type)73 static int type_to_code(knot_ctl_type_t type)
74 {
75 	switch (type) {
76 	case KNOT_CTL_TYPE_END:   return  0;
77 	case KNOT_CTL_TYPE_DATA:  return  1;
78 	case KNOT_CTL_TYPE_EXTRA: return  2;
79 	case KNOT_CTL_TYPE_BLOCK: return  3;
80 	default:                  return -1;
81 	}
82 }
83 
code_to_type(uint8_t code)84 static int code_to_type(uint8_t code)
85 {
86 	switch (code) {
87 	case 0:  return KNOT_CTL_TYPE_END;
88 	case 1:  return KNOT_CTL_TYPE_DATA;
89 	case 2:  return KNOT_CTL_TYPE_EXTRA;
90 	case 3:  return KNOT_CTL_TYPE_BLOCK;
91 	default: return -1;
92 	}
93 }
94 
is_data_type(knot_ctl_type_t type)95 static bool is_data_type(knot_ctl_type_t type)
96 {
97 	switch (type) {
98 	case KNOT_CTL_TYPE_DATA:
99 	case KNOT_CTL_TYPE_EXTRA:
100 		return true;
101 	default:
102 		return false;
103 	}
104 }
105 
idx_to_code(knot_ctl_idx_t idx)106 static int idx_to_code(knot_ctl_idx_t idx)
107 {
108 	if (idx >= KNOT_CTL_IDX__COUNT) {
109 		return -1;
110 	}
111 
112 	return DATA_CODE_OFFSET + idx;
113 }
114 
code_to_idx(uint8_t code)115 static int code_to_idx(uint8_t code)
116 {
117 	if (code <  DATA_CODE_OFFSET ||
118 	    code >= DATA_CODE_OFFSET + KNOT_CTL_IDX__COUNT) {
119 		return -1;
120 	}
121 
122 	return code - DATA_CODE_OFFSET;
123 }
124 
reset_buffers(knot_ctl_t * ctx)125 static void reset_buffers(knot_ctl_t *ctx)
126 {
127 	ctx->wire_out = wire_ctx_init(ctx->buff_out, CTL_BUFF_SIZE);
128 	ctx->wire_in = wire_ctx_init(ctx->buff_in, 0);
129 }
130 
clean_data(knot_ctl_t * ctx)131 static void clean_data(knot_ctl_t *ctx)
132 {
133 	mp_flush(ctx->mm.ctx);
134 	memzero(ctx->data, sizeof(ctx->data));
135 }
136 
close_sock(int * sock)137 static void close_sock(int *sock)
138 {
139 	if (*sock < 0) {
140 		return;
141 	}
142 
143 	close(*sock);
144 	*sock = -1;
145 }
146 
147 _public_
knot_ctl_alloc(void)148 knot_ctl_t* knot_ctl_alloc(void)
149 {
150 	knot_ctl_t *ctx = calloc(1, sizeof(*ctx));
151 	if (ctx == NULL) {
152 		return NULL;
153 	}
154 
155 	mm_ctx_mempool(&ctx->mm, MM_DEFAULT_BLKSIZE);
156 	ctx->timeout = DEFAULT_TIMEOUT;
157 	ctx->listen_sock = -1;
158 	ctx->sock = -1;
159 
160 	reset_buffers(ctx);
161 
162 	return ctx;
163 }
164 
165 _public_
knot_ctl_free(knot_ctl_t * ctx)166 void knot_ctl_free(knot_ctl_t *ctx)
167 {
168 	if (ctx == NULL) {
169 		return;
170 	}
171 
172 	close_sock(&ctx->listen_sock);
173 	close_sock(&ctx->sock);
174 
175 	clean_data(ctx);
176 
177 	mp_delete(ctx->mm.ctx);
178 
179 	memzero(ctx, sizeof(*ctx));
180 	free(ctx);
181 }
182 
183 _public_
knot_ctl_set_timeout(knot_ctl_t * ctx,int timeout_ms)184 void knot_ctl_set_timeout(knot_ctl_t *ctx, int timeout_ms)
185 {
186 	if (ctx == NULL) {
187 		return;
188 	}
189 
190 	ctx->timeout = (timeout_ms > 0) ? timeout_ms : -1;
191 }
192 
193 _public_
knot_ctl_bind(knot_ctl_t * ctx,const char * path)194 int knot_ctl_bind(knot_ctl_t *ctx, const char *path)
195 {
196 	if (ctx == NULL || path == NULL) {
197 		return KNOT_EINVAL;
198 	}
199 
200 	// Prepare socket address.
201 	struct sockaddr_storage addr;
202 	int ret = sockaddr_set(&addr, AF_UNIX, path, 0);
203 	if (ret != KNOT_EOK) {
204 		return ret;
205 	}
206 
207 	// Bind the socket.
208 	ctx->listen_sock = net_bound_socket(SOCK_STREAM, &addr, 0);
209 	if (ctx->listen_sock < 0) {
210 		return ctx->listen_sock;
211 	}
212 
213 	// Start listening.
214 	if (listen(ctx->listen_sock, LISTEN_BACKLOG) != 0) {
215 		close_sock(&ctx->listen_sock);
216 		return knot_map_errno();
217 	}
218 
219 	return KNOT_EOK;
220 }
221 
222 _public_
knot_ctl_unbind(knot_ctl_t * ctx)223 void knot_ctl_unbind(knot_ctl_t *ctx)
224 {
225 	if (ctx == NULL || ctx->listen_sock < 0) {
226 		return;
227 	}
228 
229 	// Remove the control socket file.
230 	struct sockaddr_storage addr;
231 	socklen_t addr_len = sizeof(addr);
232 	if (getsockname(ctx->listen_sock, (struct sockaddr *)&addr, &addr_len) == 0) {
233 		char addr_str[SOCKADDR_STRLEN] = { 0 };
234 		if (sockaddr_tostr(addr_str, sizeof(addr_str), &addr) > 0) {
235 			(void)unlink(addr_str);
236 		}
237 	}
238 
239 	// Close the listening socket.
240 	close_sock(&ctx->listen_sock);
241 }
242 
243 _public_
knot_ctl_accept(knot_ctl_t * ctx)244 int knot_ctl_accept(knot_ctl_t *ctx)
245 {
246 	if (ctx == NULL) {
247 		return KNOT_EINVAL;
248 	}
249 
250 	knot_ctl_close(ctx);
251 
252 	// Control interface.
253 	struct pollfd pfd = { .fd = ctx->listen_sock, .events = POLLIN };
254 	int ret = poll(&pfd, 1, -1);
255 	if (ret <= 0) {
256 		return knot_map_errno();
257 	}
258 
259 	int client = net_accept(ctx->listen_sock, NULL);
260 	if (client < 0) {
261 		return client;
262 	}
263 
264 	ctx->sock = client;
265 
266 	reset_buffers(ctx);
267 
268 	return KNOT_EOK;
269 }
270 
271 _public_
knot_ctl_connect(knot_ctl_t * ctx,const char * path)272 int knot_ctl_connect(knot_ctl_t *ctx, const char *path)
273 {
274 	if (ctx == NULL || path == NULL) {
275 		return KNOT_EINVAL;
276 	}
277 
278 	// Prepare socket address.
279 	struct sockaddr_storage addr;
280 	int ret = sockaddr_set(&addr, AF_UNIX, path, 0);
281 	if (ret != KNOT_EOK) {
282 		return ret;
283 	}
284 
285 	// Connect to socket.
286 	ctx->sock = net_connected_socket(SOCK_STREAM, &addr, NULL, false);
287 	if (ctx->sock < 0) {
288 		return ctx->sock;
289 	}
290 
291 	reset_buffers(ctx);
292 
293 	return KNOT_EOK;
294 }
295 
296 _public_
knot_ctl_close(knot_ctl_t * ctx)297 void knot_ctl_close(knot_ctl_t *ctx)
298 {
299 	if (ctx == NULL) {
300 		return;
301 	}
302 
303 	close_sock(&ctx->sock);
304 }
305 
ensure_output(knot_ctl_t * ctx,uint16_t len)306 static int ensure_output(knot_ctl_t *ctx, uint16_t len)
307 {
308 	wire_ctx_t *w = &ctx->wire_out;
309 
310 	// Check for enough available room in the output buffer.
311 	size_t available = wire_ctx_available(w);
312 	if (available >= len) {
313 		return KNOT_EOK;
314 	}
315 
316 	// Flush the buffer.
317 	int ret = net_stream_send(ctx->sock, w->wire, wire_ctx_offset(w),
318 	                          ctx->timeout);
319 	if (ret < 0) {
320 		return ret;
321 	}
322 
323 	*w = wire_ctx_init(w->wire, CTL_BUFF_SIZE);
324 
325 	return KNOT_EOK;
326 }
327 
send_item(knot_ctl_t * ctx,uint8_t code,const char * data,bool flush)328 static int send_item(knot_ctl_t *ctx, uint8_t code, const char *data, bool flush)
329 {
330 	wire_ctx_t *w = &ctx->wire_out;
331 
332 	// Write the control block code.
333 	int ret = ensure_output(ctx, sizeof(uint8_t));
334 	if (ret != KNOT_EOK) {
335 		return ret;
336 	}
337 	wire_ctx_write_u8(w, code);
338 	if (w->error != KNOT_EOK) {
339 		return w->error;
340 	}
341 
342 	// Control block data is optional.
343 	if (data != NULL) {
344 		// Get the data length.
345 		size_t data_len = strlen(data);
346 		if (data_len > UINT16_MAX) {
347 			return KNOT_ERANGE;
348 		}
349 
350 		// Write the data length.
351 		ret = ensure_output(ctx, sizeof(uint16_t));
352 		if (ret != KNOT_EOK) {
353 			return ret;
354 		}
355 		wire_ctx_write_u16(w, data_len);
356 		if (w->error != KNOT_EOK) {
357 			return w->error;
358 		}
359 
360 		// Write the data.
361 		ret = ensure_output(ctx, data_len);
362 		if (ret != KNOT_EOK) {
363 			return ret;
364 		}
365 		wire_ctx_write(w, (uint8_t *)data, data_len);
366 		if (w->error != KNOT_EOK) {
367 			return w->error;
368 		}
369 	}
370 
371 	// Send finalized buffer.
372 	if (flush && wire_ctx_offset(w) > 0) {
373 		ret = net_stream_send(ctx->sock, w->wire, wire_ctx_offset(w),
374 		                      ctx->timeout);
375 		if (ret < 0) {
376 			return ret;
377 		}
378 
379 		*w = wire_ctx_init(w->wire, CTL_BUFF_SIZE);
380 	}
381 
382 	return KNOT_EOK;
383 }
384 
385 _public_
knot_ctl_send(knot_ctl_t * ctx,knot_ctl_type_t type,knot_ctl_data_t * data)386 int knot_ctl_send(knot_ctl_t *ctx, knot_ctl_type_t type, knot_ctl_data_t *data)
387 {
388 	if (ctx == NULL) {
389 		return KNOT_EINVAL;
390 	}
391 
392 	// Get the type code.
393 	int code = type_to_code(type);
394 	if (code == -1) {
395 		return KNOT_EINVAL;
396 	}
397 
398 	// Send unit type.
399 	int ret = send_item(ctx, code, NULL, !is_data_type(type));
400 	if (ret != KNOT_EOK) {
401 		return ret;
402 	}
403 
404 	// Send unit data.
405 	if (is_data_type(type) && data != NULL) {
406 		// Send all non-empty data items.
407 		for (knot_ctl_idx_t i = 0; i < KNOT_CTL_IDX__COUNT; i++) {
408 			const char *value = (*data)[i];
409 			if (value == NULL) {
410 				continue;
411 			}
412 
413 			ret = send_item(ctx, idx_to_code(i), value, false);
414 			if (ret != KNOT_EOK) {
415 				return ret;
416 			}
417 		}
418 	}
419 
420 	return KNOT_EOK;
421 }
422 
ensure_input(knot_ctl_t * ctx,uint16_t len)423 static int ensure_input(knot_ctl_t *ctx, uint16_t len)
424 {
425 	wire_ctx_t *w = &ctx->wire_in;
426 
427 	// Check for enough available room in the input buffer.
428 	size_t available = wire_ctx_available(w);
429 	if (available >= len) {
430 		return KNOT_EOK;
431 	}
432 
433 	// Move unprocessed data to the beginning of the buffer.
434 	memmove(w->wire, w->wire + wire_ctx_offset(w), available);
435 
436 	// Receive enough data.
437 	while (available < len) {
438 		int ret = net_stream_recv(ctx->sock, w->wire + available,
439 		                          CTL_BUFF_SIZE - available,
440 		                          ctx->timeout);
441 		if (ret < 0) {
442 			return ret;
443 		}
444 		assert(ret > 0);
445 		available += ret;
446 	}
447 
448 	ctx->wire_in = wire_ctx_init(w->wire, available);
449 
450 	return KNOT_EOK;
451 }
452 
receive_item_code(knot_ctl_t * ctx,uint8_t * code)453 static int receive_item_code(knot_ctl_t *ctx, uint8_t *code)
454 {
455 	wire_ctx_t *w = &ctx->wire_in;
456 
457 	// Read the type.
458 	int ret = ensure_input(ctx, sizeof(uint8_t));
459 	if (ret != KNOT_EOK) {
460 		return ret;
461 	}
462 	*code = wire_ctx_read_u8(w);
463 	if (w->error != KNOT_EOK) {
464 		return w->error;
465 	}
466 
467 	return KNOT_EOK;
468 }
469 
receive_item_value(knot_ctl_t * ctx,char ** value)470 static int receive_item_value(knot_ctl_t *ctx, char **value)
471 {
472 	wire_ctx_t *w = &ctx->wire_in;
473 
474 	// Read value length.
475 	int ret = ensure_input(ctx, sizeof(uint16_t));
476 	if (ret != KNOT_EOK) {
477 		return ret;
478 	}
479 	uint16_t data_len = wire_ctx_read_u16(w);
480 	if (w->error != KNOT_EOK) {
481 		return w->error;
482 	}
483 
484 	// Read the value.
485 	ret = ensure_input(ctx, data_len);
486 	if (ret != KNOT_EOK) {
487 		return ret;
488 	}
489 	*value = mm_alloc(&ctx->mm, data_len + 1);
490 	if (*value == NULL) {
491 		return KNOT_ENOMEM;
492 	}
493 	wire_ctx_read(w, *value, data_len);
494 	if (w->error != KNOT_EOK) {
495 		return w->error;
496 	}
497 	(*value)[data_len] = '\0';
498 
499 	return KNOT_EOK;
500 }
501 
502 _public_
knot_ctl_receive(knot_ctl_t * ctx,knot_ctl_type_t * type,knot_ctl_data_t * data)503 int knot_ctl_receive(knot_ctl_t *ctx, knot_ctl_type_t *type, knot_ctl_data_t *data)
504 {
505 	if (ctx == NULL || type == NULL) {
506 		return KNOT_EINVAL;
507 	}
508 
509 	wire_ctx_t *w = &ctx->wire_in;
510 
511 	// Reset output variables.
512 	*type = KNOT_CTL_TYPE_END;
513 	clean_data(ctx);
514 
515 	// Read data units until end of message.
516 	bool have_type = false;
517 	while (true) {
518 		uint8_t code;
519 		int ret = receive_item_code(ctx, &code);
520 		if (ret != KNOT_EOK) {
521 			return ret;
522 		}
523 
524 		// Process unit type.
525 		int current_type = code_to_type(code);
526 		if (current_type != -1) {
527 			if (have_type) {
528 				// Revert parsed type.
529 				wire_ctx_skip(w, -sizeof(uint8_t));
530 				assert(w->error == KNOT_EOK);
531 				break;
532 			}
533 
534 			// Set the unit type.
535 			*type = current_type;
536 
537 			if (is_data_type(current_type)) {
538 				have_type = true;
539 				continue;
540 			} else {
541 				break;
542 			}
543 		}
544 
545 		// Check for data item code.
546 		int idx = code_to_idx(code);
547 		if (idx == -1) {
548 			return KNOT_EINVAL;
549 		}
550 
551 		// Store the item data value.
552 		ret = receive_item_value(ctx, (char **)&ctx->data[idx]);
553 		if (ret != KNOT_EOK) {
554 			return ret;
555 		}
556 	}
557 
558 	// Set the output data.
559 	if (data != NULL) {
560 		memcpy(*data, ctx->data, sizeof(*data));
561 	}
562 
563 	return KNOT_EOK;
564 }
565