libnftnl  1.0.8
expr/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 const char *get_unit(uint64_t u)
190 {
191  switch (u) {
192  case 1: return "second";
193  case 60: return "minute";
194  case 60 * 60: return "hour";
195  case 60 * 60 * 24: return "day";
196  case 60 * 60 * 24 * 7: return "week";
197  }
198  return "error";
199 }
200 
201 static int nftnl_expr_limit_export(char *buf, size_t size,
202  const struct nftnl_expr *e, int type)
203 {
204  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
205  NFTNL_BUF_INIT(b, buf, size);
206 
207  if (e->flags & (1 << NFTNL_EXPR_LIMIT_RATE))
208  nftnl_buf_u64(&b, type, limit->rate, RATE);
209  if (e->flags & (1 << NFTNL_EXPR_LIMIT_UNIT))
210  nftnl_buf_u64(&b, type, limit->unit, UNIT);
211  if (e->flags & (1 << NFTNL_EXPR_LIMIT_BURST))
212  nftnl_buf_u32(&b, type, limit->burst, BURST);
213  if (e->flags & (1 << NFTNL_EXPR_LIMIT_TYPE))
214  nftnl_buf_u32(&b, type, limit->type, TYPE);
215  if (e->flags & (1 << NFTNL_EXPR_LIMIT_FLAGS))
216  nftnl_buf_u32(&b, type, limit->flags, FLAGS);
217 
218  return nftnl_buf_done(&b);
219 }
220 
221 static const char *limit_to_type(enum nft_limit_type type)
222 {
223  switch (type) {
224  default:
225  case NFT_LIMIT_PKTS:
226  return "packets";
227  case NFT_LIMIT_PKT_BYTES:
228  return "bytes";
229  }
230 }
231 
232 static int nftnl_expr_limit_snprintf_default(char *buf, size_t len,
233  const struct nftnl_expr *e)
234 {
235  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
236 
237  return snprintf(buf, len, "rate %"PRIu64"/%s burst %u type %s flags 0x%x ",
238  limit->rate, get_unit(limit->unit), limit->burst,
239  limit_to_type(limit->type), limit->flags);
240 }
241 
242 static int
243 nftnl_expr_limit_snprintf(char *buf, size_t len, uint32_t type,
244  uint32_t flags, const struct nftnl_expr *e)
245 {
246  switch(type) {
247  case NFTNL_OUTPUT_DEFAULT:
248  return nftnl_expr_limit_snprintf_default(buf, len, e);
249  case NFTNL_OUTPUT_XML:
250  case NFTNL_OUTPUT_JSON:
251  return nftnl_expr_limit_export(buf, len, e, type);
252  default:
253  break;
254  }
255  return -1;
256 }
257 
258 static bool nftnl_expr_limit_cmp(const struct nftnl_expr *e1,
259  const struct nftnl_expr *e2)
260 {
261  struct nftnl_expr_limit *l1 = nftnl_expr_data(e1);
262  struct nftnl_expr_limit *l2 = nftnl_expr_data(e2);
263  bool eq = true;
264 
265  if (e1->flags & (1 << NFTNL_EXPR_LIMIT_RATE))
266  eq &= (l1->rate == l2->rate);
267  if (e1->flags & (1 << NFTNL_EXPR_LIMIT_UNIT))
268  eq &= (l1->unit == l2->unit);
269  if (e1->flags & (1 << NFTNL_EXPR_LIMIT_BURST))
270  eq &= (l1->burst == l2->burst);
271  if (e1->flags & (1 << NFTNL_EXPR_LIMIT_TYPE))
272  eq &= (l1->type == l2->type);
273  if (e1->flags & (1 << NFTNL_EXPR_LIMIT_FLAGS))
274  eq &= (l1->flags == l2->flags);
275 
276  return eq;
277 }
278 
279 struct expr_ops expr_ops_limit = {
280  .name = "limit",
281  .alloc_len = sizeof(struct nftnl_expr_limit),
282  .max_attr = NFTA_LIMIT_MAX,
283  .set = nftnl_expr_limit_set,
284  .cmp = nftnl_expr_limit_cmp,
285  .get = nftnl_expr_limit_get,
286  .parse = nftnl_expr_limit_parse,
287  .build = nftnl_expr_limit_build,
288  .snprintf = nftnl_expr_limit_snprintf,
289  .json_parse = nftnl_expr_limit_json_parse,
290 };