Use kbtree BST for exact match in site and port 'to' fields

So, for 'to' fields too, we use two separate data structures: binary
search trees (BST) for exact match and linked lists for substring match.

Now all 'from' and 'to' fields in filtering rules use these two data
structures.

To repeat, filtering rules should be written with exact matches instead
of substring matches, as much as possible. Because BST search must be
much faster than substring search over linked lists.

To repeat, we have modifed kbtree to support complex data structures in
from fields.

Also, update the unit tests accordingly.
pull/48/head
Soner Tari 3 years ago
parent 15991dfb93
commit 4f36a21c78

@ -197,61 +197,101 @@ filter_rules_free(opts_t *opts)
opts->filter_rules = NULL; opts->filter_rules = NULL;
} }
#define free_port(p) { \
free(*p->port); \
free(*p); }
static void
filter_port_btree_free(kbtree_t(port) *port_btree)
{
if (port_btree) {
__kb_traverse(filter_port_p_t, port_btree, free_port);
__kb_destroy(port_btree);
}
}
static void static void
filter_port_free(filter_port_t *port) filter_port_list_free(filter_port_list_t *port)
{ {
while (port) { while (port) {
filter_port_t *p = port->next; filter_port_list_t *p = port->next;
free(port->port); free_port(&port)
free(port);
port = p; port = p;
} }
} }
static filter_site_t * #define free_site(p) { \
filter_site_free(filter_site_t *site) free(*p->site); \
filter_port_btree_free(*p->port_btree); \
filter_port_list_free(*p->port_list); \
free(*p); }
static filter_site_list_t *
filter_site_free(filter_site_list_t *site_list)
{ {
filter_site_t *s = site->next; filter_site_list_t *s = site_list->next;
free(site->site); free_site(&site_list->site)
filter_port_free(site->port); free(site_list);
free(site);
return s; return s;
} }
static void static void
filter_list_free(filter_list_t *list) filter_list_free(filter_list_t *list)
{ {
while (list->ip) if (list->ip_btree) {
list->ip = filter_site_free(list->ip); __kb_traverse(filter_site_p_t, list->ip_btree, free_site);
while (list->sni) __kb_destroy(list->ip_btree);
list->sni = filter_site_free(list->sni); }
while (list->cn) while (list->ip_list)
list->cn = filter_site_free(list->cn); list->ip_list = filter_site_free(list->ip_list);
while (list->host)
list->host = filter_site_free(list->host); if (list->sni_btree) {
while (list->uri) __kb_traverse(filter_site_p_t, list->sni_btree, free_site);
list->uri = filter_site_free(list->uri); __kb_destroy(list->sni_btree);
}
while (list->sni_list)
list->sni_list = filter_site_free(list->sni_list);
if (list->cn_btree) {
__kb_traverse(filter_site_p_t, list->cn_btree, free_site);
__kb_destroy(list->cn_btree);
}
while (list->cn_list)
list->cn_list = filter_site_free(list->cn_list);
if (list->host_btree) {
__kb_traverse(filter_site_p_t, list->host_btree, free_site);
__kb_destroy(list->host_btree);
}
while (list->host_list)
list->host_list = filter_site_free(list->host_list);
if (list->uri_btree) {
__kb_traverse(filter_site_p_t, list->uri_btree, free_site);
__kb_destroy(list->uri_btree);
}
while (list->uri_list)
list->uri_list = filter_site_free(list->uri_list);
free(list); free(list);
} }
#define free_keyword(p) { \
free(*p->keyword); \
filter_list_free(*p->list); \
free(*p); }
static void static void
filter_keyword_list_free(filter_keyword_list_t *list) filter_keyword_list_free(filter_keyword_list_t *list)
{ {
while (list) { while (list) {
free(list->keyword->keyword);
filter_list_free(list->keyword->list);
filter_keyword_list_t *keyword = list->next; filter_keyword_list_t *keyword = list->next;
free_keyword(&list->keyword)
free(list); free(list);
list = keyword; list = keyword;
} }
} }
#define free_keyword(p) { \
free(*p->keyword); \
filter_list_free(*p->list); \
free(*p); }
static void static void
filter_user_free(filter_user_t *user) filter_user_free(filter_user_t *user)
{ {
@ -438,7 +478,7 @@ filter_rules_copy(filter_rule_t *rule, const char *argv0, opts_t *opts)
return oom_return(argv0); return oom_return(argv0);
} }
r->all_sites = rule->all_sites; r->all_sites = rule->all_sites;
r->exact = rule->exact; r->exact_site = rule->exact_site;
if (rule->port) { if (rule->port) {
r->port = strdup(rule->port); r->port = strdup(rule->port);
@ -563,7 +603,7 @@ filter_rule_str(filter_rule_t *rule)
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
STRORNONE(rule->user), STRORNONE(rule->keyword), STRORNONE(rule->user), STRORNONE(rule->keyword),
#endif /* !WITHOUT_USERAUTH */ #endif /* !WITHOUT_USERAUTH */
rule->exact ? "site" : "", rule->exact_port ? "port" : "", rule->exact_ip ? "ip" : "", rule->exact_site ? "site" : "", rule->exact_port ? "port" : "", rule->exact_ip ? "ip" : "",
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
rule->exact_user ? "user" : "", rule->exact_keyword ? "keyword" : "", rule->exact_user ? "user" : "", rule->exact_keyword ? "keyword" : "",
#endif /* !WITHOUT_USERAUTH */ #endif /* !WITHOUT_USERAUTH */
@ -607,33 +647,33 @@ out:
} }
static char * static char *
filter_port_str(filter_port_t *port) filter_port_str(filter_port_list_t *port_list)
{ {
char *s = NULL; char *s = NULL;
int count = 0; int count = 0;
while (port) { while (port_list) {
char *p; char *p;
if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s"
#ifndef WITHOUT_MIRROR #ifndef WITHOUT_MIRROR
"|%s" "|%s"
#endif /* !WITHOUT_MIRROR */ #endif /* !WITHOUT_MIRROR */
", precedence=%d)", STRORNONE(s), count, ", precedence=%d)", STRORNONE(s), count,
port->port, port->all_ports ? "all_ports, " : "", port->exact ? "exact" : "substring", port_list->port->port, port_list->port->all_ports ? "all_ports, " : "", port_list->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_list->port->action.divert ? "divert" : "", port_list->port->action.split ? "split" : "", port_list->port->action.pass ? "pass" : "", port_list->port->action.block ? "block" : "", port_list->port->action.match ? "match" : "",
port->action.log_connect ? (port->action.log_connect == 1 ? "!connect" : "connect") : "", port->action.log_master ? (port->action.log_master == 1 ? "!master" : "master") : "", port_list->port->action.log_connect ? (port_list->port->action.log_connect == 1 ? "!connect" : "connect") : "", port_list->port->action.log_master ? (port_list->port->action.log_master == 1 ? "!master" : "master") : "",
port->action.log_cert ? (port->action.log_cert == 1 ? "!cert" : "cert") : "", port->action.log_content ? (port->action.log_content == 1 ? "!content" : "content") : "", port_list->port->action.log_cert ? (port_list->port->action.log_cert == 1 ? "!cert" : "cert") : "", port_list->port->action.log_content ? (port_list->port->action.log_content == 1 ? "!content" : "content") : "",
port->action.log_pcap ? (port->action.log_pcap == 1 ? "!pcap" : "pcap") : "", port_list->port->action.log_pcap ? (port_list->port->action.log_pcap == 1 ? "!pcap" : "pcap") : "",
#ifndef WITHOUT_MIRROR #ifndef WITHOUT_MIRROR
port->action.log_mirror ? (port->action.log_mirror == 1 ? "!mirror" : "mirror") : "", port_list->port->action.log_mirror ? (port_list->port->action.log_mirror == 1 ? "!mirror" : "mirror") : "",
#endif /* !WITHOUT_MIRROR */ #endif /* !WITHOUT_MIRROR */
port->action.precedence) < 0) { port_list->port->action.precedence) < 0) {
goto err; goto err;
} }
if (s) if (s)
free(s); free(s);
s = p; s = p;
port = port->next; port_list = port_list->next;
count++; count++;
} }
goto out; goto out;
@ -646,41 +686,74 @@ out:
return s; return s;
} }
#define build_port_list(p) { \
filter_port_list_t *s = malloc(sizeof(filter_port_list_t)); \
memset(s, 0, sizeof(filter_port_list_t)); \
s->port = *p; \
s->next = port; \
port = s; }
static void
filter_tmp_port_list_free(filter_port_list_t *port_list)
{
while (port_list) {
filter_port_list_t *next = port_list->next;
free(port_list);
port_list = next;
}
}
static char * static char *
filter_sites_str(filter_site_t *site) filter_sites_str(filter_site_list_t *site_list)
{ {
char *s = NULL; char *s = NULL;
int count = 0; int count = 0;
while (site) { while (site_list) {
char *ports = filter_port_str(site->port); filter_port_list_t *port = NULL;
if (site_list->site->port_btree)
__kb_traverse(filter_port_p_t, site_list->site->port_btree, build_port_list);
char *ports_exact = filter_port_str(port);
char *ports_substring = filter_port_str(site_list->site->port_list);
char *p; char *p;
if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s" if (asprintf(&p, "%s\n %d: %s (%s%s, action=%s|%s|%s|%s|%s, log=%s|%s|%s|%s|%s"
#ifndef WITHOUT_MIRROR #ifndef WITHOUT_MIRROR
"|%s" "|%s"
#endif /* !WITHOUT_MIRROR */ #endif /* !WITHOUT_MIRROR */
", precedence=%d)%s%s", STRORNONE(s), count, ", precedence=%d)%s%s%s%s",
site->site, site->all_sites ? "all_sites, " : "", site->exact ? "exact" : "substring", STRORNONE(s), count,
site->action.divert ? "divert" : "", site->action.split ? "split" : "", site->action.pass ? "pass" : "", site->action.block ? "block" : "", site->action.match ? "match" : "", site_list->site->site, site_list->site->all_sites ? "all_sites, " : "", site_list->site->exact ? "exact" : "substring",
site->action.log_connect ? (site->action.log_connect == 1 ? "!connect" : "connect") : "", site->action.log_master ? (site->action.log_master == 1 ? "!master" : "master") : "", site_list->site->action.divert ? "divert" : "", site_list->site->action.split ? "split" : "", site_list->site->action.pass ? "pass" : "", site_list->site->action.block ? "block" : "", site_list->site->action.match ? "match" : "",
site->action.log_cert ? (site->action.log_cert == 1 ? "!cert" : "cert") : "", site->action.log_content ? (site->action.log_content == 1 ? "!content" : "content") : "", site_list->site->action.log_connect ? (site_list->site->action.log_connect == 1 ? "!connect" : "connect") : "", site_list->site->action.log_master ? (site_list->site->action.log_master == 1 ? "!master" : "master") : "",
site->action.log_pcap ? (site->action.log_pcap == 1 ? "!pcap" : "pcap") : "", site_list->site->action.log_cert ? (site_list->site->action.log_cert == 1 ? "!cert" : "cert") : "", site_list->site->action.log_content ? (site_list->site->action.log_content == 1 ? "!content" : "content") : "",
site_list->site->action.log_pcap ? (site_list->site->action.log_pcap == 1 ? "!pcap" : "pcap") : "",
#ifndef WITHOUT_MIRROR #ifndef WITHOUT_MIRROR
site->action.log_mirror ? (site->action.log_mirror == 1 ? "!mirror" : "mirror") : "", site_list->site->action.log_mirror ? (site_list->site->action.log_mirror == 1 ? "!mirror" : "mirror") : "",
#endif /* !WITHOUT_MIRROR */ #endif /* !WITHOUT_MIRROR */
site->action.precedence, site_list->site->action.precedence,
ports ? "\n port:" : "", STRORNONE(ports)) < 0) { ports_exact ? "\n port exact:" : "", STRORNONE(ports_exact),
if (ports) ports_substring ? "\n port substring:" : "", STRORNONE(ports_substring)) < 0) {
free(ports); if (ports_exact) {
free(ports_exact);
filter_tmp_port_list_free(port);
}
if (ports_substring)
free(ports_substring);
goto err; goto err;
} }
if (ports) if (ports_exact) {
free(ports); free(ports_exact);
filter_tmp_port_list_free(port);
}
if (ports_substring)
free(ports_substring);
if (s) if (s)
free(s); free(s);
s = p; s = p;
site = site->next; site_list = site_list->next;
count++; count++;
} }
goto out; goto out;
@ -694,63 +767,95 @@ out:
} }
static char * static char *
filter_list_str(filter_list_t *list) filter_list_sub_str(filter_site_list_t *list, char *old_s, const char *name)
{ {
char *p = NULL; char *new_s = NULL;
char *op = NULL; char *s = filter_sites_str(list);
if (asprintf(&new_s, "%s%s %s: %s", STRORNONE(old_s), old_s ? "\n" : "", name, STRORNONE(s)) < 0) {
// @todo Handle oom, don't use STRORNONE() // @todo Handle oom, and don't just use STRORNONE()
char *s = filter_sites_str(list->ip); new_s = NULL;
if (asprintf(&p, " ip: %s", STRORNONE(s)) < 0) {
goto err;
} }
if (s) if (s)
free(s); free(s);
op = p; if (old_s)
free(old_s);
return new_s;
}
s = filter_sites_str(list->sni); static void
if (asprintf(&p, "%s\n sni: %s", op, STRORNONE(s)) < 0) { filter_tmp_site_list_free(filter_site_list_t **list)
goto err; {
while (*list) {
filter_site_list_t *next = (*list)->next;
free(*list);
*list = next;
} }
if (s) *list = NULL;
free(s); }
free(op);
op = p;
s = filter_sites_str(list->cn); static char *
if (asprintf(&p, "%s\n cn: %s", op, STRORNONE(s)) < 0) { filter_list_str(filter_list_t *list)
goto err; {
char *s = NULL;
filter_site_list_t *site = NULL;
#define build_site_list(p) { \
filter_site_list_t *s = malloc(sizeof(filter_site_list_t)); \
memset(s, 0, sizeof(filter_site_list_t)); \
s->site = *p; \
s->next = site; \
site = s; }
if (list->ip_btree) {
__kb_traverse(filter_site_p_t, list->ip_btree, build_site_list);
s = filter_list_sub_str(site, s, "ip exact");
filter_tmp_site_list_free(&site);
} }
if (s)
free(s);
free(op);
op = p;
s = filter_sites_str(list->host); if (list->ip_list) {
if (asprintf(&p, "%s\n host: %s", op, STRORNONE(s)) < 0) { s = filter_list_sub_str(list->ip_list, s, "ip substring");
goto err;
} }
if (s)
free(s);
free(op);
op = p;
s = filter_sites_str(list->uri); if (list->sni_btree) {
if (asprintf(&p, "%s\n uri: %s", op, STRORNONE(s)) < 0) { __kb_traverse(filter_site_p_t, list->sni_btree, build_site_list);
goto err; s = filter_list_sub_str(site, s, "sni exact");
filter_tmp_site_list_free(&site);
} }
goto out;
err: if (list->sni_list) {
if (p) { s = filter_list_sub_str(list->sni_list, s, "sni substring");
free(p);
p = NULL;
} }
out:
if (s) if (list->cn_btree) {
free(s); __kb_traverse(filter_site_p_t, list->cn_btree, build_site_list);
if (op) s = filter_list_sub_str(site, s, "cn exact");
free(op); filter_tmp_site_list_free(&site);
return p; }
if (list->cn_list) {
s = filter_list_sub_str(list->cn_list, s, "cn substring");
}
if (list->host_btree) {
__kb_traverse(filter_site_p_t, list->host_btree, build_site_list);
s = filter_list_sub_str(site, s, "host exact");
filter_tmp_site_list_free(&site);
}
if (list->host_list) {
s = filter_list_sub_str(list->host_list, s, "host substring");
}
if (list->uri_btree) {
__kb_traverse(filter_site_p_t, list->uri_btree, build_site_list);
s = filter_list_sub_str(site, s, "uri exact");
filter_tmp_site_list_free(&site);
}
if (list->uri_list) {
s = filter_list_sub_str(list->uri_list, s, "uri substring");
}
return s;
} }
static char * static char *
@ -763,7 +868,8 @@ filter_ip_list_str(filter_ip_list_t *ip_list)
char *list = filter_list_str(ip_list->ip->list); char *list = filter_list_str(ip_list->ip->list);
char *p; char *p;
if (asprintf(&p, "%s%s ip %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, ip_list->ip->ip, STRORNONE(list)) < 0) { if (asprintf(&p, "%s%s ip %d %s (%s)= \n%s", STRORNONE(s), s ? "\n" : "",
count, ip_list->ip->ip, ip_list->ip->exact ? "exact" : "substring", STRORNONE(list)) < 0) {
if (list) if (list)
free(list); free(list);
goto err; goto err;
@ -832,7 +938,8 @@ filter_user_list_str(filter_user_list_t *user)
// It is possible to have users without any filter rule, // It is possible to have users without any filter rule,
// but the user exists because it has keyword filters // but the user exists because it has keyword filters
if (list) { if (list) {
if (asprintf(&p, "%s%s user %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, user->user->user, list) < 0) { if (asprintf(&p, "%s%s user %d %s (%s)= \n%s", STRORNONE(s), s ? "\n" : "",
count, user->user->user, user->user->exact ? "exact" : "substring", list) < 0) {
free(list); free(list);
goto err; goto err;
} }
@ -891,7 +998,8 @@ filter_keyword_list_str(filter_keyword_list_t *keyword)
char *list = filter_list_str(keyword->keyword->list); char *list = filter_list_str(keyword->keyword->list);
char *p; char *p;
if (asprintf(&p, "%s%s keyword %d %s= \n%s", STRORNONE(s), s ? "\n" : "", count, keyword->keyword->keyword, STRORNONE(list)) < 0) { if (asprintf(&p, "%s%s keyword %d %s (%s)= \n%s", STRORNONE(s), s ? "\n" : "",
count, keyword->keyword->keyword, keyword->keyword->exact ? "exact" : "substring", STRORNONE(list)) < 0) {
if (list) if (list)
free(list); free(list);
goto err; goto err;
@ -955,7 +1063,11 @@ filter_userkeyword_list_str(filter_user_list_t *user)
char *list_substr = filter_keyword_list_str(user->user->keyword_list); char *list_substr = filter_keyword_list_str(user->user->keyword_list);
char *p = NULL; char *p = NULL;
if (asprintf(&p, "%s%s user %d %s=\n exact=\n%s\n substring=\n%s", STRORNONE(s), s ? "\n" : "", count, user->user->user, STRORNONE(list_exact), STRORNONE(list_substr)) < 0) { if (asprintf(&p, "%s%s user %d %s (%s)=%s%s%s%s", STRORNONE(s), s ? "\n" : "",
count, user->user->user, user->user->exact ? "exact" : "substring",
list_exact ? "\n keyword exact:\n" : "", STRORNONE(list_exact),
list_substr ? "\n keyword substring:\n" : "", STRORNONE(list_substr)
) < 0) {
if (list_exact) if (list_exact)
free(list_exact); free(list_exact);
if (list_substr) if (list_substr)
@ -1125,7 +1237,7 @@ filter_rule_dbg_print(filter_rule_t *rule)
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
STRORNONE(rule->user), STRORNONE(rule->keyword), STRORNONE(rule->user), STRORNONE(rule->keyword),
#endif /* !WITHOUT_USERAUTH */ #endif /* !WITHOUT_USERAUTH */
rule->exact ? "site" : "", rule->exact_port ? "port" : "", rule->exact_ip ? "ip" : "", rule->exact_site ? "site" : "", rule->exact_port ? "port" : "", rule->exact_ip ? "ip" : "",
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
rule->exact_user ? "user" : "", rule->exact_keyword ? "keyword" : "", rule->exact_user ? "user" : "", rule->exact_keyword ? "keyword" : "",
#endif /* !WITHOUT_USERAUTH */ #endif /* !WITHOUT_USERAUTH */
@ -1189,14 +1301,14 @@ filter_passsite_set(opts_t *opts, char *value, int line_num)
} }
if (argv[0][len - 1] == '*') { if (argv[0][len - 1] == '*') {
rule->exact = 0; rule->exact_site = 0;
len--; len--;
argv[0][len] = '\0'; argv[0][len] = '\0';
// site == "*" ? // site == "*" ?
if (len == 0) if (len == 0)
rule->all_sites = 1; rule->all_sites = 1;
} else { } else {
rule->exact = 1; rule->exact_site = 1;
} }
rule->site = strdup(argv[0]); rule->site = strdup(argv[0]);
@ -1381,14 +1493,14 @@ filter_site_set(filter_rule_t *rule, const char *site, int line_num)
return oom_return_na(); return oom_return_na();
if (rule->site[len - 1] == '*') { if (rule->site[len - 1] == '*') {
rule->exact = 0; rule->exact_site = 0;
len--; len--;
rule->site[len] = '\0'; rule->site[len] = '\0';
// site == "*" ? // site == "*" ?
if (len == 0) if (len == 0)
rule->all_sites = 1; rule->all_sites = 1;
} else { } else {
rule->exact = 1; rule->exact_site = 1;
} }
// redundant? // redundant?
@ -1997,170 +2109,280 @@ filter_rule_set(opts_t *opts, const char *name, char *value, int line_num)
} }
static filter_port_t * static filter_port_t *
filter_port_find(filter_port_t *port, filter_rule_t *rule) filter_port_btree_exact_match(kbtree_t(port) *port_btree, char *p)
{ {
while (port) { if (!port_btree)
if ((port->exact == rule->exact_port) && !strcmp(port->port, rule->port)) return NULL;
filter_port_t **port = kb_get(port, port_btree, p);
return port ? *port : NULL;
}
static filter_port_t *
filter_port_list_substring_match(filter_port_list_t *list, char *p)
{
while (list) {
if (strstr(p, list->port->port))
break;
list = list->next;
}
return list ? list->port : NULL;
}
filter_port_t *
filter_port_find(filter_site_t *site, char *p)
{
filter_port_t *port = filter_port_btree_exact_match(site->port_btree, p);
if (port)
return port;
return filter_port_list_substring_match(site->port_list, p);
}
static filter_port_t *
filter_port_list_exact_match(filter_port_list_t *list, char *p)
{
while (list) {
if (!strcmp(list->port->port, p))
break; break;
port = port->next; list = list->next;
} }
return port; return list ? list->port : NULL;
}
static filter_port_t *
filter_rule_port_find(filter_site_t *site, filter_rule_t *rule)
{
if (rule->exact_port)
return filter_port_btree_exact_match(site->port_btree, rule->port);
else
return filter_port_list_exact_match(site->port_list, rule->port);
} }
static int NONNULL(1,2) WUNRES static int NONNULL(1,2) WUNRES
filter_port_add(filter_port_t **port, filter_rule_t *rule) filter_port_add(filter_site_t *site, filter_rule_t *rule)
{ {
filter_port_t *p = filter_port_find(*port, rule); filter_port_t *port = filter_rule_port_find(site, rule);
if (!p) { if (!port) {
p = malloc(sizeof(filter_port_t)); port = malloc(sizeof(filter_port_t));
if (!p) if (!port)
return oom_return_na(); return oom_return_na();
memset(p, 0, sizeof(filter_port_t)); memset(port, 0, sizeof(filter_port_t));
p->port = strdup(rule->port);
if (!p->port) port->port = strdup(rule->port);
if (!port->port)
return oom_return_na(); return oom_return_na();
// all_ports should be at the end of the port list, it has the lowest precedence if (rule->exact_port) {
filter_port_t *prev = NULL; if (!site->port_btree)
filter_port_t *l = *port; if (!(site->port_btree = kb_init(port, KB_DEFAULT_SIZE)))
while (l) { return oom_return_na();
if (l->all_ports)
break;
prev = l;
l = l->next;
}
if (prev) { kb_put(port, site->port_btree, port);
p->next = prev->next;
prev->next = p;
} }
else { else {
if (*port) filter_port_list_t *port_list = malloc(sizeof(filter_port_list_t));
p->next = *port; if (!port_list)
*port = p; return oom_return_na();
memset(port_list, 0, sizeof(filter_port_list_t));
port_list->port = port;
// all_ports should be at the end of the port list, it has the lowest precedence
filter_port_list_t *prev = NULL;
filter_port_list_t *l = site->port_list;
while (l) {
if (l->port->all_ports)
break;
prev = l;
l = l->next;
}
if (prev) {
port_list->next = prev->next;
prev->next = port_list;
}
else {
if (site->port_list)
port_list->next = site->port_list;
site->port_list = port_list;
}
} }
} }
port->all_ports = rule->all_ports;
port->exact = rule->exact_port;
// Do not override the specs of port rules at higher precedence // Do not override the specs of port rules at higher precedence
// precedence can only go up not down // precedence can only go up not down
if (rule->action.precedence >= p->action.precedence) { if (rule->action.precedence >= port->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 // Multiple rules can set an action for the same port, hence the bit-wise OR
p->action.divert |= rule->action.divert; port->action.divert |= rule->action.divert;
p->action.split |= rule->action.split; port->action.split |= rule->action.split;
p->action.pass |= rule->action.pass; port->action.pass |= rule->action.pass;
p->action.block |= rule->action.block; port->action.block |= rule->action.block;
p->action.match |= rule->action.match; port->action.match |= rule->action.match;
// Multiple log actions can be set for the same port // 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 // Multiple rules can enable/disable or don't change a log action for the same port
// 0: don't change, 1: disable, 2: enable // 0: don't change, 1: disable, 2: enable
if (rule->action.log_connect) if (rule->action.log_connect)
p->action.log_connect = rule->action.log_connect; port->action.log_connect = rule->action.log_connect;
if (rule->action.log_master) if (rule->action.log_master)
p->action.log_master = rule->action.log_master; port->action.log_master = rule->action.log_master;
if (rule->action.log_cert) if (rule->action.log_cert)
p->action.log_cert = rule->action.log_cert; port->action.log_cert = rule->action.log_cert;
if (rule->action.log_content) if (rule->action.log_content)
p->action.log_content = rule->action.log_content; port->action.log_content = rule->action.log_content;
if (rule->action.log_pcap) if (rule->action.log_pcap)
p->action.log_pcap = rule->action.log_pcap; port->action.log_pcap = rule->action.log_pcap;
#ifndef WITHOUT_MIRROR #ifndef WITHOUT_MIRROR
if (rule->action.log_mirror) if (rule->action.log_mirror)
p->action.log_mirror = rule->action.log_mirror; port->action.log_mirror = rule->action.log_mirror;
#endif /* !WITHOUT_MIRROR */ #endif /* !WITHOUT_MIRROR */
p->action.precedence = rule->action.precedence; port->action.precedence = rule->action.precedence;
} }
return 0; return 0;
} }
filter_site_t *
filter_site_btree_exact_match(kbtree_t(site) *site_btree, char *s)
{
if (!site_btree)
return NULL;
filter_site_t **site = kb_get(site, site_btree, s);
return site ? *site : NULL;
}
filter_site_t *
filter_site_list_substring_match(filter_site_list_t *list, char *s)
{
while (list) {
if (strstr(s, list->site->site))
break;
list = list->next;
}
return list ? list->site : NULL;
}
filter_site_t *
filter_site_find(kbtree_t(site) *site_btree, filter_site_list_t *list, char *s)
{
filter_site_t *site = filter_site_btree_exact_match(site_btree, s);
if (site)
return site;
return filter_site_list_substring_match(list, s);
}
static filter_site_t * static filter_site_t *
filter_site_find(filter_site_t *site, filter_rule_t *rule) filter_site_list_exact_match(filter_site_list_t *list, char *s)
{ {
while (site) { while (list) {
if ((site->exact == rule->exact) && !strcmp(site->site, rule->site)) if (!strcmp(list->site->site, s))
break; break;
site = site->next; list = list->next;
} }
return site; return list ? list->site : NULL;
} }
static int NONNULL(1,2) WUNRES static filter_site_t *
filter_site_add(filter_site_t **site, filter_rule_t *rule) filter_rule_site_find(kbtree_t(site) *site_btree, filter_site_list_t *list, filter_rule_t *rule)
{ {
filter_site_t *s = filter_site_find(*site, rule); if (rule->exact_site)
if (!s) { return filter_site_btree_exact_match(site_btree, rule->site);
s = malloc(sizeof(filter_site_t)); else
if (!s) return filter_site_list_exact_match(list, rule->site);
}
static int NONNULL(3) WUNRES
filter_site_add(kbtree_t(site) **site_btree, filter_site_list_t **site_list, filter_rule_t *rule)
{
filter_site_t *site = filter_rule_site_find(*site_btree, *site_list, rule);
if (!site) {
site = malloc(sizeof(filter_site_t));
if (!site)
return oom_return_na(); return oom_return_na();
memset(s, 0, sizeof(filter_site_t)); memset(site, 0, sizeof(filter_site_t));
s->site = strdup(rule->site);
if (!s->site) site->site = strdup(rule->site);
if (!site->site)
return oom_return_na(); return oom_return_na();
// all_sites should be at the end of the site list, it has the lowest precedence if (rule->exact_site) {
filter_site_t *prev = NULL; if (!*site_btree)
filter_site_t *l = *site; if (!(*site_btree = kb_init(site, KB_DEFAULT_SIZE)))
while (l) { return oom_return_na();
if (l->all_sites)
break;
prev = l;
l = l->next;
}
if (prev) { kb_put(site, *site_btree, site);
s->next = prev->next;
prev->next = s;
} }
else { else {
if (*site) filter_site_list_t *list = malloc(sizeof(filter_site_list_t));
s->next = *site; if (!list)
*site = s; return oom_return_na();
memset(list, 0, sizeof(filter_site_list_t));
list->site = site;
// all_sites should be at the end of the site list, it has the lowest precedence
filter_site_list_t *prev = NULL;
filter_site_list_t *l = *site_list;
while (l) {
if (l->site->all_sites)
break;
prev = l;
l = l->next;
}
if (prev) {
list->next = prev->next;
prev->next = list;
}
else {
if (*site_list)
list->next = *site_list;
*site_list = list;
}
} }
} }
s->all_sites = rule->all_sites; site->all_sites = rule->all_sites;
s->exact = rule->exact; site->exact = rule->exact_site;
// Do not override the specs of a site with a port rule // Do not override the specs of a site with a port rule
// Port rule is added as a new port under the same site // Port rule is added as a new port under the same site
// hence 'if else', not just 'if' // hence 'if else', not just 'if'
if (rule->port) { if (rule->port) {
if (filter_port_add(&s->port, rule) == -1) if (filter_port_add(site, rule) == -1)
return -1; return -1;
} }
// Do not override the specs of site rules at higher precedence // Do not override the specs of site rules at higher precedence
// precedence can only go up not down // precedence can only go up not down
else if (rule->action.precedence >= s->action.precedence) { else if (rule->action.precedence >= site->action.precedence) {
// Multiple rules can set an action for the same site, hence the bit-wise OR // Multiple rules can set an action for the same site, hence the bit-wise OR
s->action.divert |= rule->action.divert; site->action.divert |= rule->action.divert;
s->action.split |= rule->action.split; site->action.split |= rule->action.split;
s->action.pass |= rule->action.pass; site->action.pass |= rule->action.pass;
s->action.block |= rule->action.block; site->action.block |= rule->action.block;
s->action.match |= rule->action.match; site->action.match |= rule->action.match;
// Multiple log actions can be set for the same site // 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 // Multiple rules can enable/disable or don't change a log action for the same site
// 0: don't change, 1: disable, 2: enable // 0: don't change, 1: disable, 2: enable
if (rule->action.log_connect) if (rule->action.log_connect)
s->action.log_connect = rule->action.log_connect; site->action.log_connect = rule->action.log_connect;
if (rule->action.log_master) if (rule->action.log_master)
s->action.log_master = rule->action.log_master; site->action.log_master = rule->action.log_master;
if (rule->action.log_cert) if (rule->action.log_cert)
s->action.log_cert = rule->action.log_cert; site->action.log_cert = rule->action.log_cert;
if (rule->action.log_content) if (rule->action.log_content)
s->action.log_content = rule->action.log_content; site->action.log_content = rule->action.log_content;
if (rule->action.log_pcap) if (rule->action.log_pcap)
s->action.log_pcap = rule->action.log_pcap; site->action.log_pcap = rule->action.log_pcap;
#ifndef WITHOUT_MIRROR #ifndef WITHOUT_MIRROR
if (rule->action.log_mirror) if (rule->action.log_mirror)
s->action.log_mirror = rule->action.log_mirror; site->action.log_mirror = rule->action.log_mirror;
#endif /* !WITHOUT_MIRROR */ #endif /* !WITHOUT_MIRROR */
s->action.precedence = rule->action.precedence; site->action.precedence = rule->action.precedence;
} }
return 0; return 0;
} }
@ -2169,23 +2391,23 @@ static int
filter_sitelist_add(filter_list_t *list, filter_rule_t *rule) filter_sitelist_add(filter_list_t *list, filter_rule_t *rule)
{ {
if (rule->dstip) { if (rule->dstip) {
if (filter_site_add(&list->ip, rule) == -1) if (filter_site_add(&list->ip_btree, &list->ip_list, rule) == -1)
return -1; return -1;
} }
if (rule->sni) { if (rule->sni) {
if (filter_site_add(&list->sni, rule) == -1) if (filter_site_add(&list->sni_btree, &list->sni_list, rule) == -1)
return -1; return -1;
} }
if (rule->cn) { if (rule->cn) {
if (filter_site_add(&list->cn, rule) == -1) if (filter_site_add(&list->cn_btree, &list->cn_list, rule) == -1)
return -1; return -1;
} }
if (rule->host) { if (rule->host) {
if (filter_site_add(&list->host, rule) == -1) if (filter_site_add(&list->host_btree, &list->host_list, rule) == -1)
return -1; return -1;
} }
if (rule->uri) { if (rule->uri) {
if (filter_site_add(&list->uri, rule) == -1) if (filter_site_add(&list->uri_btree, &list->uri_list, rule) == -1)
return -1; return -1;
} }
return 0; return 0;
@ -2259,6 +2481,8 @@ filter_ip_get(filter_t *filter, filter_rule_t *rule)
if (!ip->ip) if (!ip->ip)
return oom_return_na_null(); return oom_return_na_null();
ip->exact = rule->exact_ip;
if (rule->exact_ip) { if (rule->exact_ip) {
if (!filter->ip_btree) if (!filter->ip_btree)
if (!(filter->ip_btree = kb_init(ip, KB_DEFAULT_SIZE))) if (!(filter->ip_btree = kb_init(ip, KB_DEFAULT_SIZE)))
@ -2350,6 +2574,8 @@ filter_keyword_get(filter_t *filter, filter_user_t *user, filter_rule_t *rule)
if (!keyword->keyword) if (!keyword->keyword)
return oom_return_na_null(); return oom_return_na_null();
keyword->exact = rule->exact_keyword;
if (rule->exact_keyword) { if (rule->exact_keyword) {
if (user) { if (user) {
if (!user->keyword_btree) if (!user->keyword_btree)
@ -2448,6 +2674,8 @@ filter_user_get(filter_t *filter, filter_rule_t *rule)
if (!user->user) if (!user->user)
return oom_return_na_null(); return oom_return_na_null();
user->exact = rule->exact_user;
if (rule->exact_user) { if (rule->exact_user) {
if (!filter->user_btree) if (!filter->user_btree)
if (!(filter->user_btree = kb_init(user, KB_DEFAULT_SIZE))) if (!(filter->user_btree = kb_init(user, KB_DEFAULT_SIZE)))
@ -2543,9 +2771,9 @@ filter_set(filter_rule_t *rule)
filter_user_p_t x, y = NULL; filter_user_p_t x, y = NULL;
__kb_traverse(filter_user_p_t, filter->user_btree, traverse_user); __kb_traverse(filter_user_p_t, filter->user_btree, traverse_user);
__kb_get_first(filter_user_p_t, filter->user_btree, x); __kb_get_first(filter_user_p_t, filter->user_btree, x);
printf("user_exact # of elements from traversal: %d\n", cnt); fprintf(stderr, "user_exact # of elements from traversal: %d\n", cnt);
if (cnt) if (cnt)
printf("user_exact first element: %s == %s\n", x->user, y->user); fprintf(stderr, "user_exact first element: %s == %s\n", x->user, y->user);
} }
#define traverse_keyword(p) { if (cnt == 0) y2 = *p; ++cnt; } #define traverse_keyword(p) { if (cnt == 0) y2 = *p; ++cnt; }
if (filter->keyword_btree) { if (filter->keyword_btree) {
@ -2553,9 +2781,9 @@ filter_set(filter_rule_t *rule)
filter_keyword_p_t x2, y2 = NULL; filter_keyword_p_t x2, y2 = NULL;
__kb_traverse(filter_keyword_p_t, filter->keyword_btree, traverse_keyword); __kb_traverse(filter_keyword_p_t, filter->keyword_btree, traverse_keyword);
__kb_get_first(filter_keyword_p_t, filter->keyword_btree, x2); __kb_get_first(filter_keyword_p_t, filter->keyword_btree, x2);
printf("keyword_exact # of elements from traversal: %d\n", cnt); fprintf(stderr, "keyword_exact # of elements from traversal: %d\n", cnt);
if (cnt) if (cnt)
printf("keyword_exact first element: %s == %s\n", x2->keyword, y2->keyword); fprintf(stderr, "keyword_exact first element: %s == %s\n", x2->keyword, y2->keyword);
} }
#define traverse_ip(p) { if (cnt == 0) y3 = *p; ++cnt; } #define traverse_ip(p) { if (cnt == 0) y3 = *p; ++cnt; }
if (filter->ip_btree) { if (filter->ip_btree) {
@ -2563,9 +2791,9 @@ filter_set(filter_rule_t *rule)
filter_ip_p_t x3, y3 = NULL; filter_ip_p_t x3, y3 = NULL;
__kb_traverse(filter_ip_p_t, filter->ip_btree, traverse_ip); __kb_traverse(filter_ip_p_t, filter->ip_btree, traverse_ip);
__kb_get_first(filter_ip_p_t, filter->ip_btree, x3); __kb_get_first(filter_ip_p_t, filter->ip_btree, x3);
printf("ip_exact # of elements from traversal: %d\n", cnt); fprintf(stderr, "ip_exact # of elements from traversal: %d\n", cnt);
if (cnt) if (cnt)
printf("ip_exact first element: %s == %s\n", x3->ip, y3->ip); fprintf(stderr, "ip_exact first element: %s == %s\n", x3->ip, y3->ip);
} }
#endif /* DEBUG_OPTS */ #endif /* DEBUG_OPTS */
return filter; return filter;

@ -91,13 +91,13 @@ typedef struct filter_action {
typedef struct filter_rule { typedef struct filter_rule {
// from: source filter // from: source filter
unsigned int all_conns : 1; /* 1 to apply to all src ips and users */ unsigned int all_conns : 1; /* 1 to apply to all src ips and users */
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
unsigned int all_users : 1; /* 1 to apply to all users */ unsigned int all_users : 1; /* 1 to apply to all users */
char *user; char *user;
unsigned int exact_user : 1; /* 1 for exact, 0 for substring match */ unsigned int exact_user : 1; /* 1 for exact, 0 for substring match */
char *keyword; char *keyword;
unsigned int exact_keyword : 1; /* 1 for exact, 0 for substring match */ unsigned int exact_keyword : 1; /* 1 for exact, 0 for substring match */
@ -109,7 +109,7 @@ typedef struct filter_rule {
// to: target filter // to: target filter
char *site; char *site;
unsigned int all_sites : 1; /* 1 to match all sites == '*' */ unsigned int all_sites : 1; /* 1 to match all sites == '*' */
unsigned int exact : 1; /* 1 for exact, 0 for substring match */ unsigned int exact_site : 1; /* 1 for exact, 0 for substring match */
// Used with dstip filters only, i.e. if the site is an ip address // 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 // This is not for the src ip in the 'from' part of rules
@ -132,36 +132,63 @@ typedef struct filter_rule {
typedef struct filter_port { typedef struct filter_port {
char *port; char *port;
unsigned int all_ports : 1; unsigned int all_ports : 1;
unsigned int exact : 1; unsigned int exact : 1; /* used in debug logging only */
struct filter_action action; struct filter_action action;
struct filter_port *next;
} filter_port_t; } filter_port_t;
typedef const char *str_t;
#define getk_port(a) (a)->port
typedef filter_port_t *filter_port_p_t;
KBTREE_INIT(port, filter_port_p_t, kb_str_cmp, str_t, getk_port)
typedef struct filter_port_list {
struct filter_port *port;
struct filter_port_list *next;
} filter_port_list_t;
typedef struct filter_site { typedef struct filter_site {
char *site; char *site;
unsigned int all_sites : 1; unsigned int all_sites : 1;
unsigned int exact : 1; unsigned int exact : 1; /* used in debug logging only */
// Used with dstip filters only, i.e. if the site is an ip address // Used with dstip filters only, i.e. if the site is an ip address
struct filter_port *port; kbtree_t(port) *port_btree;
struct filter_port_list *port_list;
struct filter_action action; struct filter_action action;
struct filter_site *next;
} filter_site_t; } filter_site_t;
#define getk_site(a) (a)->site
typedef filter_site_t *filter_site_p_t;
KBTREE_INIT(site, filter_site_p_t, kb_str_cmp, str_t, getk_site)
typedef struct filter_site_list {
struct filter_site *site;
struct filter_site_list *next;
} filter_site_list_t;
typedef struct filter_list { typedef struct filter_list {
struct filter_site *ip; kbtree_t(site) *ip_btree;
struct filter_site *sni; struct filter_site_list *ip_list;
struct filter_site *cn;
struct filter_site *host; kbtree_t(site) *sni_btree;
struct filter_site *uri; struct filter_site_list *sni_list;
kbtree_t(site) *cn_btree;
struct filter_site_list *cn_list;
kbtree_t(site) *host_btree;
struct filter_site_list *host_list;
kbtree_t(site) *uri_btree;
struct filter_site_list *uri_list;
} filter_list_t; } filter_list_t;
typedef struct filter_ip { typedef struct filter_ip {
char *ip; char *ip;
unsigned int exact : 1; /* used in debug logging only */
struct filter_list *list; struct filter_list *list;
} filter_ip_t; } filter_ip_t;
@ -173,11 +200,10 @@ typedef struct filter_ip_list {
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
typedef struct filter_keyword { typedef struct filter_keyword {
char *keyword; char *keyword;
unsigned int exact : 1; /* used in debug logging only */
struct filter_list *list; struct filter_list *list;
} filter_keyword_t; } filter_keyword_t;
typedef const char *str_t;
#define getk_keyword(a) (a)->keyword #define getk_keyword(a) (a)->keyword
typedef filter_keyword_t *filter_keyword_p_t; typedef filter_keyword_t *filter_keyword_p_t;
KBTREE_INIT(keyword, filter_keyword_p_t, kb_str_cmp, str_t, getk_keyword) KBTREE_INIT(keyword, filter_keyword_p_t, kb_str_cmp, str_t, getk_keyword)
@ -189,6 +215,7 @@ typedef struct filter_keyword_list {
typedef struct filter_user { typedef struct filter_user {
char *user; char *user;
unsigned int exact : 1; /* used in debug logging only */
struct filter_list *list; struct filter_list *list;
kbtree_t(keyword) *keyword_btree; kbtree_t(keyword) *keyword_btree;
struct filter_keyword_list *keyword_list; struct filter_keyword_list *keyword_list;
@ -210,17 +237,17 @@ KBTREE_INIT(ip, filter_ip_p_t, kb_str_cmp, str_t, getk_ip)
typedef struct filter { typedef struct filter {
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
kbtree_t(user) *user_btree; // exact kbtree_t(user) *user_btree; /* exact */
struct filter_user_list *user_list; // substring struct filter_user_list *user_list; /* substring */
kbtree_t(keyword) *keyword_btree; // exact kbtree_t(keyword) *keyword_btree; /* exact */
struct filter_keyword_list *keyword_list; // substring struct filter_keyword_list *keyword_list; /* substring */
struct filter_list *all_user; struct filter_list *all_user;
#endif /* !WITHOUT_USERAUTH */ #endif /* !WITHOUT_USERAUTH */
kbtree_t(ip) *ip_btree; // exact kbtree_t(ip) *ip_btree; /* exact */
struct filter_ip_list *ip_list; // substring struct filter_ip_list *ip_list; /* substring */
struct filter_list *all; struct filter_list *all;
} filter_t; } filter_t;
@ -246,6 +273,12 @@ char *filter_str(filter_t *);
int filter_passsite_set(opts_t *, char *, int) WUNRES; int filter_passsite_set(opts_t *, char *, int) WUNRES;
int filter_macro_set(opts_t *, char *, int) WUNRES; int filter_macro_set(opts_t *, char *, int) WUNRES;
filter_port_t *filter_port_find(filter_site_t *, char *) NONNULL(1,2);
filter_site_t *filter_site_btree_exact_match(kbtree_t(site) *, char *);
filter_site_t *filter_site_list_substring_match(filter_site_list_t *, char *);
filter_site_t *filter_site_find(kbtree_t(site) *, filter_site_list_t *, char *) NONNULL(3) WUNRES;
filter_ip_t *filter_ip_find(filter_t *, char *) NONNULL(1,2); filter_ip_t *filter_ip_find(filter_t *, char *) NONNULL(1,2);
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
filter_keyword_t *filter_keyword_find(filter_t *, filter_user_t *, char *) NONNULL(1,3); filter_keyword_t *filter_keyword_find(filter_t *, filter_user_t *, char *) NONNULL(1,3);

@ -386,60 +386,76 @@ protohttp_filter_request_header_line(const char *line, protohttp_ctx_t *http_ctx
return (char*)line; return (char*)line;
} }
static int NONNULL(1,2) static filter_action_t * NONNULL(1,2)
protohttp_filter_match_host(pxy_conn_ctx_t *ctx, filter_site_t *site) protohttp_filter_match_host(pxy_conn_ctx_t *ctx, filter_list_t *list)
{ {
protohttp_ctx_t *http_ctx = ctx->protoctx->arg; protohttp_ctx_t *http_ctx = ctx->protoctx->arg;
filter_site_t *site = filter_site_find(list->host_btree, list->host_list, http_ctx->http_host);
if (!site)
return NULL;
#ifndef WITHOUT_USERAUTH
log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(http_ctx->http_host));
#else /* WITHOUT_USERAUTH */
log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(http_ctx->http_host));
#endif /* WITHOUT_USERAUTH */
if (site->action.precedence < ctx->filter_precedence) { if (site->action.precedence < ctx->filter_precedence) {
log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, http_ctx->http_host); log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, http_ctx->http_host);
return 0; return NULL;
} }
if (site->all_sites) { #ifdef DEBUG_PROXY
if (site->all_sites)
log_finest_va("Match all host: %s, %s", site->site, http_ctx->http_host); log_finest_va("Match all host: %s, %s", site->site, http_ctx->http_host);
return 1; else if (site->exact)
} log_finest_va("Match exact with host: %s, %s", site->site, http_ctx->http_host);
else if (site->exact) { else
if (http_ctx->http_host && !strcmp(http_ctx->http_host, site->site)) { log_finest_va("Match substring in host: %s, %s", site->site, http_ctx->http_host);
log_finest_va("Match exact with host: %s, %s", site->site, http_ctx->http_host); #endif /* DEBUG_PROXY */
return 1;
} return &site->action;
} else {
if (http_ctx->http_host && strstr(http_ctx->http_host, site->site)) {
log_finest_va("Match substring in host: %s, %s", site->site, http_ctx->http_host);
return 1;
}
}
return 0;
} }
static int NONNULL(1,2) static filter_action_t * NONNULL(1,2)
protohttp_filter_match_uri(pxy_conn_ctx_t *ctx, filter_site_t *site) protohttp_filter_match_uri(pxy_conn_ctx_t *ctx, filter_list_t *list)
{ {
protohttp_ctx_t *http_ctx = ctx->protoctx->arg; protohttp_ctx_t *http_ctx = ctx->protoctx->arg;
filter_site_t *site = filter_site_find(list->uri_btree, list->uri_list, http_ctx->http_uri);
if (!site)
return NULL;
#ifndef WITHOUT_USERAUTH
log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(http_ctx->http_uri));
#else /* WITHOUT_USERAUTH */
log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(http_ctx->http_uri));
#endif /* WITHOUT_USERAUTH */
if (site->action.precedence < ctx->filter_precedence) { if (site->action.precedence < ctx->filter_precedence) {
log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, http_ctx->http_uri); log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, http_ctx->http_uri);
return 0; return NULL;
} }
if (site->all_sites) { #ifdef DEBUG_PROXY
if (site->all_sites)
log_finest_va("Match all uri: %s, %s", site->site, http_ctx->http_uri); log_finest_va("Match all uri: %s, %s", site->site, http_ctx->http_uri);
return 1; else if (site->exact)
} log_finest_va("Match exact with uri: %s, %s", site->site, http_ctx->http_uri);
else if (site->exact) { else
if (!strcmp(http_ctx->http_uri, site->site)) { log_finest_va("Match substring in uri: %s, %s", site->site, http_ctx->http_uri);
log_finest_va("Match exact with uri: %s, %s", site->site, http_ctx->http_uri); #endif /* DEBUG_PROXY */
return 1;
} return &site->action;
} else {
if (strstr(http_ctx->http_uri, site->site)) {
log_finest_va("Match substring in uri: %s, %s", site->site, http_ctx->http_uri);
return 1;
}
}
return 0;
} }
static unsigned int NONNULL(1,2) static unsigned int NONNULL(1,2)
@ -448,21 +464,9 @@ protohttp_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
protohttp_ctx_t *http_ctx = ctx->protoctx->arg; protohttp_ctx_t *http_ctx = ctx->protoctx->arg;
if (http_ctx->http_host) { if (http_ctx->http_host) {
filter_site_t *site = list->host; filter_action_t *action;
while (site) { if ((action = protohttp_filter_match_host(ctx, list))) {
if (protohttp_filter_match_host(ctx, site)) { return pxyconn_set_filter_action(ctx, action, http_ctx->http_host);
#ifndef WITHOUT_USERAUTH
log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(http_ctx->http_host));
#else /* WITHOUT_USERAUTH */
log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(http_ctx->http_host));
#endif /* WITHOUT_USERAUTH */
return pxyconn_set_filter_action(ctx, site->action, site->site);
}
site = site->next;
} }
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
log_finest_va("No filter match with host: %s:%s, %s:%s, %s, %s, %s, %s", log_finest_va("No filter match with host: %s:%s, %s:%s, %s, %s, %s, %s",
@ -476,21 +480,9 @@ protohttp_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
} }
if (http_ctx->http_uri) { if (http_ctx->http_uri) {
filter_site_t *site = list->uri; filter_action_t *action;
while (site) { if ((action = protohttp_filter_match_uri(ctx, list))) {
if (protohttp_filter_match_uri(ctx, site)) { return pxyconn_set_filter_action(ctx, action, http_ctx->http_uri);
#ifndef WITHOUT_USERAUTH
log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(http_ctx->http_uri));
#else /* WITHOUT_USERAUTH */
log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(http_ctx->http_uri));
#endif /* WITHOUT_USERAUTH */
return pxyconn_set_filter_action(ctx, site->action, site->site);
}
site = site->next;
} }
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
log_finest_va("No filter match with uri: %s:%s, %s:%s, %s, %s, %s, %s", log_finest_va("No filter match with uri: %s:%s, %s:%s, %s, %s, %s, %s",

@ -590,121 +590,117 @@ protossl_srccert_create(pxy_conn_ctx_t *ctx)
return cert; return cert;
} }
static int NONNULL(1,2) static filter_action_t * NONNULL(1,2)
protossl_filter_match_sni(pxy_conn_ctx_t *ctx, filter_site_t *site) protossl_filter_match_sni(pxy_conn_ctx_t *ctx, filter_list_t *list)
{ {
filter_site_t *site = filter_site_find(list->sni_btree, list->sni_list, ctx->sslctx->sni);
if (!site)
return NULL;
#ifndef WITHOUT_USERAUTH
log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(ctx->sslctx->sni));
#else /* WITHOUT_USERAUTH */
log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->sslctx->sni));
#endif /* WITHOUT_USERAUTH */
if (site->action.precedence < ctx->filter_precedence) { if (site->action.precedence < ctx->filter_precedence) {
log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, ctx->sslctx->sni); log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, ctx->sslctx->sni);
return 0; return NULL;
} }
if (site->all_sites) { #ifdef DEBUG_PROXY
if (site->all_sites)
log_finest_va("Match all sni: %s, %s", site->site, ctx->sslctx->sni); log_finest_va("Match all sni: %s, %s", site->site, ctx->sslctx->sni);
return 1; else if (site->exact)
} log_finest_va("Match exact with sni: %s, %s", site->site, ctx->sslctx->sni);
else if (site->exact) { else
if (!strcmp(ctx->sslctx->sni, site->site)) { log_finest_va("Match substring in sni: %s, %s", site->site, ctx->sslctx->sni);
log_finest_va("Match exact with sni: %s, %s", site->site, ctx->sslctx->sni); #endif /* DEBUG_PROXY */
return 1;
} return &site->action;
} else {
if (strstr(ctx->sslctx->sni, site->site)) {
log_finest_va("Match substring in sni: %s, %s", site->site, ctx->sslctx->sni);
return 1;
}
}
return 0;
} }
static int NONNULL(1,2) static filter_action_t * NONNULL(1,2)
protossl_filter_match_cn(pxy_conn_ctx_t *ctx, filter_site_t *site) protossl_filter_match_cn(pxy_conn_ctx_t *ctx, filter_list_t *list)
{ {
if (site->action.precedence < ctx->filter_precedence) { filter_site_t *site = NULL;
log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, ctx->sslctx->ssl_names);
return 0;
}
if (site->all_sites) { // ballpark figures
log_finest_va("Match all common names: %s, %s", site->site, ctx->sslctx->ssl_names); #define MAX_CN_LEN 2048
return 1; #define MAX_CN_TOKENS 50
}
else if (site->exact) {
// Avoid multithreading issues by copying the site arg to a local var
// site arg is from the spec filter, which may be being used by other threads
size_t len = strlen(site->site); int argc = 0;
char *p, *last = NULL;
// Common names are separated by slashes size_t len = strlen(ctx->sslctx->ssl_names);
char _site[len + 3];
memcpy(_site + 1, site->site, len);
_site[0] = '/';
_site[len + 1] = '/';
_site[len + 2] = '\0';
len += 2;
// Skip the first slash if (len > MAX_CN_LEN) {
char *s = _site + 1; log_err_level_printf(LOG_WARNING, "Skip too long common names, max len %d: %s\n", MAX_CN_LEN, ctx->sslctx->ssl_names);
return NULL;
}
// Replace the last slash with null // strtok_r() modifies the string param, so copy ssl_names to a local var and pass it to strtok_r()
_site[len - 1] = '\0'; char _cn[len + 1];
memcpy(_cn, ctx->sslctx->ssl_names, len);
_cn[len] = '\0';
// Single common name: "example.com" for ((p = strtok_r(_cn, "/", &last));
if (!strcmp(ctx->sslctx->ssl_names, s)) { p;
log_finest_va("Match exact with single common name: %s", ctx->sslctx->ssl_names); (p = strtok_r(NULL, "/", &last))) {
return 1; if (argc < MAX_CN_TOKENS) {
site = filter_site_btree_exact_match(list->cn_btree, p);
if (site) {
log_finest_va("Match exact with common name: %s, %s", p, ctx->sslctx->ssl_names);
break;
}
} }
else {
// Restore the slash at the end log_err_level_printf(LOG_WARNING, "Too many tokens in common names, max tokens %d: %s\n", MAX_CN_TOKENS, ctx->sslctx->ssl_names);
_site[len - 1] = '/'; break;
// First common name: "example.com/"
if (strstr(ctx->sslctx->ssl_names, s) == ctx->sslctx->ssl_names) {
log_finest_va("Match exact with the first common name: %s, %s", ctx->sslctx->ssl_names, s);
return 1;
} }
}
// Middle common name: "/example.com/" if (!site) {
if (strstr(ctx->sslctx->ssl_names, _site)) { site = filter_site_list_substring_match(list->cn_list, ctx->sslctx->ssl_names);
log_finest_va("Match exact with a middle common name: %s, %s", ctx->sslctx->ssl_names, _site); if (site)
return 1; log_finest_va("Match substring in common names: %s, %s", site->site, ctx->sslctx->ssl_names);
} }
// Replace the last slash with null if (!site)
_site[len - 1] = '\0'; return NULL;
// Last common name: "/example.com" #ifndef WITHOUT_USERAUTH
if (strstr(ctx->sslctx->ssl_names, _site) == ctx->sslctx->ssl_names + strlen(ctx->sslctx->ssl_names) - strlen(_site)) { log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
log_finest_va("Match exact with the last common name: %s, %s", ctx->sslctx->ssl_names, _site); STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
return 1; STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(ctx->sslctx->ssl_names));
} #else /* WITHOUT_USERAUTH */
} else { log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
if (strstr(ctx->sslctx->ssl_names, site->site)) { STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
log_finest_va("Match substring in common names: %s, %s", site->site, ctx->sslctx->ssl_names); STRORDASH(ctx->sslctx->ssl_names));
return 1; #endif /* WITHOUT_USERAUTH */
}
if (site->action.precedence < ctx->filter_precedence) {
log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, ctx->sslctx->ssl_names);
return NULL;
} }
return 0;
if (site->all_sites)
log_finest_va("Match all common names: %s, %s", site->site, ctx->sslctx->ssl_names);
return &site->action;
} }
static unsigned int NONNULL(1,2) static unsigned int NONNULL(1,2)
protossl_filter(pxy_conn_ctx_t *ctx, filter_list_t *list) protossl_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
{ {
if (ctx->sslctx->sni) { if (ctx->sslctx->sni) {
filter_site_t *site = list->sni; filter_action_t *action;
while (site) { if ((action = protossl_filter_match_sni(ctx, list))) {
if (protossl_filter_match_sni(ctx, site)) { return pxyconn_set_filter_action(ctx, action, ctx->sslctx->sni);
#ifndef WITHOUT_USERAUTH
log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(ctx->sslctx->sni));
#else /* WITHOUT_USERAUTH */
log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->sslctx->sni));
#endif /* WITHOUT_USERAUTH */
return pxyconn_set_filter_action(ctx, site->action, site->site);
}
site = site->next;
} }
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
log_finest_va("No filter match with sni: %s:%s, %s:%s, %s, %s, %s, %s", log_finest_va("No filter match with sni: %s:%s, %s:%s, %s, %s, %s, %s",
@ -718,21 +714,9 @@ protossl_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
} }
if (ctx->sslctx->ssl_names) { if (ctx->sslctx->ssl_names) {
filter_site_t *site = list->cn; filter_action_t *action;
while (site) { if ((action = protossl_filter_match_cn(ctx, list))) {
if (protossl_filter_match_cn(ctx, site)) { return pxyconn_set_filter_action(ctx, action, ctx->sslctx->ssl_names);
#ifndef WITHOUT_USERAUTH
log_fine_va("Found site: %s for %s:%s, %s:%s, %s, %s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->user), STRORDASH(ctx->desc), STRORDASH(ctx->sslctx->ssl_names));
#else /* WITHOUT_USERAUTH */
log_fine_va("Found site: %s for %s:%s, %s:%s, %s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
STRORDASH(ctx->sslctx->ssl_names));
#endif /* WITHOUT_USERAUTH */
return pxyconn_set_filter_action(ctx, site->action, site->site);
}
site = site->next;
} }
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
log_finest_va("No filter match with common names: %s:%s, %s:%s, %s, %s, %s, %s", log_finest_va("No filter match with common names: %s:%s, %s:%s, %s, %s, %s, %s",

@ -516,71 +516,56 @@ prototcp_filter_match_port(pxy_conn_ctx_t *ctx, filter_port_t *port)
return 0; return 0;
} }
if (port->all_ports) { #ifdef DEBUG_PROXY
if (port->all_ports)
log_finest_va("Match all dst ports: %s, %s", port->port, ctx->dstport_str); log_finest_va("Match all dst ports: %s, %s", port->port, ctx->dstport_str);
return 1; else if (port->exact)
} log_finest_va("Match exact with port: %s, %s", port->port, ctx->dstport_str);
else if (port->exact) { else
if (!strcmp(ctx->dstport_str, port->port)) { log_finest_va("Match substring in dst port: %s, %s", port->port, ctx->dstport_str);
log_finest_va("Match exact with port: %s, %s", port->port, ctx->dstport_str); #endif /* DEBUG_PROXY */
return 1;
} return 1;
}
else {
if (strstr(ctx->dstport_str, port->port)) {
log_finest_va("Match substring in dst port: %s, %s", port->port, ctx->dstport_str);
return 1;
}
}
return 0;
} }
static filter_action_t * NONNULL(1,2) static filter_action_t * NONNULL(1,2)
prototcp_filter_match_ip(pxy_conn_ctx_t *ctx, filter_site_t *site) prototcp_filter_match_ip(pxy_conn_ctx_t *ctx, filter_list_t *list)
{ {
filter_site_t *site = filter_site_find(list->ip_btree, list->ip_list, ctx->dsthost_str);
if (!site)
return NULL;
log_fine_va("Found site: %s for %s:%s, %s:%s", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
// Port spec determines the precedence of a site rule, unless the rule does not have any port // Port spec determines the precedence of a site rule, unless the rule does not have any port
if (!site->port && (site->action.precedence < ctx->filter_precedence)) { if (!site->port_list && (site->action.precedence < ctx->filter_precedence)) {
log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, ctx->dsthost_str); log_finest_va("Rule precedence lower than conn filter precedence %d < %d: %s, %s", site->action.precedence, ctx->filter_precedence, site->site, ctx->dsthost_str);
return NULL; return NULL;
} }
filter_action_t *action = NULL; filter_action_t *action = &site->action;
if (site->all_sites) { #ifdef DEBUG_PROXY
if (site->all_sites)
log_finest_va("Match all dst: %s, %s", site->site, ctx->dsthost_str); log_finest_va("Match all dst: %s, %s", site->site, ctx->dsthost_str);
action = &site->action; else if (site->exact)
} log_finest_va("Match exact with dst: %s, %s", site->site, ctx->dsthost_str);
else if (site->exact) { else
if (!strcmp(ctx->dsthost_str, site->site)) { log_finest_va("Match substring in dst: %s, %s", site->site, ctx->dsthost_str);
log_finest_va("Match exact with dst: %s, %s", site->site, ctx->dsthost_str); #endif /* DEBUG_PROXY */
action = &site->action;
}
}
else {
if (strstr(ctx->dsthost_str, site->site)) {
log_finest_va("Match substring in dst: %s, %s", site->site, ctx->dsthost_str);
action = &site->action;
}
}
if (action) { filter_port_t *port = filter_port_find(site, ctx->dstport_str);
log_fine_va("Found site: %s for %s:%s, %s:%s", site->site, if (port) {
log_fine_va("Found port: %s for %s:%s, %s:%s", port->port,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str)); STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
if (prototcp_filter_match_port(ctx, port))
if (site->port) { return &port->action;
filter_port_t *port = site->port;
while (port) {
if (prototcp_filter_match_port(ctx, port)) {
log_fine_va("Found port: %s for %s:%s, %s:%s", port->port,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
return &port->action;
}
port = port->next;
}
log_finest_va("No filter match with port: %s:%s, %s:%s",
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
}
} }
else
log_finest_va("No filter match with port: %s:%s, %s:%s",
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
return action; return action;
} }
@ -588,13 +573,10 @@ static unsigned int NONNULL(1,2)
prototcp_dsthost_filter(pxy_conn_ctx_t *ctx, filter_list_t *list) prototcp_dsthost_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
{ {
if (ctx->dsthost_str) { if (ctx->dsthost_str) {
filter_site_t *site = list->ip; filter_action_t *action;
while (site) { if ((action = prototcp_filter_match_ip(ctx, list)))
filter_action_t *action = prototcp_filter_match_ip(ctx, site); return pxyconn_set_filter_action(ctx, action, ctx->dsthost_str);
if (action)
return pxyconn_set_filter_action(ctx, *action, site->site);
site = site->next;
}
log_finest_va("No filter match with ip: %s:%s, %s:%s", log_finest_va("No filter match with ip: %s:%s, %s:%s",
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str)); STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
} }

@ -2007,63 +2007,63 @@ pxyconn_apply_deferred_block_action(pxy_conn_ctx_t *ctx)
} }
unsigned int unsigned int
pxyconn_set_filter_action(pxy_conn_ctx_t *ctx, filter_action_t a, UNUSED char *site) pxyconn_set_filter_action(pxy_conn_ctx_t *ctx, filter_action_t *a, UNUSED char *site)
{ {
unsigned int action = FILTER_ACTION_NONE; unsigned int action = FILTER_ACTION_NONE;
if (a.divert) { if (a->divert) {
log_fine_va("Filter divert action for %s, precedence %d", site, a.precedence); log_fine_va("Filter divert action for %s, precedence %d", site, a->precedence);
action = FILTER_ACTION_DIVERT; action = FILTER_ACTION_DIVERT;
} }
else if (a.split) { else if (a->split) {
log_fine_va("Filter split action for %s, precedence %d", site, a.precedence); log_fine_va("Filter split action for %s, precedence %d", site, a->precedence);
action = FILTER_ACTION_SPLIT; action = FILTER_ACTION_SPLIT;
} }
else if (a.pass) { else if (a->pass) {
// Ignore pass action if already in passthrough mode // Ignore pass action if already in passthrough mode
if (!ctx->pass) { if (!ctx->pass) {
log_fine_va("Filter pass action for %s, precedence %d", site, a.precedence); log_fine_va("Filter pass action for %s, precedence %d", site, a->precedence);
action = FILTER_ACTION_PASS; action = FILTER_ACTION_PASS;
} }
} }
else if (a.block) { else if (a->block) {
log_fine_va("Filter block action for %s, precedence %d", site, a.precedence); log_fine_va("Filter block action for %s, precedence %d", site, a->precedence);
action = FILTER_ACTION_BLOCK; action = FILTER_ACTION_BLOCK;
} }
else if (a.match) { else if (a->match) {
log_fine_va("Filter match action for %s, precedence %d", site, a.precedence); log_fine_va("Filter match action for %s, precedence %d", site, a->precedence);
action = FILTER_ACTION_MATCH; action = FILTER_ACTION_MATCH;
} }
// Multiple log actions can be defined, hence no 'else' // Multiple log actions can be defined, hence no 'else'
// 0: don't change, 1: disable, 2: enable // 0: don't change, 1: disable, 2: enable
if (a.log_connect) { if (a->log_connect) {
log_fine_va("Filter %s connect log for %s, precedence %d", a.log_connect % 2 ? "disable" : "enable", site, a.precedence); log_fine_va("Filter %s connect log for %s, precedence %d", a->log_connect % 2 ? "disable" : "enable", site, a->precedence);
action |= (a.log_connect % 2) ? FILTER_LOG_NOCONNECT : FILTER_LOG_CONNECT; action |= (a->log_connect % 2) ? FILTER_LOG_NOCONNECT : FILTER_LOG_CONNECT;
} }
if (a.log_master) { if (a->log_master) {
log_fine_va("Filter %s master log for %s, precedence %d", a.log_master % 2 ? "disable" : "enable", site, a.precedence); log_fine_va("Filter %s master log for %s, precedence %d", a->log_master % 2 ? "disable" : "enable", site, a->precedence);
action |= (a.log_master % 2) ? FILTER_LOG_NOMASTER : FILTER_LOG_MASTER; action |= (a->log_master % 2) ? FILTER_LOG_NOMASTER : FILTER_LOG_MASTER;
} }
if (a.log_cert) { if (a->log_cert) {
log_fine_va("Filter %s cert log for %s, precedence %d", a.log_cert % 2 ? "disable" : "enable", site, a.precedence); log_fine_va("Filter %s cert log for %s, precedence %d", a->log_cert % 2 ? "disable" : "enable", site, a->precedence);
action |= (a.log_cert % 2) ? FILTER_LOG_NOCERT : FILTER_LOG_CERT; action |= (a->log_cert % 2) ? FILTER_LOG_NOCERT : FILTER_LOG_CERT;
} }
if (a.log_content) { if (a->log_content) {
log_fine_va("Filter %s content log for %s, precedence %d", a.log_content % 2 ? "disable" : "enable", site, a.precedence); log_fine_va("Filter %s content log for %s, precedence %d", a->log_content % 2 ? "disable" : "enable", site, a->precedence);
action |= (a.log_content % 2) ? FILTER_LOG_NOCONTENT : FILTER_LOG_CONTENT; action |= (a->log_content % 2) ? FILTER_LOG_NOCONTENT : FILTER_LOG_CONTENT;
} }
if (a.log_pcap) { if (a->log_pcap) {
log_fine_va("Filter %s pcap log for %s, precedence %d", a.log_pcap % 2 ? "disable" : "enable", site, a.precedence); log_fine_va("Filter %s pcap log for %s, precedence %d", a->log_pcap % 2 ? "disable" : "enable", site, a->precedence);
action |= (a.log_pcap % 2) ? FILTER_LOG_NOPCAP : FILTER_LOG_PCAP; action |= (a->log_pcap % 2) ? FILTER_LOG_NOPCAP : FILTER_LOG_PCAP;
} }
#ifndef WITHOUT_MIRROR #ifndef WITHOUT_MIRROR
if (a.log_mirror) { if (a->log_mirror) {
log_fine_va("Filter %s mirror log for %s, precedence %d", a.log_mirror % 2 ? "disable" : "enable", site, a.precedence); log_fine_va("Filter %s mirror log for %s, precedence %d", a->log_mirror % 2 ? "disable" : "enable", site, a->precedence);
action |= (a.log_mirror % 2) ? FILTER_LOG_NOMIRROR : FILTER_LOG_MIRROR; action |= (a->log_mirror % 2) ? FILTER_LOG_NOMIRROR : FILTER_LOG_MIRROR;
} }
#endif /* !WITHOUT_MIRROR */ #endif /* !WITHOUT_MIRROR */
action |= a.precedence; action |= a->precedence;
return action; return action;
} }

@ -446,7 +446,7 @@ void pxy_classify_user(pxy_conn_ctx_t *) NONNULL(1);
void pxy_userauth(pxy_conn_ctx_t *) NONNULL(1); void pxy_userauth(pxy_conn_ctx_t *) NONNULL(1);
#endif /* !WITHOUT_USERAUTH */ #endif /* !WITHOUT_USERAUTH */
int pxyconn_apply_deferred_block_action(pxy_conn_ctx_t *) NONNULL(1) WUNRES; int pxyconn_apply_deferred_block_action(pxy_conn_ctx_t *) NONNULL(1) WUNRES;
unsigned int pxyconn_set_filter_action(pxy_conn_ctx_t *, filter_action_t, UNUSED char *) NONNULL(1,3) WUNRES; unsigned int pxyconn_set_filter_action(pxy_conn_ctx_t *, filter_action_t *, UNUSED char *) NONNULL(1,2,3) WUNRES;
unsigned int pxyconn_filter(pxy_conn_ctx_t *, proto_filter_func_t) NONNULL(1) WUNRES; unsigned int pxyconn_filter(pxy_conn_ctx_t *, proto_filter_func_t) NONNULL(1) WUNRES;
void pxy_conn_setup(evutil_socket_t, struct sockaddr *, int, void pxy_conn_setup(evutil_socket_t, struct sockaddr *, int,
pxy_thrmgr_ctx_t *, proxyspec_t *, global_t *, pxy_thrmgr_ctx_t *, proxyspec_t *, global_t *,

@ -1360,55 +1360,60 @@ START_TEST(set_filter_rule_07)
s = filter_rule_str(opts->filter_rules); s = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(s, fail_unless(!strcmp(s,
"filter rule 0: site=, substring, port=, , ip=, user=, keyword=, all=conns||sites|, action=divert||||, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=0\n" "filter rule 0: site=, port=, ip=, user=, keyword=, exact=||||, all=conns||sites|, action=divert||||, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=0\n"
"filter rule 1: site=, substring, port=, , ip=, user=, keyword=, all=conns||sites|, action=|split|||, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=0\n" "filter rule 1: site=, port=, ip=, user=, keyword=, exact=||||, all=conns||sites|, action=|split|||, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=0\n"
"filter rule 2: site=, substring, port=, , ip=, user=, keyword=, all=conns||sites|, action=||pass||, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=0\n" "filter rule 2: site=, port=, ip=, user=, keyword=, exact=||||, all=conns||sites|, action=||pass||, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=0\n"
"filter rule 3: site=, substring, port=, , ip=, user=, keyword=, all=|users|sites|, action=|||block|, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=1\n" "filter rule 3: site=, port=, ip=, user=, keyword=, exact=||||, all=|users|sites|, action=|||block|, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=1\n"
"filter rule 4: site=, substring, port=, , ip=, user=, keyword=desc, all=|users|sites|, action=||||match, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=2\n" "filter rule 4: site=, port=, ip=, user=, keyword=desc, exact=||||keyword, all=|users|sites|, action=||||match, log=|||||, apply to=dstip|sni|cn|host|uri, precedence=2\n"
"filter rule 5: site=, substring, port=, , ip=, user=, keyword=, all=conns||sites|, action=||||match, log=connect|master|cert|content|pcap|mirror, apply to=dstip|sni|cn|host|uri, precedence=1"), "filter rule 5: site=, port=, ip=, user=, keyword=, exact=||||, all=conns||sites|, action=||||match, log=connect|master|cert|content|pcap|mirror, apply to=dstip|sni|cn|host|uri, precedence=1"),
"failed to parse rule: %s", s); "failed to parse rule: %s", s);
free(s); free(s);
close(2);
opts->filter = filter_set(opts->filter_rules); opts->filter = filter_set(opts->filter_rules);
s = filter_str(opts->filter); s = filter_str(opts->filter);
fail_unless(!strcmp(s, "filter=>\n" fail_unless(!strcmp(s, "filter=>\n"
"userkeyword_filter->\n" "userkeyword_filter_exact->\n"
"user_filter->\n" "userkeyword_filter_substr->\n"
"keyword_filter->\n" "user_filter_exact->\n"
" keyword 0 desc= \n" "user_filter_substr->\n"
" ip: \n" "keyword_filter_exact->\n"
" keyword 0 desc (exact)= \n"
" ip substring: \n"
" 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n" " 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n"
" sni: \n" " sni substring: \n"
" 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n" " 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n"
" cn: \n" " cn substring: \n"
" 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n" " 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n"
" host: \n" " host substring: \n"
" 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n" " 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n"
" uri: \n" " uri substring: \n"
" 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n" " 0: (all_sites, substring, action=||||match, log=|||||, precedence=2)\n"
"keyword_filter_substr->\n"
"all_user_filter->\n" "all_user_filter->\n"
" ip: \n" " ip substring: \n"
" 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n" " 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n"
" sni: \n" " sni substring: \n"
" 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n" " 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n"
" cn: \n" " cn substring: \n"
" 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n" " 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n"
" host: \n" " host substring: \n"
" 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n" " 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n"
" uri: \n" " uri substring: \n"
" 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n" " 0: (all_sites, substring, action=|||block|, log=|||||, precedence=1)\n"
"ip_filter->\n" "ip_filter_exact->\n"
"ip_filter_substr->\n"
"all_filter->\n" "all_filter->\n"
" ip: \n" " ip substring: \n"
" 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n" " 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n"
" sni: \n" " sni substring: \n"
" 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n" " 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n"
" cn: \n" " cn substring: \n"
" 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n" " 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n"
" host: \n" " host substring: \n"
" 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n" " 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n"
" uri: \n" " uri substring: \n"
" 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n"), "failed to translate rule: %s", s); " 0: (all_sites, substring, action=divert|split|pass||match, log=connect|master|cert|content|pcap|mirror, precedence=1)\n"), "failed to translate rule: %s", s);
free(s); free(s);
@ -1475,56 +1480,44 @@ START_TEST(set_filter_rule_08)
s = filter_rule_str(opts->filter_rules); s = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(s, fail_unless(!strcmp(s,
"filter rule 0: site=192.168.0.2, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=divert||||, log=|||||, apply to=dstip||||, precedence=1\n" "filter rule 0: site=192.168.0.2, port=, ip=192.168.0.1, user=, keyword=, exact=site||ip||, all=|||, action=divert||||, log=|||||, apply to=dstip||||, precedence=1\n"
"filter rule 1: site=192.168.0.2, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=dstip||||, precedence=2\n" "filter rule 1: site=192.168.0.2, port=, ip=192.168.0.1, user=, keyword=, exact=site||ip||, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=dstip||||, precedence=2\n"
"filter rule 2: site=192.168.0.2, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=dstip||||, precedence=2\n" "filter rule 2: site=192.168.0.2, port=, ip=192.168.0.1, user=, keyword=, exact=site||ip||, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=dstip||||, precedence=2\n"
"filter rule 3: site=192.168.0.2, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=|||block|, log=|||||, apply to=dstip||||, precedence=1\n" "filter rule 3: site=192.168.0.2, port=, ip=192.168.0.1, user=, keyword=, exact=site||ip||, all=|||, action=|||block|, log=|||||, apply to=dstip||||, precedence=1\n"
"filter rule 4: site=192.168.0.3, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n" "filter rule 4: site=192.168.0.3, port=, ip=192.168.0.1, user=, keyword=, exact=site||ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n"
"filter rule 5: site=192.168.0.1, exact, port=, , ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n" "filter rule 5: site=192.168.0.1, port=, ip=192.168.0.2, user=, keyword=, exact=site||ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n"
"filter rule 6: site=, substring, port=, , ip=192.168.0.2, user=, keyword=, all=||sites|, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n" "filter rule 6: site=, port=, ip=192.168.0.2, user=, keyword=, exact=||ip||, all=||sites|, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n"
"filter rule 7: site=192.168.0., substring, port=, , ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n" "filter rule 7: site=192.168.0., port=, ip=192.168.0.2, user=, keyword=, exact=||ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1\n"
"filter rule 8: site=192.168.0.3, exact, port=, , ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1"), "filter rule 8: site=192.168.0.3, port=, ip=192.168.0.2, user=, keyword=, exact=site||ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=1"),
"failed to parse rule: %s", s); "failed to parse rule: %s", s);
free(s); free(s);
close(2);
opts->filter = filter_set(opts->filter_rules); opts->filter = filter_set(opts->filter_rules);
s = filter_str(opts->filter); s = filter_str(opts->filter);
fail_unless(!strcmp(s, "filter=>\n" fail_unless(!strcmp(s, "filter=>\n"
"userkeyword_filter->\n" "userkeyword_filter_exact->\n"
"user_filter->\n" "userkeyword_filter_substr->\n"
"keyword_filter->\n" "user_filter_exact->\n"
"user_filter_substr->\n"
"keyword_filter_exact->\n"
"keyword_filter_substr->\n"
"all_user_filter->\n" "all_user_filter->\n"
" ip: \n" "ip_filter_exact->\n"
" sni: \n" " ip 0 192.168.0.2 (exact)= \n"
" cn: \n" " ip exact: \n"
" host: \n" " 0: 192.168.0.3 (exact, action=||||match, log=|||||, precedence=1)\n"
" uri: \n" " 1: 192.168.0.1 (exact, action=||||match, log=|||||, precedence=1)\n"
"ip_filter->\n" " ip substring: \n"
" ip 0 192.168.0.2= \n" " 0: 192.168.0. (substring, action=||||match, log=|||||, precedence=1)\n"
" ip: \n" " 1: (all_sites, substring, action=||||match, log=|||||, precedence=1)\n"
" 0: 192.168.0.1 (exact, action=||||match, log=|||||, precedence=1)\n" " ip 1 192.168.0.1 (exact)= \n"
" 1: 192.168.0. (substring, action=||||match, log=|||||, precedence=1)\n" " ip exact: \n"
" 2: 192.168.0.3 (exact, action=||||match, log=|||||, precedence=1)\n" " 0: 192.168.0.3 (exact, action=||||match, log=|||||, precedence=1)\n"
" 3: (all_sites, substring, action=||||match, log=|||||, precedence=1)\n" " 1: 192.168.0.2 (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=2)\n"
" sni: \n" "ip_filter_substr->\n"
" cn: \n" "all_filter->\n"), "failed to translate rule: %s", s);
" host: \n"
" uri: \n"
" ip 1 192.168.0.1= \n"
" ip: \n"
" 0: 192.168.0.2 (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=2)\n"
" 1: 192.168.0.3 (exact, action=||||match, log=|||||, precedence=1)\n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"
"all_filter->\n"
" ip: \n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"), "failed to translate rule: %s", s);
free(s); free(s);
opts_free(opts); opts_free(opts);
@ -1596,63 +1589,51 @@ START_TEST(set_filter_rule_09)
s = filter_rule_str(opts->filter_rules); s = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(s, fail_unless(!strcmp(s,
"filter rule 0: site=192.168.0.2, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=divert||||, log=|||||, apply to=dstip||||, precedence=2\n" "filter rule 0: site=192.168.0.2, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=divert||||, log=|||||, apply to=dstip||||, precedence=2\n"
"filter rule 1: site=192.168.0.2, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=dstip||||, precedence=3\n" "filter rule 1: site=192.168.0.2, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=dstip||||, precedence=3\n"
"filter rule 2: site=192.168.0.2, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 2: site=192.168.0.2, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 3: site=192.168.0.2, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=|||block|, log=|||||, apply to=dstip||||, precedence=2\n" "filter rule 3: site=192.168.0.2, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=|||block|, log=|||||, apply to=dstip||||, precedence=2\n"
"filter rule 4: site=192.168.0.3, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|||||!mirror, apply to=dstip||||, precedence=2\n" "filter rule 4: site=192.168.0.3, port=, ip=192.168.0.1, user=, keyword=, exact=site||ip||, all=|||, action=||||match, log=|||||!mirror, apply to=dstip||||, precedence=2\n"
"filter rule 5: site=192.168.0.3, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n" "filter rule 5: site=192.168.0.3, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n"
"filter rule 6: site=192.168.0.3, exact, port=80, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n" "filter rule 6: site=192.168.0.3, port=80, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n"
"filter rule 7: site=192.168.0.1, exact, port=443, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n" "filter rule 7: site=192.168.0.1, port=443, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n"
"filter rule 8: site=192.168.0.1, exact, port=, substring_port, ip=192.168.0.2, user=, keyword=, all=|||ports, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n" "filter rule 8: site=192.168.0.1, port=, ip=192.168.0.2, user=, keyword=, exact=site||ip||, all=|||ports, action=||||match, log=|||||, apply to=dstip||||, precedence=2\n"
"filter rule 9: site=192.168.0.1, exact, port=80, substring_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2"), "filter rule 9: site=192.168.0.1, port=80, ip=192.168.0.2, user=, keyword=, exact=site||ip||, all=|||, action=||||match, log=|||||, apply to=dstip||||, precedence=2"),
"failed to parse rule: %s", s); "failed to parse rule: %s", s);
free(s); free(s);
close(2);
opts->filter = filter_set(opts->filter_rules); opts->filter = filter_set(opts->filter_rules);
s = filter_str(opts->filter); s = filter_str(opts->filter);
fail_unless(!strcmp(s, "filter=>\n" fail_unless(!strcmp(s, "filter=>\n"
"userkeyword_filter->\n" "userkeyword_filter_exact->\n"
"user_filter->\n" "userkeyword_filter_substr->\n"
"keyword_filter->\n" "user_filter_exact->\n"
"user_filter_substr->\n"
"keyword_filter_exact->\n"
"keyword_filter_substr->\n"
"all_user_filter->\n" "all_user_filter->\n"
" ip: \n" "ip_filter_exact->\n"
" sni: \n" " ip 0 192.168.0.2 (exact)= \n"
" cn: \n" " ip exact: \n"
" host: \n"
" uri: \n"
"ip_filter->\n"
" ip 0 192.168.0.2= \n"
" ip: \n"
" 0: 192.168.0.1 (exact, action=||||, log=|||||, precedence=0)\n" " 0: 192.168.0.1 (exact, action=||||, log=|||||, precedence=0)\n"
" port:\n" " port exact:\n"
" 0: 443 (exact, action=||||match, log=|||||, precedence=2)\n" " 0: 443 (exact, action=||||match, log=|||||, precedence=2)\n"
" 1: 80 (substring, action=||||match, log=|||||, precedence=2)\n" " port substring:\n"
" 2: (all_ports, substring, action=||||match, log=|||||, precedence=2)\n" " 0: 80 (substring, action=||||match, log=|||||, precedence=2)\n"
" sni: \n" " 1: (all_ports, substring, action=||||match, log=|||||, precedence=2)\n"
" cn: \n" " ip 1 192.168.0.1 (exact)= \n"
" host: \n" " ip exact: \n"
" uri: \n" " 0: 192.168.0.3 (exact, action=||||match, log=|||||!mirror, precedence=2)\n"
" ip 1 192.168.0.1= \n" " port exact:\n"
" ip: \n" " 0: 80 (exact, action=||||match, log=|||||, precedence=2)\n"
" 0: 192.168.0.2 (exact, action=||||, log=|||||, precedence=0)\n" " 1: 443 (exact, action=||||match, log=|||||, precedence=2)\n"
" port:\n" " 1: 192.168.0.2 (exact, action=||||, log=|||||, precedence=0)\n"
" port exact:\n"
" 0: 443 (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=3)\n" " 0: 443 (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=3)\n"
" 1: 192.168.0.3 (exact, action=||||match, log=|||||!mirror, precedence=2)\n" "ip_filter_substr->\n"
" port:\n" "all_filter->\n"), "failed to translate rule: %s", s);
" 0: 443 (exact, action=||||match, log=|||||, precedence=2)\n"
" 1: 80 (exact, action=||||match, log=|||||, precedence=2)\n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"
"all_filter->\n"
" ip: \n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"), "failed to translate rule: %s", s);
free(s); free(s);
opts_free(opts); opts_free(opts);
@ -1720,56 +1701,44 @@ START_TEST(set_filter_rule_10)
s = filter_rule_str(opts->filter_rules); s = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(s, fail_unless(!strcmp(s,
"filter rule 0: site=example.com, exact, port=, , ip=, user=root, keyword=, all=|||, action=divert||||, log=|||||, apply to=|sni|||, precedence=3\n" "filter rule 0: site=example.com, port=, ip=, user=root, keyword=, exact=site|||user|, all=|||, action=divert||||, log=|||||, apply to=|sni|||, precedence=3\n"
"filter rule 1: site=example.com, exact, port=, , ip=, user=root, keyword=, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=|sni|||, precedence=4\n" "filter rule 1: site=example.com, port=, ip=, user=root, keyword=, exact=site|||user|, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=|sni|||, precedence=4\n"
"filter rule 2: site=example.com, exact, port=, , ip=, user=root, keyword=, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=|sni|||, precedence=4\n" "filter rule 2: site=example.com, port=, ip=, user=root, keyword=, exact=site|||user|, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=|sni|||, precedence=4\n"
"filter rule 3: site=example.com, exact, port=, , ip=, user=root, keyword=, all=|||, action=|||block|, log=|||||, apply to=|sni|||, precedence=3\n" "filter rule 3: site=example.com, port=, ip=, user=root, keyword=, exact=site|||user|, all=|||, action=|||block|, log=|||||, apply to=|sni|||, precedence=3\n"
"filter rule 4: site=example2.com, exact, port=, , ip=, user=root, keyword=, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n" "filter rule 4: site=example2.com, port=, ip=, user=root, keyword=, exact=site|||user|, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n"
"filter rule 5: site=example.com, exact, port=, , ip=, user=daemon, keyword=, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n" "filter rule 5: site=example.com, port=, ip=, user=daemon, keyword=, exact=site|||user|, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n"
"filter rule 6: site=, substring, port=, , ip=, user=daemon, keyword=, all=||sites|, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n" "filter rule 6: site=, port=, ip=, user=daemon, keyword=, exact=|||user|, all=||sites|, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n"
"filter rule 7: site=.example.com, substring, port=, , ip=, user=daemon, keyword=, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n" "filter rule 7: site=.example.com, port=, ip=, user=daemon, keyword=, exact=|||user|, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3\n"
"filter rule 8: site=example3.com, exact, port=, , ip=, user=daemon, keyword=, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3"), "filter rule 8: site=example3.com, port=, ip=, user=daemon, keyword=, exact=site|||user|, all=|||, action=||||match, log=|||||, apply to=|sni|||, precedence=3"),
"failed to parse rule: %s", s); "failed to parse rule: %s", s);
free(s); free(s);
close(2);
opts->filter = filter_set(opts->filter_rules); opts->filter = filter_set(opts->filter_rules);
s = filter_str(opts->filter); s = filter_str(opts->filter);
fail_unless(!strcmp(s, "filter=>\n" fail_unless(!strcmp(s, "filter=>\n"
"userkeyword_filter->\n" "userkeyword_filter_exact->\n"
"user_filter->\n" "userkeyword_filter_substr->\n"
" user 0 daemon= \n" "user_filter_exact->\n"
" ip: \n" " user 0 root (exact)= \n"
" sni: \n" " sni exact: \n"
" 0: example.com (exact, action=||||match, log=|||||, precedence=3)\n" " 0: example2.com (exact, action=||||match, log=|||||, precedence=3)\n"
" 1: .example.com (substring, action=||||match, log=|||||, precedence=3)\n" " 1: example.com (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=4)\n"
" 2: example3.com (exact, action=||||match, log=|||||, precedence=3)\n" " user 1 daemon (exact)= \n"
" 3: (all_sites, substring, action=||||match, log=|||||, precedence=3)\n" " sni exact: \n"
" cn: \n" " 0: example3.com (exact, action=||||match, log=|||||, precedence=3)\n"
" host: \n" " 1: example.com (exact, action=||||match, log=|||||, precedence=3)\n"
" uri: \n" " sni substring: \n"
" user 1 root= \n" " 0: .example.com (substring, action=||||match, log=|||||, precedence=3)\n"
" ip: \n" " 1: (all_sites, substring, action=||||match, log=|||||, precedence=3)\n"
" sni: \n" "user_filter_substr->\n"
" 0: example.com (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=4)\n" "keyword_filter_exact->\n"
" 1: example2.com (exact, action=||||match, log=|||||, precedence=3)\n" "keyword_filter_substr->\n"
" cn: \n"
" host: \n"
" uri: \n"
"keyword_filter->\n"
"all_user_filter->\n" "all_user_filter->\n"
" ip: \n" "ip_filter_exact->\n"
" sni: \n" "ip_filter_substr->\n"
" cn: \n" "all_filter->\n"), "failed to translate rule: %s", s);
" host: \n"
" uri: \n"
"ip_filter->\n"
"all_filter->\n"
" ip: \n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"), "failed to translate rule: %s", s);
free(s); free(s);
opts_free(opts); opts_free(opts);
@ -1861,84 +1830,63 @@ START_TEST(set_filter_rule_11)
s = filter_rule_str(opts->filter_rules); s = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(s, fail_unless(!strcmp(s,
"filter rule 0: site=example.com, exact, port=, , ip=, user=root, keyword=desc, all=|||, action=divert||||, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 0: site=example.com, port=, ip=, user=root, keyword=desc, exact=site|||user|keyword, all=|||, action=divert||||, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 1: site=example.com, exact, port=, , ip=, user=root, keyword=desc, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=||cn||, precedence=5\n" "filter rule 1: site=example.com, port=, ip=, user=root, keyword=desc, exact=site|||user|keyword, all=|||, action=|split|||, log=connect|master|cert|content|pcap|mirror, apply to=||cn||, precedence=5\n"
"filter rule 2: site=example.com, exact, port=, , ip=, user=root, keyword=desc, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=||cn||, precedence=5\n" "filter rule 2: site=example.com, port=, ip=, user=root, keyword=desc, exact=site|||user|keyword, all=|||, action=||pass||, log=!connect||!cert||!pcap|, apply to=||cn||, precedence=5\n"
"filter rule 3: site=example.com, exact, port=, , ip=, user=root, keyword=desc, all=|||, action=|||block|, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 3: site=example.com, port=, ip=, user=root, keyword=desc, exact=site|||user|keyword, all=|||, action=|||block|, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 4: site=example2.com, exact, port=, , ip=, user=root, keyword=desc, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 4: site=example2.com, port=, ip=, user=root, keyword=desc, exact=site|||user|keyword, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 5: site=example.com, exact, port=, , ip=, user=daemon, keyword=desc, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 5: site=example.com, port=, ip=, user=daemon, keyword=desc, exact=site|||user|keyword, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 6: site=, substring, port=, , ip=, user=daemon, keyword=desc, all=||sites|, action=||||match, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 6: site=, port=, ip=, user=daemon, keyword=desc, exact=|||user|keyword, all=||sites|, action=||||match, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 7: site=.example.com, substring, port=, , ip=, user=daemon, keyword=desc, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 7: site=.example.com, port=, ip=, user=daemon, keyword=desc, exact=|||user|keyword, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 8: site=example3.com, exact, port=, , ip=, user=daemon, keyword=desc, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 8: site=example3.com, port=, ip=, user=daemon, keyword=desc, exact=site|||user|keyword, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 9: site=example4.com, exact, port=, , ip=, user=daemon, keyword=desc2, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n" "filter rule 9: site=example4.com, port=, ip=, user=daemon, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=|||||, apply to=||cn||, precedence=4\n"
"filter rule 10: site=example5.com, exact, port=, , ip=, user=, keyword=desc, all=|users||, action=||||match, log=|||||, apply to=||cn||, precedence=3\n" "filter rule 10: site=example5.com, port=, ip=, user=, keyword=desc, exact=site||||keyword, all=|users||, action=||||match, log=|||||, apply to=||cn||, precedence=3\n"
"filter rule 11: site=, substring, port=, , ip=, user=, keyword=desc, all=|users|sites|, action=||||match, log=|||||, apply to=|||host|, precedence=3\n" "filter rule 11: site=, port=, ip=, user=, keyword=desc, exact=||||keyword, all=|users|sites|, action=||||match, log=|||||, apply to=|||host|, precedence=3\n"
"filter rule 12: site=example6.com, exact, port=, , ip=, user=, keyword=desc3, all=|users||, action=||||match, log=|||||, apply to=||||uri, precedence=3"), "filter rule 12: site=example6.com, port=, ip=, user=, keyword=desc3, exact=site||||keyword, all=|users||, action=||||match, log=|||||, apply to=||||uri, precedence=3"),
"failed to parse rule: %s", s); "failed to parse rule: %s", s);
free(s); free(s);
close(2);
opts->filter = filter_set(opts->filter_rules); opts->filter = filter_set(opts->filter_rules);
s = filter_str(opts->filter); s = filter_str(opts->filter);
fail_unless(!strcmp(s, "filter=>\n" fail_unless(!strcmp(s, "filter=>\n"
"userkeyword_filter->\n" "userkeyword_filter_exact->\n"
" user 0 daemon=\n" " user 0 root (exact)=\n"
" keyword 0 desc2= \n" " keyword exact:\n"
" ip: \n" " keyword 0 desc (exact)= \n"
" sni: \n" " cn exact: \n"
" cn: \n" " 0: example2.com (exact, action=||||match, log=|||||, precedence=4)\n"
" 1: example.com (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=5)\n"
" user 1 daemon (exact)=\n"
" keyword exact:\n"
" keyword 0 desc2 (exact)= \n"
" cn exact: \n"
" 0: example4.com (exact, action=||||match, log=|||||, precedence=4)\n" " 0: example4.com (exact, action=||||match, log=|||||, precedence=4)\n"
" host: \n" " keyword 1 desc (exact)= \n"
" uri: \n" " cn exact: \n"
" keyword 1 desc= \n" " 0: example3.com (exact, action=||||match, log=|||||, precedence=4)\n"
" ip: \n" " 1: example.com (exact, action=||||match, log=|||||, precedence=4)\n"
" sni: \n" " cn substring: \n"
" cn: \n" " 0: .example.com (substring, action=||||match, log=|||||, precedence=4)\n"
" 0: example.com (exact, action=||||match, log=|||||, precedence=4)\n" " 1: (all_sites, substring, action=||||match, log=|||||, precedence=4)\n"
" 1: .example.com (substring, action=||||match, log=|||||, precedence=4)\n" "userkeyword_filter_substr->\n"
" 2: example3.com (exact, action=||||match, log=|||||, precedence=4)\n" "user_filter_exact->\n"
" 3: (all_sites, substring, action=||||match, log=|||||, precedence=4)\n" "user_filter_substr->\n"
" host: \n" "keyword_filter_exact->\n"
" uri: \n" " keyword 0 desc3 (exact)= \n"
" user 1 root=\n" " uri exact: \n"
" keyword 0 desc= \n"
" ip: \n"
" sni: \n"
" cn: \n"
" 0: example.com (exact, action=divert|split|pass||, log=!connect|master|!cert|content|!pcap|mirror, precedence=5)\n"
" 1: example2.com (exact, action=||||match, log=|||||, precedence=4)\n"
" host: \n"
" uri: \n"
"user_filter->\n"
"keyword_filter->\n"
" keyword 0 desc3= \n"
" ip: \n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"
" 0: example6.com (exact, action=||||match, log=|||||, precedence=3)\n" " 0: example6.com (exact, action=||||match, log=|||||, precedence=3)\n"
" keyword 1 desc= \n" " keyword 1 desc (exact)= \n"
" ip: \n" " cn exact: \n"
" sni: \n"
" cn: \n"
" 0: example5.com (exact, action=||||match, log=|||||, precedence=3)\n" " 0: example5.com (exact, action=||||match, log=|||||, precedence=3)\n"
" host: \n" " host substring: \n"
" 0: (all_sites, substring, action=||||match, log=|||||, precedence=3)\n" " 0: (all_sites, substring, action=||||match, log=|||||, precedence=3)\n"
" uri: \n" "keyword_filter_substr->\n"
"all_user_filter->\n" "all_user_filter->\n"
" ip: \n" "ip_filter_exact->\n"
" sni: \n" "ip_filter_substr->\n"
" cn: \n" "all_filter->\n"), "failed to translate rule: %s", s);
" host: \n"
" uri: \n"
"ip_filter->\n"
"all_filter->\n"
" ip: \n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"), "failed to translate rule: %s", s);
free(s); free(s);
opts_free(opts); opts_free(opts);
@ -1978,73 +1926,60 @@ START_TEST(set_filter_rule_12)
s = filter_rule_str(opts->filter_rules); s = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(s, fail_unless(!strcmp(s,
"filter rule 0: site=192.168.0.3, exact, port=80, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 0: site=192.168.0.3, port=80, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 1: site=192.168.0.3, exact, port=80, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 1: site=192.168.0.3, port=80, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 2: site=192.168.0.3, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 2: site=192.168.0.3, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 3: site=192.168.0.3, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 3: site=192.168.0.3, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 4: site=192.168.0.4, exact, port=80, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 4: site=192.168.0.4, port=80, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 5: site=192.168.0.4, exact, port=80, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 5: site=192.168.0.4, port=80, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 6: site=192.168.0.4, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 6: site=192.168.0.4, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 7: site=192.168.0.4, exact, port=443, exact_port, ip=192.168.0.1, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 7: site=192.168.0.4, port=443, ip=192.168.0.1, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 8: site=192.168.0.3, exact, port=80, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 8: site=192.168.0.3, port=80, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 9: site=192.168.0.3, exact, port=80, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 9: site=192.168.0.3, port=80, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 10: site=192.168.0.3, exact, port=443, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 10: site=192.168.0.3, port=443, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 11: site=192.168.0.3, exact, port=443, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 11: site=192.168.0.3, port=443, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 12: site=192.168.0.4, exact, port=80, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 12: site=192.168.0.4, port=80, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 13: site=192.168.0.4, exact, port=80, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n" "filter rule 13: site=192.168.0.4, port=80, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3\n"
"filter rule 14: site=192.168.0.4, exact, port=443, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n" "filter rule 14: site=192.168.0.4, port=443, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=|!master||||, apply to=dstip||||, precedence=3\n"
"filter rule 15: site=192.168.0.4, exact, port=443, exact_port, ip=192.168.0.2, user=, keyword=, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3"), "filter rule 15: site=192.168.0.4, port=443, ip=192.168.0.2, user=, keyword=, exact=site|port|ip||, all=|||, action=||||match, log=||||!pcap|, apply to=dstip||||, precedence=3"),
"failed to parse rule: %s", s); "failed to parse rule: %s", s);
free(s); free(s);
close(2);
opts->filter = filter_set(opts->filter_rules); opts->filter = filter_set(opts->filter_rules);
s = filter_str(opts->filter); s = filter_str(opts->filter);
fail_unless(!strcmp(s, "filter=>\n" fail_unless(!strcmp(s, "filter=>\n"
"userkeyword_filter->\n" "userkeyword_filter_exact->\n"
"user_filter->\n" "userkeyword_filter_substr->\n"
"keyword_filter->\n" "user_filter_exact->\n"
"user_filter_substr->\n"
"keyword_filter_exact->\n"
"keyword_filter_substr->\n"
"all_user_filter->\n" "all_user_filter->\n"
" ip: \n" "ip_filter_exact->\n"
" sni: \n" " ip 0 192.168.0.2 (exact)= \n"
" cn: \n" " ip exact: \n"
" host: \n" " 0: 192.168.0.4 (exact, action=||||, log=|||||, precedence=0)\n"
" uri: \n" " port exact:\n"
"ip_filter->\n"
" ip 0 192.168.0.2= \n"
" ip: \n"
" 0: 192.168.0.3 (exact, action=||||, log=|||||, precedence=0)\n"
" port:\n"
" 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" 1: 192.168.0.4 (exact, action=||||, log=|||||, precedence=0)\n" " 1: 192.168.0.3 (exact, action=||||, log=|||||, precedence=0)\n"
" port:\n" " port exact:\n"
" 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" sni: \n" " ip 1 192.168.0.1 (exact)= \n"
" cn: \n" " ip exact: \n"
" host: \n" " 0: 192.168.0.4 (exact, action=||||, log=|||||, precedence=0)\n"
" uri: \n" " port exact:\n"
" ip 1 192.168.0.1= \n"
" ip: \n"
" 0: 192.168.0.3 (exact, action=||||, log=|||||, precedence=0)\n"
" port:\n"
" 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" 1: 192.168.0.4 (exact, action=||||, log=|||||, precedence=0)\n" " 1: 192.168.0.3 (exact, action=||||, log=|||||, precedence=0)\n"
" port:\n" " port exact:\n"
" 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 0: 80 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n" " 1: 443 (exact, action=||||match, log=|!master|||!pcap|, precedence=3)\n"
" sni: \n" "ip_filter_substr->\n"
" cn: \n" "all_filter->\n"), "failed to translate rule: %s", s);
" host: \n"
" uri: \n"
"all_filter->\n"
" ip: \n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"), "failed to translate rule: %s", s);
free(s); free(s);
opts_free(opts); opts_free(opts);
@ -2075,7 +2010,9 @@ START_TEST(set_filter_rule_13)
// check errors out if we add all log actions to the macro: // check errors out if we add all log actions to the macro:
// "../../src/check_pack.c:306: Message string too long" // "../../src/check_pack.c:306: Message string too long"
// so use 3 log actions only // so use 3 log actions only
s = strdup("$logs connect content mirror"); // Also, the compiler gives:
// warning: string length 4186 is greater than the length 4095 ISO C99 compilers are required to support [-Woverlength-strings]
s = strdup("$logs connect content");
rv = filter_macro_set(opts, s, 0); rv = filter_macro_set(opts, s, 0);
fail_unless(rv == 0, "failed to set macro"); fail_unless(rv == 0, "failed to set macro");
free(s); free(s);
@ -2089,87 +2026,60 @@ START_TEST(set_filter_rule_13)
s = filter_rule_str(opts->filter_rules); s = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(s, fail_unless(!strcmp(s,
"filter rule 0: site=site1, exact, port=, , ip=, user=root, keyword=desc1, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n" "filter rule 0: site=site1, port=, ip=, user=root, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 1: site=site1, exact, port=, , ip=, user=root, keyword=desc1, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n" "filter rule 1: site=site1, port=, ip=, user=root, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 2: site=site1, exact, port=, , ip=, user=root, keyword=desc1, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5\n" "filter rule 2: site=site2, port=, ip=, user=root, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 3: site=site2, exact, port=, , ip=, user=root, keyword=desc1, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n" "filter rule 3: site=site2, port=, ip=, user=root, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 4: site=site2, exact, port=, , ip=, user=root, keyword=desc1, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n" "filter rule 4: site=site1, port=, ip=, user=root, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 5: site=site2, exact, port=, , ip=, user=root, keyword=desc1, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5\n" "filter rule 5: site=site1, port=, ip=, user=root, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 6: site=site1, exact, port=, , ip=, user=root, keyword=desc2, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n" "filter rule 6: site=site2, port=, ip=, user=root, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 7: site=site1, exact, port=, , ip=, user=root, keyword=desc2, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n" "filter rule 7: site=site2, port=, ip=, user=root, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 8: site=site1, exact, port=, , ip=, user=root, keyword=desc2, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5\n" "filter rule 8: site=site1, port=, ip=, user=daemon, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 9: site=site2, exact, port=, , ip=, user=root, keyword=desc2, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n" "filter rule 9: site=site1, port=, ip=, user=daemon, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 10: site=site2, exact, port=, , ip=, user=root, keyword=desc2, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n" "filter rule 10: site=site2, port=, ip=, user=daemon, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 11: site=site2, exact, port=, , ip=, user=root, keyword=desc2, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5\n" "filter rule 11: site=site2, port=, ip=, user=daemon, keyword=desc1, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 12: site=site1, exact, port=, , ip=, user=daemon, keyword=desc1, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n" "filter rule 12: site=site1, port=, ip=, user=daemon, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 13: site=site1, exact, port=, , ip=, user=daemon, keyword=desc1, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n" "filter rule 13: site=site1, port=, ip=, user=daemon, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 14: site=site1, exact, port=, , ip=, user=daemon, keyword=desc1, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5\n" "filter rule 14: site=site2, port=, ip=, user=daemon, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 15: site=site2, exact, port=, , ip=, user=daemon, keyword=desc1, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n" "filter rule 15: site=site2, port=, ip=, user=daemon, keyword=desc2, exact=site|||user|keyword, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5"),
"filter rule 16: site=site2, exact, port=, , ip=, user=daemon, keyword=desc1, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 17: site=site2, exact, port=, , ip=, user=daemon, keyword=desc1, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5\n"
"filter rule 18: site=site1, exact, port=, , ip=, user=daemon, keyword=desc2, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 19: site=site1, exact, port=, , ip=, user=daemon, keyword=desc2, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 20: site=site1, exact, port=, , ip=, user=daemon, keyword=desc2, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5\n"
"filter rule 21: site=site2, exact, port=, , ip=, user=daemon, keyword=desc2, all=|||, action=||||match, log=connect|||||, apply to=|sni|||, precedence=5\n"
"filter rule 22: site=site2, exact, port=, , ip=, user=daemon, keyword=desc2, all=|||, action=||||match, log=|||content||, apply to=|sni|||, precedence=5\n"
"filter rule 23: site=site2, exact, port=, , ip=, user=daemon, keyword=desc2, all=|||, action=||||match, log=|||||mirror, apply to=|sni|||, precedence=5"),
"failed to parse rule: %s", s); "failed to parse rule: %s", s);
free(s); free(s);
close(2);
opts->filter = filter_set(opts->filter_rules); opts->filter = filter_set(opts->filter_rules);
s = filter_str(opts->filter); s = filter_str(opts->filter);
fail_unless(!strcmp(s, "filter=>\n" fail_unless(!strcmp(s, "filter=>\n"
"userkeyword_filter->\n" "userkeyword_filter_exact->\n"
" user 0 daemon=\n" " user 0 root (exact)=\n"
" keyword 0 desc2= \n" " keyword exact:\n"
" ip: \n" " keyword 0 desc2 (exact)= \n"
" sni: \n" " sni exact: \n"
" 0: site1 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n" " 0: site2 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" 1: site2 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n" " 1: site1 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" cn: \n" " keyword 1 desc1 (exact)= \n"
" host: \n" " sni exact: \n"
" uri: \n" " 0: site2 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" keyword 1 desc1= \n" " 1: site1 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" ip: \n" " user 1 daemon (exact)=\n"
" sni: \n" " keyword exact:\n"
" 0: site1 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n" " keyword 0 desc2 (exact)= \n"
" 1: site2 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n" " sni exact: \n"
" cn: \n" " 0: site2 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" host: \n" " 1: site1 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" uri: \n" " keyword 1 desc1 (exact)= \n"
" user 1 root=\n" " sni exact: \n"
" keyword 0 desc2= \n" " 0: site2 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" ip: \n" " 1: site1 (exact, action=||||match, log=connect|||content||, precedence=5)\n"
" sni: \n" "userkeyword_filter_substr->\n"
" 0: site1 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n" "user_filter_exact->\n"
" 1: site2 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n" "user_filter_substr->\n"
" cn: \n" "keyword_filter_exact->\n"
" host: \n" "keyword_filter_substr->\n"
" uri: \n"
" keyword 1 desc1= \n"
" ip: \n"
" sni: \n"
" 0: site1 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n"
" 1: site2 (exact, action=||||match, log=connect|||content||mirror, precedence=5)\n"
" cn: \n"
" host: \n"
" uri: \n"
"user_filter->\n"
"keyword_filter->\n"
"all_user_filter->\n" "all_user_filter->\n"
" ip: \n" "ip_filter_exact->\n"
" sni: \n" "ip_filter_substr->\n"
" cn: \n" "all_filter->\n"), "failed to translate rule: %s", s);
" host: \n"
" uri: \n"
"ip_filter->\n"
"all_filter->\n"
" ip: \n"
" sni: \n"
" cn: \n"
" host: \n"
" uri: \n"), "failed to translate rule: %s", s);
free(s); free(s);
opts_free(opts); opts_free(opts);

