Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.16 224 lines 6.1 kB view raw
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}; 37 38static void nft_nat_eval(const struct nft_expr *expr, 39 struct nft_data data[NFT_REG_MAX + 1], 40 const struct nft_pktinfo *pkt) 41{ 42 const struct nft_nat *priv = nft_expr_priv(expr); 43 enum ip_conntrack_info ctinfo; 44 struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo); 45 struct nf_nat_range range; 46 47 memset(&range, 0, sizeof(range)); 48 if (priv->sreg_addr_min) { 49 if (priv->family == AF_INET) { 50 range.min_addr.ip = (__force __be32) 51 data[priv->sreg_addr_min].data[0]; 52 range.max_addr.ip = (__force __be32) 53 data[priv->sreg_addr_max].data[0]; 54 55 } else { 56 memcpy(range.min_addr.ip6, 57 data[priv->sreg_addr_min].data, 58 sizeof(struct nft_data)); 59 memcpy(range.max_addr.ip6, 60 data[priv->sreg_addr_max].data, 61 sizeof(struct nft_data)); 62 } 63 range.flags |= NF_NAT_RANGE_MAP_IPS; 64 } 65 66 if (priv->sreg_proto_min) { 67 range.min_proto.all = (__force __be16) 68 data[priv->sreg_proto_min].data[0]; 69 range.max_proto.all = (__force __be16) 70 data[priv->sreg_proto_max].data[0]; 71 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 72 } 73 74 data[NFT_REG_VERDICT].verdict = 75 nf_nat_setup_info(ct, &range, priv->type); 76} 77 78static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = { 79 [NFTA_NAT_TYPE] = { .type = NLA_U32 }, 80 [NFTA_NAT_FAMILY] = { .type = NLA_U32 }, 81 [NFTA_NAT_REG_ADDR_MIN] = { .type = NLA_U32 }, 82 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 }, 83 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 }, 84 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 }, 85}; 86 87static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 88 const struct nlattr * const tb[]) 89{ 90 struct nft_nat *priv = nft_expr_priv(expr); 91 u32 family; 92 int err; 93 94 if (tb[NFTA_NAT_TYPE] == NULL) 95 return -EINVAL; 96 97 switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) { 98 case NFT_NAT_SNAT: 99 priv->type = NF_NAT_MANIP_SRC; 100 break; 101 case NFT_NAT_DNAT: 102 priv->type = NF_NAT_MANIP_DST; 103 break; 104 default: 105 return -EINVAL; 106 } 107 108 if (tb[NFTA_NAT_FAMILY] == NULL) 109 return -EINVAL; 110 111 family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY])); 112 if (family != AF_INET && family != AF_INET6) 113 return -EAFNOSUPPORT; 114 if (family != ctx->afi->family) 115 return -EOPNOTSUPP; 116 priv->family = family; 117 118 if (tb[NFTA_NAT_REG_ADDR_MIN]) { 119 priv->sreg_addr_min = ntohl(nla_get_be32( 120 tb[NFTA_NAT_REG_ADDR_MIN])); 121 err = nft_validate_input_register(priv->sreg_addr_min); 122 if (err < 0) 123 return err; 124 } 125 126 if (tb[NFTA_NAT_REG_ADDR_MAX]) { 127 priv->sreg_addr_max = ntohl(nla_get_be32( 128 tb[NFTA_NAT_REG_ADDR_MAX])); 129 err = nft_validate_input_register(priv->sreg_addr_max); 130 if (err < 0) 131 return err; 132 } else 133 priv->sreg_addr_max = priv->sreg_addr_min; 134 135 if (tb[NFTA_NAT_REG_PROTO_MIN]) { 136 priv->sreg_proto_min = ntohl(nla_get_be32( 137 tb[NFTA_NAT_REG_PROTO_MIN])); 138 err = nft_validate_input_register(priv->sreg_proto_min); 139 if (err < 0) 140 return err; 141 } 142 143 if (tb[NFTA_NAT_REG_PROTO_MAX]) { 144 priv->sreg_proto_max = ntohl(nla_get_be32( 145 tb[NFTA_NAT_REG_PROTO_MAX])); 146 err = nft_validate_input_register(priv->sreg_proto_max); 147 if (err < 0) 148 return err; 149 } else 150 priv->sreg_proto_max = priv->sreg_proto_min; 151 152 return 0; 153} 154 155static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr) 156{ 157 const struct nft_nat *priv = nft_expr_priv(expr); 158 159 switch (priv->type) { 160 case NF_NAT_MANIP_SRC: 161 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT))) 162 goto nla_put_failure; 163 break; 164 case NF_NAT_MANIP_DST: 165 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT))) 166 goto nla_put_failure; 167 break; 168 } 169 170 if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family))) 171 goto nla_put_failure; 172 if (nla_put_be32(skb, 173 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min))) 174 goto nla_put_failure; 175 if (nla_put_be32(skb, 176 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max))) 177 goto nla_put_failure; 178 if (priv->sreg_proto_min) { 179 if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN, 180 htonl(priv->sreg_proto_min))) 181 goto nla_put_failure; 182 if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX, 183 htonl(priv->sreg_proto_max))) 184 goto nla_put_failure; 185 } 186 return 0; 187 188nla_put_failure: 189 return -1; 190} 191 192static struct nft_expr_type nft_nat_type; 193static const struct nft_expr_ops nft_nat_ops = { 194 .type = &nft_nat_type, 195 .size = NFT_EXPR_SIZE(sizeof(struct nft_nat)), 196 .eval = nft_nat_eval, 197 .init = nft_nat_init, 198 .dump = nft_nat_dump, 199}; 200 201static struct nft_expr_type nft_nat_type __read_mostly = { 202 .name = "nat", 203 .ops = &nft_nat_ops, 204 .policy = nft_nat_policy, 205 .maxattr = NFTA_NAT_MAX, 206 .owner = THIS_MODULE, 207}; 208 209static int __init nft_nat_module_init(void) 210{ 211 return nft_register_expr(&nft_nat_type); 212} 213 214static void __exit nft_nat_module_exit(void) 215{ 216 nft_unregister_expr(&nft_nat_type); 217} 218 219module_init(nft_nat_module_init); 220module_exit(nft_nat_module_exit); 221 222MODULE_LICENSE("GPL"); 223MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>"); 224MODULE_ALIAS_NFT_EXPR("nat");