18 #include <arpa/inet.h>
20 #include <libmnl/libmnl.h>
22 #include <linux/netfilter/nf_tables.h>
24 #include <libnftnl/expr.h>
25 #include <libnftnl/rule.h>
30 enum nft_registers dreg;
31 enum nft_payload_bases base;
37 nft_rule_expr_payload_set(
struct nft_rule_expr *e, uint16_t type,
38 const void *data, uint32_t data_len)
43 case NFT_EXPR_PAYLOAD_DREG:
44 payload->dreg = *((uint32_t *)data);
46 case NFT_EXPR_PAYLOAD_BASE:
47 payload->base = *((uint32_t *)data);
49 case NFT_EXPR_PAYLOAD_OFFSET:
50 payload->offset = *((
unsigned int *)data);
52 case NFT_EXPR_PAYLOAD_LEN:
53 payload->len = *((
unsigned int *)data);
62 nft_rule_expr_payload_get(
const struct nft_rule_expr *e, uint16_t type,
68 case NFT_EXPR_PAYLOAD_DREG:
69 *data_len =
sizeof(payload->dreg);
70 return &payload->dreg;
71 case NFT_EXPR_PAYLOAD_BASE:
72 *data_len =
sizeof(payload->base);
73 return &payload->base;
74 case NFT_EXPR_PAYLOAD_OFFSET:
75 *data_len =
sizeof(payload->offset);
76 return &payload->offset;
77 case NFT_EXPR_PAYLOAD_LEN:
78 *data_len =
sizeof(payload->len);
84 static int nft_rule_expr_payload_cb(
const struct nlattr *attr,
void *data)
86 const struct nlattr **tb = data;
87 int type = mnl_attr_get_type(attr);
89 if (mnl_attr_type_valid(attr, NFTA_PAYLOAD_MAX) < 0)
93 case NFTA_PAYLOAD_DREG:
94 case NFTA_PAYLOAD_BASE:
95 case NFTA_PAYLOAD_OFFSET:
96 case NFTA_PAYLOAD_LEN:
97 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
98 perror(
"mnl_attr_validate");
109 nft_rule_expr_payload_build(
struct nlmsghdr *nlh,
struct nft_rule_expr *e)
113 if (e->flags & (1 << NFT_EXPR_PAYLOAD_DREG))
114 mnl_attr_put_u32(nlh, NFTA_PAYLOAD_DREG, htonl(payload->dreg));
115 if (e->flags & (1 << NFT_EXPR_PAYLOAD_BASE))
116 mnl_attr_put_u32(nlh, NFTA_PAYLOAD_BASE, htonl(payload->base));
117 if (e->flags & (1 << NFT_EXPR_PAYLOAD_OFFSET))
118 mnl_attr_put_u32(nlh, NFTA_PAYLOAD_OFFSET, htonl(payload->offset));
119 if (e->flags & (1 << NFT_EXPR_PAYLOAD_LEN))
120 mnl_attr_put_u32(nlh, NFTA_PAYLOAD_LEN, htonl(payload->len));
124 nft_rule_expr_payload_parse(
struct nft_rule_expr *e,
struct nlattr *attr)
127 struct nlattr *tb[NFTA_PAYLOAD_MAX+1] = {};
129 if (mnl_attr_parse_nested(attr, nft_rule_expr_payload_cb, tb) < 0)
132 if (tb[NFTA_PAYLOAD_DREG]) {
133 payload->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_PAYLOAD_DREG]));
134 e->flags |= (1 << NFT_EXPR_PAYLOAD_DREG);
136 if (tb[NFTA_PAYLOAD_BASE]) {
137 payload->base = ntohl(mnl_attr_get_u32(tb[NFTA_PAYLOAD_BASE]));
138 e->flags |= (1 << NFT_EXPR_PAYLOAD_BASE);
140 if (tb[NFTA_PAYLOAD_OFFSET]) {
141 payload->offset = ntohl(mnl_attr_get_u32(tb[NFTA_PAYLOAD_OFFSET]));
142 e->flags |= (1 << NFT_EXPR_PAYLOAD_OFFSET);
144 if (tb[NFTA_PAYLOAD_LEN]) {
145 payload->len = ntohl(mnl_attr_get_u32(tb[NFTA_PAYLOAD_LEN]));
146 e->flags |= (1 << NFT_EXPR_PAYLOAD_LEN);
152 static char *base2str_array[NFT_PAYLOAD_TRANSPORT_HEADER+1] = {
153 [NFT_PAYLOAD_LL_HEADER] =
"link",
154 [NFT_PAYLOAD_NETWORK_HEADER] =
"network",
155 [NFT_PAYLOAD_TRANSPORT_HEADER] =
"transport",
158 static const char *base2str(
enum nft_payload_bases base)
160 if (base > NFT_PAYLOAD_TRANSPORT_HEADER)
163 return base2str_array[base];
167 nft_rule_expr_payload_snprintf_json(
char *buf,
size_t len, uint32_t flags,
168 struct nft_rule_expr *e)
171 int size = len, offset = 0, ret;
173 if (e->flags & (1 << NFT_EXPR_PAYLOAD_DREG)) {
174 ret = snprintf(buf, len,
"\"dreg\":%u,", payload->dreg);
175 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
177 if (e->flags & (1 << NFT_EXPR_PAYLOAD_OFFSET)) {
178 ret = snprintf(buf + offset, len,
"\"offset\":%u,",
180 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
182 if (e->flags & (1 << NFT_EXPR_PAYLOAD_LEN)) {
183 ret = snprintf(buf + offset, len,
"\"len\":%u,", payload->len);
184 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
186 if (e->flags & (1 << NFT_EXPR_PAYLOAD_BASE)) {
187 ret = snprintf(buf + offset, len,
"\"base\":\"%s\"",
188 base2str(payload->base));
189 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
194 static inline int nft_str2base(
const char *base)
196 if (strcmp(base,
"link") == 0)
197 return NFT_PAYLOAD_LL_HEADER;
198 else if (strcmp(base,
"network") == 0)
199 return NFT_PAYLOAD_NETWORK_HEADER;
200 else if (strcmp(base,
"transport") == 0)
201 return NFT_PAYLOAD_TRANSPORT_HEADER;
209 nft_rule_expr_payload_json_parse(
struct nft_rule_expr *e, json_t *root,
210 struct nft_parse_err *err)
213 const char *base_str;
214 uint32_t reg, uval32;
217 if (nft_jansson_parse_reg(root,
"dreg", NFT_TYPE_U32, ®, err) == 0)
218 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_DREG, reg);
220 base_str = nft_jansson_parse_str(root,
"base", err);
221 if (base_str != NULL) {
222 base = nft_str2base(base_str);
226 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_BASE, base);
229 if (nft_jansson_parse_val(root,
"offset", NFT_TYPE_U32, &uval32,
231 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_OFFSET, uval32);
233 if (nft_jansson_parse_val(root,
"len", NFT_TYPE_U32, &uval32, err) == 0)
234 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_LEN, uval32);
244 nft_rule_expr_payload_xml_parse(
struct nft_rule_expr *e, mxml_node_t *tree,
245 struct nft_parse_err *err)
248 const char *base_str;
250 uint32_t dreg, offset, len;
252 if (nft_mxml_reg_parse(tree,
"dreg", &dreg, MXML_DESCEND_FIRST,
253 NFT_XML_MAND, err) == 0)
254 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_DREG, dreg);
256 base_str = nft_mxml_str_parse(tree,
"base", MXML_DESCEND_FIRST,
258 if (base_str != NULL) {
259 base = nft_str2base(base_str);
263 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_BASE, base);
266 if (nft_mxml_num_parse(tree,
"offset", MXML_DESCEND_FIRST, BASE_DEC,
267 &offset, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
268 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_OFFSET, offset);
271 if (nft_mxml_num_parse(tree,
"len", MXML_DESCEND_FIRST, BASE_DEC,
272 &len, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
273 nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_LEN, len);
283 nft_rule_expr_payload_snprintf_xml(
char *buf,
size_t len, uint32_t flags,
284 struct nft_rule_expr *e)
287 int size = len, offset = 0, ret;
289 if (e->flags & (1 << NFT_EXPR_PAYLOAD_DREG)) {
290 ret = snprintf(buf, len,
"<dreg>%u</dreg>", payload->dreg);
291 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
293 if (e->flags & (1 << NFT_EXPR_PAYLOAD_OFFSET)) {
294 ret = snprintf(buf + offset, len,
"<offset>%u</offset>",
296 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
298 if (e->flags & (1 << NFT_EXPR_PAYLOAD_LEN)) {
299 ret = snprintf(buf + offset, len,
"<len>%u</len>", payload->len);
300 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
302 if (e->flags & (1 << NFT_EXPR_PAYLOAD_BASE)) {
303 ret = snprintf(buf + offset, len,
"<base>%s</base>",
304 base2str(payload->base));
305 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
312 nft_rule_expr_payload_snprintf(
char *buf,
size_t len, uint32_t type,
313 uint32_t flags,
struct nft_rule_expr *e)
318 case NFT_OUTPUT_DEFAULT:
319 return snprintf(buf, len,
"load %ub @ %s header + %u => reg %u ",
320 payload->len, base2str(payload->base),
321 payload->offset, payload->dreg);
323 return nft_rule_expr_payload_snprintf_xml(buf, len, flags, e);
324 case NFT_OUTPUT_JSON:
325 return nft_rule_expr_payload_snprintf_json(buf, len, flags, e);
332 struct expr_ops expr_ops_payload = {
335 .max_attr = NFTA_PAYLOAD_MAX,
336 .set = nft_rule_expr_payload_set,
337 .get = nft_rule_expr_payload_get,
338 .parse = nft_rule_expr_payload_parse,
339 .build = nft_rule_expr_payload_build,
340 .snprintf = nft_rule_expr_payload_snprintf,
341 .xml_parse = nft_rule_expr_payload_xml_parse,
342 .json_parse = nft_rule_expr_payload_json_parse,
345 static void __init expr_payload_init(
void)
347 nft_expr_ops_register(&expr_ops_payload);