2008-06-29 15:48:28 +00:00
|
|
|
#include "condition.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
2008-07-25 22:42:08 +00:00
|
|
|
static gboolean condition_parse_ip(condition_rvalue *val, const char *txt) {
|
|
|
|
if (parse_ipv4(txt, &val->ipv4.addr, NULL)) {
|
|
|
|
val->type = COND_VALUE_SOCKET_IPV4;
|
|
|
|
val->ipv4.networkmask = 0xFFFFFFFF;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (parse_ipv6(txt, val->ipv6.addr, NULL)) {
|
|
|
|
val->type = COND_VALUE_SOCKET_IPV6;
|
|
|
|
val->ipv6.network = 128;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean condition_parse_ip_net(condition_rvalue *val, const char *txt) {
|
|
|
|
if (parse_ipv4(txt, &val->ipv4.addr, &val->ipv4.networkmask)) {
|
|
|
|
val->type = COND_VALUE_SOCKET_IPV4;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (parse_ipv6(txt, val->ipv6.addr, &val->ipv6.network)) {
|
|
|
|
val->type = COND_VALUE_SOCKET_IPV6;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean condition_ip_from_socket(condition_rvalue *val, sock_addr *addr) {
|
|
|
|
switch (addr->plain.sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
val->type = COND_VALUE_SOCKET_IPV4;
|
|
|
|
val->ipv4.addr = addr->ipv4.sin_addr.s_addr;
|
|
|
|
val->ipv4.networkmask = 0xFFFFFFFF;
|
|
|
|
return TRUE;
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
case AF_INET6:
|
|
|
|
val->type = COND_VALUE_SOCKET_IPV6;
|
|
|
|
memcpy(val->ipv6.addr, addr->ipv6.sin6_addr.s6_addr, 16);
|
|
|
|
val->ipv6.network = 128;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
condition_lvalue* condition_lvalue_new(cond_lvalue_t type, GString *key) {
|
|
|
|
condition_lvalue *lvalue = g_slice_new0(condition_lvalue);
|
2008-08-07 12:12:51 +00:00
|
|
|
if (type == COMP_REQUEST_HEADER) g_string_ascii_down(key);
|
2008-07-25 12:09:03 +00:00
|
|
|
lvalue->type = type;
|
|
|
|
lvalue->key = key;
|
|
|
|
lvalue->refcount = 1;
|
|
|
|
return lvalue;
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
void condition_lvalue_acquire(condition_lvalue *lvalue) {
|
|
|
|
assert(lvalue->refcount > 0);
|
|
|
|
lvalue->refcount++;
|
|
|
|
}
|
2008-06-29 15:48:28 +00:00
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
void condition_lvalue_release(condition_lvalue *lvalue) {
|
2008-08-06 18:46:42 +00:00
|
|
|
if (!lvalue) return;
|
2008-07-25 12:09:03 +00:00
|
|
|
assert(lvalue->refcount > 0);
|
|
|
|
if (!(--lvalue->refcount)) {
|
|
|
|
if (lvalue->key) g_string_free(lvalue->key, TRUE);
|
|
|
|
g_slice_free(condition_lvalue, lvalue);
|
|
|
|
}
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
static condition* condition_new(comp_operator_t op, condition_lvalue *lvalue) {
|
2008-06-29 15:48:28 +00:00
|
|
|
condition *c = g_slice_new0(condition);
|
|
|
|
c->refcount = 1;
|
2008-07-17 17:32:11 +00:00
|
|
|
c->op = op;
|
2008-07-25 12:09:03 +00:00
|
|
|
c->lvalue = lvalue;
|
2008-06-29 15:48:28 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2008-07-25 20:38:42 +00:00
|
|
|
/* only EQ and NE */
|
2008-07-25 12:09:03 +00:00
|
|
|
static condition* cond_new_string(comp_operator_t op, condition_lvalue *lvalue, GString *str) {
|
2008-07-25 20:38:42 +00:00
|
|
|
condition *c;
|
|
|
|
c = condition_new(op, lvalue);
|
2008-07-25 12:09:03 +00:00
|
|
|
c->rvalue.type = COND_VALUE_STRING;
|
2008-07-25 20:38:42 +00:00
|
|
|
c->rvalue.string = str;
|
2008-06-29 15:48:28 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2008-07-25 20:38:42 +00:00
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
/* only MATCH and NOMATCH */
|
|
|
|
static condition* cond_new_match(server *srv, comp_operator_t op, condition_lvalue *lvalue, GString *str) {
|
|
|
|
UNUSED(op); UNUSED(lvalue); UNUSED(str);
|
|
|
|
ERROR(srv, "%s", "pcre not supported for now");
|
2008-08-07 12:12:51 +00:00
|
|
|
/* TODO: pcre */
|
2008-07-25 20:38:42 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* only IP and NOTIP */
|
|
|
|
static condition* cond_new_ip(server *srv, comp_operator_t op, condition_lvalue *lvalue, GString *str) {
|
2008-07-25 22:42:08 +00:00
|
|
|
condition *c;
|
|
|
|
c = condition_new(op, lvalue);
|
|
|
|
if (!condition_parse_ip_net(&c->rvalue, str->str)) {
|
|
|
|
ERROR(srv, "Invalid ip address '%s'", str->str);
|
|
|
|
condition_release(srv, c);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return c;
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
|
|
|
|
2008-07-25 20:38:42 +00:00
|
|
|
condition* condition_new_string(server *srv, comp_operator_t op, condition_lvalue *lvalue, GString *str) {
|
|
|
|
switch (op) {
|
|
|
|
case CONFIG_COND_EQ:
|
|
|
|
case CONFIG_COND_NE:
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_PREFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOPREFIX:
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_SUFFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOSUFFIX:
|
2008-07-25 12:09:03 +00:00
|
|
|
return cond_new_string(op, lvalue, str);
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_MATCH:
|
|
|
|
case CONFIG_COND_NOMATCH:
|
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
return cond_new_match(srv, op, lvalue, str);
|
|
|
|
#else
|
|
|
|
ERROR(srv, "compiled without pcre, cannot use '%s'", comp_op_to_string(op));
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
case CONFIG_COND_IP:
|
|
|
|
case CONFIG_COND_NOTIP:
|
|
|
|
return cond_new_ip(srv, op, lvalue, str);
|
|
|
|
case CONFIG_COND_GT:
|
|
|
|
case CONFIG_COND_GE:
|
|
|
|
case CONFIG_COND_LT:
|
|
|
|
case CONFIG_COND_LE:
|
|
|
|
ERROR(srv, "Cannot compare strings with '%s'", comp_op_to_string(op));
|
|
|
|
return NULL;
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
2008-07-25 20:38:42 +00:00
|
|
|
ERROR(srv, "Condition creation failed: %s %s '%s' (perhaps you compiled without pcre?)",
|
|
|
|
cond_lvalue_to_string(lvalue->type), comp_op_to_string(op),
|
|
|
|
str->str);
|
2008-06-30 10:25:01 +00:00
|
|
|
return NULL;
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
|
|
|
|
2008-07-25 20:38:42 +00:00
|
|
|
condition* condition_new_int(server *srv, comp_operator_t op, condition_lvalue *lvalue, gint64 i) {
|
2008-06-29 15:48:28 +00:00
|
|
|
condition *c;
|
2008-07-25 20:38:42 +00:00
|
|
|
switch (op) {
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_PREFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOPREFIX:
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_SUFFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOSUFFIX:
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_MATCH:
|
|
|
|
case CONFIG_COND_NOMATCH:
|
|
|
|
case CONFIG_COND_IP:
|
|
|
|
case CONFIG_COND_NOTIP:
|
|
|
|
ERROR(srv, "Cannot compare integers with '%s'", comp_op_to_string(op));
|
2008-07-19 10:56:44 +00:00
|
|
|
return NULL;
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_EQ:
|
|
|
|
case CONFIG_COND_NE:
|
|
|
|
case CONFIG_COND_GT:
|
|
|
|
case CONFIG_COND_GE:
|
|
|
|
case CONFIG_COND_LT:
|
|
|
|
case CONFIG_COND_LE:
|
|
|
|
c = condition_new(op, lvalue);
|
|
|
|
c->rvalue.type = COND_VALUE_INT;
|
|
|
|
c->rvalue.i = i;
|
|
|
|
return c;
|
2008-07-19 10:56:44 +00:00
|
|
|
}
|
2008-07-25 20:38:42 +00:00
|
|
|
ERROR(srv, "Condition creation failed: %s %s %"G_GINT64_FORMAT" (perhaps you compiled without pcre?)",
|
|
|
|
cond_lvalue_to_string(lvalue->type), comp_op_to_string(op),
|
|
|
|
i);
|
|
|
|
return NULL;
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
|
|
|
|
2008-07-25 20:38:42 +00:00
|
|
|
|
2008-06-29 15:48:28 +00:00
|
|
|
static void condition_free(condition *c) {
|
2008-07-25 12:09:03 +00:00
|
|
|
switch (c->rvalue.type) {
|
2008-06-30 10:25:01 +00:00
|
|
|
case COND_VALUE_INT:
|
|
|
|
/* nothing to free */
|
2008-06-29 15:48:28 +00:00
|
|
|
break;
|
2008-06-30 10:25:01 +00:00
|
|
|
case COND_VALUE_STRING:
|
2008-07-25 20:38:42 +00:00
|
|
|
g_string_free(c->rvalue.string, TRUE);
|
|
|
|
break;
|
2008-06-29 15:48:28 +00:00
|
|
|
#ifdef HAVE_PCRE_H
|
2008-07-25 20:38:42 +00:00
|
|
|
case COND_VALUE_REGEXP
|
|
|
|
if (c->rvalue.regex) pcre_free(c->rvalue.regex);
|
|
|
|
if (c->rvalue.regex_study) pcre_free(c->rvalue.regex_study);
|
2008-06-29 15:48:28 +00:00
|
|
|
#endif
|
2008-07-25 20:38:42 +00:00
|
|
|
break;
|
|
|
|
case COND_VALUE_SOCKET_IPV4:
|
|
|
|
case COND_VALUE_SOCKET_IPV6:
|
|
|
|
/* nothing to free */
|
2008-06-29 15:48:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
g_slice_free(condition, c);
|
|
|
|
}
|
|
|
|
|
2008-07-24 11:25:40 +00:00
|
|
|
void condition_acquire(condition *c) {
|
|
|
|
assert(c->refcount > 0);
|
|
|
|
c->refcount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void condition_release(server *srv, condition* c) {
|
|
|
|
UNUSED(srv);
|
2008-08-06 18:46:42 +00:00
|
|
|
if (!c) return;
|
|
|
|
assert(c->refcount > 0);
|
2008-06-29 15:48:28 +00:00
|
|
|
if (!(--c->refcount)) {
|
|
|
|
condition_free(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-19 10:56:44 +00:00
|
|
|
const char* comp_op_to_string(comp_operator_t op) {
|
2008-07-17 17:32:11 +00:00
|
|
|
switch (op) {
|
|
|
|
case CONFIG_COND_EQ: return "==";
|
|
|
|
case CONFIG_COND_NE: return "!=";
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_PREFIX: return "=^";
|
|
|
|
case CONFIG_COND_NOPREFIX: return "=^";
|
|
|
|
case CONFIG_COND_SUFFIX: return "=$";
|
|
|
|
case CONFIG_COND_NOSUFFIX: return "!$";
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_MATCH: return "=~";
|
2008-07-17 17:32:11 +00:00
|
|
|
case CONFIG_COND_NOMATCH: return "!~";
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_IP: return "=/";
|
|
|
|
case CONFIG_COND_NOTIP: return "!/";
|
|
|
|
case CONFIG_COND_GT: return ">";
|
|
|
|
case CONFIG_COND_GE: return ">=";
|
|
|
|
case CONFIG_COND_LT: return "<";
|
|
|
|
case CONFIG_COND_LE: return "<=";
|
2008-07-17 17:32:11 +00:00
|
|
|
}
|
2008-06-29 15:48:28 +00:00
|
|
|
|
2008-07-17 17:32:11 +00:00
|
|
|
return "<unkown>";
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
const char* cond_lvalue_to_string(cond_lvalue_t t) {
|
|
|
|
switch (t) {
|
|
|
|
case COMP_REQUEST_LOCALIP: return "request.localip";
|
|
|
|
case COMP_REQUEST_REMOTEIP: return "request.remoteip";
|
|
|
|
case COMP_REQUEST_PATH: return "request.path";
|
|
|
|
case COMP_REQUEST_HOST: return "request.host";
|
|
|
|
case COMP_REQUEST_SCHEME: return "request.scheme";
|
|
|
|
case COMP_REQUEST_QUERY_STRING: return "request.querystring";
|
|
|
|
case COMP_REQUEST_METHOD: return "request.method";
|
|
|
|
case COMP_REQUEST_CONTENT_LENGTH: return "request.length";
|
|
|
|
case COMP_PHYSICAL_PATH: return "physical.path";
|
|
|
|
case COMP_PHYSICAL_PATH_EXISTS: return "physical.pathexist";
|
|
|
|
case COMP_PHYSICAL_SIZE: return "physical.size";
|
|
|
|
case COMP_REQUEST_HEADER: return "request.header";
|
|
|
|
}
|
2008-06-29 15:48:28 +00:00
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
return "<unknown>";
|
2008-06-29 15:48:28 +00:00
|
|
|
}
|
2008-06-30 10:25:01 +00:00
|
|
|
|
2008-07-25 20:38:42 +00:00
|
|
|
/* COND_VALUE_STRING and COND_VALUE_REGEXP only */
|
2008-06-30 10:25:01 +00:00
|
|
|
static gboolean condition_check_eval_string(server *srv, connection *con, condition *cond) {
|
2008-07-25 22:42:08 +00:00
|
|
|
const char *value = "";
|
2008-06-30 10:25:01 +00:00
|
|
|
gboolean result = FALSE;
|
|
|
|
UNUSED(srv);
|
|
|
|
UNUSED(con);
|
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
switch (cond->lvalue->type) {
|
|
|
|
case COMP_REQUEST_LOCALIP:
|
2008-07-25 22:42:08 +00:00
|
|
|
value = con->local_addr_str->str;
|
2008-07-25 12:09:03 +00:00
|
|
|
break;
|
|
|
|
case COMP_REQUEST_REMOTEIP:
|
2008-07-25 22:42:08 +00:00
|
|
|
value = con->remote_addr_str->str;
|
2008-06-30 10:25:01 +00:00
|
|
|
break;
|
2008-06-30 11:38:52 +00:00
|
|
|
case COMP_REQUEST_PATH:
|
2008-06-30 10:25:01 +00:00
|
|
|
value = con->request.uri.path->str;
|
|
|
|
break;
|
2008-06-30 11:38:52 +00:00
|
|
|
case COMP_REQUEST_HOST:
|
2008-08-09 15:20:12 +00:00
|
|
|
value = con->request.uri.host->str;
|
2008-06-30 10:25:01 +00:00
|
|
|
break;
|
2008-06-30 11:38:52 +00:00
|
|
|
case COMP_REQUEST_SCHEME:
|
2008-07-25 22:42:08 +00:00
|
|
|
value = con->is_ssl ? "https" : "http";
|
2008-06-30 10:25:01 +00:00
|
|
|
break;
|
2008-06-30 11:38:52 +00:00
|
|
|
case COMP_REQUEST_QUERY_STRING:
|
2008-06-30 10:25:01 +00:00
|
|
|
value = con->request.uri.query->str;
|
|
|
|
break;
|
2008-06-30 11:38:52 +00:00
|
|
|
case COMP_REQUEST_METHOD:
|
2008-06-30 10:25:01 +00:00
|
|
|
value = con->request.http_method_str->str;
|
|
|
|
break;
|
|
|
|
case COMP_PHYSICAL_PATH:
|
2008-08-07 12:12:51 +00:00
|
|
|
value = con->physical.path->str;
|
|
|
|
break;
|
2008-06-30 10:25:01 +00:00
|
|
|
case COMP_PHYSICAL_PATH_EXISTS:
|
2008-08-07 12:12:51 +00:00
|
|
|
/* TODO: physical path exists */
|
2008-07-25 12:09:03 +00:00
|
|
|
break;
|
|
|
|
case COMP_REQUEST_HEADER:
|
2008-08-07 12:12:51 +00:00
|
|
|
http_header_get_fast(srv->tmp_str, con->request.headers, GSTR_LEN(cond->lvalue->key));
|
|
|
|
value = srv->tmp_str->str;
|
2008-06-30 10:25:01 +00:00
|
|
|
break;
|
2008-06-30 12:01:53 +00:00
|
|
|
case COMP_PHYSICAL_SIZE:
|
2008-08-07 12:12:51 +00:00
|
|
|
/* TODO: physical size */
|
|
|
|
g_string_printf(srv->tmp_str, "%"L_GOFFSET_FORMAT, (goffset) 0);
|
|
|
|
value = srv->tmp_str->str;
|
2008-07-25 22:42:08 +00:00
|
|
|
break;
|
2008-06-30 12:01:53 +00:00
|
|
|
case COMP_REQUEST_CONTENT_LENGTH:
|
2008-08-07 12:12:51 +00:00
|
|
|
g_string_printf(srv->tmp_str, "%"L_GOFFSET_FORMAT, con->request.content_length);
|
|
|
|
value = srv->tmp_str->str;
|
2008-06-30 11:38:52 +00:00
|
|
|
break;
|
2008-06-30 10:25:01 +00:00
|
|
|
}
|
2008-06-30 11:38:52 +00:00
|
|
|
|
2008-07-25 22:42:08 +00:00
|
|
|
switch (cond->op) {
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_EQ:
|
2008-08-13 20:10:20 +00:00
|
|
|
result = g_str_equal(value, cond->rvalue.string->str);
|
2008-06-30 12:34:37 +00:00
|
|
|
break;
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_NE:
|
2008-08-13 20:10:20 +00:00
|
|
|
result = g_str_equal(value, cond->rvalue.string->str);
|
|
|
|
break;
|
|
|
|
case CONFIG_COND_PREFIX:
|
|
|
|
result = g_str_has_prefix(value, cond->rvalue.string->str);
|
|
|
|
break;
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOPREFIX:
|
|
|
|
result = !g_str_has_prefix(value, cond->rvalue.string->str);
|
|
|
|
break;
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_SUFFIX:
|
|
|
|
result = g_str_has_suffix(value, cond->rvalue.string->str);
|
2008-06-30 12:34:37 +00:00
|
|
|
break;
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOSUFFIX:
|
|
|
|
result = !g_str_has_suffix(value, cond->rvalue.string->str);
|
|
|
|
break;
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_MATCH:
|
|
|
|
case CONFIG_COND_NOMATCH:
|
|
|
|
#ifdef HAVE_PCRE_H
|
2008-06-30 12:34:37 +00:00
|
|
|
/* TODO: pcre */
|
2008-07-25 20:38:42 +00:00
|
|
|
ERROR(srv, "%s", "regexp match not supported yet");
|
|
|
|
#else
|
|
|
|
ERROR(srv, "compiled without pcre, cannot use '%s'", comp_op_to_string(cond->op));
|
|
|
|
#endif
|
2008-06-30 12:34:37 +00:00
|
|
|
break;
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_IP:
|
|
|
|
case CONFIG_COND_NOTIP:
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_GE:
|
|
|
|
case CONFIG_COND_GT:
|
|
|
|
case CONFIG_COND_LE:
|
|
|
|
case CONFIG_COND_LT:
|
2008-07-25 20:38:42 +00:00
|
|
|
ERROR(srv, "cannot compare string/regexp with '%s'", comp_op_to_string(cond->op));
|
2008-06-30 12:34:37 +00:00
|
|
|
break;
|
2008-06-30 10:25:01 +00:00
|
|
|
}
|
2008-06-30 12:01:53 +00:00
|
|
|
|
2008-06-30 10:25:01 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-06-30 11:38:52 +00:00
|
|
|
|
|
|
|
static gboolean condition_check_eval_int(server *srv, connection *con, condition *cond) {
|
|
|
|
UNUSED(srv);
|
|
|
|
UNUSED(con);
|
|
|
|
gint64 value;
|
|
|
|
|
2008-07-25 12:09:03 +00:00
|
|
|
switch (cond->lvalue->type) {
|
2008-06-30 12:34:37 +00:00
|
|
|
case COMP_REQUEST_CONTENT_LENGTH:
|
|
|
|
value = con->request.content_length;
|
|
|
|
case COMP_PHYSICAL_SIZE:
|
|
|
|
value = con->physical.size;
|
|
|
|
break;
|
|
|
|
default:
|
2008-08-07 12:12:51 +00:00
|
|
|
CON_ERROR(srv, con, "couldn't get int value for '%s', using -1", cond_lvalue_to_string(cond->lvalue->type));
|
2008-06-30 12:34:37 +00:00
|
|
|
value = -1;
|
2008-06-30 11:38:52 +00:00
|
|
|
}
|
|
|
|
|
2008-07-17 17:32:11 +00:00
|
|
|
if (value > 0) switch (cond->op) {
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_EQ: /** == */
|
2008-07-25 12:09:03 +00:00
|
|
|
return (value == cond->rvalue.i);
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_NE: /** != */
|
2008-07-25 12:09:03 +00:00
|
|
|
return (value != cond->rvalue.i);
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_LT: /** < */
|
2008-07-25 12:09:03 +00:00
|
|
|
return (value < cond->rvalue.i);
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_LE: /** <= */
|
2008-07-25 12:09:03 +00:00
|
|
|
return (value <= cond->rvalue.i);
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_GT: /** > */
|
2008-07-25 12:09:03 +00:00
|
|
|
return (value > cond->rvalue.i);
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_GE: /** >= */
|
2008-07-25 12:09:03 +00:00
|
|
|
return (value >= cond->rvalue.i);
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_PREFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOPREFIX:
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_SUFFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOSUFFIX:
|
2008-06-30 12:34:37 +00:00
|
|
|
case CONFIG_COND_MATCH:
|
|
|
|
case CONFIG_COND_NOMATCH:
|
2008-07-25 20:38:42 +00:00
|
|
|
case CONFIG_COND_IP:
|
|
|
|
case CONFIG_COND_NOTIP:
|
|
|
|
ERROR(srv, "cannot compare int with '%s'", comp_op_to_string(cond->op));
|
2008-06-30 12:34:37 +00:00
|
|
|
return FALSE;
|
2008-06-30 11:38:52 +00:00
|
|
|
}
|
2008-07-01 18:56:59 +00:00
|
|
|
|
|
|
|
return FALSE;
|
2008-06-30 11:38:52 +00:00
|
|
|
}
|
|
|
|
|
2008-06-30 10:25:01 +00:00
|
|
|
static gboolean ipv4_in_ipv4_net(guint32 target, guint32 match, guint32 networkmask) {
|
|
|
|
return (target & networkmask) == (match & networkmask);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean ipv6_in_ipv6_net(const unsigned char *target, const guint8 *match, guint network) {
|
|
|
|
guint8 mask = network % 8;
|
|
|
|
if (0 != memcmp(target, match, network / 8)) return FALSE;
|
|
|
|
if (!mask) return TRUE;
|
|
|
|
mask = ~(((guint) 1 << (8-mask)) - 1);
|
|
|
|
return (target[network / 8] & mask) == (match[network / 8] & mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean ipv6_in_ipv4_net(const unsigned char *target, guint32 match, guint32 networkmask) {
|
|
|
|
static const guint8 ipv6match[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
|
|
|
|
if (!ipv6_in_ipv6_net(target, ipv6match, 96)) return FALSE;
|
|
|
|
return ipv4_in_ipv4_net(*(guint32*)(target+12), match, networkmask);
|
|
|
|
}
|
2008-07-25 22:42:08 +00:00
|
|
|
|
|
|
|
static gboolean ipv4_in_ipv6_net(guint32 target, const guint8 *match, guint network) {
|
|
|
|
guint8 ipv6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
|
|
|
|
*(guint32*) (ipv6+12) = target;
|
|
|
|
return ipv6_in_ipv6_net(ipv6, match, network);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean ip_in_net(condition_rvalue *target, condition_rvalue *network) {
|
|
|
|
if (target->type == COND_VALUE_SOCKET_IPV4) {
|
|
|
|
if (network->type == COND_VALUE_SOCKET_IPV4) {
|
|
|
|
return ipv4_in_ipv4_net(target->ipv4.addr, network->ipv4.addr, network->ipv4.networkmask);
|
|
|
|
} else if (network->type == COND_VALUE_SOCKET_IPV6) {
|
|
|
|
return ipv4_in_ipv6_net(target->ipv4.addr, network->ipv6.addr, network->ipv6.network);
|
|
|
|
}
|
|
|
|
} else if (target->type == COND_VALUE_SOCKET_IPV6) {
|
|
|
|
if (network->type == COND_VALUE_SOCKET_IPV4) {
|
|
|
|
return ipv6_in_ipv4_net(target->ipv6.addr, network->ipv4.addr, network->ipv4.networkmask);
|
|
|
|
} else if (network->type == COND_VALUE_SOCKET_IPV6) {
|
|
|
|
return ipv6_in_ipv6_net(target->ipv6.addr, network->ipv6.addr, network->ipv6.network);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CONFIG_COND_IP and CONFIG_COND_NOTIP only */
|
|
|
|
static gboolean condition_check_eval_ip(server *srv, connection *con, condition *cond) {
|
|
|
|
condition_rvalue ipval;
|
|
|
|
const char *value = NULL;
|
|
|
|
gboolean result = FALSE;
|
|
|
|
UNUSED(srv);
|
|
|
|
UNUSED(con);
|
|
|
|
|
|
|
|
ipval.type = COND_VALUE_INT;
|
|
|
|
|
|
|
|
switch (cond->lvalue->type) {
|
|
|
|
case COMP_REQUEST_LOCALIP:
|
|
|
|
if (!condition_ip_from_socket(&ipval, &con->local_addr))
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
|
|
|
break;
|
|
|
|
case COMP_REQUEST_REMOTEIP:
|
|
|
|
if (!condition_ip_from_socket(&ipval, &con->remote_addr))
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
|
|
|
break;
|
|
|
|
case COMP_REQUEST_PATH:
|
2008-08-07 12:12:51 +00:00
|
|
|
ERROR(srv, "%s", "Cannot parse request.path as ip");
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
2008-07-25 22:42:08 +00:00
|
|
|
break;
|
|
|
|
case COMP_REQUEST_HOST:
|
2008-08-09 15:20:12 +00:00
|
|
|
value = con->request.uri.host->str;
|
2008-07-25 22:42:08 +00:00
|
|
|
break;
|
|
|
|
case COMP_REQUEST_SCHEME:
|
|
|
|
ERROR(srv, "%s", "Cannot parse request.scheme as ip");
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
|
|
|
case COMP_REQUEST_QUERY_STRING:
|
|
|
|
value = con->request.uri.query->str;
|
|
|
|
break;
|
|
|
|
case COMP_REQUEST_METHOD:
|
2008-08-07 12:12:51 +00:00
|
|
|
ERROR(srv, "%s", "Cannot request.method as ip");
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
2008-07-25 22:42:08 +00:00
|
|
|
break;
|
|
|
|
case COMP_PHYSICAL_PATH:
|
|
|
|
case COMP_PHYSICAL_PATH_EXISTS:
|
2008-08-07 12:12:51 +00:00
|
|
|
ERROR(srv, "%s", "Cannot physical.path(-exists) as ip");
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
2008-07-25 22:42:08 +00:00
|
|
|
break;
|
|
|
|
case COMP_REQUEST_HEADER:
|
2008-08-07 12:12:51 +00:00
|
|
|
http_header_get_fast(srv->tmp_str, con->request.headers, GSTR_LEN(cond->lvalue->key));
|
|
|
|
value = srv->tmp_str->str;
|
2008-07-25 22:42:08 +00:00
|
|
|
break;
|
|
|
|
case COMP_PHYSICAL_SIZE:
|
|
|
|
case COMP_REQUEST_CONTENT_LENGTH:
|
|
|
|
ERROR(srv, "%s", "Cannot parse integers as ip");
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipval.type == COND_VALUE_INT) {
|
|
|
|
if (!value || !condition_parse_ip(&ipval, value))
|
|
|
|
return (cond->op == CONFIG_COND_NOTIP);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (cond->op) {
|
|
|
|
case CONFIG_COND_IP:
|
|
|
|
return ip_in_net(&ipval, &cond->rvalue);
|
|
|
|
case CONFIG_COND_NOTIP:
|
|
|
|
return !ip_in_net(&ipval, &cond->rvalue);
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_PREFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOPREFIX:
|
2008-08-13 20:10:20 +00:00
|
|
|
case CONFIG_COND_SUFFIX:
|
2008-08-13 20:26:45 +00:00
|
|
|
case CONFIG_COND_NOSUFFIX:
|
2008-07-25 22:42:08 +00:00
|
|
|
case CONFIG_COND_EQ:
|
|
|
|
case CONFIG_COND_NE:
|
|
|
|
case CONFIG_COND_MATCH:
|
|
|
|
case CONFIG_COND_NOMATCH:
|
|
|
|
case CONFIG_COND_GE:
|
|
|
|
case CONFIG_COND_GT:
|
|
|
|
case CONFIG_COND_LE:
|
|
|
|
case CONFIG_COND_LT:
|
|
|
|
ERROR(srv, "cannot match ips with '%s'", comp_op_to_string(cond->op));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2008-06-30 10:25:01 +00:00
|
|
|
|
2008-07-25 20:38:42 +00:00
|
|
|
gboolean condition_check(server *srv, connection *con, condition *cond) {
|
2008-07-25 12:09:03 +00:00
|
|
|
switch (cond->rvalue.type) {
|
2008-06-30 12:34:37 +00:00
|
|
|
case COND_VALUE_STRING:
|
2008-07-25 20:38:42 +00:00
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
case COND_VALUE_REGEXP:
|
|
|
|
#endif
|
2008-06-30 12:34:37 +00:00
|
|
|
return condition_check_eval_string(srv, con, cond);
|
|
|
|
case COND_VALUE_INT:
|
|
|
|
return condition_check_eval_int(srv, con, cond);
|
2008-07-25 20:38:42 +00:00
|
|
|
case COND_VALUE_SOCKET_IPV4:
|
|
|
|
case COND_VALUE_SOCKET_IPV6:
|
2008-07-25 22:42:08 +00:00
|
|
|
return condition_check_eval_ip(srv, con, cond);
|
2008-06-30 10:25:01 +00:00
|
|
|
}
|
2008-07-25 20:38:42 +00:00
|
|
|
return FALSE;
|
2008-06-30 10:25:01 +00:00
|
|
|
}
|