libnftnl 1.2.6
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, 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
61static const void *
62nftnl_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
87static 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
113static void
114nftnl_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
130static int
131nftnl_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
163static 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
175static 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
186static int
187nftnl_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
197struct 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 .output = nftnl_expr_limit_snprintf,
206};