aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHannes Eder <heder@google.com>2010-07-23 06:42:58 -0400
committerPatrick McHardy <kaber@trash.net>2010-07-23 06:42:58 -0400
commit9c3e1c39679144c250dda95098333ecb5f1f407a (patch)
tree3a734fdf60ff07d46a14cbc0a67c134e6cfe0e80 /net
parent22cb516696304a9b85892b18c483a27d97cfa51b (diff)
netfilter: xt_ipvs (netfilter matcher for IPVS)
This implements the kernel-space side of the netfilter matcher xt_ipvs. [ minor fixes by Simon Horman <horms@verge.net.au> ] Signed-off-by: Hannes Eder <heder@google.com> Signed-off-by: Simon Horman <horms@verge.net.au> [ Patrick: added xt_ipvs.h to Kbuild ] Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/Kconfig10
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c1
-rw-r--r--net/netfilter/xt_ipvs.c189
4 files changed, 201 insertions, 0 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 5fb8efa84df3..551b58419df9 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -742,6 +742,16 @@ config NETFILTER_XT_MATCH_IPRANGE
742 742
743 If unsure, say M. 743 If unsure, say M.
744 744
745config NETFILTER_XT_MATCH_IPVS
746 tristate '"ipvs" match support'
747 depends on IP_VS
748 depends on NETFILTER_ADVANCED
749 depends on NF_CONNTRACK
750 help
751 This option allows you to match against IPVS properties of a packet.
752
753 If unsure, say N.
754
745config NETFILTER_XT_MATCH_LENGTH 755config NETFILTER_XT_MATCH_LENGTH
746 tristate '"length" match support' 756 tristate '"length" match support'
747 depends on NETFILTER_ADVANCED 757 depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 36ef8e63be1e..4366c79a6683 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
77obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o 77obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
78obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o 78obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
79obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o 79obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
80obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
80obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o 81obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
81obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o 82obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
82obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o 83obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 2d3d5e4b35f8..027f654799fe 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -98,6 +98,7 @@ struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto)
98 98
99 return NULL; 99 return NULL;
100} 100}
101EXPORT_SYMBOL(ip_vs_proto_get);
101 102
102 103
103/* 104/*
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c
new file mode 100644
index 000000000000..7a4d66db95ae
--- /dev/null
+++ b/net/netfilter/xt_ipvs.c
@@ -0,0 +1,189 @@
1/*
2 * xt_ipvs - kernel module to match IPVS connection properties
3 *
4 * Author: Hannes Eder <heder@google.com>
5 */
6
7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
9#include <linux/module.h>
10#include <linux/moduleparam.h>
11#include <linux/spinlock.h>
12#include <linux/skbuff.h>
13#ifdef CONFIG_IP_VS_IPV6
14#include <net/ipv6.h>
15#endif
16#include <linux/ip_vs.h>
17#include <linux/types.h>
18#include <linux/netfilter/x_tables.h>
19#include <linux/netfilter/x_tables.h>
20#include <linux/netfilter/xt_ipvs.h>
21#include <net/netfilter/nf_conntrack.h>
22
23#include <net/ip_vs.h>
24
25MODULE_AUTHOR("Hannes Eder <heder@google.com>");
26MODULE_DESCRIPTION("Xtables: match IPVS connection properties");
27MODULE_LICENSE("GPL");
28MODULE_ALIAS("ipt_ipvs");
29MODULE_ALIAS("ip6t_ipvs");
30
31/* borrowed from xt_conntrack */
32static bool ipvs_mt_addrcmp(const union nf_inet_addr *kaddr,
33 const union nf_inet_addr *uaddr,
34 const union nf_inet_addr *umask,
35 unsigned int l3proto)
36{
37 if (l3proto == NFPROTO_IPV4)
38 return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
39#ifdef CONFIG_IP_VS_IPV6
40 else if (l3proto == NFPROTO_IPV6)
41 return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
42 &uaddr->in6) == 0;
43#endif
44 else
45 return false;
46}
47
48static bool
49ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)
50{
51 const struct xt_ipvs_mtinfo *data = par->matchinfo;
52 /* ipvs_mt_check ensures that family is only NFPROTO_IPV[46]. */
53 const u_int8_t family = par->family;
54 struct ip_vs_iphdr iph;
55 struct ip_vs_protocol *pp;
56 struct ip_vs_conn *cp;
57 bool match = true;
58
59 if (data->bitmask == XT_IPVS_IPVS_PROPERTY) {
60 match = skb->ipvs_property ^
61 !!(data->invert & XT_IPVS_IPVS_PROPERTY);
62 goto out;
63 }
64
65 /* other flags than XT_IPVS_IPVS_PROPERTY are set */
66 if (!skb->ipvs_property) {
67 match = false;
68 goto out;
69 }
70
71 ip_vs_fill_iphdr(family, skb_network_header(skb), &iph);
72
73 if (data->bitmask & XT_IPVS_PROTO)
74 if ((iph.protocol == data->l4proto) ^
75 !(data->invert & XT_IPVS_PROTO)) {
76 match = false;
77 goto out;
78 }
79
80 pp = ip_vs_proto_get(iph.protocol);
81 if (unlikely(!pp)) {
82 match = false;
83 goto out;
84 }
85
86 /*
87 * Check if the packet belongs to an existing entry
88 */
89 cp = pp->conn_out_get(family, skb, pp, &iph, iph.len, 1 /* inverse */);
90 if (unlikely(cp == NULL)) {
91 match = false;
92 goto out;
93 }
94
95 /*
96 * We found a connection, i.e. ct != 0, make sure to call
97 * __ip_vs_conn_put before returning. In our case jump to out_put_con.
98 */
99
100 if (data->bitmask & XT_IPVS_VPORT)
101 if ((cp->vport == data->vport) ^
102 !(data->invert & XT_IPVS_VPORT)) {
103 match = false;
104 goto out_put_cp;
105 }
106
107 if (data->bitmask & XT_IPVS_VPORTCTL)
108 if ((cp->control != NULL &&
109 cp->control->vport == data->vportctl) ^
110 !(data->invert & XT_IPVS_VPORTCTL)) {
111 match = false;
112 goto out_put_cp;
113 }
114
115 if (data->bitmask & XT_IPVS_DIR) {
116 enum ip_conntrack_info ctinfo;
117 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
118
119 if (ct == NULL || nf_ct_is_untracked(ct)) {
120 match = false;
121 goto out_put_cp;
122 }
123
124 if ((ctinfo >= IP_CT_IS_REPLY) ^
125 !!(data->invert & XT_IPVS_DIR)) {
126 match = false;
127 goto out_put_cp;
128 }
129 }
130
131 if (data->bitmask & XT_IPVS_METHOD)
132 if (((cp->flags & IP_VS_CONN_F_FWD_MASK) == data->fwd_method) ^
133 !(data->invert & XT_IPVS_METHOD)) {
134 match = false;
135 goto out_put_cp;
136 }
137
138 if (data->bitmask & XT_IPVS_VADDR) {
139 if (ipvs_mt_addrcmp(&cp->vaddr, &data->vaddr,
140 &data->vmask, family) ^
141 !(data->invert & XT_IPVS_VADDR)) {
142 match = false;
143 goto out_put_cp;
144 }
145 }
146
147out_put_cp:
148 __ip_vs_conn_put(cp);
149out:
150 pr_debug("match=%d\n", match);
151 return match;
152}
153
154static int ipvs_mt_check(const struct xt_mtchk_param *par)
155{
156 if (par->family != NFPROTO_IPV4
157#ifdef CONFIG_IP_VS_IPV6
158 && par->family != NFPROTO_IPV6
159#endif
160 ) {
161 pr_info("protocol family %u not supported\n", par->family);
162 return -EINVAL;
163 }
164
165 return 0;
166}
167
168static struct xt_match xt_ipvs_mt_reg __read_mostly = {
169 .name = "ipvs",
170 .revision = 0,
171 .family = NFPROTO_UNSPEC,
172 .match = ipvs_mt,
173 .checkentry = ipvs_mt_check,
174 .matchsize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
175 .me = THIS_MODULE,
176};
177
178static int __init ipvs_mt_init(void)
179{
180 return xt_register_match(&xt_ipvs_mt_reg);
181}
182
183static void __exit ipvs_mt_exit(void)
184{
185 xt_unregister_match(&xt_ipvs_mt_reg);
186}
187
188module_init(ipvs_mt_init);
189module_exit(ipvs_mt_exit);