12 #include <arpa/inet.h>
16 #include <linux/netfilter/nf_tables.h>
19 #include <libmnl/libmnl.h>
20 #include <libnftnl/object.h>
24 static const char *
const tcp_state_to_name[] = {
25 [NFTNL_CTTIMEOUT_TCP_SYN_SENT] =
"SYN_SENT",
26 [NFTNL_CTTIMEOUT_TCP_SYN_RECV] =
"SYN_RECV",
27 [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] =
"ESTABLISHED",
28 [NFTNL_CTTIMEOUT_TCP_FIN_WAIT] =
"FIN_WAIT",
29 [NFTNL_CTTIMEOUT_TCP_CLOSE_WAIT] =
"CLOSE_WAIT",
30 [NFTNL_CTTIMEOUT_TCP_LAST_ACK] =
"LAST_ACK",
31 [NFTNL_CTTIMEOUT_TCP_TIME_WAIT] =
"TIME_WAIT",
32 [NFTNL_CTTIMEOUT_TCP_CLOSE] =
"CLOSE",
33 [NFTNL_CTTIMEOUT_TCP_SYN_SENT2] =
"SYN_SENT2",
34 [NFTNL_CTTIMEOUT_TCP_RETRANS] =
"RETRANS",
35 [NFTNL_CTTIMEOUT_TCP_UNACK] =
"UNACKNOWLEDGED",
38 static uint32_t tcp_dflt_timeout[] = {
39 [NFTNL_CTTIMEOUT_TCP_SYN_SENT] = 120,
40 [NFTNL_CTTIMEOUT_TCP_SYN_RECV] = 60,
41 [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] = 432000,
42 [NFTNL_CTTIMEOUT_TCP_FIN_WAIT] = 120,
43 [NFTNL_CTTIMEOUT_TCP_CLOSE_WAIT] = 60,
44 [NFTNL_CTTIMEOUT_TCP_LAST_ACK] = 30,
45 [NFTNL_CTTIMEOUT_TCP_TIME_WAIT] = 120,
46 [NFTNL_CTTIMEOUT_TCP_CLOSE] = 10,
47 [NFTNL_CTTIMEOUT_TCP_SYN_SENT2] = 120,
48 [NFTNL_CTTIMEOUT_TCP_RETRANS] = 300,
49 [NFTNL_CTTIMEOUT_TCP_UNACK] = 300,
52 static const char *
const udp_state_to_name[] = {
53 [NFTNL_CTTIMEOUT_UDP_UNREPLIED] =
"UNREPLIED",
54 [NFTNL_CTTIMEOUT_UDP_REPLIED] =
"REPLIED",
57 static uint32_t udp_dflt_timeout[] = {
58 [NFTNL_CTTIMEOUT_UDP_UNREPLIED] = 30,
59 [NFTNL_CTTIMEOUT_UDP_REPLIED] = 180,
64 const char *
const *state_to_name;
65 uint32_t *dflt_timeout;
66 } timeout_protocol[IPPROTO_MAX] = {
68 .attr_max = NFTNL_CTTIMEOUT_TCP_MAX,
69 .state_to_name = tcp_state_to_name,
70 .dflt_timeout = tcp_dflt_timeout,
73 .attr_max = NFTNL_CTTIMEOUT_UDP_MAX,
74 .state_to_name = udp_state_to_name,
75 .dflt_timeout = udp_dflt_timeout,
80 unsigned int nlattr_max;
85 nftnl_timeout_policy_attr_set_u32(
struct nftnl_obj *e,
86 uint32_t type, uint32_t data)
88 struct nftnl_obj_ct_timeout *t = nftnl_obj_data(e);
90 if (type >= NFTNL_CTTIMEOUT_ARRAY_MAX)
93 t->timeout[type] = data;
95 if (!(e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_ARRAY)))
96 e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_ARRAY);
102 parse_timeout_attr_policy_cb(
const struct nlattr *attr,
void *data)
105 const struct nlattr **tb = data_cb->tb;
106 uint16_t type = mnl_attr_get_type(attr);
108 if (mnl_attr_type_valid(attr, data_cb->nlattr_max) < 0)
111 if (type <= data_cb->nlattr_max) {
112 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
120 timeout_parse_attr_data(
struct nftnl_obj *e,
121 const struct nlattr *nest)
123 struct nftnl_obj_ct_timeout *t = nftnl_obj_data(e);
124 unsigned int attr_max = timeout_protocol[t->l4proto].attr_max;
125 struct nlattr *tb[attr_max];
127 .nlattr_max = attr_max,
132 memset(tb, 0,
sizeof(
struct nlattr *) * attr_max);
134 mnl_attr_parse_nested(nest, parse_timeout_attr_policy_cb, &cnt);
136 for (i = 1; i <= attr_max; i++) {
138 nftnl_timeout_policy_attr_set_u32(e, i-1,
139 ntohl(mnl_attr_get_u32(tb[i])));
144 static int nftnl_obj_ct_timeout_set(
struct nftnl_obj *e, uint16_t type,
145 const void *data, uint32_t data_len)
147 struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e);
150 case NFTNL_OBJ_CT_TIMEOUT_L3PROTO:
151 memcpy(&timeout->l3proto, data,
sizeof(timeout->l3proto));
153 case NFTNL_OBJ_CT_TIMEOUT_L4PROTO:
154 memcpy(&timeout->l4proto, data,
sizeof(timeout->l4proto));
156 case NFTNL_OBJ_CT_TIMEOUT_ARRAY:
157 memcpy(timeout->timeout, data,
158 sizeof(uint32_t) * NFTNL_CTTIMEOUT_ARRAY_MAX);
166 static const void *nftnl_obj_ct_timeout_get(
const struct nftnl_obj *e,
167 uint16_t type, uint32_t *data_len)
169 struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e);
172 case NFTNL_OBJ_CT_TIMEOUT_L3PROTO:
173 *data_len =
sizeof(timeout->l3proto);
174 return &timeout->l3proto;
175 case NFTNL_OBJ_CT_TIMEOUT_L4PROTO:
176 *data_len =
sizeof(timeout->l4proto);
177 return &timeout->l4proto;
178 case NFTNL_OBJ_CT_TIMEOUT_ARRAY:
179 *data_len =
sizeof(uint32_t) * NFTNL_CTTIMEOUT_ARRAY_MAX;
180 return timeout->timeout;
185 static int nftnl_obj_ct_timeout_cb(
const struct nlattr *attr,
void *data)
187 int type = mnl_attr_get_type(attr);
188 const struct nlattr **tb = data;
190 if (mnl_attr_type_valid(attr, NFTA_CT_TIMEOUT_MAX) < 0)
194 case NFTA_CT_TIMEOUT_L3PROTO:
195 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
198 case NFTA_CT_TIMEOUT_L4PROTO:
199 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
202 case NFTA_CT_TIMEOUT_DATA:
203 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
213 nftnl_obj_ct_timeout_build(
struct nlmsghdr *nlh,
const struct nftnl_obj *e)
215 struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e);
218 if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO))
219 mnl_attr_put_u16(nlh, NFTA_CT_TIMEOUT_L3PROTO, htons(timeout->l3proto));
220 if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO))
221 mnl_attr_put_u8(nlh, NFTA_CT_TIMEOUT_L4PROTO, timeout->l4proto);
222 if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_ARRAY)) {
225 nest = mnl_attr_nest_start(nlh, NFTA_CT_TIMEOUT_DATA);
226 for (i = 0; i < timeout_protocol[timeout->l4proto].attr_max; i++)
227 mnl_attr_put_u32(nlh, i+1, htonl(timeout->timeout[i]));
229 mnl_attr_nest_end(nlh, nest);
234 nftnl_obj_ct_timeout_parse(
struct nftnl_obj *e,
struct nlattr *attr)
236 struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e);
237 struct nlattr *tb[NFTA_CT_TIMEOUT_MAX + 1] = {};
239 if (mnl_attr_parse_nested(attr, nftnl_obj_ct_timeout_cb, tb) < 0)
242 if (tb[NFTA_CT_TIMEOUT_L3PROTO]) {
243 timeout->l3proto = ntohs(mnl_attr_get_u16(tb[NFTA_CT_TIMEOUT_L3PROTO]));
244 e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO);
246 if (tb[NFTA_CT_TIMEOUT_L4PROTO]) {
247 timeout->l4proto = mnl_attr_get_u8(tb[NFTA_CT_TIMEOUT_L4PROTO]);
248 e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO);
250 if (tb[NFTA_CT_TIMEOUT_DATA]) {
251 timeout_parse_attr_data(e, tb[NFTA_CT_TIMEOUT_DATA]);
252 e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_ARRAY);
257 static int nftnl_obj_ct_timeout_snprintf_default(
char *buf,
size_t len,
258 const struct nftnl_obj *e)
261 int offset = 0, remain = len;
263 struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e);
265 if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO)) {
266 ret = snprintf(buf + offset, len,
"family %d ",
268 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
270 if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO)) {
271 ret = snprintf(buf + offset, len,
"protocol %d ",
273 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
275 if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_ARRAY)) {
276 uint8_t l4num = timeout->l4proto;
280 if (timeout_protocol[timeout->l4proto].attr_max == 0)
283 ret = snprintf(buf + offset, len,
"policy = {");
284 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
286 for (i = 0; i < timeout_protocol[l4num].attr_max; i++) {
287 const char *state_name =
288 timeout_protocol[l4num].state_to_name[i][0] ?
289 timeout_protocol[l4num].state_to_name[i] :
292 if (timeout->timeout[i] != timeout_protocol[l4num].dflt_timeout[i]) {
293 ret = snprintf(buf + offset, len,
294 "%s = %u,", state_name, timeout->timeout[i]);
295 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
299 ret = snprintf(buf + offset, len,
"}");
300 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
307 static int nftnl_obj_ct_timeout_snprintf(
char *buf,
size_t len, uint32_t type,
309 const struct nftnl_obj *e)
315 case NFTNL_OUTPUT_DEFAULT:
316 return nftnl_obj_ct_timeout_snprintf_default(buf, len, e);
317 case NFTNL_OUTPUT_JSON:
324 struct obj_ops obj_ops_ct_timeout = {
325 .name =
"ct_timeout",
326 .type = NFT_OBJECT_CT_TIMEOUT,
327 .alloc_len =
sizeof(
struct nftnl_obj_ct_timeout),
328 .max_attr = NFTA_CT_TIMEOUT_MAX,
329 .set = nftnl_obj_ct_timeout_set,
330 .get = nftnl_obj_ct_timeout_get,
331 .parse = nftnl_obj_ct_timeout_parse,
332 .build = nftnl_obj_ct_timeout_build,
333 .snprintf = nftnl_obj_ct_timeout_snprintf,