Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
0004  * Copyright (c) 2013 Eric Leblond <eric@regit.org>
0005  *
0006  * Development of this code funded by Astaro AG (http://www.astaro.com/)
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/netlink.h>
0013 #include <linux/netfilter.h>
0014 #include <linux/netfilter/nf_tables.h>
0015 #include <net/netfilter/nf_tables.h>
0016 #include <net/netfilter/nft_reject.h>
0017 #include <linux/icmp.h>
0018 #include <linux/icmpv6.h>
0019 
0020 const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
0021     [NFTA_REJECT_TYPE]      = { .type = NLA_U32 },
0022     [NFTA_REJECT_ICMP_CODE]     = { .type = NLA_U8 },
0023 };
0024 EXPORT_SYMBOL_GPL(nft_reject_policy);
0025 
0026 int nft_reject_validate(const struct nft_ctx *ctx,
0027             const struct nft_expr *expr,
0028             const struct nft_data **data)
0029 {
0030     return nft_chain_validate_hooks(ctx->chain,
0031                     (1 << NF_INET_LOCAL_IN) |
0032                     (1 << NF_INET_FORWARD) |
0033                     (1 << NF_INET_LOCAL_OUT) |
0034                     (1 << NF_INET_PRE_ROUTING));
0035 }
0036 EXPORT_SYMBOL_GPL(nft_reject_validate);
0037 
0038 int nft_reject_init(const struct nft_ctx *ctx,
0039             const struct nft_expr *expr,
0040             const struct nlattr * const tb[])
0041 {
0042     struct nft_reject *priv = nft_expr_priv(expr);
0043     int icmp_code;
0044 
0045     if (tb[NFTA_REJECT_TYPE] == NULL)
0046         return -EINVAL;
0047 
0048     priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
0049     switch (priv->type) {
0050     case NFT_REJECT_ICMP_UNREACH:
0051     case NFT_REJECT_ICMPX_UNREACH:
0052         if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
0053             return -EINVAL;
0054 
0055         icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
0056         if (priv->type == NFT_REJECT_ICMPX_UNREACH &&
0057             icmp_code > NFT_REJECT_ICMPX_MAX)
0058             return -EINVAL;
0059 
0060         priv->icmp_code = icmp_code;
0061         break;
0062     case NFT_REJECT_TCP_RST:
0063         break;
0064     default:
0065         return -EINVAL;
0066     }
0067 
0068     return 0;
0069 }
0070 EXPORT_SYMBOL_GPL(nft_reject_init);
0071 
0072 int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
0073 {
0074     const struct nft_reject *priv = nft_expr_priv(expr);
0075 
0076     if (nla_put_be32(skb, NFTA_REJECT_TYPE, htonl(priv->type)))
0077         goto nla_put_failure;
0078 
0079     switch (priv->type) {
0080     case NFT_REJECT_ICMP_UNREACH:
0081     case NFT_REJECT_ICMPX_UNREACH:
0082         if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
0083             goto nla_put_failure;
0084         break;
0085     default:
0086         break;
0087     }
0088 
0089     return 0;
0090 
0091 nla_put_failure:
0092     return -1;
0093 }
0094 EXPORT_SYMBOL_GPL(nft_reject_dump);
0095 
0096 static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX + 1] = {
0097     [NFT_REJECT_ICMPX_NO_ROUTE]     = ICMP_NET_UNREACH,
0098     [NFT_REJECT_ICMPX_PORT_UNREACH]     = ICMP_PORT_UNREACH,
0099     [NFT_REJECT_ICMPX_HOST_UNREACH]     = ICMP_HOST_UNREACH,
0100     [NFT_REJECT_ICMPX_ADMIN_PROHIBITED] = ICMP_PKT_FILTERED,
0101 };
0102 
0103 int nft_reject_icmp_code(u8 code)
0104 {
0105     if (WARN_ON_ONCE(code > NFT_REJECT_ICMPX_MAX))
0106         return ICMP_NET_UNREACH;
0107 
0108     return icmp_code_v4[code];
0109 }
0110 
0111 EXPORT_SYMBOL_GPL(nft_reject_icmp_code);
0112 
0113 
0114 static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX + 1] = {
0115     [NFT_REJECT_ICMPX_NO_ROUTE]     = ICMPV6_NOROUTE,
0116     [NFT_REJECT_ICMPX_PORT_UNREACH]     = ICMPV6_PORT_UNREACH,
0117     [NFT_REJECT_ICMPX_HOST_UNREACH]     = ICMPV6_ADDR_UNREACH,
0118     [NFT_REJECT_ICMPX_ADMIN_PROHIBITED] = ICMPV6_ADM_PROHIBITED,
0119 };
0120 
0121 int nft_reject_icmpv6_code(u8 code)
0122 {
0123     if (WARN_ON_ONCE(code > NFT_REJECT_ICMPX_MAX))
0124         return ICMPV6_NOROUTE;
0125 
0126     return icmp_code_v6[code];
0127 }
0128 
0129 EXPORT_SYMBOL_GPL(nft_reject_icmpv6_code);
0130 
0131 MODULE_LICENSE("GPL");
0132 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
0133 MODULE_DESCRIPTION("Netfilter x_tables over nftables module");