1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Support nat functions for openvswitch and used by OVS and TC conntrack. */
4 #include <net/netfilter/nf_nat.h>
6 /* Modelled after nf_nat_ipv[46]_fn().
7 * range is only used for new, uninitialized NAT state.
8 * Returns either NF_ACCEPT or NF_DROP.
10 static int nf_ct_nat_execute(struct sk_buff
*skb
, struct nf_conn
*ct
,
11 enum ip_conntrack_info ctinfo
, int *action
,
12 const struct nf_nat_range2
*range
,
13 enum nf_nat_manip_type maniptype
)
15 __be16 proto
= skb_protocol(skb
, true);
16 int hooknum
, err
= NF_ACCEPT
;
18 /* See HOOK2MANIP(). */
19 if (maniptype
== NF_NAT_MANIP_SRC
)
20 hooknum
= NF_INET_LOCAL_IN
; /* Source NAT */
22 hooknum
= NF_INET_LOCAL_OUT
; /* Destination NAT */
26 case IP_CT_RELATED_REPLY
:
27 if (proto
== htons(ETH_P_IP
) &&
28 ip_hdr(skb
)->protocol
== IPPROTO_ICMP
) {
29 if (!nf_nat_icmp_reply_translation(skb
, ct
, ctinfo
,
33 } else if (IS_ENABLED(CONFIG_IPV6
) && proto
== htons(ETH_P_IPV6
)) {
35 u8 nexthdr
= ipv6_hdr(skb
)->nexthdr
;
36 int hdrlen
= ipv6_skip_exthdr(skb
,
37 sizeof(struct ipv6hdr
),
40 if (hdrlen
>= 0 && nexthdr
== IPPROTO_ICMPV6
) {
41 if (!nf_nat_icmpv6_reply_translation(skb
, ct
,
49 /* Non-ICMP, fall thru to initialize if needed. */
52 /* Seen it before? This can happen for loopback, retrans,
55 if (!nf_nat_initialized(ct
, maniptype
)) {
56 /* Initialize according to the NAT action. */
57 err
= (range
&& range
->flags
& NF_NAT_RANGE_MAP_IPS
)
58 /* Action is set up to establish a new
61 ? nf_nat_setup_info(ct
, range
, maniptype
)
62 : nf_nat_alloc_null_binding(ct
, hooknum
);
68 case IP_CT_ESTABLISHED
:
69 case IP_CT_ESTABLISHED_REPLY
:
77 err
= nf_nat_packet(ct
, ctinfo
, hooknum
, skb
);
80 *action
|= BIT(maniptype
);
85 int nf_ct_nat(struct sk_buff
*skb
, struct nf_conn
*ct
,
86 enum ip_conntrack_info ctinfo
, int *action
,
87 const struct nf_nat_range2
*range
, bool commit
)
89 enum nf_nat_manip_type maniptype
;
90 int err
, ct_action
= *action
;
94 /* Add NAT extension if not confirmed yet. */
95 if (!nf_ct_is_confirmed(ct
) && !nf_ct_nat_ext_add(ct
))
96 return NF_DROP
; /* Can't NAT. */
98 if (ctinfo
!= IP_CT_NEW
&& (ct
->status
& IPS_NAT_MASK
) &&
99 (ctinfo
!= IP_CT_RELATED
|| commit
)) {
100 /* NAT an established or related connection like before. */
101 if (CTINFO2DIR(ctinfo
) == IP_CT_DIR_REPLY
)
102 /* This is the REPLY direction for a connection
103 * for which NAT was applied in the forward
104 * direction. Do the reverse NAT.
106 maniptype
= ct
->status
& IPS_SRC_NAT
107 ? NF_NAT_MANIP_DST
: NF_NAT_MANIP_SRC
;
109 maniptype
= ct
->status
& IPS_SRC_NAT
110 ? NF_NAT_MANIP_SRC
: NF_NAT_MANIP_DST
;
111 } else if (ct_action
& BIT(NF_NAT_MANIP_SRC
)) {
112 maniptype
= NF_NAT_MANIP_SRC
;
113 } else if (ct_action
& BIT(NF_NAT_MANIP_DST
)) {
114 maniptype
= NF_NAT_MANIP_DST
;
119 err
= nf_ct_nat_execute(skb
, ct
, ctinfo
, action
, range
, maniptype
);
120 if (err
== NF_ACCEPT
&& ct
->status
& IPS_DST_NAT
) {
121 if (ct
->status
& IPS_SRC_NAT
) {
122 if (maniptype
== NF_NAT_MANIP_SRC
)
123 maniptype
= NF_NAT_MANIP_DST
;
125 maniptype
= NF_NAT_MANIP_SRC
;
127 err
= nf_ct_nat_execute(skb
, ct
, ctinfo
, action
, range
,
129 } else if (CTINFO2DIR(ctinfo
) == IP_CT_DIR_ORIGINAL
) {
130 err
= nf_ct_nat_execute(skb
, ct
, ctinfo
, action
, NULL
,
136 EXPORT_SYMBOL_GPL(nf_ct_nat
);