/** find elem using XPath like query * name -- "name" for the child tag of that name * "name/name" for a sub child (recurses) * "?attrib" to match the first tag with that attrib defined * "?attrib=value" to match the first tag with that attrib and value * or any combination: "name/name/?attrib", etc */ int nad_find_elem_path(nad_t nad, int elem, int ns, const char *name) { char *str, *slash, *qmark, *equals; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || name == NULL) return -1; /* if it's plain name just search children */ if(strstr(name, "/") == NULL && strstr(name,"?") == NULL) return nad_find_elem(nad, elem, ns, name, 1); str = strdup(name); slash = strstr(str, "/"); qmark = strstr(str, "?"); equals = strstr(str, "="); /* no / in element name part */ if(qmark != NULL && (slash == NULL || qmark < slash)) { /* of type ?attrib */ *qmark = '\0'; qmark++; if(equals != NULL) { *equals = '\0'; equals++; } for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) { if(elem < 0) break; if(strcmp(qmark, "xmlns") == 0) { if(nad_find_namespace(nad, elem, equals, NULL) >= 0) break; } else { if(nad_find_attr(nad, elem, ns, qmark, equals) >= 0) break; } } free(str); return elem; } /* there is a / in element name part - need to recurse */ *slash = '\0'; ++slash; for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) { if(elem < 0) break; if((elem = nad_find_elem_path(nad, elem, ns, slash)) >= 0) break; } free(str); return elem; }
int filter_packet(router_t r, nad_t nad) { acl_t acl; int ato, afrom, error = 0; unsigned char *cur, *to = NULL, *from = NULL; ato = nad_find_attr(nad, 1, -1, "to", NULL); afrom = nad_find_attr(nad, 1, -1, "from", NULL); if(ato >= 0 && NAD_AVAL_L(nad,ato) > 0) { to = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, ato) + 1)); sprintf(to, "%.*s", NAD_AVAL_L(nad, ato), NAD_AVAL(nad, ato)); cur = strstr(to, "@"); /* skip node part */ if(cur != NULL) cur = strstr(cur, "/"); else cur = strstr(to, "/"); if(cur != NULL) *cur = '\0'; /* remove the resource part */ } if(afrom >= 0 && NAD_AVAL_L(nad,afrom) > 0) { from = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, afrom) + 1)); sprintf(from, "%.*s", NAD_AVAL_L(nad, afrom), NAD_AVAL(nad, afrom)); cur = strstr(from, "@"); if(cur != NULL) cur = strstr(cur, "/"); else cur = strstr(from, "/"); if(cur != NULL) *cur = '\0'; } for(acl = r->filter; acl != NULL; acl = acl->next) { if( from == NULL && acl->from != NULL) continue; /* no match if NULL matched vs not-NULL */ if( to == NULL && acl->to != NULL ) continue; if( from != NULL && acl->from == NULL) continue; /* no match if not-NULL matched vs NULL */ if( to != NULL && acl->to == NULL ) continue; if( from != NULL && acl->from != NULL && fnmatch(acl->from, from, 0) != 0 ) continue; /* do filename-like match */ if( to != NULL && acl->to != NULL && fnmatch(acl->to, to, 0) != 0 ) continue; if( acl->what != NULL && nad_find_elem_path(nad, 0, -1, acl->what) < 0 ) continue; /* match packet type */ log_debug(ZONE, "matched packet %s->%s vs rule (%s %s->%s)", from, to, acl->what, acl->from, acl->to); if (acl->log) { if (acl->redirect) log_write(r->log, LOG_NOTICE, "filter: redirect packet from=%s to=%s - rule (from=%s to=%s what=%s), new to=%s", from, to, acl->from, acl->to, acl->what, acl->redirect); else log_write(r->log, LOG_NOTICE, "filter: %s packet from=%s to=%s - rule (from=%s to=%s what=%s)",(acl->error?"deny":"allow"), from, to, acl->from, acl->to, acl->what); } if (acl->redirect) nad_set_attr(nad, 0, -1, "to", acl->redirect, acl->redirect_len); error = acl->error; break; } if(to != NULL) free(to); if(from != NULL) free(from); return error; }