0001
0002
0003
0004
0005
0006
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");