diff options
author | oleg <oleg@FreeBSD.org> | 2006-05-24 13:09:55 +0000 |
---|---|---|
committer | oleg <oleg@FreeBSD.org> | 2006-05-24 13:09:55 +0000 |
commit | 499297c74cc00692bc00ddab18c1e67dcbfaf0a9 (patch) | |
tree | adaee99342bafc97133da0f20bc5246de5eb3ec8 /sbin/ipfw | |
parent | 8ba778a258996098a6ddb344d5b39d907258b460 (diff) | |
download | FreeBSD-src-499297c74cc00692bc00ddab18c1e67dcbfaf0a9.zip FreeBSD-src-499297c74cc00692bc00ddab18c1e67dcbfaf0a9.tar.gz |
Implement internal (i.e. inside kernel) packet tagging using mbuf_tags(9).
Since tags are kept while packet resides in kernelspace, it's possible to
use other kernel facilities (like netgraph nodes) for altering those tags.
Submitted by: Andrey Elsukov <bu7cher at yandex dot ru>
Submitted by: Vadim Goncharov <vadimnuclight at tpu dot ru>
Approved by: glebius (mentor)
Idea from: OpenBSD PF
MFC after: 1 month
Diffstat (limited to 'sbin/ipfw')
-rw-r--r-- | sbin/ipfw/ipfw.8 | 62 | ||||
-rw-r--r-- | sbin/ipfw/ipfw2.c | 80 |
2 files changed, 133 insertions, 9 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 6dd3b6d..2011dd2 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 12, 2006 +.Dd May 24, 2006 .Dt IPFW 8 .Os .Sh NAME @@ -420,6 +420,10 @@ rules is the following: .Ar action .Op Cm log Op Cm logamount Ar number .Op Cm altq Ar queue +.Oo +.Bro Cm tag | untag +.Brc Ar number +.Oc .Ar body .Ek .Ed @@ -552,6 +556,53 @@ command. Note: logging is done after all other packet matching conditions have been successfully verified, and before performing the final action (accept, deny, etc.) on the packet. +.It Cm tag Ar number +When a packet matches a rule with the +.Cm tag +keyword, the numeric tag for the given +.Ar number +in the range 0..65535 will be attached to the packet. +The tag acts as an internal marker (it is not sent out over +the wire) that can be used to identify these packets later on. +This can be used, for example, to provide trust between interfaces +and to start doing policy-based filtering. +A packet can have mutiple tags at the same time. +Tags are "sticky", meaning once a tag is applied to a packet by a +matching rule it exists until explicit removal. +Tags are kept with the packet everywhere within the kernel, but are +lost when packet leaves the kernel, for example, on transmitting +packet out to the network or sending packet to a +.Xr divert 4 +socket. +.Pp +To check for previously applied tags, use the +.Cm tagged +rule option. To delete previously applied tag, use the +.Cm untag +keyword. +.Pp +Note: since tags are kept with the packet everywhere in kernelspace, +they can be set and unset anywhere in kernel network subsystem +(using +.Xr mbuf_tags 9 +facility), not only by means of +.Xr ipfw 4 +.Cm tag +and +.Cm untag +keywords. +For example, there can be a specialized +.Xr netgraph 4 +node doing traffic analyzing and tagging for later inspecting +in firewall. +.It Cm untag Ar number +When a packet matches a rule with the +.Cm untag +keyword, the tag with the number +.Ar number +is searched among the tags attached to this packet and, +if found, removed from it. +Other tags bound to packet, if present, are left untouched. .It Cm altq Ar queue When a packet matches a rule with the .Cm altq @@ -1362,6 +1413,15 @@ specified as an argument. .It Cm src-port Ar ports Matches IP packets whose source port is one of the port(s) specified as argument. +.It Cm tagged Ar tag-list +Matches packets whose tags are included in +.Ar tag-list , +which is either a single value or a list of values or ranges +specified in the same way as +.Ar ports . +Tags can be applied to the packet using +.Cm tag +rule action parameter (see it's description for details on tags). .It Cm tcpack Ar ack TCP packets only. Match if the TCP header acknowledgment number field is set to diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index eb5a5ab..36c3282 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -82,6 +82,15 @@ int */ #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} +#define NOT_NUMBER(str, msg) do { \ + char *c; \ + for (c = str; *c != '\0'; c++) { \ + if (isdigit(*c)) \ + continue; \ + errx(EX_DATAERR, msg); \ + } \ +} while (0) + /* * _s_x is a structure that stores a string <-> token pairs, used in * various places in the parser. Entries are stored in arrays, @@ -212,7 +221,10 @@ enum tokens { TOK_ALTQ, TOK_LOG, + TOK_TAG, + TOK_UNTAG, + TOK_TAGGED, TOK_UID, TOK_GID, TOK_JAIL, @@ -340,10 +352,13 @@ struct _s_x rule_actions[] = { struct _s_x rule_action_params[] = { { "altq", TOK_ALTQ }, { "log", TOK_LOG }, + { "tag", TOK_TAG }, + { "untag", TOK_UNTAG }, { NULL, 0 } /* terminator */ }; struct _s_x rule_options[] = { + { "tagged", TOK_TAGGED }, { "uid", TOK_UID }, { "gid", TOK_GID }, { "jail", TOK_JAIL }, @@ -572,6 +587,7 @@ struct _s_x _port_name[] = { {"ipttl", O_IPTTL}, {"mac-type", O_MAC_TYPE}, {"tcpdatalen", O_TCPDATALEN}, + {"tagged", O_TAGGED}, {NULL, 0} }; @@ -1358,7 +1374,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) { static int twidth = 0; int l; - ipfw_insn *cmd; + ipfw_insn *cmd, *tagptr = NULL; char *comment = NULL; /* ptr to comment if we have one */ int proto = 0; /* default */ int flags = 0; /* prerequisites */ @@ -1500,6 +1516,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) altqptr = (ipfw_insn_altq *)cmd; break; + case O_TAG: + tagptr = cmd; + break; + default: printf("** unrecognized action %d len %d ", cmd->opcode, cmd->len); @@ -1520,6 +1540,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) else printf(" altq %s", qname); } + if (tagptr) { + if (tagptr->len & F_NOT) + printf(" untag %hu", tagptr->arg1); + else + printf(" tag %hu", tagptr->arg1); + } /* * then print the body. @@ -1906,6 +1932,14 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) print_ext6hdr( (ipfw_insn *) cmd ); break; + case O_TAGGED: + if (F_LEN(cmd) == 1) + printf(" tagged %hu", cmd->arg1 ); + else + print_newports((ipfw_insn_u16 *)cmd, 0, + O_TAGGED); + break; + default: printf(" [opcode %d len %d]", cmd->opcode, cmd->len); @@ -3775,7 +3809,7 @@ add(int ac, char *av[]) * various flags used to record that we entered some fields. */ ipfw_insn *have_state = NULL; /* check-state or keep-state */ - ipfw_insn *have_log = NULL, *have_altq = NULL; + ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL; size_t len; int i; @@ -4016,6 +4050,20 @@ chkarg: } break; + case TOK_TAG: + case TOK_UNTAG: + { + if (have_tag) + errx(EX_USAGE, "tag and untag cannot be specified more than once"); + NEED1("missing tag number"); + NOT_NUMBER(*av, "invalid tag number"); + have_tag = cmd; + fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, + strtoul(*av, NULL, 0)); + ac--; av++; + } + break; + default: abort(); } @@ -4605,6 +4653,19 @@ read_options: ac = 0; break; + case TOK_TAGGED: + NEED1("missing tag number"); + if (strpbrk(*av, "-,")) { + if (!add_ports(cmd, *av, 0, O_TAGGED)) + errx(EX_DATAERR, "invalid tag %s", *av); + } else { + NOT_NUMBER(*av, "invalid tag number"); + fill_cmd(cmd, O_TAGGED, 0, + strtoul(*av, NULL, 0)); + } + ac--; av++; + break; + default: errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); } @@ -4641,9 +4702,8 @@ done: fill_cmd(dst, O_PROBE_STATE, 0, 0); dst = next_cmd(dst); } - /* - * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ - */ + + /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { i = F_LEN(src); @@ -4652,6 +4712,7 @@ done: case O_KEEP_STATE: case O_LIMIT: case O_ALTQ: + case O_TAG: break; default: bcopy(src, dst, i * sizeof(uint32_t)); @@ -4672,9 +4733,7 @@ done: */ rule->act_ofs = dst - rule->cmd; - /* - * put back O_LOG, O_ALTQ if necessary - */ + /* put back O_LOG, O_ALTQ, O_TAG if necessary */ if (have_log) { i = F_LEN(have_log); bcopy(have_log, dst, i * sizeof(uint32_t)); @@ -4685,6 +4744,11 @@ done: bcopy(have_altq, dst, i * sizeof(uint32_t)); dst += i; } + if (have_tag) { + i = F_LEN(have_tag); + bcopy(have_tag, dst, i * sizeof(uint32_t)); + dst += i; + } /* * copy all other actions */ |