18 #include <netinet/in.h>
20 #include <libmnl/libmnl.h>
21 #include <linux/netfilter/nfnetlink.h>
22 #include <linux/netfilter/nfnetlink_cttimeout.h>
24 #include <libnetfilter_cttimeout/libnetfilter_cttimeout.h>
26 static const char *
const tcp_state_to_name[] = {
27 [NFCT_TIMEOUT_ATTR_TCP_SYN_SENT] =
"SYN_SENT",
28 [NFCT_TIMEOUT_ATTR_TCP_SYN_RECV] =
"SYN_RECV",
29 [NFCT_TIMEOUT_ATTR_TCP_ESTABLISHED] =
"ESTABLISHED",
30 [NFCT_TIMEOUT_ATTR_TCP_FIN_WAIT] =
"FIN_WAIT",
31 [NFCT_TIMEOUT_ATTR_TCP_CLOSE_WAIT] =
"CLOSE_WAIT",
32 [NFCT_TIMEOUT_ATTR_TCP_LAST_ACK] =
"LAST_ACK",
33 [NFCT_TIMEOUT_ATTR_TCP_TIME_WAIT] =
"TIME_WAIT",
34 [NFCT_TIMEOUT_ATTR_TCP_CLOSE] =
"CLOSE",
35 [NFCT_TIMEOUT_ATTR_TCP_SYN_SENT2] =
"SYN_SENT2",
36 [NFCT_TIMEOUT_ATTR_TCP_RETRANS] =
"RETRANS",
37 [NFCT_TIMEOUT_ATTR_TCP_UNACK] =
"UNACKNOWLEDGED",
40 static const char *
const generic_state_to_name[] = {
41 [NFCT_TIMEOUT_ATTR_GENERIC] =
"TIMEOUT",
44 static const char *
const udp_state_to_name[] = {
45 [NFCT_TIMEOUT_ATTR_UDP_UNREPLIED] =
"UNREPLIED",
46 [NFCT_TIMEOUT_ATTR_UDP_REPLIED] =
"REPLIED",
49 static const char *
const sctp_state_to_name[] = {
50 [NFCT_TIMEOUT_ATTR_SCTP_CLOSED] =
"CLOSED",
51 [NFCT_TIMEOUT_ATTR_SCTP_COOKIE_WAIT] =
"COOKIE_WAIT",
52 [NFCT_TIMEOUT_ATTR_SCTP_COOKIE_ECHOED] =
"COOKIE_ECHOED",
53 [NFCT_TIMEOUT_ATTR_SCTP_ESTABLISHED] =
"ESTABLISHED",
54 [NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_SENT] =
"SHUTDOWN_SENT",
55 [NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_RECD] =
"SHUTDOWN_RECD",
56 [NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_ACK_SENT] =
"SHUTDOWN_ACK_SENT",
59 static const char *
const dccp_state_to_name[] = {
60 [NFCT_TIMEOUT_ATTR_DCCP_REQUEST] =
"REQUEST",
61 [NFCT_TIMEOUT_ATTR_DCCP_RESPOND] =
"RESPOND",
62 [NFCT_TIMEOUT_ATTR_DCCP_PARTOPEN] =
"PARTOPEN",
63 [NFCT_TIMEOUT_ATTR_DCCP_OPEN] =
"OPEN",
64 [NFCT_TIMEOUT_ATTR_DCCP_CLOSEREQ] =
"CLOSEREQ",
65 [NFCT_TIMEOUT_ATTR_DCCP_CLOSING] =
"CLOSING",
66 [NFCT_TIMEOUT_ATTR_DCCP_TIMEWAIT] =
"TIMEWAIT",
69 static const char *
const icmp_state_to_name[] = {
70 [NFCT_TIMEOUT_ATTR_ICMP] =
"TIMEOUT",
73 static const char *
const icmpv6_state_to_name[] = {
74 [NFCT_TIMEOUT_ATTR_ICMPV6] =
"TIMEOUT",
80 const char *
const *state_to_name;
81 } timeout_protocol[IPPROTO_MAX] = {
83 .nlattr_max = __CTA_TIMEOUT_ICMP_MAX,
84 .attr_max = NFCT_TIMEOUT_ATTR_ICMP_MAX,
85 .state_to_name = icmp_state_to_name,
88 .nlattr_max = __CTA_TIMEOUT_TCP_MAX,
89 .attr_max = NFCT_TIMEOUT_ATTR_TCP_MAX,
90 .state_to_name = tcp_state_to_name,
93 .nlattr_max = __CTA_TIMEOUT_UDP_MAX,
94 .attr_max = NFCT_TIMEOUT_ATTR_UDP_MAX,
95 .state_to_name = udp_state_to_name,
98 .nlattr_max = __CTA_TIMEOUT_GRE_MAX,
99 .attr_max = NFCT_TIMEOUT_ATTR_GRE_MAX,
100 .state_to_name = udp_state_to_name,
103 .nlattr_max = __CTA_TIMEOUT_SCTP_MAX,
104 .attr_max = NFCT_TIMEOUT_ATTR_SCTP_MAX,
105 .state_to_name = sctp_state_to_name,
108 .nlattr_max = __CTA_TIMEOUT_DCCP_MAX,
109 .attr_max = NFCT_TIMEOUT_ATTR_DCCP_MAX,
110 .state_to_name = dccp_state_to_name,
112 [IPPROTO_UDPLITE] = {
113 .nlattr_max = __CTA_TIMEOUT_UDPLITE_MAX,
114 .attr_max = NFCT_TIMEOUT_ATTR_UDPLITE_MAX,
115 .state_to_name = udp_state_to_name,
118 .nlattr_max = __CTA_TIMEOUT_ICMPV6_MAX,
119 .attr_max = NFCT_TIMEOUT_ATTR_ICMPV6_MAX,
120 .state_to_name = icmpv6_state_to_name,
124 .nlattr_max = __CTA_TIMEOUT_GENERIC_MAX,
125 .attr_max = NFCT_TIMEOUT_ATTR_GENERIC_MAX,
126 .state_to_name = generic_state_to_name,
131 struct nfct_timeout {
192 struct nfct_timeout *t;
194 t = calloc(1,
sizeof(
struct nfct_timeout));
224 case NFCT_TIMEOUT_ATTR_NAME:
225 strncpy(t->name, data,
sizeof(t->name));
226 t->name[
sizeof(t->name)-1] =
'\0';
228 case NFCT_TIMEOUT_ATTR_L3PROTO:
229 t->l3num = *((uint16_t *) data);
231 case NFCT_TIMEOUT_ATTR_L4PROTO:
232 t->l4num = *((uint8_t *) data);
236 t->attrset |= (1 << type);
274 t->attrset &= ~(1 << type);
286 uint32_t type, uint32_t data)
288 size_t timeout_array_size;
291 if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)))
294 if (t->timeout == NULL) {
296 if (timeout_protocol[t->l4num].attr_max != 0) {
299 timeout_protocol[t->l4num].attr_max;
303 timeout_protocol[IPPROTO_RAW].attr_max;
305 t->timeout = calloc(1, timeout_array_size);
306 if (t->timeout == NULL)
311 if (type > timeout_protocol[t->l4num].attr_max)
314 t->timeout[type] = data;
315 t->polset |= (1 << type);
317 if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY)))
318 t->attrset |= (1 << NFCT_TIMEOUT_ATTR_POLICY);
331 t->attrset &= ~(1 << type);
345 if (timeout_protocol[l4proto].state_to_name == NULL) {
346 printf(
"no array state name\n");
350 if (timeout_protocol[l4proto].state_to_name[state] == NULL) {
351 printf(
"state %d does not exists\n", state);
355 return timeout_protocol[l4proto].state_to_name[state];
369 nfct_timeout_snprintf_default(
char *buf,
size_t size,
370 const struct nfct_timeout *t,
374 unsigned int offset = 0;
376 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME)) {
377 ret = snprintf(buf+offset, size,
".%s = {\n", t->name);
381 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO)) {
382 ret = snprintf(buf+offset, size,
"\t.l3proto = %u,\n",
387 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)) {
388 ret = snprintf(buf+offset, size,
"\t.l4proto = %u,\n",
393 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY)) {
394 uint8_t l4num = t->l4num;
398 if (timeout_protocol[t->l4num].attr_max == 0)
401 ret = snprintf(buf+offset, size,
"\t.policy = {\n");
405 for (i=0; i<timeout_protocol[l4num].attr_max; i++) {
406 const char *state_name =
407 timeout_protocol[l4num].state_to_name[i][0] ?
408 timeout_protocol[l4num].state_to_name[i] :
411 ret = snprintf(buf+offset, size,
412 "\t\t.%s = %u,\n", state_name, t->timeout[i]);
417 ret = snprintf(buf+offset, size,
"\t},\n");
421 ret = snprintf(buf+offset, size,
"};");
442 unsigned int type,
unsigned int flags)
447 case NFCT_TIMEOUT_O_DEFAULT:
448 ret = nfct_timeout_snprintf_default(buf, size, t, flags);
482 uint16_t flags, uint32_t seq)
484 struct nlmsghdr *nlh;
485 struct nfgenmsg *nfh;
487 nlh = mnl_nlmsg_put_header(buf);
488 nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8) | cmd;
489 nlh->nlmsg_flags = NLM_F_REQUEST | flags;
490 nlh->nlmsg_seq = seq;
492 nfh = mnl_nlmsg_put_extra_header(nlh,
sizeof(
struct nfgenmsg));
493 nfh->nfgen_family = AF_UNSPEC;
494 nfh->version = NFNETLINK_V0;
508 const struct nfct_timeout *t)
513 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME))
514 mnl_attr_put_strz(nlh, CTA_TIMEOUT_NAME, t->name);
516 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO))
517 mnl_attr_put_u16(nlh, CTA_TIMEOUT_L3PROTO, htons(t->l3num));
519 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO))
520 mnl_attr_put_u8(nlh, CTA_TIMEOUT_L4PROTO, t->l4num);
522 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY) && t->polset) {
523 nest = mnl_attr_nest_start(nlh, CTA_TIMEOUT_DATA);
525 for (i=0; i<timeout_protocol[t->l4num].attr_max; i++) {
526 if (t->polset & (1 << i)) {
527 mnl_attr_put_u32(nlh, i+1,
528 htonl(t->timeout[i]));
531 mnl_attr_nest_end(nlh, nest);
538 timeout_nlmsg_parse_attr_cb(
const struct nlattr *attr,
void *data)
540 const struct nlattr **tb = data;
541 uint16_t type = mnl_attr_get_type(attr);
543 if (mnl_attr_type_valid(attr, CTA_TIMEOUT_MAX) < 0)
547 case CTA_TIMEOUT_NAME:
548 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
549 perror(
"mnl_attr_validate");
553 case CTA_TIMEOUT_L3PROTO:
554 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
555 perror(
"mnl_attr_validate");
559 case CTA_TIMEOUT_L4PROTO:
560 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
561 perror(
"mnl_attr_validate");
565 case CTA_TIMEOUT_DATA:
566 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
567 perror(
"mnl_attr_validate");
576 struct _container_policy_cb {
577 unsigned int nlattr_max;
582 parse_timeout_attr_policy_cb(
const struct nlattr *attr,
void *data)
584 struct _container_policy_cb *data_cb = data;
585 const struct nlattr **tb = data_cb->tb;
586 uint16_t type = mnl_attr_get_type(attr);
588 if (mnl_attr_type_valid(attr, data_cb->nlattr_max) < 0)
591 if (type <= data_cb->nlattr_max) {
592 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
593 perror(
"mnl_attr_validate");
602 timeout_parse_attr_data(
struct nfct_timeout *t,
const struct nlattr *nest)
604 unsigned int nlattr_max = timeout_protocol[t->l4num].nlattr_max;
605 struct nlattr *tb[nlattr_max];
606 struct _container_policy_cb cnt = {
607 .nlattr_max = nlattr_max,
612 memset(tb, 0,
sizeof(
struct nlattr *) * nlattr_max);
614 mnl_attr_parse_nested(nest, parse_timeout_attr_policy_cb, &cnt);
616 for (i=1; i<nlattr_max; i++) {
619 ntohl(mnl_attr_get_u32(tb[i])));
634 struct nfct_timeout *t)
636 struct nlattr *tb[CTA_TIMEOUT_MAX+1] = {};
637 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
639 mnl_attr_parse(nlh,
sizeof(*nfg), timeout_nlmsg_parse_attr_cb, tb);
640 if (tb[CTA_TIMEOUT_NAME]) {
642 mnl_attr_get_str(tb[CTA_TIMEOUT_NAME]));
644 if (tb[CTA_TIMEOUT_L3PROTO]) {
646 ntohs(mnl_attr_get_u16(tb[CTA_TIMEOUT_L3PROTO])));
648 if (tb[CTA_TIMEOUT_L4PROTO]) {
650 mnl_attr_get_u8(tb[CTA_TIMEOUT_L4PROTO]));
652 if (tb[CTA_TIMEOUT_DATA]) {
653 timeout_parse_attr_data(t, tb[CTA_TIMEOUT_DATA]);
int nfct_timeout_snprintf(char *buf, size_t size, const struct nfct_timeout *t, unsigned int type, unsigned int flags)
void nfct_timeout_policy_attr_unset(struct nfct_timeout *t, uint32_t type)
void nfct_timeout_free(struct nfct_timeout *t)
int nfct_timeout_attr_set_u16(struct nfct_timeout *t, uint32_t type, uint16_t data)
int nfct_timeout_attr_set_u8(struct nfct_timeout *t, uint32_t type, uint8_t data)
void nfct_timeout_attr_unset(struct nfct_timeout *t, uint32_t type)
int nfct_timeout_policy_attr_set_u32(struct nfct_timeout *t, uint32_t type, uint32_t data)
struct nfct_timeout * nfct_timeout_alloc(void)
const char * nfct_timeout_policy_attr_to_name(uint8_t l4proto, uint32_t state)
int nfct_timeout_attr_set(struct nfct_timeout *t, uint32_t type, const void *data)
void nfct_timeout_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nfct_timeout *t)
int nfct_timeout_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfct_timeout *t)
struct nlmsghdr * nfct_timeout_nlmsg_build_hdr(char *buf, uint8_t cmd, uint16_t flags, uint32_t seq)