nft_reject_inet.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2014 Patrick McHardy <kaber@trash.net>
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/init.h>
  7. #include <linux/module.h>
  8. #include <linux/netlink.h>
  9. #include <linux/netfilter.h>
  10. #include <linux/netfilter/nf_tables.h>
  11. #include <net/netfilter/nf_tables.h>
  12. #include <net/netfilter/nft_reject.h>
  13. #include <net/netfilter/ipv4/nf_reject.h>
  14. #include <net/netfilter/ipv6/nf_reject.h>
  15. static void nft_reject_inet_eval(const struct nft_expr *expr,
  16. struct nft_regs *regs,
  17. const struct nft_pktinfo *pkt)
  18. {
  19. struct nft_reject *priv = nft_expr_priv(expr);
  20. switch (nft_pf(pkt)) {
  21. case NFPROTO_IPV4:
  22. switch (priv->type) {
  23. case NFT_REJECT_ICMP_UNREACH:
  24. nf_send_unreach(pkt->skb, priv->icmp_code,
  25. nft_hook(pkt));
  26. break;
  27. case NFT_REJECT_TCP_RST:
  28. nf_send_reset(nft_net(pkt), pkt->skb, nft_hook(pkt));
  29. break;
  30. case NFT_REJECT_ICMPX_UNREACH:
  31. nf_send_unreach(pkt->skb,
  32. nft_reject_icmp_code(priv->icmp_code),
  33. nft_hook(pkt));
  34. break;
  35. }
  36. break;
  37. case NFPROTO_IPV6:
  38. switch (priv->type) {
  39. case NFT_REJECT_ICMP_UNREACH:
  40. nf_send_unreach6(nft_net(pkt), pkt->skb,
  41. priv->icmp_code, nft_hook(pkt));
  42. break;
  43. case NFT_REJECT_TCP_RST:
  44. nf_send_reset6(nft_net(pkt), pkt->skb, nft_hook(pkt));
  45. break;
  46. case NFT_REJECT_ICMPX_UNREACH:
  47. nf_send_unreach6(nft_net(pkt), pkt->skb,
  48. nft_reject_icmpv6_code(priv->icmp_code),
  49. nft_hook(pkt));
  50. break;
  51. }
  52. break;
  53. }
  54. regs->verdict.code = NF_DROP;
  55. }
  56. static int nft_reject_inet_init(const struct nft_ctx *ctx,
  57. const struct nft_expr *expr,
  58. const struct nlattr * const tb[])
  59. {
  60. struct nft_reject *priv = nft_expr_priv(expr);
  61. int icmp_code;
  62. if (tb[NFTA_REJECT_TYPE] == NULL)
  63. return -EINVAL;
  64. priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
  65. switch (priv->type) {
  66. case NFT_REJECT_ICMP_UNREACH:
  67. case NFT_REJECT_ICMPX_UNREACH:
  68. if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
  69. return -EINVAL;
  70. icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
  71. if (priv->type == NFT_REJECT_ICMPX_UNREACH &&
  72. icmp_code > NFT_REJECT_ICMPX_MAX)
  73. return -EINVAL;
  74. priv->icmp_code = icmp_code;
  75. break;
  76. case NFT_REJECT_TCP_RST:
  77. break;
  78. default:
  79. return -EINVAL;
  80. }
  81. return 0;
  82. }
  83. static int nft_reject_inet_dump(struct sk_buff *skb,
  84. const struct nft_expr *expr)
  85. {
  86. const struct nft_reject *priv = nft_expr_priv(expr);
  87. if (nla_put_be32(skb, NFTA_REJECT_TYPE, htonl(priv->type)))
  88. goto nla_put_failure;
  89. switch (priv->type) {
  90. case NFT_REJECT_ICMP_UNREACH:
  91. case NFT_REJECT_ICMPX_UNREACH:
  92. if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
  93. goto nla_put_failure;
  94. break;
  95. default:
  96. break;
  97. }
  98. return 0;
  99. nla_put_failure:
  100. return -1;
  101. }
  102. static struct nft_expr_type nft_reject_inet_type;
  103. static const struct nft_expr_ops nft_reject_inet_ops = {
  104. .type = &nft_reject_inet_type,
  105. .size = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
  106. .eval = nft_reject_inet_eval,
  107. .init = nft_reject_inet_init,
  108. .dump = nft_reject_inet_dump,
  109. .validate = nft_reject_validate,
  110. };
  111. static struct nft_expr_type nft_reject_inet_type __read_mostly = {
  112. .family = NFPROTO_INET,
  113. .name = "reject",
  114. .ops = &nft_reject_inet_ops,
  115. .policy = nft_reject_policy,
  116. .maxattr = NFTA_REJECT_MAX,
  117. .owner = THIS_MODULE,
  118. };
  119. static int __init nft_reject_inet_module_init(void)
  120. {
  121. return nft_register_expr(&nft_reject_inet_type);
  122. }
  123. static void __exit nft_reject_inet_module_exit(void)
  124. {
  125. nft_unregister_expr(&nft_reject_inet_type);
  126. }
  127. module_init(nft_reject_inet_module_init);
  128. module_exit(nft_reject_inet_module_exit);
  129. MODULE_LICENSE("GPL");
  130. MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
  131. MODULE_ALIAS_NFT_AF_EXPR(1, "reject");
  132. MODULE_DESCRIPTION("Netfilter nftables reject inet support");