From 822266b74b1b64e6bc7af5ec54555da116eb184b Mon Sep 17 00:00:00 2001 From: Vadim Vetrov Date: Mon, 22 Jul 2024 22:46:16 +0300 Subject: [PATCH] Specify dependencies libs explicitly. Such setup is better for cross compilation. Also changed Makefile to properly make the project with these libraries. --- Makefile | 61 +- deps/libmnl/.gitignore | 20 + deps/libmnl/COPYING | 502 ++++++ deps/libmnl/Make_global.am | 24 + deps/libmnl/Makefile.am | 11 + deps/libmnl/README | 28 + deps/libmnl/autogen.sh | 4 + deps/libmnl/configure.ac | 70 + deps/libmnl/doxygen/.gitignore | 4 + deps/libmnl/doxygen/Makefile.am | 25 + deps/libmnl/doxygen/doxygen.cfg.in | 23 + deps/libmnl/doxygen/finalize_manpages.sh | 40 + deps/libmnl/examples/Makefile.am | 1 + deps/libmnl/examples/genl/.gitignore | 2 + deps/libmnl/examples/genl/Makefile.am | 10 + deps/libmnl/examples/genl/genl-family-get.c | 241 +++ deps/libmnl/examples/genl/genl-group-events.c | 63 + deps/libmnl/examples/kobject/.gitignore | 1 + deps/libmnl/examples/kobject/Makefile.am | 6 + deps/libmnl/examples/kobject/kobject-event.c | 49 + deps/libmnl/examples/netfilter/.gitignore | 6 + deps/libmnl/examples/netfilter/Makefile.am | 26 + deps/libmnl/examples/netfilter/nf-log.c | 219 +++ deps/libmnl/examples/netfilter/nf-queue.c | 243 +++ .../examples/netfilter/nfct-create-batch.c | 187 ++ deps/libmnl/examples/netfilter/nfct-daemon.c | 365 ++++ deps/libmnl/examples/netfilter/nfct-dump.c | 319 ++++ deps/libmnl/examples/netfilter/nfct-event.c | 240 +++ deps/libmnl/examples/rtnl/.gitignore | 12 + deps/libmnl/examples/rtnl/Makefile.am | 48 + deps/libmnl/examples/rtnl/rtnl-addr-add.c | 119 ++ deps/libmnl/examples/rtnl/rtnl-addr-dump.c | 133 ++ deps/libmnl/examples/rtnl/rtnl-link-can.c | 452 +++++ deps/libmnl/examples/rtnl/rtnl-link-dump.c | 130 ++ deps/libmnl/examples/rtnl/rtnl-link-dump2.c | 103 ++ deps/libmnl/examples/rtnl/rtnl-link-dump3.c | 103 ++ deps/libmnl/examples/rtnl/rtnl-link-event.c | 95 + deps/libmnl/examples/rtnl/rtnl-link-set.c | 84 + deps/libmnl/examples/rtnl/rtnl-neigh-dump.c | 158 ++ deps/libmnl/examples/rtnl/rtnl-route-add.c | 127 ++ deps/libmnl/examples/rtnl/rtnl-route-dump.c | 356 ++++ deps/libmnl/examples/rtnl/rtnl-route-event.c | 341 ++++ deps/libmnl/include/Makefile.am | 1 + deps/libmnl/include/libmnl/Makefile.am | 1 + deps/libmnl/include/libmnl/libmnl.h | 202 +++ deps/libmnl/include/linux/Makefile.am | 2 + deps/libmnl/include/linux/can.h | 298 +++ deps/libmnl/include/linux/can/Makefile.am | 1 + deps/libmnl/include/linux/can/netlink.h | 185 ++ .../include/linux/netfilter/Makefile.am | 1 + .../linux/netfilter/nfnetlink_conntrack.h | 252 +++ deps/libmnl/include/linux/netlink.h | 153 ++ deps/libmnl/include/linux/socket.h | 21 + deps/libmnl/libmnl.pc.in | 15 + deps/libmnl/m4/.gitignore | 2 + deps/libmnl/m4/gcc4_visibility.m4 | 21 + deps/libmnl/src/Makefile.am | 5 + deps/libmnl/src/attr.c | 742 ++++++++ deps/libmnl/src/callback.c | 167 ++ deps/libmnl/src/internal.h | 11 + deps/libmnl/src/libmnl.map | 79 + deps/libmnl/src/nlmsg.c | 592 ++++++ deps/libmnl/src/socket.c | 351 ++++ deps/libnetfilter_queue/.gitignore | 24 + deps/libnetfilter_queue/COPYING | 339 ++++ deps/libnetfilter_queue/Make_global.am | 2 + deps/libnetfilter_queue/Makefile.am | 12 + deps/libnetfilter_queue/autogen.sh | 39 + deps/libnetfilter_queue/configure.ac | 85 + deps/libnetfilter_queue/doxygen/Makefile.am | 45 + deps/libnetfilter_queue/doxygen/build_man.sh | 323 ++++ .../libnetfilter_queue/doxygen/doxygen.cfg.in | 27 + deps/libnetfilter_queue/examples/Makefile.am | 7 + deps/libnetfilter_queue/examples/nf-queue.c | 233 +++ deps/libnetfilter_queue/include/Makefile.am | 1 + .../include/libnetfilter_queue/Makefile.am | 8 + .../libnetfilter_queue/libnetfilter_queue.h | 160 ++ .../libnetfilter_queue_icmp.h | 8 + .../libnetfilter_queue_ipv4.h | 13 + .../libnetfilter_queue_ipv6.h | 12 + .../libnetfilter_queue_tcp.h | 21 + .../libnetfilter_queue_udp.h | 18 + .../linux_nfnetlink_queue.h | 123 ++ .../include/libnetfilter_queue/pktbuff.h | 31 + .../include/linux/Makefile.am | 1 + .../include/linux/netfilter/Makefile.am | 1 + .../include/linux/netfilter/nfnetlink_queue.h | 115 ++ .../libnetfilter_queue.pc.in | 16 + deps/libnetfilter_queue/m4/.gitignore | 2 + deps/libnetfilter_queue/m4/gcc4_visibility.m4 | 21 + deps/libnetfilter_queue/src/Makefile.am | 41 + deps/libnetfilter_queue/src/extra/checksum.c | 83 + deps/libnetfilter_queue/src/extra/icmp.c | 57 + deps/libnetfilter_queue/src/extra/ipv4.c | 194 ++ deps/libnetfilter_queue/src/extra/ipv6.c | 203 +++ deps/libnetfilter_queue/src/extra/pktbuff.c | 455 +++++ deps/libnetfilter_queue/src/extra/tcp.c | 300 +++ deps/libnetfilter_queue/src/extra/udp.c | 249 +++ deps/libnetfilter_queue/src/internal.h | 38 + .../src/libnetfilter_queue.c | 1581 ++++++++++++++++ deps/libnetfilter_queue/src/nlmsg.c | 383 ++++ deps/libnetfilter_queue/utils/.gitignore | 1 + deps/libnetfilter_queue/utils/Makefile.am | 9 + deps/libnetfilter_queue/utils/nfqnl_test.c | 187 ++ deps/libnfnetlink/.gitignore | 17 + deps/libnfnetlink/COPYING | 339 ++++ deps/libnfnetlink/Make_global.am | 8 + deps/libnfnetlink/Makefile.am | 16 + deps/libnfnetlink/README | 50 + deps/libnfnetlink/autogen.sh | 37 + deps/libnfnetlink/configure.ac | 33 + deps/libnfnetlink/doxygen.cfg | 180 ++ deps/libnfnetlink/doxygen.cfg.in | 180 ++ deps/libnfnetlink/include/Makefile.am | 2 + .../include/libnfnetlink/Makefile.am | 3 + .../include/libnfnetlink/libnfnetlink.h | 267 +++ .../include/libnfnetlink/linux_nfnetlink.h | 53 + .../libnfnetlink/linux_nfnetlink_compat.h | 61 + deps/libnfnetlink/include/linux_list.h | 727 ++++++++ deps/libnfnetlink/libnfnetlink.pc.in | 15 + deps/libnfnetlink/m4/.gitignore | 2 + deps/libnfnetlink/src/Makefile.am | 11 + deps/libnfnetlink/src/iftable.c | 348 ++++ deps/libnfnetlink/src/iftable.h | 12 + deps/libnfnetlink/src/libnfnetlink.c | 1602 +++++++++++++++++ deps/libnfnetlink/src/nfnl.version | 55 + deps/libnfnetlink/src/rtnl.c | 266 +++ deps/libnfnetlink/src/rtnl.h | 37 + deps/libnfnetlink/utils/.gitignore | 1 + deps/libnfnetlink/utils/Makefile.am | 7 + deps/libnfnetlink/utils/iftest.c | 52 + 131 files changed, 17984 insertions(+), 18 deletions(-) create mode 100644 deps/libmnl/.gitignore create mode 100644 deps/libmnl/COPYING create mode 100644 deps/libmnl/Make_global.am create mode 100644 deps/libmnl/Makefile.am create mode 100644 deps/libmnl/README create mode 100755 deps/libmnl/autogen.sh create mode 100644 deps/libmnl/configure.ac create mode 100644 deps/libmnl/doxygen/.gitignore create mode 100644 deps/libmnl/doxygen/Makefile.am create mode 100644 deps/libmnl/doxygen/doxygen.cfg.in create mode 100644 deps/libmnl/doxygen/finalize_manpages.sh create mode 100644 deps/libmnl/examples/Makefile.am create mode 100644 deps/libmnl/examples/genl/.gitignore create mode 100644 deps/libmnl/examples/genl/Makefile.am create mode 100644 deps/libmnl/examples/genl/genl-family-get.c create mode 100644 deps/libmnl/examples/genl/genl-group-events.c create mode 100644 deps/libmnl/examples/kobject/.gitignore create mode 100644 deps/libmnl/examples/kobject/Makefile.am create mode 100644 deps/libmnl/examples/kobject/kobject-event.c create mode 100644 deps/libmnl/examples/netfilter/.gitignore create mode 100644 deps/libmnl/examples/netfilter/Makefile.am create mode 100644 deps/libmnl/examples/netfilter/nf-log.c create mode 100644 deps/libmnl/examples/netfilter/nf-queue.c create mode 100644 deps/libmnl/examples/netfilter/nfct-create-batch.c create mode 100644 deps/libmnl/examples/netfilter/nfct-daemon.c create mode 100644 deps/libmnl/examples/netfilter/nfct-dump.c create mode 100644 deps/libmnl/examples/netfilter/nfct-event.c create mode 100644 deps/libmnl/examples/rtnl/.gitignore create mode 100644 deps/libmnl/examples/rtnl/Makefile.am create mode 100644 deps/libmnl/examples/rtnl/rtnl-addr-add.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-addr-dump.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-link-can.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-link-dump.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-link-dump2.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-link-dump3.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-link-event.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-link-set.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-neigh-dump.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-route-add.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-route-dump.c create mode 100644 deps/libmnl/examples/rtnl/rtnl-route-event.c create mode 100644 deps/libmnl/include/Makefile.am create mode 100644 deps/libmnl/include/libmnl/Makefile.am create mode 100644 deps/libmnl/include/libmnl/libmnl.h create mode 100644 deps/libmnl/include/linux/Makefile.am create mode 100644 deps/libmnl/include/linux/can.h create mode 100644 deps/libmnl/include/linux/can/Makefile.am create mode 100644 deps/libmnl/include/linux/can/netlink.h create mode 100644 deps/libmnl/include/linux/netfilter/Makefile.am create mode 100644 deps/libmnl/include/linux/netfilter/nfnetlink_conntrack.h create mode 100644 deps/libmnl/include/linux/netlink.h create mode 100644 deps/libmnl/include/linux/socket.h create mode 100644 deps/libmnl/libmnl.pc.in create mode 100644 deps/libmnl/m4/.gitignore create mode 100644 deps/libmnl/m4/gcc4_visibility.m4 create mode 100644 deps/libmnl/src/Makefile.am create mode 100644 deps/libmnl/src/attr.c create mode 100644 deps/libmnl/src/callback.c create mode 100644 deps/libmnl/src/internal.h create mode 100644 deps/libmnl/src/libmnl.map create mode 100644 deps/libmnl/src/nlmsg.c create mode 100644 deps/libmnl/src/socket.c create mode 100644 deps/libnetfilter_queue/.gitignore create mode 100644 deps/libnetfilter_queue/COPYING create mode 100644 deps/libnetfilter_queue/Make_global.am create mode 100644 deps/libnetfilter_queue/Makefile.am create mode 100755 deps/libnetfilter_queue/autogen.sh create mode 100644 deps/libnetfilter_queue/configure.ac create mode 100644 deps/libnetfilter_queue/doxygen/Makefile.am create mode 100755 deps/libnetfilter_queue/doxygen/build_man.sh create mode 100644 deps/libnetfilter_queue/doxygen/doxygen.cfg.in create mode 100644 deps/libnetfilter_queue/examples/Makefile.am create mode 100644 deps/libnetfilter_queue/examples/nf-queue.c create mode 100644 deps/libnetfilter_queue/include/Makefile.am create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/Makefile.am create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue.h create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_icmp.h create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_ipv4.h create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_ipv6.h create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_tcp.h create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_udp.h create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/linux_nfnetlink_queue.h create mode 100644 deps/libnetfilter_queue/include/libnetfilter_queue/pktbuff.h create mode 100644 deps/libnetfilter_queue/include/linux/Makefile.am create mode 100644 deps/libnetfilter_queue/include/linux/netfilter/Makefile.am create mode 100644 deps/libnetfilter_queue/include/linux/netfilter/nfnetlink_queue.h create mode 100644 deps/libnetfilter_queue/libnetfilter_queue.pc.in create mode 100644 deps/libnetfilter_queue/m4/.gitignore create mode 100644 deps/libnetfilter_queue/m4/gcc4_visibility.m4 create mode 100644 deps/libnetfilter_queue/src/Makefile.am create mode 100644 deps/libnetfilter_queue/src/extra/checksum.c create mode 100644 deps/libnetfilter_queue/src/extra/icmp.c create mode 100644 deps/libnetfilter_queue/src/extra/ipv4.c create mode 100644 deps/libnetfilter_queue/src/extra/ipv6.c create mode 100644 deps/libnetfilter_queue/src/extra/pktbuff.c create mode 100644 deps/libnetfilter_queue/src/extra/tcp.c create mode 100644 deps/libnetfilter_queue/src/extra/udp.c create mode 100644 deps/libnetfilter_queue/src/internal.h create mode 100644 deps/libnetfilter_queue/src/libnetfilter_queue.c create mode 100644 deps/libnetfilter_queue/src/nlmsg.c create mode 100644 deps/libnetfilter_queue/utils/.gitignore create mode 100644 deps/libnetfilter_queue/utils/Makefile.am create mode 100644 deps/libnetfilter_queue/utils/nfqnl_test.c create mode 100644 deps/libnfnetlink/.gitignore create mode 100644 deps/libnfnetlink/COPYING create mode 100644 deps/libnfnetlink/Make_global.am create mode 100644 deps/libnfnetlink/Makefile.am create mode 100644 deps/libnfnetlink/README create mode 100755 deps/libnfnetlink/autogen.sh create mode 100644 deps/libnfnetlink/configure.ac create mode 100644 deps/libnfnetlink/doxygen.cfg create mode 100644 deps/libnfnetlink/doxygen.cfg.in create mode 100644 deps/libnfnetlink/include/Makefile.am create mode 100644 deps/libnfnetlink/include/libnfnetlink/Makefile.am create mode 100644 deps/libnfnetlink/include/libnfnetlink/libnfnetlink.h create mode 100644 deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink.h create mode 100644 deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink_compat.h create mode 100644 deps/libnfnetlink/include/linux_list.h create mode 100644 deps/libnfnetlink/libnfnetlink.pc.in create mode 100644 deps/libnfnetlink/m4/.gitignore create mode 100644 deps/libnfnetlink/src/Makefile.am create mode 100644 deps/libnfnetlink/src/iftable.c create mode 100644 deps/libnfnetlink/src/iftable.h create mode 100644 deps/libnfnetlink/src/libnfnetlink.c create mode 100644 deps/libnfnetlink/src/nfnl.version create mode 100644 deps/libnfnetlink/src/rtnl.c create mode 100644 deps/libnfnetlink/src/rtnl.h create mode 100644 deps/libnfnetlink/utils/.gitignore create mode 100644 deps/libnfnetlink/utils/Makefile.am create mode 100644 deps/libnfnetlink/utils/iftest.c diff --git a/Makefile b/Makefile index 11859b2..c6f52f5 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,10 @@ +BUILD_DIR := $(CURDIR)/build +DEPSDIR := $(BUILD_DIR)/deps + CC := gcc -CC_FLAGS:=-Wall -Wpedantic -Wno-unused-variable - -LD_FLAGS:=-lmnl -lnetfilter_queue -BUILD_DIR:=build -APP:=$(BUILD_DIR)/youtubeUnblock - -SRCS := youtubeUnblock.c -OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o) +LD := gcc +CFLAGS:=-Wall -Wpedantic -Wno-unused-variable -I$(DEPSDIR)/include -Os +LDFLAGS:=-L$(DEPSDIR)/lib -static # PREFIX is environment variable, if not set default to /usr/local ifeq ($(PREFIX),) @@ -15,46 +13,73 @@ else PREFIX := $(DESTDIR) endif +export CC LD CFLAGS LDFLAGS + +APP:=$(BUILD_DIR)/youtubeUnblock + +SRCS := youtubeUnblock.c +OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o) + +LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a +LIBMNL := $(DEPSDIR)/lib/libmnl.a +LIBNETFILTER_QUEUE := $(DEPSDIR)/lib/libnetfilter_queue.a + + .PHONY: default all dev dev_attrs prepare_dirs default: all - run_dev: dev bash -c "sudo ./$(APP) 537" - dev: dev_attrs all dev_attrs: - $(eval CC_FLAGS := $(CC_FLAGS) -DDEBUG -ggdb -g3) + $(eval CFLAGS := $(CFLAGS) -DDEBUG -ggdb -g3) all: prepare_dirs $(APP) - prepare_dirs: mkdir -p $(BUILD_DIR) + mkdir -p $(DEPSDIR) -$(APP): $(OBJS) +$(LIBNFNETLINK): + cd deps/libnfnetlink && ./autogen.sh && ./configure --prefix=$(DEPSDIR) + $(MAKE) -C deps/libnfnetlink + $(MAKE) install -C deps/libnfnetlink + +$(LIBMNL): + cd deps/libmnl && ./autogen.sh && ./configure --prefix=$(DEPSDIR) + $(MAKE) -C deps/libmnl + $(MAKE) install -C deps/libmnl + +$(LIBNETFILTER_QUEUE): $(LIBNFNETLINK) $(LIBMNL) + cd deps/libnetfilter_queue && ./autogen.sh && ./configure --prefix=$(DEPSDIR) + $(MAKE) -C deps/libnetfilter_queue + $(MAKE) install -C deps/libnetfilter_queue + +$(APP): $(OBJS) $(LIBNETFILTER_QUEUE) $(LIBMNL) @echo 'LD $(APP)' - @$(CC) $(OBJS) -o $(APP) $(LD_FLAGS) + @$(LD) $(OBJS) -o $(APP) -L$(DEPSDIR)/lib -lmnl -lnetfilter_queue -$(BUILD_DIR)/%.o: %.c +$(BUILD_DIR)/%.o: %.c $(LIBNETFILTER_QUEUE) $(LIBMNL) @echo 'CC $@' - @$(CC) -c $(CC_FLAGS) $^ -o $@ + @$(CC) -c $(CFLAGS) $^ -o $@ install: all install -d $(PREFIX)/bin/ install -m 755 $(APP) $(PREFIX)/bin/ install -d $(PREFIX)/lib/systemd/system/ - @cp youtubeUnblock.service $(BUILD_DIR) @sed -i 's/$$(PREFIX)/$(subst /,\/,$(PREFIX))/g' $(BUILD_DIR)/youtubeUnblock.service install -m 644 $(BUILD_DIR)/youtubeUnblock.service $(PREFIX)/lib/systemd/system/ uninstall: rm $(PREFIX)/bin/youtubeUnblock - systemctl disable youtubeUnblock.service rm $(PREFIX)/lib/systemd/system/youtubeUnblock.service + systemctl disable youtubeUnblock.service clean: rm -rf $(BUILD_DIR) + $(MAKE) distclean -C deps/libnetfilter_queue || true + $(MAKE) distclean -C deps/libmnl || true + $(MAKE) distclean -C deps/libnfnetlink || true diff --git a/deps/libmnl/.gitignore b/deps/libmnl/.gitignore new file mode 100644 index 0000000..b6b8d60 --- /dev/null +++ b/deps/libmnl/.gitignore @@ -0,0 +1,20 @@ +*~ +*.la +*.lo +*.o +.deps/ +.libs/ +Makefile +Makefile.in + +/aclocal.m4 +/autom4te.cache/ +/build-aux/ +/config.* +/configure +/libtool +/stamp-h1 + +/libmnl.pc + +/libmnl-*.tar.bz2 diff --git a/deps/libmnl/COPYING b/deps/libmnl/COPYING new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/deps/libmnl/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/deps/libmnl/Make_global.am b/deps/libmnl/Make_global.am new file mode 100644 index 0000000..7810dab --- /dev/null +++ b/deps/libmnl/Make_global.am @@ -0,0 +1,24 @@ +# 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=2:0:2 + +AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include +AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN} diff --git a/deps/libmnl/Makefile.am b/deps/libmnl/Makefile.am new file mode 100644 index 0000000..94e6935 --- /dev/null +++ b/deps/libmnl/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/Make_global.am + +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = src include examples doxygen +DIST_SUBDIRS = src include examples doxygen + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libmnl.pc + +${pkgconfig_DATA}: ${top_builddir}/config.status diff --git a/deps/libmnl/README b/deps/libmnl/README new file mode 100644 index 0000000..fbac9d2 --- /dev/null +++ b/deps/libmnl/README @@ -0,0 +1,28 @@ += What is libmnl? = + +libmnl is a minimalistic user-space library oriented to Netlink developers. +There are a lot of common tasks in parsing, validating, constructing of +both the Netlink header and TLVs that are repetitive and easy to get wrong. +This library aims to provide simple helpers that allows you to re-use code +and to avoid re-inventing the wheel. The main features of this library are: + +* Small: the shared library requires around 30KB for an x86-based computer. +* Simple: this library avoids complexity and elaborated abstractions that +tend to hide Netlink details. +* Easy to use: the library simplifies the work for Netlink-wise developers. +It provides functions to make socket handling, message building, validating, +parsing and sequence tracking, easier. +* Easy to re-use: you can use the library to build your own abstraction layer +on top of this library. +* Decoupling: the interdependency of the main bricks that compose the library +is reduced, i.e. the library provides many helpers, but the programmer is not +forced to use them. + += Example files = + +You can find several example files under examples/ that you can compile by +invoking `make check'. + +-- +08/sep/2010 +Pablo Neira Ayuso diff --git a/deps/libmnl/autogen.sh b/deps/libmnl/autogen.sh new file mode 100755 index 0000000..5e1344a --- /dev/null +++ b/deps/libmnl/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/sh -e + +autoreconf -fi +rm -Rf autom4te.cache diff --git a/deps/libmnl/configure.ac b/deps/libmnl/configure.ac new file mode 100644 index 0000000..4698aec --- /dev/null +++ b/deps/libmnl/configure.ac @@ -0,0 +1,70 @@ +dnl Process this file with autoconf to create configure. + +AC_INIT([libmnl], [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([foreign tar-pax no-dist-gzip dist-xz 1.6 subdir-objects]) + +dnl kernel style compile messages +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PROG_CC +AM_PROG_CC_C_O +AC_EXEEXT +AC_DISABLE_STATIC +LT_INIT +CHECK_GCC_FVISIBILITY +case "$host" in +*-*-linux* | *-*-uclinux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + +regular_CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_REENTRANT" +regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \ + -Wmissing-prototypes -Wshadow -Wstrict-prototypes \ + -Wformat=2 -pipe" +AC_SUBST([regular_CPPFLAGS]) +AC_SUBST([regular_CFLAGS]) +AC_CONFIG_FILES([Makefile + src/Makefile + include/Makefile + include/libmnl/Makefile + include/linux/Makefile + include/linux/can/Makefile + include/linux/netfilter/Makefile + examples/Makefile + examples/genl/Makefile + examples/kobject/Makefile + examples/netfilter/Makefile + examples/rtnl/Makefile + libmnl.pc + doxygen/doxygen.cfg + doxygen/Makefile]) + +AC_ARG_WITH([doxygen], [AS_HELP_STRING([--with-doxygen], + [create doxygen documentation])], + [with_doxygen="$withval"], [with_doxygen=yes]) + +AS_IF([test "x$with_doxygen" != xno], [ + 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"]) +AS_IF([test "x$DOXYGEN" = x], [ + AS_IF([test "x$with_doxygen" != xno], [ + dnl Only run doxygen Makefile if doxygen installed + AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]) + with_doxygen=no + ]) +]) +AC_OUTPUT + +echo " +libmnl configuration: + doxygen: ${with_doxygen}" diff --git a/deps/libmnl/doxygen/.gitignore b/deps/libmnl/doxygen/.gitignore new file mode 100644 index 0000000..2196cf8 --- /dev/null +++ b/deps/libmnl/doxygen/.gitignore @@ -0,0 +1,4 @@ +doxyfile.stamp +doxygen.cfg +html/ +man/ diff --git a/deps/libmnl/doxygen/Makefile.am b/deps/libmnl/doxygen/Makefile.am new file mode 100644 index 0000000..4770fc7 --- /dev/null +++ b/deps/libmnl/doxygen/Makefile.am @@ -0,0 +1,25 @@ +if HAVE_DOXYGEN +doc_srcs = $(shell find $(top_srcdir)/src -name '*.c') + +doxyfile.stamp: $(doc_srcs) Makefile.am + rm -rf html man + doxygen doxygen.cfg >/dev/null + $(SHELL) $(top_srcdir)/doxygen/finalize_manpages.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/ + +# make distcheck needs uninstall-local +uninstall-local: + rm -r $(DESTDIR)$(mandir) man html doxyfile.stamp +endif + +EXTRA_DIST = finalize_manpages.sh diff --git a/deps/libmnl/doxygen/doxygen.cfg.in b/deps/libmnl/doxygen/doxygen.cfg.in new file mode 100644 index 0000000..24089ac --- /dev/null +++ b/deps/libmnl/doxygen/doxygen.cfg.in @@ -0,0 +1,23 @@ +# Difference with default Doxyfile 1.8.20 +PROJECT_NAME = @PACKAGE@ +PROJECT_NUMBER = @VERSION@ +OUTPUT_DIRECTORY = . +ABBREVIATE_BRIEF = +FULL_PATH_NAMES = NO +TAB_SIZE = 8 +OPTIMIZE_OUTPUT_FOR_C = YES +INPUT = @top_srcdir@ +FILE_PATTERNS = */src/*.c +RECURSIVE = YES +EXCLUDE_SYMBOLS = EXPORT_SYMBOL mnl_nlmsg_batch mnl_socket +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 +MAN_LINKS = YES +HAVE_DOT = @HAVE_DOT@ +DOT_TRANSPARENT = YES diff --git a/deps/libmnl/doxygen/finalize_manpages.sh b/deps/libmnl/doxygen/finalize_manpages.sh new file mode 100644 index 0000000..6f230b1 --- /dev/null +++ b/deps/libmnl/doxygen/finalize_manpages.sh @@ -0,0 +1,40 @@ +# +# We need to use bash for its associative array facility +# +[ "$BASH" ] || exec bash $0 +# +# (`bash -p` prevents import of functions from the environment). +# +set -p + +declare -A renamed_page + +main(){ set -e; cd man/man3; rm -f _* + count_real_pages + rename_real_pages + make_symlinks +} + +count_real_pages(){ page_count=0 + for i in $(ls -S) + do head -n1 $i | grep -E -q '^\.so' && break + page_count=$(($page_count + 1)) + done + first_link=$(($page_count + 1)) +} + +rename_real_pages(){ for i in $(ls -S | head -n$page_count) + do for j in $(ls -S | tail -n+$first_link) + do grep -E -q $i$ $j && break + done + mv -f $i $j + renamed_page[$i]=$j + done +} + +make_symlinks(){ for j in $(ls -S | tail -n+$first_link) + do ln -sf ${renamed_page[$(cat $j | cut -f2 -d/)]} $j + done +} + +main diff --git a/deps/libmnl/examples/Makefile.am b/deps/libmnl/examples/Makefile.am new file mode 100644 index 0000000..e5cb052 --- /dev/null +++ b/deps/libmnl/examples/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = genl kobject netfilter rtnl diff --git a/deps/libmnl/examples/genl/.gitignore b/deps/libmnl/examples/genl/.gitignore new file mode 100644 index 0000000..a7d8966 --- /dev/null +++ b/deps/libmnl/examples/genl/.gitignore @@ -0,0 +1,2 @@ +/genl-family-get +/genl-group-events \ No newline at end of file diff --git a/deps/libmnl/examples/genl/Makefile.am b/deps/libmnl/examples/genl/Makefile.am new file mode 100644 index 0000000..b4b7954 --- /dev/null +++ b/deps/libmnl/examples/genl/Makefile.am @@ -0,0 +1,10 @@ +include $(top_srcdir)/Make_global.am + +check_PROGRAMS = genl-family-get \ + genl-group-events + +genl_family_get_SOURCES = genl-family-get.c +genl_family_get_LDADD = ../../src/libmnl.la + +genl_group_events_SOURCES = genl-group-events.c +genl_group_events_LDADD = ../../src/libmnl.la diff --git a/deps/libmnl/examples/genl/genl-family-get.c b/deps/libmnl/examples/genl/genl-family-get.c new file mode 100644 index 0000000..ba8de12 --- /dev/null +++ b/deps/libmnl/examples/genl/genl-family-get.c @@ -0,0 +1,241 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include + +#include +#include + +static int parse_mc_grps_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, CTRL_ATTR_MCAST_GRP_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTRL_ATTR_MCAST_GRP_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_MCAST_GRP_NAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void parse_genl_mc_grps(struct nlattr *nested) +{ + struct nlattr *pos; + + mnl_attr_for_each_nested(pos, nested) { + struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1] = {}; + + mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb); + if (tb[CTRL_ATTR_MCAST_GRP_ID]) { + printf("id-0x%x ", + mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID])); + } + if (tb[CTRL_ATTR_MCAST_GRP_NAME]) { + printf("name: %s ", + mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME])); + } + printf("\n"); + } +} + +static int parse_family_ops_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTRL_ATTR_OP_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTRL_ATTR_OP_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_OP_MAX: + break; + default: + return MNL_CB_OK; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void parse_genl_family_ops(struct nlattr *nested) +{ + struct nlattr *pos; + + mnl_attr_for_each_nested(pos, nested) { + struct nlattr *tb[CTRL_ATTR_OP_MAX+1] = {}; + + mnl_attr_parse_nested(pos, parse_family_ops_cb, tb); + if (tb[CTRL_ATTR_OP_ID]) { + printf("id-0x%x ", + mnl_attr_get_u32(tb[CTRL_ATTR_OP_ID])); + } + if (tb[CTRL_ATTR_OP_MAX]) { + printf("flags "); + } + printf("\n"); + } +} + +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTRL_ATTR_FAMILY_NAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_FAMILY_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_VERSION: + case CTRL_ATTR_HDRSIZE: + case CTRL_ATTR_MAXATTR: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTRL_ATTR_OPS: + case CTRL_ATTR_MCAST_GROUPS: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[CTRL_ATTR_MAX+1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), data_attr_cb, tb); + if (tb[CTRL_ATTR_FAMILY_NAME]) { + printf("name=%s\t", + mnl_attr_get_str(tb[CTRL_ATTR_FAMILY_NAME])); + } + if (tb[CTRL_ATTR_FAMILY_ID]) { + printf("id=%u\t", + mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID])); + } + if (tb[CTRL_ATTR_VERSION]) { + printf("version=%u\t", + mnl_attr_get_u32(tb[CTRL_ATTR_VERSION])); + } + if (tb[CTRL_ATTR_HDRSIZE]) { + printf("hdrsize=%u\t", + mnl_attr_get_u32(tb[CTRL_ATTR_HDRSIZE])); + } + if (tb[CTRL_ATTR_MAXATTR]) { + printf("maxattr=%u\t", + mnl_attr_get_u32(tb[CTRL_ATTR_MAXATTR])); + } + printf("\n"); + if (tb[CTRL_ATTR_OPS]) { + printf("ops:\n"); + parse_genl_family_ops(tb[CTRL_ATTR_OPS]); + } + if (tb[CTRL_ATTR_MCAST_GROUPS]) { + printf("grps:\n"); + parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS]); + } + printf("\n"); + return MNL_CB_OK; +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct genlmsghdr *genl; + int ret; + unsigned int seq, portid; + + if (argc > 2) { + printf("%s [family name]\n", argv[0]); + exit(EXIT_FAILURE); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = GENL_ID_CTRL; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + + genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); + genl->cmd = CTRL_CMD_GETFAMILY; + genl->version = 1; + + mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL); + if (argc >= 2) + mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, argv[1]); + else + nlh->nlmsg_flags |= NLM_F_DUMP; + + nl = mnl_socket_open(NETLINK_GENERIC); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/genl/genl-group-events.c b/deps/libmnl/examples/genl/genl-group-events.c new file mode 100644 index 0000000..d5f0a18 --- /dev/null +++ b/deps/libmnl/examples/genl/genl-group-events.c @@ -0,0 +1,63 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include + +#include +#include + +static int group; + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + printf("received event type=%d from genetlink group %d\n", + nlh->nlmsg_type, group); + return MNL_CB_OK; +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + int ret; + + if (argc != 2) { + printf("%s [group]\n", argv[0]); + exit(EXIT_FAILURE); + } + group = atoi(argv[1]); + + nl = mnl_socket_open(NETLINK_GENERIC); + 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); + } + + if (mnl_socket_setsockopt(nl, NETLINK_ADD_MEMBERSHIP, &group, + sizeof(int)) < 0) { + perror("mnl_socket_setsockopt"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, 0, 0, data_cb, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/kobject/.gitignore b/deps/libmnl/examples/kobject/.gitignore new file mode 100644 index 0000000..4d95e59 --- /dev/null +++ b/deps/libmnl/examples/kobject/.gitignore @@ -0,0 +1 @@ +/kobject-event diff --git a/deps/libmnl/examples/kobject/Makefile.am b/deps/libmnl/examples/kobject/Makefile.am new file mode 100644 index 0000000..9197f7a --- /dev/null +++ b/deps/libmnl/examples/kobject/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/Make_global.am + +check_PROGRAMS = kobject-event + +kobject_event_SOURCES = kobject-event.c +kobject_event_LDADD = ../../src/libmnl.la diff --git a/deps/libmnl/examples/kobject/kobject-event.c b/deps/libmnl/examples/kobject/kobject-event.c new file mode 100644 index 0000000..97debdf --- /dev/null +++ b/deps/libmnl/examples/kobject/kobject-event.c @@ -0,0 +1,49 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + int ret; + + nl = mnl_socket_open(NETLINK_KOBJECT_UEVENT); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + /* There is one single group in kobject over netlink */ + if (mnl_socket_bind(nl, (1<<0), MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + int i; + + /* kobject uses a string based protocol, with no initial + * netlink header. + */ + for (i=0; i +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int 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, NFULA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case NFULA_MARK: + case NFULA_IFINDEX_INDEV: + case NFULA_IFINDEX_OUTDEV: + case NFULA_IFINDEX_PHYSINDEV: + case NFULA_IFINDEX_PHYSOUTDEV: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case NFULA_TIMESTAMP: + if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, + sizeof(struct nfulnl_msg_packet_timestamp)) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + case NFULA_HWADDR: + if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, + sizeof(struct nfulnl_msg_packet_hw)) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + case NFULA_PREFIX: + if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case NFULA_PAYLOAD: + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int log_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[NFULA_MAX+1] = {}; + struct nfulnl_msg_packet_hdr *ph = NULL; + const char *prefix = NULL; + uint32_t mark = 0; + + mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb); + if (tb[NFULA_PACKET_HDR]) + ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]); + if (tb[NFULA_PREFIX]) + prefix = mnl_attr_get_str(tb[NFULA_PREFIX]); + if (tb[NFULA_MARK]) + mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK])); + + printf("log received (prefix=\"%s\" hw=0x%04x hook=%u mark=%u)\n", + prefix ? prefix : "", ntohs(ph->hw_protocol), ph->hook, + mark); + + return MNL_CB_OK; +} + +static struct nlmsghdr * +nflog_build_cfg_pf_request(char *buf, uint8_t command) +{ + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG; + nlh->nlmsg_flags = NLM_F_REQUEST; + + struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); + nfg->nfgen_family = AF_INET; + nfg->version = NFNETLINK_V0; + + struct nfulnl_msg_config_cmd cmd = { + .command = command, + }; + mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd); + + return nlh; +} + +static struct nlmsghdr * +nflog_build_cfg_request(char *buf, uint8_t command, int qnum) +{ + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG; + nlh->nlmsg_flags = NLM_F_REQUEST; + + struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); + nfg->nfgen_family = AF_INET; + nfg->version = NFNETLINK_V0; + nfg->res_id = htons(qnum); + + struct nfulnl_msg_config_cmd cmd = { + .command = command, + }; + mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd); + + return nlh; +} + +static struct nlmsghdr * +nflog_build_cfg_params(char *buf, uint8_t mode, int range, int qnum) +{ + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG; + 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(qnum); + + struct nfulnl_msg_config_mode params = { + .copy_range = htonl(range), + .copy_mode = mode, + }; + mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), ¶ms); + + return nlh; +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + int ret; + unsigned int portid, qnum; + + if (argc != 2) { + printf("Usage: %s [queue_num]\n", argv[0]); + exit(EXIT_FAILURE); + } + qnum = 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); + + nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_UNBIND); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + while (ret > 0) { + ret = mnl_cb_run(buf, ret, 0, portid, log_cb, NULL); + if (ret < 0){ + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/netfilter/nf-queue.c b/deps/libmnl/examples/netfilter/nf-queue.c new file mode 100644 index 0000000..957e365 --- /dev/null +++ b/deps/libmnl/examples/netfilter/nf-queue.c @@ -0,0 +1,243 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int 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: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case NFQA_TIMESTAMP: + if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, + sizeof(struct nfqnl_msg_packet_timestamp)) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + case NFQA_HWADDR: + if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, + sizeof(struct nfqnl_msg_packet_hw)) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + case NFQA_PAYLOAD: + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int queue_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[NFQA_MAX+1] = {}; + struct nfqnl_msg_packet_hdr *ph = NULL; + uint32_t id = 0; + + mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb); + if (tb[NFQA_PACKET_HDR]) { + ph = mnl_attr_get_payload(tb[NFQA_PACKET_HDR]); + id = ntohl(ph->packet_id); + + printf("packet received (id=%u hw=0x%04x hook=%u)\n", + id, ntohs(ph->hw_protocol), ph->hook); + } + + return MNL_CB_OK + id; +} + +static struct nlmsghdr * +nfq_build_cfg_pf_request(char *buf, uint8_t command) +{ + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG; + 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; + + struct nfqnl_msg_config_cmd cmd = { + .command = command, + .pf = htons(AF_INET), + }; + mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd); + + return nlh; +} + +static struct nlmsghdr * +nfq_build_cfg_request(char *buf, uint8_t command, int queue_num) +{ + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG; + 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); + + struct nfqnl_msg_config_cmd cmd = { + .command = command, + .pf = htons(AF_INET), + }; + mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd); + + return nlh; +} + +static struct nlmsghdr * +nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num) +{ + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG; + 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); + + struct nfqnl_msg_config_params params = { + .copy_range = htonl(range), + .copy_mode = mode, + }; + mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), ¶ms); + + return nlh; +} + +static struct nlmsghdr * +nfq_build_verdict(char *buf, int id, int queue_num, int verd) +{ + struct nlmsghdr *nlh; + struct nfgenmsg *nfg; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT; + nlh->nlmsg_flags = NLM_F_REQUEST; + nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); + nfg->nfgen_family = AF_UNSPEC; + nfg->version = NFNETLINK_V0; + nfg->res_id = htons(queue_num); + + struct nfqnl_msg_verdict_hdr vh = { + .verdict = htonl(verd), + .id = htonl(id), + }; + mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh); + + return nlh; +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + 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); + + nlh = nfq_build_cfg_pf_request(buf, NFQNL_CFG_CMD_PF_UNBIND); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + nlh = nfq_build_cfg_pf_request(buf, NFQNL_CFG_CMD_PF_BIND); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + nlh = nfq_build_cfg_request(buf, NFQNL_CFG_CMD_BIND, queue_num); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + nlh = nfq_build_cfg_params(buf, NFQNL_COPY_PACKET, 0xFFFF, queue_num); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + while (ret > 0) { + uint32_t id; + + ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL); + if (ret < 0){ + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + + id = ret - MNL_CB_OK; + nlh = nfq_build_verdict(buf, id, queue_num, NF_ACCEPT); + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/netfilter/nfct-create-batch.c b/deps/libmnl/examples/netfilter/nfct-create-batch.c new file mode 100644 index 0000000..4675789 --- /dev/null +++ b/deps/libmnl/examples/netfilter/nfct-create-batch.c @@ -0,0 +1,187 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static void put_msg(char *buf, uint16_t i, int seq) +{ + struct nlmsghdr *nlh; + struct nfgenmsg *nfh; + struct nlattr *nest1, *nest2; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW; + nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; + nlh->nlmsg_seq = seq; + + nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); + nfh->nfgen_family = AF_INET; + nfh->version = NFNETLINK_V0; + nfh->res_id = 0; + + nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_ORIG); + nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP); + mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("1.1.1.1")); + mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("2.2.2.2")); + mnl_attr_nest_end(nlh, nest2); + + nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO); + mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP); + mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(i)); + mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(1025)); + mnl_attr_nest_end(nlh, nest2); + mnl_attr_nest_end(nlh, nest1); + + nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_REPLY); + nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP); + mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("2.2.2.2")); + mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("1.1.1.1")); + mnl_attr_nest_end(nlh, nest2); + + nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO); + mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP); + mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(1025)); + mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(i)); + mnl_attr_nest_end(nlh, nest2); + mnl_attr_nest_end(nlh, nest1); + + nest1 = mnl_attr_nest_start(nlh, CTA_PROTOINFO); + nest2 = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP); + mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE, TCP_CONNTRACK_SYN_SENT); + mnl_attr_nest_end(nlh, nest2); + mnl_attr_nest_end(nlh, nest1); + + mnl_attr_put_u32(nlh, CTA_STATUS, htonl(IPS_CONFIRMED)); + mnl_attr_put_u32(nlh, CTA_TIMEOUT, htonl(1000)); +} + +static int cb_err(const struct nlmsghdr *nlh, void *data) +{ + struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); + if (err->error != 0) + printf("message with seq %u has failed: %s\n", + nlh->nlmsg_seq, strerror(-err->error)); + return MNL_CB_OK; +} + +static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = { + [NLMSG_ERROR] = cb_err, +}; + +static void +send_batch(struct mnl_socket *nl, struct mnl_nlmsg_batch *b, int portid) +{ + int ret, fd = mnl_socket_get_fd(nl); + size_t len = mnl_nlmsg_batch_size(b); + char rcv_buf[MNL_SOCKET_BUFFER_SIZE]; + + ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b), len); + if (ret == -1) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + /* receive and digest all the acknowledgments from the kernel. */ + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 0 + }; + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + ret = select(fd+1, &readfds, NULL, NULL, &tv); + if (ret == -1) { + perror("select"); + exit(EXIT_FAILURE); + } + while (ret > 0 && FD_ISSET(fd, &readfds)) { + ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run2(rcv_buf, ret, 0, portid, + NULL, NULL, cb_ctl_array, + MNL_ARRAY_SIZE(cb_ctl_array)); + if (ret == -1) { + perror("mnl_cb_run2"); + exit(EXIT_FAILURE); + } + + ret = select(fd+1, &readfds, NULL, NULL, &tv); + if (ret == -1) { + perror("select"); + exit(EXIT_FAILURE); + } + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + } +} + +int main(void) +{ + struct mnl_socket *nl; + char snd_buf[MNL_SOCKET_BUFFER_SIZE*2]; + struct mnl_nlmsg_batch *b; + int j; + unsigned int seq, portid; + uint16_t i; + + 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); + + /* The buffer that we use to batch messages is MNL_SOCKET_BUFFER_SIZE + * multiplied by 2 bytes long, but we limit the batch to half of it + * since the last message that does not fit the batch goes over the + * upper boundary, if you break this rule, expect memory corruptions. */ + b = mnl_nlmsg_batch_start(snd_buf, MNL_SOCKET_BUFFER_SIZE); + if (b == NULL) { + perror("mnl_nlmsg_batch_start"); + exit(EXIT_FAILURE); + } + + seq = time(NULL); + for (i=1024, j=0; i<65535; i++, j++) { + put_msg(mnl_nlmsg_batch_current(b), i, seq+j); + + /* is there room for more messages in this batch? + * if so, continue. */ + if (mnl_nlmsg_batch_next(b)) + continue; + + send_batch(nl, b, portid); + + /* this moves the last message that did not fit into the + * batch to the head of it. */ + mnl_nlmsg_batch_reset(b); + } + + /* check if there is any message in the batch not sent yet. */ + if (!mnl_nlmsg_batch_is_empty(b)) + send_batch(nl, b, portid); + + mnl_nlmsg_batch_stop(b); + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/netfilter/nfct-daemon.c b/deps/libmnl/examples/netfilter/nfct-daemon.c new file mode 100644 index 0000000..d223ac2 --- /dev/null +++ b/deps/libmnl/examples/netfilter/nfct-daemon.c @@ -0,0 +1,365 @@ +/* A very simple skeleton code that implements a daemon that collects + * conntrack statistics from ctnetlink. + * + * This example is placed in the public domain. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct nstats { + LIST_ENTRY(nstats) list; + + uint8_t family; + + union { + struct in_addr ip; + struct in6_addr ip6; + }; + uint64_t pkts, bytes; +}; + +static LIST_HEAD(nstats_head, nstats) nstats_head; + +static int parse_counters_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_COUNTERS_PACKETS: + case CTA_COUNTERS_BYTES: + if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void parse_counters(const struct nlattr *nest, struct nstats *ns) +{ + struct nlattr *tb[CTA_COUNTERS_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_counters_cb, tb); + if (tb[CTA_COUNTERS_PACKETS]) + ns->pkts += be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS])); + + if (tb[CTA_COUNTERS_BYTES]) + ns->bytes += be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES])); +} + +static int parse_ip_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_IP_V4_SRC: + case CTA_IP_V4_DST: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_IP_V6_SRC: + case CTA_IP_V6_DST: + if (mnl_attr_validate2(attr, MNL_TYPE_BINARY, + sizeof(struct in6_addr)) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void parse_ip(const struct nlattr *nest, struct nstats *ns) +{ + struct nlattr *tb[CTA_IP_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_ip_cb, tb); + if (tb[CTA_IP_V4_SRC]) { + struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]); + ns->ip = *in; + ns->family = AF_INET; + } + if (tb[CTA_IP_V6_SRC]) { + struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_SRC]); + ns->ip6 = *in; + ns->family = AF_INET6; + } +} + +static int parse_tuple_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_TUPLE_IP: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void parse_tuple(const struct nlattr *nest, struct nstats *ns) +{ + struct nlattr *tb[CTA_TUPLE_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_tuple_cb, tb); + if (tb[CTA_TUPLE_IP]) + parse_ip(tb[CTA_TUPLE_IP], ns); +} + +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_TUPLE_ORIG: + case CTA_COUNTERS_ORIG: + case CTA_COUNTERS_REPLY: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[CTA_MAX+1] = {}; + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + struct nstats ns = {}, *cur, *new; + + mnl_attr_parse(nlh, sizeof(*nfg), data_attr_cb, tb); + if (tb[CTA_TUPLE_ORIG]) + parse_tuple(tb[CTA_TUPLE_ORIG], &ns); + + if (tb[CTA_COUNTERS_ORIG]) + parse_counters(tb[CTA_COUNTERS_ORIG], &ns); + + if (tb[CTA_COUNTERS_REPLY]) + parse_counters(tb[CTA_COUNTERS_REPLY], &ns); + + /* Look up for existing statistics object ... */ + LIST_FOREACH(cur, &nstats_head, list) { + if (memcmp(&ns.ip6, &cur->ip6, sizeof(struct in6_addr)) == 0) { + /* ... and sum counters */ + cur->pkts += ns.pkts; + cur->bytes += ns.bytes; + return MNL_CB_OK; + } + } + + /* ... if it does not exist, add new stats object */ + new = calloc(1, sizeof(struct nstats)); + if (!new) + return MNL_CB_OK; + + new->family = ns.family; + new->ip6 = ns.ip6; + new->pkts = ns.pkts; + new->bytes = ns.bytes; + + LIST_INSERT_HEAD(&nstats_head, new, list); + + return MNL_CB_OK; +} + +static int handle(struct mnl_socket *nl) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + int ret; + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + /* It only happens if NETLINK_NO_ENOBUFS is not set, it means + * we are leaking statistics. + */ + if (errno == ENOBUFS) { + fprintf(stderr, "The daemon has hit ENOBUFS, you can " + "increase the size of your receiver " + "buffer to mitigate this or enable " + "reliable delivery.\n"); + } else { + perror("mnl_socket_recvfrom"); + } + return -1; + } + + ret = mnl_cb_run(buf, ret, 0, 0, data_cb, NULL); + if (ret == -1) { + perror("mnl_cb_run"); + return -1; + } else if (ret <= MNL_CB_STOP) + return 0; + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct nfgenmsg *nfh; + struct nstats *cur; + struct timeval tv = {}; + int ret, secs, on = 1, buffersize = (1 << 22); + + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + secs = atoi(argv[1]); + + LIST_INIT(&nstats_head); + + printf("Polling every %d seconds from kernel...\n", secs); + + /* Set high priority for this process, less chances to overrun + * the netlink receiver buffer since the scheduler gives this process + * more chances to run. + */ + nice(-20); + + /* Open netlink socket to operate with netfilter */ + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + /* Subscribe to destroy events to avoid leaking counters. The same + * socket is used to periodically atomically dump and reset counters. + */ + if (mnl_socket_bind(nl, NF_NETLINK_CONNTRACK_DESTROY, + MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + /* Set netlink receiver buffer to 16 MBytes, to avoid packet drops */ + setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUFFORCE, + &buffersize, sizeof(socklen_t)); + + /* The two tweaks below enable reliable event delivery, packets may + * be dropped if the netlink receiver buffer overruns. This happens ... + * + * a) if the kernel spams this user-space process until the receiver + * is filled. + * + * or: + * + * b) if the user-space process does not pull messages from the + * receiver buffer so often. + */ + mnl_socket_setsockopt(nl, NETLINK_BROADCAST_ERROR, &on, sizeof(int)); + mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &on, sizeof(int)); + + nlh = mnl_nlmsg_put_header(buf); + /* Counters are atomically zeroed in each dump */ + nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | + IPCTNL_MSG_CT_GET_CTRZERO; + nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; + + nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); + nfh->nfgen_family = AF_INET; + nfh->version = NFNETLINK_V0; + nfh->res_id = 0; + + /* Filter by mark: We only want to dump entries whose mark is zero */ + mnl_attr_put_u32(nlh, CTA_MARK, htonl(0)); + mnl_attr_put_u32(nlh, CTA_MARK_MASK, htonl(0xffffffff)); + + while (1) { + int fd_max = mnl_socket_get_fd(nl); + fd_set readfds; + + /* Every N seconds ... */ + if (tv.tv_sec == 0 && tv.tv_usec == 0) { + /* ... request a fresh dump of the table from kernel */ + ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len); + if (ret == -1) { + perror("mnl_socket_sendto"); + return -1; + } + tv.tv_sec = secs; + tv.tv_usec = 0; + + /* print the content of the list */ + LIST_FOREACH(cur, &nstats_head, list) { + char out[INET6_ADDRSTRLEN]; + + if (inet_ntop(cur->family, &cur->ip, out, sizeof(out))) + printf("src=%s ", out); + + printf("counters %"PRIu64" %"PRIu64"\n", + cur->pkts, cur->bytes); + } + } + + FD_ZERO(&readfds); + FD_SET(mnl_socket_get_fd(nl), &readfds); + + ret = select(fd_max+1, &readfds, NULL, NULL, &tv); + if (ret < 0) { + if (errno == EINTR) + continue; + + perror("select"); + exit(EXIT_FAILURE); + } + + /* Handled event and periodic atomic-dump-and-reset messages */ + if (FD_ISSET(mnl_socket_get_fd(nl), &readfds)) { + if (handle(nl) < 0) + return EXIT_FAILURE; + } + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/netfilter/nfct-dump.c b/deps/libmnl/examples/netfilter/nfct-dump.c new file mode 100644 index 0000000..cb8e52c --- /dev/null +++ b/deps/libmnl/examples/netfilter/nfct-dump.c @@ -0,0 +1,319 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int parse_counters_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_COUNTERS_PACKETS: + case CTA_COUNTERS_BYTES: + if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void print_counters(const struct nlattr *nest) +{ + struct nlattr *tb[CTA_COUNTERS_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_counters_cb, tb); + if (tb[CTA_COUNTERS_PACKETS]) { + printf("packets=%"PRIu64" ", + be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS]))); + } + if (tb[CTA_COUNTERS_BYTES]) { + printf("bytes=%"PRIu64" ", + be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES]))); + } +} + +static int parse_ip_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_IP_V4_SRC: + case CTA_IP_V4_DST: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_IP_V6_SRC: + case CTA_IP_V6_DST: + if (mnl_attr_validate2(attr, MNL_TYPE_BINARY, + sizeof(struct in6_addr)) < 0) { + perror("mnl_attr_validate2"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void print_ip(const struct nlattr *nest) +{ + struct nlattr *tb[CTA_IP_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_ip_cb, tb); + if (tb[CTA_IP_V4_SRC]) { + struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]); + printf("src=%s ", inet_ntoa(*in)); + } + if (tb[CTA_IP_V4_DST]) { + struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_DST]); + printf("dst=%s ", inet_ntoa(*in)); + } + if (tb[CTA_IP_V6_SRC]) { + struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_SRC]); + char out[INET6_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET6, in, out, sizeof(out))) + printf("src=%s ", out); + } + if (tb[CTA_IP_V6_DST]) { + struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_DST]); + char out[INET6_ADDRSTRLEN]; + + if (!inet_ntop(AF_INET6, in, out, sizeof(out))) + printf("dst=%s ", out); + } +} + +static int parse_proto_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_PROTO_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_PROTO_NUM: + case CTA_PROTO_ICMP_TYPE: + case CTA_PROTO_ICMP_CODE: + if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_PROTO_SRC_PORT: + case CTA_PROTO_DST_PORT: + case CTA_PROTO_ICMP_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void print_proto(const struct nlattr *nest) +{ + struct nlattr *tb[CTA_PROTO_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_proto_cb, tb); + if (tb[CTA_PROTO_NUM]) { + printf("proto=%u ", mnl_attr_get_u8(tb[CTA_PROTO_NUM])); + } + if (tb[CTA_PROTO_SRC_PORT]) { + printf("sport=%u ", + ntohs(mnl_attr_get_u16(tb[CTA_PROTO_SRC_PORT]))); + } + if (tb[CTA_PROTO_DST_PORT]) { + printf("dport=%u ", + ntohs(mnl_attr_get_u16(tb[CTA_PROTO_DST_PORT]))); + } + if (tb[CTA_PROTO_ICMP_ID]) { + printf("id=%u ", + ntohs(mnl_attr_get_u16(tb[CTA_PROTO_ICMP_ID]))); + } + if (tb[CTA_PROTO_ICMP_TYPE]) { + printf("type=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_TYPE])); + } + if (tb[CTA_PROTO_ICMP_CODE]) { + printf("code=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_CODE])); + } +} + +static int parse_tuple_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_TUPLE_IP: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_TUPLE_PROTO: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void print_tuple(const struct nlattr *nest) +{ + struct nlattr *tb[CTA_TUPLE_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_tuple_cb, tb); + if (tb[CTA_TUPLE_IP]) { + print_ip(tb[CTA_TUPLE_IP]); + } + if (tb[CTA_TUPLE_PROTO]) { + print_proto(tb[CTA_TUPLE_PROTO]); + } +} + +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_TUPLE_ORIG: + case CTA_COUNTERS_ORIG: + case CTA_COUNTERS_REPLY: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_TIMEOUT: + case CTA_MARK: + case CTA_SECMARK: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[CTA_MAX+1] = {}; + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*nfg), data_attr_cb, tb); + if (tb[CTA_TUPLE_ORIG]) + print_tuple(tb[CTA_TUPLE_ORIG]); + + if (tb[CTA_MARK]) + printf("mark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_MARK]))); + + if (tb[CTA_SECMARK]) + printf("secmark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_SECMARK]))); + + if (tb[CTA_COUNTERS_ORIG]) { + printf("original "); + print_counters(tb[CTA_COUNTERS_ORIG]); + } + + if (tb[CTA_COUNTERS_REPLY]) { + printf("reply "); + print_counters(tb[CTA_COUNTERS_REPLY]); + } + + printf("\n"); + return MNL_CB_OK; +} + +int main(void) +{ + char buf[MNL_SOCKET_DUMP_SIZE]; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct nfgenmsg *nfh; + uint32_t seq, portid; + int ret; + + 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); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET; + nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + + nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); + nfh->nfgen_family = AF_INET; + nfh->version = NFNETLINK_V0; + nfh->res_id = 0; + + ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len); + if (ret == -1) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + portid = mnl_socket_get_portid(nl); + + while (1) { + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret == -1) { + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } else if (ret <= MNL_CB_STOP) + break; + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/netfilter/nfct-event.c b/deps/libmnl/examples/netfilter/nfct-event.c new file mode 100644 index 0000000..94603d4 --- /dev/null +++ b/deps/libmnl/examples/netfilter/nfct-event.c @@ -0,0 +1,240 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include + +#include +#include +#include + +static int parse_ip_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_IP_V4_SRC: + case CTA_IP_V4_DST: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void print_ip(const struct nlattr *nest) +{ + struct nlattr *tb[CTA_IP_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_ip_cb, tb); + if (tb[CTA_IP_V4_SRC]) { + struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]); + printf("src=%s ", inet_ntoa(*in)); + } + if (tb[CTA_IP_V4_DST]) { + struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_DST]); + printf("dst=%s ", inet_ntoa(*in)); + } +} + +static int parse_proto_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_PROTO_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_PROTO_NUM: + case CTA_PROTO_ICMP_TYPE: + case CTA_PROTO_ICMP_CODE: + if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_PROTO_SRC_PORT: + case CTA_PROTO_DST_PORT: + case CTA_PROTO_ICMP_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void print_proto(const struct nlattr *nest) +{ + struct nlattr *tb[CTA_PROTO_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_proto_cb, tb); + if (tb[CTA_PROTO_NUM]) { + printf("proto=%u ", mnl_attr_get_u8(tb[CTA_PROTO_NUM])); + } + if (tb[CTA_PROTO_SRC_PORT]) { + printf("sport=%u ", + ntohs(mnl_attr_get_u16(tb[CTA_PROTO_SRC_PORT]))); + } + if (tb[CTA_PROTO_DST_PORT]) { + printf("dport=%u ", + ntohs(mnl_attr_get_u16(tb[CTA_PROTO_DST_PORT]))); + } + if (tb[CTA_PROTO_ICMP_ID]) { + printf("id=%u ", + ntohs(mnl_attr_get_u16(tb[CTA_PROTO_ICMP_ID]))); + } + if (tb[CTA_PROTO_ICMP_TYPE]) { + printf("type=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_TYPE])); + } + if (tb[CTA_PROTO_ICMP_CODE]) { + printf("code=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_CODE])); + } +} + +static int parse_tuple_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_TUPLE_IP: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_TUPLE_PROTO: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void print_tuple(const struct nlattr *nest) +{ + struct nlattr *tb[CTA_TUPLE_MAX+1] = {}; + + mnl_attr_parse_nested(nest, parse_tuple_cb, tb); + if (tb[CTA_TUPLE_IP]) { + print_ip(tb[CTA_TUPLE_IP]); + } + if (tb[CTA_TUPLE_PROTO]) { + print_proto(tb[CTA_TUPLE_PROTO]); + } +} + +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case CTA_TUPLE_ORIG: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case CTA_TIMEOUT: + case CTA_MARK: + case CTA_SECMARK: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[CTA_MAX+1] = {}; + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + + switch(nlh->nlmsg_type & 0xFF) { + case IPCTNL_MSG_CT_NEW: + if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL)) + printf("%9s ", "[NEW] "); + else + printf("%9s ", "[UPDATE] "); + break; + case IPCTNL_MSG_CT_DELETE: + printf("%9s ", "[DESTROY] "); + break; + } + + mnl_attr_parse(nlh, sizeof(*nfg), data_attr_cb, tb); + if (tb[CTA_TUPLE_ORIG]) { + print_tuple(tb[CTA_TUPLE_ORIG]); + } + if (tb[CTA_MARK]) { + printf("mark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_MARK]))); + } + if (tb[CTA_SECMARK]) { + printf("secmark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_SECMARK]))); + } + printf("\n"); + return MNL_CB_OK; +} + +int main(void) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + int ret; + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY, + MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + while (1) { + 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, 0, data_cb, NULL); + if (ret == -1) { + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/.gitignore b/deps/libmnl/examples/rtnl/.gitignore new file mode 100644 index 0000000..4b16c53 --- /dev/null +++ b/deps/libmnl/examples/rtnl/.gitignore @@ -0,0 +1,12 @@ +/rtnl-addr-add +/rtnl-addr-dump +/rtnl-link-can +/rtnl-link-dump +/rtnl-link-dump2 +/rtnl-link-dump3 +/rtnl-link-event +/rtnl-link-set +/rtnl-neigh-dump +/rtnl-route-event +/rtnl-route-add +/rtnl-route-dump diff --git a/deps/libmnl/examples/rtnl/Makefile.am b/deps/libmnl/examples/rtnl/Makefile.am new file mode 100644 index 0000000..5a28e09 --- /dev/null +++ b/deps/libmnl/examples/rtnl/Makefile.am @@ -0,0 +1,48 @@ +include $(top_srcdir)/Make_global.am + +check_PROGRAMS = rtnl-addr-add \ + rtnl-addr-dump \ + rtnl-link-can \ + rtnl-link-dump rtnl-link-dump2 rtnl-link-dump3 \ + rtnl-link-event \ + rtnl-link-set \ + rtnl-route-add \ + rtnl-route-dump \ + rtnl-route-event \ + rtnl-neigh-dump + +rtnl_addr_add_SOURCES = rtnl-addr-add.c +rtnl_addr_add_LDADD = ../../src/libmnl.la + +rtnl_link_can_SOURCES = rtnl-link-can.c +rtnl_link_can_LDADD = ../../src/libmnl.la + +rtnl_addr_dump_SOURCES = rtnl-addr-dump.c +rtnl_addr_dump_LDADD = ../../src/libmnl.la + +rtnl_link_dump_SOURCES = rtnl-link-dump.c +rtnl_link_dump_LDADD = ../../src/libmnl.la + +rtnl_link_dump2_SOURCES = rtnl-link-dump2.c +rtnl_link_dump2_LDADD = ../../src/libmnl.la + +rtnl_link_dump3_SOURCES = rtnl-link-dump3.c +rtnl_link_dump3_LDADD = ../../src/libmnl.la + +rtnl_route_add_SOURCES = rtnl-route-add.c +rtnl_route_add_LDADD = ../../src/libmnl.la + +rtnl_link_event_SOURCES = rtnl-link-event.c +rtnl_link_event_LDADD = ../../src/libmnl.la + +rtnl_link_set_SOURCES = rtnl-link-set.c +rtnl_link_set_LDADD = ../../src/libmnl.la + +rtnl_route_dump_SOURCES = rtnl-route-dump.c +rtnl_route_dump_LDADD = ../../src/libmnl.la + +rtnl_route_event_SOURCES = rtnl-route-event.c +rtnl_route_event_LDADD = ../../src/libmnl.la + +rtnl_neigh_dump_SOURCES = rtnl-neigh-dump.c +rtnl_neigh_dump_LDADD = ../../src/libmnl.la diff --git a/deps/libmnl/examples/rtnl/rtnl-addr-add.c b/deps/libmnl/examples/rtnl/rtnl-addr-add.c new file mode 100644 index 0000000..f9a69dc --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-addr-add.c @@ -0,0 +1,119 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct ifaddrmsg *ifm; + uint32_t seq, portid; + union { + in_addr_t ip; + struct in6_addr ip6; + } addr; + int ret, family = AF_INET; + + uint32_t prefix; + int iface; + + + if (argc <= 3) { + printf("Usage: %s iface destination cidr\n", argv[0]); + printf("Example: %s eth0 10.0.1.12 32\n", argv[0]); + printf(" %s eth0 ffff::10.0.1.12 128\n", argv[0]); + exit(EXIT_FAILURE); + } + + iface = if_nametoindex(argv[1]); + if (iface == 0) { + perror("if_nametoindex"); + exit(EXIT_FAILURE); + } + + if (!inet_pton(AF_INET, argv[2], &addr)) { + if (!inet_pton(AF_INET6, argv[2], &addr)) { + perror("inet_pton"); + exit(EXIT_FAILURE); + } + family = AF_INET6; + } + + if (sscanf(argv[3], "%u", &prefix) == 0) { + perror("sscanf"); + exit(EXIT_FAILURE); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_NEWADDR; + + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + + ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ifaddrmsg)); + + ifm->ifa_family = family; + ifm->ifa_prefixlen = prefix; + ifm->ifa_flags = IFA_F_PERMANENT; + + ifm->ifa_scope = RT_SCOPE_UNIVERSE; + ifm->ifa_index = iface; + + /* + * The exact meaning of IFA_LOCAL and IFA_ADDRESS depend + * on the address family being used and the device type. + * For broadcast devices (like the interfaces we use), + * for IPv4 we specify both and they are used interchangeably. + * For IPv6, only IFA_ADDRESS needs to be set. + */ + if (family == AF_INET) { + mnl_attr_put_u32(nlh, IFA_LOCAL, addr.ip); + mnl_attr_put_u32(nlh, IFA_ADDRESS, addr.ip); + } else { + mnl_attr_put(nlh, IFA_ADDRESS, sizeof(struct in6_addr), &addr); + } + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret < 0) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret < 0) { + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-addr-dump.c b/deps/libmnl/examples/rtnl/rtnl-addr-dump.c new file mode 100644 index 0000000..675e9b0 --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-addr-dump.c @@ -0,0 +1,133 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int data_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, IFA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case IFA_ADDRESS: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[IFA_MAX + 1] = {}; + struct ifaddrmsg *ifa = mnl_nlmsg_get_payload(nlh); + + printf("index=%d family=%d ", ifa->ifa_index, ifa->ifa_family); + + mnl_attr_parse(nlh, sizeof(*ifa), data_attr_cb, tb); + printf("addr="); + if (tb[IFA_ADDRESS]) { + void *addr = mnl_attr_get_payload(tb[IFA_ADDRESS]); + char out[INET6_ADDRSTRLEN]; + + if (inet_ntop(ifa->ifa_family, addr, out, sizeof(out))) + printf("%s ", out); + } + printf("scope="); + switch(ifa->ifa_scope) { + case 0: + printf("global "); + break; + case 200: + printf("site "); + break; + case 253: + printf("link "); + break; + case 254: + printf("host "); + break; + case 255: + printf("nowhere "); + break; + default: + printf("%d ", ifa->ifa_scope); + break; + } + + printf("\n"); + return MNL_CB_OK; +} + +int main(int argc, char *argv[]) +{ + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct rtgenmsg *rt; + int ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETADDR; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + if (strcmp(argv[1], "inet") == 0) + rt->rtgen_family = AF_INET; + else if (strcmp(argv[1], "inet6") == 0) + rt->rtgen_family = AF_INET6; + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-link-can.c b/deps/libmnl/examples/rtnl/rtnl-link-can.c new file mode 100644 index 0000000..8ed70d1 --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-link-can.c @@ -0,0 +1,452 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static void incomplete_command(void) __attribute__((noreturn)); + +#define NEXT_ARG() \ + do { \ + if (argc <= 0) incomplete_command(); \ + argv++; \ + argc--; \ + } while (0) + +static void duparg2(const char *key, const char *arg) +{ + fprintf(stderr, + "Error: either \"%s\" is duplicate, or \"%s\" is a garbage.\n", + key, arg); + exit(-1); +} + +static void incomplete_command(void) +{ + fprintf(stderr, "Command line is not complete. Try option \"help\"\n"); + exit(EXIT_FAILURE); +} + +/* Returns false if 'prefix' is a not empty prefix of 'string'. + */ +static bool matches(const char *prefix, const char *string) +{ + if (!*prefix) + return true; + + while (*string && *prefix == *string) { + prefix++; + string++; + } + + return !!*prefix; +} + +static int get_u16(__u16 *val, const char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + + res = strtoul(arg, &ptr, base); + + /* empty string or trailing non-digits */ + if (!ptr || ptr == arg || *ptr) + return -1; + + /* overflow */ + if (res == ULONG_MAX && errno == ERANGE) + return -1; + + if (res > 0xFFFFUL) + return -1; + + *val = res; + return 0; +} + +static int get_u32(__u32 *val, const char *arg, int base) +{ + unsigned long res; + char *ptr; + + if (!arg || !*arg) + return -1; + + res = strtoul(arg, &ptr, base); + + /* empty string or trailing non-digits */ + if (!ptr || ptr == arg || *ptr) + return -1; + + /* overflow */ + if (res == ULONG_MAX && errno == ERANGE) + return -1; + + /* in case UL > 32 bits */ + if (res > 0xFFFFFFFFUL) + return -1; + + *val = res; + return 0; +} + +static int get_float(float *val, const char *arg) +{ + float res; + char *ptr; + + if (!arg || !*arg) + return -1; + + res = strtof(arg, &ptr); + if (!ptr || ptr == arg || *ptr) + return -1; + + *val = res; + return 0; +} + +static void set_ctrlmode(char *name, char *arg, + struct can_ctrlmode *cm, __u32 flags) +{ + if (strcmp(arg, "on") == 0) { + cm->flags |= flags; + } else if (strcmp(arg, "off") != 0) { + fprintf(stderr, + "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", + name, arg); + exit(EXIT_FAILURE); + } + + cm->mask |= flags; +} + +static void invarg(const char *msg, const char *arg) +{ + fprintf(stderr, "Error: argument \"%s\" is wrong: %s\n", arg, msg); + exit(-1); +} + +static void print_usage(FILE *f) +{ + fprintf(f, + "Usage: ip link set DEVICE type can\n" + "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |\n" + "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n \t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n" + "\n" + "\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |\n" + "\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n \t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n" + "\n" + "\t[ loopback { on | off } ]\n" + "\t[ listen-only { on | off } ]\n" + "\t[ triple-sampling { on | off } ]\n" + "\t[ one-shot { on | off } ]\n" + "\t[ berr-reporting { on | off } ]\n" + "\t[ fd { on | off } ]\n" + "\t[ fd-non-iso { on | off } ]\n" + "\t[ presume-ack { on | off } ]\n" + "\t[ cc-len8-dlc { on | off } ]\n" + "\n" + "\t[ restart-ms TIME-MS ]\n" + "\t[ restart ]\n" + "\n" + "\t[ termination { 0..65535 } ]\n" + "\n" + "\tWhere: BITRATE := { 1..1000000 }\n" + "\t SAMPLE-POINT := { 0.000..0.999 }\n" + "\t TQ := { NUMBER }\n" + "\t PROP-SEG := { 1..8 }\n" + "\t PHASE-SEG1 := { 1..8 }\n" + "\t PHASE-SEG2 := { 1..8 }\n" + "\t SJW := { 1..4 }\n" + "\t RESTART-MS := { 0 | NUMBER }\n" + ); +} + +static void usage(void) +{ + print_usage(stderr); +} + +static int iplink_set_can_parse(int argc, char **argv, struct nlmsghdr *nlh) +{ + struct can_bittiming bt = {}, dbt = {}; + struct can_ctrlmode cm = {}; + + while (argc > 0) { + if (matches(*argv, "bitrate") == 0) { + NEXT_ARG(); + if (get_u32(&bt.bitrate, *argv, 0)) + invarg("invalid \"bitrate\" value\n", *argv); + } else if (matches(*argv, "sample-point") == 0) { + float sp; + + NEXT_ARG(); + if (get_float(&sp, *argv)) + invarg("invalid \"sample-point\" value\n", + *argv); + + bt.sample_point = (__u32)(sp * 1000); + } else if (matches(*argv, "tq") == 0) { + NEXT_ARG(); + if (get_u32(&bt.tq, *argv, 0)) + invarg("invalid \"tq\" value\n", *argv); + } else if (matches(*argv, "prop-seg") == 0) { + NEXT_ARG(); + if (get_u32(&bt.prop_seg, *argv, 0)) + invarg("invalid \"prop-seg\" value\n", *argv); + } else if (matches(*argv, "phase-seg1") == 0) { + NEXT_ARG(); + if (get_u32(&bt.phase_seg1, *argv, 0)) + invarg("invalid \"phase-seg1\" value\n", *argv); + } else if (matches(*argv, "phase-seg2") == 0) { + NEXT_ARG(); + if (get_u32(&bt.phase_seg2, *argv, 0)) + invarg("invalid \"phase-seg2\" value\n", *argv); + } else if (matches(*argv, "sjw") == 0) { + NEXT_ARG(); + if (get_u32(&bt.sjw, *argv, 0)) + invarg("invalid \"sjw\" value\n", *argv); + } else if (matches(*argv, "dbitrate") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.bitrate, *argv, 0)) + invarg("invalid \"dbitrate\" value\n", *argv); + } else if (matches(*argv, "dsample-point") == 0) { + float sp; + + NEXT_ARG(); + if (get_float(&sp, *argv)) + invarg("invalid \"dsample-point\" value\n", *argv); + dbt.sample_point = (__u32)(sp * 1000); + } else if (matches(*argv, "dtq") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.tq, *argv, 0)) + invarg("invalid \"dtq\" value\n", *argv); + } else if (matches(*argv, "dprop-seg") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.prop_seg, *argv, 0)) + invarg("invalid \"dprop-seg\" value\n", *argv); + } else if (matches(*argv, "dphase-seg1") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.phase_seg1, *argv, 0)) + invarg("invalid \"dphase-seg1\" value\n", *argv); + } else if (matches(*argv, "dphase-seg2") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.phase_seg2, *argv, 0)) + invarg("invalid \"dphase-seg2\" value\n", *argv); + } else if (matches(*argv, "dsjw") == 0) { + NEXT_ARG(); + if (get_u32(&dbt.sjw, *argv, 0)) + invarg("invalid \"dsjw\" value\n", *argv); + } else if (matches(*argv, "loopback") == 0) { + NEXT_ARG(); + set_ctrlmode("loopback", *argv, &cm, + CAN_CTRLMODE_LOOPBACK); + } else if (matches(*argv, "listen-only") == 0) { + NEXT_ARG(); + set_ctrlmode("listen-only", *argv, &cm, + CAN_CTRLMODE_LISTENONLY); + } else if (matches(*argv, "triple-sampling") == 0) { + NEXT_ARG(); + set_ctrlmode("triple-sampling", *argv, &cm, + CAN_CTRLMODE_3_SAMPLES); + } else if (matches(*argv, "one-shot") == 0) { + NEXT_ARG(); + set_ctrlmode("one-shot", *argv, &cm, + CAN_CTRLMODE_ONE_SHOT); + } else if (matches(*argv, "berr-reporting") == 0) { + NEXT_ARG(); + set_ctrlmode("berr-reporting", *argv, &cm, + CAN_CTRLMODE_BERR_REPORTING); + } else if (matches(*argv, "fd") == 0) { + NEXT_ARG(); + set_ctrlmode("fd", *argv, &cm, + CAN_CTRLMODE_FD); + } else if (matches(*argv, "fd-non-iso") == 0) { + NEXT_ARG(); + set_ctrlmode("fd-non-iso", *argv, &cm, + CAN_CTRLMODE_FD_NON_ISO); + } else if (matches(*argv, "presume-ack") == 0) { + NEXT_ARG(); + set_ctrlmode("presume-ack", *argv, &cm, + CAN_CTRLMODE_PRESUME_ACK); +#if defined(CAN_CTRLMODE_CC_LEN8_DLC) + } else if (matches(*argv, "cc-len8-dlc") == 0) { + NEXT_ARG(); + set_ctrlmode("cc-len8-dlc", *argv, &cm, + CAN_CTRLMODE_CC_LEN8_DLC); +#endif + } else if (matches(*argv, "restart") == 0) { + __u32 val = 1; + + mnl_attr_put(nlh, IFLA_CAN_RESTART, sizeof(val), &val); + } else if (matches(*argv, "restart-ms") == 0) { + __u32 val; + + NEXT_ARG(); + if (get_u32(&val, *argv, 0)) + invarg("invalid \"restart-ms\" value\n", *argv); + + mnl_attr_put(nlh, IFLA_CAN_RESTART_MS, sizeof(val), &val); + } else if (matches(*argv, "termination") == 0) { + __u16 val; + + NEXT_ARG(); + if (get_u16(&val, *argv, 0)) + invarg("invalid \"termination\" value\n", + *argv); + + mnl_attr_put(nlh, IFLA_CAN_TERMINATION, sizeof(val), &val); + } else { + fprintf(stderr, "unknown option \"%s\"\n", *argv); + usage(); + return -1; + } + + NEXT_ARG(); + } + + if (bt.bitrate || bt.tq) + mnl_attr_put(nlh, IFLA_CAN_BITTIMING, sizeof(bt), &bt); + + if (cm.mask) + mnl_attr_put(nlh, IFLA_CAN_CTRLMODE, sizeof(cm), &cm); + + return 0; +} + +int main(int argc, char *argv[]) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct ifinfomsg *ifm; + int ret; + unsigned int seq, portid; + struct nlattr *linkinfo, *data; + const char *signatures[] = { + "ip", "link", "set", "" + }; + char *type = NULL; + char *dev = NULL; + int i; + + NEXT_ARG(); + for (i = 0; argc > 0 && signatures[i][0];) { + if (matches(*argv, signatures[i])) + incomplete_command(); + + NEXT_ARG(); + i++; + } + + if (argc == 0) + incomplete_command(); + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_NEWLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); + ifm->ifi_family = AF_UNSPEC; + ifm->ifi_change = 0; + ifm->ifi_flags = 0; + + while (argc > 0) { + if (matches(*argv, "up") == 0) { + ifm->ifi_change |= IFF_UP; + ifm->ifi_flags |= IFF_UP; + } else if (matches(*argv, "down") == 0) { + ifm->ifi_change |= IFF_UP; + ifm->ifi_flags &= ~IFF_UP; + } else if (matches(*argv, "type") == 0) { + NEXT_ARG(); + type = *argv; + NEXT_ARG(); + break; + } else if (matches(*argv, "help") == 0) { + usage(); + exit(EXIT_FAILURE); + } else { + if (matches(*argv, "dev") == 0) + NEXT_ARG(); + + if (dev) + duparg2("dev", *argv); + + dev = *argv; + } + + NEXT_ARG(); + } + + if (dev) + mnl_attr_put_str(nlh, IFLA_IFNAME, dev); + + if (type) { + if (matches(type, "can")) { + fprintf(stderr, "unknown type \"%s\"\n", type); + usage(); + exit(EXIT_FAILURE); + } + + linkinfo = mnl_attr_nest_start(nlh, IFLA_LINKINFO); + mnl_attr_put_str(nlh, IFLA_INFO_KIND, "can"); + data = mnl_attr_nest_start(nlh, IFLA_INFO_DATA); + + if (iplink_set_can_parse(argc, argv, nlh)) + return -1; + + mnl_attr_nest_end(nlh, data); + mnl_attr_nest_end(nlh, linkinfo); + } + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, + sizeof(struct ifinfomsg)); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret == -1) { + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-link-dump.c b/deps/libmnl/examples/rtnl/rtnl-link-dump.c new file mode 100644 index 0000000..031346f --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-link-dump.c @@ -0,0 +1,130 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int data_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, IFLA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case IFLA_ADDRESS: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[IFLA_MAX+1] = {}; + struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh); + + printf("index=%d type=%d flags=%d family=%d ", + ifm->ifi_index, ifm->ifi_type, + ifm->ifi_flags, ifm->ifi_family); + + if (ifm->ifi_flags & IFF_RUNNING) + printf("[RUNNING] "); + else + printf("[NOT RUNNING] "); + + mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb); + if (tb[IFLA_MTU]) { + printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU])); + } + if (tb[IFLA_IFNAME]) { + printf("name=%s ", mnl_attr_get_str(tb[IFLA_IFNAME])); + } + if (tb[IFLA_ADDRESS]) { + uint8_t *hwaddr = mnl_attr_get_payload(tb[IFLA_ADDRESS]); + int i; + + printf("hwaddr="); + for (i=0; inlmsg_type = RTM_GETLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + rt->rtgen_family = AF_PACKET; + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-link-dump2.c b/deps/libmnl/examples/rtnl/rtnl-link-dump2.c new file mode 100644 index 0000000..890e51a --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-link-dump2.c @@ -0,0 +1,103 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include + +#include +#include +#include +#include + +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + /* skip unsupported attribute in user-space */ + if (mnl_attr_type_valid(attr, IFLA_MAX) < 0) + return MNL_CB_OK; + + switch(mnl_attr_get_type(attr)) { + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + printf("mtu=%d ", mnl_attr_get_u32(attr)); + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + printf("name=%s ", mnl_attr_get_str(attr)); + break; + } + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh); + + printf("index=%d type=%d flags=%d family=%d ", + ifm->ifi_index, ifm->ifi_type, + ifm->ifi_flags, ifm->ifi_family); + + if (ifm->ifi_flags & IFF_RUNNING) + printf("[RUNNING] "); + else + printf("[NOT RUNNING] "); + + mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, NULL); + printf("\n"); + return MNL_CB_OK; +} + +int main(void) +{ + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct rtgenmsg *rt; + int ret; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + rt->rtgen_family = AF_PACKET; + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-link-dump3.c b/deps/libmnl/examples/rtnl/rtnl-link-dump3.c new file mode 100644 index 0000000..a381da1 --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-link-dump3.c @@ -0,0 +1,103 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include + +#include +#include +#include +#include + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh); + struct nlattr *attr; + + printf("index=%d type=%d flags=%d family=%d ", + ifm->ifi_index, ifm->ifi_type, + ifm->ifi_flags, ifm->ifi_family); + + if (ifm->ifi_flags & IFF_RUNNING) + printf("[RUNNING] "); + else + printf("[NOT RUNNING] "); + + mnl_attr_for_each(attr, nlh, sizeof(*ifm)) { + int type = mnl_attr_get_type(attr); + + /* skip unsupported attribute in user-space */ + if (mnl_attr_type_valid(attr, IFLA_MAX) < 0) + continue; + + switch(type) { + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + printf("mtu=%d ", mnl_attr_get_u32(attr)); + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + printf("name=%s ", mnl_attr_get_str(attr)); + break; + } + } + printf("\n"); + + return MNL_CB_OK; +} + +int main(void) +{ + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct rtgenmsg *rt; + int ret; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + rt->rtgen_family = AF_PACKET; + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-link-event.c b/deps/libmnl/examples/rtnl/rtnl-link-event.c new file mode 100644 index 0000000..123fb88 --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-link-event.c @@ -0,0 +1,95 @@ +/* This example is placed in the public domain. */ +#include +#include +#include + +#include +#include +#include +#include + +static int data_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, IFLA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case IFLA_MTU: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case IFLA_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[IFLA_MAX+1] = {}; + struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh); + + printf("index=%d type=%d flags=%d family=%d ", + ifm->ifi_index, ifm->ifi_type, + ifm->ifi_flags, ifm->ifi_family); + + if (ifm->ifi_flags & IFF_RUNNING) + printf("[RUNNING] "); + else + printf("[NOT RUNNING] "); + + mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb); + if (tb[IFLA_MTU]) { + printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU])); + } + if (tb[IFLA_IFNAME]) { + printf("name=%s", mnl_attr_get_str(tb[IFLA_IFNAME])); + } + printf("\n"); + return MNL_CB_OK; +} + +int main(void) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + int ret; + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, RTMGRP_LINK, MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, 0, 0, data_cb, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-link-set.c b/deps/libmnl/examples/rtnl/rtnl-link-set.c new file mode 100644 index 0000000..6086c37 --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-link-set.c @@ -0,0 +1,84 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct ifinfomsg *ifm; + int ret; + unsigned int seq, portid, change = 0, flags = 0; + + if (argc != 3) { + printf("Usage: %s [ifname] [up|down]\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (strncasecmp(argv[2], "up", strlen("up")) == 0) { + change |= IFF_UP; + flags |= IFF_UP; + } else if (strncasecmp(argv[2], "down", strlen("down")) == 0) { + change |= IFF_UP; + flags &= ~IFF_UP; + } else { + fprintf(stderr, "%s is not `up' nor `down'\n", argv[2]); + exit(EXIT_FAILURE); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_NEWLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); + ifm->ifi_family = AF_UNSPEC; + ifm->ifi_change = change; + ifm->ifi_flags = flags; + + mnl_attr_put_str(nlh, IFLA_IFNAME, argv[1]); + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, + sizeof(struct ifinfomsg)); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret == -1){ + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-neigh-dump.c b/deps/libmnl/examples/rtnl/rtnl-neigh-dump.c new file mode 100644 index 0000000..8dd5f7e --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-neigh-dump.c @@ -0,0 +1,158 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int data_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, NDA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case NDA_DST: + case NDA_LLADDR: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[NDA_MAX + 1] = {}; + struct ndmsg *ndm = mnl_nlmsg_get_payload(nlh); + + printf("index=%d family=%d ", ndm->ndm_ifindex, ndm->ndm_family); + + mnl_attr_parse(nlh, sizeof(*ndm), data_attr_cb, tb); + printf("dst="); + if (tb[NDA_DST]) { + void *addr = mnl_attr_get_payload(tb[NDA_DST]); + char out[INET6_ADDRSTRLEN]; + + if (inet_ntop(ndm->ndm_family, addr, out, sizeof(out))) + printf("%s ", out); + } + + mnl_attr_parse(nlh, sizeof(*ndm), data_attr_cb, tb); + printf("lladdr="); + if (tb[NDA_LLADDR]) { + void *addr = mnl_attr_get_payload(tb[NDA_LLADDR]); + unsigned char lladdr[6] = {0}; + + if (memcpy(&lladdr, addr, 6)) + printf("%02x:%02x:%02x:%02x:%02x:%02x ", + lladdr[0], lladdr[1], lladdr[2], + lladdr[3], lladdr[4], lladdr[5]); + } + + printf("state="); + switch(ndm->ndm_state) { + case NUD_INCOMPLETE: + printf("incomplete "); + break; + case NUD_REACHABLE: + printf("reachable "); + break; + case NUD_STALE: + printf("stale "); + break; + case NUD_DELAY: + printf("delay "); + break; + case NUD_PROBE: + printf("probe "); + break; + case NUD_FAILED: + printf("failed "); + break; + case NUD_NOARP: + printf("noarp "); + break; + case NUD_PERMANENT: + printf("permanent "); + break; + default: + printf("%d ", ndm->ndm_state); + break; + } + + printf("\n"); + return MNL_CB_OK; +} + +int main(int argc, char *argv[]) +{ + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct ndmsg *nd; + int ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETNEIGH; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + + nd = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ndmsg)); + if (strcmp(argv[1], "inet") == 0) + nd->ndm_family = AF_INET; + else if (strcmp(argv[1], "inet6") == 0) + nd->ndm_family = AF_INET6; + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-route-add.c b/deps/libmnl/examples/rtnl/rtnl-route-add.c new file mode 100644 index 0000000..97578cd --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-route-add.c @@ -0,0 +1,127 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct rtmsg *rtm; + uint32_t prefix, seq, portid; + union { + in_addr_t ip; + struct in6_addr ip6; + } dst; + union { + in_addr_t ip; + struct in6_addr ip6; + } gw; + int iface, ret, family = AF_INET; + + if (argc <= 3) { + printf("Usage: %s iface destination cidr [gateway]\n", argv[0]); + printf("Example: %s eth0 10.0.1.12 32 10.0.1.11\n", argv[0]); + printf(" %s eth0 ffff::10.0.1.12 128 fdff::1\n", argv[0]); + exit(EXIT_FAILURE); + } + + iface = if_nametoindex(argv[1]); + if (iface == 0) { + perror("if_nametoindex"); + exit(EXIT_FAILURE); + } + + if (!inet_pton(AF_INET, argv[2], &dst)) { + if (!inet_pton(AF_INET6, argv[2], &dst)) { + perror("inet_pton"); + exit(EXIT_FAILURE); + } + family = AF_INET6; + } + + if (sscanf(argv[3], "%u", &prefix) == 0) { + perror("sscanf"); + exit(EXIT_FAILURE); + } + + if (argc == 5 && !inet_pton(family, argv[4], &gw)) { + perror("inet_pton"); + exit(EXIT_FAILURE); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_NEWROUTE; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + + rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg)); + rtm->rtm_family = family; + rtm->rtm_dst_len = prefix; + rtm->rtm_src_len = 0; + rtm->rtm_tos = 0; + rtm->rtm_protocol = RTPROT_STATIC; + rtm->rtm_table = RT_TABLE_MAIN; + rtm->rtm_type = RTN_UNICAST; + /* is there any gateway? */ + rtm->rtm_scope = (argc == 4) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + rtm->rtm_flags = 0; + + if (family == AF_INET) + mnl_attr_put_u32(nlh, RTA_DST, dst.ip); + else + mnl_attr_put(nlh, RTA_DST, sizeof(struct in6_addr), &dst); + + mnl_attr_put_u32(nlh, RTA_OIF, iface); + if (argc == 5) { + if (family == AF_INET) + mnl_attr_put_u32(nlh, RTA_GATEWAY, gw.ip); + else { + mnl_attr_put(nlh, RTA_GATEWAY, sizeof(struct in6_addr), + &gw.ip6); + } + } + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret < 0) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret < 0) { + perror("mnl_cb_run"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-route-dump.c b/deps/libmnl/examples/rtnl/rtnl-route-dump.c new file mode 100644 index 0000000..02ac6b2 --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-route-dump.c @@ -0,0 +1,356 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int data_attr_cb2(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + + /* skip unsupported attribute in user-space */ + if (mnl_attr_type_valid(attr, RTAX_MAX) < 0) + return MNL_CB_OK; + + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + + tb[mnl_attr_get_type(attr)] = attr; + return MNL_CB_OK; +} + +static void attributes_show_ipv4(struct nlattr *tb[]) +{ + if (tb[RTA_TABLE]) { + printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE])); + } + if (tb[RTA_DST]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_DST]); + printf("dst=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_SRC]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]); + printf("src=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_OIF]) { + printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF])); + } + if (tb[RTA_FLOW]) { + printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW])); + } + if (tb[RTA_PREFSRC]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]); + printf("prefsrc=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_GATEWAY]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]); + printf("gw=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_PRIORITY]) { + printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY])); + } + if (tb[RTA_METRICS]) { + int i; + struct nlattr *tbx[RTAX_MAX+1] = {}; + + mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx); + + for (i=0; irtm_family); + + /* destination CIDR, eg. 24 or 32 for IPv4 */ + printf("dst_len=%u ", rm->rtm_dst_len); + + /* source CIDR */ + printf("src_len=%u ", rm->rtm_src_len); + + /* type of service (TOS), eg. 0 */ + printf("tos=%u ", rm->rtm_tos); + + /* table id: + * RT_TABLE_UNSPEC = 0 + * + * ... user defined values ... + * + * RT_TABLE_COMPAT = 252 + * RT_TABLE_DEFAULT = 253 + * RT_TABLE_MAIN = 254 + * RT_TABLE_LOCAL = 255 + * RT_TABLE_MAX = 0xFFFFFFFF + * + * Synonimous attribute: RTA_TABLE. + */ + printf("table=%u ", rm->rtm_table); + + /* type: + * RTN_UNSPEC = 0 + * RTN_UNICAST = 1 + * RTN_LOCAL = 2 + * RTN_BROADCAST = 3 + * RTN_ANYCAST = 4 + * RTN_MULTICAST = 5 + * RTN_BLACKHOLE = 6 + * RTN_UNREACHABLE = 7 + * RTN_PROHIBIT = 8 + * RTN_THROW = 9 + * RTN_NAT = 10 + * RTN_XRESOLVE = 11 + * __RTN_MAX = 12 + */ + printf("type=%u ", rm->rtm_type); + + /* scope: + * RT_SCOPE_UNIVERSE = 0 : everywhere in the universe + * + * ... user defined values ... + * + * RT_SCOPE_SITE = 200 + * RT_SCOPE_LINK = 253 : destination attached to link + * RT_SCOPE_HOST = 254 : local address + * RT_SCOPE_NOWHERE = 255 : not existing destination + */ + printf("scope=%u ", rm->rtm_scope); + + /* protocol: + * RTPROT_UNSPEC = 0 + * RTPROT_REDIRECT = 1 + * RTPROT_KERNEL = 2 : route installed by kernel + * RTPROT_BOOT = 3 : route installed during boot + * RTPROT_STATIC = 4 : route installed by administrator + * + * Values >= RTPROT_STATIC are not interpreted by kernel, they are + * just user-defined. + */ + printf("proto=%u ", rm->rtm_protocol); + + /* flags: + * RTM_F_NOTIFY = 0x100: notify user of route change + * RTM_F_CLONED = 0x200: this route is cloned + * RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI + * RTM_F_PREFIX = 0x800: Prefix addresses + */ + printf("flags=%x ", rm->rtm_flags); + + switch(rm->rtm_family) { + case AF_INET: + mnl_attr_parse(nlh, sizeof(*rm), data_ipv4_attr_cb, tb); + attributes_show_ipv4(tb); + break; + case AF_INET6: + mnl_attr_parse(nlh, sizeof(*rm), data_ipv6_attr_cb, tb); + attributes_show_ipv6(tb); + break; + } + + printf("\n"); + return MNL_CB_OK; +} + +int main(int argc, char *argv[]) +{ + char buf[MNL_SOCKET_DUMP_SIZE]; + unsigned int seq, portid; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct rtmsg *rtm; + int ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETROUTE; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg)); + + if (strcmp(argv[1], "inet") == 0) + rtm->rtm_family = AF_INET; + else if (strcmp(argv[1], "inet6") == 0) + rtm->rtm_family = AF_INET6; + + nl = mnl_socket_open(NETLINK_ROUTE); + 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); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_sendto"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/examples/rtnl/rtnl-route-event.c b/deps/libmnl/examples/rtnl/rtnl-route-event.c new file mode 100644 index 0000000..6cad9f0 --- /dev/null +++ b/deps/libmnl/examples/rtnl/rtnl-route-event.c @@ -0,0 +1,341 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int data_attr_cb2(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + + /* skip unsupported attribute in user-space */ + if (mnl_attr_type_valid(attr, RTAX_MAX) < 0) + return MNL_CB_OK; + + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + + tb[mnl_attr_get_type(attr)] = attr; + return MNL_CB_OK; +} + +static void attributes_show_ipv4(struct nlattr *tb[]) +{ + if (tb[RTA_TABLE]) { + printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE])); + } + if (tb[RTA_DST]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_DST]); + printf("dst=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_SRC]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]); + printf("src=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_OIF]) { + printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF])); + } + if (tb[RTA_FLOW]) { + printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW])); + } + if (tb[RTA_PREFSRC]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]); + printf("prefsrc=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_GATEWAY]) { + struct in_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]); + printf("gw=%s ", inet_ntoa(*addr)); + } + if (tb[RTA_PRIORITY]) { + printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY])); + } + if (tb[RTA_METRICS]) { + int i; + struct nlattr *tbx[RTAX_MAX+1] = {}; + + mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx); + + for (i=0; inlmsg_type) { + case RTM_NEWROUTE: + printf("[NEW] "); + break; + case RTM_DELROUTE: + printf("[DEL] "); + break; + } + + /* protocol family = AF_INET | AF_INET6 */ + printf("family=%u ", rm->rtm_family); + + /* destination CIDR, eg. 24 or 32 for IPv4 */ + printf("dst_len=%u ", rm->rtm_dst_len); + + /* source CIDR */ + printf("src_len=%u ", rm->rtm_src_len); + + /* type of service (TOS), eg. 0 */ + printf("tos=%u ", rm->rtm_tos); + + /* table id: + * RT_TABLE_UNSPEC = 0 + * + * ... user defined values ... + * + * RT_TABLE_COMPAT = 252 + * RT_TABLE_DEFAULT = 253 + * RT_TABLE_MAIN = 254 + * RT_TABLE_LOCAL = 255 + * RT_TABLE_MAX = 0xFFFFFFFF + * + * Synonimous attribute: RTA_TABLE. + */ + printf("table=%u ", rm->rtm_table); + + /* type: + * RTN_UNSPEC = 0 + * RTN_UNICAST = 1 + * RTN_LOCAL = 2 + * RTN_BROADCAST = 3 + * RTN_ANYCAST = 4 + * RTN_MULTICAST = 5 + * RTN_BLACKHOLE = 6 + * RTN_UNREACHABLE = 7 + * RTN_PROHIBIT = 8 + * RTN_THROW = 9 + * RTN_NAT = 10 + * RTN_XRESOLVE = 11 + * __RTN_MAX = 12 + */ + printf("type=%u ", rm->rtm_type); + + /* scope: + * RT_SCOPE_UNIVERSE = 0 : everywhere in the universe + * + * ... user defined values ... + * + * RT_SCOPE_SITE = 200 + * RT_SCOPE_LINK = 253 : destination attached to link + * RT_SCOPE_HOST = 254 : local address + * RT_SCOPE_NOWHERE = 255 : not existing destination + */ + printf("scope=%u ", rm->rtm_scope); + + /* protocol: + * RTPROT_UNSPEC = 0 + * RTPROT_REDIRECT = 1 + * RTPROT_KERNEL = 2 : route installed by kernel + * RTPROT_BOOT = 3 : route installed during boot + * RTPROT_STATIC = 4 : route installed by administrator + * + * Values >= RTPROT_STATIC are not interpreted by kernel, they are + * just user-defined. + */ + printf("proto=%u ", rm->rtm_protocol); + + /* flags: + * RTM_F_NOTIFY = 0x100: notify user of route change + * RTM_F_CLONED = 0x200: this route is cloned + * RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI + * RTM_F_PREFIX = 0x800: Prefix addresses + */ + printf("flags=%x ", rm->rtm_flags); + + switch(rm->rtm_family) { + case AF_INET: + mnl_attr_parse(nlh, sizeof(*rm), data_ipv4_attr_cb, tb); + attributes_show_ipv4(tb); + break; + case AF_INET6: + mnl_attr_parse(nlh, sizeof(*rm), data_ipv6_attr_cb, tb); + attributes_show_ipv6(tb); + break; + } + + printf("\n"); + return MNL_CB_OK; +} + +int main(int argc, char *argv[]) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + int ret; + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE, + MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, 0, 0, data_cb, NULL); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + + return 0; +} diff --git a/deps/libmnl/include/Makefile.am b/deps/libmnl/include/Makefile.am new file mode 100644 index 0000000..bc92c42 --- /dev/null +++ b/deps/libmnl/include/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = libmnl linux diff --git a/deps/libmnl/include/libmnl/Makefile.am b/deps/libmnl/include/libmnl/Makefile.am new file mode 100644 index 0000000..b03f68a --- /dev/null +++ b/deps/libmnl/include/libmnl/Makefile.am @@ -0,0 +1 @@ +pkginclude_HEADERS = libmnl.h diff --git a/deps/libmnl/include/libmnl/libmnl.h b/deps/libmnl/include/libmnl/libmnl.h new file mode 100644 index 0000000..4bd0b92 --- /dev/null +++ b/deps/libmnl/include/libmnl/libmnl.h @@ -0,0 +1,202 @@ +#ifndef _LIBMNL_H_ +#define _LIBMNL_H_ + +#include +#include +#include +#include +#include /* for sa_family_t */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Netlink socket API + */ + +#define MNL_SOCKET_AUTOPID 0 +#define MNL_SOCKET_BUFFER_SIZE (sysconf(_SC_PAGESIZE) < 8192L ? sysconf(_SC_PAGESIZE) : 8192L) +#define MNL_SOCKET_DUMP_SIZE 32768 + +struct mnl_socket; + +extern struct mnl_socket *mnl_socket_open(int bus); +extern struct mnl_socket *mnl_socket_open2(int bus, int flags); +extern struct mnl_socket *mnl_socket_fdopen(int fd); +extern int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid); +extern int mnl_socket_close(struct mnl_socket *nl); +extern int mnl_socket_get_fd(const struct mnl_socket *nl); +extern unsigned int mnl_socket_get_portid(const struct mnl_socket *nl); +extern ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *req, size_t siz); +extern ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t siz); +extern int mnl_socket_setsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t len); +extern int mnl_socket_getsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t *len); + +/* + * Netlink message API + */ + +#define MNL_ALIGNTO 4 +#define MNL_ALIGN(len) (((len)+MNL_ALIGNTO-1) & ~(MNL_ALIGNTO-1)) +#define MNL_NLMSG_HDRLEN MNL_ALIGN(sizeof(struct nlmsghdr)) + +extern size_t mnl_nlmsg_size(size_t len); +extern size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh); + +/* Netlink message header builder */ +extern struct nlmsghdr *mnl_nlmsg_put_header(void *buf); +extern void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size); + +/* Netlink message iterators */ +extern bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len); +extern struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len); + +/* Netlink sequence tracking */ +extern bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq); + +/* Netlink portID checking */ +extern bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid); + +/* Netlink message getters */ +extern void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh); +extern void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset); +extern void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh); + +/* Netlink message printer */ +extern void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, size_t extra_header_size); + +/* Message batch helpers */ +struct mnl_nlmsg_batch; +extern struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t bufsiz); +extern bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b); +extern void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b); +extern size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b); +extern void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b); +extern void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b); +extern void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b); +extern bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b); + +/* + * Netlink attributes API + */ +#define MNL_ATTR_HDRLEN MNL_ALIGN(sizeof(struct nlattr)) + +/* TLV attribute getters */ +extern uint16_t mnl_attr_get_type(const struct nlattr *attr); +extern uint16_t mnl_attr_get_len(const struct nlattr *attr); +extern uint16_t mnl_attr_get_payload_len(const struct nlattr *attr); +extern void *mnl_attr_get_payload(const struct nlattr *attr); +extern uint8_t mnl_attr_get_u8(const struct nlattr *attr); +extern uint16_t mnl_attr_get_u16(const struct nlattr *attr); +extern uint32_t mnl_attr_get_u32(const struct nlattr *attr); +extern uint64_t mnl_attr_get_u64(const struct nlattr *attr); +extern const char *mnl_attr_get_str(const struct nlattr *attr); + +/* TLV attribute putters */ +extern void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data); +extern void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data); +extern void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data); +extern void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data); +extern void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data); +extern void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data); +extern void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data); + +/* TLV attribute putters with buffer boundary checkings */ +extern bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, size_t len, const void *data); +extern bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint8_t data); +extern bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint16_t data); +extern bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint32_t data); +extern bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint64_t data); +extern bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data); +extern bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data); + +/* TLV attribute nesting */ +extern struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type); +extern struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type); +extern void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start); +extern void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start); + +/* TLV validation */ +extern int mnl_attr_type_valid(const struct nlattr *attr, uint16_t maxtype); + +enum mnl_attr_data_type { + MNL_TYPE_UNSPEC, + MNL_TYPE_U8, + MNL_TYPE_U16, + MNL_TYPE_U32, + MNL_TYPE_U64, + MNL_TYPE_STRING, + MNL_TYPE_FLAG, + MNL_TYPE_MSECS, + MNL_TYPE_NESTED, + MNL_TYPE_NESTED_COMPAT, + MNL_TYPE_NUL_STRING, + MNL_TYPE_BINARY, + MNL_TYPE_MAX, +}; + +extern int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type); +extern int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t len); + +/* TLV iterators */ +extern bool mnl_attr_ok(const struct nlattr *attr, int len); +extern struct nlattr *mnl_attr_next(const struct nlattr *attr); + +#define mnl_attr_for_each(attr, nlh, offset) \ + for ((attr) = mnl_nlmsg_get_payload_offset((nlh), (offset)); \ + mnl_attr_ok((attr), (char *)mnl_nlmsg_get_payload_tail(nlh) - (char *)(attr)); \ + (attr) = mnl_attr_next(attr)) + +#define mnl_attr_for_each_nested(attr, nest) \ + for ((attr) = mnl_attr_get_payload(nest); \ + mnl_attr_ok((attr), (char *)mnl_attr_get_payload(nest) + mnl_attr_get_payload_len(nest) - (char *)(attr)); \ + (attr) = mnl_attr_next(attr)) + +#define mnl_attr_for_each_payload(payload, payload_size) \ + for ((attr) = (payload); \ + mnl_attr_ok((attr), (char *)(payload) + payload_size - (char *)(attr)); \ + (attr) = mnl_attr_next(attr)) + +/* TLV callback-based attribute parsers */ +typedef int (*mnl_attr_cb_t)(const struct nlattr *attr, void *data); + +extern int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data); +extern int mnl_attr_parse_nested(const struct nlattr *attr, mnl_attr_cb_t cb, void *data); +extern int mnl_attr_parse_payload(const void *payload, size_t payload_len, mnl_attr_cb_t cb, void *data); + +/* + * callback API + */ +#define MNL_CB_ERROR -1 +#define MNL_CB_STOP 0 +#define MNL_CB_OK 1 + +typedef int (*mnl_cb_t)(const struct nlmsghdr *nlh, void *data); + +extern int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, + unsigned int portid, mnl_cb_t cb_data, void *data); + +extern int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq, + unsigned int portid, mnl_cb_t cb_data, void *data, + const mnl_cb_t *cb_ctl_array, + unsigned int cb_ctl_array_len); + +/* + * other declarations + */ + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +#ifndef MNL_ARRAY_SIZE +#define MNL_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/deps/libmnl/include/linux/Makefile.am b/deps/libmnl/include/linux/Makefile.am new file mode 100644 index 0000000..ee0993d --- /dev/null +++ b/deps/libmnl/include/linux/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = can netfilter +noinst_HEADERS = can.h netlink.h socket.h diff --git a/deps/libmnl/include/linux/can.h b/deps/libmnl/include/linux/can.h new file mode 100644 index 0000000..2c6a3ee --- /dev/null +++ b/deps/libmnl/include/linux/can.h @@ -0,0 +1,298 @@ +/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * linux/can.h + * + * Definitions for CAN network layer (socket addr / CAN frame / CAN filter) + * + * Authors: Oliver Hartkopp + * Urs Thuermann + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _UAPI_CAN_H +#define _UAPI_CAN_H + +#include +#include +#include /* for offsetof */ + +/* controller area network (CAN) kernel definitions */ + +/* special address description flags for the CAN_ID */ +#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */ +#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */ +#define CAN_ERR_FLAG 0x20000000U /* error message frame */ + +/* valid bits in CAN ID for frame formats */ +#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */ +#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */ +#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */ +#define CANXL_PRIO_MASK CAN_SFF_MASK /* 11 bit priority mask */ + +/* + * Controller Area Network Identifier structure + * + * bit 0-28 : CAN identifier (11/29 bit) + * bit 29 : error message frame flag (0 = data frame, 1 = error message) + * bit 30 : remote transmission request flag (1 = rtr frame) + * bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit) + */ +typedef __u32 canid_t; + +#define CAN_SFF_ID_BITS 11 +#define CAN_EFF_ID_BITS 29 +#define CANXL_PRIO_BITS CAN_SFF_ID_BITS + +/* + * Controller Area Network Error Message Frame Mask structure + * + * bit 0-28 : error class mask (see include/uapi/linux/can/error.h) + * bit 29-31 : set to zero + */ +typedef __u32 can_err_mask_t; + +/* CAN payload length and DLC definitions according to ISO 11898-1 */ +#define CAN_MAX_DLC 8 +#define CAN_MAX_RAW_DLC 15 +#define CAN_MAX_DLEN 8 + +/* CAN FD payload length and DLC definitions according to ISO 11898-7 */ +#define CANFD_MAX_DLC 15 +#define CANFD_MAX_DLEN 64 + +/* + * CAN XL payload length and DLC definitions according to ISO 11898-1 + * CAN XL DLC ranges from 0 .. 2047 => data length from 1 .. 2048 byte + */ +#define CANXL_MIN_DLC 0 +#define CANXL_MAX_DLC 2047 +#define CANXL_MAX_DLC_MASK 0x07FF +#define CANXL_MIN_DLEN 1 +#define CANXL_MAX_DLEN 2048 + +/** + * struct can_frame - Classical CAN frame structure (aka CAN 2.0B) + * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition + * @len: CAN frame payload length in byte (0 .. 8) + * @can_dlc: deprecated name for CAN frame payload length in byte (0 .. 8) + * @__pad: padding + * @__res0: reserved / padding + * @len8_dlc: optional DLC value (9 .. 15) at 8 byte payload length + * len8_dlc contains values from 9 .. 15 when the payload length is + * 8 bytes but the DLC value (see ISO 11898-1) is greater then 8. + * CAN_CTRLMODE_CC_LEN8_DLC flag has to be enabled in CAN driver. + * @data: CAN frame payload (up to 8 byte) + */ +struct can_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + union { + /* CAN frame payload length in byte (0 .. CAN_MAX_DLEN) + * was previously named can_dlc so we need to carry that + * name for legacy support + */ + __u8 len; + __u8 can_dlc; /* deprecated */ + } __attribute__((packed)); /* disable padding added in some ABIs */ + __u8 __pad; /* padding */ + __u8 __res0; /* reserved / padding */ + __u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */ + __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8))); +}; + +/* + * defined bits for canfd_frame.flags + * + * The use of struct canfd_frame implies the FD Frame (FDF) bit to + * be set in the CAN frame bitstream on the wire. The FDF bit switch turns + * the CAN controllers bitstream processor into the CAN FD mode which creates + * two new options within the CAN FD frame specification: + * + * Bit Rate Switch - to indicate a second bitrate is/was used for the payload + * Error State Indicator - represents the error state of the transmitting node + * + * As the CANFD_ESI bit is internally generated by the transmitting CAN + * controller only the CANFD_BRS bit is relevant for real CAN controllers when + * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make + * sense for virtual CAN interfaces to test applications with echoed frames. + * + * The struct can_frame and struct canfd_frame intentionally share the same + * layout to be able to write CAN frame content into a CAN FD frame structure. + * When this is done the former differentiation via CAN_MTU / CANFD_MTU gets + * lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of + * using struct canfd_frame for mixed CAN / CAN FD content (dual use). + * Since the introduction of CAN XL the CANFD_FDF flag is set in all CAN FD + * frame structures provided by the CAN subsystem of the Linux kernel. + */ +#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */ +#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */ +#define CANFD_FDF 0x04 /* mark CAN FD for dual use of struct canfd_frame */ + +/** + * struct canfd_frame - CAN flexible data rate frame structure + * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition + * @len: frame payload length in byte (0 .. CANFD_MAX_DLEN) + * @flags: additional flags for CAN FD + * @__res0: reserved / padding + * @__res1: reserved / padding + * @data: CAN FD frame payload (up to CANFD_MAX_DLEN byte) + */ +struct canfd_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + __u8 len; /* frame payload length in byte */ + __u8 flags; /* additional flags for CAN FD */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ + __u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8))); +}; + +/* + * defined bits for canxl_frame.flags + * + * The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC + * and shares the relative position of the struct can[fd]_frame.len element. + * The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame. + * As a side effect setting this bit intentionally breaks the length checks + * for Classical CAN and CAN FD frames. + * + * Undefined bits in canxl_frame.flags are reserved and shall be set to zero. + */ +#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */ +#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */ + +/** + * struct canxl_frame - CAN with e'X'tended frame 'L'ength frame structure + * @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags + * @flags: additional flags for CAN XL + * @sdt: SDU (service data unit) type + * @len: frame payload length in byte (CANXL_MIN_DLEN .. CANXL_MAX_DLEN) + * @af: acceptance field + * @data: CAN XL frame payload (CANXL_MIN_DLEN .. CANXL_MAX_DLEN byte) + * + * @prio shares the same position as @can_id from struct can[fd]_frame. + */ +struct canxl_frame { + canid_t prio; /* 11 bit priority for arbitration (canid_t) */ + __u8 flags; /* additional flags for CAN XL */ + __u8 sdt; /* SDU (service data unit) type */ + __u16 len; /* frame payload length in byte */ + __u32 af; /* acceptance field */ + __u8 data[CANXL_MAX_DLEN]; +}; + +#define CAN_MTU (sizeof(struct can_frame)) +#define CANFD_MTU (sizeof(struct canfd_frame)) +#define CANXL_MTU (sizeof(struct canxl_frame)) +#define CANXL_HDR_SIZE (offsetof(struct canxl_frame, data)) +#define CANXL_MIN_MTU (CANXL_HDR_SIZE + 64) +#define CANXL_MAX_MTU CANXL_MTU + +/* particular protocols of the protocol family PF_CAN */ +#define CAN_RAW 1 /* RAW sockets */ +#define CAN_BCM 2 /* Broadcast Manager */ +#define CAN_TP16 3 /* VAG Transport Protocol v1.6 */ +#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */ +#define CAN_MCNET 5 /* Bosch MCNet */ +#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */ +#define CAN_J1939 7 /* SAE J1939 */ +#define CAN_NPROTO 8 + +#define SOL_CAN_BASE 100 + +/* + * This typedef was introduced in Linux v3.1-rc2 + * (commit 6602a4b net: Make userland include of netlink.h more sane) + * in . It must be duplicated here to make the CAN + * headers self-contained. + */ +typedef unsigned short __kernel_sa_family_t; + +/** + * struct sockaddr_can - the sockaddr structure for CAN sockets + * @can_family: address family number AF_CAN. + * @can_ifindex: CAN network interface index. + * @can_addr: protocol specific address information + */ +struct sockaddr_can { + __kernel_sa_family_t can_family; + int can_ifindex; + union { + /* transport protocol class address information (e.g. ISOTP) */ + struct { canid_t rx_id, tx_id; } tp; + + /* J1939 address information */ + struct { + /* 8 byte name when using dynamic addressing */ + __u64 name; + + /* pgn: + * 8 bit: PS in PDU2 case, else 0 + * 8 bit: PF + * 1 bit: DP + * 1 bit: reserved + */ + __u32 pgn; + + /* 1 byte address */ + __u8 addr; + } j1939; + + /* reserved for future CAN protocols address information */ + } can_addr; +}; + +/** + * struct can_filter - CAN ID based filter in can_register(). + * @can_id: relevant bits of CAN ID which are not masked out. + * @can_mask: CAN mask (see description) + * + * Description: + * A filter matches, when + * + * & mask == can_id & mask + * + * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can + * filter for error message frames (CAN_ERR_FLAG bit set in mask). + */ +struct can_filter { + canid_t can_id; + canid_t can_mask; +}; + +#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ +#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ + +#endif /* !_UAPI_CAN_H */ diff --git a/deps/libmnl/include/linux/can/Makefile.am b/deps/libmnl/include/linux/can/Makefile.am new file mode 100644 index 0000000..2d02887 --- /dev/null +++ b/deps/libmnl/include/linux/can/Makefile.am @@ -0,0 +1 @@ +noinst_HEADERS = netlink.h diff --git a/deps/libmnl/include/linux/can/netlink.h b/deps/libmnl/include/linux/can/netlink.h new file mode 100644 index 0000000..02ec32d --- /dev/null +++ b/deps/libmnl/include/linux/can/netlink.h @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * linux/can/netlink.h + * + * Definitions for the CAN netlink interface + * + * Copyright (c) 2009 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * 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. + */ + +#ifndef _UAPI_CAN_NETLINK_H +#define _UAPI_CAN_NETLINK_H + +#include + +/* + * CAN bit-timing parameters + * + * For further information, please read chapter "8 BIT TIMING + * REQUIREMENTS" of the "Bosch CAN Specification version 2.0" + * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf. + */ +struct can_bittiming { + __u32 bitrate; /* Bit-rate in bits/second */ + __u32 sample_point; /* Sample point in one-tenth of a percent */ + __u32 tq; /* Time quanta (TQ) in nanoseconds */ + __u32 prop_seg; /* Propagation segment in TQs */ + __u32 phase_seg1; /* Phase buffer segment 1 in TQs */ + __u32 phase_seg2; /* Phase buffer segment 2 in TQs */ + __u32 sjw; /* Synchronisation jump width in TQs */ + __u32 brp; /* Bit-rate prescaler */ +}; + +/* + * CAN hardware-dependent bit-timing constant + * + * Used for calculating and checking bit-timing parameters + */ +struct can_bittiming_const { + char name[16]; /* Name of the CAN controller hardware */ + __u32 tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */ + __u32 tseg1_max; + __u32 tseg2_min; /* Time segment 2 = phase_seg2 */ + __u32 tseg2_max; + __u32 sjw_max; /* Synchronisation jump width */ + __u32 brp_min; /* Bit-rate prescaler */ + __u32 brp_max; + __u32 brp_inc; +}; + +/* + * CAN clock parameters + */ +struct can_clock { + __u32 freq; /* CAN system clock frequency in Hz */ +}; + +/* + * CAN operational and error states + */ +enum can_state { + CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */ + CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */ + CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */ + CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */ + CAN_STATE_STOPPED, /* Device is stopped */ + CAN_STATE_SLEEPING, /* Device is sleeping */ + CAN_STATE_MAX +}; + +/* + * CAN bus error counters + */ +struct can_berr_counter { + __u16 txerr; + __u16 rxerr; +}; + +/* + * CAN controller mode + */ +struct can_ctrlmode { + __u32 mask; + __u32 flags; +}; + +#define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */ +#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ +#define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ +#define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ +#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ +#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ +#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ +#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ +#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ +#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */ +#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */ + +/* + * CAN device statistics + */ +struct can_device_stats { + __u32 bus_error; /* Bus errors */ + __u32 error_warning; /* Changes to error warning state */ + __u32 error_passive; /* Changes to error passive state */ + __u32 bus_off; /* Changes to bus off state */ + __u32 arbitration_lost; /* Arbitration lost errors */ + __u32 restarts; /* CAN controller re-starts */ +}; + +/* + * CAN netlink interface + */ +enum { + IFLA_CAN_UNSPEC, + IFLA_CAN_BITTIMING, + IFLA_CAN_BITTIMING_CONST, + IFLA_CAN_CLOCK, + IFLA_CAN_STATE, + IFLA_CAN_CTRLMODE, + IFLA_CAN_RESTART_MS, + IFLA_CAN_RESTART, + IFLA_CAN_BERR_COUNTER, + IFLA_CAN_DATA_BITTIMING, + IFLA_CAN_DATA_BITTIMING_CONST, + IFLA_CAN_TERMINATION, + IFLA_CAN_TERMINATION_CONST, + IFLA_CAN_BITRATE_CONST, + IFLA_CAN_DATA_BITRATE_CONST, + IFLA_CAN_BITRATE_MAX, + IFLA_CAN_TDC, + IFLA_CAN_CTRLMODE_EXT, + + /* add new constants above here */ + __IFLA_CAN_MAX, + IFLA_CAN_MAX = __IFLA_CAN_MAX - 1 +}; + +/* + * CAN FD Transmitter Delay Compensation (TDC) + * + * Please refer to struct can_tdc_const and can_tdc in + * include/linux/can/bittiming.h for further details. + */ +enum { + IFLA_CAN_TDC_UNSPEC, + IFLA_CAN_TDC_TDCV_MIN, /* u32 */ + IFLA_CAN_TDC_TDCV_MAX, /* u32 */ + IFLA_CAN_TDC_TDCO_MIN, /* u32 */ + IFLA_CAN_TDC_TDCO_MAX, /* u32 */ + IFLA_CAN_TDC_TDCF_MIN, /* u32 */ + IFLA_CAN_TDC_TDCF_MAX, /* u32 */ + IFLA_CAN_TDC_TDCV, /* u32 */ + IFLA_CAN_TDC_TDCO, /* u32 */ + IFLA_CAN_TDC_TDCF, /* u32 */ + + /* add new constants above here */ + __IFLA_CAN_TDC, + IFLA_CAN_TDC_MAX = __IFLA_CAN_TDC - 1 +}; + +/* + * IFLA_CAN_CTRLMODE_EXT nest: controller mode extended parameters + */ +enum { + IFLA_CAN_CTRLMODE_UNSPEC, + IFLA_CAN_CTRLMODE_SUPPORTED, /* u32 */ + + /* add new constants above here */ + __IFLA_CAN_CTRLMODE, + IFLA_CAN_CTRLMODE_MAX = __IFLA_CAN_CTRLMODE - 1 +}; + +/* u16 termination range: 1..65535 Ohms */ +#define CAN_TERMINATION_DISABLED 0 + +#endif /* !_UAPI_CAN_NETLINK_H */ diff --git a/deps/libmnl/include/linux/netfilter/Makefile.am b/deps/libmnl/include/linux/netfilter/Makefile.am new file mode 100644 index 0000000..64a975e --- /dev/null +++ b/deps/libmnl/include/linux/netfilter/Makefile.am @@ -0,0 +1 @@ +noinst_HEADERS = nfnetlink_conntrack.h diff --git a/deps/libmnl/include/linux/netfilter/nfnetlink_conntrack.h b/deps/libmnl/include/linux/netfilter/nfnetlink_conntrack.h new file mode 100644 index 0000000..08fabc6 --- /dev/null +++ b/deps/libmnl/include/linux/netfilter/nfnetlink_conntrack.h @@ -0,0 +1,252 @@ +#ifndef _IPCONNTRACK_NETLINK_H +#define _IPCONNTRACK_NETLINK_H +#include + +enum cntl_msg_types { + IPCTNL_MSG_CT_NEW, + IPCTNL_MSG_CT_GET, + IPCTNL_MSG_CT_DELETE, + IPCTNL_MSG_CT_GET_CTRZERO, + IPCTNL_MSG_CT_GET_STATS_CPU, + IPCTNL_MSG_CT_GET_STATS, + IPCTNL_MSG_CT_GET_DYING, + IPCTNL_MSG_CT_GET_UNCONFIRMED, + + IPCTNL_MSG_MAX +}; + +enum ctnl_exp_msg_types { + IPCTNL_MSG_EXP_NEW, + IPCTNL_MSG_EXP_GET, + IPCTNL_MSG_EXP_DELETE, + IPCTNL_MSG_EXP_GET_STATS_CPU, + + IPCTNL_MSG_EXP_MAX +}; + + +enum ctattr_type { + CTA_UNSPEC, + CTA_TUPLE_ORIG, + CTA_TUPLE_REPLY, + CTA_STATUS, + CTA_PROTOINFO, + CTA_HELP, + CTA_NAT_SRC, +#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */ + CTA_TIMEOUT, + CTA_MARK, + CTA_COUNTERS_ORIG, + CTA_COUNTERS_REPLY, + CTA_USE, + CTA_ID, + CTA_NAT_DST, + CTA_TUPLE_MASTER, + CTA_NAT_SEQ_ADJ_ORIG, + CTA_NAT_SEQ_ADJ_REPLY, + CTA_SECMARK, /* obsolete */ + CTA_ZONE, + CTA_SECCTX, + CTA_TIMESTAMP, + CTA_MARK_MASK, + CTA_LABELS, + CTA_LABELS_MASK, + __CTA_MAX +}; +#define CTA_MAX (__CTA_MAX - 1) + +enum ctattr_tuple { + CTA_TUPLE_UNSPEC, + CTA_TUPLE_IP, + CTA_TUPLE_PROTO, + __CTA_TUPLE_MAX +}; +#define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1) + +enum ctattr_ip { + CTA_IP_UNSPEC, + CTA_IP_V4_SRC, + CTA_IP_V4_DST, + CTA_IP_V6_SRC, + CTA_IP_V6_DST, + __CTA_IP_MAX +}; +#define CTA_IP_MAX (__CTA_IP_MAX - 1) + +enum ctattr_l4proto { + CTA_PROTO_UNSPEC, + CTA_PROTO_NUM, + CTA_PROTO_SRC_PORT, + CTA_PROTO_DST_PORT, + CTA_PROTO_ICMP_ID, + CTA_PROTO_ICMP_TYPE, + CTA_PROTO_ICMP_CODE, + CTA_PROTO_ICMPV6_ID, + CTA_PROTO_ICMPV6_TYPE, + CTA_PROTO_ICMPV6_CODE, + __CTA_PROTO_MAX +}; +#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1) + +enum ctattr_protoinfo { + CTA_PROTOINFO_UNSPEC, + CTA_PROTOINFO_TCP, + CTA_PROTOINFO_DCCP, + CTA_PROTOINFO_SCTP, + __CTA_PROTOINFO_MAX +}; +#define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1) + +enum ctattr_protoinfo_tcp { + CTA_PROTOINFO_TCP_UNSPEC, + CTA_PROTOINFO_TCP_STATE, + CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, + CTA_PROTOINFO_TCP_WSCALE_REPLY, + CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, + CTA_PROTOINFO_TCP_FLAGS_REPLY, + __CTA_PROTOINFO_TCP_MAX +}; +#define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1) + +enum ctattr_protoinfo_dccp { + CTA_PROTOINFO_DCCP_UNSPEC, + CTA_PROTOINFO_DCCP_STATE, + CTA_PROTOINFO_DCCP_ROLE, + CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, + __CTA_PROTOINFO_DCCP_MAX, +}; +#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1) + +enum ctattr_protoinfo_sctp { + CTA_PROTOINFO_SCTP_UNSPEC, + CTA_PROTOINFO_SCTP_STATE, + CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, + CTA_PROTOINFO_SCTP_VTAG_REPLY, + __CTA_PROTOINFO_SCTP_MAX +}; +#define CTA_PROTOINFO_SCTP_MAX (__CTA_PROTOINFO_SCTP_MAX - 1) + +enum ctattr_counters { + CTA_COUNTERS_UNSPEC, + CTA_COUNTERS_PACKETS, /* 64bit counters */ + CTA_COUNTERS_BYTES, /* 64bit counters */ + CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */ + CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */ + __CTA_COUNTERS_MAX +}; +#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1) + +enum ctattr_tstamp { + CTA_TIMESTAMP_UNSPEC, + CTA_TIMESTAMP_START, + CTA_TIMESTAMP_STOP, + __CTA_TIMESTAMP_MAX +}; +#define CTA_TIMESTAMP_MAX (__CTA_TIMESTAMP_MAX - 1) + +enum ctattr_nat { + CTA_NAT_UNSPEC, + CTA_NAT_V4_MINIP, +#define CTA_NAT_MINIP CTA_NAT_V4_MINIP + CTA_NAT_V4_MAXIP, +#define CTA_NAT_MAXIP CTA_NAT_V4_MAXIP + CTA_NAT_PROTO, + CTA_NAT_V6_MINIP, + CTA_NAT_V6_MAXIP, + __CTA_NAT_MAX +}; +#define CTA_NAT_MAX (__CTA_NAT_MAX - 1) + +enum ctattr_protonat { + CTA_PROTONAT_UNSPEC, + CTA_PROTONAT_PORT_MIN, + CTA_PROTONAT_PORT_MAX, + __CTA_PROTONAT_MAX +}; +#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1) + +enum ctattr_natseq { + CTA_NAT_SEQ_UNSPEC, + CTA_NAT_SEQ_CORRECTION_POS, + CTA_NAT_SEQ_OFFSET_BEFORE, + CTA_NAT_SEQ_OFFSET_AFTER, + __CTA_NAT_SEQ_MAX +}; +#define CTA_NAT_SEQ_MAX (__CTA_NAT_SEQ_MAX - 1) + +enum ctattr_expect { + CTA_EXPECT_UNSPEC, + CTA_EXPECT_MASTER, + CTA_EXPECT_TUPLE, + CTA_EXPECT_MASK, + CTA_EXPECT_TIMEOUT, + CTA_EXPECT_ID, + CTA_EXPECT_HELP_NAME, + CTA_EXPECT_ZONE, + CTA_EXPECT_FLAGS, + CTA_EXPECT_CLASS, + CTA_EXPECT_NAT, + CTA_EXPECT_FN, + __CTA_EXPECT_MAX +}; +#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) + +enum ctattr_expect_nat { + CTA_EXPECT_NAT_UNSPEC, + CTA_EXPECT_NAT_DIR, + CTA_EXPECT_NAT_TUPLE, + __CTA_EXPECT_NAT_MAX +}; +#define CTA_EXPECT_NAT_MAX (__CTA_EXPECT_NAT_MAX - 1) + +enum ctattr_help { + CTA_HELP_UNSPEC, + CTA_HELP_NAME, + CTA_HELP_INFO, + __CTA_HELP_MAX +}; +#define CTA_HELP_MAX (__CTA_HELP_MAX - 1) + +enum ctattr_secctx { + CTA_SECCTX_UNSPEC, + CTA_SECCTX_NAME, + __CTA_SECCTX_MAX +}; +#define CTA_SECCTX_MAX (__CTA_SECCTX_MAX - 1) + +enum ctattr_stats_cpu { + CTA_STATS_UNSPEC, + CTA_STATS_SEARCHED, + CTA_STATS_FOUND, + CTA_STATS_NEW, + CTA_STATS_INVALID, + CTA_STATS_IGNORE, + CTA_STATS_DELETE, + CTA_STATS_DELETE_LIST, + CTA_STATS_INSERT, + CTA_STATS_INSERT_FAILED, + CTA_STATS_DROP, + CTA_STATS_EARLY_DROP, + CTA_STATS_ERROR, + CTA_STATS_SEARCH_RESTART, + __CTA_STATS_MAX, +}; +#define CTA_STATS_MAX (__CTA_STATS_MAX - 1) + +enum ctattr_stats_global { + CTA_STATS_GLOBAL_UNSPEC, + CTA_STATS_GLOBAL_ENTRIES, + __CTA_STATS_GLOBAL_MAX, +}; +#define CTA_STATS_GLOBAL_MAX (__CTA_STATS_GLOBAL_MAX - 1) + +enum ctattr_expect_stats { + CTA_STATS_EXP_UNSPEC, + CTA_STATS_EXP_NEW, + CTA_STATS_EXP_CREATE, + CTA_STATS_EXP_DELETE, + __CTA_STATS_EXP_MAX, +}; +#define CTA_STATS_EXP_MAX (__CTA_STATS_EXP_MAX - 1) + +#endif /* _IPCONNTRACK_NETLINK_H */ diff --git a/deps/libmnl/include/linux/netlink.h b/deps/libmnl/include/linux/netlink.h new file mode 100644 index 0000000..ced0e1a --- /dev/null +++ b/deps/libmnl/include/linux/netlink.h @@ -0,0 +1,153 @@ +#ifndef __LINUX_NETLINK_H +#define __LINUX_NETLINK_H + +#include /* for __kernel_sa_family_t */ +#include + +#define NETLINK_ROUTE 0 /* Routing/device hook */ +#define NETLINK_UNUSED 1 /* Unused number */ +#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ +#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */ +#define NETLINK_SOCK_DIAG 4 /* socket monitoring */ +#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ +#define NETLINK_XFRM 6 /* ipsec */ +#define NETLINK_SELINUX 7 /* SELinux event notifications */ +#define NETLINK_ISCSI 8 /* Open-iSCSI */ +#define NETLINK_AUDIT 9 /* auditing */ +#define NETLINK_FIB_LOOKUP 10 +#define NETLINK_CONNECTOR 11 +#define NETLINK_NETFILTER 12 /* netfilter subsystem */ +#define NETLINK_IP6_FW 13 +#define NETLINK_DNRTMSG 14 /* DECnet routing messages */ +#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ +#define NETLINK_GENERIC 16 +/* leave room for NETLINK_DM (DM Events) */ +#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ +#define NETLINK_ECRYPTFS 19 +#define NETLINK_RDMA 20 +#define NETLINK_CRYPTO 21 /* Crypto layer */ + +#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG + +#define MAX_LINKS 32 + +struct sockaddr_nl { + __kernel_sa_family_t nl_family; /* AF_NETLINK */ + unsigned short nl_pad; /* zero */ + __u32 nl_pid; /* port ID */ + __u32 nl_groups; /* multicast groups mask */ +}; + +struct nlmsghdr { + __u32 nlmsg_len; /* Length of message including header */ + __u16 nlmsg_type; /* Message content */ + __u16 nlmsg_flags; /* Additional flags */ + __u32 nlmsg_seq; /* Sequence number */ + __u32 nlmsg_pid; /* Sending process port ID */ +}; + +/* Flags values */ + +#define NLM_F_REQUEST 1 /* It is request message. */ +#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ +#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ +#define NLM_F_ECHO 8 /* Echo this request */ +#define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */ + +/* Modifiers to GET request */ +#define NLM_F_ROOT 0x100 /* specify tree root */ +#define NLM_F_MATCH 0x200 /* return all matching */ +#define NLM_F_ATOMIC 0x400 /* atomic GET */ +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +/* Modifiers to NEW request */ +#define NLM_F_REPLACE 0x100 /* Override existing */ +#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ +#define NLM_F_CREATE 0x400 /* Create, if it does not exist */ +#define NLM_F_APPEND 0x800 /* Add to end of list */ + +/* + 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL + 4.4BSD CHANGE NLM_F_REPLACE + + True CHANGE NLM_F_CREATE|NLM_F_REPLACE + Append NLM_F_CREATE + Check NLM_F_EXCL + */ + +#define NLMSG_ALIGNTO 4U +#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) +#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) +#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) +#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ + (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) +#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len <= (len)) +#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) + +#define NLMSG_NOOP 0x1 /* Nothing. */ +#define NLMSG_ERROR 0x2 /* Error */ +#define NLMSG_DONE 0x3 /* End of a dump */ +#define NLMSG_OVERRUN 0x4 /* Data lost */ + +#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ + +struct nlmsgerr { + int error; + struct nlmsghdr msg; +}; + +#define NETLINK_ADD_MEMBERSHIP 1 +#define NETLINK_DROP_MEMBERSHIP 2 +#define NETLINK_PKTINFO 3 +#define NETLINK_BROADCAST_ERROR 4 +#define NETLINK_NO_ENOBUFS 5 + +struct nl_pktinfo { + __u32 group; +}; + +#define NET_MAJOR 36 /* Major 36 is reserved for networking */ + +enum { + NETLINK_UNCONNECTED = 0, + NETLINK_CONNECTED, +}; + +/* + * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | (struct nlattr) | ing | | ing | + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * <-------------- nlattr->nla_len --------------> + */ + +struct nlattr { + __u16 nla_len; + __u16 nla_type; +}; + +/* + * nla_type (16 bits) + * +---+---+-------------------------------+ + * | N | O | Attribute Type | + * +---+---+-------------------------------+ + * N := Carries nested attributes + * O := Payload stored in network byte order + * + * Note: The N and O flag are mutually exclusive. + */ +#define NLA_F_NESTED (1 << 15) +#define NLA_F_NET_BYTEORDER (1 << 14) +#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) + +#define NLA_ALIGNTO 4 +#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) +#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) + + +#endif /* __LINUX_NETLINK_H */ diff --git a/deps/libmnl/include/linux/socket.h b/deps/libmnl/include/linux/socket.h new file mode 100644 index 0000000..8c1e501 --- /dev/null +++ b/deps/libmnl/include/linux/socket.h @@ -0,0 +1,21 @@ +#ifndef _LINUX_SOCKET_H +#define _LINUX_SOCKET_H + +/* + * Desired design of maximum size and alignment (see RFC2553) + */ +#define _K_SS_MAXSIZE 128 /* Implementation specific max size */ +#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *)) + /* Implementation specific desired alignment */ + +typedef unsigned short __kernel_sa_family_t; + +struct __kernel_sockaddr_storage { + __kernel_sa_family_t ss_family; /* address family */ + /* Following field(s) are implementation specific */ + char __data[_K_SS_MAXSIZE - sizeof(unsigned short)]; + /* space to achieve desired size, */ + /* _SS_MAXSIZE value minus size of ss_family */ +} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */ + +#endif /* _LINUX_SOCKET_H */ diff --git a/deps/libmnl/libmnl.pc.in b/deps/libmnl/libmnl.pc.in new file mode 100644 index 0000000..8a24315 --- /dev/null +++ b/deps/libmnl/libmnl.pc.in @@ -0,0 +1,15 @@ +# libmnl pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libmnl +Description: Minimalistic Netlink communication library +URL: http://netfilter.org/projects/libmnl/ +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lmnl +Cflags: -I${includedir} diff --git a/deps/libmnl/m4/.gitignore b/deps/libmnl/m4/.gitignore new file mode 100644 index 0000000..64d9bbc --- /dev/null +++ b/deps/libmnl/m4/.gitignore @@ -0,0 +1,2 @@ +/libtool.m4 +/lt*.m4 diff --git a/deps/libmnl/m4/gcc4_visibility.m4 b/deps/libmnl/m4/gcc4_visibility.m4 new file mode 100644 index 0000000..214d3f3 --- /dev/null +++ b/deps/libmnl/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/deps/libmnl/src/Makefile.am b/deps/libmnl/src/Makefile.am new file mode 100644 index 0000000..9aab516 --- /dev/null +++ b/deps/libmnl/src/Makefile.am @@ -0,0 +1,5 @@ +include $(top_srcdir)/Make_global.am +lib_LTLIBRARIES = libmnl.la + +libmnl_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmnl.map -version-info $(LIBVERSION) +libmnl_la_SOURCES = socket.c callback.c nlmsg.c attr.c internal.h libmnl.map diff --git a/deps/libmnl/src/attr.c b/deps/libmnl/src/attr.c new file mode 100644 index 0000000..bc39df4 --- /dev/null +++ b/deps/libmnl/src/attr.c @@ -0,0 +1,742 @@ +/* + * (C) 2008-2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ +#include /* for INT_MAX */ +#include +#include +#include +#include "internal.h" + +/** + * \defgroup attr Netlink attribute helpers + * + * Netlink Type-Length-Value (TLV) attribute: + * \verbatim + |<-- 2 bytes -->|<-- 2 bytes -->|<-- variable -->| + ------------------------------------------------- + | length | type | value | + ------------------------------------------------- + |<--------- header ------------>|<-- payload --->| +\endverbatim + * The payload of the Netlink message contains sequences of attributes that are + * expressed in TLV format. + * + * @{ + */ + +/** + * mnl_attr_get_type - get type of netlink attribute + * \param attr pointer to netlink attribute + * + * \return the attribute type + */ +EXPORT_SYMBOL uint16_t mnl_attr_get_type(const struct nlattr *attr) +{ + return attr->nla_type & NLA_TYPE_MASK; +} + +/** + * mnl_attr_get_len - get length of netlink attribute + * \param attr pointer to netlink attribute + * + * \return the attribute length + * + * The attribute length is the length of the attribute header plus the + * attribute payload. + * + */ +EXPORT_SYMBOL uint16_t mnl_attr_get_len(const struct nlattr *attr) +{ + return attr->nla_len; +} + +/** + * mnl_attr_get_payload_len - get the attribute payload-value length + * \param attr pointer to netlink attribute + * + * \return the attribute payload-value length + */ +EXPORT_SYMBOL uint16_t mnl_attr_get_payload_len(const struct nlattr *attr) +{ + return attr->nla_len - MNL_ATTR_HDRLEN; +} + +/** + * mnl_attr_get_payload - get pointer to the attribute payload + * \param attr pointer to netlink attribute + * + * \return pointer to the attribute payload + */ +EXPORT_SYMBOL void *mnl_attr_get_payload(const struct nlattr *attr) +{ + return (void *)attr + MNL_ATTR_HDRLEN; +} + +/** + * mnl_attr_ok - check if there is room for an attribute in a buffer + * \param attr attribute that we want to check if there is room for + * \param len remaining bytes in a buffer that contains the attribute + * + * This function is used to check that a buffer, which is supposed to contain + * an attribute, has enough room for the attribute that it stores, i.e. this + * function can be used to verify that an attribute is neither malformed nor + * truncated. + * + * This function does not set errno in case of error since it is intended + * for iterations. + * + * The len parameter may be negative in the case of malformed messages during + * attribute iteration, that is why we use a signed integer. + * + * \return true if there is room for the attribute, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_ok(const struct nlattr *attr, int len) +{ + return len >= (int)sizeof(struct nlattr) && + attr->nla_len >= sizeof(struct nlattr) && + (int)attr->nla_len <= len; +} + +/** + * mnl_attr_next - get the next attribute in the payload of a netlink message + * \param attr pointer to the current attribute + * + * \return a pointer to the next attribute after the one passed in + * + * You have to use mnl_attr_ok() on the returned attribute to ensure that the + * next attribute is valid. + * + */ +EXPORT_SYMBOL struct nlattr *mnl_attr_next(const struct nlattr *attr) +{ + return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len)); +} + +/** + * mnl_attr_type_valid - check if the attribute type is valid + * \param attr pointer to attribute to be checked + * \param max maximum attribute type + * + * This function allows one to check if the attribute type is higher than the + * maximum supported type. + * + * Strict attribute checking in user-space is not a good idea since you may + * run an old application with a newer kernel that supports new attributes. + * This leads to backward compatibility breakages in user-space. Better check + * if you support an attribute, if not, skip it. + * + * On an error, errno is explicitly set. + * + * \return 1 if the attribute is valid, -1 otherwise + * + */ +EXPORT_SYMBOL int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max) +{ + if (mnl_attr_get_type(attr) > max) { + errno = EOPNOTSUPP; + return -1; + } + return 1; +} + +static int __mnl_attr_validate(const struct nlattr *attr, + enum mnl_attr_data_type type, size_t exp_len) +{ + uint16_t attr_len = mnl_attr_get_payload_len(attr); + const char *attr_data = mnl_attr_get_payload(attr); + + if (attr_len < exp_len) { + errno = ERANGE; + return -1; + } + switch(type) { + case MNL_TYPE_FLAG: + if (attr_len > 0) { + errno = ERANGE; + return -1; + } + break; + case MNL_TYPE_NUL_STRING: + if (attr_len == 0) { + errno = ERANGE; + return -1; + } + if (attr_data[attr_len-1] != '\0') { + errno = EINVAL; + return -1; + } + break; + case MNL_TYPE_STRING: + if (attr_len == 0) { + errno = ERANGE; + return -1; + } + break; + case MNL_TYPE_NESTED: + /* empty nested attributes are OK. */ + if (attr_len == 0) + break; + /* if not empty, they must contain one header, eg. flag */ + if (attr_len < MNL_ATTR_HDRLEN) { + errno = ERANGE; + return -1; + } + break; + default: + /* make gcc happy. */ + break; + } + if (exp_len && attr_len > exp_len) { + errno = ERANGE; + return -1; + } + return 0; +} + +static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = { + [MNL_TYPE_U8] = sizeof(uint8_t), + [MNL_TYPE_U16] = sizeof(uint16_t), + [MNL_TYPE_U32] = sizeof(uint32_t), + [MNL_TYPE_U64] = sizeof(uint64_t), + [MNL_TYPE_MSECS] = sizeof(uint64_t), +}; + +/** + * mnl_attr_validate - validate netlink attribute (simplified version) + * \param attr pointer to netlink attribute that we want to validate + * \param type data type (see enum mnl_attr_data_type) + * + * The validation is based on the data type. Specifically, it checks that + * integers (u8, u16, u32 and u64) have enough room for them. + * + * On an error, errno is explicitly set. + * + * \return 0 on success, -1 on error + */ +EXPORT_SYMBOL int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type) +{ + int exp_len; + + if (type >= MNL_TYPE_MAX) { + errno = EINVAL; + return -1; + } + exp_len = mnl_attr_data_type_len[type]; + return __mnl_attr_validate(attr, type, exp_len); +} + +/** + * mnl_attr_validate2 - validate netlink attribute (extended version) + * \param attr pointer to netlink attribute that we want to validate + * \param type attribute type (see enum mnl_attr_data_type) + * \param exp_len expected attribute data size + * + * This function allows one to perform a more accurate validation for attributes + * whose size is variable. + * + * On an error, errno is explicitly set. + * + * \return 0 if the attribute is valid and fits within the expected length, -1 + * otherwise + */ +EXPORT_SYMBOL int mnl_attr_validate2(const struct nlattr *attr, + enum mnl_attr_data_type type, + size_t exp_len) +{ + if (type >= MNL_TYPE_MAX) { + errno = EINVAL; + return -1; + } + return __mnl_attr_validate(attr, type, exp_len); +} + +/** + * mnl_attr_parse - parse attributes + * \param nlh pointer to netlink message + * \param offset offset to start parsing from (if payload is after any header) + * \param cb callback function that is called for each attribute + * \param data pointer to data that is passed to the callback function + * + * This function allows you to iterate over the sequence of attributes that + * compose the Netlink message. You can then put the attribute in an array as it + * usually happens at this stage or you can use any other data structure (such + * as lists or trees). + * + * \return propagated value from callback, one of MNL_CB_ERROR, MNL_CB_STOP + * or MNL_CB_OK + */ +EXPORT_SYMBOL int mnl_attr_parse(const struct nlmsghdr *nlh, + unsigned int offset, mnl_attr_cb_t cb, + void *data) +{ + int ret = MNL_CB_OK; + const struct nlattr *attr; + + mnl_attr_for_each(attr, nlh, offset) + if ((ret = cb(attr, data)) <= MNL_CB_STOP) + return ret; + return ret; +} + +/** + * mnl_attr_parse_nested - parse attributes inside a nest + * \param nested pointer to netlink attribute that contains a nest + * \param cb callback function that is called for each attribute in the nest + * \param data pointer to data passed to the callback function + * + * This function allows you to iterate over the sequence of attributes that + * compose the Netlink message. You can then put the attribute in an array as it + * usually happens at this stage or you can use any other data structure (such + * as lists or trees). + * +* \return propagated value from callback, one of MNL_CB_ERROR, MNL_CB_STOP +* or MNL_CB_OK + */ +EXPORT_SYMBOL int mnl_attr_parse_nested(const struct nlattr *nested, + mnl_attr_cb_t cb, void *data) +{ + int ret = MNL_CB_OK; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) + if ((ret = cb(attr, data)) <= MNL_CB_STOP) + return ret; + return ret; +} + +/** + * mnl_attr_parse_payload - parse attributes in payload of Netlink message + * \param payload pointer to payload of the Netlink message + * \param payload_len payload length that contains the attributes + * \param cb callback function that is called for each attribute + * \param data pointer to data that is passed to the callback function + * + * This function takes a pointer to the area that contains the attributes, + * commonly known as the payload of the Netlink message. Thus, you have to + * pass a pointer to the Netlink message payload, instead of the entire + * message. + * + * This function allows you to iterate over the sequence of attributes that are + * located at some payload offset. You can then put the attributes in one array + * as usual, or you can use any other data structure (such as lists or trees). + * + * \return propagated value from callback, one of MNL_CB_ERROR, MNL_CB_STOP + * or MNL_CB_OK + */ +EXPORT_SYMBOL int mnl_attr_parse_payload(const void *payload, + size_t payload_len, + mnl_attr_cb_t cb, void *data) +{ + int ret = MNL_CB_OK; + const struct nlattr *attr; + + mnl_attr_for_each_payload(payload, payload_len) + if ((ret = cb(attr, data)) <= MNL_CB_STOP) + return ret; + return ret; +} + +/** + * mnl_attr_get_u8 - get 8-bit unsigned integer attribute payload + * \param attr pointer to netlink attribute + * + * \return 8-bit value of the attribute payload + */ +EXPORT_SYMBOL uint8_t mnl_attr_get_u8(const struct nlattr *attr) +{ + return *((uint8_t *)mnl_attr_get_payload(attr)); +} + +/** + * mnl_attr_get_u16 - get 16-bit unsigned integer attribute payload + * \param attr pointer to netlink attribute + * + * \return 16-bit value of the attribute payload + */ +EXPORT_SYMBOL uint16_t mnl_attr_get_u16(const struct nlattr *attr) +{ + return *((uint16_t *)mnl_attr_get_payload(attr)); +} + +/** + * mnl_attr_get_u32 - get 32-bit unsigned integer attribute payload + * \param attr pointer to netlink attribute + * + * \return 32-bit value of the attribute payload + */ +EXPORT_SYMBOL uint32_t mnl_attr_get_u32(const struct nlattr *attr) +{ + return *((uint32_t *)mnl_attr_get_payload(attr)); +} + +/** + * mnl_attr_get_u64 - get 64-bit unsigned integer attribute + * \param attr pointer to netlink attribute + * + * This function reads the 64-bit nlattr payload in an alignment safe manner. + * + * \return 64-bit value of the attribute payload + */ +EXPORT_SYMBOL uint64_t mnl_attr_get_u64(const struct nlattr *attr) +{ + uint64_t tmp; + memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp)); + return tmp; +} + +/** + * mnl_attr_get_str - get pointer to string attribute + * \param attr pointer to netlink attribute + * + * \return string pointer of the attribute payload + */ +EXPORT_SYMBOL const char *mnl_attr_get_str(const struct nlattr *attr) +{ + return mnl_attr_get_payload(attr); +} + +/** + * mnl_attr_put - add an attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type that you want to add + * \param len netlink attribute payload length + * \param data pointer to the data that will be stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +EXPORT_SYMBOL void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, + size_t len, const void *data) +{ + struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh); + uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len; + int pad; + + attr->nla_type = type; + attr->nla_len = payload_len; + memcpy(mnl_attr_get_payload(attr), data, len); + pad = MNL_ALIGN(len) - len; + if (pad > 0) + memset(mnl_attr_get_payload(attr) + len, 0, pad); + + nlh->nlmsg_len += MNL_ALIGN(payload_len); +} + +/** + * mnl_attr_put_u8 - add 8-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 8-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +EXPORT_SYMBOL void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, + uint8_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint8_t), &data); +} + +/** + * mnl_attr_put_u16 - add 16-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 16-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +EXPORT_SYMBOL void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, + uint16_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint16_t), &data); +} + +/** + * mnl_attr_put_u32 - add 32-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 32-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +EXPORT_SYMBOL void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, + uint32_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint32_t), &data); +} + +/** + * mnl_attr_put_u64 - add 64-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 64-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +EXPORT_SYMBOL void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, + uint64_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint64_t), &data); +} + +/** + * mnl_attr_put_str - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +EXPORT_SYMBOL void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, + const char *data) +{ + mnl_attr_put(nlh, type, strlen(data), data); +} + +/** + * mnl_attr_put_strz - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function is similar to mnl_attr_put_str, but it includes the + * NUL/zero ('\0') terminator at the end of the string. + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +EXPORT_SYMBOL void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, + const char *data) +{ + mnl_attr_put(nlh, type, strlen(data)+1, data); +} + +/** + * mnl_attr_nest_start - start an attribute nest + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * + * This function adds the attribute header that identifies the beginning of + * an attribute nest. + * + * \return valid pointer to the beginning of the nest + */ +EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, + uint16_t type) +{ + struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh); + + /* set start->nla_len in mnl_attr_nest_end() */ + start->nla_type = NLA_F_NESTED | type; + nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr)); + + return start; +} + +/** + * mnl_attr_put_check - add an attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type that you want to add + * \param len netlink attribute payload length + * \param data pointer to the data that will be stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. + * + * \return true if the attribute could be added, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, size_t len, + const void *data) +{ + if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen) + return false; + mnl_attr_put(nlh, type, len, data); + return true; +} + +/** + * mnl_attr_put_u8_check - add 8-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 8-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. + * + * \return true if the attribute could be added, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint8_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data); +} + +/** + * mnl_attr_put_u16_check - add 16-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 16-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. + * + * \return true if the attribute could be added, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint16_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data); +} + +/** + * mnl_attr_put_u32_check - add 32-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 32-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. + * + * \return true if the attribute could be added, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint32_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data); +} + +/** + * mnl_attr_put_u64_check - add 64-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 64-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. + * + * \return true if the attribute could be added, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint64_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data); +} + +/** + * mnl_attr_put_str_check - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. + * + * \return true if the attribute could be added, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, const char *data) +{ + return mnl_attr_put_check(nlh, buflen, type, strlen(data), data); +} + +/** + * mnl_attr_put_strz_check - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function is similar to mnl_attr_put_str, but it includes the + * NUL/zero ('\0') terminator at the end of the string. + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. + * + * \return true if the attribute could be added, false otherwise + */ +EXPORT_SYMBOL bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, const char *data) +{ + return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data); +} + +/** + * mnl_attr_nest_start_check - start an attribute nest + * \param buflen size of buffer which stores the message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * + * This function adds the attribute header that identifies the beginning of + * an attribute nest. + * + * \return NULL if the attribute cannot be added, otherwise a pointer to the + * beginning of the nest + */ +EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, + size_t buflen, + uint16_t type) +{ + if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen) + return NULL; + return mnl_attr_nest_start(nlh, type); +} + +/** + * mnl_attr_nest_end - end an attribute nest + * \param nlh pointer to the netlink message + * \param start pointer to the attribute nest returned by mnl_attr_nest_start() + * + * This function updates the attribute header that identifies the nest. + */ +EXPORT_SYMBOL void mnl_attr_nest_end(struct nlmsghdr *nlh, + struct nlattr *start) +{ + start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start; +} + +/** + * mnl_attr_nest_cancel - cancel an attribute nest + * \param nlh pointer to the netlink message + * \param start pointer to the attribute nest returned by mnl_attr_nest_start() + * + * This function updates the attribute header that identifies the nest. + */ +EXPORT_SYMBOL void mnl_attr_nest_cancel(struct nlmsghdr *nlh, + struct nlattr *start) +{ + nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start; +} + +/** + * @} + */ diff --git a/deps/libmnl/src/callback.c b/deps/libmnl/src/callback.c new file mode 100644 index 0000000..f5349c3 --- /dev/null +++ b/deps/libmnl/src/callback.c @@ -0,0 +1,167 @@ +/* + * (C) 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 Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include "internal.h" + +static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data) +{ + return MNL_CB_OK; +} + +static int mnl_cb_error(const struct nlmsghdr *nlh, void *data) +{ + const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); + + if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) { + errno = EBADMSG; + return MNL_CB_ERROR; + } + /* Netlink subsystems returns the errno value with different signess */ + if (err->error < 0) + errno = -err->error; + else + errno = err->error; + + return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR; +} + +static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data) +{ + return MNL_CB_STOP; +} + +static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = { + [NLMSG_NOOP] = mnl_cb_noop, + [NLMSG_ERROR] = mnl_cb_error, + [NLMSG_DONE] = mnl_cb_stop, + [NLMSG_OVERRUN] = mnl_cb_noop, +}; + +static inline int __mnl_cb_run(const void *buf, size_t numbytes, + unsigned int seq, unsigned int portid, + mnl_cb_t cb_data, void *data, + const mnl_cb_t *cb_ctl_array, + unsigned int cb_ctl_array_len) +{ + int ret = MNL_CB_OK, len = numbytes; + const struct nlmsghdr *nlh = buf; + + while (mnl_nlmsg_ok(nlh, len)) { + /* check message source */ + if (!mnl_nlmsg_portid_ok(nlh, portid)) { + errno = ESRCH; + return -1; + } + /* perform sequence tracking */ + if (!mnl_nlmsg_seq_ok(nlh, seq)) { + errno = EPROTO; + return -1; + } + + /* dump was interrupted */ + if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) { + errno = EINTR; + return -1; + } + + /* netlink data message handling */ + if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) { + if (cb_data){ + ret = cb_data(nlh, data); + if (ret <= MNL_CB_STOP) + goto out; + } + } else if (nlh->nlmsg_type < cb_ctl_array_len) { + if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) { + ret = cb_ctl_array[nlh->nlmsg_type](nlh, data); + if (ret <= MNL_CB_STOP) + goto out; + } + } else if (default_cb_array[nlh->nlmsg_type]) { + ret = default_cb_array[nlh->nlmsg_type](nlh, data); + if (ret <= MNL_CB_STOP) + goto out; + } + nlh = mnl_nlmsg_next(nlh, &len); + } +out: + return ret; +} + +/** + * \defgroup callback Callback helpers + * @{ + */ + +/** + * mnl_cb_run2 - callback runqueue for netlink messages + * \param buf buffer that contains the netlink messages + * \param numbytes number of bytes stored in the buffer + * \param seq sequence number that we expect to receive + * \param portid Netlink PortID that we expect to receive + * \param cb_data callback handler for data messages + * \param data pointer to data that will be passed to the data callback handler + * \param cb_ctl_array array of custom callback handlers from control messages + * \param cb_ctl_array_len array length of custom control callback handlers + * + * You can set the cb_ctl_array to NULL if you want to use the default control + * callback handlers, in that case, the parameter cb_ctl_array_len is not + * checked. + * + * Your callback may return three possible values: + * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue. + * - MNL_CB_STOP (=0): stop callback runqueue. + * - MNL_CB_OK (>=1): no problem has occurred. + * + * This function propagates the callback return value. On error, it returns + * -1 and errno is explicitly set. If the portID is not the expected, errno + * is set to ESRCH. If the sequence number is not the expected, errno is set + * to EPROTO. If the dump was interrupted, errno is set to EINTR and you should + * request a new fresh dump again. + */ +EXPORT_SYMBOL int mnl_cb_run2(const void *buf, size_t numbytes, + unsigned int seq, unsigned int portid, + mnl_cb_t cb_data, void *data, + const mnl_cb_t *cb_ctl_array, + unsigned int cb_ctl_array_len) +{ + return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, + cb_ctl_array, cb_ctl_array_len); +} + +/** + * mnl_cb_run - callback runqueue for netlink messages (simplified version) + * \param buf buffer that contains the netlink messages + * \param numbytes number of bytes stored in the buffer + * \param seq sequence number that we expect to receive + * \param portid Netlink PortID that we expect to receive + * \param cb_data callback handler for data messages + * \param data pointer to data that will be passed to the data callback handler + * + * This function is like mnl_cb_run2() but it does not allow you to set + * the control callback handlers. + * + * Your callback may return three possible values: + * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue. + * - MNL_CB_STOP (=0): stop callback runqueue. + * - MNL_CB_OK (>=1): no problems has occurred. + * + * This function propagates the callback return value. + */ +EXPORT_SYMBOL int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, + unsigned int portid, mnl_cb_t cb_data, void *data) +{ + return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0); +} + +/** + * @} + */ diff --git a/deps/libmnl/src/internal.h b/deps/libmnl/src/internal.h new file mode 100644 index 0000000..d69eaf3 --- /dev/null +++ b/deps/libmnl/src/internal.h @@ -0,0 +1,11 @@ +#ifndef INTERNAL_H +#define INTERNAL_H 1 + +#include "config.h" +#ifdef HAVE_VISIBILITY_HIDDEN +# define EXPORT_SYMBOL __attribute__((visibility("default"))) +#else +# define EXPORT_SYMBOL +#endif + +#endif diff --git a/deps/libmnl/src/libmnl.map b/deps/libmnl/src/libmnl.map new file mode 100644 index 0000000..e5920e5 --- /dev/null +++ b/deps/libmnl/src/libmnl.map @@ -0,0 +1,79 @@ +LIBMNL_1.0 { +global: + mnl_attr_get_len; + mnl_attr_get_payload; + mnl_attr_get_payload_len; + mnl_attr_get_str; + mnl_attr_get_type; + mnl_attr_get_u16; + mnl_attr_get_u32; + mnl_attr_get_u64; + mnl_attr_get_u8; + mnl_attr_nest_end; + mnl_attr_nest_start; + mnl_attr_nest_start_check; + mnl_attr_nest_cancel; + mnl_attr_next; + mnl_attr_ok; + mnl_attr_parse; + mnl_attr_parse_nested; + mnl_attr_put; + mnl_attr_put_str; + mnl_attr_put_strz; + mnl_attr_put_u16; + mnl_attr_put_u32; + mnl_attr_put_u64; + mnl_attr_put_u8; + mnl_attr_put_check; + mnl_attr_put_str_check; + mnl_attr_put_strz_check; + mnl_attr_put_u16_check; + mnl_attr_put_u32_check; + mnl_attr_put_u64_check; + mnl_attr_put_u8_check; + mnl_attr_type_valid; + mnl_attr_validate; + mnl_attr_validate2; + mnl_cb_run; + mnl_cb_run2; + mnl_nlmsg_fprintf; + mnl_nlmsg_get_payload; + mnl_nlmsg_get_payload_len; + mnl_nlmsg_get_payload_offset; + mnl_nlmsg_get_payload_tail; + mnl_nlmsg_next; + mnl_nlmsg_ok; + mnl_nlmsg_portid_ok; + mnl_nlmsg_put_extra_header; + mnl_nlmsg_put_header; + mnl_nlmsg_seq_ok; + mnl_nlmsg_size; + mnl_nlmsg_batch_start; + mnl_nlmsg_batch_stop; + mnl_nlmsg_batch_next; + mnl_nlmsg_batch_size; + mnl_nlmsg_batch_reset; + mnl_nlmsg_batch_current; + mnl_nlmsg_batch_head; + mnl_nlmsg_batch_is_empty; + mnl_socket_bind; + mnl_socket_close; + mnl_socket_get_fd; + mnl_socket_get_portid; + mnl_socket_getsockopt; + mnl_socket_open; + mnl_socket_recvfrom; + mnl_socket_sendto; + mnl_socket_setsockopt; + +local: *; +}; + +LIBMNL_1.1 { + mnl_attr_parse_payload; +} LIBMNL_1.0; + +LIBMNL_1.2 { + mnl_socket_open2; + mnl_socket_fdopen; +} LIBMNL_1.1; diff --git a/deps/libmnl/src/nlmsg.c b/deps/libmnl/src/nlmsg.c new file mode 100644 index 0000000..30a7e63 --- /dev/null +++ b/deps/libmnl/src/nlmsg.c @@ -0,0 +1,592 @@ +/* + * (C) 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 Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +/** + * \defgroup nlmsg Netlink message helpers + * + * Netlink message: + * \verbatim + |<----------------- 4 bytes ------------------->| + |<----- 2 bytes ------>|<------- 2 bytes ------>| + |-----------------------------------------------| + | Message length (including header) | + |-----------------------------------------------| + | Message type | Message flags | + |-----------------------------------------------| + | Message sequence number | + |-----------------------------------------------| + | Netlink PortID | + |-----------------------------------------------| + | | + . Payload . + |_______________________________________________| +\endverbatim + * + * There is usually an extra header after the the Netlink header (at the + * beginning of the payload). This extra header is specific of the Netlink + * subsystem. After this extra header, it comes the sequence of attributes + * that are expressed in Type-Length-Value (TLV) format. + * + * @{ + */ + +/** + * mnl_nlmsg_size - calculate the size of Netlink message (without alignment) + * \param len length of the Netlink payload + * + * This function returns the size of a netlink message (header plus payload) + * without alignment. + */ +EXPORT_SYMBOL size_t mnl_nlmsg_size(size_t len) +{ + return len + MNL_NLMSG_HDRLEN; +} + +/** + * mnl_nlmsg_get_payload_len - get the length of the Netlink payload + * \param nlh pointer to the header of the Netlink message + * + * This function returns the Length of the netlink payload, ie. the length + * of the full message minus the size of the Netlink header. + */ +EXPORT_SYMBOL size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh) +{ + return nlh->nlmsg_len - MNL_NLMSG_HDRLEN; +} + +/** + * mnl_nlmsg_put_header - reserve and prepare room for Netlink header + * \param buf memory already allocated to store the Netlink header + * + * This function sets to zero the room that is required to put the Netlink + * header in the memory buffer passed as parameter. This function also + * initializes the nlmsg_len field to the size of the Netlink header. This + * function returns a pointer to the Netlink header structure. + */ +EXPORT_SYMBOL struct nlmsghdr *mnl_nlmsg_put_header(void *buf) +{ + int len = MNL_ALIGN(sizeof(struct nlmsghdr)); + struct nlmsghdr *nlh = buf; + + memset(buf, 0, len); + nlh->nlmsg_len = len; + return nlh; +} + +/** + * mnl_nlmsg_put_extra_header - reserve and prepare room for an extra header + * \param nlh pointer to Netlink header + * \param size size of the extra header that we want to put + * + * This function sets to zero the room that is required to put the extra + * header after the initial Netlink header. This function also increases + * the nlmsg_len field. You have to invoke mnl_nlmsg_put_header() before + * you call this function. This function returns a pointer to the extra + * header. + */ +EXPORT_SYMBOL void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, + size_t size) +{ + char *ptr = (char *)nlh + nlh->nlmsg_len; + size_t len = MNL_ALIGN(size); + nlh->nlmsg_len += len; + memset(ptr, 0, len); + return ptr; +} + +/** + * mnl_nlmsg_get_payload - get a pointer to the payload of the netlink message + * \param nlh pointer to a netlink header + * + * This function returns a pointer to the payload of the netlink message. + */ +EXPORT_SYMBOL void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh) +{ + return (void *)nlh + MNL_NLMSG_HDRLEN; +} + +/** + * mnl_nlmsg_get_payload_offset - get a pointer to the payload of the message + * \param nlh pointer to a netlink header + * \param offset offset to the payload of the attributes TLV set + * + * This function returns a pointer to the payload of the netlink message plus + * a given offset. + */ +EXPORT_SYMBOL void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, + size_t offset) +{ + return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset); +} + +/** + * mnl_nlmsg_ok - check a there is room for netlink message + * \param nlh netlink message that we want to check + * \param len remaining bytes in a buffer that contains the netlink message + * + * This function is used to check that a buffer that contains a netlink + * message has enough room for the netlink message that it stores, ie. this + * function can be used to verify that a netlink message is not malformed nor + * truncated. + * + * This function does not set errno in case of error since it is intended + * for iterations. Thus, it returns true on success and false on error. + * + * The len parameter may become negative in malformed messages during message + * iteration, that is why we use a signed integer. + */ +EXPORT_SYMBOL bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len) +{ + size_t ulen = len; + + if (len < 0) + return false; + + return ulen >= sizeof(struct nlmsghdr) && + nlh->nlmsg_len >= sizeof(struct nlmsghdr) && + nlh->nlmsg_len <= ulen; +} + +/** + * mnl_nlmsg_next - get the next netlink message in a multipart message + * \param nlh current netlink message that we are handling + * \param len length of the remaining bytes in the buffer (passed by reference). + * + * This function returns a pointer to the next netlink message that is part + * of a multi-part netlink message. Netlink can batch several messages into + * one buffer so that the receiver has to iterate over the whole set of + * Netlink messages. + * + * You have to use mnl_nlmsg_ok() to check if the next Netlink message is + * valid. + */ +EXPORT_SYMBOL struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, + int *len) +{ + *len -= MNL_ALIGN(nlh->nlmsg_len); + return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len)); +} + +/** + * mnl_nlmsg_get_payload_tail - get the ending of the netlink message + * \param nlh pointer to netlink message + * + * This function returns a pointer to the netlink message tail. This is useful + * to build a message since we continue adding attributes at the end of the + * message. + */ +EXPORT_SYMBOL void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh) +{ + return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len); +} + +/** + * mnl_nlmsg_seq_ok - perform sequence tracking + * \param nlh current netlink message that we are handling + * \param seq last sequence number used to send a message + * + * This functions returns true if the sequence tracking is fulfilled, otherwise + * false is returned. We skip the tracking for netlink messages whose sequence + * number is zero since it is usually reserved for event-based kernel + * notifications. On the other hand, if seq is set but the message sequence + * number is not set (i.e. this is an event message coming from kernel-space), + * then we also skip the tracking. This approach is good if we use the same + * socket to send commands to kernel-space (that we want to track) and to + * listen to events (that we do not track). + */ +EXPORT_SYMBOL bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, + unsigned int seq) +{ + return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true; +} + +/** + * mnl_nlmsg_portid_ok - perform portID origin check + * \param nlh current netlink message that we are handling + * \param portid netlink portid that we want to check + * + * This functions returns true if the origin is fulfilled, otherwise + * false is returned. We skip the tracking for netlink message whose portID + * is zero since it is reserved for event-based kernel notifications. On the + * other hand, if portid is set but the message PortID is not (i.e. this + * is an event message coming from kernel-space), then we also skip the + * tracking. This approach is good if we use the same socket to send commands + * to kernel-space (that we want to track) and to listen to events (that we + * do not track). + */ +EXPORT_SYMBOL bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, + unsigned int portid) +{ + return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true; +} + +static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh) +{ + fprintf(fd, "----------------\t------------------\n"); + fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len); + fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n", + nlh->nlmsg_type, + nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-', + nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-', + nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-', + nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-'); + fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq); + fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid); + fprintf(fd, "----------------\t------------------\n"); +} + +static void mnl_fprintf_attr_color(FILE *fd, const struct nlattr *attr) +{ + fprintf(fd, "|%c[%d;%dm" + "%.5u" + "%c[%dm" + "|" + "%c[%d;%dm" + "%c%c" + "%c[%dm" + "|" + "%c[%d;%dm" + "%.5u" + "%c[%dm|\t", + 27, 1, 31, + attr->nla_len, + 27, 0, + 27, 1, 32, + attr->nla_type & NLA_F_NESTED ? 'N' : '-', + attr->nla_type & NLA_F_NET_BYTEORDER ? 'B' : '-', + 27, 0, + 27, 1, 34, + attr->nla_type & NLA_TYPE_MASK, + 27, 0); +} + +static void mnl_fprintf_attr_raw(FILE *fd, const struct nlattr *attr) +{ + fprintf(fd, "|" + "%.5u" + "|" + "%c%c" + "|" + "%.5u" + "|\t", + attr->nla_len, + attr->nla_type & NLA_F_NESTED ? 'N' : '-', + attr->nla_type & NLA_F_NET_BYTEORDER ? 'B' : '-', + attr->nla_type & NLA_TYPE_MASK); +} + +static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh, + size_t extra_header_size) +{ + int colorize = 0; + unsigned int i; + int rem = 0; + int fdnum; + + fdnum = fileno(fd); + if (fdnum != -1) + colorize = isatty(fdnum); + + for (i=sizeof(struct nlmsghdr); inlmsg_len; i+=4) { + char *b = (char *) nlh; + struct nlattr *attr = (struct nlattr *) (b+i); + + /* netlink control message. */ + if (nlh->nlmsg_type < NLMSG_MIN_TYPE) { + fprintf(fd, "| %.2x %.2x %.2x %.2x |\t", + 0xff & b[i], 0xff & b[i+1], + 0xff & b[i+2], 0xff & b[i+3]); + fprintf(fd, "| |\n"); + /* special handling for the extra header. */ + } else if (extra_header_size > 0) { + extra_header_size -= 4; + fprintf(fd, "| %.2x %.2x %.2x %.2x |\t", + 0xff & b[i], 0xff & b[i+1], + 0xff & b[i+2], 0xff & b[i+3]); + fprintf(fd, "| extra header |\n"); + /* this seems like an attribute header. */ + } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) { + if (colorize) { + mnl_fprintf_attr_color(fd, attr); + } else { + mnl_fprintf_attr_raw(fd, attr); + } + fprintf(fd, "|len |flags| type|\n"); + + if (!(attr->nla_type & NLA_F_NESTED)) { + rem = NLA_ALIGN(attr->nla_len) - + sizeof(struct nlattr); + } + /* this is the attribute payload. */ + } else if (rem > 0) { + rem -= 4; + fprintf(fd, "| %.2x %.2x %.2x %.2x |\t", + 0xff & b[i], 0xff & b[i+1], + 0xff & b[i+2], 0xff & b[i+3]); + fprintf(fd, "| data |"); + fprintf(fd, "\t %c %c %c %c\n", + isprint(b[i]) ? b[i] : ' ', + isprint(b[i+1]) ? b[i+1] : ' ', + isprint(b[i+2]) ? b[i+2] : ' ', + isprint(b[i+3]) ? b[i+3] : ' '); + } + } + fprintf(fd, "----------------\t------------------\n"); +} + +/** + * mnl_nlmsg_fprintf - print netlink message to file + * \param fd pointer to file type + * \param data pointer to the buffer that contains messages to be printed + * \param datalen length of data stored in the buffer + * \param extra_header_size size of the extra header (if any) + * + * This function prints the netlink header to a file handle. + * It may be useful for debugging purposes. One example of the output + * is the following: + * + *\verbatim +---------------- ------------------ +| 0000000040 | | message length | +| 00016 | R-A- | | type | flags | +| 1289148991 | | sequence number| +| 0000000000 | | port ID | +---------------- ------------------ +| 00 00 00 00 | | extra header | +| 00 00 00 00 | | extra header | +| 01 00 00 00 | | extra header | +| 01 00 00 00 | | extra header | +|00008|--|00003| |len |flags| type| +| 65 74 68 30 | | data | e t h 0 +---------------- ------------------ +\endverbatim + * + * This example above shows the netlink message that is send to kernel-space + * to set up the link interface eth0. The netlink and attribute header data + * are displayed in base 10 whereas the extra header and the attribute payload + * are expressed in base 16. The possible flags in the netlink header are: + * + * - R, that indicates that NLM_F_REQUEST is set. + * - M, that indicates that NLM_F_MULTI is set. + * - A, that indicates that NLM_F_ACK is set. + * - E, that indicates that NLM_F_ECHO is set. + * + * The lack of one flag is displayed with '-'. On the other hand, the possible + * attribute flags available are: + * + * - N, that indicates that NLA_F_NESTED is set. + * - B, that indicates that NLA_F_NET_BYTEORDER is set. + */ +EXPORT_SYMBOL void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, + size_t extra_header_size) +{ + const struct nlmsghdr *nlh = data; + int len = datalen; + + while (mnl_nlmsg_ok(nlh, len)) { + mnl_nlmsg_fprintf_header(fd, nlh); + mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size); + nlh = mnl_nlmsg_next(nlh, &len); + } +} + +/** + * @} + */ + +/** + * \defgroup batch Netlink message batch helpers + * + * This library provides helpers to batch several messages into one single + * datagram. These helpers do not perform strict memory boundary checkings. + * + * The following figure represents a Netlink message batch: + *\verbatim + |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->| + |<-------------------- batch ------------------>| | + |-----------|-----------|-----------|-----------|-----------| + |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->| + |-----------|-----------|-----------|-----------|-----------| + ^ ^ + | | + message N message N+1 +\endverbatim + * + * To start the batch, you have to call mnl_nlmsg_batch_start() and you can + * use mnl_nlmsg_batch_stop() to release it. + * + * You have to invoke mnl_nlmsg_batch_next() to get room for a new message + * in the batch. If this function returns NULL, it means that the last + * message that was added (message N+1 in the figure above) does not fit the + * batch. Thus, you have to send the batch (which includes until message N) + * and, then, you have to call mnl_nlmsg_batch_reset() to re-initialize + * the batch (this moves message N+1 to the head of the buffer). For that + * reason, the buffer that you have to use to store the batch must be double + * of MNL_SOCKET_BUFFER_SIZE to ensure that the last message (message N+1) + * that did not fit into the batch is written inside valid memory boundaries. + * + * @{ + */ + +struct mnl_nlmsg_batch { + /* the buffer that is used to store the batch. */ + void *buf; + size_t limit; + size_t buflen; + /* the current netlink message in the batch. */ + void *cur; + bool overflow; +}; + +/** + * mnl_nlmsg_batch_start - initialize a batch + * \param buf pointer to the buffer that will store this batch + * \param limit maximum size of the batch (should be MNL_SOCKET_BUFFER_SIZE). + * + * The buffer that you pass must be double of MNL_SOCKET_BUFFER_SIZE. The + * limit must be half of the buffer size, otherwise expect funny memory + * corruptions 8-). + * + * You can allocate the buffer that you use to store the batch in the stack or + * the heap, no restrictions in this regard. This function returns NULL on + * error. + */ +EXPORT_SYMBOL struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, + size_t limit) +{ + struct mnl_nlmsg_batch *b; + + b = malloc(sizeof(struct mnl_nlmsg_batch)); + if (b == NULL) + return NULL; + + b->buf = buf; + b->limit = limit; + b->buflen = 0; + b->cur = buf; + b->overflow = false; + + return b; +} + +/** + * mnl_nlmsg_batch_stop - release a batch + * \param b pointer to batch + * + * This function releases the batch allocated by mnl_nlmsg_batch_start(). + */ +EXPORT_SYMBOL void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b) +{ + free(b); +} + +/** + * mnl_nlmsg_batch_next - get room for the next message in the batch + * \param b pointer to batch + * + * This function returns false if the last message did not fit into the + * batch. Otherwise, it prepares the batch to provide room for the new + * Netlink message in the batch and returns true. + * + * You have to put at least one message in the batch before calling this + * function, otherwise your application is likely to crash. + */ +EXPORT_SYMBOL bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b) +{ + struct nlmsghdr *nlh = b->cur; + + if (b->buflen + nlh->nlmsg_len > b->limit) { + b->overflow = true; + return false; + } + b->cur = b->buf + b->buflen + nlh->nlmsg_len; + b->buflen += nlh->nlmsg_len; + return true; +} + +/** + * mnl_nlmsg_batch_reset - reset the batch + * \param b pointer to batch + * + * This function allows you to reset a batch, so you can reuse it to create a + * new one. This function moves the last message which does not fit the batch to + * the head of the buffer, if any. + */ +EXPORT_SYMBOL void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b) +{ + if (b->overflow) { + struct nlmsghdr *nlh = b->cur; + memcpy(b->buf, b->cur, nlh->nlmsg_len); + b->buflen = nlh->nlmsg_len; + b->cur = b->buf + b->buflen; + b->overflow = false; + } else { + b->buflen = 0; + b->cur = b->buf; + } +} + +/** + * mnl_nlmsg_batch_size - get current size of the batch + * \param b pointer to batch + * + * This function returns the current size of the batch. + */ +EXPORT_SYMBOL size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b) +{ + return b->buflen; +} + +/** + * mnl_nlmsg_batch_head - get head of this batch + * \param b pointer to batch + * + * This function returns a pointer to the head of the batch, which is the + * beginning of the buffer that is used. + */ +EXPORT_SYMBOL void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b) +{ + return b->buf; +} + +/** + * mnl_nlmsg_batch_current - returns current position in the batch + * \param b pointer to batch + * + * This function returns a pointer to the current position in the buffer + * that is used to store the batch. + */ +EXPORT_SYMBOL void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b) +{ + return b->cur; +} + +/** + * mnl_nlmsg_batch_is_empty - check if there is any message in the batch + * \param b pointer to batch + * + * This function returns true if the batch is empty. + */ +EXPORT_SYMBOL bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b) +{ + return b->buflen == 0; +} + +/** + * @} + */ diff --git a/deps/libmnl/src/socket.c b/deps/libmnl/src/socket.c new file mode 100644 index 0000000..85b6bcc --- /dev/null +++ b/deps/libmnl/src/socket.c @@ -0,0 +1,351 @@ +/* + * (C) 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 Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +/** + * \mainpage + * + * libmnl is a minimalistic user-space library oriented to Netlink developers. + * There are a lot of common tasks in parsing, validating, constructing of + * both the Netlink header and TLVs that are repetitive and easy to get wrong. + * This library aims to provide simple helpers that allows you to avoid + * re-inventing the wheel in common Netlink tasks. + * + * \verbatim +"Simplify, simplify" -- Henry David Thoureau. Walden (1854) +\endverbatim + * + * The acronym libmnl stands for LIBrary Minimalistic NetLink. + * + * libmnl homepage is: + * http://www.netfilter.org/projects/libmnl/ + * + * \section features Main Features + * - Small: the shared library requires around 30KB for an x86-based computer. + * - Simple: this library avoids complex abstractions that tend to hide Netlink + * details. It avoids elaborated object-oriented infrastructure and complex + * callback-based workflow. + * - Easy to use: the library simplifies the work for Netlink-wise developers. + * It provides functions to make socket handling, message building, + * validating, parsing and sequence tracking, easier. + * - Easy to re-use: you can use this library to build your own abstraction + * layer upon this library, if you want to provide another library that + * hides Netlink details to your users. + * - Decoupling: the interdependency of the main bricks that compose this + * library is reduced, i.e. the library provides many helpers, but the + * programmer is not forced to use them. + * + * \section licensing Licensing terms + * This library is released under the LGPLv2.1 or any later (at your option). + * + * \section Dependencies + * You have to install the Linux kernel headers that you want to use to develop + * your application. Moreover, this library requires that you have some basics + * on Netlink. + * + * \section scm Git Tree + * The current development version of libmnl can be accessed at: + * https://git.netfilter.org/libmnl/ + * + * \section using Using libmnl + * You can access several example files under examples/ in the libmnl source + * code tree. + */ + +struct mnl_socket { + int fd; + struct sockaddr_nl addr; +}; + +/** + * \defgroup socket Netlink socket helpers + * @{ + */ + +/** + * mnl_socket_get_fd - obtain file descriptor from netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * + * This function returns the file descriptor of a given netlink socket. + */ +EXPORT_SYMBOL int mnl_socket_get_fd(const struct mnl_socket *nl) +{ + return nl->fd; +} + +/** + * mnl_socket_get_portid - obtain Netlink PortID from netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * + * This function returns the Netlink PortID of a given netlink socket. + * It's a common mistake to assume that this PortID equals the process ID + * which is not always true. This is the case if you open more than one + * socket that is binded to the same Netlink subsystem from the same process. + */ +EXPORT_SYMBOL unsigned int mnl_socket_get_portid(const struct mnl_socket *nl) +{ + return nl->addr.nl_pid; +} + +static struct mnl_socket *__mnl_socket_open(int bus, int flags) +{ + struct mnl_socket *nl; + + nl = calloc(1, sizeof(struct mnl_socket)); + if (nl == NULL) + return NULL; + + nl->fd = socket(AF_NETLINK, SOCK_RAW | flags, bus); + if (nl->fd == -1) { + free(nl); + return NULL; + } + + return nl; +} + +/** + * mnl_socket_open - open a netlink socket + * \param bus the netlink socket bus ID (see NETLINK_* constants) + * + * On error, it returns NULL and errno is appropriately set. Otherwise, it + * returns a valid pointer to the mnl_socket structure. + */ +EXPORT_SYMBOL struct mnl_socket *mnl_socket_open(int bus) +{ + return __mnl_socket_open(bus, 0); +} + +/** + * mnl_socket_open2 - open a netlink socket with appropriate flags + * \param bus the netlink socket bus ID (see NETLINK_* constants) + * \param flags the netlink socket flags (see SOCK_* constants in socket(2)) + * + * This is similar to mnl_socket_open(), but allows one to set flags like + * SOCK_CLOEXEC at socket creation time (useful for multi-threaded programs + * performing exec calls). + * + * On error, it returns NULL and errno is appropriately set. Otherwise, it + * returns a valid pointer to the mnl_socket structure. + */ +EXPORT_SYMBOL struct mnl_socket *mnl_socket_open2(int bus, int flags) +{ + return __mnl_socket_open(bus, flags); +} + +/** + * mnl_socket_fdopen - associates a mnl_socket object with pre-existing socket. + * \param fd pre-existing socket descriptor. + * + * On error, it returns NULL and errno is appropriately set. Otherwise, it + * returns a valid pointer to the mnl_socket structure. It also sets the portID + * if the socket fd is already bound and it is AF_NETLINK. + * + * Note that mnl_socket_get_portid() returns 0 if this function is used with + * non-netlink socket. + */ +EXPORT_SYMBOL struct mnl_socket *mnl_socket_fdopen(int fd) +{ + int ret; + struct mnl_socket *nl; + struct sockaddr_nl addr; + socklen_t addr_len = sizeof(struct sockaddr_nl); + + ret = getsockname(fd, (struct sockaddr *) &addr, &addr_len); + if (ret == -1) + return NULL; + + nl = calloc(1, sizeof(struct mnl_socket)); + if (nl == NULL) + return NULL; + + nl->fd = fd; + if (addr.nl_family == AF_NETLINK) + nl->addr = addr; + + return nl; +} + +/** + * mnl_socket_bind - bind netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * \param groups the group of message you're interested in + * \param pid the port ID you want to use (use zero for automatic selection) + * + * On error, this function returns -1 and errno is appropriately set. On + * success, 0 is returned. You can use MNL_SOCKET_AUTOPID which is 0 for + * automatic port ID selection. + */ +EXPORT_SYMBOL int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, + pid_t pid) +{ + int ret; + socklen_t addr_len; + + nl->addr.nl_family = AF_NETLINK; + nl->addr.nl_groups = groups; + nl->addr.nl_pid = pid; + + ret = bind(nl->fd, (struct sockaddr *) &nl->addr, sizeof (nl->addr)); + if (ret < 0) + return ret; + + addr_len = sizeof(nl->addr); + ret = getsockname(nl->fd, (struct sockaddr *) &nl->addr, &addr_len); + if (ret < 0) + return ret; + + if (addr_len != sizeof(nl->addr)) { + errno = EINVAL; + return -1; + } + if (nl->addr.nl_family != AF_NETLINK) { + errno = EINVAL; + return -1; + } + return 0; +} + +/** + * mnl_socket_sendto - send a netlink message of a certain size + * \param nl netlink socket obtained via mnl_socket_open() + * \param buf buffer containing the netlink message to be sent + * \param len number of bytes in the buffer that you want to send + * + * On error, it returns -1 and errno is appropriately set. Otherwise, it + * returns the number of bytes sent. + */ +EXPORT_SYMBOL ssize_t mnl_socket_sendto(const struct mnl_socket *nl, + const void *buf, size_t len) +{ + static const struct sockaddr_nl snl = { + .nl_family = AF_NETLINK + }; + return sendto(nl->fd, buf, len, 0, + (struct sockaddr *) &snl, sizeof(snl)); +} + +/** + * mnl_socket_recvfrom - receive a netlink message + * \param nl netlink socket obtained via mnl_socket_open() + * \param buf buffer that you want to use to store the netlink message + * \param bufsiz size of the buffer passed to store the netlink message + * + * On error, it returns -1 and errno is appropriately set. If errno is set + * to ENOSPC, it means that the buffer that you have passed to store the + * netlink message is too small, so you have received a truncated message. + * To avoid this, you have to allocate a buffer of MNL_SOCKET_BUFFER_SIZE + * (which is 8KB, see linux/netlink.h for more information). Using this + * buffer size ensures that your buffer is big enough to store the netlink + * message without truncating it. + */ +EXPORT_SYMBOL ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, + void *buf, size_t bufsiz) +{ + ssize_t ret; + struct sockaddr_nl addr; + struct iovec iov = { + .iov_base = buf, + .iov_len = bufsiz, + }; + struct msghdr msg = { + .msg_name = &addr, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + ret = recvmsg(nl->fd, &msg, 0); + if (ret == -1) + return ret; + + if (msg.msg_flags & MSG_TRUNC) { + errno = ENOSPC; + return -1; + } + if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { + errno = EINVAL; + return -1; + } + return ret; +} + +/** + * mnl_socket_close - close a given netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * + * On error, this function returns -1 and errno is appropriately set. + * On success, it returns 0. + */ +EXPORT_SYMBOL int mnl_socket_close(struct mnl_socket *nl) +{ + int ret = close(nl->fd); + free(nl); + return ret; +} + +/** + * mnl_socket_setsockopt - set Netlink socket option + * \param nl netlink socket obtained via mnl_socket_open() + * \param type type of Netlink socket options + * \param buf the buffer that contains the data about this option + * \param len the size of the buffer passed + * + * This function allows you to set some Netlink socket option. As of writing + * this (see linux/netlink.h), the existing options are: + * + * - \#define NETLINK_ADD_MEMBERSHIP 1 + * - \#define NETLINK_DROP_MEMBERSHIP 2 + * - \#define NETLINK_PKTINFO 3 + * - \#define NETLINK_BROADCAST_ERROR 4 + * - \#define NETLINK_NO_ENOBUFS 5 + * + * In the early days, Netlink only supported 32 groups expressed in a + * 32-bits mask. However, since 2.6.14, Netlink may have up to 2^32 multicast + * groups but you have to use setsockopt() with NETLINK_ADD_MEMBERSHIP to + * join a given multicast group. This function internally calls setsockopt() + * to join a given netlink multicast group. You can still use mnl_bind() + * and the 32-bit mask to join a set of Netlink multicast groups. + * + * On error, this function returns -1 and errno is appropriately set. + */ +EXPORT_SYMBOL int mnl_socket_setsockopt(const struct mnl_socket *nl, int type, + void *buf, socklen_t len) +{ + return setsockopt(nl->fd, SOL_NETLINK, type, buf, len); +} + +/** + * mnl_socket_getsockopt - get a Netlink socket option + * \param nl netlink socket obtained via mnl_socket_open() + * \param type type of Netlink socket options + * \param buf pointer to the buffer to store the value of this option + * \param len size of the information written in the buffer + * + * On error, this function returns -1 and errno is appropriately set. + */ +EXPORT_SYMBOL int mnl_socket_getsockopt(const struct mnl_socket *nl, int type, + void *buf, socklen_t *len) +{ + return getsockopt(nl->fd, SOL_NETLINK, type, buf, len); +} + +/** + * @} + */ diff --git a/deps/libnetfilter_queue/.gitignore b/deps/libnetfilter_queue/.gitignore new file mode 100644 index 0000000..ae3e740 --- /dev/null +++ b/deps/libnetfilter_queue/.gitignore @@ -0,0 +1,24 @@ +.deps/ +.libs/ +Makefile +Makefile.in +.dirstamp +*.o +*.la +*.lo + +/aclocal.m4 +/autom4te.cache/ +/build-aux/ +/config.* +/configure +/libtool +/stamp-h1 + +/doxygen/doxygen.cfg +/libnetfilter_queue.pc + +/examples/nf-queue +/doxygen/doxyfile.stamp +/doxygen/html/ +/doxygen/man/ diff --git a/deps/libnetfilter_queue/COPYING b/deps/libnetfilter_queue/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/Make_global.am b/deps/libnetfilter_queue/Make_global.am new file mode 100644 index 0000000..91da5da --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/Makefile.am b/deps/libnetfilter_queue/Makefile.am new file mode 100644 index 0000000..a5b347b --- /dev/null +++ b/deps/libnetfilter_queue/Makefile.am @@ -0,0 +1,12 @@ +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 diff --git a/deps/libnetfilter_queue/autogen.sh b/deps/libnetfilter_queue/autogen.sh new file mode 100755 index 0000000..57c3532 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/configure.ac b/deps/libnetfilter_queue/configure.ac new file mode 100644 index 0000000..7359fba --- /dev/null +++ b/deps/libnetfilter_queue/configure.ac @@ -0,0 +1,85 @@ +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-xz 1.6]) +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) + +dnl kernel style compile messages +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_ARG_ENABLE([html-doc], + AS_HELP_STRING([--enable-html-doc], [Enable html documentation]), + [], [enable_html_doc=no]) +AM_CONDITIONAL([BUILD_HTML], [test "$enable_html_doc" = yes]) +AS_IF([test "$enable_html_doc" = yes], + [AC_SUBST(GEN_HTML, YES)], + [AC_SUBST(GEN_HTML, NO)]) + +AC_ARG_ENABLE([man-pages], + AS_HELP_STRING([--disable-man-pages], [Disable man page documentation]), + [], [enable_man_pages=yes]) +AM_CONDITIONAL([BUILD_MAN], [test "$enable_man_pages" = yes]) +AS_IF([test "$enable_man_pages" = yes], + [AC_SUBST(GEN_MAN, YES)], + [AC_SUBST(GEN_MAN, NO)]) + +AC_PROG_CC +AM_PROG_CC_C_O +AC_DISABLE_STATIC +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]) + +AS_IF([test "$enable_man_pages" = no -a "$enable_html_doc" = no], + [with_doxygen=no], [with_doxygen=yes]) + +AS_IF([test "x$with_doxygen" != xno], [ + AC_CHECK_PROGS([DOXYGEN], [doxygen], [""]) + AC_CHECK_PROGS([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"]) +AS_IF([test "x$DOXYGEN" = x], [ + AS_IF([test "x$with_doxygen" != xno], [ + dnl Only run doxygen Makefile if doxygen installed + AC_MSG_WARN([Doxygen not found - not building documentation]) + enable_html_doc=no + enable_man_pages=no + ]) +], [ + dnl Warn user if html docs will be missing diagrams + AS_IF([test "$enable_html_doc" = yes -a -z "$DOT"], + AC_MSG_WARN([Dot not found - install graphviz to get interactive diagrams in HTML])) +]) + +dnl Output the makefiles +AC_CONFIG_FILES([Makefile src/Makefile utils/Makefile examples/Makefile + libnetfilter_queue.pc + include/Makefile include/libnetfilter_queue/Makefile + doxygen/Makefile doxygen/doxygen.cfg + include/linux/Makefile include/linux/netfilter/Makefile]) + +AC_OUTPUT + +echo " +libnetfilter_queue configuration: +man pages: ${enable_man_pages} +html docs: ${enable_html_doc}" diff --git a/deps/libnetfilter_queue/doxygen/Makefile.am b/deps/libnetfilter_queue/doxygen/Makefile.am new file mode 100644 index 0000000..68be963 --- /dev/null +++ b/deps/libnetfilter_queue/doxygen/Makefile.am @@ -0,0 +1,45 @@ +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/ipv4.c\ + $(top_srcdir)/src/extra/pktbuff.c\ + $(top_srcdir)/src/extra/ipv6.c\ + $(top_srcdir)/src/extra/tcp.c\ + $(top_srcdir)/src/extra/udp.c\ + $(top_srcdir)/src/extra/icmp.c + +doxyfile.stamp: $(doc_srcs) Makefile build_man.sh + rm -rf html man + doxygen doxygen.cfg >/dev/null + +if BUILD_MAN + $(abs_top_srcdir)/doxygen/build_man.sh libnetfilter_queue libnetfilter_queue.c +endif + + touch doxyfile.stamp + +CLEANFILES = doxyfile.stamp + +all-local: doxyfile.stamp +clean-local: + rm -rf man html +install-data-local: +if BUILD_MAN + mkdir -p $(DESTDIR)$(mandir)/man3 + cp --no-dereference --preserve=links,mode,timestamps man/man3/*.3\ + $(DESTDIR)$(mandir)/man3/ +endif +if BUILD_HTML + mkdir -p $(DESTDIR)$(htmldir) + cp --no-dereference --preserve=links,mode,timestamps html/*\ + $(DESTDIR)$(htmldir) +endif + +# make distcheck needs uninstall-local +uninstall-local: + rm -rf $(DESTDIR)$(mandir) man html doxyfile.stamp $(DESTDIR)$(htmldir) +endif + +EXTRA_DIST = build_man.sh diff --git a/deps/libnetfilter_queue/doxygen/build_man.sh b/deps/libnetfilter_queue/doxygen/build_man.sh new file mode 100755 index 0000000..7eab8fa --- /dev/null +++ b/deps/libnetfilter_queue/doxygen/build_man.sh @@ -0,0 +1,323 @@ +#!/bin/sh +[ -n "$BASH" ] || exec bash -p $0 $@ + +# Script to process man pages output by doxygen. +# We need to use bash for its associative array facility. +# (`bash -p` prevents import of functions from the environment). +# Args: none or 2 being man7 page name & relative path of source with \mainpage + +declare -A renamed_page + +main(){ + set -e + pushd man/man3 >/dev/null; rm -f _* + count_real_pages + rename_real_pages + make_symlinks + post_process $@ +} + +count_real_pages(){ + page_count=0 + # + # Count "real" man pages (i.e. not generated by MAN_LINKS) + # MAN_LINKS pages are 1-liners starting .so + # Method: list files in descending order of size, + # looking for the first 1-liner + # + for i in $(ls -S) + do head -n1 $i | grep -E -q '^\.so' && break + page_count=$(($page_count + 1)) + done + first_link=$(($page_count + 1)) +} + +rename_real_pages(){ + for i in $(ls -S | head -n$page_count) + do for j in $(ls -S | tail -n+$first_link) + do grep -E -q $i$ $j && break + done + mv -f $i $j + renamed_page[$i]=$j + done +} + +make_symlinks(){ + for j in $(ls -S | tail -n+$first_link) + do ln -sf ${renamed_page[$(cat $j | cut -f2 -d/)]} $j + done +} + +post_process(){ + make_temp_files + # + # DIAGNOSTIC / DEVELOPMENT CODE + # set -x and restrict processing to keep_me: un-comment to activate + # Change keep_me as required + # + #keep_me=nfq_icmp_get_hdr.3;\ + #do_diagnostics;\ + # + # Work through the "real" man pages + for target in $(ls -S | head -n$page_count) + do mygrep "^\\.SH \"Function Documentation" $target + # Next file if this isn't a function page + [ $linnum -ne 0 ] || continue + + del_modules + del_bogus_synopsis + fix_name_line + move_synopsis + del_empty_det_desc + del_def_at_lines + fix_double_blanks + + # Fix rendering of verbatim "\n" (in code snippets) + sed -i 's/\\n/\\\\n/' $target + + done + + [ $# -ne 2 ] || make_man7 $@ + + remove_temp_files +} + +make_man7(){ + popd >/dev/null + target=$(grep -Ew INPUT doxygen.cfg | rev | cut -f1 -d' ' | rev)/$2 + mypath=$(dirname $0) + + # Build up temporary source in temp.c + # (doxygen only makes man pages from .c files). + mygrep \\\\mainpage $target + tail -n+$((linnum-1)) $target | head -n1 >temp.c + echo " * \\defgroup $1 $1 overview" >>temp.c + tail -n+$((linnum+1)) $target >$fileA + linnum=$(grep -En '\*/' $fileA | head -n1 | cut -d: -f1) + head -n$((linnum - 1)) $fileA >> temp.c + + echo ' */' >> temp.c + cat >> temp.c <$fileC + for i in \ + PROJECT_NAME \ + PROJECT_NUMBER \ + ABBREVIATE_BRIEF \ + FULL_PATH_NAMES \ + TAB_SIZE \ + OPTIMIZE_OUTPUT_FOR_C \ + EXAMPLE_PATTERNS \ + ALPHABETICAL_INDEX \ + SEARCHENGINE \ + GENERATE_LATEX \ + ; do grep -Ew $i doxygen.cfg >>$fileC; done + cat >>$fileC </dev/null + + # Remove SYNOPSIS line if there is one + target=man/man7/$1.7 + mygrep "SH SYNOPSIS" $target + [ $linnum -eq 0 ] || delete_lines $linnum $((linnum+1)) + + # doxygen 1.8.9.1 and possibly newer run the first para into NAME + # (i.e. in this unusual group). There won't be a SYNOPSIS when this happens + if grep -Eq "overview$1" $target; then + head -n2 temp.c >$fileA + cat >>$fileA <>$fileA + cat $fileA >temp.c + doxygen $fileC >/dev/null + fi + + # Insert top-level "See also" of man7 page in all real man3 pages + for target in $(find man/man3 -type f) + do mygrep "Detailed Description" $target + [ $linnum -ne 0 ] || mygrep "Function Documentation" $target + [ $linnum -ne 0 ] || { echo "NO HEADER IN $target" >&2; continue; } + head -n$((linnum-1)) $target >$fileA + cat >>$fileA <>$fileA + cp $fileA $target + done + + rm temp.c +} + +fix_double_blanks(){ + linnum=1 + # + # Older versions of man display a blank line on encountering "\fB\fP"; + # newer versions of man do not. + # doxygen emits "\fB\fP" on seeing "\par" on a line by itself. + # "\par" gives us double-spacing in the web doc, which we want, but double- + # spacing looks odd in a man page so remove "\fB\fP". + # + while [ $linnum -ne 0 ] + do mygrep \\\\fB\\\\fP $target + [ $linnum -eq 0 ] || delete_lines $linnum $linnum + done +} + +del_def_at_lines(){ + linnum=1 + while [ $linnum -ne 0 ] + do mygrep '^Definition at line (\\fB)?[[:digit:]]*(\\fP)? of file' $target + [ $linnum -eq 0 ] || delete_lines $(($linnum - 1)) $linnum + done +} + +# Only invoked if you un-comment the 2 diagnostic / development lines above +do_diagnostics(){ + mv $keep_me xxx + rm *.3 + mv xxx $keep_me + page_count=1 + set -x +} + +del_empty_det_desc(){ + mygrep "^\\.SH \"Function Documentation" $target + i=$linnum + mygrep "^\\.SH \"Detailed Description" $target + [ $linnum -ne 0 ] || return 0 + [ $(($i - $linnum)) -eq 3 ] || return 0 + # A 1-line Detailed Description is also 3 lines long, + # but the 3rd line is not empty + i=$(($i -1)) + [ $(tail -n+$i $target | head -n1 | wc -c) -le 2 ] || return 0 + delete_lines $linnum $i +} + +move_synopsis(){ + mygrep "SH SYNOPSIS" $target + [ $linnum -ne 0 ] || return 0 + i=$linnum + # If this is a doxygen-created synopsis, leave it. + # (We haven't inserted our own one in the source yet) + mygrep "^\\.SS \"Functions" $target + [ $i -gt $linnum ] || return 0 + + mygrep "^\\.SH \"Function Documentation" $target + j=$(($linnum - 1)) + head -n$(($j - 1)) $target | tail -n$(($linnum - $i - 1)) >$fileC + delete_lines $i $j + mygrep "^\\.SS \"Functions" $target + head -n$(($linnum - 1)) $target >$fileA + tail -n+$(($linnum + 1)) $target >$fileB + cat $fileA $fileC $fileB >$target +} + +fix_name_line(){ + all_funcs="" + + # Search a shortened version of the page in case there are .RI lines later + mygrep "^\\.SH \"Function Documentation" $target + head -n$linnum $target >$fileC + + while : + do mygrep ^\\.RI $fileC + [ $linnum -ne 0 ] || break + # Discard this entry + tail -n+$(($linnum + 1)) $fileC >$fileB + cp $fileB $fileC + + func=$(cat $fileG | cut -f2 -d\\ | cut -c3-) + [ -z "$all_funcs" ] && all_funcs=$func ||\ + all_funcs="$all_funcs, $func" + done + # For now, assume name is at line 5 + head -n4 $target >$fileA + desc=$(head -n5 $target | tail -n1 | cut -f3- -d" ") + tail -n+6 $target >$fileB + cat $fileA >$target + echo "$all_funcs \\- $desc" >>$target + cat $fileB >>$target +} + +del_modules(){ + mygrep "^\.SS \"Modules" $target + [ $linnum -ne 0 ] || return 0 + i=$linnum + mygrep "^\\.SS \"Functions" $target + delete_lines $i $(($linnum - 1)) +} + +del_bogus_synopsis(){ + mygrep "SH SYNOPSIS" $target + # + # doxygen 1.8.20 inserts its own SYNOPSIS line but there is no mention + # in the documentation or git log what to do with it. + # So get rid of it + # + [ $linnum -ne 0 ] || return 0 + i=$linnum + # Look for the next one + tail -n+$(($i + 1)) $target >$fileC;\ + mygrep "SH SYNOPSIS" $fileC + [ $linnum -ne 0 ] || return 0 + + mygrep "^\\.SS \"Functions" $target + delete_lines $i $(($linnum - 1)) +} + +# Delete lines $1 through $2 from $target +delete_lines(){ + head -n$(($1 - 1)) $target >$fileA + tail -n+$(($2 +1)) $target >$fileB + cat $fileA $fileB >$target +} + +mygrep(){ + set +e + grep -En "$1" $2 2>/dev/null >$fileH + [ $? -ne 0 ] && linnum=0 ||\ + { head -n1 $fileH >$fileG; linnum=$(cat $fileG | cut -f1 -d:); } + set -e +} + +make_temp_files(){ + temps="A B C G H" + for i in $temps + do declare -g file$i=$(mktemp) + done +} + +remove_temp_files(){ + for i in $temps + do j=file$i + rm ${!j} + done +} + +main $@ diff --git a/deps/libnetfilter_queue/doxygen/doxygen.cfg.in b/deps/libnetfilter_queue/doxygen/doxygen.cfg.in new file mode 100644 index 0000000..97174ff --- /dev/null +++ b/deps/libnetfilter_queue/doxygen/doxygen.cfg.in @@ -0,0 +1,27 @@ +# Difference with default Doxyfile 1.8.20 +PROJECT_NAME = @PACKAGE@ +PROJECT_NUMBER = @VERSION@ +ABBREVIATE_BRIEF = +FULL_PATH_NAMES = NO +TAB_SIZE = 8 +OPTIMIZE_OUTPUT_FOR_C = YES +INPUT = @abs_top_srcdir@/src +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 = @GEN_MAN@ +GENERATE_HTML = @GEN_HTML@ +MAN_LINKS = YES +HAVE_DOT = @HAVE_DOT@ diff --git a/deps/libnetfilter_queue/examples/Makefile.am b/deps/libnetfilter_queue/examples/Makefile.am new file mode 100644 index 0000000..97bb70c --- /dev/null +++ b/deps/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 -lmnl +nf_queue_LDFLAGS = -dynamic diff --git a/deps/libnetfilter_queue/examples/nf-queue.c b/deps/libnetfilter_queue/examples/nf-queue.c new file mode 100644 index 0000000..1ae52e4 --- /dev/null +++ b/deps/libnetfilter_queue/examples/nf-queue.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/* NFQA_CT requires CTA_* attributes defined in nfnetlink_conntrack.h */ +#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; + + /* Parse netlink message received from the kernel, the array of + * attributes is set up to store metadata and the actual packet. + */ + if (nfq_nlmsg_parse(nlh, attr) < 0) { + perror("problems parsing"); + return MNL_CB_ERROR; + } + + nfg = mnl_nlmsg_get_payload(nlh); + + if (attr[NFQA_PACKET_HDR] == NULL) { + fputs("metaheader not set\n", stderr); + return MNL_CB_ERROR; + } + + /* Access packet metadata, which provides unique packet ID, hook number + * and ethertype. See struct nfqnl_msg_packet_hdr for details. + */ + ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]); + + /* Access actual packet data length. */ + plen = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]); + + /* Access actual packet data */ + /* void *payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]); */ + + /* Fetch metadata flags, possible flags values are: + * + * - NFQA_SKB_CSUMNOTREADY: + * Kernel performed partial checksum validation, see CHECKSUM_PARTIAL. + * - NFQA_SKB_CSUM_NOTVERIFIED: + * Kernel already verified checksum. + * - NFQA_SKB_GSO: + * Not the original packet received from the wire. Kernel has + * aggregated several packets into one single packet via GSO. + */ + skbinfo = attr[NFQA_SKB_INFO] ? ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])) : 0; + + /* Kernel has truncated the packet, fetch original packet length. */ + if (attr[NFQA_CAP_LEN]) { + uint32_t orig_len = ntohl(mnl_attr_get_u32(attr[NFQA_CAP_LEN])); + if (orig_len != plen) + 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); + + /* Fetch ethernet destination address. */ + if (attr[NFQA_HWADDR]) { + struct nfqnl_msg_packet_hw *hw = mnl_attr_get_payload(attr[NFQA_HWADDR]); + unsigned int hwlen = ntohs(hw->hw_addrlen); + const unsigned char *addr = hw->hw_addr; + unsigned int i; + + printf(", hwaddr %02x", addr[0]); + for (i = 1; i < hwlen; i++) { + if (i >= sizeof(hw->hw_addr)) { + printf("[truncated]"); + break; + } + printf(":%02x", (unsigned char)addr[i]); + } + + printf(" len %u", hwlen); + } + + /* + * ip/tcp checksums are not yet valid, e.g. due to GRO/GSO. + * The application should behave as if the checksums are correct. + * + * 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]); + + /* + * Set up netlink socket to communicate with the netfilter subsystem. + */ + 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); + } + + /* Configure the pipeline between kernel and userspace, build and send + * a netlink message to specify queue number to bind to. Your ruleset + * has to use this queue number to deliver packets to userspace. + */ + nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num); + nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_send"); + exit(EXIT_FAILURE); + } + + /* Build and send a netlink message to specify how many bytes are + * copied from kernel to userspace for this queue. + */ + nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num); + nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff); + + 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)); + + /* Loop forever on packets received from the kernel and run the + * callback handler. + */ + for (;;) { + ret = mnl_socket_recvfrom(nl, buf, sizeof_buf); + if (ret == -1) { + 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/deps/libnetfilter_queue/include/Makefile.am b/deps/libnetfilter_queue/include/Makefile.am new file mode 100644 index 0000000..54ea0b4 --- /dev/null +++ b/deps/libnetfilter_queue/include/Makefile.am @@ -0,0 +1 @@ +SUBDIRS= libnetfilter_queue linux diff --git a/deps/libnetfilter_queue/include/libnetfilter_queue/Makefile.am b/deps/libnetfilter_queue/include/libnetfilter_queue/Makefile.am new file mode 100644 index 0000000..e436bab --- /dev/null +++ b/deps/libnetfilter_queue/include/libnetfilter_queue/Makefile.am @@ -0,0 +1,8 @@ +pkginclude_HEADERS = libnetfilter_queue.h \ + linux_nfnetlink_queue.h \ + libnetfilter_queue_icmp.h \ + libnetfilter_queue_ipv4.h \ + libnetfilter_queue_ipv6.h \ + libnetfilter_queue_tcp.h \ + libnetfilter_queue_udp.h \ + pktbuff.h diff --git a/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue.h b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue.h new file mode 100644 index 0000000..f7e68d8 --- /dev/null +++ b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue.h @@ -0,0 +1,160 @@ +/* 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); +struct nlmsghdr *nfq_nlmsg_put2(char *buf, int type, uint32_t queue_num, uint16_t flags); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __LIBNFQNETLINK_H */ diff --git a/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_icmp.h b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_icmp.h new file mode 100644 index 0000000..9a8bd52 --- /dev/null +++ b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_icmp.h @@ -0,0 +1,8 @@ +#ifndef _LIBNFQUEUE_ICMP_H_ +#define _LIBNFQUEUE_ICMP_H_ + +struct pkt_buff; + +struct icmphdr *nfq_icmp_get_hdr(struct pkt_buff *pktb); + +#endif diff --git a/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_ipv4.h b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_ipv4.h new file mode 100644 index 0000000..17be93e --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_ipv6.h b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_ipv6.h new file mode 100644 index 0000000..c0a7d37 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_tcp.h b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_tcp.h new file mode 100644 index 0000000..e1b9690 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_udp.h b/deps/libnetfilter_queue/include/libnetfilter_queue/libnetfilter_queue_udp.h new file mode 100644 index 0000000..9d594f2 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/include/libnetfilter_queue/linux_nfnetlink_queue.h b/deps/libnetfilter_queue/include/libnetfilter_queue/linux_nfnetlink_queue.h new file mode 100644 index 0000000..6844270 --- /dev/null +++ b/deps/libnetfilter_queue/include/libnetfilter_queue/linux_nfnetlink_queue.h @@ -0,0 +1,123 @@ +#ifndef _NFNETLINK_QUEUE_H +#define _NFNETLINK_QUEUE_H + +#warning "libnetfilter_queue/linux_nfnetlink_queue.h is deprecated, add #include to your source code before #include " + +#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, /* nfnetlink_conntrack.h */ + NFQA_CT_INFO, /* enum ip_conntrack_info */ + NFQA_CAP_LEN, /* __u32 length of captured packet */ + NFQA_SKB_INFO, /* __u32 skb meta information */ + NFQA_EXP, /* nfnetlink_conntrack.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/deps/libnetfilter_queue/include/libnetfilter_queue/pktbuff.h b/deps/libnetfilter_queue/include/libnetfilter_queue/pktbuff.h new file mode 100644 index 0000000..d3588c7 --- /dev/null +++ b/deps/libnetfilter_queue/include/libnetfilter_queue/pktbuff.h @@ -0,0 +1,31 @@ +#ifndef _PKTBUFF_H_ +#define _PKTBUFF_H_ + +#include + +struct pkt_buff; + +struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra); +void pktb_free(struct pkt_buff *pktb); + +struct pkt_buff *pktb_setup_raw(void *pktb, int family, void *data, size_t len, size_t extra); +size_t pktb_head_size(void); + +uint8_t *pktb_data(struct pkt_buff *pktb); +uint32_t pktb_len(struct pkt_buff *pktb); + +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/deps/libnetfilter_queue/include/linux/Makefile.am b/deps/libnetfilter_queue/include/linux/Makefile.am new file mode 100644 index 0000000..38eb109 --- /dev/null +++ b/deps/libnetfilter_queue/include/linux/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = netfilter diff --git a/deps/libnetfilter_queue/include/linux/netfilter/Makefile.am b/deps/libnetfilter_queue/include/linux/netfilter/Makefile.am new file mode 100644 index 0000000..d0937cb --- /dev/null +++ b/deps/libnetfilter_queue/include/linux/netfilter/Makefile.am @@ -0,0 +1 @@ +noinst_HEADERS = nfnetlink_queue.h diff --git a/deps/libnetfilter_queue/include/linux/netfilter/nfnetlink_queue.h b/deps/libnetfilter_queue/include/linux/netfilter/nfnetlink_queue.h new file mode 100644 index 0000000..8e2e469 --- /dev/null +++ b/deps/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, /* nfnetlink_conntrack.h */ + NFQA_CT_INFO, /* enum ip_conntrack_info */ + NFQA_CAP_LEN, /* __u32 length of captured packet */ + NFQA_SKB_INFO, /* __u32 skb meta information */ + NFQA_EXP, /* nfnetlink_conntrack.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/deps/libnetfilter_queue/libnetfilter_queue.pc.in b/deps/libnetfilter_queue/libnetfilter_queue.pc.in new file mode 100644 index 0000000..9c6c2c4 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/m4/.gitignore b/deps/libnetfilter_queue/m4/.gitignore new file mode 100644 index 0000000..64d9bbc --- /dev/null +++ b/deps/libnetfilter_queue/m4/.gitignore @@ -0,0 +1,2 @@ +/libtool.m4 +/lt*.m4 diff --git a/deps/libnetfilter_queue/m4/gcc4_visibility.m4 b/deps/libnetfilter_queue/m4/gcc4_visibility.m4 new file mode 100644 index 0000000..214d3f3 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/src/Makefile.am b/deps/libnetfilter_queue/src/Makefile.am new file mode 100644 index 0000000..079853e --- /dev/null +++ b/deps/libnetfilter_queue/src/Makefile.am @@ -0,0 +1,41 @@ +# 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 \ + -version-info $(LIBVERSION) +libnetfilter_queue_la_SOURCES = libnetfilter_queue.c \ + nlmsg.c \ + extra/checksum.c \ + extra/icmp.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/deps/libnetfilter_queue/src/extra/checksum.c b/deps/libnetfilter_queue/src/extra/checksum.c new file mode 100644 index 0000000..33480af --- /dev/null +++ b/deps/libnetfilter_queue/src/extra/checksum.c @@ -0,0 +1,83 @@ +/* + * (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 + +#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/deps/libnetfilter_queue/src/extra/icmp.c b/deps/libnetfilter_queue/src/extra/icmp.c new file mode 100644 index 0000000..eaade7b --- /dev/null +++ b/deps/libnetfilter_queue/src/extra/icmp.c @@ -0,0 +1,57 @@ +/* + * (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 +#define _GNU_SOURCE +#include + +#include + +#include "internal.h" + +/** + * \defgroup icmp ICMP helper functions + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * nfq_icmp_get_hdr - get the ICMP header. + * \param pktb: pointer to user-space network packet buffer + * \returns validated pointer to the ICMP header or NULL if the ICMP 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 ICMP header. + */ +EXPORT_SYMBOL +struct icmphdr *nfq_icmp_get_hdr(struct pkt_buff *pktb) +{ + if (pktb->transport_header == NULL) + return NULL; + + /* No room for the ICMP header. */ + if (pktb_tail(pktb) - pktb->transport_header < sizeof(struct icmphdr)) + return NULL; + + return (struct icmphdr *)pktb->transport_header; +} + +/** + * @} + */ diff --git a/deps/libnetfilter_queue/src/extra/ipv4.c b/deps/libnetfilter_queue/src/extra/ipv4.c new file mode 100644 index 0000000..58fb471 --- /dev/null +++ b/deps/libnetfilter_queue/src/extra/ipv4.c @@ -0,0 +1,194 @@ +/* + * (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 ipv4 IPv4 helper functions + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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. + * + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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_ip_snprintf - print IPv4 header into buffer in iptables LOG format + * \param buf: Pointer to buffer that will be used to print the header + * \param size: Size of the buffer (or remaining room in it) + * \param iph: Pointer to a valid IPv4 header + * \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/deps/libnetfilter_queue/src/extra/ipv6.c b/deps/libnetfilter_queue/src/extra/ipv6.c new file mode 100644 index 0000000..fd8ebc4 --- /dev/null +++ b/deps/libnetfilter_queue/src/extra/ipv6.c @@ -0,0 +1,203 @@ +/* + * (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 + +#include "internal.h" + +/** + * \defgroup ipv6 IPv6 helper functions + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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 == IPPROTO_HOPOPTS || + nexthdr == IPPROTO_ROUTING || + nexthdr == IPPROTO_FRAGMENT || + nexthdr == IPPROTO_AH || + nexthdr == IPPROTO_NONE || + nexthdr == IPPROTO_DSTOPTS) { + struct ip6_ext *ip6_ext; + uint32_t hdrlen; + + /* Extension header was requested, we're done. */ + if (nexthdr == target) + break; + + /* 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 + 1) << 3; + + nexthdr = ip6_ext->ip6e_nxt; + cur += hdrlen; + } + if (nexthdr != target) + cur = NULL; + 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/deps/libnetfilter_queue/src/extra/pktbuff.c b/deps/libnetfilter_queue/src/extra/pktbuff.c new file mode 100644 index 0000000..40d2250 --- /dev/null +++ b/deps/libnetfilter_queue/src/extra/pktbuff.c @@ -0,0 +1,455 @@ +/* + * (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 + * + * These functions provide the user-space network packet buffer. + * This abstraction is strongly inspired by Linux kernel network buffer, + * the so-called sk_buff. + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +static int __pktb_setup(int family, struct pkt_buff *pktb) +{ + struct ethhdr *ethhdr; + + switch (family) { + case AF_INET: + case AF_INET6: + pktb->network_header = pktb->data; + break; + case AF_BRIDGE: + ethhdr = (struct ethhdr *)pktb->data; + pktb->mac_header = pktb->data; + + switch(ethhdr->h_proto) { + case ETH_P_IP: + case ETH_P_IPV6: + pktb->network_header = pktb->data + ETH_HLEN; + break; + default: + /* This protocol is unsupported. */ + errno = EPROTONOSUPPORT; + return -1; + } + break; + } + + return 0; +} + +static void pktb_setup_metadata(struct pkt_buff *pktb, void *pkt_data, + size_t len, size_t extra) +{ + pktb->len = len; + pktb->data_len = len + extra; + pktb->data = pkt_data; +} + +/** + * pktb_alloc - allocate a new packet buffer + * \param family Indicate what family. Currently supported families are + * 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). This function copies + * the memory area provided as a pointer to packet data into the packet buffer + * structure. + * + * The extra length provides extra packet data room at the tail of the packet + * buffer in case you need to mangle it. + * + * \return Pointer to a new userspace packet buffer or NULL on failure. + * \par Errors + * __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; + 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_setup_metadata(pktb, pkt_data, len, extra); + + if (__pktb_setup(family, pktb) < 0) { + free(pktb); + return NULL; + } + + return pktb; +} + +/** + * pktb_setup_raw - set up a packet buffer from memory area + * \param pktb Pointer to memory of length pktb_head_size() bytes + * \param family Supported families are AF_BRIDGE, AF_INET & AF_INET6. + * \param data Pointer to packet data + * \param len Packet data length + * \param extra Extra memory available after packet data (for mangling). + * + * Use this function to set up a packet buffer from a memory area, minimum size + * of such memory area must be pktb_head_size(). This function attaches the + * packet data that is provided to the packet buffer (data is not copied). Use + * this function as an alternative to the pktb_alloc() interface for more + * control on memory management. + * + * \return Pointer to a new userspace packet buffer or NULL on failure. + * \par Errors + * __EPROTONOSUPPORT__ _family_ was __AF_BRIDGE__ and this is not an IP packet + * (v4 or v6) + */ +EXPORT_SYMBOL +struct pkt_buff *pktb_setup_raw(void *pktb, int family, void *data, + size_t len, size_t extra) +{ + memset(pktb, 0, sizeof (struct pkt_buff)); + pktb_setup_metadata(pktb, data, len, extra); + if (__pktb_setup(family, pktb) < 0) + pktb = NULL; + + 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 + * + * 2. Internal functions, described in Module __Internal functions__ + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * \defgroup do_not_use Internal functions + * + * Do not use these functions. Instead, always use the mangle + * function appropriate to the level at which you are working. + * \n + * pktb_mangle() uses all the below functions except _pktb_pull_, which is not + * used by anything. + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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(), nfq_udp_mangle_ipv4() or IPv6 variants. + \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; +} + +/** + * pktb_head_size - get number of bytes needed for a packet buffer + * (control part only) + * \return size of struct pkt_buff + */ + +EXPORT_SYMBOL +size_t pktb_head_size(void) +{ + return sizeof(struct pkt_buff); +} + +/** + * @} + */ diff --git a/deps/libnetfilter_queue/src/extra/tcp.c b/deps/libnetfilter_queue/src/extra/tcp.c new file mode 100644 index 0000000..720afd2 --- /dev/null +++ b/deps/libnetfilter_queue/src/extra/tcp.c @@ -0,0 +1,300 @@ +/* + * (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 + +#include "internal.h" + +/** + * \defgroup tcp TCP helper functions + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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. + * + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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/deps/libnetfilter_queue/src/extra/udp.c b/deps/libnetfilter_queue/src/extra/udp.c new file mode 100644 index 0000000..ede2196 --- /dev/null +++ b/deps/libnetfilter_queue/src/extra/udp.c @@ -0,0 +1,249 @@ +/* + * (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 + +#include "internal.h" + +/** + * \defgroup udp UDP helper functions + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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. + * + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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/deps/libnetfilter_queue/src/internal.h b/deps/libnetfilter_queue/src/internal.h new file mode 100644 index 0000000..ae849d6 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/src/libnetfilter_queue.c b/deps/libnetfilter_queue/src/libnetfilter_queue.c new file mode 100644 index 0000000..bf67a19 --- /dev/null +++ b/deps/libnetfilter_queue/src/libnetfilter_queue.c @@ -0,0 +1,1581 @@ +/* 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 +#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/ + * +

Dependencies

+ * libnetfilter_queue requires libmnl, libnfnetlink and a kernel that includes + * the Netfilter NFQUEUE over NFNETLINK interface (i.e. 2.6.14 or later). + * + *

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. + * + *

Git Tree

+ * The current development version of libnetfilter_queue can be accessed at + * https://git.netfilter.org/libnetfilter_queue. + * + *

Privileges

+ * You need the CAP_NET_ADMIN capability in order to allow your application + * to receive from and to send packets to kernel-space. + * + *

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 + * \htmlonly +LibrarySetup +\endhtmlonly + * \manonly +\fBLibrarySetup\fP\ +\endmanonly + * is Deprecated and + * incompatible with non-deprecated functions. It is hoped to produce a + * corresponding non-deprecated (*Current*) topic soon. + * + * 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/ + * + *

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. + * + *

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) + * - make your application offload aware to avoid costly normalization on kernel + * side. See NFQA_CFG_F_GSO flag to nfq_set_queue_flags(). + * Linux kernel >= 3.10. + * - increase queue max length with nfq_set_queue_maxlen() to resist to packets + * burst + */ + +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 chosen, the verdict has to be given + * by calling nfq_set_verdict() or nfq_set_verdict2(). The verdict + * determines the destiny of the packet as follows: + * + * - 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 fetched by using message parsing + * functions (See \link Parsing \endlink). + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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. + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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] + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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] + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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/deps/libnetfilter_queue/src/nlmsg.c b/deps/libnetfilter_queue/src/nlmsg.c new file mode 100644 index 0000000..39fd12d --- /dev/null +++ b/deps/libnetfilter_queue/src/nlmsg.c @@ -0,0 +1,383 @@ +/* + * (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 + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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 + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +/** + * 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 + * + * \manonly +.SH SYNOPSIS +.nf +\fB +#include +#include +\endmanonly + * + * @{ + */ + +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_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: + case NFQA_SECCTX: + 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) +{ + return nfq_nlmsg_put2(buf, type, queue_num, 0); +} + +/** + * nfq_nlmsg_put2 - Set up a netlink header with user-specified flags + * in a memory buffer + * \param *buf Pointer to memory buffer + * \param type One of NFQNL_MSG_CONFIG, NFQNL_MSG_VERDICT + * or NFQNL_MSG_VERDICT_BATCH + * \param queue_num Queue number + * \param flags additional NLM_F_xxx flags to put in message header. These are + * defined in /usr/include/linux/netlink.h. nfq_nlmsg_put2() always + * sets NLM_F_REQUEST + * \returns Pointer to netlink header + * + * For most applications, the only sensible flag will be NLM_F_ACK. + * Use it to get an explicit acknowledgment from the kernel, e.g. + * attempt to configure NFQA_CFG_F_SECCTX on a kernel not supporting + * CONFIG_NETWORK_SECMARK. + * \n + * The kernel always sends a message in response to a failed command. + * NLM_F_ACK instructs the kernel to also send a message in response + * to a successful command. + * \n + * This code snippet demonstrates reading these responses: + * \verbatim + char buf[MNL_SOCKET_BUFFER_SIZE]; + + nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, queue_num, + NLM_F_ACK); + mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, NFQA_CFG_F_SECCTX); + mnl_attr_put_u32(nlh, NFQA_CFG_MASK, NFQA_CFG_F_SECCTX); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { + perror("mnl_socket_send"); + exit(EXIT_FAILURE); + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof buf); + if (ret == -1) { + perror("mnl_socket_recvfrom"); + exit(EXIT_FAILURE); + } + + ret = mnl_cb_run(buf, ret, 0, portid, NULL, NULL); + if (ret == -1) + fprintf(stderr, "This kernel version does not allow to " + "retrieve security context.\n"); +\endverbatim + * + */ + +EXPORT_SYMBOL +struct nlmsghdr *nfq_nlmsg_put2(char *buf, int type, uint32_t queue_num, + uint16_t flags) +{ + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | type; + nlh->nlmsg_flags = NLM_F_REQUEST | flags; + + 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/deps/libnetfilter_queue/utils/.gitignore b/deps/libnetfilter_queue/utils/.gitignore new file mode 100644 index 0000000..10fe6e9 --- /dev/null +++ b/deps/libnetfilter_queue/utils/.gitignore @@ -0,0 +1 @@ +/nfqnl_test diff --git a/deps/libnetfilter_queue/utils/Makefile.am b/deps/libnetfilter_queue/utils/Makefile.am new file mode 100644 index 0000000..d3147e3 --- /dev/null +++ b/deps/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/deps/libnetfilter_queue/utils/nfqnl_test.c b/deps/libnetfilter_queue/utils/nfqnl_test.c new file mode 100644 index 0000000..682f3d7 --- /dev/null +++ b/deps/libnetfilter_queue/utils/nfqnl_test.c @@ -0,0 +1,187 @@ + +#include +#include +#include +#include +#include +#include /* for NF_ACCEPT */ +#include +#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/deps/libnfnetlink/.gitignore b/deps/libnfnetlink/.gitignore new file mode 100644 index 0000000..6bf816e --- /dev/null +++ b/deps/libnfnetlink/.gitignore @@ -0,0 +1,17 @@ +.deps/ +.libs/ +Makefile +Makefile.in +*.o +*.la +*.lo + +/aclocal.m4 +/autom4te.cache/ +/build-aux/ +/config.* +/configure +/libtool +/stamp-h1 + +/*.pc diff --git a/deps/libnfnetlink/COPYING b/deps/libnfnetlink/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/deps/libnfnetlink/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/deps/libnfnetlink/Make_global.am b/deps/libnfnetlink/Make_global.am new file mode 100644 index 0000000..3d2dd5e --- /dev/null +++ b/deps/libnfnetlink/Make_global.am @@ -0,0 +1,8 @@ +# This is _NOT_ the library release version, it's an API version. +# Please read Chapter 6 "Library interface versions" of the libtool +# documentation before making any modification +# http://sources.redhat.com/autobook/autobook/autobook_91.html +LIBVERSION=2:0:2 + +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -Wall -fvisibility=hidden -D'NFNL_EXPORT=__attribute__((visibility("default")))' diff --git a/deps/libnfnetlink/Makefile.am b/deps/libnfnetlink/Makefile.am new file mode 100644 index 0000000..d38da7d --- /dev/null +++ b/deps/libnfnetlink/Makefile.am @@ -0,0 +1,16 @@ +include $(top_srcdir)/Make_global.am + +ACLOCAL_AMFLAGS = -I m4 + +EXTRA_DIST = $(man_MANS) + +SUBDIRS = src include utils +DIST_SUBDIRS = src include utils + +man_MANS = #nfnetlink.3 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libnfnetlink.pc + +dist-hook: + rm -rf `find $(distdir)/debian -name .svn` diff --git a/deps/libnfnetlink/README b/deps/libnfnetlink/README new file mode 100644 index 0000000..4a5631d --- /dev/null +++ b/deps/libnfnetlink/README @@ -0,0 +1,50 @@ +libnfnetlink - userspace library for handling of netfilter netlink messages +(C) 2001-2005 Netfilter Core Team +=========================================================================== + +What is nfnetlink? + +nfnetlink is a netlink(7) based kernel/userspace transport layer. It +provides a unified kernel/userspace interface for the various netfilter +subsystems, such as connection tracking, logging and queueing. + + +What is libnfnetlink? + +libnfnetlink is a userspace library that provides some low-level +nfnetlink handling functions. It is used as a foundation for other, netfilter +subsystem specific libraries such as libnfnetlink_conntrack, libnfnetlink_log +and libnfnetlink_queue. + + +Prerequirements for libnfnetlink + +You will need kernel headers from a kernel that has nfnetlink support. The +first official kernel release to include nfnetlink support is 2.6.14. +You can specify the location of your kernel sources using the "--with-kernel=" +configure option. + + +Where can I find documentation? + +At the moment, you will have to RTFS. Sorry, but we have barely enough +manpower to keep development ongoing. If you want to conribute documentation, +please contact us. + + +It has bugs. Where do I report them? + +Please report all libnfnetlink bugs to https://bugzilla.netfilter.org/, using +the "libnfnetlink" Product. + + +License + +This library is released under GPLv2+. + + +Where do I get support? + +The netfilter@lists.netfilter.org and netfilter-devel@lists.netfilter.org +mailinglists server as support forum. + diff --git a/deps/libnfnetlink/autogen.sh b/deps/libnfnetlink/autogen.sh new file mode 100755 index 0000000..f320a0c --- /dev/null +++ b/deps/libnfnetlink/autogen.sh @@ -0,0 +1,37 @@ +#!/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.h ] + then + TARGET=include/libnfnetlink/linux_nfnetlink.h + echo "Copying nfnetlink.h to linux_nfnetlink.h" + cp $INCLUDEDIR/netfilter/nfnetlink.h $TARGET + TMP=`mktemp` + sed 's/#include /#include /g' $TARGET > $TMP + cp $TMP $TARGET + else + echo "can't find nfnetlink.h kernel file in $INCLUDEDIR" + exit 1 + fi + + if [ -f $INCLUDEDIR/netfilter/nfnetlink_compat.h ] + then + TARGET=include/libnfnetlink/linux_nfnetlink_compat.h + echo "Copying nfnetlink_compat.h to linux_nfnetlink_compat.h" + cp $INCLUDEDIR/netfilter/nfnetlink_compat.h $TARGET + else + echo "can't find nfnetlink.h kernel file in $INCLUDEDIR, ignoring" + fi +} + +[ "x$1" = "xdistrib" ] && include +autoreconf -fi +rm -Rf autom4te.cache diff --git a/deps/libnfnetlink/configure.ac b/deps/libnfnetlink/configure.ac new file mode 100644 index 0000000..4593824 --- /dev/null +++ b/deps/libnfnetlink/configure.ac @@ -0,0 +1,33 @@ +dnl Process this file with autoconf to create configure. + +AC_INIT(libnfnetlink, 1.0.2) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects + tar-pax no-dist-gzip dist-xz 1.6]) +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) + +dnl kernel style compile messages +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PROG_CC +AM_PROG_CC_C_O +AC_DISABLE_STATIC +AM_PROG_LIBTOOL + +case "$host" in +*-*-linux* | *-*-uclinux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + + +dnl-------------------------------- +dnl-------------------------------- + + +dnl Output the makefile +AC_CONFIG_FILES([Makefile src/Makefile include/Makefile doxygen.cfg + include/libnfnetlink/Makefile utils/Makefile libnfnetlink.pc]) +AC_OUTPUT diff --git a/deps/libnfnetlink/doxygen.cfg b/deps/libnfnetlink/doxygen.cfg new file mode 100644 index 0000000..cedc44d --- /dev/null +++ b/deps/libnfnetlink/doxygen.cfg @@ -0,0 +1,180 @@ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = libnfnetlink +PROJECT_NUMBER = 1.0.2 +OUTPUT_DIRECTORY = doxygen +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +FILE_VERSION_FILTER = +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +INPUT = . +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c libnfnetlink.h +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */.git/* .*.d +EXCLUDE_SYMBOLS = EXPORT_SYMBOL +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_STYLESHEET = +GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +SEARCHENGINE = NO diff --git a/deps/libnfnetlink/doxygen.cfg.in b/deps/libnfnetlink/doxygen.cfg.in new file mode 100644 index 0000000..eba08e0 --- /dev/null +++ b/deps/libnfnetlink/doxygen.cfg.in @@ -0,0 +1,180 @@ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = @PACKAGE@ +PROJECT_NUMBER = @VERSION@ +OUTPUT_DIRECTORY = doxygen +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +FILE_VERSION_FILTER = +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +INPUT = . +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c libnfnetlink.h +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */.git/* .*.d +EXCLUDE_SYMBOLS = EXPORT_SYMBOL +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_STYLESHEET = +GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +SEARCHENGINE = NO diff --git a/deps/libnfnetlink/include/Makefile.am b/deps/libnfnetlink/include/Makefile.am new file mode 100644 index 0000000..288c711 --- /dev/null +++ b/deps/libnfnetlink/include/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = libnfnetlink +noinst_HEADERS = linux_list.h diff --git a/deps/libnfnetlink/include/libnfnetlink/Makefile.am b/deps/libnfnetlink/include/libnfnetlink/Makefile.am new file mode 100644 index 0000000..76128c8 --- /dev/null +++ b/deps/libnfnetlink/include/libnfnetlink/Makefile.am @@ -0,0 +1,3 @@ + +pkginclude_HEADERS = libnfnetlink.h linux_nfnetlink.h linux_nfnetlink_compat.h + diff --git a/deps/libnfnetlink/include/libnfnetlink/libnfnetlink.h b/deps/libnfnetlink/include/libnfnetlink/libnfnetlink.h new file mode 100644 index 0000000..49ce878 --- /dev/null +++ b/deps/libnfnetlink/include/libnfnetlink/libnfnetlink.h @@ -0,0 +1,267 @@ +/* libnfnetlink.h: Header file for generic netfilter netlink interface + * + * (C) 2002 Harald Welte + * + * 2005-10-29 Pablo Neira Ayuso : + * Fix NFNL_HEADER_LEN + * 2005-11-13 Pablo Neira Ayuso : + * Define NETLINK_NETFILTER if it's undefined + */ + +#ifndef __LIBNFNETLINK_H +#define __LIBNFNETLINK_H + +#ifndef aligned_u64 +#define aligned_u64 unsigned long long __attribute__((aligned(8))) +#endif + +#include +#include /* for sa_family_t */ +#include +#include + +#ifndef NETLINK_NETFILTER +#define NETLINK_NETFILTER 12 +#endif + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +#ifndef NETLINK_BROADCAST_SEND_ERROR +#define NETLINK_BROADCAST_SEND_ERROR 4 +#endif + +#ifndef NETLINK_NO_ENOBUFS +#define NETLINK_NO_ENOBUFS 5 +#endif + +#define NLMSG_TAIL(nlh) \ + (((void *) (nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)) + +#define NFNL_HEADER_LEN (NLMSG_ALIGN(sizeof(struct nlmsghdr)) \ + +NLMSG_ALIGN(sizeof(struct nfgenmsg))) + +#define NFNL_BUFFSIZE 8192 + +#ifndef NFNL_EXPORT +#define NFNL_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct nfnlhdr { + struct nlmsghdr nlh; + struct nfgenmsg nfmsg; +}; + +struct nfnl_callback { + int (*call)(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data); + void *data; + uint16_t attr_count; +}; + +struct nfnl_handle; +struct nfnl_subsys_handle; + +extern NFNL_EXPORT int nfnl_fd(struct nfnl_handle *h); +extern NFNL_EXPORT unsigned int nfnl_portid(const struct nfnl_handle *h); + +/* get a new library handle */ +extern NFNL_EXPORT struct nfnl_handle *nfnl_open(void); +extern NFNL_EXPORT int nfnl_close(struct nfnl_handle *); + +extern NFNL_EXPORT struct nfnl_subsys_handle *nfnl_subsys_open(struct nfnl_handle *, + uint8_t, uint8_t, + unsigned int); +extern NFNL_EXPORT void nfnl_subsys_close(struct nfnl_subsys_handle *); + +/* set and unset sequence tracking */ +extern NFNL_EXPORT void nfnl_set_sequence_tracking(struct nfnl_handle *h); +extern NFNL_EXPORT void nfnl_unset_sequence_tracking(struct nfnl_handle *h); + +/* set receive buffer size (for nfnl_catch) */ +extern NFNL_EXPORT void nfnl_set_rcv_buffer_size(struct nfnl_handle *h, unsigned int size); + +/* sending of data */ +extern NFNL_EXPORT int nfnl_send(struct nfnl_handle *, struct nlmsghdr *); +extern NFNL_EXPORT int nfnl_sendmsg(const struct nfnl_handle *, const struct msghdr *msg, + unsigned int flags); +extern NFNL_EXPORT int nfnl_sendiov(const struct nfnl_handle *nfnlh, + const struct iovec *iov, unsigned int num, + unsigned int flags); +extern NFNL_EXPORT void nfnl_fill_hdr(struct nfnl_subsys_handle *, struct nlmsghdr *, + unsigned int, uint8_t, uint16_t, uint16_t, + uint16_t); +extern NFNL_EXPORT __attribute__((deprecated)) int +nfnl_talk(struct nfnl_handle *, struct nlmsghdr *, pid_t, + unsigned, struct nlmsghdr *, + int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *), void *); + +/* simple challenge/response */ +extern NFNL_EXPORT __attribute__((deprecated)) int +nfnl_listen(struct nfnl_handle *, + int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *), void *); + +/* receiving */ +extern NFNL_EXPORT ssize_t nfnl_recv(const struct nfnl_handle *h, unsigned char *buf, size_t len); +extern NFNL_EXPORT int nfnl_callback_register(struct nfnl_subsys_handle *, + uint8_t type, struct nfnl_callback *cb); +extern NFNL_EXPORT int nfnl_callback_unregister(struct nfnl_subsys_handle *, uint8_t type); +extern NFNL_EXPORT int nfnl_handle_packet(struct nfnl_handle *, char *buf, int len); + +/* parsing */ +extern NFNL_EXPORT struct nfattr *nfnl_parse_hdr(const struct nfnl_handle *nfnlh, + const struct nlmsghdr *nlh, + struct nfgenmsg **genmsg); +extern NFNL_EXPORT int nfnl_check_attributes(const struct nfnl_handle *nfnlh, + const struct nlmsghdr *nlh, + struct nfattr *tb[]); +extern NFNL_EXPORT struct nlmsghdr *nfnl_get_msg_first(struct nfnl_handle *h, + const unsigned char *buf, + size_t len); +extern NFNL_EXPORT struct nlmsghdr *nfnl_get_msg_next(struct nfnl_handle *h, + const unsigned char *buf, + size_t len); + +/* callback verdict */ +enum { + NFNL_CB_FAILURE = -1, /* failure */ + NFNL_CB_STOP = 0, /* stop the query */ + NFNL_CB_CONTINUE = 1, /* keep iterating */ +}; + +/* join a certain netlink multicast group */ +extern NFNL_EXPORT int nfnl_join(const struct nfnl_handle *nfnlh, unsigned int group); + +/* process a netlink message */ +extern NFNL_EXPORT int nfnl_process(struct nfnl_handle *h, + const unsigned char *buf, + size_t len); + +/* iterator API */ + +extern NFNL_EXPORT struct nfnl_iterator * +nfnl_iterator_create(const struct nfnl_handle *h, + const char *buf, + size_t len); + +extern NFNL_EXPORT void nfnl_iterator_destroy(struct nfnl_iterator *it); + +extern NFNL_EXPORT int nfnl_iterator_process(struct nfnl_handle *h, + struct nfnl_iterator *it); + +extern NFNL_EXPORT int nfnl_iterator_next(const struct nfnl_handle *h, + struct nfnl_iterator *it); + +/* replacement for nfnl_listen */ +extern NFNL_EXPORT int nfnl_catch(struct nfnl_handle *h); + +/* replacement for nfnl_talk */ +extern NFNL_EXPORT int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh); + +#define nfnl_attr_present(tb, attr) \ + (tb[attr-1]) + +#define nfnl_get_data(tb, attr, type) \ + ({ type __ret = 0; \ + if (tb[attr-1]) \ + __ret = *(type *)NFA_DATA(tb[attr-1]); \ + __ret; \ + }) + +#define nfnl_get_pointer_to_data(tb, attr, type) \ + ({ type *__ret = NULL; \ + if (tb[attr-1]) \ + __ret = NFA_DATA(tb[attr-1]); \ + __ret; \ + }) + +#ifndef NLA_F_NESTED +#define NLA_F_NESTED (1 << 15) +#endif + +/* nfnl attribute handling functions */ +extern NFNL_EXPORT int nfnl_addattr_l(struct nlmsghdr *, int, int, const void *, int); +extern NFNL_EXPORT int nfnl_addattr8(struct nlmsghdr *, int, int, uint8_t); +extern NFNL_EXPORT int nfnl_addattr16(struct nlmsghdr *, int, int, uint16_t); +extern NFNL_EXPORT int nfnl_addattr32(struct nlmsghdr *, int, int, uint32_t); +extern NFNL_EXPORT int nfnl_nfa_addattr_l(struct nfattr *, int, int, const void *, int); +extern NFNL_EXPORT int nfnl_nfa_addattr16(struct nfattr *, int, int, uint16_t); +extern NFNL_EXPORT int nfnl_nfa_addattr32(struct nfattr *, int, int, uint32_t); +extern NFNL_EXPORT int nfnl_parse_attr(struct nfattr **, int, struct nfattr *, int); +#define nfnl_parse_nested(tb, max, nfa) \ + nfnl_parse_attr((tb), (max), NFA_DATA((nfa)), NFA_PAYLOAD((nfa))) +#define nfnl_nest(nlh, bufsize, type) \ +({ struct nfattr *__start = NLMSG_TAIL(nlh); \ + nfnl_addattr_l(nlh, bufsize, (NLA_F_NESTED | type), NULL, 0); \ + __start; }) +#define nfnl_nest_end(nlh, tail) \ +({ (tail)->nfa_len = (void *) NLMSG_TAIL(nlh) - (void *) tail; }) + +extern NFNL_EXPORT void nfnl_build_nfa_iovec(struct iovec *iov, struct nfattr *nfa, + uint16_t type, uint32_t len, + unsigned char *val); +extern NFNL_EXPORT unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, + unsigned int size); + + +extern NFNL_EXPORT void nfnl_dump_packet(struct nlmsghdr *, int, char *); + +/* + * index to interface name API + */ + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +struct nlif_handle; + +extern NFNL_EXPORT struct nlif_handle *nlif_open(void); +extern NFNL_EXPORT void nlif_close(struct nlif_handle *orig); +extern NFNL_EXPORT int nlif_fd(struct nlif_handle *nlif_handle); +extern NFNL_EXPORT int nlif_query(struct nlif_handle *nlif_handle); +extern NFNL_EXPORT int nlif_catch(struct nlif_handle *nlif_handle); +extern NFNL_EXPORT int nlif_index2name(struct nlif_handle *nlif_handle, + unsigned int if_index, + char *name); +extern NFNL_EXPORT int nlif_get_ifflags(const struct nlif_handle *h, + unsigned int index, + unsigned int *flags); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* Pablo: What is the equivalence of be64_to_cpu in userspace? + * + * Harald: Good question. I don't think there's a standard way [yet?], + * so I'd suggest manually implementing it by "#if little endian" bitshift + * operations in C (at least for now). + * + * All the payload of any nfattr will always be in network byte order. + * This would allow easy transport over a real network in the future + * (e.g. jamal's netlink2). + * + * Pablo: I've called it __be64_to_cpu instead of be64_to_cpu, since maybe + * there will one in the userspace headers someday. We don't want to + * pollute POSIX space naming, + */ + +#include +#if __BYTE_ORDER == __BIG_ENDIAN +# ifndef __be64_to_cpu +# define __be64_to_cpu(x) (x) +# endif +# else +# if __BYTE_ORDER == __LITTLE_ENDIAN +# ifndef __be64_to_cpu +# define __be64_to_cpu(x) __bswap_64(x) +# endif +# endif +#endif + +#endif /* __LIBNFNETLINK_H */ diff --git a/deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink.h b/deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink.h new file mode 100644 index 0000000..44a38d6 --- /dev/null +++ b/deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink.h @@ -0,0 +1,53 @@ +#ifndef _NFNETLINK_H +#define _NFNETLINK_H +#include +#include + +enum nfnetlink_groups { + NFNLGRP_NONE, +#define NFNLGRP_NONE NFNLGRP_NONE + NFNLGRP_CONNTRACK_NEW, +#define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW + NFNLGRP_CONNTRACK_UPDATE, +#define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE + NFNLGRP_CONNTRACK_DESTROY, +#define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY + NFNLGRP_CONNTRACK_EXP_NEW, +#define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW + NFNLGRP_CONNTRACK_EXP_UPDATE, +#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE + NFNLGRP_CONNTRACK_EXP_DESTROY, +#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY + __NFNLGRP_MAX, +}; +#define NFNLGRP_MAX (__NFNLGRP_MAX - 1) + +/* General form of address family dependent message. + */ +struct nfgenmsg { + __u8 nfgen_family; /* AF_xxx */ + __u8 version; /* nfnetlink version */ + __be16 res_id; /* resource id */ +}; + +#define NFNETLINK_V0 0 + +/* netfilter netlink message types are split in two pieces: + * 8 bit subsystem, 8bit operation. + */ + +#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) +#define NFNL_MSG_TYPE(x) (x & 0x00ff) + +/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS() + * won't work anymore */ +#define NFNL_SUBSYS_NONE 0 +#define NFNL_SUBSYS_CTNETLINK 1 +#define NFNL_SUBSYS_CTNETLINK_EXP 2 +#define NFNL_SUBSYS_QUEUE 3 +#define NFNL_SUBSYS_ULOG 4 +#define NFNL_SUBSYS_OSF 5 +#define NFNL_SUBSYS_IPSET 6 +#define NFNL_SUBSYS_COUNT 7 + +#endif /* _NFNETLINK_H */ diff --git a/deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink_compat.h b/deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink_compat.h new file mode 100644 index 0000000..74b9e55 --- /dev/null +++ b/deps/libnfnetlink/include/libnfnetlink/linux_nfnetlink_compat.h @@ -0,0 +1,61 @@ +#ifndef _NFNETLINK_COMPAT_H +#define _NFNETLINK_COMPAT_H + +#include + +/* Old nfnetlink macros for userspace */ + +/* nfnetlink groups: Up to 32 maximum */ +#define NF_NETLINK_CONNTRACK_NEW 0x00000001 +#define NF_NETLINK_CONNTRACK_UPDATE 0x00000002 +#define NF_NETLINK_CONNTRACK_DESTROY 0x00000004 +#define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008 +#define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010 +#define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020 + +/* Generic structure for encapsulation optional netfilter information. + * It is reminiscent of sockaddr, but with sa_family replaced + * with attribute type. + * ! This should someday be put somewhere generic as now rtnetlink and + * ! nfnetlink use the same attributes methods. - J. Schulist. + */ + +struct nfattr { + __u16 nfa_len; + __u16 nfa_type; /* we use 15 bits for the type, and the highest + * bit to indicate whether the payload is nested */ +}; + +/* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from + * rtnetlink.h, it's time to put this in a generic file */ + +#define NFNL_NFA_NEST 0x8000 +#define NFA_TYPE(attr) ((attr)->nfa_type & 0x7fff) + +#define NFA_ALIGNTO 4 +#define NFA_ALIGN(len) (((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1)) +#define NFA_OK(nfa,len) ((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \ + && (nfa)->nfa_len <= (len)) +#define NFA_NEXT(nfa,attrlen) ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \ + (struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len))) +#define NFA_LENGTH(len) (NFA_ALIGN(sizeof(struct nfattr)) + (len)) +#define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len)) +#define NFA_DATA(nfa) ((void *)(((char *)(nfa)) + NFA_LENGTH(0))) +#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0)) +#define NFA_NEST(skb, type) \ +({ struct nfattr *__start = (struct nfattr *)skb_tail_pointer(skb); \ + NFA_PUT(skb, (NFNL_NFA_NEST | type), 0, NULL); \ + __start; }) +#define NFA_NEST_END(skb, start) \ +({ (start)->nfa_len = skb_tail_pointer(skb) - (unsigned char *)(start); \ + (skb)->len; }) +#define NFA_NEST_CANCEL(skb, start) \ +({ if (start) \ + skb_trim(skb, (unsigned char *) (start) - (skb)->data); \ + -1; }) + +#define NFM_NFA(n) ((struct nfattr *)(((char *)(n)) \ + + NLMSG_ALIGN(sizeof(struct nfgenmsg)))) +#define NFM_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg)) + +#endif /* _NFNETLINK_COMPAT_H */ diff --git a/deps/libnfnetlink/include/linux_list.h b/deps/libnfnetlink/include/linux_list.h new file mode 100644 index 0000000..cf71837 --- /dev/null +++ b/deps/libnfnetlink/include/linux_list.h @@ -0,0 +1,727 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Check at compile time that something is of a particular type. + * Always evaluates to 1 so you may use it easily in comparisons. + */ +#define typecheck(type,x) \ +({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ +}) + +#define prefetch(x) ((void)0) + +/* empty define to make this work in userspace -HW */ +#ifndef smp_wmb +#define smp_wmb() +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add_rcu(struct list_head * new, + struct list_head * prev, struct list_head * next) +{ + new->next = next; + new->prev = prev; + smp_wmb(); + next->prev = new; + prev->next = new; +} + +/** + * list_add_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_rcu(struct list_head *new, struct list_head *head) +{ + __list_add_rcu(new, head, head->next); +} + +/** + * list_add_tail_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_tail_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_tail_rcu(struct list_head *new, + struct list_head *head) +{ + __list_add_rcu(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_rcu - deletes entry from list without re-initialization + * @entry: the element to delete from the list. + * + * Note: list_empty on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_del_rcu() + * or list_add_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + * + * Note that the caller is not permitted to immediately free + * the newly deleted entry. Instead, either synchronize_kernel() + * or call_rcu() must be used to defer freeing until an RCU + * grace period has elapsed. + */ +static inline void list_del_rcu(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +/** + * list_for_each_safe_rcu - iterate over an rcu-protected list safe + * against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + ({ smp_read_barrier_depends(); 0;}), \ + prefetch(pos->member.next)) + + +/** + * list_for_each_continue_rcu - iterate over an rcu-protected list + * continuing after existing point. + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ + (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +#define hlist_del_rcu_init hlist_del_init + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + + +/** + * hlist_add_head_rcu - adds the specified element to the specified hlist, + * while permitting racing traversals. + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(), but only if smp_read_barrier_depends() + * is used to prevent memory-consistency problems on Alpha CPUs. + * Regardless of the type of CPU, the list-traversal primitive + * must be guarded by rcu_read_lock(). + * + * OK, so why don't we have an hlist_for_each_entry_rcu()??? + */ +static inline void hlist_add_head_rcu(struct hlist_node *n, + struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + n->pprev = &h->first; + smp_wmb(); + if (first) + first->pprev = &n->next; + h->first = n; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0; }) ) + +#endif diff --git a/deps/libnfnetlink/libnfnetlink.pc.in b/deps/libnfnetlink/libnfnetlink.pc.in new file mode 100644 index 0000000..d0fa9b2 --- /dev/null +++ b/deps/libnfnetlink/libnfnetlink.pc.in @@ -0,0 +1,15 @@ +# libnfnetlink pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libnfnetlink +Description: Low-level netfilter netlink communication library +URL: http://netfilter.org/projects/libnfnetlink/ +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lnfnetlink +Cflags: -I${includedir} diff --git a/deps/libnfnetlink/m4/.gitignore b/deps/libnfnetlink/m4/.gitignore new file mode 100644 index 0000000..64d9bbc --- /dev/null +++ b/deps/libnfnetlink/m4/.gitignore @@ -0,0 +1,2 @@ +/libtool.m4 +/lt*.m4 diff --git a/deps/libnfnetlink/src/Makefile.am b/deps/libnfnetlink/src/Makefile.am new file mode 100644 index 0000000..877ff31 --- /dev/null +++ b/deps/libnfnetlink/src/Makefile.am @@ -0,0 +1,11 @@ +include $(top_srcdir)/Make_global.am + +lib_LTLIBRARIES = libnfnetlink.la + +libnfnetlink_la_LDFLAGS = -Wc,-nostartfiles \ + -version-info $(LIBVERSION) \ + -Wl,--version-script=$(srcdir)/nfnl.version +libnfnetlink_la_SOURCES = libnfnetlink.c iftable.c rtnl.c nfnl.version +EXTRA_libnfnetlink_la_DEPENDENCIES = $(srcdir)/nfnl.version + +noinst_HEADERS = iftable.h rtnl.h diff --git a/deps/libnfnetlink/src/iftable.c b/deps/libnfnetlink/src/iftable.c new file mode 100644 index 0000000..aab59b3 --- /dev/null +++ b/deps/libnfnetlink/src/iftable.c @@ -0,0 +1,348 @@ +/* iftable - table of network interfaces + * + * (C) 2004 by Astaro AG, written by Harald Welte + * (C) 2008 by Pablo Neira Ayuso + * + * This software is Free Software and licensed under GNU GPLv2+. + */ + +/* IFINDEX handling */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "rtnl.h" +#include "linux_list.h" + +/** + * \defgroup iftable Functions in iftable.c [DEPRECATED] + * This documentation is provided for the benefit of maintainers of legacy code. + * + * New applications should use + * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/). + * @{ + */ + +struct ifindex_node { + struct list_head head; + + uint32_t index; + uint32_t type; + uint32_t alen; + uint32_t flags; + char addr[8]; + char name[16]; +}; + +struct nlif_handle { + struct list_head ifindex_hash[16]; + struct rtnl_handle *rtnl_handle; + struct rtnl_handler ifadd_handler; + struct rtnl_handler ifdel_handler; +}; + +/* iftable_add - Add/Update an entry to/in the interface table + * @n: netlink message header of a RTM_NEWLINK message + * @arg: not used + * + * This function adds/updates an entry in the intrface table. + * Returns -1 on error, 1 on success. + */ +static int iftable_add(struct nlmsghdr *n, void *arg) +{ + unsigned int hash, found = 0; + struct ifinfomsg *ifi_msg = NLMSG_DATA(n); + struct ifindex_node *this; + struct rtattr *cb[IFLA_MAX+1]; + struct nlif_handle *h = arg; + + if (n->nlmsg_type != RTM_NEWLINK) + return -1; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg))) + return -1; + + rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n)); + + if (!cb[IFLA_IFNAME]) + return -1; + + hash = ifi_msg->ifi_index & 0xF; + list_for_each_entry(this, &h->ifindex_hash[hash], head) { + if (this->index == ifi_msg->ifi_index) { + found = 1; + break; + } + } + + if (!found) { + this = malloc(sizeof(*this)); + if (!this) + return -1; + + this->index = ifi_msg->ifi_index; + } + + this->type = ifi_msg->ifi_type; + this->flags = ifi_msg->ifi_flags; + if (cb[IFLA_ADDRESS]) { + unsigned int alen; + this->alen = alen = RTA_PAYLOAD(cb[IFLA_ADDRESS]); + if (alen > sizeof(this->addr)) + alen = sizeof(this->addr); + memcpy(this->addr, RTA_DATA(cb[IFLA_ADDRESS]), alen); + } else { + this->alen = 0; + memset(this->addr, 0, sizeof(this->addr)); + } + strcpy(this->name, RTA_DATA(cb[IFLA_IFNAME])); + + if (!found) + list_add(&this->head, &h->ifindex_hash[hash]); + + return 1; +} + +/* iftable_del - Delete an entry from the interface table + * @n: netlink message header of a RTM_DELLINK nlmsg + * @arg: not used + * + * Delete an entry from the interface table. + * Returns -1 on error, 0 if no matching entry was found or 1 on success. + */ +static int iftable_del(struct nlmsghdr *n, void *arg) +{ + struct ifinfomsg *ifi_msg = NLMSG_DATA(n); + struct rtattr *cb[IFLA_MAX+1]; + struct nlif_handle *h = arg; + struct ifindex_node *this, *tmp; + unsigned int hash; + + if (n->nlmsg_type != RTM_DELLINK) + return -1; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg))) + return -1; + + rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n)); + + hash = ifi_msg->ifi_index & 0xF; + list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash], head) { + if (this->index == ifi_msg->ifi_index) { + list_del(&this->head); + free(this); + return 1; + } + } + + return 0; +} + +/** Get the name for an ifindex + * + * \param nlif_handle A pointer to a ::nlif_handle created + * \param index ifindex to be resolved + * \param name interface name, pass a buffer of IFNAMSIZ size + * \return -1 on error, 1 on success + */ +int nlif_index2name(struct nlif_handle *h, + unsigned int index, + char *name) +{ + unsigned int hash; + struct ifindex_node *this; + + assert(h != NULL); + assert(name != NULL); + + if (index == 0) { + strcpy(name, "*"); + return 1; + } + + hash = index & 0xF; + list_for_each_entry(this, &h->ifindex_hash[hash], head) { + if (this->index == index) { + strcpy(name, this->name); + return 1; + } + } + + errno = ENOENT; + return -1; +} + +/** Get the flags for an ifindex + * + * \param nlif_handle A pointer to a ::nlif_handle created + * \param index ifindex to be resolved + * \param flags pointer to variable used to store the interface flags + * \return -1 on error, 1 on success + */ +int nlif_get_ifflags(const struct nlif_handle *h, + unsigned int index, + unsigned int *flags) +{ + unsigned int hash; + struct ifindex_node *this; + + assert(h != NULL); + assert(flags != NULL); + + if (index == 0) { + errno = ENOENT; + return -1; + } + + hash = index & 0xF; + list_for_each_entry(this, &h->ifindex_hash[hash], head) { + if (this->index == index) { + *flags = this->flags; + return 1; + } + } + errno = ENOENT; + return -1; +} + +/** Initialize interface table + * + * Initialize rtnl interface and interface table + * Call this before any nlif_* function + * + * \return file descriptor to netlink socket + */ +struct nlif_handle *nlif_open(void) +{ + int i; + struct nlif_handle *h; + + h = calloc(1, sizeof(struct nlif_handle)); + if (h == NULL) + goto err; + + for (i=0; i<16; i++) + INIT_LIST_HEAD(&h->ifindex_hash[i]); + + h->ifadd_handler.nlmsg_type = RTM_NEWLINK; + h->ifadd_handler.handlefn = iftable_add; + h->ifadd_handler.arg = h; + h->ifdel_handler.nlmsg_type = RTM_DELLINK; + h->ifdel_handler.handlefn = iftable_del; + h->ifdel_handler.arg = h; + + h->rtnl_handle = rtnl_open(); + if (h->rtnl_handle == NULL) + goto err; + + if (rtnl_handler_register(h->rtnl_handle, &h->ifadd_handler) < 0) + goto err_close; + + if (rtnl_handler_register(h->rtnl_handle, &h->ifdel_handler) < 0) + goto err_unregister; + + return h; + +err_unregister: + rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler); +err_close: + rtnl_close(h->rtnl_handle); + free(h); +err: + return NULL; +} + +/** Destructor of interface table + * + * \param nlif_handle A pointer to a ::nlif_handle created + * via nlif_open() + */ +void nlif_close(struct nlif_handle *h) +{ + int i; + struct ifindex_node *this, *tmp; + + assert(h != NULL); + + rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler); + rtnl_handler_unregister(h->rtnl_handle, &h->ifdel_handler); + rtnl_close(h->rtnl_handle); + + for (i=0; i<16; i++) { + list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) { + list_del(&this->head); + free(this); + } + } + + free(h); + h = NULL; /* bugtrap */ +} + +/** Receive message from netlink and update interface table + * + * \param nlif_handle A pointer to a ::nlif_handle created + * \return 0 if OK + */ +int nlif_catch(struct nlif_handle *h) +{ + assert(h != NULL); + + if (h->rtnl_handle) + return rtnl_receive(h->rtnl_handle); + + return -1; +} + +static int nlif_catch_multi(struct nlif_handle *h) +{ + assert(h != NULL); + + if (h->rtnl_handle) + return rtnl_receive_multi(h->rtnl_handle); + + return -1; +} + +/** + * nlif_query - request a dump of interfaces available in the system + * @h: pointer to a valid nlif_handler + */ +int nlif_query(struct nlif_handle *h) +{ + assert(h != NULL); + + if (rtnl_dump_type(h->rtnl_handle, RTM_GETLINK) < 0) + return -1; + + return nlif_catch_multi(h); +} + +/** Returns socket descriptor for the netlink socket + * + * \param nlif_handle A pointer to a ::nlif_handle created + * \return The fd or -1 if there's an error + */ +int nlif_fd(struct nlif_handle *h) +{ + assert(h != NULL); + + if (h->rtnl_handle) + return h->rtnl_handle->rtnl_fd; + + return -1; +} + +/** + * @} + */ diff --git a/deps/libnfnetlink/src/iftable.h b/deps/libnfnetlink/src/iftable.h new file mode 100644 index 0000000..655df6b --- /dev/null +++ b/deps/libnfnetlink/src/iftable.h @@ -0,0 +1,12 @@ +#ifndef _IFTABLE_H +#define _IFTABLE_H + +int iftable_delete(uint32_t dst, uint32_t mask, uint32_t gw, uint32_t oif); +int iftable_insert(uint32_t dst, uint32_t mask, uint32_t gw, uint32_t oif); + +int iftable_init(void); +void iftable_fini(void); + +int iftable_dump(FILE *outfd); +int iftable_up(unsigned int index); +#endif diff --git a/deps/libnfnetlink/src/libnfnetlink.c b/deps/libnfnetlink/src/libnfnetlink.c new file mode 100644 index 0000000..667e5ef --- /dev/null +++ b/deps/libnfnetlink/src/libnfnetlink.c @@ -0,0 +1,1602 @@ +/* libnfnetlink.c: generic library for communication with netfilter + * + * (C) 2002-2006 by Harald Welte + * (C) 2006-2011 by Pablo Neira Ayuso + * + * Based on some original ideas from Jay Schulist + * + * Development of this code funded by Astaro AG (http://www.astaro.com) + * + * 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. + * + * 2005-09-14 Pablo Neira Ayuso : + * Define structure nfnlhdr + * Added __be64_to_cpu function + * Use NFA_TYPE macro to get the attribute type + * + * 2006-01-14 Harald Welte : + * introduce nfnl_subsys_handle + * + * 2006-01-15 Pablo Neira Ayuso : + * set missing subsys_id in nfnl_subsys_open + * set missing nfnlh->local.nl_pid in nfnl_open + * + * 2006-01-26 Harald Welte : + * remove bogus nfnlh->local.nl_pid from nfnl_open ;) + * add 16bit attribute functions + * + * 2006-07-03 Pablo Neira Ayuso : + * add iterator API + * add replacements for nfnl_listen and nfnl_talk + * fix error handling + * add assertions + * add documentation + * minor cleanups + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +/** + * \mainpage + * + * Deprecated + * --- + * New applications should use + * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/). + * + * [libnetfilter_queue] + * (https://netfilter.org/projects/libnetfilter_queue/doxygen/html/) + * now provides a set of helpers for libmnl, in addition to those it provides + * for libnfnetlink (which are now deprecated). + */ + +/** + * \defgroup libnfnetlink Functions in libnfnetlink.c [DEPRECATED] + * This documentation is provided for the benefit of maintainers of legacy code. + * + * New applications should use + * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/). + * @{ + */ + +#ifndef NETLINK_ADD_MEMBERSHIP +#define NETLINK_ADD_MEMBERSHIP 1 +#endif + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +#define nfnl_error(format, args...) \ + fprintf(stderr, "%s: " format "\n", __FUNCTION__, ## args) + +#ifdef _NFNL_DEBUG +#define nfnl_debug_dump_packet nfnl_dump_packet +#else +#define nfnl_debug_dump_packet(a, b, ...) +#endif + +struct nfnl_subsys_handle { + struct nfnl_handle *nfnlh; + uint32_t subscriptions; + uint8_t subsys_id; + uint8_t cb_count; + struct nfnl_callback *cb; /* array of callbacks */ +}; + +#define NFNL_MAX_SUBSYS 16 /* enough for now */ + +#define NFNL_F_SEQTRACK_ENABLED (1 << 0) + +struct nfnl_handle { + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + uint32_t subscriptions; + uint32_t seq; + uint32_t dump; + uint32_t rcv_buffer_size; /* for nfnl_catch */ + uint32_t flags; + struct nlmsghdr *last_nlhdr; + struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1]; +}; + +void nfnl_dump_packet(struct nlmsghdr *nlh, int received_len, char *desc) +{ + void *nlmsg_data = NLMSG_DATA(nlh); + struct nfattr *nfa = NFM_NFA(NLMSG_DATA(nlh)); + int len = NFM_PAYLOAD(nlh); + + printf("%s called from %s\n", __FUNCTION__, desc); + printf(" nlmsghdr = %p, received_len = %u\n", nlh, received_len); + printf(" NLMSG_DATA(nlh) = %p (+%td bytes)\n", nlmsg_data, + (nlmsg_data - (void *)nlh)); + printf(" NFM_NFA(NLMSG_DATA(nlh)) = %p (+%td bytes)\n", + nfa, ((void *)nfa - (void *)nlh)); + printf(" NFM_PAYLOAD(nlh) = %u\n", len); + printf(" nlmsg_type = %u, nlmsg_len = %u, nlmsg_seq = %u " + "nlmsg_flags = 0x%x\n", nlh->nlmsg_type, nlh->nlmsg_len, + nlh->nlmsg_seq, nlh->nlmsg_flags); + + while (NFA_OK(nfa, len)) { + printf(" nfa@%p: nfa_type=%u, nfa_len=%u\n", + nfa, NFA_TYPE(nfa), nfa->nfa_len); + nfa = NFA_NEXT(nfa,len); + } +} + +/** + * nfnl_fd - returns the descriptor that identifies the socket + * @nfnlh: nfnetlink handler + * + * Use this function if you need to interact with the socket. Common + * scenarios are the use of poll()/select() to achieve multiplexation. + */ +int nfnl_fd(struct nfnl_handle *h) +{ + assert(h); + return h->fd; +} + +/** + * nfnl_portid - returns the Netlink port ID of this socket + * @h: nfnetlink handler + */ +unsigned int nfnl_portid(const struct nfnl_handle *h) +{ + assert(h); + return h->local.nl_pid; +} + +static int recalc_rebind_subscriptions(struct nfnl_handle *nfnlh) +{ + int i, err; + uint32_t new_subscriptions = nfnlh->subscriptions; + + for (i = 0; i < NFNL_MAX_SUBSYS; i++) + new_subscriptions |= nfnlh->subsys[i].subscriptions; + + nfnlh->local.nl_groups = new_subscriptions; + err = bind(nfnlh->fd, (struct sockaddr *)&nfnlh->local, + sizeof(nfnlh->local)); + if (err == -1) + return -1; + + nfnlh->subscriptions = new_subscriptions; + + return 0; +} + +/** + * nfnl_open - open a nfnetlink handler + * + * This function creates a nfnetlink handler, this is required to establish + * a communication between the userspace and the nfnetlink system. + * + * On success, a valid address that points to a nfnl_handle structure + * is returned. On error, NULL is returned and errno is set approapiately. + */ +struct nfnl_handle *nfnl_open(void) +{ + struct nfnl_handle *nfnlh; + unsigned int addr_len; + + nfnlh = malloc(sizeof(*nfnlh)); + if (!nfnlh) + return NULL; + + memset(nfnlh, 0, sizeof(*nfnlh)); + nfnlh->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (nfnlh->fd == -1) + goto err_free; + + nfnlh->local.nl_family = AF_NETLINK; + nfnlh->peer.nl_family = AF_NETLINK; + + addr_len = sizeof(nfnlh->local); + if (getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len)) + goto err_close; + if (addr_len != sizeof(nfnlh->local)) { + errno = EINVAL; + goto err_close; + } + if (nfnlh->local.nl_family != AF_NETLINK) { + errno = EINVAL; + goto err_close; + } + nfnlh->seq = time(NULL); + nfnlh->rcv_buffer_size = NFNL_BUFFSIZE; + + /* don't set pid here, only first socket of process has real pid !!! + * binding to pid '0' will default */ + + /* let us do the initial bind */ + if (recalc_rebind_subscriptions(nfnlh) < 0) + goto err_close; + + /* use getsockname to get the netlink pid that the kernel assigned us */ + addr_len = sizeof(nfnlh->local); + if (getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len)) + goto err_close; + if (addr_len != sizeof(nfnlh->local)) { + errno = EINVAL; + goto err_close; + } + /* sequence tracking enabled by default */ + nfnlh->flags |= NFNL_F_SEQTRACK_ENABLED; + + return nfnlh; + +err_close: + close(nfnlh->fd); +err_free: + free(nfnlh); + return NULL; +} + +/** + * nfnl_set_sequence_tracking - set netlink sequence tracking + * @h: nfnetlink handler + */ +void nfnl_set_sequence_tracking(struct nfnl_handle *h) +{ + h->flags |= NFNL_F_SEQTRACK_ENABLED; +} + +/** + * nfnl_unset_sequence_tracking - set netlink sequence tracking + * @h: nfnetlink handler + */ +void nfnl_unset_sequence_tracking(struct nfnl_handle *h) +{ + h->flags &= ~NFNL_F_SEQTRACK_ENABLED; +} + +/** + * nfnl_set_rcv_buffer_size - set the size of the receive buffer + * @h: libnfnetlink handler + * @size: buffer size + * + * This function sets the size of the receive buffer size, i.e. the size + * of the buffer used by nfnl_recv. Default value is 4096 bytes. + */ +void nfnl_set_rcv_buffer_size(struct nfnl_handle *h, unsigned int size) +{ + h->rcv_buffer_size = size; +} + +/** + * nfnl_subsys_open - open a netlink subsystem + * @nfnlh: libnfnetlink handle + * @subsys_id: which nfnetlink subsystem we are interested in + * @cb_count: number of callbacks that are used maximum. + * @subscriptions: netlink groups we want to be subscribed to + * + * This function creates a subsystem handler that contains the set of + * callbacks that handle certain types of messages coming from a netfilter + * subsystem. Initially the callback set is empty, you can register callbacks + * via nfnl_callback_register(). + * + * On error, NULL is returned and errno is set appropiately. On success, + * a valid address that points to a nfnl_subsys_handle structure is returned. + */ +struct nfnl_subsys_handle * +nfnl_subsys_open(struct nfnl_handle *nfnlh, uint8_t subsys_id, + uint8_t cb_count, uint32_t subscriptions) +{ + struct nfnl_subsys_handle *ssh; + + assert(nfnlh); + + if (subsys_id > NFNL_MAX_SUBSYS) { + errno = ENOENT; + return NULL; + } + + ssh = &nfnlh->subsys[subsys_id]; + if (ssh->cb) { + errno = EBUSY; + return NULL; + } + + ssh->cb = calloc(cb_count, sizeof(*(ssh->cb))); + if (!ssh->cb) + return NULL; + + ssh->nfnlh = nfnlh; + ssh->cb_count = cb_count; + ssh->subscriptions = subscriptions; + ssh->subsys_id = subsys_id; + + /* although now we have nfnl_join to subscribe to certain + * groups, just keep this to ensure compatibility */ + if (recalc_rebind_subscriptions(nfnlh) < 0) { + free(ssh->cb); + ssh->cb = NULL; + return NULL; + } + + return ssh; +} + +/** + * nfnl_subsys_close - close a nfnetlink subsys handler + * @ssh: nfnetlink subsystem handler + * + * Release all the callbacks registered in a subsystem handler. + */ +void nfnl_subsys_close(struct nfnl_subsys_handle *ssh) +{ + assert(ssh); + + ssh->subscriptions = 0; + ssh->cb_count = 0; + if (ssh->cb) { + free(ssh->cb); + ssh->cb = NULL; + } +} + +/** + * nfnl_close - close a nfnetlink handler + * @nfnlh: nfnetlink handler + * + * This function closes the nfnetlink handler. On success, 0 is returned. + * On error, -1 is returned and errno is set appropiately. + */ +int nfnl_close(struct nfnl_handle *nfnlh) +{ + int i, ret; + + assert(nfnlh); + + for (i = 0; i < NFNL_MAX_SUBSYS; i++) + nfnl_subsys_close(&nfnlh->subsys[i]); + + ret = close(nfnlh->fd); + if (ret < 0) + return ret; + + free(nfnlh); + + return 0; +} + +/** + * nfnl_join - join a nfnetlink multicast group + * @nfnlh: nfnetlink handler + * @group: group we want to join + * + * This function is used to join a certain multicast group. It must be + * called once the nfnetlink handler has been created. If any doubt, + * just use it if you have to listen to nfnetlink events. + * + * On success, 0 is returned. On error, -1 is returned and errno is set + * approapiately. + */ +int nfnl_join(const struct nfnl_handle *nfnlh, unsigned int group) +{ + assert(nfnlh); + return setsockopt(nfnlh->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &group, sizeof(group)); +} + +/** + * nfnl_send - send a nfnetlink message through netlink socket + * @nfnlh: nfnetlink handler + * @n: netlink message + * + * On success, the number of bytes is returned. On error, -1 is returned + * and errno is set appropiately. + */ +int nfnl_send(struct nfnl_handle *nfnlh, struct nlmsghdr *n) +{ + assert(nfnlh); + assert(n); + + nfnl_debug_dump_packet(n, n->nlmsg_len+sizeof(*n), "nfnl_send"); + + return sendto(nfnlh->fd, n, n->nlmsg_len, 0, + (struct sockaddr *)&nfnlh->peer, sizeof(nfnlh->peer)); +} + +int nfnl_sendmsg(const struct nfnl_handle *nfnlh, const struct msghdr *msg, + unsigned int flags) +{ + assert(nfnlh); + assert(msg); + + return sendmsg(nfnlh->fd, msg, flags); +} + +int nfnl_sendiov(const struct nfnl_handle *nfnlh, const struct iovec *iov, + unsigned int num, unsigned int flags) +{ + struct msghdr msg; + + assert(nfnlh); + + msg.msg_name = (struct sockaddr *) &nfnlh->peer; + msg.msg_namelen = sizeof(nfnlh->peer); + msg.msg_iov = (struct iovec *) iov; + msg.msg_iovlen = num; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + return nfnl_sendmsg(nfnlh, &msg, flags); +} + +/** + * nfnl_fill_hdr - fill in netlink and nfnetlink header + * @nfnlh: nfnetlink handle + * @nlh: netlink message to be filled in + * @len: length of _payload_ bytes (not including nfgenmsg) + * @family: AF_INET / ... + * @res_id: resource id + * @msg_type: nfnetlink message type (without subsystem) + * @msg_flags: netlink message flags + * + * This function sets up appropiately the nfnetlink header. See that the + * pointer to the netlink message passed must point to a memory region of + * at least the size of struct nlmsghdr + struct nfgenmsg. + */ +void nfnl_fill_hdr(struct nfnl_subsys_handle *ssh, + struct nlmsghdr *nlh, unsigned int len, + uint8_t family, + uint16_t res_id, + uint16_t msg_type, + uint16_t msg_flags) +{ + assert(ssh); + assert(nlh); + + struct nfgenmsg *nfg = (void *)nlh + sizeof(*nlh); + + nlh->nlmsg_len = NLMSG_LENGTH(len+sizeof(*nfg)); + nlh->nlmsg_type = (ssh->subsys_id<<8)|msg_type; + nlh->nlmsg_flags = msg_flags; + nlh->nlmsg_pid = 0; + + if (ssh->nfnlh->flags & NFNL_F_SEQTRACK_ENABLED) { + nlh->nlmsg_seq = ++ssh->nfnlh->seq; + /* kernel uses sequence number zero for events */ + if (!ssh->nfnlh->seq) + nlh->nlmsg_seq = ssh->nfnlh->seq = time(NULL); + } else { + /* unset sequence number, ignore it */ + nlh->nlmsg_seq = 0; + } + + nfg->nfgen_family = family; + nfg->version = NFNETLINK_V0; + nfg->res_id = htons(res_id); +} + +struct nfattr * +nfnl_parse_hdr(const struct nfnl_handle *nfnlh, + const struct nlmsghdr *nlh, + struct nfgenmsg **genmsg) +{ + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg))) + return NULL; + + if (nlh->nlmsg_len == NLMSG_LENGTH(sizeof(struct nfgenmsg))) { + if (genmsg) + *genmsg = (void *)nlh + sizeof(*nlh); + return NULL; + } + + if (genmsg) + *genmsg = (void *)nlh + sizeof(*nlh); + + return (void *)nlh + NLMSG_LENGTH(sizeof(struct nfgenmsg)); +} + +/** + * nfnl_recv - receive data from a nfnetlink subsystem + * @h: nfnetlink handler + * @buf: buffer where the data will be stored + * @len: size of the buffer + * + * This function doesn't perform any sanity checking. So do no expect + * that the data is well-formed. Such checkings are done by the parsing + * functions. + * + * On success, 0 is returned. On error, -1 is returned and errno is set + * appropiately. + * + * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In + * that case is possible that the information requested is incomplete. + */ +ssize_t +nfnl_recv(const struct nfnl_handle *h, unsigned char *buf, size_t len) +{ + socklen_t addrlen; + int status; + struct sockaddr_nl peer; + + assert(h); + assert(buf); + assert(len > 0); + + if (len < sizeof(struct nlmsgerr) + || len < sizeof(struct nlmsghdr)) { + errno = EBADMSG; + return -1; + } + + addrlen = sizeof(h->peer); + status = recvfrom(h->fd, buf, len, 0, (struct sockaddr *)&peer, + &addrlen); + if (status <= 0) + return status; + + if (addrlen != sizeof(peer)) { + errno = EINVAL; + return -1; + } + + if (peer.nl_pid != 0) { + errno = ENOMSG; + return -1; + } + + return status; +} +/** + * nfnl_listen: listen for one or more netlink messages + * @nfnhl: libnfnetlink handle + * @handler: callback function to be called for every netlink message + * - the callback handler should normally return 0 + * - but may return a negative error code which will cause + * nfnl_listen to return immediately with the same error code + * - or return a postivie error code which will cause + * nfnl_listen to return after it has finished processing all + * the netlink messages in the current packet + * Thus a positive error code will terminate nfnl_listen "soon" + * without any loss of data, a negative error code will terminate + * nfnl_listen "very soon" and throw away data already read from + * the netlink socket. + * @jarg: opaque argument passed on to callback + * + * This function is used to receive and process messages coming from an open + * nfnetlink handler like events or information request via nfnl_send(). + * + * On error, -1 is returned, unfortunately errno is not always set + * appropiately. For that reason, the use of this function is DEPRECATED. + * Please, use nfnl_receive_process() instead. + */ +int nfnl_listen(struct nfnl_handle *nfnlh, + int (*handler)(struct sockaddr_nl *, struct nlmsghdr *n, + void *), void *jarg) +{ + struct sockaddr_nl nladdr; + char buf[NFNL_BUFFSIZE] __attribute__ ((aligned)); + struct iovec iov; + int remain; + struct nlmsghdr *h; + struct nlmsgerr *msgerr; + int quit=0; + + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + + while (! quit) { + remain = recvmsg(nfnlh->fd, &msg, 0); + if (remain < 0) { + if (errno == EINTR) + continue; + /* Bad file descriptor */ + else if (errno == EBADF) + break; + else if (errno == EAGAIN) + break; + nfnl_error("recvmsg overrun: %s", strerror(errno)); + continue; + } + if (remain == 0) { + nfnl_error("EOF on netlink"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + nfnl_error("Bad sender address len (%d)", + msg.msg_namelen); + return -1; + } + + for (h = (struct nlmsghdr *)buf; remain >= sizeof(*h);) { + int err; + int len = h->nlmsg_len; + int l = len - sizeof(*h); + + if (l < 0 || len > remain) { + if (msg.msg_flags & MSG_TRUNC) { + nfnl_error("MSG_TRUNC"); + return -1; + } + nfnl_error("Malformed msg (len=%d)", len); + return -1; + } + + /* end of messages reached, let's return */ + if (h->nlmsg_type == NLMSG_DONE) + return 0; + + /* Break the loop if success is explicitely + * reported via NLM_F_ACK flag set */ + if (h->nlmsg_type == NLMSG_ERROR) { + msgerr = NLMSG_DATA(h); + return msgerr->error; + } + + err = handler(&nladdr, h, jarg); + if (err < 0) + return err; + quit |= err; + + /* FIXME: why not _NEXT macros, etc.? */ + //h = NLMSG_NEXT(h, remain); + remain -= NLMSG_ALIGN(len); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + nfnl_error("MSG_TRUNC"); + continue; + } + if (remain) { + nfnl_error("remnant size %d", remain); + return -1; + } + } + + return quit; +} + +/** + * nfnl_talk - send a request and then receive and process messages returned + * @nfnlh: nfnetelink handler + * @n: netlink message that contains the request + * @peer: peer PID + * @groups: netlink groups + * @junk: callback called if out-of-sequence messages were received + * @jarg: data for the junk callback + * + * This function is used to request an action that does not returns any + * information. On error, a negative value is returned, errno could be + * set appropiately. For that reason, the use of this function is DEPRECATED. + * Please, use nfnl_query() instead. + */ +int nfnl_talk(struct nfnl_handle *nfnlh, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer, + int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *), + void *jarg) +{ + char buf[NFNL_BUFFSIZE] __attribute__ ((aligned)); + struct sockaddr_nl nladdr; + struct nlmsghdr *h; + unsigned int seq; + int status; + struct iovec iov = { + n, n->nlmsg_len + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = peer; + nladdr.nl_groups = groups; + + n->nlmsg_seq = seq = ++nfnlh->seq; + /* FIXME: why ? */ + if (!answer) + n->nlmsg_flags |= NLM_F_ACK; + + status = sendmsg(nfnlh->fd, &msg, 0); + if (status < 0) { + nfnl_error("sendmsg(netlink) %s", strerror(errno)); + return -1; + } + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + + while (1) { + status = recvmsg(nfnlh->fd, &msg, 0); + if (status < 0) { + if (errno == EINTR) + continue; + nfnl_error("recvmsg over-run"); + continue; + } + if (status == 0) { + nfnl_error("EOF on netlink"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + nfnl_error("Bad sender address len %d", + msg.msg_namelen); + return -1; + } + + for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { + int len = h->nlmsg_len; + int l = len - sizeof(*h); + int err; + + if (l < 0 || len > status) { + if (msg.msg_flags & MSG_TRUNC) { + nfnl_error("Truncated message\n"); + return -1; + } + nfnl_error("Malformed message: len=%d\n", len); + return -1; /* FIXME: libnetlink exits here */ + } + + if (h->nlmsg_pid != nfnlh->local.nl_pid || + h->nlmsg_seq != seq) { + if (junk) { + err = junk(&nladdr, h, jarg); + if (err < 0) + return err; + } + goto cont; + } + + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = NLMSG_DATA(h); + if (l < sizeof(struct nlmsgerr)) + nfnl_error("ERROR truncated\n"); + else { + errno = -err->error; + if (errno == 0) { + if (answer) + memcpy(answer, h, h->nlmsg_len); + return 0; + } + perror("NFNETLINK answers"); + } + return err->error; + } + if (answer) { + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + nfnl_error("Unexpected reply!\n"); +cont: + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + nfnl_error("Messages truncated\n"); + continue; + } + if (status) + nfnl_error("Remnant of size %d\n", status); + } +} + +/** + * nfnl_addattr_l - Add variable length attribute to nlmsghdr + * @n: netlink message header to which attribute is to be added + * @maxlen: maximum length of netlink message header + * @type: type of new attribute + * @data: content of new attribute + * @len: attribute length + */ +int nfnl_addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) +{ + int len = NFA_LENGTH(alen); + struct nfattr *nfa; + + assert(n); + assert(maxlen > 0); + assert(type >= 0); + + if ((NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) { + errno = ENOSPC; + return -1; + } + + nfa = NLMSG_TAIL(n); + nfa->nfa_type = type; + nfa->nfa_len = len; + memcpy(NFA_DATA(nfa), data, alen); + memset((uint8_t *)nfa + nfa->nfa_len, 0, NFA_ALIGN(alen) - alen); + n->nlmsg_len = (NLMSG_ALIGN(n->nlmsg_len) + NFA_ALIGN(len)); + return 0; +} + +/** + * nfnl_nfa_addattr_l - Add variable length attribute to struct nfattr + * + * @nfa: struct nfattr + * @maxlen: maximal length of nfattr buffer + * @type: type for new attribute + * @data: content of new attribute + * @alen: length of new attribute + * + */ +int nfnl_nfa_addattr_l(struct nfattr *nfa, int maxlen, int type, + const void *data, int alen) +{ + struct nfattr *subnfa; + int len = NFA_LENGTH(alen); + + assert(nfa); + assert(maxlen > 0); + assert(type >= 0); + + if (NFA_ALIGN(nfa->nfa_len) + len > maxlen) { + errno = ENOSPC; + return -1; + } + + subnfa = (struct nfattr *)(((char *)nfa) + NFA_ALIGN(nfa->nfa_len)); + subnfa->nfa_type = type; + subnfa->nfa_len = len; + memcpy(NFA_DATA(subnfa), data, alen); + nfa->nfa_len = NFA_ALIGN(nfa->nfa_len) + len; + + return 0; +} + +/** + * nfnl_addattr8 - Add uint8_t attribute to nlmsghdr + * + * @n: netlink message header to which attribute is to be added + * @maxlen: maximum length of netlink message header + * @type: type of new attribute + * @data: content of new attribute + */ +int nfnl_addattr8(struct nlmsghdr *n, int maxlen, int type, uint8_t data) +{ + assert(n); + assert(maxlen > 0); + assert(type >= 0); + + return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data)); +} + +/** + * nfnl_nfa_addattr16 - Add uint16_t attribute to struct nfattr + * + * @nfa: struct nfattr + * @maxlen: maximal length of nfattr buffer + * @type: type for new attribute + * @data: content of new attribute + * + */ +int nfnl_nfa_addattr16(struct nfattr *nfa, int maxlen, int type, + uint16_t data) +{ + assert(nfa); + assert(maxlen > 0); + assert(type >= 0); + + return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data)); +} + +/** + * nfnl_addattr16 - Add uint16_t attribute to nlmsghdr + * + * @n: netlink message header to which attribute is to be added + * @maxlen: maximum length of netlink message header + * @type: type of new attribute + * @data: content of new attribute + * + */ +int nfnl_addattr16(struct nlmsghdr *n, int maxlen, int type, + uint16_t data) +{ + assert(n); + assert(maxlen > 0); + assert(type >= 0); + + return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data)); +} + +/** + * nfnl_nfa_addattr32 - Add uint32_t attribute to struct nfattr + * + * @nfa: struct nfattr + * @maxlen: maximal length of nfattr buffer + * @type: type for new attribute + * @data: content of new attribute + * + */ +int nfnl_nfa_addattr32(struct nfattr *nfa, int maxlen, int type, + uint32_t data) +{ + assert(nfa); + assert(maxlen > 0); + assert(type >= 0); + + return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data)); +} + +/** + * nfnl_addattr32 - Add uint32_t attribute to nlmsghdr + * + * @n: netlink message header to which attribute is to be added + * @maxlen: maximum length of netlink message header + * @type: type of new attribute + * @data: content of new attribute + * + */ +int nfnl_addattr32(struct nlmsghdr *n, int maxlen, int type, + uint32_t data) +{ + assert(n); + assert(maxlen > 0); + assert(type >= 0); + + return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data)); +} + +/** + * nfnl_parse_attr - Parse a list of nfattrs into a pointer array + * + * @tb: pointer array, will be filled in (output) + * @max: size of pointer array + * @nfa: pointer to list of nfattrs + * @len: length of 'nfa' + * + * The returned value is equal to the number of remaining bytes of the netlink + * message that cannot be parsed. + */ +int nfnl_parse_attr(struct nfattr *tb[], int max, struct nfattr *nfa, int len) +{ + assert(tb); + assert(max > 0); + assert(nfa); + + memset(tb, 0, sizeof(struct nfattr *) * max); + + while (NFA_OK(nfa, len)) { + if (NFA_TYPE(nfa) <= max) + tb[NFA_TYPE(nfa)-1] = nfa; + nfa = NFA_NEXT(nfa,len); + } + + return len; +} + +/** + * nfnl_build_nfa_iovec - Build two iovec's from tag, length and value + * + * @iov: pointer to array of two 'struct iovec' (caller-allocated) + * @nfa: pointer to 'struct nfattr' (caller-allocated) + * @type: type (tag) of attribute + * @len: length of value + * @val: pointer to buffer containing 'value' + * + */ +void nfnl_build_nfa_iovec(struct iovec *iov, struct nfattr *nfa, + uint16_t type, uint32_t len, unsigned char *val) +{ + assert(iov); + assert(nfa); + + /* Set the attribut values */ + nfa->nfa_len = sizeof(struct nfattr) + len; + nfa->nfa_type = type; + + iov[0].iov_base = nfa; + iov[0].iov_len = sizeof(*nfa); + iov[1].iov_base = val; + iov[1].iov_len = NFA_ALIGN(len); +} + +#ifndef SO_RCVBUFFORCE +#define SO_RCVBUFFORCE (33) +#endif + +/** + * nfnl_rcvbufsiz - set the socket buffer size + * @h: nfnetlink handler + * @size: size of the buffer we want to set + * + * This function sets the new size of the socket buffer. Use this setting + * to increase the socket buffer size if your system is reporting ENOBUFS + * errors. + * + * This function returns the new size of the socket buffer. + */ +unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, unsigned int size) +{ + int status; + socklen_t socklen = sizeof(size); + unsigned int read_size = 0; + + assert(h); + + /* first we try the FORCE option, which is introduced in kernel + * 2.6.14 to give "root" the ability to override the system wide + * maximum */ + status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, socklen); + if (status < 0) { + /* if this didn't work, we try at least to get the system + * wide maximum (or whatever the user requested) */ + setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &size, socklen); + } + getsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &read_size, &socklen); + + return read_size; +} + +/** + * nfnl_get_msg_first - get the first message of a multipart netlink message + * @h: nfnetlink handle + * @buf: data received that we want to process + * @len: size of the data received + * + * This function returns a pointer to the first netlink message contained + * in the chunk of data received from certain nfnetlink subsystem. + * + * On success, a valid address that points to the netlink message is returned. + * On error, NULL is returned. + */ +struct nlmsghdr *nfnl_get_msg_first(struct nfnl_handle *h, + const unsigned char *buf, + size_t len) +{ + struct nlmsghdr *nlh; + + assert(h); + assert(buf); + assert(len > 0); + + /* first message in buffer */ + nlh = (struct nlmsghdr *)buf; + if (!NLMSG_OK(nlh, len)) + return NULL; + h->last_nlhdr = nlh; + + return nlh; +} + +struct nlmsghdr *nfnl_get_msg_next(struct nfnl_handle *h, + const unsigned char *buf, + size_t len) +{ + struct nlmsghdr *nlh; + size_t remain_len; + + assert(h); + assert(buf); + assert(len > 0); + + /* if last header in handle not inside this buffer, + * drop reference to last header */ + if (!h->last_nlhdr || + (unsigned char *)h->last_nlhdr >= (buf + len) || + (unsigned char *)h->last_nlhdr < buf) { + h->last_nlhdr = NULL; + return NULL; + } + + /* n-th part of multipart message */ + if (h->last_nlhdr->nlmsg_type == NLMSG_DONE || + h->last_nlhdr->nlmsg_flags & NLM_F_MULTI) { + /* if last part in multipart message or no + * multipart message at all, return */ + h->last_nlhdr = NULL; + return NULL; + } + + remain_len = (len - ((unsigned char *)h->last_nlhdr - buf)); + nlh = NLMSG_NEXT(h->last_nlhdr, remain_len); + + if (!NLMSG_OK(nlh, remain_len)) { + h->last_nlhdr = NULL; + return NULL; + } + + h->last_nlhdr = nlh; + + return nlh; +} + +/** + * nfnl_callback_register - register a callback for a certain message type + * @ssh: nfnetlink subsys handler + * @type: subsys call + * @cb: nfnetlink callback to be registered + * + * On success, 0 is returned. On error, -1 is returned and errno is set + * appropiately. + */ +int nfnl_callback_register(struct nfnl_subsys_handle *ssh, + uint8_t type, struct nfnl_callback *cb) +{ + assert(ssh); + assert(cb); + + if (type >= ssh->cb_count) { + errno = EINVAL; + return -1; + } + + memcpy(&ssh->cb[type], cb, sizeof(*cb)); + + return 0; +} + +/** + * nfnl_callback_unregister - unregister a certain callback + * @ssh: nfnetlink subsys handler + * @type: subsys call + * + * On sucess, 0 is returned. On error, -1 is returned and errno is + * set appropiately. + */ +int nfnl_callback_unregister(struct nfnl_subsys_handle *ssh, uint8_t type) +{ + assert(ssh); + + if (type >= ssh->cb_count) { + errno = EINVAL; + return -1; + } + + ssh->cb[type].call = NULL; + + return 0; +} + +int nfnl_check_attributes(const struct nfnl_handle *h, + const struct nlmsghdr *nlh, + struct nfattr *nfa[]) +{ + assert(h); + assert(nlh); + assert(nfa); + + int min_len; + uint8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type); + uint8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type); + const struct nfnl_subsys_handle *ssh; + struct nfnl_callback *cb; + + if (subsys_id > NFNL_MAX_SUBSYS) + return -EINVAL; + + ssh = &h->subsys[subsys_id]; + cb = &ssh->cb[type]; + +#if 1 + /* checks need to be enabled as soon as this is called from + * somebody else than __nfnl_handle_msg */ + if (type >= ssh->cb_count) + return -EINVAL; + + min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + if (nlh->nlmsg_len < min_len) + return -EINVAL; +#endif + memset(nfa, 0, sizeof(struct nfattr *) * cb->attr_count); + + if (nlh->nlmsg_len > min_len) { + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + while (NFA_OK(attr, attrlen)) { + unsigned int flavor = NFA_TYPE(attr); + if (flavor) { + if (flavor > cb->attr_count) { + /* we have received an attribute from + * the kernel which we don't understand + * yet. We have to silently ignore this + * for the sake of future compatibility */ + attr = NFA_NEXT(attr, attrlen); + continue; + } + nfa[flavor - 1] = attr; + } + attr = NFA_NEXT(attr, attrlen); + } + } + + return 0; +} + +static int __nfnl_handle_msg(struct nfnl_handle *h, struct nlmsghdr *nlh, + int len) +{ + struct nfnl_subsys_handle *ssh; + uint8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type); + uint8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type); + int err = 0; + + if (subsys_id > NFNL_MAX_SUBSYS) + return -1; + + ssh = &h->subsys[subsys_id]; + + if (nlh->nlmsg_len < NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) + return -1; + + if (type >= ssh->cb_count) + return -1; + + if (ssh->cb[type].attr_count) { + struct nfattr *nfa[ssh->cb[type].attr_count]; + + err = nfnl_check_attributes(h, nlh, nfa); + if (err < 0) + return err; + if (ssh->cb[type].call) + return ssh->cb[type].call(nlh, nfa, ssh->cb[type].data); + } + return 0; +} + +int nfnl_handle_packet(struct nfnl_handle *h, char *buf, int len) +{ + + while (len >= NLMSG_SPACE(0)) { + uint32_t rlen; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + if (nlh->nlmsg_len < sizeof(struct nlmsghdr) + || len < nlh->nlmsg_len) + return -1; + + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > len) + rlen = len; + + if (__nfnl_handle_msg(h, nlh, rlen) < 0) + return -1; + + len -= rlen; + buf += rlen; + } + return 0; +} + +static int nfnl_is_error(struct nfnl_handle *h, struct nlmsghdr *nlh) +{ + /* This message is an ACK or a DONE */ + if (nlh->nlmsg_type == NLMSG_ERROR || + (nlh->nlmsg_type == NLMSG_DONE && + nlh->nlmsg_flags & NLM_F_MULTI)) { + if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) { + errno = EBADMSG; + return 1; + } + errno = -(*((int *)NLMSG_DATA(nlh))); + return 1; + } + return 0; +} + +/* On error, -1 is returned and errno is set appropiately. On success, + * 0 is returned if there is no more data to process, >0 if there is + * more data to process */ +static int nfnl_step(struct nfnl_handle *h, struct nlmsghdr *nlh) +{ + struct nfnl_subsys_handle *ssh; + uint8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type); + uint8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type); + + /* Is this an error message? */ + if (nfnl_is_error(h, nlh)) { + /* This is an ACK */ + if (errno == 0) + return 0; + /* This an error message */ + return -1; + } + + /* nfnetlink sanity checks: check for nfgenmsg size */ + if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) { + errno = ENOSPC; + return -1; + } + + if (subsys_id > NFNL_MAX_SUBSYS) { + errno = ENOENT; + return -1; + } + + ssh = &h->subsys[subsys_id]; + if (!ssh) { + errno = ENOENT; + return -1; + } + + if (type >= ssh->cb_count) { + errno = ENOENT; + return -1; + } + + if (ssh->cb[type].attr_count) { + int err; + struct nfattr *tb[ssh->cb[type].attr_count]; + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + err = nfnl_parse_attr(tb, ssh->cb[type].attr_count, attr, len); + if (err == -1) + return -1; + + if (ssh->cb[type].call) { + /* + * On error, the callback returns NFNL_CB_FAILURE and + * errno must be explicitely set. On success, + * NFNL_CB_STOP is returned and we're done, otherwise + * NFNL_CB_CONTINUE means that we want to continue + * data processing. + */ + return ssh->cb[type].call(nlh, + tb, + ssh->cb[type].data); + } + } + /* no callback set, continue data processing */ + return 1; +} + +/** + * nfnl_process - process data coming from a nfnetlink system + * @h: nfnetlink handler + * @buf: buffer that contains the netlink message + * @len: size of the data contained in the buffer (not the buffer size) + * + * This function processes all the nfnetlink messages contained inside a + * buffer. It performs the appropiate sanity checks and passes the message + * to a certain handler that is registered via register_callback(). + * + * On success, NFNL_CB_STOP is returned if the data processing has finished. + * If a value NFNL_CB_CONTINUE is returned, then there is more data to + * process. On error, NFNL_CB_CONTINUE is returned and errno is set to the + * appropiate value. + * + * In case that the callback returns NFNL_CB_FAILURE, errno may be set by + * the library client. If your callback decides not to process data anymore + * for any reason, then it must return NFNL_CB_STOP. Otherwise, if the + * callback continues the processing NFNL_CB_CONTINUE is returned. + */ +int nfnl_process(struct nfnl_handle *h, const unsigned char *buf, size_t len) +{ + int ret = 0; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + assert(h); + assert(buf); + assert(len > 0); + + /* check for out of sequence message */ + if (nlh->nlmsg_seq && nlh->nlmsg_seq != h->seq) { + errno = EILSEQ; + return -1; + } + while (len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) { + + ret = nfnl_step(h, nlh); + if (ret <= NFNL_CB_STOP) + break; + + nlh = NLMSG_NEXT(nlh, len); + } + return ret; +} + +/* + * New parsing functions based on iterators + */ + +struct nfnl_iterator { + struct nlmsghdr *nlh; + unsigned int len; +}; + +/** + * nfnl_iterator_create: create an nfnetlink iterator + * @h: nfnetlink handler + * @buf: buffer that contains data received from a nfnetlink system + * @len: size of the data contained in the buffer (not the buffer size) + * + * This function creates an iterator that can be used to parse nfnetlink + * message one by one. The iterator gives more control to the programmer + * in the messages processing. + * + * On success, a valid address is returned. On error, NULL is returned + * and errno is set to the appropiate value. + */ +struct nfnl_iterator * +nfnl_iterator_create(const struct nfnl_handle *h, + const char *buf, + size_t len) +{ + struct nlmsghdr *nlh; + struct nfnl_iterator *it; + + assert(h); + assert(buf); + assert(len > 0); + + it = malloc(sizeof(struct nfnl_iterator)); + if (!it) { + errno = ENOMEM; + return NULL; + } + + /* first message in buffer */ + nlh = (struct nlmsghdr *)buf; + if (len < NLMSG_SPACE(0) || !NLMSG_OK(nlh, len)) { + free(it); + errno = EBADMSG; + return NULL; + } + it->nlh = nlh; + it->len = len; + + return it; +} + +/** + * nfnl_iterator_destroy - destroy a nfnetlink iterator + * @it: nfnetlink iterator + * + * This function destroys a certain iterator. Nothing is returned. + */ +void nfnl_iterator_destroy(struct nfnl_iterator *it) +{ + assert(it); + free(it); +} + +/** + * nfnl_iterator_process - process a nfnetlink message + * @h: nfnetlink handler + * @it: nfnetlink iterator that contains the current message to be proccesed + * + * This function process just the current message selected by the iterator. + * On success, a value greater or equal to zero is returned. On error, + * -1 is returned and errno is appropiately set. + */ +int nfnl_iterator_process(struct nfnl_handle *h, struct nfnl_iterator *it) +{ + assert(h); + assert(it->nlh); + + /* check for out of sequence message */ + if (it->nlh->nlmsg_seq && it->nlh->nlmsg_seq != h->seq) { + errno = EILSEQ; + return -1; + } + if (it->len < NLMSG_SPACE(0) || !NLMSG_OK(it->nlh, it->len)) { + errno = EBADMSG; + return -1; + } + return nfnl_step(h, it->nlh); +} + +/** + * nfnl_iterator_next - get the next message hold by the iterator + * @h: nfnetlink handler + * @it: nfnetlink iterator that contains the current message processed + * + * This function update the current message to be processed pointer. + * It returns NFNL_CB_CONTINUE if there is still more messages to be + * processed, otherwise NFNL_CB_STOP is returned. + */ +int nfnl_iterator_next(const struct nfnl_handle *h, struct nfnl_iterator *it) +{ + assert(h); + assert(it); + + it->nlh = NLMSG_NEXT(it->nlh, it->len); + if (!it->nlh) + return 0; + return 1; +} + +/** + * nfnl_catch - get responses from the nfnetlink system and process them + * @h: nfnetlink handler +* + * This function handles the data received from the nfnetlink system. + * For example, events generated by one of the subsystems. The message + * is passed to the callback registered via callback_register(). Note that + * this a replacement of nfnl_listen and its use is recommended. + * + * On success, 0 is returned. On error, a -1 is returned. If you do not + * want to listen to events anymore, then your callback must return + * NFNL_CB_STOP. + * + * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In + * that case is possible that the information requested is incomplete. + */ +int nfnl_catch(struct nfnl_handle *h) +{ + int ret; + + assert(h); + + while (1) { + unsigned char buf[h->rcv_buffer_size] + __attribute__ ((aligned)); + + ret = nfnl_recv(h, buf, sizeof(buf)); + if (ret == -1) { + /* interrupted syscall must retry */ + if (errno == EINTR) + continue; + break; + } + + ret = nfnl_process(h, buf, ret); + if (ret <= NFNL_CB_STOP) + break; + } + + return ret; +} + +/** + * nfnl_query - request/response communication challenge + * @h: nfnetlink handler + * @nlh: nfnetlink message to be sent + * + * This function sends a nfnetlink message to a certain subsystem and + * receives the response messages associated, such messages are passed to + * the callback registered via register_callback(). Note that this function + * is a replacement for nfnl_talk, its use is recommended. + * + * On success, 0 is returned. On error, a negative is returned. If your + * does not want to listen to events anymore, then your callback must + * return NFNL_CB_STOP. + * + * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In + * that case is possible that the information requested is incomplete. + */ +int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh) +{ + assert(h); + assert(nlh); + + if (nfnl_send(h, nlh) == -1) + return -1; + + return nfnl_catch(h); +} + +/** + * @} + */ diff --git a/deps/libnfnetlink/src/nfnl.version b/deps/libnfnetlink/src/nfnl.version new file mode 100644 index 0000000..c3817dd --- /dev/null +++ b/deps/libnfnetlink/src/nfnl.version @@ -0,0 +1,55 @@ +NFNETLINK_1.0.1 { + global: + nfnl_fd; + nfnl_portid; + nfnl_open; + nfnl_close; + nfnl_subsys_open; + nfnl_subsys_close; + nfnl_set_sequence_tracking; + nfnl_unset_sequence_tracking; + nfnl_set_rcv_buffer_size; + nfnl_send; + nfnl_sendmsg; + nfnl_sendiov; + nfnl_fill_hdr; + nfnl_talk; + nfnl_listen; + nfnl_recv; + nfnl_callback_register; + nfnl_callback_unregister; + nfnl_handle_packet; + nfnl_parse_hdr; + nfnl_check_attributes; + nfnl_get_msg_first; + nfnl_get_msg_next; + nfnl_join; + nfnl_process; + nfnl_iterator_create; + nfnl_iterator_destroy; + nfnl_iterator_process; + nfnl_iterator_next; + nfnl_catch; + nfnl_query; + nfnl_addattr_l; + nfnl_addattr8; + nfnl_addattr16; + nfnl_addattr32; + nfnl_nfa_addattr_l; + nfnl_nfa_addattr16; + nfnl_nfa_addattr32; + nfnl_parse_attr; + nfnl_build_nfa_iovec; + nfnl_rcvbufsiz; + nfnl_dump_packet; + nlif_open; + nlif_close; + nlif_fd; + nlif_query; + nlif_catch; + nlif_index2name; + nlif_get_ifflags; + + local: + *; +}; diff --git a/deps/libnfnetlink/src/rtnl.c b/deps/libnfnetlink/src/rtnl.c new file mode 100644 index 0000000..284eecd --- /dev/null +++ b/deps/libnfnetlink/src/rtnl.c @@ -0,0 +1,266 @@ +/* rtnl - rtnetlink utility functions + * + * (C) 2004 by Astaro AG, written by Harald Welte + * + * Adapted to nfnetlink by Eric Leblond + * + * This software is free software and licensed under GNU GPLv2+. + * + */ + +/* rtnetlink - routing table netlink interface */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "rtnl.h" + +#define rtnl_log(x, ...) + +static inline struct rtnl_handler * +find_handler(struct rtnl_handle *rtnl_handle, uint16_t type) +{ + struct rtnl_handler *h; + for (h = rtnl_handle->handlers; h; h = h->next) { + if (h->nlmsg_type == type) + return h; + } + return NULL; +} + +static int call_handler(struct rtnl_handle *rtnl_handle, + uint16_t type, + struct nlmsghdr *hdr) +{ + struct rtnl_handler *h = find_handler(rtnl_handle, type); + + if (!h) { + rtnl_log(LOG_DEBUG, "no registered handler for type %u", type); + return 0; + } + + return (h->handlefn)(hdr, h->arg); +} + +/* rtnl_handler_register - register handler for given nlmsg type + * @hdlr: handler structure + */ +int rtnl_handler_register(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr) +{ + rtnl_log(LOG_DEBUG, "registering handler for type %u", + hdlr->nlmsg_type); + hdlr->next = rtnl_handle->handlers; + rtnl_handle->handlers = hdlr; + return 1; +} + +/* rtnl_handler_unregister - unregister handler for given nlmst type + * @hdlr: handler structure + */ +int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr) +{ + struct rtnl_handler *h, *prev = NULL; + + rtnl_log(LOG_DEBUG, "unregistering handler for type %u", + hdlr->nlmsg_type); + + for (h = rtnl_handle->handlers; h; h = h->next) { + if (h == hdlr) { + if (prev) + prev->next = h->next; + else + rtnl_handle->handlers = h->next; + return 1; + } + prev = h; + } + return 0; +} + +int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + memset(tb, 0, sizeof(struct rtattr *) * max); + + while (RTA_OK(rta, len)) { + if (rta->rta_type <= max) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta,len); + } + if (len) + return -1; + return 0; +} + +/* rtnl_dump_type - ask rtnetlink to dump a specific table + * @type: type of table to be dumped + */ +int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type) +{ + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct sockaddr_nl nladdr; + + memset(&nladdr, 0, sizeof(nladdr)); + memset(&req, 0, sizeof(req)); + nladdr.nl_family = AF_NETLINK; + + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = rtnl_handle->rtnl_dump = ++(rtnl_handle->rtnl_seq); + req.g.rtgen_family = AF_INET; + + return sendto(rtnl_handle->rtnl_fd, &req, sizeof(req), 0, + (struct sockaddr*)&nladdr, sizeof(nladdr)); +} + +/* rtnl_receive - receive netlink packets from rtnetlink socket */ +int rtnl_receive(struct rtnl_handle *rtnl_handle) +{ + int status; + char buf[8192]; + struct sockaddr_nl nladdr; + struct iovec iov = { buf, sizeof(buf) }; + struct nlmsghdr *h; + + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + status = recvmsg(rtnl_handle->rtnl_fd, &msg, 0); + if (status < 0) { + if (errno == EINTR) + return 0; + rtnl_log(LOG_NOTICE, "OVERRUN on rtnl socket"); + return -1; + } + if (status == 0) { + rtnl_log(LOG_ERROR, "EOF on rtnl socket"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + rtnl_log(LOG_ERROR, "invalid address size"); + return -1; + } + + h = (struct nlmsghdr *) buf; + while (NLMSG_OK(h, status)) { +#if 0 + if (h->nlmsg_pid != rtnl_local.nl_pid || + h->nlmsg_seq != rtnl_dump) { + goto skip; + } +#endif + + if (h->nlmsg_type == NLMSG_DONE) { + rtnl_log(LOG_NOTICE, "NLMSG_DONE"); + return 0; + } + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = NLMSG_DATA(h); + if (h->nlmsg_len>=NLMSG_LENGTH(sizeof(struct nlmsgerr))) + errno = -err->error; + rtnl_log(LOG_ERROR, "NLMSG_ERROR, errnp=%d", + errno); + return -1; + } + + if (call_handler(rtnl_handle, h->nlmsg_type, h) == 0) + rtnl_log(LOG_NOTICE, "unhandled nlmsg_type %u", + h->nlmsg_type); + h = NLMSG_NEXT(h, status); + } + return 1; +} + +int rtnl_receive_multi(struct rtnl_handle *rtnl_handle) +{ + while (1) { + if (rtnl_receive(rtnl_handle) <= 0) + break; + } + return 1; +} + +/* rtnl_open - constructor of rtnetlink module */ +struct rtnl_handle *rtnl_open(void) +{ + socklen_t addrlen; + struct rtnl_handle *h; + + h = calloc(1, sizeof(struct rtnl_handle)); + if (!h) + return NULL; + + addrlen = sizeof(h->rtnl_local); + + h->rtnl_local.nl_pid = getpid(); + h->rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (h->rtnl_fd < 0) { + rtnl_log(LOG_ERROR, "unable to create rtnetlink socket"); + goto err; + } + + memset(&h->rtnl_local, 0, sizeof(h->rtnl_local)); + h->rtnl_local.nl_family = AF_NETLINK; + h->rtnl_local.nl_groups = RTMGRP_LINK; + if (bind(h->rtnl_fd, (struct sockaddr *) &h->rtnl_local, addrlen) < 0) { + rtnl_log(LOG_ERROR, "unable to bind rtnetlink socket"); + goto err_close; + } + + if (getsockname(h->rtnl_fd, + (struct sockaddr *) &h->rtnl_local, + &addrlen) < 0) { + rtnl_log(LOG_ERROR, "cannot gescockname(rtnl_socket)"); + goto err_close; + } + + if (addrlen != sizeof(h->rtnl_local)) { + rtnl_log(LOG_ERROR, "invalid address size %u", addr_len); + goto err_close; + } + + if (h->rtnl_local.nl_family != AF_NETLINK) { + rtnl_log(LOG_ERROR, "invalid AF %u", h->rtnl_local.nl_family); + goto err_close; + } + + h->rtnl_seq = time(NULL); + + return h; + +err_close: + close(h->rtnl_fd); +err: + free(h); + return NULL; +} + +/* rtnl_close - destructor of rtnetlink module */ +void rtnl_close(struct rtnl_handle *rtnl_handle) +{ + close(rtnl_handle->rtnl_fd); + free(rtnl_handle); + return; +} diff --git a/deps/libnfnetlink/src/rtnl.h b/deps/libnfnetlink/src/rtnl.h new file mode 100644 index 0000000..2cb22a8 --- /dev/null +++ b/deps/libnfnetlink/src/rtnl.h @@ -0,0 +1,37 @@ +#ifndef _RTNL_H +#define _RTNL_H + +#include +#include + +struct rtnl_handler { + struct rtnl_handler *next; + + uint16_t nlmsg_type; + int (*handlefn)(struct nlmsghdr *h, void *arg); + void *arg; +}; + +struct rtnl_handle { + int rtnl_fd; + int rtnl_seq; + int rtnl_dump; + struct sockaddr_nl rtnl_local; + struct rtnl_handler *handlers; +}; + +/* api for handler plugins */ +int rtnl_handler_register(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr); +int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr); +int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); +int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type); + +/* api for core program */ +struct rtnl_handle *rtnl_open(void); +void rtnl_close(struct rtnl_handle *rtnl_handle); +int rtnl_receive(struct rtnl_handle *rtnl_handle); +int rtnl_receive_multi(struct rtnl_handle *rtnl_handle); + +#endif diff --git a/deps/libnfnetlink/utils/.gitignore b/deps/libnfnetlink/utils/.gitignore new file mode 100644 index 0000000..ddd4de3 --- /dev/null +++ b/deps/libnfnetlink/utils/.gitignore @@ -0,0 +1 @@ +/iftest diff --git a/deps/libnfnetlink/utils/Makefile.am b/deps/libnfnetlink/utils/Makefile.am new file mode 100644 index 0000000..69827ca --- /dev/null +++ b/deps/libnfnetlink/utils/Makefile.am @@ -0,0 +1,7 @@ +include $(top_srcdir)/Make_global.am + +check_PROGRAMS = iftest + +iftest_SOURCES = iftest.c +iftest_LDADD = ../src/libnfnetlink.la +iftest_LDFLAGS = -dynamic -ldl diff --git a/deps/libnfnetlink/utils/iftest.c b/deps/libnfnetlink/utils/iftest.c new file mode 100644 index 0000000..02f5807 --- /dev/null +++ b/deps/libnfnetlink/utils/iftest.c @@ -0,0 +1,52 @@ +/* simple test for index to interface name API */ + +#include +#include +#include +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + int idx; + struct nlif_handle *h; + char name[IFNAMSIZ]; + unsigned int flags; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + h = nlif_open(); + if (h == NULL) { + perror("nlif_open"); + exit(EXIT_FAILURE); + } + + if (nlif_query(h) == -1) { + fprintf(stderr, "failed query to retrieve interfaces: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + + idx = if_nametoindex(argv[1]); + + /* Superfluous: just to make sure nlif_index2name is working fine */ + if (nlif_index2name(h, idx, name) == -1) + fprintf(stderr, "Cannot translate device idx=%u\n", idx); + + if (nlif_get_ifflags(h, idx, &flags) == -1) { + fprintf(stderr, "Cannot get flags for device `%s'\n", argv[1]); + exit(EXIT_FAILURE); + } + + printf("index (%d) is %s (%s) (%s)\n", idx, argv[1], + flags & IFF_RUNNING ? "RUNNING" : "NOT RUNNING", + flags & IFF_UP ? "UP" : "DOWN"); + + nlif_close(h); + return EXIT_SUCCESS; +}