summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--doxygen/Makefile.am8
-rwxr-xr-xdoxygen/build_man.sh274
-rw-r--r--doxygen/doxygen.cfg.in1
-rw-r--r--examples/nf-queue.c36
-rw-r--r--include/libnetfilter_queue/libnetfilter_queue.h9
-rw-r--r--include/libnetfilter_queue/pktbuff.h5
-rw-r--r--src/extra/ipv6.c6
-rw-r--r--src/extra/pktbuff.c63
-rw-r--r--src/extra/tcp.c2
-rw-r--r--src/extra/udp.c2
-rw-r--r--src/libnetfilter_queue.c34
-rw-r--r--src/nlmsg.c58
13 files changed, 388 insertions, 112 deletions
diff --git a/configure.ac b/configure.ac
index f279bcf..7359fba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ 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
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index c6eeed7..d3f8593 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -10,12 +10,12 @@ doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c\
$(top_srcdir)/src/extra/udp.c\
$(top_srcdir)/src/extra/icmp.c
-doxyfile.stamp: $(doc_srcs) Makefile
+doxyfile.stamp: $(doc_srcs) Makefile build_man.sh
rm -rf html man
doxygen doxygen.cfg >/dev/null
if BUILD_MAN
- $(abs_top_srcdir)/doxygen/build_man.sh
+ $(abs_top_srcdir)/doxygen/build_man.sh libnetfilter_queue libnetfilter_queue.c
endif
touch doxyfile.stamp
@@ -27,9 +27,11 @@ clean-local:
rm -rf man html
install-data-local:
if BUILD_MAN
- mkdir -p $(DESTDIR)$(mandir)/man3
+ mkdir -p $(DESTDIR)$(mandir)/man3 $(DESTDIR)$(mandir)/man7
cp --no-dereference --preserve=links,mode,timestamps man/man3/*.3\
$(DESTDIR)$(mandir)/man3/
+ cp --no-dereference --preserve=links,mode,timestamps man/man7/*.7\
+ $(DESTDIR)$(mandir)/man7/
endif
if BUILD_HTML
mkdir -p $(DESTDIR)$(htmldir)
diff --git a/doxygen/build_man.sh b/doxygen/build_man.sh
index c68876c..50ab884 100755
--- a/doxygen/build_man.sh
+++ b/doxygen/build_man.sh
@@ -1,18 +1,25 @@
-#!/bin/bash -p
+#!/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
+done_synopsis=false
main(){
set -e
- cd man/man3; rm -f _*
+ # make_man7 has no dependencies or dependants so kick it off now
+ [ $# -ne 2 ] || make_man7 $@ &
+ pushd man/man3 >/dev/null; rm -f _*
count_real_pages
rename_real_pages
- make_symlinks
- post_process
+ # Nothing depends on make_symlinks so background it
+ make_symlinks &
+ post_process $@
+ wait
}
count_real_pages(){
@@ -32,9 +39,16 @@ count_real_pages(){
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
+ do
+ j=$(ed -s $i <<////
+/Functions/+1;.#
+/^\\.RI/;.#
+.,.s/^.*\\\\fB//
+.,.s/\\\\.*//
+.,.w /dev/stdout
+Q
+////
+).3
mv -f $i $j
renamed_page[$i]=$j
done
@@ -47,35 +61,144 @@ make_symlinks(){
}
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;\
- #
+ #keep_me=nfq_icmp_get_hdr.3
+ #do_diagnostics
+
+ # Record doxygen version
+ i=$(doxygen --version)
+ doxymajor=$(echo $i|cut -f1 -d.)
+ doxyminor=$(echo $i|cut -f2 -d.)
+
+ # Decide if we need to fix rendering of verbatim "\n"
+ [ $doxymajor -eq 1 -a $doxyminor -lt 9 ] &&
+ fix_newlines=true || fix_newlines=false
+
+ # Decide if we need to fix double-to-single-quote conversion
+ [ $doxymajor -eq 1 -a $doxyminor -ge 9 -a $doxyminor -lt 13 ] &&
+ fix_quotes = true || fix_quotes=false
+
# 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
+ do grep -Eq "^\\.SH \"Function Documentation" $target || continue
- del_modules
- del_bogus_synopsis
- fix_name_line
- move_synopsis
- del_empty_det_desc
- del_def_at_lines
- fix_double_blanks
+ {
+ del_bogus_synopsis
+ $done_synopsis || del_modules
+ fix_name_line
+ move_synopsis
+ del_empty_det_desc
+ del_def_at_lines
+ fix_double_blanks
+ [ $# -ne 2 ] || insert_see_also $@
- # Fix rendering of verbatim "\n" (in code snippets)
- sed -i 's/\\n/\\\\n/' $target
+ # Work around doxygen bugs (doxygen version-specific)
+
+ # Best effort: \" becomes \'
+ # Only do lines with some kind of printf,
+ # since other single quotes might be OK as-is.
+ $fix_quotes && sed -i '/printf/s/'\''/"/g' $target
+
+ # Fix rendering of verbatim "\n" (in code snippets)
+ $fix_newlines && sed -i 's/\\n/\\\\n/' $target
+ }&
done
- remove_temp_files
+}
+
+make_man7(){
+ 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).
+ ed -s $target << ////
+1,/\\\\mainpage/d
+0i
+/**
+ * \\defgroup $1 $1 overview
+.
+/\\*\\//+1,\$d
+a
+
+/**
+ * @{
+ *
+ * $1 - DELETE_ME
+ */
+int $1(void)
+{
+ return 0;
+}
+/**
+ * @}
+ */
+.
+wq temp.c
+////
+
+ # Create temporary doxygen config in doxytmp
+ grep -Ew PROJECT_NUMBER doxygen.cfg >doxytmp
+ cat >>doxytmp <<////
+PROJECT_NAME = $1
+ABBREVIATE_BRIEF =
+FULL_PATH_NAMES = NO
+TAB_SIZE = 8
+OPTIMIZE_OUTPUT_FOR_C = YES
+EXAMPLE_PATTERNS =
+ALPHABETICAL_INDEX = NO
+SEARCHENGINE = NO
+GENERATE_LATEX = NO
+INPUT = temp.c
+GENERATE_HTML = NO
+GENERATE_MAN = YES
+MAN_EXTENSION = .7
+////
+
+ doxygen doxytmp >/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
+ echo "Re-running doxygen $(doxygen --version)"
+ ed -s temp.c << ////
+2a
+ * \\manonly
+.PP
+.SH "Detailed Description"
+.PP
+\\endmanonly
+.
+wq
+////
+ doxygen doxytmp >/dev/null
+ fi
+
+ rm temp.c doxytmp
+}
+
+# Insert top-level "See also" of man7 page in man3 page
+insert_see_also(){
+ mygrep "Detailed Description" $target
+ [ $linnum -ne 0 ] || mygrep "Function Documentation" $target
+ [ $linnum -ne 0 ] || { echo "NO HEADER IN $target" >&2; return; }
+ ed -s $target <<////
+${linnum}i
+.SH "See also"
+\\fB${1}\\fP(7)
+.
+wq
+////
}
fix_double_blanks(){
@@ -132,14 +255,13 @@ move_synopsis(){
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
+ ed -s $target <<////
+/^\\.SS \"Functions\"/;.d
+.ka
+/^\\.SH SYNOPSIS/;/^[[:space:]]*\$/-1m'a-1
+/\"Function Documentation\"/-1;.d
+wq
+////
}
fix_name_line(){
@@ -147,81 +269,69 @@ fix_name_line(){
# Search a shortened version of the page in case there are .RI lines later
mygrep "^\\.SH \"Function Documentation" $target
- head -n$linnum $target >$fileC
+ head -n$linnum $target >../$target.tmp
while :
- do mygrep ^\\.RI $fileC
- [ $linnum -ne 0 ] || break
- # Discard this entry
- tail -n+$(($linnum + 1)) $fileC >$fileB
- cp $fileB $fileC
+ do foundline=$(grep -En "^\\.RI" ../$target.tmp 2>/dev/null | head -n1)
+ [ "$foundline" ] || break
+ linnum=$(echo $foundline | cut -f1 -d:)
+ # Discard this entry (and all previous lines)
+ ed -s ../$target.tmp <<////
+1,${linnum}d
+wq
+////
- func=$(cat $fileG | cut -f2 -d\\ | cut -c3-)
+ func=$(echo $foundline | 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
+ ed -s $target <<////
+5c
+$all_funcs \\- $desc
+.
+wq
+////
+ rm ../$target.tmp
}
+# Prior to doxygen 1.8.20 there was a "Modules" entry which became part of the
+# "bogus" synopsis. Doxygen 1.11.0 replaces "Modules" with "Topics" still as
+# part of the "bogus" synopsis and so cleaned up by del_bogus_synopsis().
del_modules(){
- mygrep "^\.SS \"Modules" $target
- [ $linnum -ne 0 ] || return 0
- i=$linnum
- mygrep "^\\.SS \"Functions" $target
- delete_lines $i $(($linnum - 1))
+ grep -Eq "^\\.SS \"Modules" $target || return 0
+ ed -s $target <<////
+/^\\.SS \"Modules/,/^\\.SS \"Functions/-1d
+wq
+////
}
del_bogus_synopsis(){
- mygrep "SH SYNOPSIS" $target
+ [ $(grep -E 'SH SYNOPSIS' $target | wc -l) -eq 2 ] || return 0
#
# 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))
+ ed -s $target <<////
+/SH SYNOPSIS/,/^\\.SS \"Functions/-1d
+wq
+////
+ done_synopsis=true
}
# 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
+ ed -s $target <<////
+$1,$2d
+wq
+////
}
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
+ linnum=$(grep -En "$1" $2 2>/dev/null | head -n1 | cut -f1 -d:)
+ [ $linnum ] || linnum=0
}
-main
+main $@
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index 14bd0cf..97174ff 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -25,4 +25,3 @@ 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 6983418..1ae52e4 100644
--- a/examples/nf-queue.c
+++ b/examples/nf-queue.c
@@ -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,10 +106,11 @@ 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 char *addr = hw->hw_addr;
+ const unsigned char *addr = hw->hw_addr;
unsigned int i;
printf(", hwaddr %02x", addr[0]);
@@ -135,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");
@@ -153,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);
@@ -161,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);
@@ -179,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/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/src/extra/ipv6.c b/src/extra/ipv6.c
index 69d86a8..fd8ebc4 100644
--- a/src/extra/ipv6.c
+++ b/src/extra/ipv6.c
@@ -113,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 005172c..40d2250 100644
--- a/src/extra/pktbuff.c
+++ b/src/extra/pktbuff.c
@@ -67,6 +67,14 @@ static int __pktb_setup(int family, struct pkt_buff *pktb)
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
@@ -76,7 +84,12 @@ static int __pktb_setup(int family, struct pkt_buff *pktb)
* \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
@@ -100,10 +113,7 @@ 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->data = pkt_data;
+ pktb_setup_metadata(pktb, pkt_data, len, extra);
if (__pktb_setup(family, pktb) < 0) {
free(pktb);
@@ -114,6 +124,37 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
}
/**
+ * 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;
+
+ return pktb;
+}
+
+/**
* pktb_data - get pointer to network packet
* \param pktb Pointer to userspace packet buffer
* \return Pointer to start of network packet data within __pktb__
@@ -398,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 720afd2..1bc379f 100644
--- a/src/extra/tcp.c
+++ b/src/extra/tcp.c
@@ -168,7 +168,7 @@ union tcp_word_hdr {
#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words[3])
/**
- * nfq_pkt_snprintf_tcp_hdr - print tcp header into one buffer in a humnan
+ * nfq_tcp_snprintf - print tcp header into one buffer in a human
* readable way
* \param buf: pointer to buffer that is used to print the object
* \param size: size of the buffer (or remaining room in it).
diff --git a/src/extra/udp.c b/src/extra/udp.c
index ede2196..4d457ea 100644
--- a/src/extra/udp.c
+++ b/src/extra/udp.c
@@ -228,7 +228,7 @@ int nfq_udp_mangle_ipv6(struct pkt_buff *pktb,
}
/**
- * nfq_pkt_snprintf_udp_hdr - print udp header into one buffer in a humnan
+ * nfq_udp_snprintf - print udp header into one buffer in a human
* readable way
* \param buf: pointer to buffer that is used to print the object
* \param size: size of the buffer (or remaining room in it).
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index a170143..1cde910 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -45,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
@@ -71,24 +71,31 @@
* 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*)
* nf-queue.c source file.
* Simple compile line:
* \verbatim
-gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
+gcc -Wall nf-queue.c -o nf-queue -lnetfilter_queue -lmnl
\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.
*
@@ -97,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.
@@ -106,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:
*
@@ -120,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
*/
@@ -471,7 +481,13 @@ EXPORT_SYMBOL
int nfq_close(struct nfq_handle *h)
{
int ret;
+ struct nfq_q_handle *qh;
+ while (h->qh_list) {
+ qh = h->qh_list;
+ h->qh_list = qh->next;
+ free(qh);
+ }
ret = nfnl_close(h->nfnlh);
if (ret == 0)
free(h);
diff --git a/src/nlmsg.c b/src/nlmsg.c
index 5400dd7..39fd12d 100644
--- a/src/nlmsg.c
+++ b/src/nlmsg.c
@@ -310,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;