This commit is contained in:
Zxilly 2020-11-27 18:49:35 +08:00
parent 9673c3d61b
commit 75ccb3eb67
40 changed files with 4730 additions and 8 deletions

17
ref/libnetfilter-queue/.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
.deps/
.libs/
Makefile
Makefile.in
*.o
*.la
*.lo
/aclocal.m4
/autom4te.cache/
/build-aux/
/config.*
/configure
/libtool
/doxygen.cfg
/libnetfilter_queue.pc

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -0,0 +1,2 @@
AM_CPPFLAGS = -I${top_srcdir}/include ${LIBNFNETLINK_CFLAGS} ${LIBMNL_CFLAGS}
AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN}

View File

@ -0,0 +1,13 @@
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = $(man_MANS) include/linux
SUBDIRS = src utils include examples doxygen
man_MANS = #nfnetlink_queue.3 nfnetlink_queue.7
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnetfilter_queue.pc
EXTRA_DIST += Make_global.am
EXTRA_DIST += fixmanpages.sh

View File

@ -0,0 +1,39 @@
#!/bin/sh -e
include ()
{
# If we keep a copy of the kernel header in the SVN tree, we'll have
# to worry about synchronization issues forever. Instead, we just copy
# the headers that we need from the lastest kernel version at autogen
# stage.
INCLUDEDIR=${KERNEL_DIR:-/lib/modules/`uname -r`/build}/include/linux
if [ -f $INCLUDEDIR/netfilter/nfnetlink_queue.h ]
then
TARGET=include/libnetfilter_queue/linux_nfnetlink_queue.h
echo "Copying nfnetlink_queue.h to linux_nfnetlink_queue.h"
cp $INCLUDEDIR/netfilter/nfnetlink_queue.h $TARGET
TEMP=`tempfile`
sed 's/linux\/netfilter\/nfnetlink.h/libnfnetlink\/linux_nfnetlink.h/g' $TARGET > $TEMP
# Add aligned_u64 definition after #define _NFNETLINK_QUEUE_H
awk '{
if ( $0 == "#define _NFNETLINK_QUEUE_H" ) {
print $0
getline
print $0
print "#ifndef aligned_u64"
print "#define aligned_u64 unsigned long long __attribute__((aligned(8)))"
print "#endif"
}
print $0
}' $TEMP > $TARGET
else
echo "can't find nfnetlink_queue.h kernel file in $INCLUDEDIR"
exit 1
fi
}
[ "x$1" = "xdistrib" ] && include
autoreconf -fi
rm -Rf autom4te.cache

View File

@ -0,0 +1,55 @@
dnl Process this file with autoconf to create configure.
AC_INIT([libnetfilter_queue], [1.0.5])
AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_HOST
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])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC
AM_PROG_CC_C_O
AC_DISABLE_STATIC
AM_PROG_LIBTOOL
AC_PROG_INSTALL
CHECK_GCC_FVISIBILITY
case "$host" in
*-*-linux* | *-*-uclinux*) ;;
*) AC_MSG_ERROR([Linux only, dude!]);;
esac
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 [default=no]])],
[], [with_doxygen=no])
AS_IF([test "x$with_doxygen" = xyes], [
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AC_CHECK_PROGS([DOT], [dot], [""])
AS_IF([test "x$DOT" != "x"],
[AC_SUBST(HAVE_DOT, YES)],
[AC_SUBST(HAVE_DOT, NO)])
])
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
AC_OUTPUT
echo "
libnetfilter_queue configuration:
doxygen: ${with_doxygen}"

View File

@ -0,0 +1,27 @@
# 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 = .
FILE_PATTERNS = *.c
RECURSIVE = YES
EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
tcp_word_hdr \
nfq_handle \
nfq_data \
nfq_q_handle \
tcp_flag_word
EXAMPLE_PATTERNS =
INPUT_FILTER = "sed 's/EXPORT_SYMBOL//g'"
SOURCE_BROWSER = YES
ALPHABETICAL_INDEX = NO
SEARCHENGINE = NO
GENERATE_LATEX = NO
LATEX_CMD_NAME = latex
GENERATE_MAN = YES
HAVE_DOT = @HAVE_DOT@
DOT_TRANSPARENT = YES

View File

@ -0,0 +1,23 @@
if HAVE_DOXYGEN
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/pktbuff.c
doxyfile.stamp: $(doc_srcs) $(top_srcdir)/fixmanpages.sh
rm -rf html man && cd .. && doxygen doxygen.cfg >/dev/null && ./fixmanpages.sh
touch doxyfile.stamp
CLEANFILES = doxyfile.stamp
all-local: doxyfile.stamp
clean-local:
rm -rf $(top_srcdir)/doxygen/man $(top_srcdir)/doxygen/html
install-data-local:
mkdir -p $(DESTDIR)$(mandir)/man3
cp --no-dereference --preserve=links,mode,timestamps man/man3/*.3 $(DESTDIR)$(mandir)/man3/
endif

View File

@ -0,0 +1,7 @@
include ${top_srcdir}/Make_global.am
check_PROGRAMS = nf-queue
nf_queue_SOURCES = nf-queue.c
nf_queue_LDADD = ../src/libnetfilter_queue.la
nf_queue_LDFLAGS = -dynamic -lmnl

View File

@ -0,0 +1,181 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <libmnl/libmnl.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/types.h>
#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
/* only for NFQA_CT, not needed otherwise: */
#include <linux/netfilter/nfnetlink_conntrack.h>
static struct mnl_socket *nl;
static void
nfq_send_verdict(int queue_num, uint32_t id)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
struct nlattr *nest;
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, queue_num);
nfq_nlmsg_verdict_put(nlh, id, NF_ACCEPT);
/* example to set the connmark. First, start NFQA_CT section: */
nest = mnl_attr_nest_start(nlh, NFQA_CT);
/* then, add the connmark attribute: */
mnl_attr_put_u32(nlh, CTA_MARK, htonl(42));
/* more conntrack attributes, e.g. CTA_LABELS could be set here */
/* end conntrack section */
mnl_attr_nest_end(nlh, nest);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
}
static int queue_cb(const struct nlmsghdr *nlh, void *data)
{
struct nfqnl_msg_packet_hdr *ph = NULL;
struct nlattr *attr[NFQA_MAX+1] = {};
uint32_t id = 0, skbinfo;
struct nfgenmsg *nfg;
uint16_t plen;
if (nfq_nlmsg_parse(nlh, attr) < 0) {
perror("problems parsing");
return MNL_CB_ERROR;
}
nfg = mnl_nlmsg_get_payload(nlh);
if (attr[NFQA_PACKET_HDR] == NULL) {
fputs("metaheader not set\n", stderr);
return MNL_CB_ERROR;
}
ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]);
plen = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]);
/* void *payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]); */
skbinfo = attr[NFQA_SKB_INFO] ? ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])) : 0;
if (attr[NFQA_CAP_LEN]) {
uint32_t orig_len = ntohl(mnl_attr_get_u32(attr[NFQA_CAP_LEN]));
if (orig_len != plen)
printf("truncated ");
}
if (skbinfo & NFQA_SKB_GSO)
printf("GSO ");
id = ntohl(ph->packet_id);
printf("packet received (id=%u hw=0x%04x hook=%u, payload len %u",
id, ntohs(ph->hw_protocol), ph->hook, plen);
/*
* ip/tcp checksums are not yet valid, e.g. due to GRO/GSO.
* The application should behave as if the checksums are correct.
*
* If these packets are later forwarded/sent out, the checksums will
* be corrected by kernel/hardware.
*/
if (skbinfo & NFQA_SKB_CSUMNOTREADY)
printf(", checksum not ready");
puts(")");
nfq_send_verdict(ntohs(nfg->res_id), id);
return MNL_CB_OK;
}
int main(int argc, char *argv[])
{
char *buf;
/* largest possible packet payload, plus netlink data overhead: */
size_t sizeof_buf = 0xffff + (MNL_SOCKET_BUFFER_SIZE/2);
struct nlmsghdr *nlh;
int ret;
unsigned int portid, queue_num;
if (argc != 2) {
printf("Usage: %s [queue_num]\n", argv[0]);
exit(EXIT_FAILURE);
}
queue_num = atoi(argv[1]);
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
exit(EXIT_FAILURE);
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
exit(EXIT_FAILURE);
}
portid = mnl_socket_get_portid(nl);
buf = malloc(sizeof_buf);
if (!buf) {
perror("allocate receive buffer");
exit(EXIT_FAILURE);
}
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff);
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(NFQA_CFG_F_GSO));
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(NFQA_CFG_F_GSO));
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
/* ENOBUFS is signalled to userspace when packets were lost
* on kernel side. In most cases, userspace isn't interested
* in this information, so turn it off.
*/
ret = 1;
mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &ret, sizeof(int));
for (;;) {
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, queue_cb, NULL);
if (ret < 0){
perror("mnl_cb_run");
exit(EXIT_FAILURE);
}
}
mnl_socket_close(nl);
return 0;
}

View File

@ -0,0 +1,65 @@
#!/bin/bash -p
#set -x
function main
{
set -e
cd doxygen/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
}
function setgroup
{
mv $1.3 $2.3
BASE=$2
}
function add2group
{
for i in $@
do
ln -sf $BASE.3 $i.3
done
}
main

View File

@ -0,0 +1 @@
SUBDIRS= libnetfilter_queue linux

View File

@ -0,0 +1,7 @@
pkginclude_HEADERS = libnetfilter_queue.h \
linux_nfnetlink_queue.h \
libnetfilter_queue_ipv4.h \
libnetfilter_queue_ipv6.h \
libnetfilter_queue_tcp.h \
libnetfilter_queue_udp.h \
pktbuff.h

View File

