libnftnl  1.2.9
log.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4  *
5  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6  */
7 
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <string.h>
11 #include <arpa/inet.h>
12 #include <errno.h>
13 #include <linux/netfilter/nf_tables.h>
14 #include <linux/netfilter/nf_log.h>
15 
16 #include "internal.h"
17 #include <libmnl/libmnl.h>
18 #include <libnftnl/expr.h>
19 #include <libnftnl/rule.h>
20 
22  uint32_t snaplen;
23  uint16_t group;
24  uint16_t qthreshold;
25  uint32_t level;
26  uint32_t flags;
27  const char *prefix;
28 };
29 
30 static int nftnl_expr_log_set(struct nftnl_expr *e, uint16_t type,
31  const void *data, uint32_t data_len)
32 {
33  struct nftnl_expr_log *log = nftnl_expr_data(e);
34 
35  switch(type) {
36  case NFTNL_EXPR_LOG_PREFIX:
37  if (log->flags & (1 << NFTNL_EXPR_LOG_PREFIX))
38  xfree(log->prefix);
39 
40  log->prefix = strdup(data);
41  if (!log->prefix)
42  return -1;
43  break;
44  case NFTNL_EXPR_LOG_GROUP:
45  memcpy(&log->group, data, data_len);
46  break;
47  case NFTNL_EXPR_LOG_SNAPLEN:
48  memcpy(&log->snaplen, data, data_len);
49  break;
50  case NFTNL_EXPR_LOG_QTHRESHOLD:
51  memcpy(&log->qthreshold, data, data_len);
52  break;
53  case NFTNL_EXPR_LOG_LEVEL:
54  memcpy(&log->level, data, data_len);
55  break;
56  case NFTNL_EXPR_LOG_FLAGS:
57  memcpy(&log->flags, data, data_len);
58  break;
59  }
60  return 0;
61 }
62 
63 static const void *
64 nftnl_expr_log_get(const struct nftnl_expr *e, uint16_t type,
65  uint32_t *data_len)
66 {
67  struct nftnl_expr_log *log = nftnl_expr_data(e);
68 
69  switch(type) {
70  case NFTNL_EXPR_LOG_PREFIX:
71  *data_len = strlen(log->prefix)+1;
72  return log->prefix;
73  case NFTNL_EXPR_LOG_GROUP:
74  *data_len = sizeof(log->group);
75  return &log->group;
76  case NFTNL_EXPR_LOG_SNAPLEN:
77  *data_len = sizeof(log->snaplen);
78  return &log->snaplen;
79  case NFTNL_EXPR_LOG_QTHRESHOLD:
80  *data_len = sizeof(log->qthreshold);
81  return &log->qthreshold;
82  case NFTNL_EXPR_LOG_LEVEL:
83  *data_len = sizeof(log->level);
84  return &log->level;
85  case NFTNL_EXPR_LOG_FLAGS:
86  *data_len = sizeof(log->flags);
87  return &log->flags;
88  }
89  return NULL;
90 }
91 
92 static int nftnl_expr_log_cb(const struct nlattr *attr, void *data)
93 {
94  const struct nlattr **tb = data;
95  int type = mnl_attr_get_type(attr);
96 
97  if (mnl_attr_type_valid(attr, NFTA_LOG_MAX) < 0)
98  return MNL_CB_OK;
99 
100  switch(type) {
101  case NFTA_LOG_PREFIX:
102  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
103  abi_breakage();
104  break;
105  case NFTA_LOG_GROUP:
106  case NFTA_LOG_QTHRESHOLD:
107  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
108  abi_breakage();
109  break;
110  case NFTA_LOG_SNAPLEN:
111  case NFTA_LOG_LEVEL:
112  case NFTA_LOG_FLAGS:
113  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
114  abi_breakage();
115  break;
116  }
117 
118  tb[type] = attr;
119  return MNL_CB_OK;
120 }
121 
122 static void
123 nftnl_expr_log_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
124 {
125  struct nftnl_expr_log *log = nftnl_expr_data(e);
126 
127  if (e->flags & (1 << NFTNL_EXPR_LOG_PREFIX))
128  mnl_attr_put_strz(nlh, NFTA_LOG_PREFIX, log->prefix);
129  if (e->flags & (1 << NFTNL_EXPR_LOG_GROUP))
130  mnl_attr_put_u16(nlh, NFTA_LOG_GROUP, htons(log->group));
131  if (e->flags & (1 << NFTNL_EXPR_LOG_SNAPLEN))
132  mnl_attr_put_u32(nlh, NFTA_LOG_SNAPLEN, htonl(log->snaplen));
133  if (e->flags & (1 << NFTNL_EXPR_LOG_QTHRESHOLD))
134  mnl_attr_put_u16(nlh, NFTA_LOG_QTHRESHOLD, htons(log->qthreshold));
135  if (e->flags & (1 << NFTNL_EXPR_LOG_LEVEL))
136  mnl_attr_put_u32(nlh, NFTA_LOG_LEVEL, htonl(log->level));
137  if (e->flags & (1 << NFTNL_EXPR_LOG_FLAGS))
138  mnl_attr_put_u32(nlh, NFTA_LOG_FLAGS, htonl(log->flags));
139 }
140 
141 static int
142 nftnl_expr_log_parse(struct nftnl_expr *e, struct nlattr *attr)
143 {
144  struct nftnl_expr_log *log = nftnl_expr_data(e);
145  struct nlattr *tb[NFTA_LOG_MAX+1] = {};
146 
147  if (mnl_attr_parse_nested(attr, nftnl_expr_log_cb, tb) < 0)
148  return -1;
149 
150  if (tb[NFTA_LOG_PREFIX]) {
151  if (log->prefix)
152  xfree(log->prefix);
153 
154  log->prefix = strdup(mnl_attr_get_str(tb[NFTA_LOG_PREFIX]));
155  if (!log->prefix)
156  return -1;
157  e->flags |= (1 << NFTNL_EXPR_LOG_PREFIX);
158  }
159  if (tb[NFTA_LOG_GROUP]) {
160  log->group = ntohs(mnl_attr_get_u16(tb[NFTA_LOG_GROUP]));
161  e->flags |= (1 << NFTNL_EXPR_LOG_GROUP);
162  }
163  if (tb[NFTA_LOG_SNAPLEN]) {
164  log->snaplen = ntohl(mnl_attr_get_u32(tb[NFTA_LOG_SNAPLEN]));
165  e->flags |= (1 << NFTNL_EXPR_LOG_SNAPLEN);
166  }
167  if (tb[NFTA_LOG_QTHRESHOLD]) {
168  log->qthreshold = ntohs(mnl_attr_get_u16(tb[NFTA_LOG_QTHRESHOLD]));
169  e->flags |= (1 << NFTNL_EXPR_LOG_QTHRESHOLD);
170  }
171  if (tb[NFTA_LOG_LEVEL]) {
172  log->level = ntohl(mnl_attr_get_u32(tb[NFTA_LOG_LEVEL]));
173  e->flags |= (1 << NFTNL_EXPR_LOG_LEVEL);
174  }
175  if (tb[NFTA_LOG_FLAGS]) {
176  log->flags = ntohl(mnl_attr_get_u32(tb[NFTA_LOG_FLAGS]));
177  e->flags |= (1 << NFTNL_EXPR_LOG_FLAGS);
178  }
179 
180  return 0;
181 }
182 
183 static int
184 nftnl_expr_log_snprintf(char *buf, size_t remain,
185  uint32_t flags, const struct nftnl_expr *e)
186 {
187  struct nftnl_expr_log *log = nftnl_expr_data(e);
188  int ret, offset = 0;
189 
190  if (e->flags & (1 << NFTNL_EXPR_LOG_PREFIX)) {
191  ret = snprintf(buf, remain, "prefix %s ", log->prefix);
192  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
193  }
194 
195  if (e->flags & (1 << NFTNL_EXPR_LOG_GROUP)) {
196  ret = snprintf(buf + offset, remain,
197  "group %u snaplen %u qthreshold %u ",
198  log->group, log->snaplen, log->qthreshold);
199  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
200  } else {
201  if (e->flags & (1 << NFTNL_EXPR_LOG_LEVEL)) {
202  ret = snprintf(buf + offset, remain, "level %u ",
203  log->level);
204  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
205  }
206  if (e->flags & (1 << NFTNL_EXPR_LOG_FLAGS)) {
207  if (log->flags & NF_LOG_TCPSEQ) {
208  ret = snprintf(buf + offset, remain, "tcpseq ");
209  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
210  }
211  if (log->flags & NF_LOG_TCPOPT) {
212  ret = snprintf(buf + offset, remain, "tcpopt ");
213  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
214  }
215  if (log->flags & NF_LOG_IPOPT) {
216  ret = snprintf(buf + offset, remain, "ipopt ");
217  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
218  }
219  if (log->flags & NF_LOG_UID) {
220  ret = snprintf(buf + offset, remain, "uid ");
221  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
222  }
223  if (log->flags & NF_LOG_MACDECODE) {
224  ret = snprintf(buf + offset, remain,
225  "macdecode ");
226  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
227  }
228  }
229  }
230 
231  return offset;
232 }
233 
234 static void nftnl_expr_log_free(const struct nftnl_expr *e)
235 {
236  struct nftnl_expr_log *log = nftnl_expr_data(e);
237 
238  xfree(log->prefix);
239 }
240 
241 static struct attr_policy log_attr_policy[__NFTNL_EXPR_LOG_MAX] = {
242  [NFTNL_EXPR_LOG_PREFIX] = { .maxlen = NF_LOG_PREFIXLEN },
243  [NFTNL_EXPR_LOG_GROUP] = { .maxlen = sizeof(uint16_t) },
244  [NFTNL_EXPR_LOG_SNAPLEN] = { .maxlen = sizeof(uint32_t) },
245  [NFTNL_EXPR_LOG_QTHRESHOLD] = { .maxlen = sizeof(uint16_t) },
246  [NFTNL_EXPR_LOG_LEVEL] = { .maxlen = sizeof(uint32_t) },
247  [NFTNL_EXPR_LOG_FLAGS] = { .maxlen = sizeof(uint32_t) },
248 };
249 
250 struct expr_ops expr_ops_log = {
251  .name = "log",
252  .alloc_len = sizeof(struct nftnl_expr_log),
253  .nftnl_max_attr = __NFTNL_EXPR_LOG_MAX - 1,
254  .attr_policy = log_attr_policy,
255  .free = nftnl_expr_log_free,
256  .set = nftnl_expr_log_set,
257  .get = nftnl_expr_log_get,
258  .parse = nftnl_expr_log_parse,
259  .build = nftnl_expr_log_build,
260  .output = nftnl_expr_log_snprintf,
261 };