commit 34c2f31a93016062ca38c04d049eccc96ad6b39c
parent c80e1d3767569ce5a0702de5824b2cd9d2502ee8
Author: Joris Vink <joris@coders.se>
Date: Sat, 9 Nov 2013 16:21:52 +0100
Add validators to kore, specified in the configuration using 'validator' keyword.
Example:
validator v_id function v_id_function
validator v_url regex ^/url/path/[a-z]*$
You can then call these using kore_validator_run(char *, char *), example:
if (!kore_validator_run("v_url", req->path))
[req->path is bad];
Diffstat:
8 files changed, 207 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
@@ -5,7 +5,7 @@ BIN=kore
S_SRC+= src/kore.c src/accesslog.c src/buf.c src/config.c src/connection.c \
src/domain.c src/http.c src/mem.c src/module.c src/net.c src/pool.c \
- src/spdy.c src/utils.c src/worker.c src/zlib_dict.c
+ src/spdy.c src/validator.c src/utils.c src/worker.c src/zlib_dict.c
S_OBJS= $(S_SRC:.c=.o)
CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes
diff --git a/includes/kore.h b/includes/kore.h
@@ -194,6 +194,19 @@ struct kore_domain {
TAILQ_HEAD(kore_domain_h, kore_domain);
+#define KORE_VALIDATOR_TYPE_REGEX 1
+#define KORE_VALIDATOR_TYPE_FUNCTION 2
+
+struct kore_validator {
+ u_int8_t type;
+ char *name;
+ char *arg;
+ regex_t rctx;
+ int (*func)(char *);
+
+ TAILQ_ENTRY(kore_validator) list;
+};
+
#define KORE_BUF_INITIAL 128
#define KORE_BUF_INCREMENT KORE_BUF_INITIAL
@@ -333,11 +346,17 @@ void kore_module_load(char *);
void kore_module_reload(void);
int kore_module_loaded(void);
void kore_domain_closelogs(void);
+void *kore_module_getsym(char *);
void kore_domain_sslstart(struct kore_domain *);
int kore_module_handler_new(char *, char *, char *, int);
struct kore_domain *kore_domain_lookup(const char *);
struct kore_module_handle *kore_module_handler_find(char *, char *);
+void kore_validator_init(void);
+void kore_validator_reload(void);
+int kore_validator_add(char *, u_int8_t, char *);
+int kore_validator_run(char *, char *);
+
void fatal(const char *, ...);
void kore_debug_internal(char *, int, const char *, ...);
diff --git a/modules/example/module.conf b/modules/example/module.conf
@@ -53,6 +53,12 @@ workers 4
# Specifies what module to be loaded.
load modules/example/example.module
+# Validators
+# validator name type regex|function
+#
+validator v_example function v_example_func
+validator v_regex regex ^/test/[a-z]*$
+
# Specify the SSL ciphers that will be used.
#ssl_cipher ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK
@@ -98,6 +104,7 @@ domain localhost {
static /spdy-reset serve_spdyreset
static /upload serve_file_upload
static /lock-test serve_lock_test
+ static /validator serve_validator
}
#domain domain.com {
diff --git a/modules/example/src/example.c b/modules/example/src/example.c
@@ -26,8 +26,10 @@ int serve_b64test(struct http_request *);
int serve_spdyreset(struct http_request *);
int serve_file_upload(struct http_request *);
int serve_lock_test(struct http_request *);
+int serve_validator(struct http_request *);
void my_callback(void);
+int v_example_func(char *);
void test_base64(u_int8_t *, u_int32_t, struct kore_buf *);
char *b64tests[] = {
@@ -204,6 +206,27 @@ test_base64(u_int8_t *src, u_int32_t slen, struct kore_buf *res)
kore_buf_appendf(res, "\n");
}
+int
+serve_validator(struct http_request *req)
+{
+ if (kore_validator_run("v_example", "test"))
+ kore_log(LOG_NOTICE, "v_example ok (expected)");
+ else
+ kore_log(LOG_NOTICE, "v_example failed");
+
+ if (kore_validator_run("v_regex", "/test/123"))
+ kore_log(LOG_NOTICE, "regex #1 ok");
+ else
+ kore_log(LOG_NOTICE, "regex #1 failed (expected)");
+
+ if (kore_validator_run("v_regex", "/test/joris"))
+ kore_log(LOG_NOTICE, "regex #2 ok (expected)");
+ else
+ kore_log(LOG_NOTICE, "regex #2 failed");
+
+ return (http_response(req, 200, (u_int8_t *)"OK", 2));
+}
+
void
my_callback(void)
{
@@ -212,3 +235,14 @@ my_callback(void)
else
kore_log(LOG_NOTICE, "running from parent");
}
+
+int
+v_example_func(char *data)
+{
+ kore_log(LOG_NOTICE, "v_example_func called");
+
+ if (!strcmp(data, "test"))
+ return (KORE_RESULT_OK);
+
+ return (KORE_RESULT_ERROR);
+}
diff --git a/src/config.c b/src/config.c
@@ -46,6 +46,7 @@ static int configure_http_header_max(char **);
static int configure_http_postbody_max(char **);
static int configure_http_hsts_enable(char **);
static int configure_http_keepalive_time(char **);
+static int configure_validator(char **);
static void domain_sslstart(void);
static struct {
@@ -77,6 +78,7 @@ static struct {
{ "http_postbody_max", configure_http_postbody_max },
{ "http_hsts_enable", configure_http_hsts_enable },
{ "http_keepalive_time", configure_http_keepalive_time },
+ { "validator", configure_validator },
{ NULL, NULL },
};
@@ -599,6 +601,31 @@ configure_http_keepalive_time(char **argv)
return (KORE_RESULT_OK);
}
+static int
+configure_validator(char **argv)
+{
+ u_int8_t type;
+
+ if (argv[3] == NULL)
+ return (KORE_RESULT_ERROR);
+
+ if (!strcmp(argv[2], "regex")) {
+ type = KORE_VALIDATOR_TYPE_REGEX;
+ } else if (!strcmp(argv[2], "function")) {
+ type = KORE_VALIDATOR_TYPE_FUNCTION;
+ } else {
+ printf("bad type for validator %s\n", argv[1]);
+ return (KORE_RESULT_ERROR);
+ }
+
+ if (!kore_validator_add(argv[1], type, argv[3])) {
+ printf("bad validator specified: %s\n", argv[1]);
+ return (KORE_RESULT_ERROR);
+ }
+
+ return (KORE_RESULT_OK);
+}
+
static void
domain_sslstart(void)
{
diff --git a/src/kore.c b/src/kore.c
@@ -87,6 +87,7 @@ main(int argc, char *argv[])
kore_log_init();
kore_mem_init();
kore_domain_init();
+ kore_validator_init();
kore_server_sslstart();
kore_parse_config();
diff --git a/src/module.c b/src/module.c
@@ -86,6 +86,8 @@ kore_module_reload(void)
}
}
+ kore_validator_reload();
+
if (kore_module_onload != NULL) {
onload = dlsym(mod_handle, kore_module_onload);
if (onload == NULL)
@@ -169,3 +171,9 @@ kore_module_handler_find(char *domain, char *path)
return (NULL);
}
+
+void *
+kore_module_getsym(char *symbol)
+{
+ return (dlsym(mod_handle, symbol));
+}
diff --git a/src/validator.c b/src/validator.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Joris Vink <joris@coders.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "kore.h"
+
+TAILQ_HEAD(, kore_validator) validators;
+
+void
+kore_validator_init(void)
+{
+ TAILQ_INIT(&validators);
+}
+
+int
+kore_validator_add(char *name, u_int8_t type, char *arg)
+{
+ struct kore_validator *val;
+
+ val = kore_malloc(sizeof(*val));
+ val->type = type;
+
+ switch (val->type) {
+ case KORE_VALIDATOR_TYPE_REGEX:
+ if (regcomp(&(val->rctx), arg, REG_NOSUB)) {
+ kore_mem_free(val);
+ kore_log(LOG_NOTICE,
+ "validator %s has bad regex %s", name, arg);
+ return (KORE_RESULT_ERROR);
+ }
+ break;
+ case KORE_VALIDATOR_TYPE_FUNCTION:
+ if ((val->func = kore_module_getsym(arg)) == NULL) {
+ kore_mem_free(val);
+ kore_log(LOG_NOTICE,
+ "validator %s has undefined callback %s",
+ name, arg);
+ return (KORE_RESULT_ERROR);
+ }
+ break;
+ default:
+ kore_mem_free(val);
+ return (KORE_RESULT_ERROR);
+ }
+
+ val->arg = kore_strdup(arg);
+ val->name = kore_strdup(name);
+ TAILQ_INSERT_TAIL(&validators, val, list);
+
+ return (KORE_RESULT_OK);
+}
+
+int
+kore_validator_run(char *name, char *data)
+{
+ int r;
+ struct kore_validator *val;
+
+ TAILQ_FOREACH(val, &validators, list) {
+ if (strcmp(val->name, name))
+ continue;
+
+ switch (val->type) {
+ case KORE_VALIDATOR_TYPE_REGEX:
+ if (!regexec(&(val->rctx), data, 0, NULL, 0))
+ r = KORE_RESULT_OK;
+ else
+ r = KORE_RESULT_ERROR;
+ break;
+ case KORE_VALIDATOR_TYPE_FUNCTION:
+ r = val->func(data);
+ break;
+ default:
+ r = KORE_RESULT_ERROR;
+ kore_log(LOG_NOTICE, "invalid type %d for validator %s",
+ val->type, val->name);
+ break;
+ }
+
+ return (r);
+ }
+
+ return (KORE_RESULT_ERROR);
+}
+
+void
+kore_validator_reload(void)
+{
+ struct kore_validator *val;
+
+ TAILQ_FOREACH(val, &validators, list) {
+ if (val->type != KORE_VALIDATOR_TYPE_FUNCTION)
+ continue;
+
+ if ((val->func = kore_module_getsym(val->arg)) == NULL)
+ fatal("no function for validator %s found", val->name);
+ }
+}