ChangeSet 1.1547, 2004/12/21 17:47:22+01:00, [EMAIL PROTECTED]

        [NETFILTER]: Backport fixes for ip6tables
         
        This patch fixes the following bugs:
         
          - "offset" argument of match functions are always 0.
          - "datalen" argument of match functions includes extension headers.
         
        And I deleted the code skipping extension headers in {tcp,udp}_match().
         
        Signed-off-by: Yasuyuki KOZAKAI <[EMAIL PROTECTED]>
        Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]>



 ip6_tables.c |   94 +++++++++++++++++++++--------------------------------------
 1 files changed, 34 insertions(+), 60 deletions(-)


diff -Nru a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
--- a/net/ipv6/netfilter/ip6_tables.c   2005-01-15 07:04:55 -08:00
+++ b/net/ipv6/netfilter/ip6_tables.c   2005-01-15 07:04:55 -08:00
@@ -149,14 +149,15 @@
 /* Returns whether matches rule or not. */
 static inline int
 ip6_packet_match(const struct sk_buff *skb,
-                const struct ipv6hdr *ipv6,
                 const char *indev,
                 const char *outdev,
                 const struct ip6t_ip6 *ip6info,
-                int isfrag)
+                unsigned int *protoff,
+                int *fragoff)
 {
        size_t i;
        unsigned long ret;
+       const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
 
@@ -210,6 +211,7 @@
                struct ipv6_opt_hdr *hdrptr;
                u_int16_t ptr;          /* Header offset in skb */
                u_int16_t hdrlen;       /* Header */
+               u_int16_t foff = 0;
 
                ptr = IPV6_HDR_LEN;
 
@@ -229,6 +231,16 @@
 
                        /* Size calculation */
                        if (currenthdr == IPPROTO_FRAGMENT) {
+                               unsigned int foff_off;
+
+                               foff_off = ptr + offsetof(struct frag_hdr,
+                                                         frag_off);
+                               if (skb->len - foff_off < sizeof(foff))
+                                       return 0;
+
+                               foff = ntohs(*(u_int16_t *)(skb->data
+                                                           + foff_off))
+                                      & ~0x7;
                                hdrlen = 8;
                        } else if (currenthdr == IPPROTO_AH)
                                hdrlen = (hdrptr->hdrlen+2)<<2;
@@ -240,8 +252,16 @@
                        /* ptr is too large */
                        if ( ptr > skb->len ) 
                                return 0;
+                       if (foff) {
+                               if (ip6t_ext_hdr(currenthdr))
+                                       return 0;
+                               break;
+                       }
                }
 
+               *protoff = ptr;
+               *fragoff = foff;
+
                /* currenthdr contains the protocol header */
 
                dprintf("Packet protocol %hi ?= %s%hi.\n",
@@ -329,10 +349,8 @@
              void *userdata)
 {
        static const char nulldevname[IFNAMSIZ] = { 0 };
-       u_int16_t offset = 0;
-       struct ipv6hdr *ipv6;
-       void *protohdr;
-       u_int16_t datalen;
+       int offset = 0;
+       unsigned int protoff = 0;
        int hotdrop = 0;
        /* Initializing verdict to NF_DROP keeps gcc happy. */
        unsigned int verdict = NF_DROP;
@@ -341,9 +359,6 @@
        struct ip6t_entry *e, *back;
 
        /* Initialization */
-       ipv6 = (*pskb)->nh.ipv6h;
-       protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN);
-       datalen = (*pskb)->len - IPV6_HDR_LEN;
        indev = in ? in->name : nulldevname;
        outdev = out ? out->name : nulldevname;
 
@@ -381,17 +396,20 @@
                IP_NF_ASSERT(e);
                IP_NF_ASSERT(back);
                (*pskb)->nfcache |= e->nfcache;
