/* Returns whether matches rule or not. */ static inline int ip6_packet_match(const struct sk_buff *skb, const char *indev, const char *outdev, const struct ip6t_ip6 *ip6info, 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)) if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src), IP6T_INV_SRCIP) || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst), IP6T_INV_DSTIP)) { dprintf("Source or dest mismatch.\n"); /* dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, ipinfo->smsk.s_addr, ipinfo->src.s_addr, ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : ""); dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr, ipinfo->dmsk.s_addr, ipinfo->dst.s_addr, ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/ return 0; } /* Look for ifname matches; this should unroll nicely. */ for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ret |= (((const unsigned long *)indev)[i] ^ ((const unsigned long *)ip6info->iniface)[i]) & ((const unsigned long *)ip6info->iniface_mask)[i]; } if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { dprintf("VIA in mismatch (%s vs %s).%s\n", indev, ip6info->iniface, ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":""); return 0; } for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ret |= (((const unsigned long *)outdev)[i] ^ ((const unsigned long *)ip6info->outiface)[i]) & ((const unsigned long *)ip6info->outiface_mask)[i]; } if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { dprintf("VIA out mismatch (%s vs %s).%s\n", outdev, ip6info->outiface, ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":""); return 0; } /* ... might want to do something with class and flowlabel here ... */ /* look for the desired protocol header */ if((ip6info->flags & IP6T_F_PROTO)) { u_int8_t currenthdr = ipv6->nexthdr; struct ipv6_opt_hdr _hdr, *hp; u_int16_t ptr; /* Header offset in skb */ u_int16_t hdrlen; /* Header */ u_int16_t _fragoff = 0, *fp = NULL; ptr = IPV6_HDR_LEN; while (ip6t_ext_hdr(currenthdr)) { /* Is there enough space for the next ext header? */ if (skb->len - ptr < IPV6_OPTHDR_LEN) return 0; /* NONE or ESP: there isn't protocol part */ /* If we want to count these packets in '-p all', * we will change the return 0 to 1*/ if ((currenthdr == IPPROTO_NONE) || (currenthdr == IPPROTO_ESP)) return 0; hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); BUG_ON(hp == NULL); /* Size calculation */ if (currenthdr == IPPROTO_FRAGMENT) { fp = skb_header_pointer(skb, ptr+offsetof(struct frag_hdr, frag_off), sizeof(_fragoff), &_fragoff); if (fp == NULL) return 0; _fragoff = ntohs(*fp) & ~0x7; hdrlen = 8; } else if (currenthdr == IPPROTO_AH)
/* Returns whether matches rule or not. */ static inline int ip6_packet_match(const struct sk_buff *skb, const char *indev, const char *outdev, const struct ip6t_ip6 *ip6info, 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)) if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk, &ip6info->src), IP6T_INV_SRCIP) || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk, &ip6info->dst), IP6T_INV_DSTIP)) { dprintf("Source or dest mismatch.\n"); /* dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, ipinfo->smsk.s_addr, ipinfo->src.s_addr, ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : ""); dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr, ipinfo->dmsk.s_addr, ipinfo->dst.s_addr, ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/ return 0; } /* Look for ifname matches; this should unroll nicely. */ for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ret |= (((const unsigned long *)indev)[i] ^ ((const unsigned long *)ip6info->iniface)[i]) & ((const unsigned long *)ip6info->iniface_mask)[i]; } if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { dprintf("VIA in mismatch (%s vs %s).%s\n", indev, ip6info->iniface, ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":""); return 0; } for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { ret |= (((const unsigned long *)outdev)[i] ^ ((const unsigned long *)ip6info->outiface)[i]) & ((const unsigned long *)ip6info->outiface_mask)[i]; } if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { dprintf("VIA out mismatch (%s vs %s).%s\n", outdev, ip6info->outiface, ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":""); return 0; } /* ... might want to do something with class and flowlabel here ... */ /* look for the desired protocol header */ if((ip6info->flags & IP6T_F_PROTO)) { int protohdr; unsigned short _frag_off; protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off); if (protohdr < 0) return 0; *fragoff = _frag_off; dprintf("Packet protocol %hi ?= %s%hi.\n", protohdr, ip6info->invflags & IP6T_INV_PROTO ? "!":"", ip6info->proto); if (ip6info->proto == protohdr) { if(ip6info->invflags & IP6T_INV_PROTO) { return 0; } return 1; } /* We need match for the '-p all', too! */ if ((ip6info->proto != 0) && !(ip6info->invflags & IP6T_INV_PROTO)) return 0; } return 1; }