Commit d1992b169d31f339dc5ea4e9f312567c8cf322a3
Committed by
Pablo Neira Ayuso
1 parent
da2e852612
netfilter: xt_HMARK: fix endianness and provide consistent hashing
This patch addresses two issues: a) Fix usage of u32 and __be32 that causes endianess warnings via sparse. b) Ensure consistent hashing in a cluster that is composed of big and little endian systems. Thus, we obtain the same hash mark in an heterogeneous cluster. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Hans Schillstrom <hans@schillstrom.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Showing 2 changed files with 46 additions and 31 deletions Side-by-side Diff
include/linux/netfilter/xt_HMARK.h
net/netfilter/xt_HMARK.c
... | ... | @@ -32,13 +32,13 @@ |
32 | 32 | MODULE_ALIAS("ip6t_HMARK"); |
33 | 33 | |
34 | 34 | struct hmark_tuple { |
35 | - u32 src; | |
36 | - u32 dst; | |
35 | + __be32 src; | |
36 | + __be32 dst; | |
37 | 37 | union hmark_ports uports; |
38 | - uint8_t proto; | |
38 | + u8 proto; | |
39 | 39 | }; |
40 | 40 | |
41 | -static inline u32 hmark_addr6_mask(const __u32 *addr32, const __u32 *mask) | |
41 | +static inline __be32 hmark_addr6_mask(const __be32 *addr32, const __be32 *mask) | |
42 | 42 | { |
43 | 43 | return (addr32[0] & mask[0]) ^ |
44 | 44 | (addr32[1] & mask[1]) ^ |
... | ... | @@ -46,8 +46,8 @@ |
46 | 46 | (addr32[3] & mask[3]); |
47 | 47 | } |
48 | 48 | |
49 | -static inline u32 | |
50 | -hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask) | |
49 | +static inline __be32 | |
50 | +hmark_addr_mask(int l3num, const __be32 *addr32, const __be32 *mask) | |
51 | 51 | { |
52 | 52 | switch (l3num) { |
53 | 53 | case AF_INET: |
... | ... | @@ -58,6 +58,22 @@ |
58 | 58 | return 0; |
59 | 59 | } |
60 | 60 | |
61 | +static inline void hmark_swap_ports(union hmark_ports *uports, | |
62 | + const struct xt_hmark_info *info) | |
63 | +{ | |
64 | + union hmark_ports hp; | |
65 | + u16 src, dst; | |
66 | + | |
67 | + hp.b32 = (uports->b32 & info->port_mask.b32) | info->port_set.b32; | |
68 | + src = ntohs(hp.b16.src); | |
69 | + dst = ntohs(hp.b16.dst); | |
70 | + | |
71 | + if (dst > src) | |
72 | + uports->v32 = (dst << 16) | src; | |
73 | + else | |
74 | + uports->v32 = (src << 16) | dst; | |
75 | +} | |
76 | + | |
61 | 77 | static int |
62 | 78 | hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, |
63 | 79 | const struct xt_hmark_info *info) |
64 | 80 | |
... | ... | @@ -74,22 +90,19 @@ |
74 | 90 | otuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
75 | 91 | rtuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; |
76 | 92 | |
77 | - t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.all, | |
78 | - info->src_mask.all); | |
79 | - t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.all, | |
80 | - info->dst_mask.all); | |
93 | + t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.ip6, | |
94 | + info->src_mask.ip6); | |
95 | + t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.ip6, | |
96 | + info->dst_mask.ip6); | |
81 | 97 | |
82 | 98 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) |
83 | 99 | return 0; |
84 | 100 | |
85 | 101 | t->proto = nf_ct_protonum(ct); |
86 | 102 | if (t->proto != IPPROTO_ICMP) { |
87 | - t->uports.p16.src = otuple->src.u.all; | |
88 | - t->uports.p16.dst = rtuple->src.u.all; | |
89 | - t->uports.v32 = (t->uports.v32 & info->port_mask.v32) | | |
90 | - info->port_set.v32; | |
91 | - if (t->uports.p16.dst < t->uports.p16.src) | |
92 | - swap(t->uports.p16.dst, t->uports.p16.src); | |
103 | + t->uports.b16.src = otuple->src.u.all; | |
104 | + t->uports.b16.dst = rtuple->src.u.all; | |
105 | + hmark_swap_ports(&t->uports, info); | |
93 | 106 | } |
94 | 107 | |
95 | 108 | return 0; |
96 | 109 | |
97 | 110 | |
98 | 111 | |
... | ... | @@ -98,15 +111,19 @@ |
98 | 111 | #endif |
99 | 112 | } |
100 | 113 | |
114 | +/* This hash function is endian independent, to ensure consistent hashing if | |
115 | + * the cluster is composed of big and little endian systems. */ | |
101 | 116 | static inline u32 |
102 | 117 | hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info) |
103 | 118 | { |
104 | 119 | u32 hash; |
120 | + u32 src = ntohl(t->src); | |
121 | + u32 dst = ntohl(t->dst); | |
105 | 122 | |
106 | - if (t->dst < t->src) | |
107 | - swap(t->src, t->dst); | |
123 | + if (dst < src) | |
124 | + swap(src, dst); | |
108 | 125 | |
109 | - hash = jhash_3words(t->src, t->dst, t->uports.v32, info->hashrnd); | |
126 | + hash = jhash_3words(src, dst, t->uports.v32, info->hashrnd); | |
110 | 127 | hash = hash ^ (t->proto & info->proto_mask); |
111 | 128 | |
112 | 129 | return (((u64)hash * info->hmodulus) >> 32) + info->hoffset; |
... | ... | @@ -126,11 +143,7 @@ |
126 | 143 | if (skb_copy_bits(skb, nhoff, &t->uports, sizeof(t->uports)) < 0) |
127 | 144 | return; |
128 | 145 | |
129 | - t->uports.v32 = (t->uports.v32 & info->port_mask.v32) | | |
130 | - info->port_set.v32; | |
131 | - | |
132 | - if (t->uports.p16.dst < t->uports.p16.src) | |
133 | - swap(t->uports.p16.dst, t->uports.p16.src); | |
146 | + hmark_swap_ports(&t->uports, info); | |
134 | 147 | } |
135 | 148 | |
136 | 149 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) |
... | ... | @@ -178,8 +191,8 @@ |
178 | 191 | return -1; |
179 | 192 | } |
180 | 193 | noicmp: |
181 | - t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.all); | |
182 | - t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.all); | |
194 | + t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.ip6); | |
195 | + t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.ip6); | |
183 | 196 | |
184 | 197 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) |
185 | 198 | return 0; |
... | ... | @@ -255,11 +268,8 @@ |
255 | 268 | } |
256 | 269 | } |
257 | 270 | |
258 | - t->src = (__force u32) ip->saddr; | |
259 | - t->dst = (__force u32) ip->daddr; | |
260 | - | |
261 | - t->src &= info->src_mask.ip; | |
262 | - t->dst &= info->dst_mask.ip; | |
271 | + t->src = ip->saddr & info->src_mask.ip; | |
272 | + t->dst = ip->daddr & info->dst_mask.ip; | |
263 | 273 | |
264 | 274 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) |
265 | 275 | return 0; |