libnftnl  1.2.1
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  memcpy(&limit->rate, data, sizeof(limit->rate));
42  break;
43  case NFTNL_EXPR_LIMIT_UNIT:
44  memcpy(&limit->unit, data, sizeof(limit->unit));
45  break;
46  case NFTNL_EXPR_LIMIT_BURST:
47  memcpy(&limit->burst, data, sizeof(limit->burst));
48  break;
49  case NFTNL_EXPR_LIMIT_TYPE:
50  memcpy(&limit->type, data, sizeof(limit->type));
51  break;
52  case NFTNL_EXPR_LIMIT_FLAGS:
53  memcpy(&limit->flags, data, sizeof(limit->flags));
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 const char *get_unit(uint64_t u)
164 {
165  switch (u) {
166  case 1: return "second";
167  case 60: return "minute";
168  case 60 * 60: return "hour";
169  case 60 * 60 * 24: return "day";
170  case 60 * 60 * 24 * 7: return "week";
171  }
172  return "error";
173 }
174 
175 static const char *limit_to_type(enum nft_limit_type type)
176 {
177  switch (type) {
178  default:
179  case NFT_LIMIT_PKTS:
180  return "packets";
181  case NFT_LIMIT_PKT_BYTES:
182  return "bytes";
183  }
184 }
185 
186 static int
187 nftnl_expr_limit_snprintf(char *buf, size_t len,
188  uint32_t flags, const struct nftnl_expr *e)
189 {
190  struct nftnl_expr_limit *limit = nftnl_expr_data(e);
191 
192  return snprintf(buf, len, "rate %"PRIu64"/%s burst %u type %s flags 0x%x ",
193  limit->rate, get_unit(limit->unit), limit->burst,
194  limit_to_type(limit->type), limit->flags);
195 }
196 
197 struct expr_ops expr_ops_limit = {
198  .name = "limit",
199  .alloc_len = sizeof(struct nftnl_expr_limit),
200  .max_attr = NFTA_LIMIT_MAX,
201  .set = nftnl_expr_limit_set,
202  .get = nftnl_expr_limit_get,
203  .parse = nftnl_expr_limit_parse,
204  .build = nftnl_expr_limit_build,
205  .snprintf = nftnl_expr_limit_snprintf,
206 };