-               if (ip6_packet_match(*pskb, ipv6, indev, outdev, 
-                       &e->ipv6, offset)) {
+               if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
+                                    &protoff, &offset)) {
                        struct ip6t_entry_target *t;
 
                        if (IP6T_MATCH_ITERATE(e, do_match,
                                               *pskb, in, out,
-                                              offset, protohdr,
-                                              datalen, &hotdrop) != 0)
+                                              offset,
+                                              (void *)((*pskb)->data
+                                                       + protoff),
+                                              (*pskb)->len - protoff,
+                                              &hotdrop) != 0)
                                goto no_match;
 
-                       ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + 
IPV6_HDR_LEN, 1);
+                       ADD_COUNTER(e->counters, 
ntohs((*pskb)->nh.ipv6h->payload_len) + IPV6_HDR_LEN, 1);
 
                        t = ip6t_get_target(e);
                        IP_NF_ASSERT(t->u.kernel.target);
@@ -447,11 +465,6 @@
                                ((struct ip6t_entry *)table_base)->comefrom
                                        = 0x57acc001;
 #endif
-                               /* Target might have changed stuff. */
-                               ipv6 = (*pskb)->nh.ipv6h;
-                               protohdr = (u_int32_t *)((void *)ipv6 + 
IPV6_HDR_LEN);
-                               datalen = (*pskb)->len - IPV6_HDR_LEN;
-
                                if (verdict == IP6T_CONTINUE)
                                        e = (void *)e + e->next_offset;
                                else
@@ -1567,10 +1580,8 @@
          u_int16_t datalen,
          int *hotdrop)
 {
-       const struct tcphdr *tcp;
+       const struct tcphdr *tcp = hdr;
        const struct ip6t_tcp *tcpinfo = matchinfo;
-       int tcpoff;
-       u8 nexthdr = skb->nh.ipv6h->nexthdr;
 
        /* To quote Alan:
 
@@ -1591,24 +1602,6 @@
                return 0;
        }
 
-       tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
-       tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff);
-       if (tcpoff < 0 || tcpoff > skb->len) {
-               duprintf("tcp_match: cannot skip exthdr. Dropping.\n");
-               *hotdrop = 1;
-               return 0;
-       } else if (nexthdr == IPPROTO_FRAGMENT)
-               return 0;
-       else if (nexthdr != IPPROTO_TCP ||
-                skb->len - tcpoff < sizeof(struct tcphdr)) {
-               /* cannot be occured */
-               duprintf("tcp_match: cannot get TCP header. Dropping.\n");
-               *hotdrop = 1;
-               return 0;
-       }
-
-       tcp = (struct tcphdr *)(skb->data + tcpoff);
-
        /* FIXME: Try tcp doff >> packet len against various stacks --RR */
 
 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
@@ -1659,10 +1652,8 @@
          u_int16_t datalen,
          int *hotdrop)
 {
-       const struct udphdr *udp;
+       const struct udphdr *udp = hdr;
        const struct ip6t_udp *udpinfo = matchinfo;
-       int udpoff;
-       u8 nexthdr = skb->nh.ipv6h->nexthdr;
 
        if (offset == 0 && datalen < sizeof(struct udphdr)) {
                /* We've been asked to examine this packet, and we
@@ -1671,23 +1662,6 @@
                *hotdrop = 1;
                return 0;
        }
-
-       udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
-       udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff);
-       if (udpoff < 0 || udpoff > skb->len) {
-               duprintf("udp_match: cannot skip exthdr. Dropping.\n");
-               *hotdrop = 1;
-               return 0;
-       } else if (nexthdr == IPPROTO_FRAGMENT)
-               return 0;
-       else if (nexthdr != IPPROTO_UDP ||
-                skb->len - udpoff < sizeof(struct udphdr)) {
-               duprintf("udp_match: cannot get UDP header. Dropping.\n");
-               *hotdrop = 1;
-               return 0;
-       }
-
-       udp = (struct udphdr *)(skb->data + udpoff);
 
        /* Must not be a fragment. */
        return !offset
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-24" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to