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