diff options
author | piso <piso@FreeBSD.org> | 2009-04-01 20:23:47 +0000 |
---|---|---|
committer | piso <piso@FreeBSD.org> | 2009-04-01 20:23:47 +0000 |
commit | c9b4c109954a4dd9052f62f379febea366d11a07 (patch) | |
tree | 12380d32edc71a17a6bfe18bb48510a54c10f4f3 | |
parent | e965f0a26dd194aa82e93f27e2493e7c4d0afea2 (diff) | |
download | FreeBSD-src-c9b4c109954a4dd9052f62f379febea366d11a07.zip FreeBSD-src-c9b4c109954a4dd9052f62f379febea366d11a07.tar.gz |
Implement an ipfw action to reassemble ip packets: reass.
-rw-r--r-- | sbin/ipfw/ipfw.8 | 7 | ||||
-rw-r--r-- | sbin/ipfw/ipfw2.c | 9 | ||||
-rw-r--r-- | sbin/ipfw/ipfw2.h | 1 | ||||
-rw-r--r-- | sbin/ipfw/main.c | 2 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 4 | ||||
-rw-r--r-- | sys/netinet/ip_fw2.c | 53 | ||||
-rw-r--r-- | sys/netinet/ip_fw_pfil.c | 6 |
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__)); } |