nft_socket.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #include <linux/module.h>
  3. #include <linux/netfilter/nf_tables.h>
  4. #include <net/netfilter/nf_tables.h>
  5. #include <net/netfilter/nf_tables_core.h>
  6. #include <net/netfilter/nf_socket.h>
  7. #include <net/inet_sock.h>
  8. #include <net/tcp.h>
  9. struct nft_socket {
  10. enum nft_socket_keys key:8;
  11. union {
  12. enum nft_registers dreg:8;
  13. };
  14. };
  15. static void nft_socket_wildcard(const struct nft_pktinfo *pkt,
  16. struct nft_regs *regs, struct sock *sk,
  17. u32 *dest)
  18. {
  19. switch (nft_pf(pkt)) {
  20. case NFPROTO_IPV4:
  21. nft_reg_store8(dest, inet_sk(sk)->inet_rcv_saddr == 0);
  22. break;
  23. #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
  24. case NFPROTO_IPV6:
  25. nft_reg_store8(dest, ipv6_addr_any(&sk->sk_v6_rcv_saddr));
  26. break;
  27. #endif
  28. default:
  29. regs->verdict.code = NFT_BREAK;
  30. return;
  31. }
  32. }
  33. static void nft_socket_eval(const struct nft_expr *expr,
  34. struct nft_regs *regs,
  35. const struct nft_pktinfo *pkt)
  36. {
  37. const struct nft_socket *priv = nft_expr_priv(expr);
  38. struct sk_buff *skb = pkt->skb;
  39. struct sock *sk = skb->sk;
  40. u32 *dest = &regs->data[priv->dreg];
  41. if (sk && !net_eq(nft_net(pkt), sock_net(sk)))
  42. sk = NULL;
  43. if (!sk)
  44. switch(nft_pf(pkt)) {
  45. case NFPROTO_IPV4:
  46. sk = nf_sk_lookup_slow_v4(nft_net(pkt), skb, nft_in(pkt));
  47. break;
  48. #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
  49. case NFPROTO_IPV6:
  50. sk = nf_sk_lookup_slow_v6(nft_net(pkt), skb, nft_in(pkt));
  51. break;
  52. #endif
  53. default:
  54. WARN_ON_ONCE(1);
  55. regs->verdict.code = NFT_BREAK;
  56. return;
  57. }
  58. if (!sk) {
  59. regs->verdict.code = NFT_BREAK;
  60. return;
  61. }
  62. switch(priv->key) {
  63. case NFT_SOCKET_TRANSPARENT:
  64. nft_reg_store8(dest, inet_sk_transparent(sk));
  65. break;
  66. case NFT_SOCKET_MARK:
  67. if (sk_fullsock(sk)) {
  68. *dest = sk->sk_mark;
  69. } else {
  70. regs->verdict.code = NFT_BREAK;
  71. return;
  72. }
  73. break;
  74. case NFT_SOCKET_WILDCARD:
  75. if (!sk_fullsock(sk)) {
  76. regs->verdict.code = NFT_BREAK;
  77. return;
  78. }
  79. nft_socket_wildcard(pkt, regs, sk, dest);
  80. break;
  81. default:
  82. WARN_ON(1);
  83. regs->verdict.code = NFT_BREAK;
  84. }
  85. if (sk != skb->sk)
  86. sock_gen_put(sk);
  87. }
  88. static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
  89. [NFTA_SOCKET_KEY] = { .type = NLA_U32 },
  90. [NFTA_SOCKET_DREG] = { .type = NLA_U32 },
  91. };
  92. static int nft_socket_init(const struct nft_ctx *ctx,
  93. const struct nft_expr *expr,
  94. const struct nlattr * const tb[])
  95. {
  96. struct nft_socket *priv = nft_expr_priv(expr);
  97. unsigned int len;
  98. if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])
  99. return -EINVAL;
  100. switch(ctx->family) {
  101. case NFPROTO_IPV4:
  102. #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
  103. case NFPROTO_IPV6:
  104. #endif
  105. case NFPROTO_INET:
  106. break;
  107. default:
  108. return -EOPNOTSUPP;
  109. }
  110. priv->key = ntohl(nla_get_u32(tb[NFTA_SOCKET_KEY]));
  111. switch(priv->key) {
  112. case NFT_SOCKET_TRANSPARENT:
  113. case NFT_SOCKET_WILDCARD:
  114. len = sizeof(u8);
  115. break;
  116. case NFT_SOCKET_MARK:
  117. len = sizeof(u32);
  118. break;
  119. default:
  120. return -EOPNOTSUPP;
  121. }
  122. priv->dreg = nft_parse_register(tb[NFTA_SOCKET_DREG]);
  123. return nft_validate_register_store(ctx, priv->dreg, NULL,
  124. NFT_DATA_VALUE, len);
  125. }
  126. static int nft_socket_dump(struct sk_buff *skb,
  127. const struct nft_expr *expr)
  128. {
  129. const struct nft_socket *priv = nft_expr_priv(expr);
  130. if (nla_put_u32(skb, NFTA_SOCKET_KEY, htonl(priv->key)))
  131. return -1;
  132. if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
  133. return -1;
  134. return 0;
  135. }
  136. static struct nft_expr_type nft_socket_type;
  137. static const struct nft_expr_ops nft_socket_ops = {
  138. .type = &nft_socket_type,
  139. .size = NFT_EXPR_SIZE(sizeof(struct nft_socket)),
  140. .eval = nft_socket_eval,
  141. .init = nft_socket_init,
  142. .dump = nft_socket_dump,
  143. };
  144. static struct nft_expr_type nft_socket_type __read_mostly = {
  145. .name = "socket",
  146. .ops = &nft_socket_ops,
  147. .policy = nft_socket_policy,
  148. .maxattr = NFTA_SOCKET_MAX,
  149. .owner = THIS_MODULE,
  150. };
  151. static int __init nft_socket_module_init(void)
  152. {
  153. return nft_register_expr(&nft_socket_type);
  154. }
  155. static void __exit nft_socket_module_exit(void)
  156. {
  157. nft_unregister_expr(&nft_socket_type);
  158. }
  159. module_init(nft_socket_module_init);
  160. module_exit(nft_socket_module_exit);
  161. MODULE_LICENSE("GPL");
  162. MODULE_AUTHOR("Máté Eckl");
  163. MODULE_DESCRIPTION("nf_tables socket match module");
  164. MODULE_ALIAS_NFT_EXPR("socket");