Blame view

net/netfilter/xt_cluster.c 4.91 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
2
3
  /*
   * (C) 2008-2009 Pablo Neira Ayuso <pablo@netfilter.org>
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
4
   */
8bee4bad0   Jan Engelhardt   netfilter: xt ext...
5
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
6
7
8
9
10
11
12
13
14
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/jhash.h>
  #include <linux/ip.h>
  #include <net/ipv6.h>
  
  #include <linux/netfilter/x_tables.h>
  #include <net/netfilter/nf_conntrack.h>
  #include <linux/netfilter/xt_cluster.h>
f9ffc3125   Patrick McHardy   netfilter: fix so...
15
  static inline u32 nf_ct_orig_ipv4_src(const struct nf_conn *ct)
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
16
  {
f9ffc3125   Patrick McHardy   netfilter: fix so...
17
  	return (__force u32)ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
18
  }
f9ffc3125   Patrick McHardy   netfilter: fix so...
19
  static inline const u32 *nf_ct_orig_ipv6_src(const struct nf_conn *ct)
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
20
  {
f9ffc3125   Patrick McHardy   netfilter: fix so...
21
  	return (__force u32 *)ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6;
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  }
  
  static inline u_int32_t
  xt_cluster_hash_ipv4(u_int32_t ip, const struct xt_cluster_match_info *info)
  {
  	return jhash_1word(ip, info->hash_seed);
  }
  
  static inline u_int32_t
  xt_cluster_hash_ipv6(const void *ip, const struct xt_cluster_match_info *info)
  {
  	return jhash2(ip, NF_CT_TUPLE_L3SIZE / sizeof(__u32), info->hash_seed);
  }
  
  static inline u_int32_t
  xt_cluster_hash(const struct nf_conn *ct,
  		const struct xt_cluster_match_info *info)
  {
  	u_int32_t hash = 0;
  
  	switch(nf_ct_l3num(ct)) {
  	case AF_INET:
  		hash = xt_cluster_hash_ipv4(nf_ct_orig_ipv4_src(ct), info);
  		break;
  	case AF_INET6:
  		hash = xt_cluster_hash_ipv6(nf_ct_orig_ipv6_src(ct), info);
  		break;
  	default:
  		WARN_ON(1);
  		break;
  	}
8fc54f689   Daniel Borkmann   net: use reciproc...
53
54
  
  	return reciprocal_scale(hash, info->total_nodes);
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
55
56
57
58
59
60
61
62
63
64
65
66
  }
  
  static inline bool
  xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
  {
  	bool is_multicast = false;
  
  	switch(family) {
  	case NFPROTO_IPV4:
  		is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr);
  		break;
  	case NFPROTO_IPV6:
580c7d9e4   Taehee Yoo   netfilter: xt_clu...
67
  		is_multicast = ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr);
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
68
69
70
71
72
73
74
75
76
  		break;
  	default:
  		WARN_ON(1);
  		break;
  	}
  	return is_multicast;
  }
  
  static bool
