📄 ipfieldinfo.cc
字号:
/* * ipfieldinfo.{cc,hh} -- IP-packet filter with tcpdumplike syntax * Eddie Kohler * * Copyright (c) 2005 Regents of the University of California * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "ipfieldinfo.hh"#include <click/integers.hh>#include <click/confparse.hh>#include <click/error.hh>#include <stdarg.h>CLICK_DECLS#define BITFIELD(proto, offset, length) \ (((proto) << IPField::PROTO_SHIFT) \ | ((offset) << IPField::OFFSET_SHIFT) \ | (((length) - 1) << IPField::LENGTH_SHIFT) \ | IPField::MARKER)static const StaticNameDB::Entry ip_fields[] = { { "df", BITFIELD(0, 6*8 + 1, 1) }, { "dport", BITFIELD(IP_PROTO_TCP_OR_UDP, 2*8, 16) }, { "dscp", BITFIELD(0, 1*8, 6) }, { "dst", BITFIELD(0, 16*8, 32) }, { "ecn", BITFIELD(0, 1*8 + 6, 2) }, { "fragoff",BITFIELD(0, 6*8 + 3, 13) }, { "hl", BITFIELD(0, 4, 4) }, { "id", BITFIELD(0, 4*8, 16) }, { "len", BITFIELD(0, 2*8, 16) }, { "mf", BITFIELD(0, 6*8 + 2, 1) }, { "off", BITFIELD(0, 6*8, 16) }, { "proto", BITFIELD(0, 9*8, 8) }, { "rf", BITFIELD(0, 6*8, 1) }, { "sport", BITFIELD(IP_PROTO_TCP_OR_UDP, 0, 16) }, { "src", BITFIELD(0, 12*8, 32) }, { "sum", BITFIELD(0, 10*8, 16) }, { "tos", BITFIELD(0, 1*8, 8) }, { "ttl", BITFIELD(0, 8*8, 8) }, { "vers", BITFIELD(0, 0, 4) }};static const StaticNameDB::Entry udp_fields[] = { { "dport", BITFIELD(IP_PROTO_UDP, 2*8, 16) }, { "len", BITFIELD(IP_PROTO_UDP, 4*8, 16) }, { "sport", BITFIELD(IP_PROTO_UDP, 0, 16) }, { "sum", BITFIELD(IP_PROTO_UDP, 6*8, 16) }};static const StaticNameDB::Entry tcp_fields[] = { { "ackno", BITFIELD(IP_PROTO_TCP, 8*8, 32) }, { "ack", BITFIELD(IP_PROTO_TCP, 13*8+3, 1) }, { "dport", BITFIELD(IP_PROTO_TCP, 2*8, 16) }, { "fin", BITFIELD(IP_PROTO_TCP, 13*8+7, 1) }, { "flags", BITFIELD(IP_PROTO_TCP, 13*8, 8) }, { "hl", BITFIELD(IP_PROTO_TCP, 12*8, 4) }, { "psh", BITFIELD(IP_PROTO_TCP, 13*8+4, 1) }, { "push", BITFIELD(IP_PROTO_TCP, 13*8+4, 1) }, { "rst", BITFIELD(IP_PROTO_TCP, 13*8+5, 1) }, { "seq", BITFIELD(IP_PROTO_TCP, 4*8, 32) }, { "seqno", BITFIELD(IP_PROTO_TCP, 4*8, 32) }, { "sport", BITFIELD(IP_PROTO_TCP, 0, 16) }, { "sum", BITFIELD(IP_PROTO_TCP, 16*8, 16) }, { "syn", BITFIELD(IP_PROTO_TCP, 13*8+6, 1) }, { "urg", BITFIELD(IP_PROTO_TCP, 13*8+2, 1) }, { "urp", BITFIELD(IP_PROTO_TCP, 18*8, 16) }, { "win", BITFIELD(IP_PROTO_TCP, 14*8, 16) }};static const StaticNameDB::Entry icmp_fields[] = { { "code", BITFIELD(IP_PROTO_ICMP, 1*8, 8) }, { "sum", BITFIELD(IP_PROTO_ICMP, 2*8, 16) }, { "type", BITFIELD(IP_PROTO_ICMP, 0*8, 8) }};static const StaticNameDB::Entry tcp_or_udp_fields[] = { { "dport", BITFIELD(IP_PROTO_TCP_OR_UDP, 2*8, 16) }, { "sport", BITFIELD(IP_PROTO_TCP_OR_UDP, 0, 16) }};IPField::IPField(int proto, int bit_offset, int bit_length){ if (proto >= 0 && proto <= MAX_PROTO && bit_offset >= 0 && bit_length >= 0) { if (bit_offset <= MAX_OFFSET && bit_length <= MAX_LENGTH + 1) _val = (proto << PROTO_SHIFT) | (bit_offset << OFFSET_SHIFT) | ((bit_length - 1) << LENGTH_SHIFT) | MARKER; else if ((bit_offset & 7) == 0 && (bit_length & 7) == 0 && bit_length <= (MAX_LENGTH + 1) << 3) _val = (proto << PROTO_SHIFT) | BYTES | ((bit_offset >> 3) << OFFSET_SHIFT) | (((bit_length >> 3) - 1) << LENGTH_SHIFT) | MARKER; else _val = -1; } else _val = -1;}static NameDB *dbs[5];voidIPFieldInfo::static_initialize(){ dbs[0] = new StaticNameDB(NameInfo::T_IP_FIELDNAME, String(), ip_fields, sizeof(ip_fields) / sizeof(ip_fields[0])); dbs[1] = new StaticNameDB(NameInfo::T_ICMP_FIELDNAME, String(), icmp_fields, sizeof(icmp_fields) / sizeof(icmp_fields[0])); dbs[2] = new StaticNameDB(NameInfo::T_TCP_FIELDNAME, String(), tcp_fields, sizeof(tcp_fields) / sizeof(tcp_fields[0])); dbs[3] = new StaticNameDB(NameInfo::T_UDP_FIELDNAME, String(), udp_fields, sizeof(udp_fields) / sizeof(udp_fields[0])); dbs[4] = new StaticNameDB(NameInfo::T_IP_FIELDNAME + IP_PROTO_TCP_OR_UDP, String(), tcp_or_udp_fields, sizeof(tcp_or_udp_fields) / sizeof(tcp_or_udp_fields[0])); for (int i = 0; i < 5; i++) if (dbs[i]) NameInfo::installdb(dbs[i], 0);}voidIPFieldInfo::static_cleanup(){ for (int i = 0; i < 5; i++) if (dbs[i]) { NameInfo::removedb(dbs[i]); delete dbs[i]; dbs[i] = 0; }}const char *cp_scanf(const char *begin, const char *end, const char *format, ...){ const char *s, *ss; bool must_space = false; uint32_t delimiters[8]; bool know_delimiters = false; va_list val; va_start(val, format); for (s = begin; *format; format++) if (*format == ' ') { if (must_space && format[1] != '%' && (s == end || !isspace((unsigned char) *s))) goto kill; while (s < end && isspace((unsigned char) *s)) s++; must_space = false; } else if (*format == '%') { format++; switch (*format) { case 'u': { uint32_t *d = va_arg(val, uint32_t *); if ((ss = cp_unsigned(s, end, 0, d)) == s) goto kill; s = ss; must_space = false; break; } case 'N': { uint32_t nametype = va_arg(val, uint32_t); Element *elt = va_arg(val, Element *); const char *w = s; while (s < end && !isspace((unsigned char) *s) && (!know_delimiters || !(delimiters[((unsigned char) *s) >> 5] & (1 << (((unsigned char) *s) % 32))))) s++; uint32_t *store = va_arg(val, uint32_t *); if (w == s || !NameInfo::query(nametype, elt, String(w, s), store, sizeof(*store))) goto kill; must_space = false; break; } case 'D': { const char *delim = va_arg(val, const char *); if (!know_delimiters) memset(delimiters, 0, sizeof(delimiters)); for (; *delim; delim++) delimiters[((unsigned char) *delim) >> 5] |= (1 << (((unsigned char) *delim) % 32)); know_delimiters = true; break; } case 'B': if (s != end && (isalnum((unsigned char) *s) || *s == '_')) goto kill; break; case '%': goto normal; } } else { normal: if (s == end || *s != *format) goto kill; s++; must_space = true; } va_end(val); return s; kill: va_end(val); return 0;}static const char * const cp_ip_field_messages[] = { "expected 'HEADER [NAME] [{OFFSET:LENGTH}] [/PREFIX] [& MASK]'", "bad offset or length in TCP/IP field", "bad prefix or mask in TCP/IP field"};static const char *cp_ip_field_helper(const char *begin, int which, ErrorHandler *errh){ if (errh) errh->error(cp_ip_field_messages[which]); return begin;}const char *IPField::parse(const char *begin, const char *end, int proto, IPField *result, ErrorHandler *errh, Element *elt){ // determine header, if any int32_t header = -1; const char *ehdr; if ((ehdr = cp_scanf(begin, end, "ip proto %u", &header))) /* OK */; else if ((ehdr = cp_scanf(begin, end, "ip%B"))) header = 0; else if ((ehdr = cp_scanf(begin, end, "%N", NameInfo::T_IP_PROTO, elt, &header))) /* OK */; else if ((header = proto) < 0) return cp_ip_field_helper(begin, 0, errh); // field name IPField field(-1); const char *enam; if ((enam = cp_scanf(ehdr, end, " %D%N", "/[{&", NameInfo::T_IP_FIELDNAME + header, elt, &field))) /* OK */; else enam = ehdr; // limitation int32_t offset = -1, length = -1; const char *elim; if ((elim = cp_scanf(enam, end, " [ %u ]", &offset))) offset *= 8, length = 8; else if ((elim = cp_scanf(enam, end, " [ %u : %u ]", &offset, &length))) offset *= 8, length *= 8; else if ((elim = cp_scanf(enam, end, " [ %u - %u ]", &offset, &length))) offset *= 8, length = (length - offset + 1) * 8; else if ((elim = cp_scanf(enam, end, " { %u }", &offset))) length = 1; else if ((elim = cp_scanf(enam, end, " { %u : %u }", &offset, &length))) /* OK */; else if ((elim = cp_scanf(enam, end, " { %u - %u }", &offset, &length))) length = length - offset + 1; else if (!field.ok()) { click_chatter("%.*s", end - enam, enam); return cp_ip_field_helper(begin, 0, errh);} else elim = enam; if (offset >= 0 && length <= 0) return cp_ip_field_helper(begin, 1, errh); if (field.ok() && (offset >= field.bit_length() || offset + length > field.bit_length())) return cp_ip_field_helper(begin, 1, errh); else if (field.ok() && offset >= 0) field = IPField(field.proto(), field.bit_offset() + offset, length); else if (offset >= 0) field = IPField(header, offset, length); else if (!field.ok()) return cp_ip_field_helper(begin, 1, errh); // limitations const char *epfx, *emask; if ((epfx = cp_scanf(elim, end, " / %u", &length))) { if (length > field.bit_length()) return cp_ip_field_helper(begin, 2, errh); field = IPField(field.proto(), field.bit_offset(), length); } else epfx = elim; if ((emask = cp_scanf(epfx, end, " & %u", &length))) { offset = ffs_lsb((uint32_t) length) - 1; int msb = ffs_lsb((uint32_t) length + (1 << offset)) - 1; if (length == 0 || ((length + (1 << offset)) & (length + (1 << offset) - 1)) != 0 || msb > field.bit_length()) return cp_ip_field_helper(begin, 2, errh); field = IPField(field.proto(), field.bit_offset() + field.bit_length() - msb, msb - offset); } else emask = epfx; *result = field; return emask;}StringIPField::unparse(Element *elt, bool tcpdump_rules){ if (!ok()) return String::stable_string("<bad>"); String protstr; int32_t val = proto(); if (val == 0) protstr = "ip"; else if ((protstr = NameInfo::revquery(NameInfo::T_IP_PROTO, elt, &val, 4))) /* OK */; else protstr = "ip proto " + String(proto()); String s; if ((s = NameInfo::revquery(NameInfo::T_IP_FIELDNAME + proto(), elt, &_val, 4))) return protstr + " " + s; int bo = bit_offset(), bl = bit_length(); for (int container = 8; container < 64 && !tcpdump_rules; container *= 2) if (bo / container == (bo + bl - 1) / container) { IPField x(proto(), bo & ~(container - 1), container); if ((s = NameInfo::revquery(NameInfo::T_IP_FIELDNAME + proto(), elt, &x, 4))) { protstr += " " + s; bo &= container - 1; if (bo == 0) return protstr + "/" + String(bl); break; } } String mask; if (tcpdump_rules && (bo % 8 != 0 || bl % 8 != 0) && bl / 32 == (bo + bl - 1) / 32) { uint32_t maskval = ((1 << bl) - 1) << (7 - (bo + bl - 1) % 8); mask = " & " + String(maskval); bl = (bo % 8 + bl + 7) & ~7; bo &= ~7; } if (bo % 8 == 0 && bl == 8) return protstr + "[" + String(bo / 8) + "]" + mask; else if (bo % 8 == 0 && bl % 8 == 0) return protstr + "[" + String(bo / 8) + ":" + String(bl / 8) + "]" + mask; else if (bl == 1) return protstr + "{" + String(bo) + "}" + mask; else return protstr + "{" + String(bo) + ":" + String(bl) + "}" + mask;}CLICK_ENDDECLSEXPORT_ELEMENT(IPFieldInfo)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -