--- sbin/ipfw/ipfw.8.start 2009-04-02 12:52:03.000000000 +0200 +++ sbin/ipfw/ipfw.8 2009-04-02 12:53:13.000000000 +0200 @@ -866,6 +866,13 @@ 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 --- sbin/ipfw/ipfw2.c.start 2009-04-02 12:49:33.000000000 +0200 +++ sbin/ipfw/ipfw2.c 2009-04-02 12:53:05.000000000 +0200 @@ -211,6 +211,7 @@ { "check-state", TOK_CHECKSTATE }, { "//", TOK_COMMENT }, { "nat", TOK_NAT }, + { "reass", TOK_REASS }, { "setfib", TOK_SETFIB }, { NULL, 0 } /* terminator */ }; @@ -1089,6 +1090,10 @@ 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 @@ ac--; av++; break; } + + case TOK_REASS: + action->opcode = O_REASS; + break; default: errx(EX_DATAERR, "invalid action %s\n", av[-1]); --- sbin/ipfw/ipfw2.h.start 2009-04-02 12:49:48.000000000 +0200 +++ sbin/ipfw/ipfw2.h 2009-04-02 12:52:53.000000000 +0200 @@ -95,6 +95,7 @@ TOK_UNREACH, TOK_CHECKSTATE, TOK_NAT, + TOK_REASS, TOK_ALTQ, TOK_LOG, --- sbin/ipfw/main.c.start 2009-04-02 12:51:53.000000000 +0200 +++ sbin/ipfw/main.c 2009-04-02 12:53:05.000000000 +0200 @@ -54,7 +54,7 @@ "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" --- sys/netinet/ip_fw.h.start 2009-04-02 12:50:03.000000000 +0200 +++ sys/netinet/ip_fw.h 2009-04-02 12:52:57.000000000 +0200 @@ -133,7 +133,8 @@ O_FORWARD_IP, /* fwd sockaddr */ O_FORWARD_MAC, /* fwd mac */ O_NAT, /* nope */ - + O_REASS, /* none */ + /* * More opcodes. */ @@ -568,6 +569,7 @@ IP_FW_NETGRAPH, IP_FW_NGTEE, IP_FW_NAT, + IP_FW_REASS, }; /* flags for divert mtag */ --- sys/netinet/ip_fw2.c.start 2009-04-02 12:50:16.000000000 +0200 +++ sys/netinet/ip_fw2.c 2009-04-02 12:53:23.000000000 +0200 @@ -868,6 +868,9 @@ case O_NAT: action = "Nat"; break; + case O_REASS: + action = "Reass"; + break; default: action = "UNKNOWN"; break; @@ -3334,6 +3337,55 @@ 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 */ @@ -3980,6 +4032,7 @@ case O_UNREACH6: #endif case O_SKIPTO: + case O_REASS: check_size: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; --- sys/netinet/ip_fw_pfil.c.start 2009-04-02 12:50:47.000000000 +0200 +++ sys/netinet/ip_fw_pfil.c 2009-04-02 12:52:57.000000000 +0200 @@ -191,6 +191,9 @@ case IP_FW_NAT: goto again; /* continue with packet */ + case IP_FW_REASS: + goto again; + default: KASSERT(0, ("%s: unknown retval", __func__)); } @@ -320,6 +323,9 @@ case IP_FW_NAT: goto again; /* continue with packet */ + case IP_FW_REASS: + goto again; + default: KASSERT(0, ("%s: unknown retval", __func__)); }