2 * Copyright (C)2004 USAGI/WIDE Project
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
9 * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
12 #include <linux/types.h>
13 #include <linux/ipv6.h>
14 #include <linux/in6.h>
15 #include <linux/netfilter.h>
16 #include <linux/module.h>
17 #include <linux/skbuff.h>
18 #include <linux/icmp.h>
20 #include <net/inet_frag.h>
22 #include <linux/netfilter_bridge.h>
23 #include <linux/netfilter_ipv6.h>
24 #include <linux/netfilter_ipv6/ip6_tables.h>
25 #include <net/netfilter/nf_conntrack.h>
26 #include <net/netfilter/nf_conntrack_helper.h>
27 #include <net/netfilter/nf_conntrack_l4proto.h>
28 #include <net/netfilter/nf_conntrack_l3proto.h>
29 #include <net/netfilter/nf_conntrack_core.h>
30 #include <net/netfilter/nf_conntrack_zones.h>
31 #include <net/netfilter/nf_conntrack_seqadj.h>
32 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
33 #include <net/netfilter/nf_nat_helper.h>
34 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
35 #include <net/netfilter/nf_log.h>
37 static int conntrack6_net_id
;
38 static DEFINE_MUTEX(register_ipv6_hooks
);
40 struct conntrack6_net
{
44 static bool ipv6_pkt_to_tuple(const struct sk_buff
*skb
, unsigned int nhoff
,
45 struct nf_conntrack_tuple
*tuple
)
50 ap
= skb_header_pointer(skb
, nhoff
+ offsetof(struct ipv6hdr
, saddr
),
51 sizeof(_addrs
), _addrs
);
55 memcpy(tuple
->src
.u3
.ip6
, ap
, sizeof(tuple
->src
.u3
.ip6
));
56 memcpy(tuple
->dst
.u3
.ip6
, ap
+ 4, sizeof(tuple
->dst
.u3
.ip6
));
61 static bool ipv6_invert_tuple(struct nf_conntrack_tuple
*tuple
,
62 const struct nf_conntrack_tuple
*orig
)
64 memcpy(tuple
->src
.u3
.ip6
, orig
->dst
.u3
.ip6
, sizeof(tuple
->src
.u3
.ip6
));
65 memcpy(tuple
->dst
.u3
.ip6
, orig
->src
.u3
.ip6
, sizeof(tuple
->dst
.u3
.ip6
));
70 static void ipv6_print_tuple(struct seq_file
*s
,
71 const struct nf_conntrack_tuple
*tuple
)
73 seq_printf(s
, "src=%pI6 dst=%pI6 ",
74 tuple
->src
.u3
.ip6
, tuple
->dst
.u3
.ip6
);
77 static int ipv6_get_l4proto(const struct sk_buff
*skb
, unsigned int nhoff
,
78 unsigned int *dataoff
, u_int8_t
*protonum
)
80 unsigned int extoff
= nhoff
+ sizeof(struct ipv6hdr
);
85 if (skb_copy_bits(skb
, nhoff
+ offsetof(struct ipv6hdr
, nexthdr
),
86 &nexthdr
, sizeof(nexthdr
)) != 0) {
87 pr_debug("ip6_conntrack_core: can't get nexthdr\n");
90 protoff
= ipv6_skip_exthdr(skb
, extoff
, &nexthdr
, &frag_off
);
92 * (protoff == skb->len) means the packet has not data, just
93 * IPv6 and possibly extensions headers, but it is tracked anyway
95 if (protoff
< 0 || (frag_off
& htons(~0x7)) != 0) {
96 pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
105 static unsigned int ipv6_helper(void *priv
,
107 const struct nf_hook_state
*state
)
110 const struct nf_conn_help
*help
;
111 const struct nf_conntrack_helper
*helper
;
112 enum ip_conntrack_info ctinfo
;
117 /* This is where we call the helper: as the packet goes out. */
118 ct
= nf_ct_get(skb
, &ctinfo
);
119 if (!ct
|| ctinfo
== IP_CT_RELATED_REPLY
)
122 help
= nfct_help(ct
);
125 /* rcu_read_lock()ed by nf_hook_thresh */
126 helper
= rcu_dereference(help
->helper
);
130 nexthdr
= ipv6_hdr(skb
)->nexthdr
;
131 protoff
= ipv6_skip_exthdr(skb
, sizeof(struct ipv6hdr
), &nexthdr
,
133 if (protoff
< 0 || (frag_off
& htons(~0x7)) != 0) {
134 pr_debug("proto header not found\n");
138 return helper
->help(skb
, protoff
, ct
, ctinfo
);
141 static unsigned int ipv6_confirm(void *priv
,
143 const struct nf_hook_state
*state
)
146 enum ip_conntrack_info ctinfo
;
147 unsigned char pnum
= ipv6_hdr(skb
)->nexthdr
;
151 ct
= nf_ct_get(skb
, &ctinfo
);
152 if (!ct
|| ctinfo
== IP_CT_RELATED_REPLY
)
155 protoff
= ipv6_skip_exthdr(skb
, sizeof(struct ipv6hdr
), &pnum
,
157 if (protoff
< 0 || (frag_off
& htons(~0x7)) != 0) {
158 pr_debug("proto header not found\n");
162 /* adjust seqs for loopback traffic only in outgoing direction */
163 if (test_bit(IPS_SEQ_ADJUST_BIT
, &ct
->status
) &&
164 !nf_is_loopback_packet(skb
)) {
165 if (!nf_ct_seq_adjust(skb
, ct
, ctinfo
, protoff
)) {
166 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct
), drop
);
171 /* We've seen it coming out the other side: confirm it */
172 return nf_conntrack_confirm(skb
);
175 static unsigned int ipv6_conntrack_in(void *priv
,
177 const struct nf_hook_state
*state
)
179 return nf_conntrack_in(state
->net
, PF_INET6
, state
->hook
, skb
);
182 static unsigned int ipv6_conntrack_local(void *priv
,
184 const struct nf_hook_state
*state
)
186 /* root is playing with raw sockets. */
187 if (skb
->len
< sizeof(struct ipv6hdr
)) {
188 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
191 return nf_conntrack_in(state
->net
, PF_INET6
, state
->hook
, skb
);
194 static struct nf_hook_ops ipv6_conntrack_ops
[] __read_mostly
= {
196 .hook
= ipv6_conntrack_in
,
198 .hooknum
= NF_INET_PRE_ROUTING
,
199 .priority
= NF_IP6_PRI_CONNTRACK
,
202 .hook
= ipv6_conntrack_local
,
204 .hooknum
= NF_INET_LOCAL_OUT
,
205 .priority
= NF_IP6_PRI_CONNTRACK
,
210 .hooknum
= NF_INET_POST_ROUTING
,
211 .priority
= NF_IP6_PRI_CONNTRACK_HELPER
,
214 .hook
= ipv6_confirm
,
216 .hooknum
= NF_INET_POST_ROUTING
,
217 .priority
= NF_IP6_PRI_LAST
,
222 .hooknum
= NF_INET_LOCAL_IN
,
223 .priority
= NF_IP6_PRI_CONNTRACK_HELPER
,
226 .hook
= ipv6_confirm
,
228 .hooknum
= NF_INET_LOCAL_IN
,
229 .priority
= NF_IP6_PRI_LAST
-1,
234 ipv6_getorigdst(struct sock
*sk
, int optval
, void __user
*user
, int *len
)
236 const struct inet_sock
*inet
= inet_sk(sk
);
237 const struct ipv6_pinfo
*inet6
= inet6_sk(sk
);
238 const struct nf_conntrack_tuple_hash
*h
;
239 struct sockaddr_in6 sin6
;
240 struct nf_conntrack_tuple tuple
= { .src
.l3num
= NFPROTO_IPV6
};
243 tuple
.src
.u3
.in6
= sk
->sk_v6_rcv_saddr
;
244 tuple
.src
.u
.tcp
.port
= inet
->inet_sport
;
245 tuple
.dst
.u3
.in6
= sk
->sk_v6_daddr
;
246 tuple
.dst
.u
.tcp
.port
= inet
->inet_dport
;
247 tuple
.dst
.protonum
= sk
->sk_protocol
;
249 if (sk
->sk_protocol
!= IPPROTO_TCP
&& sk
->sk_protocol
!= IPPROTO_SCTP
)
252 if (*len
< 0 || (unsigned int) *len
< sizeof(sin6
))
255 h
= nf_conntrack_find_get(sock_net(sk
), &nf_ct_zone_dflt
, &tuple
);
257 pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n",
258 &tuple
.src
.u3
.ip6
, ntohs(tuple
.src
.u
.tcp
.port
),
259 &tuple
.dst
.u3
.ip6
, ntohs(tuple
.dst
.u
.tcp
.port
));
263 ct
= nf_ct_tuplehash_to_ctrack(h
);
265 sin6
.sin6_family
= AF_INET6
;
266 sin6
.sin6_port
= ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.u
.tcp
.port
;
267 sin6
.sin6_flowinfo
= inet6
->flow_label
& IPV6_FLOWINFO_MASK
;
268 memcpy(&sin6
.sin6_addr
,
269 &ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.u3
.in6
,
270 sizeof(sin6
.sin6_addr
));
273 sin6
.sin6_scope_id
= ipv6_iface_scope_id(&sin6
.sin6_addr
,
274 sk
->sk_bound_dev_if
);
275 return copy_to_user(user
, &sin6
, sizeof(sin6
)) ? -EFAULT
: 0;
278 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
280 #include <linux/netfilter/nfnetlink.h>
281 #include <linux/netfilter/nfnetlink_conntrack.h>
283 static int ipv6_tuple_to_nlattr(struct sk_buff
*skb
,
284 const struct nf_conntrack_tuple
*tuple
)
286 if (nla_put_in6_addr(skb
, CTA_IP_V6_SRC
, &tuple
->src
.u3
.in6
) ||
287 nla_put_in6_addr(skb
, CTA_IP_V6_DST
, &tuple
->dst
.u3
.in6
))
288 goto nla_put_failure
;
295 static const struct nla_policy ipv6_nla_policy
[CTA_IP_MAX
+1] = {
296 [CTA_IP_V6_SRC
] = { .len
= sizeof(u_int32_t
)*4 },
297 [CTA_IP_V6_DST
] = { .len
= sizeof(u_int32_t
)*4 },
300 static int ipv6_nlattr_to_tuple(struct nlattr
*tb
[],
301 struct nf_conntrack_tuple
*t
)
303 if (!tb
[CTA_IP_V6_SRC
] || !tb
[CTA_IP_V6_DST
])
306 t
->src
.u3
.in6
= nla_get_in6_addr(tb
[CTA_IP_V6_SRC
]);
307 t
->dst
.u3
.in6
= nla_get_in6_addr(tb
[CTA_IP_V6_DST
]);
312 static int ipv6_nlattr_tuple_size(void)
314 return nla_policy_len(ipv6_nla_policy
, CTA_IP_MAX
+ 1);
318 static int ipv6_hooks_register(struct net
*net
)
320 struct conntrack6_net
*cnet
= net_generic(net
, conntrack6_net_id
);
323 mutex_lock(®ister_ipv6_hooks
);
328 err
= nf_defrag_ipv6_enable(net
);
334 err
= nf_register_net_hooks(net
, ipv6_conntrack_ops
,
335 ARRAY_SIZE(ipv6_conntrack_ops
));
339 mutex_unlock(®ister_ipv6_hooks
);
343 static void ipv6_hooks_unregister(struct net
*net
)
345 struct conntrack6_net
*cnet
= net_generic(net
, conntrack6_net_id
);
347 mutex_lock(®ister_ipv6_hooks
);
348 if (cnet
->users
&& (--cnet
->users
== 0))
349 nf_unregister_net_hooks(net
, ipv6_conntrack_ops
,
350 ARRAY_SIZE(ipv6_conntrack_ops
));
351 mutex_unlock(®ister_ipv6_hooks
);
354 struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly
= {
357 .pkt_to_tuple
= ipv6_pkt_to_tuple
,
358 .invert_tuple
= ipv6_invert_tuple
,
359 .print_tuple
= ipv6_print_tuple
,
360 .get_l4proto
= ipv6_get_l4proto
,
361 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
362 .tuple_to_nlattr
= ipv6_tuple_to_nlattr
,
363 .nlattr_tuple_size
= ipv6_nlattr_tuple_size
,
364 .nlattr_to_tuple
= ipv6_nlattr_to_tuple
,
365 .nla_policy
= ipv6_nla_policy
,
367 .net_ns_get
= ipv6_hooks_register
,
368 .net_ns_put
= ipv6_hooks_unregister
,
372 MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6
));
373 MODULE_LICENSE("GPL");
374 MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
376 static struct nf_sockopt_ops so_getorigdst6
= {
378 .get_optmin
= IP6T_SO_ORIGINAL_DST
,
379 .get_optmax
= IP6T_SO_ORIGINAL_DST
+ 1,
380 .get
= ipv6_getorigdst
,
381 .owner
= THIS_MODULE
,
384 static struct nf_conntrack_l4proto
*builtin_l4proto6
[] = {
385 &nf_conntrack_l4proto_tcp6
,
386 &nf_conntrack_l4proto_udp6
,
387 &nf_conntrack_l4proto_icmpv6
,
388 #ifdef CONFIG_NF_CT_PROTO_DCCP
389 &nf_conntrack_l4proto_dccp6
,
391 #ifdef CONFIG_NF_CT_PROTO_SCTP
392 &nf_conntrack_l4proto_sctp6
,
394 #ifdef CONFIG_NF_CT_PROTO_UDPLITE
395 &nf_conntrack_l4proto_udplite6
,
399 static int ipv6_net_init(struct net
*net
)
403 ret
= nf_ct_l4proto_pernet_register(net
, builtin_l4proto6
,
404 ARRAY_SIZE(builtin_l4proto6
));
408 ret
= nf_ct_l3proto_pernet_register(net
, &nf_conntrack_l3proto_ipv6
);
410 pr_err("nf_conntrack_ipv6: pernet registration failed.\n");
411 nf_ct_l4proto_pernet_unregister(net
, builtin_l4proto6
,
412 ARRAY_SIZE(builtin_l4proto6
));
417 static void ipv6_net_exit(struct net
*net
)
419 nf_ct_l3proto_pernet_unregister(net
, &nf_conntrack_l3proto_ipv6
);
420 nf_ct_l4proto_pernet_unregister(net
, builtin_l4proto6
,
421 ARRAY_SIZE(builtin_l4proto6
));
424 static struct pernet_operations ipv6_net_ops
= {
425 .init
= ipv6_net_init
,
426 .exit
= ipv6_net_exit
,
427 .id
= &conntrack6_net_id
,
428 .size
= sizeof(struct conntrack6_net
),
431 static int __init
nf_conntrack_l3proto_ipv6_init(void)
437 ret
= nf_register_sockopt(&so_getorigdst6
);
439 pr_err("Unable to register netfilter socket option\n");
443 ret
= register_pernet_subsys(&ipv6_net_ops
);
445 goto cleanup_sockopt
;
447 ret
= nf_ct_l4proto_register(builtin_l4proto6
,
448 ARRAY_SIZE(builtin_l4proto6
));
452 ret
= nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6
);
454 pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n");
455 goto cleanup_l4proto
;
459 nf_ct_l4proto_unregister(builtin_l4proto6
,
460 ARRAY_SIZE(builtin_l4proto6
));
462 unregister_pernet_subsys(&ipv6_net_ops
);
464 nf_unregister_sockopt(&so_getorigdst6
);
468 static void __exit
nf_conntrack_l3proto_ipv6_fini(void)
471 nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6
);
472 nf_ct_l4proto_unregister(builtin_l4proto6
,
473 ARRAY_SIZE(builtin_l4proto6
));
474 unregister_pernet_subsys(&ipv6_net_ops
);
475 nf_unregister_sockopt(&so_getorigdst6
);
478 module_init(nf_conntrack_l3proto_ipv6_init
);
479 module_exit(nf_conntrack_l3proto_ipv6_fini
);