@ -650,7 +650,7 @@ START_TEST(opts_set_passsite_01)
ps = filter_rule_str(opts->filter_rules); ps = filter_rule_str(opts->filter_rules);
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, port=, , ip=, user=, keyword=, all=conns|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=1"), "failed parsing passite example.com: %s", ps); fail_unless(!strcmp(ps, "filter rule 0: site=example.com, port=, ip=, user=, keyword=, exact=site||||, all=conns|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=1"), "failed parsing passite example.com: %s", ps);
#else /* WITHOUT_USERAUTH */ #else /* WITHOUT_USERAUTH */
fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, ip=, all=conns|, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=1"), "failed parsing passite example.com: %s", ps); fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, ip=, all=conns|, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=1"), "failed parsing passite example.com: %s", ps);
#endif /* WITHOUT_USERAUTH */ #endif /* WITHOUT_USERAUTH */
@ -680,7 +680,7 @@ START_TEST(opts_set_passsite_02)
ps = filter_rule_str(opts->filter_rules); ps = filter_rule_str(opts->filter_rules);
#ifndef WITHOUT_USERAUTH #ifndef WITHOUT_USERAUTH
fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2"), "failed parsing passite example.com 192.168.0.1: %s", ps); fail_unless(!strcmp(ps, "filter rule 0: site=example.com, port=, ip=192.168.0.1, user=, keyword=, exact=site||||, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2"), "failed parsing passite example.com 192.168.0.1: %s", ps);
#else /* WITHOUT_USERAUTH */ #else /* WITHOUT_USERAUTH */
fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, ip=192.168.0.1, all=|, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2"), "failed parsing passite example.com 192.168.0.1: %s", ps); fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, ip=192.168.0.1, all=|, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2"), "failed parsing passite example.com 192.168.0.1: %s", ps);
#endif /* !WITHOUT_USERAUTH */ #endif /* !WITHOUT_USERAUTH */
@ -710,7 +710,7 @@ START_TEST(opts_set_passsite_03)
fail_unless(!opts->filter_rules->next, "next set"); fail_unless(!opts->filter_rules->next, "next set");
ps = filter_rule_str(opts->filter_rules); ps = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, port=, , ip=, user=root, keyword=, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3"), "failed parsing passite example.com root: %s", ps); fail_unless(!strcmp(ps, "filter rule 0: site=example.com, port=, ip=, user=root, keyword=, exact=site||||, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3"), "failed parsing passite example.com root: %s", ps);
free(ps); free(ps);
opts_free(opts); opts_free(opts);
@ -737,7 +737,7 @@ START_TEST(opts_set_passsite_04)
fail_unless(!opts->filter_rules->next, "next set"); fail_unless(!opts->filter_rules->next, "next set");
ps = filter_rule_str(opts->filter_rules); ps = filter_rule_str(opts->filter_rules);
fail_unless(!strcmp(ps, "filter rule 0: site=*.google.com, exact, port=, , ip=, user=, keyword=android, all=|users||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3"), "failed parsing passite *.google.com * android: %s", ps); fail_unless(!strcmp(ps, "filter rule 0: site=*.google.com, port=, ip=, user=, keyword=android, exact=site||||, all=|users||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3"), "failed parsing passite *.google.com * android: %s", ps);
free(ps); free(ps);
opts_free(opts); opts_free(opts);
@ -792,11 +792,11 @@ START_TEST(opts_set_passsite_05)
fail_unless(opts->filter_rules->next->next->next, "next->next->next not set"); fail_unless(opts->filter_rules->next->next->next, "next->next->next not set");
fail_unless(opts->filter_rules->next->next->next->next, "next->next->next->next not set"); fail_unless(opts->filter_rules->next->next->next->next, "next->next->next->next not set");
fail_unless(!opts->filter_rules->next->next->next->next->next, "next->next->next->next->next set"); fail_unless(!opts->filter_rules->next->next->next->next->next, "next->next->next->next->next set");
fail_unless(!strcmp(ps, "filter rule 0: site=example.com, exact, port=, , ip=, user=, keyword=, all=conns|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=1\n" fail_unless(!strcmp(ps, "filter rule 0: site=example.com, port=, ip=, user=, keyword=, exact=site||||, all=conns|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=1\n"
"filter rule 1: site=example.com, exact, port=, , ip=, user=, keyword=, all=|users||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2\n" "filter rule 1: site=example.com, port=, ip=, user=, keyword=, exact=site||||, all=|users||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2\n"
"filter rule 2: site=example.com, exact, port=, , ip=192.168.0.1, user=, keyword=, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2\n" "filter rule 2: site=example.com, port=, ip=192.168.0.1, user=, keyword=, exact=site||||, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=2\n"
"filter rule 3: site=example.com, exact, port=, , ip=, user=root, keyword=, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3\n" "filter rule 3: site=example.com, port=, ip=, user=root, keyword=, exact=site||||, all=|||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3\n"
"filter rule 4: site=*.google.com, exact, port=, , ip=, user=, keyword=android, all=|users||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3"), "filter rule 4: site=*.google.com, port=, ip=, user=, keyword=android, exact=site||||, all=|users||, action=||pass||, log=|||||, apply to=|sni|cn||, precedence=3"),
"failed parsing multiple passites: %s", ps); "failed parsing multiple passites: %s", ps);
#else /* WITHOUT_USERAUTH */ #else /* WITHOUT_USERAUTH */
fail_unless(!opts->filter_rules->next->next->next, "next->next->next set"); fail_unless(!opts->filter_rules->next->next->next, "next->next->next set");

Loading…
Cancel
Save