1/* 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 3 * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org> 4 * Copyright (c) 2012 Intel Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 */ 11 12#include <linux/module.h> 13#include <linux/init.h> 14#include <linux/skbuff.h> 15#include <linux/ip.h> 16#include <linux/string.h> 17#include <linux/netlink.h> 18#include <linux/netfilter.h> 19#include <linux/netfilter_ipv4.h> 20#include <linux/netfilter/nfnetlink.h> 21#include <linux/netfilter/nf_tables.h> 22#include <net/netfilter/nf_conntrack.h> 23#include <net/netfilter/nf_nat.h> 24#include <net/netfilter/nf_nat_core.h> 25#include <net/netfilter/nf_tables.h> 26#include <net/netfilter/nf_nat_l3proto.h> 27#include <net/ip.h> 28 29struct nft_nat { 30 enum nft_registers sreg_addr_min:8; 31 enum nft_registers sreg_addr_max:8; 32 enum nft_registers sreg_proto_min:8; 33 enum nft_registers sreg_proto_max:8; 34 enum nf_nat_manip_type type:8; 35 u8 family; 36 u16 flags; 37}; 38 39static void nft_nat_eval(const struct nft_expr *expr, 40 struct nft_regs *regs, 41 const struct nft_pktinfo *pkt) 42{ 43 const struct nft_nat *priv = nft_expr_priv(expr); 44 enum ip_conntrack_info ctinfo; 45 struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo); 46 struct nf_nat_range range; 47 48 memset(&range, 0, sizeof(range)); 49 if (priv->sreg_addr_min) { 50 if (priv->family == AF_INET) { 51 range.min_addr.ip = (__force __be32) 52 regs->data[priv->sreg_addr_min]; 53 range.max_addr.ip = (__force __be32) 54 regs->data[priv->sreg_addr_max]; 55 56 } else { 57 memcpy(range.min_addr.ip6, 58 ®s->data[priv->sreg_addr_min], 59 sizeof(range.min_addr.ip6)); 60 memcpy(range.max_addr.ip6, 61 ®s->data[priv->sreg_addr_max], 62 sizeof(range.max_addr.ip6)); 63 } 64 range.flags |= NF_NAT_RANGE_MAP_IPS; 65 } 66 67 if (priv->sreg_proto_min) { 68 range.min_proto.all = 69 *(__be16 *)®s->data[priv->sreg_proto_min]; 70 range.max_proto.all = 71 *(__be16 *)®s->data[priv->sreg_proto_max]; 72 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 73 } 74 75 range.flags |= priv->flags; 76 77 regs->verdict.code = nf_nat_setup_info(ct, &range, priv->type); 78} 79 80static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = { 81 [NFTA_NAT_TYPE] = { .type = NLA_U32 }, 82 [NFTA_NAT_FAMILY] = { .type = NLA_U32 }, 83 [NFTA_NAT_REG_ADDR_MIN] = { .type = NLA_U32 }, 84 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 }, 85 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 }, 86 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 }, 87 [NFTA_NAT_FLAGS] = { .type = NLA_U32 }, 88}; 89 90static int nft_nat_validate(const struct nft_ctx *ctx, 91 const struct nft_expr *expr, 92 const struct nft_data **data) 93{ 94 struct nft_nat *priv = nft_expr_priv(expr); 95 int err; 96 97 err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); 98 if (err < 0) 99 return err; 100 101 switch (priv->type) { 102 case NFT_NAT_SNAT: 103 err = nft_chain_validate_hooks(ctx->chain, 104 (1 << NF_INET_POST_ROUTING) | 105 (1 << NF_INET_LOCAL_IN)); 106 break; 107 case NFT_NAT_DNAT: 108 err = nft_chain_validate_hooks(ctx->chain, 109 (1 << NF_INET_PRE_ROUTING) | 110 (1 << NF_INET_LOCAL_OUT)); 111 break; 112 } 113 114 return err; 115} 116 117static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 118 const struct nlattr * const tb[]) 119{ 120 struct nft_nat *priv = nft_expr_priv(expr); 121 unsigned int alen, plen; 122 u32 family; 123 int err; 124 125 if (tb[NFTA_NAT_TYPE] == NULL || 126 (tb[NFTA_NAT_REG_ADDR_MIN] == NULL && 127 tb[NFTA_NAT_REG_PROTO_MIN] == NULL)) 128 return -EINVAL; 129 130 switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) { 131 case NFT_NAT_SNAT: 132 priv->type = NF_NAT_MANIP_SRC; 133 break; 134 case NFT_NAT_DNAT: 135 priv->type = NF_NAT_MANIP_DST; 136 break; 137 default: 138 return -EINVAL; 139 } 140 141 err = nft_nat_validate(ctx, expr, NULL); 142 if (err < 0) 143 return err; 144 145 if (tb[NFTA_NAT_FAMILY] == NULL) 146 return -EINVAL; 147 148 family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY])); 149 if (family != ctx->afi->family) 150 return -EOPNOTSUPP; 151 152 switch (family) { 153 case NFPROTO_IPV4: 154 alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip); 155 break; 156 case NFPROTO_IPV6: 157 alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip6); 158 break; 159 default: 160 return -EAFNOSUPPORT; 161 } 162 priv->family = family; 163 164 if (tb[NFTA_NAT_REG_ADDR_MIN]) { 165 priv->sreg_addr_min = 166 nft_parse_register(tb[NFTA_NAT_REG_ADDR_MIN]); 167 err = nft_validate_register_load(priv->sreg_addr_min, alen); 168 if (err < 0) 169 return err; 170 171 if (tb[NFTA_NAT_REG_ADDR_MAX]) { 172 priv->sreg_addr_max = 173 nft_parse_register(tb[NFTA_NAT_REG_ADDR_MAX]); 174 175 err = nft_validate_register_load(priv->sreg_addr_max, 176 alen); 177 if (err < 0) 178 return err; 179 } else { 180 priv->sreg_addr_max = priv->sreg_addr_min; 181 } 182 } 183 184 plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all); 185 if (tb[NFTA_NAT_REG_PROTO_MIN]) { 186 priv->sreg_proto_min = 187 nft_parse_register(tb[NFTA_NAT_REG_PROTO_MIN]); 188 189 err = nft_validate_register_load(priv->sreg_proto_min, plen); 190 if (err < 0) 191 return err; 192 193 if (tb[NFTA_NAT_REG_PROTO_MAX]) { 194 priv->sreg_proto_max = 195 nft_parse_register(tb[NFTA_NAT_REG_PROTO_MAX]); 196 197 err = nft_validate_register_load(priv->sreg_proto_max, 198 plen); 199 if (err < 0) 200 return err; 201 } else { 202 priv->sreg_proto_max = priv->sreg_proto_min; 203 } 204 } 205 206 if (tb[NFTA_NAT_FLAGS]) { 207 priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS])); 208 if (priv->flags & ~NF_NAT_RANGE_MASK) 209 return -EINVAL; 210 } 211 212 return 0; 213} 214 215static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr) 216{ 217 const struct nft_nat *priv = nft_expr_priv(expr); 218 219 switch (priv->type) { 220 case NF_NAT_MANIP_SRC: 221 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT))) 222 goto nla_put_failure; 223 break; 224 case NF_NAT_MANIP_DST: 225 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT))) 226 goto nla_put_failure; 227 break; 228 } 229 230 if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family))) 231 goto nla_put_failure; 232 233 if (priv->sreg_addr_min) { 234 if (nft_dump_register(skb, NFTA_NAT_REG_ADDR_MIN, 235 priv->sreg_addr_min) || 236 nft_dump_register(skb, NFTA_NAT_REG_ADDR_MAX, 237 priv->sreg_addr_max)) 238 goto nla_put_failure; 239 } 240 241 if (priv->sreg_proto_min) { 242 if (nft_dump_register(skb, NFTA_NAT_REG_PROTO_MIN, 243 priv->sreg_proto_min) || 244 nft_dump_register(skb, NFTA_NAT_REG_PROTO_MAX, 245 priv->sreg_proto_max)) 246 goto nla_put_failure; 247 } 248 249 if (priv->flags != 0) { 250 if (nla_put_be32(skb, NFTA_NAT_FLAGS, htonl(priv->flags))) 251 goto nla_put_failure; 252 } 253 254 return 0; 255 256nla_put_failure: 257 return -1; 258} 259 260static struct nft_expr_type nft_nat_type; 261static const struct nft_expr_ops nft_nat_ops = { 262 .type = &nft_nat_type, 263 .size = NFT_EXPR_SIZE(sizeof(struct nft_nat)), 264 .eval = nft_nat_eval, 265 .init = nft_nat_init, 266 .dump = nft_nat_dump, 267 .validate = nft_nat_validate, 268}; 269 270static struct nft_expr_type nft_nat_type __read_mostly = { 271 .name = "nat", 272 .ops = &nft_nat_ops, 273 .policy = nft_nat_policy, 274 .maxattr = NFTA_NAT_MAX, 275 .owner = THIS_MODULE, 276}; 277 278static int __init nft_nat_module_init(void) 279{ 280 return nft_register_expr(&nft_nat_type); 281} 282 283static void __exit nft_nat_module_exit(void) 284{ 285 nft_unregister_expr(&nft_nat_type); 286} 287 288module_init(nft_nat_module_init); 289module_exit(nft_nat_module_exit); 290 291MODULE_LICENSE("GPL"); 292MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>"); 293MODULE_ALIAS_NFT_EXPR("nat"); 294