libnftnl  1.2.9
expr/limit.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 <inttypes.h>
11 #include <string.h>
12 #include <arpa/inet.h>
13 #include <errno.h>
14 #include <linux/netfilter/nf_tables.h>
15 
16 #include "internal.h"
17 #include <libmnl/libmnl.h>
18 #include <libnftnl/expr.h>
19 #include <libnftnl/rule.h>
20 
22  uint64_t rate;
23  uint64_t unit;
24  uint32_t burst;
25  enum nft_limit_type type;
26  uint32_t flags;
27 };
28 
29 static int
30 nftnl_expr_limit_set(struct nftnl_expr *e, uint16_t type,
31  const void *data, uint32_t data_len)
32 {
33  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
34 
35  switch(type) {
36  case NFTNL_EXPR_LIMIT_RATE:
37  memcpy(&limit->rate, data, data_len);
38  break;
39  case NFTNL_EXPR_LIMIT_UNIT:
40  memcpy(&limit->unit, data, data_len);
41  break;
42  case NFTNL_EXPR_LIMIT_BURST:
43  memcpy(&limit->burst, data, data_len);
44  break;
45  case NFTNL_EXPR_LIMIT_TYPE:
46  memcpy(&limit->type, data, data_len);
47  break;
48  case NFTNL_EXPR_LIMIT_FLAGS:
49  memcpy(&limit->flags, data, data_len);
50  break;
51  }
52  return 0;
53 }
54 
55 static const void *
56 nftnl_expr_limit_get(const struct nftnl_expr *e, uint16_t type,
57  uint32_t *data_len)
58 {
59  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
60 
61  switch(type) {
62  case NFTNL_EXPR_LIMIT_RATE:
63  *data_len = sizeof(uint64_t);
64  return &limit->rate;
65  case NFTNL_EXPR_LIMIT_UNIT:
66  *data_len = sizeof(uint64_t);
67  return &limit->unit;
68  case NFTNL_EXPR_LIMIT_BURST:
69  *data_len = sizeof(uint32_t);
70  return &limit->burst;
71  case NFTNL_EXPR_LIMIT_TYPE:
72  *data_len = sizeof(uint32_t);
73  return &limit->type;
74  case NFTNL_EXPR_LIMIT_FLAGS:
75  *data_len = sizeof(uint32_t);
76  return &limit->flags;
77  }
78  return NULL;
79 }
80 
81 static int nftnl_expr_limit_cb(const struct nlattr *attr, void *data)
82 {
83  const struct nlattr **tb = data;
84  int type = mnl_attr_get_type(attr);
85 
86  if (mnl_attr_type_valid(attr, NFTA_LIMIT_MAX) < 0)
87  return MNL_CB_OK;
88 
89  switch(type) {
90  case NFTA_LIMIT_RATE:
91  case NFTA_LIMIT_UNIT:
92  if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
93  abi_breakage();
94  break;
95  case NFTA_LIMIT_BURST:
96  case NFTA_LIMIT_TYPE:
97  case NFTA_LIMIT_FLAGS:
98  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
99  abi_breakage();
100  break;
101  }
102 
103  tb[type] = attr;
104  return MNL_CB_OK;
105 }
106 
107 static void
108 nftnl_expr_limit_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
109 {
110  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
111 
112  if (e->flags & (1 << NFTNL_EXPR_LIMIT_RATE))
113  mnl_attr_put_u64(nlh, NFTA_LIMIT_RATE, htobe64(limit->rate));
114  if (e->flags & (1 << NFTNL_EXPR_LIMIT_UNIT))
115  mnl_attr_put_u64(nlh, NFTA_LIMIT_UNIT, htobe64(limit->unit));
116  if (e->flags & (1 << NFTNL_EXPR_LIMIT_BURST))
117  mnl_attr_put_u32(nlh, NFTA_LIMIT_BURST, htonl(limit->burst));
118  if (e->flags & (1 << NFTNL_EXPR_LIMIT_TYPE))
119  mnl_attr_put_u32(nlh, NFTA_LIMIT_TYPE, htonl(limit->type));
120  if (e->flags & (1 << NFTNL_EXPR_LIMIT_FLAGS))
121  mnl_attr_put_u32(nlh, NFTA_LIMIT_FLAGS, htonl(limit->flags));
122 }
123 
124 static int
125 nftnl_expr_limit_parse(struct nftnl_expr *e, struct nlattr *attr)
126 {
127  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
128  struct nlattr *tb[NFTA_LIMIT_MAX+1] = {};
129 
130  if (mnl_attr_parse_nested(attr, nftnl_expr_limit_cb, tb) < 0)
131  return -1;
132 
133  if (tb[NFTA_LIMIT_RATE]) {
134  limit->rate = be64toh(mnl_attr_get_u64(tb[NFTA_LIMIT_RATE]));
135  e->flags |= (1 << NFTNL_EXPR_LIMIT_RATE);
136  }
137  if (tb[NFTA_LIMIT_UNIT]) {
138  limit->unit = be64toh(mnl_attr_get_u64(tb[NFTA_LIMIT_UNIT]));
139  e->flags |= (1 << NFTNL_EXPR_LIMIT_UNIT);
140  }
141  if (tb[NFTA_LIMIT_BURST]) {
142  limit->burst = ntohl(mnl_attr_get_u32(tb[NFTA_LIMIT_BURST]));
143  e->flags |= (1 << NFTNL_EXPR_LIMIT_BURST);
144  }
145  if (tb[NFTA_LIMIT_TYPE]) {
146  limit->type = ntohl(mnl_attr_get_u32(tb[NFTA_LIMIT_TYPE]));
147  e->flags |= (1 << NFTNL_EXPR_LIMIT_TYPE);
148  }
149  if (tb[NFTA_LIMIT_FLAGS]) {
150  limit->flags = ntohl(mnl_attr_get_u32(tb[NFTA_LIMIT_FLAGS]));
151  e->flags |= (1 << NFTNL_EXPR_LIMIT_FLAGS);
152  }
153 
154  return 0;
155 }
156 
157 static const char *get_time(uint64_t seconds, uint64_t *val)
158 {
159  static const struct {
160  unsigned int size;
161  const char *name;
162  } units[] = {
163  { 0, "second" },
164  { 60, "minute" },
165  { 60, "hour" },
166  { 24, "day" },
167  { 7, "week" }
168  };
169  int i;
170 
171  for (i = 1; i < array_size(units); i++) {
172  if (seconds % units[i].size)
173  break;
174  seconds /= units[i].size;
175  }
176  if (val)
177  *val = seconds;
178  return units[i - 1].name;
179 }
180 
181 static const char *limit_to_type(enum nft_limit_type type)
182 {
183  switch (type) {
184  default:
185  case NFT_LIMIT_PKTS:
186  return "packets";
187  case NFT_LIMIT_PKT_BYTES:
188  return "bytes";
189  }
190 }
191 
192 static int
193 nftnl_expr_limit_snprintf(char *buf, size_t len,
194  uint32_t flags, const struct nftnl_expr *e)
195 {
196  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
197  unsigned int offset = 0;
198  const char *time_unit;
199  uint64_t time_val;
200  int ret;
201 
202  ret = snprintf(buf, len, "rate %"PRIu64"/", limit->rate);
203  SNPRINTF_BUFFER_SIZE(ret, len, offset);
204 
205  time_unit = get_time(limit->unit, &time_val);
206  if (time_val > 1) {
207  ret = snprintf(buf + offset, len, "%"PRIu64" ", time_val);
208  SNPRINTF_BUFFER_SIZE(ret, len, offset);
209  }
210 
211  ret = snprintf(buf + offset, len, "%s burst %u type %s flags 0x%x ",
212  time_unit, limit->burst, limit_to_type(limit->type),
213  limit->flags);
214  SNPRINTF_BUFFER_SIZE(ret, len, offset);
215 
216  return offset;
217 }
218 
219 static struct attr_policy limit_attr_policy[__NFTNL_EXPR_LIMIT_MAX] = {
220  [NFTNL_EXPR_LIMIT_RATE] = { .maxlen = sizeof(uint64_t) },
221  [NFTNL_EXPR_LIMIT_UNIT] = { .maxlen = sizeof(uint64_t) },
222  [NFTNL_EXPR_LIMIT_BURST] = { .maxlen = sizeof(uint32_t) },
223  [NFTNL_EXPR_LIMIT_TYPE] = { .maxlen = sizeof(uint32_t) },
224  [NFTNL_EXPR_LIMIT_FLAGS] = { .maxlen = sizeof(uint32_t) },
225 };
226 
227 struct expr_ops expr_ops_limit = {
228  .name = "limit",
229  .alloc_len = sizeof(struct nftnl_expr_limit),
230  .nftnl_max_attr = __NFTNL_EXPR_LIMIT_MAX - 1,
231  .attr_policy = limit_attr_policy,
232  .set = nftnl_expr_limit_set,
233  .get = nftnl_expr_limit_get,
234  .parse = nftnl_expr_limit_parse,
235  .build = nftnl_expr_limit_build,
236  .output = nftnl_expr_limit_snprintf,
237 };