summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoroleg <oleg@FreeBSD.org>2006-05-24 13:09:55 +0000
committeroleg <oleg@FreeBSD.org>2006-05-24 13:09:55 +0000
commit499297c74cc00692bc00ddab18c1e67dcbfaf0a9 (patch)
treeadaee99342bafc97133da0f20bc5246de5eb3ec8 /sys
parent8ba778a258996098a6ddb344d5b39d907258b460 (diff)
downloadFreeBSD-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 'sys')
-rw-r--r--sys/netinet/ip_fw.h6
-rw-r--r--sys/netinet/ip_fw2.c58
2 files changed, 63 insertions, 1 deletions
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 0893e46..14ca1d5 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -157,6 +157,9 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_UNREACH6, /* arg1=icmpv6 code arg (deny) */
+ O_TAG, /* arg1=tag number */
+ O_TAGGED, /* arg1=tag number */
+
O_LAST_OPCODE /* not an opcode! */
};
@@ -215,6 +218,8 @@ typedef struct _ipfw_insn { /* template for instructions */
*/
#define F_INSN_SIZE(t) ((sizeof (t))/sizeof(u_int32_t))
+#define MTAG_IPFW 1148380143 /* IPFW-tagged cookie */
+
/*
* This is used to store an array of 16-bit entries (ports etc.)
*/
@@ -346,6 +351,7 @@ typedef struct _ipfw_insn_icmp6 {
* + 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
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index 559d5cd..bb4933b 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -781,6 +781,9 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
if (cmd->opcode == O_PROB)
cmd += F_LEN(cmd);
+ if (cmd->opcode == O_TAG)
+ cmd += F_LEN(cmd);
+
action = action2;
switch (cmd->opcode) {
case O_DENY:
@@ -1660,6 +1663,8 @@ lookup_next_rule(struct ip_fw *me)
cmd += F_LEN(cmd);
if (cmd->opcode == O_ALTQ)
cmd += F_LEN(cmd);
+ if (cmd->opcode == O_TAG)
+ cmd += F_LEN(cmd);
if ( cmd->opcode == O_SKIPTO )
for (rule = me->next; rule ; rule = rule->next)
if (rule->rulenum >= cmd->arg1)
@@ -2886,6 +2891,55 @@ check_body:
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 */
+ for (mtag = m_tag_first(m);
+ mtag != NULL && !match;
+ mtag = m_tag_next(m, mtag)) {
+ uint16_t *p;
+ int i;
+
+ if (mtag->m_tag_cookie != MTAG_IPFW)
+ continue;
+
+ p = ((ipfw_insn_u16 *)cmd)->ports;
+ i = cmdlen - 1;
+ for(; !match && i > 0; i--, p += 2)
+ match =
+ mtag->m_tag_id >= p[0] &&
+ mtag->m_tag_id <= p[1];
+ }
+ break;
+
/*
* The second set of opcodes represents 'actions',
* i.e. the terminal part of a rule once the packet
@@ -2905,7 +2959,7 @@ check_body:
* 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
@@ -3528,6 +3582,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_IP6:
#endif
case O_IP4:
+ case O_TAG:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
goto bad_size;
break;
@@ -3600,6 +3655,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_IPTTL:
case O_IPLEN:
case O_TCPDATALEN:
+ case O_TAGGED:
if (cmdlen < 1 || cmdlen > 31)
goto bad_size;
break;
OpenPOWER on IntegriCloud