From: Jennifer Richards Date: Wed, 7 Jun 2017 19:23:40 +0000 (-0400) Subject: In-progress check-in. X-Git-Tag: v3.0.0~23 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=commitdiff_plain;h=066de6020d4bc90e8a1a3f84dd5283a7f0eea1a9 In-progress check-in. * Created TR_NAME version of wildcard matching, plus a unit test * Added function to compare a TR_NAME with plain C string * Renamed TR_FILTER_TYPE enum entries * Reordered some #includes * Added filter field handling table and accessors * Implemented general tr_filter_apply() function --- diff --git a/Makefile.am b/Makefile.am index 830f9b1..b8a5104 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,8 @@ DISTCHECK_CONFIGURE_FLAGS = \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) -bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/tests/tr_dh_test common/tests/mq_test common/tests/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/tests/cfg_test common/tests/commtest +bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/tests/tr_dh_test common/tests/mq_test \ + common/tests/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/tests/cfg_test \ + common/tests/commtest common/tests/name_test AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS) AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS) SUBDIRS = gsscon @@ -9,7 +11,7 @@ common_srcs = common/tr_name.c \ common/jansson_iterators.h \ common/tr_msg.c \ common/tr_dh.c \ - common/tr_debug.c \ + common/tr_debug.c \ common/tr_util.c \ common/tr_apc.c \ common/tr_comm.c \ @@ -145,6 +147,14 @@ common_tests_commtest_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread common_tests_thread_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread +common_tests_name_test_SOURCES = common/tests/name_test.c \ + $(common_srcs) \ + $(tid_srcs) \ + $(trp_srcs) +common_tests_name_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) +common_tests_name_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread + + pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \ include/tr_debug.h include/trust_router/trp.h \ include/trust_router/tr_dh.h \ diff --git a/common/tests/filt_test.c b/common/tests/filt_test.c new file mode 100644 index 0000000..cffeebc --- /dev/null +++ b/common/tests/filt_test.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include + +int test_field_lookup(void) +{ + + return 0; +} + +int main(void) +{ + + printf("Success.\n"); + return 0; +} \ No newline at end of file diff --git a/common/tests/name_test.c b/common/tests/name_test.c new file mode 100644 index 0000000..ae47ebb --- /dev/null +++ b/common/tests/name_test.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include + +/* returns 1 on success */ +int test_wildcard_prefix_match(const char *s, const char *wcs, int expect); + +int test_wildcards(void); + +int test_wildcards(void) +{ + /* various non-wildcard matches with mismatch in different places */ + assert(test_wildcard_prefix_match("test", "test", 1)); + assert(test_wildcard_prefix_match("test", "nest", 0)); + assert(test_wildcard_prefix_match("test", "text", 0)); + assert(test_wildcard_prefix_match("test", "tess", 0)); + assert(test_wildcard_prefix_match("test", "tes", 0)); + assert(test_wildcard_prefix_match("tes", "test", 0)); + assert(test_wildcard_prefix_match("test", "tex", 0)); + assert(test_wildcard_prefix_match("tex", "test", 0)); + + /* wildcard matches */ + assert(test_wildcard_prefix_match("test", "*test", 1)); + assert(test_wildcard_prefix_match("test", "*est", 1)); + assert(test_wildcard_prefix_match("test", "*st", 1)); + assert(test_wildcard_prefix_match("test", "*t", 1)); + assert(test_wildcard_prefix_match("test", "*", 1)); + assert(test_wildcard_prefix_match("test", "*text", 0)); + assert(test_wildcard_prefix_match("test", "*ext", 0)); + assert(test_wildcard_prefix_match("test", "*tests", 0)); + assert(test_wildcard_prefix_match("test", "tes*", 0)); + assert(test_wildcard_prefix_match("test", "test*", 0)); + assert(test_wildcard_prefix_match("*", "*", 1)); + assert(test_wildcard_prefix_match(" *", " *", 1)); + assert(test_wildcard_prefix_match(" x", " *", 0)); + assert(test_wildcard_prefix_match("*", "* ", 0)); + assert(test_wildcard_prefix_match("test*", "*", 1)); + assert(test_wildcard_prefix_match("test*", "**", 1)); + assert(test_wildcard_prefix_match("testx", "**", 0)); + return 1; + +} + +int test_wildcard_prefix_match(const char *s, const char *wcs, int expect) +{ + TR_NAME *str=tr_new_name(s); + TR_NAME *wc_str=tr_new_name(wcs); + + assert(str); + assert(wc_str); + + assert(expect==tr_name_prefix_wildcard_match(str, wc_str)); + + tr_free_name(str); + tr_free_name(wc_str); + return 1; +} + +int main(void) +{ + assert(test_wildcards()); + + printf("Success.\n"); + return 0; +} \ No newline at end of file diff --git a/common/tr_config.c b/common/tr_config.c index 4f35358..ab3388e 100644 --- a/common/tr_config.c +++ b/common/tr_config.c @@ -597,7 +597,7 @@ static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_C jfilt=json_object_get(jfilts, "tid_inbound"); if (jfilt!=NULL) { - filt=tr_cfg_parse_one_filter(tmp_ctx, jfilt, TR_FILTER_TYPE_TID_INCOMING, rc); + filt=tr_cfg_parse_one_filter(tmp_ctx, jfilt, TR_FILTER_TYPE_TID_INBOUND, rc); if (*rc!=TR_CFG_SUCCESS) { tr_debug("tr_cfg_parse_filters: Error parsing tid_inbound filter."); *rc=TR_CFG_NOPARSE; @@ -1127,7 +1127,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_ *rc=TR_CFG_NOMEM; goto cleanup; } - tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INCOMING); + tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INBOUND); filt->lines[0]=tr_fline_new(filt); if (filt->lines[0]==NULL) { tr_debug("tr_cfg_default_filter: could not allocate filter line."); diff --git a/common/tr_constraint.c b/common/tr_constraint.c index f1227f6..0a507c2 100644 --- a/common/tr_constraint.c +++ b/common/tr_constraint.c @@ -36,11 +36,10 @@ #include #include -#include -#include - #include +#include #include +#include static int tr_constraint_destructor(void *obj) diff --git a/common/tr_filter.c b/common/tr_filter.c index ecc0a24..701ec85 100644 --- a/common/tr_filter.c +++ b/common/tr_filter.c @@ -35,16 +35,200 @@ #include #include #include +#include #include +#include #include +#include +#include +const TR_FILTER_TYPE tr_filter_types[] = { + TR_FILTER_TYPE_TID_INBOUND, + TR_FILTER_TYPE_TRP_INBOUND, + TR_FILTER_TYPE_TRP_OUTBOUND +}; +const size_t tr_num_filter_types=sizeof(tr_filter_types)/sizeof(tr_filter_types[0]); +static const char *tr_filter_type_strings[] = { + "tid_inbound", + "trp_inbound", + "trp_outbound" +}; + +const char *tr_filter_type_to_string(TR_FILTER_TYPE t) { + int ii; + for (ii=0; iirp_realm); +} + +static TR_NAME *tr_ff_get_tid_rp_realm(void *rp_req_arg) +{ + TID_REQ *req=talloc_get_type_abort(rp_req_arg, TID_REQ); + assert(req); + return tr_dup_name(req->rp_realm); +} + +static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val) +{ + TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC); + char *valstr=NULL; + int val_type=0; + + assert(val); + assert(inforec); + + /* nothing matches unknown */ + if (inforec->type==TRP_INFOREC_TYPE_UNKNOWN) + return 0; + + valstr = tr_name_strdup(val); /* get this as an official null-terminated string */ + val_type = trp_inforec_type_from_string(valstr); + free(valstr); + + return (val_type==inforec->type); +} + +static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg) +{ + TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC); + return tr_new_name(trp_inforec_type_to_string(inforec->type)); +} + +/** + * Apply a filter to a target record or TID request. + * + * If one of the filter lines matches, out_action is set to the applicable action. If constraints + * is not NULL, the constraints from the matching filter line will be added to the constraint set + * *constraints, or to a new one if *constraints is NULL. In this case, TR_FILTER_MATCH will be + * returned. + * + * If there is no match, returns TR_FILTER_NO_MATCH, out_action is undefined, and constraints + * will not be changed. + * + * @param target Record or request to which the filter is applied + * @param filt Filter to apply + * @param constraints Pointer to existing set of constraints (NULL if not tracking constraints) + * @param out_action Action to be carried out (output) + * @return TR_FILTER_MATCH or TR_FILTER_NO_MATCH + */ +int tr_filter_apply(void *target, + TR_FILTER *filt, + TR_CONSTRAINT_SET **constraints, + TR_FILTER_ACTION *out_action) +{ + unsigned int ii=0, jj=0; + int retval=TR_FILTER_NO_MATCH; + + /* Default action is reject */ + *out_action = TR_FILTER_ACTION_REJECT; + + /* Validate filter */ + if ((filt==NULL) || (filt->type==TR_FILTER_TYPE_UNKNOWN)) + return TR_FILTER_NO_MATCH; + + /* Step through filter lines looking for a match. If a line matches, retval + * will be set to TR_FILTER_MATCH, so stop then. */ + for (ii=0, retval=TR_FILTER_NO_MATCH; + (iilines[ii]==NULL) + continue; + + /* Assume we are going to succeed. If any specs fail to match, we'll set + * this to TR_FILTER_NO_MATCH. */ + retval=TR_FILTER_MATCH; + for (jj=0; jjlines[ii]->specs[jj]==NULL) + continue; + + if (!tr_fspec_matches(filt->lines[ii]->specs[jj], filt->type, target)) { + retval=TR_FILTER_NO_MATCH; /* set this in case this is the last filter line */ + break; /* give up on this filter line */ + } + } + } + + if (retval==TR_FILTER_MATCH) { + /* Matched line ii. Grab its action and constraints. */ + *out_action = filt->lines[ii]->action; + if (constraints!=NULL) { + /* if either constraint is missing, these are no-ops */ + tr_constraint_add_to_set(constraints, filt->lines[ii]->realm_cons); + tr_constraint_add_to_set(constraints, filt->lines[ii]->domain_cons); + } + } + + return retval; +} int tr_filter_process_rp_permitted(TR_NAME *rp_realm, TR_FILTER *rpp_filter, TR_CONSTRAINT_SET *in_constraints, TR_CONSTRAINT_SET **out_constraints, - int *out_action) + TR_FILTER_ACTION *out_action) { int i = 0, j = 0; @@ -53,7 +237,7 @@ int tr_filter_process_rp_permitted(TR_NAME *rp_realm, /* If this isn't a valid rp_permitted filter, return no match. */ if ((!rpp_filter) || - (TR_FILTER_TYPE_RP_PERMITTED != rpp_filter->type)) { + (TR_FILTER_TYPE_TID_INBOUND != rpp_filter->type)) { return TR_FILTER_NO_MATCH; } @@ -63,7 +247,7 @@ int tr_filter_process_rp_permitted(TR_NAME *rp_realm, if ((rpp_filter->lines[i]) && (rpp_filter->lines[i]->specs[j]) && - (tr_fspec_matches(rpp_filter->lines[i]->specs[j], rp_realm))) { + (tr_fspec_matches(rpp_filter->lines[i]->specs[j], 0, rp_realm))) { /* todo: fix or remove */ *out_action = rpp_filter->lines[i]->action; *out_constraints = in_constraints; if (rpp_filter->lines[i]->realm_cons) @@ -117,10 +301,22 @@ void tr_fspec_set_match(TR_FSPEC *fspec, TR_NAME *match) } /* returns 1 if the spec matches */ -int tr_fspec_matches(TR_FSPEC *fspec, TR_NAME *name) +int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target) { + struct tr_filter_field_entry *field=NULL; + TR_NAME *name=NULL; + + if ((fspec==NULL) || (fspec->match==NULL)) + return 0; + + /* Look up how to handle the requested field */ + field = tr_filter_field_entry(ftype, fspec->field); + if (field==NULL) + return 0; + + name=field->get(target); return ((fspec->match != NULL) && - (0 != tr_prefix_wildcard_match(name->buf, fspec->match->buf))); + (0 != tr_name_prefix_wildcard_match(name, fspec->match))); } void tr_fline_free(TR_FLINE *fline) diff --git a/common/tr_name.c b/common/tr_name.c index eacef63..83d1db0 100644 --- a/common/tr_name.c +++ b/common/tr_name.c @@ -48,7 +48,7 @@ void tr_free_name (TR_NAME *name) free(name); } -TR_NAME *tr_new_name (const char *name) +TR_NAME *tr_new_name (const char *name) { TR_NAME *new; @@ -102,6 +102,64 @@ int tr_name_cmp(TR_NAME *one, TR_NAME *two) return cmp; } +/** + * Compare a TR_NAME with a null-terminated string. + * + * @param one TR_NAME to compare + * @param two_str Ordinary C null-terminated string + * @return 0 on match, <0 if one precedes two, >0 if two precedes one + */ +int tr_name_cmp_str(TR_NAME *one, const char *two_str) +{ + TR_NAME *two=tr_new_name(two_str); + int cmp=tr_name_cmp(one, two); + tr_free_name(two); + return cmp; +} + +/** + * Compare strings, allowing one to have a single '*' as the wildcard character if it is the first character. + * Leading whitespace is significant. + * + * @param str Fixed string to compare + * @param wc_str Wildcard string to compare + * @return 1 if the the string (str) matches the wildcard string (wc_str), 0 if not. + * + */ +int tr_name_prefix_wildcard_match(TR_NAME *str, TR_NAME *wc_str) +{ + const char *wc_post=NULL; + size_t wc_len = 0; + + if ((!str) || (!wc_str)) + return 0; + + if (0 == (wc_len = wc_str->len)) + return 0; + + if ('*' == wc_str->buf[0]) { + /* Wildcard, so the actual compare will start at the second character of wc_str */ + wc_post = wc_str->buf + 1; + wc_len--; + } else if (str->len == wc_len) { + /* No wildcard, but the strings are the same length so may match. + * Compare the full strings. */ + wc_post=wc_str->buf; + wc_len=wc_str->len; + } else { + /* No wildcard and strings are different length, so no match */ + return 0; + } + + /* A match is not possible if the fixed part of the wildcard string is longer than + * the string to match it against. */ + if (wc_len > str->len) + return 0; + + /* Now we compare the last wc_len characters of str against wc_post */ + return (0 == strncmp(str->buf + str->len - wc_len, wc_post, wc_len)); +} + void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len) { size_t used_len; @@ -113,7 +171,7 @@ void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len) else dest[0] = '\0'; } - + char * tr_name_strdup(TR_NAME *src) { char *s = calloc(src->len+1, 1); diff --git a/include/tr_filter.h b/include/tr_filter.h index bb71725..c3d4ed1 100644 --- a/include/tr_filter.h +++ b/include/tr_filter.h @@ -40,6 +40,8 @@ #include #include +#include +#include #define TR_MAX_FILTERS 5 #define TR_MAX_FILTER_LINES 8 @@ -58,12 +60,15 @@ typedef enum { /* Filter types */ typedef enum { - TR_FILTER_TYPE_TID_INCOMING = 0, + TR_FILTER_TYPE_TID_INBOUND = 0, + TR_FILTER_TYPE_TRP_INBOUND, + TR_FILTER_TYPE_TRP_OUTBOUND, TR_FILTER_TYPE_UNKNOWN } TR_FILTER_TYPE; -/* #define for backward compatibility, TODO: get rid of this -jlr */ -#define TR_FILTER_TYPE_RP_PERMITTED TR_FILTER_TYPE_TID_INCOMING +extern const size_t tr_num_filter_types; +const char *tr_filter_type_to_string(TR_FILTER_TYPE t); +TR_FILTER_TYPE tr_filter_type_from_string(const char *s); typedef struct tr_fspec { TR_NAME *field; @@ -100,14 +105,15 @@ void tr_fspec_free(TR_FSPEC *fspec); void tr_fspec_set_match(TR_FSPEC *fspec, TR_NAME *match); -int tr_fspec_matches(TR_FSPEC *fspec, TR_NAME *name); +int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target); /*In tr_constraint.c and exported, but not really a public symbol; needed by tr_filter.c and by tr_constraint.c*/ int TR_EXPORT tr_prefix_wildcard_match(const char *str, const char *wc_str); +int tr_filter_apply(void *target, TR_FILTER *filt, TR_CONSTRAINT_SET **constraints, TR_FILTER_ACTION *out_action); int tr_filter_process_rp_permitted(TR_NAME *rp_realm, TR_FILTER *rpp_filter, TR_CONSTRAINT_SET *in_constraints, - TR_CONSTRAINT_SET **out_constraints, int *out_action); + TR_CONSTRAINT_SET **out_constraints, TR_FILTER_ACTION *out_action); TR_CONSTRAINT_SET *tr_constraint_set_from_fline(TR_FLINE *fline); diff --git a/include/trust_router/tr_name.h b/include/trust_router/tr_name.h index 7e86003..1f392a8 100644 --- a/include/trust_router/tr_name.h +++ b/include/trust_router/tr_name.h @@ -49,6 +49,8 @@ TR_EXPORT TR_NAME *tr_new_name (const char *name); TR_EXPORT TR_NAME *tr_dup_name (TR_NAME *from); TR_EXPORT void tr_free_name (TR_NAME *name); TR_EXPORT int tr_name_cmp (TR_NAME *one, TR_NAME *two); +int tr_name_cmp_str(TR_NAME *one, const char *two_str); +int tr_name_prefix_wildcard_match(TR_NAME *str, TR_NAME *wc_str); TR_EXPORT void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len); TR_EXPORT char *tr_name_strdup(TR_NAME *); TR_EXPORT json_t *tr_name_to_json_string(TR_NAME *src); diff --git a/tr/tr_tid.c b/tr/tr_tid.c index 64c0a16..fb76dd7 100644 --- a/tr/tr_tid.c +++ b/tr/tr_tid.c @@ -247,7 +247,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids, TID_REQ *fwd_req = NULL; TR_COMM *cfg_comm = NULL; TR_COMM *cfg_apc = NULL; - int oaction = TR_FILTER_ACTION_REJECT; + TR_FILTER_ACTION oaction = TR_FILTER_ACTION_REJECT; time_t expiration_interval=0; struct tr_tids_event_cookie *cookie=talloc_get_type_abort(cookie_in, struct tr_tids_event_cookie); TR_CFG_MGR *cfg_mgr=cookie->cfg_mgr;