diff options
Diffstat (limited to '')
-rw-r--r-- | py/Makefile.am | 1 | ||||
-rw-r--r-- | py/Makefile.in | 455 | ||||
-rw-r--r-- | py/pyproject.toml | 3 | ||||
-rw-r--r-- | py/setup.cfg | 24 | ||||
-rwxr-xr-x | py/setup.py | 5 | ||||
-rw-r--r-- | py/src/__init__.py | 1 | ||||
-rw-r--r-- | py/src/nftables.py | 604 | ||||
-rw-r--r-- | py/src/schema.json | 16 |
8 files changed, 1109 insertions, 0 deletions
diff --git a/py/Makefile.am b/py/Makefile.am new file mode 100644 index 0000000..76aa082 --- /dev/null +++ b/py/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = pyproject.toml setup.cfg setup.py src diff --git a/py/Makefile.in b/py/Makefile.in new file mode 100644 index 0000000..3f7ea9e --- /dev/null +++ b/py/Makefile.in @@ -0,0 +1,455 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = py +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +A2X = @A2X@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBMNL_CFLAGS = @LIBMNL_CFLAGS@ +LIBMNL_LIBS = @LIBMNL_LIBS@ +LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@ +LIBNFTNL_LIBS = @LIBNFTNL_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +XTABLES_CFLAGS = @XTABLES_CFLAGS@ +XTABLES_LIBS = @XTABLES_LIBS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = pyproject.toml setup.cfg setup.py src +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign py/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign py/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/py/pyproject.toml b/py/pyproject.toml new file mode 100644 index 0000000..fed528d --- /dev/null +++ b/py/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/py/setup.cfg b/py/setup.cfg new file mode 100644 index 0000000..953b7f4 --- /dev/null +++ b/py/setup.cfg @@ -0,0 +1,24 @@ +[metadata] +name = nftables +version = attr: nftables.NFTABLES_VERSION +description = Libnftables binding +author = Netfilter project +author_email = coreteam@netfilter.org +url = https://netfilter.org/projects/nftables/index.html +provides = nftables +classifiers = + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: Developers + License :: OSI Approved :: GNU General Public License v2 (GPLv2) + Operating System :: POSIX :: Linux + Programming Language :: Python + Topic :: System :: Networking :: Firewalls + +[options] +packages = nftables +package_dir = + nftables = src + +[options.package_data] +nftables = schema.json diff --git a/py/setup.py b/py/setup.py new file mode 100755 index 0000000..beda28e --- /dev/null +++ b/py/setup.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +from setuptools import setup + +setup() diff --git a/py/src/__init__.py b/py/src/__init__.py new file mode 100644 index 0000000..7567f09 --- /dev/null +++ b/py/src/__init__.py @@ -0,0 +1 @@ +from .nftables import * diff --git a/py/src/nftables.py b/py/src/nftables.py new file mode 100644 index 0000000..f1e43ad --- /dev/null +++ b/py/src/nftables.py @@ -0,0 +1,604 @@ +#!/usr/bin/python +# Copyright(C) 2018 Phil Sutter <phil@nwl.cc> + +# 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, version 2 of the License. +# +# 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. + +import json +from ctypes import * +import sys +import os + +NFTABLES_VERSION = "0.1" + +class SchemaValidator: + """Libnftables JSON validator using jsonschema""" + + def __init__(self): + schema_path = os.path.join(os.path.dirname(__file__), "schema.json") + with open(schema_path, 'r') as schema_file: + self.schema = json.load(schema_file) + import jsonschema + self.jsonschema = jsonschema + + def validate(self, json): + self.jsonschema.validate(instance=json, schema=self.schema) + +class Nftables: + """A class representing libnftables interface""" + + input_flags = { + "no-dns": 0x1, + "json": 0x2, + } + + debug_flags = { + "scanner": 0x1, + "parser": 0x2, + "eval": 0x4, + "netlink": 0x8, + "mnl": 0x10, + "proto-ctx": 0x20, + "segtree": 0x40, + } + + output_flags = { + "reversedns": (1 << 0), + "service": (1 << 1), + "stateless": (1 << 2), + "handle": (1 << 3), + "json": (1 << 4), + "echo": (1 << 5), + "guid": (1 << 6), + "numeric_proto": (1 << 7), + "numeric_prio": (1 << 8), + "numeric_symbol": (1 << 9), + "numeric_time": (1 << 10), + "terse": (1 << 11), + } + + validator = None + + def __init__(self, sofile="libnftables.so.1"): + """Instantiate a new Nftables class object. + + Accepts a shared object file to open, by default standard search path + is searched for a file named 'libnftables.so'. + + After loading the library using ctypes module, a new nftables context + is requested from the library and buffering of output and error streams + is turned on. + """ + self.__ctx = None + + lib = cdll.LoadLibrary(sofile) + + ### API function definitions + + self.nft_ctx_new = lib.nft_ctx_new + self.nft_ctx_new.restype = c_void_p + self.nft_ctx_new.argtypes = [c_int] + + self.nft_ctx_input_get_flags = lib.nft_ctx_input_get_flags + self.nft_ctx_input_get_flags.restype = c_uint + self.nft_ctx_input_get_flags.argtypes = [c_void_p] + + self.nft_ctx_input_set_flags = lib.nft_ctx_input_set_flags + self.nft_ctx_input_set_flags.restype = c_uint + self.nft_ctx_input_set_flags.argtypes = [c_void_p, c_uint] + + self.nft_ctx_output_get_flags = lib.nft_ctx_output_get_flags + self.nft_ctx_output_get_flags.restype = c_uint + self.nft_ctx_output_get_flags.argtypes = [c_void_p] + + self.nft_ctx_output_set_flags = lib.nft_ctx_output_set_flags + self.nft_ctx_output_set_flags.argtypes = [c_void_p, c_uint] + + self.nft_ctx_output_get_debug = lib.nft_ctx_output_get_debug + self.nft_ctx_output_get_debug.restype = c_int + self.nft_ctx_output_get_debug.argtypes = [c_void_p] + + self.nft_ctx_output_set_debug = lib.nft_ctx_output_set_debug + self.nft_ctx_output_set_debug.argtypes = [c_void_p, c_int] + + self.nft_ctx_buffer_output = lib.nft_ctx_buffer_output + self.nft_ctx_buffer_output.restype = c_int + self.nft_ctx_buffer_output.argtypes = [c_void_p] + + self.nft_ctx_get_output_buffer = lib.nft_ctx_get_output_buffer + self.nft_ctx_get_output_buffer.restype = c_char_p + self.nft_ctx_get_output_buffer.argtypes = [c_void_p] + + self.nft_ctx_buffer_error = lib.nft_ctx_buffer_error + self.nft_ctx_buffer_error.restype = c_int + self.nft_ctx_buffer_error.argtypes = [c_void_p] + + self.nft_ctx_get_error_buffer = lib.nft_ctx_get_error_buffer + self.nft_ctx_get_error_buffer.restype = c_char_p + self.nft_ctx_get_error_buffer.argtypes = [c_void_p] + + self.nft_run_cmd_from_buffer = lib.nft_run_cmd_from_buffer + self.nft_run_cmd_from_buffer.restype = c_int + self.nft_run_cmd_from_buffer.argtypes = [c_void_p, c_char_p] + + self.nft_run_cmd_from_filename = lib.nft_run_cmd_from_filename + self.nft_run_cmd_from_filename.restype = c_int + self.nft_run_cmd_from_filename.argtypes = [c_void_p, c_char_p] + + self.nft_ctx_add_include_path = lib.nft_ctx_add_include_path + self.nft_ctx_add_include_path.restype = c_int + self.nft_ctx_add_include_path.argtypes = [c_void_p, c_char_p] + + self.nft_ctx_clear_include_paths = lib.nft_ctx_clear_include_paths + self.nft_ctx_clear_include_paths.argtypes = [c_void_p] + + self.nft_ctx_get_dry_run = lib.nft_ctx_get_dry_run + self.nft_ctx_get_dry_run.restype = c_bool + self.nft_ctx_get_dry_run.argtypes = [c_void_p] + + self.nft_ctx_set_dry_run = lib.nft_ctx_set_dry_run + self.nft_ctx_set_dry_run.argtypes = [c_void_p, c_bool] + + self.nft_ctx_add_var = lib.nft_ctx_add_var + self.nft_ctx_add_var.restype = c_int + self.nft_ctx_add_var.argtypes = [c_void_p, c_char_p] + + self.nft_ctx_clear_vars = lib.nft_ctx_clear_vars + self.nft_ctx_clear_vars.argtypes = [c_void_p] + + self.nft_ctx_free = lib.nft_ctx_free + lib.nft_ctx_free.argtypes = [c_void_p] + + # initialize libnftables context + self.__ctx = self.nft_ctx_new(0) + self.nft_ctx_buffer_output(self.__ctx) + self.nft_ctx_buffer_error(self.__ctx) + + def __del__(self): + if self.__ctx is not None: + self.nft_ctx_free(self.__ctx) + self.__ctx = None + + def _flags_from_numeric(self, flags_dict, val): + names = [] + for n, v in flags_dict.items(): + if val & v: + names.append(n) + val &= ~v + if val: + names.append(val) + return names + + def _flags_to_numeric(self, flags_dict, values): + if isinstance(values, (str, int)): + values = (values,) + + val = 0 + for v in values: + if isinstance(v, str): + v = flags_dict.get(v) + if v is None: + raise ValueError("Invalid argument") + elif isinstance(v, int): + if v < 0 or v > 0xFFFFFFFF: + raise ValueError("Invalid argument") + else: + raise TypeError("Not a valid flag") + val |= v + + return val + + def get_input_flags(self): + """Get currently active input flags. + + Returns a set of flag names. See set_input_flags() for details. + """ + val = self.nft_ctx_input_get_flags(self.__ctx) + return self._flags_from_numeric(self.input_flags, val) + + def set_input_flags(self, values): + """Set input flags. + + Resets all input flags to values. Accepts either a single flag or a list + of flags. Each flag might be given either as string or integer value as + shown in the following table: + + Name | Value (hex) + ----------------------- + "no-dns" | 0x1 + "json" | 0x2 + + "no-dns" disables blocking address lookup. + "json" enables JSON mode for input. + + Returns a set of previously active input flags, as returned by + get_input_flags() method. + """ + val = self._flags_to_numeric(self.input_flags, values) + old = self.nft_ctx_input_set_flags(self.__ctx, val) + return self._flags_from_numeric(self.input_flags, old) + + def __get_output_flag(self, name): + flag = self.output_flags[name] + return (self.nft_ctx_output_get_flags(self.__ctx) & flag) != 0 + + def __set_output_flag(self, name, val): + flag = self.output_flags[name] + flags = self.nft_ctx_output_get_flags(self.__ctx) + if val: + new_flags = flags | flag + else: + new_flags = flags & ~flag + self.nft_ctx_output_set_flags(self.__ctx, new_flags) + return (flags & flag) != 0 + + def get_reversedns_output(self): + """Get the current state of reverse DNS output. + + Returns a boolean indicating whether reverse DNS lookups are performed + for IP addresses in output. + """ + return self.__get_output_flag("reversedns") + + def set_reversedns_output(self, val): + """Enable or disable reverse DNS output. + + Accepts a boolean turning reverse DNS lookups in output on or off. + + Returns the previous value. + """ + return self.__set_output_flag("reversedns", val) + + def get_service_output(self): + """Get the current state of service name output. + + Returns a boolean indicating whether service names are used for port + numbers in output or not. + """ + return self.__get_output_flag("service") + + def set_service_output(self, val): + """Enable or disable service name output. + + Accepts a boolean turning service names for port numbers in output on + or off. + + Returns the previous value. + """ + return self.__set_output_flag("service", val) + + def get_stateless_output(self): + """Get the current state of stateless output. + + Returns a boolean indicating whether stateless output is active or not. + """ + return self.__get_output_flag("stateless") + + def set_stateless_output(self, val): + """Enable or disable stateless output. + + Accepts a boolean turning stateless output either on or off. + + Returns the previous value. + """ + return self.__set_output_flag("stateless", val) + + def get_handle_output(self): + """Get the current state of handle output. + + Returns a boolean indicating whether handle output is active or not. + """ + return self.__get_output_flag("handle") + + def set_handle_output(self, val): + """Enable or disable handle output. + + Accepts a boolean turning handle output on or off. + + Returns the previous value. + """ + return self.__set_output_flag("handle", val) + + def get_json_output(self): + """Get the current state of JSON output. + + Returns a boolean indicating whether JSON output is active or not. + """ + return self.__get_output_flag("json") + + def set_json_output(self, val): + """Enable or disable JSON output. + + Accepts a boolean turning JSON output either on or off. + + Returns the previous value. + """ + return self.__set_output_flag("json", val) + + def get_echo_output(self): + """Get the current state of echo output. + + Returns a boolean indicating whether echo output is active or not. + """ + return self.__get_output_flag("echo") + + def set_echo_output(self, val): + """Enable or disable echo output. + + Accepts a boolean turning echo output on or off. + + Returns the previous value. + """ + return self.__set_output_flag("echo", val) + + def get_guid_output(self): + """Get the current state of GID/UID output. + + Returns a boolean indicating whether names for group/user IDs are used + in output or not. + """ + return self.__get_output_flag("guid") + + def set_guid_output(self, val): + """Enable or disable GID/UID output. + + Accepts a boolean turning names for group/user IDs on or off. + + Returns the previous value. + """ + return self.__set_output_flag("guid", val) + + def get_numeric_proto_output(self): + """Get current status of numeric protocol output flag. + + Returns a boolean value indicating the status. + """ + return self.__get_output_flag("numeric_proto") + + def set_numeric_proto_output(self, val): + """Set numeric protocol output flag. + + Accepts a boolean turning numeric protocol output either on or off. + + Returns the previous value. + """ + return self.__set_output_flag("numeric_proto", val) + + def get_numeric_prio_output(self): + """Get current status of numeric chain priority output flag. + + Returns a boolean value indicating the status. + """ + return self.__get_output_flag("numeric_prio") + + def set_numeric_prio_output(self, val): + """Set numeric chain priority output flag. + + Accepts a boolean turning numeric chain priority output either on or + off. + + Returns the previous value. + """ + return self.__set_output_flag("numeric_prio", val) + + def get_numeric_symbol_output(self): + """Get current status of numeric symbols output flag. + + Returns a boolean value indicating the status. + """ + return self.__get_output_flag("numeric_symbol") + + def set_numeric_symbol_output(self, val): + """Set numeric symbols output flag. + + Accepts a boolean turning numeric representation of symbolic constants + in output either on or off. + + Returns the previous value. + """ + return self.__set_output_flag("numeric_symbol", val) + + def get_numeric_time_output(self): + """Get current status of numeric times output flag. + + Returns a boolean value indicating the status. + """ + return self.__get_output_flag("numeric_time") + + def set_numeric_time_output(self, val): + """Set numeric times output flag. + + Accepts a boolean turning numeric representation of time values + in output either on or off. + + Returns the previous value. + """ + return self.__set_output_flag("numeric_time", val) + + def get_terse_output(self): + """Get the current state of terse output. + + Returns a boolean indicating whether terse output is active or not. + """ + return self.__get_output_flag("terse") + + def set_terse_output(self, val): + """Enable or disable terse output. + + Accepts a boolean turning terse output either on or off. + + Returns the previous value. + """ + return self.__set_output_flag("terse", val) + + def get_debug(self): + """Get currently active debug flags. + + Returns a set of flag names. See set_debug() for details. + """ + val = self.nft_ctx_output_get_debug(self.__ctx) + return self._flags_from_numeric(self.debug_flags, val) + + def set_debug(self, values): + """Set debug output flags. + + Accepts either a single flag or a set of flags. Each flag might be + given either as string or integer value as shown in the following + table: + + Name | Value (hex) + ----------------------- + scanner | 0x1 + parser | 0x2 + eval | 0x4 + netlink | 0x8 + mnl | 0x10 + proto-ctx | 0x20 + segtree | 0x40 + + Returns a set of previously active debug flags, as returned by + get_debug() method. + """ + val = self._flags_to_numeric(self.debug_flags, values) + old = self.get_debug() + self.nft_ctx_output_set_debug(self.__ctx, val) + return old + + def cmd(self, cmdline): + """Run a simple nftables command via libnftables. + + Accepts a string containing an nftables command just like what one + would enter into an interactive nftables (nft -i) session. + + Returns a tuple (rc, output, error): + rc -- return code as returned by nft_run_cmd_from_buffer() fuction + output -- a string containing output written to stdout + error -- a string containing output written to stderr + """ + cmdline_is_unicode = False + if not isinstance(cmdline, bytes): + cmdline_is_unicode = True + cmdline = cmdline.encode("utf-8") + rc = self.nft_run_cmd_from_buffer(self.__ctx, cmdline) + output = self.nft_ctx_get_output_buffer(self.__ctx) + error = self.nft_ctx_get_error_buffer(self.__ctx) + if cmdline_is_unicode: + output = output.decode("utf-8") + error = error.decode("utf-8") + + return (rc, output, error) + + def json_cmd(self, json_root): + """Run an nftables command in JSON syntax via libnftables. + + Accepts a hash object as input. + + Returns a tuple (rc, output, error): + rc -- return code as returned by nft_run_cmd_from_buffer() function + output -- a hash object containing library standard output + error -- a string containing output written to stderr + """ + json_out_old = self.set_json_output(True) + rc, output, error = self.cmd(json.dumps(json_root)) + if not json_out_old: + self.set_json_output(json_out_old) + if len(output): + output = json.loads(output) + return (rc, output, error) + + def json_validate(self, json_root): + """Validate JSON object against libnftables schema. + + Accepts a hash object as input. + + Returns True if JSON is valid, raises an exception otherwise. + """ + if not self.validator: + self.validator = SchemaValidator() + + self.validator.validate(json_root) + return True + + def cmd_from_file(self, filename): + """Run a nftables command set from a file + + filename can be a str or a Path + + Returns a tuple (rc, output, error): + rc -- return code as returned by nft_run_cmd_from_filename() function + output -- a string containing output written to stdout + error -- a string containing output written to stderr + """ + filename_is_unicode = False + if not isinstance(filename, bytes): + filename_is_unicode = True + filename = str(filename) + filename= filename.encode("utf-8") + rc = self.nft_run_cmd_from_filename(self.__ctx, filename) + output = self.nft_ctx_get_output_buffer(self.__ctx) + error = self.nft_ctx_get_error_buffer(self.__ctx) + if filename_is_unicode: + output = output.decode("utf-8") + error = error.decode("utf-8") + return (rc, output, error) + + def add_include_path(self, filename): + """Add a path to the include file list + The default list includes the built-in default one + + Returns True on success, False if memory allocation fails + """ + if not isinstance(filename, bytes): + filename = str(filename) + filename= filename.encode("utf-8") + rc = self.nft_ctx_add_include_path(self.__ctx, filename) + return rc == 0 + + def clear_include_paths(self): + """Clear include path list + + Will also remove the built-in default one + """ + self.nft_ctx_clear_include_paths(self.__ctx) + + def get_dry_run(self): + """Get dry run state + + Returns True if set, False otherwise + """ + return self.nft_ctx_get_dry_run(self.__ctx) + + def set_dry_run(self, onoff): + """ Set dry run state + + Returns the previous dry run state + """ + old = self.get_dry_run() + self.nft_ctx_set_dry_run(self.__ctx, onoff) + + return old + + def add_var(self, var): + """Add a variable to the variable list + + Returns True if added, False otherwise + """ + if not isinstance(var, bytes): + var = var.encode("utf-8") + rc = self.nft_ctx_add_var(self.__ctx, var) + return rc == 0 + + def clear_vars(self): + """Clear variable list + """ + self.nft_ctx_clear_vars(self.__ctx) diff --git a/py/src/schema.json b/py/src/schema.json new file mode 100644 index 0000000..460e215 --- /dev/null +++ b/py/src/schema.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/schema#", + "description": "libnftables JSON API schema", + + "type": "object", + "properties": { + "nftables": { + "type": "array", + "minitems": 0, + "items": { + "type": "object" + } + } + }, + "required": [ "nftables" ] +} |