62fc80510   Jan Engelhardt   netfilter: xtable...
77
  xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par)
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  {
  	struct sk_buff *pskb = (struct sk_buff *)skb;
  	const struct xt_cluster_match_info *info = par->matchinfo;
  	const struct nf_conn *ct;
  	enum ip_conntrack_info ctinfo;
  	unsigned long hash;
  
  	/* This match assumes that all nodes see the same packets. This can be
  	 * achieved if the switch that connects the cluster nodes support some
  	 * sort of 'port mirroring'. However, if your switch does not support
  	 * this, your cluster nodes can reply ARP request using a multicast MAC
  	 * address. Thus, your switch will flood the same packets to the
  	 * cluster nodes with the same multicast MAC address. Using a multicast
  	 * link address is a RFC 1812 (section 3.3.2) violation, but this works
  	 * fine in practise.
  	 *
  	 * Unfortunately, if you use the multicast MAC address, the link layer
  	 * sets skbuff's pkt_type to PACKET_MULTICAST, which is not accepted
  	 * by TCP and others for packets coming to this node. For that reason,
  	 * this match mangles skbuff's pkt_type if it detects a packet
  	 * addressed to a unicast address but using PACKET_MULTICAST. Yes, I
  	 * know, matches should not alter packets, but we are doing this here
  	 * because we would need to add a PKTTYPE target for this sole purpose.
  	 */
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
102
  	if (!xt_cluster_is_multicast_addr(skb, xt_family(par)) &&
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
103
104
105
106
107
108
109
  	    skb->pkt_type == PACKET_MULTICAST) {
  	    	pskb->pkt_type = PACKET_HOST;
  	}
  
  	ct = nf_ct_get(skb, &ctinfo);
  	if (ct == NULL)
  		return false;
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
110
111
112
113
114
115
116
117
  	if (ct->master)
  		hash = xt_cluster_hash(ct->master, info);
  	else
  		hash = xt_cluster_hash(ct, info);
  
  	return !!((1 << hash) & info->node_mask) ^
  	       !!(info->flags & XT_CLUSTER_F_INV);
  }
b0f38452f   Jan Engelhardt   netfilter: xtable...
118
  static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
119
120
  {
  	struct xt_cluster_match_info *info = par->matchinfo;
c1dc29120   Martin Willi   netfilter: xt_clu...
121
  	int ret;
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
122

280f37afa   Pablo Neira Ayuso   netfilter: xt_clu...
123
  	if (info->total_nodes > XT_CLUSTER_NODES_MAX) {
b26066447   Florian Westphal   netfilter: x_tabl...
124
125
126
  		pr_info_ratelimited("you have exceeded the maximum number of cluster nodes (%u > %u)
  ",
  				    info->total_nodes, XT_CLUSTER_NODES_MAX);
bd414ee60   Jan Engelhardt   netfilter: xtable...
127
  		return -EINVAL;
280f37afa   Pablo Neira Ayuso   netfilter: xt_clu...
128
129
  	}
  	if (info->node_mask >= (1ULL << info->total_nodes)) {
b26066447   Florian Westphal   netfilter: x_tabl...
130
131
  		pr_info_ratelimited("node mask cannot exceed total number of nodes
  ");
4a5a5c73b   Jan Engelhardt   netfilter: xtable...
132
  		return -EDOM;
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
133
  	}
c1dc29120   Martin Willi   netfilter: xt_clu...
134
135
136
137
138
139
140
141
142
143
144
145
  
  	ret = nf_ct_netns_get(par->net, par->family);
  	if (ret < 0)
  		pr_info_ratelimited("cannot load conntrack support for proto=%u
  ",
  				    par->family);
  	return ret;
  }
  
  static void xt_cluster_mt_destroy(const struct xt_mtdtor_param *par)
  {
  	nf_ct_netns_put(par->net, par->family);
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
146
147
148
149
150
151
152
153
  }
  
  static struct xt_match xt_cluster_match __read_mostly = {
  	.name		= "cluster",
  	.family		= NFPROTO_UNSPEC,
  	.match		= xt_cluster_mt,
  	.checkentry	= xt_cluster_mt_checkentry,
  	.matchsize	= sizeof(struct xt_cluster_match_info),
c1dc29120   Martin Willi   netfilter: xt_clu...
154
  	.destroy	= xt_cluster_mt_destroy,
0269ea493   Pablo Neira Ayuso   netfilter: xtable...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  	.me		= THIS_MODULE,
  };
  
  static int __init xt_cluster_mt_init(void)
  {
  	return xt_register_match(&xt_cluster_match);
  }
  
  static void __exit xt_cluster_mt_fini(void)
  {
  	xt_unregister_match(&xt_cluster_match);
  }
  
  MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Xtables: hash-based cluster match");
  MODULE_ALIAS("ipt_cluster");
  MODULE_ALIAS("ip6t_cluster");
  module_init(xt_cluster_mt_init);
  module_exit(xt_cluster_mt_fini);