summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--configure.ac55
-rw-r--r--doxygen/Makefile.am107
-rwxr-xr-xdoxygen/build_man.sh323
-rw-r--r--doxygen/doxygen.cfg.in (renamed from doxygen.cfg.in)8
-rw-r--r--examples/nf-queue.c54
-rw-r--r--include/libnetfilter_queue/libnetfilter_queue.h9
-rw-r--r--include/libnetfilter_queue/linux_nfnetlink_queue.h6
-rw-r--r--include/libnetfilter_queue/pktbuff.h5
-rw-r--r--include/linux/netfilter/nfnetlink_queue.h4
-rw-r--r--src/extra/checksum.c1
-rw-r--r--src/extra/icmp.c9
-rw-r--r--src/extra/ipv4.c21
-rw-r--r--src/extra/ipv6.c18
-rw-r--r--src/extra/pktbuff.c153
-rw-r--r--src/extra/tcp.c21
-rw-r--r--src/extra/udp.c21
-rw-r--r--src/libnetfilter_queue.c67
-rw-r--r--src/nlmsg.c88
-rw-r--r--utils/nfqnl_test.c1
20 files changed, 820 insertions, 156 deletions
diff --git a/.gitignore b/.gitignore
index 525628e..ae3e740 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,7 +15,10 @@ Makefile.in
/libtool
/stamp-h1
-/doxygen.cfg
+/doxygen/doxygen.cfg
/libnetfilter_queue.pc
/examples/nf-queue
+/doxygen/doxyfile.stamp
+/doxygen/html/
+/doxygen/man/
diff --git a/configure.ac b/configure.ac
index bdbee98..7359fba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,12 +7,28 @@ AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
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
AC_DISABLE_STATIC
@@ -29,19 +45,11 @@ dnl Dependencies
PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 0.0.41])
PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
-dnl Output the makefiles
-AC_CONFIG_FILES([Makefile src/Makefile utils/Makefile examples/Makefile
- libnetfilter_queue.pc doxygen.cfg
- include/Makefile include/libnetfilter_queue/Makefile
- doxygen/Makefile
- include/linux/Makefile include/linux/netfilter/Makefile])
-
-AC_ARG_WITH([doxygen], [AS_HELP_STRING([--with-doxygen],
- [create doxygen documentation])],
- [with_doxygen="$withval"], [with_doxygen=yes])
+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([DOXYGEN], [doxygen], [""])
AC_CHECK_PROGS([DOT], [dot], [""])
AS_IF([test "x$DOT" != "x"],
[AC_SUBST(HAVE_DOT, YES)],
@@ -50,11 +58,28 @@ AS_IF([test "x$with_doxygen" != xno], [
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
AS_IF([test "x$DOXYGEN" = x], [
- dnl Only run doxygen Makefile if doxygen installed
- AC_MSG_WARN([Doxygen not found - continuing without Doxygen support])
+ 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 Warn user if html docs will be missing diagrams
+ AS_IF([test "$enable_html_doc" = yes -a -z "$DOT"],
+ AC_MSG_WARN([Dot not found - install graphviz to get interactive diagrams in HTML]))
])
+
+dnl Output the makefiles
+AC_CONFIG_FILES([Makefile src/Makefile utils/Makefile examples/Makefile
+ libnetfilter_queue.pc
+ include/Makefile include/libnetfilter_queue/Makefile
+ doxygen/Makefile doxygen/doxygen.cfg
+ include/linux/Makefile include/linux/netfilter/Makefile])
+
AC_OUTPUT
echo "
libnetfilter_queue configuration:
- doxygen: ${with_doxygen}"
+man pages: ${enable_man_pages}
+html docs: ${enable_html_doc}"
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index b4268a5..68be963 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -1,83 +1,22 @@
if HAVE_DOXYGEN
-# Be sure to add new source files to this table
-doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c \
- $(top_srcdir)/src/nlmsg.c \
- $(top_srcdir)/src/extra/checksum.c \
- $(top_srcdir)/src/extra/ipv6.c \
- $(top_srcdir)/src/extra/ipv4.c \
- $(top_srcdir)/src/extra/tcp.c \
- $(top_srcdir)/src/extra/udp.c \
- $(top_srcdir)/src/extra/icmp.c \
- $(top_srcdir)/src/extra/pktbuff.c
-
-doxyfile.stamp: $(doc_srcs) Makefile.am
+doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c\
+ $(top_srcdir)/src/nlmsg.c\
+ $(top_srcdir)/src/extra/checksum.c\
+ $(top_srcdir)/src/extra/ipv4.c\
+ $(top_srcdir)/src/extra/pktbuff.c\
+ $(top_srcdir)/src/extra/ipv6.c\
+ $(top_srcdir)/src/extra/tcp.c\
+ $(top_srcdir)/src/extra/udp.c\
+ $(top_srcdir)/src/extra/icmp.c
+
+doxyfile.stamp: $(doc_srcs) Makefile build_man.sh
rm -rf html man
+ doxygen doxygen.cfg >/dev/null
-# Test for running under make distcheck.
-# If so, sibling src directory will be empty:
-# move it out of the way and symlink the real one while we run doxygen.
- [ -f ../src/Makefile.in ] || \
-{ set -x; cd ..; mv src src.distcheck; ln -s $(top_srcdir)/src; }
-
- cd ..; doxygen doxygen.cfg >/dev/null
-
- [ ! -d ../src.distcheck ] || \
-{ set -x; cd ..; rm src; mv src.distcheck src; }
-
-# Keep this command up to date after adding new functions and source files.
-# The command has to be a single line so the functions work
-# (hence ";\" at the end of every line but the last).
- main() { set -e; cd man/man3; rm -f _*;\
-setgroup LibrarySetup nfq_open;\
- add2group nfq_close nfq_bind_pf nfq_unbind_pf;\
-setgroup Parsing nfq_get_msg_packet_hdr;\
- add2group nfq_get_nfmark nfq_get_timestamp nfq_get_indev nfq_get_physindev;\
- add2group nfq_get_outdev nfq_get_physoutdev nfq_get_indev_name;\
- add2group nfq_get_physindev_name nfq_get_outdev_name;\
- add2group nfq_get_physoutdev_name nfq_get_packet_hw;\
- add2group nfq_get_skbinfo;\
- add2group nfq_get_uid nfq_get_gid;\
- add2group nfq_get_secctx nfq_get_payload;\
-setgroup Queue nfq_fd;\
- add2group nfq_create_queue nfq_destroy_queue nfq_handle_packet nfq_set_mode;\
- add2group nfq_set_queue_flags nfq_set_queue_maxlen nfq_set_verdict;\
- add2group nfq_set_verdict2 nfq_set_verdict_batch;\
- add2group nfq_set_verdict_batch2 nfq_set_verdict_mark;\
-setgroup ipv4 nfq_ip_get_hdr;\
- add2group nfq_ip_set_transport_header nfq_ip_mangle nfq_ip_snprintf;\
- setgroup ip_internals nfq_ip_set_checksum;\
-setgroup ipv6 nfq_ip6_get_hdr;\
- add2group nfq_ip6_set_transport_header nfq_ip6_mangle nfq_ip6_snprintf;\
-setgroup nfq_cfg nfq_nlmsg_cfg_put_cmd;\
- add2group nfq_nlmsg_cfg_put_params nfq_nlmsg_cfg_put_qmaxlen;\
-setgroup nfq_verd nfq_nlmsg_verdict_put;\
- add2group nfq_nlmsg_verdict_put_mark nfq_nlmsg_verdict_put_pkt;\
-setgroup nlmsg nfq_nlmsg_parse;\
- add2group nfq_nlmsg_put;\
-setgroup pktbuff pktb_alloc;\
- add2group pktb_data pktb_len pktb_mangle pktb_mangled;\
- add2group pktb_free;\
- setgroup otherfns pktb_tailroom;\
- add2group pktb_mac_header pktb_network_header pktb_transport_header;\
- setgroup uselessfns pktb_push;\
- add2group pktb_pull pktb_put pktb_trim;\
-setgroup tcp nfq_tcp_get_hdr;\
- add2group nfq_tcp_get_payload nfq_tcp_get_payload_len;\
- add2group nfq_tcp_snprintf nfq_tcp_mangle_ipv4 nfq_tcp_mangle_ipv6;\
- setgroup tcp_internals nfq_tcp_compute_checksum_ipv4;\
- add2group nfq_tcp_compute_checksum_ipv6;\
-setgroup udp nfq_udp_get_hdr;\
- add2group nfq_udp_get_payload nfq_udp_get_payload_len;\
- add2group nfq_udp_mangle_ipv4 nfq_udp_mangle_ipv6 nfq_udp_snprintf;\
- setgroup udp_internals nfq_udp_compute_checksum_ipv4;\
- add2group nfq_udp_compute_checksum_ipv6;\
-setgroup Printing nfq_snprintf_xml;\
-setgroup icmp nfq_icmp_get_hdr;\
-};\
-setgroup() { mv $$1.3 $$2.3; BASE=$$2; };\
-add2group() { for i in $$@; do ln -sf $$BASE.3 $$i.3; done; };\
-main
+if BUILD_MAN
+ $(abs_top_srcdir)/doxygen/build_man.sh libnetfilter_queue libnetfilter_queue.c
+endif
touch doxyfile.stamp
@@ -85,12 +24,22 @@ CLEANFILES = doxyfile.stamp
all-local: doxyfile.stamp
clean-local:
- rm -rf $(top_srcdir)/doxygen/man $(top_srcdir)/doxygen/html
+ 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/
+ 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 -r $(DESTDIR)$(mandir) man html doxyfile.stamp
+ 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..7eab8fa
--- /dev/null
+++ b/doxygen/build_man.sh
@@ -0,0 +1,323 @@
+#!/bin/sh
+[ -n "$BASH" ] || exec bash -p $0 $@
+
+# 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).
+# Args: none or 2 being man7 page name & relative path of source with \mainpage
+
+declare -A renamed_page
+
+main(){
+ set -e
+ pushd man/man3 >/dev/null; 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
+
+ [ $# -ne 2 ] || make_man7 $@
+
+ remove_temp_files
+}
+
+make_man7(){
+ popd >/dev/null
+ target=$(grep -Ew INPUT doxygen.cfg | rev | cut -f1 -d' ' | rev)/$2
+ mypath=$(dirname $0)
+
+ # Build up temporary source in temp.c
+ # (doxygen only makes man pages from .c files).
+ mygrep \\\\mainpage $target
+ tail -n+$((linnum-1)) $target | head -n1 >temp.c
+ echo " * \\defgroup $1 $1 overview" >>temp.c
+ tail -n+$((linnum+1)) $target >$fileA
+ linnum=$(grep -En '\*/' $fileA | head -n1 | cut -d: -f1)
+ head -n$((linnum - 1)) $fileA >> temp.c
+
+ echo ' */' >> temp.c
+ cat >> temp.c <<////
+
+ /**
+ * @{
+ *
+ * $1 - DELETE_ME
+ */
+int $1(void)
+{
+ return 0;
+}
+/**
+ * @}
+ */
+////
+
+ # Create temporary doxygen config in fileC
+ cat /dev/null >$fileC
+ for i in \
+ PROJECT_NAME \
+ PROJECT_NUMBER \
+ ABBREVIATE_BRIEF \
+ FULL_PATH_NAMES \
+ TAB_SIZE \
+ OPTIMIZE_OUTPUT_FOR_C \
+ EXAMPLE_PATTERNS \
+ ALPHABETICAL_INDEX \
+ SEARCHENGINE \
+ GENERATE_LATEX \
+ ; do grep -Ew $i doxygen.cfg >>$fileC; done
+ cat >>$fileC <<////
+INPUT = temp.c
+GENERATE_HTML = NO
+GENERATE_MAN = YES
+MAN_EXTENSION = .7
+////
+
+ doxygen $fileC >/dev/null
+
+ # Remove SYNOPSIS line if there is one
+ target=man/man7/$1.7
+ mygrep "SH SYNOPSIS" $target
+ [ $linnum -eq 0 ] || delete_lines $linnum $((linnum+1))
+
+ # doxygen 1.8.9.1 and possibly newer run the first para into NAME
+ # (i.e. in this unusual group). There won't be a SYNOPSIS when this happens
+ if grep -Eq "overview$1" $target; then
+ head -n2 temp.c >$fileA
+ cat >>$fileA <<////
+ * \\manonly
+.PP
+.SH "Detailed Description"
+.PP
+\\endmanonly
+////
+ tail -n+3 temp.c >>$fileA
+ cat $fileA >temp.c
+ doxygen $fileC >/dev/null
+ fi
+
+ # Insert top-level "See also" of man7 page in all real man3 pages
+ for target in $(find man/man3 -type f)
+ do mygrep "Detailed Description" $target
+ [ $linnum -ne 0 ] || mygrep "Function Documentation" $target
+ [ $linnum -ne 0 ] || { echo "NO HEADER IN $target" >&2; continue; }
+ head -n$((linnum-1)) $target >$fileA
+ cat >>$fileA <<////
+.SH "See also"
+\\fB${1}\\fP(7)
+////
+ tail -n+$linnum $target >>$fileA
+ cp $fileA $target
+ done
+
+ rm temp.c
+}
+
+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 (\\fB)?[[:digit:]]*(\\fP)? 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 4c16e3e..97174ff 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 = EXPORT_SYMBOL \
@@ -22,6 +21,7 @@ ALPHABETICAL_INDEX = NO
SEARCHENGINE = NO
GENERATE_LATEX = NO
LATEX_CMD_NAME = latex
-GENERATE_MAN = YES
+GENERATE_MAN = @GEN_MAN@
+GENERATE_HTML = @GEN_HTML@
+MAN_LINKS = YES
HAVE_DOT = @HAVE_DOT@
-DOT_TRANSPARENT = YES
diff --git a/examples/nf-queue.c b/examples/nf-queue.c
index 3da2c24..1ae52e4 100644
--- a/examples/nf-queue.c
+++ b/examples/nf-queue.c
@@ -15,7 +15,7 @@
#include <libnetfilter_queue/libnetfilter_queue.h>
-/* only for NFQA_CT, not needed otherwise: */
+/* NFQA_CT requires CTA_* attributes defined in nfnetlink_conntrack.h */
#include <linux/netfilter/nfnetlink_conntrack.h>
static struct mnl_socket *nl;
@@ -54,6 +54,9 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data)
struct nfgenmsg *nfg;
uint16_t plen;
+ /* Parse netlink message received from the kernel, the array of
+ * attributes is set up to store metadata and the actual packet.
+ */
if (nfq_nlmsg_parse(nlh, attr) < 0) {
perror("problems parsing");
return MNL_CB_ERROR;
@@ -66,13 +69,30 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_ERROR;
}
+ /* Access packet metadata, which provides unique packet ID, hook number
+ * and ethertype. See struct nfqnl_msg_packet_hdr for details.
+ */
ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]);
+ /* Access actual packet data length. */
plen = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]);
+
+ /* Access actual packet data */
/* void *payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]); */
+ /* Fetch metadata flags, possible flags values are:
+ *
+ * - NFQA_SKB_CSUMNOTREADY:
+ * Kernel performed partial checksum validation, see CHECKSUM_PARTIAL.
+ * - NFQA_SKB_CSUM_NOTVERIFIED:
+ * Kernel already verified checksum.
+ * - NFQA_SKB_GSO:
+ * Not the original packet received from the wire. Kernel has
+ * aggregated several packets into one single packet via GSO.
+ */
skbinfo = attr[NFQA_SKB_INFO] ? ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])) : 0;
+ /* Kernel has truncated the packet, fetch original packet length. */
if (attr[NFQA_CAP_LEN]) {
uint32_t orig_len = ntohl(mnl_attr_get_u32(attr[NFQA_CAP_LEN]));
if (orig_len != plen)
@@ -86,6 +106,25 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data)
printf("packet received (id=%u hw=0x%04x hook=%u, payload len %u",
id, ntohs(ph->hw_protocol), ph->hook, plen);
+ /* Fetch ethernet destination address. */
+ if (attr[NFQA_HWADDR]) {
+ struct nfqnl_msg_packet_hw *hw = mnl_attr_get_payload(attr[NFQA_HWADDR]);
+ unsigned int hwlen = ntohs(hw->hw_addrlen);
+ const unsigned char *addr = hw->hw_addr;
+ unsigned int i;
+
+ printf(", hwaddr %02x", addr[0]);
+ for (i = 1; i < hwlen; i++) {
+ if (i >= sizeof(hw->hw_addr)) {
+ printf("[truncated]");
+ break;
+ }
+ printf(":%02x", (unsigned char)addr[i]);
+ }
+
+ printf(" len %u", hwlen);
+ }
+
/*
* ip/tcp checksums are not yet valid, e.g. due to GRO/GSO.
* The application should behave as if the checksums are correct.
@@ -117,6 +156,9 @@ int main(int argc, char *argv[])
}
queue_num = atoi(argv[1]);
+ /*
+ * Set up netlink socket to communicate with the netfilter subsystem.
+ */
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
@@ -135,6 +177,10 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
+ /* Configure the pipeline between kernel and userspace, build and send
+ * a netlink message to specify queue number to bind to. Your ruleset
+ * has to use this queue number to deliver packets to userspace.
+ */
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND);
@@ -143,6 +189,9 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
+ /* Build and send a netlink message to specify how many bytes are
+ * copied from kernel to userspace for this queue.
+ */
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff);
@@ -161,6 +210,9 @@ int main(int argc, char *argv[])
ret = 1;
mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &ret, sizeof(int));
+ /* Loop forever on packets received from the kernel and run the
+ * callback handler.
+ */
for (;;) {
ret = mnl_socket_recvfrom(nl, buf, sizeof_buf);
if (ret == -1) {
diff --git a/include/libnetfilter_queue/libnetfilter_queue.h b/include/libnetfilter_queue/libnetfilter_queue.h
index a19122f..f7e68d8 100644
--- a/include/libnetfilter_queue/libnetfilter_queue.h
+++ b/include/libnetfilter_queue/libnetfilter_queue.h
@@ -3,9 +3,9 @@
* (C) 2005 by Harald Welte <laforge@gnumonks.org>
*
*
- * Changelog :
+ * Changelog :
* (2005/08/11) added parsing function (Eric Leblond <regit@inl.fr>)
- *
+ *
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
@@ -82,7 +82,7 @@ extern int nfq_set_verdict_batch2(struct nfq_q_handle *qh,
uint32_t mark);
extern __attribute__((deprecated))
-int nfq_set_verdict_mark(struct nfq_q_handle *qh,
+int nfq_set_verdict_mark(struct nfq_q_handle *qh,
uint32_t id,
uint32_t verdict,
uint32_t mark,
@@ -111,7 +111,7 @@ extern int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata);
extern int nfq_get_indev_name(struct nlif_handle *nlif_handle,
struct nfq_data *nfad, char *name);
extern int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
- struct nfq_data *nfad, char *name);
+ struct nfq_data *nfad, char *name);
extern int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
struct nfq_data *nfad, char *name);
extern int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle,
@@ -151,6 +151,7 @@ void nfq_nlmsg_verdict_put_pkt(struct nlmsghdr *nlh, const void *pkt, uint32_t p
int nfq_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr **attr);
struct nlmsghdr *nfq_nlmsg_put(char *buf, int type, uint32_t queue_num);
+struct nlmsghdr *nfq_nlmsg_put2(char *buf, int type, uint32_t queue_num, uint16_t flags);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/include/libnetfilter_queue/linux_nfnetlink_queue.h b/include/libnetfilter_queue/linux_nfnetlink_queue.h
index 1975dfa..6844270 100644
--- a/include/libnetfilter_queue/linux_nfnetlink_queue.h
+++ b/include/libnetfilter_queue/linux_nfnetlink_queue.h
@@ -1,6 +1,8 @@
#ifndef _NFNETLINK_QUEUE_H
#define _NFNETLINK_QUEUE_H
+#warning "libnetfilter_queue/linux_nfnetlink_queue.h is deprecated, add #include <linux/netfilter/nfnetlink_queue.h> to your source code before #include <libnetfilter_queue/libnetfilter_queue.h>"
+
#ifndef aligned_u64
#define aligned_u64 unsigned long long __attribute__((aligned(8)))
#endif
@@ -46,11 +48,11 @@ enum nfqnl_attr_type {
NFQA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */
NFQA_HWADDR, /* nfqnl_msg_packet_hw */
NFQA_PAYLOAD, /* opaque data payload */
- NFQA_CT, /* nf_conntrack_netlink.h */
+ NFQA_CT, /* nfnetlink_conntrack.h */
NFQA_CT_INFO, /* enum ip_conntrack_info */
NFQA_CAP_LEN, /* __u32 length of captured packet */
NFQA_SKB_INFO, /* __u32 skb meta information */
- NFQA_EXP, /* nf_conntrack_netlink.h */
+ NFQA_EXP, /* nfnetlink_conntrack.h */
NFQA_UID, /* __u32 sk uid */
NFQA_GID, /* __u32 sk gid */
NFQA_SECCTX, /* security context string */
diff --git a/include/libnetfilter_queue/pktbuff.h b/include/libnetfilter_queue/pktbuff.h
index 42bc153..d3588c7 100644
--- a/include/libnetfilter_queue/pktbuff.h
+++ b/include/libnetfilter_queue/pktbuff.h
@@ -1,11 +1,16 @@
#ifndef _PKTBUFF_H_
#define _PKTBUFF_H_
+#include <stdbool.h>
+
struct pkt_buff;
struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra);
void pktb_free(struct pkt_buff *pktb);
+struct pkt_buff *pktb_setup_raw(void *pktb, int family, void *data, size_t len, size_t extra);
+size_t pktb_head_size(void);
+
uint8_t *pktb_data(struct pkt_buff *pktb);
uint32_t pktb_len(struct pkt_buff *pktb);
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h
index 030672d..8e2e469 100644
--- a/include/linux/netfilter/nfnetlink_queue.h
+++ b/include/linux/netfilter/nfnetlink_queue.h
@@ -42,11 +42,11 @@ enum nfqnl_attr_type {
NFQA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */
NFQA_HWADDR, /* nfqnl_msg_packet_hw */
NFQA_PAYLOAD, /* opaque data payload */
- NFQA_CT, /* nf_conntrack_netlink.h */
+ NFQA_CT, /* nfnetlink_conntrack.h */
NFQA_CT_INFO, /* enum ip_conntrack_info */
NFQA_CAP_LEN, /* __u32 length of captured packet */
NFQA_SKB_INFO, /* __u32 skb meta information */
- NFQA_EXP, /* nf_conntrack_netlink.h */
+ NFQA_EXP, /* nfnetlink_conntrack.h */
NFQA_UID, /* __u32 sk uid */
NFQA_GID, /* __u32 sk gid */
NFQA_SECCTX,
diff --git a/src/extra/checksum.c b/src/extra/checksum.c
index ffc8c75..33480af 100644
--- a/src/extra/checksum.c
+++ b/src/extra/checksum.c
@@ -17,6 +17,7 @@
#include <netinet/ip6.h>
#include <netinet/tcp.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
diff --git a/src/extra/icmp.c b/src/extra/icmp.c
index a97979b..eaade7b 100644
--- a/src/extra/icmp.c
+++ b/src/extra/icmp.c
@@ -19,6 +19,15 @@
/**
* \defgroup icmp ICMP helper functions
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/libnetfilter_queue_icmp.h>
+\endmanonly
+ *
* @{
*/
diff --git a/src/extra/ipv4.c b/src/extra/ipv4.c
index 797bab1..58fb471 100644
--- a/src/extra/ipv4.c
+++ b/src/extra/ipv4.c
@@ -14,6 +14,7 @@
#include <arpa/inet.h>
#include <netinet/ip.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/pktbuff.h>
@@ -22,6 +23,15 @@
/**
* \defgroup ipv4 IPv4 helper functions
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
+\endmanonly
+ *
* @{
*/
@@ -87,6 +97,15 @@ int nfq_ip_set_transport_header(struct pkt_buff *pktb, struct iphdr *iph)
*
* Most user-space programs will never need these.
*
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
+\endmanonly
+ *
* @{
*/
@@ -142,7 +161,7 @@ int nfq_ip_mangle(struct pkt_buff *pktb, unsigned int dataoff,
}
/**
- * nfq_pkt_snprintf_ip - print IPv4 header into buffer in iptables LOG format
+ * nfq_ip_snprintf - print IPv4 header into buffer in iptables LOG format
* \param buf: Pointer to buffer that will be used to print the header
* \param size: Size of the buffer (or remaining room in it)
* \param iph: Pointer to a valid IPv4 header
diff --git a/src/extra/ipv6.c b/src/extra/ipv6.c
index 23f64ba..fd8ebc4 100644
--- a/src/extra/ipv6.c
+++ b/src/extra/ipv6.c
@@ -15,6 +15,7 @@
#include <arpa/inet.h>
#include <netinet/ip6.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
#include <libnetfilter_queue/pktbuff.h>
@@ -23,6 +24,17 @@
/**
* \defgroup ipv6 IPv6 helper functions
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <arpa/inet.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
+\endmanonly
+ *
* @{
*/
@@ -101,11 +113,11 @@ int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *ip6h,
break;
}
- frag_off = (uint16_t *)cur +
- offsetof(struct ip6_frag, ip6f_offlg);
+ frag_off = (uint16_t *)(cur +
+ offsetof(struct ip6_frag, ip6f_offlg));
/* Fragment offset is only 13 bits long. */
- if (htons(*frag_off & ~0x7)) {
+ if (htons(*frag_off) & ~0x7) {
/* Not the first fragment, it does not contain
* any headers.
*/
diff --git a/src/extra/pktbuff.c b/src/extra/pktbuff.c
index 6dd0ca9..40d2250 100644
--- a/src/extra/pktbuff.c
+++ b/src/extra/pktbuff.c
@@ -23,12 +23,58 @@
/**
* \defgroup pktbuff User-space network packet buffer
*
- * This library provides the user-space network packet buffer. This abstraction
- * is strongly inspired by Linux kernel network buffer, the so-called sk_buff.
+ * These functions provide the user-space network packet buffer.
+ * This abstraction is strongly inspired by Linux kernel network buffer,
+ * the so-called sk_buff.
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/pktbuff.h>
+\endmanonly
*
* @{
*/
+static int __pktb_setup(int family, struct pkt_buff *pktb)
+{
+ struct ethhdr *ethhdr;
+
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ pktb->network_header = pktb->data;
+ break;
+ case AF_BRIDGE:
+ ethhdr = (struct ethhdr *)pktb->data;
+ pktb->mac_header = pktb->data;
+
+ switch(ethhdr->h_proto) {
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ pktb->network_header = pktb->data + ETH_HLEN;
+ break;
+ default:
+ /* This protocol is unsupported. */
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void pktb_setup_metadata(struct pkt_buff *pktb, void *pkt_data,
+ size_t len, size_t extra)
+{
+ pktb->len = len;
+ pktb->data_len = len + extra;
+ pktb->data = pkt_data;
+}
+
/**
* pktb_alloc - allocate a new packet buffer
* \param family Indicate what family. Currently supported families are
@@ -38,7 +84,12 @@
* \param extra Extra memory in the tail to be allocated (for mangling)
*
* This function returns a packet buffer that contains the packet data and
- * some extra memory room in the tail (if requested).
+ * some extra memory room in the tail (if requested). This function copies
+ * the memory area provided as a pointer to packet data into the packet buffer
+ * structure.
+ *
+ * The extra length provides extra packet data room at the tail of the packet
+ * buffer in case you need to mangle it.
*
* \return Pointer to a new userspace packet buffer or NULL on failure.
* \par Errors
@@ -52,7 +103,6 @@ EXPORT_SYMBOL
struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
{
struct pkt_buff *pktb;
- struct ethhdr *ethhdr;
void *pkt_data;
pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
@@ -63,33 +113,44 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff);
memcpy(pkt_data, data, len);
- pktb->len = len;
- pktb->data_len = len + extra;
+ pktb_setup_metadata(pktb, pkt_data, len, extra);
- pktb->data = pkt_data;
+ if (__pktb_setup(family, pktb) < 0) {
+ free(pktb);
+ return NULL;
+ }
- switch(family) {
- case AF_INET:
- case AF_INET6:
- pktb->network_header = pktb->data;
- break;
- case AF_BRIDGE:
- ethhdr = (struct ethhdr *)pktb->data;
- pktb->mac_header = pktb->data;
+ return pktb;
+}
+
+/**
+ * pktb_setup_raw - set up a packet buffer from memory area
+ * \param pktb Pointer to memory of length pktb_head_size() bytes
+ * \param family Supported families are AF_BRIDGE, AF_INET & AF_INET6.
+ * \param data Pointer to packet data
+ * \param len Packet data length
+ * \param extra Extra memory available after packet data (for mangling).
+ *
+ * Use this function to set up a packet buffer from a memory area, minimum size
+ * of such memory area must be pktb_head_size(). This function attaches the
+ * packet data that is provided to the packet buffer (data is not copied). Use
+ * this function as an alternative to the pktb_alloc() interface for more
+ * control on memory management.
+ *
+ * \return Pointer to a new userspace packet buffer or NULL on failure.
+ * \par Errors
+ * __EPROTONOSUPPORT__ _family_ was __AF_BRIDGE__ and this is not an IP packet
+ * (v4 or v6)
+ */
+EXPORT_SYMBOL
+struct pkt_buff *pktb_setup_raw(void *pktb, int family, void *data,
+ size_t len, size_t extra)
+{
+ memset(pktb, 0, sizeof (struct pkt_buff));
+ pktb_setup_metadata(pktb, data, len, extra);
+ if (__pktb_setup(family, pktb) < 0)
+ pktb = NULL;
- switch(ethhdr->h_proto) {
- case ETH_P_IP:
- case ETH_P_IPV6:
- pktb->network_header = pktb->data + ETH_HLEN;
- break;
- default:
- /* This protocol is unsupported. */
- errno = EPROTONOSUPPORT;
- free(pktb);
- return NULL;
- }
- break;
- }
return pktb;
}
@@ -139,21 +200,37 @@ void pktb_free(struct pkt_buff *pktb)
* \n
* 1. Functions to get values of members of opaque __struct pktbuff__, described
* below
- * \n
+ *
* 2. Internal functions, described in Module __Internal functions__
*
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/pktbuff.h>
+\endmanonly
+ *
* @{
*/
/**
- * \defgroup uselessfns Internal functions
+ * \defgroup do_not_use Internal functions
*
- * \warning Do not use these functions. Instead, always use the mangle
+ * Do not use these functions. Instead, always use the mangle
* function appropriate to the level at which you are working.
* \n
* pktb_mangle() uses all the below functions except _pktb_pull_, which is not
* used by anything.
*
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/pktbuff.h>
+\endmanonly
+ *
* @{
*/
@@ -306,7 +383,7 @@ static int enlarge_pkt(struct pkt_buff *pktb, unsigned int extra)
* excess of \b rep_len over \b match_len
\warning pktb_mangle does not update any checksums. Developers should use the
appropriate mangler for the protocol level: nfq_ip_mangle(),
- nfq_tcp_mangle_ipv4() or nfq_udp_mangle_ipv4(). IPv6 versions are planned.
+ nfq_tcp_mangle_ipv4(), nfq_udp_mangle_ipv4() or IPv6 variants.
\n
It is appropriate to use pktb_mangle to change the MAC header.
*/
@@ -362,5 +439,17 @@ bool pktb_mangled(const struct pkt_buff *pktb)
}
/**
+ * pktb_head_size - get number of bytes needed for a packet buffer
+ * (control part only)
+ * \return size of struct pkt_buff
+ */
+
+EXPORT_SYMBOL
+size_t pktb_head_size(void)
+{
+ return sizeof(struct pkt_buff);
+}
+
+/**
* @}
*/
diff --git a/src/extra/tcp.c b/src/extra/tcp.c
index 933c6ee..720afd2 100644
--- a/src/extra/tcp.c
+++ b/src/extra/tcp.c
@@ -18,6 +18,7 @@
#define _GNU_SOURCE
#include <netinet/tcp.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
@@ -28,6 +29,15 @@
/**
* \defgroup tcp TCP helper functions
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
+\endmanonly
+ *
* @{
*/
@@ -91,6 +101,17 @@ unsigned int nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb)
*
* Most user-space programs will never need these.
*
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
+\endmanonly
+ *
* @{
*/
diff --git a/src/extra/udp.c b/src/extra/udp.c
index f232127..ede2196 100644
--- a/src/extra/udp.c
+++ b/src/extra/udp.c
@@ -17,6 +17,7 @@
#define _GNU_SOURCE
#include <netinet/udp.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
@@ -27,6 +28,15 @@
/**
* \defgroup udp UDP helper functions
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libmnl/libmnl.h>
+#include <libnetfilter_queue/libnetfilter_queue_udp.h>
+\endmanonly
+ *
* @{
*/
@@ -91,6 +101,17 @@ unsigned int nfq_udp_get_payload_len(struct udphdr *udph, struct pkt_buff *pktb)
*
* Most user-space programs will never need these.
*
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <libnetfilter_queue/libnetfilter_queue_udp.h>
+\endmanonly
+ *
* @{
*/
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index ef3b211..bf67a19 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -29,6 +29,7 @@
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
@@ -44,11 +45,11 @@
* libnetfilter_queue homepage is:
* https://netfilter.org/projects/libnetfilter_queue/
*
- * \section deps Dependencies
+ <h1>Dependencies</h1>
* libnetfilter_queue requires libmnl, libnfnetlink and a kernel that includes
* the Netfilter NFQUEUE over NFNETLINK interface (i.e. 2.6.14 or later).
*
- * \section features Main Features
+ * <h1>Main Features</h1>
* - receiving queued packets from the kernel nfnetlink_queue subsystem
* - issuing verdicts and possibly reinjecting altered packets to the kernel
* nfnetlink_queue subsystem
@@ -70,15 +71,15 @@
* When a queue is full, packets that should have been enqueued are dropped by
* kernel instead of being enqueued.
*
- * \section git Git Tree
+ * <h1>Git Tree</h1>
* The current development version of libnetfilter_queue can be accessed at
* https://git.netfilter.org/libnetfilter_queue.
*
- * \section privs Privileges
+ * <h1>Privileges</h1>
* You need the CAP_NET_ADMIN capability in order to allow your application
* to receive from and to send packets to kernel-space.
*
- * \section using Using libnetfilter_queue
+ * <h1>Using libnetfilter_queue</h1>
*
* To write your own program using libnetfilter_queue, you should start by
* reading (or, if feasible, compiling and stepping through with *gdb*)
@@ -87,7 +88,14 @@
* \verbatim
gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
\endverbatim
- * The doxygen documentation \link LibrarySetup \endlink is Deprecated and
+ *The doxygen documentation
+ * \htmlonly
+<a class="el" href="group__LibrarySetup.html">LibrarySetup </a>
+\endhtmlonly
+ * \manonly
+\fBLibrarySetup\fP\
+\endmanonly
+ * is Deprecated and
* incompatible with non-deprecated functions. It is hoped to produce a
* corresponding non-deprecated (*Current*) topic soon.
*
@@ -96,7 +104,7 @@ gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
* article:
* https://home.regit.org/netfilter-en/using-nfqueue-and-libnetfilter_queue/
*
- * \section errors ENOBUFS errors in recv()
+ * <h1>ENOBUFS errors in recv()</h1>
*
* recv() may return -1 and errno is set to ENOBUFS in case that your
* application is not fast enough to retrieve the packets from the kernel.
@@ -105,7 +113,7 @@ gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
* you may hit it again sooner or later. The next section provides some hints
* on how to obtain the best performance for your application.
*
- * \section perf Performance
+ * <h1>Performance</h1>
* To improve your libnetfilter_queue application in terms of performance,
* you may consider the following tweaks:
*
@@ -119,6 +127,9 @@ gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
* (it requires Linux kernel >= 2.6.31).
* - consider using fail-open option see nfq_set_queue_flags() (it requires
* Linux kernel >= 3.6)
+ * - make your application offload aware to avoid costly normalization on kernel
+ * side. See NFQA_CFG_F_GSO flag to nfq_set_queue_flags().
+ * Linux kernel >= 3.10.
* - increase queue max length with nfq_set_queue_maxlen() to resist to packets
* burst
*/
@@ -270,7 +281,7 @@ struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h)
nfq_handle_packet(h, buf, rv);
}
\endverbatim
- * When the decision on a packet has been choosed, the verdict has to be given
+ * When the decision on a packet has been chosen, the verdict has to be given
* by calling nfq_set_verdict() or nfq_set_verdict2(). The verdict
* determines the destiny of the packet as follows:
*
@@ -287,8 +298,18 @@ struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h)
* is to also set an nfmark using nfq_set_verdict2, and set up the nefilter
* rules to only queue a packet when the mark is not (yet) set.
*
- * Data and information about the packet can be fetch by using message parsing
+ * Data and information about the packet can be fetched by using message parsing
* functions (See \link Parsing \endlink).
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
+ *
* @{
*/
@@ -437,6 +458,14 @@ out_free:
* When the program has finished with libnetfilter_queue, it has to call
* the nfq_close() function to free all associated resources.
*
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
+ *
* @{
*/
@@ -949,6 +978,15 @@ int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id,
/**
* \defgroup Parsing Message parsing functions [DEPRECATED]
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
+ *
* @{
*/
@@ -1348,6 +1386,15 @@ do { \
/**
* \defgroup Printing Printing [DEPRECATED]
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
+ *
* @{
*/
diff --git a/src/nlmsg.c b/src/nlmsg.c
index e141156..39fd12d 100644
--- a/src/nlmsg.c
+++ b/src/nlmsg.c
@@ -27,6 +27,16 @@
/**
* \defgroup nfq_verd Verdict helpers
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
+ *
* @{
*/
@@ -139,6 +149,15 @@ void nfq_nlmsg_verdict_put_pkt(struct nlmsghdr *nlh, const void *pkt,
/**
* \defgroup nfq_cfg Config helpers
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
+ *
* @{
*/
@@ -205,6 +224,15 @@ void nfq_nlmsg_cfg_put_qmaxlen(struct nlmsghdr *nlh, uint32_t queue_maxlen)
/**
* \defgroup nlmsg Netlink message helper functions
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
+ *
* @{
*/
@@ -225,7 +253,6 @@ static int nfq_pkt_parse_attr_cb(const struct nlattr *attr, void *data)
case NFQA_IFINDEX_PHYSOUTDEV:
case NFQA_CAP_LEN:
case NFQA_SKB_INFO:
- case NFQA_SECCTX:
case NFQA_UID:
case NFQA_GID:
case NFQA_CT_INFO:
@@ -253,6 +280,7 @@ static int nfq_pkt_parse_attr_cb(const struct nlattr *attr, void *data)
case NFQA_PAYLOAD:
case NFQA_CT:
case NFQA_EXP:
+ case NFQA_SECCTX:
break;
}
tb[type] = attr;
@@ -282,9 +310,65 @@ int nfq_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr **attr)
EXPORT_SYMBOL
struct nlmsghdr *nfq_nlmsg_put(char *buf, int type, uint32_t queue_num)
{
+ return nfq_nlmsg_put2(buf, type, queue_num, 0);
+}
+
+/**
+ * nfq_nlmsg_put2 - Set up a netlink header with user-specified flags
+ * in a memory buffer
+ * \param *buf Pointer to memory buffer
+ * \param type One of NFQNL_MSG_CONFIG, NFQNL_MSG_VERDICT
+ * or NFQNL_MSG_VERDICT_BATCH
+ * \param queue_num Queue number
+ * \param flags additional NLM_F_xxx flags to put in message header. These are
+ * defined in /usr/include/linux/netlink.h. nfq_nlmsg_put2() always
+ * sets NLM_F_REQUEST
+ * \returns Pointer to netlink header
+ *
+ * For most applications, the only sensible flag will be NLM_F_ACK.
+ * Use it to get an explicit acknowledgment from the kernel, e.g.
+ * attempt to configure NFQA_CFG_F_SECCTX on a kernel not supporting
+ * CONFIG_NETWORK_SECMARK.
+ * \n
+ * The kernel always sends a message in response to a failed command.
+ * NLM_F_ACK instructs the kernel to also send a message in response
+ * to a successful command.
+ * \n
+ * This code snippet demonstrates reading these responses:
+ * \verbatim
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, queue_num,
+ NLM_F_ACK);
+ mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, NFQA_CFG_F_SECCTX);
+ mnl_attr_put_u32(nlh, NFQA_CFG_MASK, NFQA_CFG_F_SECCTX);
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_send");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof buf);
+ if (ret == -1) {
+ perror("mnl_socket_recvfrom");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = mnl_cb_run(buf, ret, 0, portid, NULL, NULL);
+ if (ret == -1)
+ fprintf(stderr, "This kernel version does not allow to "
+ "retrieve security context.\n");
+\endverbatim
+ *
+ */
+
+EXPORT_SYMBOL
+struct nlmsghdr *nfq_nlmsg_put2(char *buf, int type, uint32_t queue_num,
+ uint16_t flags)
+{
struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | type;
- nlh->nlmsg_flags = NLM_F_REQUEST;
+ nlh->nlmsg_flags = NLM_F_REQUEST | flags;
struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
nfg->nfgen_family = AF_UNSPEC;
diff --git a/utils/nfqnl_test.c b/utils/nfqnl_test.c
index 5e76ffe..682f3d7 100644
--- a/utils/nfqnl_test.c
+++ b/utils/nfqnl_test.c
@@ -5,6 +5,7 @@
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h> /* for NF_ACCEPT */
+#include <linux/netfilter/nfnetlink_queue.h>
#include <errno.h>
#include <libnetfilter_queue/libnetfilter_queue.h>