--- src/sbin/ipfw/ipfw2.c.orig Thu Mar 9 12:18:37 2006 +++ src/sbin/ipfw/ipfw2.c Sat May 13 00:06:49 2006 @@ -212,7 +212,10 @@ TOK_ALTQ, TOK_LOG, + TOK_TAG, + TOK_UNTAG, + TOK_TAGGED, TOK_UID, TOK_GID, TOK_JAIL, @@ -340,10 +343,13 @@ 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 +578,7 @@ {"ipttl", O_IPTTL}, {"mac-type", O_MAC_TYPE}, {"tcpdatalen", O_TCPDATALEN}, + {"tagged", O_TAGGED}, {NULL, 0} }; @@ -1358,7 +1365,7 @@ { 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 +1507,10 @@ 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 +1531,12 @@ else printf(" altq %s", qname); } + if (tagptr) { + if (tagptr->len & F_NOT) + printf(" untag %d", tagptr->arg1); + else + printf(" tag %d", tagptr->arg1); + } /* * then print the body. @@ -1906,6 +1923,14 @@ print_ext6hdr( (ipfw_insn *) cmd ); break; + case O_TAGGED: + if (F_LEN(cmd) == 1) + printf(" tagged %u", cmd->arg1 ); + else + print_newports((ipfw_insn_u16 *)cmd, 0, + O_TAGGED); + break; + default: printf(" [opcode %d len %d]", cmd->opcode, cmd->len); @@ -3759,7 +3784,7 @@ * 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; @@ -4002,6 +4027,21 @@ } break; + case TOK_TAG: + case TOK_UNTAG: + { + NEED1("missing tag number"); + if (have_tag) + errx(EX_DATAERR, + "tag and untag cannot be specified more than once"); + have_tag = cmd; + fill_cmd(cmd, O_TAG, + (i == TOK_TAG) ? 0: F_NOT, + strtoul(*av, NULL, 0)); + ac--; av++; + } + break; + default: abort(); } @@ -4591,6 +4631,16 @@ 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 + fill_cmd(cmd, O_TAGGED, 0, strtoul(*av, NULL, 0)); + ac--; av++; + break; + default: errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); } @@ -4628,7 +4678,8 @@ 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); @@ -4638,6 +4689,7 @@ case O_KEEP_STATE: case O_LIMIT: case O_ALTQ: + case O_TAG: break; default: bcopy(src, dst, i * sizeof(uint32_t)); @@ -4669,6 +4721,11 @@ if (have_altq) { i = F_LEN(have_altq); 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; } /* --- src/sbin/ipfw/ipfw.8.orig Thu Mar 9 12:18:36 2006 +++ src/sbin/ipfw/ipfw.8 Sat May 13 00:07:18 2006 @@ -550,6 +550,53 @@ 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 @@ -1360,6 +1407,15 @@ .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 --- src/sys/sys/mbuf.h.orig Fri Mar 24 02:24:32 2006 +++ src/sys/sys/mbuf.h Sat May 13 00:06:49 2006 @@ -779,6 +779,9 @@ #define PACKET_TAG_IPOPTIONS 27 /* Saved IP options */ #define PACKET_TAG_CARP 28 /* CARP info */ + +#define MTAG_IPFW 1804200305 /* IPFW-tagged cookie */ + /* Packet tag routines. */ struct m_tag *m_tag_alloc(u_int32_t, int, int, int); void m_tag_delete(struct mbuf *, struct m_tag *); --- src/sys/netinet/ip_fw.h.orig Fri Feb 17 19:46:47 2006 +++ src/sys/netinet/ip_fw.h Sat May 13 00:06:49 2006 @@ -157,6 +157,9 @@ O_UNREACH6, /* arg1=icmpv6 code arg (deny) */ + O_TAG, /* arg1=tag number */ + O_TAGGED, /* arg1=tag number */ + O_LAST_OPCODE /* not an opcode! */ }; @@ -359,6 +362,7 @@ * + if a rule has a "log" option, then the first action * (at ACTION_PTR(r)) MUST be O_LOG * + if a rule has an "altq" option, it comes after "log" + * + if a rule has an O_TAG option, it comes after "log" and "altq" * * NOTE: we use a simple linked list of rules because we never need * to delete a rule without scanning the list. We do not use --- src/sys/netinet/ip_fw2.c.orig Thu Mar 9 16:42:44 2006 +++ src/sys/netinet/ip_fw2.c Sat May 13 00:06:49 2006 @@ -2917,6 +2917,52 @@ match = is_ipv4; break; + case O_TAG: + /* Packet is already tagged with this tag? */ + mtag = m_tag_locate(m, MTAG_IPFW, + ((ipfw_insn *) cmd)->arg1, NULL); + + /* We have `untag' action when F_NOT flag is present. + * And we must remove this mtag from mbuf and reset + * `match' to zero (`match' will be inversed later). + * + * Otherwise we should allocate new mtag and push it + * into mbuf. + */ + if (cmd->len & F_NOT) { /* `untag' action */ + if (mtag != NULL) + m_tag_delete(m, mtag); + } else if (mtag == NULL) { + mtag = m_tag_alloc(MTAG_IPFW, + ((ipfw_insn *) cmd)->arg1, 0, M_NOWAIT); + if (mtag != NULL) + m_tag_prepend(m, mtag); + } + match = (cmd->len & F_NOT) ? 0: 1; + break; + + case O_TAGGED: + if (cmdlen == 1) { + match = (m_tag_locate(m, MTAG_IPFW, + ((ipfw_insn *) cmd)->arg1, NULL) != NULL); + break; + } + + /* we have ranges */ + mtag = m_tag_first(m); + while(mtag != NULL) { + if (mtag->m_tag_cookie == MTAG_IPFW) { + uint16_t *p = ((ipfw_insn_u16 *) cmd)->ports; + int i = cmdlen - 1; + for(; !match && i > 0; i--, p += 2) + match = (mtag->m_tag_id >= p[0] && + mtag->m_tag_id <= p[1] ); + } + if (match) break; + mtag = m_tag_next(m, mtag); + } + break; + /* * The second set of opcodes represents 'actions', * i.e. the terminal part of a rule once the packet @@ -2936,7 +2982,7 @@ * or to the SKIPTO target ('goto again' after * having set f, cmd and l), respectively. * - * O_LOG and O_ALTQ action parameters: + * O_TAG, O_LOG and O_ALTQ action parameters: * perform some action and set match = 1; * * O_LIMIT and O_KEEP_STATE: these opcodes are @@ -3587,6 +3633,7 @@ case O_IP6: #endif case O_IP4: + case O_TAG: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; break; @@ -3659,6 +3706,7 @@ case O_IPTTL: case O_IPLEN: case O_TCPDATALEN: + case O_TAGGED: if (cmdlen < 1 || cmdlen > 31) goto bad_size; break;