Add exact bit, do not add slashes around sites, avoid unnecessary strdups

Limit site len to 200
pull/48/head
Soner Tari 3 years ago
parent 85fb1bd214
commit ff3bcab3f1

@ -2280,6 +2280,8 @@ opts_unset_validate_proto(opts_t *opts)
void
opts_set_passsite(opts_t *opts, char *value, int line_num)
{
#define MAX_SITE_LEN 200
// site[*] [(clientaddr|user|*) [description keyword]]
char *argv[sizeof(char *) * 3];
int argc = 0;
@ -2300,51 +2302,53 @@ opts_set_passsite(opts_t *opts, char *value, int line_num)
exit(EXIT_FAILURE);
}
filter_rule_t *fr = malloc(sizeof(filter_rule_t));
memset(fr, 0, sizeof(filter_rule_t));
filter_rule_t *rule = malloc(sizeof(filter_rule_t));
memset(rule, 0, sizeof(filter_rule_t));
// The for loop with strtok_r() above does not output empty strings
// So, no need to check if the length of argv[0] > 0
size_t len = strlen(argv[0]);
// Common names are separated by slashes
char s[len + 3];
memcpy(s + 1, argv[0], len);
s[0] = '/';
s[len + 1] = '/';
s[len + 2] = '\0';
fr->site = strdup(s);
if (len > MAX_SITE_LEN) {
fprintf(stderr, "Filter site too long %zu > %d, on line %d\n", len, MAX_SITE_LEN, line_num);
exit(EXIT_FAILURE);
}
if (fr->site[len] != '*') {
fr->exact = 1;
if (argv[0][len - 1] == '*') {
rule->exact = 0;
argv[0][len - 1] = '\0';
} else {
rule->exact = 1;
}
rule->site = strdup(argv[0]);
if (argc == 1) {
// Apply filter rule to all conns
// Equivalent to "site *" without keyword
fr->all = 1;
rule->all = 1;
}
if (argc > 1) {
if (!strcmp(argv[1], "*")) {
// Apply filter rule to all ips or users perhaps with keyword
fr->all = 1;
rule->all = 1;
#ifndef WITHOUT_USERAUTH
} else if (sys_isuser(argv[1])) {
if (!opts->user_auth) {
fprintf(stderr, "User filter requires user auth on line %d\n", line_num);
exit(EXIT_FAILURE);
}
fr->user = strdup(argv[1]);
rule->user = strdup(argv[1]);
#endif /* !WITHOUT_USERAUTH */
} else {
fr->ip = strdup(argv[1]);
rule->ip = strdup(argv[1]);
}
}
if (argc > 2) {
if (fr->ip) {
fprintf(stderr, "Ip filter cannot define keyword filter, or user '%s' does not exist on line %d\n", fr->ip, line_num);
if (rule->ip) {
fprintf(stderr, "Ip filter cannot define keyword filter, or user '%s' does not exist on line %d\n", rule->ip, line_num);
exit(EXIT_FAILURE);
}
#ifndef WITHOUT_USERAUTH
@ -2352,37 +2356,37 @@ opts_set_passsite(opts_t *opts, char *value, int line_num)
fprintf(stderr, "Keyword filter requires user auth on line %d\n", line_num);
exit(EXIT_FAILURE);
}
fr->keyword = strdup(argv[2]);
rule->keyword = strdup(argv[2]);
#endif /* !WITHOUT_USERAUTH */
}
fr->sni = 1;
fr->cn = 1;
fr->pass = 1;
rule->sni = 1;
rule->cn = 1;
rule->pass = 1;
fr->next = opts->filter_rules;
opts->filter_rules = fr;
rule->next = opts->filter_rules;
opts->filter_rules = rule;
#ifdef DEBUG_OPTS
log_dbg_printf("Filter rule: %s, %s, %s"
#ifndef WITHOUT_USERAUTH
", %s, %s"
#endif /* !WITHOUT_USERAUTH */
", all=%d, action=%s|%s|%s|%s, , apply to=%s|%s|%s|%s|%s\n",
fr->site, fr->exact ? "exact" : "substring", STRORNONE(fr->ip),
rule->site, rule->exact ? "exact" : "substring", STRORNONE(rule->ip),
#ifndef WITHOUT_USERAUTH
STRORNONE(fr->user), STRORNONE(fr->keyword),
STRORNONE(rule->user), STRORNONE(rule->keyword),
#endif /* !WITHOUT_USERAUTH */
fr->all,
fr->divert ? "divert" : "", fr->split ? "split" : "", fr->pass ? "pass" : "", fr->block ? "block" : "",
fr->dstip ? "dstip" : "", fr->sni ? "sni" : "", fr->cn ? "cn" : "", fr->host ? "host" : "", fr->uri ? "uri" : "");
rule->all,
rule->divert ? "divert" : "", rule->split ? "split" : "", rule->pass ? "pass" : "", rule->block ? "block" : "",
rule->dstip ? "dstip" : "", rule->sni ? "sni" : "", rule->cn ? "cn" : "", rule->host ? "host" : "", rule->uri ? "uri" : "");
#endif /* DEBUG_OPTS */
}
static filter_site_t *
opts_find_site(filter_site_t *site, char *s)
opts_find_site(filter_site_t *site, filter_rule_t *rule)
{
while (site) {
if (!strcmp(site->site, s))
if ((site->exact == rule->exact) && !strcmp(site->site, rule->site))
break;
site = site->next;
}
@ -2392,7 +2396,7 @@ opts_find_site(filter_site_t *site, char *s)
static filter_site_t *
opts_add_site(filter_site_t *site, filter_rule_t *rule)
{
filter_site_t *s = opts_find_site(site, rule->site);
filter_site_t *s = opts_find_site(site, rule);
if (!s) {
s = malloc(sizeof(filter_site_t));
if (!s)
@ -2401,6 +2405,8 @@ opts_add_site(filter_site_t *site, filter_rule_t *rule)
s->site = strdup(rule->site);
}
s->exact = rule->exact;
// Multiple rules can set the action for the same site
if (rule->divert)
s->divert = 1;

@ -181,6 +181,7 @@ typedef struct filter_rule {
typedef struct filter_site {
char *site;
unsigned int exact : 1;
unsigned int divert : 1;
unsigned int split : 1;
unsigned int pass : 1;

@ -384,65 +384,39 @@ protohttp_filter_request_header_line(const char *line, protohttp_ctx_t *http_ctx
}
static int NONNULL(1,2)
protossl_match_host(pxy_conn_ctx_t *ctx, const char *site)
protossl_match_host(pxy_conn_ctx_t *ctx, filter_site_t *site)
{
protohttp_ctx_t *http_ctx = ctx->protoctx->arg;
//log_finest_va("ENTER, %s, %s", site, STRORDASH(http_ctx->http_host));
size_t len = strlen(site);
char _site[len + 1];
memcpy(_site, site, sizeof _site);
// Skip the first slash
char *s = _site + 1;
if (_site[len - 2] == '*') {
_site[len - 2] = '\0';
if (http_ctx->http_host && strstr(http_ctx->http_host, s)) {
log_finest_va("Match substring in host: %s, %s", http_ctx->http_host, s);
if (site->exact) {
if (http_ctx->http_host && !strcmp(http_ctx->http_host, site->site)) {
log_finest_va("Match exact with host: %s, %s", site->site, http_ctx->http_host);
return 1;
}
} 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;
}
// The end of substring search
return 0;
}
// The start of exact search
if (http_ctx->http_host && !strcmp(http_ctx->http_host, s)) {
log_finest_va("Match exact with host: %s", http_ctx->http_host);
return 1;
}
return 0;
}
static int NONNULL(1,2)
protossl_match_uri(pxy_conn_ctx_t *ctx, const char *site)
protossl_match_uri(pxy_conn_ctx_t *ctx, filter_site_t *site)
{
protohttp_ctx_t *http_ctx = ctx->protoctx->arg;
//log_finest_va("ENTER, %s, %s", site, STRORDASH(http_ctx->http_uri));
size_t len = strlen(site);
char _site[len + 1];
memcpy(_site, site, sizeof _site);
// Skip the first slash
char *s = _site + 1;
if (_site[len - 2] == '*') {
_site[len - 2] = '\0';
if (strstr(http_ctx->http_uri, s)) {
log_finest_va("Match substring in uri: %s, %s", http_ctx->http_uri, s);
if (site->exact) {
if (!strcmp(http_ctx->http_uri, site->site)) {
log_finest_va("Match exact with uri: %s, %s", site->site, http_ctx->http_uri);
return 1;
}
} 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;
}
// The end of substring search
return 0;
}
// The start of exact search
if (strcmp(http_ctx->http_uri, s)) {
log_finest_va("Match exact with uri: %s", http_ctx->http_uri);
return 1;
}
return 0;
}
@ -452,46 +426,48 @@ protohttp_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
{
protohttp_ctx_t *http_ctx = ctx->protoctx->arg;
filter_site_t *site = list->host;
while (site) {
if (protossl_match_host(ctx, site->site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %.*s for %s:%s, %s:%s"
if (http_ctx->http_host) {
filter_site_t *site = list->host;
while (site) {
if (protossl_match_host(ctx, site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %s for %s:%s, %s:%s"
#ifndef WITHOUT_USERAUTH
", %s, %s"
", %s, %s"
#endif /* !WITHOUT_USERAUTH */
", %s\n",
(int)strlen(site->site) - 2, site->site + 1,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
", %s\n", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
#ifndef WITHOUT_USERAUTH
STRORDASH(ctx->user), STRORDASH(ctx->desc),
STRORDASH(ctx->user), STRORDASH(ctx->desc),
#endif /* !WITHOUT_USERAUTH */
STRORDASH(http_ctx->http_host));
ctx->pass = 1;
return 1;
STRORDASH(http_ctx->http_host));
ctx->pass = 1;
return 1;
}
site = site->next;
}
site = site->next;
}
site = list->uri;
while (site) {
if (protossl_match_uri(ctx, site->site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %.*s for %s:%s, %s:%s"
if (http_ctx->http_uri) {
filter_site_t *site = list->uri;
while (site) {
if (protossl_match_uri(ctx, site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %s for %s:%s, %s:%s"
#ifndef WITHOUT_USERAUTH
", %s, %s"
", %s, %s"
#endif /* !WITHOUT_USERAUTH */
", %s\n",
(int)strlen(site->site) - 2, site->site + 1,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
", %s\n", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
#ifndef WITHOUT_USERAUTH
STRORDASH(ctx->user), STRORDASH(ctx->desc),
STRORDASH(ctx->user), STRORDASH(ctx->desc),
#endif /* !WITHOUT_USERAUTH */
STRORDASH(http_ctx->http_uri));
ctx->pass = 1;
return 1;
STRORDASH(http_ctx->http_uri));
ctx->pass = 1;
return 1;
}
site = site->next;
}
site = site->next;
}
#ifndef WITHOUT_USERAUTH

@ -591,111 +591,79 @@ protossl_srccert_create(pxy_conn_ctx_t *ctx)
}
static int NONNULL(1,2)
protossl_match_sni(pxy_conn_ctx_t *ctx, const char *site)
protossl_match_sni(pxy_conn_ctx_t *ctx, filter_site_t *site)
{
//log_finest_va("ENTER, %s, %s", site, STRORDASH(ctx->sslctx->sni));
// @attention Make sure sni is not null
if (!ctx->sslctx->sni) {
return 0;
}
// site has surrounding slashes: "/example.com/"
// site is never empty or just "//", @see opts_set_filter_rule(),
// so no need to check if the length of site > 0 or 2
size_t len = strlen(site);
// 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
// @todo Check if multithreaded read access causes any issues
char _site[len + 1];
memcpy(_site, site, sizeof _site);
// Skip the first slash
char *s = _site + 1;
if (_site[len - 2] == '*') {
_site[len - 2] = '\0';
if (strstr(ctx->sslctx->sni, s)) {
log_finest_va("Match substring in sni: %s, %s", ctx->sslctx->sni, s);
if (site->exact) {
if (!strcmp(ctx->sslctx->sni, site->site)) {
log_finest_va("Match exact with sni: %s, %s", site->site, ctx->sslctx->sni);
return 1;
}
} else {
if (strstr(ctx->sslctx->sni, site->site)) {
log_finest_va("Match substring in sni: %s, %s", site->site, ctx->sslctx->sni);
return 1;
}
// The end of substring search
return 0;
}
// The start of exact search
// Replace the last slash with null
_site[len - 1] = '\0';
// SNI: "example.com"
if (!strcmp(ctx->sslctx->sni, s)) {
log_finest_va("Match exact with sni: %s", ctx->sslctx->sni);
return 1;
}
return 0;
}
static int NONNULL(1,2)
protossl_match_cn(pxy_conn_ctx_t *ctx, const char *site)
protossl_match_cn(pxy_conn_ctx_t *ctx, filter_site_t *site)
{
//log_finest_va("ENTER, %s, %s", site, STRORDASH(ctx->sslctx->ssl_names));
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
// @attention Make sure ssl_names is not null
if (!ctx->sslctx->ssl_names) {
return 0;
}
size_t len = strlen(site->site);
size_t len = strlen(site);
// Common names are separated by slashes
char _site[len + 3];
memcpy(_site + 1, site->site, len);
_site[0] = '/';
_site[len + 1] = '/';
_site[len + 2] = '\0';
len += 2;
char _site[len + 1];
memcpy(_site, site, sizeof _site);
// Skip the first slash
char *s = _site + 1;
// Skip the first slash
char *s = _site + 1;
// Replace the last slash with null
_site[len - 1] = '\0';
if (_site[len - 2] == '*') {
_site[len - 2] = '\0';
if (strstr(ctx->sslctx->ssl_names, s)) {
log_finest_va("Match substring in common names: %s, %s", ctx->sslctx->ssl_names, s);
// Single common name: "example.com"
if (!strcmp(ctx->sslctx->ssl_names, s)) {
log_finest_va("Match exact with single common name: %s", ctx->sslctx->ssl_names);
return 1;
}
// The end of substring search
return 0;
}
// The start of exact search
// Replace the last slash with null
_site[len - 1] = '\0';
// Restore the slash at the end
_site[len - 1] = '/';
// Single common name: "example.com"
if (!strcmp(ctx->sslctx->ssl_names, s)) {
log_finest_va("Match exact with single common name: %s", ctx->sslctx->ssl_names);
return 1;
}
// Restore the slash at the end
_site[len - 1] = '/';
// 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;
}
// 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 (strstr(ctx->sslctx->ssl_names, _site)) {
log_finest_va("Match exact with a middle common name: %s, %s", ctx->sslctx->ssl_names, _site);
return 1;
}
// Middle common name: "/example.com/"
if (strstr(ctx->sslctx->ssl_names, _site)) {
log_finest_va("Match exact with a middle common name: %s, %s", ctx->sslctx->ssl_names, _site);
return 1;
}
// Replace the last slash with null
_site[len - 1] = '\0';
// Replace the last slash with null
_site[len - 1] = '\0';
// Last common name: "/example.com"
if (strstr(ctx->sslctx->ssl_names, _site) == ctx->sslctx->ssl_names + strlen(ctx->sslctx->ssl_names) - strlen(_site)) {
log_finest_va("Match exact with the last common name: %s, %s", ctx->sslctx->ssl_names, _site);
return 1;
// Last common name: "/example.com"
if (strstr(ctx->sslctx->ssl_names, _site) == ctx->sslctx->ssl_names + strlen(ctx->sslctx->ssl_names) - strlen(_site)) {
log_finest_va("Match exact with the last common name: %s, %s", ctx->sslctx->ssl_names, _site);
return 1;
}
} else {
if (strstr(ctx->sslctx->ssl_names, site->site)) {
log_finest_va("Match substring in common names: %s, %s", site->site, ctx->sslctx->ssl_names);
return 1;
}
}
return 0;
}
@ -703,46 +671,48 @@ protossl_match_cn(pxy_conn_ctx_t *ctx, const char *site)
static int
protossl_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
{
filter_site_t *site = list->sni;
while (site) {
if (protossl_match_sni(ctx, site->site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %.*s for %s:%s, %s:%s"
if (ctx->sslctx->sni) {
filter_site_t *site = list->sni;
while (site) {
if (protossl_match_sni(ctx, site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %s for %s:%s, %s:%s"
#ifndef WITHOUT_USERAUTH
", %s, %s"
", %s, %s"
#endif /* !WITHOUT_USERAUTH */
", %s\n",
(int)strlen(site->site) - 2, site->site + 1,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
", %s\n", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
#ifndef WITHOUT_USERAUTH
STRORDASH(ctx->user), STRORDASH(ctx->desc),
STRORDASH(ctx->user), STRORDASH(ctx->desc),
#endif /* !WITHOUT_USERAUTH */
STRORDASH(ctx->sslctx->sni));
ctx->pass = 1;
return 1;
STRORDASH(ctx->sslctx->sni));
ctx->pass = 1;
return 1;
}
site = site->next;
}
site = site->next;
}
site = list->cn;
while (site) {
if (protossl_match_cn(ctx, site->site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %.*s for %s:%s, %s:%s"
if (ctx->sslctx->ssl_names) {
filter_site_t *site = list->cn;
while (site) {
if (protossl_match_cn(ctx, site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %s for %s:%s, %s:%s"
#ifndef WITHOUT_USERAUTH
", %s, %s"
", %s, %s"
#endif /* !WITHOUT_USERAUTH */
", %s\n",
(int)strlen(site->site) - 2, site->site + 1,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
", %s\n", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str),
#ifndef WITHOUT_USERAUTH
STRORDASH(ctx->user), STRORDASH(ctx->desc),
STRORDASH(ctx->user), STRORDASH(ctx->desc),
#endif /* !WITHOUT_USERAUTH */
STRORDASH(ctx->sslctx->ssl_names));
ctx->pass = 1;
return 1;
STRORDASH(ctx->sslctx->ssl_names));
ctx->pass = 1;
return 1;
}
site = site->next;
}
site = site->next;
}
#ifndef WITHOUT_USERAUTH

@ -1974,32 +1974,18 @@ pxy_userauth(pxy_conn_ctx_t *ctx)
#endif /* !WITHOUT_USERAUTH */
static int NONNULL(1,2)
pxyconn_filter_match(pxy_conn_ctx_t *ctx, const char *site)
pxyconn_filter_match(pxy_conn_ctx_t *ctx, filter_site_t *site)
{
//log_finest_va("ENTER, %s, %s", site, STRORDASH(ctx->dsthost_str));
size_t len = strlen(site);
char _site[len + 1];
memcpy(_site, site, sizeof _site);
// Skip the first slash
char *s = _site + 1;
if (_site[len - 2] == '*') {
_site[len - 2] = '\0';
if (ctx->dsthost_str && strstr(ctx->dsthost_str, s)) {
log_finest_va("Match substring in dst: %s, %s", ctx->dsthost_str, s);
if (site->exact) {
if (!strcmp(ctx->dsthost_str, site->site)) {
log_finest_va("Match exact with dst: %s, %s", site->site, ctx->dsthost_str);
return 1;
}
} else {
if (strstr(ctx->dsthost_str, site->site)) {
log_finest_va("Match substring in dst: %s, %s", site->site, ctx->dsthost_str);
return 1;
}
// The end of substring search
return 0;
}
// The start of exact search
if (ctx->dsthost_str && !strcmp(ctx->dsthost_str, s)) {
log_finest_va("Match exact with dst: %s", ctx->dsthost_str);
return 1;
}
return 0;
}
@ -2007,17 +1993,18 @@ pxyconn_filter_match(pxy_conn_ctx_t *ctx, const char *site)
int
pxyconn_dsthost_filter(pxy_conn_ctx_t *ctx, filter_list_t *list)
{
filter_site_t *site = list->ip;
while (site) {
if (pxyconn_filter_match(ctx, site->site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %.*s for %s:%s, %s:%s\n",
(int)strlen(site->site) - 2, site->site + 1,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
ctx->pass = 1;
return 1;
if (ctx->dsthost_str) {
filter_site_t *site = list->ip;
while (site) {
if (pxyconn_filter_match(ctx, site)) {
// Do not print the surrounding slashes
log_err_level_printf(LOG_WARNING, "Found site: %s for %s:%s, %s:%s\n", site->site,
STRORDASH(ctx->srchost_str), STRORDASH(ctx->srcport_str), STRORDASH(ctx->dsthost_str), STRORDASH(ctx->dstport_str));
ctx->pass = 1;
return 1;
}
site = site->next;
}
site = site->next;
}
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));

Loading…
Cancel
Save