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