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