summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiso <piso@FreeBSD.org>2009-04-01 20:23:47 +0000
committerpiso <piso@FreeBSD.org>2009-04-01 20:23:47 +0000
commitc9b4c109954a4dd9052f62f379febea366d11a07 (patch)
tree12380d32edc71a17a6bfe18bb48510a54c10f4f3
parente965f0a26dd194aa82e93f27e2493e7c4d0afea2 (diff)
downloadFreeBSD-src-c9b4c109954a4dd9052f62f379febea366d11a07.zip
FreeBSD-src-c9b4c109954a4dd9052f62f379febea366d11a07.tar.gz
Implement an ipfw action to reassemble ip packets: reass.
-rw-r--r--sbin/ipfw/ipfw.87
-rw-r--r--sbin/ipfw/ipfw2.c9
-rw-r--r--sbin/ipfw/ipfw2.h1
-rw-r--r--sbin/ipfw/main.c2
-rw-r--r--sys/netinet/ip_fw.h4
-rw-r--r--sys/netinet/ip_fw2.c53
-rw-r--r--sys/netinet/ip_fw_pfil.c6
7 files changed, 80 insertions, 2 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index d163106..4cc2f9e 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -866,6 +866,13 @@ in any subsequent forwarding decisions.
Initially this is limited to the values 0 through 15, see
.Xr setfib 8 .
Processing continues at the next rule.
+.It Cm reass
+Queue and reassemble ip fragments.
+If the packet is not fragmented, counters are updated and processing continues with the next rule.
+If the packet is the last logical fragment, the packet is reassembled and, if
+.Va net.inet.ip.fw.one_pass
+is set to 0, processing continues with the next rule, else packet is allowed to pass and search terminates.
+If the packet is a fragment in the middle, it is consumed and processing stops immediately.
.El
.Ss RULE BODY
The body of a rule contains zero or more patterns (such as
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index c0dfac3..9d95ec4 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -211,6 +211,7 @@ static struct _s_x rule_actions[] = {
{ "check-state", TOK_CHECKSTATE },
{ "//", TOK_COMMENT },
{ "nat", TOK_NAT },
+ { "reass", TOK_REASS },
{ "setfib", TOK_SETFIB },
{ NULL, 0 } /* terminator */
};
@@ -1089,6 +1090,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_SETFIB:
PRINT_UINT_ARG("setfib ", cmd->arg1);
break;
+
+ case O_REASS:
+ printf("reass");
+ break;
default:
printf("** unrecognized action %d len %d ",
@@ -2781,6 +2786,10 @@ chkarg:
ac--; av++;
break;
}
+
+ case TOK_REASS:
+ action->opcode = O_REASS;
+ break;
default:
errx(EX_DATAERR, "invalid action %s\n", av[-1]);
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 442e7b6..508bb6c 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -95,6 +95,7 @@ enum tokens {
TOK_UNREACH,
TOK_CHECKSTATE,
TOK_NAT,
+ TOK_REASS,
TOK_ALTQ,
TOK_LOG,
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
index a83dd5f..3916057 100644
--- a/sbin/ipfw/main.c
+++ b/sbin/ipfw/main.c
@@ -54,7 +54,7 @@ help(void)
"RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
"ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n"
" skipto N | {divert|tee} PORT | forward ADDR |\n"
-" pipe N | queue N | nat N | setfib FIB\n"
+" pipe N | queue N | nat N | setfib FIB | reass\n"
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
"ADDR: [ MAC dst src ether_type ] \n"
" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 0cf1a52..35e7e12 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -139,7 +139,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_FORWARD_IP, /* fwd sockaddr */
O_FORWARD_MAC, /* fwd mac */
O_NAT, /* nope */
-
+ O_REASS, /* none */
+
/*
* More opcodes.
*/
@@ -574,6 +575,7 @@ enum {
IP_FW_NETGRAPH,
IP_FW_NGTEE,
IP_FW_NAT,
+ IP_FW_REASS,
};
/* flags for divert mtag */
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index 1405a27..fa6e6f1 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -898,6 +898,9 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
case O_NAT:
action = "Nat";
break;
+ case O_REASS:
+ action = "Reass";
+ break;
default:
action = "UNKNOWN";
break;
@@ -3375,6 +3378,55 @@ check_body:
goto done;
}
+ case O_REASS: {
+ int ip_off;
+
+ f->pcnt++;
+ f->bcnt += pktlen;
+ ip_off = (args->eh != NULL) ? ntohs(ip->ip_off) : ip->ip_off;
+ if (ip_off & (IP_MF | IP_OFFMASK)) {
+ /*
+ * ip_reass() expects len & off in host
+ * byte order: fix them in case we come
+ * from layer2.
+ */
+ if (args->eh != NULL) {
+ ip->ip_len = ntohs(ip->ip_len);
+ ip->ip_off = ntohs(ip->ip_off);
+ }
+
+ m = ip_reass(m);
+ args->m = m;
+
+ /*
+ * IP header checksum fixup after
+ * reassembly and leave header
+ * in network byte order.
+ */
+ if (m != NULL) {
+ int hlen;
+
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
+ /* revert len & off for layer2 pkts */
+ if (args->eh != NULL)
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_sum = 0;
+ if (hlen == sizeof(struct ip))
+ ip->ip_sum = in_cksum_hdr(ip);
+ else
+ ip->ip_sum = in_cksum(m, hlen);
+ retval = IP_FW_REASS;
+ args->rule = f;
+ goto done;
+ } else {
+ retval = IP_FW_DENY;
+ goto done;
+ }
+ }
+ goto next_rule;
+ }
+
default:
panic("-- unknown opcode %d\n", cmd->opcode);
} /* end of switch() on opcodes */
@@ -4024,6 +4076,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_UNREACH6:
#endif
case O_SKIPTO:
+ case O_REASS:
check_size:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
goto bad_size;
diff --git a/sys/netinet/ip_fw_pfil.c b/sys/netinet/ip_fw_pfil.c
index 1e6d2b0..11560a7 100644
--- a/sys/netinet/ip_fw_pfil.c
+++ b/sys/netinet/ip_fw_pfil.c
@@ -200,6 +200,9 @@ again:
case IP_FW_NAT:
goto again; /* continue with packet */
+ case IP_FW_REASS:
+ goto again;
+
default:
KASSERT(0, ("%s: unknown retval", __func__));
}
@@ -329,6 +332,9 @@ again:
case IP_FW_NAT:
goto again; /* continue with packet */
+ case IP_FW_REASS:
+ goto again;
+
default:
KASSERT(0, ("%s: unknown retval", __func__));
}
OpenPOWER on IntegriCloud