📄 ipfilter.cc
字号:
blank_ok = false; next++; } pos = next; } if (!blank_ok) errh->error("missing term"); finish_expr_subtree(tree); return pos;}static intparse_brackets(IPFilter::Primitive& prim, const Vector<String>& words, int pos, ErrorHandler* errh){ int first_pos = pos + 1; String combination; for (pos++; pos < words.size() && words[pos] != "]"; pos++) combination += words[pos]; if (pos >= words.size()) { errh->error("missing ']'"); return first_pos; } pos++; // parse 'combination' int fieldpos, len = 1; const char* colon = find(combination.begin(), combination.end(), ':'); const char* comma = find(combination.begin(), combination.end(), ','); if (colon < combination.end() - 1) { if (cp_integer(combination.begin(), colon, 0, &fieldpos) == colon && cp_integer(colon + 1, combination.end(), 0, &len) == combination.end()) goto non_syntax_error; } else if (comma < combination.end() - 1) { int pos2; if (cp_integer(combination.begin(), comma, 0, &fieldpos) == comma && cp_integer(comma + 1, combination.end(), 0, &pos2) == combination.end()) { len = pos2 - fieldpos + 1; goto non_syntax_error; } } else if (cp_integer(combination, &fieldpos)) goto non_syntax_error; errh->error("syntax error after '[', expected '[POS]' or '[POS:LEN]'"); return pos; non_syntax_error: if (len < 1 || len > 4) errh->error("LEN in '[POS:LEN]' out of range, should be between 1 and 4"); else if ((fieldpos & ~3) != ((fieldpos + len - 1) & ~3)) errh->error("field [%d:%d] does not fit in a single word", fieldpos, len); else if (prim._transp_proto == IPFilter::UNKNOWN) prim.set_type(IPFilter::TYPE_FIELD | ((fieldpos*8) << IPFilter::FIELD_OFFSET_SHIFT) | ((len*8 - 1) << IPFilter::FIELD_LENGTH_SHIFT), errh); else prim.set_type(IPFilter::TYPE_FIELD | (prim._transp_proto << IPFilter::FIELD_PROTO_SHIFT) | ((fieldpos*8) << IPFilter::FIELD_OFFSET_SHIFT) | ((len*8 - 1) << IPFilter::FIELD_LENGTH_SHIFT), errh); return pos;}intIPFilter::parse_factor(const Vector<String> &words, int pos, Vector<int> &tree, Primitive &prev_prim, bool negated, ErrorHandler *errh){ // return immediately on last word, ")", "||", "or", "?", ":" if (pos >= words.size() || words[pos] == ")" || words[pos] == "||" || words[pos] == "or" || words[pos] == "?" || words[pos] == ":") return pos; // easy cases // 'true' and 'false' if (words[pos] == "true") { add_expr(tree, 0, 0, 0); if (negated) negate_expr_subtree(tree); return pos + 1; } if (words[pos] == "false") { add_expr(tree, 0, 0, 0); if (!negated) negate_expr_subtree(tree); return pos + 1; } // ! factor if (words[pos] == "not" || words[pos] == "!") { int next = parse_factor(words, pos + 1, tree, prev_prim, !negated, errh); if (next == pos + 1) errh->error("missing factor after '%s'", words[pos].c_str()); return next; } // ( expr ) if (words[pos] == "(") { int next = parse_expr(words, pos + 1, tree, prev_prim, errh); if (next == pos + 1) errh->error("missing expression after '('"); if (next >= 0) { if (next >= words.size() || words[next] != ")") errh->error("missing ')'"); else next++; if (negated) negate_expr_subtree(tree); } return next; } // hard case // expect quals [relop] data int first_pos = pos; Primitive prim; // collect qualifiers for (; pos < words.size(); pos++) { String wd = words[pos]; uint32_t wdata; int wt = lookup(wd, 0, UNKNOWN, wdata, 0); if (wt >= 0 && wt == TYPE_TYPE) { prim.set_type(wdata, errh); if ((wdata & TYPE_FIELD) && (wdata & FIELD_PROTO_MASK)) prim.set_transp_proto((wdata & FIELD_PROTO_MASK) >> FIELD_PROTO_SHIFT, errh); } else if (wt >= 0 && wt == TYPE_PROTO) prim.set_transp_proto(wdata, errh); else if (wt != -1) break; else if (wd == "src") { if (pos < words.size() - 2 && (words[pos+2] == "dst" || words[pos+2] == "dest")) { if (words[pos+1] == "and" || words[pos+1] == "&&") { prim.set_srcdst(SD_AND, errh); pos += 2; } else if (words[pos+1] == "or" || words[pos+1] == "||") { prim.set_srcdst(SD_OR, errh); pos += 2; } else prim.set_srcdst(SD_SRC, errh); } else prim.set_srcdst(SD_SRC, errh); } else if (wd == "dst" || wd == "dest") prim.set_srcdst(SD_DST, errh); else if (wd == "ip") /* nada */; else if (wd == "not" || wd == "!") negated = !negated; else break; } // prev_prim is not relevant if there were any qualifiers if (pos != first_pos) prev_prim.clear(); // optional [] syntax String wd = (pos >= words.size() - 1 ? String() : words[pos]); if (wd == "[" && pos > first_pos && prim._type == TYPE_NONE) { pos = parse_brackets(prim, words, pos, errh); wd = (pos >= words.size() - 1 ? String() : words[pos]); } // optional bitmask uint32_t provided_mask = 0; if (wd == "&" && pos < words.size() - 1 && cp_unsigned(words[pos + 1], &provided_mask)) { pos += 2; wd = (pos >= words.size() - 1 ? String() : words[pos]); if (provided_mask == 0) errh->error("bitmask of 0 ignored"); } // optional relational operation pos++; if (wd == "=" || wd == "==") /* nada */; else if (wd == "!=") prim._op_negated = true; else if (wd == ">") prim._op = OP_GT; else if (wd == "<") prim._op = OP_LT; else if (wd == ">=") { prim._op = OP_LT; prim._op_negated = true; } else if (wd == "<=") { prim._op = OP_GT; prim._op_negated = true; } else pos--; // now collect the actual data if (pos < words.size()) { wd = words[pos]; uint32_t wdata; int wt = lookup(wd, prim._type, prim._transp_proto, wdata, errh); pos++; if (wt == -2) // ambiguous or incorrect word type /* absorb word, but do nothing */ prim._type = -2; else if (wt != -1 && wt != TYPE_TYPE) { prim._data = wt; prim._u.u = wdata; } else if (cp_integer(wd, &prim._u.i)) prim._data = TYPE_INT; else if (cp_ip_address(wd, prim._u.c, this)) { if (pos < words.size() - 1 && words[pos] == "mask" && cp_ip_address(words[pos+1], prim._mask.c, this)) { pos += 2; prim._data = TYPE_NET; } else if (prim._type == TYPE_NET && cp_ip_prefix(wd, prim._u.c, prim._mask.c, this)) prim._data = TYPE_NET; else prim._data = TYPE_HOST; } else if (cp_ip_prefix(wd, prim._u.c, prim._mask.c, this)) prim._data = TYPE_NET; else { if (prim._op != OP_EQ || prim._op_negated) errh->error("dangling operator near '%s'", wd.cc()); pos--; } } if (pos == first_pos) { errh->error("empty term near '%s'", wd.cc()); return pos; } // add if it is valid if (prim.check(prev_prim, provided_mask, errh) >= 0) { prim.add_exprs(this, tree); if (negated) negate_expr_subtree(tree); prev_prim = prim; } return pos;}intIPFilter::configure(Vector<String> &conf, ErrorHandler *errh){ int before_nerrors = errh->nerrors(); _output_everything = -1; // requires packet headers be aligned _align_offset = 0; Vector<int> tree; init_expr_subtree(tree); // [QUALS] [host|net|port|proto] [data] // QUALS ::= src | dst | src and dst | src or dst | \empty // | ip | icmp | tcp | udp for (int argno = 0; argno < conf.size(); argno++) { Vector<String> words; separate_text(cp_unquote(conf[argno]), words); if (words.size() == 0) { errh->error("empty pattern %d", argno); continue; } PrefixErrorHandler cerrh(errh, "pattern " + String(argno) + ": "); // get slot int slot = noutputs(); { String slotwd = words[0]; if (slotwd == "allow") { slot = 0; if (noutputs() == 0) cerrh.error("'allow' is meaningless, element has zero outputs"); } else if (slotwd == "deny") { slot = noutputs(); if (noutputs() > 1) cerrh.warning("meaning of 'deny' has changed (now it means 'drop')"); } else if (slotwd == "drop") slot = noutputs(); else if (cp_integer(slotwd, &slot)) { if (slot < 0 || slot >= noutputs()) { cerrh.error("slot '%d' out of range", slot); slot = noutputs(); } } else cerrh.error("unknown slot ID '%s'", slotwd.cc()); } start_expr_subtree(tree); // check for "-" if (words.size() == 1 || (words.size() == 2 && words[1] == "-") || (words.size() == 2 && words[1] == "any") || (words.size() == 2 && words[1] == "all")) add_expr(tree, 0, 0, 0); else { // start with a blank primitive Primitive prev_prim; int pos = parse_expr(words, 1, tree, prev_prim, &cerrh); if (pos < words.size()) cerrh.error("garbage after expression at '%s'", words[pos].c_str()); } finish_expr_subtree(tree, C_AND, -slot); } finish_expr_subtree(tree, C_OR, -noutputs(), -noutputs()); //{ String sxxx = program_string(this, 0); click_chatter("%s", sxxx.cc()); } optimize_exprs(errh); //{ String sxxx = program_string(this, 0); click_chatter("%s", sxxx.cc()); } return (errh->nerrors() == before_nerrors ? 0 : -1);}//// RUNNING//voidIPFilter::length_checked_push(Packet *p){ const unsigned char *neth_data = (const unsigned char *)p->ip_header(); const unsigned char *transph_data = (const unsigned char *)p->transport_header(); int packet_length = p->length() + TRANSP_FAKE_OFFSET - p->transport_header_offset(); Expr *ex = &_exprs[0]; // avoid bounds checking int pos = 0; do { int off = ex[pos].offset; unsigned data; if (off + 4 > packet_length) goto check_length; length_ok: if (off >= TRANSP_FAKE_OFFSET) data = *(const unsigned *)(transph_data + off - TRANSP_FAKE_OFFSET); else data = *(const unsigned *)(neth_data + off); if ((data & ex[pos].mask.u) == ex[pos].value.u) pos = ex[pos].yes; else pos = ex[pos].no; continue; check_length: if (ex[pos].offset < packet_length) { unsigned available = packet_length - ex[pos].offset; if (!(ex[pos].mask.c[3] || (ex[pos].mask.c[2] && available <= 2) || (ex[pos].mask.c[1] && available == 1))) goto length_ok; } pos = ex[pos].no; } while (pos > 0); checked_output_push(-pos, p);}voidIPFilter::push(int, Packet *p){ const unsigned char *neth_data = (const unsigned char *)p->ip_header(); const unsigned char *transph_data = (const unsigned char *)p->transport_header(); Expr *ex; int pos = 0; if (_output_everything >= 0) { // must use checked_output_push because the output number might be // out of range pos = -_output_everything; goto found; } else if (p->length() + TRANSP_FAKE_OFFSET - p->transport_header_offset() < _safe_length) { // common case never checks packet length length_checked_push(p); return; } ex = &_exprs[0]; // avoid bounds checking do { int off = ex[pos].offset; unsigned data; if (off >= TRANSP_FAKE_OFFSET) data = *(const unsigned *)(transph_data + off - TRANSP_FAKE_OFFSET); else data = *(const unsigned *)(neth_data + off); if ((data & ex[pos].mask.u) == ex[pos].value.u) pos = ex[pos].yes; else pos = ex[pos].no; } while (pos > 0); found: checked_output_push(-pos, p);}CLICK_ENDDECLSELEMENT_REQUIRES(Classifier)EXPORT_ELEMENT(IPFilter)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -