root/net/ipv6/netfilter/ip6t_hbh.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hbh_mt6
  2. hbh_mt6_check
  3. hbh_mt6_init
  4. hbh_mt6_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* Kernel module to match Hop-by-Hop and Destination parameters. */
   3 
   4 /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
   5  */
   6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   7 #include <linux/module.h>
   8 #include <linux/skbuff.h>
   9 #include <linux/ipv6.h>
  10 #include <linux/types.h>
  11 #include <net/checksum.h>
  12 #include <net/ipv6.h>
  13 
  14 #include <asm/byteorder.h>
  15 
  16 #include <linux/netfilter/x_tables.h>
  17 #include <linux/netfilter_ipv6/ip6_tables.h>
  18 #include <linux/netfilter_ipv6/ip6t_opts.h>
  19 
  20 MODULE_LICENSE("GPL");
  21 MODULE_DESCRIPTION("Xtables: IPv6 Hop-By-Hop and Destination Header match");
  22 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
  23 MODULE_ALIAS("ip6t_dst");
  24 
  25 /*
  26  *  (Type & 0xC0) >> 6
  27  *      0       -> ignorable
  28  *      1       -> must drop the packet
  29  *      2       -> send ICMP PARM PROB regardless and drop packet
  30  *      3       -> Send ICMP if not a multicast address and drop packet
  31  *  (Type & 0x20) >> 5
  32  *      0       -> invariant
  33  *      1       -> can change the routing
  34  *  (Type & 0x1F) Type
  35  *      0       -> Pad1 (only 1 byte!)
  36  *      1       -> PadN LENGTH info (total length = length + 2)
  37  *      C0 | 2  -> JUMBO 4 x x x x ( xxxx > 64k )
  38  *      5       -> RTALERT 2 x x
  39  */
  40 
  41 static struct xt_match hbh_mt6_reg[] __read_mostly;
  42 
  43 static bool
  44 hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
  45 {
  46         struct ipv6_opt_hdr _optsh;
  47         const struct ipv6_opt_hdr *oh;
  48         const struct ip6t_opts *optinfo = par->matchinfo;
  49         unsigned int temp;
  50         unsigned int ptr = 0;
  51         unsigned int hdrlen = 0;
  52         bool ret = false;
  53         u8 _opttype;
  54         u8 _optlen;
  55         const u_int8_t *tp = NULL;
  56         const u_int8_t *lp = NULL;
  57         unsigned int optlen;
  58         int err;
  59 
  60         err = ipv6_find_hdr(skb, &ptr,
  61                             (par->match == &hbh_mt6_reg[0]) ?
  62                             NEXTHDR_HOP : NEXTHDR_DEST, NULL, NULL);
  63         if (err < 0) {
  64                 if (err != -ENOENT)
  65                         par->hotdrop = true;
  66                 return false;
  67         }
  68 
  69         oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
  70         if (oh == NULL) {
  71                 par->hotdrop = true;
  72                 return false;
  73         }
  74 
  75         hdrlen = ipv6_optlen(oh);
  76         if (skb->len - ptr < hdrlen) {
  77                 /* Packet smaller than it's length field */
  78                 return false;
  79         }
  80 
  81         pr_debug("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
  82 
  83         pr_debug("len %02X %04X %02X ",
  84                  optinfo->hdrlen, hdrlen,
  85                  (!(optinfo->flags & IP6T_OPTS_LEN) ||
  86                   ((optinfo->hdrlen == hdrlen) ^
  87                    !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
  88 
  89         ret = (oh != NULL) &&
  90               (!(optinfo->flags & IP6T_OPTS_LEN) ||
  91                ((optinfo->hdrlen == hdrlen) ^
  92                 !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
  93 
  94         ptr += 2;
  95         hdrlen -= 2;
  96         if (!(optinfo->flags & IP6T_OPTS_OPTS)) {
  97                 return ret;
  98         } else {
  99                 pr_debug("Strict ");
 100                 pr_debug("#%d ", optinfo->optsnr);
 101                 for (temp = 0; temp < optinfo->optsnr; temp++) {
 102                         /* type field exists ? */
 103                         if (hdrlen < 1)
 104                                 break;
 105                         tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
 106                                                 &_opttype);
 107                         if (tp == NULL)
 108                                 break;
 109 
 110                         /* Type check */
 111                         if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) {
 112                                 pr_debug("Tbad %02X %02X\n", *tp,
 113                                          (optinfo->opts[temp] & 0xFF00) >> 8);
 114                                 return false;
 115                         } else {
 116                                 pr_debug("Tok ");
 117                         }
 118                         /* Length check */
 119                         if (*tp) {
 120                                 u16 spec_len;
 121 
 122                                 /* length field exists ? */
 123                                 if (hdrlen < 2)
 124                                         break;
 125                                 lp = skb_header_pointer(skb, ptr + 1,
 126                                                         sizeof(_optlen),
 127                                                         &_optlen);
 128                                 if (lp == NULL)
 129                                         break;
 130                                 spec_len = optinfo->opts[temp] & 0x00FF;
 131 
 132                                 if (spec_len != 0x00FF && spec_len != *lp) {
 133                                         pr_debug("Lbad %02X %04X\n", *lp,
 134                                                  spec_len);
 135                                         return false;
 136                                 }
 137                                 pr_debug("Lok ");
 138                                 optlen = *lp + 2;
 139                         } else {
 140                                 pr_debug("Pad1\n");
 141                                 optlen = 1;
 142                         }
 143 
 144                         /* Step to the next */
 145                         pr_debug("len%04X\n", optlen);
 146 
 147                         if ((ptr > skb->len - optlen || hdrlen < optlen) &&
 148                             temp < optinfo->optsnr - 1) {
 149                                 pr_debug("new pointer is too large!\n");
 150                                 break;
 151                         }
 152                         ptr += optlen;
 153                         hdrlen -= optlen;
 154                 }
 155                 if (temp == optinfo->optsnr)
 156                         return ret;
 157                 else
 158                         return false;
 159         }
 160 
 161         return false;
 162 }
 163 
 164 static int hbh_mt6_check(const struct xt_mtchk_param *par)
 165 {
 166         const struct ip6t_opts *optsinfo = par->matchinfo;
 167 
 168         if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
 169                 pr_debug("unknown flags %X\n", optsinfo->invflags);
 170                 return -EINVAL;
 171         }
 172 
 173         if (optsinfo->flags & IP6T_OPTS_NSTRICT) {
 174                 pr_debug("Not strict - not implemented");
 175                 return -EINVAL;
 176         }
 177 
 178         return 0;
 179 }
 180 
 181 static struct xt_match hbh_mt6_reg[] __read_mostly = {
 182         {
 183                 /* Note, hbh_mt6 relies on the order of hbh_mt6_reg */
 184                 .name           = "hbh",
 185                 .family         = NFPROTO_IPV6,
 186                 .match          = hbh_mt6,
 187                 .matchsize      = sizeof(struct ip6t_opts),
 188                 .checkentry     = hbh_mt6_check,
 189                 .me             = THIS_MODULE,
 190         },
 191         {
 192                 .name           = "dst",
 193                 .family         = NFPROTO_IPV6,
 194                 .match          = hbh_mt6,
 195                 .matchsize      = sizeof(struct ip6t_opts),
 196                 .checkentry     = hbh_mt6_check,
 197                 .me             = THIS_MODULE,
 198         },
 199 };
 200 
 201 static int __init hbh_mt6_init(void)
 202 {
 203         return xt_register_matches(hbh_mt6_reg, ARRAY_SIZE(hbh_mt6_reg));
 204 }
 205 
 206 static void __exit hbh_mt6_exit(void)
 207 {
 208         xt_unregister_matches(hbh_mt6_reg, ARRAY_SIZE(hbh_mt6_reg));
 209 }
 210 
 211 module_init(hbh_mt6_init);
 212 module_exit(hbh_mt6_exit);

/* [<][>][^][v][top][bottom][index][help] */