diff --git a/src/filter.c b/src/filter.c new file mode 100644 index 0000000..77d108f --- /dev/null +++ b/src/filter.c @@ -0,0 +1,2013 @@ +/*- + * SSLproxy + * + * Copyright (c) 2017-2021, Soner Tari . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opts.h" +#include "filter.h" + +#include "sys.h" +#include "log.h" +#include "util.h" + +static void +filter_value_free(value_t *value) +{ + while (value) { + value_t *next = value->next; + free(value->value); + free(value); + value = next; + } +} + +void +filter_macro_free(opts_t *opts) +{ + macro_t *macro = opts->macro; + while (macro) { + macro_t *next = macro->next; + free(macro->name); + filter_value_free(macro->value); + free(macro); + macro = next; + } + opts->macro = NULL; +} + +void +filter_rules_free(opts_t *opts) +{ + filter_rule_t *rule = opts->filter_rules; + while (rule) { + filter_rule_t *next = rule->next; + free(rule->site); + if (rule->port) + free(rule->port); + if (rule->ip) + free(rule->ip); +#ifndef WITHOUT_USERAUTH + if (rule->user) + free(rule->user); + if (rule->keyword) + free(rule->keyword); +#endif /* !WITHOUT_USERAUTH */ + free(rule); + rule = next; + } + opts->filter_rules = NULL; +} + +static void +filter_port_free(filter_port_t *port) +{ + while (port) { + filter_port_t *p = port->next; + free(port->port); + free(port); + port = p; + } +} + +static filter_site_t * +filter_site_free(filter_site_t *site) +{ + filter_site_t *s = site->next; + free(site->site); + filter_port_free(site->port); + free(site); + return s; +} + +static void +filter_list_free(filter_list_t *list) +{ + while (list->ip) + list->ip = filter_site_free(list->ip); + while (list->sni) + list->sni = filter_site_free(list->sni); + while (list->cn) + list->cn = filter_site_free(list->cn); + while (list->host) + list->host = filter_site_free(list->host); + while (list->uri) + list->uri = filter_site_free(list->uri); + free(list); +} + +void +filter_free(opts_t *opts) +{ + if (!opts->filter) + return; + + filter_t *pf = opts->filter; +#ifndef WITHOUT_USERAUTH + while (pf->user) { + while (pf->user->keyword) { + filter_list_free(pf->user->keyword->list); + filter_keyword_t *keyword = pf->user->keyword->next; + free(pf->user->keyword); + pf->user->keyword = keyword; + } + filter_list_free(pf->user->list); + filter_user_t *user = pf->user->next; + free(pf->user); + pf->user = user; + } + while (pf->keyword) { + filter_list_free(pf->keyword->list); + filter_keyword_t *keyword = pf->keyword->next; + free(pf->keyword); + pf->keyword = keyword; + } + filter_list_free(pf->all_user); +#endif /* !WITHOUT_USERAUTH */ + while (pf->ip) { + filter_list_free(pf->ip->list); + filter_ip_t *ip = pf->ip->next; + free(pf->ip); + pf->ip = ip; + } + filter_list_free(pf->all); + free(opts->filter); + opts->filter = NULL; +} + +static void +filter_macro_value_append(value_t **list, value_t *value) +{ + value_t *l = *list; + while (l) { + if (!l->next) + break; + l = l->next; + } + + if (l) + l->next = value; + else + *list = value; +} + +int +filter_macro_copy(macro_t *macro, const char *argv0, opts_t *opts) +{ + while (macro) { + macro_t *m = malloc(sizeof(macro_t)); + if (!m) + return oom_return(argv0); + memset(m, 0, sizeof(macro_t)); + + m->name = strdup(macro->name); + if (!m->name) + return oom_return(argv0); + + value_t *value = macro->value; + while (value) { + value_t *v = malloc(sizeof(value_t)); + if (!v) + return oom_return(argv0); + memset(v, 0, sizeof(value_t)); + + v->value = strdup(value->value); + if (!v->value) + return oom_return(argv0); + + filter_macro_value_append(&m->value, v); + + value = value->next; + } + + m->next = opts->macro; + opts->macro = m; + + macro = macro->next; + } + return 0; +} + +static void +filter_rule_append(filter_rule_t **list, filter_rule_t *rule) +{ + filter_rule_t *l = *list; + while (l) { + if (!l->next) + break; + l = l->next; + } + + if (l) + l->next = rule; + else + *list = rule; +} + +int +filter_rules_copy(filter_rule_t *rule, const char *argv0, opts_t *opts) +{ + while (rule) { + filter_rule_t *r = malloc(sizeof(filter_rule_t)); + if (!r) + return oom_return(argv0); + memset(r, 0, sizeof(filter_rule_t)); + + r->all_conns = rule->all_conns; + +#ifndef WITHOUT_USERAUTH + r->all_users = rule->all_users; + + if (rule->user) { + r->user = strdup(rule->user); + if (!r->user) + return oom_return(argv0); + } + + if (rule->keyword) { + r->keyword = strdup(rule->keyword); + if (!r->keyword) + return oom_return(argv0); + } +#endif /* !WITHOUT_USERAUTH */ + + if (rule->ip) { + r->ip = strdup(rule->ip); + if (!r->ip) + return oom_return(argv0); + } + + if (rule->site) { + r->site = strdup(rule->site); + if (!r->site) + return oom_return(argv0); + } + r->all_sites = rule->all_sites; + r->exact = rule->exact; + + if (rule->port) { + r->port = strdup(rule->port); + if (!r->port) + return oom_return(argv0); + } + r->all_ports = rule->all_ports; + r->exact_port = rule->exact_port; + + r->dstip = rule->dstip; + r->sni = rule->sni; + r->cn = rule->cn; + r->host = rule->host; + r->uri = rule->uri; + + // The action field is not a pointer, hence the direct assignment (copy) + r->action = rule->action; + + filter_rule_append(&opts->filter_rules, r); + + rule = rule->next; + } + return 0; +} + +static char * +filter_value_str(value_t *value) +{ + char *s = NULL; + + while (value) { + char *p; + if (asprintf(&p, "%s%s%s", STRORNONE(s), s ? ", " : "", value->value) < 0) { + goto err; + } + if (s) + free(s); + s = p; + value = value->next; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} + +char * +filter_macro_str(macro_t *macro) +{ + char *s = NULL; + + if (!macro) { + s = strdup(""); + if (!s) + return oom_return_na_null(); + goto out; + } + + while (macro) { + char *v = filter_value_str(macro->value); + + char *p; + if (asprintf(&p, "%s%smacro %s = %s", STRORNONE(s), s ? "\n" : "", macro->name, STRORNONE(v)) < 0) { + if (v) + free(v); + goto err; + } + if (v) + free(v); + if (s) + free(s); + s = p; + macro = macro->next; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} + +char * +filter_rule_str(filter_rule_t *rule) +{ + char *frs = NULL; + + if (!rule) { + frs = strdup(""); + if (!frs) + return oom_return_na_null(); + goto out; + } + + int count = 0; + while (rule) { + char *p; + if (asprintf(&p, "site=%s, %s, port=%s, %s, ip=%s" +#ifndef WITHOUT_USERAUTH + ", user=%s, keyword=%s" +#endif /* !WITHOUT_USERAUTH */ + ", all=%s" +#ifndef WITHOUT_USERAUTH + "|%s" +#endif /* !WITHOUT_USERAUTH */ + "|%s|%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" +#ifndef WITHOUT_MIRROR + "|%s" +#endif /* !WITHOUT_MIRROR */ + ", apply to=%s|%s|%s|%s|%s, precedence=%d", + rule->site, rule->exact ? "exact" : "substring", + STRORNONE(rule->port), rule->port ? (rule->exact_port ? "exact_port" : "substring_port") : "", + STRORNONE(rule->ip), +#ifndef WITHOUT_USERAUTH + STRORNONE(rule->user), STRORNONE(rule->keyword), +#endif /* !WITHOUT_USERAUTH */ + rule->all_conns ? "conns" : "", +#ifndef WITHOUT_USERAUTH + rule->all_users ? "users" : "", +#endif /* !WITHOUT_USERAUTH */ + rule->all_sites ? "sites" : "", rule->all_ports ? "ports" : "", + rule->action.divert ? "divert" : "", rule->action.split ? "split" : "", rule->action.pass ? "pass" : "", rule->action.block ? "block" : "", rule->action.match ? "match" : "", + rule->action.log_connect ? (rule->action.log_connect == 1 ? "!connect" : "connect") : "", rule->action.log_master ? (rule->action.log_master == 1 ? "!master" : "master") : "", + rule->action.log_cert ? (rule->action.log_cert == 1 ? "!cert" : "cert") : "", rule->action.log_content ? (rule->action.log_content == 1 ? "!content" : "content") : "", + rule->action.log_pcap ? (rule->action.log_pcap == 1 ? "!pcap" : "pcap") : "", +#ifndef WITHOUT_MIRROR + rule->action.log_mirror ? (rule->action.log_mirror == 1 ? "!mirror" : "mirror") : "", +#endif /* !WITHOUT_MIRROR */ + rule->dstip ? "dstip" : "", rule->sni ? "sni" : "", rule->cn ? "cn" : "", rule->host ? "host" : "", rule->uri ? "uri" : "", + rule->action.precedence) < 0) { + goto err; + } + char *nfrs; + if (asprintf(&nfrs, "%s%sfilter rule %d: %s", + STRORNONE(frs), frs ? "\n" : "", count, p) < 0) { + free(p); + goto err; + } + free(p); + if (frs) + free(frs); + frs = nfrs; + rule = rule->next; + count++; + } + goto out; +err: + if (frs) { + free(frs); + frs = NULL; + } +out: + return frs; +} + +static char * +filter_port_str(filter_port_t *port) +{ + char *s = NULL; + + int count = 0; + while (port) { + char *p; + if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" +#ifndef WITHOUT_MIRROR + "|%s" +#endif /* !WITHOUT_MIRROR */ + ", precedence=%d)", STRORNONE(s), count, + port->port, port->all_ports ? "all_ports, " : "", port->exact ? "exact" : "substring", + port->action.divert ? "divert" : "", port->action.split ? "split" : "", port->action.pass ? "pass" : "", port->action.block ? "block" : "", port->action.match ? "match" : "", + port->action.log_connect ? (port->action.log_connect == 1 ? "!connect" : "connect") : "", port->action.log_master ? (port->action.log_master == 1 ? "!master" : "master") : "", + port->action.log_cert ? (port->action.log_cert == 1 ? "!cert" : "cert") : "", port->action.log_content ? (port->action.log_content == 1 ? "!content" : "content") : "", + port->action.log_pcap ? (port->action.log_pcap == 1 ? "!pcap" : "pcap") : "", +#ifndef WITHOUT_MIRROR + port->action.log_mirror ? (port->action.log_mirror == 1 ? "!mirror" : "mirror") : "", +#endif /* !WITHOUT_MIRROR */ + port->action.precedence) < 0) { + goto err; + } + if (s) + free(s); + s = p; + port = port->next; + count++; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} + +static char * +filter_sites_str(filter_site_t *site) +{ + char *s = NULL; + + int count = 0; + while (site) { + char *ports = filter_port_str(site->port); + + char *p; + if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" +#ifndef WITHOUT_MIRROR + "|%s" +#endif /* !WITHOUT_MIRROR */ + ", precedence=%d)%s%s", STRORNONE(s), count, + site->site, site->all_sites ? "all_sites, " : "", site->exact ? "exact" : "substring", + site->action.divert ? "divert" : "", site->action.split ? "split" : "", site->action.pass ? "pass" : "", site->action.block ? "block" : "", site->action.match ? "match" : "", + site->action.log_connect ? (site->action.log_connect == 1 ? "!connect" : "connect") : "", site->action.log_master ? (site->action.log_master == 1 ? "!master" : "master") : "", + site->action.log_cert ? (site->action.log_cert == 1 ? "!cert" : "cert") : "", site->action.log_content ? (site->action.log_content == 1 ? "!content" : "content") : "", + site->action.log_pcap ? (site->action.log_pcap == 1 ? "!pcap" : "pcap") : "", +#ifndef WITHOUT_MIRROR + site->action.log_mirror ? (site->action.log_mirror == 1 ? "!mirror" : "mirror") : "", +#endif /* !WITHOUT_MIRROR */ + site->action.precedence, + ports ? "\n port:" : "", STRORNONE(ports)) < 0) { + if (ports) + free(ports); + goto err; + } + if (ports) + free(ports); + if (s) + free(s); + s = p; + site = site->next; + count++; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} + +static char * +filter_list_str(filter_list_t *list) +{ + char *p = NULL; + char *op = NULL; + + // @todo Handle oom, don't use STRORNONE() + char *s = filter_sites_str(list->ip); + if (asprintf(&p, " ip: %s", STRORNONE(s)) < 0) { + goto err; + } + if (s) + free(s); + op = p; + + s = filter_sites_str(list->sni); + if (asprintf(&p, "%s\n sni: %s", op, STRORNONE(s)) < 0) { + goto err; + } + if (s) + free(s); + free(op); + op = p; + + s = filter_sites_str(list->cn); + if (asprintf(&p, "%s\n cn: %s", op, STRORNONE(s)) < 0) { + goto err; + } + if (s) + free(s); + free(op); + op = p; + + s = filter_sites_str(list->host); + if (asprintf(&p, "%s\n host: %s", op, STRORNONE(s)) < 0) { + goto err; + } + if (s) + free(s); + free(op); + op = p; + + s = filter_sites_str(list->uri); + if (asprintf(&p, "%s\n uri: %s", op, STRORNONE(s)) < 0) { + goto err; + } + goto out; +err: + if (p) { + free(p); + p = NULL; + } +out: + if (s) + free(s); + if (op) + free(op); + return p; +} + +static char * +filter_ips_str(filter_ip_t *ip) +{ + char *s = NULL; + + int count = 0; + while (ip) { + char *list = filter_list_str(ip->list); + + char *p; + if (asprintf(&p, "%s%s ip %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, ip->ip, STRORNONE(list)) < 0) { + if (list) + free(list); + goto err; + } + if (list) + free(list); + if (s) + free(s); + s = p; + ip = ip->next; + count++; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} + +#ifndef WITHOUT_USERAUTH +static char * +filter_users_str(filter_user_t *user) +{ + char *s = NULL; + + int count = 0; + while (user) { + // Make sure the current user does not have any keyword + if (user->keyword) + goto skip; + + char *list = filter_list_str(user->list); + + char *p = NULL; + + // Make sure the user has a filter rule + // It is possible to have users without any filter rule, + // but the user exists because it has keyword filters + if (list) { + if (asprintf(&p, "%s%s user %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, user->user, list) < 0) { + free(list); + goto err; + } + free(list); + } + if (s) + free(s); + s = p; + count++; +skip: + user = user->next; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} + +static char * +filter_keywords_str(filter_keyword_t *keyword) +{ + char *s = NULL; + + int count = 0; + while (keyword) { + char *list = filter_list_str(keyword->list); + + char *p; + if (asprintf(&p, "%s%s keyword %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, keyword->keyword, STRORNONE(list)) < 0) { + if (list) + free(list); + goto err; + } + if (list) + free(list); + if (s) + free(s); + s = p; + keyword = keyword->next; + count++; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} + +static char * +filter_userkeywords_str(filter_user_t *user) +{ + char *s = NULL; + + int count = 0; + while (user) { + // Make sure the current user has a keyword + if (!user->keyword) + goto skip; + + char *list = filter_keywords_str(user->keyword); + + char *p = NULL; + if (list) { + if (asprintf(&p, "%s%s user %d %s=\n%s", STRORNONE(s), s ? "\n" : "", count, user->user, STRORNONE(list)) < 0) { + free(list); + goto err; + } + free(list); + } + if (s) + free(s); + s = p; + count++; +skip: + user = user->next; + } + goto out; +err: + if (s) { + free(s); + s = NULL; + } +out: + return s; +} +#endif /* !WITHOUT_USERAUTH */ + +char * +filter_str(filter_t *filter) +{ + char *fs = NULL; +#ifndef WITHOUT_USERAUTH + char *userkeyword_filter = NULL; + char *user_filter = NULL; + char *keyword_filter = NULL; + char *all_user_filter = NULL; +#endif /* !WITHOUT_USERAUTH */ + char *ip_filter = NULL; + char *all_filter = NULL; + + if (!filter) { + fs = strdup(""); + if (!fs) + return oom_return_na_null(); + goto out; + } + +#ifndef WITHOUT_USERAUTH + userkeyword_filter = filter_userkeywords_str(filter->user); + user_filter = filter_users_str(filter->user); + keyword_filter = filter_keywords_str(filter->keyword); + all_user_filter = filter_list_str(filter->all_user); +#endif /* !WITHOUT_USERAUTH */ + ip_filter = filter_ips_str(filter->ip); + all_filter = filter_list_str(filter->all); + + if (asprintf(&fs, "filter=>\n" +#ifndef WITHOUT_USERAUTH + "userkeyword_filter->%s%s\nuser_filter->%s%s\nkeyword_filter->%s%s\nall_user_filter->%s%s\n" +#endif /* !WITHOUT_USERAUTH */ + "ip_filter->%s%s\nall_filter->%s%s\n", +#ifndef WITHOUT_USERAUTH + userkeyword_filter ? "\n" : "", STRORNONE(userkeyword_filter), + user_filter ? "\n" : "", STRORNONE(user_filter), + keyword_filter ? "\n" : "", STRORNONE(keyword_filter), + all_user_filter ? "\n" : "", STRORNONE(all_user_filter), +#endif /* !WITHOUT_USERAUTH */ + ip_filter ? "\n" : "", STRORNONE(ip_filter), + all_filter ? "\n" : "", STRORNONE(all_filter)) < 0) { + // fs is undefined + goto err; + } + goto out; +err: + if (fs) { + free(fs); + fs = NULL; + } +out: +#ifndef WITHOUT_USERAUTH + if (userkeyword_filter) + free(userkeyword_filter); + if (user_filter) + free(user_filter); + if (keyword_filter) + free(keyword_filter); + if (all_user_filter) + free(all_user_filter); +#endif /* !WITHOUT_USERAUTH */ + if (ip_filter) + free(ip_filter); + if (all_filter) + free(all_filter); + return fs; +} + +#ifdef DEBUG_OPTS +static void +filter_rule_dbg_print(filter_rule_t *rule) +{ + log_dbg_printf("Filter rule: %s, %s, %s, %s, %s" +#ifndef WITHOUT_USERAUTH + ", %s, %s" +#endif /* !WITHOUT_USERAUTH */ + ", all=%s|" +#ifndef WITHOUT_USERAUTH + "%s|" +#endif /* !WITHOUT_USERAUTH */ + "%s|%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" +#ifndef WITHOUT_MIRROR + "|%s" +#endif /* !WITHOUT_MIRROR */ + ", apply to=%s|%s|%s|%s|%s, precedence=%d\n", + rule->site, rule->exact ? "exact" : "substring", + STRORNONE(rule->port), rule->port ? (rule->exact_port ? "exact_port" : "substring_port") : "", + STRORNONE(rule->ip), +#ifndef WITHOUT_USERAUTH + STRORNONE(rule->user), STRORNONE(rule->keyword), +#endif /* !WITHOUT_USERAUTH */ + rule->all_conns ? "conns" : "", +#ifndef WITHOUT_USERAUTH + rule->all_users ? "users" : "", +#endif /* !WITHOUT_USERAUTH */ + rule->all_sites ? "sites" : "", rule->all_ports ? "ports" : "", + rule->action.divert ? "divert" : "", rule->action.split ? "split" : "", rule->action.pass ? "pass" : "", rule->action.block ? "block" : "", rule->action.match ? "match" : "", + rule->action.log_connect ? (rule->action.log_connect == 1 ? "!connect" : "connect") : "", rule->action.log_master ? (rule->action.log_master == 1 ? "!master" : "master") : "", + rule->action.log_cert ? (rule->action.log_cert == 1 ? "!cert" : "cert") : "", rule->action.log_content ? (rule->action.log_content == 1 ? "!content" : "content") : "", + rule->action.log_pcap ? (rule->action.log_pcap == 1 ? "!pcap" : "pcap") : "", +#ifndef WITHOUT_MIRROR + rule->action.log_mirror ? (rule->action.log_mirror == 1 ? "!mirror" : "mirror") : "", +#endif /* !WITHOUT_MIRROR */ + rule->dstip ? "dstip" : "", rule->sni ? "sni" : "", rule->cn ? "cn" : "", rule->host ? "host" : "", rule->uri ? "uri" : "", + rule->action.precedence); +} +#endif /* DEBUG_OPTS */ + +#define MAX_SITE_LEN 200 + +int +filter_passsite_set(opts_t *opts, char *value, int line_num) +{ +#define MAX_PASSSITE_TOKENS 3 + + // site[*] [(clientaddr|user|*) [keyword]] + char *argv[sizeof(char *) * MAX_PASSSITE_TOKENS]; + int argc = 0; + char *p, *last = NULL; + + for ((p = strtok_r(value, " ", &last)); + p; + (p = strtok_r(NULL, " ", &last))) { + if (argc < MAX_PASSSITE_TOKENS) { + argv[argc++] = p; + } else { + fprintf(stderr, "Too many arguments in passsite option on line %d\n", line_num); + return -1; + } + } + + if (!argc) { + fprintf(stderr, "Filter rule requires at least one parameter on line %d\n", line_num); + return -1; + } + + filter_rule_t *rule = malloc(sizeof(filter_rule_t)); + if (!rule) + return oom_return_na(); + memset(rule, 0, sizeof(filter_rule_t)); + + // The for loop with strtok_r() above does not output empty strings + // So, no need to check if the length of argv[0] > 0 + size_t len = strlen(argv[0]); + + if (len > MAX_SITE_LEN) { + fprintf(stderr, "Filter site too long %zu > %d on line %d\n", len, MAX_SITE_LEN, line_num); + return -1; + } + + if (argv[0][len - 1] == '*') { + rule->exact = 0; + len--; + argv[0][len] = '\0'; + // site == "*" ? + if (len == 0) + rule->all_sites = 1; + } else { + rule->exact = 1; + } + + rule->site = strdup(argv[0]); + if (!rule->site) + return oom_return_na(); + + // precedence can only go up not down + rule->action.precedence = 0; + + if (argc == 1) { + // Apply filter rule to all conns + // Equivalent to "site *" without user auth + rule->all_conns = 1; + } + + if (argc > 1) { + if (!strcmp(argv[1], "*")) { +#ifndef WITHOUT_USERAUTH + // Apply filter rule to all users perhaps with keyword + rule->action.precedence++; + rule->all_users = 1; + } else if (sys_isuser(argv[1])) { + if (!opts->user_auth) { + fprintf(stderr, "User filter requires user auth on line %d\n", line_num); + return -1; + } + rule->action.precedence += 2; + rule->user = strdup(argv[1]); + if (!rule->user) + return oom_return_na(); +#else /* !WITHOUT_USERAUTH */ + // Apply filter rule to all conns, if USERAUTH is disabled, ip == '*' + rule->all_conns = 1; +#endif /* WITHOUT_USERAUTH */ + } else { + rule->action.precedence++; + rule->ip = strdup(argv[1]); + if (!rule->ip) + return oom_return_na(); + } + } + + if (argc > 2) { + if (rule->ip) { + fprintf(stderr, "Ip filter cannot define keyword filter" +#ifndef WITHOUT_USERAUTH + ", or user '%s' does not exist" +#endif /* !WITHOUT_USERAUTH */ + " on line %d\n", +#ifndef WITHOUT_USERAUTH + rule->ip, +#endif /* !WITHOUT_USERAUTH */ + line_num); + return -1; + } +#ifndef WITHOUT_USERAUTH + if (!opts->user_auth) { + fprintf(stderr, "Keyword filter requires user auth on line %d\n", line_num); + return -1; + } + rule->action.precedence++; + rule->keyword = strdup(argv[2]); + if (!rule->keyword) + return oom_return_na(); +#endif /* !WITHOUT_USERAUTH */ + } + + rule->action.precedence++; + rule->sni = 1; + rule->cn = 1; + rule->action.pass = 1; + + filter_rule_append(&opts->filter_rules, rule); + +#ifdef DEBUG_OPTS + filter_rule_dbg_print(rule); +#endif /* DEBUG_OPTS */ + return 0; +} + +static macro_t * +filter_macro_find(macro_t *macro, char *name) +{ + while (macro) { + if (equal(macro->name, name)) { + return macro; + } + macro = macro->next; + } + return NULL; +} + +int +filter_macro_set(opts_t *opts, char *value, int line_num) +{ +#define MAX_MACRO_TOKENS 50 + + // $name value1 [value2 [value3] ...] + char *argv[sizeof(char *) * MAX_MACRO_TOKENS]; + int argc = 0; + char *p, *last = NULL; + + for ((p = strtok_r(value, " ", &last)); + p; + (p = strtok_r(NULL, " ", &last))) { + if (argc < MAX_MACRO_TOKENS) { + argv[argc++] = p; + } else { + fprintf(stderr, "Too many arguments in macro definition on line %d\n", line_num); + return -1; + } + } + + if (argc < 2) { + fprintf(stderr, "Macro definition requires at least two arguments on line %d\n", line_num); + return -1; + } + + if (argv[0][0] != '$') { + fprintf(stderr, "Macro name should start with '$' on line %d\n", line_num); + return -1; + } + + if (filter_macro_find(opts->macro, argv[0])) { + fprintf(stderr, "Macro name '%s' already exists on line %d\n", argv[0], line_num); + return -1; + } + + macro_t *macro = malloc(sizeof(macro_t)); + if (!macro) + return oom_return_na(); + memset(macro, 0, sizeof(macro_t)); + + macro->name = strdup(argv[0]); + if (!macro->name) + return oom_return_na(); + + int i = 1; + while (i < argc) { + // Do not allow macro within macro, no recursive macro definitions + if (argv[i][0] == '$') { + fprintf(stderr, "Invalid macro value '%s' on line %d\n", argv[i], line_num); + return -1; + } + + value_t *v = malloc(sizeof(value_t)); + if (!v) + return oom_return_na(); + memset(v, 0, sizeof(value_t)); + + v->value = strdup(argv[i++]); + if (!v->value) + return oom_return_na(); + + filter_macro_value_append(¯o->value, v); + } + + macro->next = opts->macro; + opts->macro = macro; + +#ifdef DEBUG_OPTS + log_dbg_printf("Macro: %s = %s\n", macro->name, filter_value_str(macro->value)); +#endif /* DEBUG_OPTS */ + return 0; +} + +static int WUNRES +filter_site_set(filter_rule_t *rule, const char *site, int line_num) +{ + // The for loop with strtok_r() does not output empty strings + // So, no need to check if the length of site > 0 + size_t len = strlen(site); + + if (len > MAX_SITE_LEN) { + fprintf(stderr, "Filter site too long %zu > %d on line %d\n", len, MAX_SITE_LEN, line_num); + return -1; + } + + // Don't modify site, site is reused in macro expansion + rule->site = strdup(site); + if (!rule->site) + return oom_return_na(); + + if (rule->site[len - 1] == '*') { + rule->exact = 0; + len--; + rule->site[len] = '\0'; + // site == "*" ? + if (len == 0) + rule->all_sites = 1; + } else { + rule->exact = 1; + } + + // redundant? + if (equal(rule->site, "*")) + rule->all_sites = 1; + return 0; +} + +static int WUNRES +filter_port_set(filter_rule_t *rule, const char *port, int line_num) +{ +#define MAX_PORT_LEN 6 + + size_t len = strlen(port); + + if (len > MAX_PORT_LEN) { + fprintf(stderr, "Filter port too long %zu > %d on line %d\n", len, MAX_PORT_LEN, line_num); + return -1; + } + + rule->port = strdup(port); + if (!rule->port) + return oom_return_na(); + + if (rule->port[len - 1] == '*') { + rule->exact_port = 0; + len--; + rule->port[len] = '\0'; + // site == "*" ? + if (len == 0) + rule->all_ports = 1; + } else { + rule->exact_port = 1; + } + + // redundant? + if (equal(rule->port, "*")) + rule->all_ports = 1; + + if (!rule->site) { + rule->site = strdup(""); + if (!rule->site) + return oom_return_na(); + } + return 0; +} + +static int WUNRES +filter_arg_index_inc(int i, int argc, char *last, int line_num) +{ + if (i + 1 < argc) { + return i + 1; + } else { + fprintf(stderr, "Not enough arguments in filter rule after '%s' on line %d\n", last, line_num); + return -1; + } +} + +static int WUNRES +filter_rule_translate(opts_t *opts, const char *name, int argc, char **argv, int line_num) +{ + //(Divert|Split|Pass|Block|Match) + // ([from ( + // user (username|$macro|*) [desc (keyword|$macro|*)]| + // desc (keyword|$macro|*)| + // ip (clientip|$macro|*)| + // *)] + // [to ( + // sni (servername[*]|$macro|*)| + // cn (commonname[*]|$macro|*)| + // host (host[*]|$macro|*)| + // uri (uri[*]|$macro|*)| + // ip (serverip[*]|$macro|*) [port (serverport[*]|$macro|*)]| + // port (serverport[*]|$macro|*)| + // *)] + // [log ([[!]connect] [[!]master] [[!]cert] + // [[!]content] [[!]pcap] [[!]mirror] [$macro]|*|!*)] + // |*) + + filter_rule_t *rule = malloc(sizeof(filter_rule_t)); + if (!rule) + return oom_return_na(); + memset(rule, 0, sizeof(filter_rule_t)); + + if (equal(name, "Divert")) + rule->action.divert = 1; + else if (equal(name, "Split")) + rule->action.split = 1; + else if (equal(name, "Pass")) + rule->action.pass = 1; + else if (equal(name, "Block")) + rule->action.block = 1; + else if (equal(name, "Match")) + rule->action.match = 1; + + // precedence can only go up not down + rule->action.precedence = 0; + + int done_from = 0; + int done_to = 0; + int i = 0; + while (i < argc) { + if (equal(argv[i], "*")) { + i++; + } + else if (equal(argv[i], "from")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; +#ifndef WITHOUT_USERAUTH + if (equal(argv[i], "user") || equal(argv[i], "desc")) { + if (equal(argv[i], "user")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + rule->action.precedence++; + + if (equal(argv[i], "*")) { + rule->all_users = 1; + } else { + rule->action.precedence++; + rule->user = strdup(argv[i]); + if (!rule->user) + return oom_return_na(); + } + i++; + } + + if (i < argc && equal(argv[i], "desc")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + rule->action.precedence++; + rule->keyword = strdup(argv[i++]); + if (!rule->keyword) + return oom_return_na(); + } + + done_from = 1; + } + else +#endif /* !WITHOUT_USERAUTH */ + if (equal(argv[i], "ip")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if (equal(argv[i], "*")) { + rule->all_conns = 1; + } else { + rule->action.precedence++; + rule->ip = strdup(argv[i]); + if (!rule->ip) + return oom_return_na(); + } + i++; + done_from = 1; + } + else if (equal(argv[i], "*")) { + i++; + } + } + else if (equal(argv[i], "to")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if (equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri")) { + rule->action.precedence++; + if (equal(argv[i], "sni")) + rule->sni = 1; + else if (equal(argv[i], "cn")) + rule->cn = 1; + else if (equal(argv[i], "host")) + rule->host = 1; + else if (equal(argv[i], "uri")) + rule->uri = 1; + + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if (filter_site_set(rule, argv[i++], line_num) == -1) + return -1; + + done_to = 1; + } + else if (equal(argv[i], "ip") || equal(argv[i], "port")) { + rule->dstip = 1; + + if (equal(argv[i], "ip")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + // Just ip spec should not increase rule precedence + + if (filter_site_set(rule, argv[i++], line_num) == -1) + return -1; + } + + if (i < argc && equal(argv[i], "port")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + rule->action.precedence++; + + if (filter_port_set(rule, argv[i++], line_num) == -1) + return -1; + } + + done_to = 1; + } + else if (equal(argv[i], "*")) { + i++; + } + } + else if (equal(argv[i], "log")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + rule->action.precedence++; + + if (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || + equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") +#ifndef WITHOUT_MIRROR + || equal(argv[i], "mirror") || equal(argv[i], "!mirror") +#endif /* !WITHOUT_MIRROR */ + ) { + do { + if (equal(argv[i], "connect")) + rule->action.log_connect = 2; + else if (equal(argv[i], "master")) + rule->action.log_master = 2; + else if (equal(argv[i], "cert")) + rule->action.log_cert = 2; + else if (equal(argv[i], "content")) + rule->action.log_content = 2; + else if (equal(argv[i], "pcap")) + rule->action.log_pcap = 2; + else if (equal(argv[i], "!connect")) + rule->action.log_connect = 1; + else if (equal(argv[i], "!master")) + rule->action.log_master = 1; + else if (equal(argv[i], "!cert")) + rule->action.log_cert = 1; + else if (equal(argv[i], "!content")) + rule->action.log_content = 1; + else if (equal(argv[i], "!pcap")) + rule->action.log_pcap = 1; +#ifndef WITHOUT_MIRROR + else if (equal(argv[i], "mirror")) + rule->action.log_mirror = 2; + else if (equal(argv[i], "!mirror")) + rule->action.log_mirror = 1; +#endif /* !WITHOUT_MIRROR */ + + if (++i == argc) + break; + } while (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || + equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") +#ifndef WITHOUT_MIRROR + || equal(argv[i], "mirror") || equal(argv[i], "!mirror") +#endif /* !WITHOUT_MIRROR */ + ); + } + else if (equal(argv[i], "*")) { + rule->action.log_connect = 2; + rule->action.log_master = 2; + rule->action.log_cert = 2; + rule->action.log_content = 2; + rule->action.log_pcap = 2; +#ifndef WITHOUT_MIRROR + rule->action.log_mirror = 2; +#endif /* !WITHOUT_MIRROR */ + i++; + } + else if (equal(argv[i], "!*")) { + rule->action.log_connect = 1; + rule->action.log_master = 1; + rule->action.log_cert = 1; + rule->action.log_content = 1; + rule->action.log_pcap = 1; +#ifndef WITHOUT_MIRROR + rule->action.log_mirror = 1; +#endif /* !WITHOUT_MIRROR */ + i++; + } + } + } + + if (!done_from) { + rule->all_conns = 1; + } + if (!done_to) { + rule->site = strdup(""); + if (!rule->site) + return oom_return_na(); + rule->all_sites = 1; + rule->sni = 1; + rule->cn = 1; + rule->host = 1; + rule->uri = 1; + rule->dstip = 1; + } + + filter_rule_append(&opts->filter_rules, rule); + +#ifdef DEBUG_OPTS + filter_rule_dbg_print(rule); +#endif /* DEBUG_OPTS */ + return 0; +} + +static int WUNRES +filter_rule_parse(opts_t *opts, const char *name, int argc, char **argv, int line_num); + +#define MAX_FILTER_RULE_TOKENS 15 + +static int WUNRES +filter_rule_macro_expand(opts_t *opts, const char *name, int argc, char **argv, int i, int line_num) +{ + if (argv[i][0] == '$') { + macro_t *macro; + if ((macro = filter_macro_find(opts->macro, argv[i]))) { + value_t *value = macro->value; + while (value) { + // Prevent infinite macro expansion, macros do not allow it, but macro expansion should detect it too + if (value->value[0] == '$') { + fprintf(stderr, "Invalid macro value '%s' on line %d\n", value->value, line_num); + return -1; + } + + char *expanded_argv[sizeof(char *) * MAX_FILTER_RULE_TOKENS]; + memcpy(expanded_argv, argv, sizeof expanded_argv); + + expanded_argv[i] = value->value; + + if (filter_rule_parse(opts, name, argc, expanded_argv, line_num) == -1) + return -1; + + value = value->next; + } + // End of macro expansion, the caller must stop processing the rule + return 1; + } + else { + fprintf(stderr, "No such macro '%s' on line %d\n", argv[i], line_num); + return -1; + } + } + return 0; +} + +static int WUNRES +filter_rule_parse(opts_t *opts, const char *name, int argc, char **argv, int line_num) +{ + int done_all = 0; + int done_from = 0; + int done_to = 0; + int done_log = 0; + int rv = 0; + int i = 0; + while (i < argc) { + if (equal(argv[i], "*")) { + if (done_all) { + fprintf(stderr, "Only one '*' statement allowed on line %d\n", line_num); + return -1; + } + if (++i > argc) { + fprintf(stderr, "Too many arguments for '*' on line %d\n", line_num); + return -1; + } + done_all = 1; + } + else if (equal(argv[i], "from")) { + if (done_from) { + fprintf(stderr, "Only one 'from' statement allowed on line %d\n", line_num); + return -1; + } + + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; +#ifndef WITHOUT_USERAUTH + if (equal(argv[i], "user") || equal(argv[i], "desc")) { + if (equal(argv[i], "user")) { + if (!opts->user_auth) { + fprintf(stderr, "User filter requires user auth on line %d\n", line_num); + return -1; + } + + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if (equal(argv[i], "*")) { + // Nothing to do + } + else if ((rv = filter_rule_macro_expand(opts, name, argc, argv, i, line_num)) != 0) { + return rv; + } + else if (!sys_isuser(argv[i])) { + fprintf(stderr, "No such user '%s' on line %d\n", argv[i], line_num); + return -1; + } + i++; + } + + // It is possible to define desc without user (i.e. * or all_users), hence no 'else' here + if (i < argc && equal(argv[i], "desc")) { + if (!opts->user_auth) { + fprintf(stderr, "Desc filter requires user auth on line %d\n", line_num); + return -1; + } + + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if ((rv = filter_rule_macro_expand(opts, name, argc, argv, i, line_num)) != 0) { + return rv; + } + i++; + } + + done_from = 1; + } + else +#endif /* !WITHOUT_USERAUTH */ + if (equal(argv[i], "ip")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if (equal(argv[i], "*")) { + // Nothing to do + } + else if ((rv = filter_rule_macro_expand(opts, name, argc, argv, i, line_num)) != 0) { + return rv; + } + i++; + done_from = 1; + } + else if (equal(argv[i], "*")) { + i++; + } + else { + fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); + return -1; + } + } + else if (equal(argv[i], "to")) { + if (done_to) { + fprintf(stderr, "Only one 'to' statement allowed on line %d\n", line_num); + return -1; + } + + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if (equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if ((rv = filter_rule_macro_expand(opts, name, argc, argv, i, line_num)) != 0) { + return rv; + } + i++; + + done_to = 1; + } + else if (equal(argv[i], "ip") || equal(argv[i], "port")) { + if (equal(argv[i], "ip")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if ((rv = filter_rule_macro_expand(opts, name, argc, argv, i, line_num)) != 0) { + return rv; + } + i++; + } + + // It is possible to define port without ip (i.e. * or all_sites), hence no 'else' here + if (i < argc && equal(argv[i], "port")) { + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if ((rv = filter_rule_macro_expand(opts, name, argc, argv, i, line_num)) != 0) { + return rv; + } + i++; + } + + done_to = 1; + } + else if (equal(argv[i], "*")) { + i++; + } + else { + fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); + return -1; + } + } + else if (equal(argv[i], "log")) { + if (done_log) { + fprintf(stderr, "Only one 'log' statement allowed on line %d\n", line_num); + return -1; + } + + if ((i = filter_arg_index_inc(i, argc, argv[i], line_num)) == -1) + return -1; + + if (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || + equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") +#ifndef WITHOUT_MIRROR + || equal(argv[i], "mirror") || equal(argv[i], "!mirror") +#endif /* !WITHOUT_MIRROR */ + || argv[i][0] == '$') { + do { + if ((rv = filter_rule_macro_expand(opts, name, argc, argv, i, line_num)) != 0) { + return rv; + } + if (++i == argc) + break; + } while (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || + equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") +#ifndef WITHOUT_MIRROR + || equal(argv[i], "mirror") || equal(argv[i], "!mirror") +#endif /* !WITHOUT_MIRROR */ + || argv[i][0] == '$'); + + done_log = 1; + } + else if (equal(argv[i], "*")) { + i++; + done_log = 1; + } + else if (equal(argv[i], "!*")) { + i++; + done_log = 1; + } + else { + fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); + return -1; + } + } + else { + fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); + return -1; + } + } + + // All checks passed and all macros expanded, if any + return filter_rule_translate(opts, name, argc, argv, line_num); +} + +int +filter_rule_set(opts_t *opts, const char *name, char *value, int line_num) +{ + char *argv[sizeof(char *) * MAX_FILTER_RULE_TOKENS]; + int argc = 0; + char *p, *last = NULL; + + for ((p = strtok_r(value, " ", &last)); + p; + (p = strtok_r(NULL, " ", &last))) { + if (argc < MAX_FILTER_RULE_TOKENS) { + argv[argc++] = p; + } else { + fprintf(stderr, "Too many arguments in filter rule on line %d\n", line_num); + return -1; + } + } + + return filter_rule_parse(opts, name, argc, argv, line_num); +} + +static filter_port_t * +filter_port_find(filter_port_t *port, filter_rule_t *rule) +{ + while (port) { + if ((port->exact == rule->exact_port) && !strcmp(port->port, rule->port)) + break; + port = port->next; + } + return port; +} + +static int NONNULL(1,2) WUNRES +filter_port_add(filter_port_t **port, filter_rule_t *rule) +{ + filter_port_t *p = filter_port_find(*port, rule); + if (!p) { + p = malloc(sizeof(filter_port_t)); + if (!p) + return oom_return_na(); + memset(p, 0, sizeof(filter_port_t)); + p->port = strdup(rule->port); + if (!p->port) + return oom_return_na(); + + // all_ports should be at the end of the port list, it has the lowest precedence + filter_port_t *prev = NULL; + filter_port_t *l = *port; + while (l) { + if (l->all_ports) + break; + prev = l; + l = l->next; + } + + if (prev) { + p->next = prev->next; + prev->next = p; + } + else { + if (*port) + p->next = *port; + *port = p; + } + } + + // Do not override the specs of port rules at higher precedence + // precedence can only go up not down + if (rule->action.precedence >= p->action.precedence) { + p->all_ports = rule->all_ports; + p->exact = rule->exact_port; + + // Multiple rules can set an action for the same port, hence the bit-wise OR + p->action.divert |= rule->action.divert; + p->action.split |= rule->action.split; + p->action.pass |= rule->action.pass; + p->action.block |= rule->action.block; + p->action.match |= rule->action.match; + + // Multiple log actions can be set for the same port + // Multiple rules can enable/disable or don't change a log action for the same port + // 0: don't change, 1: disable, 2: enable + if (rule->action.log_connect) + p->action.log_connect = rule->action.log_connect; + if (rule->action.log_master) + p->action.log_master = rule->action.log_master; + if (rule->action.log_cert) + p->action.log_cert = rule->action.log_cert; + if (rule->action.log_content) + p->action.log_content = rule->action.log_content; + if (rule->action.log_pcap) + p->action.log_pcap = rule->action.log_pcap; +#ifndef WITHOUT_MIRROR + if (rule->action.log_mirror) + p->action.log_mirror = rule->action.log_mirror; +#endif /* !WITHOUT_MIRROR */ + + p->action.precedence = rule->action.precedence; + } + return 0; +} + +static filter_site_t * +filter_site_find(filter_site_t *site, filter_rule_t *rule) +{ + while (site) { + if ((site->exact == rule->exact) && !strcmp(site->site, rule->site)) + break; + site = site->next; + } + return site; +} + +static int NONNULL(1,2) WUNRES +filter_site_add(filter_site_t **site, filter_rule_t *rule) +{ + filter_site_t *s = filter_site_find(*site, rule); + if (!s) { + s = malloc(sizeof(filter_site_t)); + if (!s) + return oom_return_na(); + memset(s, 0, sizeof(filter_site_t)); + s->site = strdup(rule->site); + if (!s->site) + return oom_return_na(); + + // all_sites should be at the end of the site list, it has the lowest precedence + filter_site_t *prev = NULL; + filter_site_t *l = *site; + while (l) { + if (l->all_sites) + break; + prev = l; + l = l->next; + } + + if (prev) { + s->next = prev->next; + prev->next = s; + } + else { + if (*site) + s->next = *site; + *site = s; + } + } + + s->all_sites = rule->all_sites; + s->exact = rule->exact; + + // Do not override the specs of a site with a port rule + // Port rule is added as a new port under the same site + // hence 'if else', not just 'if' + if (rule->port) { + if (filter_port_add(&s->port, rule) == -1) + return -1; + } + // Do not override the specs of site rules at higher precedence + // precedence can only go up not down + else if (rule->action.precedence >= s->action.precedence) { + // Multiple rules can set an action for the same site, hence the bit-wise OR + s->action.divert |= rule->action.divert; + s->action.split |= rule->action.split; + s->action.pass |= rule->action.pass; + s->action.block |= rule->action.block; + s->action.match |= rule->action.match; + + // Multiple log actions can be set for the same site + // Multiple rules can enable/disable or don't change a log action for the same site + // 0: don't change, 1: disable, 2: enable + if (rule->action.log_connect) + s->action.log_connect = rule->action.log_connect; + if (rule->action.log_master) + s->action.log_master = rule->action.log_master; + if (rule->action.log_cert) + s->action.log_cert = rule->action.log_cert; + if (rule->action.log_content) + s->action.log_content = rule->action.log_content; + if (rule->action.log_pcap) + s->action.log_pcap = rule->action.log_pcap; +#ifndef WITHOUT_MIRROR + if (rule->action.log_mirror) + s->action.log_mirror = rule->action.log_mirror; +#endif /* !WITHOUT_MIRROR */ + + s->action.precedence = rule->action.precedence; + } + return 0; +} + +static int +filter_sitelist_add(filter_list_t *list, filter_rule_t *rule) +{ + if (rule->dstip) { + if (filter_site_add(&list->ip, rule) == -1) + return -1; + } + if (rule->sni) { + if (filter_site_add(&list->sni, rule) == -1) + return -1; + } + if (rule->cn) { + if (filter_site_add(&list->cn, rule) == -1) + return -1; + } + if (rule->host) { + if (filter_site_add(&list->host, rule) == -1) + return -1; + } + if (rule->uri) { + if (filter_site_add(&list->uri, rule) == -1) + return -1; + } + return 0; +} + +filter_ip_t * +filter_ip_find(filter_ip_t *list, char *i) +{ + while (list) { + if (!strcmp(list->ip, i)) + break; + list = list->next; + } + return list; +} + +static filter_ip_t * +filter_ip_get(filter_ip_t **list, char *i) +{ + filter_ip_t *ip = filter_ip_find(*list, i); + if (!ip) { + ip = malloc(sizeof(filter_ip_t)); + if (!ip) + return oom_return_na_null(); + memset(ip, 0, sizeof(filter_ip_t)); + + ip->list = malloc(sizeof(filter_list_t)); + if (!ip->list) + return oom_return_na_null(); + memset(ip->list, 0, sizeof(filter_list_t)); + + ip->ip = strdup(i); + if (!ip->ip) + return oom_return_na_null(); + ip->next = *list; + *list = ip; + } + return ip; +} + +#ifndef WITHOUT_USERAUTH +filter_keyword_t * +filter_keyword_find(filter_keyword_t *list, char *k) +{ + while (list) { + if (!strcmp(list->keyword, k)) + break; + list = list->next; + } + return list; +} + +static filter_keyword_t * +filter_keyword_get(filter_keyword_t **list, char *k) +{ + filter_keyword_t *keyword = filter_keyword_find(*list, k); + if (!keyword) { + keyword = malloc(sizeof(filter_keyword_t)); + if (!keyword) + return oom_return_na_null(); + memset(keyword, 0, sizeof(filter_keyword_t)); + + keyword->list = malloc(sizeof(filter_list_t)); + if (!keyword->list) + return oom_return_na_null(); + memset(keyword->list, 0, sizeof(filter_list_t)); + + keyword->keyword = strdup(k); + if (!keyword->keyword) + return oom_return_na_null(); + keyword->next = *list; + *list = keyword; + } + return keyword; +} + +filter_user_t * +filter_user_find(filter_user_t *list, char *u) +{ + while (list) { + if (!strcmp(list->user, u)) + break; + list = list->next; + } + return list; +} + +static filter_user_t * +filter_user_get(filter_user_t **list, char *u) +{ + filter_user_t *user = filter_user_find(*list, u); + if (!user) { + user = malloc(sizeof(filter_user_t)); + if (!user) + return oom_return_na_null(); + memset(user, 0, sizeof(filter_user_t)); + + user->list = malloc(sizeof(filter_list_t)); + if (!user->list) + return oom_return_na_null(); + memset(user->list, 0, sizeof(filter_list_t)); + + user->user = strdup(u); + if (!user->user) + return oom_return_na_null(); + user->next = *list; + *list = user; + } + return user; +} +#endif /* WITHOUT_USERAUTH */ + +filter_t * +filter_set(filter_rule_t *rule) +{ + filter_t *filter = malloc(sizeof(filter_t)); + if (!filter) + return oom_return_na_null(); + memset(filter, 0, sizeof(filter_t)); + +#ifndef WITHOUT_USERAUTH + filter->all_user = malloc(sizeof(filter_list_t)); + if (!filter->all_user) + return oom_return_na_null(); + memset(filter->all_user, 0, sizeof(filter_list_t)); +#endif /* WITHOUT_USERAUTH */ + + filter->all = malloc(sizeof(filter_list_t)); + if (!filter->all) + return oom_return_na_null(); + memset(filter->all, 0, sizeof(filter_list_t)); + + while (rule) { +#ifndef WITHOUT_USERAUTH + if (rule->user) { + filter_user_t *user = filter_user_get(&filter->user, rule->user); + if (!user) + return NULL; + if (rule->keyword) { + filter_keyword_t *keyword = filter_keyword_get(&user->keyword, rule->keyword); + if (!keyword) + return NULL; + if (filter_sitelist_add(keyword->list, rule) == -1) + return NULL; + } + else { + if (filter_sitelist_add(user->list, rule) == -1) + return NULL; + } + } + else if (rule->keyword) { + filter_keyword_t *keyword = filter_keyword_get(&filter->keyword, rule->keyword); + if (!keyword) + return NULL; + if (filter_sitelist_add(keyword->list, rule) == -1) + return NULL; + } + else if (rule->all_users) { + if (filter_sitelist_add(filter->all_user, rule) == -1) + return NULL; + } + else +#endif /* WITHOUT_USERAUTH */ + if (rule->ip) { + filter_ip_t *ip = filter_ip_get(&filter->ip, rule->ip); + if (!ip) + return NULL; + if (filter_sitelist_add(ip->list, rule) == -1) + return NULL; + } + else if (rule->all_conns) { + if (filter_sitelist_add(filter->all, rule) == -1) + return NULL; + } + rule = rule->next; + } + return filter; +} + +/* vim: set noet ft=c: */ diff --git a/src/filter.h b/src/filter.h new file mode 100644 index 0000000..a29fb39 --- /dev/null +++ b/src/filter.h @@ -0,0 +1,212 @@ +/*- + * SSLproxy + * + * Copyright (c) 2017-2021, Soner Tari . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FILTER_H +#define FILTER_H + +#include "opts.h" + +#define FILTER_ACTION_NONE 0x00000000U +#define FILTER_ACTION_MATCH 0x00000200U +#define FILTER_ACTION_DIVERT 0x00000400U +#define FILTER_ACTION_SPLIT 0x00000800U +#define FILTER_ACTION_PASS 0x00001000U +#define FILTER_ACTION_BLOCK 0x00002000U + +#define FILTER_LOG_CONNECT 0x00004000U +#define FILTER_LOG_MASTER 0x00008000U +#define FILTER_LOG_CERT 0x00010000U +#define FILTER_LOG_CONTENT 0x00020000U +#define FILTER_LOG_PCAP 0x00040000U +#define FILTER_LOG_MIRROR 0x00080000U + +#define FILTER_LOG_NOCONNECT 0x00100000U +#define FILTER_LOG_NOMASTER 0x00200000U +#define FILTER_LOG_NOCERT 0x00400000U +#define FILTER_LOG_NOCONTENT 0x00800000U +#define FILTER_LOG_NOPCAP 0x01000000U +#define FILTER_LOG_NOMIRROR 0x02000000U + +#define FILTER_PRECEDENCE 0x000000FFU + +typedef struct value { + char *value; + struct value *next; +} value_t; + +typedef struct macro { + char *name; + struct value *value; + struct macro *next; +} macro_t; + +typedef struct filter_action { + // Filter action + unsigned int divert : 1; + unsigned int split : 1; + unsigned int pass : 1; + unsigned int block : 1; + unsigned int match : 1; + + // Log action, two bits + // 0: don't change, 1: disable, 2: enable + unsigned int log_connect : 2; + unsigned int log_master : 2; + unsigned int log_cert : 2; + unsigned int log_content : 2; + unsigned int log_pcap : 2; +#ifndef WITHOUT_MIRROR + unsigned int log_mirror : 2; +#endif /* !WITHOUT_MIRROR */ + + // Precedence is used in rule application + // More specific rules have higher precedence + unsigned int precedence; +} filter_action_t; + +typedef struct filter_rule { + // from: source filter + unsigned int all_conns : 1; /* 1 to apply to all src ips and users */ + +#ifndef WITHOUT_USERAUTH + unsigned int all_users : 1; /* 1 to apply to all users */ + + char *user; + char *keyword; +#endif /* !WITHOUT_USERAUTH */ + char *ip; + + // to: target filter + char *site; + unsigned int all_sites : 1; /* 1 to match all sites == '*' */ + unsigned int exact : 1; /* 1 for exact, 0 for substring match */ + + // Used with dstip filters only, i.e. if the site is an ip address + // This is not for the src ip in the 'from' part of rules + char *port; + unsigned int all_ports : 1; /* 1 to match all ports == '*' */ + unsigned int exact_port : 1; /* 1 for exact, 0 for substring match */ + + // Conn field to apply filter to + unsigned int dstip : 1; /* 1 to apply to dst ip */ + unsigned int host : 1; /* 1 to apply to http host */ + unsigned int uri : 1; /* 1 to apply to http uri */ + unsigned int sni : 1; /* 1 to apply to sni */ + unsigned int cn : 1; /* 1 to apply to common names */ + + struct filter_action action; + + struct filter_rule *next; +} filter_rule_t; + +typedef struct filter_port { + char *port; + unsigned int all_ports : 1; + unsigned int exact : 1; + + struct filter_action action; + + struct filter_port *next; +} filter_port_t; + +typedef struct filter_site { + char *site; + unsigned int all_sites : 1; + unsigned int exact : 1; + + // Used with dstip filters only, i.e. if the site is an ip address + struct filter_port *port; + + struct filter_action action; + + struct filter_site *next; +} filter_site_t; + +typedef struct filter_list { + struct filter_site *ip; + struct filter_site *sni; + struct filter_site *cn; + struct filter_site *host; + struct filter_site *uri; +} filter_list_t; + +typedef struct filter_ip { + char *ip; + struct filter_list *list; + struct filter_ip *next; +} filter_ip_t; + +#ifndef WITHOUT_USERAUTH +typedef struct filter_keyword { + char *keyword; + struct filter_list *list; + struct filter_keyword *next; +} filter_keyword_t; + +typedef struct filter_user { + char *user; + struct filter_list *list; + struct filter_keyword *keyword; + struct filter_user *next; +} filter_user_t; +#endif /* !WITHOUT_USERAUTH */ + +typedef struct filter { +#ifndef WITHOUT_USERAUTH + struct filter_user *user; + struct filter_keyword *keyword; + struct filter_list *all_user; +#endif /* !WITHOUT_USERAUTH */ + struct filter_ip *ip; + struct filter_list *all; +} filter_t; + +void filter_macro_free(opts_t *); +void filter_rules_free(opts_t *) NONNULL(1); +void filter_free(opts_t *); + +int filter_macro_copy(macro_t *, const char *, opts_t *) NONNULL(2,3) WUNRES; +int filter_rules_copy(filter_rule_t *, const char *, opts_t *) NONNULL(2,3) WUNRES; + +char *filter_macro_str(macro_t *); +char *filter_rule_str(filter_rule_t *); +char *filter_str(filter_t *); + +int filter_passsite_set(opts_t *, char *, int) WUNRES; +int filter_macro_set(opts_t *, char *, int) WUNRES; + +filter_ip_t *filter_ip_find(filter_ip_t *, char *) NONNULL(2); +#ifndef WITHOUT_USERAUTH +filter_keyword_t *filter_keyword_find(filter_keyword_t *, char *) NONNULL(2); +filter_user_t *filter_user_find(filter_user_t *, char *) NONNULL(2); +#endif /* !WITHOUT_USERAUTH */ +int filter_rule_set(opts_t *, const char *, char *, int) NONNULL(1,2,3) WUNRES; +filter_t *filter_set(filter_rule_t *); + +#endif /* !FILTER_H */ + +/* vim: set noet ft=c: */ diff --git a/src/main.c b/src/main.c index fd5bdfc..104f1d2 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,7 @@ #endif /* __APPLE__ */ #include "opts.h" +#include "filter.h" #include "proxy.h" #include "privsep.h" #include "ssl.h" @@ -615,7 +616,7 @@ main(int argc, char *argv[]) for (proxyspec_t *spec = global->spec; spec; spec = spec->next) { if (spec->opts->filter_rules) { - spec->opts->filter = opts_set_filter(spec->opts->filter_rules); + spec->opts->filter = filter_set(spec->opts->filter_rules); if (!spec->opts->filter) oom_die(argv0); } @@ -932,9 +933,9 @@ main(int argc, char *argv[]) // Free filter rules in linked lists, not needed anymore // We use filter in conn handling, not filter rule lists for (proxyspec_t *spec = global->spec; spec; spec = spec->next) { - opts_free_filter_rules(spec->opts); + filter_rules_free(spec->opts); } - opts_free_filter_rules(global->opts); + filter_rules_free(global->opts); /* * Initialize as much as possible before daemon() in order to be diff --git a/src/opts.c b/src/opts.c index 6c0f804..1cb65e1 100644 --- a/src/opts.c +++ b/src/opts.c @@ -28,6 +28,7 @@ */ #include "opts.h" +#include "filter.h" #include "sys.h" #include "log.h" @@ -61,28 +62,28 @@ typedef struct spec_addrs { * Returning -1 instead of calling exit() is necessary for reporting the * include file the error has occurred in. */ -static int WUNRES +int oom_return(const char *argv0) { fprintf(stderr, "%s: out of memory\n", argv0); return -1; } -static void * WUNRES +void * oom_return_null(const char *argv0) { fprintf(stderr, "%s: out of memory\n", argv0); return NULL; } -static int WUNRES +int oom_return_na() { fprintf(stderr, "Out of memory\n"); return -1; } -static void * WUNRES +void * oom_return_na_null() { fprintf(stderr, "Out of memory\n"); @@ -185,130 +186,6 @@ free_userlist(userlist_t *ul) } #endif /* !WITHOUT_USERAUTH */ -static void -opts_free_values(value_t *value) -{ - while (value) { - value_t *next = value->next; - free(value->value); - free(value); - value = next; - } -} - -static void -opts_free_macros(opts_t *opts) -{ - macro_t *macro = opts->macro; - while (macro) { - macro_t *next = macro->next; - free(macro->name); - opts_free_values(macro->value); - free(macro); - macro = next; - } - opts->macro = NULL; -} - -void -opts_free_filter_rules(opts_t *opts) -{ - filter_rule_t *rule = opts->filter_rules; - while (rule) { - filter_rule_t *next = rule->next; - free(rule->site); - if (rule->port) - free(rule->port); - if (rule->ip) - free(rule->ip); -#ifndef WITHOUT_USERAUTH - if (rule->user) - free(rule->user); - if (rule->keyword) - free(rule->keyword); -#endif /* !WITHOUT_USERAUTH */ - free(rule); - rule = next; - } - opts->filter_rules = NULL; -} - -static void -opts_free_filter_port(filter_port_t *port) -{ - while (port) { - filter_port_t *p = port->next; - free(port->port); - free(port); - port = p; - } -} - -static filter_site_t * -opts_free_filter_site(filter_site_t *site) -{ - filter_site_t *s = site->next; - free(site->site); - opts_free_filter_port(site->port); - free(site); - return s; -} - -static void -opts_free_filter_list(filter_list_t *list) -{ - while (list->ip) - list->ip = opts_free_filter_site(list->ip); - while (list->sni) - list->sni = opts_free_filter_site(list->sni); - while (list->cn) - list->cn = opts_free_filter_site(list->cn); - while (list->host) - list->host = opts_free_filter_site(list->host); - while (list->uri) - list->uri = opts_free_filter_site(list->uri); - free(list); -} - -void -opts_free_filter(opts_t *opts) -{ - if (!opts->filter) - return; - - filter_t *pf = opts->filter; -#ifndef WITHOUT_USERAUTH - while (pf->user) { - while (pf->user->keyword) { - opts_free_filter_list(pf->user->keyword->list); - filter_keyword_t *keyword = pf->user->keyword->next; - free(pf->user->keyword); - pf->user->keyword = keyword; - } - opts_free_filter_list(pf->user->list); - filter_user_t *user = pf->user->next; - free(pf->user); - pf->user = user; - } - while (pf->keyword) { - opts_free_filter_list(pf->keyword->list); - filter_keyword_t *keyword = pf->keyword->next; - free(pf->keyword); - pf->keyword = keyword; - } - opts_free_filter_list(pf->all_user); -#endif /* !WITHOUT_USERAUTH */ - while (pf->ip) { - opts_free_filter_list(pf->ip->list); - filter_ip_t *ip = pf->ip->next; - free(pf->ip); - pf->ip = ip; - } - opts_free_filter_list(pf->all); - free(opts->filter); - opts->filter = NULL; -} - void opts_free(opts_t *opts) { @@ -351,11 +228,11 @@ opts_free(opts_t *opts) free_userlist(opts->passusers); #endif /* !WITHOUT_USERAUTH */ - opts_free_macros(opts); + filter_macro_free(opts); - // No need to call opts_free_filter_rules() here, filter rules are freed during startup - opts_free_filter_rules(opts); - opts_free_filter(opts); + // No need to call filter_rules_free() here, filter rules are freed during startup + filter_rules_free(opts); + filter_free(opts); memset(opts, 0, sizeof(opts_t)); free(opts); @@ -691,38 +568,6 @@ opts_proto_dbg_dump(opts_t *opts) return s; } -static void -opts_append_to_filter_rules(filter_rule_t **list, filter_rule_t *rule) -{ - filter_rule_t *l = *list; - while (l) { - if (!l->next) - break; - l = l->next; - } - - if (l) - l->next = rule; - else - *list = rule; -} - -static void -opts_append_to_macro_values(value_t **list, value_t *value) -{ - value_t *l = *list; - while (l) { - if (!l->next) - break; - l = l->next; - } - - if (l) - l->next = value; - else - *list = value; -} - #ifndef WITHOUT_USERAUTH static int WUNRES opts_set_user_auth_url(opts_t *opts, const char * argv0, const char *optarg) @@ -740,10 +585,10 @@ opts_set_user_auth_url(opts_t *opts, const char * argv0, const char *optarg) #endif /* !WITHOUT_USERAUTH */ static opts_t * WUNRES -clone_global_opts(global_t *global, const char *argv0, tmp_global_opts_t *tmp_global_opts) +global_opts_copy(global_t *global, const char *argv0, tmp_global_opts_t *tmp_global_opts) { #ifdef DEBUG_OPTS - log_dbg_printf("Clone global opts\n"); + log_dbg_printf("Copy global opts\n"); #endif /* DEBUG_OPTS */ opts_t *opts = opts_new(); @@ -873,98 +718,12 @@ clone_global_opts(global_t *global, const char *argv0, tmp_global_opts_t *tmp_gl } #endif /* !WITHOUT_USERAUTH */ - macro_t *macro = global->opts->macro; - while (macro) { - macro_t *m = malloc(sizeof(macro_t)); - if (!m) - return oom_return_null(argv0); - memset(m, 0, sizeof(macro_t)); - - m->name = strdup(macro->name); - if (!m->name) - return oom_return_null(argv0); - - value_t *value = macro->value; - while (value) { - value_t *v = malloc(sizeof(value_t)); - if (!v) - return oom_return_null(argv0); - memset(v, 0, sizeof(value_t)); - - v->value = strdup(value->value); - if (!v->value) - return oom_return_null(argv0); - - opts_append_to_macro_values(&m->value, v); - - value = value->next; - } - - m->next = opts->macro; - opts->macro = m; - - macro = macro->next; - } - - filter_rule_t *rule = global->opts->filter_rules; - while (rule) { - filter_rule_t *r = malloc(sizeof(filter_rule_t)); - if (!r) - return oom_return_null(argv0); - memset(r, 0, sizeof(filter_rule_t)); - - r->all_conns = rule->all_conns; - -#ifndef WITHOUT_USERAUTH - r->all_users = rule->all_users; - - if (rule->user) { - r->user = strdup(rule->user); - if (!r->user) - return oom_return_null(argv0); - } - - if (rule->keyword) { - r->keyword = strdup(rule->keyword); - if (!r->keyword) - return oom_return_null(argv0); - } -#endif /* !WITHOUT_USERAUTH */ - - if (rule->ip) { - r->ip = strdup(rule->ip); - if (!r->ip) - return oom_return_null(argv0); - } - - if (rule->site) { - r->site = strdup(rule->site); - if (!r->site) - return oom_return_null(argv0); - } - r->all_sites = rule->all_sites; - r->exact = rule->exact; - - if (rule->port) { - r->port = strdup(rule->port); - if (!r->port) - return oom_return_null(argv0); - } - r->all_ports = rule->all_ports; - r->exact_port = rule->exact_port; - - r->dstip = rule->dstip; - r->sni = rule->sni; - r->cn = rule->cn; - r->host = rule->host; - r->uri = rule->uri; - - r->action = rule->action; + if (filter_macro_copy(global->opts->macro, argv0, opts) == -1) + return oom_return_null(argv0); - opts_append_to_filter_rules(&opts->filter_rules, r); + if (filter_rules_copy(global->opts->filter_rules, argv0, opts) == -1) + return oom_return_null(argv0); - rule = rule->next; - } return opts; } @@ -975,7 +734,7 @@ proxyspec_new(global_t *global, const char *argv0, tmp_global_opts_t *tmp_global if (!spec) return oom_return_null(argv0); memset(spec, 0, sizeof(proxyspec_t)); - spec->opts = clone_global_opts(global, argv0, tmp_global_opts); + spec->opts = global_opts_copy(global, argv0, tmp_global_opts); if (!spec->opts) return NULL; return spec; @@ -1298,2593 +1057,878 @@ proxyspec_parse(int *argc, char **argv[], const char *natengine, global_t *globa return 0; } +#ifndef WITHOUT_USERAUTH static char * -value_str(value_t *value) -{ - char *s = NULL; - - while (value) { - char *p; - if (asprintf(&p, "%s%s%s", STRORNONE(s), s ? ", " : "", value->value) < 0) { - goto err; - } - if (s) - free(s); - s = p; - value = value->next; - } - goto out; -err: - if (s) { - free(s); - s = NULL; - } -out: - return s; -} - -static char * -macro_str(macro_t *macro) +users_str(userlist_t *u) { - char *s = NULL; + char *us = NULL; - if (!macro) { - s = strdup(""); - if (!s) + if (!u) { + us = strdup(""); + if (!us) return oom_return_na_null(); goto out; } - while (macro) { - char *p; - if (asprintf(&p, "%s%smacro %s = %s", STRORNONE(s), s ? "\n" : "", macro->name, value_str(macro->value)) < 0) { + while (u) { + char *nus; + if (asprintf(&nus, "%s%s%s", STRORNONE(us), us ? "," : "", u->user) < 0) { goto err; } - if (s) - free(s); - s = p; - macro = macro->next; + + if (us) + free(us); + us = nus; + u = u->next; } goto out; err: - if (s) { - free(s); - s = NULL; + if (us) { + free(us); + us = NULL; } out: - return s; + return us; } +#endif /* !WITHOUT_USERAUTH */ -char * -filter_rule_str(filter_rule_t *rule) +static char * +opts_str(opts_t *opts) { + char *s = NULL; + char *proto_dump = NULL; + char *ms = NULL; char *frs = NULL; + char *fs = NULL; - if (!rule) { - frs = strdup(""); - if (!frs) - return oom_return_na_null(); +#ifndef WITHOUT_USERAUTH + char *du = NULL; + char *pu = NULL; + + du = users_str(opts->divertusers); + if (!du) goto out; - } - int count = 0; - while (rule) { - char *p; - if (asprintf(&p, "site=%s, %s, port=%s, %s, ip=%s" -#ifndef WITHOUT_USERAUTH - ", user=%s, keyword=%s" + pu = users_str(opts->passusers); + if (!pu) + goto out; #endif /* !WITHOUT_USERAUTH */ - ", all=%s" + + ms = filter_macro_str(opts->macro); + if (!ms) + goto out; + + frs = filter_rule_str(opts->filter_rules); + if (!frs) + goto out; + + fs = filter_str(opts->filter); + if (!fs) + goto out; + + proto_dump = opts_proto_dbg_dump(opts); + if (!proto_dump) + goto out; + + if (asprintf(&s, "opts=%s%s" +#ifdef HAVE_SSLV2 + "%s" +#endif /* HAVE_SSLV2 */ +#ifdef HAVE_SSLV3 + "%s" +#endif /* HAVE_SSLV3 */ +#ifdef HAVE_TLSV10 + "%s" +#endif /* HAVE_TLSV10 */ +#ifdef HAVE_TLSV11 + "%s" +#endif /* HAVE_TLSV11 */ +#ifdef HAVE_TLSV12 + "%s" +#endif /* HAVE_TLSV12 */ +#ifdef HAVE_TLSV13 + "%s" +#endif /* HAVE_TLSV13 */ + "%s%s|%s|%s" +#ifndef OPENSSL_NO_ECDH + "|%s" +#endif /* !OPENSSL_NO_ECDH */ + "|%s%s%s%s%s" #ifndef WITHOUT_USERAUTH - "|%s" + "%s|%s|%d|%s|%s" #endif /* !WITHOUT_USERAUTH */ - "|%s|%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" -#ifndef WITHOUT_MIRROR - "|%s" -#endif /* !WITHOUT_MIRROR */ - ", apply to=%s|%s|%s|%s|%s, precedence=%d", - rule->site, rule->exact ? "exact" : "substring", - STRORNONE(rule->port), rule->port ? (rule->exact_port ? "exact_port" : "substring_port") : "", - STRORNONE(rule->ip), + "%s|%d\n%s%s%s%s%s%s%s", + (opts->divert ? "divert" : "split"), + (!opts->sslcomp ? "|no sslcomp" : ""), +#ifdef HAVE_SSLV2 + (opts->no_ssl2 ? "|no_ssl2" : ""), +#endif /* HAVE_SSLV2 */ +#ifdef HAVE_SSLV3 + (opts->no_ssl3 ? "|no_ssl3" : ""), +#endif /* HAVE_SSLV3 */ +#ifdef HAVE_TLSV10 + (opts->no_tls10 ? "|no_tls10" : ""), +#endif /* HAVE_TLSV10 */ +#ifdef HAVE_TLSV11 + (opts->no_tls11 ? "|no_tls11" : ""), +#endif /* HAVE_TLSV11 */ +#ifdef HAVE_TLSV12 + (opts->no_tls12 ? "|no_tls12" : ""), +#endif /* HAVE_TLSV12 */ +#ifdef HAVE_TLSV13 + (opts->no_tls13 ? "|no_tls13" : ""), +#endif /* HAVE_TLSV13 */ + (opts->passthrough ? "|passthrough" : ""), + (opts->deny_ocsp ? "|deny_ocsp" : ""), + (opts->ciphers ? opts->ciphers : "no ciphers"), + (opts->ciphersuites ? opts->ciphersuites : "no ciphersuites"), +#ifndef OPENSSL_NO_ECDH + (opts->ecdhcurve ? opts->ecdhcurve : "no ecdhcurve"), +#endif /* !OPENSSL_NO_ECDH */ + (opts->leafcrlurl ? opts->leafcrlurl : "no leafcrlurl"), + (opts->remove_http_accept_encoding ? "|remove_http_accept_encoding" : ""), + (opts->remove_http_referer ? "|remove_http_referer" : ""), + (opts->verify_peer ? "|verify_peer" : ""), + (opts->allow_wrong_host ? "|allow_wrong_host" : ""), #ifndef WITHOUT_USERAUTH - STRORNONE(rule->user), STRORNONE(rule->keyword), + (opts->user_auth ? "|user_auth" : ""), + (opts->user_auth_url ? opts->user_auth_url : "no user_auth_url"), + opts->user_timeout, + du, + pu, #endif /* !WITHOUT_USERAUTH */ - rule->all_conns ? "conns" : "", + (opts->validate_proto ? "|validate_proto" : ""), + opts->max_http_header_size, + proto_dump, + strlen(ms) ? "\n" : "", ms, + strlen(frs) ? "\n" : "", frs, + strlen(fs) ? "\n" : "", fs) < 0) { + s = NULL; + } +out: #ifndef WITHOUT_USERAUTH - rule->all_users ? "users" : "", + if (du) + free(du); + if (pu) + free(pu); #endif /* !WITHOUT_USERAUTH */ - rule->all_sites ? "sites" : "", rule->all_ports ? "ports" : "", - rule->action.divert ? "divert" : "", rule->action.split ? "split" : "", rule->action.pass ? "pass" : "", rule->action.block ? "block" : "", rule->action.match ? "match" : "", - rule->action.log_connect ? (rule->action.log_connect == 1 ? "!connect" : "connect") : "", rule->action.log_master ? (rule->action.log_master == 1 ? "!master" : "master") : "", - rule->action.log_cert ? (rule->action.log_cert == 1 ? "!cert" : "cert") : "", rule->action.log_content ? (rule->action.log_content == 1 ? "!content" : "content") : "", - rule->action.log_pcap ? (rule->action.log_pcap == 1 ? "!pcap" : "pcap") : "", -#ifndef WITHOUT_MIRROR - rule->action.log_mirror ? (rule->action.log_mirror == 1 ? "!mirror" : "mirror") : "", -#endif /* !WITHOUT_MIRROR */ - rule->dstip ? "dstip" : "", rule->sni ? "sni" : "", rule->cn ? "cn" : "", rule->host ? "host" : "", rule->uri ? "uri" : "", - rule->action.precedence) < 0) { - goto err; - } - char *nfrs; - if (asprintf(&nfrs, "%s%sfilter rule %d: %s", - STRORNONE(frs), frs ? "\n" : "", count, p) < 0) { - free(p); - goto err; - } - free(p); - if (frs) - free(frs); - frs = nfrs; - rule = rule->next; - count++; - } - goto out; -err: - if (frs) { + if (ms) + free(ms); + if (frs) free(frs); - frs = NULL; - } -out: - return frs; + if (fs) + free(fs); + if (proto_dump) + free(proto_dump); + return s; } -static char * -filter_port_str(filter_port_t *port) +/* + * Return text representation of proxy spec for display to the user. + * Returned string must be freed by caller. + */ +char * +proxyspec_str(proxyspec_t *spec) { char *s = NULL; + char *lhbuf = NULL; + char *lpbuf = NULL; + char *cbuf = NULL; + char *pdstbuf = NULL; + char *csrcbuf = NULL; + char *optsstr = NULL; - int count = 0; - while (port) { - char *p; - if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" -#ifndef WITHOUT_MIRROR - "|%s" -#endif /* !WITHOUT_MIRROR */ - ", precedence=%d)", STRORNONE(s), count, - port->port, port->all_ports ? "all_ports, " : "", port->exact ? "exact" : "substring", - port->action.divert ? "divert" : "", port->action.split ? "split" : "", port->action.pass ? "pass" : "", port->action.block ? "block" : "", port->action.match ? "match" : "", - port->action.log_connect ? (port->action.log_connect == 1 ? "!connect" : "connect") : "", port->action.log_master ? (port->action.log_master == 1 ? "!master" : "master") : "", - port->action.log_cert ? (port->action.log_cert == 1 ? "!cert" : "cert") : "", port->action.log_content ? (port->action.log_content == 1 ? "!content" : "content") : "", - port->action.log_pcap ? (port->action.log_pcap == 1 ? "!pcap" : "pcap") : "", -#ifndef WITHOUT_MIRROR - port->action.log_mirror ? (port->action.log_mirror == 1 ? "!mirror" : "mirror") : "", -#endif /* !WITHOUT_MIRROR */ - port->action.precedence) < 0) { - goto err; + if (sys_sockaddr_str((struct sockaddr *)&spec->listen_addr, + spec->listen_addrlen, &lhbuf, &lpbuf) != 0) { + goto out; + } + if (spec->connect_addrlen) { + char *chbuf, *cpbuf; + if (sys_sockaddr_str((struct sockaddr *)&spec->connect_addr, + spec->connect_addrlen, + &chbuf, &cpbuf) != 0) { + goto out; } - if (s) - free(s); - s = p; - port = port->next; - count++; + int rv = asprintf(&cbuf, "\nconnect= [%s]:%s", chbuf, cpbuf); + free(chbuf); + free(cpbuf); + if (rv < 0) + goto out; } - goto out; -err: - if (s) { - free(s); - s = NULL; + if (spec->conn_dst_addrlen) { + char *chbuf, *cpbuf; + if (sys_sockaddr_str((struct sockaddr *)&spec->conn_dst_addr, + spec->conn_dst_addrlen, + &chbuf, &cpbuf) != 0) { + goto out; + } + int rv = asprintf(&pdstbuf, "\nparent dst addr= [%s]:%s", chbuf, cpbuf); + free(chbuf); + free(cpbuf); + if (rv < 0) + goto out; } -out: - return s; -} - -static char * -filter_sites_str(filter_site_t *site) -{ - char *s = NULL; - char *ports = NULL; - - int count = 0; - while (site) { - ports = filter_port_str(site->port); - - char *p; - if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" -#ifndef WITHOUT_MIRROR - "|%s" -#endif /* !WITHOUT_MIRROR */ - ", precedence=%d)%s%s", STRORNONE(s), count, - site->site, site->all_sites ? "all_sites, " : "", site->exact ? "exact" : "substring", - site->action.divert ? "divert" : "", site->action.split ? "split" : "", site->action.pass ? "pass" : "", site->action.block ? "block" : "", site->action.match ? "match" : "", - site->action.log_connect ? (site->action.log_connect == 1 ? "!connect" : "connect") : "", site->action.log_master ? (site->action.log_master == 1 ? "!master" : "master") : "", - site->action.log_cert ? (site->action.log_cert == 1 ? "!cert" : "cert") : "", site->action.log_content ? (site->action.log_content == 1 ? "!content" : "content") : "", - site->action.log_pcap ? (site->action.log_pcap == 1 ? "!pcap" : "pcap") : "", -#ifndef WITHOUT_MIRROR - site->action.log_mirror ? (site->action.log_mirror == 1 ? "!mirror" : "mirror") : "", -#endif /* !WITHOUT_MIRROR */ - site->action.precedence, - ports ? "\n port:" : "", STRORNONE(ports)) < 0) { - goto err; + if (spec->child_src_addrlen) { + char *chbuf, *cpbuf; + if (sys_sockaddr_str((struct sockaddr *)&spec->child_src_addr, + spec->child_src_addrlen, + &chbuf, &cpbuf) != 0) { + goto out; + } + int rv = asprintf(&csrcbuf, "\nchild src addr= [%s]:%s", chbuf, cpbuf); + free(chbuf); + free(cpbuf); + if (rv < 0) + goto out; + } + if (spec->sni_port) { + if (asprintf(&cbuf, "\nsni %i", spec->sni_port) < 0) { + goto out; } - if (s) - free(s); - s = p; - site = site->next; - count++; } - goto out; -err: - if (s) { - free(s); + optsstr = opts_str(spec->opts); + if (!optsstr) { + goto out; + } + if (asprintf(&s, "listen=[%s]:%s %s%s%s%s%s %s%s%s\n%s%s", lhbuf, lpbuf, + (spec->ssl ? "ssl" : "tcp"), + (spec->upgrade ? "|autossl" : ""), + (spec->http ? "|http" : ""), + (spec->pop3 ? "|pop3" : ""), + (spec->smtp ? "|smtp" : ""), + (spec->natengine ? spec->natengine : cbuf), + STRORNONE(pdstbuf), + STRORNONE(csrcbuf), + optsstr, + !spec->opts->divert && spec->conn_dst_addrlen ? "\nWARNING: Divert address specified in split mode" : "") < 0) { s = NULL; } out: + if (optsstr) + free(optsstr); + if (lhbuf) + free(lhbuf); + if (lpbuf) + free(lpbuf); + if (cbuf) + free(cbuf); + if (pdstbuf) + free(pdstbuf); + if (csrcbuf) + free(csrcbuf); return s; } -static char * -filter_list_str(filter_list_t *list) +int +opts_set_cacrt(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) { - char *p = NULL; - char *op = NULL; - - char *s = filter_sites_str(list->ip); - if (asprintf(&p, " ip: %s", STRORNONE(s)) < 0) { - goto err; - } - if (s) - free(s); - op = p; - - s = filter_sites_str(list->sni); - if (asprintf(&p, "%s\n sni: %s", op, STRORNONE(s)) < 0) { - goto err; - } - if (s) - free(s); - free(op); - op = p; - - s = filter_sites_str(list->cn); - if (asprintf(&p, "%s\n cn: %s", op, STRORNONE(s)) < 0) { - goto err; + if (tmp_global_opts) { + if (tmp_global_opts->cacrt_str) + free(tmp_global_opts->cacrt_str); + tmp_global_opts->cacrt_str = strdup(optarg); + if (!tmp_global_opts->cacrt_str) + return oom_return(argv0); } - if (s) - free(s); - free(op); - op = p; - s = filter_sites_str(list->host); - if (asprintf(&p, "%s\n host: %s", op, STRORNONE(s)) < 0) { - goto err; + if (opts->cacrt) + X509_free(opts->cacrt); + opts->cacrt = ssl_x509_load(optarg); + if (!opts->cacrt) { + fprintf(stderr, "%s: error loading CA cert from '%s':\n", + argv0, optarg); + if (errno) { + fprintf(stderr, "%s\n", strerror(errno)); + } else { + ERR_print_errors_fp(stderr); + } + return -1; } - if (s) - free(s); - free(op); - op = p; - - s = filter_sites_str(list->uri); - if (asprintf(&p, "%s\n uri: %s", op, STRORNONE(s)) < 0) { - goto err; + ssl_x509_refcount_inc(opts->cacrt); + sk_X509_insert(opts->chain, opts->cacrt, 0); + if (!opts->cakey) { + opts->cakey = ssl_key_load(optarg); } - goto out; -err: - if (p) { - free(p); - p = NULL; +#ifndef OPENSSL_NO_DH + if (!opts->dh) { + opts->dh = ssl_dh_load(optarg); } -out: - if (s) - free(s); - if (op) - free(op); - return p; +#endif /* !OPENSSL_NO_DH */ +#ifdef DEBUG_OPTS + log_dbg_printf("CACert: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; } -static char * -filter_ips_str(filter_ip_t *ip) +int +opts_set_cakey(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) { - char *s = NULL; - char *list = NULL; - - int count = 0; - while (ip) { - list = filter_list_str(ip->list); + if (tmp_global_opts) { + if (tmp_global_opts->cakey_str) + free(tmp_global_opts->cakey_str); + tmp_global_opts->cakey_str = strdup(optarg); + if (!tmp_global_opts->cakey_str) + return oom_return(argv0); + } - char *p; - if (asprintf(&p, "%s%s ip %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, ip->ip, list) < 0) { - goto err; + if (opts->cakey) + EVP_PKEY_free(opts->cakey); + opts->cakey = ssl_key_load(optarg); + if (!opts->cakey) { + fprintf(stderr, "%s: error loading CA key from '%s':\n", + argv0, optarg); + if (errno) { + fprintf(stderr, "%s\n", strerror(errno)); + } else { + ERR_print_errors_fp(stderr); } - if (list) - free(list); - if (s) - free(s); - s = p; - ip = ip->next; - count++; - } - goto out; -err: - if (list) - free(list); - if (s) { - free(s); - s = NULL; + return -1; } -out: - return s; -} - -#ifndef WITHOUT_USERAUTH -static char * -filter_users_str(filter_user_t *user) -{ - char *s = NULL; - char *list = NULL; - - int count = 0; - while (user) { - // Make sure the current user does not have any keyword - if (user->keyword) - goto skip; - - list = filter_list_str(user->list); - - char *p = NULL; - - // Make sure the user has a filter rule - // It is possible to have users without any filter rule, - // but the user exists because it has keyword filters - if (list) { - if (asprintf(&p, "%s%s user %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, user->user, list) < 0) { - goto err; - } - free(list); + if (!opts->cacrt) { + opts->cacrt = ssl_x509_load(optarg); + if (opts->cacrt) { + ssl_x509_refcount_inc(opts->cacrt); + sk_X509_insert(opts->chain, opts->cacrt, 0); } - if (s) - free(s); - s = p; - count++; -skip: - user = user->next; } - goto out; -err: - if (list) - free(list); - if (s) { - free(s); - s = NULL; +#ifndef OPENSSL_NO_DH + if (!opts->dh) { + opts->dh = ssl_dh_load(optarg); } -out: - return s; +#endif /* !OPENSSL_NO_DH */ +#ifdef DEBUG_OPTS + log_dbg_printf("CAKey: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; } -static char * -filter_keywords_str(filter_keyword_t *keyword) +int +opts_set_chain(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) { - char *s = NULL; - char *list = NULL; - - int count = 0; - while (keyword) { - list = filter_list_str(keyword->list); + if (tmp_global_opts) { + if (tmp_global_opts->chain_str) + free(tmp_global_opts->chain_str); + tmp_global_opts->chain_str = strdup(optarg); + if (!tmp_global_opts->chain_str) + return oom_return(argv0); + } - char *p; - if (asprintf(&p, "%s%s keyword %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, keyword->keyword, list) < 0) { - goto err; + if (ssl_x509chain_load(NULL, &opts->chain, optarg) == -1) { + fprintf(stderr, "%s: error loading chain from '%s':\n", + argv0, optarg); + if (errno) { + fprintf(stderr, "%s\n", strerror(errno)); + } else { + ERR_print_errors_fp(stderr); } - if (list) - free(list); - if (s) - free(s); - s = p; - keyword = keyword->next; - count++; - } - goto out; -err: - if (list) - free(list); - if (s) { - free(s); - s = NULL; + return -1; } -out: - return s; +#ifdef DEBUG_OPTS + log_dbg_printf("CAChain: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; } -static char * -filter_userkeywords_str(filter_user_t *user) +int +opts_set_leafcrlurl(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) { - char *s = NULL; - char *list = NULL; - - int count = 0; - while (user) { - // Make sure the current user has a keyword - if (!user->keyword) - goto skip; - - list = filter_keywords_str(user->keyword); - - char *p = NULL; - if (list) { - if (asprintf(&p, "%s%s user %d %s=\n%s", STRORNONE(s), s ? "\n" : "", count, user->user, list) < 0) { - goto err; - } - free(list); - } - if (s) - free(s); - s = p; - count++; -skip: - user = user->next; + if (tmp_global_opts) { + if (tmp_global_opts->leafcrlurl_str) + free(tmp_global_opts->leafcrlurl_str); + tmp_global_opts->leafcrlurl_str = strdup(optarg); + if (!tmp_global_opts->leafcrlurl_str) + return oom_return(argv0); } - goto out; -err: - if (list) - free(list); - if (s) { - free(s); - s = NULL; - } -out: - return s; + + if (opts->leafcrlurl) + free(opts->leafcrlurl); + opts->leafcrlurl = strdup(optarg); + if (!opts->leafcrlurl) + return oom_return(argv0); +#ifdef DEBUG_OPTS + log_dbg_printf("LeafCRLURL: %s\n", opts->leafcrlurl); +#endif /* DEBUG_OPTS */ + return 0; } -#endif /* !WITHOUT_USERAUTH */ -char * -filter_str(filter_t *filter) +static int WUNRES +set_certgendir(global_t *global, const char *argv0, const char *optarg) { - char *fs = NULL; -#ifndef WITHOUT_USERAUTH - char *userkeyword_filter = NULL; - char *user_filter = NULL; - char *keyword_filter = NULL; - char *all_user_filter = NULL; -#endif /* !WITHOUT_USERAUTH */ - char *ip_filter = NULL; - char *all_filter = NULL; + if (global->certgendir) + free(global->certgendir); + global->certgendir = strdup(optarg); + if (!global->certgendir) + return oom_return(argv0); + return 0; +} - if (!filter) { - fs = strdup(""); - if (!fs) - return oom_return_na_null(); - goto out; - } +void +opts_set_deny_ocsp(opts_t *opts) +{ + opts->deny_ocsp = 1; +} -#ifndef WITHOUT_USERAUTH - userkeyword_filter = filter_userkeywords_str(filter->user); - user_filter = filter_users_str(filter->user); - keyword_filter = filter_keywords_str(filter->keyword); - all_user_filter = filter_list_str(filter->all_user); -#endif /* !WITHOUT_USERAUTH */ - ip_filter = filter_ips_str(filter->ip); - all_filter = filter_list_str(filter->all); +void +opts_unset_deny_ocsp(opts_t *opts) +{ + opts->deny_ocsp = 0; +} - if (asprintf(&fs, "filter=>\n" -#ifndef WITHOUT_USERAUTH - "userkeyword_filter->%s%s\nuser_filter->%s%s\nkeyword_filter->%s%s\nall_user_filter->%s%s\n" -#endif /* !WITHOUT_USERAUTH */ - "ip_filter->%s%s\nall_filter->%s%s\n", -#ifndef WITHOUT_USERAUTH - userkeyword_filter ? "\n" : "", STRORNONE(userkeyword_filter), - user_filter ? "\n" : "", STRORNONE(user_filter), - keyword_filter ? "\n" : "", STRORNONE(keyword_filter), - all_user_filter ? "\n" : "", STRORNONE(all_user_filter), -#endif /* !WITHOUT_USERAUTH */ - ip_filter ? "\n" : "", STRORNONE(ip_filter), - all_filter ? "\n" : "", STRORNONE(all_filter)) < 0) { - goto err; - } - goto out; -err: - if (fs) { - free(fs); - fs = NULL; - } -out: -#ifndef WITHOUT_USERAUTH - if (userkeyword_filter) - free(userkeyword_filter); - if (user_filter) - free(user_filter); - if (keyword_filter) - free(keyword_filter); - if (all_user_filter) - free(all_user_filter); -#endif /* !WITHOUT_USERAUTH */ - if (ip_filter) - free(ip_filter); - if (all_filter) - free(all_filter); - return fs; +void +opts_set_passthrough(opts_t *opts) +{ + opts->passthrough = 1; } -#ifndef WITHOUT_USERAUTH -static char * -users_str(userlist_t *u) +void +opts_unset_passthrough(opts_t *opts) { - char *us = NULL; + opts->passthrough = 0; +} - if (!u) { - us = strdup(""); - if (!us) - return oom_return_na_null(); - goto out; +int +opts_set_clientcrt(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) +{ + if (tmp_global_opts) { + if (tmp_global_opts->clientcrt_str) + free(tmp_global_opts->clientcrt_str); + tmp_global_opts->clientcrt_str = strdup(optarg); + if (!tmp_global_opts->clientcrt_str) + return oom_return(argv0); } - while (u) { - char *nus; - if (asprintf(&nus, "%s%s%s", STRORNONE(us), us ? "," : "", u->user) < 0) { - goto err; + if (opts->clientcrt) + X509_free(opts->clientcrt); + opts->clientcrt = ssl_x509_load(optarg); + if (!opts->clientcrt) { + fprintf(stderr, "%s: error loading client cert from '%s':\n", + argv0, optarg); + if (errno) { + fprintf(stderr, "%s\n", strerror(errno)); + } else { + ERR_print_errors_fp(stderr); } + return -1; + } +#ifdef DEBUG_OPTS + log_dbg_printf("ClientCert: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; +} - if (us) - free(us); - us = nus; - u = u->next; +int +opts_set_clientkey(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) +{ + if (tmp_global_opts) { + if (tmp_global_opts->clientkey_str) + free(tmp_global_opts->clientkey_str); + tmp_global_opts->clientkey_str = strdup(optarg); + if (!tmp_global_opts->clientkey_str) + return oom_return(argv0); } - goto out; -err: - if (us) { - free(us); - us = NULL; + + if (opts->clientkey) + EVP_PKEY_free(opts->clientkey); + opts->clientkey = ssl_key_load(optarg); + if (!opts->clientkey) { + fprintf(stderr, "%s: error loading client key from '%s':\n", + argv0, optarg); + if (errno) { + fprintf(stderr, "%s\n", strerror(errno)); + } else { + ERR_print_errors_fp(stderr); + } + return -1; } -out: - return us; +#ifdef DEBUG_OPTS + log_dbg_printf("ClientKey: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; } -#endif /* !WITHOUT_USERAUTH */ -static char * -opts_str(opts_t *opts) +#ifndef OPENSSL_NO_DH +int +opts_set_dh(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) { - char *s = NULL; - char *proto_dump = NULL; - char *ms = NULL; - char *frs = NULL; - char *fs = NULL; - -#ifndef WITHOUT_USERAUTH - char *du = NULL; - char *pu = NULL; + if (tmp_global_opts) { + if (tmp_global_opts->dh_str) + free(tmp_global_opts->dh_str); + tmp_global_opts->dh_str = strdup(optarg); + if (!tmp_global_opts->dh_str) + return oom_return(argv0); + } - du = users_str(opts->divertusers); - if (!du) - goto out; + if (opts->dh) + DH_free(opts->dh); + opts->dh = ssl_dh_load(optarg); + if (!opts->dh) { + fprintf(stderr, "%s: error loading DH params from '%s':\n", + argv0, optarg); + if (errno) { + fprintf(stderr, "%s\n", strerror(errno)); + } else { + ERR_print_errors_fp(stderr); + } + return -1; + } +#ifdef DEBUG_OPTS + log_dbg_printf("DHGroupParams: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; +} +#endif /* !OPENSSL_NO_DH */ - pu = users_str(opts->passusers); - if (!pu) - goto out; -#endif /* !WITHOUT_USERAUTH */ +#ifndef OPENSSL_NO_ECDH +int +opts_set_ecdhcurve(opts_t *opts, const char *argv0, const char *optarg) +{ + EC_KEY *ec; + if (opts->ecdhcurve) + free(opts->ecdhcurve); + if (!(ec = ssl_ec_by_name(optarg))) { + fprintf(stderr, "%s: unknown curve '%s'\n", argv0, optarg); + return -1; + } + EC_KEY_free(ec); + opts->ecdhcurve = strdup(optarg); + if (!opts->ecdhcurve) + return oom_return(argv0); +#ifdef DEBUG_OPTS + log_dbg_printf("ECDHCurve: %s\n", opts->ecdhcurve); +#endif /* DEBUG_OPTS */ + return 0; +} +#endif /* !OPENSSL_NO_ECDH */ - ms = macro_str(opts->macro); - if (!ms) - goto out; +void +opts_set_sslcomp(opts_t *opts) +{ + opts->sslcomp = 1; +} - frs = filter_rule_str(opts->filter_rules); - if (!frs) - goto out; +void +opts_unset_sslcomp(opts_t *opts) +{ + opts->sslcomp = 0; +} - fs = filter_str(opts->filter); - if (!fs) - goto out; +int +opts_set_ciphers(opts_t *opts, const char *argv0, const char *optarg) +{ + if (opts->ciphers) + free(opts->ciphers); + opts->ciphers = strdup(optarg); + if (!opts->ciphers) + return oom_return(argv0); +#ifdef DEBUG_OPTS + log_dbg_printf("Ciphers: %s\n", opts->ciphers); +#endif /* DEBUG_OPTS */ + return 0; +} - proto_dump = opts_proto_dbg_dump(opts); - if (!proto_dump) - goto out; +int +opts_set_ciphersuites(opts_t *opts, const char *argv0, const char *optarg) +{ + if (opts->ciphersuites) + free(opts->ciphersuites); + opts->ciphersuites = strdup(optarg); + if (!opts->ciphersuites) + return oom_return(argv0); +#ifdef DEBUG_OPTS + log_dbg_printf("CipherSuites: %s\n", opts->ciphersuites); +#endif /* DEBUG_OPTS */ + return 0; +} - if (asprintf(&s, "opts=%s%s" +/* + * Parse SSL proto string in optarg and look up the corresponding SSL method. + */ +int +opts_force_proto(opts_t *opts, const char *argv0, const char *optarg) +{ +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20702000L) + if (opts->sslmethod != SSLv23_method) { +#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + if (opts->sslversion) { +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + fprintf(stderr, "%s: cannot use -r multiple times\n", argv0); + return -1; + } + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20702000L) #ifdef HAVE_SSLV2 - "%s" + if (!strcmp(optarg, "ssl2")) { + opts->sslmethod = SSLv2_method; + } else #endif /* HAVE_SSLV2 */ #ifdef HAVE_SSLV3 - "%s" + if (!strcmp(optarg, "ssl3")) { + opts->sslmethod = SSLv3_method; + } else #endif /* HAVE_SSLV3 */ #ifdef HAVE_TLSV10 - "%s" + if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { + opts->sslmethod = TLSv1_method; + } else #endif /* HAVE_TLSV10 */ #ifdef HAVE_TLSV11 - "%s" + if (!strcmp(optarg, "tls11")) { + opts->sslmethod = TLSv1_1_method; + } else #endif /* HAVE_TLSV11 */ #ifdef HAVE_TLSV12 - "%s" + if (!strcmp(optarg, "tls12")) { + opts->sslmethod = TLSv1_2_method; + } else #endif /* HAVE_TLSV12 */ -#ifdef HAVE_TLSV13 - "%s" -#endif /* HAVE_TLSV13 */ - "%s%s|%s|%s" -#ifndef OPENSSL_NO_ECDH - "|%s" -#endif /* !OPENSSL_NO_ECDH */ - "|%s%s%s%s%s" -#ifndef WITHOUT_USERAUTH - "%s|%s|%d|%s|%s" -#endif /* !WITHOUT_USERAUTH */ - "%s|%d\n%s%s%s%s%s%s%s", - (opts->divert ? "divert" : "split"), - (!opts->sslcomp ? "|no sslcomp" : ""), -#ifdef HAVE_SSLV2 - (opts->no_ssl2 ? "|no_ssl2" : ""), -#endif /* HAVE_SSLV2 */ +/* There is no TLSv1_3_method defined, + * since no ssl version < 0x10100000L supports it. */ +#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ +/* + * Support for SSLv2 and the corresponding SSLv2_method(), + * SSLv2_server_method() and SSLv2_client_method() functions were + * removed in OpenSSL 1.1.0. + */ #ifdef HAVE_SSLV3 - (opts->no_ssl3 ? "|no_ssl3" : ""), + if (!strcmp(optarg, "ssl3")) { + opts->sslversion = SSL3_VERSION; + } else #endif /* HAVE_SSLV3 */ #ifdef HAVE_TLSV10 - (opts->no_tls10 ? "|no_tls10" : ""), + if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { + opts->sslversion = TLS1_VERSION; + } else #endif /* HAVE_TLSV10 */ #ifdef HAVE_TLSV11 - (opts->no_tls11 ? "|no_tls11" : ""), + if (!strcmp(optarg, "tls11")) { + opts->sslversion = TLS1_1_VERSION; + } else #endif /* HAVE_TLSV11 */ #ifdef HAVE_TLSV12 - (opts->no_tls12 ? "|no_tls12" : ""), + if (!strcmp(optarg, "tls12")) { + opts->sslversion = TLS1_2_VERSION; + } else #endif /* HAVE_TLSV12 */ #ifdef HAVE_TLSV13 - (opts->no_tls13 ? "|no_tls13" : ""), + if (!strcmp(optarg, "tls13")) { + opts->sslversion = TLS1_3_VERSION; + } else #endif /* HAVE_TLSV13 */ - (opts->passthrough ? "|passthrough" : ""), - (opts->deny_ocsp ? "|deny_ocsp" : ""), - (opts->ciphers ? opts->ciphers : "no ciphers"), - (opts->ciphersuites ? opts->ciphersuites : "no ciphersuites"), -#ifndef OPENSSL_NO_ECDH - (opts->ecdhcurve ? opts->ecdhcurve : "no ecdhcurve"), -#endif /* !OPENSSL_NO_ECDH */ - (opts->leafcrlurl ? opts->leafcrlurl : "no leafcrlurl"), - (opts->remove_http_accept_encoding ? "|remove_http_accept_encoding" : ""), - (opts->remove_http_referer ? "|remove_http_referer" : ""), - (opts->verify_peer ? "|verify_peer" : ""), - (opts->allow_wrong_host ? "|allow_wrong_host" : ""), -#ifndef WITHOUT_USERAUTH - (opts->user_auth ? "|user_auth" : ""), - (opts->user_auth_url ? opts->user_auth_url : "no user_auth_url"), - opts->user_timeout, - du, - pu, -#endif /* !WITHOUT_USERAUTH */ - (opts->validate_proto ? "|validate_proto" : ""), - opts->max_http_header_size, - proto_dump, - strlen(ms) ? "\n" : "", ms, - strlen(frs) ? "\n" : "", frs, - strlen(fs) ? "\n" : "", fs) < 0) { - s = NULL; - } -out: -#ifndef WITHOUT_USERAUTH - if (du) - free(du); - if (pu) - free(pu); -#endif /* !WITHOUT_USERAUTH */ - if (ms) - free(ms); - if (frs) - free(frs); - if (fs) - free(fs); - if (proto_dump) - free(proto_dump); - return s; -} - -/* - * Return text representation of proxy spec for display to the user. - * Returned string must be freed by caller. - */ -char * -proxyspec_str(proxyspec_t *spec) -{ - char *s = NULL; - char *lhbuf = NULL; - char *lpbuf = NULL; - char *cbuf = NULL; - char *pdstbuf = NULL; - char *csrcbuf = NULL; - char *optsstr = NULL; - - if (sys_sockaddr_str((struct sockaddr *)&spec->listen_addr, - spec->listen_addrlen, &lhbuf, &lpbuf) != 0) { - goto out; - } - if (spec->connect_addrlen) { - char *chbuf, *cpbuf; - if (sys_sockaddr_str((struct sockaddr *)&spec->connect_addr, - spec->connect_addrlen, - &chbuf, &cpbuf) != 0) { - goto out; - } - int rv = asprintf(&cbuf, "\nconnect= [%s]:%s", chbuf, cpbuf); - free(chbuf); - free(cpbuf); - if (rv < 0) - goto out; - } - if (spec->conn_dst_addrlen) { - char *chbuf, *cpbuf; - if (sys_sockaddr_str((struct sockaddr *)&spec->conn_dst_addr, - spec->conn_dst_addrlen, - &chbuf, &cpbuf) != 0) { - goto out; - } - int rv = asprintf(&pdstbuf, "\nparent dst addr= [%s]:%s", chbuf, cpbuf); - free(chbuf); - free(cpbuf); - if (rv < 0) - goto out; - } - if (spec->child_src_addrlen) { - char *chbuf, *cpbuf; - if (sys_sockaddr_str((struct sockaddr *)&spec->child_src_addr, - spec->child_src_addrlen, - &chbuf, &cpbuf) != 0) { - goto out; - } - int rv = asprintf(&csrcbuf, "\nchild src addr= [%s]:%s", chbuf, cpbuf); - free(chbuf); - free(cpbuf); - if (rv < 0) - goto out; - } - if (spec->sni_port) { - if (asprintf(&cbuf, "\nsni %i", spec->sni_port) < 0) { - goto out; - } - } - optsstr = opts_str(spec->opts); - if (!optsstr) { - goto out; - } - if (asprintf(&s, "listen=[%s]:%s %s%s%s%s%s %s%s%s\n%s%s", lhbuf, lpbuf, - (spec->ssl ? "ssl" : "tcp"), - (spec->upgrade ? "|autossl" : ""), - (spec->http ? "|http" : ""), - (spec->pop3 ? "|pop3" : ""), - (spec->smtp ? "|smtp" : ""), - (spec->natengine ? spec->natengine : cbuf), - STRORNONE(pdstbuf), - STRORNONE(csrcbuf), - optsstr, - !spec->opts->divert && spec->conn_dst_addrlen ? "\nWARNING: Divert address specified in split mode" : "") < 0) { - s = NULL; - } -out: - if (optsstr) - free(optsstr); - if (lhbuf) - free(lhbuf); - if (lpbuf) - free(lpbuf); - if (cbuf) - free(cbuf); - if (pdstbuf) - free(pdstbuf); - if (csrcbuf) - free(csrcbuf); - return s; -} - -int -opts_set_cacrt(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) -{ - if (tmp_global_opts) { - if (tmp_global_opts->cacrt_str) - free(tmp_global_opts->cacrt_str); - tmp_global_opts->cacrt_str = strdup(optarg); - if (!tmp_global_opts->cacrt_str) - return oom_return(argv0); - } - - if (opts->cacrt) - X509_free(opts->cacrt); - opts->cacrt = ssl_x509_load(optarg); - if (!opts->cacrt) { - fprintf(stderr, "%s: error loading CA cert from '%s':\n", - argv0, optarg); - if (errno) { - fprintf(stderr, "%s\n", strerror(errno)); - } else { - ERR_print_errors_fp(stderr); - } - return -1; - } - ssl_x509_refcount_inc(opts->cacrt); - sk_X509_insert(opts->chain, opts->cacrt, 0); - if (!opts->cakey) { - opts->cakey = ssl_key_load(optarg); - } -#ifndef OPENSSL_NO_DH - if (!opts->dh) { - opts->dh = ssl_dh_load(optarg); - } -#endif /* !OPENSSL_NO_DH */ -#ifdef DEBUG_OPTS - log_dbg_printf("CACert: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -int -opts_set_cakey(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) -{ - if (tmp_global_opts) { - if (tmp_global_opts->cakey_str) - free(tmp_global_opts->cakey_str); - tmp_global_opts->cakey_str = strdup(optarg); - if (!tmp_global_opts->cakey_str) - return oom_return(argv0); - } - - if (opts->cakey) - EVP_PKEY_free(opts->cakey); - opts->cakey = ssl_key_load(optarg); - if (!opts->cakey) { - fprintf(stderr, "%s: error loading CA key from '%s':\n", - argv0, optarg); - if (errno) { - fprintf(stderr, "%s\n", strerror(errno)); - } else { - ERR_print_errors_fp(stderr); - } - return -1; - } - if (!opts->cacrt) { - opts->cacrt = ssl_x509_load(optarg); - if (opts->cacrt) { - ssl_x509_refcount_inc(opts->cacrt); - sk_X509_insert(opts->chain, opts->cacrt, 0); - } - } -#ifndef OPENSSL_NO_DH - if (!opts->dh) { - opts->dh = ssl_dh_load(optarg); - } -#endif /* !OPENSSL_NO_DH */ -#ifdef DEBUG_OPTS - log_dbg_printf("CAKey: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -int -opts_set_chain(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) -{ - if (tmp_global_opts) { - if (tmp_global_opts->chain_str) - free(tmp_global_opts->chain_str); - tmp_global_opts->chain_str = strdup(optarg); - if (!tmp_global_opts->chain_str) - return oom_return(argv0); - } - - if (ssl_x509chain_load(NULL, &opts->chain, optarg) == -1) { - fprintf(stderr, "%s: error loading chain from '%s':\n", - argv0, optarg); - if (errno) { - fprintf(stderr, "%s\n", strerror(errno)); - } else { - ERR_print_errors_fp(stderr); - } - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("CAChain: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -int -opts_set_leafcrlurl(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) -{ - if (tmp_global_opts) { - if (tmp_global_opts->leafcrlurl_str) - free(tmp_global_opts->leafcrlurl_str); - tmp_global_opts->leafcrlurl_str = strdup(optarg); - if (!tmp_global_opts->leafcrlurl_str) - return oom_return(argv0); - } - - if (opts->leafcrlurl) - free(opts->leafcrlurl); - opts->leafcrlurl = strdup(optarg); - if (!opts->leafcrlurl) - return oom_return(argv0); -#ifdef DEBUG_OPTS - log_dbg_printf("LeafCRLURL: %s\n", opts->leafcrlurl); -#endif /* DEBUG_OPTS */ - return 0; -} - -static int WUNRES -set_certgendir(global_t *global, const char *argv0, const char *optarg) -{ - if (global->certgendir) - free(global->certgendir); - global->certgendir = strdup(optarg); - if (!global->certgendir) - return oom_return(argv0); - return 0; -} - -void -opts_set_deny_ocsp(opts_t *opts) -{ - opts->deny_ocsp = 1; -} - -void -opts_unset_deny_ocsp(opts_t *opts) -{ - opts->deny_ocsp = 0; -} - -void -opts_set_passthrough(opts_t *opts) -{ - opts->passthrough = 1; -} - -void -opts_unset_passthrough(opts_t *opts) -{ - opts->passthrough = 0; -} - -int -opts_set_clientcrt(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) -{ - if (tmp_global_opts) { - if (tmp_global_opts->clientcrt_str) - free(tmp_global_opts->clientcrt_str); - tmp_global_opts->clientcrt_str = strdup(optarg); - if (!tmp_global_opts->clientcrt_str) - return oom_return(argv0); - } - - if (opts->clientcrt) - X509_free(opts->clientcrt); - opts->clientcrt = ssl_x509_load(optarg); - if (!opts->clientcrt) { - fprintf(stderr, "%s: error loading client cert from '%s':\n", - argv0, optarg); - if (errno) { - fprintf(stderr, "%s\n", strerror(errno)); - } else { - ERR_print_errors_fp(stderr); - } - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("ClientCert: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -int -opts_set_clientkey(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) -{ - if (tmp_global_opts) { - if (tmp_global_opts->clientkey_str) - free(tmp_global_opts->clientkey_str); - tmp_global_opts->clientkey_str = strdup(optarg); - if (!tmp_global_opts->clientkey_str) - return oom_return(argv0); - } - - if (opts->clientkey) - EVP_PKEY_free(opts->clientkey); - opts->clientkey = ssl_key_load(optarg); - if (!opts->clientkey) { - fprintf(stderr, "%s: error loading client key from '%s':\n", - argv0, optarg); - if (errno) { - fprintf(stderr, "%s\n", strerror(errno)); - } else { - ERR_print_errors_fp(stderr); - } - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("ClientKey: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -#ifndef OPENSSL_NO_DH -int -opts_set_dh(opts_t *opts, const char *argv0, const char *optarg, tmp_global_opts_t *tmp_global_opts) -{ - if (tmp_global_opts) { - if (tmp_global_opts->dh_str) - free(tmp_global_opts->dh_str); - tmp_global_opts->dh_str = strdup(optarg); - if (!tmp_global_opts->dh_str) - return oom_return(argv0); - } - - if (opts->dh) - DH_free(opts->dh); - opts->dh = ssl_dh_load(optarg); - if (!opts->dh) { - fprintf(stderr, "%s: error loading DH params from '%s':\n", - argv0, optarg); - if (errno) { - fprintf(stderr, "%s\n", strerror(errno)); - } else { - ERR_print_errors_fp(stderr); - } - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("DHGroupParams: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} -#endif /* !OPENSSL_NO_DH */ - -#ifndef OPENSSL_NO_ECDH -int -opts_set_ecdhcurve(opts_t *opts, const char *argv0, const char *optarg) -{ - EC_KEY *ec; - if (opts->ecdhcurve) - free(opts->ecdhcurve); - if (!(ec = ssl_ec_by_name(optarg))) { - fprintf(stderr, "%s: unknown curve '%s'\n", argv0, optarg); - return -1; - } - EC_KEY_free(ec); - opts->ecdhcurve = strdup(optarg); - if (!opts->ecdhcurve) - return oom_return(argv0); -#ifdef DEBUG_OPTS - log_dbg_printf("ECDHCurve: %s\n", opts->ecdhcurve); -#endif /* DEBUG_OPTS */ - return 0; -} -#endif /* !OPENSSL_NO_ECDH */ - -void -opts_set_sslcomp(opts_t *opts) -{ - opts->sslcomp = 1; -} - -void -opts_unset_sslcomp(opts_t *opts) -{ - opts->sslcomp = 0; -} - -int -opts_set_ciphers(opts_t *opts, const char *argv0, const char *optarg) -{ - if (opts->ciphers) - free(opts->ciphers); - opts->ciphers = strdup(optarg); - if (!opts->ciphers) - return oom_return(argv0); -#ifdef DEBUG_OPTS - log_dbg_printf("Ciphers: %s\n", opts->ciphers); -#endif /* DEBUG_OPTS */ - return 0; -} - -int -opts_set_ciphersuites(opts_t *opts, const char *argv0, const char *optarg) -{ - if (opts->ciphersuites) - free(opts->ciphersuites); - opts->ciphersuites = strdup(optarg); - if (!opts->ciphersuites) - return oom_return(argv0); -#ifdef DEBUG_OPTS - log_dbg_printf("CipherSuites: %s\n", opts->ciphersuites); -#endif /* DEBUG_OPTS */ - return 0; -} - -/* - * Parse SSL proto string in optarg and look up the corresponding SSL method. - */ -int -opts_force_proto(opts_t *opts, const char *argv0, const char *optarg) -{ -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20702000L) - if (opts->sslmethod != SSLv23_method) { -#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - if (opts->sslversion) { -#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - fprintf(stderr, "%s: cannot use -r multiple times\n", argv0); - return -1; - } - -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20702000L) -#ifdef HAVE_SSLV2 - if (!strcmp(optarg, "ssl2")) { - opts->sslmethod = SSLv2_method; - } else -#endif /* HAVE_SSLV2 */ -#ifdef HAVE_SSLV3 - if (!strcmp(optarg, "ssl3")) { - opts->sslmethod = SSLv3_method; - } else -#endif /* HAVE_SSLV3 */ -#ifdef HAVE_TLSV10 - if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { - opts->sslmethod = TLSv1_method; - } else -#endif /* HAVE_TLSV10 */ -#ifdef HAVE_TLSV11 - if (!strcmp(optarg, "tls11")) { - opts->sslmethod = TLSv1_1_method; - } else -#endif /* HAVE_TLSV11 */ -#ifdef HAVE_TLSV12 - if (!strcmp(optarg, "tls12")) { - opts->sslmethod = TLSv1_2_method; - } else -#endif /* HAVE_TLSV12 */ -/* There is no TLSv1_3_method defined, - * since no ssl version < 0x10100000L supports it. */ -#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ -/* - * Support for SSLv2 and the corresponding SSLv2_method(), - * SSLv2_server_method() and SSLv2_client_method() functions were - * removed in OpenSSL 1.1.0. - */ -#ifdef HAVE_SSLV3 - if (!strcmp(optarg, "ssl3")) { - opts->sslversion = SSL3_VERSION; - } else -#endif /* HAVE_SSLV3 */ -#ifdef HAVE_TLSV10 - if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { - opts->sslversion = TLS1_VERSION; - } else -#endif /* HAVE_TLSV10 */ -#ifdef HAVE_TLSV11 - if (!strcmp(optarg, "tls11")) { - opts->sslversion = TLS1_1_VERSION; - } else -#endif /* HAVE_TLSV11 */ -#ifdef HAVE_TLSV12 - if (!strcmp(optarg, "tls12")) { - opts->sslversion = TLS1_2_VERSION; - } else -#endif /* HAVE_TLSV12 */ -#ifdef HAVE_TLSV13 - if (!strcmp(optarg, "tls13")) { - opts->sslversion = TLS1_3_VERSION; - } else -#endif /* HAVE_TLSV13 */ -#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - { - fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", - argv0, optarg); - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("ForceSSLProto: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -/* - * Parse SSL proto string in optarg and set the corresponding no_foo bit. - */ -int -opts_disable_proto(opts_t *opts, const char *argv0, const char *optarg) -{ -#ifdef HAVE_SSLV2 - if (!strcmp(optarg, "ssl2")) { - opts->no_ssl2 = 1; - } else -#endif /* HAVE_SSLV2 */ -#ifdef HAVE_SSLV3 - if (!strcmp(optarg, "ssl3")) { - opts->no_ssl3 = 1; - } else -#endif /* HAVE_SSLV3 */ -#ifdef HAVE_TLSV10 - if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { - opts->no_tls10 = 1; - } else -#endif /* HAVE_TLSV10 */ -#ifdef HAVE_TLSV11 - if (!strcmp(optarg, "tls11")) { - opts->no_tls11 = 1; - } else -#endif /* HAVE_TLSV11 */ -#ifdef HAVE_TLSV12 - if (!strcmp(optarg, "tls12")) { - opts->no_tls12 = 1; - } else -#endif /* HAVE_TLSV12 */ -#ifdef HAVE_TLSV13 - if (!strcmp(optarg, "tls13")) { - opts->no_tls13 = 1; - } else -#endif /* HAVE_TLSV13 */ - { - fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", - argv0, optarg); - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("DisableSSLProto: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -static int WUNRES -opts_set_min_proto(UNUSED opts_t *opts, const char *argv0, const char *optarg) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20702000L) -#ifdef HAVE_SSLV3 - if (!strcmp(optarg, "ssl3")) { - opts->minsslversion = SSL3_VERSION; - } else -#endif /* HAVE_SSLV3 */ -#ifdef HAVE_TLSV10 - if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { - opts->minsslversion = TLS1_VERSION; - } else -#endif /* HAVE_TLSV10 */ -#ifdef HAVE_TLSV11 - if (!strcmp(optarg, "tls11")) { - opts->minsslversion = TLS1_1_VERSION; - } else -#endif /* HAVE_TLSV11 */ -#ifdef HAVE_TLSV12 - if (!strcmp(optarg, "tls12")) { - opts->minsslversion = TLS1_2_VERSION; - } else -#endif /* HAVE_TLSV12 */ -#ifdef HAVE_TLSV13 - if (!strcmp(optarg, "tls13")) { - opts->minsslversion = TLS1_3_VERSION; - } else -#endif /* HAVE_TLSV13 */ -#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - { - fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", - argv0, optarg); - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("MinSSLProto: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -static int WUNRES -opts_set_max_proto(UNUSED opts_t *opts, const char *argv0, const char *optarg) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20702000L) -#ifdef HAVE_SSLV3 - if (!strcmp(optarg, "ssl3")) { - opts->maxsslversion = SSL3_VERSION; - } else -#endif /* HAVE_SSLV3 */ -#ifdef HAVE_TLSV10 - if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { - opts->maxsslversion = TLS1_VERSION; - } else -#endif /* HAVE_TLSV10 */ -#ifdef HAVE_TLSV11 - if (!strcmp(optarg, "tls11")) { - opts->maxsslversion = TLS1_1_VERSION; - } else -#endif /* HAVE_TLSV11 */ -#ifdef HAVE_TLSV12 - if (!strcmp(optarg, "tls12")) { - opts->maxsslversion = TLS1_2_VERSION; - } else -#endif /* HAVE_TLSV12 */ -#ifdef HAVE_TLSV13 - if (!strcmp(optarg, "tls13")) { - opts->maxsslversion = TLS1_3_VERSION; - } else -#endif /* HAVE_TLSV13 */ -#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - { - fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", - argv0, optarg); - return -1; - } -#ifdef DEBUG_OPTS - log_dbg_printf("MaxSSLProto: %s\n", optarg); -#endif /* DEBUG_OPTS */ - return 0; -} - -static void -opts_set_remove_http_accept_encoding(opts_t *opts) -{ - opts->remove_http_accept_encoding = 1; -} - -static void -opts_unset_remove_http_accept_encoding(opts_t *opts) -{ - opts->remove_http_accept_encoding = 0; -} - -static void -opts_set_remove_http_referer(opts_t *opts) -{ - opts->remove_http_referer = 1; -} - -static void -opts_unset_remove_http_referer(opts_t *opts) -{ - opts->remove_http_referer = 0; -} - -static void -opts_set_verify_peer(opts_t *opts) -{ - opts->verify_peer = 1; -} - -static void -opts_unset_verify_peer(opts_t *opts) -{ - opts->verify_peer = 0; -} - -static void -opts_set_allow_wrong_host(opts_t *opts) -{ - opts->allow_wrong_host = 1; -} - -static void -opts_unset_allow_wrong_host(opts_t *opts) -{ - opts->allow_wrong_host = 0; -} - -#ifndef WITHOUT_USERAUTH -static void -opts_set_user_auth(UNUSED opts_t *opts) -{ -#if defined(__OpenBSD__) || defined(__linux__) - // Enable user auth on OpenBSD and Linux only - opts->user_auth = 1; -#endif /* __OpenBSD__ || __linux__ */ -} - -static void -opts_unset_user_auth(opts_t *opts) -{ - opts->user_auth = 0; -} -#endif /* !WITHOUT_USERAUTH */ - -static void -opts_set_validate_proto(opts_t *opts) -{ - opts->validate_proto = 1; -} - -static void -opts_unset_validate_proto(opts_t *opts) -{ - opts->validate_proto = 0; -} - -#ifdef DEBUG_OPTS -static void -opts_dbg_print_filter_rule(filter_rule_t *rule) -{ - log_dbg_printf("Filter rule: %s, %s, %s, %s, %s" -#ifndef WITHOUT_USERAUTH - ", %s, %s" -#endif /* !WITHOUT_USERAUTH */ - ", all=%s|" -#ifndef WITHOUT_USERAUTH - "%s|" -#endif /* !WITHOUT_USERAUTH */ - "%s|%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" -#ifndef WITHOUT_MIRROR - "|%s" -#endif /* !WITHOUT_MIRROR */ - ", apply to=%s|%s|%s|%s|%s, precedence=%d\n", - rule->site, rule->exact ? "exact" : "substring", - STRORNONE(rule->port), rule->port ? (rule->exact_port ? "exact_port" : "substring_port") : "", - STRORNONE(rule->ip), -#ifndef WITHOUT_USERAUTH - STRORNONE(rule->user), STRORNONE(rule->keyword), -#endif /* !WITHOUT_USERAUTH */ - rule->all_conns ? "conns" : "", -#ifndef WITHOUT_USERAUTH - rule->all_users ? "users" : "", -#endif /* !WITHOUT_USERAUTH */ - rule->all_sites ? "sites" : "", rule->all_ports ? "ports" : "", - rule->action.divert ? "divert" : "", rule->action.split ? "split" : "", rule->action.pass ? "pass" : "", rule->action.block ? "block" : "", rule->action.match ? "match" : "", - rule->action.log_connect ? (rule->action.log_connect == 1 ? "!connect" : "connect") : "", rule->action.log_master ? (rule->action.log_master == 1 ? "!master" : "master") : "", - rule->action.log_cert ? (rule->action.log_cert == 1 ? "!cert" : "cert") : "", rule->action.log_content ? (rule->action.log_content == 1 ? "!content" : "content") : "", - rule->action.log_pcap ? (rule->action.log_pcap == 1 ? "!pcap" : "pcap") : "", -#ifndef WITHOUT_MIRROR - rule->action.log_mirror ? (rule->action.log_mirror == 1 ? "!mirror" : "mirror") : "", -#endif /* !WITHOUT_MIRROR */ - rule->dstip ? "dstip" : "", rule->sni ? "sni" : "", rule->cn ? "cn" : "", rule->host ? "host" : "", rule->uri ? "uri" : "", - rule->action.precedence); -} -#endif /* DEBUG_OPTS */ - -#define MAX_SITE_LEN 200 - -int -opts_set_passsite(opts_t *opts, char *value, int line_num) -{ -#define MAX_PASSSITE_TOKENS 3 - - // site[*] [(clientaddr|user|*) [keyword]] - char *argv[sizeof(char *) * MAX_PASSSITE_TOKENS]; - int argc = 0; - char *p, *last = NULL; - - for ((p = strtok_r(value, " ", &last)); - p; - (p = strtok_r(NULL, " ", &last))) { - if (argc < MAX_PASSSITE_TOKENS) { - argv[argc++] = p; - } else { - fprintf(stderr, "Too many arguments in passsite option on line %d\n", line_num); - return -1; - } - } - - if (!argc) { - fprintf(stderr, "Filter rule requires at least one parameter on line %d\n", line_num); - return -1; - } - - filter_rule_t *rule = malloc(sizeof(filter_rule_t)); - if (!rule) - return oom_return_na(); - memset(rule, 0, sizeof(filter_rule_t)); - - // The for loop with strtok_r() above does not output empty strings - // So, no need to check if the length of argv[0] > 0 - size_t len = strlen(argv[0]); - - if (len > MAX_SITE_LEN) { - fprintf(stderr, "Filter site too long %zu > %d on line %d\n", len, MAX_SITE_LEN, line_num); - return -1; - } - - if (argv[0][len - 1] == '*') { - rule->exact = 0; - len--; - argv[0][len] = '\0'; - // site == "*" ? - if (len == 0) - rule->all_sites = 1; - } else { - rule->exact = 1; - } - - rule->site = strdup(argv[0]); - if (!rule->site) - return oom_return_na(); - - // precedence can only go up not down - rule->action.precedence = 0; - - if (argc == 1) { - // Apply filter rule to all conns - // Equivalent to "site *" without user auth - rule->all_conns = 1; - } - - if (argc > 1) { - if (!strcmp(argv[1], "*")) { -#ifndef WITHOUT_USERAUTH - // Apply filter rule to all users perhaps with keyword - rule->action.precedence++; - rule->all_users = 1; - } else if (sys_isuser(argv[1])) { - if (!opts->user_auth) { - fprintf(stderr, "User filter requires user auth on line %d\n", line_num); - return -1; - } - rule->action.precedence += 2; - rule->user = strdup(argv[1]); - if (!rule->user) - return oom_return_na(); -#else /* !WITHOUT_USERAUTH */ - // Apply filter rule to all conns, if USERAUTH is disabled, ip == '*' - rule->all_conns = 1; -#endif /* WITHOUT_USERAUTH */ - } else { - rule->action.precedence++; - rule->ip = strdup(argv[1]); - if (!rule->ip) - return oom_return_na(); - } - } - - if (argc > 2) { - if (rule->ip) { - fprintf(stderr, "Ip filter cannot define keyword filter" -#ifndef WITHOUT_USERAUTH - ", or user '%s' does not exist" -#endif /* !WITHOUT_USERAUTH */ - " on line %d\n", -#ifndef WITHOUT_USERAUTH - rule->ip, -#endif /* !WITHOUT_USERAUTH */ - line_num); - return -1; - } -#ifndef WITHOUT_USERAUTH - if (!opts->user_auth) { - fprintf(stderr, "Keyword filter requires user auth on line %d\n", line_num); - return -1; - } - rule->action.precedence++; - rule->keyword = strdup(argv[2]); - if (!rule->keyword) - return oom_return_na(); -#endif /* !WITHOUT_USERAUTH */ - } - - rule->action.precedence++; - rule->sni = 1; - rule->cn = 1; - rule->action.pass = 1; - - opts_append_to_filter_rules(&opts->filter_rules, rule); - -#ifdef DEBUG_OPTS - opts_dbg_print_filter_rule(rule); -#endif /* DEBUG_OPTS */ - return 0; -} - -static macro_t * -opts_find_macro(macro_t *macro, char *name) -{ - while (macro) { - if (equal(macro->name, name)) { - return macro; - } - macro = macro->next; - } - return NULL; -} - -int -opts_set_macro(opts_t *opts, char *value, int line_num) -{ -#define MAX_MACRO_TOKENS 50 - - // $name value1 [value2 [value3] ...] - char *argv[sizeof(char *) * MAX_MACRO_TOKENS]; - int argc = 0; - char *p, *last = NULL; - - for ((p = strtok_r(value, " ", &last)); - p; - (p = strtok_r(NULL, " ", &last))) { - if (argc < MAX_MACRO_TOKENS) { - argv[argc++] = p; - } else { - fprintf(stderr, "Too many arguments in macro definition on line %d\n", line_num); - return -1; - } - } - - if (argc < 2) { - fprintf(stderr, "Macro definition requires at least two arguments on line %d\n", line_num); - return -1; - } - - if (argv[0][0] != '$') { - fprintf(stderr, "Macro name should start with '$' on line %d\n", line_num); - return -1; - } - - if (opts_find_macro(opts->macro, argv[0])) { - fprintf(stderr, "Macro name '%s' already exists on line %d\n", argv[0], line_num); - return -1; - } - - macro_t *macro = malloc(sizeof(macro_t)); - if (!macro) - return oom_return_na(); - memset(macro, 0, sizeof(macro_t)); - - macro->name = strdup(argv[0]); - if (!macro->name) - return oom_return_na(); - - int i = 1; - while (i < argc) { - // Do not allow macro within macro, no recursive macro definitions - if (argv[i][0] == '$') { - fprintf(stderr, "Invalid macro value '%s' on line %d\n", argv[i], line_num); - return -1; - } - - value_t *v = malloc(sizeof(value_t)); - if (!v) - return oom_return_na(); - memset(v, 0, sizeof(value_t)); - - v->value = strdup(argv[i++]); - if (!v->value) - return oom_return_na(); - - opts_append_to_macro_values(¯o->value, v); - } - - macro->next = opts->macro; - opts->macro = macro; - -#ifdef DEBUG_OPTS - log_dbg_printf("Macro: %s = %s\n", macro->name, value_str(macro->value)); -#endif /* DEBUG_OPTS */ - return 0; -} - -static int WUNRES -opts_set_site(filter_rule_t *rule, const char *site, int line_num) -{ - // The for loop with strtok_r() does not output empty strings - // So, no need to check if the length of argv[0] > 0 - size_t len = strlen(site); - - if (len > MAX_SITE_LEN) { - fprintf(stderr, "Filter site too long %zu > %d on line %d\n", len, MAX_SITE_LEN, line_num); - return -1; - } - - // Don't modify site, site is reused in macro expansion - rule->site = strdup(site); - if (!rule->site) - return oom_return_na(); - - if (rule->site[len - 1] == '*') { - rule->exact = 0; - len--; - rule->site[len] = '\0'; - // site == "*" ? - if (len == 0) - rule->all_sites = 1; - } else { - rule->exact = 1; - } - - // redundant? - if (equal(rule->site, "*")) - rule->all_sites = 1; - return 0; -} - -static int WUNRES -opts_set_port(filter_rule_t *rule, const char *port, int line_num) -{ -#define MAX_PORT_LEN 6 - - size_t len = strlen(port); - - if (len > MAX_PORT_LEN) { - fprintf(stderr, "Filter port too long %zu > %d on line %d\n", len, MAX_PORT_LEN, line_num); - return -1; - } - - rule->port = strdup(port); - if (!rule->port) - return oom_return_na(); - - if (rule->port[len - 1] == '*') { - rule->exact_port = 0; - len--; - rule->port[len] = '\0'; - // site == "*" ? - if (len == 0) - rule->all_ports = 1; - } else { - rule->exact_port = 1; - } - - // redundant? - if (equal(rule->port, "*")) - rule->all_ports = 1; - - if (!rule->site) { - rule->site = strdup(""); - if (!rule->site) - return oom_return_na(); - } - return 0; -} - -static int WUNRES -opts_inc_arg_index(int i, int argc, char *last, int line_num) -{ - if (i + 1 < argc) { - return i + 1; - } else { - fprintf(stderr, "Not enough arguments in filter rule after '%s' on line %d\n", last, line_num); - return -1; - } -} - -static int WUNRES -filter_rule_translate(opts_t *opts, const char *name, int argc, char **argv, int line_num) -{ - //(Divert|Split|Pass|Block|Match) - // ([from ( - // user (username|$macro|*) [desc (keyword|$macro|*)]| - // desc (keyword|$macro|*)| - // ip (clientip|$macro|*)| - // *)] - // [to ( - // sni (servername[*]|$macro|*)| - // cn (commonname[*]|$macro|*)| - // host (host[*]|$macro|*)| - // uri (uri[*]|$macro|*)| - // ip (serverip[*]|$macro|*) [port (serverport[*]|$macro|*)]| - // port (serverport[*]|$macro|*)| - // *)] - // [log ([[!]connect] [[!]master] [[!]cert] - // [[!]content] [[!]pcap] [[!]mirror] [$macro]|*|!*)] - // |*) - - filter_rule_t *rule = malloc(sizeof(filter_rule_t)); - if (!rule) - return oom_return_na(); - memset(rule, 0, sizeof(filter_rule_t)); - - if (equal(name, "Divert")) - rule->action.divert = 1; - else if (equal(name, "Split")) - rule->action.split = 1; - else if (equal(name, "Pass")) - rule->action.pass = 1; - else if (equal(name, "Block")) - rule->action.block = 1; - else if (equal(name, "Match")) - rule->action.match = 1; - - // precedence can only go up not down - rule->action.precedence = 0; - - int done_from = 0; - int done_to = 0; - int i = 0; - while (i < argc) { - if (equal(argv[i], "*")) { - i++; - } - else if (equal(argv[i], "from")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; -#ifndef WITHOUT_USERAUTH - if (equal(argv[i], "user") || equal(argv[i], "desc")) { - if (equal(argv[i], "user")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - rule->action.precedence++; - - if (equal(argv[i], "*")) { - rule->all_users = 1; - } else { - rule->action.precedence++; - rule->user = strdup(argv[i]); - if (!rule->user) - return oom_return_na(); - } - i++; - } - - if (i < argc && equal(argv[i], "desc")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - rule->action.precedence++; - rule->keyword = strdup(argv[i++]); - if (!rule->keyword) - return oom_return_na(); - } - - done_from = 1; - } - else -#endif /* !WITHOUT_USERAUTH */ - if (equal(argv[i], "ip")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if (equal(argv[i], "*")) { - rule->all_conns = 1; - } else { - rule->action.precedence++; - rule->ip = strdup(argv[i]); - if (!rule->ip) - return oom_return_na(); - } - i++; - done_from = 1; - } - else if (equal(argv[i], "*")) { - i++; - } - } - else if (equal(argv[i], "to")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if (equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri")) { - rule->action.precedence++; - if (equal(argv[i], "sni")) - rule->sni = 1; - else if (equal(argv[i], "cn")) - rule->cn = 1; - else if (equal(argv[i], "host")) - rule->host = 1; - else if (equal(argv[i], "uri")) - rule->uri = 1; - - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if (opts_set_site(rule, argv[i++], line_num) == -1) - return -1; - - done_to = 1; - } - else if (equal(argv[i], "ip") || equal(argv[i], "port")) { - rule->dstip = 1; - - if (equal(argv[i], "ip")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - // Just ip spec should not increase rule precedence - - if (opts_set_site(rule, argv[i++], line_num) == -1) - return -1; - } - - if (i < argc && equal(argv[i], "port")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - rule->action.precedence++; - - if (opts_set_port(rule, argv[i++], line_num) == -1) - return -1; - } - - done_to = 1; - } - else if (equal(argv[i], "*")) { - i++; - } - } - else if (equal(argv[i], "log")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - rule->action.precedence++; - - if (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || - equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") -#ifndef WITHOUT_MIRROR - || equal(argv[i], "mirror") || equal(argv[i], "!mirror") -#endif /* !WITHOUT_MIRROR */ - ) { - do { - if (equal(argv[i], "connect")) - rule->action.log_connect = 2; - else if (equal(argv[i], "master")) - rule->action.log_master = 2; - else if (equal(argv[i], "cert")) - rule->action.log_cert = 2; - else if (equal(argv[i], "content")) - rule->action.log_content = 2; - else if (equal(argv[i], "pcap")) - rule->action.log_pcap = 2; - else if (equal(argv[i], "!connect")) - rule->action.log_connect = 1; - else if (equal(argv[i], "!master")) - rule->action.log_master = 1; - else if (equal(argv[i], "!cert")) - rule->action.log_cert = 1; - else if (equal(argv[i], "!content")) - rule->action.log_content = 1; - else if (equal(argv[i], "!pcap")) - rule->action.log_pcap = 1; -#ifndef WITHOUT_MIRROR - else if (equal(argv[i], "mirror")) - rule->action.log_mirror = 2; - else if (equal(argv[i], "!mirror")) - rule->action.log_mirror = 1; -#endif /* !WITHOUT_MIRROR */ - - if (++i == argc) - break; - } while (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || - equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") -#ifndef WITHOUT_MIRROR - || equal(argv[i], "mirror") || equal(argv[i], "!mirror") -#endif /* !WITHOUT_MIRROR */ - ); - } - else if (equal(argv[i], "*")) { - rule->action.log_connect = 2; - rule->action.log_master = 2; - rule->action.log_cert = 2; - rule->action.log_content = 2; - rule->action.log_pcap = 2; -#ifndef WITHOUT_MIRROR - rule->action.log_mirror = 2; -#endif /* !WITHOUT_MIRROR */ - i++; - } - else if (equal(argv[i], "!*")) { - rule->action.log_connect = 1; - rule->action.log_master = 1; - rule->action.log_cert = 1; - rule->action.log_content = 1; - rule->action.log_pcap = 1; -#ifndef WITHOUT_MIRROR - rule->action.log_mirror = 1; -#endif /* !WITHOUT_MIRROR */ - i++; - } - } - } - - if (!done_from) { - rule->all_conns = 1; - } - if (!done_to) { - rule->site = strdup(""); - if (!rule->site) - return oom_return_na(); - rule->all_sites = 1; - rule->sni = 1; - rule->cn = 1; - rule->host = 1; - rule->uri = 1; - rule->dstip = 1; - } - - opts_append_to_filter_rules(&opts->filter_rules, rule); - -#ifdef DEBUG_OPTS - opts_dbg_print_filter_rule(rule); -#endif /* DEBUG_OPTS */ - return 0; -} - -static int WUNRES -filter_rule_parse(opts_t *opts, const char *name, int argc, char **argv, int line_num); - -#define MAX_FILTER_RULE_TOKENS 15 - -static int WUNRES -filter_rule_expand_macro(opts_t *opts, const char *name, int argc, char **argv, int i, int line_num) -{ - if (argv[i][0] == '$') { - macro_t *macro; - if ((macro = opts_find_macro(opts->macro, argv[i]))) { - value_t *value = macro->value; - while (value) { - // Prevent infinite macro expansion, macros do not allow it, but macro expansion should detect it too - if (value->value[0] == '$') { - fprintf(stderr, "Invalid macro value '%s' on line %d\n", value->value, line_num); - return -1; - } - - char *expanded_argv[sizeof(char *) * MAX_FILTER_RULE_TOKENS]; - memcpy(expanded_argv, argv, sizeof expanded_argv); - - expanded_argv[i] = value->value; - - if (filter_rule_parse(opts, name, argc, expanded_argv, line_num) == -1) - return -1; - - value = value->next; - } - // End of macro expansion, the caller must stop processing the rule - return 1; - } - else { - fprintf(stderr, "No such macro '%s' on line %d\n", argv[i], line_num); - return -1; - } - } - return 0; -} - -static int WUNRES -filter_rule_parse(opts_t *opts, const char *name, int argc, char **argv, int line_num) -{ - int done_all = 0; - int done_from = 0; - int done_to = 0; - int done_log = 0; - int rv = 0; - int i = 0; - while (i < argc) { - if (equal(argv[i], "*")) { - if (done_all) { - fprintf(stderr, "Only one '*' statement allowed on line %d\n", line_num); - return -1; - } - if (++i > argc) { - fprintf(stderr, "Too many arguments for '*' on line %d\n", line_num); - return -1; - } - done_all = 1; - } - else if (equal(argv[i], "from")) { - if (done_from) { - fprintf(stderr, "Only one 'from' statement allowed on line %d\n", line_num); - return -1; - } - - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; -#ifndef WITHOUT_USERAUTH - if (equal(argv[i], "user") || equal(argv[i], "desc")) { - if (equal(argv[i], "user")) { - if (!opts->user_auth) { - fprintf(stderr, "User filter requires user auth on line %d\n", line_num); - return -1; - } - - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if (equal(argv[i], "*")) { - // Nothing to do - } - else if ((rv = filter_rule_expand_macro(opts, name, argc, argv, i, line_num)) != 0) { - return rv; - } - else if (!sys_isuser(argv[i])) { - fprintf(stderr, "No such user '%s' on line %d\n", argv[i], line_num); - return -1; - } - i++; - } - - // It is possible to define desc without user (i.e. * or all_users), hence no 'else' here - if (i < argc && equal(argv[i], "desc")) { - if (!opts->user_auth) { - fprintf(stderr, "Desc filter requires user auth on line %d\n", line_num); - return -1; - } - - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if ((rv = filter_rule_expand_macro(opts, name, argc, argv, i, line_num)) != 0) { - return rv; - } - i++; - } - - done_from = 1; - } - else -#endif /* !WITHOUT_USERAUTH */ - if (equal(argv[i], "ip")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if (equal(argv[i], "*")) { - // Nothing to do - } - else if ((rv = filter_rule_expand_macro(opts, name, argc, argv, i, line_num)) != 0) { - return rv; - } - i++; - done_from = 1; - } - else if (equal(argv[i], "*")) { - i++; - } - else { - fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); - return -1; - } - } - else if (equal(argv[i], "to")) { - if (done_to) { - fprintf(stderr, "Only one 'to' statement allowed on line %d\n", line_num); - return -1; - } - - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if (equal(argv[i], "sni") || equal(argv[i], "cn") || equal(argv[i], "host") || equal(argv[i], "uri")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if ((rv = filter_rule_expand_macro(opts, name, argc, argv, i, line_num)) != 0) { - return rv; - } - i++; - - done_to = 1; - } - else if (equal(argv[i], "ip") || equal(argv[i], "port")) { - if (equal(argv[i], "ip")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if ((rv = filter_rule_expand_macro(opts, name, argc, argv, i, line_num)) != 0) { - return rv; - } - i++; - } - - // It is possible to define port without ip (i.e. * or all_sites), hence no 'else' here - if (i < argc && equal(argv[i], "port")) { - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if ((rv = filter_rule_expand_macro(opts, name, argc, argv, i, line_num)) != 0) { - return rv; - } - i++; - } - - done_to = 1; - } - else if (equal(argv[i], "*")) { - i++; - } - else { - fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); - return -1; - } - } - else if (equal(argv[i], "log")) { - if (done_log) { - fprintf(stderr, "Only one 'log' statement allowed on line %d\n", line_num); - return -1; - } - - if ((i = opts_inc_arg_index(i, argc, argv[i], line_num)) == -1) - return -1; - - if (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || - equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") -#ifndef WITHOUT_MIRROR - || equal(argv[i], "mirror") || equal(argv[i], "!mirror") -#endif /* !WITHOUT_MIRROR */ - || argv[i][0] == '$') { - do { - if ((rv = filter_rule_expand_macro(opts, name, argc, argv, i, line_num)) != 0) { - return rv; - } - if (++i == argc) - break; - } while (equal(argv[i], "connect") || equal(argv[i], "master") || equal(argv[i], "cert") || equal(argv[i], "content") || equal(argv[i], "pcap") || - equal(argv[i], "!connect") || equal(argv[i], "!master") || equal(argv[i], "!cert") || equal(argv[i], "!content") || equal(argv[i], "!pcap") -#ifndef WITHOUT_MIRROR - || equal(argv[i], "mirror") || equal(argv[i], "!mirror") -#endif /* !WITHOUT_MIRROR */ - || argv[i][0] == '$'); - - done_log = 1; - } - else if (equal(argv[i], "*")) { - i++; - done_log = 1; - } - else if (equal(argv[i], "!*")) { - i++; - done_log = 1; - } - else { - fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); - return -1; - } - } - else { - fprintf(stderr, "Unknown argument in filter rule at '%s' on line %d\n", argv[i], line_num); - return -1; - } - } - - // All checks passed and all macros expanded, if any - return filter_rule_translate(opts, name, argc, argv, line_num); -} - -int -opts_set_filter_rule(opts_t *opts, const char *name, char *value, int line_num) -{ - char *argv[sizeof(char *) * MAX_FILTER_RULE_TOKENS]; - int argc = 0; - char *p, *last = NULL; - - for ((p = strtok_r(value, " ", &last)); - p; - (p = strtok_r(NULL, " ", &last))) { - if (argc < MAX_FILTER_RULE_TOKENS) { - argv[argc++] = p; - } else { - fprintf(stderr, "Too many arguments in filter rule on line %d\n", line_num); - return -1; - } +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + { + fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", + argv0, optarg); + return -1; } - - return filter_rule_parse(opts, name, argc, argv, line_num); +#ifdef DEBUG_OPTS + log_dbg_printf("ForceSSLProto: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; } -static filter_port_t * -opts_find_port(filter_port_t *port, filter_rule_t *rule) +/* + * Parse SSL proto string in optarg and set the corresponding no_foo bit. + */ +int +opts_disable_proto(opts_t *opts, const char *argv0, const char *optarg) { - while (port) { - if ((port->exact == rule->exact_port) && !strcmp(port->port, rule->port)) - break; - port = port->next; +#ifdef HAVE_SSLV2 + if (!strcmp(optarg, "ssl2")) { + opts->no_ssl2 = 1; + } else +#endif /* HAVE_SSLV2 */ +#ifdef HAVE_SSLV3 + if (!strcmp(optarg, "ssl3")) { + opts->no_ssl3 = 1; + } else +#endif /* HAVE_SSLV3 */ +#ifdef HAVE_TLSV10 + if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { + opts->no_tls10 = 1; + } else +#endif /* HAVE_TLSV10 */ +#ifdef HAVE_TLSV11 + if (!strcmp(optarg, "tls11")) { + opts->no_tls11 = 1; + } else +#endif /* HAVE_TLSV11 */ +#ifdef HAVE_TLSV12 + if (!strcmp(optarg, "tls12")) { + opts->no_tls12 = 1; + } else +#endif /* HAVE_TLSV12 */ +#ifdef HAVE_TLSV13 + if (!strcmp(optarg, "tls13")) { + opts->no_tls13 = 1; + } else +#endif /* HAVE_TLSV13 */ + { + fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", + argv0, optarg); + return -1; } - return port; +#ifdef DEBUG_OPTS + log_dbg_printf("DisableSSLProto: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; } -static int NONNULL(1,2) WUNRES -opts_add_port(filter_port_t **port, filter_rule_t *rule) +static int WUNRES +opts_set_min_proto(UNUSED opts_t *opts, const char *argv0, const char *optarg) { - filter_port_t *p = opts_find_port(*port, rule); - if (!p) { - p = malloc(sizeof(filter_port_t)); - if (!p) - return oom_return_na(); - memset(p, 0, sizeof(filter_port_t)); - p->port = strdup(rule->port); - if (!p->port) - return oom_return_na(); - - // all_ports should be at the end of the port list, it has the lowest precedence - filter_port_t *prev = NULL; - filter_port_t *l = *port; - while (l) { - if (l->all_ports) - break; - prev = l; - l = l->next; - } - - if (prev) { - p->next = prev->next; - prev->next = p; - } - else { - if (*port) - p->next = *port; - *port = p; - } - } - - // Do not override the specs of port rules at higher precedence - // precedence can only go up not down - if (rule->action.precedence >= p->action.precedence) { - p->all_ports = rule->all_ports; - p->exact = rule->exact_port; - - // Multiple rules can set an action for the same port, hence the bit-wise OR - p->action.divert |= rule->action.divert; - p->action.split |= rule->action.split; - p->action.pass |= rule->action.pass; - p->action.block |= rule->action.block; - p->action.match |= rule->action.match; - - // Multiple log actions can be set for the same port - // Multiple rules can enable/disable or don't change a log action for the same port - // 0: don't change, 1: disable, 2: enable - if (rule->action.log_connect) - p->action.log_connect = rule->action.log_connect; - if (rule->action.log_master) - p->action.log_master = rule->action.log_master; - if (rule->action.log_cert) - p->action.log_cert = rule->action.log_cert; - if (rule->action.log_content) - p->action.log_content = rule->action.log_content; - if (rule->action.log_pcap) - p->action.log_pcap = rule->action.log_pcap; -#ifndef WITHOUT_MIRROR - if (rule->action.log_mirror) - p->action.log_mirror = rule->action.log_mirror; -#endif /* !WITHOUT_MIRROR */ - - p->action.precedence = rule->action.precedence; +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20702000L) +#ifdef HAVE_SSLV3 + if (!strcmp(optarg, "ssl3")) { + opts->minsslversion = SSL3_VERSION; + } else +#endif /* HAVE_SSLV3 */ +#ifdef HAVE_TLSV10 + if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { + opts->minsslversion = TLS1_VERSION; + } else +#endif /* HAVE_TLSV10 */ +#ifdef HAVE_TLSV11 + if (!strcmp(optarg, "tls11")) { + opts->minsslversion = TLS1_1_VERSION; + } else +#endif /* HAVE_TLSV11 */ +#ifdef HAVE_TLSV12 + if (!strcmp(optarg, "tls12")) { + opts->minsslversion = TLS1_2_VERSION; + } else +#endif /* HAVE_TLSV12 */ +#ifdef HAVE_TLSV13 + if (!strcmp(optarg, "tls13")) { + opts->minsslversion = TLS1_3_VERSION; + } else +#endif /* HAVE_TLSV13 */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + { + fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", + argv0, optarg); + return -1; } +#ifdef DEBUG_OPTS + log_dbg_printf("MinSSLProto: %s\n", optarg); +#endif /* DEBUG_OPTS */ return 0; } -static filter_site_t * -opts_find_site(filter_site_t *site, filter_rule_t *rule) +static int WUNRES +opts_set_max_proto(UNUSED opts_t *opts, const char *argv0, const char *optarg) { - while (site) { - if ((site->exact == rule->exact) && !strcmp(site->site, rule->site)) - break; - site = site->next; +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20702000L) +#ifdef HAVE_SSLV3 + if (!strcmp(optarg, "ssl3")) { + opts->maxsslversion = SSL3_VERSION; + } else +#endif /* HAVE_SSLV3 */ +#ifdef HAVE_TLSV10 + if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) { + opts->maxsslversion = TLS1_VERSION; + } else +#endif /* HAVE_TLSV10 */ +#ifdef HAVE_TLSV11 + if (!strcmp(optarg, "tls11")) { + opts->maxsslversion = TLS1_1_VERSION; + } else +#endif /* HAVE_TLSV11 */ +#ifdef HAVE_TLSV12 + if (!strcmp(optarg, "tls12")) { + opts->maxsslversion = TLS1_2_VERSION; + } else +#endif /* HAVE_TLSV12 */ +#ifdef HAVE_TLSV13 + if (!strcmp(optarg, "tls13")) { + opts->maxsslversion = TLS1_3_VERSION; + } else +#endif /* HAVE_TLSV13 */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + { + fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", + argv0, optarg); + return -1; } - return site; +#ifdef DEBUG_OPTS + log_dbg_printf("MaxSSLProto: %s\n", optarg); +#endif /* DEBUG_OPTS */ + return 0; } -static int NONNULL(1,2) WUNRES -opts_add_site(filter_site_t **site, filter_rule_t *rule) +static void +opts_set_remove_http_accept_encoding(opts_t *opts) { - filter_site_t *s = opts_find_site(*site, rule); - if (!s) { - s = malloc(sizeof(filter_site_t)); - if (!s) - return oom_return_na(); - memset(s, 0, sizeof(filter_site_t)); - s->site = strdup(rule->site); - if (!s->site) - return oom_return_na(); - - // all_sites should be at the end of the site list, it has the lowest precedence - filter_site_t *prev = NULL; - filter_site_t *l = *site; - while (l) { - if (l->all_sites) - break; - prev = l; - l = l->next; - } - - if (prev) { - s->next = prev->next; - prev->next = s; - } - else { - if (*site) - s->next = *site; - *site = s; - } - } - - s->all_sites = rule->all_sites; - s->exact = rule->exact; - - // Do not override the specs of a site with a port rule - // Port rule is added as a new port under the same site - // hence 'if else', not just 'if' - if (rule->port) { - if (opts_add_port(&s->port, rule) == -1) - return -1; - } - // Do not override the specs of site rules at higher precedence - // precedence can only go up not down - else if (rule->action.precedence >= s->action.precedence) { - // Multiple rules can set an action for the same site, hence the bit-wise OR - s->action.divert |= rule->action.divert; - s->action.split |= rule->action.split; - s->action.pass |= rule->action.pass; - s->action.block |= rule->action.block; - s->action.match |= rule->action.match; - - // Multiple log actions can be set for the same site - // Multiple rules can enable/disable or don't change a log action for the same site - // 0: don't change, 1: disable, 2: enable - if (rule->action.log_connect) - s->action.log_connect = rule->action.log_connect; - if (rule->action.log_master) - s->action.log_master = rule->action.log_master; - if (rule->action.log_cert) - s->action.log_cert = rule->action.log_cert; - if (rule->action.log_content) - s->action.log_content = rule->action.log_content; - if (rule->action.log_pcap) - s->action.log_pcap = rule->action.log_pcap; -#ifndef WITHOUT_MIRROR - if (rule->action.log_mirror) - s->action.log_mirror = rule->action.log_mirror; -#endif /* !WITHOUT_MIRROR */ - - s->action.precedence = rule->action.precedence; - } - return 0; + opts->remove_http_accept_encoding = 1; } -static int -opts_add_to_sitelist(filter_list_t *list, filter_rule_t *rule) +static void +opts_unset_remove_http_accept_encoding(opts_t *opts) { - if (rule->dstip) { - if (opts_add_site(&list->ip, rule) == -1) - return -1; - } - if (rule->sni) { - if (opts_add_site(&list->sni, rule) == -1) - return -1; - } - if (rule->cn) { - if (opts_add_site(&list->cn, rule) == -1) - return -1; - } - if (rule->host) { - if (opts_add_site(&list->host, rule) == -1) - return -1; - } - if (rule->uri) { - if (opts_add_site(&list->uri, rule) == -1) - return -1; - } - return 0; + opts->remove_http_accept_encoding = 0; } -filter_ip_t * -opts_find_ip(filter_ip_t *list, char *i) +static void +opts_set_remove_http_referer(opts_t *opts) { - while (list) { - if (!strcmp(list->ip, i)) - break; - list = list->next; - } - return list; + opts->remove_http_referer = 1; } -static filter_ip_t * -opts_get_ip(filter_ip_t **list, char *i) +static void +opts_unset_remove_http_referer(opts_t *opts) { - filter_ip_t *ip = opts_find_ip(*list, i); - if (!ip) { - ip = malloc(sizeof(filter_ip_t)); - if (!ip) - return oom_return_na_null(); - memset(ip, 0, sizeof(filter_ip_t)); - - ip->list = malloc(sizeof(filter_list_t)); - if (!ip->list) - return oom_return_na_null(); - memset(ip->list, 0, sizeof(filter_list_t)); - - ip->ip = strdup(i); - if (!ip->ip) - return oom_return_na_null(); - ip->next = *list; - *list = ip; - } - return ip; + opts->remove_http_referer = 0; } -#ifndef WITHOUT_USERAUTH -filter_keyword_t * -opts_find_keyword(filter_keyword_t *list, char *k) +static void +opts_set_verify_peer(opts_t *opts) { - while (list) { - if (!strcmp(list->keyword, k)) - break; - list = list->next; - } - return list; + opts->verify_peer = 1; } -static filter_keyword_t * -opts_get_keyword(filter_keyword_t **list, char *k) +static void +opts_unset_verify_peer(opts_t *opts) { - filter_keyword_t *keyword = opts_find_keyword(*list, k); - if (!keyword) { - keyword = malloc(sizeof(filter_keyword_t)); - if (!keyword) - return oom_return_na_null(); - memset(keyword, 0, sizeof(filter_keyword_t)); - - keyword->list = malloc(sizeof(filter_list_t)); - if (!keyword->list) - return oom_return_na_null(); - memset(keyword->list, 0, sizeof(filter_list_t)); - - keyword->keyword = strdup(k); - if (!keyword->keyword) - return oom_return_na_null(); - keyword->next = *list; - *list = keyword; - } - return keyword; + opts->verify_peer = 0; } -filter_user_t * -opts_find_user(filter_user_t *list, char *u) +static void +opts_set_allow_wrong_host(opts_t *opts) { - while (list) { - if (!strcmp(list->user, u)) - break; - list = list->next; - } - return list; + opts->allow_wrong_host = 1; } -static filter_user_t * -opts_get_user(filter_user_t **list, char *u) +static void +opts_unset_allow_wrong_host(opts_t *opts) { - filter_user_t *user = opts_find_user(*list, u); - if (!user) { - user = malloc(sizeof(filter_user_t)); - if (!user) - return oom_return_na_null(); - memset(user, 0, sizeof(filter_user_t)); - - user->list = malloc(sizeof(filter_list_t)); - if (!user->list) - return oom_return_na_null(); - memset(user->list, 0, sizeof(filter_list_t)); - - user->user = strdup(u); - if (!user->user) - return oom_return_na_null(); - user->next = *list; - *list = user; - } - return user; + opts->allow_wrong_host = 0; } -#endif /* WITHOUT_USERAUTH */ -filter_t * -opts_set_filter(filter_rule_t *rule) +#ifndef WITHOUT_USERAUTH +static void +opts_set_user_auth(UNUSED opts_t *opts) { - filter_t *filter = malloc(sizeof(filter_t)); - if (!filter) - return oom_return_na_null(); - memset(filter, 0, sizeof(filter_t)); +#if defined(__OpenBSD__) || defined(__linux__) + // Enable user auth on OpenBSD and Linux only + opts->user_auth = 1; +#endif /* __OpenBSD__ || __linux__ */ +} -#ifndef WITHOUT_USERAUTH - filter->all_user = malloc(sizeof(filter_list_t)); - if (!filter->all_user) - return oom_return_na_null(); - memset(filter->all_user, 0, sizeof(filter_list_t)); -#endif /* WITHOUT_USERAUTH */ +static void +opts_unset_user_auth(opts_t *opts) +{ + opts->user_auth = 0; +} +#endif /* !WITHOUT_USERAUTH */ - filter->all = malloc(sizeof(filter_list_t)); - if (!filter->all) - return oom_return_na_null(); - memset(filter->all, 0, sizeof(filter_list_t)); +static void +opts_set_validate_proto(opts_t *opts) +{ + opts->validate_proto = 1; +} - while (rule) { -#ifndef WITHOUT_USERAUTH - if (rule->user) { - filter_user_t *user = opts_get_user(&filter->user, rule->user); - if (!user) - return NULL; - if (rule->keyword) { - filter_keyword_t *keyword = opts_get_keyword(&user->keyword, rule->keyword); - if (!keyword) - return NULL; - if (opts_add_to_sitelist(keyword->list, rule) == -1) - return NULL; - } - else { - if (opts_add_to_sitelist(user->list, rule) == -1) - return NULL; - } - } - else if (rule->keyword) { - filter_keyword_t *keyword = opts_get_keyword(&filter->keyword, rule->keyword); - if (!keyword) - return NULL; - if (opts_add_to_sitelist(keyword->list, rule) == -1) - return NULL; - } - else if (rule->all_users) { - if (opts_add_to_sitelist(filter->all_user, rule) == -1) - return NULL; - } - else -#endif /* WITHOUT_USERAUTH */ - if (rule->ip) { - filter_ip_t *ip = opts_get_ip(&filter->ip, rule->ip); - if (!ip) - return NULL; - if (opts_add_to_sitelist(ip->list, rule) == -1) - return NULL; - } - else if (rule->all_conns) { - if (opts_add_to_sitelist(filter->all, rule) == -1) - return NULL; - } - rule = rule->next; - } - return filter; +static void +opts_unset_validate_proto(opts_t *opts) +{ + opts->validate_proto = 0; } #ifndef WITHOUT_USERAUTH @@ -3918,7 +1962,7 @@ opts_set_userlist(char *value, int line_num, userlist_t **list, const char *list return -1; } - // Override the cloned global list, if any + // Override the copied global list, if any if (*list) { free_userlist(*list); *list = NULL; @@ -4652,15 +2696,15 @@ set_option(opts_t *opts, const char *argv0, log_dbg_printf("RemoveHTTPReferer: %u\n", opts->remove_http_referer); #endif /* DEBUG_OPTS */ } else if (equal(name, "PassSite")) { - return opts_set_passsite(opts, value, line_num); + return filter_passsite_set(opts, value, line_num); } else if (equal(name, "Define")) { - return opts_set_macro(opts, value, line_num); + return filter_macro_set(opts, value, line_num); } else if (equal(name, "Split") || equal(name, "Pass") || equal(name, "Block") || equal(name, "Match")) { - return opts_set_filter_rule(opts, name, value, line_num); + return filter_rule_set(opts, name, value, line_num); } else if (equal(name, "Divert")) { yes = is_yesno(value); if (yes == -1) - return opts_set_filter_rule(opts, name, value, line_num); + return filter_rule_set(opts, name, value, line_num); else yes ? opts_set_divert(opts) : opts_unset_divert(opts); } else { diff --git a/src/opts.h b/src/opts.h index 3f54817..1f59910 100644 --- a/src/opts.h +++ b/src/opts.h @@ -177,138 +177,6 @@ typedef struct proxyspec { opts_t *opts; } proxyspec_t; -typedef struct value { - char *value; - struct value *next; -} value_t; - -typedef struct macro { - char *name; - struct value *value; - struct macro *next; -} macro_t; - -typedef struct filter_action { - // Filter action - unsigned int divert : 1; - unsigned int split : 1; - unsigned int pass : 1; - unsigned int block : 1; - unsigned int match : 1; - - // Log action, two bits - // 0: don't change, 1: disable, 2: enable - unsigned int log_connect : 2; - unsigned int log_master : 2; - unsigned int log_cert : 2; - unsigned int log_content : 2; - unsigned int log_pcap : 2; -#ifndef WITHOUT_MIRROR - unsigned int log_mirror : 2; -#endif /* !WITHOUT_MIRROR */ - - // Precedence is used in rule application - // More specific rules have higher precedence - unsigned int precedence; -} filter_action_t; - -typedef struct filter_rule { - // from: source filter - unsigned int all_conns : 1; /* 1 to apply to all src ips and users */ - -#ifndef WITHOUT_USERAUTH - unsigned int all_users : 1; /* 1 to apply to all users */ - - char *user; - char *keyword; -#endif /* !WITHOUT_USERAUTH */ - char *ip; - - // to: target filter - char *site; - unsigned int all_sites : 1; /* 1 to match all sites == '*' */ - unsigned int exact : 1; /* 1 for exact, 0 for substring match */ - - // Used with dstip filters only, i.e. if the site is an ip address - // This is not for the src ip in the 'from' part of rules - char *port; - unsigned int all_ports : 1; /* 1 to match all ports == '*' */ - unsigned int exact_port : 1; /* 1 for exact, 0 for substring match */ - - // Conn field to apply filter to - unsigned int dstip : 1; /* 1 to apply to dst ip */ - unsigned int host : 1; /* 1 to apply to http host */ - unsigned int uri : 1; /* 1 to apply to http uri */ - unsigned int sni : 1; /* 1 to apply to sni */ - unsigned int cn : 1; /* 1 to apply to common names */ - - struct filter_action action; - - struct filter_rule *next; -} filter_rule_t; - -typedef struct filter_port { - char *port; - unsigned int all_ports : 1; - unsigned int exact : 1; - - struct filter_action action; - - struct filter_port *next; -} filter_port_t; - -typedef struct filter_site { - char *site; - unsigned int all_sites : 1; - unsigned int exact : 1; - - // Used with dstip filters only, i.e. if the site is an ip address - struct filter_port *port; - - struct filter_action action; - - struct filter_site *next; -} filter_site_t; - -typedef struct filter_list { - struct filter_site *ip; - struct filter_site *sni; - struct filter_site *cn; - struct filter_site *host; - struct filter_site *uri; -} filter_list_t; - -typedef struct filter_ip { - char *ip; - struct filter_list *list; - struct filter_ip *next; -} filter_ip_t; - -#ifndef WITHOUT_USERAUTH -typedef struct filter_keyword { - char *keyword; - struct filter_list *list; - struct filter_keyword *next; -} filter_keyword_t; - -typedef struct filter_user { - char *user; - struct filter_list *list; - struct filter_keyword *keyword; - struct filter_user *next; -} filter_user_t; -#endif /* !WITHOUT_USERAUTH */ - -typedef struct filter { -#ifndef WITHOUT_USERAUTH - struct filter_user *user; - struct filter_keyword *keyword; - struct filter_list *all_user; -#endif /* !WITHOUT_USERAUTH */ - struct filter_ip *ip; - struct filter_list *all; -} filter_t; - // Temporary global options // global opts strings used while cloning into proxyspec opts // A var of this type is passed around as a flag to indicate if these opts are @@ -393,6 +261,11 @@ typedef struct userdbkeys { } userdbkeys_t; #endif /* !WITHOUT_USERAUTH */ +int oom_return(const char *) WUNRES; +void *oom_return_null(const char *) WUNRES; +int oom_return_na() WUNRES; +void *oom_return_na_null() WUNRES; + cert_t *opts_load_cert_chain_key(const char *) NONNULL(1); void opts_unset_divert(opts_t *) NONNULL(1); @@ -405,9 +278,6 @@ char *proxyspec_str(proxyspec_t *) NONNULL(1) MALLOC WUNRES; opts_t *opts_new(void) MALLOC WUNRES; void opts_free(opts_t *) NONNULL(1); -void opts_free_filter_rules(opts_t *) NONNULL(1); -char *filter_rule_str(filter_rule_t *); -char *filter_str(filter_t *filter); char *opts_proto_dbg_dump(opts_t *) NONNULL(1); int opts_set_cacrt(opts_t *, const char *, const char *, tmp_global_opts_t *) NONNULL(1,2,3) WUNRES; int opts_set_cakey(opts_t *, const char *, const char *, tmp_global_opts_t *) NONNULL(1,2,3) WUNRES; @@ -428,16 +298,6 @@ int opts_force_proto(opts_t *, const char *, const char *) NONNULL(1,2,3) WUNRES int opts_disable_proto(opts_t *, const char *, const char *) NONNULL(1,2,3) WUNRES; int opts_set_ciphers(opts_t *, const char *, const char *) NONNULL(1,2,3) WUNRES; int opts_set_ciphersuites(opts_t *, const char *, const char *) NONNULL(1,2,3) WUNRES; -int opts_set_passsite(opts_t *, char *, int) WUNRES; - -int opts_set_macro(opts_t *, char *, int) WUNRES; -filter_ip_t *opts_find_ip(filter_ip_t *, char *) NONNULL(2); -#ifndef WITHOUT_USERAUTH -filter_keyword_t *opts_find_keyword(filter_keyword_t *, char *) NONNULL(2); -filter_user_t *opts_find_user(filter_user_t *, char *) NONNULL(2); -#endif /* !WITHOUT_USERAUTH */ -int opts_set_filter_rule(opts_t *, const char *, char *, int) WUNRES; -filter_t *opts_set_filter(filter_rule_t *); #define OPTS_DEBUG(global) unlikely((global)->debug) diff --git a/src/pxyconn.c b/src/pxyconn.c index a99e00e..747c277 100644 --- a/src/pxyconn.c +++ b/src/pxyconn.c @@ -2078,11 +2078,11 @@ pxyconn_filter(pxy_conn_ctx_t *ctx, proto_filter_func_t filtercb) #ifndef WITHOUT_USERAUTH if (ctx->user) { log_finest_va("Searching user: %s", ctx->user); - filter_user_t *user = opts_find_user(filter->user, ctx->user); + filter_user_t *user = filter_user_find(filter->user, ctx->user); if (user) { if (ctx->desc) { log_finest_va("Searching user keyword: %s, %s", ctx->user, ctx->desc); - filter_keyword_t *keyword = opts_find_keyword(user->keyword, ctx->desc); + filter_keyword_t *keyword = filter_keyword_find(user->keyword, ctx->desc); if (keyword && (action = filtercb(ctx, keyword->list))) { return action; } @@ -2094,7 +2094,7 @@ pxyconn_filter(pxy_conn_ctx_t *ctx, proto_filter_func_t filtercb) if (ctx->desc) { log_finest_va("Searching keyword: %s", ctx->desc); - filter_keyword_t *keyword = opts_find_keyword(filter->keyword, ctx->desc); + filter_keyword_t *keyword = filter_keyword_find(filter->keyword, ctx->desc); if (keyword && (action = filtercb(ctx, keyword->list))) { return action; } @@ -2108,7 +2108,7 @@ pxyconn_filter(pxy_conn_ctx_t *ctx, proto_filter_func_t filtercb) #endif /* !WITHOUT_USERAUTH */ if (ctx->srchost_str) { log_finest_va("Searching ip: %s", ctx->srchost_str); - filter_ip_t *ip = opts_find_ip(filter->ip, ctx->srchost_str); + filter_ip_t *ip = filter_ip_find(filter->ip, ctx->srchost_str); if (ip && (action = filtercb(ctx, ip->list))) { return action; } diff --git a/src/pxyconn.h b/src/pxyconn.h index f26f8a2..05d25d9 100644 --- a/src/pxyconn.h +++ b/src/pxyconn.h @@ -36,6 +36,7 @@ #include "proxy.h" #include "opts.h" +#include "filter.h" #include "attrib.h" #include "pxythrmgr.h" #include "log.h" diff --git a/tests/check/filter.t.c b/tests/check/filter.t.c index 3895fde..a53271e 100644 --- a/tests/check/filter.t.c +++ b/tests/check/filter.t.c @@ -27,6 +27,7 @@ #include "attrib.h" #include "opts.h" +#include "filter.h" #include #include @@ -38,78 +39,78 @@ START_TEST(set_filter_rule_01) opts_t *opts = opts_new(); s = strdup("*"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); @@ -124,71 +125,71 @@ START_TEST(set_filter_rule_02) opts_t *opts = opts_new(); s = strdup("from ip *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("$macro 192.168.0.1 192.168.0.2"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); // macro expansion returns 1, not 0 s = strdup("from ip $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from ip $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from ip $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from ip $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from ip $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); @@ -203,221 +204,221 @@ START_TEST(set_filter_rule_03) opts_t *opts = opts_new(); s = strdup("$macro root daemon"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); close(2); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == -1, "failed to parse rule"); free(s); opts->user_auth = 1; s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user * desc keyword"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc keyword"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("from user $macro desc $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); @@ -432,159 +433,159 @@ START_TEST(set_filter_rule_04) opts_t *opts = opts_new(); s = strdup("to ip *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port 443"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port 443"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port 443"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port 443"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip * port 443"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port 443"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port 443"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port 443"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port 443"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to ip 192.168.0.1 port 443"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("$macro1 192.168.0.1 192.168.0.2"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("$macro2 443 444"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("to ip $macro1 port $macro2"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to ip $macro1 port $macro2"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to ip $macro1 port $macro2"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to ip $macro1 port $macro2"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to ip $macro1 port $macro2"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); @@ -599,259 +600,259 @@ START_TEST(set_filter_rule_05) opts_t *opts = opts_new(); s = strdup("$macro example.com example*"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("to sni *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni example.com"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni example.com"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni example.com"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni example.com"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni example.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to sni $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to sni $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to sni $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to sni $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to sni $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to cn *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn example.com"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn example.com"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn example.com"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn example.com"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn example.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to cn $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to cn $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to cn $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to cn $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to cn $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to host *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host example.com"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host example.com"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host example.com"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host example.com"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host example.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to host $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to host $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to host $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to host $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to host $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to uri *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri example.com"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri example.com"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri example.com"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri example.com"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri example.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("to uri $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to uri $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to uri $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to uri $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("to uri $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); @@ -866,452 +867,452 @@ START_TEST(set_filter_rule_06) opts_t *opts = opts_new(); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log connect"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log connect"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log connect"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log connect"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log connect"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log master"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log master"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log master"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log master"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log master"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log cert"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log cert"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log cert"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log cert"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log cert"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log content"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log content"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log content"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log content"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log content"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log pcap"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log pcap"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log pcap"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log pcap"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log pcap"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log mirror"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log mirror"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log mirror"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log mirror"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log mirror"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !*"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !*"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !*"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !*"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !*"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !connect"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !connect"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !connect"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !connect"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !connect"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !master"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !master"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !master"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !master"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !master"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !cert"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !cert"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !cert"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !cert"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !cert"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !content"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !content"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !content"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !content"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !content"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !pcap"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !pcap"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !pcap"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !pcap"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !pcap"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !mirror"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !mirror"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !mirror"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !mirror"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("log !mirror"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("$macro connect master cert content pcap mirror"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("log $macro"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("$macro2 !connect !master !cert !content !pcap !mirror"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("log $macro2"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro2"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro2"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro2"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro2"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("$macro3 connect !master cert !content pcap !mirror"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("log $macro3"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro3"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro3"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro3"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro3"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("$macro4 !connect master !cert content !pcap mirror"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("log $macro4"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro4"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro4"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro4"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro4"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("$macro5 connect master cert !content !pcap !mirror"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("log $macro5"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro5"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro5"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro5"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro5"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("$macro6 !connect !master !cert content pcap mirror"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("log $macro6"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro6"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro6"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro6"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); s = strdup("log $macro6"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); @@ -1326,34 +1327,34 @@ START_TEST(set_filter_rule_07) opts_t *opts = opts_new(); s = strdup("*"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from *"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip *"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); opts->user_auth = 1; s = strdup("from user *"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user * desc desc"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from * to * log *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); @@ -1368,7 +1369,7 @@ START_TEST(set_filter_rule_07) "failed to parse rule: %s", s); free(s); - opts->filter = opts_set_filter(opts->filter_rules); + opts->filter = filter_set(opts->filter_rules); s = filter_str(opts->filter); fail_unless(!strcmp(s, "filter=>\n" @@ -1422,53 +1423,53 @@ START_TEST(set_filter_rule_08) opts_t *opts = opts_new(); s = strdup("from ip 192.168.0.1 to ip 192.168.0.2"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1 to ip 192.168.0.2 log connect master cert content pcap mirror"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1 to ip 192.168.0.2 log !connect !cert !pcap"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Block action at precedence 1 is not applied to a site of the same rule at precedence 2 now s = strdup("from ip 192.168.0.1 to ip 192.168.0.2"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target s = strdup("from ip 192.168.0.1 to ip 192.168.0.3"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another source s = strdup("from ip 192.168.0.2 to ip 192.168.0.1"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // all_sites should always be the last element s = strdup("from ip 192.168.0.2 to ip *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Search substring (subnet?) s = strdup("from ip 192.168.0.2 to ip 192.168.0.*"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target s = strdup("from ip 192.168.0.2 to ip 192.168.0.3"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); @@ -1486,7 +1487,7 @@ START_TEST(set_filter_rule_08) "failed to parse rule: %s", s); free(s); - opts->filter = opts_set_filter(opts->filter_rules); + opts->filter = filter_set(opts->filter_rules); s = filter_str(opts->filter); fail_unless(!strcmp(s, "filter=>\n" @@ -1537,59 +1538,59 @@ START_TEST(set_filter_rule_09) opts_t *opts = opts_new(); s = strdup("from ip 192.168.0.1 to ip 192.168.0.2 port 443"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1 to ip 192.168.0.2 port 443 log connect master cert content pcap mirror"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from ip 192.168.0.1 to ip 192.168.0.2 port 443 log !connect !cert !pcap"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Block action at precedence 2 is not applied to a port of the same rule at precedence 3 now s = strdup("from ip 192.168.0.1 to ip 192.168.0.2 port 443"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target, the following port rules should not change this site rule s = strdup("from ip 192.168.0.1 to ip 192.168.0.3 log !mirror"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target port s = strdup("from ip 192.168.0.1 to ip 192.168.0.3 port 443"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target port s = strdup("from ip 192.168.0.1 to ip 192.168.0.3 port 80"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another source s = strdup("from ip 192.168.0.2 to ip 192.168.0.1 port 443"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // all_sites should always be the last element s = strdup("from ip 192.168.0.2 to ip 192.168.0.1 port *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Search substring s = strdup("from ip 192.168.0.2 to ip 192.168.0.1 port 80*"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); @@ -1608,7 +1609,7 @@ START_TEST(set_filter_rule_09) "failed to parse rule: %s", s); free(s); - opts->filter = opts_set_filter(opts->filter_rules); + opts->filter = filter_set(opts->filter_rules); s = filter_str(opts->filter); fail_unless(!strcmp(s, "filter=>\n" @@ -1667,53 +1668,53 @@ START_TEST(set_filter_rule_10) opts->user_auth = 1; s = strdup("from user root to sni example.com"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user root to sni example.com log connect master cert content pcap mirror"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user root to sni example.com log !connect !cert !pcap"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Block action at precedence 2 is not applied to a site of the same rule at precedence 4 now s = strdup("from user root to sni example.com"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target s = strdup("from user root to sni example2.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another source s = strdup("from user daemon to sni example.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // all_sites should always be the last element s = strdup("from user daemon to sni *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Search substring (subdomain?) s = strdup("from user daemon to sni .example.com*"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target s = strdup("from user daemon to sni example3.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); @@ -1731,7 +1732,7 @@ START_TEST(set_filter_rule_10) "failed to parse rule: %s", s); free(s); - opts->filter = opts_set_filter(opts->filter_rules); + opts->filter = filter_set(opts->filter_rules); s = filter_str(opts->filter); fail_unless(!strcmp(s, "filter=>\n" @@ -1784,77 +1785,77 @@ START_TEST(set_filter_rule_11) opts->user_auth = 1; s = strdup("from user root desc desc to cn example.com"); - rv = opts_set_filter_rule(opts, "Divert", s, 0); + rv = filter_rule_set(opts, "Divert", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user root desc desc to cn example.com log connect master cert content pcap mirror"); - rv = opts_set_filter_rule(opts, "Split", s, 0); + rv = filter_rule_set(opts, "Split", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); s = strdup("from user root desc desc to cn example.com log !connect !cert !pcap"); - rv = opts_set_filter_rule(opts, "Pass", s, 0); + rv = filter_rule_set(opts, "Pass", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Block action at precedence 2 is not applied to a site of the same rule at precedence 5 now s = strdup("from user root desc desc to cn example.com"); - rv = opts_set_filter_rule(opts, "Block", s, 0); + rv = filter_rule_set(opts, "Block", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target s = strdup("from user root desc desc to cn example2.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another source s = strdup("from user daemon desc desc to cn example.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // all_sites should always be the last element s = strdup("from user daemon desc desc to cn *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Search substring (subdomain?) s = strdup("from user daemon desc desc to cn .example.com*"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another target s = strdup("from user daemon desc desc to cn example3.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another desc s = strdup("from user daemon desc desc2 to cn example4.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add all users s = strdup("from user * desc desc to cn example5.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add all users all host sites s = strdup("from user * desc desc to host *"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); // Add another desc s = strdup("from user * desc desc3 to uri example6.com"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 0, "failed to parse rule"); free(s); @@ -1876,7 +1877,7 @@ START_TEST(set_filter_rule_11) "failed to parse rule: %s", s); free(s); - opts->filter = opts_set_filter(opts->filter_rules); + opts->filter = filter_set(opts->filter_rules); s = filter_str(opts->filter); fail_unless(!strcmp(s, "filter=>\n" @@ -1951,27 +1952,27 @@ START_TEST(set_filter_rule_12) opts_t *opts = opts_new(); s = strdup("$ips 192.168.0.1 192.168.0.2"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("$dstips 192.168.0.3 192.168.0.4"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("$ports 80 443"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("$logs !master !pcap"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("from ip $ips to ip $dstips port $ports log $logs"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); @@ -1996,7 +1997,7 @@ START_TEST(set_filter_rule_12) "failed to parse rule: %s", s); free(s); - opts->filter = opts_set_filter(opts->filter_rules); + opts->filter = filter_set(opts->filter_rules); s = filter_str(opts->filter); fail_unless(!strcmp(s, "filter=>\n" @@ -2057,17 +2058,17 @@ START_TEST(set_filter_rule_13) opts_t *opts = opts_new(); s = strdup("$users root daemon"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("$descs desc1 desc2"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); s = strdup("$sites site1 site2"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); @@ -2075,14 +2076,14 @@ START_TEST(set_filter_rule_13) // "../../src/check_pack.c:306: Message string too long" // so use 3 log actions only s = strdup("$logs connect content mirror"); - rv = opts_set_macro(opts, s, 0); + rv = filter_macro_set(opts, s, 0); fail_unless(rv == 0, "failed to set macro"); free(s); opts->user_auth = 1; s = strdup("from user $users desc $descs to sni $sites log $logs"); - rv = opts_set_filter_rule(opts, "Match", s, 0); + rv = filter_rule_set(opts, "Match", s, 0); fail_unless(rv == 1, "failed to parse rule"); free(s); @@ -2115,7 +2116,7 @@ START_TEST(set_filter_rule_13) "failed to parse rule: %s", s); free(s); - opts->filter = opts_set_filter(opts->filter_rules); + opts->filter = filter_set(opts->filter_rules); s = filter_str(opts->filter); fail_unless(!strcmp(s, "filter=>\n" diff --git a/tests/check/opts.t.c b/tests/check/opts.t.c index f36fa5b..8517a19 100644 --- a/tests/check/opts.t.c +++ b/tests/check/opts.t.c @@ -29,6 +29,7 @@ #include "attrib.h" #include "opts.h" +#include "filter.h" #include #include @@ -635,7 +636,7 @@ START_TEST(opts_set_passsite_01) opts_t *opts = opts_new(); char *s = strdup("example.com"); - UNUSED int rv = opts_set_passsite(opts, s, 0); + UNUSED int rv = filter_passsite_set(opts, s, 0); free(s); fail_unless(!strcmp(opts->filter_rules->site, "example.com"), "site not example.com"); @@ -665,7 +666,7 @@ START_TEST(opts_set_passsite_02) opts_t *opts = opts_new(); char *s = strdup("example.com 192.168.0.1"); - UNUSED int rv = opts_set_passsite(opts, s, 0); + UNUSED int rv = filter_passsite_set(opts, s, 0); free(s); fail_unless(!strcmp(opts->filter_rules->site, "example.com"), "site not example.com"); @@ -698,7 +699,7 @@ START_TEST(opts_set_passsite_03) opts->user_auth = 1; char *s = strdup("example.com root"); - UNUSED int rv = opts_set_passsite(opts, s, 0); + UNUSED int rv = filter_passsite_set(opts, s, 0); free(s); fail_unless(!strcmp(opts->filter_rules->site, "example.com"), "site not example.com"); @@ -724,7 +725,7 @@ START_TEST(opts_set_passsite_04) opts->user_auth = 1; char *s = strdup("*.google.com * android"); - UNUSED int rv = opts_set_passsite(opts, s, 0); + UNUSED int rv = filter_passsite_set(opts, s, 0); free(s); fail_unless(!strcmp(opts->filter_rules->site, "*.google.com"), "site not *.google.com"); @@ -752,18 +753,18 @@ START_TEST(opts_set_passsite_05) // Dup string using strdup(), otherwise strtok_r() in opts_set_passsite() will cause segmentation fault s = strdup("example.com"); - UNUSED int rv = opts_set_passsite(opts, s, 0); + UNUSED int rv = filter_passsite_set(opts, s, 0); free(s); fail_unless(!opts->filter_rules->next, "next set"); s = strdup("example.com *"); - rv = opts_set_passsite(opts, s, 1); + rv = filter_passsite_set(opts, s, 1); free(s); fail_unless(opts->filter_rules->next, "next not set"); fail_unless(!opts->filter_rules->next->next, "next->next set"); s = strdup("example.com 192.168.0.1"); - rv = opts_set_passsite(opts, s, 2); + rv = filter_passsite_set(opts, s, 2); free(s); fail_unless(opts->filter_rules->next, "next not set"); fail_unless(opts->filter_rules->next->next, "next->next not set"); @@ -773,7 +774,7 @@ START_TEST(opts_set_passsite_05) opts->user_auth = 1; // Use root user, opts_set_passsite() calls sys_isuser() to validate the user s = strdup("example.com root"); - rv = opts_set_passsite(opts, s, 3); + rv = filter_passsite_set(opts, s, 3); free(s); fail_unless(opts->filter_rules->next, "next not set"); fail_unless(opts->filter_rules->next->next, "next->next not set"); @@ -781,7 +782,7 @@ START_TEST(opts_set_passsite_05) fail_unless(!opts->filter_rules->next->next->next->next, "next->next->next->next set"); s = strdup("*.google.com * android"); - rv = opts_set_passsite(opts, s, 4); + rv = filter_passsite_set(opts, s, 4); free(s); #endif /* !WITHOUT_USERAUTH */ ps = filter_rule_str(opts->filter_rules);