root/net/netfilter/nft_socket.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nft_socket_eval
  2. nft_socket_init
  3. nft_socket_dump
  4. nft_socket_module_init
  5. nft_socket_module_exit

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

/* [<][>][^][v][top][bottom][index][help] */