1 /*-
2 * SSLproxy
3 *
4 * Copyright (c) 2017-2021, Soner Tari <sonertari@gmail.com>.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "opts.h"
29 #include "filter.h"
30
31 #include "sys.h"
32 #include "log.h"
33 #include "util.h"
34
35 ACM_DEFINE (char);
36
37 #define free_list(list, type) do { \
38 while (list) { \
39 type *next = (list)->next; \
40 free(list); \
41 list = next; \
42 } \
43 } while (0)
44
45 #define append_list(list, value, type) do { \
46 type *l = *list; \
47 while (l) { \
48 if (!l->next) \
49 break; \
50 l = l->next; \
51 } \
52 if (l) \
53 l->next = value; \
54 else \
55 *list = value; \
56 } while (0)
57
58 #define match_acm(acm, haystack, value) do { \
59 const ACState(char) *state = ACM_reset(acm); \
60 for (char *c = haystack; *c; c++) { \
61 if (ACM_match(state, *c)) { \
62 ACM_get_match(state, 0, 0, (void **)&value); \
63 break; \
64 } \
65 } \
66 } while (0)
67
68 #ifndef WITHOUT_USERAUTH
69 void
filter_userlist_free(userlist_t * ul)70 filter_userlist_free(userlist_t *ul)
71 {
72 while (ul) {
73 userlist_t *next = ul->next;
74 free(ul->user);
75 free(ul);
76 ul = next;
77 }
78 }
79
80 int
filter_userlist_copy(userlist_t * userlist,const char * argv0,userlist_t ** ul)81 filter_userlist_copy(userlist_t *userlist, const char *argv0, userlist_t **ul)
82 {
83 while (userlist) {
84 userlist_t *du = malloc(sizeof(userlist_t));
85 if (!du)
86 return oom_return(argv0);
87 memset(du, 0, sizeof(userlist_t));
88
89 du->user = strdup(userlist->user);
90 if (!du->user)
91 return oom_return(argv0);
92
93 append_list(ul, du, userlist_t);
94
95 userlist = userlist->next;
96 }
97 return 0;
98 }
99
100 char *
filter_userlist_str(userlist_t * u)101 filter_userlist_str(userlist_t *u)
102 {
103 char *us = NULL;
104
105 if (!u) {
106 us = strdup("");
107 if (!us)
108 return oom_return_na_null();
109 goto out;
110 }
111
112 while (u) {
113 char *nus;
114 if (asprintf(&nus, "%s%s%s", STRORNONE(us), us ? "," : "", u->user) < 0) {
115 goto err;
116 }
117
118 if (us)
119 free(us);
120 us = nus;
121 u = u->next;
122 }
123 goto out;
124 err:
125 if (us) {
126 free(us);
127 us = NULL;
128 }
129 out:
130 return us;
131 }
132
133 // Limit the number of users to max 50
134 #define MAX_USERS 50
135
136 int
filter_userlist_set(char * value,unsigned int line_num,userlist_t ** list,const char * listname)137 filter_userlist_set(char *value, unsigned int line_num, userlist_t **list, const char *listname)
138 {
139 // Delimiter can be either or all of ",", " ", and "\t"
140 // Using space as a delimiter disables spaces in user names too
141 // user1[,user2[,user3]]
142 char *argv[sizeof(char *) * MAX_USERS];
143 int argc = 0;
144 char *p, *last = NULL;
145
146 // strtok_r() removes all delimiters around user names, and does not return empty tokens
147 for ((p = strtok_r(value, ", \t", &last));
148 p;
149 (p = strtok_r(NULL, ", \t", &last))) {
150 if (argc < MAX_USERS) {
151 argv[argc++] = p;
152 } else {
153 fprintf(stderr, "Too many arguments in user list, max users allowed %d, on line %d\n", MAX_USERS, line_num);
154 return -1;
155 }
156 }
157
158 if (!argc) {
159 fprintf(stderr, "%s requires at least one parameter on line %d\n", listname, line_num);
160 return -1;
161 }
162
163 // Override the copied global list, if any
164 if (*list) {
165 filter_userlist_free(*list);
166 *list = NULL;
167 }
168
169 while (argc--) {
170 userlist_t *ul = malloc(sizeof(userlist_t));
171 if (!ul)
172 return oom_return_na();
173 memset(ul, 0, sizeof(userlist_t));
174
175 ul->user = strdup(argv[argc]);
176 if (!ul->user)
177 return oom_return_na();
178
179 append_list(list, ul, userlist_t);
180 }
181 return 0;
182 }
183 #endif /* !WITHOUT_USERAUTH */
184
185 static void
filter_value_free(value_t * value)186 filter_value_free(value_t *value)
187 {
188 while (value) {
189 value_t *next = value->next;
190 free(value->value);
191 free(value);
192 value = next;
193 }
194 }
195
196 void
filter_macro_free(opts_t * opts)197 filter_macro_free(opts_t *opts)
198 {
199 macro_t *macro = opts->macro;
200 while (macro) {
201 macro_t *next = macro->next;
202 free(macro->name);
203 filter_value_free(macro->value);
204 free(macro);
205 macro = next;
206 }
207 opts->macro = NULL;
208 }
209
210 static void
filter_rule_free(filter_rule_t * rule)211 filter_rule_free(filter_rule_t *rule)
212 {
213 if (rule->dstip)
214 free(rule->dstip);
215 if (rule->sni)
216 free(rule->sni);
217 if (rule->cn)
218 free(rule->cn);
219 if (rule->host)
220 free(rule->host);
221 if (rule->uri)
222 free(rule->uri);
223 if (rule->port)
224 free(rule->port);
225 if (rule->ip)
226 free(rule->ip);
227 #ifndef WITHOUT_USERAUTH
228 if (rule->user)
229 free(rule->user);
230 if (rule->desc)
231 free(rule->desc);
232 #endif /* !WITHOUT_USERAUTH */
233 if (rule->action.conn_opts)
234 conn_opts_free(rule->action.conn_opts);
235 free(rule);
236 }
237
238 void
filter_rules_free(opts_t * opts)239 filter_rules_free(opts_t *opts)
240 {
241 filter_rule_t *rule = opts->filter_rules;
242 while (rule) {
243 filter_rule_t *next = rule->next;
244 filter_rule_free(rule);
245 rule = next;
246 }
247 opts->filter_rules = NULL;
248 }
249
250 #define free_port(p) do { \
251 if ((*p)->action.conn_opts) \
252 conn_opts_free((*p)->action.conn_opts); \
253 free((*p)->port); \
254 free(*p); \
255 } while (0)
256
257 static void
free_port_func(void * p)258 free_port_func(void *p)
259 {
260 free_port((filter_port_t **)&p);
261 }
262
263 static void
filter_port_btree_free(kbtree_t (port)* btree)264 filter_port_btree_free(kbtree_t(port) *btree)
265 {
266 if (btree) {
267 __kb_traverse(filter_port_p_t, btree, free_port);
268 __kb_destroy(btree);
269 }
270 }
271
272 #define free_site(p) do { \
273 if ((*p)->action.conn_opts) \
274 conn_opts_free((*p)->action.conn_opts); \
275 free((*p)->site); \
276 filter_port_btree_free((*p)->port_btree); \
277 if ((*p)->port_acm) \
278 ACM_release((*p)->port_acm); \
279 if ((*p)->port_all) \
280 free_port_func((*p)->port_all); \
281 free(*p); \
282 } while (0)
283
284 static void
free_site_func(void * s)285 free_site_func(void *s)
286 {
287 free_site((filter_site_t **)&s);
288 }
289
290 static void
filter_list_free(filter_list_t * list)291 filter_list_free(filter_list_t *list)
292 {
293 if (list->ip_btree) {
294 __kb_traverse(filter_site_p_t, list->ip_btree, free_site);
295 __kb_destroy(list->ip_btree);
296 }
297 if (list->ip_acm)
298 ACM_release(list->ip_acm);
299 if (list->ip_all)
300 free_site_func(list->ip_all);
301
302 if (list->sni_btree) {
303 __kb_traverse(filter_site_p_t, list->sni_btree, free_site);
304 __kb_destroy(list->sni_btree);
305 }
306 if (list->sni_acm)
307 ACM_release(list->sni_acm);
308 if (list->sni_all)
309 free_site_func(list->sni_all);
310
311 if (list->cn_btree) {
312 __kb_traverse(filter_site_p_t, list->cn_btree, free_site);
313 __kb_destroy(list->cn_btree);
314 }
315 if (list->cn_acm)
316 ACM_release(list->cn_acm);
317 if (list->cn_all)
318 free_site_func(list->cn_all);
319
320 if (list->host_btree) {
321 __kb_traverse(filter_site_p_t, list->host_btree, free_site);
322 __kb_destroy(list->host_btree);
323 }
324 if (list->host_acm)
325 ACM_release(list->host_acm);
326 if (list->host_all)
327 free_site_func(list->host_all);
328
329 if (list->uri_btree) {
330 __kb_traverse(filter_site_p_t, list->uri_btree, free_site);
331 __kb_destroy(list->uri_btree);
332 }
333 if (list->uri_acm)
334 ACM_release(list->uri_acm);
335 if (list->uri_all)
336 free_site_func(list->uri_all);
337
338 free(list);
339 }
340
341 #ifndef WITHOUT_USERAUTH
342 #define free_desc(p) do { \
343 free((*p)->desc); \
344 filter_list_free((*p)->list); \
345 free(*p); \
346 } while (0)
347
348 static void
filter_user_free(filter_user_t * user)349 filter_user_free(filter_user_t *user)
350 {
351 free(user->user);
352 filter_list_free(user->list);
353
354 if (user->desc_btree) {
355 __kb_traverse(filter_desc_p_t, user->desc_btree, free_desc);
356 __kb_destroy(user->desc_btree);
357 }
358
359 if (user->desc_acm)
360 ACM_release(user->desc_acm);
361 }
362
363 #define free_user(p) do { \
364 filter_user_free(*p); \
365 free(*p); \
366 } while (0)
367 #endif /* !WITHOUT_USERAUTH */
368
369 #define free_ip(p) do { \
370 free((*p)->ip); \
371 filter_list_free((*p)->list); \
372 free(*p); \
373 } while (0)
374
375 void
filter_free(opts_t * opts)376 filter_free(opts_t *opts)
377 {
378 if (!opts->filter)
379 return;
380
381 filter_t *pf = opts->filter;
382 #ifndef WITHOUT_USERAUTH
383 if (pf->user_btree) {
384 __kb_traverse(filter_user_p_t, pf->user_btree, free_user);
385 __kb_destroy(pf->user_btree);
386 }
387
388 if (pf->user_acm)
389 ACM_release(pf->user_acm);
390
391 if (pf->desc_btree) {
392 __kb_traverse(filter_desc_p_t, pf->desc_btree, free_desc);
393 __kb_destroy(pf->desc_btree);
394 }
395
396 if (pf->desc_acm)
397 ACM_release(pf->desc_acm);
398
399 filter_list_free(pf->all_user);
400 #endif /* !WITHOUT_USERAUTH */
401
402 if (pf->ip_btree) {
403 __kb_traverse(filter_ip_p_t, pf->ip_btree, free_ip);
404 __kb_destroy(pf->ip_btree);
405 }
406
407 if (pf->ip_acm)
408 ACM_release(pf->ip_acm);
409
410 filter_list_free(pf->all);
411
412 free(opts->filter);
413 opts->filter = NULL;
414 }
415
416 int
filter_macro_copy(macro_t * macro,const char * argv0,opts_t * opts)417 filter_macro_copy(macro_t *macro, const char *argv0, opts_t *opts)
418 {
419 while (macro) {
420 macro_t *m = malloc(sizeof(macro_t));
421 if (!m)
422 return oom_return(argv0);
423 memset(m, 0, sizeof(macro_t));
424
425 m->name = strdup(macro->name);
426 if (!m->name)
427 return oom_return(argv0);
428
429 value_t *value = macro->value;
430 while (value) {
431 value_t *v = malloc(sizeof(value_t));
432 if (!v)
433 return oom_return(argv0);
434 memset(v, 0, sizeof(value_t));
435
436 v->value = strdup(value->value);
437 if (!v->value)
438 return oom_return(argv0);
439
440 append_list(&m->value, v, value_t);
441 value = value->next;
442 }
443
444 append_list(&opts->macro, m, macro_t);
445 macro = macro->next;
446 }
447 return 0;
448 }
449
450 int
filter_rule_copy(filter_rule_t * rule,const char * argv0,opts_t * opts,tmp_opts_t * tmp_opts)451 filter_rule_copy(filter_rule_t *rule, const char *argv0, opts_t *opts, tmp_opts_t *tmp_opts)
452 {
453 while (rule) {
454 filter_rule_t *r = malloc(sizeof(filter_rule_t));
455 if (!r)
456 return oom_return(argv0);
457 memset(r, 0, sizeof(filter_rule_t));
458
459 r->all_conns = rule->all_conns;
460
461 #ifndef WITHOUT_USERAUTH
462 r->all_users = rule->all_users;
463
464 if (rule->user) {
465 r->user = strdup(rule->user);
466 if (!r->user)
467 return oom_return(argv0);
468 }
469 r->exact_user = rule->exact_user;
470
471 if (rule->desc) {
472 r->desc = strdup(rule->desc);
473 if (!r->desc)
474 return oom_return(argv0);
475 }
476 r->exact_desc = rule->exact_desc;
477 #endif /* !WITHOUT_USERAUTH */
478
479 if (rule->ip) {
480 r->ip = strdup(rule->ip);
481 if (!r->ip)
482 return oom_return(argv0);
483 }
484 r->exact_ip = rule->exact_ip;
485
486 if (rule->dstip) {
487 r->dstip = strdup(rule->dstip);
488 if (!r->dstip)
489 return oom_return(argv0);
490 }
491 if (rule->sni) {
492 r->sni = strdup(rule->sni);
493 if (!r->sni)
494 return oom_return(argv0);
495 }
496 if (rule->cn) {
497 r->cn = strdup(rule->cn);
498 if (!r->cn)
499 return oom_return(argv0);
500 }
501 if (rule->host) {
502 r->host = strdup(rule->host);
503 if (!r->host)
504 return oom_return(argv0);
505 }
506 if (rule->uri) {
507 r->uri = strdup(rule->uri);
508 if (!r->uri)
509 return oom_return(argv0);
510 }
511
512 r->exact_dstip = rule->exact_dstip;
513 r->exact_sni = rule->exact_sni;
514 r->exact_cn = rule->exact_cn;
515 r->exact_host = rule->exact_host;
516 r->exact_uri = rule->exact_uri;
517
518 r->all_dstips = rule->all_dstips;
519 r->all_snis = rule->all_snis;
520 r->all_cns = rule->all_cns;
521 r->all_hosts = rule->all_hosts;
522 r->all_uris = rule->all_uris;
523
524 if (rule->port) {
525 r->port = strdup(rule->port);
526 if (!r->port)
527 return oom_return(argv0);
528 }
529 r->all_ports = rule->all_ports;
530 r->exact_port = rule->exact_port;
531
532 // The action field is not a pointer, hence the direct assignment (copy)
533 r->action = rule->action;
534
535 // But deep copy for conn_opts
536 if (rule->action.conn_opts) {
537 r->action.conn_opts = conn_opts_copy(rule->action.conn_opts, argv0, tmp_opts);
538 if (!r->action.conn_opts)
539 return oom_return(argv0);
540 }
541
542 append_list(&opts->filter_rules, r, filter_rule_t);
543
544 rule = rule->next;
545 }
546 return 0;
547 }
548
549 static char *
filter_value_str(value_t * value)550 filter_value_str(value_t *value)
551 {
552 char *s = NULL;
553
554 while (value) {
555 char *p;
556 if (asprintf(&p, "%s%s%s", STRORNONE(s), s ? ", " : "", value->value) < 0) {
557 goto err;
558 }
559 if (s)
560 free(s);
561 s = p;
562 value = value->next;
563 }
564 goto out;
565 err:
566 if (s) {
567 free(s);
568 s = NULL;
569 }
570 out:
571 return s;
572 }
573
574 char *
filter_macro_str(macro_t * macro)575 filter_macro_str(macro_t *macro)
576 {
577 char *s = NULL;
578
579 if (!macro) {
580 s = strdup("");
581 if (!s)
582 return oom_return_na_null();
583 goto out;
584 }
585
586 while (macro) {
587 char *v = filter_value_str(macro->value);
588
589 char *p;
590 if (asprintf(&p, "%s%smacro %s = %s", STRORNONE(s), NLORNONE(s), macro->name, STRORNONE(v)) < 0) {
591 if (v)
592 free(v);
593 goto err;
594 }
595 if (v)
596 free(v);
597 if (s)
598 free(s);
599 s = p;
600 macro = macro->next;
601 }
602 goto out;
603 err:
604 if (s) {
605 free(s);
606 s = NULL;
607 }
608 out:
609 return s;
610 }
611
612 static char *
filter_rule_site_str(filter_rule_t * rule,char * site,unsigned int exact_site,unsigned int all_sites,char * apply_to,int rule_num)613 filter_rule_site_str(filter_rule_t *rule, char *site, unsigned int exact_site, unsigned int all_sites, char *apply_to, int rule_num)
614 {
615 char *s = NULL;
616
617 char *copts_str = conn_opts_str(rule->action.conn_opts);
618 if (!copts_str)
619 return oom_return_na_null();
620
621 char *rule_num_str = NULL;
622 if (rule_num >= 0) {
623 if (asprintf(&rule_num_str, " %d", rule_num) < 0)
624 goto err;
625 } else {
626 rule_num_str = strdup("");
627 if (!rule_num_str)
628 goto err;
629 }
630
631 if (asprintf(&s, "filter rule%s: %s=%s, dstport=%s, srcip=%s"
632 #ifndef WITHOUT_USERAUTH
633 ", user=%s, desc=%s"
634 #endif /* !WITHOUT_USERAUTH */
635 ", exact=%s|%s|%s"
636 #ifndef WITHOUT_USERAUTH
637 "|%s|%s"
638 #endif /* !WITHOUT_USERAUTH */
639 ", all=%s|"
640 #ifndef WITHOUT_USERAUTH
641 "%s|"
642 #endif /* !WITHOUT_USERAUTH */
643 "%s|%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s"
644 #ifndef WITHOUT_MIRROR
645 "|%s"
646 #endif /* !WITHOUT_MIRROR */
647 ", precedence=%d"
648 #ifdef DEBUG_PROXY
649 ", line=%d"
650 #endif /* DEBUG_PROXY */
651 "%s%s\n",
652 rule_num_str, apply_to, site, STRORNONE(rule->port), STRORNONE(rule->ip),
653 #ifndef WITHOUT_USERAUTH
654 STRORNONE(rule->user), STRORNONE(rule->desc),
655 #endif /* !WITHOUT_USERAUTH */
656 exact_site ? "site" : "", rule->exact_port ? "port" : "", rule->exact_ip ? "ip" : "",
657 #ifndef WITHOUT_USERAUTH
658 rule->exact_user ? "user" : "", rule->exact_desc ? "desc" : "",
659 #endif /* !WITHOUT_USERAUTH */
660 rule->all_conns ? "conns" : "",
661 #ifndef WITHOUT_USERAUTH
662 rule->all_users ? "users" : "",
663 #endif /* !WITHOUT_USERAUTH */
664 all_sites ? "sites" : "", rule->all_ports ? "ports" : "",
665 rule->action.divert ? "divert" : "", rule->action.split ? "split" : "", rule->action.pass ? "pass" : "", rule->action.block ? "block" : "", rule->action.match ? "match" : "",
666 rule->action.log_connect ? (rule->action.log_connect == 1 ? "!connect" : "connect") : "", rule->action.log_master ? (rule->action.log_master == 1 ? "!master" : "master") : "",
667 rule->action.log_cert ? (rule->action.log_cert == 1 ? "!cert" : "cert") : "", rule->action.log_content ? (rule->action.log_content == 1 ? "!content" : "content") : "",
668 rule->action.log_pcap ? (rule->action.log_pcap == 1 ? "!pcap" : "pcap") : "",
669 #ifndef WITHOUT_MIRROR
670 rule->action.log_mirror ? (rule->action.log_mirror == 1 ? "!mirror" : "mirror") : "",
671 #endif /* !WITHOUT_MIRROR */
672 rule->action.precedence,
673 #ifdef DEBUG_PROXY
674 rule->action.line_num,
675 #endif /* DEBUG_PROXY */
676 strlen(copts_str) ? "\n " : "", copts_str) < 0) {
677 s = NULL;
678 }
679 err:
680 if (rule_num_str)
681 free(rule_num_str);
682 free(copts_str);
683 return s;
684 }
685
686 static char *
filter_rule_site_all_str(filter_rule_t * rule,int rule_num)687 filter_rule_site_all_str(filter_rule_t *rule, int rule_num)
688 {
689 char *s = NULL;
690
691 char *dstip = NULL;
692 char *sni = NULL;
693 char *cn = NULL;
694 char *host = NULL;
695 char *uri = NULL;
696
697 if (rule->dstip) {
698 dstip = filter_rule_site_str(rule, rule->dstip, rule->exact_dstip, rule->all_dstips, "dstip", rule_num);
699 if (!dstip)
700 goto err;
701 }
702 if (rule->sni) {
703 sni = filter_rule_site_str(rule, rule->sni, rule->exact_sni, rule->all_snis, "sni", rule_num);
704 if (!sni)
705 goto err;
706 }
707 if (rule->cn) {
708 cn = filter_rule_site_str(rule, rule->cn, rule->exact_cn, rule->all_cns, "cn", rule_num);
709 if (!cn)
710 goto err;
711 }
712 if (rule->host) {
713 host = filter_rule_site_str(rule, rule->host, rule->exact_host, rule->all_hosts, "host", rule_num);
714 if (!host)
715 goto err;
716 }
717 if (rule->uri) {
718 uri = filter_rule_site_str(rule, rule->uri, rule->exact_uri, rule->all_uris, "uri", rule_num);
719 if (!uri)
720 goto err;
721 }
722
723 if (asprintf(&s, "%s%s%s%s%s", STRORNONE(dstip), STRORNONE(sni), STRORNONE(cn), STRORNONE(host), STRORNONE(uri)) < 0) {
724 s = NULL;
725 }
726 err:
727 if (dstip)
728 free(dstip);
729 if (sni)
730 free(sni);
731 if (cn)
732 free(cn);
733 if (host)
734 free(host);
735 if (uri)
736 free(uri);
737 return s;
738 }
739
740 char *
filter_rule_str(filter_rule_t * rule)741 filter_rule_str(filter_rule_t *rule)
742 {
743 char *frs = NULL;
744
745 if (!rule) {
746 frs = strdup("");
747 if (!frs)
748 return oom_return_na_null();
749 goto out;
750 }
751
752 int count = 0;
753 while (rule) {
754 char *p = filter_rule_site_all_str(rule, count);
755 if (!p)
756 goto err;
757
758 char *nfrs;
759 if (asprintf(&nfrs, "%s%s", STRORNONE(frs), p) < 0) {
760 free(p);
761 goto err;
762 }
763 free(p);
764 if (frs)
765 free(frs);
766 frs = nfrs;
767 rule = rule->next;
768 count++;
769 }
770 goto out;
771 err:
772 if (frs) {
773 free(frs);
774 frs = NULL;
775 }
776 out:
777 return frs;
778 }
779
780 static char *
filter_port_str(filter_port_list_t * port_list)781 filter_port_str(filter_port_list_t *port_list)
782 {
783 char *s = NULL;
784
785 int count = 0;
786 while (port_list) {
787 char *copts_str = conn_opts_str(port_list->port->action.conn_opts);
788 if (!copts_str)
789 goto err;
790
791 char *p;
792 if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s"
793 #ifndef WITHOUT_MIRROR
794 "|%s"
795 #endif /* !WITHOUT_MIRROR */
796 ", precedence=%d"
797 #ifdef DEBUG_PROXY
798 ", line=%d"
799 #endif /* DEBUG_PROXY */
800 "%s%s)", STRORNONE(s), count,
801 port_list->port->port, port_list->port->all_ports ? "all_ports, " : "", port_list->port->exact ? "exact" : "substring",
802 port_list->port->action.divert ? "divert" : "", port_list->port->action.split ? "split" : "", port_list->port->action.pass ? "pass" : "", port_list->port->action.block ? "block" : "", port_list->port->action.match ? "match" : "",
803 port_list->port->action.log_connect ? (port_list->port->action.log_connect == 1 ? "!connect" : "connect") : "", port_list->port->action.log_master ? (port_list->port->action.log_master == 1 ? "!master" : "master") : "",
804 port_list->port->action.log_cert ? (port_list->port->action.log_cert == 1 ? "!cert" : "cert") : "", port_list->port->action.log_content ? (port_list->port->action.log_content == 1 ? "!content" : "content") : "",
805 port_list->port->action.log_pcap ? (port_list->port->action.log_pcap == 1 ? "!pcap" : "pcap") : "",
806 #ifndef WITHOUT_MIRROR
807 port_list->port->action.log_mirror ? (port_list->port->action.log_mirror == 1 ? "!mirror" : "mirror") : "",
808 #endif /* !WITHOUT_MIRROR */
809 port_list->port->action.precedence,
810 #ifdef DEBUG_PROXY
811 port_list->port->action.line_num,
812 #endif /* DEBUG_PROXY */
813 strlen(copts_str) ? "\n " : "", copts_str) < 0) {
814 if (copts_str)
815 free(copts_str);
816 goto err;
817 }
818 if (copts_str)
819 free(copts_str);
820 if (s)
821 free(s);
822 s = p;
823 port_list = port_list->next;
824 count++;
825 }
826 goto out;
827 err:
828 if (s) {
829 free(s);
830 s = NULL;
831 }
832 out:
833 return s;
834 }
835
836 #define build_port_list(p) do { \
837 filter_port_list_t *s = malloc(sizeof(filter_port_list_t)); \
838 memset(s, 0, sizeof(filter_port_list_t)); \
839 s->port = *p; \
840 append_list(&port, s, filter_port_list_t); \
841 } while (0)
842
843 static filter_port_list_t *port_list_acm = NULL;
844
845 static void
build_port_list_acm(UNUSED MatchHolder (char)match,void * v)846 build_port_list_acm(UNUSED MatchHolder(char) match, void *v)
847 {
848 filter_port_t *port = v;
849
850 filter_port_list_t *p = malloc(sizeof(filter_port_list_t));
851 memset(p, 0, sizeof(filter_port_list_t));
852 p->port = port;
853
854 append_list(&port_list_acm, p, filter_port_list_t);
855 }
856
857 static char *
filter_sites_str(filter_site_list_t * site_list)858 filter_sites_str(filter_site_list_t *site_list)
859 {
860 char *s = NULL;
861
862 int count = 0;
863 while (site_list) {
864 filter_port_list_t *port = NULL;
865
866 if (site_list->site->port_btree)
867 __kb_traverse(filter_port_p_t, site_list->site->port_btree, build_port_list);
868
869 char *ports_exact = filter_port_str(port);
870 free_list(port, filter_port_list_t);
871
872 if (site_list->site->port_acm)
873 ACM_foreach_keyword(site_list->site->port_acm, build_port_list_acm);
874
875 char *ports_substring = filter_port_str(port_list_acm);
876 free_list(port_list_acm, filter_port_list_t);
877 port_list_acm = NULL;
878
879 if (site_list->site->port_all)
880 build_port_list_acm((MatchHolder(char)){0}, site_list->site->port_all);
881
882 char *ports_all = filter_port_str(port_list_acm);
883 free_list(port_list_acm, filter_port_list_t);
884 port_list_acm = NULL;
885
886 char *copts_str = conn_opts_str(site_list->site->action.conn_opts);
887 if (!copts_str)
888 goto err;
889
890 char *p;
891 if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s"
892 #ifndef WITHOUT_MIRROR
893 "|%s"
894 #endif /* !WITHOUT_MIRROR */
895 ", precedence=%d"
896 #ifdef DEBUG_PROXY
897 ", line=%d"
898 #endif /* DEBUG_PROXY */
899 "%s%s)%s%s%s%s%s%s",
900 STRORNONE(s), count,
901 site_list->site->site, site_list->site->all_sites ? "all_sites, " : "", site_list->site->exact ? "exact" : "substring",
902 site_list->site->action.divert ? "divert" : "", site_list->site->action.split ? "split" : "", site_list->site->action.pass ? "pass" : "", site_list->site->action.block ? "block" : "", site_list->site->action.match ? "match" : "",
903 site_list->site->action.log_connect ? (site_list->site->action.log_connect == 1 ? "!connect" : "connect") : "", site_list->site->action.log_master ? (site_list->site->action.log_master == 1 ? "!master" : "master") : "",
904 site_list->site->action.log_cert ? (site_list->site->action.log_cert == 1 ? "!cert" : "cert") : "", site_list->site->action.log_content ? (site_list->site->action.log_content == 1 ? "!content" : "content") : "",
905 site_list->site->action.log_pcap ? (site_list->site->action.log_pcap == 1 ? "!pcap" : "pcap") : "",
906 #ifndef WITHOUT_MIRROR
907 site_list->site->action.log_mirror ? (site_list->site->action.log_mirror == 1 ? "!mirror" : "mirror") : "",
908 #endif /* !WITHOUT_MIRROR */
909 site_list->site->action.precedence,
910 #ifdef DEBUG_PROXY
911 site_list->site->action.line_num,
912 #endif /* DEBUG_PROXY */
913 strlen(copts_str) ? "\n " : "", copts_str,
914 ports_exact ? "\n port exact:" : "", STRORNONE(ports_exact),
915 ports_substring ? "\n port substring:" : "", STRORNONE(ports_substring),
916 ports_all ? "\n port all:" : "", STRORNONE(ports_all)) < 0) {
917 if (ports_exact)
918 free(ports_exact);
919 if (ports_substring)
920 free(ports_substring);
921 if (ports_all)
922 free(ports_all);
923 if (copts_str)
924 free(copts_str);
925 goto err;
926 }
927 if (ports_exact)
928 free(ports_exact);
929 if (ports_substring)
930 free(ports_substring);
931 if (ports_all)
932 free(ports_all);
933 if (copts_str)
934 free(copts_str);
935 if (s)
936 free(s);
937 s = p;
938 site_list = site_list->next;
939 count++;
940 }
941 goto out;
942 err:
943 if (s) {
944 free(s);
945 s = NULL;
946 }
947 out:
948 return s;
949 }
950
951 static char *
filter_list_sub_str(filter_site_list_t * list,char * old_s,const char * name)952 filter_list_sub_str(filter_site_list_t *list, char *old_s, const char *name)
953 {
954 char *new_s = NULL;
955 char *s = filter_sites_str(list);
956 if (asprintf(&new_s, "%s%s %s:%s", STRORNONE(old_s), NLORNONE(old_s), name, STRORNONE(s)) < 0) {
957 // @todo Handle oom, and don't just use STRORNONE()
958 new_s = NULL;
959 }
960 if (s)
961 free(s);
962 if (old_s)
963 free(old_s);
964 return new_s;
965 }
966
967 static filter_site_list_t *site_list_acm = NULL;
968
969 static void
build_site_list_acm(UNUSED MatchHolder (char)match,void * v)970 build_site_list_acm(UNUSED MatchHolder(char) match, void *v)
971 {
972 filter_site_t *site = v;
973
974 filter_site_list_t *s = malloc(sizeof(filter_site_list_t));
975 memset(s, 0, sizeof(filter_site_list_t));
976 s->site = site;
977
978 append_list(&site_list_acm, s, filter_site_list_t);
979 }
980
981 static void
filter_tmp_site_list_free(filter_site_list_t ** list)982 filter_tmp_site_list_free(filter_site_list_t **list)
983 {
984 free_list(*list, filter_site_list_t);
985 *list = NULL;
986 }
987
988 static char *
filter_list_str(filter_list_t * list)989 filter_list_str(filter_list_t *list)
990 {
991 char *s = NULL;
992 filter_site_list_t *site = NULL;
993
994 #define build_site_list(p) do { \
995 filter_site_list_t *s = malloc(sizeof(filter_site_list_t)); \
996 memset(s, 0, sizeof(filter_site_list_t)); \
997 s->site = *p; \
998 append_list(&site, s, filter_site_list_t); \
999 } while (0)
1000
1001 if (list->ip_btree) {
1002 __kb_traverse(filter_site_p_t, list->ip_btree, build_site_list);
1003 s = filter_list_sub_str(site, s, "ip exact");
1004 filter_tmp_site_list_free(&site);
1005 }
1006 if (list->ip_acm) {
1007 ACM_foreach_keyword(list->ip_acm, build_site_list_acm);
1008 s = filter_list_sub_str(site_list_acm, s, "ip substring");
1009 filter_tmp_site_list_free(&site_list_acm);
1010 }
1011 if (list->ip_all) {
1012 build_site_list_acm((MatchHolder(char)){0}, list->ip_all);
1013 s = filter_list_sub_str(site_list_acm, s, "ip all");
1014 filter_tmp_site_list_free(&site_list_acm);
1015 }
1016
1017 if (list->sni_btree) {
1018 __kb_traverse(filter_site_p_t, list->sni_btree, build_site_list);
1019 s = filter_list_sub_str(site, s, "sni exact");
1020 filter_tmp_site_list_free(&site);
1021 }
1022 if (list->sni_acm) {
1023 ACM_foreach_keyword(list->sni_acm, build_site_list_acm);
1024 s = filter_list_sub_str(site_list_acm, s, "sni substring");
1025 filter_tmp_site_list_free(&site_list_acm);
1026 }
1027 if (list->sni_all) {
1028 build_site_list_acm((MatchHolder(char)){0}, list->sni_all);
1029 s = filter_list_sub_str(site_list_acm, s, "sni all");
1030 filter_tmp_site_list_free(&site_list_acm);
1031 }
1032
1033 if (list->cn_btree) {
1034 __kb_traverse(filter_site_p_t, list->cn_btree, build_site_list);
1035 s = filter_list_sub_str(site, s, "cn exact");
1036 filter_tmp_site_list_free(&site);
1037 }
1038 if (list->cn_acm) {
1039 ACM_foreach_keyword(list->cn_acm, build_site_list_acm);
1040 s = filter_list_sub_str(site_list_acm, s, "cn substring");
1041 filter_tmp_site_list_free(&site_list_acm);
1042 }
1043 if (list->cn_all) {
1044 build_site_list_acm((MatchHolder(char)){0}, list->cn_all);
1045 s = filter_list_sub_str(site_list_acm, s, "cn all");
1046 filter_tmp_site_list_free(&site_list_acm);
1047 }
1048
1049 if (list->host_btree) {
1050 __kb_traverse(filter_site_p_t, list->host_btree, build_site_list);
1051 s = filter_list_sub_str(site, s, "host exact");
1052 filter_tmp_site_list_free(&site);
1053 }
1054 if (list->host_acm) {
1055 ACM_foreach_keyword(list->host_acm, build_site_list_acm);
1056 s = filter_list_sub_str(site_list_acm, s, "host substring");
1057 filter_tmp_site_list_free(&site_list_acm);
1058 }
1059 if (list->host_all) {
1060 build_site_list_acm((MatchHolder(char)){0}, list->host_all);
1061 s = filter_list_sub_str(site_list_acm, s, "host all");
1062 filter_tmp_site_list_free(&site_list_acm);
1063 }
1064
1065 if (list->uri_btree) {
1066 __kb_traverse(filter_site_p_t, list->uri_btree, build_site_list);
1067 s = filter_list_sub_str(site, s, "uri exact");
1068 filter_tmp_site_list_free(&site);
1069 }
1070 if (list->uri_acm) {
1071 ACM_foreach_keyword(list->uri_acm, build_site_list_acm);
1072 s = filter_list_sub_str(site_list_acm, s, "uri substring");
1073 filter_tmp_site_list_free(&site_list_acm);
1074 }
1075 if (list->uri_all) {
1076 build_site_list_acm((MatchHolder(char)){0}, list->uri_all);
1077 s = filter_list_sub_str(site_list_acm, s, "uri all");
1078 filter_tmp_site_list_free(&site_list_acm);
1079 }
1080 return s;
1081 }
1082
1083 static char *
filter_ip_list_str(filter_ip_list_t * ip_list)1084 filter_ip_list_str(filter_ip_list_t *ip_list)
1085 {
1086 char *s = NULL;
1087
1088 int count = 0;
1089 while (ip_list) {
1090 char *list = filter_list_str(ip_list->ip->list);
1091
1092 char *p;
1093 if (asprintf(&p, "%s%s ip %d %s (%s)=\n%s", STRORNONE(s), NLORNONE(s),
1094 count, ip_list->ip->ip, ip_list->ip->exact ? "exact" : "substring", STRORNONE(list)) < 0) {
1095 if (list)
1096 free(list);
1097 goto err;
1098 }
1099 if (list)
1100 free(list);
1101 if (s)
1102 free(s);
1103 s = p;
1104 ip_list = ip_list->next;
1105 count++;
1106 }
1107 goto out;
1108 err:
1109 if (s) {
1110 free(s);
1111 s = NULL;
1112 }
1113 out:
1114 return s;
1115 }
1116
1117 static char *
filter_ip_btree_str(kbtree_t (ip)* btree)1118 filter_ip_btree_str(kbtree_t(ip) *btree)
1119 {
1120 if (!btree)
1121 return NULL;
1122
1123 #define build_ip_list(p) do { \
1124 filter_ip_list_t *i = malloc(sizeof(filter_ip_list_t)); \
1125 memset(i, 0, sizeof(filter_ip_list_t)); \
1126 i->ip = *p; \
1127 append_list(&ip, i, filter_ip_list_t); \
1128 } while (0)
1129
1130 filter_ip_list_t *ip = NULL;
1131 __kb_traverse(filter_ip_p_t, btree, build_ip_list);
1132
1133 char *s = filter_ip_list_str(ip);
1134
1135 free_list(ip, filter_ip_list_t);
1136 return s;
1137 }
1138
1139 static filter_ip_list_t *ip_list_acm = NULL;
1140
1141 static void
build_ip_list_acm(UNUSED MatchHolder (char)match,void * v)1142 build_ip_list_acm(UNUSED MatchHolder(char) match, void *v)
1143 {
1144 filter_ip_t *ip = v;
1145
1146 filter_ip_list_t *i = malloc(sizeof(filter_ip_list_t));
1147 memset(i, 0, sizeof(filter_ip_list_t));
1148 i->ip = ip;
1149
1150 append_list(&ip_list_acm, i, filter_ip_list_t);
1151 }
1152
1153 static char *
filter_ip_acm_str(ACMachine (char)* acm)1154 filter_ip_acm_str(ACMachine(char) *acm)
1155 {
1156 if (!acm)
1157 return NULL;
1158
1159 ACM_foreach_keyword(acm, build_ip_list_acm);
1160
1161 char *s = filter_ip_list_str(ip_list_acm);
1162
1163 free_list(ip_list_acm, filter_ip_list_t);
1164 ip_list_acm = NULL;
1165 return s;
1166 }
1167
1168 #ifndef WITHOUT_USERAUTH
1169 static char *
filter_user_list_str(filter_user_list_t * user)1170 filter_user_list_str(filter_user_list_t *user)
1171 {
1172 char *s = NULL;
1173
1174 int count = 0;
1175 while (user) {
1176 // Make sure the user has a filter rule
1177 // It is possible to have users without any filter rule,
1178 // but the user exists because it has desc filters,
1179 // so the current user should not have any desc
1180 if (user->user->desc_btree || user->user->desc_acm)
1181 goto skip;
1182
1183 char *list = filter_list_str(user->user->list);
1184
1185 char *p = NULL;
1186
1187 if (list) {
1188 if (asprintf(&p, "%s%s user %d %s (%s)=\n%s", STRORNONE(s), NLORNONE(s),
1189 count, user->user->user, user->user->exact ? "exact" : "substring", list) < 0) {
1190 free(list);
1191 goto err;
1192 }
1193 free(list);
1194 }
1195 if (s)
1196 free(s);
1197 s = p;
1198 count++;
1199 skip:
1200 user = user->next;
1201 }
1202 goto out;
1203 err:
1204 if (s) {
1205 free(s);
1206 s = NULL;
1207 }
1208 out:
1209 return s;
1210 }
1211
1212 #define build_user_list(p) do { \
1213 filter_user_list_t *u = malloc(sizeof(filter_user_list_t)); \
1214 memset(u, 0, sizeof(filter_user_list_t)); \
1215 u->user = *p; \
1216 append_list(&user, u, filter_user_list_t); \
1217 } while (0)
1218
1219 static char *
filter_user_btree_str(kbtree_t (user)* btree)1220 filter_user_btree_str(kbtree_t(user) *btree)
1221 {
1222 if (!btree)
1223 return NULL;
1224
1225 filter_user_list_t *user = NULL;
1226 __kb_traverse(filter_user_p_t, btree, build_user_list);
1227
1228 char *s = filter_user_list_str(user);
1229
1230 free_list(user, filter_user_list_t);
1231 return s;
1232 }
1233
1234 static filter_user_list_t *user_list_acm = NULL;
1235
1236 static void
build_user_list_acm(UNUSED MatchHolder (char)match,void * v)1237 build_user_list_acm(UNUSED MatchHolder(char) match, void *v)
1238 {
1239 filter_user_t *user = v;
1240
1241 filter_user_list_t *u = malloc(sizeof(filter_user_list_t));
1242 memset(u, 0, sizeof(filter_user_list_t));
1243 u->user = user;
1244
1245 append_list(&user_list_acm, u, filter_user_list_t);
1246 }
1247
1248 static char *
filter_user_acm_str(ACMachine (char)* acm)1249 filter_user_acm_str(ACMachine(char) *acm)
1250 {
1251 if (!acm)
1252 return NULL;
1253
1254 ACM_foreach_keyword(acm, build_user_list_acm);
1255
1256 char *s = filter_user_list_str(user_list_acm);
1257
1258 free_list(user_list_acm, filter_user_list_t);
1259 user_list_acm = NULL;
1260 return s;
1261 }
1262
1263 static char *
filter_desc_list_str(filter_desc_list_t * desc)1264 filter_desc_list_str(filter_desc_list_t *desc)
1265 {
1266 char *s = NULL;
1267
1268 int count = 0;
1269 while (desc) {
1270 char *list = filter_list_str(desc->desc->list);
1271
1272 char *p;
1273 if (asprintf(&p, "%s%s desc %d %s (%s)=\n%s", STRORNONE(s), NLORNONE(s),
1274 count, desc->desc->desc, desc->desc->exact ? "exact" : "substring", STRORNONE(list)) < 0) {
1275 if (list)
1276 free(list);
1277 goto err;
1278 }
1279 if (list)
1280 free(list);
1281 if (s)
1282 free(s);
1283 s = p;
1284 desc = desc->next;
1285 count++;
1286 }
1287 goto out;
1288 err:
1289 if (s) {
1290 free(s);
1291 s = NULL;
1292 }
1293 out:
1294 return s;
1295 }
1296
1297 static char *
filter_desc_btree_str(kbtree_t (desc)* btree)1298 filter_desc_btree_str(kbtree_t(desc) *btree)
1299 {
1300 if (!btree)
1301 return NULL;
1302
1303 #define build_desc_list(p) do { \
1304 filter_desc_list_t *d = malloc(sizeof(filter_desc_list_t)); \
1305 memset(d, 0, sizeof(filter_desc_list_t)); \
1306 d->desc = *p; \
1307 append_list(&desc, d, filter_desc_list_t); \
1308 } while (0)
1309
1310 filter_desc_list_t *desc = NULL;
1311 __kb_traverse(filter_desc_p_t, btree, build_desc_list);
1312
1313 char *s = filter_desc_list_str(desc);
1314
1315 free_list(desc, filter_desc_list_t);
1316 return s;
1317 }
1318
1319 static filter_desc_list_t *desc_list_acm = NULL;
1320
1321 static void
build_desc_list_acm(UNUSED MatchHolder (char)match,void * v)1322 build_desc_list_acm(UNUSED MatchHolder(char) match, void *v)
1323 {
1324 filter_desc_t *desc = v;
1325
1326 filter_desc_list_t *d = malloc(sizeof(filter_desc_list_t));
1327 memset(d, 0, sizeof(filter_desc_list_t));
1328 d->desc = desc;
1329
1330 append_list(&desc_list_acm, d, filter_desc_list_t);
1331 }
1332
1333 static char *
filter_desc_acm_str(ACMachine (char)* acm)1334 filter_desc_acm_str(ACMachine(char) *acm)
1335 {
1336 if (!acm)
1337 return NULL;
1338
1339 ACM_foreach_keyword(acm, build_desc_list_acm);
1340
1341 char *s = filter_desc_list_str(desc_list_acm);
1342
1343 free_list(desc_list_acm, filter_desc_list_t);
1344 desc_list_acm = NULL;
1345 return s;
1346 }
1347
1348 static char *
filter_userdesc_list_str(filter_user_list_t * user)1349 filter_userdesc_list_str(filter_user_list_t *user)
1350 {
1351 char *s = NULL;
1352
1353 int count = 0;
1354 while (user) {
1355 // Make sure the current user has a desc
1356 if (!user->user->desc_btree && !user->user->desc_acm)
1357 goto skip;
1358
1359 char *list_exact = filter_desc_btree_str(user->user->desc_btree);
1360 char *list_substr = filter_desc_acm_str(user->user->desc_acm);
1361
1362 char *p = NULL;
1363 if (asprintf(&p, "%s%s user %d %s (%s)=%s%s%s%s", STRORNONE(s), NLORNONE(s),
1364 count, user->user->user, user->user->exact ? "exact" : "substring",
1365 list_exact ? "\n desc exact:\n" : "", STRORNONE(list_exact),
1366 list_substr ? "\n desc substring:\n" : "", STRORNONE(list_substr)
1367 ) < 0) {
1368 if (list_exact)
1369 free(list_exact);
1370 if (list_substr)
1371 free(list_substr);
1372 goto err;
1373 }
1374 if (list_exact)
1375 free(list_exact);
1376 if (list_substr)
1377 free(list_substr);
1378 if (s)
1379 free(s);
1380 s = p;
1381 count++;
1382 skip:
1383 user = user->next;
1384 }
1385 goto out;
1386 err:
1387 if (s) {
1388 free(s);
1389 s = NULL;
1390 }
1391 out:
1392 return s;
1393 }
1394
1395 static char *
filter_userdesc_btree_str(kbtree_t (user)* btree)1396 filter_userdesc_btree_str(kbtree_t(user) *btree)
1397 {
1398 if (!btree)
1399 return NULL;
1400
1401 filter_user_list_t *user = NULL;
1402 __kb_traverse(filter_user_p_t, btree, build_user_list);
1403
1404 char *s = filter_userdesc_list_str(user);
1405
1406 free_list(user, filter_user_list_t);
1407 return s;
1408 }
1409
1410 static char *
filter_userdesc_acm_str(ACMachine (char)* acm)1411 filter_userdesc_acm_str(ACMachine(char) *acm)
1412 {
1413 if (!acm)
1414 return NULL;
1415
1416 ACM_foreach_keyword(acm, build_user_list_acm);
1417
1418 char *s = filter_userdesc_list_str(user_list_acm);
1419
1420 free_list(user_list_acm, filter_user_list_t);
1421 user_list_acm = NULL;
1422 return s;
1423 }
1424
1425 #endif /* !WITHOUT_USERAUTH */
1426
1427 char *
filter_str(filter_t * filter)1428 filter_str(filter_t *filter)
1429 {
1430 char *fs = NULL;
1431 #ifndef WITHOUT_USERAUTH
1432 char *userdesc_filter_exact = NULL;
1433 char *userdesc_filter_substr = NULL;
1434 char *user_filter_exact = NULL;
1435 char *user_filter_substr = NULL;
1436 char *desc_filter_exact = NULL;
1437 char *desc_filter_substr = NULL;
1438 char *user_filter_all = NULL;
1439 #endif /* !WITHOUT_USERAUTH */
1440 char *ip_filter_exact = NULL;
1441 char *ip_filter_substr = NULL;
1442 char *filter_all = NULL;
1443
1444 if (!filter) {
1445 fs = strdup("");
1446 if (!fs)
1447 return oom_return_na_null();
1448 goto out;
1449 }
1450
1451 #ifndef WITHOUT_USERAUTH
1452 userdesc_filter_exact = filter_userdesc_btree_str(filter->user_btree);
1453 userdesc_filter_substr = filter_userdesc_acm_str(filter->user_acm);
1454 user_filter_exact = filter_user_btree_str(filter->user_btree);
1455 user_filter_substr = filter_user_acm_str(filter->user_acm);
1456 desc_filter_exact = filter_desc_btree_str(filter->desc_btree);
1457 desc_filter_substr = filter_desc_acm_str(filter->desc_acm);
1458 user_filter_all = filter_list_str(filter->all_user);
1459 #endif /* !WITHOUT_USERAUTH */
1460 ip_filter_exact = filter_ip_btree_str(filter->ip_btree);
1461 ip_filter_substr = filter_ip_acm_str(filter->ip_acm);
1462 filter_all = filter_list_str(filter->all);
1463
1464 if (asprintf(&fs, "filter=>\n"
1465 #ifndef WITHOUT_USERAUTH
1466 "userdesc_filter_exact->%s%s\n"
1467 "userdesc_filter_substring->%s%s\n"
1468 "user_filter_exact->%s%s\n"
1469 "user_filter_substring->%s%s\n"
1470 "desc_filter_exact->%s%s\n"
1471 "desc_filter_substring->%s%s\n"
1472 "user_filter_all->%s%s\n"
1473 #endif /* !WITHOUT_USERAUTH */
1474 "ip_filter_exact->%s%s\n"
1475 "ip_filter_substring->%s%s\n"
1476 "filter_all->%s%s\n",
1477 #ifndef WITHOUT_USERAUTH
1478 NLORNONE(userdesc_filter_exact), STRORNONE(userdesc_filter_exact),
1479 NLORNONE(userdesc_filter_substr), STRORNONE(userdesc_filter_substr),
1480 NLORNONE(user_filter_exact), STRORNONE(user_filter_exact),
1481 NLORNONE(user_filter_substr), STRORNONE(user_filter_substr),
1482 NLORNONE(desc_filter_exact), STRORNONE(desc_filter_exact),
1483 NLORNONE(desc_filter_substr), STRORNONE(desc_filter_substr),
1484 NLORNONE(user_filter_all), STRORNONE(user_filter_all),
1485 #endif /* !WITHOUT_USERAUTH */
1486 NLORNONE(ip_filter_exact), STRORNONE(ip_filter_exact),
1487 NLORNONE(ip_filter_substr), STRORNONE(ip_filter_substr),
1488 NLORNONE(filter_all), STRORNONE(filter_all)) < 0) {
1489 // fs is undefined
1490 goto err;
1491 }
1492 goto out;
1493 err:
1494 if (fs) {
1495 free(fs);
1496 fs = NULL;
1497 }
1498 out:
1499 #ifndef WITHOUT_USERAUTH
1500 if (userdesc_filter_exact)
1501 free(userdesc_filter_exact);
1502 if (userdesc_filter_substr)
1503 free(userdesc_filter_substr);
1504 if (user_filter_exact)
1505 free(user_filter_exact);
1506 if (user_filter_substr)
1507 free(user_filter_substr);
1508 if (desc_filter_exact)
1509 free(desc_filter_exact);
1510 if (desc_filter_substr)
1511 free(desc_filter_substr);
1512 if (user_filter_all)
1513 free(user_filter_all);
1514 #endif /* !WITHOUT_USERAUTH */
1515 if (ip_filter_exact)
1516 free(ip_filter_exact);
1517 if (ip_filter_substr)
1518 free(ip_filter_substr);
1519 if (filter_all)
1520 free(filter_all);
1521 return fs;
1522 }
1523
1524 #ifdef DEBUG_OPTS
1525 static void
filter_rule_dbg_print(filter_rule_t * rule)1526 filter_rule_dbg_print(filter_rule_t *rule)
1527 {
1528 char *s = filter_rule_site_all_str(rule, -1);
1529 if (!s)
1530 return;
1531 log_dbg_printf("%s", s);
1532 free(s);
1533 }
1534 #endif /* DEBUG_OPTS */
1535
1536 #define MAX_SITE_LEN 200
1537
1538 int
filter_passsite_set(opts_t * opts,UNUSED conn_opts_t * conn_opts,char * value,unsigned int line_num)1539 filter_passsite_set(opts_t *opts, UNUSED conn_opts_t *conn_opts, char *value, unsigned int line_num)
1540 {
1541 #define MAX_PASSSITE_TOKENS 3
1542
1543 // site[*] [(clientaddr|user|*) [desc]]
1544 char *argv[sizeof(char *) * MAX_PASSSITE_TOKENS];
1545 int argc = 0;
1546 char *p, *last = NULL;
1547
1548 for ((p = strtok_r(value, " ", &last));
1549 p;
1550 (p = strtok_r(NULL, " ", &last))) {
1551 if (argc < MAX_PASSSITE_TOKENS) {
1552 argv[argc++] = p;
1553 } else {
1554 fprintf(stderr, "Too many arguments in passsite option on line %d\n", line_num);
1555 return -1;
1556 }
1557 }
1558
1559 if (!argc) {
1560 fprintf(stderr, "Filter rule requires at least one parameter on line %d\n", line_num);
1561 return -1;
1562 }
1563
1564 filter_rule_t *rule = malloc(sizeof(filter_rule_t));
1565 if (!rule)
1566 return oom_return_na();
1567 memset(rule, 0, sizeof(filter_rule_t));
1568
1569 // The for loop with strtok_r() above does not output empty strings
1570 // So, no need to check if the length of argv[0] > 0
1571 size_t len = strlen(argv[0]);
1572
1573 if (len > MAX_SITE_LEN) {
1574 fprintf(stderr, "Filter site too long %zu > %d on line %d\n", len, MAX_SITE_LEN, line_num);
1575 return -1;
1576 }
1577
1578 unsigned int exact_site = 0;
1579 unsigned int all_sites = 0;
1580 if (argv[0][len - 1] == '*') {
1581 exact_site = 0;
1582 len--;
1583 argv[0][len] = '\0';
1584 // site == "*" ?
1585 if (len == 0)
1586 all_sites = 1;
1587 } else {
1588 exact_site = 1;
1589 }
1590
1591 rule->sni = strdup(argv[0]);
1592 if (!rule->sni)
1593 return oom_return_na();
1594 rule->exact_sni = exact_site;
1595 rule->all_snis = all_sites;
1596
1597 rule->cn = strdup(argv[0]);
1598 if (!rule->cn)
1599 return oom_return_na();
1600 rule->exact_cn = exact_site;
1601 rule->all_cns = all_sites;
1602
1603 // precedence can only go up not down
1604 rule->action.precedence = 0;
1605
1606 if (argc == 1) {
1607 // Apply filter rule to all conns
1608 // Equivalent to "site *" without user auth
1609 rule->all_conns = 1;
1610 }
1611
1612 if (argc > 1) {
1613 if (!strcmp(argv[1], "*")) {
1614 #ifndef WITHOUT_USERAUTH
1615 // Apply filter rule to all users perhaps with desc
1616 rule->action.precedence++;
1617 rule->all_users = 1;
1618 } else if (sys_isuser(argv[1])) {
1619 if (!conn_opts->user_auth) {
1620 fprintf(stderr, "User filter requires user auth on line %d\n", line_num);
1621 return -1;
1622 }
1623 rule->action.precedence += 2;
1624 rule->user = strdup(argv[1]);
1625 if (!rule->user)
1626 return oom_return_na();
1627 #else /* !WITHOUT_USERAUTH */
1628 // Apply filter rule to all conns, if USERAUTH is disabled, ip == '*'
1629 rule->all_conns = 1;
1630 #endif /* WITHOUT_USERAUTH */
1631 } else {
1632 rule->action.precedence++;
1633 rule->ip = strdup(argv[1]);
1634 if (!rule->ip)
1635 return oom_return_na();
1636 }
1637 }
1638
1639 if (argc > 2) {
1640 if (rule->ip) {
1641 fprintf(stderr, "Ip filter cannot define desc filter"
1642 #ifndef WITHOUT_USERAUTH
1643 ", or user '%s' does not exist"
1644 #endif /* !WITHOUT_USERAUTH */
1645 " on line %d\n",
1646 #ifndef WITHOUT_USERAUTH
1647 rule->ip,
1648 #endif /* !WITHOUT_USERAUTH */
1649 line_num);
1650 return -1;
1651 }
1652 #ifndef WITHOUT_USERAUTH
1653 if (!conn_opts->user_auth) {
1654 fprintf(stderr, "Keyword filter requires user auth on line %d\n", line_num);
1655 return -1;
1656 }
1657 rule->action.precedence++;
1658 rule->desc = strdup(argv[2]);
1659 if (!rule->desc)
1660 return oom_return_na();
1661 #endif /* !WITHOUT_USERAUTH */
1662 }
1663
1664 rule->action.precedence++;
1665 rule->action.pass = 1;
1666
1667 append_list(&opts->filter_rules, rule, filter_rule_t);
1668
1669 #ifdef DEBUG_OPTS
1670 filter_rule_dbg_print(rule);
1671 #endif /* DEBUG_OPTS */
1672 return 0;
1673 }
1674
1675 static macro_t *
filter_macro_find(macro_t * macro,char * name)1676 filter_macro_find(macro_t *macro, char *name)
1677 {
1678 while (macro) {
1679 if (equal(macro->name, name)) {
1680 return macro;
1681 }
1682 macro = macro->next;
1683 }
1684 return NULL;
1685 }
1686
1687 int
filter_macro_set(opts_t * opts,char * value,unsigned int line_num)1688 filter_macro_set(opts_t *opts, char *value, unsigned int line_num)
1689 {
1690 #define MAX_MACRO_TOKENS 50
1691
1692 // $name value1 [value2 [value3] ...]
1693 char *argv[sizeof(char *) * MAX_MACRO_TOKENS];
1694 int argc = 0;
1695 char *p, *last = NULL;
1696
1697 for ((p = strtok_r(value, " ", &last));
1698 p;
1699 (p = strtok_r(NULL, " ", &last))) {
1700 if (argc < MAX_MACRO_TOKENS) {
1701 argv[argc++] = p;
1702 } else {
1703 fprintf(stderr, "Too many arguments in macro definition on line %d\n", line_num);
1704 return -1;
1705 }
1706 }
1707
1708 if (argc < 2) {
1709 fprintf(stderr, "Macro definition requires at least two arguments on line %d\n", line_num);
1710 return -1;
1711 }
1712
1713 if (argv[0][0] != '$') {
1714 fprintf(stderr, "Macro name should start with '$' on line %d\n", line_num);
1715 return -1;
1716 }
1717
1718 if (filter_macro_find(opts->macro, argv[0])) {
1719 fprintf(stderr, "Macro name '%s' already exists on line %d\n", argv[0], line_num);
1720 return -1;
1721 }
1722
1723 macro_t *macro = malloc(sizeof(macro_t));
1724 if (!macro)
1725 return oom_return_na();
1726 memset(macro, 0, sizeof(macro_t));
1727
1728 macro->name = strdup(argv[0]);
1729 if (!macro->name)
1730 return oom_return_na();
1731
1732 int i = 1;
1733 while (i < argc) {
1734 // Do not allow macro within macro, no recursive macro definitions
1735 if (argv[i][0] == '$') {
1736 fprintf(stderr, "Invalid macro value '%s' on line %d\n", argv[i], line_num);
1737 return -1;
1738 }
1739
1740 value_t *v = malloc(sizeof(value_t));
1741 if (!v)
1742 return oom_return_na();
1743 memset(v, 0, sizeof(value_t));
1744
1745 v->value = strdup(argv[i++]);
1746 if (!v->value)
1747 return oom_return_na();
1748
1749 append_list(¯o->value, v, value_t);
1750 }
1751
1752 append_list(&opts->macro, macro, macro_t);
1753
1754 #ifdef DEBUG_OPTS
1755 char *s = filter_value_str(macro->value);
1756 if (!s)
1757 return oom_return_na();
1758 log_dbg_printf("Macro: %s = %s\n", macro->name, s);
1759 free(s);
1760 #endif /* DEBUG_OPTS */
1761 return 0;
1762 }
1763
1764 static char * WUNRES
filter_site_set(filter_rule_t * rule,const char * name,const char * site,unsigned int line_num)1765 filter_site_set(filter_rule_t *rule, const char *name, const char *site, unsigned int line_num)
1766 {
1767 // The for loop with strtok_r() does not output empty strings
1768 // So, no need to check if the length of site > 0
1769 size_t len = strlen(site);
1770
1771 if (len > MAX_SITE_LEN) {
1772 fprintf(stderr, "Filter site too long %zu > %d on line %d\n", len, MAX_SITE_LEN, line_num);
1773 return NULL;
1774 }
1775
1776 // Don't modify site, site is reused in macro expansion
1777 char *s = strdup(site);
1778 if (!s)
1779 return oom_return_na_null();
1780
1781 unsigned int exact_site = 0;
1782 unsigned int all_sites = 0;
1783 if (s[len - 1] == '*') {
1784 exact_site = 0;
1785 len--;
1786 s[len] = '\0';
1787 // site == "*" ?
1788 if (len == 0)
1789 all_sites = 1;
1790 } else {
1791 exact_site = 1;
1792 }
1793
1794 // redundant?
1795 if (equal(s, "*"))
1796 all_sites = 1;
1797
1798 if (equal(name, "ip") || equal(name, "DstIp")) {
1799 rule->dstip = s;
1800 rule->exact_dstip = exact_site;
1801 rule->all_dstips = all_sites;
1802 }
1803 else if (equal(name, "sni") || equal(name, "SNI")) {
1804 rule->sni = s;
1805 rule->exact_sni = exact_site;
1806 rule->all_snis = all_sites;
1807 }
1808 else if (equal(name, "cn") || equal(name, "CN")) {
1809 rule->cn = s;
1810 rule->exact_cn = exact_site;
1811 rule->all_cns = all_sites;
1812 }
1813 else if (equal(name, "host") || equal(name, "Host")) {
1814 rule->host = s;
1815 rule->exact_host = exact_site;
1816 rule->all_hosts = all_sites;
1817 }
1818 else if (equal(name, "uri") || equal(name, "URI")) {
1819 rule->uri = s;
1820 rule->exact_uri = exact_site;
1821 rule->all_uris = all_sites;
1822 }
1823
1824 return s;
1825 }
1826
1827 static int WUNRES
filter_port_set(filter_rule_t * rule,const char * port,unsigned int line_num)1828 filter_port_set(filter_rule_t *rule, const char *port, unsigned int line_num)
1829 {
1830 #define MAX_PORT_LEN 6
1831
1832 size_t len = strlen(port);
1833
1834 if (len > MAX_PORT_LEN) {
1835 fprintf(stderr, "Filter port too long %zu > %d on line %d\n", len, MAX_PORT_LEN, line_num);
1836 return -1;
1837 }
1838
1839 rule->port = strdup(port);
1840 if (!rule->port)
1841 return oom_return_na();
1842
1843 if (rule->port[len - 1] == '*') {
1844 rule->exact_port = 0;
1845 len--;
1846 rule->port[len] = '\0';
1847 // site == "*" ?
1848 if (len == 0)
1849 rule->all_ports = 1;
1850 } else {
1851 rule->exact_port = 1;
1852 }
1853
1854 // redundant?
1855 if (equal(rule->port, "*"))
1856 rule->all_ports = 1;
1857 return 0;
1858 }
1859
1860 static int WUNRES
filter_is_exact(const char * arg)1861 filter_is_exact(const char *arg)
1862 {
1863 return arg[strlen(arg) - 1] != '*';
1864 }
1865
1866 static int WUNRES
filter_is_all(const char * arg)1867 filter_is_all(const char *arg)
1868 {
1869 return equal(arg, "*");
1870 }
1871
1872 static int WUNRES
filter_field_set(char ** field,const char * arg,unsigned int line_num)1873 filter_field_set(char **field, const char *arg, unsigned int line_num)
1874 {
1875 // The for loop with strtok_r() does not output empty strings
1876 // So, no need to check if the length of field > 0
1877 size_t len = strlen(arg);
1878
1879 if (len > MAX_SITE_LEN) {
1880 fprintf(stderr, "Filter field too long %zu > %d on line %d\n", len, MAX_SITE_LEN, line_num);
1881 return -1;
1882 }
1883
1884 *field = strdup(arg);
1885 if (!*field)
1886 return oom_return_na();
1887
1888 if ((*field)[len - 1] == '*')
1889 (*field)[len - 1] = '\0';
1890 return 0;
1891 }
1892
1893 static int WUNRES
filter_arg_index_inc(int i,int argc,char * last,unsigned int line_num)1894 filter_arg_index_inc(int i, int argc, char *last, unsigned int line_num)
1895 {
1896 if (i + 1 < argc) {
1897 return i + 1;
1898 } else {
1899 fprintf(stderr, "Not enough arguments in filter rule after '%s' on line %d\n", last, line_num);
1900 return -1;
1901 }
1902 }
1903
1904 static int WUNRES
filter_rule_translate(opts_t * opts,const char * name,int argc,char ** argv,unsigned int line_num)1905 filter_rule_translate(opts_t *opts, const char *name, int argc, char **argv, unsigned int line_num)
1906 {
1907 filter_rule_t *rule = malloc(sizeof(filter_rule_t));
1908 if (!rule)
1909 return oom_return_na();
1910 memset(rule, 0, sizeof(filter_rule_t));
1911
1912 if (equal(name, "Divert"))
1913 rule->action.divert = 1;
1914 else if (equal(name, "Split"))
1915 rule->action.split = 1;
1916 else if (equal(name, "Pass"))
1917 rule->action.pass = 1;
1918 else if (equal(name, "Block"))
1919 rule->action.block = 1;
1920 else if (equal(name, "Match"))
1921 rule->action.match = 1;
1922
1923 // precedence can only go up not down
1924 rule->action.precedence = 0;
1925
1926 int done_from = 0;
1927 int done_site = 0;
1928 int i = 0;
1929 while (i < argc) {
1930 if (equal(argv[i], "*")) {
1931 i++;
1932 }
1933 else if (equal(argv[i], "from")) {
1934 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
1935 return -1;
1936 #ifndef WITHOUT_USERAUTH
1937 if (equal(argv[i], "user") || equal(argv[i], "desc")) {
1938 // The existence of user or desc should increment precedence, all_users or not
1939 // user spec is more specific than ip spec
1940 rule->action.precedence++;
1941
1942 if (equal(argv[i], "user")) {
1943 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
1944 return -1;
1945
1946 rule->all_users = filter_is_all(argv[i]);
1947
1948 if (!rule->all_users) {
1949 rule->exact_user = filter_is_exact(argv[i]);
1950 if (filter_field_set(&rule->user, argv[i], line_num) == -1)
1951 return -1;
1952 rule->action.precedence++;
1953 }
1954 i++;
1955 }
1956
1957 if (i < argc && equal(argv[i], "desc")) {
1958 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
1959 return -1;
1960
1961 if (filter_is_all(argv[i])) {
1962 if (!rule->user) {
1963 rule->all_users = 1;
1964 }
1965 }
1966 else {
1967 rule->exact_desc = filter_is_exact(argv[i]);
1968 if (filter_field_set(&rule->desc, argv[i], line_num) == -1)
1969 return -1;
1970 rule->action.precedence++;
1971 }
1972 i++;
1973 }
1974
1975 done_from = 1;
1976 }
1977 else
1978 #endif /* !WITHOUT_USERAUTH */
1979 if (equal(argv[i], "ip")) {
1980 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
1981 return -1;
1982
1983 rule->all_conns = filter_is_all(argv[i]);
1984
1985 if (!rule->all_conns) {
1986 rule->exact_ip = filter_is_exact(argv[i]);
1987 if (filter_field_set(&rule->ip, argv[i], line_num) == -1)
1988 return -1;
1989 rule->action.precedence++;
1990 }
1991 i++;
1992 done_from = 1;
1993 }
1994 else if (equal(argv[i], "*")) {
1995 i++;
1996 }
1997 }
1998 else if (equal(argv[i], "to")) {
1999 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2000 return -1;
2001
2002 if (equal(argv[i], "ip") || equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri") ||
2003 equal(argv[i], "port")) {
2004 if (equal(argv[i], "ip") || equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri")) {
2005 char *name = argv[i];
2006
2007 if ((i = filter_arg_index_inc(i, argc, name, line_num)) == -1)
2008 return -1;
2009
2010 char *value = argv[i++];
2011
2012 if (!filter_site_set(rule, name, value, line_num))
2013 return -1;
2014
2015 rule->action.precedence++;
2016 done_site = 1;
2017 }
2018
2019 if (i < argc && equal(argv[i], "port")) {
2020 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2021 return -1;
2022
2023 rule->action.precedence++;
2024
2025 if (filter_port_set(rule, argv[i++], line_num) == -1)
2026 return -1;
2027 }
2028 }
2029 else if (equal(argv[i], "*")) {
2030 i++;
2031 }
2032 }
2033 else if (equal(argv[i], "log")) {
2034 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2035 return -1;
2036
2037 // Log actions increase rule precedence too, but this effects log actions only, not the precedence of filter actions
2038 rule->action.precedence++;
2039
2040 if (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") ||
2041 equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap")
2042 #ifndef WITHOUT_MIRROR
2043 || equal(argv[i], "mirror") || equal(argv[i], "!mirror")
2044 #endif /* !WITHOUT_MIRROR */
2045 ) {
2046 do {
2047 if (equal(argv[i], "connect"))
2048 rule->action.log_connect = 2;
2049 else if (equal(argv[i], "master"))
2050 rule->action.log_master = 2;
2051 else if (equal(argv[i], "cert"))
2052 rule->action.log_cert = 2;
2053 else if (equal(argv[i], "content"))
2054 rule->action.log_content = 2;
2055 else if (equal(argv[i], "pcap"))
2056 rule->action.log_pcap = 2;
2057 else if (equal(argv[i], "!connect"))
2058 rule->action.log_connect = 1;
2059 else if (equal(argv[i], "!master"))
2060 rule->action.log_master = 1;
2061 else if (equal(argv[i], "!cert"))
2062 rule->action.log_cert = 1;
2063 else if (equal(argv[i], "!content"))
2064 rule->action.log_content = 1;
2065 else if (equal(argv[i], "!pcap"))
2066 rule->action.log_pcap = 1;
2067 #ifndef WITHOUT_MIRROR
2068 else if (equal(argv[i], "mirror"))
2069 rule->action.log_mirror = 2;
2070 else if (equal(argv[i], "!mirror"))
2071 rule->action.log_mirror = 1;
2072 #endif /* !WITHOUT_MIRROR */
2073
2074 if (++i == argc)
2075 break;
2076 } while (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") ||
2077 equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap")
2078 #ifndef WITHOUT_MIRROR
2079 || equal(argv[i], "mirror") || equal(argv[i], "!mirror")
2080 #endif /* !WITHOUT_MIRROR */
2081 );
2082 }
2083 else if (equal(argv[i], "*")) {
2084 rule->action.log_connect = 2;
2085 rule->action.log_master = 2;
2086 rule->action.log_cert = 2;
2087 rule->action.log_content = 2;
2088 rule->action.log_pcap = 2;
2089 #ifndef WITHOUT_MIRROR
2090 rule->action.log_mirror = 2;
2091 #endif /* !WITHOUT_MIRROR */
2092 i++;
2093 }
2094 else if (equal(argv[i], "!*")) {
2095 rule->action.log_connect = 1;
2096 rule->action.log_master = 1;
2097 rule->action.log_cert = 1;
2098 rule->action.log_content = 1;
2099 rule->action.log_pcap = 1;
2100 #ifndef WITHOUT_MIRROR
2101 rule->action.log_mirror = 1;
2102 #endif /* !WITHOUT_MIRROR */
2103 i++;
2104 }
2105 }
2106 }
2107
2108 if (!done_from) {
2109 rule->all_conns = 1;
2110 }
2111 if (!done_site) {
2112 rule->dstip = strdup("");
2113 if (!rule->dstip)
2114 return oom_return_na();
2115 rule->all_dstips = 1;
2116
2117 rule->sni = strdup("");
2118 if (!rule->sni)
2119 return oom_return_na();
2120 rule->all_snis = 1;
2121
2122 rule->cn = strdup("");
2123 if (!rule->cn)
2124 return oom_return_na();
2125 rule->all_cns = 1;
2126
2127 rule->host = strdup("");
2128 if (!rule->host)
2129 return oom_return_na();
2130 rule->all_hosts = 1;
2131
2132 rule->uri = strdup("");
2133 if (!rule->uri)
2134 return oom_return_na();
2135 rule->all_uris = 1;
2136 }
2137
2138 #ifdef DEBUG_PROXY
2139 rule->action.line_num = line_num;
2140 #endif /* DEBUG_PROXY */
2141
2142 append_list(&opts->filter_rules, rule, filter_rule_t);
2143
2144 #ifdef DEBUG_OPTS
2145 filter_rule_dbg_print(rule);
2146 #endif /* DEBUG_OPTS */
2147 return 0;
2148 }
2149
2150 static int WUNRES
2151 filter_rule_parse(opts_t *opts, conn_opts_t *conn_opts, const char *name, int argc, char **argv, unsigned int line_num);
2152
2153 // Max = from(1) + user(2) + desc(2) + to(1) + sni(2) + port(2) + log(16 with macro)
2154 #define MAX_FILTER_RULE_TOKENS 26
2155
2156 static int WUNRES
filter_rule_macro_expand(opts_t * opts,conn_opts_t * conn_opts,const char * name,int argc,char ** argv,int i,unsigned int line_num)2157 filter_rule_macro_expand(opts_t *opts, conn_opts_t *conn_opts, const char *name, int argc, char **argv, int i, unsigned int line_num)
2158 {
2159 if (argv[i][0] == '$') {
2160 macro_t *macro;
2161 if ((macro = filter_macro_find(opts->macro, argv[i]))) {
2162 value_t *value = macro->value;
2163 while (value) {
2164 // Prevent infinite macro expansion, macros do not allow it, but macro expansion should detect it too
2165 if (value->value[0] == '$') {
2166 fprintf(stderr, "Invalid macro value '%s' on line %d\n", value->value, line_num);
2167 return -1;
2168 }
2169
2170 char *expanded_argv[sizeof(char *) * MAX_FILTER_RULE_TOKENS];
2171 memcpy(expanded_argv, argv, sizeof expanded_argv);
2172
2173 expanded_argv[i] = value->value;
2174
2175 if (filter_rule_parse(opts, conn_opts, name, argc, expanded_argv, line_num) == -1)
2176 return -1;
2177
2178 value = value->next;
2179 }
2180 // End of macro expansion, the caller must stop processing the rule
2181 return 1;
2182 }
2183 else {
2184 fprintf(stderr, "No such macro '%s' on line %d\n", argv[i], line_num);
2185 return -1;
2186 }
2187 }
2188 return 0;
2189 }
2190
2191 static int WUNRES
filter_rule_parse(opts_t * opts,conn_opts_t * conn_opts,const char * name,int argc,char ** argv,unsigned int line_num)2192 filter_rule_parse(opts_t *opts, conn_opts_t *conn_opts, const char *name, int argc, char **argv, unsigned int line_num)
2193 {
2194 int done_all = 0;
2195 int done_from = 0;
2196 int done_to = 0;
2197 int done_log = 0;
2198 int rv = 0;
2199 int i = 0;
2200 while (i < argc) {
2201 if (equal(argv[i], "*")) {
2202 if (done_all) {
2203 fprintf(stderr, "Only one '*' statement allowed on line %d\n", line_num);
2204 return -1;
2205 }
2206 if (++i > argc) {
2207 fprintf(stderr, "Too many arguments for '*' on line %d\n", line_num);
2208 return -1;
2209 }
2210 done_all = 1;
2211 }
2212 else if (equal(argv[i], "from")) {
2213 if (done_from) {
2214 fprintf(stderr, "Only one 'from' statement allowed on line %d\n", line_num);
2215 return -1;
2216 }
2217
2218 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2219 return -1;
2220 #ifndef WITHOUT_USERAUTH
2221 if (equal(argv[i], "user") || equal(argv[i], "desc")) {
2222 if (equal(argv[i], "user")) {
2223 if (!conn_opts->user_auth) {
2224 fprintf(stderr, "User filter requires user auth on line %d\n", line_num);
2225 return -1;
2226 }
2227
2228 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2229 return -1;
2230
2231 if (argv[i][strlen(argv[i]) - 1] == '*') {
2232 // Nothing to do for '*' or substring search for 'user*'
2233 }
2234 else if ((rv = filter_rule_macro_expand(opts, conn_opts, name, argc, argv, i, line_num)) != 0) {
2235 return rv;
2236 }
2237 else if (!sys_isuser(argv[i])) {
2238 fprintf(stderr, "No such user '%s' on line %d\n", argv[i], line_num);
2239 return -1;
2240 }
2241 i++;
2242 }
2243
2244 // It is possible to define desc without user (i.e. * or all_users), hence no 'else' here
2245 if (i < argc && equal(argv[i], "desc")) {
2246 if (!conn_opts->user_auth) {
2247 fprintf(stderr, "Desc filter requires user auth on line %d\n", line_num);
2248 return -1;
2249 }
2250
2251 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2252 return -1;
2253
2254 if (argv[i][strlen(argv[i]) - 1] == '*') {
2255 // Nothing to do for '*' or substring search for 'desc*'
2256 }
2257 else if ((rv = filter_rule_macro_expand(opts, conn_opts, name, argc, argv, i, line_num)) != 0) {
2258 return rv;
2259 }
2260 i++;
2261 }
2262
2263 done_from = 1;
2264 }
2265 else
2266 #endif /* !WITHOUT_USERAUTH */
2267 if (equal(argv[i], "ip")) {
2268 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2269 return -1;
2270
2271 if (argv[i][strlen(argv[i]) - 1] == '*') {
2272 // Nothing to do for '*' or substring search for 'ip*'
2273 }
2274 else if ((rv = filter_rule_macro_expand(opts, conn_opts, name, argc, argv, i, line_num)) != 0) {
2275 return rv;
2276 }
2277 i++;
2278 done_from = 1;
2279 }
2280 else if (equal(argv[i], "*")) {
2281 i++;
2282 }
2283 else {
2284 fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num);
2285 return -1;
2286 }
2287 }
2288 else if (equal(argv[i], "to")) {
2289 if (done_to) {
2290 fprintf(stderr, "Only one 'to' statement allowed on line %d\n", line_num);
2291 return -1;
2292 }
2293
2294 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2295 return -1;
2296
2297 if (equal(argv[i], "ip") || equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri") ||
2298 equal(argv[i], "port")) {
2299 if (equal(argv[i], "ip") || equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri")) {
2300 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2301 return -1;
2302
2303 if ((rv = filter_rule_macro_expand(opts, conn_opts, name, argc, argv, i, line_num)) != 0) {
2304 return rv;
2305 }
2306 i++;
2307 }
2308
2309 // It is possible to define port without site (i.e. * or all_sites), hence no 'else' here
2310 if (i < argc && equal(argv[i], "port")) {
2311 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2312 return -1;
2313
2314 if ((rv = filter_rule_macro_expand(opts, conn_opts, name, argc, argv, i, line_num)) != 0) {
2315 return rv;
2316 }
2317 i++;
2318 }
2319 done_to = 1;
2320 }
2321 else if (equal(argv[i], "*")) {
2322 i++;
2323 }
2324 else {
2325 fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num);
2326 return -1;
2327 }
2328 }
2329 else if (equal(argv[i], "log")) {
2330 if (done_log) {
2331 fprintf(stderr, "Only one 'log' statement allowed on line %d\n", line_num);
2332 return -1;
2333 }
2334
2335 if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1)
2336 return -1;
2337
2338 if (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") ||
2339 equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap")
2340 #ifndef WITHOUT_MIRROR
2341 || equal(argv[i], "mirror") || equal(argv[i], "!mirror")
2342 #endif /* !WITHOUT_MIRROR */
2343 || argv[i][0] == '$') {
2344 do {
2345 if ((rv = filter_rule_macro_expand(opts, conn_opts, name, argc, argv, i, line_num)) != 0) {
2346 return rv;
2347 }
2348 if (++i == argc)
2349 break;
2350 } while (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") ||
2351 equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap")
2352 #ifndef WITHOUT_MIRROR
2353 || equal(argv[i], "mirror") || equal(argv[i], "!mirror")
2354 #endif /* !WITHOUT_MIRROR */
2355 || argv[i][0] == '$');
2356
2357 done_log = 1;
2358 }
2359 else if (equal(argv[i], "*")) {
2360 i++;
2361 done_log = 1;
2362 }
2363 else if (equal(argv[i], "!*")) {
2364 i++;
2365 done_log = 1;
2366 }
2367 else {
2368 fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num);
2369 return -1;
2370 }
2371 }
2372 else {
2373 fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num);
2374 return -1;
2375 }
2376 }
2377
2378 // All checks passed and all macros expanded, if any
2379 return filter_rule_translate(opts, name, argc, argv, line_num);
2380 }
2381
2382 int
filter_rule_set(opts_t * opts,conn_opts_t * conn_opts,const char * name,char * value,unsigned int line_num)2383 filter_rule_set(opts_t *opts, conn_opts_t *conn_opts, const char *name, char *value, unsigned int line_num)
2384 {
2385 char *argv[sizeof(char *) * MAX_FILTER_RULE_TOKENS];
2386 int argc = 0;
2387 char *p, *last = NULL;
2388
2389 for ((p = strtok_r(value, " ", &last));
2390 p;
2391 (p = strtok_r(NULL, " ", &last))) {
2392 if (argc < MAX_FILTER_RULE_TOKENS) {
2393 argv[argc++] = p;
2394 } else {
2395 fprintf(stderr, "Too many arguments in filter rule on line %d\n", line_num);
2396 return -1;
2397 }
2398 }
2399
2400 return filter_rule_parse(opts, conn_opts, name, argc, argv, line_num);
2401 }
2402
2403 static int WUNRES
filter_rule_struct_translate(filter_rule_t * rule,UNUSED conn_opts_t * conn_opts,const char * name,char * value,unsigned int line_num)2404 filter_rule_struct_translate(filter_rule_t *rule, UNUSED conn_opts_t *conn_opts, const char *name, char *value, unsigned int line_num)
2405 {
2406 if (equal(name, "Action")) {
2407 if (equal(value, "Divert"))
2408 rule->action.divert = 1;
2409 else if (equal(value, "Split"))
2410 rule->action.split = 1;
2411 else if (equal(value, "Pass"))
2412 rule->action.pass = 1;
2413 else if (equal(value, "Block"))
2414 rule->action.block = 1;
2415 else if (equal(value, "Match"))
2416 rule->action.match = 1;
2417 else {
2418 fprintf(stderr, "Error in conf: Unknown Action '%s' on line %d\n", value, line_num);
2419 return -1;
2420 }
2421 }
2422 #ifndef WITHOUT_USERAUTH
2423 else if (equal(name, "User")) {
2424 if (!conn_opts->user_auth) {
2425 fprintf(stderr, "User filter requires user auth on line %d\n", line_num);
2426 return -1;
2427 }
2428
2429 if (value[strlen(value) - 1] != '*' && !sys_isuser(value)) {
2430 fprintf(stderr, "No such user '%s' on line %d\n", value, line_num);
2431 return -1;
2432 }
2433
2434 if (!rule->desc && !rule->all_users) {
2435 rule->action.precedence++;
2436 }
2437
2438 rule->all_users = filter_is_all(value);
2439
2440 if (!rule->all_users) {
2441 rule->exact_user = filter_is_exact(value);
2442 if (filter_field_set(&rule->user, value, line_num) == -1)
2443 return -1;
2444 rule->action.precedence++;
2445 }
2446 }
2447 else if (equal(name, "Desc")) {
2448 if (!conn_opts->user_auth) {
2449 fprintf(stderr, "Desc filter requires user auth on line %d\n", line_num);
2450 return -1;
2451 }
2452
2453 if (!rule->user && !rule->all_users) {
2454 rule->action.precedence++;
2455 }
2456
2457 if (filter_is_all(value)) {
2458 if (!rule->user) {
2459 rule->all_users = 1;
2460 }
2461 }
2462 else {
2463 rule->exact_desc = filter_is_exact(value);
2464 if (filter_field_set(&rule->desc, value, line_num) == -1)
2465 return -1;
2466 rule->action.precedence++;
2467 }
2468 }
2469 #endif /* !WITHOUT_USERAUTH */
2470 else if (equal(name, "SrcIp")) {
2471 rule->all_conns = filter_is_all(value);
2472
2473 if (!rule->all_conns) {
2474 rule->exact_ip = filter_is_exact(value);
2475 if (filter_field_set(&rule->ip, value, line_num) == -1)
2476 return -1;
2477 rule->action.precedence++;
2478 }
2479 }
2480 else if (equal(name, "SNI") || equal(name, "CN") || equal(name, "Host") || equal(name, "URI") || equal(name, "DstIp")) {
2481 if (!filter_site_set(rule, name, value, line_num))
2482 return -1;
2483 }
2484 else if (equal(name, "DstPort")) {
2485 rule->action.precedence++;
2486
2487 if (filter_port_set(rule, value, line_num) == -1)
2488 return -1;
2489 }
2490 else if (equal(name, "Log")) {
2491 // We don't support $macros within multi valued Log lines, i.e. cannot mix log actions with $macros
2492 // use either log actions concat with spaces or just a $macro, and no point trying to support it either
2493 #define MAX_LOG_TOKENS 14
2494 int argc = 0;
2495 char *p, *last = NULL;
2496
2497 for ((p = strtok_r(value, " ", &last));
2498 p;
2499 (p = strtok_r(NULL, " ", &last))) {
2500 if (argc < MAX_LOG_TOKENS) {
2501 argc++;
2502
2503 if (equal(p, "connect"))
2504 rule->action.log_connect = 2;
2505 else if (equal(p, "master"))
2506 rule->action.log_master = 2;
2507 else if (equal(p, "cert"))
2508 rule->action.log_cert = 2;
2509 else if (equal(p, "content"))
2510 rule->action.log_content = 2;
2511 else if (equal(p, "pcap"))
2512 rule->action.log_pcap = 2;
2513 else if (equal(p, "!connect"))
2514 rule->action.log_connect = 1;
2515 else if (equal(p, "!master"))
2516 rule->action.log_master = 1;
2517 else if (equal(p, "!cert"))
2518 rule->action.log_cert = 1;
2519 else if (equal(p, "!content"))
2520 rule->action.log_content = 1;
2521 else if (equal(p, "!pcap"))
2522 rule->action.log_pcap = 1;
2523 #ifndef WITHOUT_MIRROR
2524 else if (equal(p, "mirror"))
2525 rule->action.log_mirror = 2;
2526 else if (equal(p, "!mirror"))
2527 rule->action.log_mirror = 1;
2528 #endif /* !WITHOUT_MIRROR */
2529 else if (equal(p, "*")) {
2530 rule->action.log_connect = 2;
2531 rule->action.log_master = 2;
2532 rule->action.log_cert = 2;
2533 rule->action.log_content = 2;
2534 rule->action.log_pcap = 2;
2535 #ifndef WITHOUT_MIRROR
2536 rule->action.log_mirror = 2;
2537 #endif /* !WITHOUT_MIRROR */
2538 }
2539 else if (equal(p, "!*")) {
2540 rule->action.log_connect = 1;
2541 rule->action.log_master = 1;
2542 rule->action.log_cert = 1;
2543 rule->action.log_content = 1;
2544 rule->action.log_pcap = 1;
2545 #ifndef WITHOUT_MIRROR
2546 rule->action.log_mirror = 1;
2547 #endif /* !WITHOUT_MIRROR */
2548 }
2549 else {
2550 fprintf(stderr, "Error in conf: Unknown Log '%s' on line %d\n", p, line_num);
2551 return -1;
2552 }
2553 } else {
2554 fprintf(stderr, "Too many Log arguments in filter rule on line %d\n", line_num);
2555 return -1;
2556 }
2557 }
2558 }
2559 else if (equal(name, "ReconnectSSL")) {
2560 // Already processed by the parser
2561 }
2562 else {
2563 // This should have been handled by the parser, but in case
2564 fprintf(stderr, "Error in conf: Unknown option '%s' on line %d\n", name, line_num);
2565 return -1;
2566 }
2567 return 0;
2568 }
2569
2570 static int WUNRES
filter_rule_struct_translate_nvls(opts_t * opts,name_value_lines_t nvls[],int nvls_size,conn_opts_t * conn_opts,const char * argv0,tmp_opts_t * tmp_opts,filter_parse_state_t parse_state)2571 filter_rule_struct_translate_nvls(opts_t *opts, name_value_lines_t nvls[], int nvls_size, conn_opts_t *conn_opts,
2572 const char *argv0, tmp_opts_t *tmp_opts, filter_parse_state_t parse_state)
2573 {
2574 filter_rule_t *rule = malloc(sizeof(filter_rule_t));
2575 if (!rule)
2576 return oom_return_na();
2577 memset(rule, 0, sizeof(filter_rule_t));
2578
2579 for (int i = 0; i < nvls_size; i++) {
2580 if (filter_rule_struct_translate(rule, conn_opts, nvls[i].name, nvls[i].value, nvls[i].line_num) == -1) {
2581 filter_rule_free(rule);
2582 return -1;
2583 }
2584 }
2585
2586 if (!rule->ip
2587 #ifndef WITHOUT_USERAUTH
2588 && !rule->all_users && !rule->user && !rule->desc
2589 #endif /* !WITHOUT_USERAUTH */
2590 ) {
2591 rule->all_conns = 1;
2592 }
2593 if (!rule->dstip && !rule->sni && !rule->cn && !rule->host && !rule->uri) {
2594 rule->dstip = strdup("");
2595 if (!rule->dstip)
2596 return oom_return_na();
2597 rule->all_dstips = 1;
2598
2599 rule->sni = strdup("");
2600 if (!rule->sni)
2601 return oom_return_na();
2602 rule->all_snis = 1;
2603
2604 rule->cn = strdup("");
2605 if (!rule->cn)
2606 return oom_return_na();
2607 rule->all_cns = 1;
2608
2609 rule->host = strdup("");
2610 if (!rule->host)
2611 return oom_return_na();
2612 rule->all_hosts = 1;
2613
2614 rule->uri = strdup("");
2615 if (!rule->uri)
2616 return oom_return_na();
2617 rule->all_uris = 1;
2618 }
2619 else {
2620 // Increment precedence for dst site only once here, we allow for multi site struct rules
2621 rule->action.precedence++;
2622 }
2623
2624 // Increment precedence for log action only once here, if any specified, because otherwise
2625 // we would inc it multiple times while translating Log specifications, since we allow for multiple Log lines
2626 if (rule->action.log_connect || rule->action.log_master || rule->action.log_cert || rule->action.log_content || rule->action.log_pcap
2627 #ifndef WITHOUT_MIRROR
2628 || rule->action.log_mirror
2629 #endif /* !WITHOUT_MIRROR */
2630 ) {
2631 rule->action.precedence++;
2632 }
2633
2634 // Set conn_opts only if the rule specifies any conn option to override the global or proxyspec conn options
2635 if (parse_state.conn_opts) {
2636 rule->action.conn_opts = conn_opts_copy(conn_opts, argv0, tmp_opts);
2637 if (!rule->action.conn_opts) {
2638 filter_rule_free(rule);
2639 return oom_return_na();
2640 }
2641 }
2642
2643 #ifdef DEBUG_PROXY
2644 rule->action.line_num = tmp_opts->line_num;
2645 #endif /* DEBUG_PROXY */
2646
2647 append_list(&opts->filter_rules, rule, filter_rule_t);
2648
2649 #ifdef DEBUG_OPTS
2650 filter_rule_dbg_print(rule);
2651 #endif /* DEBUG_OPTS */
2652 return 0;
2653 }
2654
2655 static int WUNRES
filter_rule_struct_macro_expand(opts_t * opts,name_value_lines_t nvls[],int nvls_size,conn_opts_t * conn_opts,const char * argv0,tmp_opts_t * tmp_opts,filter_parse_state_t parse_state)2656 filter_rule_struct_macro_expand(opts_t *opts, name_value_lines_t nvls[], int nvls_size, conn_opts_t *conn_opts,
2657 const char *argv0, tmp_opts_t *tmp_opts, filter_parse_state_t parse_state)
2658 {
2659 for (int i = 0; i < nvls_size; i++) {
2660 if (nvls[i].value[0] == '$') {
2661 macro_t *macro;
2662 if ((macro = filter_macro_find(opts->macro, nvls[i].value))) {
2663 value_t *value = macro->value;
2664 while (value) {
2665 // Prevent infinite macro expansion, macros do not allow it, but macro expansion should detect it too
2666 if (value->value[0] == '$') {
2667 fprintf(stderr, "Invalid macro value '%s' on line %d\n", value->value, nvls[i].line_num);
2668 return -1;
2669 }
2670
2671 name_value_lines_t n[nvls_size];
2672 memcpy(n, nvls, sizeof(name_value_lines_t) * nvls_size);
2673
2674 n[i].value = value->value;
2675
2676 if (filter_rule_struct_macro_expand(opts, n, nvls_size, conn_opts, argv0, tmp_opts, parse_state) == -1)
2677 return -1;
2678
2679 value = value->next;
2680 }
2681 // End of macro expansion, the caller must stop processing the rule
2682 return 1;
2683 }
2684 else {
2685 fprintf(stderr, "No such macro '%s' on line %d\n", nvls[i].value, nvls[i].line_num);
2686 return -1;
2687 }
2688 }
2689 }
2690
2691 if (filter_rule_struct_translate_nvls(opts, nvls, nvls_size, conn_opts, argv0, tmp_opts, parse_state) == -1)
2692 return -1;
2693 return 0;
2694 }
2695
2696 static int WUNRES
filter_rule_struct_parse(name_value_lines_t nvls[],int * nvls_size,conn_opts_t * conn_opts,const char * argv0,char * name,char * value,unsigned int line_num,tmp_opts_t * tmp_opts,filter_parse_state_t * parse_state)2697 filter_rule_struct_parse(name_value_lines_t nvls[], int *nvls_size, conn_opts_t *conn_opts, const char *argv0,
2698 char *name, char *value, unsigned int line_num, tmp_opts_t *tmp_opts, filter_parse_state_t *parse_state)
2699 {
2700 // Closing brace '}' is the only option without a value
2701 // and only allowed in structured filtering rules and proxyspecs
2702 if ((!value || !strlen(value)) && !equal(name, "}")) {
2703 fprintf(stderr, "Error in conf: No value assigned for %s on line %d\n", name, line_num);
2704 return -1;
2705 }
2706
2707 if (equal(name, "}")) {
2708 #ifdef DEBUG_OPTS
2709 log_dbg_printf("FilterRule } on line %d\n", line_num);
2710 #endif /* DEBUG_OPTS */
2711 if (!parse_state->action) {
2712 fprintf(stderr, "Incomplete FilterRule on line %d\n", line_num);
2713 return -1;
2714 }
2715 // Return 2 to indicate the end of structured filter rule
2716 return 2;
2717 }
2718
2719 int rv = set_conn_opts_option(conn_opts, argv0, name, value, line_num, tmp_opts);
2720 if (rv == -1) {
2721 fprintf(stderr, "Error in conf: '%s' on line %d\n", name, line_num);
2722 return -1;
2723 } else if (rv == 0) {
2724 parse_state->conn_opts = 1;
2725 return 0;
2726 }
2727
2728 if (equal(name, "Action")) {
2729 if (parse_state->action) {
2730 fprintf(stderr, "Error in conf: Only one Action spec allowed '%s' on line %d\n", value, line_num);
2731 return -1;
2732 }
2733 parse_state->action = 1;
2734 }
2735 else if (equal(name, "User")) {
2736 if (parse_state->user) {
2737 fprintf(stderr, "Error in conf: Only one User spec allowed '%s' on line %d\n", value, line_num);
2738 return -1;
2739 }
2740 if (parse_state->srcip) {
2741 fprintf(stderr, "Error in conf: Cannot specify both SrcIp and User '%s' on line %d\n", value, line_num);
2742 return -1;
2743 }
2744 parse_state->user = 1;
2745 }
2746 else if (equal(name, "Desc")) {
2747 if (parse_state->desc) {
2748 fprintf(stderr, "Error in conf: Only one Desc spec allowed '%s' on line %d\n", value, line_num);
2749 return -1;
2750 }
2751 if (parse_state->srcip) {
2752 fprintf(stderr, "Error in conf: Cannot specify both SrcIp and Desc '%s' on line %d\n", value, line_num);
2753 return -1;
2754 }
2755 parse_state->desc = 1;
2756 }
2757 else if (equal(name, "SrcIp")) {
2758 if (parse_state->srcip) {
2759 fprintf(stderr, "Error in conf: Only one SrcIp spec allowed '%s' on line %d\n", value, line_num);
2760 return -1;
2761 }
2762 if (parse_state->user || parse_state->desc) {
2763 fprintf(stderr, "Error in conf: Cannot specify both User/Desc and SrcIp '%s' on line %d\n", value, line_num);
2764 return -1;
2765 }
2766 parse_state->srcip = 1;
2767 }
2768 else if (equal(name, "SNI")) {
2769 if (parse_state->sni) {
2770 fprintf(stderr, "Error in conf: Only one SNI spec allowed '%s' on line %d\n", value, line_num);
2771 return -1;
2772 }
2773 parse_state->sni = 1;
2774 }
2775 else if (equal(name, "CN")) {
2776 if (parse_state->cn) {
2777 fprintf(stderr, "Error in conf: Only one CN spec allowed '%s' on line %d\n", value, line_num);
2778 return -1;
2779 }
2780 parse_state->cn = 1;
2781 }
2782 else if (equal(name, "Host")) {
2783 if (parse_state->host) {
2784 fprintf(stderr, "Error in conf: Only one Host spec allowed '%s' on line %d\n", value, line_num);
2785 return -1;
2786 }
2787 parse_state->host = 1;
2788 }
2789 else if (equal(name, "URI")) {
2790 if (parse_state->uri) {
2791 fprintf(stderr, "Error in conf: Only one URI spec allowed '%s' on line %d\n", value, line_num);
2792 return -1;
2793 }
2794 parse_state->uri = 1;
2795 }
2796 else if (equal(name, "DstIp")) {
2797 if (parse_state->dstip) {
2798 fprintf(stderr, "Error in conf: Only one DstIp spec allowed '%s' on line %d\n", value, line_num);
2799 return -1;
2800 }
2801 parse_state->dstip = 1;
2802 }
2803 else if (equal(name, "DstPort")) {
2804 if (parse_state->dstport) {
2805 fprintf(stderr, "Error in conf: Only one DstPort spec allowed '%s' on line %d\n", value, line_num);
2806 return -1;
2807 }
2808 parse_state->dstport = 1;
2809 }
2810 else if (equal(name, "Log")) {
2811 // Log can be used more than once to define multiple log actions, if not using macros
2812 }
2813 else if (equal(name, "ReconnectSSL")) {
2814 if (parse_state->reconnect_ssl) {
2815 fprintf(stderr, "Error in conf: Only one ReconnectSSL spec allowed '%s' on line %d\n", value, line_num);
2816 return -1;
2817 }
2818 parse_state->reconnect_ssl = 1;
2819
2820 int yes = check_value_yesno(value, "ReconnectSSL", line_num);
2821 if (yes == -1)
2822 return -1;
2823 conn_opts->reconnect_ssl = yes;
2824 #ifdef DEBUG_OPTS
2825 log_dbg_printf("ReconnectSSL: %u\n", conn_opts->reconnect_ssl);
2826 #endif /* DEBUG_OPTS */
2827 }
2828 else {
2829 fprintf(stderr, "Error in conf: Unknown option '%s' on line %d\n", name, line_num);
2830 return -1;
2831 }
2832
2833 nvls[*nvls_size].name = strdup(name);
2834 nvls[*nvls_size].value = strdup(value);
2835 nvls[*nvls_size].line_num = line_num;
2836 (*nvls_size)++;
2837
2838 return 0;
2839 }
2840
2841 int
load_filterrule_struct(opts_t * opts,conn_opts_t * conn_opts,const char * argv0,unsigned int * line_num,FILE * f,tmp_opts_t * orig_tmp_opts)2842 load_filterrule_struct(opts_t *opts, conn_opts_t *conn_opts, const char *argv0, unsigned int *line_num, FILE *f, tmp_opts_t *orig_tmp_opts)
2843 {
2844 int retval = -1;
2845 char *name, *value;
2846 char *line = NULL;
2847 size_t line_len;
2848 int i;
2849
2850 filter_parse_state_t parse_state;
2851 memset(&parse_state, 0, sizeof(filter_parse_state_t));
2852
2853 #define MAX_NVLS_SIZE 100
2854 int nvls_size = 0;
2855 name_value_lines_t nvls[MAX_NVLS_SIZE];
2856
2857 conn_opts_t *copts = conn_opts_copy(conn_opts, argv0, orig_tmp_opts);
2858 if (!copts)
2859 return -1;
2860
2861 // Operate on a local copy of orig_tmp_opts, do not modify the orig_tmp_opts
2862 // otherwise struct filtering rules can override global or proxyspec options
2863 tmp_opts_t *tmp_opts = tmp_opts_copy(orig_tmp_opts);
2864 if (!tmp_opts) {
2865 retval = -1;
2866 goto err;
2867 }
2868
2869 #ifdef DEBUG_PROXY
2870 tmp_opts->line_num = *line_num;
2871 #endif /* DEBUG_PROXY */
2872
2873 int closing_brace = 0;
2874
2875 while (!feof(f) && !closing_brace) {
2876 if (getline(&line, &line_len, f) == -1) {
2877 break;
2878 }
2879 if (line == NULL) {
2880 fprintf(stderr, "Error in conf file: getline() returns NULL line after line %d\n", *line_num);
2881 retval = -1;
2882 goto err;
2883 }
2884 (*line_num)++;
2885
2886 /* Skip white space */
2887 for (name = line; *name == ' ' || *name == '\t'; name++);
2888
2889 /* Skip comments and empty lines */
2890 if ((name[0] == '\0') || (name[0] == '#') || (name[0] == ';') ||
2891 (name[0] == '\r') || (name[0] == '\n')) {
2892 continue;
2893 }
2894
2895 retval = get_name_value(name, &value, ' ', *line_num);
2896 if (retval == 0) {
2897 retval = filter_rule_struct_parse(nvls, &nvls_size, copts, argv0, name, value, *line_num, tmp_opts, &parse_state);
2898 }
2899 if (retval == -1) {
2900 goto err;
2901 } else if (retval == 2) {
2902 closing_brace = 1;
2903 }
2904
2905 if (nvls_size >= MAX_NVLS_SIZE) {
2906 fprintf(stderr, "Error in conf file: max allowed lines reached in struct FilterRule on line %d\n", *line_num);
2907 retval = -1;
2908 goto err;
2909 }
2910
2911 free(line);
2912 line = NULL;
2913 }
2914
2915 if (!closing_brace) {
2916 fprintf(stderr, "Error in conf file: struct FilterRule has no closing brace '}' after line %d\n", *line_num);
2917 retval = -1;
2918 goto err;
2919 }
2920
2921 if (filter_rule_struct_macro_expand(opts, nvls, nvls_size, copts, argv0, tmp_opts, parse_state) == -1) {
2922 retval = -1;
2923 goto err;
2924 }
2925
2926 retval = 0;
2927 err:
2928 conn_opts_free(copts);
2929 if (tmp_opts)
2930 tmp_opts_free(tmp_opts);
2931 for (i = 0; i < nvls_size; i++) {
2932 free(nvls[i].name);
2933 free(nvls[i].value);
2934 }
2935 if (line)
2936 free(line);
2937 return retval;
2938 }
2939
2940 static filter_port_t *
filter_port_exact_match(kbtree_t (port)* btree,char * p)2941 filter_port_exact_match(kbtree_t(port) *btree, char *p)
2942 {
2943 if (!btree)
2944 return NULL;
2945 filter_port_t **port = kb_get(port, btree, p);
2946 return port ? *port : NULL;
2947 }
2948
2949 static filter_port_t *
filter_port_substring_match(ACMachine (char)* acm,char * port)2950 filter_port_substring_match(ACMachine(char) *acm, char *port)
2951 {
2952 if (!acm)
2953 return NULL;
2954 filter_port_t *p = NULL;
2955 match_acm(acm, port, p);
2956 return p;
2957 }
2958
2959 filter_port_t *
filter_port_find(filter_site_t * site,char * p)2960 filter_port_find(filter_site_t *site, char *p)
2961 {
2962 filter_port_t *port;
2963 if ((port = filter_port_exact_match(site->port_btree, p)))
2964 return port;
2965 if ((port = filter_port_substring_match(site->port_acm, p)))
2966 return port;
2967 return site->port_all;
2968 }
2969
2970 static filter_port_t *
filter_port_substring_exact_match(ACMachine (char)* acm,char * p)2971 filter_port_substring_exact_match(ACMachine(char) *acm, char *p)
2972 {
2973 if (acm) {
2974 const ACState(char) *state = ACM_reset(acm);
2975 for (char *c = p; *c; c++) {
2976 size_t nb = ACM_match(state, *c);
2977 for (size_t j = 0; j < nb; j++) {
2978 filter_port_t *value;
2979 ACM_get_match(state, j, 0, (void **)&value);
2980 // ACM matches any substring, make sure the match is exact
2981 if (equal(value->port, p))
2982 return value;
2983 }
2984 }
2985 }
2986 return NULL;
2987 }
2988
2989 static filter_port_t *
filter_port_find_exact(filter_site_t * site,filter_rule_t * rule)2990 filter_port_find_exact(filter_site_t *site, filter_rule_t *rule)
2991 {
2992 if (rule->all_ports)
2993 return site->port_all;
2994 else if (rule->exact_port)
2995 return filter_port_exact_match(site->port_btree, rule->port);
2996 else
2997 return filter_port_substring_exact_match(site->port_acm, rule->port);
2998 }
2999
3000 static int NONNULL(1,2) WUNRES
filter_port_add(filter_site_t * site,filter_rule_t * rule,const char * argv0,tmp_opts_t * tmp_opts)3001 filter_port_add(filter_site_t *site, filter_rule_t *rule, const char *argv0, tmp_opts_t *tmp_opts)
3002 {
3003 filter_port_t *port = filter_port_find_exact(site, rule);
3004 if (!port) {
3005 port = malloc(sizeof(filter_port_t));
3006 if (!port)
3007 return oom_return_na();
3008 memset(port, 0, sizeof(filter_port_t));
3009
3010 port->port = strdup(rule->port);
3011 if (!port->port)
3012 return oom_return_na();
3013
3014 if (rule->all_ports) {
3015 site->port_all = port;
3016 }
3017 else if (rule->exact_port) {
3018 if (!site->port_btree)
3019 if (!(site->port_btree = kb_init(port, KB_DEFAULT_SIZE)))
3020 return oom_return_na();
3021
3022 kb_put(port, site->port_btree, port);
3023 }
3024 else {
3025 if (!site->port_acm)
3026 if (!(site->port_acm = ACM_create(char)))
3027 return oom_return_na();
3028
3029 Keyword(char) k;
3030 ACM_KEYWORD_SET(k, port->port, strlen(port->port));
3031 ACM_register_keyword(site->port_acm, k, port, free_port_func);
3032 }
3033 }
3034
3035 port->all_ports = rule->all_ports;
3036 port->exact = rule->exact_port;
3037
3038 // Do not override the specs of port rules at higher precedence
3039 // precedence can only go up not down
3040 if (rule->action.precedence >= port->action.precedence) {
3041 // Multiple rules can set an action for the same port, hence the bit-wise OR
3042 port->action.divert |= rule->action.divert;
3043 port->action.split |= rule->action.split;
3044 port->action.pass |= rule->action.pass;
3045 port->action.block |= rule->action.block;
3046 port->action.match |= rule->action.match;
3047
3048 // Multiple log actions can be set for the same port
3049 // Multiple rules can enable/disable or don't change a log action for the same port
3050 // 0: don't change, 1: disable, 2: enable
3051 if (rule->action.log_connect)
3052 port->action.log_connect = rule->action.log_connect;
3053 if (rule->action.log_master)
3054 port->action.log_master = rule->action.log_master;
3055 if (rule->action.log_cert)
3056 port->action.log_cert = rule->action.log_cert;
3057 if (rule->action.log_content)
3058 port->action.log_content = rule->action.log_content;
3059 if (rule->action.log_pcap)
3060 port->action.log_pcap = rule->action.log_pcap;
3061 #ifndef WITHOUT_MIRROR
3062 if (rule->action.log_mirror)
3063 port->action.log_mirror = rule->action.log_mirror;
3064 #endif /* !WITHOUT_MIRROR */
3065
3066 if (rule->action.conn_opts) {
3067 if (port->action.conn_opts)
3068 conn_opts_free(port->action.conn_opts);
3069 port->action.conn_opts = conn_opts_copy(rule->action.conn_opts, argv0, tmp_opts);
3070 if (!port->action.conn_opts)
3071 return oom_return_na();
3072 }
3073
3074 port->action.precedence = rule->action.precedence;
3075 #ifdef DEBUG_PROXY
3076 port->action.line_num = rule->action.line_num;
3077 #endif /* DEBUG_PROXY */
3078 }
3079 return 0;
3080 }
3081
3082 filter_site_t *
filter_site_exact_match(kbtree_t (site)* btree,char * s)3083 filter_site_exact_match(kbtree_t(site) *btree, char *s)
3084 {
3085 if (!btree)
3086 return NULL;
3087 filter_site_t **site = kb_get(site, btree, s);
3088 return site ? *site : NULL;
3089 }
3090
3091 filter_site_t *
filter_site_substring_match(ACMachine (char)* acm,char * site)3092 filter_site_substring_match(ACMachine(char) *acm, char *site)
3093 {
3094 if (!acm)
3095 return NULL;
3096 filter_site_t *s = NULL;
3097 match_acm(acm, site, s);
3098 return s;
3099 }
3100
3101 filter_site_t *
filter_site_find(kbtree_t (site)* btree,ACMachine (char)* acm,filter_site_t * all,char * s)3102 filter_site_find(kbtree_t(site) *btree, ACMachine(char) *acm, filter_site_t *all, char *s)
3103 {
3104 filter_site_t *site;
3105 if ((site = filter_site_exact_match(btree, s)))
3106 return site;
3107 if ((site = filter_site_substring_match(acm, s)))
3108 return site;
3109 return all;
3110 }
3111
3112 static filter_site_t *
filter_site_substring_exact_match(ACMachine (char)* acm,char * s)3113 filter_site_substring_exact_match(ACMachine(char) *acm, char *s)
3114 {
3115 if (acm) {
3116 const ACState(char) *state = ACM_reset(acm);
3117 for (char *c = s; *c; c++) {
3118 size_t nb = ACM_match(state, *c);
3119 for (size_t j = 0; j < nb; j++) {
3120 filter_site_t *value;
3121 ACM_get_match(state, j, 0, (void **)&value);
3122 // ACM matches any substring, make sure the match is exact
3123 if (equal(value->site, s))
3124 return value;
3125 }
3126 }
3127 }
3128 return NULL;
3129 }
3130
3131 static filter_site_t *
filter_site_find_exact(kbtree_t (site)* btree,ACMachine (char)* acm,filter_site_t * all,char * s,unsigned int exact_site,unsigned int all_sites)3132 filter_site_find_exact(kbtree_t(site) *btree, ACMachine(char) *acm, filter_site_t *all, char *s, unsigned int exact_site, unsigned int all_sites)
3133 {
3134 if (all_sites)
3135 return all;
3136 else if (exact_site)
3137 return filter_site_exact_match(btree, s);
3138 else
3139 return filter_site_substring_exact_match(acm, s);
3140 }
3141
3142 static int NONNULL(3) WUNRES
filter_site_add(kbtree_t (site)** btree,ACMachine (char)** acm,filter_site_t ** all,filter_rule_t * rule,char * s,unsigned int exact_site,unsigned int all_sites,const char * argv0,tmp_opts_t * tmp_opts)3143 filter_site_add(kbtree_t(site) **btree, ACMachine(char) **acm, filter_site_t **all, filter_rule_t *rule, char *s, unsigned int exact_site, unsigned int all_sites, const char *argv0, tmp_opts_t *tmp_opts)
3144 {
3145 filter_site_t *site = filter_site_find_exact(*btree, *acm, *all, s, exact_site, all_sites);
3146 if (!site) {
3147 site = malloc(sizeof(filter_site_t));
3148 if (!site)
3149 return oom_return_na();
3150 memset(site, 0, sizeof(filter_site_t));
3151
3152 site->site = strdup(s);
3153 if (!site->site)
3154 return oom_return_na();
3155
3156 if (all_sites) {
3157 *all = site;
3158 }
3159 else if (exact_site) {
3160 if (!*btree)
3161 if (!(*btree = kb_init(site, KB_DEFAULT_SIZE)))
3162 return oom_return_na();
3163
3164 kb_put(site, *btree, site);
3165 }
3166 else {
3167 if (!*acm)
3168 if (!(*acm = ACM_create(char)))
3169 return oom_return_na();
3170
3171 Keyword(char) k;
3172 ACM_KEYWORD_SET(k, site->site, strlen(site->site));
3173 ACM_register_keyword(*acm, k, site, free_site_func);
3174 }
3175 }
3176
3177 site->all_sites = all_sites;
3178 site->exact = exact_site;
3179
3180 // Do not override the specs of a site with a port rule
3181 // Port rule is added as a new port under the same site
3182 // hence 'if else', not just 'if'
3183 if (rule->port) {
3184 if (filter_port_add(site, rule, argv0, tmp_opts) == -1)
3185 return -1;
3186 }
3187 // Do not override the specs of site rules at higher precedence
3188 // precedence can only go up not down
3189 else if (rule->action.precedence >= site->action.precedence) {
3190 // Multiple rules can set an action for the same site, hence the bit-wise OR
3191 site->action.divert |= rule->action.divert;
3192 site->action.split |= rule->action.split;
3193 site->action.pass |= rule->action.pass;
3194 site->action.block |= rule->action.block;
3195 site->action.match |= rule->action.match;
3196
3197 // Multiple log actions can be set for the same site
3198 // Multiple rules can enable/disable or don't change a log action for the same site
3199 // 0: don't change, 1: disable, 2: enable
3200 if (rule->action.log_connect)
3201 site->action.log_connect = rule->action.log_connect;
3202 if (rule->action.log_master)
3203 site->action.log_master = rule->action.log_master;
3204 if (rule->action.log_cert)
3205 site->action.log_cert = rule->action.log_cert;
3206 if (rule->action.log_content)
3207 site->action.log_content = rule->action.log_content;
3208 if (rule->action.log_pcap)
3209 site->action.log_pcap = rule->action.log_pcap;
3210 #ifndef WITHOUT_MIRROR
3211 if (rule->action.log_mirror)
3212 site->action.log_mirror = rule->action.log_mirror;
3213 #endif /* !WITHOUT_MIRROR */
3214
3215 if (rule->action.conn_opts) {
3216 if (site->action.conn_opts)
3217 conn_opts_free(site->action.conn_opts);
3218 site->action.conn_opts = conn_opts_copy(rule->action.conn_opts, argv0, tmp_opts);
3219 if (!site->action.conn_opts)
3220 return oom_return_na();
3221 }
3222
3223 site->action.precedence = rule->action.precedence;
3224 #ifdef DEBUG_PROXY
3225 site->action.line_num = rule->action.line_num;
3226 #endif /* DEBUG_PROXY */
3227 }
3228 return 0;
3229 }
3230
3231 static int
filter_sitelist_add(filter_list_t * list,filter_rule_t * rule,const char * argv0,tmp_opts_t * tmp_opts)3232 filter_sitelist_add(filter_list_t *list, filter_rule_t *rule, const char *argv0, tmp_opts_t *tmp_opts)
3233 {
3234 if (rule->dstip) {
3235 if (filter_site_add(&list->ip_btree, &list->ip_acm, &list->ip_all, rule, rule->dstip, rule->exact_dstip, rule->all_dstips, argv0, tmp_opts) == -1)
3236 return -1;
3237 }
3238 if (rule->sni) {
3239 if (filter_site_add(&list->sni_btree, &list->sni_acm, &list->sni_all, rule, rule->sni, rule->exact_sni, rule->all_snis, argv0, tmp_opts) == -1)
3240 return -1;
3241 }
3242 if (rule->cn) {
3243 if (filter_site_add(&list->cn_btree, &list->cn_acm, &list->cn_all, rule, rule->cn, rule->exact_cn, rule->all_cns, argv0, tmp_opts) == -1)
3244 return -1;
3245 }
3246 if (rule->host) {
3247 if (filter_site_add(&list->host_btree, &list->host_acm, &list->host_all, rule, rule->host, rule->exact_host, rule->all_hosts, argv0, tmp_opts) == -1)
3248 return -1;
3249 }
3250 if (rule->uri) {
3251 if (filter_site_add(&list->uri_btree, &list->uri_acm, &list->uri_all, rule, rule->uri, rule->exact_uri, rule->all_uris, argv0, tmp_opts) == -1)
3252 return -1;
3253 }
3254 return 0;
3255 }
3256
3257 filter_ip_t *
filter_ip_exact_match(kbtree_t (ip)* btree,char * i)3258 filter_ip_exact_match(kbtree_t(ip) *btree, char *i)
3259 {
3260 if (!btree)
3261 return NULL;
3262 filter_ip_t **ip = kb_get(ip, btree, i);
3263 return ip ? *ip : NULL;
3264 }
3265
3266 filter_ip_t *
filter_ip_substring_match(ACMachine (char)* acm,char * ip)3267 filter_ip_substring_match(ACMachine(char) *acm, char *ip)
3268 {
3269 if (!acm)
3270 return NULL;
3271 filter_ip_t *i = NULL;
3272 match_acm(acm, ip, i);
3273 return i;
3274 }
3275
3276 static filter_ip_t *
filter_ip_substring_exact_match(ACMachine (char)* acm,char * i)3277 filter_ip_substring_exact_match(ACMachine(char) *acm, char *i)
3278 {
3279 if (acm) {
3280 const ACState(char) *state = ACM_reset(acm);
3281 for (char *c = i; *c; c++) {
3282 size_t nb = ACM_match(state, *c);
3283 for (size_t j = 0; j < nb; j++) {
3284 filter_ip_t *value;
3285 ACM_get_match(state, j, 0, (void **)&value);
3286 // ACM matches any substring, make sure the match is exact
3287 if (equal(value->ip, i))
3288 return value;
3289 }
3290 }
3291 }
3292 return NULL;
3293 }
3294
3295 static filter_ip_t *
filter_ip_find_exact(filter_t * filter,filter_rule_t * rule)3296 filter_ip_find_exact(filter_t *filter, filter_rule_t *rule)
3297 {
3298 if (rule->exact_ip)
3299 return filter_ip_exact_match(filter->ip_btree, rule->ip);
3300 else
3301 return filter_ip_substring_exact_match(filter->ip_acm, rule->ip);
3302 }
3303
3304 static void
free_ip_func(void * i)3305 free_ip_func(void *i)
3306 {
3307 free_ip((filter_ip_t **)&i);
3308 }
3309
3310 static filter_ip_t *
filter_ip_get(filter_t * filter,filter_rule_t * rule)3311 filter_ip_get(filter_t *filter, filter_rule_t *rule)
3312 {
3313 filter_ip_t *ip = filter_ip_find_exact(filter, rule);
3314 if (!ip) {
3315 ip = malloc(sizeof(filter_ip_t));
3316 if (!ip)
3317 return oom_return_na_null();
3318 memset(ip, 0, sizeof(filter_ip_t));
3319
3320 ip->list = malloc(sizeof(filter_list_t));
3321 if (!ip->list)
3322 return oom_return_na_null();
3323 memset(ip->list, 0, sizeof(filter_list_t));
3324
3325 ip->ip = strdup(rule->ip);
3326 if (!ip->ip)
3327 return oom_return_na_null();
3328
3329 ip->exact = rule->exact_ip;
3330
3331 if (rule->exact_ip) {
3332 if (!filter->ip_btree)
3333 if (!(filter->ip_btree = kb_init(ip, KB_DEFAULT_SIZE)))
3334 return oom_return_na_null();
3335
3336 kb_put(ip, filter->ip_btree, ip);
3337 }
3338 else {
3339 if (!filter->ip_acm)
3340 if (!(filter->ip_acm = ACM_create(char)))
3341 return oom_return_na_null();
3342
3343 Keyword(char) k;
3344 ACM_KEYWORD_SET(k, ip->ip, strlen(ip->ip));
3345 ACM_register_keyword(filter->ip_acm, k, ip, free_ip_func);
3346 }
3347 }
3348 return ip;
3349 }
3350
3351 #ifndef WITHOUT_USERAUTH
3352 filter_desc_t *
filter_desc_exact_match(kbtree_t (desc)* btree,char * k)3353 filter_desc_exact_match(kbtree_t(desc) *btree, char *k)
3354 {
3355 if (!btree)
3356 return NULL;
3357 filter_desc_t **desc = kb_get(desc, btree, k);
3358 return desc ? *desc : NULL;
3359 }
3360
3361 filter_desc_t *
filter_desc_substring_match(ACMachine (char)* acm,char * desc)3362 filter_desc_substring_match(ACMachine(char) *acm, char *desc)
3363 {
3364 if (!acm)
3365 return NULL;
3366 filter_desc_t *k = NULL;
3367 match_acm(acm, desc, k);
3368 return k;
3369 }
3370
3371 static filter_desc_t *
filter_desc_substring_exact_match(ACMachine (char)* acm,char * k)3372 filter_desc_substring_exact_match(ACMachine(char) *acm, char *k)
3373 {
3374 if (acm) {
3375 const ACState(char) *state = ACM_reset(acm);
3376 for (char *c = k; *c; c++) {
3377 size_t nb = ACM_match(state, *c);
3378 for (size_t j = 0; j < nb; j++) {
3379 filter_desc_t *value;
3380 ACM_get_match(state, j, 0, (void **)&value);
3381 // ACM matches any substring, make sure the match is exact
3382 if (equal(value->desc, k))
3383 return value;
3384 }
3385 }
3386 }
3387 return NULL;
3388 }
3389
3390 static filter_desc_t *
filter_desc_find_exact(filter_t * filter,filter_user_t * user,filter_rule_t * rule)3391 filter_desc_find_exact(filter_t *filter, filter_user_t *user, filter_rule_t *rule)
3392 {
3393 if (rule->exact_desc)
3394 return filter_desc_exact_match(user ? user->desc_btree : filter->desc_btree, rule->desc);
3395 else
3396 return filter_desc_substring_exact_match(user ? user->desc_acm : filter->desc_acm, rule->desc);
3397 }
3398
3399 static void
free_desc_func(void * k)3400 free_desc_func(void *k)
3401 {
3402 free_desc((filter_desc_t **)&k);
3403 }
3404
3405 static filter_desc_t *
filter_desc_get(filter_t * filter,filter_user_t * user,filter_rule_t * rule)3406 filter_desc_get(filter_t *filter, filter_user_t *user, filter_rule_t *rule)
3407 {
3408 filter_desc_t *desc = filter_desc_find_exact(filter, user, rule);
3409 if (!desc) {
3410 desc = malloc(sizeof(filter_desc_t));
3411 if (!desc)
3412 return oom_return_na_null();
3413 memset(desc, 0, sizeof(filter_desc_t));
3414
3415 desc->list = malloc(sizeof(filter_list_t));
3416 if (!desc->list)
3417 return oom_return_na_null();
3418 memset(desc->list, 0, sizeof(filter_list_t));
3419
3420 desc->desc = strdup(rule->desc);
3421 if (!desc->desc)
3422 return oom_return_na_null();
3423
3424 desc->exact = rule->exact_desc;
3425
3426 if (rule->exact_desc) {
3427 kbtree_t(desc) **btree = user ? &user->desc_btree : &filter->desc_btree;
3428 if (!*btree)
3429 if (!(*btree = kb_init(desc, KB_DEFAULT_SIZE)))
3430 return oom_return_na_null();
3431
3432 kb_put(desc, *btree, desc);
3433 }
3434 else {
3435 ACMachine(char) **acm = user ? &user->desc_acm : &filter->desc_acm;
3436 if (!*acm)
3437 if (!(*acm = ACM_create(char)))
3438 return oom_return_na_null();
3439
3440 Keyword(char) k;
3441 ACM_KEYWORD_SET(k, desc->desc, strlen(desc->desc));
3442 ACM_register_keyword(*acm, k, desc, free_desc_func);
3443 }
3444 }
3445 return desc;
3446 }
3447
3448 filter_user_t *
filter_user_exact_match(kbtree_t (user)* btree,char * u)3449 filter_user_exact_match(kbtree_t(user) *btree, char *u)
3450 {
3451 if (!btree)
3452 return NULL;
3453 filter_user_t **user = kb_get(user, btree, u);
3454 return user ? *user : NULL;
3455 }
3456
3457 filter_user_t *
filter_user_substring_match(ACMachine (char)* acm,char * user)3458 filter_user_substring_match(ACMachine(char) *acm, char *user)
3459 {
3460 if (!acm)
3461 return NULL;
3462 filter_user_t *u = NULL;
3463 match_acm(acm, user, u);
3464 return u;
3465 }
3466
3467 static filter_user_t *
filter_user_substring_exact_match(ACMachine (char)* acm,char * u)3468 filter_user_substring_exact_match(ACMachine(char) *acm, char *u)
3469 {
3470 if (acm) {
3471 const ACState(char) *state = ACM_reset(acm);
3472 for (char *c = u; *c; c++) {
3473 size_t nb = ACM_match(state, *c);
3474 for (size_t j = 0; j < nb; j++) {
3475 filter_user_t *value;
3476 ACM_get_match(state, j, 0, (void **)&value);
3477 // ACM matches any substring, make sure the match is exact
3478 if (equal(value->user, u))
3479 return value;
3480 }
3481 }
3482 }
3483 return NULL;
3484 }
3485
3486 static filter_user_t *
filter_user_find_exact(filter_t * filter,filter_rule_t * rule)3487 filter_user_find_exact(filter_t *filter, filter_rule_t *rule)
3488 {
3489 if (rule->exact_user)
3490 return filter_user_exact_match(filter->user_btree, rule->user);
3491 else
3492 return filter_user_substring_exact_match(filter->user_acm, rule->user);
3493 }
3494
3495 static void
free_user_func(void * u)3496 free_user_func(void *u)
3497 {
3498 free_user((filter_user_t **)&u);
3499 }
3500
3501 static filter_user_t *
filter_user_get(filter_t * filter,filter_rule_t * rule)3502 filter_user_get(filter_t *filter, filter_rule_t *rule)
3503 {
3504 filter_user_t *user = filter_user_find_exact(filter, rule);
3505 if (!user) {
3506 user = malloc(sizeof(filter_user_t));
3507 if (!user)
3508 return oom_return_na_null();
3509 memset(user, 0, sizeof(filter_user_t));
3510
3511 user->list = malloc(sizeof(filter_list_t));
3512 if (!user->list)
3513 return oom_return_na_null();
3514 memset(user->list, 0, sizeof(filter_list_t));
3515
3516 user->user = strdup(rule->user);
3517 if (!user->user)
3518 return oom_return_na_null();
3519
3520 user->exact = rule->exact_user;
3521
3522 if (rule->exact_user) {
3523 if (!filter->user_btree)
3524 if (!(filter->user_btree = kb_init(user, KB_DEFAULT_SIZE)))
3525 return oom_return_na_null();
3526
3527 kb_put(user, filter->user_btree, user);
3528 }
3529 else {
3530 if (!filter->user_acm)
3531 if (!(filter->user_acm = ACM_create(char)))
3532 return oom_return_na_null();
3533
3534 Keyword(char) k;
3535 ACM_KEYWORD_SET(k, user->user, strlen(user->user));
3536 ACM_register_keyword(filter->user_acm, k, user, free_user_func);
3537 }
3538 }
3539 return user;
3540 }
3541 #endif /* WITHOUT_USERAUTH */
3542
3543 /*
3544 * Translates filtering rules into data structures.
3545 * Never pass NULL as rule param.
3546 * Otherwise, we must return NULL, but NULL retval means oom.
3547 */
3548 filter_t *
filter_set(filter_rule_t * rule,const char * argv0,tmp_opts_t * tmp_opts)3549 filter_set(filter_rule_t *rule, const char *argv0, tmp_opts_t *tmp_opts)
3550 {
3551 filter_t *filter = malloc(sizeof(filter_t));
3552 if (!filter)
3553 return oom_return_na_null();
3554 memset(filter, 0, sizeof(filter_t));
3555
3556 #ifndef WITHOUT_USERAUTH
3557 filter->all_user = malloc(sizeof(filter_list_t));
3558 if (!filter->all_user)
3559 return oom_return_na_null();
3560 memset(filter->all_user, 0, sizeof(filter_list_t));
3561 #endif /* WITHOUT_USERAUTH */
3562
3563 filter->all = malloc(sizeof(filter_list_t));
3564 if (!filter->all)
3565 return oom_return_na_null();
3566 memset(filter->all, 0, sizeof(filter_list_t));
3567
3568 while (rule) {
3569 #ifndef WITHOUT_USERAUTH
3570 if (rule->user) {
3571 filter_user_t *user = filter_user_get(filter, rule);
3572 if (!user)
3573 return NULL;
3574 if (rule->desc) {
3575 filter_desc_t *desc = filter_desc_get(filter, user, rule);
3576 if (!desc)
3577 return NULL;
3578 if (filter_sitelist_add(desc->list, rule, argv0, tmp_opts) == -1)
3579 return NULL;
3580 }
3581 else {
3582 if (filter_sitelist_add(user->list, rule, argv0, tmp_opts) == -1)
3583 return NULL;
3584 }
3585 }
3586 else if (rule->desc) {
3587 filter_desc_t *desc = filter_desc_get(filter, NULL, rule);
3588 if (!desc)
3589 return NULL;
3590 if (filter_sitelist_add(desc->list, rule, argv0, tmp_opts) == -1)
3591 return NULL;
3592 }
3593 else if (rule->all_users) {
3594 if (filter_sitelist_add(filter->all_user, rule, argv0, tmp_opts) == -1)
3595 return NULL;
3596 }
3597 else
3598 #endif /* WITHOUT_USERAUTH */
3599 if (rule->ip) {
3600 filter_ip_t *ip = filter_ip_get(filter, rule);
3601 if (!ip)
3602 return NULL;
3603 if (filter_sitelist_add(ip->list, rule, argv0, tmp_opts) == -1)
3604 return NULL;
3605 }
3606 else if (rule->all_conns) {
3607 if (filter_sitelist_add(filter->all, rule, argv0, tmp_opts) == -1)
3608 return NULL;
3609 }
3610 rule = rule->next;
3611 }
3612 return filter;
3613 }
3614
3615 /* vim: set noet ft=c: */
3616