aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/Kbuild1
-rw-r--r--include/linux/netfilter/xt_ipvs.h27
-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
6 files changed, 229 insertions, 0 deletions
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index b93b64dc9fae..0cb62c857187 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -31,6 +31,7 @@ header-y += xt_dscp.h
31header-y += xt_esp.h 31header-y += xt_esp.h
32header-y += xt_hashlimit.h 32header-y += xt_hashlimit.h
33header-y += xt_iprange.h 33header-y += xt_iprange.h
34header-y += xt_ipvs.h
34header-y += xt_helper.h 35header-y += xt_helper.h
35header-y += xt_length.h 36header-y += xt_length.h
36header-y += xt_limit.h 37header-y += xt_limit.h
diff --git a/include/linux/netfilter/xt_ipvs.h b/include/linux/netfilter/xt_ipvs.h
new file mode 100644
index 000000000000..1167aeb7a347
--- /dev/null
+++ b/include/linux/netfilter/xt_ipvs.h
@@ -0,0 +1,27 @@
1#ifndef _XT_IPVS_H
2#define _XT_IPVS_H
3
4enum {
5 XT_IPVS_IPVS_PROPERTY = 1 << 0, /* all other options imply this one */
6 XT_IPVS_PROTO = 1 << 1,
7 XT_IPVS_VADDR = 1 << 2,
8 XT_IPVS_VPORT = 1 << 3,
9 XT_IPVS_DIR = 1 << 4,
10 XT_IPVS_METHOD = 1 << 5,
11 XT_IPVS_VPORTCTL = 1 << 6,
12 XT_IPVS_MASK = (1 << 7) - 1,
13 XT_IPVS_ONCE_MASK = XT_IPVS_MASK & ~XT_IPVS_IPVS_PROPERTY
14};
15
16struct xt_ipvs_mtinfo {
17 union nf_inet_addr vaddr, vmask;
18 __be16 vport;
19 __u8 l4proto;
20 __u8 fwd_method;
21 __be16 vportctl;
22
23 __u8 invert;
24 __u8 bitmask;
25};
26
27#endif /* _XT_IPVS_H */
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);