@ -0,0 +1,159 @@
/* libnfqnetlink.h: Header file for the Netfilter Queue library.
*
* (C) 2005 by Harald Welte <laforge@gnumonks.org>
*
*
* 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.
*/
#ifndef __LIBCTNETLINK_H
#define __LIBCTNETLINK_H
#include <sys/time.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nfq_handle;
struct nfq_q_handle;
struct nfq_data;
extern int nfq_errno;
extern struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h);
extern int nfq_fd(struct nfq_handle *h);
typedef int nfq_callback(struct nfq_q_handle *gh, struct nfgenmsg *nfmsg,
struct nfq_data *nfad, void *data);
extern struct nfq_handle *nfq_open(void);
extern struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh);
extern int nfq_close(struct nfq_handle *h);
extern int nfq_bind_pf(struct nfq_handle *h, uint16_t pf);
extern int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf);
extern struct nfq_q_handle *nfq_create_queue(struct nfq_handle *h,
uint16_t num,
nfq_callback *cb,
void *data);
extern int nfq_destroy_queue(struct nfq_q_handle *qh);
extern int nfq_handle_packet(struct nfq_handle *h, char *buf, int len);
extern int nfq_set_mode(struct nfq_q_handle *qh,
uint8_t mode, unsigned int len);
int nfq_set_queue_maxlen(struct nfq_q_handle *qh,
uint32_t queuelen);
extern int nfq_set_queue_flags(struct nfq_q_handle *qh,
uint32_t mask, uint32_t flags);
extern int nfq_set_verdict(struct nfq_q_handle *qh,
uint32_t id,
uint32_t verdict,
uint32_t data_len,
const unsigned char *buf);
extern int nfq_set_verdict2(struct nfq_q_handle *qh,
uint32_t id,
uint32_t verdict,
uint32_t mark,
uint32_t datalen,
const unsigned char *buf);
extern int nfq_set_verdict_batch(struct nfq_q_handle *qh,
uint32_t id,
uint32_t verdict);
extern int nfq_set_verdict_batch2(struct nfq_q_handle *qh,
uint32_t id,
uint32_t verdict,
uint32_t mark);
extern __attribute__((deprecated))
int nfq_set_verdict_mark(struct nfq_q_handle *qh,
uint32_t id,
uint32_t verdict,
uint32_t mark,
uint32_t datalen,
const unsigned char *buf);
/* message parsing function */
extern struct nfqnl_msg_packet_hdr *
nfq_get_msg_packet_hdr(struct nfq_data *nfad);
extern uint32_t nfq_get_nfmark(struct nfq_data *nfad);
extern int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv);
/* return 0 if not set */
extern uint32_t nfq_get_indev(struct nfq_data *nfad);
extern uint32_t nfq_get_physindev(struct nfq_data *nfad);
extern uint32_t nfq_get_outdev(struct nfq_data *nfad);
extern uint32_t nfq_get_physoutdev(struct nfq_data *nfad);
extern uint32_t nfq_get_skbinfo(struct nfq_data *nfad);
extern int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid);
extern int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid);
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);
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,
struct nfq_data *nfad, char *name);
extern struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad);
/* return -1 if problem, length otherwise */
extern int nfq_get_payload(struct nfq_data *nfad, unsigned char **data);
enum {
NFQ_XML_HW = (1 << 0),
NFQ_XML_MARK = (1 << 1),
NFQ_XML_DEV = (1 << 2),
NFQ_XML_PHYSDEV = (1 << 3),
NFQ_XML_PAYLOAD = (1 << 4),
NFQ_XML_TIME = (1 << 5),
NFQ_XML_UID = (1 << 6),
NFQ_XML_GID = (1 << 7),
NFQ_XML_SECCTX = (1 << 8),
NFQ_XML_ALL = ~0U,
};
extern int nfq_snprintf_xml(char *buf, size_t len, struct nfq_data *tb, int flags);
/*
* New API based on libmnl
*/
void nfq_nlmsg_cfg_put_cmd(struct nlmsghdr *nlh, uint16_t pf, uint8_t cmd);
void nfq_nlmsg_cfg_put_params(struct nlmsghdr *nlh, uint8_t mode, int range);
void nfq_nlmsg_cfg_put_qmaxlen(struct nlmsghdr *nlh, uint32_t qmaxlen);
void nfq_nlmsg_verdict_put(struct nlmsghdr *nlh, int id, int verdict);
void nfq_nlmsg_verdict_put_mark(struct nlmsghdr *nlh, uint32_t mark);
void nfq_nlmsg_verdict_put_pkt(struct nlmsghdr *nlh, const void *pkt, uint32_t pktlen);
int nfq_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr **attr);
struct nlmsghdr *nfq_nlmsg_put(char *buf, int type, uint32_t queue_num);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __LIBNFQNETLINK_H */

View File

@ -0,0 +1,13 @@
#ifndef _LIBNFQUEUE_IPV4_
#define _LIBNFQUEUE_IPV4_
struct pkt_buff;
struct iphdr;
struct iphdr *nfq_ip_get_hdr(struct pkt_buff *pktb);
int nfq_ip_set_transport_header(struct pkt_buff *pktb, struct iphdr *iph);
void nfq_ip_set_checksum(struct iphdr *iph);
int nfq_ip_mangle(struct pkt_buff *pktb, unsigned int dataoff, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len);
int nfq_ip_snprintf(char *buf, size_t size, const struct iphdr *iph);
#endif

View File

@ -0,0 +1,12 @@
#ifndef _LIBNFQUEUE_H_
#define _LIBNFQUEUE_H_
struct pkt_buff;
struct ip6_hdr;
struct ip6_hdr *nfq_ip6_get_hdr(struct pkt_buff *pktb);
int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *iph, uint8_t target);
int nfq_ip6_mangle(struct pkt_buff *pktb, unsigned int dataoff,unsigned int match_offset, unsigned int match_len,const char *rep_buffer, unsigned int rep_len);
int nfq_ip6_snprintf(char *buf, size_t size, const struct ip6_hdr *ip6h);
#endif

View File

@ -0,0 +1,21 @@
#ifndef _LIBNFQUEUE_TCP_H_
#define _LIBNFQUEUE_TCP_H_
struct pkt_buff;
struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb);
void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb);
unsigned int nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb);
struct iphdr;
struct ip6_hdr;
void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph);
void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h);
int nfq_tcp_mangle_ipv4(struct pkt_buff *pktb, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len);
int nfq_tcp_mangle_ipv6(struct pkt_buff *pktb, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len);
int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcp);
#endif

View File

@ -0,0 +1,18 @@
#ifndef _LIBNFQUEUE_UDP_H_
#define _LIBNFQUEUE_UDP_H_
struct pkt_buff;
struct udphdr *nfq_udp_get_hdr(struct pkt_buff *pktb);
void *nfq_udp_get_payload(struct udphdr *udph, struct pkt_buff *pktb);
unsigned int nfq_udp_get_payload_len(struct udphdr *udph, struct pkt_buff *pktb);
void nfq_udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph);
void nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h);
int nfq_udp_mangle_ipv4(struct pkt_buff *pktb, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len);
int nfq_udp_mangle_ipv6(struct pkt_buff *pktb, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len);
int nfq_udp_snprintf(char *buf, size_t size, const struct udphdr *udp);
#endif

View File

@ -0,0 +1,121 @@
#ifndef _NFNETLINK_QUEUE_H
#define _NFNETLINK_QUEUE_H
#ifndef aligned_u64
#define aligned_u64 unsigned long long __attribute__((aligned(8)))
#endif
#include <linux/types.h>
#include <libnfnetlink/linux_nfnetlink.h>
enum nfqnl_msg_types {
NFQNL_MSG_PACKET, /* packet from kernel to userspace */
NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */
NFQNL_MSG_CONFIG, /* connect to a particular queue */
NFQNL_MSG_VERDICT_BATCH, /* batchv from userspace to kernel */
NFQNL_MSG_MAX
};
struct nfqnl_msg_packet_hdr {
__be32 packet_id; /* unique ID of packet in queue */
__be16 hw_protocol; /* hw protocol (network order) */
__u8 hook; /* netfilter hook */
} __attribute__ ((packed));
struct nfqnl_msg_packet_hw {
__be16 hw_addrlen;
__u16 _pad;
__u8 hw_addr[8];
};
struct nfqnl_msg_packet_timestamp {
__aligned_be64 sec;
__aligned_be64 usec;
};
enum nfqnl_attr_type {
NFQA_UNSPEC,
NFQA_PACKET_HDR,
NFQA_VERDICT_HDR, /* nfqnl_msg_verdict_hrd */
NFQA_MARK, /* __u32 nfmark */
NFQA_TIMESTAMP, /* nfqnl_msg_packet_timestamp */
NFQA_IFINDEX_INDEV, /* __u32 ifindex */
NFQA_IFINDEX_OUTDEV, /* __u32 ifindex */
NFQA_IFINDEX_PHYSINDEV, /* __u32 ifindex */
NFQA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */
NFQA_HWADDR, /* nfqnl_msg_packet_hw */
NFQA_PAYLOAD, /* opaque data payload */
NFQA_CT, /* nf_conntrack_netlink.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_UID, /* __u32 sk uid */
NFQA_GID, /* __u32 sk gid */
NFQA_SECCTX, /* security context string */
__NFQA_MAX
};
#define NFQA_MAX (__NFQA_MAX - 1)
struct nfqnl_msg_verdict_hdr {
__be32 verdict;
__be32 id;
};
enum nfqnl_msg_config_cmds {
NFQNL_CFG_CMD_NONE,
NFQNL_CFG_CMD_BIND,
NFQNL_CFG_CMD_UNBIND,
NFQNL_CFG_CMD_PF_BIND,
NFQNL_CFG_CMD_PF_UNBIND,
};
struct nfqnl_msg_config_cmd {
__u8 command; /* nfqnl_msg_config_cmds */
__u8 _pad;
__be16 pf; /* AF_xxx for PF_[UN]BIND */
};
enum nfqnl_config_mode {
NFQNL_COPY_NONE,
NFQNL_COPY_META,
NFQNL_COPY_PACKET,
};
struct nfqnl_msg_config_params {
__be32 copy_range;
__u8 copy_mode; /* enum nfqnl_config_mode */
} __attribute__ ((packed));
enum nfqnl_attr_config {
NFQA_CFG_UNSPEC,
NFQA_CFG_CMD, /* nfqnl_msg_config_cmd */
NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */
NFQA_CFG_QUEUE_MAXLEN, /* __u32 */
NFQA_CFG_MASK, /* identify which flags to change */
NFQA_CFG_FLAGS, /* value of these flags (__u32) */
__NFQA_CFG_MAX
};
#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
/* Flags for NFQA_CFG_FLAGS */
#define NFQA_CFG_F_FAIL_OPEN (1 << 0)
#define NFQA_CFG_F_CONNTRACK (1 << 1)
#define NFQA_CFG_F_GSO (1 << 2)
#define NFQA_CFG_F_UID_GID (1 << 3)
#define NFQA_CFG_F_SECCTX (1 << 4)
#define NFQA_CFG_F_MAX (1 << 5)
/* flags for NFQA_SKB_INFO */
/* packet appears to have wrong checksums, but they are ok */
#define NFQA_SKB_CSUMNOTREADY (1 << 0)
/* packet is GSO (i.e., exceeds device mtu) */
#define NFQA_SKB_GSO (1 << 1)
/* csum not validated (incoming device doesn't support hw checksum, etc.) */
#define NFQA_SKB_CSUM_NOTVERIFIED (1 << 2)
#endif /* _NFNETLINK_QUEUE_H */

