libnftnl 1.2.9
range.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * (C) 2016 by Pablo Neira Ayuso <pablo@netfilter.org>
4 */
5
6#include "internal.h"
7
8#include <stdio.h>
9#include <stdint.h>
10#include <string.h>
11#include <arpa/inet.h>
12#include <errno.h>
13
14#include <libmnl/libmnl.h>
15#include <linux/netfilter/nf_tables.h>
16#include <libnftnl/expr.h>
17#include <libnftnl/rule.h>
18
20 union nftnl_data_reg data_from;
21 union nftnl_data_reg data_to;
22 enum nft_registers sreg;
23 enum nft_range_ops op;
24};
25
26static int nftnl_expr_range_set(struct nftnl_expr *e, uint16_t type,
27 const void *data, uint32_t data_len)
28{
29 struct nftnl_expr_range *range = nftnl_expr_data(e);
30
31 switch(type) {
32 case NFTNL_EXPR_RANGE_SREG:
33 memcpy(&range->sreg, data, data_len);
34 break;
35 case NFTNL_EXPR_RANGE_OP:
36 memcpy(&range->op, data, data_len);
37 break;
38 case NFTNL_EXPR_RANGE_FROM_DATA:
39 return nftnl_data_cpy(&range->data_from, data, data_len);
40 case NFTNL_EXPR_RANGE_TO_DATA:
41 return nftnl_data_cpy(&range->data_to, data, data_len);
42 }
43 return 0;
44}
45
46static const void *nftnl_expr_range_get(const struct nftnl_expr *e,
47 uint16_t type, uint32_t *data_len)
48{
49 struct nftnl_expr_range *range = nftnl_expr_data(e);
50
51 switch(type) {
52 case NFTNL_EXPR_RANGE_SREG:
53 *data_len = sizeof(range->sreg);
54 return &range->sreg;
55 case NFTNL_EXPR_RANGE_OP:
56 *data_len = sizeof(range->op);
57 return &range->op;
58 case NFTNL_EXPR_RANGE_FROM_DATA:
59 *data_len = range->data_from.len;
60 return &range->data_from.val;
61 case NFTNL_EXPR_RANGE_TO_DATA:
62 *data_len = range->data_to.len;
63 return &range->data_to.val;
64 }
65 return NULL;
66}
67
68static int nftnl_expr_range_cb(const struct nlattr *attr, void *data)
69{
70 const struct nlattr **tb = data;
71 int type = mnl_attr_get_type(attr);
72
73 if (mnl_attr_type_valid(attr, NFTA_RANGE_MAX) < 0)
74 return MNL_CB_OK;
75
76 switch(type) {
77 case NFTA_RANGE_SREG:
78 case NFTA_RANGE_OP:
79 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
80 abi_breakage();
81 break;
82 case NFTA_RANGE_FROM_DATA:
83 case NFTA_RANGE_TO_DATA:
84 if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
85 abi_breakage();
86 break;
87 }
88
89 tb[type] = attr;
90 return MNL_CB_OK;
91}
92
93static void
94nftnl_expr_range_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
95{
96 struct nftnl_expr_range *range = nftnl_expr_data(e);
97
98 if (e->flags & (1 << NFTNL_EXPR_RANGE_SREG))
99 mnl_attr_put_u32(nlh, NFTA_RANGE_SREG, htonl(range->sreg));
100 if (e->flags & (1 << NFTNL_EXPR_RANGE_OP))
101 mnl_attr_put_u32(nlh, NFTA_RANGE_OP, htonl(range->op));
102 if (e->flags & (1 << NFTNL_EXPR_RANGE_FROM_DATA)) {
103 struct nlattr *nest;
104
105 nest = mnl_attr_nest_start(nlh, NFTA_RANGE_FROM_DATA);
106 mnl_attr_put(nlh, NFTA_DATA_VALUE, range->data_from.len,
107 range->data_from.val);
108 mnl_attr_nest_end(nlh, nest);
109 }
110 if (e->flags & (1 << NFTNL_EXPR_RANGE_TO_DATA)) {
111 struct nlattr *nest;
112
113 nest = mnl_attr_nest_start(nlh, NFTA_RANGE_TO_DATA);
114 mnl_attr_put(nlh, NFTA_DATA_VALUE, range->data_to.len,
115 range->data_to.val);
116 mnl_attr_nest_end(nlh, nest);
117 }
118}
119
120static int
121nftnl_expr_range_parse(struct nftnl_expr *e, struct nlattr *attr)
122{
123 struct nftnl_expr_range *range = nftnl_expr_data(e);
124 struct nlattr *tb[NFTA_RANGE_MAX+1] = {};
125 int ret = 0;
126
127 if (mnl_attr_parse_nested(attr, nftnl_expr_range_cb, tb) < 0)
128 return -1;
129
130 if (tb[NFTA_RANGE_SREG]) {
131 range->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_RANGE_SREG]));
132 e->flags |= (1 << NFTA_RANGE_SREG);
133 }
134 if (tb[NFTA_RANGE_OP]) {
135 range->op = ntohl(mnl_attr_get_u32(tb[NFTA_RANGE_OP]));
136 e->flags |= (1 << NFTA_RANGE_OP);
137 }
138 if (tb[NFTA_RANGE_FROM_DATA]) {
139 ret = nftnl_parse_data(&range->data_from,
140 tb[NFTA_RANGE_FROM_DATA], NULL);
141 e->flags |= (1 << NFTA_RANGE_FROM_DATA);
142 }
143 if (tb[NFTA_RANGE_TO_DATA]) {
144 ret = nftnl_parse_data(&range->data_to,
145 tb[NFTA_RANGE_TO_DATA], NULL);
146 e->flags |= (1 << NFTA_RANGE_TO_DATA);
147 }
148
149 return ret;
150}
151
152static const char *expr_range_str[] = {
153 [NFT_RANGE_EQ] = "eq",
154 [NFT_RANGE_NEQ] = "neq",
155};
156
157static const char *range2str(uint32_t op)
158{
159 if (op > NFT_RANGE_NEQ)
160 return "unknown";
161
162 return expr_range_str[op];
163}
164
165static int nftnl_expr_range_snprintf(char *buf, size_t remain,
166 uint32_t flags, const struct nftnl_expr *e)
167{
168 struct nftnl_expr_range *range = nftnl_expr_data(e);
169 int offset = 0, ret;
170
171 ret = snprintf(buf, remain, "%s reg %u ",
172 range2str(range->op), range->sreg);
173 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
174
175 ret = nftnl_data_reg_snprintf(buf + offset, remain, &range->data_from,
176 0, DATA_VALUE);
177 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
178
179 ret = nftnl_data_reg_snprintf(buf + offset, remain, &range->data_to,
180 0, DATA_VALUE);
181 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
182
183 return offset;
184}
185
186static struct attr_policy range_attr_policy[__NFTNL_EXPR_RANGE_MAX] = {
187 [NFTNL_EXPR_RANGE_SREG] = { .maxlen = sizeof(uint32_t) },
188 [NFTNL_EXPR_RANGE_OP] = { .maxlen = sizeof(uint32_t) },
189 [NFTNL_EXPR_RANGE_FROM_DATA] = { .maxlen = NFT_DATA_VALUE_MAXLEN },
190 [NFTNL_EXPR_RANGE_TO_DATA] = { .maxlen = NFT_DATA_VALUE_MAXLEN },
191};
192
193struct expr_ops expr_ops_range = {
194 .name = "range",
195 .alloc_len = sizeof(struct nftnl_expr_range),
196 .nftnl_max_attr = __NFTNL_EXPR_RANGE_MAX - 1,
197 .attr_policy = range_attr_policy,
198 .set = nftnl_expr_range_set,
199 .get = nftnl_expr_range_get,
200 .parse = nftnl_expr_range_parse,
201 .build = nftnl_expr_range_build,
202 .output = nftnl_expr_range_snprintf,
203};