1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Support nat functions for openvswitch and used by OVS and TC conntrack. */ 3 4 #include <net/netfilter/nf_nat.h> 5 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. 9 */ 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) 14 { 15 __be16 proto = skb_protocol(skb, true); 16 int hooknum, err = NF_ACCEPT; 17 18 /* See HOOK2MANIP(). */ 19 if (maniptype == NF_NAT_MANIP_SRC) 20 hooknum = NF_INET_LOCAL_IN; /* Source NAT */ 21 else 22 hooknum = NF_INET_LOCAL_OUT; /* Destination NAT */ 23 24 switch (ctinfo) { 25 case IP_CT_RELATED: 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, 30 hooknum)) 31 err = NF_DROP; 32 goto out; 33 } else if (IS_ENABLED(CONFIG_IPV6) && proto == htons(ETH_P_IPV6)) { 34 __be16 frag_off; 35 u8 nexthdr = ipv6_hdr(skb)->nexthdr; 36 int hdrlen = ipv6_skip_exthdr(skb, 37 sizeof(struct ipv6hdr), 38 &nexthdr, &frag_off); 39 40 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { 41 if (!nf_nat_icmpv6_reply_translation(skb, ct, 42 ctinfo, 43 hooknum, 44 hdrlen)) 45 err = NF_DROP; 46 goto out; 47 } 48 } 49 /* Non-ICMP, fall thru to initialize if needed. */ 50 fallthrough; 51 case IP_CT_NEW: 52 /* Seen it before? This can happen for loopback, retrans, 53 * or local packets. 54 */ 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 59 * mapping. 60 */ 61 ? nf_nat_setup_info(ct, range, maniptype) 62 : nf_nat_alloc_null_binding(ct, hooknum); 63 if (err != NF_ACCEPT) 64 goto out; 65 } 66 break; 67 68 case IP_CT_ESTABLISHED: 69 case IP_CT_ESTABLISHED_REPLY: 70 break; 71 72 default: 73 err = NF_DROP; 74 goto out; 75 } 76 77 err = nf_nat_packet(ct, ctinfo, hooknum, skb); 78 if (err == NF_ACCEPT) 79 *action |= BIT(maniptype); 80 out: 81 return err; 82 } 83 84 int nf_ct_nat(struct sk_buff *skb, struct nf_conn *ct, 85 enum ip_conntrack_info ctinfo, int *action, 86 const struct nf_nat_range2 *range, bool commit) 87 { 88 enum nf_nat_manip_type maniptype; 89 int err, ct_action = *action; 90 91 *action = 0; 92 93 /* Add NAT extension if not confirmed yet. */ 94 if (!nf_ct_is_confirmed(ct) && !nf_ct_nat_ext_add(ct)) 95 return NF_DROP; /* Can't NAT. */ 96 97 if (ctinfo != IP_CT_NEW && (ct->status & IPS_NAT_MASK) && 98 (ctinfo != IP_CT_RELATED || commit)) { 99 /* NAT an established or related connection like before. */ 100 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) 101 /* This is the REPLY direction for a connection 102 * for which NAT was applied in the forward 103 * direction. Do the reverse NAT. 104 */ 105 maniptype = ct->status & IPS_SRC_NAT 106 ? NF_NAT_MANIP_DST : NF_NAT_MANIP_SRC; 107 else 108 maniptype = ct->status & IPS_SRC_NAT 109 ? NF_NAT_MANIP_SRC : NF_NAT_MANIP_DST; 110 } else if (ct_action & BIT(NF_NAT_MANIP_SRC)) { 111 maniptype = NF_NAT_MANIP_SRC; 112 } else if (ct_action & BIT(NF_NAT_MANIP_DST)) { 113 maniptype = NF_NAT_MANIP_DST; 114 } else { 115 return NF_ACCEPT; 116 } 117 118 err = nf_ct_nat_execute(skb, ct, ctinfo, action, range, maniptype); 119 if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) { 120 if (ct->status & IPS_SRC_NAT) { 121 if (maniptype == NF_NAT_MANIP_SRC) 122 maniptype = NF_NAT_MANIP_DST; 123 else 124 maniptype = NF_NAT_MANIP_SRC; 125 126 err = nf_ct_nat_execute(skb, ct, ctinfo, action, range, 127 maniptype); 128 } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { 129 err = nf_ct_nat_execute(skb, ct, ctinfo, action, NULL, 130 NF_NAT_MANIP_SRC); 131 } 132 } 133 return err; 134 } 135 EXPORT_SYMBOL_GPL(nf_ct_nat); 136