View File

@ -0,0 +1,26 @@
#ifndef _PKTBUFF_H_
#define _PKTBUFF_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);
uint8_t *pktb_data(struct pkt_buff *pktb);
uint32_t pktb_len(struct pkt_buff *pktb);
void pktb_push(struct pkt_buff *pktb, unsigned int len);
void pktb_pull(struct pkt_buff *pktb, unsigned int len);
void pktb_put(struct pkt_buff *pktb, unsigned int len);
void pktb_trim(struct pkt_buff *pktb, unsigned int len);
unsigned int pktb_tailroom(struct pkt_buff *pktb);
uint8_t *pktb_mac_header(struct pkt_buff *pktb);
uint8_t *pktb_network_header(struct pkt_buff *pktb);
uint8_t *pktb_transport_header(struct pkt_buff *pktb);
int pktb_mangle(struct pkt_buff *pktb, int dataoff, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len);
bool pktb_mangled(const struct pkt_buff *pktb);
#endif

View File

@ -0,0 +1 @@
SUBDIRS = netfilter

View File

@ -0,0 +1 @@
noinst_HEADERS = nfnetlink_queue.h

View File

@ -0,0 +1,115 @@
#ifndef _NFNETLINK_QUEUE_H
#define _NFNETLINK_QUEUE_H
#include <linux/types.h>
#include <linux/netfilter/nfnetlink.h>
enum nfqnl_msg_types {
NFQNL_MSG_PACKET, /* packet from kernel to userspace */
NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */
NFQNL_MSG_CONFIG, /* connect to a particular queue */
NFQNL_MSG_VERDICT_BATCH, /* batchv from userspace to kernel */
NFQNL_MSG_MAX
};
struct nfqnl_msg_packet_hdr {
__be32 packet_id; /* unique ID of packet in queue */
__be16 hw_protocol; /* hw protocol (network order) */
__u8 hook; /* netfilter hook */
} __attribute__ ((packed));
struct nfqnl_msg_packet_hw {
__be16 hw_addrlen;
__u16 _pad;
__u8 hw_addr[8];
};
struct nfqnl_msg_packet_timestamp {
__aligned_be64 sec;
__aligned_be64 usec;
};
enum nfqnl_attr_type {
NFQA_UNSPEC,
NFQA_PACKET_HDR,
NFQA_VERDICT_HDR, /* nfqnl_msg_verdict_hrd */
NFQA_MARK, /* __u32 nfmark */
NFQA_TIMESTAMP, /* nfqnl_msg_packet_timestamp */
NFQA_IFINDEX_INDEV, /* __u32 ifindex */
NFQA_IFINDEX_OUTDEV, /* __u32 ifindex */
NFQA_IFINDEX_PHYSINDEV, /* __u32 ifindex */
NFQA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */
NFQA_HWADDR, /* nfqnl_msg_packet_hw */
NFQA_PAYLOAD, /* opaque data payload */
NFQA_CT, /* nf_conntrack_netlink.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_UID, /* __u32 sk uid */
NFQA_GID, /* __u32 sk gid */
NFQA_SECCTX,
__NFQA_MAX
};
#define NFQA_MAX (__NFQA_MAX - 1)
struct nfqnl_msg_verdict_hdr {
__be32 verdict;
__be32 id;
};
enum nfqnl_msg_config_cmds {
NFQNL_CFG_CMD_NONE,
NFQNL_CFG_CMD_BIND,
NFQNL_CFG_CMD_UNBIND,
NFQNL_CFG_CMD_PF_BIND,
NFQNL_CFG_CMD_PF_UNBIND,
};
struct nfqnl_msg_config_cmd {
__u8 command; /* nfqnl_msg_config_cmds */
__u8 _pad;
__be16 pf; /* AF_xxx for PF_[UN]BIND */
};
enum nfqnl_config_mode {
NFQNL_COPY_NONE,
NFQNL_COPY_META,
NFQNL_COPY_PACKET,
};
struct nfqnl_msg_config_params {
__be32 copy_range;
__u8 copy_mode; /* enum nfqnl_config_mode */
} __attribute__ ((packed));
enum nfqnl_attr_config {
NFQA_CFG_UNSPEC,
NFQA_CFG_CMD, /* nfqnl_msg_config_cmd */
NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */
NFQA_CFG_QUEUE_MAXLEN, /* __u32 */
NFQA_CFG_MASK, /* identify which flags to change */
NFQA_CFG_FLAGS, /* value of these flags (__u32) */
__NFQA_CFG_MAX
};
#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
/* Flags for NFQA_CFG_FLAGS */
#define NFQA_CFG_F_FAIL_OPEN (1 << 0)
#define NFQA_CFG_F_CONNTRACK (1 << 1)
#define NFQA_CFG_F_GSO (1 << 2)
#define NFQA_CFG_F_UID_GID (1 << 3)
#define NFQA_CFG_F_SECCTX (1 << 4)
#define NFQA_CFG_F_MAX (1 << 5)
/* flags for NFQA_SKB_INFO */
/* packet appears to have wrong checksums, but they are ok */
#define NFQA_SKB_CSUMNOTREADY (1 << 0)
/* packet is GSO (i.e., exceeds device mtu) */
#define NFQA_SKB_GSO (1 << 1)
#endif /* _NFNETLINK_QUEUE_H */

View File

@ -0,0 +1,16 @@
# libnetfilter_queue pkg-config file
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libnetfilter_queue
Description: netfilter userspace packet queueing library
URL: http://netfilter.org/projects/libnetfilter_queue/
Version: @VERSION@
Requires: libnfnetlink
Conflicts:
Libs: -L${libdir} -lnetfilter_queue
Libs.private: @LIBNFNETLINK_LIBS@
Cflags: -I${includedir}

2
ref/libnetfilter-queue/m4/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/libtool.m4
/lt*.m4

View File

@ -0,0 +1,21 @@
# GCC 4.x -fvisibility=hidden
AC_DEFUN([CHECK_GCC_FVISIBILITY], [
AC_LANG_PUSH([C])
saved_CFLAGS="$CFLAGS"
CFLAGS="$saved_CFLAGS -fvisibility=hidden"
AC_CACHE_CHECK([whether compiler accepts -fvisibility=hidden],
[ac_cv_fvisibility_hidden], AC_COMPILE_IFELSE(
[AC_LANG_SOURCE()],
[ac_cv_fvisibility_hidden=yes],
[ac_cv_fvisibility_hidden=no]
))
if test "$ac_cv_fvisibility_hidden" = "yes"; then
AC_DEFINE([HAVE_VISIBILITY_HIDDEN], [1],
[True if compiler supports -fvisibility=hidden])
AC_SUBST([GCC_FVISIBILITY_HIDDEN], [-fvisibility=hidden])
fi
CFLAGS="$saved_CFLAGS"
AC_LANG_POP([C])
])

View File

@ -0,0 +1,40 @@
# This is _NOT_ the library release version, it's an API version.
# Extracted from Chapter 6 "Library interface versions" of the libtool docs.
#
# <snippet>
# Here are a set of rules to help you update your library version information:
#
# 1. Start with version information of `0:0:0' for each libtool library.
# 2. Update the version information only immediately before a public release
# of your software. More frequent updates are unnecessary, and only guarantee
# that the current interface number gets larger faster.
# 3. If the library source code has changed at all since the last update,
# then increment revision (`c:r:a' becomes `c:r+1:a').
# 4. If any interfaces have been added, removed, or changed since the last
# update, increment current, and set revision to 0.
# 5. If any interfaces have been added since the last public release, then
# increment age.
# 6. If any interfaces have been removed since the last public release, then
# set age to 0.
# </snippet>
#
LIBVERSION=6:0:5
include ${top_srcdir}/Make_global.am
lib_LTLIBRARIES = libnetfilter_queue.la
noinst_HEADERS = internal.h
libnetfilter_queue_la_LDFLAGS = -Wc,-nostartfiles -lnfnetlink \
-version-info $(LIBVERSION)
libnetfilter_queue_la_SOURCES = libnetfilter_queue.c \
nlmsg.c \
extra/checksum.c \
extra/ipv6.c \
extra/tcp.c \
extra/ipv4.c \
extra/pktbuff.c \
extra/udp.c
libnetfilter_queue_la_LIBADD = ${LIBNFNETLINK_LIBS} ${LIBMNL_LIBS}

View File

