14 #include <arpa/inet.h>
16 #include <libmnl/libmnl.h>
18 #include <linux/netfilter/nf_tables.h>
20 #include <libnftnl/expr.h>
21 #include <libnftnl/rule.h>
24 #define IPPROTO_MH 135
28 enum nft_registers dreg;
29 enum nft_registers sreg;
38 nftnl_expr_exthdr_set(
struct nftnl_expr *e, uint16_t type,
39 const void *data, uint32_t data_len)
44 case NFTNL_EXPR_EXTHDR_DREG:
45 memcpy(&exthdr->dreg, data, data_len);
47 case NFTNL_EXPR_EXTHDR_TYPE:
48 memcpy(&exthdr->type, data, data_len);
50 case NFTNL_EXPR_EXTHDR_OFFSET:
51 memcpy(&exthdr->offset, data, data_len);
53 case NFTNL_EXPR_EXTHDR_LEN:
54 memcpy(&exthdr->len, data, data_len);
56 case NFTNL_EXPR_EXTHDR_OP:
57 memcpy(&exthdr->op, data, data_len);
59 case NFTNL_EXPR_EXTHDR_FLAGS:
60 memcpy(&exthdr->flags, data, data_len);
62 case NFTNL_EXPR_EXTHDR_SREG:
63 memcpy(&exthdr->sreg, data, data_len);
70 nftnl_expr_exthdr_get(
const struct nftnl_expr *e, uint16_t type,
76 case NFTNL_EXPR_EXTHDR_DREG:
77 *data_len =
sizeof(exthdr->dreg);
79 case NFTNL_EXPR_EXTHDR_TYPE:
80 *data_len =
sizeof(exthdr->type);
82 case NFTNL_EXPR_EXTHDR_OFFSET:
83 *data_len =
sizeof(exthdr->offset);
84 return &exthdr->offset;
85 case NFTNL_EXPR_EXTHDR_LEN:
86 *data_len =
sizeof(exthdr->len);
88 case NFTNL_EXPR_EXTHDR_OP:
89 *data_len =
sizeof(exthdr->op);
91 case NFTNL_EXPR_EXTHDR_FLAGS:
92 *data_len =
sizeof(exthdr->flags);
93 return &exthdr->flags;
94 case NFTNL_EXPR_EXTHDR_SREG:
95 *data_len =
sizeof(exthdr->sreg);
101 static int nftnl_expr_exthdr_cb(
const struct nlattr *attr,
void *data)
103 const struct nlattr **tb = data;
104 int type = mnl_attr_get_type(attr);
106 if (mnl_attr_type_valid(attr, NFTA_EXTHDR_MAX) < 0)
110 case NFTA_EXTHDR_TYPE:
111 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
114 case NFTA_EXTHDR_DREG:
115 case NFTA_EXTHDR_SREG:
116 case NFTA_EXTHDR_OFFSET:
117 case NFTA_EXTHDR_LEN:
119 case NFTA_EXTHDR_FLAGS:
120 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
130 nftnl_expr_exthdr_build(
struct nlmsghdr *nlh,
const struct nftnl_expr *e)
134 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_DREG))
135 mnl_attr_put_u32(nlh, NFTA_EXTHDR_DREG, htonl(exthdr->dreg));
136 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_SREG))
137 mnl_attr_put_u32(nlh, NFTA_EXTHDR_SREG, htonl(exthdr->sreg));
138 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_TYPE))
139 mnl_attr_put_u8(nlh, NFTA_EXTHDR_TYPE, exthdr->type);
140 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_OFFSET))
141 mnl_attr_put_u32(nlh, NFTA_EXTHDR_OFFSET, htonl(exthdr->offset));
142 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_LEN))
143 mnl_attr_put_u32(nlh, NFTA_EXTHDR_LEN, htonl(exthdr->len));
144 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_OP))
145 mnl_attr_put_u32(nlh, NFTA_EXTHDR_OP, htonl(exthdr->op));
146 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_FLAGS))
147 mnl_attr_put_u32(nlh, NFTA_EXTHDR_FLAGS, htonl(exthdr->flags));
151 nftnl_expr_exthdr_parse(
struct nftnl_expr *e,
struct nlattr *attr)
154 struct nlattr *tb[NFTA_EXTHDR_MAX+1] = {};
156 if (mnl_attr_parse_nested(attr, nftnl_expr_exthdr_cb, tb) < 0)
159 if (tb[NFTA_EXTHDR_DREG]) {
160 exthdr->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_DREG]));
161 e->flags |= (1 << NFTNL_EXPR_EXTHDR_DREG);
163 if (tb[NFTA_EXTHDR_SREG]) {
164 exthdr->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_SREG]));
165 e->flags |= (1 << NFTNL_EXPR_EXTHDR_SREG);
167 if (tb[NFTA_EXTHDR_TYPE]) {
168 exthdr->type = mnl_attr_get_u8(tb[NFTA_EXTHDR_TYPE]);
169 e->flags |= (1 << NFTNL_EXPR_EXTHDR_TYPE);
171 if (tb[NFTA_EXTHDR_OFFSET]) {
172 exthdr->offset = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_OFFSET]));
173 e->flags |= (1 << NFTNL_EXPR_EXTHDR_OFFSET);
175 if (tb[NFTA_EXTHDR_LEN]) {
176 exthdr->len = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_LEN]));
177 e->flags |= (1 << NFTNL_EXPR_EXTHDR_LEN);
179 if (tb[NFTA_EXTHDR_OP]) {
180 exthdr->op = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_OP]));
181 e->flags |= (1 << NFTNL_EXPR_EXTHDR_OP);
183 if (tb[NFTA_EXTHDR_FLAGS]) {
184 exthdr->flags = ntohl(mnl_attr_get_u32(tb[NFTA_EXTHDR_FLAGS]));
185 e->flags |= (1 << NFTNL_EXPR_EXTHDR_FLAGS);
191 static const char *op2str(uint8_t op)
194 case NFT_EXTHDR_OP_TCPOPT:
196 case NFT_EXTHDR_OP_IPV6:
198 case NFT_EXTHDR_OP_IPV4:
206 nftnl_expr_exthdr_snprintf(
char *buf,
size_t len,
207 uint32_t flags,
const struct nftnl_expr *e)
211 if (e->flags & (1 << NFTNL_EXPR_EXTHDR_DREG))
212 return snprintf(buf, len,
"load%s %ub @ %u + %u%s => reg %u ",
213 op2str(exthdr->op), exthdr->len, exthdr->type,
215 exthdr->flags & NFT_EXTHDR_F_PRESENT ?
" present" :
"",
217 else if (e->flags & (1 << NFTNL_EXPR_EXTHDR_SREG))
218 return snprintf(buf, len,
"write%s reg %u => %ub @ %u + %u ",
219 op2str(exthdr->op), exthdr->sreg, exthdr->len, exthdr->type,
221 else if (exthdr->op == NFT_EXTHDR_OP_TCPOPT && exthdr->len == 0)
222 return snprintf(buf, len,
"reset tcpopt %u ", exthdr->type);
224 return snprintf(buf, len,
"op %u len %u type %u offset %u ",
225 exthdr->op, exthdr->len, exthdr->type, exthdr->offset);
229 static struct attr_policy exthdr_attr_policy[__NFTNL_EXPR_EXTHDR_MAX] = {
230 [NFTNL_EXPR_EXTHDR_DREG] = { .maxlen =
sizeof(uint32_t) },
231 [NFTNL_EXPR_EXTHDR_TYPE] = { .maxlen =
sizeof(uint8_t) },
232 [NFTNL_EXPR_EXTHDR_OFFSET] = { .maxlen =
sizeof(uint32_t) },
233 [NFTNL_EXPR_EXTHDR_LEN] = { .maxlen =
sizeof(uint32_t) },
234 [NFTNL_EXPR_EXTHDR_FLAGS] = { .maxlen =
sizeof(uint32_t) },
235 [NFTNL_EXPR_EXTHDR_OP] = { .maxlen =
sizeof(uint32_t) },
236 [NFTNL_EXPR_EXTHDR_SREG] = { .maxlen =
sizeof(uint32_t) },
239 struct expr_ops expr_ops_exthdr = {
242 .nftnl_max_attr = __NFTNL_EXPR_EXTHDR_MAX - 1,
243 .attr_policy = exthdr_attr_policy,
244 .set = nftnl_expr_exthdr_set,
245 .get = nftnl_expr_exthdr_get,
246 .parse = nftnl_expr_exthdr_parse,
247 .build = nftnl_expr_exthdr_build,
248 .output = nftnl_expr_exthdr_snprintf,