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 26static 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 40static const char *const generic_state_to_name[] = { 41 [NFCT_TIMEOUT_ATTR_GENERIC] = "TIMEOUT", 42}; 43 44static const char *const udp_state_to_name[] = { 45 [NFCT_TIMEOUT_ATTR_UDP_UNREPLIED] = "UNREPLIED", 46 [NFCT_TIMEOUT_ATTR_UDP_REPLIED] = "REPLIED", 47}; 48 49static 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 59static 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 69static const char *const icmp_state_to_name[] = { 70 [NFCT_TIMEOUT_ATTR_ICMP] = "TIMEOUT", 71}; 72 73static const char *const icmpv6_state_to_name[] = { 74 [NFCT_TIMEOUT_ATTR_ICMPV6] = "TIMEOUT", 75}; 76 77static 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 131struct 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 141/** 142 * \mainpage 143 * 144 * libnetfilter_cttimeout is the userspace library that provides a programming 145 * interface (API) to the in-kernel cttimeout infrastructure. This 146 * infrastructure allows you to define fine-grain connection tracking timeout 147 * policies that can be attached to traffic flows via iptables CT target. 148 * Before the existence of this infrastructure, you could only set global 149 * timeout policies per protocol. This library is currently used by the nfct 150 * utility that is part of the conntrack-tools. 151 * 152 * libnetfilter_cttimeout homepage is: 153 * http://netfilter.org/projects/libnetfilter_cttimeout/ 154 * 155 * \section Dependencies 156 * libnetfilter_cttimeout requires libmnl and a kernel that includes the 157 * nfnetlink_cttimeout subsystem (i.e. 3.4.0 or later). 158 * 159 * \section Main Features 160 * - listing/retrieving entries from the timeout policy table. 161 * - inserting/modifying/deleting entries from the timeout policy table. 162 * 163 * \section Git Tree 164 * The current development version of libnetfilter_cttimeout can be accessed at 165 * https://git.netfilter.org/cgi-bin/gitweb.cgi?p=libnetfilter_cttimeout.git 166 * 167 * \section Privileges 168 * You need the CAP_NET_ADMIN capability in order to allow your application 169 * to receive events from and to send commands to kernel-space, excepting 170 * the timeout policy table dumping operation. 171 * 172 * \section Authors 173 * libnetfilter_conntrack has been written by Pablo Neira Ayuso. 174 */ 175 176/** 177 * \defgroup nfcttimeout Timeout policy object handling 178 * @{ 179 */ 180 181/** 182 * nfct_timeout_alloc - allocate a new conntrack timeout object 183 * \param protonum layer 4 protocol number (use IPPROTO_* constants) 184 * 185 * You can use IPPROTO_MAX to set the timeout for the generic protocol tracker. 186 * 187 * In case of success, this function returns a valid pointer, otherwise NULL 188 * s returned and errno is appropriately set. 189 */ 190struct 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} 200EXPORT_SYMBOL(nfct_timeout_alloc); 201 202/** 203 * nfct_timeout_free - release one conntrack timeout object 204 * \param t pointer to the conntrack timeout object 205 */ 206void nfct_timeout_free(struct nfct_timeout *t) 207{ 208 if (t->timeout) 209 free(t->timeout); 210 free(t); 211} 212EXPORT_SYMBOL(nfct_timeout_free); 213 214/** 215 * nfct_timeout_attr_set - set one attribute of the conntrack timeout object 216 * \param t pointer to the conntrack timeout object 217 * \param type attribute type you want to set 218 * \param data pointer to data that will be used to set this attribute 219 */ 220int 221nfct_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} 239EXPORT_SYMBOL(nfct_timeout_attr_set); 240 241/** 242 * nfct_timeout_attr_set_u8 - set one attribute of the conntrack timeout object 243 * \param t pointer to the conntrack timeout object 244 * \param type attribute type you want to set 245 * \param data pointer to data that will be used to set this attribute 246 */ 247int 248nfct_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} 252EXPORT_SYMBOL(nfct_timeout_attr_set_u8); 253 254/** 255 * nfct_timeout_attr_set_u16 - set one attribute of the conntrack timeout object 256 * \param t pointer to the conntrack timeout object 257 * \param type attribute type you want to set 258 * \param data pointer to data that will be used to set this attribute 259 */ 260int 261nfct_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} 265EXPORT_SYMBOL(nfct_timeout_attr_set_u16); 266 267/** 268 * nfct_timeout_attr_unset - unset one attribute of the conntrack timeout object 269 * \param t pointer to the conntrack timeout object 270 * \param type attribute type you want to set 271 */ 272void nfct_timeout_attr_unset(struct nfct_timeout *t, uint32_t type) 273{ 274 t->attrset &= ~(1 << type); 275} 276EXPORT_SYMBOL(nfct_timeout_attr_unset); 277 278/** 279 * nfct_timeout_policy_attr_set_u32 - set one attribute of the policy 280 * \param t pointer to the conntrack timeout object 281 * \param type attribute type you want to set 282 * \param data data that will be used to set this attribute 283 */ 284int 285nfct_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} 322EXPORT_SYMBOL(nfct_timeout_policy_attr_set_u32); 323 324/** 325 * nfct_timeout_policy_attr_unset - unset one attribute of the policy 326 * \param t pointer to the conntrack timeout object 327 * \param type attribute type you want to set 328 */ 329void nfct_timeout_policy_attr_unset(struct nfct_timeout *t, uint32_t type) 330{ 331 t->attrset &= ~(1 << type); 332} 333EXPORT_SYMBOL(nfct_timeout_policy_attr_unset); 334 335/** 336 * nfct_timeout_policy_attr_to_name - get state name from protocol state number 337 * \param l4proto protocol, ie. IPPROTO_* 338 * \param state state number that you want to get the state name 339 * 340 * This function returns NULL if unsupported protocol or state number is passed. 341 * Otherwise, a pointer to valid string is returned. 342 */ 343const 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} 357EXPORT_SYMBOL(nfct_timeout_policy_attr_to_name); 358 359/** 360 * @} 361 */ 362 363/** 364 * \defgroup nfcttimeout_output Timeout policy object output 365 * @{ 366 */ 367 368static int 369nfct_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 430/** 431 * nfct_timeout_snprintf - print conntrack timeout object into one buffer 432 * \param buf: pointer to buffer that is used to print the object 433 * \param size: size of the buffer (or remaining room in it). 434 * \param t: pointer to a valid conntrack timeout object. 435 * \param type: output type (see NFCT_TIMEOUT_O_*) 436 * \param flags: output flags (always set this to zero). 437 * 438 * This function returns -1 in case that some mandatory attributes are 439 * missing. On sucess, it returns 0. 440 */ 441int 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} 457EXPORT_SYMBOL(nfct_timeout_snprintf); 458 459/** 460 * @} 461 */ 462 463/** 464 * \defgroup nlmsg Netlink message helper functions 465 * @{ 466 */ 467 468/** 469 * nfct_timeout_nlmsg_build_hdr - build netlink message header for ct timeout 470 * \param buf: buffer where this function outputs the netlink message. 471 * \param cmd: nfct_timeout nfnetlink command. 472 * \param flags: netlink flags. 473 * \param seq: sequence number for this message. 474 * 475 * Possible commands: 476 * - CTNL_MSG_TIMEOUT_NEW: new conntrack timeout object. 477 * - CTNL_MSG_TIMEOUT_GET: get conntrack timeout object. 478 * - CTNL_MSG_TIMEOUT_DEL: delete conntrack timeout object. 479 */ 480struct nlmsghdr * 481nfct_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} 499EXPORT_SYMBOL(nfct_timeout_nlmsg_build_hdr); 500 501/** 502 * nfct_timeout_nlmsg_build_payload - build payload from ct timeout object 503 * \param nlh: netlink message that you want to use to add the payload. 504 * \param t: pointer to a conntrack timeout object 505 */ 506void 507nfct_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} 535EXPORT_SYMBOL(nfct_timeout_nlmsg_build_payload); 536 537static int 538timeout_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 576struct _container_policy_cb { 577 unsigned int nlattr_max; 578 void *tb; 579}; 580 581static int 582parse_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 601static void 602timeout_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]) { 618 nfct_timeout_policy_attr_set_u32(t, i-1, 619 ntohl(mnl_attr_get_u32(tb[i]))); 620 } 621 } 622} 623 624/** 625 * nfct_timeout_nlmsg_parse_payload - set timeout object attributes from message 626 * \param nlh: netlink message that you want to use to add the payload. 627 * \param t: pointer to a conntrack timeout object 628 * 629 * This function returns -1 in case that some mandatory attributes are 630 * missing. On sucess, it returns 0. 631 */ 632int 633nfct_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} 657EXPORT_SYMBOL(nfct_timeout_nlmsg_parse_payload); 658 659/** 660 * @} 661 */ 662