@ -0,0 +1,82 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
#include <stdio.h>
#include <stdbool.h>
#include <endian.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
uint16_t nfq_checksum(uint32_t sum, uint16_t *buf, int size)
{
while (size > 1) {
sum += *buf++;
size -= sizeof(uint16_t);
}
if (size) {
#if __BYTE_ORDER == __BIG_ENDIAN
sum += (uint16_t)*(uint8_t *)buf << 8;
#else
sum += (uint16_t)*(uint8_t *)buf;
#endif
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >>16);
return (uint16_t)(~sum);
}
uint16_t nfq_checksum_tcpudp_ipv4(struct iphdr *iph, uint16_t protonum)
{
uint32_t sum = 0;
uint32_t iph_len = iph->ihl*4;
uint32_t len = ntohs(iph->tot_len) - iph_len;
uint8_t *payload = (uint8_t *)iph + iph_len;
sum += (iph->saddr >> 16) & 0xFFFF;
sum += (iph->saddr) & 0xFFFF;
sum += (iph->daddr >> 16) & 0xFFFF;
sum += (iph->daddr) & 0xFFFF;
sum += htons(protonum);
sum += htons(len);
return nfq_checksum(sum, (uint16_t *)payload, len);
}
uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr,
uint16_t protonum)
{
uint32_t sum = 0;
uint32_t hdr_len = (uint8_t *)transport_hdr - (uint8_t *)ip6h;
/* Allow for extra headers before the UDP header */
/* TODO: Deal with routing headers */
uint32_t len = ntohs(ip6h->ip6_plen) - (hdr_len - sizeof *ip6h);
uint8_t *payload = (uint8_t *)ip6h + hdr_len;
int i;
for (i=0; i<8; i++) {
sum += (ip6h->ip6_src.s6_addr16[i]);
}
for (i=0; i<8; i++) {
sum += (ip6h->ip6_dst.s6_addr16[i]);
}
sum += htons(protonum);
sum += htons(len);
return nfq_checksum(sum, (uint16_t *)payload, len);
}

View File

@ -0,0 +1,175 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
#include <stdio.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/pktbuff.h>
#include "internal.h"
/**
* \defgroup ipv4 IPv4 helper functions
* @{
*/
/**
* nfq_ip_get_hdr - get the IPv4 header
* \param pktb: Pointer to user-space network packet buffer
* \returns validated pointer to the IPv4 header or NULL if IP is malformed or
* not version 4
*
* Many programs will not need to call this function. A possible use is to
* determine the layer 4 protocol. The validation is that the buffer is big
* enough for the declared lengths in the header, i.e. an extra check for packet
* truncation.
*/
EXPORT_SYMBOL
struct iphdr *nfq_ip_get_hdr(struct pkt_buff *pktb)
{
struct iphdr *iph;
unsigned int pktlen = pktb_tail(pktb) - pktb->network_header;
/* Not enough room for IPv4 header. */
if (pktlen < sizeof(struct iphdr))
return NULL;
iph = (struct iphdr *)pktb->network_header;
/* Not IPv4 packet. */
if (iph->version != 4)
return NULL;
/* Malformed IPv4 total length field. */
if (ntohs(iph->tot_len) > pktlen)
return NULL;
return iph;
}
/**
* nfq_ip_set_transport_header - set the \b transport_header field in \b pktb
* \param pktb: Pointer to user-space network packet buffer
* \param iph: Pointer to the IPv4 header
* \returns 0 on success or -1 if a minimal validation check fails
* \note
* Most programs should call __nfq_ip_set_transport_header__ as soon as
* possible, since most layer 4 helper functions assume the
* \b transport_header field is valid.
*/
EXPORT_SYMBOL
int nfq_ip_set_transport_header(struct pkt_buff *pktb, struct iphdr *iph)
{
int doff = iph->ihl * 4;
/* Wrong offset to IPv4 payload. */
if ((int)pktb->len - doff <= 0)
return -1;
pktb->transport_header = pktb->network_header + doff;
return 0;
}
/**
* \defgroup ip_internals Internal IP functions
*
* Most user-space programs will never need these.
*
* @{
*/
/**
* nfq_ip_set_checksum - set IPv4 checksum
* \param iph: Pointer to the IPv4 header
* \note
* nfq_ip_mangle() invokes this function.
* As long as developers always use the appropriate mangler for the layer being
* mangled, there is no need to call __nfq_ip_set_checksum__.
*/
EXPORT_SYMBOL
void nfq_ip_set_checksum(struct iphdr *iph)
{
uint32_t iph_len = iph->ihl * 4;
iph->check = 0;
iph->check = nfq_checksum(0, (uint16_t *)iph, iph_len);
}
/**
* @}
*/
/**
* nfq_ip_mangle - mangle IPv4 packet buffer
* \param pktb: Pointer to user-space network packet buffer
* \param dataoff: Offset to layer 4 header, or zero to mangle IP header
* \param match_offset: Offset to content that you want to mangle
* \param match_len: Length of the existing content you want to mangle
* \param rep_buffer: Pointer to data you want to use to replace current content
* \param rep_len: Length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
* \note This function updates the IPv4 length if necessary and recalculates the
* IPv4 checksum.
*/
EXPORT_SYMBOL
int nfq_ip_mangle(struct pkt_buff *pktb, unsigned int dataoff,
unsigned int match_offset, unsigned int match_len,
const char *rep_buffer, unsigned int rep_len)
{
struct iphdr *iph = (struct iphdr *) pktb->network_header;
if (!pktb_mangle(pktb, dataoff, match_offset, match_len, rep_buffer,
rep_len))
return 0;
/* fix IP hdr checksum information */
iph->tot_len = htons(pktb_tail(pktb) - pktb->network_header);
nfq_ip_set_checksum(iph);
return 1;
}
/**
* nfq_pkt_snprintf_ip - 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
* \returns same as snprintf
* \sa **snprintf**(3)
*/
EXPORT_SYMBOL
int nfq_ip_snprintf(char *buf, size_t size, const struct iphdr *iph)
{
int ret;
struct in_addr src = { iph->saddr };
struct in_addr dst = { iph->daddr };
char src_str[INET_ADDRSTRLEN];
char dst_str[INET_ADDRSTRLEN];
ret = snprintf(buf, size, "SRC=%s DST=%s LEN=%u TOS=0x%X "
"PREC=0x%X TTL=%u ID=%u PROTO=%u ",
inet_ntop(AF_INET, &src, src_str, INET_ADDRSTRLEN),
inet_ntop(AF_INET, &dst, dst_str, INET_ADDRSTRLEN),
ntohs(iph->tot_len), IPTOS_TOS(iph->tos),
IPTOS_PREC(iph->tos), iph->ttl, ntohs(iph->id),
iph->protocol);
return ret;
}
/**
* @}
*/

View File

@ -0,0 +1,180 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip6.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
#include <libnetfilter_queue/pktbuff.h>
#include "internal.h"
/**
* \defgroup ipv6 IPv6 helper functions
* @{
*/
/**
* nfq_ip6_get_hdr - get IPv6 header
* \param pktb: Pointer to user-space network packet buffer
*
* \returns pointer to IPv6 header if a valid header found, else NULL.
*/
EXPORT_SYMBOL
struct ip6_hdr *nfq_ip6_get_hdr(struct pkt_buff *pktb)
{
struct ip6_hdr *ip6h;
unsigned int pktlen = pktb_tail(pktb) - pktb->network_header;
/* Not enough room for IPv6 header. */
if (pktlen < sizeof(struct ip6_hdr))
return NULL;
ip6h = (struct ip6_hdr *)pktb->network_header;
/* Not IPv6 packet. */
if ((*(uint8_t *)ip6h & 0xf0) != 0x60)
return NULL;
return ip6h;
}
/**
* nfq_ip6_set_transport_header - set transport header pointer for IPv6 packet
* \param pktb: Pointer to user-space network packet buffer
* \param ip6h: Pointer to IPv6 header
* \param target: Protocol number to find transport header (ie. IPPROTO_*)
*
* \returns 1 if the protocol has been found and the transport
* header has been set, else 0.
*/
EXPORT_SYMBOL
int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *ip6h,
uint8_t target)
{
uint8_t nexthdr = ip6h->ip6_nxt;
uint8_t *cur = (uint8_t *)ip6h + sizeof(struct ip6_hdr);
while (nexthdr != target) {
struct ip6_ext *ip6_ext;
uint32_t hdrlen;
/* No more extensions, we're done. */
if (nexthdr == IPPROTO_NONE) {
cur = NULL;
break;
}
/* No room for extension, bad packet. */
if (pktb_tail(pktb) - cur < sizeof(struct ip6_ext)) {
cur = NULL;
break;
}
ip6_ext = (struct ip6_ext *)cur;
if (nexthdr == IPPROTO_FRAGMENT) {
uint16_t *frag_off;
/* No room for full fragment header, bad packet. */
if (pktb_tail(pktb) - cur < sizeof(struct ip6_frag)) {
cur = NULL;
break;
}
frag_off = (uint16_t *)cur +
offsetof(struct ip6_frag, ip6f_offlg);
/* Fragment offset is only 13 bits long. */
if (htons(*frag_off & ~0x7)) {
/* Not the first fragment, it does not contain
* any headers.
*/
cur = NULL;
break;
}
hdrlen = sizeof(struct ip6_frag);
} else if (nexthdr == IPPROTO_AH)
hdrlen = (ip6_ext->ip6e_len + 2) << 2;
else
hdrlen = ip6_ext->ip6e_len;
nexthdr = ip6_ext->ip6e_nxt;
cur += hdrlen;
}
pktb->transport_header = cur;
return cur ? 1 : 0;
}
/**
* nfq_ip6_mangle - mangle IPv6 packet buffer
* \param pktb: Pointer to user-space network packet buffer
* \param dataoff: Offset to layer 4 header
* \param match_offset: Offset to content that you want to mangle
* \param match_len: Length of the existing content you want to mangle
* \param rep_buffer: Pointer to data you want to use to replace current content
* \param rep_len: Length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
* \note This function updates the IPv6 length (if necessary)
*/
EXPORT_SYMBOL
int nfq_ip6_mangle(struct pkt_buff *pktb, unsigned int dataoff,
unsigned int match_offset, unsigned int match_len,
const char *rep_buffer, unsigned int rep_len)
{
struct ip6_hdr *ip6h = (struct ip6_hdr *)pktb->network_header;
if (!pktb_mangle(pktb, dataoff, match_offset, match_len, rep_buffer,
rep_len))
return 0;
/* Fix IPv6 hdr length information */
ip6h->ip6_plen =
htons(pktb_tail(pktb) - pktb->network_header - sizeof *ip6h);
return 1;
}
/**
* nfq_ip6_snprintf - print IPv6 header into one buffer in iptables LOG format
* \param buf: Pointer to buffer that is used to print the object
* \param size: Size of the buffer (or remaining room in it).
* \param ip6h: Pointer to a valid IPv6 header.
* \returns same as snprintf
* \sa **snprintf**(3)
*
*/
EXPORT_SYMBOL
int nfq_ip6_snprintf(char *buf, size_t size, const struct ip6_hdr *ip6h)
{
int ret;
char src[INET6_ADDRSTRLEN];
char dst[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ip6h->ip6_src, src, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &ip6h->ip6_dst, dst, INET6_ADDRSTRLEN);
ret = snprintf(buf, size, "SRC=%s DST=%s LEN=%zu TC=0x%X "
"HOPLIMIT=%u FLOWLBL=%u ",
src, dst,
ntohs(ip6h->ip6_plen) + sizeof(struct ip6_hdr),
(ip6h->ip6_flow & 0x0ff00000) >> 20,
ip6h->ip6_hlim,
(ip6h->ip6_flow & 0x000fffff));
return ret;
}
/**
* @}
*/

