diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | configure.ac | 55 | ||||
-rw-r--r-- | doxygen/Makefile.am | 107 | ||||
-rwxr-xr-x | doxygen/build_man.sh | 323 | ||||
-rw-r--r-- | doxygen/doxygen.cfg.in (renamed from doxygen.cfg.in) | 8 | ||||
-rw-r--r-- | examples/nf-queue.c | 54 | ||||
-rw-r--r-- | include/libnetfilter_queue/libnetfilter_queue.h | 9 | ||||
-rw-r--r-- | include/libnetfilter_queue/linux_nfnetlink_queue.h | 6 | ||||
-rw-r--r-- | include/libnetfilter_queue/pktbuff.h | 5 | ||||
-rw-r--r-- | include/linux/netfilter/nfnetlink_queue.h | 4 | ||||
-rw-r--r-- | src/extra/checksum.c | 1 | ||||
-rw-r--r-- | src/extra/icmp.c | 9 | ||||
-rw-r--r-- | src/extra/ipv4.c | 21 | ||||
-rw-r--r-- | src/extra/ipv6.c | 18 | ||||
-rw-r--r-- | src/extra/pktbuff.c | 153 | ||||
-rw-r--r-- | src/extra/tcp.c | 21 | ||||
-rw-r--r-- | src/extra/udp.c | 21 | ||||
-rw-r--r-- | src/libnetfilter_queue.c | 67 | ||||
-rw-r--r-- | src/nlmsg.c | 88 | ||||
-rw-r--r-- | utils/nfqnl_test.c | 1 |
20 files changed, 820 insertions, 156 deletions
@@ -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> |