• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3   * Copyright (c) 2012-2014 Pablo Neira Ayuso <pablo@netfilter.org>
4   *
5   * This program is free software; you can redistribute it and/or modify
6   * it under the terms of the GNU General Public License version 2 as
7   * published by the Free Software Foundation.
8   *
9   * Development of this code funded by Astaro AG (http://www.astaro.com/)
10   */
11  
12  #include <linux/kernel.h>
13  #include <linux/init.h>
14  #include <linux/module.h>
15  #include <linux/netlink.h>
16  #include <linux/netfilter.h>
17  #include <linux/netfilter/nf_tables.h>
18  #include <net/netfilter/nf_tables.h>
19  #include <net/netfilter/nf_log.h>
20  #include <linux/netdevice.h>
21  
22  static const char *nft_log_null_prefix = "";
23  
24  struct nft_log {
25  	struct nf_loginfo	loginfo;
26  	char			*prefix;
27  };
28  
nft_log_eval(const struct nft_expr * expr,struct nft_regs * regs,const struct nft_pktinfo * pkt)29  static void nft_log_eval(const struct nft_expr *expr,
30  			 struct nft_regs *regs,
31  			 const struct nft_pktinfo *pkt)
32  {
33  	const struct nft_log *priv = nft_expr_priv(expr);
34  
35  	nf_log_packet(nft_net(pkt), nft_pf(pkt), nft_hook(pkt), pkt->skb,
36  		      nft_in(pkt), nft_out(pkt), &priv->loginfo, "%s",
37  		      priv->prefix);
38  }
39  
40  static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
41  	[NFTA_LOG_GROUP]	= { .type = NLA_U16 },
42  	[NFTA_LOG_PREFIX]	= { .type = NLA_STRING,
43  				    .len = NF_LOG_PREFIXLEN - 1 },
44  	[NFTA_LOG_SNAPLEN]	= { .type = NLA_U32 },
45  	[NFTA_LOG_QTHRESHOLD]	= { .type = NLA_U16 },
46  	[NFTA_LOG_LEVEL]	= { .type = NLA_U32 },
47  	[NFTA_LOG_FLAGS]	= { .type = NLA_U32 },
48  };
49  
nft_log_init(const struct nft_ctx * ctx,const struct nft_expr * expr,const struct nlattr * const tb[])50  static int nft_log_init(const struct nft_ctx *ctx,
51  			const struct nft_expr *expr,
52  			const struct nlattr * const tb[])
53  {
54  	struct nft_log *priv = nft_expr_priv(expr);
55  	struct nf_loginfo *li = &priv->loginfo;
56  	const struct nlattr *nla;
57  	int err;
58  
59  	li->type = NF_LOG_TYPE_LOG;
60  	if (tb[NFTA_LOG_LEVEL] != NULL &&
61  	    tb[NFTA_LOG_GROUP] != NULL)
62  		return -EINVAL;
63  	if (tb[NFTA_LOG_GROUP] != NULL) {
64  		li->type = NF_LOG_TYPE_ULOG;
65  		if (tb[NFTA_LOG_FLAGS] != NULL)
66  			return -EINVAL;
67  	}
68  
69  	nla = tb[NFTA_LOG_PREFIX];
70  	if (nla != NULL) {
71  		priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
72  		if (priv->prefix == NULL)
73  			return -ENOMEM;
74  		nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
75  	} else {
76  		priv->prefix = (char *)nft_log_null_prefix;
77  	}
78  
79  	switch (li->type) {
80  	case NF_LOG_TYPE_LOG:
81  		if (tb[NFTA_LOG_LEVEL] != NULL) {
82  			li->u.log.level =
83  				ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));
84  		} else {
85  			li->u.log.level = LOGLEVEL_WARNING;
86  		}
87  		if (li->u.log.level > LOGLEVEL_DEBUG) {
88  			err = -EINVAL;
89  			goto err1;
90  		}
91  
92  		if (tb[NFTA_LOG_FLAGS] != NULL) {
93  			li->u.log.logflags =
94  				ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS]));
95  			if (li->u.log.logflags & ~NF_LOG_MASK) {
96  				err = -EINVAL;
97  				goto err1;
98  			}
99  		}
100  		break;
101  	case NF_LOG_TYPE_ULOG:
102  		li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
103  		if (tb[NFTA_LOG_SNAPLEN] != NULL) {
104  			li->u.ulog.flags |= NF_LOG_F_COPY_LEN;
105  			li->u.ulog.copy_len =
106  				ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
107  		}
108  		if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
109  			li->u.ulog.qthreshold =
110  				ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
111  		}
112  		break;
113  	}
114  
115  	err = nf_logger_find_get(ctx->afi->family, li->type);
116  	if (err < 0)
117  		goto err1;
118  
119  	return 0;
120  
121  err1:
122  	if (priv->prefix != nft_log_null_prefix)
123  		kfree(priv->prefix);
124  	return err;
125  }
126  
nft_log_destroy(const struct nft_ctx * ctx,const struct nft_expr * expr)127  static void nft_log_destroy(const struct nft_ctx *ctx,
128  			    const struct nft_expr *expr)
129  {
130  	struct nft_log *priv = nft_expr_priv(expr);
131  	struct nf_loginfo *li = &priv->loginfo;
132  
133  	if (priv->prefix != nft_log_null_prefix)
134  		kfree(priv->prefix);
135  
136  	nf_logger_put(ctx->afi->family, li->type);
137  }
138  
nft_log_dump(struct sk_buff * skb,const struct nft_expr * expr)139  static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
140  {
141  	const struct nft_log *priv = nft_expr_priv(expr);
142  	const struct nf_loginfo *li = &priv->loginfo;
143  
144  	if (priv->prefix != nft_log_null_prefix)
145  		if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix))
146  			goto nla_put_failure;
147  	switch (li->type) {
148  	case NF_LOG_TYPE_LOG:
149  		if (nla_put_be32(skb, NFTA_LOG_LEVEL, htonl(li->u.log.level)))
150  			goto nla_put_failure;
151  
152  		if (li->u.log.logflags) {
153  			if (nla_put_be32(skb, NFTA_LOG_FLAGS,
154  					 htonl(li->u.log.logflags)))
155  				goto nla_put_failure;
156  		}
157  		break;
158  	case NF_LOG_TYPE_ULOG:
159  		if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group)))
160  			goto nla_put_failure;
161  
162  		if (li->u.ulog.flags & NF_LOG_F_COPY_LEN) {
163  			if (nla_put_be32(skb, NFTA_LOG_SNAPLEN,
164  					 htonl(li->u.ulog.copy_len)))
165  				goto nla_put_failure;
166  		}
167  		if (li->u.ulog.qthreshold) {
168  			if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD,
169  					 htons(li->u.ulog.qthreshold)))
170  				goto nla_put_failure;
171  		}
172  		break;
173  	}
174  	return 0;
175  
176  nla_put_failure:
177  	return -1;
178  }
179  
180  static struct nft_expr_type nft_log_type;
181  static const struct nft_expr_ops nft_log_ops = {
182  	.type		= &nft_log_type,
183  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_log)),
184  	.eval		= nft_log_eval,
185  	.init		= nft_log_init,
186  	.destroy	= nft_log_destroy,
187  	.dump		= nft_log_dump,
188  };
189  
190  static struct nft_expr_type nft_log_type __read_mostly = {
191  	.name		= "log",
192  	.ops		= &nft_log_ops,
193  	.policy		= nft_log_policy,
194  	.maxattr	= NFTA_LOG_MAX,
195  	.owner		= THIS_MODULE,
196  };
197  
nft_log_module_init(void)198  static int __init nft_log_module_init(void)
199  {
200  	return nft_register_expr(&nft_log_type);
201  }
202  
nft_log_module_exit(void)203  static void __exit nft_log_module_exit(void)
204  {
205  	nft_unregister_expr(&nft_log_type);
206  }
207  
208  module_init(nft_log_module_init);
209  module_exit(nft_log_module_exit);
210  
211  MODULE_LICENSE("GPL");
212  MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
213  MODULE_ALIAS_NFT_EXPR("log");
214