diff options
Diffstat (limited to 'sys/netinet/ip_fw2.c')
-rw-r--r-- | sys/netinet/ip_fw2.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 836be9d..7097b20 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -66,6 +66,7 @@ #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> #include <netinet/ip_fw.h> +#include <netinet/ip_divert.h> #include <netinet/ip_dummynet.h> #include <netinet/tcp.h> #include <netinet/tcp_timer.h> @@ -1457,6 +1458,7 @@ ipfw_chk(struct ip_fw_args *args) int dyn_dir = MATCH_UNKNOWN; ipfw_dyn_rule *q = NULL; struct ip_fw_chain *chain = &layer3_chain; + struct m_tag *mtag; if (m->m_flags & M_SKIP_FIREWALL) return 0; /* accept */ @@ -1545,6 +1547,7 @@ ipfw_chk(struct ip_fw_args *args) after_ip_checks: IPFW_LOCK(chain); /* XXX expensive? can we run lock free? */ + mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL); if (args->rule) { /* * Packet has already been tagged. Look for the next rule @@ -1567,7 +1570,7 @@ after_ip_checks: * Find the starting rule. It can be either the first * one, or the one after divert_rule if asked so. */ - int skipto = args->divert_rule; + int skipto = mtag ? divert_cookie(mtag) : 0; f = chain->rules; if (args->eh == NULL && skipto != 0) { @@ -1583,7 +1586,9 @@ after_ip_checks: } } } - args->divert_rule = 0; /* reset to avoid confusion later */ + /* reset divert rule to avoid confusion later */ + if (mtag) + m_tag_delete(m, mtag); /* * Now scan the rules, and parse microinstructions for each rule. @@ -2018,14 +2023,29 @@ check_body: goto done; case O_DIVERT: - case O_TEE: + case O_TEE: { + struct divert_tag *dt; + if (args->eh) /* not on layer 2 */ break; - args->divert_rule = f->rulenum; - retval = (cmd->opcode == O_DIVERT) ? + mtag = m_tag_get(PACKET_TAG_DIVERT, + sizeof(struct divert_tag), + M_NOWAIT); + if (mtag == NULL) { + /* XXX statistic */ + /* drop packet */ + IPFW_UNLOCK(chain); + return IP_FW_PORT_DENY_FLAG; + } + dt = (struct divert_tag *)(mtag+1); + dt->cookie = f->rulenum; + dt->info = (cmd->opcode == O_DIVERT) ? cmd->arg1 : cmd->arg1 | IP_FW_PORT_TEE_FLAG; + m_tag_prepend(m, mtag); + retval = dt->info; goto done; + } case O_COUNT: case O_SKIPTO: |