From a9e08317285b14a62d31a4997054e555123706ce Mon Sep 17 00:00:00 2001 From: CN_SZTL Date: Sat, 1 Feb 2020 04:53:36 +0800 Subject: [PATCH] kernel/iptables: add cgroup support --- include/netfilter.mk | 3 + package/kernel/linux/modules/netfilter.mk | 12 + package/network/utils/iptables/Makefile | 14 + .../modules/extensions/libxt_cgroup.c | 278 ++++++++++++++++++ .../modules/extensions/libxt_cgroup.man | 30 ++ .../modules/extensions/libxt_cgroup.t | 8 + .../modules/extensions/libxt_cgroup.txlate | 5 + .../include/linux/netfilter/xt_cgroup.h | 41 +++ 8 files changed, 391 insertions(+) create mode 100644 package/network/utils/iptables/modules/extensions/libxt_cgroup.c create mode 100644 package/network/utils/iptables/modules/extensions/libxt_cgroup.man create mode 100644 package/network/utils/iptables/modules/extensions/libxt_cgroup.t create mode 100644 package/network/utils/iptables/modules/extensions/libxt_cgroup.txlate create mode 100644 package/network/utils/iptables/modules/include/linux/netfilter/xt_cgroup.h diff --git a/include/netfilter.mk b/include/netfilter.mk index f750b9dbfc..f88273a955 100644 --- a/include/netfilter.mk +++ b/include/netfilter.mk @@ -150,6 +150,9 @@ $(eval $(call nf_add,IPT_IPSEC,CONFIG_NETFILTER_XT_MATCH_POLICY, $(P_XT)xt_polic # flow offload support $(eval $(call nf_add,IPT_FLOW,CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD, $(P_XT)xt_FLOWOFFLOAD)) +# cgroup +$(eval $(call nf_add,IPT_CGROUP,CONFIG_NETFILTER_XT_MATCH_CGROUP, $(P_XT)xt_cgroup)) + # IPv6 # kernel only diff --git a/package/kernel/linux/modules/netfilter.mk b/package/kernel/linux/modules/netfilter.mk index 6226bc9a4b..c8414dab52 100644 --- a/package/kernel/linux/modules/netfilter.mk +++ b/package/kernel/linux/modules/netfilter.mk @@ -458,6 +458,18 @@ endef $(eval $(call KernelPackage,ipt-nat)) +define KernelPackage/ipt-cgroup + SUBMENU:=$(NF_MENU) + TITLE:=cgroup + KCONFIG:=$(KCONFIG_IPT_CGROUP) + FILES:=$(LINUX_DIR)/net/netfilter/*cgroup*.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,$(notdir $(IPT_CGROUP-m))) + DEPENDS:= kmod-ipt-core +endef + +$(eval $(call KernelPackage,ipt-cgroup)) + + define KernelPackage/ipt-raw TITLE:=Netfilter IPv4 raw table support KCONFIG:=CONFIG_IP_NF_RAW diff --git a/package/network/utils/iptables/Makefile b/package/network/utils/iptables/Makefile index 49b966be08..e7025db04d 100644 --- a/package/network/utils/iptables/Makefile +++ b/package/network/utils/iptables/Makefile @@ -169,6 +169,19 @@ Includes support for: endef +define Package/iptables-mod-cgroup +$(call Package/iptables/Module, +kmod-ipt-cgroup) + TITLE:=cgroup support + endef + +define Package/iptables-mod-cgroup/description +iptables extension for cgroup support. + + Matches: + - cgroup + +endef + define Package/iptables-mod-imq $(call Package/iptables/Module, +kmod-ipt-imq) TITLE:=IMQ support @@ -711,6 +724,7 @@ $(eval $(call BuildPlugin,iptables-mod-conntrack-label,$(IPT_CONNTRACK_LABEL-m)) $(eval $(call BuildPlugin,iptables-mod-extra,$(IPT_EXTRA-m))) $(eval $(call BuildPlugin,iptables-mod-physdev,$(IPT_PHYSDEV-m))) $(eval $(call BuildPlugin,iptables-mod-filter,$(IPT_FILTER-m))) +$(eval $(call BuildPlugin,iptables-mod-cgroup,$(IPT_CGROUP-m))) $(eval $(call BuildPlugin,iptables-mod-imq,$(IPT_IMQ-m))) $(eval $(call BuildPlugin,iptables-mod-bandwidth,$(IPT_BANDWIDTH-m))) $(eval $(call BuildPlugin,iptables-mod-timerange,$(IPT_TIMERANGE-m))) diff --git a/package/network/utils/iptables/modules/extensions/libxt_cgroup.c b/package/network/utils/iptables/modules/extensions/libxt_cgroup.c new file mode 100644 index 0000000000..327032eaae --- /dev/null +++ b/package/network/utils/iptables/modules/extensions/libxt_cgroup.c @@ -0,0 +1,278 @@ +#include +#include +#include + +enum { + O_CLASSID = 0, + O_PATH = 1, +}; + +static void cgroup_help_v0(void) +{ + printf( +"cgroup match options:\n" +"[!] --cgroup classid Match cgroup classid\n"); +} + +static void cgroup_help_v1(void) +{ + printf( +"cgroup match options:\n" +"[!] --path path Recursively match path relative to cgroup2 root\n" +"[!] --cgroup classid Match cgroup classid, can't be used with --path\n"); +} + +static const struct xt_option_entry cgroup_opts_v0[] = { + { + .name = "cgroup", + .id = O_CLASSID, + .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_MAND | XTOPT_PUT, + XTOPT_POINTER(struct xt_cgroup_info_v0, id) + }, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry cgroup_opts_v1[] = { + { + .name = "path", + .id = O_PATH, + .type = XTTYPE_STRING, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_cgroup_info_v1, path) + }, + { + .name = "cgroup", + .id = O_CLASSID, + .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_cgroup_info_v1, classid) + }, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry cgroup_opts_v2[] = { + { + .name = "path", + .id = O_PATH, + .type = XTTYPE_STRING, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_cgroup_info_v2, path) + }, + { + .name = "cgroup", + .id = O_CLASSID, + .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_cgroup_info_v2, classid) + }, + XTOPT_TABLEEND, +}; + +static void cgroup_parse_v0(struct xt_option_call *cb) +{ + struct xt_cgroup_info_v0 *cgroupinfo = cb->data; + + xtables_option_parse(cb); + if (cb->invert) + cgroupinfo->invert = true; +} + +static void cgroup_parse_v1(struct xt_option_call *cb) +{ + struct xt_cgroup_info_v1 *info = cb->data; + + xtables_option_parse(cb); + + switch (cb->entry->id) { + case O_PATH: + info->has_path = true; + if (cb->invert) + info->invert_path = true; + break; + case O_CLASSID: + info->has_classid = true; + if (cb->invert) + info->invert_classid = true; + break; + } +} + +static void cgroup_parse_v2(struct xt_option_call *cb) +{ + struct xt_cgroup_info_v2 *info = cb->data; + + xtables_option_parse(cb); + + switch (cb->entry->id) { + case O_PATH: + info->has_path = true; + if (cb->invert) + info->invert_path = true; + break; + case O_CLASSID: + info->has_classid = true; + if (cb->invert) + info->invert_classid = true; + break; + } +} + +static void +cgroup_print_v0(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_cgroup_info_v0 *info = (void *) match->data; + + printf(" cgroup %s%u", info->invert ? "! ":"", info->id); +} + +static void cgroup_save_v0(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_cgroup_info_v0 *info = (void *) match->data; + + printf("%s --cgroup %u", info->invert ? " !" : "", info->id); +} + +static void +cgroup_print_v1(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_cgroup_info_v1 *info = (void *)match->data; + + printf(" cgroup"); + if (info->has_path) + printf(" %s%s", info->invert_path ? "! ":"", info->path); + if (info->has_classid) + printf(" %s%u", info->invert_classid ? "! ":"", info->classid); +} + +static void cgroup_save_v1(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_cgroup_info_v1 *info = (void *)match->data; + + if (info->has_path) { + printf("%s --path", info->invert_path ? " !" : ""); + xtables_save_string(info->path); + } + + if (info->has_classid) + printf("%s --cgroup %u", info->invert_classid ? " !" : "", + info->classid); +} + +static void +cgroup_print_v2(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_cgroup_info_v2 *info = (void *)match->data; + + printf(" cgroup"); + if (info->has_path) + printf(" %s%s", info->invert_path ? "! ":"", info->path); + if (info->has_classid) + printf(" %s%u", info->invert_classid ? "! ":"", info->classid); +} + +static void cgroup_save_v2(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_cgroup_info_v2 *info = (void *)match->data; + + if (info->has_path) { + printf("%s --path", info->invert_path ? " !" : ""); + xtables_save_string(info->path); + } + + if (info->has_classid) + printf("%s --cgroup %u", info->invert_classid ? " !" : "", + info->classid); +} + +static int cgroup_xlate_v0(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_cgroup_info_v0 *info = (void *)params->match->data; + + xt_xlate_add(xl, "meta cgroup %s%u", info->invert ? "!= " : "", + info->id); + return 1; +} + +static int cgroup_xlate_v1(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_cgroup_info_v1 *info = (void *)params->match->data; + + if (info->has_path) + return 0; + + if (info->has_classid) + xt_xlate_add(xl, "meta cgroup %s%u", + info->invert_classid ? "!= " : "", + info->classid); + + return 1; +} + +static int cgroup_xlate_v2(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_cgroup_info_v2 *info = (void *)params->match->data; + + if (info->has_path) + return 0; + + if (info->has_classid) + xt_xlate_add(xl, "meta cgroup %s%u", + info->invert_classid ? "!= " : "", + info->classid); + + return 1; +} + +static struct xtables_match cgroup_match[] = { + { + .family = NFPROTO_UNSPEC, + .revision = 0, + .name = "cgroup", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_cgroup_info_v0)), + .userspacesize = XT_ALIGN(sizeof(struct xt_cgroup_info_v0)), + .help = cgroup_help_v0, + .print = cgroup_print_v0, + .save = cgroup_save_v0, + .x6_parse = cgroup_parse_v0, + .x6_options = cgroup_opts_v0, + .xlate = cgroup_xlate_v0, + }, + { + .family = NFPROTO_UNSPEC, + .revision = 1, + .name = "cgroup", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_cgroup_info_v1)), + .userspacesize = offsetof(struct xt_cgroup_info_v1, priv), + .help = cgroup_help_v1, + .print = cgroup_print_v1, + .save = cgroup_save_v1, + .x6_parse = cgroup_parse_v1, + .x6_options = cgroup_opts_v1, + .xlate = cgroup_xlate_v1, + }, + { + .family = NFPROTO_UNSPEC, + .revision = 2, + .name = "cgroup", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_cgroup_info_v2)), + .userspacesize = offsetof(struct xt_cgroup_info_v2, priv), + .help = cgroup_help_v1, + .print = cgroup_print_v2, + .save = cgroup_save_v2, + .x6_parse = cgroup_parse_v2, + .x6_options = cgroup_opts_v2, + .xlate = cgroup_xlate_v2, + }, +}; + +void _init(void) +{ + xtables_register_matches(cgroup_match, ARRAY_SIZE(cgroup_match)); +} diff --git a/package/network/utils/iptables/modules/extensions/libxt_cgroup.man b/package/network/utils/iptables/modules/extensions/libxt_cgroup.man new file mode 100644 index 0000000000..4d5d1d86af --- /dev/null +++ b/package/network/utils/iptables/modules/extensions/libxt_cgroup.man @@ -0,0 +1,30 @@ +.TP +[\fB!\fP] \fB\-\-path\fP \fIpath\fP +Match cgroup2 membership. + +Each socket is associated with the v2 cgroup of the creating process. +This matches packets coming from or going to all sockets in the +sub-hierarchy of the specified path. The path should be relative to +the root of the cgroup2 hierarchy. +.TP +[\fB!\fP] \fB\-\-cgroup\fP \fIclassid\fP +Match cgroup net_cls classid. + +classid is the marker set through the cgroup net_cls controller. This +option and \-\-path can't be used together. +.PP +Example: +.IP +iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-path service/http-server \-j DROP +.IP +iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-cgroup 1 +\-j DROP +.PP +\fBIMPORTANT\fP: when being used in the INPUT chain, the cgroup +matcher is currently only of limited functionality, meaning it +will only match on packets that are processed for local sockets +through early socket demuxing. Therefore, general usage on the +INPUT chain is not advised unless the implications are well +understood. +.PP +Available since Linux 3.14. diff --git a/package/network/utils/iptables/modules/extensions/libxt_cgroup.t b/package/network/utils/iptables/modules/extensions/libxt_cgroup.t new file mode 100644 index 0000000000..72c8e37708 --- /dev/null +++ b/package/network/utils/iptables/modules/extensions/libxt_cgroup.t @@ -0,0 +1,8 @@ +:INPUT,OUTPUT,POSTROUTING +*mangle +-m cgroup --cgroup 1;=;OK +-m cgroup ! --cgroup 1;=;OK +-m cgroup --path "/";=;OK +-m cgroup ! --path "/";=;OK +-m cgroup --cgroup 1 --path "/";;FAIL +-m cgroup ;;FAIL diff --git a/package/network/utils/iptables/modules/extensions/libxt_cgroup.txlate b/package/network/utils/iptables/modules/extensions/libxt_cgroup.txlate new file mode 100644 index 0000000000..75f2e6ae16 --- /dev/null +++ b/package/network/utils/iptables/modules/extensions/libxt_cgroup.txlate @@ -0,0 +1,5 @@ +iptables-translate -t filter -A INPUT -m cgroup --cgroup 0 -j ACCEPT +nft add rule ip filter INPUT meta cgroup 0 counter accept + +iptables-translate -t filter -A INPUT -m cgroup ! --cgroup 0 -j ACCEPT +nft add rule ip filter INPUT meta cgroup != 0 counter accept diff --git a/package/network/utils/iptables/modules/include/linux/netfilter/xt_cgroup.h b/package/network/utils/iptables/modules/include/linux/netfilter/xt_cgroup.h new file mode 100644 index 0000000000..b74e370d61 --- /dev/null +++ b/package/network/utils/iptables/modules/include/linux/netfilter/xt_cgroup.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_XT_CGROUP_H +#define _UAPI_XT_CGROUP_H + +#include +#include + +struct xt_cgroup_info_v0 { + __u32 id; + __u32 invert; +}; + +struct xt_cgroup_info_v1 { + __u8 has_path; + __u8 has_classid; + __u8 invert_path; + __u8 invert_classid; + char path[PATH_MAX]; + __u32 classid; + + /* kernel internal data */ + void *priv __attribute__((aligned(8))); +}; + +#define XT_CGROUP_PATH_MAX 512 + +struct xt_cgroup_info_v2 { + __u8 has_path; + __u8 has_classid; + __u8 invert_path; + __u8 invert_classid; + union { + char path[XT_CGROUP_PATH_MAX]; + __u32 classid; + }; + + /* kernel internal data */ + void *priv __attribute__((aligned(8))); +}; + +#endif /* _UAPI_XT_CGROUP_H */