View File

@ -0,0 +1,366 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h> /* for memcpy */
#include <stdbool.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include "internal.h"
/**
* \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.
*
* @{
*/
/**
* pktb_alloc - allocate a new packet buffer
* \param family Indicate what family. Currently supported families are
* AF_BRIDGE, AF_INET & AF_INET6.
* \param data Pointer to packet data
* \param len Packet length
* \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).
*
* \return Pointer to a new userspace packet buffer or NULL on failure.
* \par Errors
* __ENOMEM__ From __calloc__()
* \n
* __EPROTONOSUPPORT__ _family_ was __AF_BRIDGE__ and this is not an IP packet
* (v4 or v6)
* \sa __calloc__(3)
*/
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);
if (pktb == NULL)
return NULL;
/* Better make sure alignment is correct. */
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;
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;
free(pktb);
return NULL;
}
break;
}
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__
* \par
* It is appropriate to use _pktb_data_ as the second argument of
* nfq_nlmsg_verdict_put_pkt()
*/
EXPORT_SYMBOL
uint8_t *pktb_data(struct pkt_buff *pktb)
{
return pktb->data;
}
/**
* pktb_len - get length of packet buffer
* \param pktb Pointer to userspace packet buffer
* \return Length of packet contained within __pktb__
* \par
* It is appropriate to use _pktb_len_ as the third argument of
* nfq_nlmsg_verdict_put_pkt()
*/
EXPORT_SYMBOL
uint32_t pktb_len(struct pkt_buff *pktb)
{
return pktb->len;
}
/**
* pktb_free - release packet buffer
* \param pktb Pointer to userspace packet buffer
*/
EXPORT_SYMBOL
void pktb_free(struct pkt_buff *pktb)
{
free(pktb);
}
/**
* \defgroup otherfns Other functions
*
* The library provides a number of other functions which many user-space
* programs will never need. These divide into 2 groups:
* \n
* 1. Functions to get values of members of opaque __struct pktbuff__, described
* below
* \n
* 2. Internal functions, described in Module __Internal functions__
*
* @{
*/
/**
* \defgroup uselessfns Internal functions
*
* \warning 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.
*
* @{
*/
/**
* pktb_push - decrement pointer to packet buffer
* \param pktb Pointer to userspace packet buffer
* \param len Number of bytes to subtract from packet start address
*/
EXPORT_SYMBOL
void pktb_push(struct pkt_buff *pktb, unsigned int len)
{
pktb->data -= len;
pktb->len += len;
}
/**
* pktb_pull - increment pointer to packet buffer
* \param pktb Pointer to userspace packet buffer
* \param len Number of bytes to add to packet start address
*/
EXPORT_SYMBOL
void pktb_pull(struct pkt_buff *pktb, unsigned int len)
{
pktb->data += len;
pktb->len -= len;
}
/**
* pktb_put - add extra bytes to the tail of the packet buffer
* \param pktb Pointer to userspace packet buffer
* \param len Number of bytes to add to packet tail (and length)
*/
EXPORT_SYMBOL
void pktb_put(struct pkt_buff *pktb, unsigned int len)
{
pktb->len += len;
}
/**
* pktb_trim - set new length for this packet buffer
* \param pktb Pointer to userspace packet buffer
* \param len New packet length (tail is adjusted to reflect this)
*/
EXPORT_SYMBOL
void pktb_trim(struct pkt_buff *pktb, unsigned int len)
{
pktb->len = len;
}
/**
* @}
*/
/**
* pktb_tailroom - get room available for packet expansion
* \param pktb Pointer to userspace packet buffer
* \return room in bytes after the tail of the packet buffer
* \n
* This starts off as the __extra__ argument to pktb_alloc().
* Programmers should ensure this __extra__ argument is sufficient for any
* packet mangle, as packet buffers cannot be expanded dynamically.
*/
EXPORT_SYMBOL
unsigned int pktb_tailroom(struct pkt_buff *pktb)
{
return pktb->data_len - pktb->len;
}
/**
* pktb_mac_header - get address of layer 2 header (if any)
* \param pktb Pointer to userspace packet buffer
* \return Pointer to MAC header or NULL if no such header present.
* \n
* Only packet buffers in family __AF_BRIDGE__ have a non-NULL MAC header.
*/
EXPORT_SYMBOL
uint8_t *pktb_mac_header(struct pkt_buff *pktb)
{
return pktb->mac_header;
}
/**
* pktb_network_header - get address of layer 3 header
* \param pktb Pointer to userspace packet buffer
* \return Pointer to layer 3 header or NULL if the packet buffer was created
* with an unsupported family
*/
EXPORT_SYMBOL
uint8_t *pktb_network_header(struct pkt_buff *pktb)
{
return pktb->network_header;
}
/**
* pktb_transport_header - get address of layer 4 header (if known)
* \param pktb Pointer to userspace packet buffer
* \return Pointer to layer 4 header or NULL if not (yet) set
* \note
* Unlike the lower-level headers, it is the programmer's responsibility to
* create the level 4 (transport) header pointer by caling e.g.
* nfq_ip_set_transport_header()
*/
EXPORT_SYMBOL
uint8_t *pktb_transport_header(struct pkt_buff *pktb)
{
return pktb->transport_header;
}
/**
* @}
*/
static int pktb_expand_tail(struct pkt_buff *pktb, int extra)
{
/* No room in packet, cannot mangle it. We don't support dynamic
* reallocation. Instead, increase the size of the extra room in
* the tail in pktb_alloc.
*/
if (pktb->len + extra > pktb->data_len)
return 0;
pktb->len += extra;
return 1;
}
static int enlarge_pkt(struct pkt_buff *pktb, unsigned int extra)
{
if (pktb->len + extra > 65535)
return 0;
if (!pktb_expand_tail(pktb, extra - pktb_tailroom(pktb)))
return 0;
return 1;
}
/**
* pktb_mangle - adjust contents of a packet
* \param pktb Pointer to userspace packet buffer
* \param dataoff Supplementary offset, usually offset from layer 3 (IP) header
* to the layer 4 (TCP or UDP) header. Specify zero to access the layer 3
* header. If \b pktb was created in family \b AF_BRIDGE, specify
* \b -ETH_HLEN (a negative offset) to access the layer 2 (MAC) header.
* \param match_offset Further offset to content that you want to mangle
* \param match_len Length of the existing content you want to mangle
* \param rep_buffer Pointer to data you want to use to replace current content
* \param rep_len Length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. Failure will occur if the \b extra
* argument to the pktb_alloc() call that created \b pktb is less than the
* 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.
\n
It is appropriate to use pktb_mangle to change the MAC header.
*/
EXPORT_SYMBOL
int pktb_mangle(struct pkt_buff *pktb,
int dataoff,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len)
{
unsigned char *data;
if (rep_len > match_len &&
rep_len - match_len > pktb_tailroom(pktb) &&
!enlarge_pkt(pktb, rep_len - match_len))
return 0;
data = pktb->network_header + dataoff;
/* move post-replacement */
memmove(data + match_offset + rep_len,
data + match_offset + match_len,
pktb_tail(pktb) - (pktb->network_header + dataoff +
match_offset + match_len));
/* insert data from buffer */
memcpy(data + match_offset, rep_buffer, rep_len);
/* update packet info */
if (rep_len > match_len)
pktb_put(pktb, rep_len - match_len);
else
pktb_trim(pktb, pktb->len + rep_len - match_len);
pktb->mangled = true;
return 1;
}
/**
* pktb_mangled - test whether packet has been mangled
* \param pktb Pointer to userspace packet buffer
* \return __true__ if packet has been mangled (modified), else __false__
* \par
* When assembling a verdict, it is not necessary to return the contents of
* un-modified packets. Use _pktb_mangled_ to decide whether packet contents
* need to be returned.
*/
EXPORT_SYMBOL
bool pktb_mangled(const struct pkt_buff *pktb)
{
return pktb->mangled;
}
/**
* @}
*/

View File

