libnetfilter_cttimeout  1.0.0
libnetfilter_cttimeout.c
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
10  */
11 #include "internal.h"
12 
13 #include <time.h>
14 #include <endian.h>
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <netinet/in.h>
19 
20 #include <libmnl/libmnl.h>
21 #include <linux/netfilter/nfnetlink.h>
22 #include <linux/netfilter/nfnetlink_cttimeout.h>
23 
24 #include <libnetfilter_cttimeout/libnetfilter_cttimeout.h>
25 
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",
38 };
39 
40 static const char *const generic_state_to_name[] = {
41  [NFCT_TIMEOUT_ATTR_GENERIC] = "TIMEOUT",
42 };
43 
44 static const char *const udp_state_to_name[] = {
45  [NFCT_TIMEOUT_ATTR_UDP_UNREPLIED] = "UNREPLIED",
46  [NFCT_TIMEOUT_ATTR_UDP_REPLIED] = "REPLIED",
47 };
48 
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",
57 };
58 
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",
67 };
68 
69 static const char *const icmp_state_to_name[] = {
70  [NFCT_TIMEOUT_ATTR_ICMP] = "TIMEOUT",
71 };
72 
73 static const char *const icmpv6_state_to_name[] = {
74  [NFCT_TIMEOUT_ATTR_ICMPV6] = "TIMEOUT",
75 };
76 
77 static struct {
78  uint32_t nlattr_max;
79  uint32_t attr_max;
80  const char *const *state_to_name;
81 } timeout_protocol[IPPROTO_MAX] = {
82  [IPPROTO_ICMP] = {
83  .nlattr_max = __CTA_TIMEOUT_ICMP_MAX,
84  .attr_max = NFCT_TIMEOUT_ATTR_ICMP_MAX,
85  .state_to_name = icmp_state_to_name,
86  },
87  [IPPROTO_TCP] = {
88  .nlattr_max = __CTA_TIMEOUT_TCP_MAX,
89  .attr_max = NFCT_TIMEOUT_ATTR_TCP_MAX,
90  .state_to_name = tcp_state_to_name,
91  },
92  [IPPROTO_UDP] = {
93  .nlattr_max = __CTA_TIMEOUT_UDP_MAX,
94  .attr_max = NFCT_TIMEOUT_ATTR_UDP_MAX,
95  .state_to_name = udp_state_to_name,
96  },
97  [IPPROTO_GRE] = {
98  .nlattr_max = __CTA_TIMEOUT_GRE_MAX,
99  .attr_max = NFCT_TIMEOUT_ATTR_GRE_MAX,
100  .state_to_name = udp_state_to_name,
101  },
102  [IPPROTO_SCTP] = {
103  .nlattr_max = __CTA_TIMEOUT_SCTP_MAX,
104  .attr_max = NFCT_TIMEOUT_ATTR_SCTP_MAX,
105  .state_to_name = sctp_state_to_name,
106  },
107  [IPPROTO_DCCP] = {
108  .nlattr_max = __CTA_TIMEOUT_DCCP_MAX,
109  .attr_max = NFCT_TIMEOUT_ATTR_DCCP_MAX,
110  .state_to_name = dccp_state_to_name,
111  },
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,
116  },
117  [IPPROTO_ICMPV6] = {
118  .nlattr_max = __CTA_TIMEOUT_ICMPV6_MAX,
119  .attr_max = NFCT_TIMEOUT_ATTR_ICMPV6_MAX,
120  .state_to_name = icmpv6_state_to_name,
121  },
122  /* add your new supported protocol tracker here. */
123  [IPPROTO_RAW] = {
124  .nlattr_max = __CTA_TIMEOUT_GENERIC_MAX,
125  .attr_max = NFCT_TIMEOUT_ATTR_GENERIC_MAX,
126  .state_to_name = generic_state_to_name,
127  },
128 };
129 
130 
131 struct nfct_timeout {
132  char name[32]; /* object name. */
133  uint16_t l3num; /* AF_INET, ... */
134  uint8_t l4num; /* UDP, TCP, ... */
135  uint16_t attrset;
136 
137  uint32_t *timeout; /* array of timeout. */
138  uint16_t polset;
139 };
140 
190 struct nfct_timeout *nfct_timeout_alloc(void)
191 {
192  struct nfct_timeout *t;
193 
194  t = calloc(1, sizeof(struct nfct_timeout));
195  if (t == NULL)
196  return NULL;
197 
198  return t;
199 }
200 EXPORT_SYMBOL(nfct_timeout_alloc);
201 
206 void nfct_timeout_free(struct nfct_timeout *t)
207 {
208  if (t->timeout)
209  free(t->timeout);
210  free(t);
211 }
212 EXPORT_SYMBOL(nfct_timeout_free);
213 
220 int
221 nfct_timeout_attr_set(struct nfct_timeout *t, uint32_t type, const void *data)
222 {
223  switch(type) {
224  case NFCT_TIMEOUT_ATTR_NAME:
225  strncpy(t->name, data, sizeof(t->name));
226  t->name[sizeof(t->name)-1] = '\0';
227  break;
228  case NFCT_TIMEOUT_ATTR_L3PROTO:
229  t->l3num = *((uint16_t *) data);
230  break;
231  case NFCT_TIMEOUT_ATTR_L4PROTO:
232  t->l4num = *((uint8_t *) data);
233  break;
234  /* NFCT_TIMEOUT_ATTR_POLICY is set by nfct_timeout_policy_attr_set. */
235  }
236  t->attrset |= (1 << type);
237  return 0;
238 }
239 EXPORT_SYMBOL(nfct_timeout_attr_set);
240 
247 int
248 nfct_timeout_attr_set_u8(struct nfct_timeout *t, uint32_t type, uint8_t data)
249 {
250  return nfct_timeout_attr_set(t, type, &data);
251 }
252 EXPORT_SYMBOL(nfct_timeout_attr_set_u8);
253 
260 int
261 nfct_timeout_attr_set_u16(struct nfct_timeout *t, uint32_t type, uint16_t data)
262 {
263  return nfct_timeout_attr_set(t, type, &data);
264 }
265 EXPORT_SYMBOL(nfct_timeout_attr_set_u16);
266 
272 void nfct_timeout_attr_unset(struct nfct_timeout *t, uint32_t type)
273 {
274  t->attrset &= ~(1 << type);
275 }
276 EXPORT_SYMBOL(nfct_timeout_attr_unset);
277 
284 int
285 nfct_timeout_policy_attr_set_u32(struct nfct_timeout *t,
286  uint32_t type, uint32_t data)
287 {
288  size_t timeout_array_size;
289 
290  /* Layer 4 protocol needs to be already set. */
291  if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)))
292  return -1;
293 
294  if (t->timeout == NULL) {
295  /* if not supported, default to generic protocol tracker. */
296  if (timeout_protocol[t->l4num].attr_max != 0) {
297  timeout_array_size =
298  sizeof(uint32_t) *
299  timeout_protocol[t->l4num].attr_max;
300  } else {
301  timeout_array_size =
302  sizeof(uint32_t) *
303  timeout_protocol[IPPROTO_RAW].attr_max;
304  }
305  t->timeout = calloc(1, timeout_array_size);
306  if (t->timeout == NULL)
307  return -1;
308  }
309 
310  /* this state does not exists in this protocol tracker. */
311  if (type > timeout_protocol[t->l4num].attr_max)
312  return -1;
313 
314  t->timeout[type] = data;
315  t->polset |= (1 << type);
316 
317  if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY)))
318  t->attrset |= (1 << NFCT_TIMEOUT_ATTR_POLICY);
319 
320  return 0;
321 }
322 EXPORT_SYMBOL(nfct_timeout_policy_attr_set_u32);
323 
329 void nfct_timeout_policy_attr_unset(struct nfct_timeout *t, uint32_t type)
330 {
331  t->attrset &= ~(1 << type);
332 }
333 EXPORT_SYMBOL(nfct_timeout_policy_attr_unset);
334 
343 const char *nfct_timeout_policy_attr_to_name(uint8_t l4proto, uint32_t state)
344 {
345  if (timeout_protocol[l4proto].state_to_name == NULL) {
346  printf("no array state name\n");
347  return NULL;
348  }
349 
350  if (timeout_protocol[l4proto].state_to_name[state] == NULL) {
351  printf("state %d does not exists\n", state);
352  return NULL;
353  }
354 
355  return timeout_protocol[l4proto].state_to_name[state];
356 }
357 EXPORT_SYMBOL(nfct_timeout_policy_attr_to_name);
358 
368 static int
369 nfct_timeout_snprintf_default(char *buf, size_t size,
370  const struct nfct_timeout *t,
371  unsigned int flags)
372 {
373  int ret = 0;
374  unsigned int offset = 0;
375 
376  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME)) {
377  ret = snprintf(buf+offset, size, ".%s = {\n", t->name);
378  offset += ret;
379  size -= ret;
380  }
381  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO)) {
382  ret = snprintf(buf+offset, size, "\t.l3proto = %u,\n",
383  t->l3num);
384  offset += ret;
385  size -= ret;
386  }
387  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)) {
388  ret = snprintf(buf+offset, size, "\t.l4proto = %u,\n",
389  t->l4num);
390  offset += ret;
391  size -= ret;
392  }
393  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY)) {
394  uint8_t l4num = t->l4num;
395  int i;
396 
397  /* default to generic protocol tracker. */
398  if (timeout_protocol[t->l4num].attr_max == 0)
399  l4num = IPPROTO_RAW;
400 
401  ret = snprintf(buf+offset, size, "\t.policy = {\n");
402  offset += ret;
403  size -= ret;
404 
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] :
409  "UNKNOWN";
410 
411  ret = snprintf(buf+offset, size,
412  "\t\t.%s = %u,\n", state_name, t->timeout[i]);
413  offset += ret;
414  size -= ret;
415  }
416 
417  ret = snprintf(buf+offset, size, "\t},\n");
418  offset += ret;
419  size -= ret;
420  }
421  ret = snprintf(buf+offset, size, "};");
422  offset += ret;
423  size -= ret;
424 
425  buf[offset]='\0';
426 
427  return ret;
428 }
429 
441 int nfct_timeout_snprintf(char *buf, size_t size, const struct nfct_timeout *t,
442  unsigned int type, unsigned int flags)
443 {
444  int ret = 0;
445 
446  switch(type) {
447  case NFCT_TIMEOUT_O_DEFAULT:
448  ret = nfct_timeout_snprintf_default(buf, size, t, flags);
449  break;
450  /* add your new output here. */
451  default:
452  break;
453  }
454 
455  return ret;
456 }
457 EXPORT_SYMBOL(nfct_timeout_snprintf);
458 
480 struct nlmsghdr *
481 nfct_timeout_nlmsg_build_hdr(char *buf, uint8_t cmd,
482  uint16_t flags, uint32_t seq)
483 {
484  struct nlmsghdr *nlh;
485  struct nfgenmsg *nfh;
486 
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;
491 
492  nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
493  nfh->nfgen_family = AF_UNSPEC;
494  nfh->version = NFNETLINK_V0;
495  nfh->res_id = 0;
496 
497  return nlh;
498 }
499 EXPORT_SYMBOL(nfct_timeout_nlmsg_build_hdr);
500 
506 void
507 nfct_timeout_nlmsg_build_payload(struct nlmsghdr *nlh,
508  const struct nfct_timeout *t)
509 {
510  int i;
511  struct nlattr *nest;
512 
513  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME))
514  mnl_attr_put_strz(nlh, CTA_TIMEOUT_NAME, t->name);
515 
516  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO))
517  mnl_attr_put_u16(nlh, CTA_TIMEOUT_L3PROTO, htons(t->l3num));
518 
519  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO))
520  mnl_attr_put_u8(nlh, CTA_TIMEOUT_L4PROTO, t->l4num);
521 
522  if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY) && t->polset) {
523  nest = mnl_attr_nest_start(nlh, CTA_TIMEOUT_DATA);
524 
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]));
529  }
530  }
531  mnl_attr_nest_end(nlh, nest);
532  }
533 
534 }
535 EXPORT_SYMBOL(nfct_timeout_nlmsg_build_payload);
536 
537 static int
538 timeout_nlmsg_parse_attr_cb(const struct nlattr *attr, void *data)
539 {
540  const struct nlattr **tb = data;
541  uint16_t type = mnl_attr_get_type(attr);
542 
543  if (mnl_attr_type_valid(attr, CTA_TIMEOUT_MAX) < 0)
544  return MNL_CB_OK;
545 
546  switch(type) {
547  case CTA_TIMEOUT_NAME:
548  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
549  perror("mnl_attr_validate");
550  return MNL_CB_ERROR;
551  }
552  break;
553  case CTA_TIMEOUT_L3PROTO:
554  if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
555  perror("mnl_attr_validate");
556  return MNL_CB_ERROR;
557  }
558  break;
559  case CTA_TIMEOUT_L4PROTO:
560  if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
561  perror("mnl_attr_validate");
562  return MNL_CB_ERROR;
563  }
564  break;
565  case CTA_TIMEOUT_DATA:
566  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
567  perror("mnl_attr_validate");
568  return MNL_CB_ERROR;
569  }
570  break;
571  }
572  tb[type] = attr;
573  return MNL_CB_OK;
574 }
575 
576 struct _container_policy_cb {
577  unsigned int nlattr_max;
578  void *tb;
579 };
580 
581 static int
582 parse_timeout_attr_policy_cb(const struct nlattr *attr, void *data)
583 {
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);
587 
588  if (mnl_attr_type_valid(attr, data_cb->nlattr_max) < 0)
589  return MNL_CB_OK;
590 
591  if (type <= data_cb->nlattr_max) {
592  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
593  perror("mnl_attr_validate");
594  return MNL_CB_ERROR;
595  }
596  tb[type] = attr;
597  }
598  return MNL_CB_OK;
599 }
600 
601 static void
602 timeout_parse_attr_data(struct nfct_timeout *t, const struct nlattr *nest)
603 {
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,
608  .tb = tb,
609  };
610  unsigned int i;
611 
612  memset(tb, 0, sizeof(struct nlattr *) * nlattr_max);
613 
614  mnl_attr_parse_nested(nest, parse_timeout_attr_policy_cb, &cnt);
615 
616  for (i=1; i<nlattr_max; i++) {
617  if (tb[i]) {
619  ntohl(mnl_attr_get_u32(tb[i])));
620  }
621  }
622 }
623 
632 int
633 nfct_timeout_nlmsg_parse_payload(const struct nlmsghdr *nlh,
634  struct nfct_timeout *t)
635 {
636  struct nlattr *tb[CTA_TIMEOUT_MAX+1] = {};
637  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
638 
639  mnl_attr_parse(nlh, sizeof(*nfg), timeout_nlmsg_parse_attr_cb, tb);
640  if (tb[CTA_TIMEOUT_NAME]) {
641  nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME,
642  mnl_attr_get_str(tb[CTA_TIMEOUT_NAME]));
643  }
644  if (tb[CTA_TIMEOUT_L3PROTO]) {
645  nfct_timeout_attr_set_u16(t, NFCT_TIMEOUT_ATTR_L3PROTO,
646  ntohs(mnl_attr_get_u16(tb[CTA_TIMEOUT_L3PROTO])));
647  }
648  if (tb[CTA_TIMEOUT_L4PROTO]) {
649  nfct_timeout_attr_set_u8(t, NFCT_TIMEOUT_ATTR_L4PROTO,
650  mnl_attr_get_u8(tb[CTA_TIMEOUT_L4PROTO]));
651  }
652  if (tb[CTA_TIMEOUT_DATA]) {
653  timeout_parse_attr_data(t, tb[CTA_TIMEOUT_DATA]);
654  }
655  return 0;
656 }
657 EXPORT_SYMBOL(nfct_timeout_nlmsg_parse_payload);
658 
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)