1 /* Kernel module to match Hop-by-Hop and Destination parameters. */
 
   3 /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
 
   5  * This program is free software; you can redistribute it and/or modify
 
   6  * it under the terms of the GNU General Public License version 2 as
 
   7  * published by the Free Software Foundation.
 
  10 #include <linux/module.h>
 
  11 #include <linux/skbuff.h>
 
  12 #include <linux/ipv6.h>
 
  13 #include <linux/types.h>
 
  14 #include <net/checksum.h>
 
  17 #include <asm/byteorder.h>
 
  19 #include <linux/netfilter/x_tables.h>
 
  20 #include <linux/netfilter_ipv6/ip6_tables.h>
 
  21 #include <linux/netfilter_ipv6/ip6t_opts.h>
 
  23 MODULE_LICENSE("GPL");
 
  24 MODULE_DESCRIPTION("IPv6 opts match");
 
  25 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 
  26 MODULE_ALIAS("ip6t_dst");
 
  31 #define DEBUGP(format, args...)
 
  37  *      1       -> must drop the packet
 
  38  *      2       -> send ICMP PARM PROB regardless and drop packet
 
  39  *      3       -> Send ICMP if not a multicast address and drop packet
 
  42  *      1       -> can change the routing
 
  44  *      0       -> Pad1 (only 1 byte!)
 
  45  *      1       -> PadN LENGTH info (total length = length + 2)
 
  46  *      C0 | 2  -> JUMBO 4 x x x x ( xxxx > 64k )
 
  51 match(const struct sk_buff *skb,
 
  52       const struct net_device *in,
 
  53       const struct net_device *out,
 
  54       const struct xt_match *match,
 
  55       const void *matchinfo,
 
  60         struct ipv6_opt_hdr _optsh, *oh;
 
  61         const struct ip6t_opts *optinfo = matchinfo;
 
  64         unsigned int hdrlen = 0;
 
  66         u8 _opttype, *tp = NULL;
 
  67         u8 _optlen, *lp = NULL;
 
  71         err = ipv6_find_hdr(skb, &ptr, match->data, NULL);
 
  78         oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
 
  84         hdrlen = ipv6_optlen(oh);
 
  85         if (skb->len - ptr < hdrlen) {
 
  86                 /* Packet smaller than it's length field */
 
  90         DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
 
  92         DEBUGP("len %02X %04X %02X ",
 
  93                optinfo->hdrlen, hdrlen,
 
  94                (!(optinfo->flags & IP6T_OPTS_LEN) ||
 
  95                 ((optinfo->hdrlen == hdrlen) ^
 
  96                  !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
 
  99               (!(optinfo->flags & IP6T_OPTS_LEN) ||
 
 100                ((optinfo->hdrlen == hdrlen) ^
 
 101                 !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
 
 105         if (!(optinfo->flags & IP6T_OPTS_OPTS)) {
 
 107         } else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
 
 108                 DEBUGP("Not strict - not implemented");
 
 111                 DEBUGP("#%d ", optinfo->optsnr);
 
 112                 for (temp = 0; temp < optinfo->optsnr; temp++) {
 
 113                         /* type field exists ? */
 
 116                         tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
 
 122                         if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) {
 
 123                                 DEBUGP("Tbad %02X %02X\n",
 
 125                                        (optinfo->opts[temp] & 0xFF00) >> 8);
 
 134                                 /* length field exists ? */
 
 137                                 lp = skb_header_pointer(skb, ptr + 1,
 
 142                                 spec_len = optinfo->opts[temp] & 0x00FF;
 
 144                                 if (spec_len != 0x00FF && spec_len != *lp) {
 
 145                                         DEBUGP("Lbad %02X %04X\n", *lp,
 
 156                         /* Step to the next */
 
 157                         DEBUGP("len%04X \n", optlen);
 
 159                         if ((ptr > skb->len - optlen || hdrlen < optlen) &&
 
 160                             (temp < optinfo->optsnr - 1)) {
 
 161                                 DEBUGP("new pointer is too large! \n");
 
 167                 if (temp == optinfo->optsnr)
 
 176 /* Called when user tries to insert an entry of this type. */
 
 178 checkentry(const char *tablename,
 
 180            const struct xt_match *match,
 
 182            unsigned int hook_mask)
 
 184         const struct ip6t_opts *optsinfo = matchinfo;
 
 186         if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
 
 187                 DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
 
 193 static struct xt_match opts_match[] = {
 
 198                 .matchsize      = sizeof(struct ip6t_opts),
 
 199                 .checkentry     = checkentry,
 
 207                 .matchsize      = sizeof(struct ip6t_opts),
 
 208                 .checkentry     = checkentry,
 
 210                 .data           = NEXTHDR_DEST,
 
 214 static int __init ip6t_hbh_init(void)
 
 216         return xt_register_matches(opts_match, ARRAY_SIZE(opts_match));
 
 219 static void __exit ip6t_hbh_fini(void)
 
 221         xt_unregister_matches(opts_match, ARRAY_SIZE(opts_match));
 
 224 module_init(ip6t_hbh_init);
 
 225 module_exit(ip6t_hbh_fini);