1 /*
2 * DNS Reply Tool (drool)
3 *
4 * Copyright (c) 2017-2018, OARC, Inc.
5 * Copyright (c) 2017, Comcast Corporation
6 * All rights reserved.
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 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. Neither the name of the copyright holder nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include "config.h"
39
40 #include "conf.h"
41 #include "parseconf/parseconf.h"
42 #include "assert.h"
43
44 #include <stdlib.h>
45 #include <string.h>
46 #include <stdio.h>
47
conf_new(void)48 drool_conf_t* conf_new(void)
49 {
50 drool_conf_t* conf = calloc(1, sizeof(drool_conf_t));
51 return conf;
52 }
53
conf_free(drool_conf_t * conf)54 void conf_free(drool_conf_t* conf)
55 {
56 if (conf) {
57 conf_release(conf);
58 free(conf);
59 }
60 }
61
conf_release(drool_conf_t * conf)62 void conf_release(drool_conf_t* conf)
63 {
64 if (conf) {
65 if (conf->have_filter) {
66 free(conf->filter);
67 conf->filter = 0;
68 }
69 if (conf->have_read) {
70 while (conf->read) {
71 drool_conf_file_t* conf_file = conf->read;
72
73 conf->read = conf_file->next;
74 conf_file_free(conf_file);
75 }
76 conf->have_read = 0;
77 }
78 if (conf->have_input) {
79 while (conf->input) {
80 drool_conf_interface_t* conf_interface = conf->input;
81
82 conf->input = conf_interface->next;
83 conf_interface_free(conf_interface);
84 }
85 conf->have_input = 0;
86 }
87 /*
88 if (conf->have_write) {
89 conf_file_release(&(conf->write));
90 conf->have_write = 0;
91 }
92 if (conf->have_output) {
93 conf_interface_release(&(conf->output));
94 conf->have_output = 0;
95 }
96 */
97 }
98 }
99
conf_have_filter(const drool_conf_t * conf)100 inline int conf_have_filter(const drool_conf_t* conf)
101 {
102 drool_assert(conf);
103 return conf->have_filter;
104 }
105
conf_have_read(const drool_conf_t * conf)106 inline int conf_have_read(const drool_conf_t* conf)
107 {
108 drool_assert(conf);
109 return conf->have_read;
110 }
111
conf_have_input(const drool_conf_t * conf)112 inline int conf_have_input(const drool_conf_t* conf)
113 {
114 drool_assert(conf);
115 return conf->have_input;
116 }
117
conf_have_read_mode(const drool_conf_t * conf)118 inline int conf_have_read_mode(const drool_conf_t* conf)
119 {
120 drool_assert(conf);
121 return conf->have_read_mode;
122 }
123
124 /*
125 inline int conf_have_write(const drool_conf_t* conf) {
126 drool_assert(conf);
127 return conf->have_write;
128 }
129
130 inline int conf_have_output(const drool_conf_t* conf) {
131 drool_assert(conf);
132 return conf->have_output;
133 }
134 */
135
conf_is_dry_run(const drool_conf_t * conf)136 inline int conf_is_dry_run(const drool_conf_t* conf)
137 {
138 drool_assert(conf);
139 return conf->is_dry_run;
140 }
141
conf_filter(const drool_conf_t * conf)142 inline const char* conf_filter(const drool_conf_t* conf)
143 {
144 drool_assert(conf);
145 return conf->filter;
146 }
147
conf_set_filter(drool_conf_t * conf,const char * filter,size_t length)148 int conf_set_filter(drool_conf_t* conf, const char* filter, size_t length)
149 {
150 if (!conf) {
151 return CONF_EINVAL;
152 }
153 if (!filter) {
154 return CONF_EINVAL;
155 }
156
157 if (conf->filter) {
158 free(conf->filter);
159 }
160 if (length) {
161 if (!(conf->filter = strndup(filter, length))) {
162 return CONF_ENOMEM;
163 }
164 conf->filter_length = length;
165 } else {
166 if (!(conf->filter = strdup(filter))) {
167 return CONF_ENOMEM;
168 }
169 conf->filter_length = strlen(conf->filter);
170 }
171 conf->have_filter = 1;
172
173 return CONF_OK;
174 }
175
conf_filter_length(const drool_conf_t * conf)176 inline size_t conf_filter_length(const drool_conf_t* conf)
177 {
178 drool_assert(conf);
179 return conf->filter_length;
180 }
181
conf_read(const drool_conf_t * conf)182 inline const drool_conf_file_t* conf_read(const drool_conf_t* conf)
183 {
184 drool_assert(conf);
185 return conf->read;
186 }
187
conf_input(const drool_conf_t * conf)188 inline const drool_conf_interface_t* conf_input(const drool_conf_t* conf)
189 {
190 drool_assert(conf);
191 return conf->input;
192 }
193
conf_read_mode(const drool_conf_t * conf)194 inline drool_conf_read_mode_t conf_read_mode(const drool_conf_t* conf)
195 {
196 drool_assert(conf);
197 return conf->read_mode;
198 }
199
conf_read_iter(const drool_conf_t * conf)200 inline size_t conf_read_iter(const drool_conf_t* conf)
201 {
202 drool_assert(conf);
203 return conf->read_iter;
204 }
205
206 /*
207 inline const drool_conf_file_t* conf_write(const drool_conf_t* conf) {
208 drool_assert(conf);
209 return &(conf->write);
210 }
211
212 inline const drool_conf_interface_t* conf_output(const drool_conf_t* conf) {
213 drool_assert(conf);
214 return &(conf->output);
215 }
216 */
217
conf_timing_mode(const drool_conf_t * conf)218 inline drool_timing_mode_t conf_timing_mode(const drool_conf_t* conf)
219 {
220 drool_assert(conf);
221 return conf->timing_mode;
222 }
223
conf_timing_increase(const drool_conf_t * conf)224 inline unsigned long int conf_timing_increase(const drool_conf_t* conf)
225 {
226 drool_assert(conf);
227 return conf->timing_increase;
228 }
229
conf_timing_reduce(const drool_conf_t * conf)230 inline unsigned long int conf_timing_reduce(const drool_conf_t* conf)
231 {
232 drool_assert(conf);
233 return conf->timing_reduce;
234 }
235
conf_timing_multiply(const drool_conf_t * conf)236 inline long double conf_timing_multiply(const drool_conf_t* conf)
237 {
238 drool_assert(conf);
239 return conf->timing_multiply;
240 }
241
conf_context_client_pools(const drool_conf_t * conf)242 inline size_t conf_context_client_pools(const drool_conf_t* conf)
243 {
244 drool_assert(conf);
245 return conf->context_client_pools;
246 }
247
conf_add_read(drool_conf_t * conf,const char * file,size_t length)248 int conf_add_read(drool_conf_t* conf, const char* file, size_t length)
249 {
250 drool_conf_file_t* conf_file;
251 int err = CONF_OK;
252
253 if (!conf) {
254 return CONF_EINVAL;
255 }
256 if (!file) {
257 return CONF_EINVAL;
258 }
259
260 if (!(conf_file = conf_file_new())) {
261 return CONF_ENOMEM;
262 }
263 if (err == CONF_OK)
264 err = conf_file_set_name(conf_file, file, length);
265 if (err == CONF_OK && conf->read)
266 err = conf_file_set_next(conf_file, conf->read);
267 if (err == CONF_OK) {
268 conf->read = conf_file;
269 conf->have_read = 1;
270 } else
271 conf_file_free(conf_file);
272
273 return err;
274 }
275
conf_add_input(drool_conf_t * conf,const char * interface,size_t length)276 int conf_add_input(drool_conf_t* conf, const char* interface, size_t length)
277 {
278 drool_conf_interface_t* conf_interface;
279 int err = CONF_OK;
280
281 if (!conf) {
282 return CONF_EINVAL;
283 }
284 if (!interface) {
285 return CONF_EINVAL;
286 }
287
288 if (!(conf_interface = conf_interface_new())) {
289 return CONF_ENOMEM;
290 }
291 if (err == CONF_OK)
292 err = conf_interface_set_name(conf_interface, interface, length);
293 if (err == CONF_OK && conf->input)
294 err = conf_interface_set_next(conf_interface, conf->input);
295 if (err == CONF_OK) {
296 conf->input = conf_interface;
297 conf->have_input = 1;
298 } else
299 conf_interface_free(conf_interface);
300
301 return CONF_OK;
302 }
303
conf_set_read_mode(drool_conf_t * conf,drool_conf_read_mode_t read_mode)304 int conf_set_read_mode(drool_conf_t* conf, drool_conf_read_mode_t read_mode)
305 {
306 if (!conf) {
307 return CONF_EINVAL;
308 }
309
310 conf->read_mode = read_mode;
311 if (read_mode == CONF_READ_MODE_NONE)
312 conf->have_read_mode = 0;
313 else
314 conf->have_read_mode = 1;
315
316 return CONF_OK;
317 }
318
conf_set_read_iter(drool_conf_t * conf,size_t read_iter)319 int conf_set_read_iter(drool_conf_t* conf, size_t read_iter)
320 {
321 if (!conf) {
322 return CONF_EINVAL;
323 }
324
325 conf->read_iter = read_iter;
326
327 return CONF_OK;
328 }
329
330 /*
331 int conf_set_write(drool_conf_t* conf, const char* file, size_t length) {
332 int ret;
333
334 if (!conf) {
335 return CONF_EINVAL;
336 }
337 if (!file) {
338 return CONF_EINVAL;
339 }
340 if (conf->have_write) {
341 return CONF_EEXIST;
342 }
343 if (conf->have_output) {
344 return CONF_EEXIST;
345 }
346
347 if ((ret = conf_file_set_name(&(conf->write), file, length)) == CONF_OK) {
348 conf->have_write = 1;
349 }
350 return ret;
351 }
352
353 int conf_set_output(drool_conf_t* conf, const char* interface, size_t length) {
354 int ret;
355
356 if (!conf) {
357 return CONF_EINVAL;
358 }
359 if (!interface) {
360 return CONF_EINVAL;
361 }
362 if (conf->have_write) {
363 return CONF_EEXIST;
364 }
365 if (conf->have_output) {
366 return CONF_EEXIST;
367 }
368
369 if ((ret = conf_interface_set_name(&(conf->output), interface, length)) == CONF_OK) {
370 conf->have_output = 1;
371 }
372 return ret;
373 }
374 */
375
conf_set_dry_run(drool_conf_t * conf,int dry_run)376 int conf_set_dry_run(drool_conf_t* conf, int dry_run)
377 {
378 if (!conf) {
379 return CONF_EINVAL;
380 }
381
382 conf->is_dry_run = dry_run ? 1 : 0;
383
384 return CONF_OK;
385 }
386
conf_set_context_client_pools(drool_conf_t * conf,size_t context_client_pools)387 int conf_set_context_client_pools(drool_conf_t* conf, size_t context_client_pools)
388 {
389 if (!conf) {
390 return CONF_EINVAL;
391 }
392 if (!context_client_pools) {
393 return CONF_EINVAL;
394 }
395
396 conf->context_client_pools = context_client_pools;
397
398 return CONF_OK;
399 }
400
conf_log(const drool_conf_t * conf)401 inline const drool_log_t* conf_log(const drool_conf_t* conf)
402 {
403 drool_assert(conf);
404 return &(conf->log);
405 }
406
conf_log_rw(drool_conf_t * conf)407 inline drool_log_t* conf_log_rw(drool_conf_t* conf)
408 {
409 drool_assert(conf);
410 return &(conf->log);
411 }
412
conf_client_pool(const drool_conf_t * conf)413 inline const drool_conf_client_pool_t* conf_client_pool(const drool_conf_t* conf)
414 {
415 drool_assert(conf);
416 return &(conf->client_pool);
417 }
418
419 /*
420 * timing conf parsers
421 */
422
423 static parseconf_token_type_t timing_ignore_tokens[] = {
424 PARSECONF_TOKEN_END
425 };
426
parse_timing_ignore(void * user,const parseconf_token_t * tokens,const char ** errstr)427 static int parse_timing_ignore(void* user, const parseconf_token_t* tokens, const char** errstr)
428 {
429 drool_conf_t* conf = (drool_conf_t*)user;
430
431 if (!conf) {
432 return 1;
433 }
434 if (!tokens) {
435 return 1;
436 }
437 if (!errstr) {
438 return 1;
439 }
440
441 conf->timing_mode = TIMING_MODE_IGNORE;
442
443 return 0;
444 }
445
446 static parseconf_token_type_t timing_keep_tokens[] = {
447 PARSECONF_TOKEN_END
448 };
449
parse_timing_keep(void * user,const parseconf_token_t * tokens,const char ** errstr)450 static int parse_timing_keep(void* user, const parseconf_token_t* tokens, const char** errstr)
451 {
452 drool_conf_t* conf = (drool_conf_t*)user;
453
454 if (!conf) {
455 return 1;
456 }
457 if (!tokens) {
458 return 1;
459 }
460 if (!errstr) {
461 return 1;
462 }
463
464 conf->timing_mode = TIMING_MODE_KEEP;
465
466 return 0;
467 }
468
469 static parseconf_token_type_t timing_increase_tokens[] = {
470 PARSECONF_TOKEN_NUMBER, PARSECONF_TOKEN_END
471 };
472
parse_timing_increase(void * user,const parseconf_token_t * tokens,const char ** errstr)473 static int parse_timing_increase(void* user, const parseconf_token_t* tokens, const char** errstr)
474 {
475 drool_conf_t* conf = (drool_conf_t*)user;
476 unsigned long int nanoseconds = 0;
477
478 if (!conf) {
479 return 1;
480 }
481 if (!tokens) {
482 return 1;
483 }
484 if (!errstr) {
485 return 1;
486 }
487
488 if (parseconf_ulongint(&tokens[2], &nanoseconds, errstr)) {
489 return 1;
490 }
491
492 conf->timing_mode = TIMING_MODE_INCREASE;
493 conf->timing_increase = nanoseconds;
494
495 return 0;
496 }
497
498 static parseconf_token_type_t timing_reduce_tokens[] = {
499 PARSECONF_TOKEN_NUMBER, PARSECONF_TOKEN_END
500 };
501
parse_timing_reduce(void * user,const parseconf_token_t * tokens,const char ** errstr)502 static int parse_timing_reduce(void* user, const parseconf_token_t* tokens, const char** errstr)
503 {
504 drool_conf_t* conf = (drool_conf_t*)user;
505 unsigned long int nanoseconds = 0;
506
507 if (!conf) {
508 return 1;
509 }
510 if (!tokens) {
511 return 1;
512 }
513 if (!errstr) {
514 return 1;
515 }
516
517 if (parseconf_ulongint(&tokens[2], &nanoseconds, errstr)) {
518 return 1;
519 }
520
521 conf->timing_mode = TIMING_MODE_REDUCE;
522 conf->timing_reduce = nanoseconds;
523
524 return 0;
525 }
526
527 static parseconf_token_type_t timing_multiply_tokens[] = {
528 PARSECONF_TOKEN_FLOAT, PARSECONF_TOKEN_END
529 };
530
parse_timing_multiply(void * user,const parseconf_token_t * tokens,const char ** errstr)531 static int parse_timing_multiply(void* user, const parseconf_token_t* tokens, const char** errstr)
532 {
533 drool_conf_t* conf = (drool_conf_t*)user;
534 long double multiply = 0;
535
536 if (!conf) {
537 return 1;
538 }
539 if (!tokens) {
540 return 1;
541 }
542 if (!errstr) {
543 return 1;
544 }
545
546 if (parseconf_longdouble(&tokens[2], &multiply, errstr)) {
547 return 1;
548 }
549
550 conf->timing_mode = TIMING_MODE_MULTIPLY;
551 conf->timing_multiply = multiply;
552
553 return 0;
554 }
555
556 static parseconf_token_type_t timing_best_effort_tokens[] = {
557 PARSECONF_TOKEN_END
558 };
559
parse_timing_best_effort(void * user,const parseconf_token_t * tokens,const char ** errstr)560 static int parse_timing_best_effort(void* user, const parseconf_token_t* tokens, const char** errstr)
561 {
562 drool_conf_t* conf = (drool_conf_t*)user;
563
564 if (!conf) {
565 return 1;
566 }
567 if (!tokens) {
568 return 1;
569 }
570 if (!errstr) {
571 return 1;
572 }
573
574 log_print(conf_log(conf), LCORE, LWARNING, "best_effort mode is deprecated, keep will be used");
575
576 conf->timing_mode = TIMING_MODE_BEST_EFFORT;
577
578 return 0;
579 }
580
581 static parseconf_syntax_t timing_syntax[] = {
582 /* timing ignore; */
583 { "ignore", parse_timing_ignore, timing_ignore_tokens, 0 },
584 /* timing keep; */
585 { "keep", parse_timing_keep, timing_keep_tokens, 0 },
586 /* timing increase <nanoseconds>; */
587 { "increase", parse_timing_increase, timing_increase_tokens, 0 },
588 /* timing reduce <nanoseconds>; */
589 { "reduce", parse_timing_reduce, timing_reduce_tokens, 0 },
590 /* timing multiply <multiplication>; */
591 { "multiply", parse_timing_multiply, timing_multiply_tokens, 0 },
592 /* timing best_effort; */
593 { "best_effort", parse_timing_best_effort, timing_best_effort_tokens, 0 },
594 PARSECONF_SYNTAX_END
595 };
596
597 /*
598 * client_pool conf parsers
599 */
600
601 static parseconf_token_type_t client_pool_target_tokens[] = {
602 PARSECONF_TOKEN_QSTRING, PARSECONF_TOKEN_QSTRING, PARSECONF_TOKEN_END
603 };
604
parse_client_pool_target(void * user,const parseconf_token_t * tokens,const char ** errstr)605 static int parse_client_pool_target(void* user, const parseconf_token_t* tokens, const char** errstr)
606 {
607 drool_conf_t* conf = (drool_conf_t*)user;
608
609 if (!conf) {
610 return 1;
611 }
612 if (!tokens) {
613 return 1;
614 }
615 if (!errstr) {
616 return 1;
617 }
618
619 return conf_client_pool_set_target(&(conf->client_pool), tokens[2].token, tokens[2].length, tokens[3].token, tokens[3].length);
620 }
621
622 static parseconf_token_type_t client_pool_max_clients_tokens[] = {
623 PARSECONF_TOKEN_NUMBER, PARSECONF_TOKEN_END
624 };
625
parse_client_pool_max_clients(void * user,const parseconf_token_t * tokens,const char ** errstr)626 static int parse_client_pool_max_clients(void* user, const parseconf_token_t* tokens, const char** errstr)
627 {
628 drool_conf_t* conf = (drool_conf_t*)user;
629 size_t max_clients = 0;
630
631 if (!conf) {
632 return 1;
633 }
634 if (!tokens) {
635 return 1;
636 }
637 if (!errstr) {
638 return 1;
639 }
640
641 if (parseconf_ulongint(&tokens[2], &max_clients, errstr)) {
642 return 1;
643 }
644
645 return conf_client_pool_set_max_clients(&(conf->client_pool), max_clients);
646 }
647
648 static parseconf_token_type_t client_pool_client_ttl_tokens[] = {
649 PARSECONF_TOKEN_FLOAT, PARSECONF_TOKEN_END
650 };
651
parse_client_pool_client_ttl(void * user,const parseconf_token_t * tokens,const char ** errstr)652 static int parse_client_pool_client_ttl(void* user, const parseconf_token_t* tokens, const char** errstr)
653 {
654 drool_conf_t* conf = (drool_conf_t*)user;
655 double client_ttl = 0.;
656
657 if (!conf) {
658 return 1;
659 }
660 if (!tokens) {
661 return 1;
662 }
663 if (!errstr) {
664 return 1;
665 }
666
667 if (parseconf_double(&tokens[2], &client_ttl, errstr)) {
668 return 1;
669 }
670
671 return conf_client_pool_set_client_ttl(&(conf->client_pool), client_ttl);
672 }
673
674 static parseconf_token_type_t client_pool_skip_reply_tokens[] = {
675 PARSECONF_TOKEN_FLOAT, PARSECONF_TOKEN_END
676 };
677
parse_client_pool_skip_reply(void * user,const parseconf_token_t * tokens,const char ** errstr)678 static int parse_client_pool_skip_reply(void* user, const parseconf_token_t* tokens, const char** errstr)
679 {
680 drool_conf_t* conf = (drool_conf_t*)user;
681
682 if (!conf) {
683 return 1;
684 }
685
686 return conf_client_pool_set_skip_reply(&(conf->client_pool));
687 }
688
689 static parseconf_token_type_t client_pool_max_reuse_clients_tokens[] = {
690 PARSECONF_TOKEN_NUMBER, PARSECONF_TOKEN_END
691 };
692
parse_client_pool_max_reuse_clients(void * user,const parseconf_token_t * tokens,const char ** errstr)693 static int parse_client_pool_max_reuse_clients(void* user, const parseconf_token_t* tokens, const char** errstr)
694 {
695 drool_conf_t* conf = (drool_conf_t*)user;
696 size_t max_reuse_clients = 0;
697
698 if (!conf) {
699 return 1;
700 }
701 if (!tokens) {
702 return 1;
703 }
704 if (!errstr) {
705 return 1;
706 }
707
708 if (parseconf_ulongint(&tokens[2], &max_reuse_clients, errstr)) {
709 return 1;
710 }
711
712 return conf_client_pool_set_max_reuse_clients(&(conf->client_pool), max_reuse_clients);
713 }
714
715 static parseconf_token_type_t client_pool_sendas_tokens[] = {
716 PARSECONF_TOKEN_STRING, PARSECONF_TOKEN_END
717 };
718
parse_client_pool_sendas(void * user,const parseconf_token_t * tokens,const char ** errstr)719 static int parse_client_pool_sendas(void* user, const parseconf_token_t* tokens, const char** errstr)
720 {
721 drool_conf_t* conf = (drool_conf_t*)user;
722 drool_client_pool_sendas_t sendas;
723
724 if (!conf) {
725 return 1;
726 }
727 if (!tokens) {
728 return 1;
729 }
730 if (!errstr) {
731 return 1;
732 }
733
734 if (!strncmp(tokens[2].token, "original", tokens[2].length)) {
735 sendas = CLIENT_POOL_SENDAS_ORIGINAL;
736 } else if (!strncmp(tokens[2].token, "udp", tokens[2].length)) {
737 sendas = CLIENT_POOL_SENDAS_UDP;
738 } else if (!strncmp(tokens[2].token, "tcp", tokens[2].length)) {
739 sendas = CLIENT_POOL_SENDAS_TCP;
740 } else {
741 *errstr = "Invalid send as";
742 return 1;
743 }
744
745 return conf_client_pool_set_sendas(&(conf->client_pool), sendas);
746 }
747
748 static parseconf_syntax_t client_pool_syntax[] = {
749 /* client_pool target <host> <port>; */
750 { "target", parse_client_pool_target, client_pool_target_tokens, 0 },
751 /* client_pool max_clients <num>; */
752 { "max_clients", parse_client_pool_max_clients, client_pool_max_clients_tokens, 0 },
753 /* client_pool client_ttl <float>; */
754 { "client_ttl", parse_client_pool_client_ttl, client_pool_client_ttl_tokens, 0 },
755 /* client_pool skip_reply; */
756 { "skip_reply", parse_client_pool_skip_reply, client_pool_skip_reply_tokens, 0 },
757 /* client_pool max_reuse_clients <num>; */
758 { "max_reuse_clients", parse_client_pool_max_reuse_clients, client_pool_max_reuse_clients_tokens, 0 },
759 /* client_pool sendas <what>; */
760 { "sendas", parse_client_pool_sendas, client_pool_sendas_tokens, 0 },
761 PARSECONF_SYNTAX_END
762 };
763
764 /*
765 * context parsers
766 */
767
768 static parseconf_token_type_t context_client_pools_tokens[] = {
769 PARSECONF_TOKEN_NUMBER, PARSECONF_TOKEN_END
770 };
771
parse_context_client_pools(void * user,const parseconf_token_t * tokens,const char ** errstr)772 static int parse_context_client_pools(void* user, const parseconf_token_t* tokens, const char** errstr)
773 {
774 drool_conf_t* conf = (drool_conf_t*)user;
775 size_t client_pools = 0;
776
777 if (!conf) {
778 return 1;
779 }
780 if (!tokens) {
781 return 1;
782 }
783 if (!errstr) {
784 return 1;
785 }
786
787 if (parseconf_ulongint(&tokens[2], &client_pools, errstr)) {
788 return 1;
789 }
790
791 return conf_set_context_client_pools(conf, client_pools);
792 }
793
794 static parseconf_syntax_t context_syntax[] = {
795 /* context client_pools <num>; */
796 { "client_pools", parse_context_client_pools, context_client_pools_tokens, 0 },
797 PARSECONF_SYNTAX_END
798 };
799
800 /*
801 * conf parsers
802 */
803
804 static parseconf_token_type_t log_tokens[] = {
805 PARSECONF_TOKEN_STRINGS, PARSECONF_TOKEN_END
806 };
807
parse_log(void * user,const parseconf_token_t * tokens,const char ** errstr)808 static int parse_log(void* user, const parseconf_token_t* tokens, const char** errstr)
809 {
810 drool_conf_t* conf = (drool_conf_t*)user;
811 drool_log_facility_t facility = LOG_FACILITY_NONE;
812 drool_log_level_t level = LOG_LEVEL_ALL;
813 int all = 0;
814
815 if (!conf) {
816 return 1;
817 }
818 if (!tokens) {
819 return 1;
820 }
821 if (!errstr) {
822 return 1;
823 }
824
825 if (!strncmp(tokens[1].token, "core", tokens[1].length)) {
826 facility = LOG_FACILITY_CORE;
827 } else if (!strncmp(tokens[1].token, "network", tokens[1].length)) {
828 facility = LOG_FACILITY_NETWORK;
829 } else if (!strncmp(tokens[1].token, "all", tokens[1].length)) {
830 all = 1;
831 } else {
832 *errstr = "Invalid log facility";
833 return 1;
834 }
835
836 if (tokens[2].type == PARSECONF_TOKEN_STRING) {
837 if (!strncmp(tokens[2].token, "debug", tokens[2].length)) {
838 level = LOG_LEVEL_DEBUG;
839 } else if (!strncmp(tokens[2].token, "info", tokens[2].length)) {
840 level = LOG_LEVEL_INFO;
841 } else if (!strncmp(tokens[2].token, "notice", tokens[2].length)) {
842 level = LOG_LEVEL_NOTICE;
843 } else if (!strncmp(tokens[2].token, "warning", tokens[2].length)) {
844 level = LOG_LEVEL_WARNING;
845 } else if (!strncmp(tokens[2].token, "error", tokens[2].length)) {
846 level = LOG_LEVEL_ERROR;
847 ;
848 } else if (!strncmp(tokens[2].token, "critical", tokens[2].length)) {
849 level = LOG_LEVEL_CRITICAL;
850 } else {
851 *errstr = "Invalid log level";
852 return 1;
853 }
854 }
855
856 if (all) {
857 if (log_enable(conf_log_rw(conf), LOG_FACILITY_CORE, level)
858 || log_enable(conf_log_rw(conf), LOG_FACILITY_NETWORK, level)) {
859 *errstr = "Unable to enable log facility (and level)";
860 return 1;
861 }
862 } else {
863 if (log_enable(conf_log_rw(conf), facility, level)) {
864 *errstr = "Unable to enable log facility (and level)";
865 return 1;
866 }
867 }
868
869 return 0;
870 }
871
872 static parseconf_token_type_t nolog_tokens[] = {
873 PARSECONF_TOKEN_STRINGS, PARSECONF_TOKEN_END
874 };
875
parse_nolog(void * user,const parseconf_token_t * tokens,const char ** errstr)876 static int parse_nolog(void* user, const parseconf_token_t* tokens, const char** errstr)
877 {
878 drool_conf_t* conf = (drool_conf_t*)user;
879 drool_log_facility_t facility = LOG_FACILITY_NONE;
880 drool_log_level_t level = LOG_LEVEL_ALL;
881 int all = 0;
882
883 if (!conf) {
884 return 1;
885 }
886 if (!tokens) {
887 return 1;
888 }
889 if (!errstr) {
890 return 1;
891 }
892
893 if (!strncmp(tokens[1].token, "core", tokens[1].length)) {
894 facility = LOG_FACILITY_CORE;
895 } else if (!strncmp(tokens[1].token, "network", tokens[1].length)) {
896 facility = LOG_FACILITY_NETWORK;
897 } else if (!strncmp(tokens[1].token, "all", tokens[1].length)) {
898 all = 1;
899 } else {
900 *errstr = "Invalid log facility";
901 return 1;
902 }
903
904 if (tokens[2].type == PARSECONF_TOKEN_STRING) {
905 if (!strncmp(tokens[2].token, "debug", tokens[2].length)) {
906 level = LOG_LEVEL_DEBUG;
907 } else if (!strncmp(tokens[2].token, "info", tokens[2].length)) {
908 level = LOG_LEVEL_INFO;
909 } else if (!strncmp(tokens[2].token, "notice", tokens[2].length)) {
910 level = LOG_LEVEL_NOTICE;
911 } else if (!strncmp(tokens[2].token, "warning", tokens[2].length)) {
912 level = LOG_LEVEL_WARNING;
913 } else if (!strncmp(tokens[2].token, "error", tokens[2].length)) {
914 level = LOG_LEVEL_ERROR;
915 ;
916 } else if (!strncmp(tokens[2].token, "critical", tokens[2].length)) {
917 level = LOG_LEVEL_CRITICAL;
918 } else {
919 *errstr = "Invalid log level";
920 return 1;
921 }
922 }
923
924 if (all) {
925 if (log_disable(conf_log_rw(conf), LOG_FACILITY_CORE, level)
926 || log_disable(conf_log_rw(conf), LOG_FACILITY_NETWORK, level)) {
927 *errstr = "Unable to disable log facility (and level)";
928 return 1;
929 }
930 } else {
931 if (log_disable(conf_log_rw(conf), facility, level)) {
932 *errstr = "Unable to disable log facility (and level)";
933 return 1;
934 }
935 }
936
937 return 0;
938 }
939
940 /*
941 static parseconf_token_type_t read_tokens[] = {
942 PARSECONF_TOKEN_QSTRING, PARSECONF_TOKEN_END
943 };
944
945 static int parse_read(void* user, const parseconf_token_t* tokens, const char** errstr) {
946 drool_conf_t* conf = (drool_conf_t*)user;
947 int err;
948
949 if (!conf) {
950 return 1;
951 }
952 if (!tokens) {
953 return 1;
954 }
955 if (!errstr) {
956 return 1;
957 }
958
959 if ((err = conf_add_read(conf, tokens[1].token, tokens[1].length)) != CONF_OK) {
960 *errstr = conf_strerr(err);
961 return 1;
962 }
963
964 return 0;
965 }
966
967 static parseconf_token_type_t input_tokens[] = {
968 PARSECONF_TOKEN_QSTRING, PARSECONF_TOKEN_END
969 };
970
971 static int parse_input(void* user, const parseconf_token_t* tokens, const char** errstr) {
972 drool_conf_t* conf = (drool_conf_t*)user;
973 int err;
974
975 if (!conf) {
976 return 1;
977 }
978 if (!tokens) {
979 return 1;
980 }
981 if (!errstr) {
982 return 1;
983 }
984
985 if ((err = conf_add_input(conf, tokens[1].token, tokens[1].length)) != CONF_OK) {
986 *errstr = conf_strerr(err);
987 return 1;
988 }
989
990 return 0;
991 }
992 */
993
994 static parseconf_token_type_t filter_tokens[] = {
995 PARSECONF_TOKEN_QSTRING, PARSECONF_TOKEN_END
996 };
997
parse_filter(void * user,const parseconf_token_t * tokens,const char ** errstr)998 static int parse_filter(void* user, const parseconf_token_t* tokens, const char** errstr)
999 {
1000 drool_conf_t* conf = (drool_conf_t*)user;
1001 int err;
1002
1003 if (!conf) {
1004 return 1;
1005 }
1006 if (!tokens) {
1007 return 1;
1008 }
1009 if (!errstr) {
1010 return 1;
1011 }
1012
1013 if ((err = conf_set_filter(conf, tokens[1].token, tokens[1].length)) != CONF_OK) {
1014 *errstr = conf_strerr(err);
1015 return 1;
1016 }
1017 return 0;
1018 }
1019
1020 /*
1021 static parseconf_token_type_t write_tokens[] = {
1022 PARSECONF_TOKEN_QSTRING, PARSECONF_TOKEN_END
1023 };
1024
1025 static int parse_write(void* user, const parseconf_token_t* tokens, const char** errstr) {
1026 drool_conf_t* conf = (drool_conf_t*)user;
1027 int err;
1028
1029 if ((err = conf_set_write(conf, tokens[1].token, tokens[1].length)) != CONF_OK) {
1030 *errstr = conf_strerr(err);
1031 return 1;
1032 }
1033
1034 return 0;
1035 }
1036
1037 static parseconf_token_type_t output_tokens[] = {
1038 PARSECONF_TOKEN_QSTRING, PARSECONF_TOKEN_END
1039 };
1040
1041 static int parse_output(void* user, const parseconf_token_t* tokens, const char** errstr) {
1042 drool_conf_t* conf = (drool_conf_t*)user;
1043 int err;
1044
1045 if ((err = conf_set_output(conf, tokens[1].token, tokens[1].length)) != CONF_OK) {
1046 *errstr = conf_strerr(err);
1047 return 1;
1048 }
1049
1050 return 0;
1051 }
1052 */
1053
1054 static parseconf_token_type_t nested_tokens[] = {
1055 PARSECONF_TOKEN_NESTED
1056 };
1057
1058 static parseconf_syntax_t _syntax2[] = {
1059 /* log <facility> [level] ; */
1060 { "log", parse_log, log_tokens, 0 },
1061 /* nolog <facility> [level] ; */
1062 { "nolog", parse_nolog, nolog_tokens, 0 },
1063 /* read " <file.pcap> " ; */
1064 /*{ "read", parse_read, read_tokens, 0 },*/
1065 /* input " <interface> " ; */
1066 /*{ "input", parse_input, input_tokens, 0 },*/
1067 /* filter " <filter> " ; */
1068 { "filter", parse_filter, filter_tokens, 0 },
1069 /* write " <file.pcap> " ; */
1070 /*{ "write", parse_write, write_tokens, 0 },*/
1071 /* output " <interface> " ; */
1072 /*{ "output", parse_output, output_tokens, 0 },*/
1073 /* timing ... ; */
1074 { "timing", 0, nested_tokens, timing_syntax },
1075 /* client_pool ... ; */
1076 { "client_pool", 0, nested_tokens, client_pool_syntax },
1077 /* context ... ; */
1078 { "context", 0, nested_tokens, context_syntax },
1079 PARSECONF_SYNTAX_END
1080 };
1081
parseconf_error(void * user,parseconf_error_t error,size_t line,size_t token,const parseconf_token_t * tokens,const char * errstr)1082 static void parseconf_error(void* user, parseconf_error_t error, size_t line, size_t token, const parseconf_token_t* tokens, const char* errstr)
1083 {
1084 drool_conf_t* conf = (drool_conf_t*)user;
1085
1086 if (!conf) {
1087 return;
1088 }
1089
1090 switch (error) {
1091 case PARSECONF_ERROR_INTERNAL:
1092 log_printf(conf_log(conf), LCORE, LERROR, "Internal conf error at line %lu", line);
1093 break;
1094
1095 case PARSECONF_ERROR_EXPECT_STRING:
1096 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu for argument %lu, expected a string", line, token);
1097 break;
1098
1099 case PARSECONF_ERROR_EXPECT_NUMBER:
1100 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu for argument %lu, expected a number", line, token);
1101 break;
1102
1103 case PARSECONF_ERROR_EXPECT_QSTRING:
1104 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu for argument %lu, expected a quoted string", line, token);
1105 break;
1106
1107 case PARSECONF_ERROR_EXPECT_FLOAT:
1108 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu for argument %lu, expected a float", line, token);
1109 break;
1110
1111 case PARSECONF_ERROR_EXPECT_ANY:
1112 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu for argument %lu, expected any type", line, token);
1113 break;
1114
1115 case PARSECONF_ERROR_UNKNOWN:
1116 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu for argument %lu, unknown configuration", line, token);
1117 break;
1118
1119 case PARSECONF_ERROR_NO_NESTED:
1120 log_printf(conf_log(conf), LCORE, LERROR, "Internal conf error at line %lu for argument %lu, no nested conf", line, token);
1121 break;
1122
1123 case PARSECONF_ERROR_NO_CALLBACK:
1124 log_printf(conf_log(conf), LCORE, LERROR, "Internal conf error at line %lu for argument %lu, no callback", line, token);
1125 break;
1126
1127 case PARSECONF_ERROR_CALLBACK:
1128 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu, %s", line, errstr);
1129 break;
1130
1131 case PARSECONF_ERROR_FILE_ERRNO:
1132 log_errnof(conf_log(conf), LCORE, LERROR, "Internal conf error at line %lu for argument %lu, errno", line, token);
1133 break;
1134
1135 case PARSECONF_ERROR_TOO_MANY_ARGUMENTS:
1136 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu, too many arguments", line);
1137 break;
1138
1139 case PARSECONF_ERROR_INVALID_SYNTAX:
1140 log_printf(conf_log(conf), LCORE, LERROR, "Conf error at line %lu, invalid syntax", line);
1141 break;
1142
1143 default:
1144 log_printf(conf_log(conf), LCORE, LERROR, "Unknown conf error %d at %lu", error, line);
1145 break;
1146 }
1147 }
1148
conf_parse_file(drool_conf_t * conf,const char * file)1149 int conf_parse_file(drool_conf_t* conf, const char* file)
1150 {
1151 int err;
1152
1153 if (!conf) {
1154 return CONF_EINVAL;
1155 }
1156 if (!file) {
1157 return CONF_EINVAL;
1158 }
1159
1160 log_printf(conf_log(conf), LCORE, LDEBUG, "Opening config file %s", file);
1161 if ((err = parseconf_file((void*)conf, file, _syntax2, parseconf_error)) != PARSECONF_OK) {
1162 log_printf(conf_log(conf), LCORE, LERROR, "Parsing file %s failed: %s", file, parseconf_strerror(err));
1163 return CONF_ERROR;
1164 }
1165
1166 return CONF_OK;
1167 }
1168
conf_parse_text(drool_conf_t * conf,const char * text,size_t length)1169 int conf_parse_text(drool_conf_t* conf, const char* text, size_t length)
1170 {
1171 int err;
1172
1173 if (!conf) {
1174 return CONF_EINVAL;
1175 }
1176 if (!text) {
1177 return CONF_EINVAL;
1178 }
1179 if (!length) {
1180 return CONF_EINVAL;
1181 }
1182
1183 if ((err = parseconf_text((void*)conf, text, length, _syntax2, parseconf_error)) != PARSECONF_OK) {
1184 log_printf(conf_log(conf), LCORE, LERROR, "Parsing text failed: %s", parseconf_strerror(err));
1185 return CONF_ERROR;
1186 }
1187
1188 return CONF_OK;
1189 }
1190
1191 /*
1192 * Error strings
1193 */
1194
conf_strerr(int errnum)1195 const char* conf_strerr(int errnum)
1196 {
1197 switch (errnum) {
1198 case CONF_ERROR:
1199 return CONF_ERROR_STR;
1200 case CONF_EINVAL:
1201 return CONF_EINVAL_STR;
1202 case CONF_ENOMEM:
1203 return CONF_ENOMEM_STR;
1204 case CONF_EEXIST:
1205 return CONF_EEXIST_STR;
1206 default:
1207 break;
1208 }
1209 return "Unknown error";
1210 }
1211