2 * xt_HMARK - Netfilter module to set mark by means of hashing
4 * (C) 2012 by Hans Schillstrom <hans.schillstrom@ericsson.com>
5 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
12 #include <linux/module.h>
13 #include <linux/skbuff.h>
14 #include <linux/icmp.h>
16 #include <linux/netfilter/x_tables.h>
17 #include <linux/netfilter/xt_HMARK.h>
20 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
21 #include <net/netfilter/nf_conntrack.h>
23 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
25 #include <linux/netfilter_ipv6/ip6_tables.h>
28 MODULE_LICENSE("GPL");
29 MODULE_AUTHOR("Hans Schillstrom <hans.schillstrom@ericsson.com>");
30 MODULE_DESCRIPTION("Xtables: packet marking using hash calculation");
31 MODULE_ALIAS("ipt_HMARK");
32 MODULE_ALIAS("ip6t_HMARK");
37 union hmark_ports uports
;
41 static inline __be32
hmark_addr6_mask(const __be32
*addr32
, const __be32
*mask
)
43 return (addr32
[0] & mask
[0]) ^
44 (addr32
[1] & mask
[1]) ^
45 (addr32
[2] & mask
[2]) ^
46 (addr32
[3] & mask
[3]);
50 hmark_addr_mask(int l3num
, const __be32
*addr32
, const __be32
*mask
)
54 return *addr32
& *mask
;
56 return hmark_addr6_mask(addr32
, mask
);
61 static inline void hmark_swap_ports(union hmark_ports
*uports
,
62 const struct xt_hmark_info
*info
)
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
);
72 uports
->v32
= (dst
<< 16) | src
;
74 uports
->v32
= (src
<< 16) | dst
;
78 hmark_ct_set_htuple(const struct sk_buff
*skb
, struct hmark_tuple
*t
,
79 const struct xt_hmark_info
*info
)
81 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
82 enum ip_conntrack_info ctinfo
;
83 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
84 struct nf_conntrack_tuple
*otuple
;
85 struct nf_conntrack_tuple
*rtuple
;
87 if (ct
== NULL
|| nf_ct_is_untracked(ct
))
90 otuple
= &ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
;
91 rtuple
= &ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
;
93 t
->src
= hmark_addr_mask(otuple
->src
.l3num
, otuple
->src
.u3
.ip6
,
95 t
->dst
= hmark_addr_mask(otuple
->src
.l3num
, rtuple
->src
.u3
.ip6
,
98 if (info
->flags
& XT_HMARK_FLAG(XT_HMARK_METHOD_L3
))
101 t
->proto
= nf_ct_protonum(ct
);
102 if (t
->proto
!= IPPROTO_ICMP
) {
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
);
114 /* This hash function is endian independent, to ensure consistent hashing if
115 * the cluster is composed of big and little endian systems. */
117 hmark_hash(struct hmark_tuple
*t
, const struct xt_hmark_info
*info
)
120 u32 src
= ntohl(t
->src
);
121 u32 dst
= ntohl(t
->dst
);
126 hash
= jhash_3words(src
, dst
, t
->uports
.v32
, info
->hashrnd
);
127 hash
= hash
^ (t
->proto
& info
->proto_mask
);
129 return reciprocal_scale(hash
, info
->hmodulus
) + info
->hoffset
;
133 hmark_set_tuple_ports(const struct sk_buff
*skb
, unsigned int nhoff
,
134 struct hmark_tuple
*t
, const struct xt_hmark_info
*info
)
138 protoff
= proto_ports_offset(t
->proto
);
143 if (skb_copy_bits(skb
, nhoff
, &t
->uports
, sizeof(t
->uports
)) < 0)
146 hmark_swap_ports(&t
->uports
, info
);
149 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
150 static int get_inner6_hdr(const struct sk_buff
*skb
, int *offset
)
152 struct icmp6hdr
*icmp6h
, _ih6
;
154 icmp6h
= skb_header_pointer(skb
, *offset
, sizeof(_ih6
), &_ih6
);
158 if (icmp6h
->icmp6_type
&& icmp6h
->icmp6_type
< 128) {
159 *offset
+= sizeof(struct icmp6hdr
);
166 hmark_pkt_set_htuple_ipv6(const struct sk_buff
*skb
, struct hmark_tuple
*t
,
167 const struct xt_hmark_info
*info
)
169 struct ipv6hdr
*ip6
, _ip6
;
170 int flag
= IP6_FH_F_AUTH
;
171 unsigned int nhoff
= 0;
175 ip6
= (struct ipv6hdr
*) (skb
->data
+ skb_network_offset(skb
));
176 nexthdr
= ipv6_find_hdr(skb
, &nhoff
, -1, &fragoff
, &flag
);
179 /* No need to check for icmp errors on fragments */
180 if ((flag
& IP6_FH_F_FRAG
) || (nexthdr
!= IPPROTO_ICMPV6
))
182 /* Use inner header in case of ICMP errors */
183 if (get_inner6_hdr(skb
, &nhoff
)) {
184 ip6
= skb_header_pointer(skb
, nhoff
, sizeof(_ip6
), &_ip6
);
187 /* If AH present, use SPI like in ESP. */
188 flag
= IP6_FH_F_AUTH
;
189 nexthdr
= ipv6_find_hdr(skb
, &nhoff
, -1, &fragoff
, &flag
);
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
);
197 if (info
->flags
& XT_HMARK_FLAG(XT_HMARK_METHOD_L3
))
201 if (t
->proto
== IPPROTO_ICMPV6
)
204 if (flag
& IP6_FH_F_FRAG
)
207 hmark_set_tuple_ports(skb
, nhoff
, t
, info
);
212 hmark_tg_v6(struct sk_buff
*skb
, const struct xt_action_param
*par
)
214 const struct xt_hmark_info
*info
= par
->targinfo
;
215 struct hmark_tuple t
;
217 memset(&t
, 0, sizeof(struct hmark_tuple
));
219 if (info
->flags
& XT_HMARK_FLAG(XT_HMARK_CT
)) {
220 if (hmark_ct_set_htuple(skb
, &t
, info
) < 0)
223 if (hmark_pkt_set_htuple_ipv6(skb
, &t
, info
) < 0)
227 skb
->mark
= hmark_hash(&t
, info
);
232 static int get_inner_hdr(const struct sk_buff
*skb
, int iphsz
, int *nhoff
)
234 const struct icmphdr
*icmph
;
237 /* Not enough header? */
238 icmph
= skb_header_pointer(skb
, *nhoff
+ iphsz
, sizeof(_ih
), &_ih
);
239 if (icmph
== NULL
|| icmph
->type
> NR_ICMP_TYPES
)
243 if (icmph
->type
!= ICMP_DEST_UNREACH
&&
244 icmph
->type
!= ICMP_SOURCE_QUENCH
&&
245 icmph
->type
!= ICMP_TIME_EXCEEDED
&&
246 icmph
->type
!= ICMP_PARAMETERPROB
&&
247 icmph
->type
!= ICMP_REDIRECT
)
250 *nhoff
+= iphsz
+ sizeof(_ih
);
255 hmark_pkt_set_htuple_ipv4(const struct sk_buff
*skb
, struct hmark_tuple
*t
,
256 const struct xt_hmark_info
*info
)
258 struct iphdr
*ip
, _ip
;
259 int nhoff
= skb_network_offset(skb
);
261 ip
= (struct iphdr
*) (skb
->data
+ nhoff
);
262 if (ip
->protocol
== IPPROTO_ICMP
) {
263 /* Use inner header in case of ICMP errors */
264 if (get_inner_hdr(skb
, ip
->ihl
* 4, &nhoff
)) {
265 ip
= skb_header_pointer(skb
, nhoff
, sizeof(_ip
), &_ip
);
271 t
->src
= ip
->saddr
& info
->src_mask
.ip
;
272 t
->dst
= ip
->daddr
& info
->dst_mask
.ip
;
274 if (info
->flags
& XT_HMARK_FLAG(XT_HMARK_METHOD_L3
))
277 t
->proto
= ip
->protocol
;
279 /* ICMP has no ports, skip */
280 if (t
->proto
== IPPROTO_ICMP
)
283 /* follow-up fragments don't contain ports, skip all fragments */
284 if (ip
->frag_off
& htons(IP_MF
| IP_OFFSET
))
287 hmark_set_tuple_ports(skb
, (ip
->ihl
* 4) + nhoff
, t
, info
);
293 hmark_tg_v4(struct sk_buff
*skb
, const struct xt_action_param
*par
)
295 const struct xt_hmark_info
*info
= par
->targinfo
;
296 struct hmark_tuple t
;
298 memset(&t
, 0, sizeof(struct hmark_tuple
));
300 if (info
->flags
& XT_HMARK_FLAG(XT_HMARK_CT
)) {
301 if (hmark_ct_set_htuple(skb
, &t
, info
) < 0)
304 if (hmark_pkt_set_htuple_ipv4(skb
, &t
, info
) < 0)
308 skb
->mark
= hmark_hash(&t
, info
);
312 static int hmark_tg_check(const struct xt_tgchk_param
*par
)
314 const struct xt_hmark_info
*info
= par
->targinfo
;
316 if (!info
->hmodulus
) {
317 pr_info("xt_HMARK: hash modulus can't be zero\n");
320 if (info
->proto_mask
&&
321 (info
->flags
& XT_HMARK_FLAG(XT_HMARK_METHOD_L3
))) {
322 pr_info("xt_HMARK: proto mask must be zero with L3 mode\n");
325 if (info
->flags
& XT_HMARK_FLAG(XT_HMARK_SPI_MASK
) &&
326 (info
->flags
& (XT_HMARK_FLAG(XT_HMARK_SPORT_MASK
) |
327 XT_HMARK_FLAG(XT_HMARK_DPORT_MASK
)))) {
328 pr_info("xt_HMARK: spi-mask and port-mask can't be combined\n");
331 if (info
->flags
& XT_HMARK_FLAG(XT_HMARK_SPI
) &&
332 (info
->flags
& (XT_HMARK_FLAG(XT_HMARK_SPORT
) |
333 XT_HMARK_FLAG(XT_HMARK_DPORT
)))) {
334 pr_info("xt_HMARK: spi-set and port-set can't be combined\n");
340 static struct xt_target hmark_tg_reg
[] __read_mostly
= {
343 .family
= NFPROTO_IPV4
,
344 .target
= hmark_tg_v4
,
345 .targetsize
= sizeof(struct xt_hmark_info
),
346 .checkentry
= hmark_tg_check
,
349 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
352 .family
= NFPROTO_IPV6
,
353 .target
= hmark_tg_v6
,
354 .targetsize
= sizeof(struct xt_hmark_info
),
355 .checkentry
= hmark_tg_check
,
361 static int __init
hmark_tg_init(void)
363 return xt_register_targets(hmark_tg_reg
, ARRAY_SIZE(hmark_tg_reg
));
366 static void __exit
hmark_tg_exit(void)
368 xt_unregister_targets(hmark_tg_reg
, ARRAY_SIZE(hmark_tg_reg
));
371 module_init(hmark_tg_init
);
372 module_exit(hmark_tg_exit
);