libnftnl  1.0.6
limit.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 <inttypes.h>
15 #include <string.h>
16 #include <arpa/inet.h>
17 #include <errno.h>
18 #include <linux/netfilter/nf_tables.h>
19 
20 #include "internal.h"
21 #include <libmnl/libmnl.h>
22 #include <libnftnl/expr.h>
23 #include <libnftnl/rule.h>
24 
26  uint64_t rate;
27  uint64_t unit;
28  uint32_t burst;
29  enum nft_limit_type type;
30  uint32_t flags;
31 };
32 
33 static int
34 nftnl_expr_limit_set(struct nftnl_expr *e, uint16_t type,
35  const void *data, uint32_t data_len)
36 {
37  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
38 
39  switch(type) {
40  case NFTNL_EXPR_LIMIT_RATE:
41  limit->rate = *((uint64_t *)data);
42  break;
43  case NFTNL_EXPR_LIMIT_UNIT:
44  limit->unit = *((uint64_t *)data);
45  break;
46  case NFTNL_EXPR_LIMIT_BURST:
47  limit->burst = *((uint32_t *)data);
48  break;
49  case NFTNL_EXPR_LIMIT_TYPE:
50  limit->type = *((uint32_t *)data);
51  break;
52  case NFTNL_EXPR_LIMIT_FLAGS:
53  limit->flags = *((uint32_t *)data);
54  break;
55  default:
56  return -1;
57  }
58  return 0;
59 }
60 
61 static const void *
62 nftnl_expr_limit_get(const struct nftnl_expr *e, uint16_t type,
63  uint32_t *data_len)
64 {
65  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
66 
67  switch(type) {
68  case NFTNL_EXPR_LIMIT_RATE:
69  *data_len = sizeof(uint64_t);
70  return &limit->rate;
71  case NFTNL_EXPR_LIMIT_UNIT:
72  *data_len = sizeof(uint64_t);
73  return &limit->unit;
74  case NFTNL_EXPR_LIMIT_BURST:
75  *data_len = sizeof(uint32_t);
76  return &limit->burst;
77  case NFTNL_EXPR_LIMIT_TYPE:
78  *data_len = sizeof(uint32_t);
79  return &limit->type;
80  case NFTNL_EXPR_LIMIT_FLAGS:
81  *data_len = sizeof(uint32_t);
82  return &limit->flags;
83  }
84  return NULL;
85 }
86 
87 static int nftnl_expr_limit_cb(const struct nlattr *attr, void *data)
88 {
89  const struct nlattr **tb = data;
90  int type = mnl_attr_get_type(attr);
91 
92  if (mnl_attr_type_valid(attr, NFTA_LIMIT_MAX) < 0)
93  return MNL_CB_OK;
94 
95  switch(type) {
96  case NFTA_LIMIT_RATE:
97  case NFTA_LIMIT_UNIT:
98  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
99  abi_breakage();
100  break;
101  case NFTA_LIMIT_BURST:
102  case NFTA_LIMIT_TYPE:
103  case NFTA_LIMIT_FLAGS:
104  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
105  abi_breakage();
106  break;
107  }
108 
109  tb[type] = attr;
110  return MNL_CB_OK;
111 }
112 
113 static void
114 nftnl_expr_limit_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
115 {
116  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
117 
118  if (e->flags & (1 << NFTNL_EXPR_LIMIT_RATE))
119  mnl_attr_put_u64(nlh, NFTA_LIMIT_RATE, htobe64(limit->rate));
120  if (e->flags & (1 << NFTNL_EXPR_LIMIT_UNIT))
121  mnl_attr_put_u64(nlh, NFTA_LIMIT_UNIT, htobe64(limit->unit));
122  if (e->flags & (1 << NFTNL_EXPR_LIMIT_BURST))
123  mnl_attr_put_u32(nlh, NFTA_LIMIT_BURST, htonl(limit->burst));
124  if (e->flags & (1 << NFTNL_EXPR_LIMIT_TYPE))
125  mnl_attr_put_u32(nlh, NFTA_LIMIT_TYPE, htonl(limit->type));
126  if (e->flags & (1 << NFTNL_EXPR_LIMIT_FLAGS))
127  mnl_attr_put_u32(nlh, NFTA_LIMIT_FLAGS, htonl(limit->flags));
128 }
129 
130 static int
131 nftnl_expr_limit_parse(struct nftnl_expr *e, struct nlattr *attr)
132 {
133  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
134  struct nlattr *tb[NFTA_LIMIT_MAX+1] = {};
135 
136  if (mnl_attr_parse_nested(attr, nftnl_expr_limit_cb, tb) < 0)
137  return -1;
138 
139  if (tb[NFTA_LIMIT_RATE]) {
140  limit->rate = be64toh(mnl_attr_get_u64(tb[NFTA_LIMIT_RATE]));
141  e->flags |= (1 << NFTNL_EXPR_LIMIT_RATE);
142  }
143  if (tb[NFTA_LIMIT_UNIT]) {
144  limit->unit = be64toh(mnl_attr_get_u64(tb[NFTA_LIMIT_UNIT]));
145  e->flags |= (1 << NFTNL_EXPR_LIMIT_UNIT);
146  }
147  if (tb[NFTA_LIMIT_BURST]) {
148  limit->burst = ntohl(mnl_attr_get_u32(tb[NFTA_LIMIT_BURST]));
149  e->flags |= (1 << NFTNL_EXPR_LIMIT_BURST);
150  }
151  if (tb[NFTA_LIMIT_TYPE]) {
152  limit->type = ntohl(mnl_attr_get_u32(tb[NFTA_LIMIT_TYPE]));
153  e->flags |= (1 << NFTNL_EXPR_LIMIT_TYPE);
154  }
155  if (tb[NFTA_LIMIT_FLAGS]) {
156  limit->flags = ntohl(mnl_attr_get_u32(tb[NFTA_LIMIT_FLAGS]));
157  e->flags |= (1 << NFTNL_EXPR_LIMIT_FLAGS);
158  }
159 
160  return 0;
161 }
162 
163 static int nftnl_expr_limit_json_parse(struct nftnl_expr *e, json_t *root,
164  struct nftnl_parse_err *err)
165 {
166 #ifdef JSON_PARSING
167  uint64_t uval64;
168  uint32_t uval32;
169 
170  if (nftnl_jansson_parse_val(root, "rate", NFTNL_TYPE_U64, &uval64, err) == 0)
171  nftnl_expr_set_u64(e, NFTNL_EXPR_LIMIT_RATE, uval64);
172 
173  if (nftnl_jansson_parse_val(root, "unit", NFTNL_TYPE_U64, &uval64, err) == 0)
174  nftnl_expr_set_u64(e, NFTNL_EXPR_LIMIT_UNIT, uval64);
175  if (nftnl_jansson_parse_val(root, "burst", NFTNL_TYPE_U32, &uval32, err) == 0)
176  nftnl_expr_set_u32(e, NFTNL_EXPR_LIMIT_BURST, uval32);
177  if (nftnl_jansson_parse_val(root, "type", NFTNL_TYPE_U32, &uval32, err) == 0)
178  nftnl_expr_set_u32(e, NFTNL_EXPR_LIMIT_TYPE, uval32);
179  if (nftnl_jansson_parse_val(root, "flags", NFTNL_TYPE_U32, &uval32, err) == 0)
180  nftnl_expr_set_u32(e, NFTNL_EXPR_LIMIT_FLAGS, uval32);
181 
182  return 0;
183 #else
184  errno = EOPNOTSUPP;
185  return -1;
186 #endif
187 }
188 
189 static int nftnl_expr_limit_xml_parse(struct nftnl_expr *e,
190  mxml_node_t *tree,
191  struct nftnl_parse_err *err)
192 {
193 #ifdef XML_PARSING
194  uint64_t rate, unit;
195  uint32_t burst, type, flags;
196 
197  if (nftnl_mxml_num_parse(tree, "rate", MXML_DESCEND_FIRST, BASE_DEC,
198  &rate, NFTNL_TYPE_U64, NFTNL_XML_MAND, err) == 0)
199  nftnl_expr_set_u64(e, NFTNL_EXPR_LIMIT_RATE, rate);
200 
201  if (nftnl_mxml_num_parse(tree, "unit", MXML_DESCEND_FIRST, BASE_DEC,
202  &unit, NFTNL_TYPE_U64, NFTNL_XML_MAND, err) == 0)
203  nftnl_expr_set_u64(e, NFTNL_EXPR_LIMIT_UNIT, unit);
204  if (nftnl_mxml_num_parse(tree, "burst", MXML_DESCEND_FIRST, BASE_DEC,
205  &burst, NFTNL_TYPE_U32, NFTNL_XML_MAND, err) == 0)
206  nftnl_expr_set_u32(e, NFTNL_EXPR_LIMIT_BURST, burst);
207  if (nftnl_mxml_num_parse(tree, "type", MXML_DESCEND_FIRST, BASE_DEC,
208  &type, NFTNL_TYPE_U32, NFTNL_XML_MAND, err) == 0)
209  nftnl_expr_set_u32(e, NFTNL_EXPR_LIMIT_TYPE, type);
210  if (nftnl_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
211  &flags, NFTNL_TYPE_U32, NFTNL_XML_MAND, err) == 0)
212  nftnl_expr_set_u32(e, NFTNL_EXPR_LIMIT_FLAGS, flags);
213 
214  return 0;
215 #else
216  errno = EOPNOTSUPP;
217  return -1;
218 #endif
219 }
220 
221 static const char *get_unit(uint64_t u)
222 {
223  switch (u) {
224  case 1: return "second";
225  case 60: return "minute";
226  case 60 * 60: return "hour";
227  case 60 * 60 * 24: return "day";
228  case 60 * 60 * 24 * 7: return "week";
229  }
230  return "error";
231 }
232 
233 static int nftnl_expr_limit_export(char *buf, size_t size,
234  const struct nftnl_expr *e, int type)
235 {
236  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
237  NFTNL_BUF_INIT(b, buf, size);
238 
239  if (e->flags & (1 << NFTNL_EXPR_LIMIT_RATE))
240  nftnl_buf_u64(&b, type, limit->rate, RATE);
241  if (e->flags & (1 << NFTNL_EXPR_LIMIT_UNIT))
242  nftnl_buf_u64(&b, type, limit->unit, UNIT);
243  if (e->flags & (1 << NFTNL_EXPR_LIMIT_BURST))
244  nftnl_buf_u32(&b, type, limit->burst, BURST);
245  if (e->flags & (1 << NFTNL_EXPR_LIMIT_TYPE))
246  nftnl_buf_u32(&b, type, limit->type, TYPE);
247  if (e->flags & (1 << NFTNL_EXPR_LIMIT_FLAGS))
248  nftnl_buf_u32(&b, type, limit->flags, FLAGS);
249 
250  return nftnl_buf_done(&b);
251 }
252 
253 static const char *limit_to_type(enum nft_limit_type type)
254 {
255  switch (type) {
256  default:
257  case NFT_LIMIT_PKTS:
258  return "packets";
259  case NFT_LIMIT_PKT_BYTES:
260  return "bytes";
261  }
262  return "unknown";
263 }
264 
265 static int nftnl_expr_limit_snprintf_default(char *buf, size_t len,
266  const struct nftnl_expr *e)
267 {
268  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
269 
270  return snprintf(buf, len, "rate %"PRIu64"/%s burst %u type %s flags 0x%x ",
271  limit->rate, get_unit(limit->unit), limit->burst,
272  limit_to_type(limit->type), limit->flags);
273 }
274 
275 static int
276 nftnl_expr_limit_snprintf(char *buf, size_t len, uint32_t type,
277  uint32_t flags, const struct nftnl_expr *e)
278 {
279  switch(type) {
280  case NFTNL_OUTPUT_DEFAULT:
281  return nftnl_expr_limit_snprintf_default(buf, len, e);
282  case NFTNL_OUTPUT_XML:
283  case NFTNL_OUTPUT_JSON:
284  return nftnl_expr_limit_export(buf, len, e, type);
285  default:
286  break;
287  }
288  return -1;
289 }
290 
291 struct expr_ops expr_ops_limit = {
292  .name = "limit",
293  .alloc_len = sizeof(struct nftnl_expr_limit),
294  .max_attr = NFTA_LIMIT_MAX,
295  .set = nftnl_expr_limit_set,
296  .get = nftnl_expr_limit_get,
297  .parse = nftnl_expr_limit_parse,
298  .build = nftnl_expr_limit_build,
299  .snprintf = nftnl_expr_limit_snprintf,
300  .xml_parse = nftnl_expr_limit_xml_parse,
301  .json_parse = nftnl_expr_limit_json_parse,
302 };