summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore9
-rw-r--r--Makefile.am2
-rwxr-xr-xautogen.sh8
-rw-r--r--configure.ac52
-rw-r--r--doxygen/Makefile.am39
-rwxr-xr-xdoxygen/build_man.sh227
-rw-r--r--doxygen/doxygen.cfg.in (renamed from doxygen.cfg.in)10
-rw-r--r--include/libnetfilter_log/libnetfilter_log.h1
-rw-r--r--libnetfilter_log.pc.in2
-rw-r--r--libnetfilter_log_libipulog.pc.in2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/libipulog_compat.c3
-rw-r--r--src/libnetfilter_log.c63
13 files changed, 394 insertions, 26 deletions
diff --git a/.gitignore b/.gitignore
index 5eaabe3..2dc0dfa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+*~
+.\#*
+\#*\#
.deps/
.libs/
Makefile
@@ -13,6 +16,8 @@ Makefile.in
/configure
/libtool
-/doxygen/
-/doxygen.cfg
+/doxygen/doxygen.cfg
+/doxygen/doxyfile.stamp
+/doxygen/man/
+/doxygen/html/
/*.pc
diff --git a/Makefile.am b/Makefile.am
index c7b86f7..46b14f9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = include src utils
+SUBDIRS = include src utils doxygen
ACLOCAL_AMFLAGS = -I m4
diff --git a/autogen.sh b/autogen.sh
index 5e1344a..93e2a23 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,4 +1,12 @@
#!/bin/sh -e
+BUILD_MAN=doxygen/build_man.sh
+
+# Allow to override build_man.sh url for local testing
+# E.g. export NFQ_URL=file:///usr/src/libnetfilter_queue
+curl ${NFQ_URL:-https://git.netfilter.org/libnetfilter_queue/plain}/$BUILD_MAN\
+ -o$BUILD_MAN
+chmod a+x $BUILD_MAN
+
autoreconf -fi
rm -Rf autom4te.cache
diff --git a/configure.ac b/configure.ac
index 85e49ed..aeb89e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,20 +1,37 @@
dnl Process this file with autoconf to create configure.
-AC_INIT([libnetfilter_log], [1.0.1])
+AC_INIT([libnetfilter_log], [1.0.2])
AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_HOST
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects
- tar-pax no-dist-gzip dist-bzip2 1.6])
+ tar-pax no-dist-gzip dist-xz 1.6])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AC_ARG_ENABLE([html-doc],
+ AS_HELP_STRING([--enable-html-doc], [Enable html documentation]),
+ [], [enable_html_doc=no])
+AM_CONDITIONAL([BUILD_HTML], [test "$enable_html_doc" = yes])
+AS_IF([test "$enable_html_doc" = yes],
+ [AC_SUBST(GEN_HTML, YES)],
+ [AC_SUBST(GEN_HTML, NO)])
+
+AC_ARG_ENABLE([man-pages],
+ AS_HELP_STRING([--disable-man-pages],
+ [Disable man page documentation]),
+ [], [enable_man_pages=yes])
+AM_CONDITIONAL([BUILD_MAN], [test "$enable_man_pages" = yes])
+AS_IF([test "$enable_man_pages" = yes],
+ [AC_SUBST(GEN_MAN, YES)],
+ [AC_SUBST(GEN_MAN, NO)])
+
AC_PROG_CC
AM_PROG_CC_C_O
-LT_INIT([disable_static])
+LT_INIT([disable-static])
AC_PROG_INSTALL
AC_PROG_LN_S
@@ -37,6 +54,27 @@ PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 1.0.2],
[HAVE_LNFCT=1], [HAVE_LNFCT=0])
AM_CONDITIONAL([BUILD_NFCT], [test "$HAVE_LNFCT" -eq 1])
+AS_IF([test "$enable_man_pages" = no -a "$enable_html_doc" = no],
+ [with_doxygen=no], [with_doxygen=yes])
+
+AS_IF([test "x$with_doxygen" != xno], [
+ AC_CHECK_PROGS([DOXYGEN], [doxygen], [""])
+ AC_CHECK_PROGS([DOT], [dot], [""])
+ AS_IF([test "x$DOT" != "x"],
+ [AC_SUBST(HAVE_DOT, YES)],
+ [AC_SUBST(HAVE_DOT, NO)])
+])
+
+AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
+AS_IF([test "x$DOXYGEN" = x], [
+ AS_IF([test "x$with_doxygen" != xno], [
+ dnl Only run doxygen Makefile if doxygen installed
+ AC_MSG_WARN([Doxygen not found - not building documentation])
+ enable_html_doc=no
+ enable_man_pages=no
+ ])
+])
+
dnl Output the makefile
AC_CONFIG_FILES([Makefile
src/Makefile
@@ -45,5 +83,11 @@ AC_CONFIG_FILES([Makefile
utils/Makefile
libnetfilter_log.pc
libnetfilter_log_libipulog.pc
- doxygen.cfg])
+ doxygen/Makefile
+ doxygen/doxygen.cfg])
AC_OUTPUT
+
+echo "
+libnetfilter_log configuration:
+man pages: ${enable_man_pages}
+html docs: ${enable_html_doc}"
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
new file mode 100644
index 0000000..582db4e
--- /dev/null
+++ b/doxygen/Makefile.am
@@ -0,0 +1,39 @@
+if HAVE_DOXYGEN
+
+doc_srcs = $(top_srcdir)/src/libnetfilter_log.c\
+ $(top_srcdir)/src/nlmsg.c\
+ $(top_srcdir)/src/libipulog_compat.c
+
+doxyfile.stamp: $(doc_srcs) Makefile
+ rm -rf html man
+ doxygen doxygen.cfg >/dev/null
+
+if BUILD_MAN
+ $(abs_top_srcdir)/doxygen/build_man.sh
+endif
+
+ touch doxyfile.stamp
+
+CLEANFILES = doxyfile.stamp
+
+all-local: doxyfile.stamp
+clean-local:
+ rm -rf man html
+install-data-local:
+if BUILD_MAN
+ mkdir -p $(DESTDIR)$(mandir)/man3
+ cp --no-dereference --preserve=links,mode,timestamps man/man3/*.3\
+ $(DESTDIR)$(mandir)/man3/
+endif
+if BUILD_HTML
+ mkdir -p $(DESTDIR)$(htmldir)
+ cp --no-dereference --preserve=links,mode,timestamps html/*\
+ $(DESTDIR)$(htmldir)
+endif
+
+# make distcheck needs uninstall-local
+uninstall-local:
+ rm -rf $(DESTDIR)$(mandir) man html doxyfile.stamp $(DESTDIR)$(htmldir)
+endif
+
+EXTRA_DIST = build_man.sh
diff --git a/doxygen/build_man.sh b/doxygen/build_man.sh
new file mode 100755
index 0000000..852c7b8
--- /dev/null
+++ b/doxygen/build_man.sh
@@ -0,0 +1,227 @@
+#!/bin/bash -p
+
+# Script to process man pages output by doxygen.
+# We need to use bash for its associative array facility.
+# (`bash -p` prevents import of functions from the environment).
+
+declare -A renamed_page
+
+main(){
+ set -e
+ cd man/man3; rm -f _*
+ count_real_pages
+ rename_real_pages
+ make_symlinks
+ post_process
+}
+
+count_real_pages(){
+ page_count=0
+ #
+ # Count "real" man pages (i.e. not generated by MAN_LINKS)
+ # MAN_LINKS pages are 1-liners starting .so
+ # Method: list files in descending order of size,
+ # looking for the first 1-liner
+ #
+ for i in $(ls -S)
+ do head -n1 $i | grep -E -q '^\.so' && break
+ page_count=$(($page_count + 1))
+ done
+ first_link=$(($page_count + 1))
+}
+
+rename_real_pages(){
+ for i in $(ls -S | head -n$page_count)
+ do for j in $(ls -S | tail -n+$first_link)
+ do grep -E -q $i$ $j && break
+ done
+ mv -f $i $j
+ renamed_page[$i]=$j
+ done
+}
+
+make_symlinks(){
+ for j in $(ls -S | tail -n+$first_link)
+ do ln -sf ${renamed_page[$(cat $j | cut -f2 -d/)]} $j
+ done
+}
+
+post_process(){
+ make_temp_files
+ #
+ # DIAGNOSTIC / DEVELOPMENT CODE
+ # set -x and restrict processing to keep_me: un-comment to activate
+ # Change keep_me as required
+ #
+ #keep_me=nfq_icmp_get_hdr.3;\
+ #do_diagnostics;\
+ #
+ # Work through the "real" man pages
+ for target in $(ls -S | head -n$page_count)
+ do mygrep "^\\.SH \"Function Documentation" $target
+ # Next file if this isn't a function page
+ [ $linnum -ne 0 ] || continue
+
+ del_modules
+ del_bogus_synopsis
+ fix_name_line
+ move_synopsis
+ del_empty_det_desc
+ del_def_at_lines
+ fix_double_blanks
+
+ # Fix rendering of verbatim "\n" (in code snippets)
+ sed -i 's/\\n/\\\\n/' $target
+
+ done
+
+ remove_temp_files
+}
+
+fix_double_blanks(){
+ linnum=1
+ #
+ # Older versions of man display a blank line on encountering "\fB\fP";
+ # newer versions of man do not.
+ # doxygen emits "\fB\fP" on seeing "\par" on a line by itself.
+ # "\par" gives us double-spacing in the web doc, which we want, but double-
+ # spacing looks odd in a man page so remove "\fB\fP".
+ #
+ while [ $linnum -ne 0 ]
+ do mygrep \\\\fB\\\\fP $target
+ [ $linnum -eq 0 ] || delete_lines $linnum $linnum
+ done
+}
+
+del_def_at_lines(){
+ linnum=1
+ while [ $linnum -ne 0 ]
+ do mygrep "^Definition at line [[:digit:]]* of file" $target
+ [ $linnum -eq 0 ] || delete_lines $(($linnum - 1)) $linnum
+ done
+}
+
+# Only invoked if you un-comment the 2 diagnostic / development lines above
+do_diagnostics(){
+ mv $keep_me xxx
+ rm *.3
+ mv xxx $keep_me
+ page_count=1
+ set -x
+}
+
+del_empty_det_desc(){
+ mygrep "^\\.SH \"Function Documentation" $target
+ i=$linnum
+ mygrep "^\\.SH \"Detailed Description" $target
+ [ $linnum -ne 0 ] || return 0
+ [ $(($i - $linnum)) -eq 3 ] || return 0
+ # A 1-line Detailed Description is also 3 lines long,
+ # but the 3rd line is not empty
+ i=$(($i -1))
+ [ $(tail -n+$i $target | head -n1 | wc -c) -le 2 ] || return 0
+ delete_lines $linnum $i
+}
+
+move_synopsis(){
+ mygrep "SH SYNOPSIS" $target
+ [ $linnum -ne 0 ] || return 0
+ i=$linnum
+ # If this is a doxygen-created synopsis, leave it.
+ # (We haven't inserted our own one in the source yet)
+ mygrep "^\\.SS \"Functions" $target
+ [ $i -gt $linnum ] || return 0
+
+ mygrep "^\\.SH \"Function Documentation" $target
+ j=$(($linnum - 1))
+ head -n$(($j - 1)) $target | tail -n$(($linnum - $i - 1)) >$fileC
+ delete_lines $i $j
+ mygrep "^\\.SS \"Functions" $target
+ head -n$(($linnum - 1)) $target >$fileA
+ tail -n+$(($linnum + 1)) $target >$fileB
+ cat $fileA $fileC $fileB >$target
+}
+
+fix_name_line(){
+ all_funcs=""
+
+ # Search a shortened version of the page in case there are .RI lines later
+ mygrep "^\\.SH \"Function Documentation" $target
+ head -n$linnum $target >$fileC
+
+ while :
+ do mygrep ^\\.RI $fileC
+ [ $linnum -ne 0 ] || break
+ # Discard this entry
+ tail -n+$(($linnum + 1)) $fileC >$fileB
+ cp $fileB $fileC
+
+ func=$(cat $fileG | cut -f2 -d\\ | cut -c3-)
+ [ -z "$all_funcs" ] && all_funcs=$func ||\
+ all_funcs="$all_funcs, $func"
+ done
+ # For now, assume name is at line 5
+ head -n4 $target >$fileA
+ desc=$(head -n5 $target | tail -n1 | cut -f3- -d" ")
+ tail -n+6 $target >$fileB
+ cat $fileA >$target
+ echo "$all_funcs \\- $desc" >>$target
+ cat $fileB >>$target
+}
+
+del_modules(){
+ mygrep "^\.SS \"Modules" $target
+ [ $linnum -ne 0 ] || return 0
+ i=$linnum
+ mygrep "^\\.SS \"Functions" $target
+ delete_lines $i $(($linnum - 1))
+}
+
+del_bogus_synopsis(){
+ mygrep "SH SYNOPSIS" $target
+ #
+ # doxygen 1.8.20 inserts its own SYNOPSIS line but there is no mention
+ # in the documentation or git log what to do with it.
+ # So get rid of it
+ #
+ [ $linnum -ne 0 ] || return 0
+ i=$linnum
+ # Look for the next one
+ tail -n+$(($i + 1)) $target >$fileC;\
+ mygrep "SH SYNOPSIS" $fileC
+ [ $linnum -ne 0 ] || return 0
+
+ mygrep "^\\.SS \"Functions" $target
+ delete_lines $i $(($linnum - 1))
+}
+
+# Delete lines $1 through $2 from $target
+delete_lines(){
+ head -n$(($1 - 1)) $target >$fileA
+ tail -n+$(($2 +1)) $target >$fileB
+ cat $fileA $fileB >$target
+}
+
+mygrep(){
+ set +e
+ grep -En "$1" $2 2>/dev/null >$fileH
+ [ $? -ne 0 ] && linnum=0 ||\
+ { head -n1 $fileH >$fileG; linnum=$(cat $fileG | cut -f1 -d:); }
+ set -e
+}
+
+make_temp_files(){
+ temps="A B C G H"
+ for i in $temps
+ do declare -g file$i=$(mktemp)
+ done
+}
+
+remove_temp_files(){
+ for i in $temps
+ do j=file$i
+ rm ${!j}
+ done
+}
+
+main
diff --git a/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index dc2fddb..ff67c36 100644
--- a/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -1,12 +1,11 @@
# Difference with default Doxyfile 1.8.20
PROJECT_NAME = @PACKAGE@
PROJECT_NUMBER = @VERSION@
-OUTPUT_DIRECTORY = doxygen
ABBREVIATE_BRIEF =
FULL_PATH_NAMES = NO
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
-INPUT = .
+INPUT = @abs_top_srcdir@/src
FILE_PATTERNS = *.c
RECURSIVE = YES
EXCLUDE_SYMBOLS = nflog_g_handle \
@@ -18,7 +17,8 @@ SOURCE_BROWSER = YES
ALPHABETICAL_INDEX = NO
GENERATE_LATEX = NO
LATEX_CMD_NAME = latex
-GENERATE_MAN = YES
-HAVE_DOT = YES
-DOT_TRANSPARENT = YES
+GENERATE_MAN = @GEN_MAN@
+GENERATE_HTML = @GEN_HTML@
+MAN_LINKS = YES
+HAVE_DOT = @HAVE_DOT@
SEARCHENGINE = NO
diff --git a/include/libnetfilter_log/libnetfilter_log.h b/include/libnetfilter_log/libnetfilter_log.h
index 16c4748..ee9121f 100644
--- a/include/libnetfilter_log/libnetfilter_log.h
+++ b/include/libnetfilter_log/libnetfilter_log.h
@@ -82,6 +82,7 @@ enum {
NFLOG_XML_PHYSDEV = (1 << 4),
NFLOG_XML_PAYLOAD = (1 << 5),
NFLOG_XML_TIME = (1 << 6),
+ NFLOG_XML_CTID = (1 << 7),
NFLOG_XML_ALL = ~0U,
};
diff --git a/libnetfilter_log.pc.in b/libnetfilter_log.pc.in
index 9dbed77..14d16ed 100644
--- a/libnetfilter_log.pc.in
+++ b/libnetfilter_log.pc.in
@@ -9,7 +9,7 @@ Name: libnetfilter_log
Description: Netfilter userspace packet logging library
URL: http://netfilter.org/projects/libnetfilter_log/
Version: @VERSION@
-Requires.private: libnfnetlink >= @LIBNFNETLINK_MIN_VERSION@,
+Requires.private: libnfnetlink >= @LIBNFNETLINK_MIN_VERSION@, \
libmnl >= @LIBMNL_MIN_VERSION@
Conflicts:
Libs: -L${libdir} -lnetfilter_log
diff --git a/libnetfilter_log_libipulog.pc.in b/libnetfilter_log_libipulog.pc.in
index 1b7d17a..3596790 100644
--- a/libnetfilter_log_libipulog.pc.in
+++ b/libnetfilter_log_libipulog.pc.in
@@ -9,7 +9,7 @@ Name: libnetfilter_log_libipulog
Description: Netfilter ULOG userspace compat library
URL: http://netfilter.org/projects/libnetfilter_log/
Version: @VERSION@
-Requires.private: libnetfilter_log >= @VERSION@,
+Requires.private: libnetfilter_log >= @VERSION@, \
libnfnetlink >= @LIBNFNETLINK_MIN_VERSION@
Conflicts:
Libs: -L${libdir} -lnetfilter_log_libipulog
diff --git a/src/Makefile.am b/src/Makefile.am
index 203ca0c..c0f5286 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@
# set age to 0.
# </snippet>
#
-LIBVERSION = 2:0:1
+LIBVERSION = 3:0:2
IPULOG_LIBVERSION = 1:0:0
include ${top_srcdir}/Make_global.am
diff --git a/src/libipulog_compat.c b/src/libipulog_compat.c
index a0de3cb..4efa501 100644
--- a/src/libipulog_compat.c
+++ b/src/libipulog_compat.c
@@ -133,10 +133,9 @@ ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h,
struct nfulnl_msg_packet_hdr *hdr;
if (!h->last_nlh) {
- printf("first\n");
nlh = nfnl_get_msg_first(nflog_nfnlh(h->nfulh), buf, len);
}else {
-next_msg: printf("next\n");
+next_msg:
nlh = nfnl_get_msg_next(nflog_nfnlh(h->nfulh), buf, len);
}
h->last_nlh = nlh;
diff --git a/src/libnetfilter_log.c b/src/libnetfilter_log.c
index 27a6a2d..339c961 100644
--- a/src/libnetfilter_log.c
+++ b/src/libnetfilter_log.c
@@ -33,6 +33,9 @@
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_log/libnetfilter_log.h>
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
/**
* \mainpage
*
@@ -158,11 +161,6 @@ static int __nflog_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
return gh->cb(gh, nfmsg, &nfldata, gh->data);
}
-static struct nfnl_callback pkt_cb = {
- .call = &__nflog_rcv_pkt,
- .attr_count = NFULA_MAX,
-};
-
/* public interface */
struct nfnl_handle *nflog_nfnlh(struct nflog_handle *h)
@@ -252,6 +250,10 @@ struct nflog_handle *nflog_open_nfnl(struct nfnl_handle *nfnlh)
{
struct nflog_handle *h;
int err;
+ struct nfnl_callback pkt_cb = {
+ .call = &__nflog_rcv_pkt,
+ .attr_count = NFULA_MAX,
+ };
h = calloc(1, sizeof(*h));
if (!h)
@@ -554,7 +556,7 @@ int nflog_set_mode(struct nflog_g_handle *gh,
* \param gh Netfilter log group handle obtained by call to nflog_bind_group().
* \param timeout Time to wait until the log buffer is pushed to userspace
*
- * This function allows to set the maximum time that nflog waits until it
+ * This function allows one to set the maximum time that nflog waits until it
* pushes the log buffer to userspace if no new logged packets have occured.
* Basically, nflog implements a buffer to reduce the computational cost
* of delivering the log message to userspace.
@@ -652,6 +654,7 @@ int nflog_set_nlbufsiz(struct nflog_g_handle *gh, uint32_t nlbufsiz)
*
* - NFULNL_CFG_F_SEQ: This enables local nflog sequence numbering.
* - NFULNL_CFG_F_SEQ_GLOBAL: This enables global nflog sequence numbering.
+ * - NFULNL_CFG_F_CONNTRACK: This enables to acquire related conntrack.
*
* \return 0 on success, -1 on failure with \b errno set.
* \par Errors
@@ -975,6 +978,38 @@ int nflog_get_seq_global(struct nflog_data *nfad, uint32_t *seq)
}
/**
+ * nflog_get_ct_id - get the conntrack id
+ * \param nfad Netlink packet data handle passed to callback function
+ * \param id conntrack id, if the function returns zero
+ *
+ * You must enable this via nflog_set_flags().
+ *
+ * \return 0 on success or -1 if conntrack itself or its id was unavailable
+ */
+int nflog_get_ctid(struct nflog_data *nfad, uint32_t *id)
+{
+ struct nlattr *cta = (struct nlattr *)nfad->nfa[NFULA_CT - 1];
+ struct nlattr *attr, *ida = NULL;
+
+ if (!cta)
+ return -1;
+
+ mnl_attr_for_each_nested(attr, cta) {
+ if (mnl_attr_get_type(attr) == CTA_ID) {
+ ida = attr;
+ break;
+ }
+ }
+
+ if (!ida || mnl_attr_validate(ida, MNL_TYPE_U32) < 0)
+ return -1;
+
+ *id = ntohl(mnl_attr_get_u32(ida));
+
+ return 0;
+}
+
+/**
* @}
*/
@@ -1016,6 +1051,7 @@ do { \
* - NFLOG_XML_PHYSDEV: include the physical device information
* - NFLOG_XML_PAYLOAD: include the payload (in hexadecimal)
* - NFLOG_XML_TIME: include the timestamp
+ * - NFLOG_XML_CTID: include conntrack id
* - NFLOG_XML_ALL: include all the logging information (all flags set)
*
* You can combine these flags with a bitwise OR.
@@ -1028,10 +1064,10 @@ do { \
*/
int nflog_snprintf_xml(char *buf, size_t rem, struct nflog_data *tb, int flags)
{
- struct nfulnl_msg_packet_hdr *ph;
- struct nfulnl_msg_packet_hw *hwph;
- uint32_t mark, ifi;
int size, offset = 0, len = 0, ret;
+ struct nfulnl_msg_packet_hw *hwph;
+ struct nfulnl_msg_packet_hdr *ph;
+ uint32_t mark, ifi, ctid;
char *data;
size = snprintf(buf + offset, rem, "<log>");
@@ -1150,6 +1186,15 @@ int nflog_snprintf_xml(char *buf, size_t rem, struct nflog_data *tb, int flags)
SNPRINTF_FAILURE(size, rem, offset, len);
}
+ if (flags & NFLOG_XML_CTID) {
+ ret = nflog_get_ctid(tb, &ctid);
+ if (ret >= 0) {
+ size = snprintf(buf + offset, rem,
+ "<ctid>%u</ctid>", ctid);
+ SNPRINTF_FAILURE(size, rem, offset, len);
+ }
+ }
+
ret = nflog_get_payload(tb, &data);
if (ret >= 0 && (flags & NFLOG_XML_PAYLOAD)) {
int i;