diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 + + 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) + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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 Lesser General +Public License instead of this License. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..65fd50d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,17 @@ +# -*- Makefile -*- + +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = extensions + +tmpdir := $(shell mktemp -dtu) +packer = xz +packext = .tar.xz + +.PHONY: tarball +tarball: +# do not use mkdir_p here. + mkdir ${tmpdir} + pushd ${top_srcdir} && git archive --prefix=${PACKAGE_NAME}-${PACKAGE_VERSION}/ HEAD | tar -C ${tmpdir} -x && popd; + pushd ${tmpdir}/${PACKAGE_NAME}-${PACKAGE_VERSION} && ./autogen.sh && popd; + tar --use=${packer} -C ${tmpdir} -cf ${PACKAGE_NAME}-${PACKAGE_VERSION}${packext} --owner=root --group=root ${PACKAGE_NAME}-${PACKAGE_VERSION}/; + rm -Rf ${tmpdir}; diff --git a/Makefile.extra b/Makefile.extra new file mode 100644 index 0000000..53f15bb --- /dev/null +++ b/Makefile.extra @@ -0,0 +1,31 @@ +# -*- Makefile -*- +# AUTOMAKE + +export AM_CPPFLAGS +export AM_CFLAGS +XA_SRCDIR = ${srcdir} +XA_TOPSRCDIR = ${top_srcdir} +XA_ABSTOPSRCDIR = ${abs_top_srcdir} +export XA_SRCDIR +export XA_TOPSRCDIR +export XA_ABSTOPSRCDIR + +_mcall = -f ${top_builddir}/Makefile.iptrules + +all-local: user-all-local + +install-exec-local: user-install-local + +clean-local: user-clean-local + +user-all-local: + ${MAKE} ${_mcall} all; + +# Have no user-install-data-local ATM +user-install-local: user-install-exec-local + +user-install-exec-local: + ${MAKE} ${_mcall} install; + +user-clean-local: + ${MAKE} ${_mcall} clean; diff --git a/Makefile.iptrules.in b/Makefile.iptrules.in new file mode 100644 index 0000000..fcac885 --- /dev/null +++ b/Makefile.iptrules.in @@ -0,0 +1,62 @@ +# -*- Makefile -*- +# MANUAL + +abs_top_srcdir = @abs_top_srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libexecdir = @libexecdir@ +xtlibdir = @xtlibdir@ + +CC = @CC@ +CCLD = ${CC} +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ + +libxtables_CFLAGS = @libxtables_CFLAGS@ +libxtables_LIBS = @libxtables_LIBS@ +AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ + +AM_DEFAULT_VERBOSITY = 0 +am__v_CC_0 = @echo " CC " $@; +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_GEN_0 = @echo " GEN " $@; +am__v_SILENT_0 = @ +am__v_CC_ = ${am__v_CC_${AM_DEFAULT_VERBOSITY}} +am__v_CCLD_ = ${am__v_CCLD_${AM_DEFAULT_VERBOSITY}} +am__v_GEN_ = ${am__v_GEN_${AM_DEFAULT_VERBOSITY}} +am__v_SILENT_ = ${am__v_SILENT_${AM_DEFAULT_VERBOSITY}} +AM_V_CC = ${am__v_CC_${V}} +AM_V_CCLD = ${am__v_CCLD_${V}} +AM_V_GEN = ${am__v_GEN_${V}} +AM_V_silent = ${am__v_GEN_${V}} + +include ${XA_TOPSRCDIR}/mconfig +-include ${XA_TOPSRCDIR}/mconfig.* +include ${XA_SRCDIR}/Mbuild +-include ${XA_SRCDIR}/Mbuild.* + +targets := $(filter-out %/,${obj-m}) +subdirs_list := $(filter %/,${obj-m}) + +.SECONDARY: + +.PHONY: all install clean + +all: ${targets} + @for i in ${subdirs_list}; do ${MAKE} -C $$i || exit $$?; done; + +install: ${targets} + @for i in ${subdirs_list}; do ${MAKE} -C $$i $@ || exit $$?; done; + install -dm0755 "${DESTDIR}/${xtlibdir}"; + @for i in $^; do install -pm0755 $$i "${DESTDIR}/${xtlibdir}"; done; + +clean: + @for i in ${subdirs_list}; do ${MAKE} -C $$i $@ || exit $$?; done; + rm -f *.oo *.so; + +lib%.so: lib%.oo + ${AM_V_CCLD}${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $< ${libxtables_LIBS} ${LDLIBS}; + +%.oo: ${XA_SRCDIR}/%.c + ${AM_V_CC}${CC} ${AM_DEPFLAGS} ${AM_CPPFLAGS} ${AM_CFLAGS} -DPIC -fPIC ${CPPFLAGS} ${CFLAGS} -o $@ -c $<; diff --git a/README.md b/README.md new file mode 100644 index 0000000..2a44a4b --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# Zenedge add-ons for netfilter/iptables + +Zentables-addons is a set of extensions to netfilter/iptables +developed by [Zenedge](http://www.zenedge.com) and +based on [Xtables-addons](http://xtables-addons.sourceforge.net/). + +## Zenset + +Zenset is a netfilter/iptables extension which provides support for matching +[Proxy Protocol](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) +source address +using [IP Set](http://ipset.netfilter.org/). + +## RESET + +RESET is a netfilter/iptables extension which provides support to finalize an +established TCP connection by emulating a TCP RST to both ends. +This extension is based on ipt\_REJECT. + +## Usage + +For example, for blocking the source address _10.10.10.10_ sent through _Proxy +Protocol_ using _TCP RST_ and a _IP set_, we can use: +``` +# ipset create blacklist hash:ip +# ipset add blacklist 10.10.10.10 +# iptables -I INPUT -m zenset --proxy-protocol --match-set blacklist src -j RESET +``` + +## Installation + +### Dependencies + +``` +# apt-get install libmnl-dev libltdl7-dev iptables-dev libxtables10 libipset-dev ipset + +``` + +### Building + +``` +$ ./autogen.sh +$ ./configure +$ make +# make install +``` + +### Running + +``` +# depmode -a +# modprobe xt_zenset +# modprobe xt_RESET +``` + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..62a89e1 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +autoreconf -fi; +rm -Rf autom4te*.cache; diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..67f9049 --- /dev/null +++ b/configure.ac @@ -0,0 +1,83 @@ +AC_INIT([xtables-addons], [2.10]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_PROG_INSTALL +AM_INIT_AUTOMAKE([1.10b -Wall foreign subdir-objects]) +AC_PROG_CC +AM_PROG_CC_C_O +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +AC_DISABLE_STATIC +AC_PROG_LIBTOOL + +AC_ARG_WITH([kbuild], + AS_HELP_STRING([--with-kbuild=PATH], + [Path to kernel build directory [[/lib/modules/CURRENT/build]]]) +AS_HELP_STRING([--without-kbuild], + [Build only userspace tools]), + [kbuilddir="$withval"], + [kbuilddir="/lib/modules/$(uname -r)/build"]) +# +# check for --without-kbuild +# +if [[ "$kbuilddir" == no ]]; then + kbuilddir=""; +fi + +AC_CHECK_HEADERS([linux/netfilter/x_tables.h], [], + [AC_MSG_ERROR([You need to have linux/netfilter/x_tables.h, see INSTALL file for details])]) +PKG_CHECK_MODULES([libxtables], [xtables >= 1.4.5]) +xtlibdir="$(pkg-config --variable=xtlibdir xtables)" + +AC_ARG_WITH([xtlibdir], + AS_HELP_STRING([--with-xtlibdir=PATH], + [Path where to install Xtables extensions [[autodetect]]]), + [xtlibdir="$withval"]) +AC_MSG_CHECKING([Xtables module directory]) +AC_MSG_RESULT([$xtlibdir]) + +regular_CPPFLAGS="-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 \ + -D_REENTRANT -I\${XA_TOPSRCDIR}/include" +regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \ + -Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \ + -Winline -pipe"; + +if test -n "$kbuilddir"; then + AC_MSG_CHECKING([kernel version that we will build against]) + krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease)"; + kmajor="${krel%%[[^0-9]]*}"; + kmajor="$(($kmajor+0))"; + krel="${krel:${#kmajor}}"; + krel="${krel#.}"; + kminor="${krel%%[[^0-9]]*}"; + kminor="$(($kminor+0))"; + krel="${krel:${#kminor}}"; + krel="${krel#.}"; + kmicro="${krel%%[[^0-9]]*}"; + kmicro="$(($kmicro+0))"; + krel="${krel:${#kmicro}}"; + krel="${krel#.}"; + kstable="${krel%%[[^0-9]]*}"; + kstable="$(($kstable+0))"; + if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then + echo "WARNING: Version detection did not succeed. Continue at own luck."; + else + echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir"; + if test "$kmajor" -gt 4 -o "$kmajor" -eq 4 -a "$kminor" -gt 3; then + echo "WARNING: That kernel version is not officially supported yet. Continue at own luck."; + elif test "$kmajor" -eq 4 -a "$kminor" -le 3; then + :; + elif test "$kmajor" -eq 3 -a "$kminor" -ge 7; then + :; + else + echo "WARNING: That kernel version is not officially supported."; + fi; + fi; +fi; + +AC_SUBST([regular_CPPFLAGS]) +AC_SUBST([regular_CFLAGS]) +AC_SUBST([kbuilddir]) +AC_SUBST([xtlibdir]) +AC_CONFIG_FILES([Makefile Makefile.iptrules extensions/Makefile]) +AC_OUTPUT diff --git a/extensions/.gitignore b/extensions/.gitignore new file mode 100644 index 0000000..3c2e675 --- /dev/null +++ b/extensions/.gitignore @@ -0,0 +1,12 @@ +.*.cmd +.*.d +.tmp_versions/ +*.ko +*.mod.c +Module.markers +Module.symvers +Modules.symvers +modules.order + +*.so +*.oo diff --git a/extensions/Kbuild b/extensions/Kbuild new file mode 100644 index 0000000..6f97b40 --- /dev/null +++ b/extensions/Kbuild @@ -0,0 +1,12 @@ +# -*- Makefile -*- + +include ${XA_ABSTOPSRCDIR}/mconfig +-include ${XA_ABSTOPSRCDIR}/mconfig.* + +obj-m += compat_xtables.o + +obj-${build_zenset} += xt_zenset.o +obj-${build_RESET} += xt_RESET.o + +-include ${M}/*.Kbuild +-include ${M}/Kbuild.* diff --git a/extensions/Makefile.am b/extensions/Makefile.am new file mode 100644 index 0000000..a487fd8 --- /dev/null +++ b/extensions/Makefile.am @@ -0,0 +1,29 @@ +# -*- Makefile -*- +# AUTOMAKE + +AM_CPPFLAGS = ${regular_CPPFLAGS} -I${abs_top_srcdir}/extensions +AM_CFLAGS = ${regular_CFLAGS} ${libxtables_CFLAGS} + +# Not having Kbuild in Makefile.extra because it will already recurse +.PHONY: modules modules_install clean_modules + +_kcall = -C ${kbuilddir} M=${abs_srcdir} + +modules: + @echo -n "Xtables-addons ${PACKAGE_VERSION} - Linux " + @if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} --no-print-directory -s kernelrelease; fi; + ${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} modules; fi; + +modules_install: + ${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} INSTALL_MOD_PATH=${DESTDIR} ext-mod-dir='$${INSTALL_MOD_DIR}' modules_install; fi; + +clean_modules: + ${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} clean; fi; + +all-local: modules + +install-exec-local: modules_install + +clean-local: clean_modules + +include ../Makefile.extra diff --git a/extensions/Mbuild b/extensions/Mbuild new file mode 100644 index 0000000..c37f987 --- /dev/null +++ b/extensions/Mbuild @@ -0,0 +1,4 @@ +# -*- Makefile -*- + +obj-${build_zenset} += libxt_zenset.so +obj-${build_RESET} += libxt_RESET.so diff --git a/extensions/compat_skbuff.h b/extensions/compat_skbuff.h new file mode 100644 index 0000000..ba064c1 --- /dev/null +++ b/extensions/compat_skbuff.h @@ -0,0 +1,16 @@ +#ifndef COMPAT_SKBUFF_H +#define COMPAT_SKBUFF_H 1 + +struct tcphdr; +struct udphdr; + +#define skb_ifindex(skb) (skb)->skb_iif +#define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark) + +#ifdef CONFIG_NETWORK_SECMARK +# define skb_secmark(skb) ((skb)->secmark) +#else +# define skb_secmark(skb) 0 +#endif + +#endif /* COMPAT_SKBUFF_H */ diff --git a/extensions/compat_user.h b/extensions/compat_user.h new file mode 100644 index 0000000..3ad168c --- /dev/null +++ b/extensions/compat_user.h @@ -0,0 +1,12 @@ +/* + * Userspace-level compat hacks + */ +#ifndef _XTABLES_COMPAT_USER_H +#define _XTABLES_COMPAT_USER_H 1 + +/* linux-glibc-devel 2.6.34 header screwup */ +#ifndef ALIGN +# define ALIGN(s, n) (((s) + ((n) - 1)) & ~((n) - 1)) +#endif + +#endif /* _XTABLES_COMPAT_USER_H */ diff --git a/extensions/compat_xtables.c b/extensions/compat_xtables.c new file mode 100644 index 0000000..d3312d5 --- /dev/null +++ b/extensions/compat_xtables.c @@ -0,0 +1,45 @@ +/* + * API compat layer + * written by Jan Engelhardt, 2008 - 2010 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License, either + * version 2 of the License, or any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "compat_skbuff.h" +#include "compat_xtnu.h" +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) +# define WITH_IPV6 1 +#endif + +void *HX_memmem(const void *space, size_t spacesize, + const void *point, size_t pointsize) +{ + size_t i; + + if (pointsize > spacesize) + return NULL; + for (i = 0; i <= spacesize - pointsize; ++i) + if (memcmp(space + i, point, pointsize) == 0) + return (void *)space + i; + return NULL; +} +EXPORT_SYMBOL_GPL(HX_memmem); + +MODULE_LICENSE("GPL"); diff --git a/extensions/compat_xtables.h b/extensions/compat_xtables.h new file mode 100644 index 0000000..a6c61ac --- /dev/null +++ b/extensions/compat_xtables.h @@ -0,0 +1,92 @@ +#ifndef _XTABLES_COMPAT_H +#define _XTABLES_COMPAT_H 1 + +#include +#include +#include "compat_skbuff.h" +#include "compat_xtnu.h" + +#define DEBUGP Use__pr_debug__instead + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) +# warning Kernels below 3.7 not supported. +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) +# define prandom_u32() random32() +#endif + +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +# if !defined(CONFIG_NF_CONNTRACK_MARK) +# warning You have CONFIG_NF_CONNTRACK enabled, but CONFIG_NF_CONNTRACK_MARK is not (please enable). +# endif +# include +#else +# warning You need CONFIG_NF_CONNTRACK. +#endif + +#if !defined(NIP6) && !defined(NIP6_FMT) +# define NIP6(addr) \ + ntohs((addr).s6_addr16[0]), \ + ntohs((addr).s6_addr16[1]), \ + ntohs((addr).s6_addr16[2]), \ + ntohs((addr).s6_addr16[3]), \ + ntohs((addr).s6_addr16[4]), \ + ntohs((addr).s6_addr16[5]), \ + ntohs((addr).s6_addr16[6]), \ + ntohs((addr).s6_addr16[7]) +# define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +#endif +#if !defined(NIPQUAD) && !defined(NIPQUAD_FMT) +# define NIPQUAD(addr) \ + ((const unsigned char *)&addr)[0], \ + ((const unsigned char *)&addr)[1], \ + ((const unsigned char *)&addr)[2], \ + ((const unsigned char *)&addr)[3] +# define NIPQUAD_FMT "%u.%u.%u.%u" +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) +static inline struct inode *file_inode(struct file *f) +{ + return f->f_path.dentry->d_inode; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) +static inline void proc_set_user(struct proc_dir_entry *de, + typeof(de->uid) uid, typeof(de->gid) gid) +{ + de->uid = uid; + de->gid = gid; +} + +static inline void *PDE_DATA(struct inode *inode) +{ + return PDE(inode)->data; +} + +static inline void proc_remove(struct proc_dir_entry *de) +{ + if (de != NULL) + remove_proc_entry(de->name, de->parent); +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) +# define ip6_local_out(xnet, xsk, xskb) ip6_local_out(xskb) +# define ip6_route_me_harder(xnet, xskb) ip6_route_me_harder(xskb) +# define ip_local_out(xnet, xsk, xskb) ip_local_out(xskb) +# define ip_route_me_harder(xnet, xskb, xaddrtype) ip_route_me_harder((xskb), (xaddrtype)) +#endif + +static inline struct net *par_net(const struct xt_action_param *par) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) + return par->net; +#else + return dev_net((par->in != NULL) ? par->in : par->out); +#endif +} + +#endif /* _XTABLES_COMPAT_H */ diff --git a/extensions/compat_xtnu.h b/extensions/compat_xtnu.h new file mode 100644 index 0000000..150dc0e --- /dev/null +++ b/extensions/compat_xtnu.h @@ -0,0 +1,67 @@ +#ifndef _COMPAT_XTNU_H +#define _COMPAT_XTNU_H 1 + +#include + +struct module; +struct sk_buff; + +struct xtnu_match { + /* + * Making it smaller by sizeof(void *) on purpose to catch + * lossy translation, if any. + */ + char name[sizeof(((struct xt_match *)NULL)->name) - 1 - sizeof(void *)]; + uint8_t revision; + bool (*match)(const struct sk_buff *, struct xt_action_param *); + int (*checkentry)(const struct xt_mtchk_param *); + void (*destroy)(const struct xt_mtdtor_param *); + struct module *me; + const char *table; + unsigned int matchsize, hooks; + unsigned short proto, family; + + void *__compat_match; +}; + +struct xtnu_target { + char name[sizeof(((struct xt_target *)NULL)->name) - 1 - sizeof(void *)]; + uint8_t revision; + unsigned int (*target)(struct sk_buff **, + const struct xt_action_param *); + int (*checkentry)(const struct xt_tgchk_param *); + void (*destroy)(const struct xt_tgdtor_param *); + struct module *me; + const char *table; + unsigned int targetsize, hooks; + unsigned short proto, family; + + void *__compat_target; +}; + +static inline struct xtnu_match *xtcompat_numatch(const struct xt_match *m) +{ + void *q; + memcpy(&q, m->name + sizeof(m->name) - sizeof(void *), sizeof(void *)); + return q; +} + +static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t) +{ + void *q; + memcpy(&q, t->name + sizeof(t->name) - sizeof(void *), sizeof(void *)); + return q; +} + +extern int xtnu_register_match(struct xtnu_match *); +extern void xtnu_unregister_match(struct xtnu_match *); +extern int xtnu_register_matches(struct xtnu_match *, unsigned int); +extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int); +extern int xtnu_register_target(struct xtnu_target *); +extern void xtnu_unregister_target(struct xtnu_target *); +extern int xtnu_register_targets(struct xtnu_target *, unsigned int); +extern void xtnu_unregister_targets(struct xtnu_target *, unsigned int); + +extern void *HX_memmem(const void *, size_t, const void *, size_t); + +#endif /* _COMPAT_XTNU_H */ diff --git a/extensions/libxt_RESET.c b/extensions/libxt_RESET.c new file mode 100644 index 0000000..bf1fb4a --- /dev/null +++ b/extensions/libxt_RESET.c @@ -0,0 +1,43 @@ +/* + * "RESET" target extension for iptables + * Copyright © Jan Engelhardt, 2008 + * Copyright (C) 2016 Zenedge Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License; either + * version 2 of the License, or any later version, as published by the + * Free Software Foundation. + */ +#include +#include +#include +#include "compat_user.h" + +static void reset_tg_help(void) +{ + printf("RESET takes no options\n\n"); +} + +static int reset_tg_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) +{ + return 0; +} + +static void reset_tg_check(unsigned int flags) +{ +} + +static struct xtables_target reset_tg_reg = { + .version = XTABLES_VERSION, + .name = "RESET", + .family = NFPROTO_UNSPEC, + .help = reset_tg_help, + .parse = reset_tg_parse, + .final_check = reset_tg_check, +}; + +static __attribute__((constructor)) void reset_tg_ldr(void) +{ + xtables_register_target(&reset_tg_reg); +} diff --git a/extensions/libxt_zenset.c b/extensions/libxt_zenset.c new file mode 100644 index 0000000..fc32fc5 --- /dev/null +++ b/extensions/libxt_zenset.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2000-2002 Joakim Axelsson + * Patrick Schaaf + * Martin Josefsson + * Copyright (C) 2003-2010 Jozsef Kadlecsik + * Copyright (C) 2016 Zenedge Inc + * + * 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. + */ + +/* Shared library add-on to iptables to add IP set matching. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xt_zenset.h" +#include "libxt_zenset.h" + +static void +zenset_check(unsigned int flags) +{ + if (!flags) + xtables_error(PARAMETER_PROBLEM, + "You must specify `--match-set' with proper arguments"); +} + +static void +print_match(const char *prefix, const struct xt_zenset_info *info) +{ + int i; + char setname[IPSET_MAXNAMELEN]; + + get_set_byid(setname, info->index); + printf("%s %s %s", + (info->flags & IPSET_INV_MATCH) ? " !" : "", + prefix, + setname); + for (i = 1; i <= info->dim; i++) { + printf("%s%s", + i == 1 ? " " : ",", + info->flags & (1 << i) ? "src" : "dst"); + } +} + +static void +zenset_help(void) +{ + printf("set match options:\n" + " [!] --match-set name flags [--return-nomatch]\n" + " [! --update-counters] [! --update-subcounters] [--proxy-protocol]\n" + " [[!] --packets-eq value | --packets-lt value | --packets-gt value\n" + " [[!] --bytes-eq value | --bytes-lt value | --bytes-gt value\n" + " 'name' is the set name from to match,\n" + " 'flags' are the comma separated list of\n" + " 'src' and 'dst' specifications.\n"); +} + +static const struct option zenset_opts[] = { + {.name = "match-set", .has_arg = true, .val = '1'}, + {.name = "set", .has_arg = true, .val = '2'}, + {.name = "return-nomatch", .has_arg = false, .val = '3'}, + {.name = "update-counters", .has_arg = false, .val = '4'}, + {.name = "packets-eq", .has_arg = true, .val = '5'}, + {.name = "packets-lt", .has_arg = true, .val = '6'}, + {.name = "packets-gt", .has_arg = true, .val = '7'}, + {.name = "bytes-eq", .has_arg = true, .val = '8'}, + {.name = "bytes-lt", .has_arg = true, .val = '9'}, + {.name = "bytes-gt", .has_arg = true, .val = '0'}, + {.name = "update-subcounters", .has_arg = false, .val = 'a'}, + {.name = "proxy-protocol", .has_arg = false, .val = 'b'}, + XT_GETOPT_TABLEEND, +}; + +static uint64_t +parse_counter(const char *opt) +{ + uintmax_t value; + + if (!xtables_strtoul(opt, NULL, &value, 0, UINT64_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Cannot parse %s as a counter value\n", + opt); + return (uint64_t)value; +} + +static int +zenset_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct xt_zenset_info_match *info = + (struct xt_zenset_info_match *) (*match)->data; + + switch (c) { + case 'b': + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--proxy-protocol flag cannot be inverted\n"); + info->match_set.flags |= ZENSET_PROXY_PROTOCOL; + break; + case 'a': + if (invert) + info->flags |= IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE; + break; + case '0': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--bytes-gt option cannot be inverted\n"); + info->bytes.op = IPSET_COUNTER_GT; + info->bytes.value = parse_counter(optarg); + break; + case '9': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--bytes-lt option cannot be inverted\n"); + info->bytes.op = IPSET_COUNTER_LT; + info->bytes.value = parse_counter(optarg); + break; + case '8': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; + info->bytes.value = parse_counter(optarg); + break; + case '7': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--packets-gt option cannot be inverted\n"); + info->packets.op = IPSET_COUNTER_GT; + info->packets.value = parse_counter(optarg); + break; + case '6': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--packets-lt option cannot be inverted\n"); + info->packets.op = IPSET_COUNTER_LT; + info->packets.value = parse_counter(optarg); + break; + case '5': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; + info->packets.value = parse_counter(optarg); + break; + case '4': + if (invert) + info->flags |= IPSET_FLAG_SKIP_COUNTER_UPDATE; + break; + case '3': + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--return-nomatch flag cannot be inverted\n"); + info->flags |= IPSET_FLAG_RETURN_NOMATCH; + break; + case '2': + fprintf(stderr, + "--set option deprecated, please use --match-set\n"); + case '1': /* --match-set [, */ + if (info->match_set.dim) + xtables_error(PARAMETER_PROBLEM, + "--match-set can be specified only once"); + if (invert) + info->match_set.flags |= IPSET_INV_MATCH; + + if (!argv[optind] + || argv[optind][0] == '-' + || argv[optind][0] == '!') + xtables_error(PARAMETER_PROBLEM, + "--match-set requires two args."); + + if (strlen(optarg) > IPSET_MAXNAMELEN - 1) + xtables_error(PARAMETER_PROBLEM, + "setname `%s' too long, max %d characters.", + optarg, IPSET_MAXNAMELEN - 1); + + get_set_byname(optarg, &info->match_set); + parse_dirs(argv[optind], &info->match_set); + DEBUGP("parse: set index %u\n", info->match_set.index); + optind++; + + *flags = 1; + break; + } + + return 1; +} + +static void +zenset_print_counter(const struct ip_set_counter_match *c, const char *name, + const char *sep) +{ + switch (c->op) { + case IPSET_COUNTER_EQ: + printf(" %s%s-eq %llu", sep, name, c->value); + break; + case IPSET_COUNTER_NE: + printf(" ! %s%s-eq %llu", sep, name, c->value); + break; + case IPSET_COUNTER_LT: + printf(" %s%s-lt %llu", sep, name, c->value); + break; + case IPSET_COUNTER_GT: + printf(" %s%s-gt %llu", sep, name, c->value); + break; + } +} + +static void +zenset_print_matchinfo(const struct xt_zenset_info_match *info, + const char *opt, const char *sep) +{ + print_match(opt, &info->match_set); + if (info->flags & IPSET_FLAG_RETURN_NOMATCH) + printf(" %sreturn-nomatch", sep); + if ((info->flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) + printf(" ! %supdate-counters", sep); + if ((info->flags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)) + printf(" ! %supdate-subcounters", sep); + zenset_print_counter(&info->packets, "packets", sep); + zenset_print_counter(&info->bytes, "bytes", sep); +} + +/* Prints out the matchinfo. */ +static void +zenset_print(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_zenset_info_match *info = (const void *)match->data; + + zenset_print_matchinfo(info, "match-set", ""); +} + +static void +zenset_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_zenset_info_match *info = (const void *)match->data; + + zenset_print_matchinfo(info, "--match-set", "--"); +} + +static struct xtables_match zenset_mt_reg = { + .name = "zenset", + .version = XTABLES_VERSION, + .revision = 0, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_zenset_info_match)), + .userspacesize = XT_ALIGN(sizeof(struct xt_zenset_info_match)), + .help = zenset_help, + .parse = zenset_parse, + .final_check = zenset_check, + .print = zenset_print, + .save = zenset_save, + .extra_opts = zenset_opts, +}; + +static __attribute__((constructor)) void zenset_mt_ldr(void) +{ + xtables_register_match(&zenset_mt_reg); +} diff --git a/extensions/libxt_zenset.h b/extensions/libxt_zenset.h new file mode 100644 index 0000000..26f9bfc --- /dev/null +++ b/extensions/libxt_zenset.h @@ -0,0 +1,172 @@ +#ifndef _LIBXT_ZENSET_H +#define _LIBXT_ZENSET_H + +#include +#include +#include +#include +#include + +#include "xshared.h" + +#ifdef DEBUG +#define DEBUGP(x, args...) fprintf(stderr, x , ## args) +#else +#define DEBUGP(x, args...) +#endif + +static int +get_version(unsigned *version) +{ + int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + struct ip_set_req_version req_version; + socklen_t size = sizeof(req_version); + + if (sockfd < 0) + xtables_error(OTHER_PROBLEM, + "Can't open socket to ipset.\n"); + + if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { + xtables_error(OTHER_PROBLEM, + "Could not set close on exec: %s\n", + strerror(errno)); + } + + req_version.op = IP_SET_OP_VERSION; + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size); + if (res != 0) + xtables_error(OTHER_PROBLEM, + "Kernel module xt_zenset is not loaded in.\n"); + + *version = req_version.version; + + return sockfd; +} + +static void +get_set_byid(char *setname, ip_set_id_t idx) +{ + struct ip_set_req_get_set req; + socklen_t size = sizeof(struct ip_set_req_get_set); + int res, sockfd; + + sockfd = get_version(&req.version); + req.op = IP_SET_OP_GET_BYINDEX; + req.set.index = idx; + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size); + close(sockfd); + + if (res != 0) + xtables_error(OTHER_PROBLEM, + "Problem when communicating with ipset, errno=%d.\n", + errno); + if (size != sizeof(struct ip_set_req_get_set)) + xtables_error(OTHER_PROBLEM, + "Incorrect return size from kernel during ipset lookup, " + "(want %zu, got %zu)\n", + sizeof(struct ip_set_req_get_set), (size_t)size); + if (req.set.name[0] == '\0') + xtables_error(PARAMETER_PROBLEM, + "Set with index %i in kernel doesn't exist.\n", idx); + + strncpy(setname, req.set.name, IPSET_MAXNAMELEN); +} + +static void +get_set_byname_only(const char *setname, struct xt_zenset_info *info, + int sockfd, unsigned int version) +{ + struct ip_set_req_get_set req = { .version = version }; + socklen_t size = sizeof(struct ip_set_req_get_set); + int res; + + req.op = IP_SET_OP_GET_BYNAME; + strncpy(req.set.name, setname, IPSET_MAXNAMELEN); + req.set.name[IPSET_MAXNAMELEN - 1] = '\0'; + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size); + close(sockfd); + + if (res != 0) + xtables_error(OTHER_PROBLEM, + "Problem when communicating with ipset, errno=%d.\n", + errno); + if (size != sizeof(struct ip_set_req_get_set)) + xtables_error(OTHER_PROBLEM, + "Incorrect return size from kernel during ipset lookup, " + "(want %zu, got %zu)\n", + sizeof(struct ip_set_req_get_set), (size_t)size); + if (req.set.index == IPSET_INVALID_ID) + xtables_error(PARAMETER_PROBLEM, + "Set %s doesn't exist.\n", setname); + + info->index = req.set.index; +} + +static void +get_set_byname(const char *setname, struct xt_zenset_info *info) +{ + struct ip_set_req_get_set_family req; + socklen_t size = sizeof(struct ip_set_req_get_set_family); + int res, sockfd, version; + + sockfd = get_version(&req.version); + version = req.version; + req.op = IP_SET_OP_GET_FNAME; + strncpy(req.set.name, setname, IPSET_MAXNAMELEN); + req.set.name[IPSET_MAXNAMELEN - 1] = '\0'; + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size); + + if (res != 0 && errno == EBADMSG) + /* Backward compatibility */ + return get_set_byname_only(setname, info, sockfd, version); + + close(sockfd); + if (res != 0) + xtables_error(OTHER_PROBLEM, + "Problem when communicating with ipset, errno=%d.\n", + errno); + if (size != sizeof(struct ip_set_req_get_set_family)) + xtables_error(OTHER_PROBLEM, + "Incorrect return size from kernel during ipset lookup, " + "(want %zu, got %zu)\n", + sizeof(struct ip_set_req_get_set_family), + (size_t)size); + if (req.set.index == IPSET_INVALID_ID) + xtables_error(PARAMETER_PROBLEM, + "Set %s doesn't exist.\n", setname); + if (!(req.family == afinfo->family || + req.family == NFPROTO_UNSPEC)) + xtables_error(PARAMETER_PROBLEM, + "The protocol family of set %s is %s, " + "which is not applicable.\n", + setname, + req.family == NFPROTO_IPV4 ? "IPv4" : "IPv6"); + + info->index = req.set.index; +} + +static void +parse_dirs(const char *opt_arg, struct xt_zenset_info *info) +{ + char *saved = strdup(opt_arg); + char *ptr, *tmp = saved; + + while (info->dim < IPSET_DIM_MAX && tmp != NULL) { + info->dim++; + ptr = strsep(&tmp, ","); + if (strncmp(ptr, "src", 3) == 0) + info->flags |= (1 << info->dim); + else if (strncmp(ptr, "dst", 3) != 0) + xtables_error(PARAMETER_PROBLEM, + "You must spefify (the comma separated list of) 'src' or 'dst'."); + } + + if (tmp) + xtables_error(PARAMETER_PROBLEM, + "Can't be more src/dst options than %i.", + IPSET_DIM_MAX); + + free(saved); +} + +#endif /*_LIBXT_ZENSET_H*/ diff --git a/extensions/xshared.h b/extensions/xshared.h new file mode 100644 index 0000000..40dd915 --- /dev/null +++ b/extensions/xshared.h @@ -0,0 +1,92 @@ +#ifndef IPTABLES_XSHARED_H +#define IPTABLES_XSHARED_H 1 + +#include +#include +#include +#include +#include +#include +#include + +enum { + OPT_NONE = 0, + OPT_NUMERIC = 1 << 0, + OPT_SOURCE = 1 << 1, + OPT_DESTINATION = 1 << 2, + OPT_PROTOCOL = 1 << 3, + OPT_JUMP = 1 << 4, + OPT_VERBOSE = 1 << 5, + OPT_EXPANDED = 1 << 6, + OPT_VIANAMEIN = 1 << 7, + OPT_VIANAMEOUT = 1 << 8, + OPT_LINENUMBERS = 1 << 9, + OPT_COUNTERS = 1 << 10, +}; + +struct xtables_globals; +struct xtables_rule_match; +struct xtables_target; + +/** + * xtables_afinfo - protocol family dependent information + * @kmod: kernel module basename (e.g. "ip_tables") + * @proc_exists: file which exists in procfs when module already loaded + * @libprefix: prefix of .so library name (e.g. "libipt_") + * @family: nfproto family + * @ipproto: used by setsockopt (e.g. IPPROTO_IP) + * @so_rev_match: optname to check revision support of match + * @so_rev_target: optname to check revision support of target + */ +struct xtables_afinfo { + const char *kmod; + const char *proc_exists; + const char *libprefix; + uint8_t family; + uint8_t ipproto; + int so_rev_match; + int so_rev_target; +}; + +struct iptables_command_state { + union { + struct ipt_entry fw; + struct ip6t_entry fw6; + }; + int invert; + int c; + unsigned int options; + struct xtables_rule_match *matches; + struct xtables_target *target; + struct xt_counters counters; + char *protocol; + int proto_used; + const char *jumpto; + char **argv; +}; + +typedef int (*mainfunc_t)(int, char **); + +struct subcommand { + const char *name; + mainfunc_t main; +}; + +enum { + XT_OPTION_OFFSET_SCALE = 256, +}; + +extern void print_extension_helps(const struct xtables_target *, + const struct xtables_rule_match *); +extern const char *proto_to_name(uint8_t, int); +extern int command_default(struct iptables_command_state *, + struct xtables_globals *); +extern struct xtables_match *load_proto(struct iptables_command_state *); +extern int subcmd_main(int, char **, const struct subcommand *); +extern void xs_init_target(struct xtables_target *); +extern void xs_init_match(struct xtables_match *); +extern bool xtables_lock(int wait); + +extern const struct xtables_afinfo *afinfo; + +#endif /* IPTABLES_XSHARED_H */ diff --git a/extensions/xt_RESET.c b/extensions/xt_RESET.c new file mode 100644 index 0000000..c1084ac --- /dev/null +++ b/extensions/xt_RESET.c @@ -0,0 +1,195 @@ +/* + * This is a module which is used for reseting TCP connections. + */ + +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2004 Netfilter Core Team + * (C) 2016 Zenedge Inc . + * + * 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. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BRIDGE_NETFILTER +#include +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lourival Vieira Neto "); +MODULE_DESCRIPTION("Zenedge: TCP reseting target for IPv4"); + +/* Send RST reply */ +static void send_reset(struct sk_buff *oldskb, int hook) +{ + struct sk_buff *nskb; + const struct iphdr *oiph; + struct iphdr *niph; + const struct tcphdr *oth; + struct tcphdr _otcph, *tcph; + + /* IP header checks: fragment. */ + if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) + return; + + oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), + sizeof(_otcph), &_otcph); + if (oth == NULL) + return; + + /* No RST for RST. */ + if (oth->rst) + return; + + if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) + return; + + /* Check checksum */ + if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) + return; + oiph = ip_hdr(oldskb); + + nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + + LL_MAX_HEADER, GFP_ATOMIC); + if (!nskb) + return; + + skb_reserve(nskb, LL_MAX_HEADER); + + skb_reset_network_header(nskb); + niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); + niph->version = 4; + niph->ihl = sizeof(struct iphdr) / 4; + niph->tos = 0; + niph->id = 0; + niph->frag_off = htons(IP_DF); + niph->protocol = IPPROTO_TCP; + niph->check = 0; + niph->saddr = oiph->daddr; + niph->daddr = oiph->saddr; + + skb_reset_transport_header(nskb); + tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); + memset(tcph, 0, sizeof(*tcph)); + tcph->source = oth->dest; + tcph->dest = oth->source; + tcph->doff = sizeof(struct tcphdr) / 4; + + if (oth->ack) + tcph->seq = oth->ack_seq; + else { + tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + + oldskb->len - ip_hdrlen(oldskb) - + (oth->doff << 2)); + tcph->ack = 1; + } + + tcph->rst = 1; + tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, + niph->daddr, 0); + nskb->ip_summed = CHECKSUM_PARTIAL; + nskb->csum_start = (unsigned char *)tcph - nskb->head; + nskb->csum_offset = offsetof(struct tcphdr, check); + + /* ip_route_me_harder expects skb->dst to be set */ + skb_dst_set_noref(nskb, skb_dst(oldskb)); + + nskb->protocol = htons(ETH_P_IP); + if (ip_route_me_harder(nskb, RTN_UNSPEC)) + goto free_nskb; + + niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); + + /* "Never happens" */ + if (nskb->len > dst_mtu(skb_dst(nskb))) + goto free_nskb; + + nf_ct_attach(nskb, oldskb); + +#ifdef CONFIG_BRIDGE_NETFILTER + /* If we use ip_local_out for bridged traffic, the MAC source on + * the RST will be ours, instead of the destination's. This confuses + * some routers/firewalls, and they drop the packet. So we need to + * build the eth header using the original destination's MAC as the + * source, and send the RST packet directly. + */ + if (oldskb->nf_bridge) { + struct ethhdr *oeth = eth_hdr(oldskb); + nskb->dev = oldskb->nf_bridge->physindev; + niph->tot_len = htons(nskb->len); + ip_send_check(niph); + if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), + oeth->h_source, oeth->h_dest, nskb->len) < 0) + goto free_nskb; + dev_queue_xmit(nskb); + } else +#endif + ip_local_out(nskb); + + return; + + free_nskb: + kfree_skb(nskb); +} + +#define TCP_CTRL(h) (((__be16 *)h)[6]) +static unsigned int +reset_tg(struct sk_buff *skb, const struct xt_action_param *par) +{ + struct tcphdr *tcph; + __be16 oldctl; + + send_reset(skb, par->hooknum); + + if (!skb_make_writable(skb, skb_headlen(skb))) + return NF_DROP; + + tcph = tcp_hdr(skb); + oldctl = TCP_CTRL(tcph); + + tcph->rst = 1; + + inet_proto_csum_replace2(&tcph->check, skb, + oldctl, TCP_CTRL(tcph), false); + + return NF_ACCEPT; +} + +static struct xt_target reset_tg_reg __read_mostly = { + .name = "RESET", + .revision = 0, + .family = NFPROTO_IPV4, + .proto = IPPROTO_TCP, + .target = reset_tg, + .table = "filter", + .hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT), + .me = THIS_MODULE, +}; + +static int __init reset_tg_init(void) +{ + return xt_register_target(&reset_tg_reg); +} + +static void __exit reset_tg_exit(void) +{ + xt_unregister_target(&reset_tg_reg); +} + +module_init(reset_tg_init); +module_exit(reset_tg_exit); diff --git a/extensions/xt_zenset.c b/extensions/xt_zenset.c new file mode 100644 index 0000000..5001142 --- /dev/null +++ b/extensions/xt_zenset.c @@ -0,0 +1,179 @@ +/* Copyright (C) 2000-2002 Joakim Axelsson + * Patrick Schaaf + * Martin Josefsson + * Copyright (C) 2003-2013 Jozsef Kadlecsik + * Copyright (C) 2016 Zenedge Inc . + * + * 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. + */ + +/* Kernel module which implements the set match for netfilter/iptables. */ + +#include +#include + +#include +#include +#include + +#include "xt_zenset.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lourival Vieira Neto "); +MODULE_DESCRIPTION("Zenedge: IP set match module"); + +#define tcp_datalen(skb) \ + (ntohs(ip_hdr(skb)->tot_len) - (ip_hdrlen(skb) + tcp_hdrlen(skb))) + +struct sk_buff * +proxy_skb(const struct sk_buff *skb, const struct xt_action_param *par) +{ + const char preamble[] = "PROXY TCP4 "; + size_t preamble_len = sizeof(preamble) - 1; + unsigned int max_addr = sizeof("255.255.255.255"); + struct sk_buff *skbp = NULL; + unsigned char *data = NULL; + struct iphdr *iph = ip_hdr(skb); + + if ((iph->protocol != IPPROTO_TCP) || + (tcp_datalen(skb) < preamble_len + max_addr)) + return NULL; + + data = skb_transport_header(skb) + tcp_hdrlen(skb); + if(strncmp(data, preamble, preamble_len) != 0) + return NULL; + + skbp = pskb_copy((struct sk_buff *) skb, GFP_ATOMIC); + if (!skbp) + return NULL; + + data += preamble_len; + if (!in4_pton(data, max_addr, (u8 *) &ip_hdr(skbp)->saddr, ' ', NULL)) { + kfree_skb(skbp); + return NULL; + } + + return skbp; +} + +static inline int +match_set(ip_set_id_t index, const struct sk_buff *skb, + const struct xt_action_param *par, + struct ip_set_adt_opt *opt, int inv) +{ + if (ip_set_test(index, skb, par, opt)) + inv = !inv; + + return inv; +} + +#define ADT_OPT(n, f, d, fs, cfs, t) \ +struct ip_set_adt_opt n = { \ + .family = f, \ + .dim = d, \ + .flags = fs, \ + .cmdflags = cfs, \ + .ext.timeout = t, \ +} + +static int +zenset_checkentry(const struct xt_mtchk_param *par) +{ + struct xt_zenset_info_match *info = par->matchinfo; + ip_set_id_t index; + + index = ip_set_nfnl_get_byindex((par)->net, info->match_set.index); + + if (index == IPSET_INVALID_ID) { + pr_warn("Cannot find set identified by id %u to match\n", + info->match_set.index); + return -ENOENT; + } + if (info->match_set.dim > IPSET_DIM_MAX) { + pr_warn("Protocol error: set match dimension is over the limit!\n"); + ip_set_nfnl_put((par)->net, info->match_set.index); + return -ERANGE; + } + + return 0; +} + +static void +zenset_destroy(const struct xt_mtdtor_param *par) +{ + struct xt_zenset_info_match *info = par->matchinfo; + + ip_set_nfnl_put((par)->net, info->match_set.index); +} + +static bool +match_counter(u64 counter, const struct ip_set_counter_match *info) +{ + switch (info->op) { + case IPSET_COUNTER_NONE: + return true; + case IPSET_COUNTER_EQ: + return counter == info->value; + case IPSET_COUNTER_NE: + return counter != info->value; + case IPSET_COUNTER_LT: + return counter < info->value; + case IPSET_COUNTER_GT: + return counter > info->value; + } + return false; +} + +static bool +zenset_match(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct xt_zenset_info_match *info = par->matchinfo; + + ADT_OPT(opt, par->family, info->match_set.dim, + info->match_set.flags, info->flags, UINT_MAX); + int ret; + struct sk_buff *skbp = (info->match_set.flags & ZENSET_PROXY_PROTOCOL) ? + proxy_skb(skb, par) : NULL; + + if (info->packets.op != IPSET_COUNTER_NONE || + info->bytes.op != IPSET_COUNTER_NONE) + opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; + + ret = match_set(info->match_set.index, skbp ? skbp : skb, par, &opt, + info->match_set.flags & IPSET_INV_MATCH); + if (skbp) + kfree_skb(skbp); + + if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) + return ret; + + if (!match_counter(opt.ext.packets, &info->packets)) + return false; + return match_counter(opt.ext.bytes, &info->bytes); +} + +static struct xt_match zenset_mt_reg __read_mostly = { + .name = "zenset", + .revision = 0, + .family = NFPROTO_IPV4, + .match = zenset_match, + .matchsize = sizeof(struct xt_zenset_info_match), + .checkentry = zenset_checkentry, + .destroy = zenset_destroy, + .me = THIS_MODULE +}; + +static int __init xt_zenset_init(void) +{ + return xt_register_match(&zenset_mt_reg); +} + +static void __exit xt_zenset_fini(void) +{ + xt_unregister_match(&zenset_mt_reg); +} + +module_init(xt_zenset_init); +module_exit(xt_zenset_fini); diff --git a/extensions/xt_zenset.h b/extensions/xt_zenset.h new file mode 100644 index 0000000..c16b81b --- /dev/null +++ b/extensions/xt_zenset.h @@ -0,0 +1,22 @@ +#ifndef _XT_ZENSET_H +#define _XT_ZENSET_H + +#include +#include + +#define ZENSET_PROXY_PROTOCOL (IPSET_INV_MATCH << 1) + +struct xt_zenset_info { + ip_set_id_t index; + __u8 dim; + __u8 flags; +}; + +struct xt_zenset_info_match { + struct xt_zenset_info match_set; + struct ip_set_counter_match packets; + struct ip_set_counter_match bytes; + __u32 flags; +}; + +#endif /*_XT_ZENSET_H*/ diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h new file mode 100644 index 0000000..2eb00b6 --- /dev/null +++ b/include/linux/netfilter.h @@ -0,0 +1,59 @@ +#ifndef __LINUX_NETFILTER_H +#define __LINUX_NETFILTER_H + +#include + + +/* Responses from hook functions. */ +#define NF_DROP 0 +#define NF_ACCEPT 1 +#define NF_STOLEN 2 +#define NF_QUEUE 3 +#define NF_REPEAT 4 +#define NF_STOP 5 +#define NF_MAX_VERDICT NF_STOP + +/* we overload the higher bits for encoding auxiliary data such as the queue + * number. Not nice, but better than additional function arguments. */ +#define NF_VERDICT_MASK 0x0000ffff +#define NF_VERDICT_BITS 16 + +#define NF_VERDICT_QMASK 0xffff0000 +#define NF_VERDICT_QBITS 16 + +#define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE) + +/* only for userspace compatibility */ +/* Generic cache responses from hook functions. + <= 0x2000 is used for protocol-flags. */ +#define NFC_UNKNOWN 0x4000 +#define NFC_ALTERED 0x8000 + +enum nf_inet_hooks { + NF_INET_PRE_ROUTING, + NF_INET_LOCAL_IN, + NF_INET_FORWARD, + NF_INET_LOCAL_OUT, + NF_INET_POST_ROUTING, + NF_INET_NUMHOOKS +}; + +enum { + NFPROTO_UNSPEC = 0, + NFPROTO_IPV4 = 2, + NFPROTO_ARP = 3, + NFPROTO_BRIDGE = 7, + NFPROTO_IPV6 = 10, + NFPROTO_DECNET = 12, + NFPROTO_NUMPROTO, +}; + +union nf_inet_addr { + __u32 all[4]; + __be32 ip; + __be32 ip6[4]; + struct in_addr in; + struct in6_addr in6; +}; + +#endif /*__LINUX_NETFILTER_H*/ diff --git a/include/linux/netfilter/nf_conntrack_tuple_common.h b/include/linux/netfilter/nf_conntrack_tuple_common.h new file mode 100644 index 0000000..2f6bbc5 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_tuple_common.h @@ -0,0 +1,39 @@ +#ifndef _NF_CONNTRACK_TUPLE_COMMON_H +#define _NF_CONNTRACK_TUPLE_COMMON_H + +enum ip_conntrack_dir { + IP_CT_DIR_ORIGINAL, + IP_CT_DIR_REPLY, + IP_CT_DIR_MAX +}; + +/* The protocol-specific manipulable parts of the tuple: always in + * network order + */ +union nf_conntrack_man_proto { + /* Add other protocols here. */ + __be16 all; + + struct { + __be16 port; + } tcp; + struct { + __be16 port; + } udp; + struct { + __be16 id; + } icmp; + struct { + __be16 port; + } dccp; + struct { + __be16 port; + } sctp; + struct { + __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */ + } gre; +}; + +#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) + +#endif /* _NF_CONNTRACK_TUPLE_COMMON_H */ diff --git a/include/linux/netfilter/nf_nat.h b/include/linux/netfilter/nf_nat.h new file mode 100644 index 0000000..bf0cc37 --- /dev/null +++ b/include/linux/netfilter/nf_nat.h @@ -0,0 +1,33 @@ +#ifndef _NETFILTER_NF_NAT_H +#define _NETFILTER_NF_NAT_H + +#include +#include + +#define NF_NAT_RANGE_MAP_IPS 1 +#define NF_NAT_RANGE_PROTO_SPECIFIED 2 +#define NF_NAT_RANGE_PROTO_RANDOM 4 +#define NF_NAT_RANGE_PERSISTENT 8 + +struct nf_nat_ipv4_range { + unsigned int flags; + __be32 min_ip; + __be32 max_ip; + union nf_conntrack_man_proto min; + union nf_conntrack_man_proto max; +}; + +struct nf_nat_ipv4_multi_range_compat { + unsigned int rangesize; + struct nf_nat_ipv4_range range[1]; +}; + +struct nf_nat_range { + unsigned int flags; + union nf_inet_addr min_addr; + union nf_inet_addr max_addr; + union nf_conntrack_man_proto min_proto; + union nf_conntrack_man_proto max_proto; +}; + +#endif /* _NETFILTER_NF_NAT_H */ diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..64d9bbc --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,2 @@ +/libtool.m4 +/lt*.m4 diff --git a/mconfig b/mconfig new file mode 100644 index 0000000..dc3e78e --- /dev/null +++ b/mconfig @@ -0,0 +1,4 @@ +# -*- Makefile -*- +# +build_zenset=m +build_RESET=m