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 #define IPPROTO_MH 135
34 enum nft_registers dreg;
41 nft_rule_expr_exthdr_set(
struct nft_rule_expr *e, uint16_t type,
42 const void *data, uint32_t data_len)
47 case NFT_EXPR_EXTHDR_DREG:
48 exthdr->dreg = *((uint32_t *)data);
50 case NFT_EXPR_EXTHDR_TYPE:
51 exthdr->type = *((uint8_t *)data);
53 case NFT_EXPR_EXTHDR_OFFSET:
54 exthdr->offset = *((uint32_t *)data);
56 case NFT_EXPR_EXTHDR_LEN:
57 exthdr->len = *((uint32_t *)data);
66 nft_rule_expr_exthdr_get(
const struct nft_rule_expr *e, uint16_t type,
72 case NFT_EXPR_EXTHDR_DREG:
73 *data_len =
sizeof(exthdr->dreg);
75 case NFT_EXPR_EXTHDR_TYPE:
76 *data_len =
sizeof(exthdr->type);
78 case NFT_EXPR_EXTHDR_OFFSET:
79 *data_len =
sizeof(exthdr->offset);
80 return &exthdr->offset;
81 case NFT_EXPR_EXTHDR_LEN:
82 *data_len =
sizeof(exthdr->len);
88 static int nft_rule_expr_exthdr_cb(
const struct nlattr *attr,
void *data)
90 const struct nlattr **tb = data;
91 int type = mnl_attr_get_type(attr);
93 if (mnl_attr_type_valid(attr, NFTA_EXTHDR_MAX) < 0)
97 case NFTA_EXTHDR_TYPE:
98 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
99 perror(
"mnl_attr_validate");
103 case NFTA_EXTHDR_DREG:
104 case NFTA_EXTHDR_OFFSET:
105 case NFTA_EXTHDR_LEN:
106 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
107 perror(
"mnl_attr_validate");
118 nft_rule_expr_exthdr_build(
struct nlmsghdr *nlh,
struct nft_rule_expr *e)
122 if (e->flags & (1 << NFT_EXPR_EXTHDR_DREG))
123 mnl_attr_put_u32(nlh, NFTA_EXTHDR_DREG, htonl(exthdr->dreg));
124 if (e->flags & (1 << NFT_EXPR_EXTHDR_TYPE))
125 mnl_attr_put_u8(nlh, NFTA_EXTHDR_TYPE, exthdr->type);
126 if (e->flags & (1 << NFT_EXPR_EXTHDR_OFFSET))
127 mnl_attr_put_u32(nlh, NFTA_EXTHDR_OFFSET, htonl(exthdr->offset));
128 if (e->flags & (1 << NFT_EXPR_EXTHDR_LEN))
129 mnl_attr_put_u32(nlh, NFTA_EXTHDR_LEN, htonl(exthdr->len));
133 nft_rule_expr_exthdr_parse(
struct nft_rule_expr *e,
struct nlattr *attr)
136 struct nlattr *tb[NFTA_EXTHDR_MAX+1] = {};
138 if (mnl_attr_parse_nested(attr, nft_rule_expr_exthdr_cb, tb) < 0)
141 if (tb[NFTA_EXTHDR_DREG]) {
142 exthdr->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_DREG]));
143 e->flags |= (1 << NFT_EXPR_EXTHDR_DREG);
145 if (tb[NFTA_EXTHDR_TYPE]) {
146 exthdr->type = mnl_attr_get_u8(tb[NFTA_EXTHDR_TYPE]);
147 e->flags |= (1 << NFT_EXPR_EXTHDR_TYPE);
149 if (tb[NFTA_EXTHDR_OFFSET]) {
150 exthdr->offset = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_OFFSET]));
151 e->flags |= (1 << NFT_EXPR_EXTHDR_OFFSET);
153 if (tb[NFTA_EXTHDR_LEN]) {
154 exthdr->len = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_LEN]));
155 e->flags |= (1 << NFT_EXPR_EXTHDR_LEN);
161 static const char *exthdr_type2str(uint32_t type)
164 case IPPROTO_HOPOPTS:
166 case IPPROTO_ROUTING:
168 case IPPROTO_FRAGMENT:
170 case IPPROTO_DSTOPTS:
179 static inline int str2exthdr_type(
const char *str)
181 if (strcmp(str,
"hopopts") == 0)
182 return IPPROTO_HOPOPTS;
183 else if (strcmp(str,
"routing") == 0)
184 return IPPROTO_ROUTING;
185 else if (strcmp(str,
"fragment") == 0)
186 return IPPROTO_FRAGMENT;
187 else if (strcmp(str,
"dstopts") == 0)
188 return IPPROTO_DSTOPTS;
189 else if (strcmp(str,
"mh") == 0)
196 nft_rule_expr_exthdr_json_parse(
struct nft_rule_expr *e, json_t *root,
197 struct nft_parse_err *err)
200 const char *exthdr_type;
204 if (nft_jansson_parse_reg(root,
"dreg", NFT_TYPE_U32, &uval32,
206 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_DREG, uval32);
208 exthdr_type = nft_jansson_parse_str(root,
"exthdr_type", err);
209 if (exthdr_type != NULL) {
210 type = str2exthdr_type(exthdr_type);
213 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_TYPE, type);
216 if (nft_jansson_parse_val(root,
"offset", NFT_TYPE_U32, &uval32,
218 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_OFFSET, uval32);
220 if (nft_jansson_parse_val(root,
"len", NFT_TYPE_U32, &uval32, err) == 0)
221 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_LEN, uval32);
231 nft_rule_expr_exthdr_xml_parse(
struct nft_rule_expr *e, mxml_node_t *tree,
232 struct nft_parse_err *err)
235 const char *exthdr_type;
237 uint32_t dreg, len, offset;
239 if (nft_mxml_reg_parse(tree,
"dreg", &dreg, MXML_DESCEND_FIRST,
240 NFT_XML_MAND, err) == 0)
241 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_DREG, dreg);
243 exthdr_type = nft_mxml_str_parse(tree,
"exthdr_type",
244 MXML_DESCEND_FIRST, NFT_XML_MAND, err);
245 if (exthdr_type != NULL) {
246 type = str2exthdr_type(exthdr_type);
249 nft_rule_expr_set_u8(e, NFT_EXPR_EXTHDR_TYPE, type);
253 if (nft_mxml_num_parse(tree,
"offset", MXML_DESCEND_FIRST, BASE_DEC,
254 &offset, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
255 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_OFFSET, offset);
258 if (nft_mxml_num_parse(tree,
"len", MXML_DESCEND_FIRST, BASE_DEC,
259 &len, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
260 nft_rule_expr_set_u32(e, NFT_EXPR_EXTHDR_LEN, len);
269 static int nft_rule_expr_exthdr_snprintf_json(
char *buf,
size_t len,
270 struct nft_rule_expr *e)
273 int ret, size = len, offset = 0;
275 if (e->flags & (1 << NFT_EXPR_EXTHDR_DREG)) {
276 ret = snprintf(buf, len,
"\"dreg\":%u,", exthdr->dreg);
277 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
279 if (e->flags & (1 << NFT_EXPR_EXTHDR_TYPE)) {
280 ret = snprintf(buf + offset, len,
"\"exthdr_type\":\"%s\",",
281 exthdr_type2str(exthdr->type));
282 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
284 if (e->flags & (1 << NFT_EXPR_EXTHDR_OFFSET)) {
285 ret = snprintf(buf + offset, len,
"\"offset\":%u,",
287 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
289 if (e->flags & (1 << NFT_EXPR_EXTHDR_LEN)) {
290 ret = snprintf(buf + offset, len,
"\"len\":%u,",
292 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
301 static int nft_rule_expr_exthdr_snprintf_xml(
char *buf,
size_t len,
302 struct nft_rule_expr *e)
305 int ret, size = len, offset = 0;
307 if (e->flags & (1 << NFT_EXPR_EXTHDR_DREG)) {
308 ret = snprintf(buf, len,
"<dreg>%u</dreg>", exthdr->dreg);
309 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
311 if (e->flags & (1 << NFT_EXPR_EXTHDR_TYPE)) {
312 ret = snprintf(buf + offset, len,
313 "<exthdr_type>%s</exthdr_type>",
314 exthdr_type2str(exthdr->type));
315 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
317 if (e->flags & (1 << NFT_EXPR_EXTHDR_OFFSET)) {
318 ret = snprintf(buf + offset, len,
"<offset>%u</offset>",
320 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
322 if (e->flags & (1 << NFT_EXPR_EXTHDR_LEN)) {
323 ret = snprintf(buf + offset, len,
"<len>%u</len>", exthdr->len);
324 SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
330 static int nft_rule_expr_exthdr_snprintf_default(
char *buf,
size_t len,
331 struct nft_rule_expr *e)
335 return snprintf(buf, len,
"load %ub @ %u + %u => reg %u ",
336 exthdr->len, exthdr->type, exthdr->offset,
341 nft_rule_expr_exthdr_snprintf(
char *buf,
size_t len, uint32_t type,
342 uint32_t flags,
struct nft_rule_expr *e)
345 case NFT_OUTPUT_DEFAULT:
346 return nft_rule_expr_exthdr_snprintf_default(buf, len, e);
348 return nft_rule_expr_exthdr_snprintf_xml(buf, len, e);
349 case NFT_OUTPUT_JSON:
350 return nft_rule_expr_exthdr_snprintf_json(buf, len, e);
357 struct expr_ops expr_ops_exthdr = {
360 .max_attr = NFTA_EXTHDR_MAX,
361 .set = nft_rule_expr_exthdr_set,
362 .get = nft_rule_expr_exthdr_get,
363 .parse = nft_rule_expr_exthdr_parse,
364 .build = nft_rule_expr_exthdr_build,
365 .snprintf = nft_rule_expr_exthdr_snprintf,
366 .xml_parse = nft_rule_expr_exthdr_xml_parse,
367 .json_parse = nft_rule_expr_exthdr_json_parse,
370 static void __init expr_exthdr_init(
void)
372 nft_expr_ops_register(&expr_ops_exthdr);