root/net/netfilter/xt_dccp.c

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

DEFINITIONS

This source file includes following definitions.
  1. dccp_find_option
  2. match_types
  3. match_option
  4. dccp_mt
  5. dccp_mt_check
  6. dccp_mt_init
  7. dccp_mt_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * iptables module for DCCP protocol header matching
   4  *
   5  * (C) 2005 by Harald Welte <laforge@netfilter.org>
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/skbuff.h>
  10 #include <linux/slab.h>
  11 #include <linux/spinlock.h>
  12 #include <net/ip.h>
  13 #include <linux/dccp.h>
  14 
  15 #include <linux/netfilter/x_tables.h>
  16 #include <linux/netfilter/xt_dccp.h>
  17 
  18 #include <linux/netfilter_ipv4/ip_tables.h>
  19 #include <linux/netfilter_ipv6/ip6_tables.h>
  20 
  21 MODULE_LICENSE("GPL");
  22 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  23 MODULE_DESCRIPTION("Xtables: DCCP protocol packet match");
  24 MODULE_ALIAS("ipt_dccp");
  25 MODULE_ALIAS("ip6t_dccp");
  26 
  27 #define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
  28                                   || (!!((invflag) & (option)) ^ (cond)))
  29 
  30 static unsigned char *dccp_optbuf;
  31 static DEFINE_SPINLOCK(dccp_buflock);
  32 
  33 static inline bool
  34 dccp_find_option(u_int8_t option,
  35                  const struct sk_buff *skb,
  36                  unsigned int protoff,
  37                  const struct dccp_hdr *dh,
  38                  bool *hotdrop)
  39 {
  40         /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
  41         const unsigned char *op;
  42         unsigned int optoff = __dccp_hdr_len(dh);
  43         unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
  44         unsigned int i;
  45 
  46         if (dh->dccph_doff * 4 < __dccp_hdr_len(dh))
  47                 goto invalid;
  48 
  49         if (!optlen)
  50                 return false;
  51 
  52         spin_lock_bh(&dccp_buflock);
  53         op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf);
  54         if (op == NULL) {
  55                 /* If we don't have the whole header, drop packet. */
  56                 goto partial;
  57         }
  58 
  59         for (i = 0; i < optlen; ) {
  60                 if (op[i] == option) {
  61                         spin_unlock_bh(&dccp_buflock);
  62                         return true;
  63                 }
  64 
  65                 if (op[i] < 2)
  66                         i++;
  67                 else
  68                         i += op[i+1]?:1;
  69         }
  70 
  71         spin_unlock_bh(&dccp_buflock);
  72         return false;
  73 
  74 partial:
  75         spin_unlock_bh(&dccp_buflock);
  76 invalid:
  77         *hotdrop = true;
  78         return false;
  79 }
  80 
  81 
  82 static inline bool
  83 match_types(const struct dccp_hdr *dh, u_int16_t typemask)
  84 {
  85         return typemask & (1 << dh->dccph_type);
  86 }
  87 
  88 static inline bool
  89 match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff,
  90              const struct dccp_hdr *dh, bool *hotdrop)
  91 {
  92         return dccp_find_option(option, skb, protoff, dh, hotdrop);
  93 }
  94 
  95 static bool
  96 dccp_mt(const struct sk_buff *skb, struct xt_action_param *par)
  97 {
  98         const struct xt_dccp_info *info = par->matchinfo;
  99         const struct dccp_hdr *dh;
 100         struct dccp_hdr _dh;
 101 
 102         if (par->fragoff != 0)
 103                 return false;
 104 
 105         dh = skb_header_pointer(skb, par->thoff, sizeof(_dh), &_dh);
 106         if (dh == NULL) {
 107                 par->hotdrop = true;
 108                 return false;
 109         }
 110 
 111         return  DCCHECK(ntohs(dh->dccph_sport) >= info->spts[0]
 112                         && ntohs(dh->dccph_sport) <= info->spts[1],
 113                         XT_DCCP_SRC_PORTS, info->flags, info->invflags)
 114                 && DCCHECK(ntohs(dh->dccph_dport) >= info->dpts[0]
 115                         && ntohs(dh->dccph_dport) <= info->dpts[1],
 116                         XT_DCCP_DEST_PORTS, info->flags, info->invflags)
 117                 && DCCHECK(match_types(dh, info->typemask),
 118                            XT_DCCP_TYPE, info->flags, info->invflags)
 119                 && DCCHECK(match_option(info->option, skb, par->thoff, dh,
 120                                         &par->hotdrop),
 121                            XT_DCCP_OPTION, info->flags, info->invflags);
 122 }
 123 
 124 static int dccp_mt_check(const struct xt_mtchk_param *par)
 125 {
 126         const struct xt_dccp_info *info = par->matchinfo;
 127 
 128         if (info->flags & ~XT_DCCP_VALID_FLAGS)
 129                 return -EINVAL;
 130         if (info->invflags & ~XT_DCCP_VALID_FLAGS)
 131                 return -EINVAL;
 132         if (info->invflags & ~info->flags)
 133                 return -EINVAL;
 134         return 0;
 135 }
 136 
 137 static struct xt_match dccp_mt_reg[] __read_mostly = {
 138         {
 139                 .name           = "dccp",
 140                 .family         = NFPROTO_IPV4,
 141                 .checkentry     = dccp_mt_check,
 142                 .match          = dccp_mt,
 143                 .matchsize      = sizeof(struct xt_dccp_info),
 144                 .proto          = IPPROTO_DCCP,
 145                 .me             = THIS_MODULE,
 146         },
 147         {
 148                 .name           = "dccp",
 149                 .family         = NFPROTO_IPV6,
 150                 .checkentry     = dccp_mt_check,
 151                 .match          = dccp_mt,
 152                 .matchsize      = sizeof(struct xt_dccp_info),
 153                 .proto          = IPPROTO_DCCP,
 154                 .me             = THIS_MODULE,
 155         },
 156 };
 157 
 158 static int __init dccp_mt_init(void)
 159 {
 160         int ret;
 161 
 162         /* doff is 8 bits, so the maximum option size is (4*256).  Don't put
 163          * this in BSS since DaveM is worried about locked TLB's for kernel
 164          * BSS. */
 165         dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
 166         if (!dccp_optbuf)
 167                 return -ENOMEM;
 168         ret = xt_register_matches(dccp_mt_reg, ARRAY_SIZE(dccp_mt_reg));
 169         if (ret)
 170                 goto out_kfree;
 171         return ret;
 172 
 173 out_kfree:
 174         kfree(dccp_optbuf);
 175         return ret;
 176 }
 177 
 178 static void __exit dccp_mt_exit(void)
 179 {
 180         xt_unregister_matches(dccp_mt_reg, ARRAY_SIZE(dccp_mt_reg));
 181         kfree(dccp_optbuf);
 182 }
 183 
 184 module_init(dccp_mt_init);
 185 module_exit(dccp_mt_exit);

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