xref: /linux/net/netfilter/nf_nat_proto.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* (C) 1999-2001 Paul `Rusty' Russell
3  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
4  */
5 
6 #include <linux/types.h>
7 #include <linux/export.h>
8 #include <linux/init.h>
9 #include <linux/udp.h>
10 #include <linux/tcp.h>
11 #include <linux/icmp.h>
12 #include <linux/icmpv6.h>
13 
14 #include <linux/dccp.h>
15 #include <linux/sctp.h>
16 #include <net/sctp/checksum.h>
17 
18 #include <linux/netfilter.h>
19 #include <net/netfilter/nf_nat.h>
20 
21 #include <linux/ipv6.h>
22 #include <linux/netfilter_ipv6.h>
23 #include <net/checksum.h>
24 #include <net/ip6_checksum.h>
25 #include <net/ip6_route.h>
26 #include <net/xfrm.h>
27 #include <net/ipv6.h>
28 #include <net/pptp.h>
29 
30 #include <net/netfilter/nf_conntrack_core.h>
31 #include <net/netfilter/nf_conntrack.h>
32 #include <linux/netfilter/nfnetlink_conntrack.h>
33 
34 static void nf_csum_update(struct sk_buff *skb,
35 			   unsigned int iphdroff, __sum16 *check,
36 			   const struct nf_conntrack_tuple *t,
37 			   enum nf_nat_manip_type maniptype);
38 
39 static void
__udp_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,struct udphdr * hdr,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype,bool do_csum)40 __udp_manip_pkt(struct sk_buff *skb,
41 	        unsigned int iphdroff, struct udphdr *hdr,
42 	        const struct nf_conntrack_tuple *tuple,
43 	        enum nf_nat_manip_type maniptype, bool do_csum)
44 {
45 	__be16 *portptr, newport;
46 
47 	if (maniptype == NF_NAT_MANIP_SRC) {
48 		/* Get rid of src port */
49 		newport = tuple->src.u.udp.port;
50 		portptr = &hdr->source;
51 	} else {
52 		/* Get rid of dst port */
53 		newport = tuple->dst.u.udp.port;
54 		portptr = &hdr->dest;
55 	}
56 	if (do_csum) {
57 		nf_csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
58 		inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport,
59 					 false);
60 		if (!hdr->check)
61 			hdr->check = CSUM_MANGLED_0;
62 	}
63 	*portptr = newport;
64 }
65 
udp_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,unsigned int hdroff,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype)66 static bool udp_manip_pkt(struct sk_buff *skb,
67 			  unsigned int iphdroff, unsigned int hdroff,
68 			  const struct nf_conntrack_tuple *tuple,
69 			  enum nf_nat_manip_type maniptype)
70 {
71 	struct udphdr *hdr;
72 
73 	if (skb_ensure_writable(skb, hdroff + sizeof(*hdr)))
74 		return false;
75 
76 	hdr = (struct udphdr *)(skb->data + hdroff);
77 	__udp_manip_pkt(skb, iphdroff, hdr, tuple, maniptype, !!hdr->check);
78 
79 	return true;
80 }
81 
82 static bool
sctp_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,unsigned int hdroff,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype)83 sctp_manip_pkt(struct sk_buff *skb,
84 	       unsigned int iphdroff, unsigned int hdroff,
85 	       const struct nf_conntrack_tuple *tuple,
86 	       enum nf_nat_manip_type maniptype)
87 {
88 #ifdef CONFIG_NF_CT_PROTO_SCTP
89 	struct sctphdr *hdr;
90 	int hdrsize = 8;
91 
92 	/* This could be an inner header returned in imcp packet; in such
93 	 * cases we cannot update the checksum field since it is outside
94 	 * of the 8 bytes of transport layer headers we are guaranteed.
95 	 */
96 	if (skb->len >= hdroff + sizeof(*hdr))
97 		hdrsize = sizeof(*hdr);
98 
99 	if (skb_ensure_writable(skb, hdroff + hdrsize))
100 		return false;
101 
102 	hdr = (struct sctphdr *)(skb->data + hdroff);
103 
104 	if (maniptype == NF_NAT_MANIP_SRC) {
105 		/* Get rid of src port */
106 		hdr->source = tuple->src.u.sctp.port;
107 	} else {
108 		/* Get rid of dst port */
109 		hdr->dest = tuple->dst.u.sctp.port;
110 	}
111 
112 	if (hdrsize < sizeof(*hdr))
113 		return true;
114 
115 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
116 		hdr->checksum = sctp_compute_cksum(skb, hdroff);
117 		skb->ip_summed = CHECKSUM_NONE;
118 	}
119 
120 #endif
121 	return true;
122 }
123 
124 static bool
tcp_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,unsigned int hdroff,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype)125 tcp_manip_pkt(struct sk_buff *skb,
126 	      unsigned int iphdroff, unsigned int hdroff,
127 	      const struct nf_conntrack_tuple *tuple,
128 	      enum nf_nat_manip_type maniptype)
129 {
130 	struct tcphdr *hdr;
131 	__be16 *portptr, newport, oldport;
132 	int hdrsize = 8; /* TCP connection tracking guarantees this much */
133 
134 	/* this could be a inner header returned in icmp packet; in such
135 	   cases we cannot update the checksum field since it is outside of
136 	   the 8 bytes of transport layer headers we are guaranteed */
137 	if (skb->len >= hdroff + sizeof(struct tcphdr))
138 		hdrsize = sizeof(struct tcphdr);
139 
140 	if (skb_ensure_writable(skb, hdroff + hdrsize))
141 		return false;
142 
143 	hdr = (struct tcphdr *)(skb->data + hdroff);
144 
145 	if (maniptype == NF_NAT_MANIP_SRC) {
146 		/* Get rid of src port */
147 		newport = tuple->src.u.tcp.port;
148 		portptr = &hdr->source;
149 	} else {
150 		/* Get rid of dst port */
151 		newport = tuple->dst.u.tcp.port;
152 		portptr = &hdr->dest;
153 	}
154 
155 	oldport = *portptr;
156 	*portptr = newport;
157 
158 	if (hdrsize < sizeof(*hdr))
159 		return true;
160 
161 	nf_csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
162 	inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, false);
163 	return true;
164 }
165 
166 static bool
icmp_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,unsigned int hdroff,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype)167 icmp_manip_pkt(struct sk_buff *skb,
168 	       unsigned int iphdroff, unsigned int hdroff,
169 	       const struct nf_conntrack_tuple *tuple,
170 	       enum nf_nat_manip_type maniptype)
171 {
172 	struct icmphdr *hdr;
173 
174 	if (skb_ensure_writable(skb, hdroff + sizeof(*hdr)))
175 		return false;
176 
177 	hdr = (struct icmphdr *)(skb->data + hdroff);
178 	switch (hdr->type) {
179 	case ICMP_ECHO:
180 	case ICMP_ECHOREPLY:
181 	case ICMP_TIMESTAMP:
182 	case ICMP_TIMESTAMPREPLY:
183 	case ICMP_INFO_REQUEST:
184 	case ICMP_INFO_REPLY:
185 	case ICMP_ADDRESS:
186 	case ICMP_ADDRESSREPLY:
187 		break;
188 	default:
189 		return true;
190 	}
191 	inet_proto_csum_replace2(&hdr->checksum, skb,
192 				 hdr->un.echo.id, tuple->src.u.icmp.id, false);
193 	hdr->un.echo.id = tuple->src.u.icmp.id;
194 	return true;
195 }
196 
197 static bool
icmpv6_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,unsigned int hdroff,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype)198 icmpv6_manip_pkt(struct sk_buff *skb,
199 		 unsigned int iphdroff, unsigned int hdroff,
200 		 const struct nf_conntrack_tuple *tuple,
201 		 enum nf_nat_manip_type maniptype)
202 {
203 	struct icmp6hdr *hdr;
204 
205 	if (skb_ensure_writable(skb, hdroff + sizeof(*hdr)))
206 		return false;
207 
208 	hdr = (struct icmp6hdr *)(skb->data + hdroff);
209 	nf_csum_update(skb, iphdroff, &hdr->icmp6_cksum, tuple, maniptype);
210 	if (hdr->icmp6_type == ICMPV6_ECHO_REQUEST ||
211 	    hdr->icmp6_type == ICMPV6_ECHO_REPLY) {
212 		inet_proto_csum_replace2(&hdr->icmp6_cksum, skb,
213 					 hdr->icmp6_identifier,
214 					 tuple->src.u.icmp.id, false);
215 		hdr->icmp6_identifier = tuple->src.u.icmp.id;
216 	}
217 	return true;
218 }
219 
220 /* manipulate a GRE packet according to maniptype */
221 static bool
gre_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,unsigned int hdroff,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype)222 gre_manip_pkt(struct sk_buff *skb,
223 	      unsigned int iphdroff, unsigned int hdroff,
224 	      const struct nf_conntrack_tuple *tuple,
225 	      enum nf_nat_manip_type maniptype)
226 {
227 #if IS_ENABLED(CONFIG_NF_CT_PROTO_GRE)
228 	const struct gre_base_hdr *greh;
229 	struct pptp_gre_header *pgreh;
230 
231 	/* pgreh includes two optional 32bit fields which are not required
232 	 * to be there.  That's where the magic '8' comes from */
233 	if (skb_ensure_writable(skb, hdroff + sizeof(*pgreh) - 8))
234 		return false;
235 
236 	greh = (void *)skb->data + hdroff;
237 	pgreh = (struct pptp_gre_header *)greh;
238 
239 	/* we only have destination manip of a packet, since 'source key'
240 	 * is not present in the packet itself */
241 	if (maniptype != NF_NAT_MANIP_DST)
242 		return true;
243 
244 	switch (greh->flags & GRE_VERSION) {
245 	case GRE_VERSION_0:
246 		/* We do not currently NAT any GREv0 packets.
247 		 * Try to behave like "nf_nat_proto_unknown" */
248 		break;
249 	case GRE_VERSION_1:
250 		pr_debug("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
251 		pgreh->call_id = tuple->dst.u.gre.key;
252 		break;
253 	default:
254 		pr_debug("can't nat unknown GRE version\n");
255 		return false;
256 	}
257 #endif
258 	return true;
259 }
260 
l4proto_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,unsigned int hdroff,const struct nf_conntrack_tuple * tuple,enum nf_nat_manip_type maniptype)261 static bool l4proto_manip_pkt(struct sk_buff *skb,
262 			      unsigned int iphdroff, unsigned int hdroff,
263 			      const struct nf_conntrack_tuple *tuple,
264 			      enum nf_nat_manip_type maniptype)
265 {
266 	switch (tuple->dst.protonum) {
267 	case IPPROTO_TCP:
268 		return tcp_manip_pkt(skb, iphdroff, hdroff,
269 				     tuple, maniptype);
270 	case IPPROTO_UDP:
271 		return udp_manip_pkt(skb, iphdroff, hdroff,
272 				     tuple, maniptype);
273 	case IPPROTO_SCTP:
274 		return sctp_manip_pkt(skb, iphdroff, hdroff,
275 				      tuple, maniptype);
276 	case IPPROTO_ICMP:
277 		return icmp_manip_pkt(skb, iphdroff, hdroff,
278 				      tuple, maniptype);
279 	case IPPROTO_ICMPV6:
280 		return icmpv6_manip_pkt(skb, iphdroff, hdroff,
281 					tuple, maniptype);
282 	case IPPROTO_GRE:
283 		return gre_manip_pkt(skb, iphdroff, hdroff,
284 				     tuple, maniptype);
285 	}
286 
287 	/* If we don't know protocol -- no error, pass it unmodified. */
288 	return true;
289 }
290 
nf_nat_ipv4_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,const struct nf_conntrack_tuple * target,enum nf_nat_manip_type maniptype)291 static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb,
292 				  unsigned int iphdroff,
293 				  const struct nf_conntrack_tuple *target,
294 				  enum nf_nat_manip_type maniptype)
295 {
296 	struct iphdr *iph;
297 	unsigned int hdroff;
298 
299 	if (skb_ensure_writable(skb, iphdroff + sizeof(*iph)))
300 		return false;
301 
302 	iph = (void *)skb->data + iphdroff;
303 	hdroff = iphdroff + iph->ihl * 4;
304 
305 	if (!l4proto_manip_pkt(skb, iphdroff, hdroff, target, maniptype))
306 		return false;
307 	iph = (void *)skb->data + iphdroff;
308 
309 	if (maniptype == NF_NAT_MANIP_SRC) {
310 		csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
311 		iph->saddr = target->src.u3.ip;
312 	} else {
313 		csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
314 		iph->daddr = target->dst.u3.ip;
315 	}
316 	return true;
317 }
318 
nf_nat_ipv6_manip_pkt(struct sk_buff * skb,unsigned int iphdroff,const struct nf_conntrack_tuple * target,enum nf_nat_manip_type maniptype)319 static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
320 				  unsigned int iphdroff,
321 				  const struct nf_conntrack_tuple *target,
322 				  enum nf_nat_manip_type maniptype)
323 {
324 #if IS_ENABLED(CONFIG_IPV6)
325 	struct ipv6hdr *ipv6h;
326 	__be16 frag_off;
327 	int hdroff;
328 	u8 nexthdr;
329 
330 	if (skb_ensure_writable(skb, iphdroff + sizeof(*ipv6h)))
331 		return false;
332 
333 	ipv6h = (void *)skb->data + iphdroff;
334 	nexthdr = ipv6h->nexthdr;
335 	hdroff = ipv6_skip_exthdr(skb, iphdroff + sizeof(*ipv6h),
336 				  &nexthdr, &frag_off);
337 	if (hdroff < 0)
338 		goto manip_addr;
339 
340 	if ((frag_off & htons(~0x7)) == 0 &&
341 	    !l4proto_manip_pkt(skb, iphdroff, hdroff, target, maniptype))
342 		return false;
343 
344 	/* must reload, offset might have changed */
345 	ipv6h = (void *)skb->data + iphdroff;
346 
347 manip_addr:
348 	if (maniptype == NF_NAT_MANIP_SRC)
349 		ipv6h->saddr = target->src.u3.in6;
350 	else
351 		ipv6h->daddr = target->dst.u3.in6;
352 
353 #endif
354 	return true;
355 }
356 
nf_nat_manip_pkt(struct sk_buff * skb,struct nf_conn * ct,enum nf_nat_manip_type mtype,enum ip_conntrack_dir dir)357 unsigned int nf_nat_manip_pkt(struct sk_buff *skb, struct nf_conn *ct,
358 			      enum nf_nat_manip_type mtype,
359 			      enum ip_conntrack_dir dir)
360 {
361 	struct nf_conntrack_tuple target;
362 
363 	/* We are aiming to look like inverse of other direction. */
364 	nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple);
365 
366 	switch (target.src.l3num) {
367 	case NFPROTO_IPV6:
368 		if (nf_nat_ipv6_manip_pkt(skb, 0, &target, mtype))
369 			return NF_ACCEPT;
370 		break;
371 	case NFPROTO_IPV4:
372 		if (nf_nat_ipv4_manip_pkt(skb, 0, &target, mtype))
373 			return NF_ACCEPT;
374 		break;
375 	default:
376 		WARN_ON_ONCE(1);
377 		break;
378 	}
379 
380 	return NF_DROP;
381 }
382 
nf_nat_ipv4_csum_update(struct sk_buff * skb,unsigned int iphdroff,__sum16 * check,const struct nf_conntrack_tuple * t,enum nf_nat_manip_type maniptype)383 static void nf_nat_ipv4_csum_update(struct sk_buff *skb,
384 				    unsigned int iphdroff, __sum16 *check,
385 				    const struct nf_conntrack_tuple *t,
386 				    enum nf_nat_manip_type maniptype)
387 {
388 	struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
389 	__be32 oldip, newip;
390 
391 	if (maniptype == NF_NAT_MANIP_SRC) {
392 		oldip = iph->saddr;
393 		newip = t->src.u3.ip;
394 	} else {
395 		oldip = iph->daddr;
396 		newip = t->dst.u3.ip;
397 	}
398 	inet_proto_csum_replace4(check, skb, oldip, newip, true);
399 }
400 
nf_nat_ipv6_csum_update(struct sk_buff * skb,unsigned int iphdroff,__sum16 * check,const struct nf_conntrack_tuple * t,enum nf_nat_manip_type maniptype)401 static void nf_nat_ipv6_csum_update(struct sk_buff *skb,
402 				    unsigned int iphdroff, __sum16 *check,
403 				    const struct nf_conntrack_tuple *t,
404 				    enum nf_nat_manip_type maniptype)
405 {
406 #if IS_ENABLED(CONFIG_IPV6)
407 	const struct ipv6hdr *ipv6h = (struct ipv6hdr *)(skb->data + iphdroff);
408 	const struct in6_addr *oldip, *newip;
409 
410 	if (maniptype == NF_NAT_MANIP_SRC) {
411 		oldip = &ipv6h->saddr;
412 		newip = &t->src.u3.in6;
413 	} else {
414 		oldip = &ipv6h->daddr;
415 		newip = &t->dst.u3.in6;
416 	}
417 	inet_proto_csum_replace16(check, skb, oldip->s6_addr32,
418 				  newip->s6_addr32, true);
419 #endif
420 }
421 
nf_csum_update(struct sk_buff * skb,unsigned int iphdroff,__sum16 * check,const struct nf_conntrack_tuple * t,enum nf_nat_manip_type maniptype)422 static void nf_csum_update(struct sk_buff *skb,
423 			   unsigned int iphdroff, __sum16 *check,
424 			   const struct nf_conntrack_tuple *t,
425 			   enum nf_nat_manip_type maniptype)
426 {
427 	switch (t->src.l3num) {
428 	case NFPROTO_IPV4:
429 		nf_nat_ipv4_csum_update(skb, iphdroff, check, t, maniptype);
430 		return;
431 	case NFPROTO_IPV6:
432 		nf_nat_ipv6_csum_update(skb, iphdroff, check, t, maniptype);
433 		return;
434 	}
435 }
436 
nf_nat_ipv4_csum_recalc(struct sk_buff * skb,u8 proto,void * data,__sum16 * check,int datalen,int oldlen)437 static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
438 				    u8 proto, void *data, __sum16 *check,
439 				    int datalen, int oldlen)
440 {
441 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
442 		const struct iphdr *iph = ip_hdr(skb);
443 
444 		skb->ip_summed = CHECKSUM_PARTIAL;
445 		skb->csum_start = skb_headroom(skb) + skb_network_offset(skb) +
446 			ip_hdrlen(skb);
447 		skb->csum_offset = (void *)check - data;
448 		*check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, datalen,
449 					    proto, 0);
450 	} else {
451 		inet_proto_csum_replace2(check, skb,
452 					 htons(oldlen), htons(datalen), true);
453 	}
454 }
455 
456 #if IS_ENABLED(CONFIG_IPV6)
nf_nat_ipv6_csum_recalc(struct sk_buff * skb,u8 proto,void * data,__sum16 * check,int datalen,int oldlen)457 static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb,
458 				    u8 proto, void *data, __sum16 *check,
459 				    int datalen, int oldlen)
460 {
461 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
462 		const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
463 
464 		skb->ip_summed = CHECKSUM_PARTIAL;
465 		skb->csum_start = skb_headroom(skb) + skb_network_offset(skb) +
466 			(data - (void *)skb->data);
467 		skb->csum_offset = (void *)check - data;
468 		*check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
469 					  datalen, proto, 0);
470 	} else {
471 		inet_proto_csum_replace2(check, skb,
472 					 htons(oldlen), htons(datalen), true);
473 	}
474 }
475 #endif
476 
nf_nat_csum_recalc(struct sk_buff * skb,u8 nfproto,u8 proto,void * data,__sum16 * check,int datalen,int oldlen)477 void nf_nat_csum_recalc(struct sk_buff *skb,
478 			u8 nfproto, u8 proto, void *data, __sum16 *check,
479 			int datalen, int oldlen)
480 {
481 	switch (nfproto) {
482 	case NFPROTO_IPV4:
483 		nf_nat_ipv4_csum_recalc(skb, proto, data, check,
484 					datalen, oldlen);
485 		return;
486 #if IS_ENABLED(CONFIG_IPV6)
487 	case NFPROTO_IPV6:
488 		nf_nat_ipv6_csum_recalc(skb, proto, data, check,
489 					datalen, oldlen);
490 		return;
491 #endif
492 	}
493 
494 	WARN_ON_ONCE(1);
495 }
496 
nf_nat_icmp_reply_translation(struct sk_buff * skb,struct nf_conn * ct,enum ip_conntrack_info ctinfo,unsigned int hooknum)497 int nf_nat_icmp_reply_translation(struct sk_buff *skb,
498 				  struct nf_conn *ct,
499 				  enum ip_conntrack_info ctinfo,
500 				  unsigned int hooknum)
501 {
502 	struct {
503 		struct icmphdr	icmp;
504 		struct iphdr	ip;
505 	} *inside;
506 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
507 	enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
508 	unsigned int hdrlen = ip_hdrlen(skb);
509 	struct nf_conntrack_tuple target;
510 	unsigned long statusbit;
511 
512 	WARN_ON(ctinfo != IP_CT_RELATED && ctinfo != IP_CT_RELATED_REPLY);
513 
514 	if (skb_ensure_writable(skb, hdrlen + sizeof(*inside)))
515 		return 0;
516 	if (nf_ip_checksum(skb, hooknum, hdrlen, IPPROTO_ICMP))
517 		return 0;
518 
519 	inside = (void *)skb->data + hdrlen;
520 	if (inside->icmp.type == ICMP_REDIRECT) {
521 		if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
522 			return 0;
523 		if (ct->status & IPS_NAT_MASK)
524 			return 0;
525 	}
526 
527 	if (manip == NF_NAT_MANIP_SRC)
528 		statusbit = IPS_SRC_NAT;
529 	else
530 		statusbit = IPS_DST_NAT;
531 
532 	/* Invert if this is reply direction */
533 	if (dir == IP_CT_DIR_REPLY)
534 		statusbit ^= IPS_NAT_MASK;
535 
536 	if (!(ct->status & statusbit))
537 		return 1;
538 
539 	if (!nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp),
540 				   &ct->tuplehash[!dir].tuple, !manip))
541 		return 0;
542 
543 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
544 		/* Reloading "inside" here since manip_pkt may reallocate */
545 		inside = (void *)skb->data + hdrlen;
546 		inside->icmp.checksum = 0;
547 		inside->icmp.checksum =
548 			csum_fold(skb_checksum(skb, hdrlen,
549 					       skb->len - hdrlen, 0));
550 	}
551 
552 	/* Change outer to look like the reply to an incoming packet */
553 	nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple);
554 	target.dst.protonum = IPPROTO_ICMP;
555 	if (!nf_nat_ipv4_manip_pkt(skb, 0, &target, manip))
556 		return 0;
557 
558 	return 1;
559 }
560 EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
561 
562 static unsigned int
nf_nat_ipv4_fn(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)563 nf_nat_ipv4_fn(void *priv, struct sk_buff *skb,
564 	       const struct nf_hook_state *state)
565 {
566 	struct nf_conn *ct;
567 	enum ip_conntrack_info ctinfo;
568 
569 	ct = nf_ct_get(skb, &ctinfo);
570 	if (!ct)
571 		return NF_ACCEPT;
572 
573 	if (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY) {
574 		if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
575 			if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
576 							   state->hook))
577 				return NF_DROP;
578 			else
579 				return NF_ACCEPT;
580 		}
581 	}
582 
583 	return nf_nat_inet_fn(priv, skb, state);
584 }
585 
586 static unsigned int
nf_nat_ipv4_pre_routing(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)587 nf_nat_ipv4_pre_routing(void *priv, struct sk_buff *skb,
588 			const struct nf_hook_state *state)
589 {
590 	unsigned int ret;
591 	__be32 daddr = ip_hdr(skb)->daddr;
592 
593 	ret = nf_nat_ipv4_fn(priv, skb, state);
594 	if (ret == NF_ACCEPT && daddr != ip_hdr(skb)->daddr)
595 		skb_dst_drop(skb);
596 
597 	return ret;
598 }
599 
600 #ifdef CONFIG_XFRM
nf_xfrm_me_harder(struct net * net,struct sk_buff * skb,unsigned int family)601 static int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
602 {
603 	struct sock *sk = skb->sk;
604 	struct dst_entry *dst;
605 	unsigned int hh_len;
606 	struct flowi fl;
607 	int err;
608 
609 	err = xfrm_decode_session(net, skb, &fl, family);
610 	if (err < 0)
611 		return err;
612 
613 	dst = skb_dst(skb);
614 	if (dst->xfrm)
615 		dst = ((struct xfrm_dst *)dst)->route;
616 	if (!dst_hold_safe(dst))
617 		return -EHOSTUNREACH;
618 
619 	if (sk && !net_eq(net, sock_net(sk)))
620 		sk = NULL;
621 
622 	dst = xfrm_lookup(net, dst, &fl, sk, 0);
623 	if (IS_ERR(dst))
624 		return PTR_ERR(dst);
625 
626 	skb_dst_drop(skb);
627 	skb_dst_set(skb, dst);
628 
629 	/* Change in oif may mean change in hh_len. */
630 	hh_len = skb_dst(skb)->dev->hard_header_len;
631 	if (skb_headroom(skb) < hh_len &&
632 	    pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
633 		return -ENOMEM;
634 	return 0;
635 }
636 #endif
637 
nf_nat_inet_port_was_mangled(const struct sk_buff * skb,__be16 sport)638 static bool nf_nat_inet_port_was_mangled(const struct sk_buff *skb, __be16 sport)
639 {
640 	enum ip_conntrack_info ctinfo;
641 	enum ip_conntrack_dir dir;
642 	const struct nf_conn *ct;
643 
644 	ct = nf_ct_get(skb, &ctinfo);
645 	if (!ct)
646 		return false;
647 
648 	switch (nf_ct_protonum(ct)) {
649 	case IPPROTO_TCP:
650 	case IPPROTO_UDP:
651 		break;
652 	default:
653 		return false;
654 	}
655 
656 	dir = CTINFO2DIR(ctinfo);
657 	if (dir != IP_CT_DIR_ORIGINAL)
658 		return false;
659 
660 	return ct->tuplehash[!dir].tuple.dst.u.all != sport;
661 }
662 
663 static unsigned int
nf_nat_ipv4_local_in(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)664 nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb,
665 		     const struct nf_hook_state *state)
666 {
667 	__be32 saddr = ip_hdr(skb)->saddr;
668 	struct sock *sk = skb->sk;
669 	unsigned int ret;
670 
671 	ret = nf_nat_ipv4_fn(priv, skb, state);
672 
673 	if (ret != NF_ACCEPT || !sk || inet_sk_transparent(sk))
674 		return ret;
675 
676 	/* skb has a socket assigned via tcp edemux. We need to check
677 	 * if nf_nat_ipv4_fn() has mangled the packet in a way that
678 	 * edemux would not have found this socket.
679 	 *
680 	 * This includes both changes to the source address and changes
681 	 * to the source port, which are both handled by the
682 	 * nf_nat_ipv4_fn() call above -- long after tcp/udp early demux
683 	 * might have found a socket for the old (pre-snat) address.
684 	 */
685 	if (saddr != ip_hdr(skb)->saddr ||
686 	    nf_nat_inet_port_was_mangled(skb, sk->sk_dport))
687 		skb_orphan(skb); /* TCP edemux obtained wrong socket */
688 
689 	return ret;
690 }
691 
692 static unsigned int
nf_nat_ipv4_out(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)693 nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
694 		const struct nf_hook_state *state)
695 {
696 #ifdef CONFIG_XFRM
697 	const struct nf_conn *ct;
698 	enum ip_conntrack_info ctinfo;
699 	int err;
700 #endif
701 	unsigned int ret;
702 
703 	ret = nf_nat_ipv4_fn(priv, skb, state);
704 #ifdef CONFIG_XFRM
705 	if (ret != NF_ACCEPT)
706 		return ret;
707 
708 	if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
709 		return ret;
710 
711 	ct = nf_ct_get(skb, &ctinfo);
712 	if (ct) {
713 		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
714 
715 		if (ct->tuplehash[dir].tuple.src.u3.ip !=
716 		     ct->tuplehash[!dir].tuple.dst.u3.ip ||
717 		    (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
718 		     ct->tuplehash[dir].tuple.src.u.all !=
719 		     ct->tuplehash[!dir].tuple.dst.u.all)) {
720 			err = nf_xfrm_me_harder(state->net, skb, AF_INET);
721 			if (err < 0)
722 				ret = NF_DROP_ERR(err);
723 		}
724 	}
725 #endif
726 	return ret;
727 }
728 
729 static unsigned int
nf_nat_ipv4_local_fn(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)730 nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
731 		     const struct nf_hook_state *state)
732 {
733 	const struct nf_conn *ct;
734 	enum ip_conntrack_info ctinfo;
735 	unsigned int ret;
736 	int err;
737 
738 	ret = nf_nat_ipv4_fn(priv, skb, state);
739 	if (ret != NF_ACCEPT)
740 		return ret;
741 
742 	ct = nf_ct_get(skb, &ctinfo);
743 	if (ct) {
744 		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
745 
746 		if (ct->tuplehash[dir].tuple.dst.u3.ip !=
747 		    ct->tuplehash[!dir].tuple.src.u3.ip) {
748 			err = ip_route_me_harder(state->net, state->sk, skb, RTN_UNSPEC);
749 			if (err < 0)
750 				ret = NF_DROP_ERR(err);
751 		}
752 #ifdef CONFIG_XFRM
753 		else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
754 			 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
755 			 ct->tuplehash[dir].tuple.dst.u.all !=
756 			 ct->tuplehash[!dir].tuple.src.u.all) {
757 			err = nf_xfrm_me_harder(state->net, skb, AF_INET);
758 			if (err < 0)
759 				ret = NF_DROP_ERR(err);
760 		}
761 #endif
762 	}
763 	return ret;
764 }
765 
766 static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
767 	/* Before packet filtering, change destination */
768 	{
769 		.hook		= nf_nat_ipv4_pre_routing,
770 		.pf		= NFPROTO_IPV4,
771 		.hooknum	= NF_INET_PRE_ROUTING,
772 		.priority	= NF_IP_PRI_NAT_DST,
773 		.hook_ops_type	= NF_HOOK_OP_NAT,
774 	},
775 	/* After packet filtering, change source */
776 	{
777 		.hook		= nf_nat_ipv4_out,
778 		.pf		= NFPROTO_IPV4,
779 		.hooknum	= NF_INET_POST_ROUTING,
780 		.priority	= NF_IP_PRI_NAT_SRC,
781 		.hook_ops_type	= NF_HOOK_OP_NAT,
782 	},
783 	/* Before packet filtering, change destination */
784 	{
785 		.hook		= nf_nat_ipv4_local_fn,
786 		.pf		= NFPROTO_IPV4,
787 		.hooknum	= NF_INET_LOCAL_OUT,
788 		.priority	= NF_IP_PRI_NAT_DST,
789 		.hook_ops_type	= NF_HOOK_OP_NAT,
790 	},
791 	/* After packet filtering, change source */
792 	{
793 		.hook		= nf_nat_ipv4_local_in,
794 		.pf		= NFPROTO_IPV4,
795 		.hooknum	= NF_INET_LOCAL_IN,
796 		.priority	= NF_IP_PRI_NAT_SRC,
797 		.hook_ops_type	= NF_HOOK_OP_NAT,
798 	},
799 };
800 
nf_nat_ipv4_register_fn(struct net * net,const struct nf_hook_ops * ops)801 int nf_nat_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops)
802 {
803 	return nf_nat_register_fn(net, ops->pf, ops, nf_nat_ipv4_ops,
804 				  ARRAY_SIZE(nf_nat_ipv4_ops));
805 }
806 EXPORT_SYMBOL_GPL(nf_nat_ipv4_register_fn);
807 
nf_nat_ipv4_unregister_fn(struct net * net,const struct nf_hook_ops * ops)808 void nf_nat_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
809 {
810 	nf_nat_unregister_fn(net, ops->pf, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
811 }
812 EXPORT_SYMBOL_GPL(nf_nat_ipv4_unregister_fn);
813 
814 #if IS_ENABLED(CONFIG_IPV6)
nf_nat_icmpv6_reply_translation(struct sk_buff * skb,struct nf_conn * ct,enum ip_conntrack_info ctinfo,unsigned int hooknum,unsigned int hdrlen)815 int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
816 				    struct nf_conn *ct,
817 				    enum ip_conntrack_info ctinfo,
818 				    unsigned int hooknum,
819 				    unsigned int hdrlen)
820 {
821 	struct {
822 		struct icmp6hdr	icmp6;
823 		struct ipv6hdr	ip6;
824 	} *inside;
825 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
826 	enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
827 	struct nf_conntrack_tuple target;
828 	unsigned long statusbit;
829 
830 	WARN_ON(ctinfo != IP_CT_RELATED && ctinfo != IP_CT_RELATED_REPLY);
831 
832 	if (skb_ensure_writable(skb, hdrlen + sizeof(*inside)))
833 		return 0;
834 	if (nf_ip6_checksum(skb, hooknum, hdrlen, IPPROTO_ICMPV6))
835 		return 0;
836 
837 	inside = (void *)skb->data + hdrlen;
838 	if (inside->icmp6.icmp6_type == NDISC_REDIRECT) {
839 		if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
840 			return 0;
841 		if (ct->status & IPS_NAT_MASK)
842 			return 0;
843 	}
844 
845 	if (manip == NF_NAT_MANIP_SRC)
846 		statusbit = IPS_SRC_NAT;
847 	else
848 		statusbit = IPS_DST_NAT;
849 
850 	/* Invert if this is reply direction */
851 	if (dir == IP_CT_DIR_REPLY)
852 		statusbit ^= IPS_NAT_MASK;
853 
854 	if (!(ct->status & statusbit))
855 		return 1;
856 
857 	if (!nf_nat_ipv6_manip_pkt(skb, hdrlen + sizeof(inside->icmp6),
858 				   &ct->tuplehash[!dir].tuple, !manip))
859 		return 0;
860 
861 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
862 		struct ipv6hdr *ipv6h = ipv6_hdr(skb);
863 
864 		inside = (void *)skb->data + hdrlen;
865 		inside->icmp6.icmp6_cksum = 0;
866 		inside->icmp6.icmp6_cksum =
867 			csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
868 					skb->len - hdrlen, IPPROTO_ICMPV6,
869 					skb_checksum(skb, hdrlen,
870 						     skb->len - hdrlen, 0));
871 	}
872 
873 	nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple);
874 	target.dst.protonum = IPPROTO_ICMPV6;
875 	if (!nf_nat_ipv6_manip_pkt(skb, 0, &target, manip))
876 		return 0;
877 
878 	return 1;
879 }
880 EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation);
881 
882 static unsigned int
nf_nat_ipv6_fn(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)883 nf_nat_ipv6_fn(void *priv, struct sk_buff *skb,
884 	       const struct nf_hook_state *state)
885 {
886 	struct nf_conn *ct;
887 	enum ip_conntrack_info ctinfo;
888 	__be16 frag_off;
889 	int hdrlen;
890 	u8 nexthdr;
891 
892 	ct = nf_ct_get(skb, &ctinfo);
893 	/* Can't track?  It's not due to stress, or conntrack would
894 	 * have dropped it.  Hence it's the user's responsibilty to
895 	 * packet filter it out, or implement conntrack/NAT for that
896 	 * protocol. 8) --RR
897 	 */
898 	if (!ct)
899 		return NF_ACCEPT;
900 
901 	if (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY) {
902 		nexthdr = ipv6_hdr(skb)->nexthdr;
903 		hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
904 					  &nexthdr, &frag_off);
905 
906 		if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
907 			if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
908 							     state->hook,
909 							     hdrlen))
910 				return NF_DROP;
911 			else
912 				return NF_ACCEPT;
913 		}
914 	}
915 
916 	return nf_nat_inet_fn(priv, skb, state);
917 }
918 
919 static unsigned int
nf_nat_ipv6_local_in(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)920 nf_nat_ipv6_local_in(void *priv, struct sk_buff *skb,
921 		     const struct nf_hook_state *state)
922 {
923 	struct in6_addr saddr = ipv6_hdr(skb)->saddr;
924 	struct sock *sk = skb->sk;
925 	unsigned int ret;
926 
927 	ret = nf_nat_ipv6_fn(priv, skb, state);
928 
929 	if (ret != NF_ACCEPT || !sk || inet_sk_transparent(sk))
930 		return ret;
931 
932 	/* see nf_nat_ipv4_local_in */
933 	if (ipv6_addr_cmp(&saddr, &ipv6_hdr(skb)->saddr) ||
934 	    nf_nat_inet_port_was_mangled(skb, sk->sk_dport))
935 		skb_orphan(skb);
936 
937 	return ret;
938 }
939 
940 static unsigned int
nf_nat_ipv6_in(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)941 nf_nat_ipv6_in(void *priv, struct sk_buff *skb,
942 	       const struct nf_hook_state *state)
943 {
944 	unsigned int ret, verdict;
945 	struct in6_addr daddr = ipv6_hdr(skb)->daddr;
946 
947 	ret = nf_nat_ipv6_fn(priv, skb, state);
948 	verdict = ret & NF_VERDICT_MASK;
949 	if (verdict != NF_DROP && verdict != NF_STOLEN &&
950 	    ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
951 		skb_dst_drop(skb);
952 
953 	return ret;
954 }
955 
956 static unsigned int
nf_nat_ipv6_out(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)957 nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
958 		const struct nf_hook_state *state)
959 {
960 #ifdef CONFIG_XFRM
961 	const struct nf_conn *ct;
962 	enum ip_conntrack_info ctinfo;
963 	int err;
964 #endif
965 	unsigned int ret;
966 
967 	ret = nf_nat_ipv6_fn(priv, skb, state);
968 #ifdef CONFIG_XFRM
969 	if (ret != NF_ACCEPT)
970 		return ret;
971 
972 	if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
973 		return ret;
974 	ct = nf_ct_get(skb, &ctinfo);
975 	if (ct) {
976 		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
977 
978 		if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
979 				      &ct->tuplehash[!dir].tuple.dst.u3) ||
980 		    (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
981 		     ct->tuplehash[dir].tuple.src.u.all !=
982 		     ct->tuplehash[!dir].tuple.dst.u.all)) {
983 			err = nf_xfrm_me_harder(state->net, skb, AF_INET6);
984 			if (err < 0)
985 				ret = NF_DROP_ERR(err);
986 		}
987 	}
988 #endif
989 
990 	return ret;
991 }
992 
993 static unsigned int
nf_nat_ipv6_local_fn(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)994 nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
995 		     const struct nf_hook_state *state)
996 {
997 	const struct nf_conn *ct;
998 	enum ip_conntrack_info ctinfo;
999 	unsigned int ret;
1000 	int err;
1001 
1002 	ret = nf_nat_ipv6_fn(priv, skb, state);
1003 	if (ret != NF_ACCEPT)
1004 		return ret;
1005 
1006 	ct = nf_ct_get(skb, &ctinfo);
1007 	if (ct) {
1008 		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
1009 
1010 		if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
1011 				      &ct->tuplehash[!dir].tuple.src.u3)) {
1012 			err = nf_ip6_route_me_harder(state->net, state->sk, skb);
1013 			if (err < 0)
1014 				ret = NF_DROP_ERR(err);
1015 		}
1016 #ifdef CONFIG_XFRM
1017 		else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
1018 			 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
1019 			 ct->tuplehash[dir].tuple.dst.u.all !=
1020 			 ct->tuplehash[!dir].tuple.src.u.all) {
1021 			err = nf_xfrm_me_harder(state->net, skb, AF_INET6);
1022 			if (err < 0)
1023 				ret = NF_DROP_ERR(err);
1024 		}
1025 #endif
1026 	}
1027 
1028 	return ret;
1029 }
1030 
1031 static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
1032 	/* Before packet filtering, change destination */
1033 	{
1034 		.hook		= nf_nat_ipv6_in,
1035 		.pf		= NFPROTO_IPV6,
1036 		.hooknum	= NF_INET_PRE_ROUTING,
1037 		.priority	= NF_IP6_PRI_NAT_DST,
1038 		.hook_ops_type	= NF_HOOK_OP_NAT,
1039 	},
1040 	/* After packet filtering, change source */
1041 	{
1042 		.hook		= nf_nat_ipv6_out,
1043 		.pf		= NFPROTO_IPV6,
1044 		.hooknum	= NF_INET_POST_ROUTING,
1045 		.priority	= NF_IP6_PRI_NAT_SRC,
1046 		.hook_ops_type	= NF_HOOK_OP_NAT,
1047 	},
1048 	/* Before packet filtering, change destination */
1049 	{
1050 		.hook		= nf_nat_ipv6_local_fn,
1051 		.pf		= NFPROTO_IPV6,
1052 		.hooknum	= NF_INET_LOCAL_OUT,
1053 		.priority	= NF_IP6_PRI_NAT_DST,
1054 		.hook_ops_type	= NF_HOOK_OP_NAT,
1055 	},
1056 	/* After packet filtering, change source */
1057 	{
1058 		.hook		= nf_nat_ipv6_local_in,
1059 		.pf		= NFPROTO_IPV6,
1060 		.hooknum	= NF_INET_LOCAL_IN,
1061 		.priority	= NF_IP6_PRI_NAT_SRC,
1062 		.hook_ops_type	= NF_HOOK_OP_NAT,
1063 	},
1064 };
1065 
nf_nat_ipv6_register_fn(struct net * net,const struct nf_hook_ops * ops)1066 int nf_nat_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops)
1067 {
1068 	return nf_nat_register_fn(net, ops->pf, ops, nf_nat_ipv6_ops,
1069 				  ARRAY_SIZE(nf_nat_ipv6_ops));
1070 }
1071 EXPORT_SYMBOL_GPL(nf_nat_ipv6_register_fn);
1072 
nf_nat_ipv6_unregister_fn(struct net * net,const struct nf_hook_ops * ops)1073 void nf_nat_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
1074 {
1075 	nf_nat_unregister_fn(net, ops->pf, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
1076 }
1077 EXPORT_SYMBOL_GPL(nf_nat_ipv6_unregister_fn);
1078 #endif /* CONFIG_IPV6 */
1079 
1080 #if defined(CONFIG_NF_TABLES_INET) && IS_ENABLED(CONFIG_NFT_NAT)
nf_nat_inet_register_fn(struct net * net,const struct nf_hook_ops * ops)1081 int nf_nat_inet_register_fn(struct net *net, const struct nf_hook_ops *ops)
1082 {
1083 	int ret;
1084 
1085 	if (WARN_ON_ONCE(ops->pf != NFPROTO_INET))
1086 		return -EINVAL;
1087 
1088 	ret = nf_nat_register_fn(net, NFPROTO_IPV6, ops, nf_nat_ipv6_ops,
1089 				 ARRAY_SIZE(nf_nat_ipv6_ops));
1090 	if (ret)
1091 		return ret;
1092 
1093 	ret = nf_nat_register_fn(net, NFPROTO_IPV4, ops, nf_nat_ipv4_ops,
1094 				 ARRAY_SIZE(nf_nat_ipv4_ops));
1095 	if (ret)
1096 		nf_nat_unregister_fn(net, NFPROTO_IPV6, ops,
1097 					ARRAY_SIZE(nf_nat_ipv6_ops));
1098 	return ret;
1099 }
1100 EXPORT_SYMBOL_GPL(nf_nat_inet_register_fn);
1101 
nf_nat_inet_unregister_fn(struct net * net,const struct nf_hook_ops * ops)1102 void nf_nat_inet_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
1103 {
1104 	nf_nat_unregister_fn(net, NFPROTO_IPV4, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
1105 	nf_nat_unregister_fn(net, NFPROTO_IPV6, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
1106 }
1107 EXPORT_SYMBOL_GPL(nf_nat_inet_unregister_fn);
1108 #endif /* NFT INET NAT */
1109