1 /* 2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo (at) netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10 #include <stdlib.h> 11 #include <string.h> /* for memset */ 12 #include <errno.h> 13 #include <assert.h> 14 15 #include "internal/internal.h" 16 17 /** 18 * \defgroup exp Expect object handling 19 * @{ 20 */ 21 22 /** 23 * nfexp_new - allocate a new expectation 24 * 25 * In case of success, this function returns a valid pointer to a memory blob, 26 * otherwise NULL is returned and errno is set appropiately. 27 */ 28 struct nf_expect *nfexp_new(void) 29 { 30 struct nf_expect *exp; 31 32 exp = malloc(sizeof(struct nf_expect)); 33 if (!exp) 34 return NULL; 35 36 memset(exp, 0, sizeof(struct nf_expect)); 37 38 return exp; 39 } 40 41 /** 42 * nfexp_destroy - release an expectation object 43 * \param exp pointer to the expectation object 44 */ 45 void nfexp_destroy(struct nf_expect *exp) 46 { 47 assert(exp != NULL); 48 free(exp); 49 exp = NULL; /* bugtrap */ 50 } 51 52 /** 53 * nfexp_sizeof - return the size in bytes of a certain expect object 54 * \param exp pointer to the expect object 55 */ 56 size_t nfexp_sizeof(const struct nf_expect *exp) 57 { 58 assert(exp != NULL); 59 return sizeof(*exp); 60 } 61 62 /** 63 * nfexp_maxsize - return the maximum size in bytes of a expect object 64 * 65 * Use this function if you want to allocate a expect object in the stack 66 * instead of the heap. For example: 67 * 68 * char buf[nfexp_maxsize()]; 69 * struct nf_expect *exp = (struct nf_expect *) buf; 70 * memset(exp, 0, nfexp_maxsize()); 71 * 72 * Note: As for now this function returns the same size that nfexp_sizeof(exp) 73 * does although _this could change in the future_. Therefore, do not assume 74 * that nfexp_sizeof(exp) == nfexp_maxsize(). 75 */ 76 size_t nfexp_maxsize(void) 77 { 78 return sizeof(struct nf_expect); 79 } 80 81 /** 82 * nfexp_clone - clone a expectation object 83 * \param exp pointer to a valid expectation object 84 * 85 * On error, NULL is returned and errno is appropiately set. Otherwise, 86 * a valid pointer to the clone expect is returned. 87 */ 88 struct nf_expect *nfexp_clone(const struct nf_expect *exp) 89 { 90 struct nf_expect *clone; 91 92 assert(exp != NULL); 93 94 if ((clone = nfexp_new()) == NULL) 95 return NULL; 96 memcpy(clone, exp, sizeof(*exp)); 97 98 return clone; 99 } 100 101 /** 102 * nfexp_cmp - compare two expectation objects 103 * \param exp1 pointer to a valid expectation object 104 * \param exp2 pointer to a valid expectation object 105 * \param flags flags 106 * 107 * This function only compare attribute set in both objects, by default 108 * the comparison is not strict, ie. if a certain attribute is not set in one 109 * of the objects, then such attribute is not used in the comparison. 110 * If you want more strict comparisons, you can use the appropriate flags 111 * to modify this behaviour (see NFCT_CMP_STRICT and NFCT_CMP_MASK). 112 * 113 * The available flags are: 114 * - NFCT_CMP_STRICT: the compared objects must have the same attributes 115 * and the same values, otherwise it returns that the objects are 116 * different. 117 * - NFCT_CMP_MASK: the first object is used as mask, this means that 118 * if an attribute is present in exp1 but not in exp2, this function 119 * returns that the objects are different. 120 * 121 * Other existing flags that are used by nfct_cmp() are ignored. 122 * 123 * If both conntrack object are equal, this function returns 1, otherwise 124 * 0 is returned. 125 */ 126 int nfexp_cmp(const struct nf_expect *exp1, const struct nf_expect *exp2, 127 unsigned int flags) 128 { 129 assert(exp1 != NULL); 130 assert(exp2 != NULL); 131 132 return __cmp_expect(exp1, exp2, flags); 133 } 134 135 /** 136 * @} 137 */ 138 139 /** 140 * \defgroup LibrarySetup Library setup 141 * @{ 142 */ 143 144 /** 145 * nfexp_callback_register - register a callback 146 * \param h library handler 147 * \param cb callback used to process expect received 148 * \param data data used by the callback, if any. 149 * 150 * This function register a callback to handle the expect received, 151 * in case of error -1 is returned and errno is set appropiately, otherwise 152 * 0 is returned. 153 * 154 * Note that the data parameter is optional, if you do not want to pass any 155 * data to your callback, then use NULL. 156 */ 157 int nfexp_callback_register(struct nfct_handle *h, 158 enum nf_conntrack_msg_type type, 159 int (*cb)(enum nf_conntrack_msg_type type, 160 struct nf_expect *exp, 161 void *data), 162 void *data) 163 { 164 struct __data_container *container; 165 166 assert(h != NULL); 167 168 container = malloc(sizeof(struct __data_container)); 169 if (!container) 170 return -1; 171 memset(container, 0, sizeof(struct __data_container)); 172 173 h->expect_cb = cb; 174 container->h = h; 175 container->type = type; 176 container->data = data; 177 178 h->nfnl_cb_exp.call = __callback; 179 h->nfnl_cb_exp.data = container; 180 h->nfnl_cb_exp.attr_count = CTA_EXPECT_MAX; 181 182 nfnl_callback_register(h->nfnlssh_exp, 183 IPCTNL_MSG_EXP_NEW, 184 &h->nfnl_cb_exp); 185 186 nfnl_callback_register(h->nfnlssh_exp, 187 IPCTNL_MSG_EXP_DELETE, 188 &h->nfnl_cb_exp); 189 190 return 0; 191 } 192 193 /** 194 * nfexp_callback_unregister - unregister a callback 195 * \param h library handler 196 */ 197 void nfexp_callback_unregister(struct nfct_handle *h) 198 { 199 assert(h != NULL); 200 201 nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_NEW); 202 nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE); 203 204 h->expect_cb = NULL; 205 free(h->nfnl_cb_exp.data); 206 207 h->nfnl_cb_exp.call = NULL; 208 h->nfnl_cb_exp.data = NULL; 209 h->nfnl_cb_exp.attr_count = 0; 210 } 211 212 /** 213 * nfexp_callback_register2 - register a callback 214 * \param h library handler 215 * \param cb callback used to process expect received 216 * \param data data used by the callback, if any. 217 * 218 * This function register a callback to handle the expect received, 219 * in case of error -1 is returned and errno is set appropiately, otherwise 220 * 0 is returned. 221 * 222 * Note that the data parameter is optional, if you do not want to pass any 223 * data to your callback, then use NULL. 224 * 225 * NOTICE: The difference with nfexp_callback_register() is that this function 226 * uses the new callback interface that includes the Netlink header. 227 * 228 * WARNING: Don't mix nfexp_callback_register() and nfexp_callback_register2() 229 * calls, use only once at a time. 230 */ 231 int nfexp_callback_register2(struct nfct_handle *h, 232 enum nf_conntrack_msg_type type, 233 int (*cb)(const struct nlmsghdr *nlh, 234 enum nf_conntrack_msg_type type, 235 struct nf_expect *exp, 236 void *data), 237 void *data) 238 { 239 struct __data_container *container; 240 241 assert(h != NULL); 242 243 container = malloc(sizeof(struct __data_container)); 244 if (!container) 245 return -1; 246 memset(container, 0, sizeof(struct __data_container)); 247 248 h->expect_cb2 = cb; 249 container->h = h; 250 container->type = type; 251 container->data = data; 252 253 h->nfnl_cb_exp.call = __callback; 254 h->nfnl_cb_exp.data = container; 255 h->nfnl_cb_exp.attr_count = CTA_EXPECT_MAX; 256 257 nfnl_callback_register(h->nfnlssh_exp, 258 IPCTNL_MSG_EXP_NEW, 259 &h->nfnl_cb_exp); 260 261 nfnl_callback_register(h->nfnlssh_exp, 262 IPCTNL_MSG_EXP_DELETE, 263 &h->nfnl_cb_exp); 264 265 return 0; 266 } 267 268 /** 269 * nfexp_callback_unregister2 - unregister a callback 270 * \param h library handler 271 */ 272 void nfexp_callback_unregister2(struct nfct_handle *h) 273 { 274 assert(h != NULL); 275 276 nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_NEW); 277 nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE); 278 279 h->expect_cb2 = NULL; 280 free(h->nfnl_cb_exp.data); 281 282 h->nfnl_cb_exp.call = NULL; 283 h->nfnl_cb_exp.data = NULL; 284 h->nfnl_cb_exp.attr_count = 0; 285 } 286 287 /** 288 * @} 289 */ 290 291 /** 292 * \defgroup exp Expect object handling 293 * @{ 294 */ 295 296 /** 297 * nfexp_set_attr - set the value of a certain expect attribute 298 * \param exp pointer to a valid expect 299 * \param type attribute type 300 * \param value pointer to the attribute value 301 * 302 * Note that certain attributes are unsettable: 303 * - ATTR_EXP_USE 304 * - ATTR_EXP_ID 305 * - ATTR_EXP_*_COUNTER_* 306 * The call of this function for such attributes do nothing. 307 */ 308 void nfexp_set_attr(struct nf_expect *exp, 309 const enum nf_expect_attr type, 310 const void *value) 311 { 312 assert(exp != NULL); 313 assert(value != NULL); 314 315 if (type >= ATTR_EXP_MAX) 316 return; 317 318 if (set_exp_attr_array[type]) { 319 set_exp_attr_array[type](exp, value); 320 set_bit(type, exp->set); 321 } 322 } 323 324 /** 325 * nfexp_set_attr_u8 - set the value of a certain expect attribute 326 * \param exp pointer to a valid expect 327 * \param type attribute type 328 * \param value unsigned 8 bits attribute value 329 */ 330 void nfexp_set_attr_u8(struct nf_expect *exp, 331 const enum nf_expect_attr type, 332 uint8_t value) 333 { 334 nfexp_set_attr(exp, type, &value); 335 } 336 337 /** 338 * nfexp_set_attr_u16 - set the value of a certain expect attribute 339 * \param exp pointer to a valid expect 340 * \param type attribute type 341 * \param value unsigned 16 bits attribute value 342 */ 343 void nfexp_set_attr_u16(struct nf_expect *exp, 344 const enum nf_expect_attr type, 345 uint16_t value) 346 { 347 nfexp_set_attr(exp, type, &value); 348 } 349 350 /** 351 * nfexp_set_attr_u32 - set the value of a certain expect attribute 352 * \param exp pointer to a valid expect 353 * \param type attribute type 354 * \param value unsigned 32 bits attribute value 355 */ 356 void nfexp_set_attr_u32(struct nf_expect *exp, 357 const enum nf_expect_attr type, 358 uint32_t value) 359 { 360 nfexp_set_attr(exp, type, &value); 361 } 362 363 /** 364 * nfexp_get_attr - get an expect attribute 365 * \param exp pointer to a valid expect 366 * \param type attribute type 367 * 368 * In case of success a valid pointer to the attribute requested is returned, 369 * on error NULL is returned and errno is set appropiately. 370 */ 371 const void *nfexp_get_attr(const struct nf_expect *exp, 372 const enum nf_expect_attr type) 373 { 374 assert(exp != NULL); 375 376 if (type >= ATTR_EXP_MAX) { 377 errno = EINVAL; 378 return NULL; 379 } 380 381 if (!test_bit(type, exp->set)) { 382 errno = ENODATA; 383 return NULL; 384 } 385 386 return get_exp_attr_array[type](exp); 387 } 388 389 /** 390 * nfexp_get_attr_u8 - get attribute of unsigned 8-bits long 391 * \param exp pointer to a valid expectation 392 * \param type attribute type 393 * 394 * Returns the value of the requested attribute, if the attribute is not 395 * set, 0 is returned. In order to check if the attribute is set or not, 396 * use nfexp_attr_is_set. 397 */ 398 uint8_t nfexp_get_attr_u8(const struct nf_expect *exp, 399 const enum nf_expect_attr type) 400 { 401 const uint8_t *ret = nfexp_get_attr(exp, type); 402 return ret == NULL ? 0 : *ret; 403 } 404 405 /** 406 * nfexp_get_attr_u16 - get attribute of unsigned 16-bits long 407 * \param exp pointer to a valid expectation 408 * \param type attribute type 409 * 410 * Returns the value of the requested attribute, if the attribute is not 411 * set, 0 is returned. In order to check if the attribute is set or not, 412 * use nfexp_attr_is_set. 413 */ 414 uint16_t nfexp_get_attr_u16(const struct nf_expect *exp, 415 const enum nf_expect_attr type) 416 { 417 const uint16_t *ret = nfexp_get_attr(exp, type); 418 return ret == NULL ? 0 : *ret; 419 } 420 421 /** 422 * nfexp_get_attr_u32 - get attribute of unsigned 32-bits long 423 * \param exp pointer to a valid expectation 424 * \param type attribute type 425 * 426 * Returns the value of the requested attribute, if the attribute is not 427 * set, 0 is returned. In order to check if the attribute is set or not, 428 * use nfexp_attr_is_set. 429 */ 430 uint32_t nfexp_get_attr_u32(const struct nf_expect *exp, 431 const enum nf_expect_attr type) 432 { 433 const uint32_t *ret = nfexp_get_attr(exp, type); 434 return ret == NULL ? 0 : *ret; 435 } 436 437 /** 438 * nfexp_attr_is_set - check if a certain attribute is set 439 * \param exp pointer to a valid expectation object 440 * \param type attribute type 441 * 442 * On error, -1 is returned and errno is set appropiately, otherwise 443 * the value of the attribute is returned. 444 */ 445 int nfexp_attr_is_set(const struct nf_expect *exp, 446 const enum nf_expect_attr type) 447 { 448 assert(exp != NULL); 449 450 if (type >= ATTR_EXP_MAX) { 451 errno = EINVAL; 452 return -1; 453 } 454 return test_bit(type, exp->set); 455 } 456 457 /** 458 * nfexp_attr_unset - unset a certain attribute 459 * \param type attribute type 460 * \param exp pointer to a valid expectation object 461 * 462 * On error, -1 is returned and errno is set appropiately, otherwise 463 * 0 is returned. 464 */ 465 int nfexp_attr_unset(struct nf_expect *exp, 466 const enum nf_expect_attr type) 467 { 468 assert(exp != NULL); 469 470 if (type >= ATTR_EXP_MAX) { 471 errno = EINVAL; 472 return -1; 473 } 474 unset_bit(type, exp->set); 475 476 return 0; 477 } 478 479 /** 480 * @} 481 */ 482 483 /** 484 * \defgroup nl Low level object to Netlink message 485 * @{ 486 */ 487 488 /** 489 * nfexp_build_expect - build a netlink message from a conntrack object 490 * \param ssh nfnetlink subsystem handler 491 * \param req buffer used to build the netlink message 492 * \param size size of the buffer passed 493 * \param type netlink message type 494 * \param flags netlink flags 495 * \param exp pointer to a conntrack object 496 * 497 * This is a low level function for those that require to be close to 498 * netlink details via libnfnetlink. If you do want to obviate the netlink 499 * details then we suggest you to use nfexp_query. 500 * 501 * On error, -1 is returned and errno is appropiately set. 502 * On success, 0 is returned. 503 */ 504 int nfexp_build_expect(struct nfnl_subsys_handle *ssh, 505 void *req, 506 size_t size, 507 uint16_t type, 508 uint16_t flags, 509 const struct nf_expect *exp) 510 { 511 assert(ssh != NULL); 512 assert(req != NULL); 513 assert(exp != NULL); 514 515 return __build_expect(ssh, req, size, type, flags, exp); 516 } 517 518 static int 519 __build_query_exp(struct nfnl_subsys_handle *ssh, 520 const enum nf_conntrack_query qt, 521 const void *data, void *buffer, unsigned int size) 522 { 523 struct nfnlhdr *req = buffer; 524 const uint8_t *family = data; 525 526 assert(ssh != NULL); 527 assert(data != NULL); 528 assert(req != NULL); 529 530 memset(req, 0, size); 531 532 switch(qt) { 533 case NFCT_Q_CREATE: 534 __build_expect(ssh, req, size, IPCTNL_MSG_EXP_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL, data); 535 break; 536 case NFCT_Q_CREATE_UPDATE: 537 __build_expect(ssh, req, size, IPCTNL_MSG_EXP_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK, data); 538 break; 539 case NFCT_Q_GET: 540 __build_expect(ssh, req, size, IPCTNL_MSG_EXP_GET, NLM_F_REQUEST|NLM_F_ACK, data); 541 break; 542 case NFCT_Q_DESTROY: 543 __build_expect(ssh, req, size, IPCTNL_MSG_EXP_DELETE, NLM_F_REQUEST|NLM_F_ACK, data); 544 break; 545 case NFCT_Q_FLUSH: 546 nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_EXP_DELETE, NLM_F_REQUEST|NLM_F_ACK); 547 break; 548 case NFCT_Q_DUMP: 549 nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_EXP_GET, NLM_F_REQUEST|NLM_F_DUMP); 550 break; 551 default: 552 errno = ENOTSUP; 553 return -1; 554 } 555 return 1; 556 } 557 558 /** 559 * nfexp_build_query - build a query in netlink message format for ctnetlink 560 * \param ssh nfnetlink subsystem handler 561 * \param qt query type 562 * \param data data required to build the query 563 * \param req buffer to build the netlink message 564 * \param size size of the buffer passed 565 * 566 * This is a low level function, use it if you want to require to work 567 * with netlink details via libnfnetlink, otherwise we suggest you to 568 * use nfexp_query. 569 * 570 * The pointer to data can be a conntrack object or the protocol family 571 * depending on the request. 572 * 573 * For query types: 574 * NFEXP_Q_CREATE 575 * NFEXP_Q_DESTROY 576 * 577 * Pass a valid pointer to an expectation object. 578 * 579 * For query types: 580 * NFEXP_Q_FLUSH 581 * NFEXP_Q_DUMP 582 * 583 * Pass a valid pointer to the protocol family (uint8_t) 584 * 585 * On success, 0 is returned. On error, -1 is returned and errno is set 586 * appropiately. 587 */ 588 int nfexp_build_query(struct nfnl_subsys_handle *ssh, 589 const enum nf_conntrack_query qt, 590 const void *data, 591 void *buffer, 592 unsigned int size) 593 { 594 return __build_query_exp(ssh, qt, data, buffer, size); 595 } 596 597 /** 598 * nfexp_parse_expect - translate a netlink message to a conntrack object 599 * \param type do the translation iif the message type is of a certain type 600 * \param nlh pointer to the netlink message 601 * \param exp pointer to the conntrack object 602 * 603 * This is a low level function, use it in case that you require to work 604 * with netlink details via libnfnetlink. Otherwise, we suggest you to 605 * use the high level API. 606 * 607 * The message types are: 608 * 609 * NFEXP_T_NEW: parse messages with new conntracks 610 * NFEXP_T_UPDATE: parse messages with conntrack updates 611 * NFEXP_T_DESTROY: parse messages with conntrack destroy 612 * NFEXP_T_ALL: all message types 613 * 614 * The message type is a flag, therefore the can be combined, ie. 615 * NFEXP_T_NEW | NFEXP_T_DESTROY to parse only new and destroy messages 616 * 617 * On error, NFEXP_T_ERROR is returned and errno is set appropiately. If 618 * the message received is not of the requested type then 0 is returned, 619 * otherwise this function returns the message type parsed. 620 */ 621 int nfexp_parse_expect(enum nf_conntrack_msg_type type, 622 const struct nlmsghdr *nlh, 623 struct nf_expect *exp) 624 { 625 unsigned int flags; 626 int len = nlh->nlmsg_len; 627 struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); 628 struct nfattr *cda[CTA_EXPECT_MAX]; 629 630 assert(nlh != NULL); 631 assert(exp != NULL); 632 633 len -= NLMSG_LENGTH(sizeof(struct nfgenmsg)); 634 if (len < 0) { 635 errno = EINVAL; 636 return NFCT_T_ERROR; 637 } 638 639 flags = __parse_expect_message_type(nlh); 640 if (!(flags & type)) 641 return 0; 642 643 nfnl_parse_attr(cda, CTA_EXPECT_MAX, NFA_DATA(nfhdr), len); 644 645 __parse_expect(nlh, cda, exp); 646 647 return flags; 648 } 649 650 /** 651 * @} 652 */ 653 654 /** 655 * \defgroup cmd Send commands to kernel-space and receive replies 656 * @{ 657 */ 658 659 /** 660 * nfexp_query - send a query to ctnetlink 661 * \param h library handler 662 * \param qt query type 663 * \param data data required to send the query 664 * 665 * On error, -1 is returned and errno is explicitely set. On success, 0 666 * is returned. 667 */ 668 int nfexp_query(struct nfct_handle *h, 669 const enum nf_conntrack_query qt, 670 const void *data) 671 { 672 const size_t size = 4096; /* enough for now */ 673 union { 674 char buffer[size]; 675 struct nfnlhdr req; 676 } u; 677 678 assert(h != NULL); 679 assert(data != NULL); 680 681 if (__build_query_exp(h->nfnlssh_exp, qt, data, &u.req, size) == -1) 682 return -1; 683 684 return nfnl_query(h->nfnlh, &u.req.nlh); 685 } 686 687 /** 688 * nfexp_send - send a query to ctnetlink 689 * \param h library handler 690 * \param qt query type 691 * \param data data required to send the query 692 * 693 * Like nfexp_query but we do not wait for the reply from ctnetlink. 694 * You can use nfexp_send() and nfexp_catch() to emulate nfexp_query(). 695 * This is particularly useful when the socket is non-blocking. 696 * 697 * On error, -1 is returned and errno is explicitely set. On success, 0 698 * is returned. 699 */ 700 int nfexp_send(struct nfct_handle *h, 701 const enum nf_conntrack_query qt, 702 const void *data) 703 { 704 const size_t size = 4096; /* enough for now */ 705 union { 706 char buffer[size]; 707 struct nfnlhdr req; 708 } u; 709 710 assert(h != NULL); 711 assert(data != NULL); 712 713 if (__build_query_exp(h->nfnlssh_exp, qt, data, &u.req, size) == -1) 714 return -1; 715 716 return nfnl_send(h->nfnlh, &u.req.nlh); 717 } 718 719 /** 720 * nfexp_catch - catch events 721 * \param h library handler 722 * 723 * This function receives the event from the kernel and it invokes the 724 * callback that was registered to this handle. 725 * 726 * On error, -1 is returned and errno is set appropiately. On success, 727 * a value greater or equal to 0 is returned indicating the callback 728 * verdict: NFCT_CB_STOP, NFCT_CB_CONTINUE or NFCT_CB_STOLEN. 729 * 730 * Beware that this function is equivalent to nfct_catch(), so it handles both 731 * conntrack and expectation events. 732 */ 733 int nfexp_catch(struct nfct_handle *h) 734 { 735 assert(h != NULL); 736 737 return nfnl_catch(h->nfnlh); 738 } 739 740 /** 741 * @} 742 */ 743 744 /** 745 * \defgroup exp Expect object handling 746 * @{ 747 */ 748 749 /** 750 * nfexp_snprintf - print a conntrack object to a buffer 751 * \param buf buffer used to build the printable conntrack 752 * \param size size of the buffer 753 * \param exp pointer to a valid expectation object 754 * \param message_type print message type (NFEXP_T_UNKNOWN, NFEXP_T_NEW,...) 755 * \param output_type print type (NFEXP_O_DEFAULT, NFEXP_O_XML, ...) 756 * \param flags extra flags for the output type (NFEXP_OF_LAYER3) 757 * 758 * If you are listening to events, probably you want to display the message 759 * type as well. In that case, set the message type parameter to any of the 760 * known existing types, ie. NFEXP_T_NEW, NFEXP_T_UPDATE, NFEXP_T_DESTROY. 761 * If you pass NFEXP_T_UNKNOWN, the message type will not be output. 762 * 763 * Currently, the output available are: 764 * - NFEXP_O_DEFAULT: default /proc-like output 765 * - NFEXP_O_XML: XML output 766 * 767 * The output flags are: 768 * - NFEXP_O_LAYER: include layer 3 information in the output, this is 769 * *only* required by NFEXP_O_DEFAULT. 770 * 771 * On error, -1 is returned and errno is set appropiately. Otherwise, 772 * 0 is returned. 773 */ 774 int nfexp_snprintf(char *buf, 775 unsigned int size, 776 const struct nf_expect *exp, 777 unsigned int msg_type, 778 unsigned int out_type, 779 unsigned int flags) 780 { 781 assert(buf != NULL); 782 assert(size > 0); 783 assert(exp != NULL); 784 785 return __snprintf_expect(buf, size, exp, msg_type, out_type, flags); 786 } 787 788 /** 789 * @} 790 */ 791