linux/net/ipv4/netfilter/ipt_ecn.c
<<
>>
Prefs
   1/* IP tables module for matching the value of the IPv4 and TCP ECN bits
   2 *
   3 * (C) 2002 by Harald Welte <laforge@gnumonks.org>
   4 *
   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.
   8 */
   9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10#include <linux/in.h>
  11#include <linux/ip.h>
  12#include <net/ip.h>
  13#include <linux/module.h>
  14#include <linux/skbuff.h>
  15#include <linux/tcp.h>
  16
  17#include <linux/netfilter/x_tables.h>
  18#include <linux/netfilter_ipv4/ip_tables.h>
  19#include <linux/netfilter_ipv4/ipt_ecn.h>
  20
  21MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  22MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match for IPv4");
  23MODULE_LICENSE("GPL");
  24
  25static inline bool match_ip(const struct sk_buff *skb,
  26                            const struct ipt_ecn_info *einfo)
  27{
  28        return ((ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect) ^
  29               !!(einfo->invert & IPT_ECN_OP_MATCH_IP);
  30}
  31
  32static inline bool match_tcp(const struct sk_buff *skb,
  33                             const struct ipt_ecn_info *einfo,
  34                             bool *hotdrop)
  35{
  36        struct tcphdr _tcph;
  37        const struct tcphdr *th;
  38
  39        /* In practice, TCP match does this, so can't fail.  But let's
  40         * be good citizens.
  41         */
  42        th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
  43        if (th == NULL) {
  44                *hotdrop = false;
  45                return false;
  46        }
  47
  48        if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
  49                if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
  50                        if (th->ece == 1)
  51                                return false;
  52                } else {
  53                        if (th->ece == 0)
  54                                return false;
  55                }
  56        }
  57
  58        if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
  59                if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
  60                        if (th->cwr == 1)
  61                                return false;
  62                } else {
  63                        if (th->cwr == 0)
  64                                return false;
  65                }
  66        }
  67
  68        return true;
  69}
  70
  71static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par)
  72{
  73        const struct ipt_ecn_info *info = par->matchinfo;
  74
  75        if (info->operation & IPT_ECN_OP_MATCH_IP)
  76                if (!match_ip(skb, info))
  77                        return false;
  78
  79        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
  80                if (!match_tcp(skb, info, &par->hotdrop))
  81                        return false;
  82        }
  83
  84        return true;
  85}
  86
  87static int ecn_mt_check(const struct xt_mtchk_param *par)
  88{
  89        const struct ipt_ecn_info *info = par->matchinfo;
  90        const struct ipt_ip *ip = par->entryinfo;
  91
  92        if (info->operation & IPT_ECN_OP_MATCH_MASK)
  93                return -EINVAL;
  94
  95        if (info->invert & IPT_ECN_OP_MATCH_MASK)
  96                return -EINVAL;
  97
  98        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) &&
  99            (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
 100                pr_info("cannot match TCP bits in rule for non-tcp packets\n");
 101                return -EINVAL;
 102        }
 103
 104        return 0;
 105}
 106
 107static struct xt_match ecn_mt_reg __read_mostly = {
 108        .name           = "ecn",
 109        .family         = NFPROTO_IPV4,
 110        .match          = ecn_mt,
 111        .matchsize      = sizeof(struct ipt_ecn_info),
 112        .checkentry     = ecn_mt_check,
 113        .me             = THIS_MODULE,
 114};
 115
 116static int __init ecn_mt_init(void)
 117{
 118        return xt_register_match(&ecn_mt_reg);
 119}
 120
 121static void __exit ecn_mt_exit(void)
 122{
 123        xt_unregister_match(&ecn_mt_reg);
 124}
 125
 126module_init(ecn_mt_init);
 127module_exit(ecn_mt_exit);
 128