1a0ae2562SFlorian Westphal // SPDX-License-Identifier: GPL-2.0
28f03dea5SMartin Josefsson
38f03dea5SMartin Josefsson #include <linux/types.h>
48f03dea5SMartin Josefsson #include <linux/netfilter.h>
58f03dea5SMartin Josefsson #include <linux/module.h>
65a0e3ad6STejun Heo #include <linux/slab.h>
7d62f9ed4SPatrick McHardy #include <linux/mutex.h>
88f03dea5SMartin Josefsson #include <linux/vmalloc.h>
98f03dea5SMartin Josefsson #include <linux/stddef.h>
108f03dea5SMartin Josefsson #include <linux/err.h>
118f03dea5SMartin Josefsson #include <linux/percpu.h>
128f03dea5SMartin Josefsson #include <linux/notifier.h>
138f03dea5SMartin Josefsson #include <linux/kernel.h>
148f03dea5SMartin Josefsson #include <linux/netdevice.h>
158f03dea5SMartin Josefsson
168f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack.h>
17605dcad6SMartin Josefsson #include <net/netfilter/nf_conntrack_l4proto.h>
188f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack_core.h>
19d035f19fSPablo Neira Ayuso #include <net/netfilter/nf_conntrack_bridge.h>
20c4f3db15SFlorian Westphal #include <net/netfilter/nf_log.h>
218f03dea5SMartin Josefsson
22a0ae2562SFlorian Westphal #include <linux/ip.h>
23a0ae2562SFlorian Westphal #include <linux/icmp.h>
24a0ae2562SFlorian Westphal #include <linux/sysctl.h>
25a0ae2562SFlorian Westphal #include <net/route.h>
26a0ae2562SFlorian Westphal #include <net/ip.h>
27a0ae2562SFlorian Westphal
28a0ae2562SFlorian Westphal #include <linux/netfilter_ipv4.h>
29a0ae2562SFlorian Westphal #include <linux/netfilter_ipv6.h>
30a0ae2562SFlorian Westphal #include <linux/netfilter_ipv6/ip6_tables.h>
31a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_helper.h>
32a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_zones.h>
33a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_seqadj.h>
34a0ae2562SFlorian Westphal #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
35a0ae2562SFlorian Westphal #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
36a0ae2562SFlorian Westphal #include <net/netfilter/nf_nat_helper.h>
37a0ae2562SFlorian Westphal #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
38a0ae2562SFlorian Westphal #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
39a0ae2562SFlorian Westphal
40a0ae2562SFlorian Westphal #include <linux/ipv6.h>
41a0ae2562SFlorian Westphal #include <linux/in6.h>
42a0ae2562SFlorian Westphal #include <net/ipv6.h>
43a0ae2562SFlorian Westphal #include <net/inet_frag.h>
44a0ae2562SFlorian Westphal
45b19caa0cSPatrick McHardy static DEFINE_MUTEX(nf_ct_proto_mutex);
46d62f9ed4SPatrick McHardy
47b19caa0cSPatrick McHardy #ifdef CONFIG_SYSCTL
4862eec0d7SFlorian Westphal __printf(4, 5)
nf_l4proto_log_invalid(const struct sk_buff * skb,const struct nf_hook_state * state,u8 protonum,const char * fmt,...)49c4f3db15SFlorian Westphal void nf_l4proto_log_invalid(const struct sk_buff *skb,
5062eec0d7SFlorian Westphal const struct nf_hook_state *state,
5162eec0d7SFlorian Westphal u8 protonum,
52c4f3db15SFlorian Westphal const char *fmt, ...)
53c4f3db15SFlorian Westphal {
5462eec0d7SFlorian Westphal struct net *net = state->net;
55c4f3db15SFlorian Westphal struct va_format vaf;
56c4f3db15SFlorian Westphal va_list args;
57c4f3db15SFlorian Westphal
58d4866805SAndrei Vagin if (net->ct.sysctl_log_invalid != protonum &&
59c4f3db15SFlorian Westphal net->ct.sysctl_log_invalid != IPPROTO_RAW)
60c4f3db15SFlorian Westphal return;
61c4f3db15SFlorian Westphal
62c4f3db15SFlorian Westphal va_start(args, fmt);
63c4f3db15SFlorian Westphal vaf.fmt = fmt;
64c4f3db15SFlorian Westphal vaf.va = &args;
65c4f3db15SFlorian Westphal
6662eec0d7SFlorian Westphal nf_log_packet(net, state->pf, 0, skb, state->in, state->out,
6762eec0d7SFlorian Westphal NULL, "nf_ct_proto_%d: %pV ", protonum, &vaf);
68c4f3db15SFlorian Westphal va_end(args);
69c4f3db15SFlorian Westphal }
70c4f3db15SFlorian Westphal EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid);
713d0b527bSFlorian Westphal
7262eec0d7SFlorian Westphal __printf(4, 5)
nf_ct_l4proto_log_invalid(const struct sk_buff * skb,const struct nf_conn * ct,const struct nf_hook_state * state,const char * fmt,...)733d0b527bSFlorian Westphal void nf_ct_l4proto_log_invalid(const struct sk_buff *skb,
743d0b527bSFlorian Westphal const struct nf_conn *ct,
7562eec0d7SFlorian Westphal const struct nf_hook_state *state,
763d0b527bSFlorian Westphal const char *fmt, ...)
773d0b527bSFlorian Westphal {
783d0b527bSFlorian Westphal struct va_format vaf;
793d0b527bSFlorian Westphal struct net *net;
803d0b527bSFlorian Westphal va_list args;
813d0b527bSFlorian Westphal
823d0b527bSFlorian Westphal net = nf_ct_net(ct);
833d0b527bSFlorian Westphal if (likely(net->ct.sysctl_log_invalid == 0))
843d0b527bSFlorian Westphal return;
853d0b527bSFlorian Westphal
863d0b527bSFlorian Westphal va_start(args, fmt);
873d0b527bSFlorian Westphal vaf.fmt = fmt;
883d0b527bSFlorian Westphal vaf.va = &args;
893d0b527bSFlorian Westphal
9062eec0d7SFlorian Westphal nf_l4proto_log_invalid(skb, state,
913d0b527bSFlorian Westphal nf_ct_protonum(ct), "%pV", &vaf);
923d0b527bSFlorian Westphal va_end(args);
933d0b527bSFlorian Westphal }
943d0b527bSFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_l4proto_log_invalid);
95d62f9ed4SPatrick McHardy #endif
96d62f9ed4SPatrick McHardy
nf_ct_l4proto_find(u8 l4proto)974a60dc74SFlorian Westphal const struct nf_conntrack_l4proto *nf_ct_l4proto_find(u8 l4proto)
988f03dea5SMartin Josefsson {
994a60dc74SFlorian Westphal switch (l4proto) {
1004a60dc74SFlorian Westphal case IPPROTO_UDP: return &nf_conntrack_l4proto_udp;
1014a60dc74SFlorian Westphal case IPPROTO_TCP: return &nf_conntrack_l4proto_tcp;
1024a60dc74SFlorian Westphal case IPPROTO_ICMP: return &nf_conntrack_l4proto_icmp;
1034a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP
1044a60dc74SFlorian Westphal case IPPROTO_DCCP: return &nf_conntrack_l4proto_dccp;
1054a60dc74SFlorian Westphal #endif
1064a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP
1074a60dc74SFlorian Westphal case IPPROTO_SCTP: return &nf_conntrack_l4proto_sctp;
1084a60dc74SFlorian Westphal #endif
1094a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE
1104a60dc74SFlorian Westphal case IPPROTO_UDPLITE: return &nf_conntrack_l4proto_udplite;
1114a60dc74SFlorian Westphal #endif
1124a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
1134a60dc74SFlorian Westphal case IPPROTO_GRE: return &nf_conntrack_l4proto_gre;
1144a60dc74SFlorian Westphal #endif
1154a60dc74SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
1164a60dc74SFlorian Westphal case IPPROTO_ICMPV6: return &nf_conntrack_l4proto_icmpv6;
1174a60dc74SFlorian Westphal #endif /* CONFIG_IPV6 */
1184a60dc74SFlorian Westphal }
1194a60dc74SFlorian Westphal
120605dcad6SMartin Josefsson return &nf_conntrack_l4proto_generic;
1214a60dc74SFlorian Westphal };
1224a60dc74SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_l4proto_find);
1230e54d217SDavide Caratti
in_vrf_postrouting(const struct nf_hook_state * state)1248e0538d8SFlorian Westphal static bool in_vrf_postrouting(const struct nf_hook_state *state)
1258e0538d8SFlorian Westphal {
1268e0538d8SFlorian Westphal #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
1278e0538d8SFlorian Westphal if (state->hook == NF_INET_POST_ROUTING &&
1288e0538d8SFlorian Westphal netif_is_l3_master(state->out))
1298e0538d8SFlorian Westphal return true;
1308e0538d8SFlorian Westphal #endif
1318e0538d8SFlorian Westphal return false;
1328e0538d8SFlorian Westphal }
1338e0538d8SFlorian Westphal
nf_confirm(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)134a70e4834SFlorian Westphal unsigned int nf_confirm(void *priv,
135a0ae2562SFlorian Westphal struct sk_buff *skb,
136a0ae2562SFlorian Westphal const struct nf_hook_state *state)
137a0ae2562SFlorian Westphal {
138a70e4834SFlorian Westphal const struct nf_conn_help *help;
139a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo;
140a70e4834SFlorian Westphal unsigned int protoff;
141827318feSFlorian Westphal struct nf_conn *ct;
142a70e4834SFlorian Westphal bool seqadj_needed;
143a70e4834SFlorian Westphal __be16 frag_off;
1445eb119daSFlorian Westphal int start;
145a70e4834SFlorian Westphal u8 pnum;
146a0ae2562SFlorian Westphal
147a0ae2562SFlorian Westphal ct = nf_ct_get(skb, &ctinfo);
148a70e4834SFlorian Westphal if (!ct || in_vrf_postrouting(state))
1498e0538d8SFlorian Westphal return NF_ACCEPT;
1508e0538d8SFlorian Westphal
151a70e4834SFlorian Westphal help = nfct_help(ct);
152a70e4834SFlorian Westphal
153a70e4834SFlorian Westphal seqadj_needed = test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && !nf_is_loopback_packet(skb);
154a70e4834SFlorian Westphal if (!help && !seqadj_needed)
155a70e4834SFlorian Westphal return nf_conntrack_confirm(skb);
156a70e4834SFlorian Westphal
157a70e4834SFlorian Westphal /* helper->help() do not expect ICMP packets */
158a70e4834SFlorian Westphal if (ctinfo == IP_CT_RELATED_REPLY)
159a70e4834SFlorian Westphal return nf_conntrack_confirm(skb);
160a70e4834SFlorian Westphal
161a70e4834SFlorian Westphal switch (nf_ct_l3num(ct)) {
162a70e4834SFlorian Westphal case NFPROTO_IPV4:
163a70e4834SFlorian Westphal protoff = skb_network_offset(skb) + ip_hdrlen(skb);
164a70e4834SFlorian Westphal break;
165a70e4834SFlorian Westphal case NFPROTO_IPV6:
166a70e4834SFlorian Westphal pnum = ipv6_hdr(skb)->nexthdr;
1675eb119daSFlorian Westphal start = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, &frag_off);
1685eb119daSFlorian Westphal if (start < 0 || (frag_off & htons(~0x7)) != 0)
169a70e4834SFlorian Westphal return nf_conntrack_confirm(skb);
1705eb119daSFlorian Westphal
1715eb119daSFlorian Westphal protoff = start;
172a70e4834SFlorian Westphal break;
173a70e4834SFlorian Westphal default:
174a70e4834SFlorian Westphal return nf_conntrack_confirm(skb);
175a0ae2562SFlorian Westphal }
176a0ae2562SFlorian Westphal
177a70e4834SFlorian Westphal if (help) {
178a70e4834SFlorian Westphal const struct nf_conntrack_helper *helper;
179a70e4834SFlorian Westphal int ret;
180a70e4834SFlorian Westphal
181a70e4834SFlorian Westphal /* rcu_read_lock()ed by nf_hook */
182a70e4834SFlorian Westphal helper = rcu_dereference(help->helper);
183a70e4834SFlorian Westphal if (helper) {
184a70e4834SFlorian Westphal ret = helper->help(skb,
185a70e4834SFlorian Westphal protoff,
186a70e4834SFlorian Westphal ct, ctinfo);
187a70e4834SFlorian Westphal if (ret != NF_ACCEPT)
188a70e4834SFlorian Westphal return ret;
189a70e4834SFlorian Westphal }
190a70e4834SFlorian Westphal }
191a70e4834SFlorian Westphal
192a70e4834SFlorian Westphal if (seqadj_needed &&
193a70e4834SFlorian Westphal !nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
194a70e4834SFlorian Westphal NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
195a70e4834SFlorian Westphal return NF_DROP;
196a70e4834SFlorian Westphal }
197a70e4834SFlorian Westphal
198a70e4834SFlorian Westphal /* We've seen it coming out the other side: confirm it */
199a70e4834SFlorian Westphal return nf_conntrack_confirm(skb);
200a70e4834SFlorian Westphal }
201a70e4834SFlorian Westphal EXPORT_SYMBOL_GPL(nf_confirm);
202a70e4834SFlorian Westphal
ipv4_conntrack_in(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)203a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv,
204a0ae2562SFlorian Westphal struct sk_buff *skb,
205a0ae2562SFlorian Westphal const struct nf_hook_state *state)
206a0ae2562SFlorian Westphal {
20793e66024SFlorian Westphal return nf_conntrack_in(skb, state);
208a0ae2562SFlorian Westphal }
209a0ae2562SFlorian Westphal
ipv4_conntrack_local(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)210a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv,
211a0ae2562SFlorian Westphal struct sk_buff *skb,
212a0ae2562SFlorian Westphal const struct nf_hook_state *state)
213a0ae2562SFlorian Westphal {
214a0ae2562SFlorian Westphal if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
215a0ae2562SFlorian Westphal enum ip_conntrack_info ctinfo;
216a0ae2562SFlorian Westphal struct nf_conn *tmpl;
217a0ae2562SFlorian Westphal
218a0ae2562SFlorian Westphal tmpl = nf_ct_get(skb, &ctinfo);
219a0ae2562SFlorian Westphal if (tmpl && nf_ct_is_template(tmpl)) {
220a0ae2562SFlorian Westphal /* when skipping ct, clear templates to avoid fooling
221a0ae2562SFlorian Westphal * later targets/matches
222a0ae2562SFlorian Westphal */
223a0ae2562SFlorian Westphal skb->_nfct = 0;
224a0ae2562SFlorian Westphal nf_ct_put(tmpl);
225a0ae2562SFlorian Westphal }
226a0ae2562SFlorian Westphal return NF_ACCEPT;
227a0ae2562SFlorian Westphal }
228a0ae2562SFlorian Westphal
22993e66024SFlorian Westphal return nf_conntrack_in(skb, state);
230a0ae2562SFlorian Westphal }
231a0ae2562SFlorian Westphal
232a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so
233a0ae2562SFlorian Westphal * make it the first hook.
234a0ae2562SFlorian Westphal */
235a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = {
236a0ae2562SFlorian Westphal {
237a0ae2562SFlorian Westphal .hook = ipv4_conntrack_in,
238a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4,
239a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING,
240a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK,
241a0ae2562SFlorian Westphal },
242a0ae2562SFlorian Westphal {
243a0ae2562SFlorian Westphal .hook = ipv4_conntrack_local,
244a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4,
245a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT,
246a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK,
247a0ae2562SFlorian Westphal },
248a0ae2562SFlorian Westphal {
249a70e4834SFlorian Westphal .hook = nf_confirm,
250a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4,
251a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING,
252a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM,
253a0ae2562SFlorian Westphal },
254a0ae2562SFlorian Westphal {
255a70e4834SFlorian Westphal .hook = nf_confirm,
256a0ae2562SFlorian Westphal .pf = NFPROTO_IPV4,
257a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN,
258a0ae2562SFlorian Westphal .priority = NF_IP_PRI_CONNTRACK_CONFIRM,
259a0ae2562SFlorian Westphal },
260a0ae2562SFlorian Westphal };
261a0ae2562SFlorian Westphal
262a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't
263a0ae2562SFlorian Westphal * blame them).
264a0ae2562SFlorian Westphal * Reversing the socket's dst/src point of view gives us the reply
265a0ae2562SFlorian Westphal * mapping.
266a0ae2562SFlorian Westphal */
267a0ae2562SFlorian Westphal static int
getorigdst(struct sock * sk,int optval,void __user * user,int * len)268a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len)
269a0ae2562SFlorian Westphal {
270a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk);
271a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h;
272a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple;
273a0ae2562SFlorian Westphal
274a0ae2562SFlorian Westphal memset(&tuple, 0, sizeof(tuple));
275a0ae2562SFlorian Westphal
276a0ae2562SFlorian Westphal lock_sock(sk);
277a0ae2562SFlorian Westphal tuple.src.u3.ip = inet->inet_rcv_saddr;
278a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport;
279a0ae2562SFlorian Westphal tuple.dst.u3.ip = inet->inet_daddr;
280a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport;
281a0ae2562SFlorian Westphal tuple.src.l3num = PF_INET;
282a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol;
283a0ae2562SFlorian Westphal release_sock(sk);
284a0ae2562SFlorian Westphal
285a0ae2562SFlorian Westphal /* We only do TCP and SCTP at the moment: is there a better way? */
286a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP &&
287*50bfbb89SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP)
288a0ae2562SFlorian Westphal return -ENOPROTOOPT;
289a0ae2562SFlorian Westphal
290*50bfbb89SFlorian Westphal if ((unsigned int)*len < sizeof(struct sockaddr_in))
291a0ae2562SFlorian Westphal return -EINVAL;
292a0ae2562SFlorian Westphal
293a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
294a0ae2562SFlorian Westphal if (h) {
295a0ae2562SFlorian Westphal struct sockaddr_in sin;
296a0ae2562SFlorian Westphal struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
297a0ae2562SFlorian Westphal
298a0ae2562SFlorian Westphal sin.sin_family = AF_INET;
299a0ae2562SFlorian Westphal sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
300a0ae2562SFlorian Westphal .tuple.dst.u.tcp.port;
301a0ae2562SFlorian Westphal sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
302a0ae2562SFlorian Westphal .tuple.dst.u3.ip;
303a0ae2562SFlorian Westphal memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
304a0ae2562SFlorian Westphal
305a0ae2562SFlorian Westphal nf_ct_put(ct);
306a0ae2562SFlorian Westphal if (copy_to_user(user, &sin, sizeof(sin)) != 0)
307a0ae2562SFlorian Westphal return -EFAULT;
308a0ae2562SFlorian Westphal else
309a0ae2562SFlorian Westphal return 0;
310a0ae2562SFlorian Westphal }
311a0ae2562SFlorian Westphal return -ENOENT;
312a0ae2562SFlorian Westphal }
313a0ae2562SFlorian Westphal
314a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = {
315a0ae2562SFlorian Westphal .pf = PF_INET,
316a0ae2562SFlorian Westphal .get_optmin = SO_ORIGINAL_DST,
317a0ae2562SFlorian Westphal .get_optmax = SO_ORIGINAL_DST + 1,
318a0ae2562SFlorian Westphal .get = getorigdst,
319a0ae2562SFlorian Westphal .owner = THIS_MODULE,
320a0ae2562SFlorian Westphal };
321a0ae2562SFlorian Westphal
322a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
323a0ae2562SFlorian Westphal static int
ipv6_getorigdst(struct sock * sk,int optval,void __user * user,int * len)324a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
325a0ae2562SFlorian Westphal {
326a0ae2562SFlorian Westphal struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
327a0ae2562SFlorian Westphal const struct ipv6_pinfo *inet6 = inet6_sk(sk);
328a0ae2562SFlorian Westphal const struct inet_sock *inet = inet_sk(sk);
329a0ae2562SFlorian Westphal const struct nf_conntrack_tuple_hash *h;
330a0ae2562SFlorian Westphal struct sockaddr_in6 sin6;
331a0ae2562SFlorian Westphal struct nf_conn *ct;
332a0ae2562SFlorian Westphal __be32 flow_label;
333a0ae2562SFlorian Westphal int bound_dev_if;
334a0ae2562SFlorian Westphal
335a0ae2562SFlorian Westphal lock_sock(sk);
336a0ae2562SFlorian Westphal tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
337a0ae2562SFlorian Westphal tuple.src.u.tcp.port = inet->inet_sport;
338a0ae2562SFlorian Westphal tuple.dst.u3.in6 = sk->sk_v6_daddr;
339a0ae2562SFlorian Westphal tuple.dst.u.tcp.port = inet->inet_dport;
340a0ae2562SFlorian Westphal tuple.dst.protonum = sk->sk_protocol;
341a0ae2562SFlorian Westphal bound_dev_if = sk->sk_bound_dev_if;
342a0ae2562SFlorian Westphal flow_label = inet6->flow_label;
343a0ae2562SFlorian Westphal release_sock(sk);
344a0ae2562SFlorian Westphal
345a0ae2562SFlorian Westphal if (tuple.dst.protonum != IPPROTO_TCP &&
346a0ae2562SFlorian Westphal tuple.dst.protonum != IPPROTO_SCTP)
347a0ae2562SFlorian Westphal return -ENOPROTOOPT;
348a0ae2562SFlorian Westphal
349a0ae2562SFlorian Westphal if (*len < 0 || (unsigned int)*len < sizeof(sin6))
350a0ae2562SFlorian Westphal return -EINVAL;
351a0ae2562SFlorian Westphal
352a0ae2562SFlorian Westphal h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
353*50bfbb89SFlorian Westphal if (!h)
354a0ae2562SFlorian Westphal return -ENOENT;
355a0ae2562SFlorian Westphal
356a0ae2562SFlorian Westphal ct = nf_ct_tuplehash_to_ctrack(h);
357a0ae2562SFlorian Westphal
358a0ae2562SFlorian Westphal sin6.sin6_family = AF_INET6;
359a0ae2562SFlorian Westphal sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
360a0ae2562SFlorian Westphal sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
361a0ae2562SFlorian Westphal memcpy(&sin6.sin6_addr,
362a0ae2562SFlorian Westphal &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
363a0ae2562SFlorian Westphal sizeof(sin6.sin6_addr));
364a0ae2562SFlorian Westphal
365a0ae2562SFlorian Westphal nf_ct_put(ct);
366a0ae2562SFlorian Westphal sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
367a0ae2562SFlorian Westphal return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
368a0ae2562SFlorian Westphal }
369a0ae2562SFlorian Westphal
370a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = {
371a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6,
372a0ae2562SFlorian Westphal .get_optmin = IP6T_SO_ORIGINAL_DST,
373a0ae2562SFlorian Westphal .get_optmax = IP6T_SO_ORIGINAL_DST + 1,
374a0ae2562SFlorian Westphal .get = ipv6_getorigdst,
375a0ae2562SFlorian Westphal .owner = THIS_MODULE,
376a0ae2562SFlorian Westphal };
377a0ae2562SFlorian Westphal
ipv6_conntrack_in(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)378a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv,
379a0ae2562SFlorian Westphal struct sk_buff *skb,
380a0ae2562SFlorian Westphal const struct nf_hook_state *state)
381a0ae2562SFlorian Westphal {
38293e66024SFlorian Westphal return nf_conntrack_in(skb, state);
383a0ae2562SFlorian Westphal }
384a0ae2562SFlorian Westphal
ipv6_conntrack_local(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)385a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv,
386a0ae2562SFlorian Westphal struct sk_buff *skb,
387a0ae2562SFlorian Westphal const struct nf_hook_state *state)
388a0ae2562SFlorian Westphal {
38993e66024SFlorian Westphal return nf_conntrack_in(skb, state);
390a0ae2562SFlorian Westphal }
391a0ae2562SFlorian Westphal
392a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = {
393a0ae2562SFlorian Westphal {
394a0ae2562SFlorian Westphal .hook = ipv6_conntrack_in,
395a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6,
396a0ae2562SFlorian Westphal .hooknum = NF_INET_PRE_ROUTING,
397a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK,
398a0ae2562SFlorian Westphal },
399a0ae2562SFlorian Westphal {
400a0ae2562SFlorian Westphal .hook = ipv6_conntrack_local,
401a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6,
402a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_OUT,
403a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_CONNTRACK,
404a0ae2562SFlorian Westphal },
405a0ae2562SFlorian Westphal {
406a70e4834SFlorian Westphal .hook = nf_confirm,
407a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6,
408a0ae2562SFlorian Westphal .hooknum = NF_INET_POST_ROUTING,
409a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST,
410a0ae2562SFlorian Westphal },
411a0ae2562SFlorian Westphal {
412a70e4834SFlorian Westphal .hook = nf_confirm,
413a0ae2562SFlorian Westphal .pf = NFPROTO_IPV6,
414a0ae2562SFlorian Westphal .hooknum = NF_INET_LOCAL_IN,
415a0ae2562SFlorian Westphal .priority = NF_IP6_PRI_LAST - 1,
416a0ae2562SFlorian Westphal },
417a0ae2562SFlorian Westphal };
418a0ae2562SFlorian Westphal #endif
419a0ae2562SFlorian Westphal
nf_ct_tcp_fixup(struct nf_conn * ct,void * _nfproto)420f94e6380SFlorian Westphal static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto)
421f94e6380SFlorian Westphal {
422f94e6380SFlorian Westphal u8 nfproto = (unsigned long)_nfproto;
423f94e6380SFlorian Westphal
424f94e6380SFlorian Westphal if (nf_ct_l3num(ct) != nfproto)
425f94e6380SFlorian Westphal return 0;
426f94e6380SFlorian Westphal
427f94e6380SFlorian Westphal if (nf_ct_protonum(ct) == IPPROTO_TCP &&
428f94e6380SFlorian Westphal ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) {
429f94e6380SFlorian Westphal ct->proto.tcp.seen[0].td_maxwin = 0;
430f94e6380SFlorian Westphal ct->proto.tcp.seen[1].td_maxwin = 0;
431f94e6380SFlorian Westphal }
432f94e6380SFlorian Westphal
433f94e6380SFlorian Westphal return 0;
434f94e6380SFlorian Westphal }
435f94e6380SFlorian Westphal
436d035f19fSPablo Neira Ayuso static struct nf_ct_bridge_info *nf_ct_bridge_info;
437d035f19fSPablo Neira Ayuso
nf_ct_netns_do_get(struct net * net,u8 nfproto)438a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
439a0ae2562SFlorian Westphal {
4400418b989SPablo Neira Ayuso struct nf_conntrack_net *cnet = nf_ct_pernet(net);
441d035f19fSPablo Neira Ayuso bool fixup_needed = false, retry = true;
442a0ae2562SFlorian Westphal int err = 0;
443d035f19fSPablo Neira Ayuso retry:
444a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex);
445a0ae2562SFlorian Westphal
446a0ae2562SFlorian Westphal switch (nfproto) {
447a0ae2562SFlorian Westphal case NFPROTO_IPV4:
448a0ae2562SFlorian Westphal cnet->users4++;
449a0ae2562SFlorian Westphal if (cnet->users4 > 1)
450a0ae2562SFlorian Westphal goto out_unlock;
451a0ae2562SFlorian Westphal err = nf_defrag_ipv4_enable(net);
452a0ae2562SFlorian Westphal if (err) {
453a0ae2562SFlorian Westphal cnet->users4 = 0;
454a0ae2562SFlorian Westphal goto out_unlock;
455a0ae2562SFlorian Westphal }
456a0ae2562SFlorian Westphal
457a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv4_conntrack_ops,
458a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops));
459a0ae2562SFlorian Westphal if (err)
460a0ae2562SFlorian Westphal cnet->users4 = 0;
461f94e6380SFlorian Westphal else
462f94e6380SFlorian Westphal fixup_needed = true;
463a0ae2562SFlorian Westphal break;
464a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
465a0ae2562SFlorian Westphal case NFPROTO_IPV6:
466a0ae2562SFlorian Westphal cnet->users6++;
467a0ae2562SFlorian Westphal if (cnet->users6 > 1)
468a0ae2562SFlorian Westphal goto out_unlock;
469a0ae2562SFlorian Westphal err = nf_defrag_ipv6_enable(net);
470a0ae2562SFlorian Westphal if (err < 0) {
471a0ae2562SFlorian Westphal cnet->users6 = 0;
472a0ae2562SFlorian Westphal goto out_unlock;
473a0ae2562SFlorian Westphal }
474a0ae2562SFlorian Westphal
475a0ae2562SFlorian Westphal err = nf_register_net_hooks(net, ipv6_conntrack_ops,
476a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops));
477a0ae2562SFlorian Westphal if (err)
478a0ae2562SFlorian Westphal cnet->users6 = 0;
479f94e6380SFlorian Westphal else
480f94e6380SFlorian Westphal fixup_needed = true;
481a0ae2562SFlorian Westphal break;
482a0ae2562SFlorian Westphal #endif
483d035f19fSPablo Neira Ayuso case NFPROTO_BRIDGE:
484d035f19fSPablo Neira Ayuso if (!nf_ct_bridge_info) {
485d035f19fSPablo Neira Ayuso if (!retry) {
486d035f19fSPablo Neira Ayuso err = -EPROTO;
487d035f19fSPablo Neira Ayuso goto out_unlock;
488d035f19fSPablo Neira Ayuso }
489d035f19fSPablo Neira Ayuso mutex_unlock(&nf_ct_proto_mutex);
490d035f19fSPablo Neira Ayuso request_module("nf_conntrack_bridge");
491d035f19fSPablo Neira Ayuso retry = false;
492d035f19fSPablo Neira Ayuso goto retry;
493d035f19fSPablo Neira Ayuso }
494d035f19fSPablo Neira Ayuso if (!try_module_get(nf_ct_bridge_info->me)) {
495d035f19fSPablo Neira Ayuso err = -EPROTO;
496d035f19fSPablo Neira Ayuso goto out_unlock;
497d035f19fSPablo Neira Ayuso }
498d035f19fSPablo Neira Ayuso cnet->users_bridge++;
499d035f19fSPablo Neira Ayuso if (cnet->users_bridge > 1)
500d035f19fSPablo Neira Ayuso goto out_unlock;
501d035f19fSPablo Neira Ayuso
502d035f19fSPablo Neira Ayuso err = nf_register_net_hooks(net, nf_ct_bridge_info->ops,
503d035f19fSPablo Neira Ayuso nf_ct_bridge_info->ops_size);
504d035f19fSPablo Neira Ayuso if (err)
505d035f19fSPablo Neira Ayuso cnet->users_bridge = 0;
506d035f19fSPablo Neira Ayuso else
507d035f19fSPablo Neira Ayuso fixup_needed = true;
508d035f19fSPablo Neira Ayuso break;
509a0ae2562SFlorian Westphal default:
510a0ae2562SFlorian Westphal err = -EPROTO;
511a0ae2562SFlorian Westphal break;
512a0ae2562SFlorian Westphal }
513a0ae2562SFlorian Westphal out_unlock:
514a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex);
515f94e6380SFlorian Westphal
5168169ff58SPablo Neira Ayuso if (fixup_needed) {
5178169ff58SPablo Neira Ayuso struct nf_ct_iter_data iter_data = {
5188169ff58SPablo Neira Ayuso .net = net,
5198169ff58SPablo Neira Ayuso .data = (void *)(unsigned long)nfproto,
5208169ff58SPablo Neira Ayuso };
5218169ff58SPablo Neira Ayuso nf_ct_iterate_cleanup_net(nf_ct_tcp_fixup, &iter_data);
5228169ff58SPablo Neira Ayuso }
523f94e6380SFlorian Westphal
524a0ae2562SFlorian Westphal return err;
525a0ae2562SFlorian Westphal }
526a0ae2562SFlorian Westphal
nf_ct_netns_do_put(struct net * net,u8 nfproto)527a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
528a0ae2562SFlorian Westphal {
5290418b989SPablo Neira Ayuso struct nf_conntrack_net *cnet = nf_ct_pernet(net);
530a0ae2562SFlorian Westphal
531a0ae2562SFlorian Westphal mutex_lock(&nf_ct_proto_mutex);
532a0ae2562SFlorian Westphal switch (nfproto) {
533a0ae2562SFlorian Westphal case NFPROTO_IPV4:
534de8c1211SFlorian Westphal if (cnet->users4 && (--cnet->users4 == 0)) {
535a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv4_conntrack_ops,
536a0ae2562SFlorian Westphal ARRAY_SIZE(ipv4_conntrack_ops));
537de8c1211SFlorian Westphal nf_defrag_ipv4_disable(net);
538de8c1211SFlorian Westphal }
539a0ae2562SFlorian Westphal break;
540a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
541a0ae2562SFlorian Westphal case NFPROTO_IPV6:
542de8c1211SFlorian Westphal if (cnet->users6 && (--cnet->users6 == 0)) {
543a0ae2562SFlorian Westphal nf_unregister_net_hooks(net, ipv6_conntrack_ops,
544a0ae2562SFlorian Westphal ARRAY_SIZE(ipv6_conntrack_ops));
545de8c1211SFlorian Westphal nf_defrag_ipv6_disable(net);
546de8c1211SFlorian Westphal }
547a0ae2562SFlorian Westphal break;
548a0ae2562SFlorian Westphal #endif
549d035f19fSPablo Neira Ayuso case NFPROTO_BRIDGE:
550d035f19fSPablo Neira Ayuso if (!nf_ct_bridge_info)
551d035f19fSPablo Neira Ayuso break;
552d035f19fSPablo Neira Ayuso if (cnet->users_bridge && (--cnet->users_bridge == 0))
553d035f19fSPablo Neira Ayuso nf_unregister_net_hooks(net, nf_ct_bridge_info->ops,
554d035f19fSPablo Neira Ayuso nf_ct_bridge_info->ops_size);
555a0ae2562SFlorian Westphal
556d035f19fSPablo Neira Ayuso module_put(nf_ct_bridge_info->me);
557d035f19fSPablo Neira Ayuso break;
558d035f19fSPablo Neira Ayuso }
559a0ae2562SFlorian Westphal mutex_unlock(&nf_ct_proto_mutex);
560a0ae2562SFlorian Westphal }
561a0ae2562SFlorian Westphal
nf_ct_netns_inet_get(struct net * net)562af9573beSPablo Neira Ayuso static int nf_ct_netns_inet_get(struct net *net)
563a0ae2562SFlorian Westphal {
564a0ae2562SFlorian Westphal int err;
565a0ae2562SFlorian Westphal
566a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
567526e81b9SEelco Chaudron #if IS_ENABLED(CONFIG_IPV6)
568a0ae2562SFlorian Westphal if (err < 0)
569a0ae2562SFlorian Westphal goto err1;
570a0ae2562SFlorian Westphal err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
571a0ae2562SFlorian Westphal if (err < 0)
572a0ae2562SFlorian Westphal goto err2;
573a0ae2562SFlorian Westphal
574af9573beSPablo Neira Ayuso return err;
575a0ae2562SFlorian Westphal err2:
576a0ae2562SFlorian Westphal nf_ct_netns_put(net, NFPROTO_IPV4);
577a0ae2562SFlorian Westphal err1:
578526e81b9SEelco Chaudron #endif
579a0ae2562SFlorian Westphal return err;
580a0ae2562SFlorian Westphal }
581af9573beSPablo Neira Ayuso
nf_ct_netns_get(struct net * net,u8 nfproto)582af9573beSPablo Neira Ayuso int nf_ct_netns_get(struct net *net, u8 nfproto)
583af9573beSPablo Neira Ayuso {
584af9573beSPablo Neira Ayuso int err;
585af9573beSPablo Neira Ayuso
586af9573beSPablo Neira Ayuso switch (nfproto) {
587af9573beSPablo Neira Ayuso case NFPROTO_INET:
588af9573beSPablo Neira Ayuso err = nf_ct_netns_inet_get(net);
589af9573beSPablo Neira Ayuso break;
590af9573beSPablo Neira Ayuso case NFPROTO_BRIDGE:
591af9573beSPablo Neira Ayuso err = nf_ct_netns_do_get(net, NFPROTO_BRIDGE);
592af9573beSPablo Neira Ayuso if (err < 0)
593af9573beSPablo Neira Ayuso return err;
594af9573beSPablo Neira Ayuso
595af9573beSPablo Neira Ayuso err = nf_ct_netns_inet_get(net);
596af9573beSPablo Neira Ayuso if (err < 0) {
597af9573beSPablo Neira Ayuso nf_ct_netns_put(net, NFPROTO_BRIDGE);
598af9573beSPablo Neira Ayuso return err;
599af9573beSPablo Neira Ayuso }
600af9573beSPablo Neira Ayuso break;
601af9573beSPablo Neira Ayuso default:
602af9573beSPablo Neira Ayuso err = nf_ct_netns_do_get(net, nfproto);
603af9573beSPablo Neira Ayuso break;
604af9573beSPablo Neira Ayuso }
605af9573beSPablo Neira Ayuso return err;
606af9573beSPablo Neira Ayuso }
607a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get);
608a0ae2562SFlorian Westphal
nf_ct_netns_put(struct net * net,uint8_t nfproto)609a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto)
610a0ae2562SFlorian Westphal {
611af9573beSPablo Neira Ayuso switch (nfproto) {
612af9573beSPablo Neira Ayuso case NFPROTO_BRIDGE:
613af9573beSPablo Neira Ayuso nf_ct_netns_do_put(net, NFPROTO_BRIDGE);
614954d8297SGustavo A. R. Silva fallthrough;
615af9573beSPablo Neira Ayuso case NFPROTO_INET:
616a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV4);
617a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, NFPROTO_IPV6);
618af9573beSPablo Neira Ayuso break;
619af9573beSPablo Neira Ayuso default:
620a0ae2562SFlorian Westphal nf_ct_netns_do_put(net, nfproto);
621af9573beSPablo Neira Ayuso break;
622a0ae2562SFlorian Westphal }
623a0ae2562SFlorian Westphal }
624a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put);
625a0ae2562SFlorian Westphal
nf_ct_bridge_register(struct nf_ct_bridge_info * info)626d035f19fSPablo Neira Ayuso void nf_ct_bridge_register(struct nf_ct_bridge_info *info)
627d035f19fSPablo Neira Ayuso {
628d035f19fSPablo Neira Ayuso WARN_ON(nf_ct_bridge_info);
629d035f19fSPablo Neira Ayuso mutex_lock(&nf_ct_proto_mutex);
630d035f19fSPablo Neira Ayuso nf_ct_bridge_info = info;
631d035f19fSPablo Neira Ayuso mutex_unlock(&nf_ct_proto_mutex);
632d035f19fSPablo Neira Ayuso }
633d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_register);
634d035f19fSPablo Neira Ayuso
nf_ct_bridge_unregister(struct nf_ct_bridge_info * info)635d035f19fSPablo Neira Ayuso void nf_ct_bridge_unregister(struct nf_ct_bridge_info *info)
636d035f19fSPablo Neira Ayuso {
637d035f19fSPablo Neira Ayuso WARN_ON(!nf_ct_bridge_info);
638d035f19fSPablo Neira Ayuso mutex_lock(&nf_ct_proto_mutex);
639d035f19fSPablo Neira Ayuso nf_ct_bridge_info = NULL;
640d035f19fSPablo Neira Ayuso mutex_unlock(&nf_ct_proto_mutex);
641d035f19fSPablo Neira Ayuso }
642d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_unregister);
643d035f19fSPablo Neira Ayuso
nf_conntrack_proto_init(void)644a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void)
645a0ae2562SFlorian Westphal {
6464a60dc74SFlorian Westphal int ret;
647a0ae2562SFlorian Westphal
648a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst);
649a0ae2562SFlorian Westphal if (ret < 0)
650a0ae2562SFlorian Westphal return ret;
651a0ae2562SFlorian Westphal
652a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
653a0ae2562SFlorian Westphal ret = nf_register_sockopt(&so_getorigdst6);
654a0ae2562SFlorian Westphal if (ret < 0)
655a0ae2562SFlorian Westphal goto cleanup_sockopt;
656a0ae2562SFlorian Westphal #endif
657dd2934a9SFlorian Westphal
658a0ae2562SFlorian Westphal return ret;
6594a60dc74SFlorian Westphal
660a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
661a0ae2562SFlorian Westphal cleanup_sockopt:
66222cbdbcfSFlorian Westphal nf_unregister_sockopt(&so_getorigdst);
663a0ae2562SFlorian Westphal #endif
664a0ae2562SFlorian Westphal return ret;
665a0ae2562SFlorian Westphal }
666a0ae2562SFlorian Westphal
nf_conntrack_proto_fini(void)667a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void)
668a0ae2562SFlorian Westphal {
669a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst);
670a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
671a0ae2562SFlorian Westphal nf_unregister_sockopt(&so_getorigdst6);
672a0ae2562SFlorian Westphal #endif
673a0ae2562SFlorian Westphal }
674a0ae2562SFlorian Westphal
nf_conntrack_proto_pernet_init(struct net * net)6754a60dc74SFlorian Westphal void nf_conntrack_proto_pernet_init(struct net *net)
676ac5357ebSPatrick McHardy {
6772a389de8SFlorian Westphal nf_conntrack_generic_init_net(net);
6782a389de8SFlorian Westphal nf_conntrack_udp_init_net(net);
6792a389de8SFlorian Westphal nf_conntrack_tcp_init_net(net);
6802a389de8SFlorian Westphal nf_conntrack_icmp_init_net(net);
68181e01647SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
6822a389de8SFlorian Westphal nf_conntrack_icmpv6_init_net(net);
68381e01647SFlorian Westphal #endif
6842a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP
6852a389de8SFlorian Westphal nf_conntrack_dccp_init_net(net);
6862a389de8SFlorian Westphal #endif
6872a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP
6882a389de8SFlorian Westphal nf_conntrack_sctp_init_net(net);
6892a389de8SFlorian Westphal #endif
6902a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
6912a389de8SFlorian Westphal nf_conntrack_gre_init_net(net);
6922a389de8SFlorian Westphal #endif
693ac5357ebSPatrick McHardy }
694ac5357ebSPatrick McHardy
695a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
696a0ae2562SFlorian Westphal &nf_conntrack_htable_size, 0600);
697a0ae2562SFlorian Westphal
698a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack");
699a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
700a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
701a0ae2562SFlorian Westphal MODULE_LICENSE("GPL");
702