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