cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nft_masq.c (7848B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo@debian.org>
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/init.h>
      8#include <linux/module.h>
      9#include <linux/netlink.h>
     10#include <linux/netfilter.h>
     11#include <linux/netfilter/nf_tables.h>
     12#include <net/netfilter/nf_tables.h>
     13#include <net/netfilter/nf_nat.h>
     14#include <net/netfilter/nf_nat_masquerade.h>
     15
     16struct nft_masq {
     17	u32			flags;
     18	u8			sreg_proto_min;
     19	u8			sreg_proto_max;
     20};
     21
     22static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = {
     23	[NFTA_MASQ_FLAGS]		= { .type = NLA_U32 },
     24	[NFTA_MASQ_REG_PROTO_MIN]	= { .type = NLA_U32 },
     25	[NFTA_MASQ_REG_PROTO_MAX]	= { .type = NLA_U32 },
     26};
     27
     28static int nft_masq_validate(const struct nft_ctx *ctx,
     29			     const struct nft_expr *expr,
     30			     const struct nft_data **data)
     31{
     32	int err;
     33
     34	err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
     35	if (err < 0)
     36		return err;
     37
     38	return nft_chain_validate_hooks(ctx->chain,
     39				        (1 << NF_INET_POST_ROUTING));
     40}
     41
     42static int nft_masq_init(const struct nft_ctx *ctx,
     43			 const struct nft_expr *expr,
     44			 const struct nlattr * const tb[])
     45{
     46	u32 plen = sizeof_field(struct nf_nat_range, min_addr.all);
     47	struct nft_masq *priv = nft_expr_priv(expr);
     48	int err;
     49
     50	if (tb[NFTA_MASQ_FLAGS]) {
     51		priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
     52		if (priv->flags & ~NF_NAT_RANGE_MASK)
     53			return -EINVAL;
     54	}
     55
     56	if (tb[NFTA_MASQ_REG_PROTO_MIN]) {
     57		err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN],
     58					      &priv->sreg_proto_min, plen);
     59		if (err < 0)
     60			return err;
     61
     62		if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
     63			err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MAX],
     64						      &priv->sreg_proto_max,
     65						      plen);
     66			if (err < 0)
     67				return err;
     68		} else {
     69			priv->sreg_proto_max = priv->sreg_proto_min;
     70		}
     71	}
     72
     73	return nf_ct_netns_get(ctx->net, ctx->family);
     74}
     75
     76static int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
     77{
     78	const struct nft_masq *priv = nft_expr_priv(expr);
     79
     80	if (priv->flags != 0 &&
     81	    nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
     82		goto nla_put_failure;
     83
     84	if (priv->sreg_proto_min) {
     85		if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN,
     86				      priv->sreg_proto_min) ||
     87		    nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX,
     88				      priv->sreg_proto_max))
     89			goto nla_put_failure;
     90	}
     91
     92	return 0;
     93
     94nla_put_failure:
     95	return -1;
     96}
     97
     98static void nft_masq_ipv4_eval(const struct nft_expr *expr,
     99			       struct nft_regs *regs,
    100			       const struct nft_pktinfo *pkt)
    101{
    102	struct nft_masq *priv = nft_expr_priv(expr);
    103	struct nf_nat_range2 range;
    104
    105	memset(&range, 0, sizeof(range));
    106	range.flags = priv->flags;
    107	if (priv->sreg_proto_min) {
    108		range.min_proto.all = (__force __be16)nft_reg_load16(
    109			&regs->data[priv->sreg_proto_min]);
    110		range.max_proto.all = (__force __be16)nft_reg_load16(
    111			&regs->data[priv->sreg_proto_max]);
    112	}
    113	regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt),
    114						    &range, nft_out(pkt));
    115}
    116
    117static void
    118nft_masq_ipv4_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
    119{
    120	nf_ct_netns_put(ctx->net, NFPROTO_IPV4);
    121}
    122
    123static struct nft_expr_type nft_masq_ipv4_type;
    124static const struct nft_expr_ops nft_masq_ipv4_ops = {
    125	.type		= &nft_masq_ipv4_type,
    126	.size		= NFT_EXPR_SIZE(sizeof(struct nft_masq)),
    127	.eval		= nft_masq_ipv4_eval,
    128	.init		= nft_masq_init,
    129	.destroy	= nft_masq_ipv4_destroy,
    130	.dump		= nft_masq_dump,
    131	.validate	= nft_masq_validate,
    132	.reduce		= NFT_REDUCE_READONLY,
    133};
    134
    135static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
    136	.family		= NFPROTO_IPV4,
    137	.name		= "masq",
    138	.ops		= &nft_masq_ipv4_ops,
    139	.policy		= nft_masq_policy,
    140	.maxattr	= NFTA_MASQ_MAX,
    141	.owner		= THIS_MODULE,
    142};
    143
    144#ifdef CONFIG_NF_TABLES_IPV6
    145static void nft_masq_ipv6_eval(const struct nft_expr *expr,
    146			       struct nft_regs *regs,
    147			       const struct nft_pktinfo *pkt)
    148{
    149	struct nft_masq *priv = nft_expr_priv(expr);
    150	struct nf_nat_range2 range;
    151
    152	memset(&range, 0, sizeof(range));
    153	range.flags = priv->flags;
    154	if (priv->sreg_proto_min) {
    155		range.min_proto.all = (__force __be16)nft_reg_load16(
    156			&regs->data[priv->sreg_proto_min]);
    157		range.max_proto.all = (__force __be16)nft_reg_load16(
    158			&regs->data[priv->sreg_proto_max]);
    159	}
    160	regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range,
    161						    nft_out(pkt));
    162}
    163
    164static void
    165nft_masq_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
    166{
    167	nf_ct_netns_put(ctx->net, NFPROTO_IPV6);
    168}
    169
    170static struct nft_expr_type nft_masq_ipv6_type;
    171static const struct nft_expr_ops nft_masq_ipv6_ops = {
    172	.type		= &nft_masq_ipv6_type,
    173	.size		= NFT_EXPR_SIZE(sizeof(struct nft_masq)),
    174	.eval		= nft_masq_ipv6_eval,
    175	.init		= nft_masq_init,
    176	.destroy	= nft_masq_ipv6_destroy,
    177	.dump		= nft_masq_dump,
    178	.validate	= nft_masq_validate,
    179	.reduce		= NFT_REDUCE_READONLY,
    180};
    181
    182static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
    183	.family		= NFPROTO_IPV6,
    184	.name		= "masq",
    185	.ops		= &nft_masq_ipv6_ops,
    186	.policy		= nft_masq_policy,
    187	.maxattr	= NFTA_MASQ_MAX,
    188	.owner		= THIS_MODULE,
    189};
    190
    191static int __init nft_masq_module_init_ipv6(void)
    192{
    193	return nft_register_expr(&nft_masq_ipv6_type);
    194}
    195
    196static void nft_masq_module_exit_ipv6(void)
    197{
    198	nft_unregister_expr(&nft_masq_ipv6_type);
    199}
    200#else
    201static inline int nft_masq_module_init_ipv6(void) { return 0; }
    202static inline void nft_masq_module_exit_ipv6(void) {}
    203#endif
    204
    205#ifdef CONFIG_NF_TABLES_INET
    206static void nft_masq_inet_eval(const struct nft_expr *expr,
    207			       struct nft_regs *regs,
    208			       const struct nft_pktinfo *pkt)
    209{
    210	switch (nft_pf(pkt)) {
    211	case NFPROTO_IPV4:
    212		return nft_masq_ipv4_eval(expr, regs, pkt);
    213	case NFPROTO_IPV6:
    214		return nft_masq_ipv6_eval(expr, regs, pkt);
    215	}
    216
    217	WARN_ON_ONCE(1);
    218}
    219
    220static void
    221nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
    222{
    223	nf_ct_netns_put(ctx->net, NFPROTO_INET);
    224}
    225
    226static struct nft_expr_type nft_masq_inet_type;
    227static const struct nft_expr_ops nft_masq_inet_ops = {
    228	.type		= &nft_masq_inet_type,
    229	.size		= NFT_EXPR_SIZE(sizeof(struct nft_masq)),
    230	.eval		= nft_masq_inet_eval,
    231	.init		= nft_masq_init,
    232	.destroy	= nft_masq_inet_destroy,
    233	.dump		= nft_masq_dump,
    234	.validate	= nft_masq_validate,
    235	.reduce		= NFT_REDUCE_READONLY,
    236};
    237
    238static struct nft_expr_type nft_masq_inet_type __read_mostly = {
    239	.family		= NFPROTO_INET,
    240	.name		= "masq",
    241	.ops		= &nft_masq_inet_ops,
    242	.policy		= nft_masq_policy,
    243	.maxattr	= NFTA_MASQ_MAX,
    244	.owner		= THIS_MODULE,
    245};
    246
    247static int __init nft_masq_module_init_inet(void)
    248{
    249	return nft_register_expr(&nft_masq_inet_type);
    250}
    251
    252static void nft_masq_module_exit_inet(void)
    253{
    254	nft_unregister_expr(&nft_masq_inet_type);
    255}
    256#else
    257static inline int nft_masq_module_init_inet(void) { return 0; }
    258static inline void nft_masq_module_exit_inet(void) {}
    259#endif
    260
    261static int __init nft_masq_module_init(void)
    262{
    263	int ret;
    264
    265	ret = nft_masq_module_init_ipv6();
    266	if (ret < 0)
    267		return ret;
    268
    269	ret = nft_masq_module_init_inet();
    270	if (ret < 0) {
    271		nft_masq_module_exit_ipv6();
    272		return ret;
    273	}
    274
    275	ret = nft_register_expr(&nft_masq_ipv4_type);
    276	if (ret < 0) {
    277		nft_masq_module_exit_inet();
    278		nft_masq_module_exit_ipv6();
    279		return ret;
    280	}
    281
    282	ret = nf_nat_masquerade_inet_register_notifiers();
    283	if (ret < 0) {
    284		nft_masq_module_exit_ipv6();
    285		nft_masq_module_exit_inet();
    286		nft_unregister_expr(&nft_masq_ipv4_type);
    287		return ret;
    288	}
    289
    290	return ret;
    291}
    292
    293static void __exit nft_masq_module_exit(void)
    294{
    295	nft_masq_module_exit_ipv6();
    296	nft_masq_module_exit_inet();
    297	nft_unregister_expr(&nft_masq_ipv4_type);
    298	nf_nat_masquerade_inet_unregister_notifiers();
    299}
    300
    301module_init(nft_masq_module_init);
    302module_exit(nft_masq_module_exit);
    303
    304MODULE_LICENSE("GPL");
    305MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
    306MODULE_ALIAS_NFT_EXPR("masq");
    307MODULE_DESCRIPTION("Netfilter nftables masquerade expression support");