diff -uNr linux-2.4.15-pre6.pristine/include/linux/netfilter_ipv4/ipt_length.h linux-2.4.15-pre6.newlength/include/linux/netfilter_ipv4/ipt_length.h --- linux-2.4.15-pre6.pristine/include/linux/netfilter_ipv4/ipt_length.h Tue Oct 30 18:08:12 2001 +++ linux-2.4.15-pre6.newlength/include/linux/netfilter_ipv4/ipt_length.h Tue Nov 20 18:13:10 2001 @@ -1,9 +1,19 @@ #ifndef _IPT_LENGTH_H #define _IPT_LENGTH_H +/* Value reserved for future merge of invert and ip/proto/payload flags. */ +// #define IPT_LENGTH_INVERT 0x01 /* Invert sense of match; only match packets outside of the specified range */ + +/* The following can be combined. 0x0C, for example, would be the + length of the protocol header and payload. */ +#define IPT_LENGTH_IP 0x02 /* Include the length of the IP header */ +#define IPT_LENGTH_PROTO 0x04 /* Include the length of the protocol (TCP, UDP, ICMP, etc.) header */ +#define IPT_LENGTH_PAYLOAD 0x08 /* Include the length of the payload */ + struct ipt_length_info { u_int16_t min, max; u_int8_t invert; + u_int8_t lengthflags; }; #endif /*_IPT_LENGTH_H*/ diff -uNr linux-2.4.15-pre6.pristine/net/ipv4/netfilter/ipt_length.c linux-2.4.15-pre6.newlength/net/ipv4/netfilter/ipt_length.c --- linux-2.4.15-pre6.pristine/net/ipv4/netfilter/ipt_length.c Tue Oct 30 18:08:12 2001 +++ linux-2.4.15-pre6.newlength/net/ipv4/netfilter/ipt_length.c Tue Nov 20 20:36:28 2001 @@ -1,6 +1,7 @@ /* Kernel module to match packet length. */ #include #include +#include #include #include @@ -20,9 +21,66 @@ int *hotdrop) { const struct ipt_length_info *info = matchinfo; - u_int16_t pktlen = ntohs(skb->nh.iph->tot_len); - - return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; + +/* Set pktlen */ + u_int16_t pktlen = ntohs(skb->nh.iph->tot_len); /* Entire packet length */ + u_int16_t ipheaderlen = 0; /* IP header length */ + u_int16_t protoheaderlen = 0; /* Protocol header length */ + u_int16_t payloadlen = 0; /* Payload only length */ + u_int16_t comparelen = 0; /* The length we'll compare against; it's the sum of one or more of the above 3 */ + +/* Set ipheaderlen */ + if (pktlen > datalen) + ipheaderlen = pktlen - datalen; + +/* Set protoheaderlen */ + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: { + struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)skb->nh.iph + skb->nh.iph->ihl); + protoheaderlen = (tcph->doff) * 4; + break; + } + case IPPROTO_UDP: { + protoheaderlen = 8; + break; + } + case IPPROTO_ICMP: { + protoheaderlen = 4; + break; + } + default: + /* Snort decides to treat all non-TCP/UDP/ICMP + as having no header; any protocol header is + treated as part of the data portion of the packet. + */ + protoheaderlen = 0; + } + +/* Set payloadlen */ + if (datalen > protoheaderlen) + payloadlen = (datalen - protoheaderlen); + +/* Quick sanity check; if all flags off, we assume the userspace tool failed to + set any of them. If all three flags were cleared, we assume we need to + match the old behavior of checking the length of all three. */ + if ((info->lengthflags & (IPT_LENGTH_IP | IPT_LENGTH_IP | IPT_LENGTH_PAYLOAD)) = 0) + comparelen = ipheader + protoheaderlen + payloadlen; + else { +/* Decide what fields we're going to compare against. */ + if ((info->lengthflags & IPT_LENGTH_IP) != 0) + comparelen = comparelen + ipheaderlen; + if ((info->lengthflags & IPT_LENGTH_PROTO) != 0) + comparelen = comparelen + protoheaderlen; + if ((info->lengthflags & IPT_LENGTH_PAYLOAD) != 0) + comparelen = comparelen + payloadlen; + } + + /* If we merge the invert and flags fields, replace + ^ info->invert + with + ^ (((info->invert) & IPT_LENGTH_INVERT) == IPT_LENGTH_INVERT ) + */ + return (comparelen >= info->min && comparelen <= info->max) ^ info->invert; } static int