libnetfilter_cttimeout
1.0.0
|
00001 /* 00002 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published 00006 * by the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com> 00010 */ 00011 #include "internal.h" 00012 00013 #include <time.h> 00014 #include <endian.h> 00015 #include <stdint.h> 00016 #include <stdlib.h> 00017 #include <string.h> 00018 #include <netinet/in.h> 00019 00020 #include <libmnl/libmnl.h> 00021 #include <linux/netfilter/nfnetlink.h> 00022 #include <linux/netfilter/nfnetlink_cttimeout.h> 00023 00024 #include <libnetfilter_cttimeout/libnetfilter_cttimeout.h> 00025 00026 static const char *const tcp_state_to_name[] = { 00027 [NFCT_TIMEOUT_ATTR_TCP_SYN_SENT] = "SYN_SENT", 00028 [NFCT_TIMEOUT_ATTR_TCP_SYN_RECV] = "SYN_RECV", 00029 [NFCT_TIMEOUT_ATTR_TCP_ESTABLISHED] = "ESTABLISHED", 00030 [NFCT_TIMEOUT_ATTR_TCP_FIN_WAIT] = "FIN_WAIT", 00031 [NFCT_TIMEOUT_ATTR_TCP_CLOSE_WAIT] = "CLOSE_WAIT", 00032 [NFCT_TIMEOUT_ATTR_TCP_LAST_ACK] = "LAST_ACK", 00033 [NFCT_TIMEOUT_ATTR_TCP_TIME_WAIT] = "TIME_WAIT", 00034 [NFCT_TIMEOUT_ATTR_TCP_CLOSE] = "CLOSE", 00035 [NFCT_TIMEOUT_ATTR_TCP_SYN_SENT2] = "SYN_SENT2", 00036 [NFCT_TIMEOUT_ATTR_TCP_RETRANS] = "RETRANS", 00037 [NFCT_TIMEOUT_ATTR_TCP_UNACK] = "UNACKNOWLEDGED", 00038 }; 00039 00040 static const char *const generic_state_to_name[] = { 00041 [NFCT_TIMEOUT_ATTR_GENERIC] = "TIMEOUT", 00042 }; 00043 00044 static const char *const udp_state_to_name[] = { 00045 [NFCT_TIMEOUT_ATTR_UDP_UNREPLIED] = "UNREPLIED", 00046 [NFCT_TIMEOUT_ATTR_UDP_REPLIED] = "REPLIED", 00047 }; 00048 00049 static const char *const sctp_state_to_name[] = { 00050 [NFCT_TIMEOUT_ATTR_SCTP_CLOSED] = "CLOSED", 00051 [NFCT_TIMEOUT_ATTR_SCTP_COOKIE_WAIT] = "COOKIE_WAIT", 00052 [NFCT_TIMEOUT_ATTR_SCTP_COOKIE_ECHOED] = "COOKIE_ECHOED", 00053 [NFCT_TIMEOUT_ATTR_SCTP_ESTABLISHED] = "ESTABLISHED", 00054 [NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_SENT] = "SHUTDOWN_SENT", 00055 [NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_RECD] = "SHUTDOWN_RECD", 00056 [NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT", 00057 }; 00058 00059 static const char *const dccp_state_to_name[] = { 00060 [NFCT_TIMEOUT_ATTR_DCCP_REQUEST] = "REQUEST", 00061 [NFCT_TIMEOUT_ATTR_DCCP_RESPOND] = "RESPOND", 00062 [NFCT_TIMEOUT_ATTR_DCCP_PARTOPEN] = "PARTOPEN", 00063 [NFCT_TIMEOUT_ATTR_DCCP_OPEN] = "OPEN", 00064 [NFCT_TIMEOUT_ATTR_DCCP_CLOSEREQ] = "CLOSEREQ", 00065 [NFCT_TIMEOUT_ATTR_DCCP_CLOSING] = "CLOSING", 00066 [NFCT_TIMEOUT_ATTR_DCCP_TIMEWAIT] = "TIMEWAIT", 00067 }; 00068 00069 static const char *const icmp_state_to_name[] = { 00070 [NFCT_TIMEOUT_ATTR_ICMP] = "TIMEOUT", 00071 }; 00072 00073 static const char *const icmpv6_state_to_name[] = { 00074 [NFCT_TIMEOUT_ATTR_ICMPV6] = "TIMEOUT", 00075 }; 00076 00077 static struct { 00078 uint32_t nlattr_max; 00079 uint32_t attr_max; 00080 const char *const *state_to_name; 00081 } timeout_protocol[IPPROTO_MAX] = { 00082 [IPPROTO_ICMP] = { 00083 .nlattr_max = __CTA_TIMEOUT_ICMP_MAX, 00084 .attr_max = NFCT_TIMEOUT_ATTR_ICMP_MAX, 00085 .state_to_name = icmp_state_to_name, 00086 }, 00087 [IPPROTO_TCP] = { 00088 .nlattr_max = __CTA_TIMEOUT_TCP_MAX, 00089 .attr_max = NFCT_TIMEOUT_ATTR_TCP_MAX, 00090 .state_to_name = tcp_state_to_name, 00091 }, 00092 [IPPROTO_UDP] = { 00093 .nlattr_max = __CTA_TIMEOUT_UDP_MAX, 00094 .attr_max = NFCT_TIMEOUT_ATTR_UDP_MAX, 00095 .state_to_name = udp_state_to_name, 00096 }, 00097 [IPPROTO_GRE] = { 00098 .nlattr_max = __CTA_TIMEOUT_GRE_MAX, 00099 .attr_max = NFCT_TIMEOUT_ATTR_GRE_MAX, 00100 .state_to_name = udp_state_to_name, 00101 }, 00102 [IPPROTO_SCTP] = { 00103 .nlattr_max = __CTA_TIMEOUT_SCTP_MAX, 00104 .attr_max = NFCT_TIMEOUT_ATTR_SCTP_MAX, 00105 .state_to_name = sctp_state_to_name, 00106 }, 00107 [IPPROTO_DCCP] = { 00108 .nlattr_max = __CTA_TIMEOUT_DCCP_MAX, 00109 .attr_max = NFCT_TIMEOUT_ATTR_DCCP_MAX, 00110 .state_to_name = dccp_state_to_name, 00111 }, 00112 [IPPROTO_UDPLITE] = { 00113 .nlattr_max = __CTA_TIMEOUT_UDPLITE_MAX, 00114 .attr_max = NFCT_TIMEOUT_ATTR_UDPLITE_MAX, 00115 .state_to_name = udp_state_to_name, 00116 }, 00117 [IPPROTO_ICMPV6] = { 00118 .nlattr_max = __CTA_TIMEOUT_ICMPV6_MAX, 00119 .attr_max = NFCT_TIMEOUT_ATTR_ICMPV6_MAX, 00120 .state_to_name = icmpv6_state_to_name, 00121 }, 00122 /* add your new supported protocol tracker here. */ 00123 [IPPROTO_RAW] = { 00124 .nlattr_max = __CTA_TIMEOUT_GENERIC_MAX, 00125 .attr_max = NFCT_TIMEOUT_ATTR_GENERIC_MAX, 00126 .state_to_name = generic_state_to_name, 00127 }, 00128 }; 00129 00130 00131 struct nfct_timeout { 00132 char name[32]; /* object name. */ 00133 uint16_t l3num; /* AF_INET, ... */ 00134 uint8_t l4num; /* UDP, TCP, ... */ 00135 uint16_t attrset; 00136 00137 uint32_t *timeout; /* array of timeout. */ 00138 uint16_t polset; 00139 }; 00140 00190 struct nfct_timeout *nfct_timeout_alloc(void) 00191 { 00192 struct nfct_timeout *t; 00193 00194 t = calloc(1, sizeof(struct nfct_timeout)); 00195 if (t == NULL) 00196 return NULL; 00197 00198 return t; 00199 } 00200 EXPORT_SYMBOL(nfct_timeout_alloc); 00201 00206 void nfct_timeout_free(struct nfct_timeout *t) 00207 { 00208 if (t->timeout) 00209 free(t->timeout); 00210 free(t); 00211 } 00212 EXPORT_SYMBOL(nfct_timeout_free); 00213 00220 int 00221 nfct_timeout_attr_set(struct nfct_timeout *t, uint32_t type, const void *data) 00222 { 00223 switch(type) { 00224 case NFCT_TIMEOUT_ATTR_NAME: 00225 strncpy(t->name, data, sizeof(t->name)); 00226 t->name[sizeof(t->name)-1] = '\0'; 00227 break; 00228 case NFCT_TIMEOUT_ATTR_L3PROTO: 00229 t->l3num = *((uint16_t *) data); 00230 break; 00231 case NFCT_TIMEOUT_ATTR_L4PROTO: 00232 t->l4num = *((uint8_t *) data); 00233 break; 00234 /* NFCT_TIMEOUT_ATTR_POLICY is set by nfct_timeout_policy_attr_set. */ 00235 } 00236 t->attrset |= (1 << type); 00237 return 0; 00238 } 00239 EXPORT_SYMBOL(nfct_timeout_attr_set); 00240 00247 int 00248 nfct_timeout_attr_set_u8(struct nfct_timeout *t, uint32_t type, uint8_t data) 00249 { 00250 return nfct_timeout_attr_set(t, type, &data); 00251 } 00252 EXPORT_SYMBOL(nfct_timeout_attr_set_u8); 00253 00260 int 00261 nfct_timeout_attr_set_u16(struct nfct_timeout *t, uint32_t type, uint16_t data) 00262 { 00263 return nfct_timeout_attr_set(t, type, &data); 00264 } 00265 EXPORT_SYMBOL(nfct_timeout_attr_set_u16); 00266 00272 void nfct_timeout_attr_unset(struct nfct_timeout *t, uint32_t type) 00273 { 00274 t->attrset &= ~(1 << type); 00275 } 00276 EXPORT_SYMBOL(nfct_timeout_attr_unset); 00277 00284 int 00285 nfct_timeout_policy_attr_set_u32(struct nfct_timeout *t, 00286 uint32_t type, uint32_t data) 00287 { 00288 size_t timeout_array_size; 00289 00290 /* Layer 4 protocol needs to be already set. */ 00291 if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO))) 00292 return -1; 00293 00294 if (t->timeout == NULL) { 00295 /* if not supported, default to generic protocol tracker. */ 00296 if (timeout_protocol[t->l4num].attr_max != 0) { 00297 timeout_array_size = 00298 sizeof(uint32_t) * 00299 timeout_protocol[t->l4num].attr_max; 00300 } else { 00301 timeout_array_size = 00302 sizeof(uint32_t) * 00303 timeout_protocol[IPPROTO_RAW].attr_max; 00304 } 00305 t->timeout = calloc(1, timeout_array_size); 00306 if (t->timeout == NULL) 00307 return -1; 00308 } 00309 00310 /* this state does not exists in this protocol tracker. */ 00311 if (type > timeout_protocol[t->l4num].attr_max) 00312 return -1; 00313 00314 t->timeout[type] = data; 00315 t->polset |= (1 << type); 00316 00317 if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY))) 00318 t->attrset |= (1 << NFCT_TIMEOUT_ATTR_POLICY); 00319 00320 return 0; 00321 } 00322 EXPORT_SYMBOL(nfct_timeout_policy_attr_set_u32); 00323 00329 void nfct_timeout_policy_attr_unset(struct nfct_timeout *t, uint32_t type) 00330 { 00331 t->attrset &= ~(1 << type); 00332 } 00333 EXPORT_SYMBOL(nfct_timeout_policy_attr_unset); 00334 00343 const char *nfct_timeout_policy_attr_to_name(uint8_t l4proto, uint32_t state) 00344 { 00345 if (timeout_protocol[l4proto].state_to_name == NULL) { 00346 printf("no array state name\n"); 00347 return NULL; 00348 } 00349 00350 if (timeout_protocol[l4proto].state_to_name[state] == NULL) { 00351 printf("state %d does not exists\n", state); 00352 return NULL; 00353 } 00354 00355 return timeout_protocol[l4proto].state_to_name[state]; 00356 } 00357 EXPORT_SYMBOL(nfct_timeout_policy_attr_to_name); 00358 00368 static int 00369 nfct_timeout_snprintf_default(char *buf, size_t size, 00370 const struct nfct_timeout *t, 00371 unsigned int flags) 00372 { 00373 int ret = 0; 00374 unsigned int offset = 0; 00375 00376 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME)) { 00377 ret = snprintf(buf+offset, size, ".%s = {\n", t->name); 00378 offset += ret; 00379 size -= ret; 00380 } 00381 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO)) { 00382 ret = snprintf(buf+offset, size, "\t.l3proto = %u,\n", 00383 t->l3num); 00384 offset += ret; 00385 size -= ret; 00386 } 00387 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)) { 00388 ret = snprintf(buf+offset, size, "\t.l4proto = %u,\n", 00389 t->l4num); 00390 offset += ret; 00391 size -= ret; 00392 } 00393 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY)) { 00394 uint8_t l4num = t->l4num; 00395 int i; 00396 00397 /* default to generic protocol tracker. */ 00398 if (timeout_protocol[t->l4num].attr_max == 0) 00399 l4num = IPPROTO_RAW; 00400 00401 ret = snprintf(buf+offset, size, "\t.policy = {\n"); 00402 offset += ret; 00403 size -= ret; 00404 00405 for (i=0; i<timeout_protocol[l4num].attr_max; i++) { 00406 const char *state_name = 00407 timeout_protocol[l4num].state_to_name[i][0] ? 00408 timeout_protocol[l4num].state_to_name[i] : 00409 "UNKNOWN"; 00410 00411 ret = snprintf(buf+offset, size, 00412 "\t\t.%s = %u,\n", state_name, t->timeout[i]); 00413 offset += ret; 00414 size -= ret; 00415 } 00416 00417 ret = snprintf(buf+offset, size, "\t},\n"); 00418 offset += ret; 00419 size -= ret; 00420 } 00421 ret = snprintf(buf+offset, size, "};"); 00422 offset += ret; 00423 size -= ret; 00424 00425 buf[offset]='\0'; 00426 00427 return ret; 00428 } 00429 00441 int nfct_timeout_snprintf(char *buf, size_t size, const struct nfct_timeout *t, 00442 unsigned int type, unsigned int flags) 00443 { 00444 int ret = 0; 00445 00446 switch(type) { 00447 case NFCT_TIMEOUT_O_DEFAULT: 00448 ret = nfct_timeout_snprintf_default(buf, size, t, flags); 00449 break; 00450 /* add your new output here. */ 00451 default: 00452 break; 00453 } 00454 00455 return ret; 00456 } 00457 EXPORT_SYMBOL(nfct_timeout_snprintf); 00458 00480 struct nlmsghdr * 00481 nfct_timeout_nlmsg_build_hdr(char *buf, uint8_t cmd, 00482 uint16_t flags, uint32_t seq) 00483 { 00484 struct nlmsghdr *nlh; 00485 struct nfgenmsg *nfh; 00486 00487 nlh = mnl_nlmsg_put_header(buf); 00488 nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8) | cmd; 00489 nlh->nlmsg_flags = NLM_F_REQUEST | flags; 00490 nlh->nlmsg_seq = seq; 00491 00492 nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); 00493 nfh->nfgen_family = AF_UNSPEC; 00494 nfh->version = NFNETLINK_V0; 00495 nfh->res_id = 0; 00496 00497 return nlh; 00498 } 00499 EXPORT_SYMBOL(nfct_timeout_nlmsg_build_hdr); 00500 00506 void 00507 nfct_timeout_nlmsg_build_payload(struct nlmsghdr *nlh, 00508 const struct nfct_timeout *t) 00509 { 00510 int i; 00511 struct nlattr *nest; 00512 00513 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME)) 00514 mnl_attr_put_strz(nlh, CTA_TIMEOUT_NAME, t->name); 00515 00516 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO)) 00517 mnl_attr_put_u16(nlh, CTA_TIMEOUT_L3PROTO, htons(t->l3num)); 00518 00519 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)) 00520 mnl_attr_put_u8(nlh, CTA_TIMEOUT_L4PROTO, t->l4num); 00521 00522 if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY) && t->polset) { 00523 nest = mnl_attr_nest_start(nlh, CTA_TIMEOUT_DATA); 00524 00525 for (i=0; i<timeout_protocol[t->l4num].attr_max; i++) { 00526 if (t->polset & (1 << i)) { 00527 mnl_attr_put_u32(nlh, i+1, 00528 htonl(t->timeout[i])); 00529 } 00530 } 00531 mnl_attr_nest_end(nlh, nest); 00532 } 00533 00534 } 00535 EXPORT_SYMBOL(nfct_timeout_nlmsg_build_payload); 00536 00537 static int 00538 timeout_nlmsg_parse_attr_cb(const struct nlattr *attr, void *data) 00539 { 00540 const struct nlattr **tb = data; 00541 uint16_t type = mnl_attr_get_type(attr); 00542 00543 if (mnl_attr_type_valid(attr, CTA_TIMEOUT_MAX) < 0) 00544 return MNL_CB_OK; 00545 00546 switch(type) { 00547 case CTA_TIMEOUT_NAME: 00548 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { 00549 perror("mnl_attr_validate"); 00550 return MNL_CB_ERROR; 00551 } 00552 break; 00553 case CTA_TIMEOUT_L3PROTO: 00554 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) { 00555 perror("mnl_attr_validate"); 00556 return MNL_CB_ERROR; 00557 } 00558 break; 00559 case CTA_TIMEOUT_L4PROTO: 00560 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) { 00561 perror("mnl_attr_validate"); 00562 return MNL_CB_ERROR; 00563 } 00564 break; 00565 case CTA_TIMEOUT_DATA: 00566 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { 00567 perror("mnl_attr_validate"); 00568 return MNL_CB_ERROR; 00569 } 00570 break; 00571 } 00572 tb[type] = attr; 00573 return MNL_CB_OK; 00574 } 00575 00576 struct _container_policy_cb { 00577 unsigned int nlattr_max; 00578 void *tb; 00579 }; 00580 00581 static int 00582 parse_timeout_attr_policy_cb(const struct nlattr *attr, void *data) 00583 { 00584 struct _container_policy_cb *data_cb = data; 00585 const struct nlattr **tb = data_cb->tb; 00586 uint16_t type = mnl_attr_get_type(attr); 00587 00588 if (mnl_attr_type_valid(attr, data_cb->nlattr_max) < 0) 00589 return MNL_CB_OK; 00590 00591 if (type <= data_cb->nlattr_max) { 00592 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { 00593 perror("mnl_attr_validate"); 00594 return MNL_CB_ERROR; 00595 } 00596 tb[type] = attr; 00597 } 00598 return MNL_CB_OK; 00599 } 00600 00601 static void 00602 timeout_parse_attr_data(struct nfct_timeout *t, const struct nlattr *nest) 00603 { 00604 unsigned int nlattr_max = timeout_protocol[t->l4num].nlattr_max; 00605 struct nlattr *tb[nlattr_max]; 00606 struct _container_policy_cb cnt = { 00607 .nlattr_max = nlattr_max, 00608 .tb = tb, 00609 }; 00610 unsigned int i; 00611 00612 memset(tb, 0, sizeof(struct nlattr *) * nlattr_max); 00613 00614 mnl_attr_parse_nested(nest, parse_timeout_attr_policy_cb, &cnt); 00615 00616 for (i=1; i<nlattr_max; i++) { 00617 if (tb[i]) { 00618 nfct_timeout_policy_attr_set_u32(t, i-1, 00619 ntohl(mnl_attr_get_u32(tb[i]))); 00620 } 00621 } 00622 } 00623 00632 int 00633 nfct_timeout_nlmsg_parse_payload(const struct nlmsghdr *nlh, 00634 struct nfct_timeout *t) 00635 { 00636 struct nlattr *tb[CTA_TIMEOUT_MAX+1] = {}; 00637 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); 00638 00639 mnl_attr_parse(nlh, sizeof(*nfg), timeout_nlmsg_parse_attr_cb, tb); 00640 if (tb[CTA_TIMEOUT_NAME]) { 00641 nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, 00642 mnl_attr_get_str(tb[CTA_TIMEOUT_NAME])); 00643 } 00644 if (tb[CTA_TIMEOUT_L3PROTO]) { 00645 nfct_timeout_attr_set_u16(t, NFCT_TIMEOUT_ATTR_L3PROTO, 00646 ntohs(mnl_attr_get_u16(tb[CTA_TIMEOUT_L3PROTO]))); 00647 } 00648 if (tb[CTA_TIMEOUT_L4PROTO]) { 00649 nfct_timeout_attr_set_u8(t, NFCT_TIMEOUT_ATTR_L4PROTO, 00650 mnl_attr_get_u8(tb[CTA_TIMEOUT_L4PROTO])); 00651 } 00652 if (tb[CTA_TIMEOUT_DATA]) { 00653 timeout_parse_attr_data(t, tb[CTA_TIMEOUT_DATA]); 00654 } 00655 return 0; 00656 } 00657 EXPORT_SYMBOL(nfct_timeout_nlmsg_parse_payload); 00658