15 #include <arpa/inet.h>
17 #include <linux/netfilter/nf_tables.h>
20 #include <libmnl/libmnl.h>
21 #include <libnftnl/expr.h>
22 #include <libnftnl/rule.h>
26 enum nft_registers dreg;
27 enum nft_registers sreg;
31 #define IP_CT_DIR_ORIGINAL 0
32 #define IP_CT_DIR_REPLY 1
35 nftnl_expr_ct_set(
struct nftnl_expr *e, uint16_t type,
36 const void *data, uint32_t data_len)
41 case NFTNL_EXPR_CT_KEY:
42 memcpy(&ct->key, data,
sizeof(ct->key));
44 case NFTNL_EXPR_CT_DIR:
45 memcpy(&ct->dir, data,
sizeof(ct->dir));
47 case NFTNL_EXPR_CT_DREG:
48 memcpy(&ct->dreg, data,
sizeof(ct->dreg));
50 case NFTNL_EXPR_CT_SREG:
51 memcpy(&ct->sreg, data,
sizeof(ct->sreg));
60 nftnl_expr_ct_get(
const struct nftnl_expr *e, uint16_t type,
66 case NFTNL_EXPR_CT_KEY:
67 *data_len =
sizeof(ct->key);
69 case NFTNL_EXPR_CT_DIR:
70 *data_len =
sizeof(ct->dir);
72 case NFTNL_EXPR_CT_DREG:
73 *data_len =
sizeof(ct->dreg);
75 case NFTNL_EXPR_CT_SREG:
76 *data_len =
sizeof(ct->sreg);
82 static int nftnl_expr_ct_cb(
const struct nlattr *attr,
void *data)
84 const struct nlattr **tb = data;
85 int type = mnl_attr_get_type(attr);
87 if (mnl_attr_type_valid(attr, NFTA_CT_MAX) < 0)
94 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
97 case NFTA_CT_DIRECTION:
98 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
108 nftnl_expr_ct_build(
struct nlmsghdr *nlh,
const struct nftnl_expr *e)
112 if (e->flags & (1 << NFTNL_EXPR_CT_KEY))
113 mnl_attr_put_u32(nlh, NFTA_CT_KEY, htonl(ct->key));
114 if (e->flags & (1 << NFTNL_EXPR_CT_DREG))
115 mnl_attr_put_u32(nlh, NFTA_CT_DREG, htonl(ct->dreg));
116 if (e->flags & (1 << NFTNL_EXPR_CT_DIR))
117 mnl_attr_put_u8(nlh, NFTA_CT_DIRECTION, ct->dir);
118 if (e->flags & (1 << NFTNL_EXPR_CT_SREG))
119 mnl_attr_put_u32(nlh, NFTA_CT_SREG, htonl(ct->sreg));
123 nftnl_expr_ct_parse(
struct nftnl_expr *e,
struct nlattr *attr)
126 struct nlattr *tb[NFTA_CT_MAX+1] = {};
128 if (mnl_attr_parse_nested(attr, nftnl_expr_ct_cb, tb) < 0)
131 if (tb[NFTA_CT_KEY]) {
132 ct->key = ntohl(mnl_attr_get_u32(tb[NFTA_CT_KEY]));
133 e->flags |= (1 << NFTNL_EXPR_CT_KEY);
135 if (tb[NFTA_CT_DREG]) {
136 ct->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_DREG]));
137 e->flags |= (1 << NFTNL_EXPR_CT_DREG);
139 if (tb[NFTA_CT_SREG]) {
140 ct->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_SREG]));
141 e->flags |= (1 << NFTNL_EXPR_CT_SREG);
143 if (tb[NFTA_CT_DIRECTION]) {
144 ct->dir = mnl_attr_get_u8(tb[NFTA_CT_DIRECTION]);
145 e->flags |= (1 << NFTNL_EXPR_CT_DIR);
151 static const char *ctkey2str_array[NFT_CT_MAX + 1] = {
152 [NFT_CT_STATE] =
"state",
153 [NFT_CT_DIRECTION] =
"direction",
154 [NFT_CT_STATUS] =
"status",
155 [NFT_CT_MARK] =
"mark",
156 [NFT_CT_SECMARK] =
"secmark",
157 [NFT_CT_EXPIRATION] =
"expiration",
158 [NFT_CT_HELPER] =
"helper",
159 [NFT_CT_L3PROTOCOL] =
"l3protocol",
160 [NFT_CT_PROTOCOL] =
"protocol",
161 [NFT_CT_SRC] =
"src",
162 [NFT_CT_DST] =
"dst",
163 [NFT_CT_PROTO_SRC] =
"proto_src",
164 [NFT_CT_PROTO_DST] =
"proto_dst",
165 [NFT_CT_LABELS] =
"label",
166 [NFT_CT_PKTS] =
"packets",
167 [NFT_CT_BYTES] =
"bytes",
168 [NFT_CT_AVGPKT] =
"avgpkt",
169 [NFT_CT_ZONE] =
"zone",
170 [NFT_CT_EVENTMASK] =
"event",
171 [NFT_CT_SRC_IP] =
"src_ip",
172 [NFT_CT_DST_IP] =
"dst_ip",
173 [NFT_CT_SRC_IP6] =
"src_ip6",
174 [NFT_CT_DST_IP6] =
"dst_ip6",
177 static const char *ctkey2str(uint32_t ctkey)
179 if (ctkey >= NFT_CT_MAX)
182 return ctkey2str_array[ctkey];
185 static inline int str2ctkey(
const char *ctkey)
189 for (i = 0; i < NFT_CT_MAX; i++) {
190 if (strcmp(ctkey2str_array[i], ctkey) == 0)
197 static const char *ctdir2str(uint8_t ctdir)
200 case IP_CT_DIR_ORIGINAL:
202 case IP_CT_DIR_REPLY:
209 static inline int str2ctdir(
const char *str, uint8_t *ctdir)
211 if (strcmp(str,
"original") == 0) {
212 *ctdir = IP_CT_DIR_ORIGINAL;
216 if (strcmp(str,
"reply") == 0) {
217 *ctdir = IP_CT_DIR_REPLY;
225 nftnl_expr_ct_snprintf_default(
char *buf,
size_t size,
226 const struct nftnl_expr *e)
228 int ret, remain = size, offset = 0;
231 if (e->flags & (1 << NFTNL_EXPR_CT_SREG)) {
232 ret = snprintf(buf, size,
"set %s with reg %u ",
233 ctkey2str(ct->key), ct->sreg);
234 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
237 if (e->flags & (1 << NFTNL_EXPR_CT_DREG)) {
238 ret = snprintf(buf, remain,
"load %s => reg %u ",
239 ctkey2str(ct->key), ct->dreg);
240 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
243 if (nftnl_expr_is_set(e, NFTNL_EXPR_CT_DIR)) {
244 ret = snprintf(buf + offset, remain,
", dir %s ",
246 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
253 nftnl_expr_ct_snprintf(
char *buf,
size_t len, uint32_t type,
254 uint32_t flags,
const struct nftnl_expr *e)
257 case NFTNL_OUTPUT_DEFAULT:
258 return nftnl_expr_ct_snprintf_default(buf, len, e);
259 case NFTNL_OUTPUT_XML:
260 case NFTNL_OUTPUT_JSON:
267 struct expr_ops expr_ops_ct = {
270 .max_attr = NFTA_CT_MAX,
271 .set = nftnl_expr_ct_set,
272 .get = nftnl_expr_ct_get,
273 .parse = nftnl_expr_ct_parse,
274 .build = nftnl_expr_ct_build,
275 .snprintf = nftnl_expr_ct_snprintf,