act_nat.c (7927B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Stateless NAT actions 4 * 5 * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> 6 */ 7 8#include <linux/errno.h> 9#include <linux/init.h> 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/netfilter.h> 13#include <linux/rtnetlink.h> 14#include <linux/skbuff.h> 15#include <linux/slab.h> 16#include <linux/spinlock.h> 17#include <linux/string.h> 18#include <linux/tc_act/tc_nat.h> 19#include <net/act_api.h> 20#include <net/pkt_cls.h> 21#include <net/icmp.h> 22#include <net/ip.h> 23#include <net/netlink.h> 24#include <net/tc_act/tc_nat.h> 25#include <net/tcp.h> 26#include <net/udp.h> 27 28 29static unsigned int nat_net_id; 30static struct tc_action_ops act_nat_ops; 31 32static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = { 33 [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) }, 34}; 35 36static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, 37 struct tc_action **a, struct tcf_proto *tp, 38 u32 flags, struct netlink_ext_ack *extack) 39{ 40 struct tc_action_net *tn = net_generic(net, nat_net_id); 41 bool bind = flags & TCA_ACT_FLAGS_BIND; 42 struct nlattr *tb[TCA_NAT_MAX + 1]; 43 struct tcf_chain *goto_ch = NULL; 44 struct tc_nat *parm; 45 int ret = 0, err; 46 struct tcf_nat *p; 47 u32 index; 48 49 if (nla == NULL) 50 return -EINVAL; 51 52 err = nla_parse_nested_deprecated(tb, TCA_NAT_MAX, nla, nat_policy, 53 NULL); 54 if (err < 0) 55 return err; 56 57 if (tb[TCA_NAT_PARMS] == NULL) 58 return -EINVAL; 59 parm = nla_data(tb[TCA_NAT_PARMS]); 60 index = parm->index; 61 err = tcf_idr_check_alloc(tn, &index, a, bind); 62 if (!err) { 63 ret = tcf_idr_create(tn, index, est, a, 64 &act_nat_ops, bind, false, flags); 65 if (ret) { 66 tcf_idr_cleanup(tn, index); 67 return ret; 68 } 69 ret = ACT_P_CREATED; 70 } else if (err > 0) { 71 if (bind) 72 return 0; 73 if (!(flags & TCA_ACT_FLAGS_REPLACE)) { 74 tcf_idr_release(*a, bind); 75 return -EEXIST; 76 } 77 } else { 78 return err; 79 } 80 err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); 81 if (err < 0) 82 goto release_idr; 83 p = to_tcf_nat(*a); 84 85 spin_lock_bh(&p->tcf_lock); 86 p->old_addr = parm->old_addr; 87 p->new_addr = parm->new_addr; 88 p->mask = parm->mask; 89 p->flags = parm->flags; 90 91 goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); 92 spin_unlock_bh(&p->tcf_lock); 93 if (goto_ch) 94 tcf_chain_put_by_act(goto_ch); 95 96 return ret; 97release_idr: 98 tcf_idr_release(*a, bind); 99 return err; 100} 101 102static int tcf_nat_act(struct sk_buff *skb, const struct tc_action *a, 103 struct tcf_result *res) 104{ 105 struct tcf_nat *p = to_tcf_nat(a); 106 struct iphdr *iph; 107 __be32 old_addr; 108 __be32 new_addr; 109 __be32 mask; 110 __be32 addr; 111 int egress; 112 int action; 113 int ihl; 114 int noff; 115 116 spin_lock(&p->tcf_lock); 117 118 tcf_lastuse_update(&p->tcf_tm); 119 old_addr = p->old_addr; 120 new_addr = p->new_addr; 121 mask = p->mask; 122 egress = p->flags & TCA_NAT_FLAG_EGRESS; 123 action = p->tcf_action; 124 125 bstats_update(&p->tcf_bstats, skb); 126 127 spin_unlock(&p->tcf_lock); 128 129 if (unlikely(action == TC_ACT_SHOT)) 130 goto drop; 131 132 noff = skb_network_offset(skb); 133 if (!pskb_may_pull(skb, sizeof(*iph) + noff)) 134 goto drop; 135 136 iph = ip_hdr(skb); 137 138 if (egress) 139 addr = iph->saddr; 140 else 141 addr = iph->daddr; 142 143 if (!((old_addr ^ addr) & mask)) { 144 if (skb_try_make_writable(skb, sizeof(*iph) + noff)) 145 goto drop; 146 147 new_addr &= mask; 148 new_addr |= addr & ~mask; 149 150 /* Rewrite IP header */ 151 iph = ip_hdr(skb); 152 if (egress) 153 iph->saddr = new_addr; 154 else 155 iph->daddr = new_addr; 156 157 csum_replace4(&iph->check, addr, new_addr); 158 } else if ((iph->frag_off & htons(IP_OFFSET)) || 159 iph->protocol != IPPROTO_ICMP) { 160 goto out; 161 } 162 163 ihl = iph->ihl * 4; 164 165 /* It would be nice to share code with stateful NAT. */ 166 switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) { 167 case IPPROTO_TCP: 168 { 169 struct tcphdr *tcph; 170 171 if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) || 172 skb_try_make_writable(skb, ihl + sizeof(*tcph) + noff)) 173 goto drop; 174 175 tcph = (void *)(skb_network_header(skb) + ihl); 176 inet_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 177 true); 178 break; 179 } 180 case IPPROTO_UDP: 181 { 182 struct udphdr *udph; 183 184 if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) || 185 skb_try_make_writable(skb, ihl + sizeof(*udph) + noff)) 186 goto drop; 187 188 udph = (void *)(skb_network_header(skb) + ihl); 189 if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) { 190 inet_proto_csum_replace4(&udph->check, skb, addr, 191 new_addr, true); 192 if (!udph->check) 193 udph->check = CSUM_MANGLED_0; 194 } 195 break; 196 } 197 case IPPROTO_ICMP: 198 { 199 struct icmphdr *icmph; 200 201 if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + noff)) 202 goto drop; 203 204 icmph = (void *)(skb_network_header(skb) + ihl); 205 206 if (!icmp_is_err(icmph->type)) 207 break; 208 209 if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph) + 210 noff)) 211 goto drop; 212 213 icmph = (void *)(skb_network_header(skb) + ihl); 214 iph = (void *)(icmph + 1); 215 if (egress) 216 addr = iph->daddr; 217 else 218 addr = iph->saddr; 219 220 if ((old_addr ^ addr) & mask) 221 break; 222 223 if (skb_try_make_writable(skb, ihl + sizeof(*icmph) + 224 sizeof(*iph) + noff)) 225 goto drop; 226 227 icmph = (void *)(skb_network_header(skb) + ihl); 228 iph = (void *)(icmph + 1); 229 230 new_addr &= mask; 231 new_addr |= addr & ~mask; 232 233 /* XXX Fix up the inner checksums. */ 234 if (egress) 235 iph->daddr = new_addr; 236 else 237 iph->saddr = new_addr; 238 239 inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, 240 false); 241 break; 242 } 243 default: 244 break; 245 } 246 247out: 248 return action; 249 250drop: 251 spin_lock(&p->tcf_lock); 252 p->tcf_qstats.drops++; 253 spin_unlock(&p->tcf_lock); 254 return TC_ACT_SHOT; 255} 256 257static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, 258 int bind, int ref) 259{ 260 unsigned char *b = skb_tail_pointer(skb); 261 struct tcf_nat *p = to_tcf_nat(a); 262 struct tc_nat opt = { 263 .index = p->tcf_index, 264 .refcnt = refcount_read(&p->tcf_refcnt) - ref, 265 .bindcnt = atomic_read(&p->tcf_bindcnt) - bind, 266 }; 267 struct tcf_t t; 268 269 spin_lock_bh(&p->tcf_lock); 270 opt.old_addr = p->old_addr; 271 opt.new_addr = p->new_addr; 272 opt.mask = p->mask; 273 opt.flags = p->flags; 274 opt.action = p->tcf_action; 275 276 if (nla_put(skb, TCA_NAT_PARMS, sizeof(opt), &opt)) 277 goto nla_put_failure; 278 279 tcf_tm_dump(&t, &p->tcf_tm); 280 if (nla_put_64bit(skb, TCA_NAT_TM, sizeof(t), &t, TCA_NAT_PAD)) 281 goto nla_put_failure; 282 spin_unlock_bh(&p->tcf_lock); 283 284 return skb->len; 285 286nla_put_failure: 287 spin_unlock_bh(&p->tcf_lock); 288 nlmsg_trim(skb, b); 289 return -1; 290} 291 292static int tcf_nat_walker(struct net *net, struct sk_buff *skb, 293 struct netlink_callback *cb, int type, 294 const struct tc_action_ops *ops, 295 struct netlink_ext_ack *extack) 296{ 297 struct tc_action_net *tn = net_generic(net, nat_net_id); 298 299 return tcf_generic_walker(tn, skb, cb, type, ops, extack); 300} 301 302static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index) 303{ 304 struct tc_action_net *tn = net_generic(net, nat_net_id); 305 306 return tcf_idr_search(tn, a, index); 307} 308 309static struct tc_action_ops act_nat_ops = { 310 .kind = "nat", 311 .id = TCA_ID_NAT, 312 .owner = THIS_MODULE, 313 .act = tcf_nat_act, 314 .dump = tcf_nat_dump, 315 .init = tcf_nat_init, 316 .walk = tcf_nat_walker, 317 .lookup = tcf_nat_search, 318 .size = sizeof(struct tcf_nat), 319}; 320 321static __net_init int nat_init_net(struct net *net) 322{ 323 struct tc_action_net *tn = net_generic(net, nat_net_id); 324 325 return tc_action_net_init(net, tn, &act_nat_ops); 326} 327 328static void __net_exit nat_exit_net(struct list_head *net_list) 329{ 330 tc_action_net_exit(net_list, nat_net_id); 331} 332 333static struct pernet_operations nat_net_ops = { 334 .init = nat_init_net, 335 .exit_batch = nat_exit_net, 336 .id = &nat_net_id, 337 .size = sizeof(struct tc_action_net), 338}; 339 340MODULE_DESCRIPTION("Stateless NAT actions"); 341MODULE_LICENSE("GPL"); 342 343static int __init nat_init_module(void) 344{ 345 return tcf_register_action(&act_nat_ops, &nat_net_ops); 346} 347 348static void __exit nat_cleanup_module(void) 349{ 350 tcf_unregister_action(&act_nat_ops, &nat_net_ops); 351} 352 353module_init(nat_init_module); 354module_exit(nat_cleanup_module);