#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
+#include <jansson.h>
#include <trp_internal.h>
#include <tid_internal.h>
* @param filt_out Will point to the loaded filter on success
* @return Return value from tr_cfg_parse_one_config_file()
*/
-int load_filter(const char *fname, TR_FILTER **filt_out)
+int load_filter(const char *fname, TR_FILTER_SET **filts_out)
{
TR_CFG *cfg=tr_cfg_new(NULL);
TR_CFG_RC rc=TR_CFG_ERROR;
assert(fname);
- assert(filt_out);
+ assert(filts_out);
rc=tr_cfg_parse_one_config_file(cfg, fname);
if (rc!=TR_CFG_SUCCESS)
/* Steal the filter from the first rp_client */
assert(cfg);
assert(cfg->rp_clients);
- assert(cfg->rp_clients->filter);
- *filt_out=cfg->rp_clients->filter;
- cfg->rp_clients->filter=NULL; /* can't use the _set_filter() because that will free the filter */
- talloc_steal(NULL, *filt_out);
+ assert(cfg->rp_clients->filters);
+ *filts_out=cfg->rp_clients->filters;
+ cfg->rp_clients->filters=NULL; /* can't use the _set_filter() because that will free the filter */
+ talloc_steal(NULL, *filts_out);
cleanup:
tr_cfg_free(cfg);
*/
int test_load_filter(void)
{
- TR_FILTER *filt=NULL;
+ TR_FILTER_SET *filts=NULL;
- assert(TR_CFG_SUCCESS==load_filter(FILTER_PATH "valid-filt.json", &filt));
- assert(TR_CFG_NOPARSE==load_filter(FILTER_PATH "invalid-filt-repeated-key.json", &filt));
- assert(TR_CFG_ERROR==load_filter(FILTER_PATH "invalid-filt-unknown-field.json", &filt));
+ assert(TR_CFG_SUCCESS==load_filter(FILTER_PATH "valid-filt.json", &filts));
+ if (filts) tr_filter_set_free(filts);
+ filts=NULL;
+ assert(TR_CFG_NOPARSE==load_filter(FILTER_PATH "invalid-filt-repeated-key.json", &filts));
+ if (filts) tr_filter_set_free(filts);
+ filts=NULL;
+ assert(TR_CFG_ERROR==load_filter(FILTER_PATH "invalid-filt-unknown-field.json", &filts));
+ if (filts) tr_filter_set_free(filts);
+ filts=NULL;
return 1;
}
-int test_trp_inforec_filter(TRP_INFOREC_TYPE type)
+/**
+ * Read the first inforec from the TR_MSG encoded in JSON file named fname.
+ *
+ * @param fname Filename with path for TR_MSG JSON
+ * @return Pointer to the decoded inforec, or NULL on failure
+ */
+TRP_INFOREC *load_inforec(const char *fname)
{
- TRP_INFOREC *inforec=trp_inforec_new(NULL, type);
- TR_FILTER *filt=tr_filter_new(NULL);
+ TR_MSG *msg=NULL;
+ TRP_UPD *upd=NULL;
+ TRP_INFOREC *inforec=NULL;
+ json_t *decoded=json_load_file(fname, JSON_REJECT_DUPLICATES|JSON_DISABLE_EOF_CHECK, NULL);
+ char *encoded=json_dumps(decoded, 0); /* silly way to read the file without mucking around */
+
+ assert(decoded);
+ json_decref(decoded);
- assert(inforec);
- assert(filt);
+ assert(encoded);
+ assert(msg=tr_msg_decode(encoded, strlen(encoded)));
+ assert(upd=tr_msg_get_trp_upd(msg));
+ assert(inforec=trp_upd_get_inforec(upd));
+ /* now remove the inforec from the update context */
+ talloc_steal(NULL, inforec);
+ tr_msg_free_decoded(msg);
+ tr_msg_free_encoded(encoded);
+ return inforec;
+}
+
+/* make this bigger than your message file */
+#define MAX_FILE_SIZE 20000
+TID_REQ *load_tid_req(const char *fname)
+{
+ TID_REQ *out=NULL;
+ TR_MSG *msg=NULL;
+ FILE *f=NULL;
+ char *msgbuf=NULL;
+ size_t msglen=0;
+ msgbuf=malloc(MAX_FILE_SIZE);
+ assert(msgbuf);
+ f=fopen(fname, "r");
+ assert(f);
+ msglen=fread(msgbuf, 1, MAX_FILE_SIZE, f);
+ assert(msglen);
+ assert(feof(f));
+ msg=tr_msg_decode(msgbuf, msglen);
+ free(msgbuf);
+ msgbuf=NULL;
- return 1;
+ assert(msg);
+ assert(tr_msg_get_msg_type(msg)==TID_REQUEST);
+
+ /* take the tid req out of the msg */
+ out=tr_msg_get_req(msg);
+ tr_msg_set_req(msg, NULL);
+ assert(out);
+
+ tr_msg_free_decoded(msg);
+ return out;
}
+/**
+ * Read a set of filters from a config JSON in filt_fname and test against the tid_req or inforec in target_fname.
+ * If expect==1, succeed if the target is accepted by the filter, otherwise succeed if it is rejected.
+ * Takes filters from the first rp_realm defined in the filter file and the first inforec or tid req from
+ * the target file.
+ *
+ * @param filt_fname Name of JSON file containing filters
+ * @param ftype Which type of filter to test
+ * @param target_fname Name of JSON file containing inforec
+ * @param expected_match 1 if we expect a match, 0 otherwise
+ * @param expected_action Expected action if the filter matches
+ * @return 1 if expected result is obtained, 0 or does not return otherwise
+ */
+int test_one_filter(const char *filt_fname,
+ TR_FILTER_TYPE ftype,
+ const char *target_fname,
+ int expected_match,
+ TR_FILTER_ACTION expected_action)
+{
+ void *target=NULL;
+ TR_FILTER_SET *filts=NULL;
+ TR_FILTER_ACTION action=TR_FILTER_ACTION_UNKNOWN;
+
+ /* load filter for first test */
+ assert(TR_CFG_SUCCESS==load_filter(filt_fname, &filts));
-int test_trp_filter(void)
+ /* load the target req or inforec */
+ switch(ftype) {
+ case TR_FILTER_TYPE_TID_INBOUND:
+ target=load_tid_req(target_fname);
+ break;
+
+ case TR_FILTER_TYPE_TRP_INBOUND:
+ case TR_FILTER_TYPE_TRP_OUTBOUND:
+ target=load_inforec(target_fname);
+ break;
+
+ default:
+ printf("Unknown filter type.\n");
+ }
+ assert(target);
+
+ assert(expected_match==tr_filter_apply(target, tr_filter_set_get(filts, ftype), NULL, &action));
+ if (expected_match==TR_FILTER_MATCH)
+ assert(action==expected_action);
+
+ tr_filter_set_free(filts);
+ switch(ftype) {
+ case TR_FILTER_TYPE_TID_INBOUND:
+ tid_req_free((TID_REQ *)target);
+ break;
+
+ case TR_FILTER_TYPE_TRP_INBOUND:
+ case TR_FILTER_TYPE_TRP_OUTBOUND:
+ trp_inforec_free((TRP_INFOREC *)target);
+ break;
+
+ default:
+ printf("Unknown filter type.\n");
+ }
+ return 1;
+}
+
+int test_filter(void)
{
- assert(test_trp_inforec_filter(TRP_INFOREC_TYPE_ROUTE));
- assert(test_trp_inforec_filter(TRP_INFOREC_TYPE_COMMUNITY));
+ json_t *test_list=json_load_file(FILTER_PATH "filter-tests.json", JSON_DISABLE_EOF_CHECK, NULL);
+ json_t *this;
+ size_t ii;
+ const char *filt_file, *target_file;
+ TR_FILTER_TYPE ftype;
+ int expect_match;
+ TR_FILTER_ACTION action;
+
+ json_array_foreach(test_list, ii, this) {
+ printf("Running filter test case: %s\n", json_string_value(json_object_get(this, "test label")));
+ fflush(stdout);
+
+ filt_file=json_string_value(json_object_get(this, "filter file"));
+ ftype=tr_filter_type_from_string(json_string_value(json_object_get(this, "filter type")));
+ target_file=json_string_value(json_object_get(this, "target file"));
+ if (0==strcmp("yes", json_string_value(json_object_get(this, "expect match"))))
+ expect_match=TR_FILTER_MATCH;
+ else
+ expect_match=TR_FILTER_NO_MATCH;
+
+ if (0==strcmp("accept", json_string_value(json_object_get(this, "action"))))
+ action=TR_FILTER_ACTION_ACCEPT;
+ else
+ action=TR_FILTER_ACTION_REJECT;
+
+ assert(test_one_filter(filt_file, ftype, target_file, expect_match, action));
+ }
+
return 1;
}
int main(void)
{
assert(test_load_filter());
+ assert(test_filter());
printf("Success\n");
return 0;
}
\ No newline at end of file
--- /dev/null
+{
+ "msg_type": "trp_update",
+ "msg_body": {
+ "community": "my community",
+ "realm": "my realm",
+ "records": [
+ {
+ "record_type": "route",
+ "trust_router": "tr",
+ "metric": 27,
+ "interval": 11
+ }
+ ]
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "local_organizations": [
+ { "organization_name": "inforec filter test 1",
+ "realms": [
+ { "realm": "realm",
+ "gss_names": ["gss"],
+ "filters": {
+ "tid_inbound": [
+ { "action": "accept",
+ "specs": [
+ { "field": "rp_realm",
+ "match": [
+ "a.realm",
+ "*.a.realm"
+ ]
+ }
+ ]
+ }
+ ],
+ "trp_inbound": [
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["route"]}
+ ]
+ },
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["community"]}
+ ]
+ }
+ ],
+ "trp_outbound": [
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["invalid value"]}
+ ]
+ },
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["community"]}
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "msg_type": "tid_request",
+ "msg_body": {
+ "rp_realm": "my realm",
+ "target_realm": "your realm",
+ "community": "our community",
+ "orig_coi": "our aliased community",
+ "dh_info": {
+ "dh_p": "DEADBEEF",
+ "dh_g": "FEA57",
+ "dh_pub_key": "12345678"
+ },
+ "constraints": [{"constraint": ["value"]}],
+ "path": ["hop", "skip", "jump"],
+ "expiration_interval": 13
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "local_organizations": [
+ { "organization_name": "tidreq filter test 1",
+ "realms": [
+ { "realm": "realm",
+ "gss_names": ["gss"],
+ "filters": {
+ "tid_inbound": [
+ { "action": "accept",
+ "specs": [
+ { "field": "rp_realm",
+ "match": [
+ "my realm",
+ "*.my realm"
+ ]
+ }
+ ]
+ }
+ ],
+ "trp_inbound": [
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["route"]}
+ ]
+ },
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["community"]}
+ ]
+ }
+ ],
+ "trp_outbound": [
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["invalid value"]}
+ ]
+ },
+ { "action": "accept",
+ "specs": [
+ { "field": "info_type",
+ "match": ["community"]}
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+[
+ { "test label": "first TRP test",
+ "filter file": "test-filters/filt-inforec-1.json",
+ "filter type": "trp_inbound",
+ "target file": "test-filters/filt-inforec-1-msg.json",
+ "expect match": "yes",
+ "action": "accept"
+ },
+ { "test label": "second TRP test",
+ "filter file": "test-filters/filt-inforec-1.json",
+ "filter type": "trp_outbound",
+ "target file": "test-filters/filt-inforec-1-msg.json",
+ "expect match": "no",
+ "action": ""
+ },
+ { "test label": "first TID test",
+ "filter file": "test-filters/filt-tidreq-1.json",
+ "filter type": "tid_inbound",
+ "target file": "test-filters/filt-tidreq-1-msg.json",
+ "expect match": "yes",
+ "action": "accept"
+ }
+]
return cons;
}
-TR_FILTER_TYPE filter_type[]={TR_FILTER_TYPE_TID_INBOUND,
- TR_FILTER_TYPE_TRP_INBOUND,
- TR_FILTER_TYPE_TRP_OUTBOUND};
-const char *filter_label[]={"tid_inbound",
- "trp_inbound",
- "trp_outbound"};
-size_t num_filter_types=sizeof(filter_type)/sizeof(filter_type[0]);
-
-static const char *filter_type_to_string(TR_FILTER_TYPE ftype)
-{
- size_t ii=0;
-
- for (ii=0; ii<num_filter_types; ii++) {
- if (ftype==filter_type[ii])
- return filter_label[ii];
- }
- return "unknown";
-}
-
-static TR_FILTER_TYPE filter_type_from_string(const char *s)
-{
- size_t ii=0;
-
- for(ii=0; ii<num_filter_types; ii++) {
- if (0==strcmp(s, filter_label[ii]))
- return filter_type[ii];
- }
- return TR_FILTER_TYPE_UNKNOWN;
-}
-
static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
{
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
TR_FILTER *filt = NULL;
json_t *jfaction = NULL;
+ json_t *jfline = NULL;
json_t *jfspecs = NULL;
json_t *this_jfspec = NULL;
json_t *jfield = NULL;
}
/* For each entry in the filter... */
- for (i = 0; i < json_array_size(jfilt); i++) {
- if ((NULL == (jfaction = json_object_get(json_array_get(jfilt, i), "action"))) ||
+ json_array_foreach(jfilt, i, jfline) {
+ if ((NULL == (jfaction = json_object_get(jfline, "action"))) ||
(!json_is_string(jfaction))) {
tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
*rc = TR_CFG_NOPARSE;
goto cleanup;
}
- if ((NULL == (jfspecs = json_object_get(json_array_get(jfilt, i), "specs"))) ||
+ if ((NULL == (jfspecs = json_object_get(jfline, "specs"))) ||
(!json_is_array(jfspecs)) ||
(0 == json_array_size(jfspecs))) {
tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
goto cleanup;
}
- if (NULL != (jrc = json_object_get(json_array_get(jfilt, i), "realm_constraints"))) {
+ if (NULL != (jrc = json_object_get(jfline, "realm_constraints"))) {
if (!json_is_array(jrc)) {
tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
*rc = TR_CFG_NOPARSE;
}
}
- if (NULL != (jdc = json_object_get(json_array_get(jfilt, i), "domain_constraints"))) {
+ if (NULL != (jdc = json_object_get(jfline, "domain_constraints"))) {
if (!json_is_array(jdc)) {
tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
*rc = TR_CFG_NOPARSE;
tr_debug("tr_cfg_parse_one_filter: Invalid filter field \"%.*s\" for %s filter, spec %d, filter %d.",
filt->lines[i]->specs[j]->field->len,
filt->lines[i]->specs[j]->field->buf,
- filter_type_to_string(filt->type),
+ tr_filter_type_to_string(filt->type),
i, j);
*rc = TR_CFG_ERROR;
goto cleanup;
return filt;
}
-static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
+static TR_FILTER_SET *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
json_t *jfilt;
const char *filt_label=NULL;
TR_FILTER *filt=NULL;
+ TR_FILTER_SET *filt_set=NULL;
TR_FILTER_TYPE filt_type=TR_FILTER_TYPE_UNKNOWN;
*rc=TR_CFG_ERROR;
goto cleanup;
}
+ filt_set=tr_filter_set_new(tmp_ctx);
+ if (filt_set==NULL) {
+ tr_debug("tr_cfg_parse_filters: Unable to allocate filter set.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
json_object_foreach(jfilts, filt_label, jfilt) {
/* check that we got a filter */
if (jfilt == NULL) {
}
/* check that we recognize the filter type */
- filt_type=filter_type_from_string(filt_label);
+ filt_type=tr_filter_type_from_string(filt_label);
if (filt_type==TR_FILTER_TYPE_UNKNOWN) {
tr_debug("tr_cfg_parse_filters: Unrecognized filter (%s) defined.", filt_label);
*rc = TR_CFG_NOPARSE;
/* finally, parse the filter */
tr_debug("tr_cfg_parse_filters: Found %s filter.", filt_label);
filt = tr_cfg_parse_one_filter(tmp_ctx, jfilt, filt_type, rc);
+ tr_filter_set_add(filt_set, filt);
if (*rc != TR_CFG_SUCCESS) {
tr_debug("tr_cfg_parse_filters: Error parsing %s filter.", filt_label);
*rc = TR_CFG_NOPARSE;
cleanup:
if (*rc==TR_CFG_SUCCESS)
- talloc_steal(mem_ctx, filt);
- else if (filt!=NULL) {
- talloc_free(filt);
- filt=NULL;
+ talloc_steal(mem_ctx, filt_set);
+ else if (filt_set!=NULL) {
+ talloc_free(filt_set);
+ filt_set=NULL;
}
talloc_free(tmp_ctx);
- return filt;
+ return filt_set;
}
static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
}
/* default filter accepts realm and *.realm */
-static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
+static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
TR_FILTER *filt=NULL;
+ TR_FILTER_SET *filt_set=NULL;
TR_CONSTRAINT *cons=NULL;
TR_NAME *name=NULL;
TR_NAME *n_prefix=tr_new_name("*.");
if ((realm==NULL) || (rc==NULL)) {
- tr_debug("tr_cfg_default_filter: invalid arguments.");
+ tr_debug("tr_cfg_default_filters: invalid arguments.");
if (rc!=NULL)
*rc=TR_CFG_BAD_PARAMS;
goto cleanup;
(n_rp_realm_2==NULL) ||
(n_domain==NULL) ||
(n_realm==NULL)) {
- tr_debug("tr_cfg_default_filter: unable to allocate names.");
+ tr_debug("tr_cfg_default_filters: unable to allocate names.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
filt=tr_filter_new(tmp_ctx);
if (filt==NULL) {
- tr_debug("tr_cfg_default_filter: could not allocate filter.");
+ tr_debug("tr_cfg_default_filters: could not allocate filter.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
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.");
+ tr_debug("tr_cfg_default_filters: could not allocate filter line.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
name=tr_dup_name(realm);
if (name==NULL) {
- tr_debug("tr_cfg_default_filter: could not allocate realm name.");
+ tr_debug("tr_cfg_default_filters: could not allocate realm name.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
n_rp_realm_2=NULL; /* we don't own this name any more */
if (NULL==(name=tr_name_cat(n_prefix, realm))) {
- tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name.");
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
/* domain constraint */
if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
- tr_debug("tr_cfg_default_filter: could not allocate domain constraint.");
+ tr_debug("tr_cfg_default_filters: could not allocate domain constraint.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
n_domain=NULL; /* belongs to the constraint now */
name=tr_dup_name(realm);
if (name==NULL) {
- tr_debug("tr_cfg_default_filter: could not allocate realm name for domain constraint.");
+ tr_debug("tr_cfg_default_filters: could not allocate realm name for domain constraint.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
cons->matches[0]=name;
name=tr_name_cat(n_prefix, realm);
if (name==NULL) {
- tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for domain constraint.");
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for domain constraint.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
/* realm constraint */
if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
- tr_debug("tr_cfg_default_filter: could not allocate realm constraint.");
+ tr_debug("tr_cfg_default_filters: could not allocate realm constraint.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
n_realm=NULL; /* belongs to the constraint now */
name=tr_dup_name(realm);
if (name==NULL) {
- tr_debug("tr_cfg_default_filter: could not allocate realm name for realm constraint.");
+ tr_debug("tr_cfg_default_filters: could not allocate realm name for realm constraint.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
cons->matches[0]=name;
name=tr_name_cat(n_prefix, realm);
if (name==NULL) {
- tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for realm constraint.");
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for realm constraint.");
*rc=TR_CFG_NOMEM;
goto cleanup;
}
name=NULL;
filt->lines[0]->realm_cons=cons;
- talloc_steal(mem_ctx, filt);
+ /* put the filter in a set */
+ filt_set=tr_filter_set_new(tmp_ctx);
+ if ((filt_set==NULL)||(0!=tr_filter_set_add(filt_set, filt))) {
+ tr_debug("tr_cfg_default_filters: could not allocate filter set.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ talloc_steal(mem_ctx, filt_set);
+
cleanup:
talloc_free(tmp_ctx);
if (name!=NULL)
tr_free_name(name);
- return filt;
+ return filt_set;
}
/* parses rp client */
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
TR_RP_CLIENT *client=NULL;
TR_CFG_RC call_rc=TR_CFG_ERROR;
- TR_FILTER *new_filt=NULL;
+ TR_FILTER_SET *new_filts=NULL;
TR_NAME *realm=NULL;
json_t *jfilt=NULL;
json_t *jrealm_id=NULL;
/* parse filters */
jfilt=json_object_get(jrealm, "filters");
if (jfilt!=NULL) {
- new_filt=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
+ new_filts=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
if (call_rc!=TR_CFG_SUCCESS) {
tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
*rc=TR_CFG_NOPARSE;
}
} else {
tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
- new_filt=tr_cfg_default_filter(tmp_ctx, realm, &call_rc);
+ new_filts= tr_cfg_default_filters(tmp_ctx, realm, &call_rc);
if (call_rc!=TR_CFG_SUCCESS) {
tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
*rc=TR_CFG_NOPARSE;
}
}
- tr_rp_client_set_filter(client, new_filt);
+ tr_rp_client_set_filters(client, new_filts);
*rc=TR_CFG_SUCCESS;
cleanup:
json_t *jfilt=NULL;
TRP_PEER *new_peer=NULL;
TR_GSS_NAMES *names=NULL;
- TR_FILTER *filt=NULL;
+ TR_FILTER_SET *filt_set=NULL;
TR_CFG_RC rc=TR_CFG_ERROR;
jhost=json_object_get(jporg, "hostname");
trp_peer_set_gss_names(new_peer, names);
if (jfilt) {
- filt=tr_cfg_parse_filters(tmp_ctx, jfilt, &rc);
+ filt_set=tr_cfg_parse_filters(tmp_ctx, jfilt, &rc);
if (rc!=TR_CFG_SUCCESS) {
tr_err("tr_cfg_parse_one_peer_org: unable to parse filters.");
rc=TR_CFG_NOPARSE;
goto cleanup;
}
- trp_peer_set_filter(new_peer, filt);
+ trp_peer_set_filters(new_peer, filt_set);
}
/* success! */
/* 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;
- (ii<TR_MAX_FILTER_LINES) && (retval==TR_FILTER_NO_MATCH);
+ ii<TR_MAX_FILTER_LINES;
ii++) {
/* skip empty lines (these shouldn't really happen) */
if (filt->lines[ii]==NULL)
break; /* give up on this filter line */
}
}
+
+ if (retval==TR_FILTER_MATCH)
+ break;
}
if (retval==TR_FILTER_MATCH) {
return 0; /* unknown field */
return 1;
-}
\ No newline at end of file
+}
+
+/**
+ * Allocate a new filter set.
+ *
+ * @param mem_ctx Talloc context for the new set
+ * @return Pointer to new set, or null on error
+ */
+TR_FILTER_SET *tr_filter_set_new(TALLOC_CTX *mem_ctx)
+{
+ TR_FILTER_SET *set=talloc(mem_ctx, TR_FILTER_SET);
+ if (set!=NULL) {
+ set->next=NULL;
+ set->this=NULL;
+ }
+ return set;
+}
+
+/**
+ * Free a filter set
+ *
+ * @param fs Filter set to free
+ */
+void tr_filter_set_free(TR_FILTER_SET *fs)
+{
+ talloc_free(fs);
+}
+
+/**
+ * Find the tail of the filter set linked list.
+ *
+ * @param set Set to find tail of
+ * @return Last element in the list
+ */
+static TR_FILTER_SET *tr_filter_set_tail(TR_FILTER_SET *set)
+{
+ while (set->next)
+ set=set->next;
+ return set;
+}
+
+/**
+ * Add new filter to filter set.
+ *
+ * @param set Filter set
+ * @param new New filter to add
+ * @return 0 on success, nonzero on error
+ */
+int tr_filter_set_add(TR_FILTER_SET *set, TR_FILTER *new)
+{
+ TR_FILTER_SET *tail=NULL;
+
+ if (set->this==NULL)
+ tail=set;
+ else {
+ tail=tr_filter_set_tail(set);
+ tail->next=tr_filter_set_new(set);
+ if (tail->next==NULL)
+ return 1;
+ tail=tail->next;
+ }
+ tail->this=new;
+ talloc_steal(tail, new);
+ return 0;
+}
+
+/**
+ * Find a filter of a given type in the filter set. If there are multiple, returns the first one.
+ *
+ * @param set Filter set to search
+ * @param type Type of filter to find
+ * @return Borrowed pointer to the filter, or null if no filter of that type is found
+ */
+TR_FILTER *tr_filter_set_get(TR_FILTER_SET *set, TR_FILTER_TYPE type)
+{
+ TR_FILTER_SET *cur=set;
+ while(cur!=NULL) {
+ if ((cur->this != NULL) && (cur->this->type == type))
+ return cur->this;
+ cur=cur->next;
+ }
+ return NULL;
+}
+
+TR_FILTER_TYPE filter_type[]={TR_FILTER_TYPE_TID_INBOUND,
+ TR_FILTER_TYPE_TRP_INBOUND,
+ TR_FILTER_TYPE_TRP_OUTBOUND};
+const char *filter_label[]={"tid_inbound",
+ "trp_inbound",
+ "trp_outbound"};
+size_t num_filter_types=sizeof(filter_type)/sizeof(filter_type[0]);
+
+const char *tr_filter_type_to_string(TR_FILTER_TYPE ftype)
+{
+ size_t ii=0;
+
+ for (ii=0; ii<num_filter_types; ii++) {
+ if (ftype==filter_type[ii])
+ return filter_label[ii];
+ }
+ return "unknown";
+}
+
+TR_FILTER_TYPE tr_filter_type_from_string(const char *s)
+{
+ size_t ii=0;
+
+ for(ii=0; ii<num_filter_types; ii++) {
+ if (0==strcmp(s, filter_label[ii]))
+ return filter_type[ii];
+ }
+ return TR_FILTER_TYPE_UNKNOWN;
+}
+
client->next=NULL;
client->comm_next=NULL;
client->gss_names=NULL;
- client->filter=NULL;
+ client->filters=NULL;
talloc_set_destructor((void *)client, tr_rp_client_destructor);
}
return client;
return tr_gss_names_add(rp_client->gss_names, gss_name);
}
-int tr_rp_client_set_filter(TR_RP_CLIENT *client, TR_FILTER *filt)
+int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts)
{
- if (client->filter!=NULL)
- tr_filter_free(client->filter);
- client->filter=filt;
- talloc_steal(client, filt);
+ if (client->filters!=NULL)
+ tr_filter_set_free(client->filters);
+ client->filters=filts;
+ talloc_steal(client, filts);
return 0; /* success */
}
/* Filter actions */
typedef enum {
- TR_FILTER_ACTION_REJECT = 0,
- TR_FILTER_ACTION_ACCEPT,
- TR_FILTER_ACTION_UNKNOWN
+ TR_FILTER_ACTION_REJECT = 0,
+ TR_FILTER_ACTION_ACCEPT,
+ TR_FILTER_ACTION_UNKNOWN
} TR_FILTER_ACTION;
/* Match codes */
/* Filter types */
typedef enum {
- TR_FILTER_TYPE_TID_INBOUND = 0,
- TR_FILTER_TYPE_TRP_INBOUND,
- TR_FILTER_TYPE_TRP_OUTBOUND,
- TR_FILTER_TYPE_UNKNOWN
+ TR_FILTER_TYPE_TID_INBOUND = 0,
+ TR_FILTER_TYPE_TRP_INBOUND,
+ TR_FILTER_TYPE_TRP_OUTBOUND,
+ TR_FILTER_TYPE_UNKNOWN
} TR_FILTER_TYPE;
typedef struct tr_fspec {
- TR_NAME *field;
- TR_NAME *match[TR_MAX_FILTER_SPEC_MATCHES];
+ TR_NAME *field;
+ TR_NAME *match[TR_MAX_FILTER_SPEC_MATCHES];
} TR_FSPEC;
typedef struct tr_fline {
- TR_FILTER_ACTION action;
- TR_FSPEC *specs[TR_MAX_FILTER_SPECS];
- TR_CONSTRAINT *realm_cons;
- TR_CONSTRAINT *domain_cons;
+ TR_FILTER_ACTION action;
+ TR_FSPEC *specs[TR_MAX_FILTER_SPECS];
+ TR_CONSTRAINT *realm_cons;
+ TR_CONSTRAINT *domain_cons;
} TR_FLINE;
typedef struct tr_filter {
- TR_FILTER_TYPE type;
- TR_FLINE *lines[TR_MAX_FILTER_LINES];
+ TR_FILTER_TYPE type;
+ TR_FLINE *lines[TR_MAX_FILTER_LINES];
} TR_FILTER;
+
+typedef struct tr_filter_set TR_FILTER_SET;
+struct tr_filter_set {
+ TR_FILTER *this;
+ TR_FILTER_SET *next;
+};
+
+TR_FILTER_SET *tr_filter_set_new(TALLOC_CTX *mem_ctx);
+void tr_filter_set_free(TR_FILTER_SET *fs);
+int tr_filter_set_add(TR_FILTER_SET *set, TR_FILTER *new);
+TR_FILTER *tr_filter_set_get(TR_FILTER_SET *set, TR_FILTER_TYPE type);
+
TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx);
void tr_filter_free(TR_FILTER *filt);
int tr_filter_validate(TR_FILTER *filt);
int tr_filter_validate_spec_field(TR_FILTER_TYPE ftype, TR_FSPEC *fspec);
+const char *tr_filter_type_to_string(TR_FILTER_TYPE ftype);
+TR_FILTER_TYPE tr_filter_type_from_string(const char *s);
#endif
/* Encoders/Decoders */
char *tr_msg_encode(TR_MSG *msg);
-TR_MSG *tr_msg_decode(char *jmsg, size_t len);
+TR_MSG *tr_msg_decode(const char *jmsg, size_t len);
void tr_msg_free_encoded(char *jmsg);
void tr_msg_free_decoded(TR_MSG *msg);
struct tr_rp_client *next;
struct tr_rp_client *comm_next;
TR_GSS_NAMES *gss_names;
- TR_FILTER *filter;
+ TR_FILTER_SET *filters;
} TR_RP_CLIENT;
/* Structure to make a linked list of RP realms by name for community config */
TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new);
#define tr_rp_client_add(clients,new) ((clients)=tr_rp_client_add_func((clients),(new)))
int tr_rp_client_add_gss_name(TR_RP_CLIENT *client, TR_NAME *name);
-int tr_rp_client_set_filter(TR_RP_CLIENT *client, TR_FILTER *filt);
+int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts);
TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name);
TR_RP_REALM *tr_rp_realm_new(TALLOC_CTX *mem_ctx);
TRP_PEER_CONN_STATUS incoming_status;
void (*conn_status_cb)(TRP_PEER *, void *); /* callback for connected status change */
void *conn_status_cookie;
- TR_FILTER *filter;
+ TR_FILTER_SET *filters;
};
typedef struct trp_ptable {
int trp_peer_is_connected(TRP_PEER *peer);
void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost);
void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie);
-void trp_peer_set_filter(TRP_PEER *peer, TR_FILTER *filt);
-TR_FILTER *trp_peer_get_filter(TRP_PEER *peer);
+void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts);
+TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype);
char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep);
#endif /* _TRP_PTABLE_H_ */
* the TIDS handler subprocess. */
if ((!tids->rp_gss) ||
- (!tids->rp_gss->filter)) {
+ (!tids->rp_gss->filters)) {
tr_notice("tr_tids_req_handler: No GSS name for incoming request.");
tids_send_err_response(tids, orig_req, "No GSS name for request");
retval=-1;
}
if ((TR_FILTER_NO_MATCH == tr_filter_process_rp_permitted(orig_req->rp_realm,
- tids->rp_gss->filter,
+ tr_filter_set_get(tids->rp_gss->filters,
+ TR_FILTER_TYPE_TID_INBOUND),
orig_req->cons,
&fwd_req->cons,
&oaction)) ||
peer->incoming_status=PEER_DISCONNECTED;
peer->conn_status_cb=NULL;
peer->conn_status_cookie=NULL;
- peer->filter=NULL;
+ peer->filters=NULL;
talloc_set_destructor((void *)peer, trp_peer_destructor);
}
return peer;
* freeing the new filter.
*
* @param peer Peer to modify
- * @param filt New filter to attach to the peer
+ * @param filts New filter to attach to the peer
*/
-void trp_peer_set_filter(TRP_PEER *peer, TR_FILTER *filt)
+void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts)
{
- if (peer->filter!=NULL)
- tr_filter_free(peer->filter);
+ if (peer->filters!=NULL)
+ tr_filter_set_free(peer->filters);
- peer->filter=filt;
- talloc_steal(peer, filt);
+ peer->filters=filts;
+ talloc_steal(peer, filts);
}
-TR_FILTER *trp_peer_get_filter(TRP_PEER *peer)
+TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype)
{
- return peer->filter;
+ return tr_filter_set_get(peer->filters, ftype);
}
struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)