root/net/netfilter/xt_ecn.c

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

DEFINITIONS

This source file includes following definitions.
  1. match_tcp
  2. match_ip
  3. ecn_mt4
  4. ecn_mt_check4
  5. match_ipv6
  6. ecn_mt6
  7. ecn_mt_check6
  8. ecn_mt_init
  9. ecn_mt_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Xtables module for matching the value of the IPv4/IPv6 and TCP ECN bits
   4  *
   5  * (C) 2002 by Harald Welte <laforge@gnumonks.org>
   6  * (C) 2011 Patrick McHardy <kaber@trash.net>
   7  */
   8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9 #include <linux/in.h>
  10 #include <linux/ip.h>
  11 #include <net/ip.h>
  12 #include <linux/module.h>
  13 #include <linux/skbuff.h>
  14 #include <linux/tcp.h>
  15 
  16 #include <linux/netfilter/x_tables.h>
  17 #include <linux/netfilter/xt_ecn.h>
  18 #include <linux/netfilter_ipv4/ip_tables.h>
  19 #include <linux/netfilter_ipv6/ip6_tables.h>
  20 
  21 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  22 MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match");
  23 MODULE_LICENSE("GPL");
  24 MODULE_ALIAS("ipt_ecn");
  25 MODULE_ALIAS("ip6t_ecn");
  26 
  27 static bool match_tcp(const struct sk_buff *skb, struct xt_action_param *par)
  28 {
  29         const struct xt_ecn_info *einfo = par->matchinfo;
  30         struct tcphdr _tcph;
  31         const struct tcphdr *th;
  32 
  33         /* In practice, TCP match does this, so can't fail.  But let's
  34          * be good citizens.
  35          */
  36         th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
  37         if (th == NULL)
  38                 return false;
  39 
  40         if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
  41                 if (einfo->invert & XT_ECN_OP_MATCH_ECE) {
  42                         if (th->ece == 1)
  43                                 return false;
  44                 } else {
  45                         if (th->ece == 0)
  46                                 return false;
  47                 }
  48         }
  49 
  50         if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
  51                 if (einfo->invert & XT_ECN_OP_MATCH_CWR) {
  52                         if (th->cwr == 1)
  53                                 return false;
  54                 } else {
  55                         if (th->cwr == 0)
  56                                 return false;
  57                 }
  58         }
  59 
  60         return true;
  61 }
  62 
  63 static inline bool match_ip(const struct sk_buff *skb,
  64                             const struct xt_ecn_info *einfo)
  65 {
  66         return ((ip_hdr(skb)->tos & XT_ECN_IP_MASK) == einfo->ip_ect) ^
  67                !!(einfo->invert & XT_ECN_OP_MATCH_IP);
  68 }
  69 
  70 static bool ecn_mt4(const struct sk_buff *skb, struct xt_action_param *par)
  71 {
  72         const struct xt_ecn_info *info = par->matchinfo;
  73 
  74         if (info->operation & XT_ECN_OP_MATCH_IP && !match_ip(skb, info))
  75                 return false;
  76 
  77         if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  78             !match_tcp(skb, par))
  79                 return false;
  80 
  81         return true;
  82 }
  83 
  84 static int ecn_mt_check4(const struct xt_mtchk_param *par)
  85 {
  86         const struct xt_ecn_info *info = par->matchinfo;
  87         const struct ipt_ip *ip = par->entryinfo;
  88 
  89         if (info->operation & XT_ECN_OP_MATCH_MASK)
  90                 return -EINVAL;
  91 
  92         if (info->invert & XT_ECN_OP_MATCH_MASK)
  93                 return -EINVAL;
  94 
  95         if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  96             (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
  97                 pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n");
  98                 return -EINVAL;
  99         }
 100 
 101         return 0;
 102 }
 103 
 104 static inline bool match_ipv6(const struct sk_buff *skb,
 105                               const struct xt_ecn_info *einfo)
 106 {
 107         return (((ipv6_hdr(skb)->flow_lbl[0] >> 4) & XT_ECN_IP_MASK) ==
 108                 einfo->ip_ect) ^
 109                !!(einfo->invert & XT_ECN_OP_MATCH_IP);
 110 }
 111 
 112 static bool ecn_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 113 {
 114         const struct xt_ecn_info *info = par->matchinfo;
 115 
 116         if (info->operation & XT_ECN_OP_MATCH_IP && !match_ipv6(skb, info))
 117                 return false;
 118 
 119         if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
 120             !match_tcp(skb, par))
 121                 return false;
 122 
 123         return true;
 124 }
 125 
 126 static int ecn_mt_check6(const struct xt_mtchk_param *par)
 127 {
 128         const struct xt_ecn_info *info = par->matchinfo;
 129         const struct ip6t_ip6 *ip = par->entryinfo;
 130 
 131         if (info->operation & XT_ECN_OP_MATCH_MASK)
 132                 return -EINVAL;
 133 
 134         if (info->invert & XT_ECN_OP_MATCH_MASK)
 135                 return -EINVAL;
 136 
 137         if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
 138             (ip->proto != IPPROTO_TCP || ip->invflags & IP6T_INV_PROTO)) {
 139                 pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n");
 140                 return -EINVAL;
 141         }
 142 
 143         return 0;
 144 }
 145 
 146 static struct xt_match ecn_mt_reg[] __read_mostly = {
 147         {
 148                 .name           = "ecn",
 149                 .family         = NFPROTO_IPV4,
 150                 .match          = ecn_mt4,
 151                 .matchsize      = sizeof(struct xt_ecn_info),
 152                 .checkentry     = ecn_mt_check4,
 153                 .me             = THIS_MODULE,
 154         },
 155         {
 156                 .name           = "ecn",
 157                 .family         = NFPROTO_IPV6,
 158                 .match          = ecn_mt6,
 159                 .matchsize      = sizeof(struct xt_ecn_info),
 160                 .checkentry     = ecn_mt_check6,
 161                 .me             = THIS_MODULE,
 162         },
 163 };
 164 
 165 static int __init ecn_mt_init(void)
 166 {
 167         return xt_register_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
 168 }
 169 
 170 static void __exit ecn_mt_exit(void)
 171 {
 172         xt_unregister_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
 173 }
 174 
 175 module_init(ecn_mt_init);
 176 module_exit(ecn_mt_exit);

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