@ -0,0 +1,279 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
#include <stdio.h>
#include <string.h> /* for memcpy */
#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#define _GNU_SOURCE
#include <netinet/tcp.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
#include <libnetfilter_queue/pktbuff.h>
#include "internal.h"
/**
* \defgroup tcp TCP helper functions
* @{
*/
/**
* nfq_tcp_get_hdr - get the TCP header
* \param pktb: pointer to user-space network packet buffer
* \returns validated pointer to the TCP header or NULL if the TCP header was
* not set or if a minimal length check fails.
* \note You have to call nfq_ip_set_transport_header() or
* nfq_ip6_set_transport_header() first to set the TCP header.
*/
EXPORT_SYMBOL
struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb)
{
if (pktb->transport_header == NULL)
return NULL;
/* No room for the TCP header. */
if (pktb_tail(pktb) - pktb->transport_header < sizeof(struct tcphdr))
return NULL;
return (struct tcphdr *)pktb->transport_header;
}
/**
* nfq_tcp_get_payload - get the TCP packet payload
* \param tcph: pointer to the TCP header
* \param pktb: pointer to user-space network packet buffer
* \returns Pointer to the TCP payload, or NULL if malformed TCP packet.
*/
EXPORT_SYMBOL
void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
{
unsigned int len = tcph->doff * 4;
/* TCP packet is too short */
if (len < sizeof(struct tcphdr))
return NULL;
/* malformed TCP data offset. */
if (pktb->transport_header + len > pktb_tail(pktb))
return NULL;
return pktb->transport_header + len;
}
/**
* nfq_tcp_get_payload_len - get the tcp packet payload
* \param tcph: pointer to the TCP header
* \param pktb: pointer to user-space network packet buffer
* \returns Length of TCP payload (user data)
*/
EXPORT_SYMBOL
unsigned int nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb)
{
return pktb_tail(pktb) - pktb->transport_header - (tcph->doff * 4);
}
/**
* \defgroup tcp_internals Internal TCP functions
*
* Most user-space programs will never need these.
*
* @{
*/
/**
* nfq_tcp_compute_checksum_ipv4 - computes IPv4/TCP packet checksum
* \param tcph: pointer to the TCP header
* \param iph: pointer to the IPv4 header
* \note
* nfq_tcp_mangle_ipv4() invokes this function.
* As long as developers always use __nfq_tcp_mangle_ipv4__ when changing the
* content of a TCP message, there is no need to call
* __nfq_tcp_compute_checksum_ipv4__.
*/
EXPORT_SYMBOL
void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
{
/* checksum field in header needs to be zero for calculation. */
tcph->check = 0;
tcph->check = nfq_checksum_tcpudp_ipv4(iph, IPPROTO_TCP);
}
/**
* nfq_tcp_compute_checksum_ipv6 - computes IPv6/TCP packet checksum
* \param tcph: pointer to the TCP header
* \param ip6h: pointer to the IPv6 header
* \note
* nfq_tcp_mangle_ipv6() invokes this function.
* As long as developers always use __nfq_tcp_mangle_ipv6__ when changing the
* content of a TCP message, there is no need to call
* __nfq_tcp_compute_checksum_ipv6__.
*/
EXPORT_SYMBOL
void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
{
/* checksum field in header needs to be zero for calculation. */
tcph->check = 0;
tcph->check = nfq_checksum_tcpudp_ipv6(ip6h, tcph, IPPROTO_TCP);
}
/**
* @}
*/
/*
* The union cast uses a gcc extension to avoid aliasing problems
* (union is compatible to any of its members)
* This means this part of the code is -fstrict-aliasing safe now.
*/
union tcp_word_hdr {
struct tcphdr hdr;
uint32_t words[5];
};
#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
* 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).
* \param tcph: pointer to a valid tcp header.
* \returns Same as \b snprintf
* \sa __snprintf__(3)
*
*/
EXPORT_SYMBOL
int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph)
{
int ret, len = 0;
#define TCP_RESERVED_BITS htonl(0x0F000000)
ret = snprintf(buf, size, "SPT=%u DPT=%u SEQ=%u ACK=%u "
"WINDOW=%u RES=0x%02x ",
ntohs(tcph->source), ntohs(tcph->dest),
ntohl(tcph->seq), ntohl(tcph->ack_seq),
ntohs(tcph->window),
(uint8_t)
(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22));
len += ret;
if (tcph->urg) {
ret = snprintf(buf+len, size-len, "URG ");
len += ret;
}
if (tcph->ack) {
ret = snprintf(buf+len, size-len, "ACK ");
len += ret;
}
if (tcph->psh) {
ret = snprintf(buf+len, size-len, "PSH ");
len += ret;
}
if (tcph->rst) {
ret = snprintf(buf+len, size-len, "RST ");
len += ret;
}
if (tcph->syn) {
ret = snprintf(buf+len, size-len, "SYN ");
len += ret;
}
if (tcph->fin) {
ret = snprintf(buf+len, size-len, "FIN ");
len += ret;
}
/* XXX: Not TCP options implemented yet, sorry. */
return ret;
}
/**
* nfq_tcp_mangle_ipv4 - mangle TCP/IPv4 packet buffer
* \param pktb: pointer to network packet buffer
* \param match_offset: offset to content that you want to mangle
* \param match_len: length of the existing content you want to mangle
* \param rep_buffer: pointer to data you want to use to replace current content
* \param rep_len: length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
* \note This function updates the IPv4 length and recalculates the IPv4 & TCP
* checksums for you.
* \warning After changing the length of a TCP message, the application will
* need to mangle sequence numbers in both directions until another change
* puts them in sync again
*/
EXPORT_SYMBOL
int nfq_tcp_mangle_ipv4(struct pkt_buff *pktb,
unsigned int match_offset, unsigned int match_len,
const char *rep_buffer, unsigned int rep_len)
{
struct iphdr *iph;
struct tcphdr *tcph;
iph = (struct iphdr *)pktb->network_header;
tcph = (struct tcphdr *)(pktb->network_header + iph->ihl*4);
if (!nfq_ip_mangle(pktb, iph->ihl*4 + tcph->doff*4,
match_offset, match_len, rep_buffer, rep_len))
return 0;
nfq_tcp_compute_checksum_ipv4(tcph, iph);
return 1;
}
/**
* nfq_tcp_mangle_ipv6 - Mangle TCP/IPv6 packet buffer
* \param pktb: Pointer to network packet buffer
* \param match_offset: Offset from start of TCP data of content that you want
* to mangle
* \param match_len: Length of the existing content you want to mangle
* \param rep_buffer: Pointer to data you want to use to replace current content
* \param rep_len: Length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
* \note This function updates the IPv6 length and recalculates the TCP
* checksum for you.
* \warning After changing the length of a TCP message, the application will
* need to mangle sequence numbers in both directions until another change
* puts them in sync again
*/
EXPORT_SYMBOL
int nfq_tcp_mangle_ipv6(struct pkt_buff *pktb,
unsigned int match_offset, unsigned int match_len,
const char *rep_buffer, unsigned int rep_len)
{
struct ip6_hdr *ip6h;
struct tcphdr *tcph;
ip6h = (struct ip6_hdr *)pktb->network_header;
tcph = (struct tcphdr *)(pktb->transport_header);
if (!tcph)
return 0;
if (!nfq_ip6_mangle(pktb,
pktb->transport_header - pktb->network_header +
tcph->doff * 4,
match_offset, match_len, rep_buffer, rep_len))
return 0;
nfq_tcp_compute_checksum_ipv6(tcph, ip6h);
return 1;
}
/**
* @}
*/

View File

@ -0,0 +1,228 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
#include <stdio.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#define _GNU_SOURCE
#include <netinet/udp.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
#include <libnetfilter_queue/pktbuff.h>
#include "internal.h"
/**
* \defgroup udp UDP helper functions
* @{
*/
/**
* nfq_udp_get_hdr - get the UDP header.
* \param pktb: Pointer to userspace network packet buffer
*
* \returns validated pointer to the UDP header or NULL if the UDP header was
* not set or if a minimal length check fails.
* \note You have to call nfq_ip_set_transport_header() or
* nfq_ip6_set_transport_header() first to set the UDP header.
*/
EXPORT_SYMBOL
struct udphdr *nfq_udp_get_hdr(struct pkt_buff *pktb)
{
if (pktb->transport_header == NULL)
return NULL;
/* No room for the UDP header. */
if (pktb_tail(pktb) - pktb->transport_header < sizeof(struct udphdr))
return NULL;
return (struct udphdr *)pktb->transport_header;
}
/**
* nfq_udp_get_payload - get the UDP packet payload.
* \param udph: Pointer to UDP header
* \param pktb: Pointer to userspace network packet buffer
* \returns Pointer to the UDP payload, or NULL if malformed UDP packet.
*/
EXPORT_SYMBOL
void *nfq_udp_get_payload(struct udphdr *udph, struct pkt_buff *pktb)
{
uint16_t len = ntohs(udph->len);
/* the UDP packet is too short. */
if (len < sizeof(struct udphdr))
return NULL;
/* malformed UDP packet. */
if (pktb->transport_header + len > pktb_tail(pktb))
return NULL;
return pktb->transport_header + sizeof(struct udphdr);
}
/**
* nfq_udp_get_payload_len - get the udp packet payload.
* \param udph: Pointer to UDP header
* \param pktb: Pointer to userspace network packet buffer
* \returns Length of UDP payload (user data)
*/
EXPORT_SYMBOL
unsigned int nfq_udp_get_payload_len(struct udphdr *udph, struct pkt_buff *pktb)
{
return pktb_tail(pktb) - pktb->transport_header - sizeof(struct udphdr);
}
/**
* \defgroup udp_internals Internal UDP functions
*
* Most user-space programs will never need these.
*
* @{
*/
/**
* nfq_udp_compute_checksum_ipv4 - sets up the UDP checksum in a UDP/IPv4 packet
* \param udph: pointer to the UDP header
* \param iph: pointer to the IPv4 header
* \note
* nfq_udp_mangle_ipv4() invokes this function.
* As long as developers always use __nfq_udp_mangle_ipv4__ when changing the
* content of a UDP message, there is no need to call
* __nfq_udp_compute_checksum_ipv4__.
*/
EXPORT_SYMBOL
void nfq_udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph)
{
/* checksum field in header needs to be zero for calculation. */
udph->check = 0;
udph->check = nfq_checksum_tcpudp_ipv4(iph, IPPROTO_UDP);
}
/**
* nfq_udp_compute_checksum_ipv6 - sets up the UDP checksum in a UDP/IPv6 packet
* \param udph: pointer to the UDP header
* \param ip6h: pointer to the IPv6 header
* \note
* nfq_udp_mangle_ipv6() invokes this function.
* As long as developers always use __nfq_udp_mangle_ipv6__ when changing the
* content of a UDP message, there is no need to call
* __nfq_udp_compute_checksum_ipv6__.
*/
EXPORT_SYMBOL
void nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h)
{
/* checksum field in header needs to be zero for calculation. */
udph->check = 0;
udph->check = nfq_checksum_tcpudp_ipv6(ip6h, udph, IPPROTO_UDP);
}
/**
* @}
*/
/**
* nfq_udp_mangle_ipv4 - Mangle UDP/IPv4 packet buffer
* \param pktb: Pointer to network packet buffer
* \param match_offset: Offset from start of UDP data of content that you want
* to mangle
* \param match_len: Length of the existing content you want to mangle
* \param rep_buffer: Pointer to data you want to use to replace current content
* \param rep_len: Length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
* \note This function updates the IPv4 and UDP lengths and recalculates their
* checksums for you.
*/
EXPORT_SYMBOL
int nfq_udp_mangle_ipv4(struct pkt_buff *pktb,
unsigned int match_offset, unsigned int match_len,
const char *rep_buffer, unsigned int rep_len)
{
struct iphdr *iph;
struct udphdr *udph;
iph = (struct iphdr *)pktb->network_header;
udph = (struct udphdr *)(pktb->network_header + iph->ihl*4);
udph->len = htons(ntohs(udph->len) + rep_len - match_len);
if (!nfq_ip_mangle(pktb, iph->ihl*4 + sizeof(struct udphdr),
match_offset, match_len, rep_buffer, rep_len))
return 0;
nfq_udp_compute_checksum_ipv4(udph, iph);
return 1;
}
/**
* nfq_udp_mangle_ipv6 - Mangle UDP/IPv6 packet buffer
* \param pktb: Pointer to network packet buffer
* \param match_offset: Offset from start of UDP data of content that you want
* to mangle
* \param match_len: Length of the existing content you want to mangle
* \param rep_buffer: Pointer to data you want to use to replace current content
* \param rep_len: Length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
* \note This function updates the IPv6 and UDP lengths and recalculates the UDP
* checksum for you.
*/
EXPORT_SYMBOL
int nfq_udp_mangle_ipv6(struct pkt_buff *pktb,
unsigned int match_offset, unsigned int match_len,
const char *rep_buffer, unsigned int rep_len)
{
struct ip6_hdr *ip6h;
struct udphdr *udph;
ip6h = (struct ip6_hdr *)pktb->network_header;
udph = (struct udphdr *)(pktb->transport_header);
if (!udph)
return 0;
udph->len = htons(ntohs(udph->len) + rep_len - match_len);
if (!nfq_ip6_mangle(pktb,
pktb->transport_header - pktb->network_header +
sizeof(struct udphdr),
match_offset, match_len, rep_buffer, rep_len))
return 0;
nfq_udp_compute_checksum_ipv6(udph, ip6h);
return 1;
}
/**
* nfq_pkt_snprintf_udp_hdr - print udp header into one buffer in a humnan
* 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).
* \param udph: pointer to a valid udp header.
* \returns The number of characters notionally written (excluding trailing NUL)
* \sa __snprintf__(3)
*
*/
EXPORT_SYMBOL
int nfq_udp_snprintf(char *buf, size_t size, const struct udphdr *udph)
{
return snprintf(buf, size, "SPT=%u DPT=%u ",
htons(udph->source), htons(udph->dest));
}
/**
* @}
*/

