diff --git a/ref/libnetfilter-queue/.gitignore b/ref/libnetfilter-queue/.gitignore new file mode 100644 index 0000000..a0fc139 --- /dev/null +++ b/ref/libnetfilter-queue/.gitignore @@ -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 diff --git a/ref/libnetfilter-queue/COPYING b/ref/libnetfilter-queue/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/ref/libnetfilter-queue/COPYING @@ -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. + + + Copyright (C) 19yy + + 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. + + , 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. diff --git a/ref/libnetfilter-queue/Make_global.am b/ref/libnetfilter-queue/Make_global.am new file mode 100644 index 0000000..91da5da --- /dev/null +++ b/ref/libnetfilter-queue/Make_global.am @@ -0,0 +1,2 @@ +AM_CPPFLAGS = -I${top_srcdir}/include ${LIBNFNETLINK_CFLAGS} ${LIBMNL_CFLAGS} +AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN} diff --git a/ref/libnetfilter-queue/Makefile.am b/ref/libnetfilter-queue/Makefile.am new file mode 100644 index 0000000..796f0d0 --- /dev/null +++ b/ref/libnetfilter-queue/Makefile.am @@ -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 diff --git a/ref/libnetfilter-queue/autogen.sh b/ref/libnetfilter-queue/autogen.sh new file mode 100644 index 0000000..57c3532 --- /dev/null +++ b/ref/libnetfilter-queue/autogen.sh @@ -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 diff --git a/ref/libnetfilter-queue/configure.ac b/ref/libnetfilter-queue/configure.ac new file mode 100644 index 0000000..32e4990 --- /dev/null +++ b/ref/libnetfilter-queue/configure.ac @@ -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}" diff --git a/ref/libnetfilter-queue/doxygen.cfg.in b/ref/libnetfilter-queue/doxygen.cfg.in new file mode 100644 index 0000000..4c16e3e --- /dev/null +++ b/ref/libnetfilter-queue/doxygen.cfg.in @@ -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 diff --git a/ref/libnetfilter-queue/doxygen/Makefile.am b/ref/libnetfilter-queue/doxygen/Makefile.am new file mode 100644 index 0000000..58d153f --- /dev/null +++ b/ref/libnetfilter-queue/doxygen/Makefile.am @@ -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 diff --git a/ref/libnetfilter-queue/examples/Makefile.am b/ref/libnetfilter-queue/examples/Makefile.am new file mode 100644 index 0000000..1906697 --- /dev/null +++ b/ref/libnetfilter-queue/examples/Makefile.am @@ -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 diff --git a/ref/libnetfilter-queue/examples/nf-queue.c b/ref/libnetfilter-queue/examples/nf-queue.c new file mode 100644 index 0000000..3da2c24 --- /dev/null +++ b/ref/libnetfilter-queue/examples/nf-queue.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/* only for NFQA_CT, not needed otherwise: */ +#include + +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; +} diff --git a/ref/libnetfilter-queue/fixmanpages.sh b/ref/libnetfilter-queue/fixmanpages.sh new file mode 100644 index 0000000..dd8b3a4 --- /dev/null +++ b/ref/libnetfilter-queue/fixmanpages.sh @@ -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 diff --git a/ref/libnetfilter-queue/include/Makefile.am b/ref/libnetfilter-queue/include/Makefile.am new file mode 100644 index 0000000..54ea0b4 --- /dev/null +++ b/ref/libnetfilter-queue/include/Makefile.am @@ -0,0 +1 @@ +SUBDIRS= libnetfilter_queue linux diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/Makefile.am b/ref/libnetfilter-queue/include/libnetfilter_queue/Makefile.am new file mode 100644 index 0000000..902fbf9 --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/Makefile.am @@ -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 diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue.h b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue.h new file mode 100644 index 0000000..a19122f --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue.h @@ -0,0 +1,159 @@ +/* libnfqnetlink.h: Header file for the Netfilter Queue library. + * + * (C) 2005 by Harald Welte + * + * + * Changelog : + * (2005/08/11) added parsing function (Eric Leblond ) + * + * 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 +#include + +#include + +#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 */ diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_ipv4.h b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_ipv4.h new file mode 100644 index 0000000..17be93e --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_ipv4.h @@ -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 diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_ipv6.h b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_ipv6.h new file mode 100644 index 0000000..c0a7d37 --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_ipv6.h @@ -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 diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_tcp.h b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_tcp.h new file mode 100644 index 0000000..e1b9690 --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_tcp.h @@ -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 diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_udp.h b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_udp.h new file mode 100644 index 0000000..9d594f2 --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/libnetfilter_queue_udp.h @@ -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 diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/linux_nfnetlink_queue.h b/ref/libnetfilter-queue/include/libnetfilter_queue/linux_nfnetlink_queue.h new file mode 100644 index 0000000..1975dfa --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/linux_nfnetlink_queue.h @@ -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 +#include + +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 */ diff --git a/ref/libnetfilter-queue/include/libnetfilter_queue/pktbuff.h b/ref/libnetfilter-queue/include/libnetfilter_queue/pktbuff.h new file mode 100644 index 0000000..42bc153 --- /dev/null +++ b/ref/libnetfilter-queue/include/libnetfilter_queue/pktbuff.h @@ -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 diff --git a/ref/libnetfilter-queue/include/linux/Makefile.am b/ref/libnetfilter-queue/include/linux/Makefile.am new file mode 100644 index 0000000..38eb109 --- /dev/null +++ b/ref/libnetfilter-queue/include/linux/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = netfilter diff --git a/ref/libnetfilter-queue/include/linux/netfilter/Makefile.am b/ref/libnetfilter-queue/include/linux/netfilter/Makefile.am new file mode 100644 index 0000000..d0937cb --- /dev/null +++ b/ref/libnetfilter-queue/include/linux/netfilter/Makefile.am @@ -0,0 +1 @@ +noinst_HEADERS = nfnetlink_queue.h diff --git a/ref/libnetfilter-queue/include/linux/netfilter/nfnetlink_queue.h b/ref/libnetfilter-queue/include/linux/netfilter/nfnetlink_queue.h new file mode 100644 index 0000000..030672d --- /dev/null +++ b/ref/libnetfilter-queue/include/linux/netfilter/nfnetlink_queue.h @@ -0,0 +1,115 @@ +#ifndef _NFNETLINK_QUEUE_H +#define _NFNETLINK_QUEUE_H + +#include +#include + +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 */ diff --git a/ref/libnetfilter-queue/libnetfilter_queue.pc.in b/ref/libnetfilter-queue/libnetfilter_queue.pc.in new file mode 100644 index 0000000..9c6c2c4 --- /dev/null +++ b/ref/libnetfilter-queue/libnetfilter_queue.pc.in @@ -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} diff --git a/ref/libnetfilter-queue/m4/.gitignore b/ref/libnetfilter-queue/m4/.gitignore new file mode 100644 index 0000000..64d9bbc --- /dev/null +++ b/ref/libnetfilter-queue/m4/.gitignore @@ -0,0 +1,2 @@ +/libtool.m4 +/lt*.m4 diff --git a/ref/libnetfilter-queue/m4/gcc4_visibility.m4 b/ref/libnetfilter-queue/m4/gcc4_visibility.m4 new file mode 100644 index 0000000..214d3f3 --- /dev/null +++ b/ref/libnetfilter-queue/m4/gcc4_visibility.m4 @@ -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]) +]) diff --git a/ref/libnetfilter-queue/src/Makefile.am b/ref/libnetfilter-queue/src/Makefile.am new file mode 100644 index 0000000..ab2a151 --- /dev/null +++ b/ref/libnetfilter-queue/src/Makefile.am @@ -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. +# +# +# 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. +# +# +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} diff --git a/ref/libnetfilter-queue/src/extra/checksum.c b/ref/libnetfilter-queue/src/extra/checksum.c new file mode 100644 index 0000000..ffc8c75 --- /dev/null +++ b/ref/libnetfilter-queue/src/extra/checksum.c @@ -0,0 +1,82 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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); +} diff --git a/ref/libnetfilter-queue/src/extra/ipv4.c b/ref/libnetfilter-queue/src/extra/ipv4.c new file mode 100644 index 0000000..797bab1 --- /dev/null +++ b/ref/libnetfilter-queue/src/extra/ipv4.c @@ -0,0 +1,175 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#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; +} + +/** + * @} + */ diff --git a/ref/libnetfilter-queue/src/extra/ipv6.c b/ref/libnetfilter-queue/src/extra/ipv6.c new file mode 100644 index 0000000..42c5e25 --- /dev/null +++ b/ref/libnetfilter-queue/src/extra/ipv6.c @@ -0,0 +1,180 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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; +} + +/** + * @} + */ diff --git a/ref/libnetfilter-queue/src/extra/pktbuff.c b/ref/libnetfilter-queue/src/extra/pktbuff.c new file mode 100644 index 0000000..6dd0ca9 --- /dev/null +++ b/ref/libnetfilter-queue/src/extra/pktbuff.c @@ -0,0 +1,366 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * 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. + */ + +#include +#include +#include /* for memcpy */ +#include + +#include +#include +#include + +#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; +} + +/** + * @} + */ diff --git a/ref/libnetfilter-queue/src/extra/tcp.c b/ref/libnetfilter-queue/src/extra/tcp.c new file mode 100644 index 0000000..933c6ee --- /dev/null +++ b/ref/libnetfilter-queue/src/extra/tcp.c @@ -0,0 +1,279 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * 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. + */ + +#include +#include /* for memcpy */ +#include +#include +#include +#include +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include + +#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; +} + +/** + * @} + */ diff --git a/ref/libnetfilter-queue/src/extra/udp.c b/ref/libnetfilter-queue/src/extra/udp.c new file mode 100644 index 0000000..f232127 --- /dev/null +++ b/ref/libnetfilter-queue/src/extra/udp.c @@ -0,0 +1,228 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * 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. + */ + +#include +#include +#include +#include +#include +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include + +#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)); +} + +/** + * @} + */ diff --git a/ref/libnetfilter-queue/src/internal.h b/ref/libnetfilter-queue/src/internal.h new file mode 100644 index 0000000..ae849d6 --- /dev/null +++ b/ref/libnetfilter-queue/src/internal.h @@ -0,0 +1,38 @@ +#ifndef INTERNAL_H +#define INTERNAL_H 1 + +#include "config.h" +#include +#include +#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 diff --git a/ref/libnetfilter-queue/src/libnetfilter_queue.c b/ref/libnetfilter-queue/src/libnetfilter_queue.c new file mode 100644 index 0000000..ef3b211 --- /dev/null +++ b/ref/libnetfilter-queue/src/libnetfilter_queue.c @@ -0,0 +1,1534 @@ +/* libnetfilter_queue.c: generic library for access to nf_queue + * + * (C) 2005 by Harald Welte + * (C) 2005, 2008-2010 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation (or any later at your option) + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-01-23 Andreas Florath + * Fix __set_verdict() that it can now handle payload. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "internal.h" + +/** + * \mainpage + * + * libnetfilter_queue is a userspace library providing an API to packets that + * have been queued by the kernel packet filter. It is is part of a system that + * replaces the old ip_queue / libipq mechanism (withdrawn in kernel 3.5). + * + * libnetfilter_queue homepage is: + * https://netfilter.org/projects/libnetfilter_queue/ + * + * \section deps Dependencies + * libnetfilter_queue requires libmnl, libnfnetlink and a kernel that includes + * the Netfilter NFQUEUE over NFNETLINK interface (i.e. 2.6.14 or later). + * + * \section features Main Features + * - receiving queued packets from the kernel nfnetlink_queue subsystem + * - issuing verdicts and possibly reinjecting altered packets to the kernel + * nfnetlink_queue subsystem + * + * The cinematic is the following: When an nft rule with action **queue** + * matches, the kernel terminates the current nft chain and enqueues the packet + * in a chained list. It then formats and sends an nfnetlink message containing + * the packet id and whatever information the userspace program configured to + * receive (packet data and/or metadata) via a socket to the userspace program. + * + * The userspace program must issue a verdict advising the kernel to **accept** + * or **drop** the packet. Either verdict takes the packet off the queue: + * **drop** discards the packet while + * **accept** passes it on to the next chain. + * Userspace can also alter packet contents or metadata (e.g. packet mark, + * contrack mark). Verdict can be done in asynchronous manner, as the only + * needed information is the packet id. + * + * When a queue is full, packets that should have been enqueued are dropped by + * kernel instead of being enqueued. + * + * \section git Git Tree + * The current development version of libnetfilter_queue can be accessed at + * https://git.netfilter.org/libnetfilter_queue. + * + * \section privs Privileges + * You need the CAP_NET_ADMIN capability in order to allow your application + * to receive from and to send packets to kernel-space. + * + * \section using Using libnetfilter_queue + * + * To write your own program using libnetfilter_queue, you should start by + * reading (or, if feasible, compiling and stepping through with *gdb*) + * nf-queue.c source file. + * Simple compile line: + * \verbatim +gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c +\endverbatim + * The doxygen documentation \link LibrarySetup \endlink is Deprecated and + * incompatible with non-deprecated functions. It is hoped to produce a + * corresponding non-deprecated (*Current*) topic soon. + * + * Somewhat outdated but possibly providing some insight into + * libnetfilter_queue usage is the following + * article: + * https://home.regit.org/netfilter-en/using-nfqueue-and-libnetfilter_queue/ + * + * \section errors ENOBUFS errors in recv() + * + * recv() may return -1 and errno is set to ENOBUFS in case that your + * application is not fast enough to retrieve the packets from the kernel. + * In that case, you can increase the socket buffer size by means of + * nfnl_rcvbufsiz(). Although this delays the appearance of ENOBUFS errors, + * you may hit it again sooner or later. The next section provides some hints + * on how to obtain the best performance for your application. + * + * \section perf Performance + * To improve your libnetfilter_queue application in terms of performance, + * you may consider the following tweaks: + * + * - increase the default socket buffer size by means of nfnl_rcvbufsiz(). + * - set nice value of your process to -20 (maximum priority). + * - set the CPU affinity of your process to a spare core that is not used + * to handle NIC interruptions. + * - set NETLINK_NO_ENOBUFS socket option to avoid receiving ENOBUFS errors + * (requires Linux kernel >= 2.6.30). + * - see --queue-balance option in NFQUEUE target for multi-threaded apps + * (it requires Linux kernel >= 2.6.31). + * - consider using fail-open option see nfq_set_queue_flags() (it requires + * Linux kernel >= 3.6) + * - increase queue max length with nfq_set_queue_maxlen() to resist to packets + * burst + */ + +struct nfq_handle +{ + struct nfnl_handle *nfnlh; + struct nfnl_subsys_handle *nfnlssh; + struct nfq_q_handle *qh_list; +}; + +struct nfq_q_handle +{ + struct nfq_q_handle *next; + struct nfq_handle *h; + uint16_t id; + + nfq_callback *cb; + void *data; +}; + +struct nfq_data { + struct nfattr **data; +}; + +EXPORT_SYMBOL int nfq_errno; + +/*********************************************************************** + * low level stuff + ***********************************************************************/ + +static void del_qh(struct nfq_q_handle *qh) +{ + struct nfq_q_handle *cur_qh, *prev_qh = NULL; + + for (cur_qh = qh->h->qh_list; cur_qh; cur_qh = cur_qh->next) { + if (cur_qh == qh) { + if (prev_qh) + prev_qh->next = qh->next; + else + qh->h->qh_list = qh->next; + return; + } + prev_qh = cur_qh; + } +} + +static void add_qh(struct nfq_q_handle *qh) +{ + qh->next = qh->h->qh_list; + qh->h->qh_list = qh; +} + +static struct nfq_q_handle *find_qh(struct nfq_handle *h, uint16_t id) +{ + struct nfq_q_handle *qh; + + for (qh = h->qh_list; qh; qh = qh->next) { + if (qh->id == id) + return qh; + } + return NULL; +} + +/* build a NFQNL_MSG_CONFIG message */ + static int +__build_send_cfg_msg(struct nfq_handle *h, uint8_t command, + uint16_t queuenum, uint16_t pf) +{ + union { + char buf[NFNL_HEADER_LEN + +NFA_LENGTH(sizeof(struct nfqnl_msg_config_cmd))]; + struct nlmsghdr nmh; + } u; + struct nfqnl_msg_config_cmd cmd; + + nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, AF_UNSPEC, queuenum, + NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); + + cmd._pad = 0; + cmd.command = command; + cmd.pf = htons(pf); + nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_CMD, &cmd, sizeof(cmd)); + + return nfnl_query(h->nfnlh, &u.nmh); +} + +static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[], + void *data) +{ + struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfq_handle *h = data; + uint16_t queue_num = ntohs(nfmsg->res_id); + struct nfq_q_handle *qh = find_qh(h, queue_num); + struct nfq_data nfqa; + + if (!qh) + return -ENODEV; + + if (!qh->cb) + return -ENODEV; + + nfqa.data = nfa; + + return qh->cb(qh, nfmsg, &nfqa, qh->data); +} + +/* public interface */ + +EXPORT_SYMBOL +struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h) +{ + return h->nfnlh; +} + +/** + * + * \defgroup Queue Queue handling [DEPRECATED] + * + * Once libnetfilter_queue library has been initialised (See + * \link LibrarySetup \endlink), it is possible to bind the program to a + * specific queue. This can be done by using nfq_create_queue(). + * + * The queue can then be tuned via nfq_set_mode() or nfq_set_queue_maxlen(). + * + * Here's a little code snippet that create queue numbered 0: + * \verbatim + printf("binding this socket to queue '0'\n"); + qh = nfq_create_queue(h, 0, &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); + } +\endverbatim + * + * Next step is the handling of incoming packets which can be done via a loop: + * + * \verbatim + fd = nfq_fd(h); + + while ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) { + printf("pkt received\n"); + nfq_handle_packet(h, buf, rv); + } +\endverbatim + * When the decision on a packet has been choosed, the verdict has to be given + * by calling nfq_set_verdict() or nfq_set_verdict2(). The verdict + * determines the destiny of the packet as follows: + * + * - NF_DROP discarded the packet + * - NF_ACCEPT the packet passes, continue iterations + * - NF_QUEUE inject the packet into a different queue + * (the target queue number is in the high 16 bits of the verdict) + * - NF_REPEAT iterate the same cycle once more + * - NF_STOP accept, but don't continue iterations + * + * The verdict NF_STOLEN must not be used, as it has special meaning in the + * kernel. + * When using NF_REPEAT, one way to prevent re-queueing of the same packet + * is to also set an nfmark using nfq_set_verdict2, and set up the nefilter + * rules to only queue a packet when the mark is not (yet) set. + * + * Data and information about the packet can be fetch by using message parsing + * functions (See \link Parsing \endlink). + * @{ + */ + +/** + * nfq_fd - get the file descriptor associated with the nfqueue handler + * \param h Netfilter queue connection handle obtained via call to nfq_open() + * + * \return a file descriptor for the netlink connection associated with the + * given queue connection handle. The file descriptor can then be used for + * receiving the queued packets for processing. + * + * This function returns a file descriptor that can be used for communication + * over the netlink connection associated with the given queue connection + * handle. + */ +EXPORT_SYMBOL +int nfq_fd(struct nfq_handle *h) +{ + return nfnl_fd(nfq_nfnlh(h)); +} +/** + * @} + */ + +/** + * \defgroup LibrarySetup Library setup [DEPRECATED] + * + * Library initialisation is made in two steps. + * + * First step is to call nfq_open() to open a NFQUEUE handler. + * + * Second step is to tell the kernel that userspace queueing is handle by + * NFQUEUE for the selected protocol. This is made by calling nfq_unbind_pf() + * and nfq_bind_pf() with protocol information. The idea behind this is to + * enable simultaneously loaded modules to be used for queuing. + * + * Here's a little code snippet that bind with AF_INET: + * \verbatim + 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); + } +\endverbatim + * Once this is done, you can setup and use a \link Queue \endlink. + * @{ + */ + +/** + * nfq_open - open a nfqueue handler + * + * This function obtains a netfilter queue connection handle. When you are + * finished with the handle returned by this function, you should destroy + * it by calling nfq_close(). A new netlink connection is obtained internally + * and associated with the queue connection handle returned. + * + * \return a pointer to a new queue handle or NULL on failure. + */ +EXPORT_SYMBOL +struct nfq_handle *nfq_open(void) +{ + struct nfnl_handle *nfnlh = nfnl_open(); + struct nfq_handle *qh; + + if (!nfnlh) + return NULL; + + /* unset netlink sequence tracking by default */ + nfnl_unset_sequence_tracking(nfnlh); + + qh = nfq_open_nfnl(nfnlh); + if (!qh) + nfnl_close(nfnlh); + + return qh; +} + +/** + * @} + */ + +/** + * nfq_open_nfnl - open a nfqueue handler from a existing nfnetlink handler + * \param nfnlh Netfilter netlink connection handle obtained by calling nfnl_open() + * + * This function obtains a netfilter queue connection handle using an existing + * netlink connection. This function is used internally to implement + * nfq_open(), and should typically not be called directly. + * + * \return a pointer to a new queue handle or NULL on failure. + */ +EXPORT_SYMBOL +struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh) +{ + struct nfnl_callback pkt_cb = { + .call = __nfq_rcv_pkt, + .attr_count = NFQA_MAX, + }; + struct nfq_handle *h; + int err; + + h = malloc(sizeof(*h)); + if (!h) + return NULL; + + memset(h, 0, sizeof(*h)); + h->nfnlh = nfnlh; + + h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE, + NFQNL_MSG_MAX, 0); + if (!h->nfnlssh) { + /* FIXME: nfq_errno */ + goto out_free; + } + + pkt_cb.data = h; + err = nfnl_callback_register(h->nfnlssh, NFQNL_MSG_PACKET, &pkt_cb); + if (err < 0) { + nfq_errno = err; + goto out_close; + } + + return h; +out_close: + nfnl_subsys_close(h->nfnlssh); +out_free: + free(h); + return NULL; +} + +/** + * \addtogroup LibrarySetup + * + * When the program has finished with libnetfilter_queue, it has to call + * the nfq_close() function to free all associated resources. + * + * @{ + */ + +/** + * nfq_close - close a nfqueue handler + * \param h Netfilter queue connection handle obtained via call to nfq_open() + * + * This function closes the nfqueue handler and free associated resources. + * + * \return 0 on success, non-zero on failure. + */ +EXPORT_SYMBOL +int nfq_close(struct nfq_handle *h) +{ + int ret; + + ret = nfnl_close(h->nfnlh); + if (ret == 0) + free(h); + return ret; +} + +/** + * nfq_bind_pf - bind a nfqueue handler to a given protocol family + * \param h Netfilter queue connection handle obtained via call to nfq_open() + * \param pf protocol family to bind to nfqueue handler obtained from nfq_open() + * + * Binds the given queue connection handle to process packets belonging to + * the given protocol family (ie. PF_INET, PF_INET6, etc). + * This call is obsolete, Linux kernels from 3.8 onwards ignore it. + * + * \return integer inferior to 0 in case of failure + */ +EXPORT_SYMBOL +int nfq_bind_pf(struct nfq_handle *h, uint16_t pf) +{ + return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_BIND, 0, pf); +} + +/** + * nfq_unbind_pf - unbind nfqueue handler from a protocol family + * \param h Netfilter queue connection handle obtained via call to nfq_open() + * \param pf protocol family to unbind family from + * + * Unbinds the given queue connection handle from processing packets belonging + * to the given protocol family. + * + * This call is obsolete, Linux kernels from 3.8 onwards ignore it. + */ +EXPORT_SYMBOL +int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf) +{ + return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_UNBIND, 0, pf); +} + + +/** + * @} + */ + +/** + * \addtogroup Queue + * @{ + */ + +/** + * nfq_create_queue - create a new queue handle and return it. + * + * \param h Netfilter queue connection handle obtained via call to nfq_open() + * \param num the number of the queue to bind to + * \param cb callback function to call for each queued packet + * \param data custom data to pass to the callback function + * + * \return a nfq_q_handle pointing to the newly created queue + * + * Creates a new queue handle, and returns it. The new queue is identified by + * \b num, and the callback specified by \b cb will be called for each enqueued + * packet. The \b data argument will be passed unchanged to the callback. If + * a queue entry with id \b num already exists, + * this function will return failure and the existing entry is unchanged. + * + * The nfq_callback type is defined in libnetfilter_queue.h as: + * \verbatim +typedef int nfq_callback(struct nfq_q_handle *qh, + struct nfgenmsg *nfmsg, + struct nfq_data *nfad, void *data); +\endverbatim + * + * Parameters: + * - qh The queue handle returned by nfq_create_queue + * - nfmsg message objetc that contains the packet + * - nfad Netlink packet data handle + * - data the value passed to the data parameter of nfq_create_queue + * + * The callback should return < 0 to stop processing. + */ + +EXPORT_SYMBOL +struct nfq_q_handle *nfq_create_queue(struct nfq_handle *h, uint16_t num, + nfq_callback *cb, void *data) +{ + int ret; + struct nfq_q_handle *qh; + + if (find_qh(h, num)) + return NULL; + + qh = malloc(sizeof(*qh)); + if (!qh) + return NULL; + + memset(qh, 0, sizeof(*qh)); + qh->h = h; + qh->id = num; + qh->cb = cb; + qh->data = data; + + ret = __build_send_cfg_msg(h, NFQNL_CFG_CMD_BIND, num, 0); + if (ret < 0) { + nfq_errno = ret; + free(qh); + return NULL; + } + + add_qh(qh); + return qh; +} + +/** + * @} + */ + +/** + * \addtogroup Queue + * @{ + */ + +/** + * nfq_destroy_queue - destroy a queue handle + * \param qh queue handle that we want to destroy created via nfq_create_queue + * + * Removes the binding for the specified queue handle. This call also unbind + * from the nfqueue handler, so you don't have to call nfq_unbind_pf. + */ +EXPORT_SYMBOL +int nfq_destroy_queue(struct nfq_q_handle *qh) +{ + int ret = __build_send_cfg_msg(qh->h, NFQNL_CFG_CMD_UNBIND, qh->id, 0); + if (ret == 0) { + del_qh(qh); + free(qh); + } + + return ret; +} + +/** + * nfq_handle_packet - handle a packet received from the nfqueue subsystem + * \param h Netfilter queue connection handle obtained via call to nfq_open() + * \param buf data to pass to the callback + * \param len length of packet data in buffer + * + * Triggers an associated callback for the given packet received from the + * queue. Packets can be read from the queue using nfq_fd() and recv(). See + * example code for nfq_fd(). + * + * \return 0 on success, non-zero on failure. + */ +EXPORT_SYMBOL +int nfq_handle_packet(struct nfq_handle *h, char *buf, int len) +{ + return nfnl_handle_packet(h->nfnlh, buf, len); +} + +/** + * nfq_set_mode - set the amount of packet data that nfqueue copies to userspace + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param mode the part of the packet that we are interested in + * \param range size of the packet that we want to get + * + * Sets the amount of data to be copied to userspace for each packet queued + * to the given queue. + * + * - NFQNL_COPY_NONE - noop, do not use it + * - NFQNL_COPY_META - copy only packet metadata + * - NFQNL_COPY_PACKET - copy entire packet + * + * \return -1 on error; >=0 otherwise. + */ +EXPORT_SYMBOL +int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range) +{ + union { + char buf[NFNL_HEADER_LEN + +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))]; + struct nlmsghdr nmh; + } u; + struct nfqnl_msg_config_params params; + + nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, + NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); + + params.copy_range = htonl(range); + params.copy_mode = mode; + nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_PARAMS, ¶ms, + sizeof(params)); + + return nfnl_query(qh->h->nfnlh, &u.nmh); +} + +/** + * nfq_set_queue_flags - set flags (options) for the kernel queue + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param mask specifies which flag bits to modify + * \param flags bitmask of flags + * + * Existing flags, that you may want to combine, are: + * + * - NFQA_CFG_F_FAIL_OPEN (requires Linux kernel >= 3.6): the kernel will + * accept the packets if the kernel queue gets full. If this flag is not + * set, the default action in this case is to drop packets. + * + * - NFQA_CFG_F_CONNTRACK (requires Linux kernel >= 3.6): the kernel will + * include the Connection Tracking system information. + * + * - NFQA_CFG_F_GSO (requires Linux kernel >= 3.10): the kernel will + * not normalize offload packets, i.e. your application will need to + * be able to handle packets larger than the mtu. + * + * Normalization is expensive, so this flag should always be set. + * Because attributes in netlink messages are limited to 65531 bytes, + * you also need to check the NFQA_CAP_LEN attribute, it contains the + * original size of the captured packet on the kernel side. + * If it is set and differs from the payload length, the packet was + * truncated. This also happens when limiting capture size + * with the NFQNL_COPY_PACKET setting, or when e.g. a local user + * sends a very large packet. + * + * If your application validates checksums (e.g., tcp checksum), + * then you must also check if the NFQA_SKB_INFO attribute is present. + * If it is, you need to test the NFQA_SKB_CSUMNOTREADY bit: + * \verbatim + if (attr[NFQA_SKB_INFO]) { + uint32_t info = ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])); + if (info & NFQA_SKB_CSUMNOTREADY) + validate_checksums = false; + } +\endverbatim + * if this bit is set, the layer 3/4 checksums of the packet appear incorrect, + * but are not (because they will be corrected later by the kernel). + * Please see example/nf-queue.c in the libnetfilter_queue source for more + * details. + * + * - NFQA_CFG_F_UID_GID: the kernel will dump UID and GID of the socket to + * which each packet belongs. + * + * Here's a little code snippet to show how to use this API: + * \verbatim + uint32_t flags = NFQA_CFG_F_FAIL_OPEN; + uint32_t mask = NFQA_CFG_F_FAIL_OPEN; + + printf("Enabling fail-open on this q\n"); + err = nfq_set_queue_flags(qh, mask, flags); + + printf("Disabling fail-open on this q\n"); + flags &= ~NFQA_CFG_F_FAIL_OPEN; + err = nfq_set_queue_flags(qh, mask, flags); +\endverbatim + * - NFQA_CFG_F_SECCTX: the kernel will dump security context of the socket to + * which each packet belongs. + * + * \warning + * When fragmentation occurs and NFQA_CFG_F_GSO is NOT set then the kernel + * dumps UID/GID and security context fields only for one fragment. To deal + * with this limitation always set NFQA_CFG_F_GSO. + * + * \return -1 on error with errno set appropriately; =0 otherwise. + */ +EXPORT_SYMBOL +int nfq_set_queue_flags(struct nfq_q_handle *qh, uint32_t mask, uint32_t flags) +{ + union { + char buf[NFNL_HEADER_LEN + +NFA_LENGTH(sizeof(mask) + +NFA_LENGTH(sizeof(flags)))]; + struct nlmsghdr nmh; + } u; + + mask = htonl(mask); + flags = htonl(flags); + + nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, + NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); + + nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_FLAGS, flags); + nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_MASK, mask); + + return nfnl_query(qh->h->nfnlh, &u.nmh); +} + +/** + * nfq_set_queue_maxlen - Set kernel queue maximum length parameter + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param queuelen the length of the queue + * + * Sets the size of the queue in kernel. This fixes the maximum number + * of packets the kernel will store before internally before dropping + * upcoming packets. + * + * \return -1 on error; >=0 otherwise. + */ +EXPORT_SYMBOL +int nfq_set_queue_maxlen(struct nfq_q_handle *qh, uint32_t queuelen) +{ + union { + char buf[NFNL_HEADER_LEN + +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))]; + struct nlmsghdr nmh; + } u; + uint32_t queue_maxlen = htonl(queuelen); + + nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, + NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); + + nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_QUEUE_MAXLEN, &queue_maxlen, + sizeof(queue_maxlen)); + + return nfnl_query(qh->h->nfnlh, &u.nmh); +} + +/** + * @} + */ + +static int __set_verdict(struct nfq_q_handle *qh, uint32_t id, + uint32_t verdict, uint32_t mark, int set_mark, + uint32_t data_len, const unsigned char *data, + enum nfqnl_msg_types type) +{ + struct nfqnl_msg_verdict_hdr vh; + union { + char buf[NFNL_HEADER_LEN + +NFA_LENGTH(sizeof(mark)) + +NFA_LENGTH(sizeof(vh))]; + struct nlmsghdr nmh; + } u; + + struct iovec iov[3]; + int nvecs; + + /* This must be declared here (and not inside the data + * handling block) because the iovec points to this. */ + struct nfattr data_attr; + + memset(iov, 0, sizeof(iov)); + + vh.verdict = htonl(verdict); + vh.id = htonl(id); + + nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, + type, NLM_F_REQUEST); + + /* add verdict header */ + nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_VERDICT_HDR, &vh, sizeof(vh)); + + if (set_mark) + nfnl_addattr32(&u.nmh, sizeof(u), NFQA_MARK, mark); + + iov[0].iov_base = &u.nmh; + iov[0].iov_len = NLMSG_TAIL(&u.nmh) - (void *)&u.nmh; + nvecs = 1; + + if (data_len) { + /* The typecast here is to cast away data's const-ness: */ + nfnl_build_nfa_iovec(&iov[1], &data_attr, NFQA_PAYLOAD, + data_len, (unsigned char *) data); + nvecs += 2; + /* Add the length of the appended data to the message + * header. The size of the attribute is given in the + * nfa_len field and is set in the nfnl_build_nfa_iovec() + * function. */ + u.nmh.nlmsg_len += data_attr.nfa_len; + } + + return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0); +} + +/** + * \addtogroup Queue + * @{ + */ + +/** + * nfq_set_verdict - issue a verdict on a packet + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param id ID assigned to packet by netfilter. + * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) + * \param data_len number of bytes of data pointed to by \b buf + * \param buf the buffer that contains the packet data + * + * Can be obtained by: + * \verbatim + int id; + struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(tb); + if (ph) + id = ntohl(ph->packet_id); +\endverbatim + * + * Notifies netfilter of the userspace verdict for the given packet. Every + * queued packet _must_ have a verdict specified by userspace, either by + * calling this function, the nfq_set_verdict2() function, or the _batch + * versions of these functions. + * + * \return -1 on error; >= 0 otherwise. + */ +EXPORT_SYMBOL +int nfq_set_verdict(struct nfq_q_handle *qh, uint32_t id, + uint32_t verdict, uint32_t data_len, + const unsigned char *buf) +{ + return __set_verdict(qh, id, verdict, 0, 0, data_len, buf, + NFQNL_MSG_VERDICT); +} + +/** + * nfq_set_verdict2 - like nfq_set_verdict, but you can set the mark. + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param id ID assigned to packet by netfilter. + * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) + * \param mark mark to put on packet + * \param data_len number of bytes of data pointed to by \b buf + * \param buf the buffer that contains the packet data + */ +EXPORT_SYMBOL +int nfq_set_verdict2(struct nfq_q_handle *qh, uint32_t id, + uint32_t verdict, uint32_t mark, + uint32_t data_len, const unsigned char *buf) +{ + return __set_verdict(qh, id, verdict, htonl(mark), 1, data_len, + buf, NFQNL_MSG_VERDICT); +} + +/** + * nfq_set_verdict_batch - issue verdicts on several packets at once + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param id maximum ID of the packets that the verdict should be applied to. + * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) + * + * Unlike nfq_set_verdict, the verdict is applied to all queued packets + * whose packet id is smaller or equal to \b id. + * + * batch support was added in Linux 3.1. + * These functions will fail silently on older kernels. + */ +EXPORT_SYMBOL +int nfq_set_verdict_batch(struct nfq_q_handle *qh, uint32_t id, + uint32_t verdict) +{ + return __set_verdict(qh, id, verdict, 0, 0, 0, NULL, + NFQNL_MSG_VERDICT_BATCH); +} + +/** + * nfq_set_verdict_batch2 - like nfq_set_verdict_batch, but you can set a mark. + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param id maximum ID of the packets that the verdict should be applied to. + * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) + * \param mark mark to put on packet + */ +EXPORT_SYMBOL +int nfq_set_verdict_batch2(struct nfq_q_handle *qh, uint32_t id, + uint32_t verdict, uint32_t mark) +{ + return __set_verdict(qh, id, verdict, htonl(mark), 1, 0, + NULL, NFQNL_MSG_VERDICT_BATCH); +} + +/** + * nfq_set_verdict_mark - like nfq_set_verdict, but you can set the mark. + * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). + * \param id ID assigned to packet by netfilter. + * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) + * \param mark the mark to put on the packet, in network byte order. + * \param data_len number of bytes of data pointed to by \b buf + * \param buf the buffer that contains the packet data + * + * \return -1 on error; >= 0 otherwise. + * + * This function is deprecated since it is broken, its use is highly + * discouraged. Please, use nfq_set_verdict2 instead. + */ +EXPORT_SYMBOL +int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id, + uint32_t verdict, uint32_t mark, + uint32_t data_len, const unsigned char *buf) +{ + return __set_verdict(qh, id, verdict, mark, 1, data_len, buf, + NFQNL_MSG_VERDICT); +} + +/** + * @} + */ + + + +/************************************************************* + * Message parsing functions + *************************************************************/ + +/** + * \defgroup Parsing Message parsing functions [DEPRECATED] + * @{ + */ + +/** + * nfqnl_msg_packet_hdr - return the metaheader that wraps the packet + * \param nfad Netlink packet data handle passed to callback function + * + * \return the netfilter queue netlink packet header for the given + * nfq_data argument. Typically, the nfq_data value is passed as the 3rd + * parameter to the callback function set by a call to nfq_create_queue(). + * + * The nfqnl_msg_packet_hdr structure is defined in libnetfilter_queue.h as: + * + * \verbatim + struct nfqnl_msg_packet_hdr { + uint32_t packet_id; // unique ID of packet in queue + uint16_t hw_protocol; // hw protocol (network order) + uint8_t hook; // netfilter hook + } __attribute__ ((packed)); +\endverbatim + */ +EXPORT_SYMBOL +struct nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(struct nfq_data *nfad) +{ + return nfnl_get_pointer_to_data(nfad->data, NFQA_PACKET_HDR, + struct nfqnl_msg_packet_hdr); +} + +/** + * nfq_get_nfmark - get the packet mark + * \param nfad Netlink packet data handle passed to callback function + * + * \return the netfilter mark currently assigned to the given queued packet. + */ +EXPORT_SYMBOL +uint32_t nfq_get_nfmark(struct nfq_data *nfad) +{ + return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, uint32_t)); +} + +/** + * nfq_get_timestamp - get the packet timestamp + * \param nfad Netlink packet data handle passed to callback function + * \param tv structure to fill with timestamp info + * + * Retrieves the received timestamp when the given queued packet. + * + * \return 0 on success, non-zero on failure. + */ +EXPORT_SYMBOL +int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv) +{ + struct nfqnl_msg_packet_timestamp *qpt; + qpt = nfnl_get_pointer_to_data(nfad->data, NFQA_TIMESTAMP, + struct nfqnl_msg_packet_timestamp); + if (!qpt) + return -1; + + tv->tv_sec = __be64_to_cpu(qpt->sec); + tv->tv_usec = __be64_to_cpu(qpt->usec); + + return 0; +} + +/** + * nfq_get_indev - get the interface that the packet was received through + * \param nfad Netlink packet data handle passed to callback function + * + * \return The index of the device the queued packet was received via. If the + * returned index is 0, the packet was locally generated or the input + * interface is not known (ie. POSTROUTING?). + * + * \warning all nfq_get_dev() functions return 0 if not set, since linux + * only allows ifindex >= 1, see net/core/dev.c:2600 (in 2.6.13.1) + */ +EXPORT_SYMBOL +uint32_t nfq_get_indev(struct nfq_data *nfad) +{ + return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_INDEV, uint32_t)); +} + +/** + * nfq_get_physindev - get the physical interface that the packet was received + * \param nfad Netlink packet data handle passed to callback function + * + * \return The index of the physical device the queued packet was received via. + * If the returned index is 0, the packet was locally generated or the + * physical input interface is no longer known (ie. POSTROUTING?). + */ +EXPORT_SYMBOL +uint32_t nfq_get_physindev(struct nfq_data *nfad) +{ + return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSINDEV, uint32_t)); +} + +/** + * nfq_get_outdev - gets the interface that the packet will be routed out + * \param nfad Netlink packet data handle passed to callback function + * + * \return The index of the device the queued packet will be sent out. If the + * returned index is 0, the packet is destined for localhost or the output + * interface is not yet known (ie. PREROUTING?). + */ +EXPORT_SYMBOL +uint32_t nfq_get_outdev(struct nfq_data *nfad) +{ + return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_OUTDEV, uint32_t)); +} + +/** + * nfq_get_physoutdev - get the physical interface that the packet output + * \param nfad Netlink packet data handle passed to callback function + * + * The index of the physical device the queued packet will be sent out. + * If the returned index is 0, the packet is destined for localhost or the + * physical output interface is not yet known (ie. PREROUTING?). + * + * \return The index of physical interface that the packet output will be routed out. + */ +EXPORT_SYMBOL +uint32_t nfq_get_physoutdev(struct nfq_data *nfad) +{ + return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSOUTDEV, uint32_t)); +} + +/** + * nfq_get_indev_name - get the name of the interface the packet + * was received through + * \param nlif_handle pointer to a nlif interface resolving handle + * \param nfad Netlink packet data handle passed to callback function + * \param name pointer to the buffer to receive the interface name; + * not more than \c IFNAMSIZ bytes will be copied to it. + * \return -1 in case of error, >0 if it succeed. + * + * To use a nlif_handle, You need first to call nlif_open() and to open + * an handler. Don't forget to store the result as it will be used + * during all your program life: + * \verbatim + h = nlif_open(); + if (h == NULL) { + perror("nlif_open"); + exit(EXIT_FAILURE); + } +\endverbatim + * Once the handler is open, you need to fetch the interface table at a + * whole via a call to nlif_query. + * \verbatim + nlif_query(h); +\endverbatim + * libnfnetlink is able to update the interface mapping when a new interface + * appears. To do so, you need to call nlif_catch() on the handler after each + * interface related event. The simplest way to get and treat event is to run + * a select() or poll() against the nlif file descriptor. To get this file + * descriptor, you need to use nlif_fd: + * \verbatim + if_fd = nlif_fd(h); +\endverbatim + * Don't forget to close the handler when you don't need the feature anymore: + * \verbatim + nlif_close(h); +\endverbatim + * + */ +EXPORT_SYMBOL +int nfq_get_indev_name(struct nlif_handle *nlif_handle, + struct nfq_data *nfad, char *name) +{ + uint32_t ifindex = nfq_get_indev(nfad); + return nlif_index2name(nlif_handle, ifindex, name); +} + +/** + * nfq_get_physindev_name - get the name of the physical interface the + * packet was received through + * \param nlif_handle pointer to a nlif interface resolving handle + * \param nfad Netlink packet data handle passed to callback function + * \param name pointer to the buffer to receive the interface name; + * not more than \c IFNAMSIZ bytes will be copied to it. + * + * See nfq_get_indev_name() documentation for nlif_handle usage. + * + * \return -1 in case of error, > 0 if it succeed. + */ +EXPORT_SYMBOL +int nfq_get_physindev_name(struct nlif_handle *nlif_handle, + struct nfq_data *nfad, char *name) +{ + uint32_t ifindex = nfq_get_physindev(nfad); + return nlif_index2name(nlif_handle, ifindex, name); +} + +/** + * nfq_get_outdev_name - get the name of the physical interface the + * packet will be sent to + * \param nlif_handle pointer to a nlif interface resolving handle + * \param nfad Netlink packet data handle passed to callback function + * \param name pointer to the buffer to receive the interface name; + * not more than \c IFNAMSIZ bytes will be copied to it. + * + * See nfq_get_indev_name() documentation for nlif_handle usage. + * + * \return -1 in case of error, > 0 if it succeed. + */ +EXPORT_SYMBOL +int nfq_get_outdev_name(struct nlif_handle *nlif_handle, + struct nfq_data *nfad, char *name) +{ + uint32_t ifindex = nfq_get_outdev(nfad); + return nlif_index2name(nlif_handle, ifindex, name); +} + +/** + * nfq_get_physoutdev_name - get the name of the interface the + * packet will be sent to + * \param nlif_handle pointer to a nlif interface resolving handle + * \param nfad Netlink packet data handle passed to callback function + * \param name pointer to the buffer to receive the interface name; + * not more than \c IFNAMSIZ bytes will be copied to it. + * + * See nfq_get_indev_name() documentation for nlif_handle usage. + * + * \return -1 in case of error, > 0 if it succeed. + */ + +EXPORT_SYMBOL +int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle, + struct nfq_data *nfad, char *name) +{ + uint32_t ifindex = nfq_get_physoutdev(nfad); + return nlif_index2name(nlif_handle, ifindex, name); +} + +/** + * nfq_get_packet_hw + * + * get hardware address + * + * \param nfad Netlink packet data handle passed to callback function + * + * Retrieves the hardware address associated with the given queued packet. + * For ethernet packets, the hardware address returned (if any) will be the + * MAC address of the packet source host. The destination MAC address is not + * known until after POSTROUTING and a successful ARP request, so cannot + * currently be retrieved. + * + * The nfqnl_msg_packet_hw structure is defined in libnetfilter_queue.h as: + * \verbatim + struct nfqnl_msg_packet_hw { + uint16_t hw_addrlen; + uint16_t _pad; + uint8_t hw_addr[8]; + } __attribute__ ((packed)); +\endverbatim + */ +EXPORT_SYMBOL +struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad) +{ + return nfnl_get_pointer_to_data(nfad->data, NFQA_HWADDR, + struct nfqnl_msg_packet_hw); +} + +/** + * nfq_get_skbinfo - return the NFQA_SKB_INFO meta information + * \param nfad Netlink packet data handle passed to callback function + * + * This can be used to obtain extra information about a packet by testing + * the returned integer for any of the following bit flags: + * + * - NFQA_SKB_CSUMNOTREADY + * packet header checksums will be computed by hardware later on, i.e. + * tcp/ip checksums in the packet must not be validated, application + * should pretend they are correct. + * - NFQA_SKB_GSO + * packet is an aggregated super-packet. It exceeds device mtu and will + * be (re-)split on transmit by hardware. + * - NFQA_SKB_CSUM_NOTVERIFIED + * packet checksum was not yet verified by the kernel/hardware, for + * example because this is an incoming packet and the NIC does not + * perform checksum validation at hardware level. + * + * \return the skbinfo value + * \sa __nfq_set_queue_flags__(3) + */ +EXPORT_SYMBOL +uint32_t nfq_get_skbinfo(struct nfq_data *nfad) +{ + if (!nfnl_attr_present(nfad->data, NFQA_SKB_INFO)) + return 0; + + return ntohl(nfnl_get_data(nfad->data, NFQA_SKB_INFO, uint32_t)); +} + +/** + * nfq_get_uid - get the UID of the user the packet belongs to + * \param nfad Netlink packet data handle passed to callback function + * \param uid Set to UID on return + * + * \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets + * may be pushed into the queue. In this case, only one fragment will have the + * UID field set. To deal with this issue always set NFQA_CFG_F_GSO. + * + * \return 1 if there is a UID available, 0 otherwise. + */ +EXPORT_SYMBOL +int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid) +{ + if (!nfnl_attr_present(nfad->data, NFQA_UID)) + return 0; + + *uid = ntohl(nfnl_get_data(nfad->data, NFQA_UID, uint32_t)); + return 1; +} + +/** + * nfq_get_gid - get the GID of the user the packet belongs to + * \param nfad Netlink packet data handle passed to callback function + * \param gid Set to GID on return + * + * \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets + * may be pushed into the queue. In this case, only one fragment will have the + * GID field set. To deal with this issue always set NFQA_CFG_F_GSO. + * + * \return 1 if there is a GID available, 0 otherwise. + */ +EXPORT_SYMBOL +int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid) +{ + if (!nfnl_attr_present(nfad->data, NFQA_GID)) + return 0; + + *gid = ntohl(nfnl_get_data(nfad->data, NFQA_GID, uint32_t)); + return 1; +} + +/** + * nfq_get_secctx - get the security context for this packet + * \param nfad Netlink packet data handle passed to callback function + * \param secdata data to write the security context to + * + * \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets + * may be pushed into the queue. In this case, only one fragment will have the + * SECCTX field set. To deal with this issue always set NFQA_CFG_F_GSO. + * + * \return -1 on error, otherwise > 0 + */ +EXPORT_SYMBOL +int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata) +{ + if (!nfnl_attr_present(nfad->data, NFQA_SECCTX)) + return -1; + + *secdata = (unsigned char *)nfnl_get_pointer_to_data(nfad->data, + NFQA_SECCTX, char); + + if (*secdata) + return NFA_PAYLOAD(nfad->data[NFQA_SECCTX-1]); + + return 0; +} + +/** + * nfq_get_payload - get payload + * \param nfad Netlink packet data handle passed to callback function + * \param data Pointer of pointer that will be pointed to the payload + * + * Retrieve the payload for a queued packet. The actual amount and type of + * data retrieved by this function will depend on the mode set with the + * nfq_set_mode() function. + * + * \return -1 on error, otherwise > 0. + */ +EXPORT_SYMBOL +int nfq_get_payload(struct nfq_data *nfad, unsigned char **data) +{ + *data = (unsigned char *) + nfnl_get_pointer_to_data(nfad->data, NFQA_PAYLOAD, char); + if (*data) + return NFA_PAYLOAD(nfad->data[NFQA_PAYLOAD-1]); + + return -1; +} + +/** + * @} + */ + +#define SNPRINTF_FAILURE(ret, rem, offset, len) \ +do { \ + if (ret < 0) \ + return ret; \ + len += ret; \ + if (ret > rem) \ + ret = rem; \ + offset += ret; \ + rem -= ret; \ +} while (0) + +/** + * \defgroup Printing Printing [DEPRECATED] + * @{ + */ + +/** + * nfq_snprintf_xml - print the enqueued packet in XML format into a buffer + * \param buf The buffer that you want to use to print the logged packet + * \param rem The size of the buffer that you have passed + * \param tb Netlink packet data handle passed to callback function + * \param flags The flag that tell what to print into the buffer + * + * This function supports the following flags: + * + * - NFQ_XML_HW: include the hardware link layer address + * - NFQ_XML_MARK: include the packet mark + * - NFQ_XML_DEV: include the device information + * - NFQ_XML_PHYSDEV: include the physical device information + * - NFQ_XML_PAYLOAD: include the payload (in hexadecimal) + * - NFQ_XML_TIME: include the timestamp + * - NFQ_XML_ALL: include all the logging information (all flags set) + * + * You can combine this flags with an binary OR. + * + * \return -1 in case of failure, otherwise the length of the string that + * would have been printed into the buffer (in case that there is enough + * room in it). See snprintf() return value for more information. + */ +EXPORT_SYMBOL +int nfq_snprintf_xml(char *buf, size_t rem, struct nfq_data *tb, int flags) +{ + struct nfqnl_msg_packet_hdr *ph; + struct nfqnl_msg_packet_hw *hwph; + uint32_t mark, ifi; + uint32_t uid, gid; + int size, offset = 0, len = 0, ret; + unsigned char *data; + + size = snprintf(buf + offset, rem, ""); + SNPRINTF_FAILURE(size, rem, offset, len); + + if (flags & NFQ_XML_TIME) { + time_t t; + struct tm tm; + + t = time(NULL); + if (localtime_r(&t, &tm) == NULL) + return -1; + + size = snprintf(buf + offset, rem, ""); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, + "%d", tm.tm_hour); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, + rem, "%02d", tm.tm_min); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, + rem, "%02d", tm.tm_sec); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, "%d", + tm.tm_wday + 1); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, "%d", tm.tm_mday); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, "%d", + tm.tm_mon + 1); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, "%d", + 1900 + tm.tm_year); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, ""); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ph = nfq_get_msg_packet_hdr(tb); + if (ph) { + size = snprintf(buf + offset, rem, + "%u%u", + ph->hook, ntohl(ph->packet_id)); + SNPRINTF_FAILURE(size, rem, offset, len); + + hwph = nfq_get_packet_hw(tb); + if (hwph && (flags & NFQ_XML_HW)) { + int i, hlen = ntohs(hwph->hw_addrlen); + + size = snprintf(buf + offset, rem, "%04x" + "", + ntohs(ph->hw_protocol)); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, ""); + SNPRINTF_FAILURE(size, rem, offset, len); + + for (i=0; ihw_addr[i]); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + size = snprintf(buf + offset, rem, ""); + SNPRINTF_FAILURE(size, rem, offset, len); + } else if (flags & NFQ_XML_HW) { + size = snprintf(buf + offset, rem, "%04x" + "", + ntohs(ph->hw_protocol)); + SNPRINTF_FAILURE(size, rem, offset, len); + } + } + + mark = nfq_get_nfmark(tb); + if (mark && (flags & NFQ_XML_MARK)) { + size = snprintf(buf + offset, rem, "%u", mark); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_indev(tb); + if (ifi && (flags & NFQ_XML_DEV)) { + size = snprintf(buf + offset, rem, "%u", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_outdev(tb); + if (ifi && (flags & NFQ_XML_DEV)) { + size = snprintf(buf + offset, rem, "%u", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_physindev(tb); + if (ifi && (flags & NFQ_XML_PHYSDEV)) { + size = snprintf(buf + offset, rem, + "%u", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_physoutdev(tb); + if (ifi && (flags & NFQ_XML_PHYSDEV)) { + size = snprintf(buf + offset, rem, + "%u", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + if (nfq_get_uid(tb, &uid) && (flags & NFQ_XML_UID)) { + size = snprintf(buf + offset, rem, "%u", uid); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + if (nfq_get_gid(tb, &gid) && (flags & NFQ_XML_GID)) { + size = snprintf(buf + offset, rem, "%u", gid); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ret = nfq_get_payload(tb, &data); + if (ret >= 0 && (flags & NFQ_XML_PAYLOAD)) { + int i; + + size = snprintf(buf + offset, rem, ""); + SNPRINTF_FAILURE(size, rem, offset, len); + + for (i=0; i"); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + size = snprintf(buf + offset, rem, ""); + SNPRINTF_FAILURE(size, rem, offset, len); + + return len; +} + +/** + * @} + */ diff --git a/ref/libnetfilter-queue/src/nlmsg.c b/ref/libnetfilter-queue/src/nlmsg.c new file mode 100644 index 0000000..e141156 --- /dev/null +++ b/ref/libnetfilter-queue/src/nlmsg.c @@ -0,0 +1,299 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * 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 +#include +#include +#include +#include + +#include + +#ifndef __aligned_be64 +#define __aligned_be64 __be64 __attribute__((aligned(8))) +#define __aligned_le64 __le64 __attribute__((aligned(8))) +#endif + +#include + +#include + +#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 + * 46 + * 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), ¶ms); +} + +/** + * 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; +} + +/** + * @} + */ diff --git a/ref/libnetfilter-queue/utils/.gitignore b/ref/libnetfilter-queue/utils/.gitignore new file mode 100644 index 0000000..10fe6e9 --- /dev/null +++ b/ref/libnetfilter-queue/utils/.gitignore @@ -0,0 +1 @@ +/nfqnl_test diff --git a/ref/libnetfilter-queue/utils/Makefile.am b/ref/libnetfilter-queue/utils/Makefile.am new file mode 100644 index 0000000..d3147e3 --- /dev/null +++ b/ref/libnetfilter-queue/utils/Makefile.am @@ -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 + + diff --git a/ref/libnetfilter-queue/utils/nfqnl_test.c b/ref/libnetfilter-queue/utils/nfqnl_test.c new file mode 100644 index 0000000..5e76ffe --- /dev/null +++ b/ref/libnetfilter-queue/utils/nfqnl_test.c @@ -0,0 +1,186 @@ + +#include +#include +#include +#include +#include +#include /* for NF_ACCEPT */ +#include + +#include + +/* 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); +} diff --git a/src/ua2f.c b/src/ua2f.c index 7782828..b2fdc05 100644 --- a/src/ua2f.c +++ b/src/ua2f.c @@ -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);