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 #include <net/ipv6.h> 6 #include <linux/ip.h> 7 #include <linux/if_vlan.h> 8 9 /* Modelled after nf_nat_ipv[46]_fn(). 10 * range is only used for new, uninitialized NAT state. 11 * Returns either NF_ACCEPT or NF_DROP. 12 */ 13 static int nf_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, 14 enum ip_conntrack_info ctinfo, int *action, 15 const struct nf_nat_range2 *range, 16 enum nf_nat_manip_type maniptype) 17 { 18 __be16 proto = skb_protocol(skb, true); 19 int hooknum, err = NF_ACCEPT; 20 21 /* See HOOK2MANIP(). */ 22 if (maniptype == NF_NAT_MANIP_SRC) 23 hooknum = NF_INET_LOCAL_IN; /* Source NAT */ 24 else 25 hooknum = NF_INET_LOCAL_OUT; /* Destination NAT */ 26 27 switch (ctinfo) { 28 case IP_CT_RELATED: 29 case IP_CT_RELATED_REPLY: 30 if (proto == htons(ETH_P_IP) && 31 ip_hdr(skb)->protocol == IPPROTO_ICMP) { 32 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, 33 hooknum)) 34 err = NF_DROP; 35 goto out; 36 } else if (IS_ENABLED(CONFIG_IPV6) && proto == htons(ETH_P_IPV6)) { 37 __be16 frag_off; 38 u8 nexthdr = ipv6_hdr(skb)->nexthdr; 39 int hdrlen = ipv6_skip_exthdr(skb, 40 sizeof(struct ipv6hdr), 41 &nexthdr, &frag_off); 42 43 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { 44 if (!nf_nat_icmpv6_reply_translation(skb, ct, 45 ctinfo, 46 hooknum, 47 hdrlen)) 48 err = NF_DROP; 49 goto out; 50 } 51 } 52 /* Non-ICMP, fall thru to initialize if needed. */ 53 fallthrough; 54 case IP_CT_NEW: 55 /* Seen it before? This can happen for loopback, retrans, 56 * or local packets. 57 */ 58 if (!nf_nat_initialized(ct, maniptype)) { 59 /* Initialize according to the NAT action. */ 60 err = (range && range->flags & NF_NAT_RANGE_MAP_IPS) 61 /* Action is set up to establish a new 62 * mapping. 63 */ 64 ? nf_nat_setup_info(ct, range, maniptype) 65 : nf_nat_alloc_null_binding(ct, hooknum); 66 if (err != NF_ACCEPT) 67 goto out; 68 } 69 break; 70 71 case IP_CT_ESTABLISHED: 72 case IP_CT_ESTABLISHED_REPLY: 73 break; 74 75 default: 76 err = NF_DROP; 77 goto out; 78 } 79 80 err = nf_nat_packet(ct, ctinfo, hooknum, skb); 81 out: 82 if (err == NF_ACCEPT) 83 *action |= BIT(maniptype); 84 85 return err; 86 } 87 88 int nf_ct_nat(struct sk_buff *skb, struct nf_conn *ct, 89 enum ip_conntrack_info ctinfo, int *action, 90 const struct nf_nat_range2 *range, bool commit) 91 { 92 enum nf_nat_manip_type maniptype; 93 int err, ct_action = *action; 94 95 *action = 0; 96 97 /* Add NAT extension if not confirmed yet. */ 98 if (!nf_ct_is_confirmed(ct) && !nf_ct_nat_ext_add(ct)) 99 return NF_DROP; /* Can't NAT. */ 100 101 if (ctinfo != IP_CT_NEW && (ct->status & IPS_NAT_MASK) && 102 (ctinfo != IP_CT_RELATED || commit)) { 103 /* NAT an established or related connection like before. */ 104 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) 105 /* This is the REPLY direction for a connection 106 * for which NAT was applied in the forward 107 * direction. Do the reverse NAT. 108 */ 109 maniptype = ct->status & IPS_SRC_NAT 110 ? NF_NAT_MANIP_DST : NF_NAT_MANIP_SRC; 111 else 112 maniptype = ct->status & IPS_SRC_NAT 113 ? NF_NAT_MANIP_SRC : NF_NAT_MANIP_DST; 114 } else if (ct_action & BIT(NF_NAT_MANIP_SRC)) { 115 maniptype = NF_NAT_MANIP_SRC; 116 } else if (ct_action & BIT(NF_NAT_MANIP_DST)) { 117 maniptype = NF_NAT_MANIP_DST; 118 } else { 119 return NF_ACCEPT; 120 } 121 122 err = nf_ct_nat_execute(skb, ct, ctinfo, action, range, maniptype); 123 if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) { 124 if (ct->status & IPS_SRC_NAT) { 125 if (maniptype == NF_NAT_MANIP_SRC) 126 maniptype = NF_NAT_MANIP_DST; 127 else 128 maniptype = NF_NAT_MANIP_SRC; 129 130 err = nf_ct_nat_execute(skb, ct, ctinfo, action, range, 131 maniptype); 132 } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { 133 err = nf_ct_nat_execute(skb, ct, ctinfo, action, NULL, 134 NF_NAT_MANIP_SRC); 135 } 136 } 137 return err; 138 } 139 EXPORT_SYMBOL_GPL(nf_ct_nat); 140