View File

@ -0,0 +1,38 @@
#ifndef INTERNAL_H
#define INTERNAL_H 1
#include "config.h"
#include <stdint.h>
#include <stdbool.h>
#ifdef HAVE_VISIBILITY_HIDDEN
# define EXPORT_SYMBOL __attribute__((visibility("default")))
#else
# define EXPORT_SYMBOL
#endif
struct iphdr;
struct ip6_hdr;
uint16_t nfq_checksum(uint32_t sum, uint16_t *buf, int size);
uint16_t nfq_checksum_tcpudp_ipv4(struct iphdr *iph, uint16_t protonum);
uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr,
uint16_t protonum);
struct pkt_buff {
uint8_t *mac_header;
uint8_t *network_header;
uint8_t *transport_header;
uint8_t *data;
uint32_t len;
uint32_t data_len;
bool mangled;
};
static inline uint8_t *pktb_tail(struct pkt_buff *pktb)
{
return pktb->data + pktb->len;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,299 @@
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <arpa/inet.h>
#include <time.h>
#include <endian.h>
#include <stdlib.h>
#include <string.h>
#include <libmnl/libmnl.h>
#ifndef __aligned_be64
#define __aligned_be64 __be64 __attribute__((aligned(8)))
#define __aligned_le64 __le64 __attribute__((aligned(8)))
#endif
#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
/**
* \defgroup nfq_verd Verdict helpers
* @{
*/
/**
* nfq_nlmsg_verdict_put - Put a verdict into a Netlink message
* \param nlh Pointer to netlink message
* \param id ID assigned to packet by netfilter
* \param verdict verdict to return to netfilter (see \b Verdicts below)
* \par Verdicts
* __NF_DROP__ Drop the packet. This is final.
* \n
* __NF_ACCEPT__ Accept the packet. Processing of the current base chain
* and any called chains terminates,
* but the packet may still be processed by subsequently invoked base chains.
* \n
* __NF_STOP__ Like __NF_ACCEPT__, but skip any further base chains using the
* current hook.
* \n
* __NF_REPEAT__ Like __NF_ACCEPT__, but re-queue this packet to the
* current base chain. One way to prevent a re-queueing loop is to
* also set a packet mark using nfq_nlmsg_verdict_put_mark() and have the
* program test for this mark in \c attr[NFQA_MARK]; or have the nefilter rules
* do this test.
* \n
* __NF_QUEUE_NR__(*new_queue*) Like __NF_ACCEPT__, but queue this packet to
* queue number *new_queue*. As with the command-line \b queue \b num verdict,
* if no process is listening to that queue then the packet is discarded; but
* again like with the command-line, one may OR in a flag to bypass *new_queue*
* if there is no listener, as in this snippet:
* \verbatim
nfq_nlmsg_verdict_put(nlh, id, NF_QUEUE_NR(new_queue) |
NF_VERDICT_FLAG_QUEUE_BYPASS);
\endverbatim
*
* See examples/nf-queue.c, line
* <a class="el" href="nf-queue_8c_source.html#l00046">46</a>
* for an example of how to use this function in context.
* The calling sequence is \b main --> \b mnl_cb_run --> \b queue_cb -->
* \b nfq_send_verdict --> \b nfq_nlmsg_verdict_put
* (\b cb being short for \b callback).
*/
EXPORT_SYMBOL
void nfq_nlmsg_verdict_put(struct nlmsghdr *nlh, int id, int verdict)
{
struct nfqnl_msg_verdict_hdr vh = {
.verdict = htonl(verdict),
.id = htonl(id),
};
mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh);
}
/**
* nfq_nlmsg_verdict_put_mark - Put a packet mark into a netlink message
* \param nlh Pointer to netlink message
* \param mark Value of mark to put
*
* The mark becomes part of the packet's metadata, and may be tested by the *nft
* primary expression* **meta mark**
* \sa __nft__(1)
*/
EXPORT_SYMBOL
void nfq_nlmsg_verdict_put_mark(struct nlmsghdr *nlh, uint32_t mark)
{
mnl_attr_put_u32(nlh, NFQA_MARK, htonl(mark));
}
EXPORT_SYMBOL
/**
* nfq_nlmsg_verdict_put_pkt - Put replacement packet content into a netlink
* message
* \param nlh Pointer to netlink message
* \param pkt Pointer to start of modified IP datagram
* \param plen Length of modified IP datagram
*
* There is only ever a need to return packet content if it has been modified.
* Usually one of the nfq_*_mangle_* functions does the modifying.
*
* This code snippet uses nfq_udp_mangle_ipv4. See nf-queue.c for
* context:
* \verbatim
// main calls queue_cb (line 64) to process an enqueued packet:
// Extra variables
uint8_t *payload, *rep_data;
unsigned int match_offset, match_len, rep_len;
// The next line was commented-out (with payload void*)
payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]);
// Copy data to a packet buffer (allow 255 bytes for mangling).
pktb = pktb_alloc(AF_INET, payload, plen, 255);
// (decide that this packet needs mangling)
nfq_udp_mangle_ipv4(pktb, match_offset, match_len, rep_data, rep_len);
// nfq_udp_mangle_ipv4 updates packet length, no need to track locally
// Eventually nfq_send_verdict (line 39) gets called
// The received packet may or may not have been modified.
// Add this code before nfq_nlmsg_verdict_put call:
if (pktb_mangled(pktb))
nfq_nlmsg_verdict_put_pkt(nlh, pktb_data(pktb), pktb_len(pktb));
\endverbatim
*/
void nfq_nlmsg_verdict_put_pkt(struct nlmsghdr *nlh, const void *pkt,
uint32_t plen)
{
mnl_attr_put(nlh, NFQA_PAYLOAD, plen, pkt);
}
/**
* @}
*/
/**
* \defgroup nfq_cfg Config helpers
* @{
*/
/**
* nfq_nlmsg_cfg_put_cmd Add netlink config command to netlink message
* \param nlh Pointer to netlink message
* \param pf Packet family (e.g. AF_INET)
* \param cmd nfqueue nfnetlink command.
*
* Possible commands are:
*
* - NFQNL_CFG_CMD_NONE: Do nothing. It can be useful to know if the queue
* subsystem is working.
* - NFQNL_CFG_CMD_BIND: Binds the program to a specific queue.
* - NFQNL_CFG_CMD_UNBIND: Unbinds the program to a specifiq queue.
*
* Obsolete commands:
* - NFQNL_CFG_CMD_PF_BIND: Binds to process packets belonging to the given
* protocol family (ie. PF_INET, PF_INET6, etc).
* - NFQNL_CFG_CMD_PF_UNBIND: Unbinds from processing packets belonging to the
* given protocol family. Both commands are ignored by Linux kernel 3.8 and
* later versions.
*/
EXPORT_SYMBOL
void nfq_nlmsg_cfg_put_cmd(struct nlmsghdr *nlh, uint16_t pf, uint8_t cmd)
{
struct nfqnl_msg_config_cmd command = {
.command = cmd,
.pf = htons(pf),
};
mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(command), &command);
}
/**
* nfq_nlmsg_cfg_put_params Add parameter to netlink message
* \param nlh Pointer to netlink message
* \param mode one of NFQNL_COPY_NONE, NFQNL_COPY_META or NFQNL_COPY_PACKET
* \param range value of parameter
*/
EXPORT_SYMBOL
void nfq_nlmsg_cfg_put_params(struct nlmsghdr *nlh, uint8_t mode, int range)
{
struct nfqnl_msg_config_params params = {
.copy_range = htonl(range),
.copy_mode = mode,
};
mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), &params);
}
/**
* nfq_nlmsg_cfg_put_qmaxlen Add queue maximum length to netlink message
* \param nlh Pointer to netlink message
* \param queue_maxlen Maximum queue length
*/
EXPORT_SYMBOL
void nfq_nlmsg_cfg_put_qmaxlen(struct nlmsghdr *nlh, uint32_t queue_maxlen)
{
mnl_attr_put_u32(nlh, NFQA_CFG_QUEUE_MAXLEN, htonl(queue_maxlen));
}
/**
* @}
*/
/**
* \defgroup nlmsg Netlink message helper functions
* @{
*/
static int nfq_pkt_parse_attr_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
/* skip unsupported attribute in user-space */
if (mnl_attr_type_valid(attr, NFQA_MAX) < 0)
return MNL_CB_OK;
switch(type) {
case NFQA_MARK:
case NFQA_IFINDEX_INDEV:
case NFQA_IFINDEX_OUTDEV:
case NFQA_IFINDEX_PHYSINDEV:
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:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
return MNL_CB_ERROR;
break;
case NFQA_TIMESTAMP:
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
sizeof(struct nfqnl_msg_packet_timestamp)) < 0) {
return MNL_CB_ERROR;
}
break;
case NFQA_HWADDR:
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
sizeof(struct nfqnl_msg_packet_hw)) < 0) {
return MNL_CB_ERROR;
}
break;
case NFQA_PACKET_HDR:
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
sizeof(struct nfqnl_msg_packet_hdr)) < 0) {
return MNL_CB_ERROR;
}
break;
case NFQA_PAYLOAD:
case NFQA_CT:
case NFQA_EXP:
break;
}
tb[type] = attr;
return MNL_CB_OK;
}
/**
* nfq_nlmsg_parse - set packet attributes from netlink message
* \param nlh Pointer to netlink message
* \param attr Pointer to array of attributes to set
* \returns MNL_CB_OK on success or MNL_CB_ERROR if any error occurs
*/
EXPORT_SYMBOL
int nfq_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr **attr)
{
return mnl_attr_parse(nlh, sizeof(struct nfgenmsg),
nfq_pkt_parse_attr_cb, attr);
}
/**
* nfq_nlmsg_put - Convert memory buffer into a Netlink buffer
* \param *buf Pointer to memory buffer
* \param type Either NFQNL_MSG_CONFIG or NFQNL_MSG_VERDICT
* \param queue_num Queue number
* \returns Pointer to netlink message
*/
EXPORT_SYMBOL
struct nlmsghdr *nfq_nlmsg_put(char *buf, int type, uint32_t queue_num)
{
struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | type;
nlh->nlmsg_flags = NLM_F_REQUEST;
struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
nfg->nfgen_family = AF_UNSPEC;
nfg->version = NFNETLINK_V0;
nfg->res_id = htons(queue_num);
return nlh;
}
/**
* @}
*/

