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
  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}
  30
  31static inline bool match_tcp(const struct sk_buff *skb,
  32                             const struct ipt_ecn_info *einfo,
  33                             bool *hotdrop)
  34{
  35        struct tcphdr _tcph;
  36        const struct tcphdr *th;
  37
  38        /* In practice, TCP match does this, so can't fail.  But let's
  39         * be good citizens.
  40         */
  41        th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
  42        if (th == NULL) {
  43                *hotdrop = false;
  44                return false;
  45        }
  46
  47        if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
  48                if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
  49                        if (th->ece == 1)
  50                                return false;
  51                } else {
  52                        if (th->ece == 0)
  53                                return false;
  54                }
  55        }
  56
  57        if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
  58                if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
  59                        if (th->cwr == 1)
  60                                return false;
  61                } else {
  62                        if (th->cwr == 0)
  63                                return false;
  64                }
  65        }
  66
  67        return true;
  68}
  69
  70static bool ecn_mt(const struct sk_buff *skb, const struct xt_match_param *par)
  71{
  72        const struct ipt_ecn_info *info = par->matchinfo;
  73
  74        if (info->operation & IPT_ECN_OP_MATCH_IP)
  75                if (!match_ip(skb, info))
  76                        return false;
  77
  78        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
  79                if (ip_hdr(skb)->protocol != IPPROTO_TCP)
  80                        return false;
  81                if (!match_tcp(skb, info, par->hotdrop))
  82                        return false;
  83        }
  84
  85        return true;
  86}
  87
  88static bool ecn_mt_check(const struct xt_mtchk_param *par)
  89{
  90        const struct ipt_ecn_info *info = par->matchinfo;
  91        const struct ipt_ip *ip = par->entryinfo;
  92
  93        if (info->operation & IPT_ECN_OP_MATCH_MASK)
  94                return false;
  95
  96        if (info->invert & IPT_ECN_OP_MATCH_MASK)
  97                return false;
  98
  99        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
 100            && ip->proto != IPPROTO_TCP) {
 101                printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
 102                       " non-tcp packets\n");
 103                return false;
 104        }
 105
 106        return true;
 107}
 108
 109static struct xt_match ecn_mt_reg __read_mostly = {
 110        .name           = "ecn",
 111        .family         = NFPROTO_IPV4,
 112        .match          = ecn_mt,
 113        .matchsize      = sizeof(struct ipt_ecn_info),
 114        .checkentry     = ecn_mt_check,
 115        .me             = THIS_MODULE,
 116};
 117
 118static int __init ecn_mt_init(void)
 119{
 120        return xt_register_match(&ecn_mt_reg);
 121}
 122
 123static void __exit ecn_mt_exit(void)
 124{
 125        xt_unregister_match(&ecn_mt_reg);
 126}
 127
 128module_init(ecn_mt_init);
 129module_exit(ecn_mt_exit);
 130