libnftnl  1.0.2
log.c
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include <arpa/inet.h>
16 #include <errno.h>
17 #include <linux/netfilter/nf_tables.h>
18 
19 #include "internal.h"
20 #include <libmnl/libmnl.h>
21 #include <libnftnl/expr.h>
22 #include <libnftnl/rule.h>
23 #include "expr_ops.h"
24 
25 struct nft_expr_log {
26  uint32_t snaplen;
27  uint16_t group;
28  uint16_t qthreshold;
29  const char *prefix;
30 };
31 
32 static int nft_rule_expr_log_set(struct nft_rule_expr *e, uint16_t type,
33  const void *data, uint32_t data_len)
34 {
35  struct nft_expr_log *log = nft_expr_data(e);
36 
37  switch(type) {
38  case NFT_EXPR_LOG_PREFIX:
39  if (log->prefix)
40  xfree(log->prefix);
41 
42  log->prefix = strdup(data);
43  break;
44  case NFT_EXPR_LOG_GROUP:
45  log->group = *((uint16_t *)data);
46  break;
47  case NFT_EXPR_LOG_SNAPLEN:
48  log->snaplen = *((uint32_t *)data);
49  break;
50  case NFT_EXPR_LOG_QTHRESHOLD:
51  log->qthreshold = *((uint16_t *)data);
52  break;
53  default:
54  return -1;
55  }
56  return 0;
57 }
58 
59 static const void *
60 nft_rule_expr_log_get(const struct nft_rule_expr *e, uint16_t type,
61  uint32_t *data_len)
62 {
63  struct nft_expr_log *log = nft_expr_data(e);
64 
65  switch(type) {
66  case NFT_EXPR_LOG_PREFIX:
67  *data_len = strlen(log->prefix)+1;
68  return log->prefix;
69  case NFT_EXPR_LOG_GROUP:
70  *data_len = sizeof(log->group);
71  return &log->group;
72  case NFT_EXPR_LOG_SNAPLEN:
73  *data_len = sizeof(log->snaplen);
74  return &log->snaplen;
75  case NFT_EXPR_LOG_QTHRESHOLD:
76  *data_len = sizeof(log->qthreshold);
77  return &log->qthreshold;
78  }
79  return NULL;
80 }
81 
82 static int nft_rule_expr_log_cb(const struct nlattr *attr, void *data)
83 {
84  const struct nlattr **tb = data;
85  int type = mnl_attr_get_type(attr);
86 
87  if (mnl_attr_type_valid(attr, NFTA_LOG_MAX) < 0)
88  return MNL_CB_OK;
89 
90  switch(type) {
91  case NFTA_LOG_PREFIX:
92  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
93  perror("mnl_attr_validate");
94  return MNL_CB_ERROR;
95  }
96  break;
97  case NFTA_LOG_GROUP:
98  case NFTA_LOG_QTHRESHOLD:
99  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
100  perror("mnl_attr_validate");
101  return MNL_CB_ERROR;
102  }
103  break;
104  case NFTA_LOG_SNAPLEN:
105  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
106  perror("mnl_attr_validate");
107  return MNL_CB_ERROR;
108  }
109  break;
110  }
111 
112  tb[type] = attr;
113  return MNL_CB_OK;
114 }
115 
116 static void
117 nft_rule_expr_log_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
118 {
119  struct nft_expr_log *log = nft_expr_data(e);
120 
121  if (e->flags & (1 << NFT_EXPR_LOG_PREFIX))
122  mnl_attr_put_strz(nlh, NFTA_LOG_PREFIX, log->prefix);
123  if (e->flags & (1 << NFT_EXPR_LOG_GROUP))
124  mnl_attr_put_u16(nlh, NFTA_LOG_GROUP, htons(log->group));
125  if (e->flags & (1 << NFT_EXPR_LOG_SNAPLEN))
126  mnl_attr_put_u32(nlh, NFTA_LOG_SNAPLEN, htonl(log->snaplen));
127  if (e->flags & (1 << NFT_EXPR_LOG_QTHRESHOLD))
128  mnl_attr_put_u16(nlh, NFTA_LOG_QTHRESHOLD, htons(log->qthreshold));
129 }
130 
131 static int
132 nft_rule_expr_log_parse(struct nft_rule_expr *e, struct nlattr *attr)
133 {
134  struct nft_expr_log *log = nft_expr_data(e);
135  struct nlattr *tb[NFTA_LOG_MAX+1] = {};
136 
137  if (mnl_attr_parse_nested(attr, nft_rule_expr_log_cb, tb) < 0)
138  return -1;
139 
140  if (tb[NFTA_LOG_PREFIX]) {
141  if (log->prefix)
142  xfree(log->prefix);
143 
144  log->prefix = strdup(mnl_attr_get_str(tb[NFTA_LOG_PREFIX]));
145  e->flags |= (1 << NFT_EXPR_LOG_PREFIX);
146  }
147  if (tb[NFTA_LOG_GROUP]) {
148  log->group = ntohs(mnl_attr_get_u16(tb[NFTA_LOG_GROUP]));
149  e->flags |= (1 << NFT_EXPR_LOG_GROUP);
150  }
151  if (tb[NFTA_LOG_SNAPLEN]) {
152  log->snaplen = ntohl(mnl_attr_get_u32(tb[NFTA_LOG_SNAPLEN]));
153  e->flags |= (1 << NFT_EXPR_LOG_SNAPLEN);
154  }
155  if (tb[NFTA_LOG_QTHRESHOLD]) {
156  log->qthreshold = ntohs(mnl_attr_get_u16(tb[NFTA_LOG_QTHRESHOLD]));
157  e->flags |= (1 << NFT_EXPR_LOG_QTHRESHOLD);
158  }
159 
160  return 0;
161 }
162 
163 static int nft_rule_expr_log_json_parse(struct nft_rule_expr *e, json_t *root,
164  struct nft_parse_err *err)
165 {
166 #ifdef JSON_PARSING
167  const char *prefix;
168  uint32_t snaplen;
169  uint16_t group, qthreshold;
170 
171  prefix = nft_jansson_parse_str(root, "prefix", err);
172  if (prefix != NULL)
173  nft_rule_expr_set_str(e, NFT_EXPR_LOG_PREFIX, prefix);
174 
175  if (nft_jansson_parse_val(root, "group", NFT_TYPE_U16, &group,
176  err) == 0)
177  nft_rule_expr_set_u16(e, NFT_EXPR_LOG_GROUP, group);
178 
179  if (nft_jansson_parse_val(root, "snaplen", NFT_TYPE_U32, &snaplen,
180  err) == 0)
181  nft_rule_expr_set_u32(e, NFT_EXPR_LOG_SNAPLEN, snaplen);
182 
183  if (nft_jansson_parse_val(root, "qthreshold", NFT_TYPE_U16,
184  &qthreshold, err) == 0)
185  nft_rule_expr_set_u16(e, NFT_EXPR_LOG_QTHRESHOLD, qthreshold);
186 
187  return 0;
188 #else
189  errno = EOPNOTSUPP;
190  return -1;
191 #endif
192 }
193 
194 static int nft_rule_expr_log_xml_parse(struct nft_rule_expr *e,
195  mxml_node_t *tree,
196  struct nft_parse_err *err)
197 {
198 #ifdef XML_PARSING
199  const char *prefix;
200  uint32_t snaplen;
201  uint16_t group, qthreshold;
202 
203  prefix = nft_mxml_str_parse(tree, "prefix", MXML_DESCEND_FIRST,
204  NFT_XML_MAND, err);
205  if (prefix != NULL)
206  nft_rule_expr_set_str(e, NFT_EXPR_LOG_PREFIX, prefix);
207 
208  if (nft_mxml_num_parse(tree, "group", MXML_DESCEND_FIRST, BASE_DEC,
209  &group, NFT_TYPE_U16, NFT_XML_MAND, err) == 0)
210  nft_rule_expr_set_u16(e, NFT_EXPR_LOG_GROUP, group);
211 
212  if (nft_mxml_num_parse(tree, "snaplen", MXML_DESCEND_FIRST, BASE_DEC,
213  &snaplen, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
214  nft_rule_expr_set_u32(e, NFT_EXPR_LOG_SNAPLEN, snaplen);
215 
216  if (nft_mxml_num_parse(tree, "qthreshold", MXML_DESCEND_FIRST, BASE_DEC,
217  &qthreshold, NFT_TYPE_U16, NFT_XML_MAND,
218  err) == 0)
219  nft_rule_expr_set_u16(e, NFT_EXPR_LOG_QTHRESHOLD, qthreshold);
220 
221  return 0;
222 #else
223  errno = EOPNOTSUPP;
224  return -1;
225 #endif
226 }
227 
228 static int nft_rule_expr_log_snprintf_default(char *buf, size_t len,
229  struct nft_rule_expr *e)
230 {
231  struct nft_expr_log *log = nft_expr_data(e);
232 
233  return snprintf(buf, len, "prefix '%s' group %u snaplen %u"
234  "qthreshold %u ",
235  log->prefix, log->group, log->snaplen, log->qthreshold);
236 }
237 
238 static int nft_rule_expr_log_snprintf_xml(char *buf, size_t size,
239  struct nft_rule_expr *e)
240 {
241  int ret, len = size, offset = 0;
242  struct nft_expr_log *log = nft_expr_data(e);
243 
244  if (e->flags & (1 << NFT_EXPR_LOG_PREFIX)) {
245  ret = snprintf(buf + offset, len, "<prefix>%s</prefix>",
246  log->prefix);
247  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
248  }
249  if (e->flags & (1 << NFT_EXPR_LOG_GROUP)) {
250  ret = snprintf(buf + offset, len, "<group>%u</group>",
251  log->group);
252  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
253  }
254  if (e->flags & (1 << NFT_EXPR_LOG_SNAPLEN)) {
255  ret = snprintf(buf + offset, len, "<snaplen>%u</snaplen>",
256  log->snaplen);
257  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
258  }
259  if (e->flags & (1 << NFT_EXPR_LOG_QTHRESHOLD)) {
260  ret = snprintf(buf + offset, len, "<qthreshold>%u</qthreshold>",
261  log->qthreshold);
262  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
263  }
264 
265  return offset;
266 }
267 
268 static int nft_rule_expr_log_snprintf_json(char *buf, size_t len,
269  struct nft_rule_expr *e)
270 {
271  int ret, size = len, offset = 0;
272  struct nft_expr_log *log = nft_expr_data(e);
273 
274  if (e->flags & (1 << NFT_EXPR_LOG_PREFIX)) {
275  ret = snprintf(buf + offset, len, "\"prefix\":\"%s\",",
276  log->prefix);
277  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
278  }
279  if (e->flags & (1 << NFT_EXPR_LOG_GROUP)) {
280  ret = snprintf(buf + offset, len, "\"group\":%u,",
281  log->group);
282  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
283  }
284  if (e->flags & (1 << NFT_EXPR_LOG_SNAPLEN)) {
285  ret = snprintf(buf + offset, len, "\"snaplen\":%u,",
286  log->snaplen);
287  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
288  }
289  if (e->flags & (1 << NFT_EXPR_LOG_QTHRESHOLD)) {
290  ret = snprintf(buf + offset, len, "\"qthreshold\":%u,",
291  log->qthreshold);
292  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
293  }
294  /* Remove the last comma characther */
295  if (offset > 0)
296  offset--;
297 
298  return offset;
299 }
300 
301 
302 static int
303 nft_rule_expr_log_snprintf(char *buf, size_t len, uint32_t type,
304  uint32_t flags, struct nft_rule_expr *e)
305 {
306  switch(type) {
307  case NFT_OUTPUT_DEFAULT:
308  return nft_rule_expr_log_snprintf_default(buf, len, e);
309  case NFT_OUTPUT_XML:
310  return nft_rule_expr_log_snprintf_xml(buf, len, e);
311  case NFT_OUTPUT_JSON:
312  return nft_rule_expr_log_snprintf_json(buf, len, e);
313  default:
314  break;
315  }
316  return -1;
317 }
318 
319 static void nft_rule_expr_log_free(struct nft_rule_expr *e)
320 {
321  struct nft_expr_log *log = nft_expr_data(e);
322 
323  xfree(log->prefix);
324 }
325 
326 struct expr_ops expr_ops_log = {
327  .name = "log",
328  .alloc_len = sizeof(struct nft_expr_log),
329  .max_attr = NFTA_LOG_MAX,
330  .free = nft_rule_expr_log_free,
331  .set = nft_rule_expr_log_set,
332  .get = nft_rule_expr_log_get,
333  .parse = nft_rule_expr_log_parse,
334  .build = nft_rule_expr_log_build,
335  .snprintf = nft_rule_expr_log_snprintf,
336  .xml_parse = nft_rule_expr_log_xml_parse,
337  .json_parse = nft_rule_expr_log_json_parse,
338 };
339 
340 static void __init expr_log_init(void)
341 {
342  nft_expr_ops_register(&expr_ops_log);
343 }