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>
28 #define IPPROTO_MH 135
32 enum nft_registers dreg;
33 enum nft_registers sreg;
42 nftnl_expr_exthdr_set(
struct nftnl_expr *e, uint16_t type,
43 const void *data, uint32_t data_len)
48 case NFTNL_EXPR_EXTHDR_DREG:
49 exthdr->dreg = *((uint32_t *)data);
51 case NFTNL_EXPR_EXTHDR_TYPE:
52 exthdr->type = *((uint8_t *)data);
54 case NFTNL_EXPR_EXTHDR_OFFSET:
55 exthdr->offset = *((uint32_t *)data);
57 case NFTNL_EXPR_EXTHDR_LEN:
58 exthdr->len = *((uint32_t *)data);
60 case NFTNL_EXPR_EXTHDR_OP:
61 exthdr->op = *((uint32_t *)data);
63 case NFTNL_EXPR_EXTHDR_FLAGS:
64 exthdr->flags = *((uint32_t *)data);
66 case NFTNL_EXPR_EXTHDR_SREG:
67 exthdr->sreg = *((uint32_t *)data);
76 nftnl_expr_exthdr_get(
const struct nftnl_expr *e, uint16_t type,
82 case NFTNL_EXPR_EXTHDR_DREG:
83 *data_len =
sizeof(exthdr->dreg);
85 case NFTNL_EXPR_EXTHDR_TYPE:
86 *data_len =
sizeof(exthdr->type);
88 case NFTNL_EXPR_EXTHDR_OFFSET:
89 *data_len =
sizeof(exthdr->offset);
90 return &exthdr->offset;
91 case NFTNL_EXPR_EXTHDR_LEN:
92 *data_len =
sizeof(exthdr->len);
94 case NFTNL_EXPR_EXTHDR_OP:
95 *data_len =
sizeof(exthdr->op);
97 case NFTNL_EXPR_EXTHDR_FLAGS:
98 *data_len =
sizeof(exthdr->flags);
99 return &exthdr->flags;
100 case NFTNL_EXPR_EXTHDR_SREG:
101 *data_len =
sizeof(exthdr->sreg);
102 return &exthdr->sreg;
107 static int nftnl_expr_exthdr_cb(
const struct nlattr *attr,
void *data)
109 const struct nlattr **tb = data;
110 int type = mnl_attr_get_type(attr);
112 if (mnl_attr_type_valid(attr, NFTA_EXTHDR_MAX) < 0)
116 case NFTA_EXTHDR_TYPE:
117 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
120 case NFTA_EXTHDR_DREG:
121 case NFTA_EXTHDR_SREG:
122 case NFTA_EXTHDR_OFFSET:
123 case NFTA_EXTHDR_LEN:
125 case NFTA_EXTHDR_FLAGS:
126 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
136 nftnl_expr_exthdr_build(
struct nlmsghdr *nlh,
const struct nftnl_expr *e)
140 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_DREG))
141 mnl_attr_put_u32(nlh, NFTA_EXTHDR_DREG, htonl(exthdr->dreg));
142 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_SREG))
143 mnl_attr_put_u32(nlh, NFTA_EXTHDR_SREG, htonl(exthdr->sreg));
144 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_TYPE))
145 mnl_attr_put_u8(nlh, NFTA_EXTHDR_TYPE, exthdr->type);
146 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_OFFSET))
147 mnl_attr_put_u32(nlh, NFTA_EXTHDR_OFFSET, htonl(exthdr->offset));
148 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_LEN))
149 mnl_attr_put_u32(nlh, NFTA_EXTHDR_LEN, htonl(exthdr->len));
150 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_OP))
151 mnl_attr_put_u32(nlh, NFTA_EXTHDR_OP, htonl(exthdr->op));
152 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_FLAGS))
153 mnl_attr_put_u32(nlh, NFTA_EXTHDR_FLAGS, htonl(exthdr->flags));
157 nftnl_expr_exthdr_parse(
struct nftnl_expr *e,
struct nlattr *attr)
160 struct nlattr *tb[NFTA_EXTHDR_MAX+1] = {};
162 if (mnl_attr_parse_nested(attr, nftnl_expr_exthdr_cb, tb) < 0)
165 if (tb[NFTA_EXTHDR_DREG]) {
166 exthdr->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_DREG]));
167 e->flags |= (1 << NFTNL_EXPR_EXTHDR_DREG);
169 if (tb[NFTA_EXTHDR_SREG]) {
170 exthdr->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_SREG]));
171 e->flags |= (1 << NFTNL_EXPR_EXTHDR_SREG);
173 if (tb[NFTA_EXTHDR_TYPE]) {
174 exthdr->type = mnl_attr_get_u8(tb[NFTA_EXTHDR_TYPE]);
175 e->flags |= (1 << NFTNL_EXPR_EXTHDR_TYPE);
177 if (tb[NFTA_EXTHDR_OFFSET]) {
178 exthdr->offset = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_OFFSET]));
179 e->flags |= (1 << NFTNL_EXPR_EXTHDR_OFFSET);
181 if (tb[NFTA_EXTHDR_LEN]) {
182 exthdr->len = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_LEN]));
183 e->flags |= (1 << NFTNL_EXPR_EXTHDR_LEN);
185 if (tb[NFTA_EXTHDR_OP]) {
186 exthdr->op = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_OP]));
187 e->flags |= (1 << NFTNL_EXPR_EXTHDR_OP);
189 if (tb[NFTA_EXTHDR_FLAGS]) {
190 exthdr->flags = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_FLAGS]));
191 e->flags |= (1 << NFTNL_EXPR_EXTHDR_FLAGS);
197 static const char *op2str(uint8_t op)
200 case NFT_EXTHDR_OP_TCPOPT:
202 case NFT_EXTHDR_OP_IPV6:
208 static const char *type2str(uint32_t type)
211 case IPPROTO_HOPOPTS:
213 case IPPROTO_ROUTING:
215 case IPPROTO_FRAGMENT:
217 case IPPROTO_DSTOPTS:
226 static inline int str2exthdr_op(
const char* str)
228 if (!strcmp(str,
"tcpopt"))
229 return NFT_EXTHDR_OP_TCPOPT;
232 return NFT_EXTHDR_OP_IPV6;
235 static inline int str2exthdr_type(
const char *str)
237 if (strcmp(str,
"hopopts") == 0)
238 return IPPROTO_HOPOPTS;
239 else if (strcmp(str,
"routing") == 0)
240 return IPPROTO_ROUTING;
241 else if (strcmp(str,
"fragment") == 0)
242 return IPPROTO_FRAGMENT;
243 else if (strcmp(str,
"dstopts") == 0)
244 return IPPROTO_DSTOPTS;
245 else if (strcmp(str,
"mh") == 0)
252 nftnl_expr_exthdr_json_parse(
struct nftnl_expr *e, json_t *root,
253 struct nftnl_parse_err *err)
256 const char *exthdr_type;
260 if (nftnl_jansson_parse_reg(root,
"dreg", NFTNL_TYPE_U32, &uval32,
262 nftnl_expr_set_u32(e, NFTNL_EXPR_EXTHDR_DREG, uval32);
264 if (nftnl_jansson_parse_reg(root,
"sreg", NFTNL_TYPE_U32, &uval32,
266 nftnl_expr_set_u32(e, NFTNL_EXPR_EXTHDR_SREG, uval32);
268 exthdr_type = nftnl_jansson_parse_str(root,
"exthdr_type", err);
269 if (exthdr_type != NULL) {
270 type = str2exthdr_type(exthdr_type);
273 nftnl_expr_set_u32(e, NFTNL_EXPR_EXTHDR_TYPE, type);
276 if (nftnl_jansson_parse_val(root,
"offset", NFTNL_TYPE_U32, &uval32,
278 nftnl_expr_set_u32(e, NFTNL_EXPR_EXTHDR_OFFSET, uval32);
280 if (nftnl_jansson_parse_val(root,
"len", NFTNL_TYPE_U32, &uval32, err) == 0)
281 nftnl_expr_set_u32(e, NFTNL_EXPR_EXTHDR_LEN, uval32);
283 if (nftnl_jansson_parse_val(root,
"op", NFTNL_TYPE_U32, &uval32, err) == 0)
284 nftnl_expr_set_u32(e, NFTNL_EXPR_EXTHDR_OP, uval32);
286 if (nftnl_jansson_parse_val(root,
"flags", NFTNL_TYPE_U32, &uval32, err) == 0)
287 nftnl_expr_set_u32(e, NFTNL_EXPR_EXTHDR_FLAGS, uval32);
296 static int nftnl_expr_exthdr_export(
char *buf,
size_t len,
297 const struct nftnl_expr *e,
int type)
300 NFTNL_BUF_INIT(b, buf, len);
302 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_DREG))
303 nftnl_buf_u32(&b, type, exthdr->dreg, DREG);
304 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_SREG))
305 nftnl_buf_u32(&b, type, exthdr->dreg, SREG);
306 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_TYPE))
307 nftnl_buf_str(&b, type, type2str(exthdr->type), EXTHDR_TYPE);
308 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_OFFSET))
309 nftnl_buf_u32(&b, type, exthdr->offset, OFFSET);
310 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_LEN))
311 nftnl_buf_u32(&b, type, exthdr->len, LEN);
312 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_OP))
313 nftnl_buf_u32(&b, type, exthdr->op, OP);
314 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_FLAGS))
315 nftnl_buf_u32(&b, type, exthdr->flags, FLAGS);
317 return nftnl_buf_done(&b);
320 static int nftnl_expr_exthdr_snprintf_default(
char *buf,
size_t len,
321 const struct nftnl_expr *e)
325 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_DREG))
326 return snprintf(buf, len,
"load%s %ub @ %u + %u%s => reg %u ",
327 op2str(exthdr->op), exthdr->len, exthdr->type,
329 exthdr->flags & NFT_EXTHDR_F_PRESENT ?
" present" :
"",
332 return snprintf(buf, len,
"write%s reg %u => %ub @ %u + %u ",
333 op2str(exthdr->op), exthdr->sreg, exthdr->len, exthdr->type,
339 nftnl_expr_exthdr_snprintf(
char *buf,
size_t len, uint32_t type,
340 uint32_t flags,
const struct nftnl_expr *e)
343 case NFTNL_OUTPUT_DEFAULT:
344 return nftnl_expr_exthdr_snprintf_default(buf, len, e);
345 case NFTNL_OUTPUT_XML:
346 case NFTNL_OUTPUT_JSON:
347 return nftnl_expr_exthdr_export(buf, len, e, type);
354 static bool nftnl_expr_exthdr_cmp(
const struct nftnl_expr *e1,
355 const struct nftnl_expr *e2)
361 if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_DREG))
362 eq &= (h1->dreg == h2->dreg);
363 if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_SREG))
364 eq &= (h1->sreg == h2->sreg);
365 if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_OFFSET))
366 eq &= (h1->offset == h2->offset);
367 if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_LEN))
368 eq &= (h1->len == h2->len);
369 if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_TYPE))
370 eq &= (h1->type == h2->type);
371 if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_OP))
372 eq &= (h1->op == h2->op);
373 if (e1->flags & (1 << NFTNL_EXPR_EXTHDR_FLAGS))
374 eq &= (h1->flags == h2->flags);
379 struct expr_ops expr_ops_exthdr = {
382 .max_attr = NFTA_EXTHDR_MAX,
383 .cmp = nftnl_expr_exthdr_cmp,
384 .set = nftnl_expr_exthdr_set,
385 .get = nftnl_expr_exthdr_get,
386 .parse = nftnl_expr_exthdr_parse,
387 .build = nftnl_expr_exthdr_build,
388 .snprintf = nftnl_expr_exthdr_snprintf,
389 .json_parse = nftnl_expr_exthdr_json_parse,