View File

@ -0,0 +1 @@
/nfqnl_test

View File

@ -0,0 +1,9 @@
include ${top_srcdir}/Make_global.am
check_PROGRAMS = nfqnl_test
nfqnl_test_SOURCES = nfqnl_test.c
nfqnl_test_LDADD = ../src/libnetfilter_queue.la
nfqnl_test_LDFLAGS = -dynamic

View File

@ -0,0 +1,186 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h> /* for NF_ACCEPT */
#include <errno.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
/* returns packet id */
static uint32_t print_pkt (struct nfq_data *tb)
{
int id = 0;
struct nfqnl_msg_packet_hdr *ph;
struct nfqnl_msg_packet_hw *hwph;
uint32_t mark, ifi, uid, gid;
int ret;
unsigned char *data, *secdata;
ph = nfq_get_msg_packet_hdr(tb);
if (ph) {
id = ntohl(ph->packet_id);
printf("hw_protocol=0x%04x hook=%u id=%u ",
ntohs(ph->hw_protocol), ph->hook, id);
}
hwph = nfq_get_packet_hw(tb);
if (hwph) {
int i, hlen = ntohs(hwph->hw_addrlen);
printf("hw_src_addr=");
for (i = 0; i < hlen-1; i++)
printf("%02x:", hwph->hw_addr[i]);
printf("%02x ", hwph->hw_addr[hlen-1]);
}
mark = nfq_get_nfmark(tb);
if (mark)
printf("mark=%u ", mark);
ifi = nfq_get_indev(tb);
if (ifi)
printf("indev=%u ", ifi);
ifi = nfq_get_outdev(tb);
if (ifi)
printf("outdev=%u ", ifi);
ifi = nfq_get_physindev(tb);
if (ifi)
printf("physindev=%u ", ifi);
ifi = nfq_get_physoutdev(tb);
if (ifi)
printf("physoutdev=%u ", ifi);
if (nfq_get_uid(tb, &uid))
printf("uid=%u ", uid);
if (nfq_get_gid(tb, &gid))
printf("gid=%u ", gid);
ret = nfq_get_secctx(tb, &secdata);
if (ret > 0)
printf("secctx=\"%.*s\" ", ret, secdata);
ret = nfq_get_payload(tb, &data);
if (ret >= 0)
printf("payload_len=%d ", ret);
fputc('\n', stdout);
return id;
}
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *data)
{
uint32_t id = print_pkt(nfa);
printf("entering callback\n");
return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
}
int main(int argc, char **argv)
{
struct nfq_handle *h;
struct nfq_q_handle *qh;
int fd;
int rv;
uint32_t queue = 0;
char buf[4096] __attribute__ ((aligned));
if (argc == 2) {
queue = atoi(argv[1]);
if (queue > 65535) {
fprintf(stderr, "Usage: %s [<0-65535>]\n", argv[0]);
exit(EXIT_FAILURE);
}
}
printf("opening library handle\n");
h = nfq_open();
if (!h) {
fprintf(stderr, "error during nfq_open()\n");
exit(1);
}
printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
if (nfq_unbind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_unbind_pf()\n");
exit(1);
}
printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
if (nfq_bind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_bind_pf()\n");
exit(1);
}
printf("binding this socket to queue '%d'\n", queue);
qh = nfq_create_queue(h, queue, &cb, NULL);
if (!qh) {
fprintf(stderr, "error during nfq_create_queue()\n");
exit(1);
}
printf("setting copy_packet mode\n");
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
fprintf(stderr, "can't set packet_copy mode\n");
exit(1);
}
printf("setting flags to request UID and GID\n");
if (nfq_set_queue_flags(qh, NFQA_CFG_F_UID_GID, NFQA_CFG_F_UID_GID)) {
fprintf(stderr, "This kernel version does not allow to "
"retrieve process UID/GID.\n");
}
printf("setting flags to request security context\n");
if (nfq_set_queue_flags(qh, NFQA_CFG_F_SECCTX, NFQA_CFG_F_SECCTX)) {
fprintf(stderr, "This kernel version does not allow to "
"retrieve security context.\n");
}
printf("Waiting for packets...\n");
fd = nfq_fd(h);
for (;;) {
if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {
printf("pkt received\n");
nfq_handle_packet(h, buf, rv);
continue;
}
/* if your application is too slow to digest the packets that
* are sent from kernel-space, the socket buffer that we use
* to enqueue packets may fill up returning ENOBUFS. Depending
* on your application, this error may be ignored. Please, see
* the doxygen documentation of this library on how to improve
* this situation.
*/
if (rv < 0 && errno == ENOBUFS) {
printf("losing packets!\n");
continue;
}
perror("recv failed");
break;
}
printf("unbinding from queue 0\n");
nfq_destroy_queue(qh);
#ifdef INSANE
/* normally, applications SHOULD NOT issue this command, since
* it detaches other programs/sockets from AF_INET, too ! */
printf("unbinding from AF_INET\n");
nfq_unbind_pf(h, AF_INET);
#endif
printf("closing library handle\n");
nfq_close(h);
exit(0);
}

View File

@ -45,7 +45,7 @@ static int queue_cb(const struct nlmsghdr *nlh, void *customdata)
plen = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]);
/* void *payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]); */
skbinfo = attr[NFQA_SKB_INFO] ? ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])) : 0;
// skbinfo = attr[NFQA_SKB_INFO] ? ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])) : 0;
if (attr[NFQA_CAP_LEN]) {
uint32_t orig_len = ntohl(mnl_attr_get_u32(attr[NFQA_CAP_LEN]));
@ -53,11 +53,14 @@ static int queue_cb(const struct nlmsghdr *nlh, void *customdata)
printf("truncated ");
}
if (skbinfo & NFQA_SKB_GSO) //NFQA_SKB_GSO为2取倒数第二位
printf("GSO ");
// if (skbinfo & NFQA_SKB_GSO) //NFQA_SKB_GSO为2取倒数第二位
// printf("GSO ");
id = ntohl(ph->packet_id);
printf("packet received (id=%u hw=0x%04x hook=%u, payload len %u",
if (ph->hw_protocol==IPPROTO_TCP){
printf("get a TCP packet\n");
}
printf("packet received (id=%u hw=%u hook=%u, payload len %u",
id, ntohs(ph->hw_protocol), ph->hook, plen);
/*
@ -67,9 +70,9 @@ static int queue_cb(const struct nlmsghdr *nlh, void *customdata)
* If these packets are later forwarded/sent out, the checksums will
* be corrected by kernel/hardware.
*/
if (skbinfo & NFQA_SKB_CSUMNOTREADY) //NFQA_SKB_GSO为2取倒数第二位
printf(", checksum not ready");
puts(")");
// if (skbinfo & NFQA_SKB_CSUMNOTREADY) //NFQA_SKB_GSO为2取倒数第二位
// printf(", checksum not ready");
// puts(")");
return MNL_CB_OK;
}
@ -81,7 +84,7 @@ int main(int argc, char *argv[])
size_t sizeof_buf = 0xffff + (MNL_SOCKET_BUFFER_SIZE/2);
struct nlmsghdr *nlh;
int ret;
unsigned int portid, queue_num;
unsigned int portid;
nl = mnl_socket_open(NETLINK_NETFILTER);