netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [iptables] extensions: add support for inner IPv6 packet 'inner6' match
@ 2018-01-18 15:13 Ahmed Abdelsalam
  2018-01-18 15:13 ` [nf-next] netfilter: Add support for inner IPv6 packet match Ahmed Abdelsalam
  0 siblings, 1 reply; 4+ messages in thread
From: Ahmed Abdelsalam @ 2018-01-18 15:13 UTC (permalink / raw)
  To: pablo, davem, fw, netfilter-devel, coreteam
  Cc: netdev, kadlec, uznet, yoshfuji, amsalam20

This patch adds a new exetension to iptables to inner IPv6
packet 'inner6' match.

Signed-off-by: Ahmed Abdelsalam <amsalam20@gmail.com>
---
 extensions/libip6t_inner6.c                | 111 +++++++++++++++++++++++++++++
 extensions/libip6t_inner6.t                |   4 ++
 include/linux/netfilter_ipv6/ip6t_inner6.h |  20 ++++++
 3 files changed, 135 insertions(+)
 create mode 100644 extensions/libip6t_inner6.c
 create mode 100644 extensions/libip6t_inner6.t
 create mode 100644 include/linux/netfilter_ipv6/ip6t_inner6.h

diff --git a/extensions/libip6t_inner6.c b/extensions/libip6t_inner6.c
new file mode 100644
index 0000000..096a913
--- /dev/null
+++ b/extensions/libip6t_inner6.c
@@ -0,0 +1,111 @@
+/* Shared library to add inner IPv6 packet matching support.
+ *
+ * Author:
+ *       Ahmed Abdelsalam       <amsalam20@gmail.com>
+ */
+
+#include <stdio.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_inner6.h>
+#include <string.h>
+
+/* inner6 command-line options */
+enum {
+	O_INNER6_SRC,
+	O_INNER6_DST,
+};
+
+static void inner6_help(void)
+{
+	printf(
+"srh match options:\n"
+"[!] --inner6-src	ip6_addr[/mask]	Source address of inner IPv6 packet\n"
+"[!] --inner6-dst	ip6_addr[/mask]	Destination address of inner IPv6 packet\n");
+}
+
+#define s struct ip6t_inner6
+static const struct xt_option_entry inner6_opts[] = {
+	{ .name = "inner6-src", .id = O_INNER6_SRC, .type = XTTYPE_HOSTMASK,
+	.flags = XTOPT_INVERT},
+	{ .name = "inner6-dst", .id = O_INNER6_DST, .type = XTTYPE_HOSTMASK,
+	.flags = XTOPT_INVERT},
+	{ }
+};
+#undef s
+
+static void inner6_init(struct xt_entry_match *m)
+{
+	struct ip6t_inner6 *inner6info = (void *)m->data;
+
+	inner6info->invflags = 0;
+}
+
+static void inner6_parse(struct xt_option_call *cb)
+{
+	struct ip6t_inner6 *inner6info = cb->data;
+
+	xtables_option_parse(cb);
+	switch (cb->entry->id) {
+	case O_INNER6_SRC:
+		inner6info->inner_src = cb->val.haddr.in6;
+		inner6info->inner_smsk = cb->val.hmask.in6;
+		if (cb->invert)
+			inner6info->invflags |= IP6T_INNER6_INV_SRC;
+		break;
+	case O_INNER6_DST:
+		inner6info->inner_dst = cb->val.haddr.in6;
+		inner6info->inner_dmsk = cb->val.hmask.in6;
+		if (cb->invert)
+			inner6info->invflags |= IP6T_INNER6_INV_DST;
+		break;
+	}
+}
+
+static void inner6_print(const void *ip, const struct xt_entry_match *match,
+			int numeric)
+{
+	const struct ip6t_inner6 *inner6info = (struct ip6t_inner6 *)match->data;
+
+	printf(" inner6 inner6-src %s %s/%u",
+		inner6info->invflags & IP6T_INNER6_INV_SRC ? "!" : "",
+		xtables_ip6addr_to_numeric(&inner6info->inner_src),
+		xtables_ip6mask_to_cidr(&inner6info->inner_smsk));
+	 printf(" inner6-dst %s %s/%u",
+		inner6info->invflags & IP6T_INNER6_INV_DST ? "!" : "",
+		xtables_ip6addr_to_numeric(&inner6info->inner_dst),
+		xtables_ip6mask_to_cidr(&inner6info->inner_dmsk));
+}
+
+static void inner6_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_inner6 *inner6info = (struct ip6t_inner6 *)match->data;
+
+	printf("%s --inner6-src %s/%u",
+		inner6info->invflags & IP6T_INNER6_INV_SRC ? " !" : "",
+		xtables_ip6addr_to_numeric(&inner6info->inner_src),
+		xtables_ip6mask_to_cidr(&inner6info->inner_smsk));
+	 printf("%s --inner6-dst %s/%u",
+		inner6info->invflags & IP6T_INNER6_INV_DST ? " !" : "",
+		xtables_ip6addr_to_numeric(&inner6info->inner_dst),
+		xtables_ip6mask_to_cidr(&inner6info->inner_dmsk));
+}
+
+static struct xtables_match inner6_mt6_reg = {
+	.name          = "inner6",
+	.version       = XTABLES_VERSION,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct ip6t_inner6)),
+	.userspacesize = XT_ALIGN(sizeof(struct ip6t_inner6)),
+	.help          = inner6_help,
+	.init          = inner6_init,
+	.print         = inner6_print,
+	.save          = inner6_save,
+	.x6_parse      = inner6_parse,
+	.x6_options    = inner6_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&inner6_mt6_reg);
+}
diff --git a/extensions/libip6t_inner6.t b/extensions/libip6t_inner6.t
new file mode 100644
index 0000000..d3d33a5
--- /dev/null
+++ b/extensions/libip6t_inner6.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-m inner6 --inner6-src a::2/64 --inner6-dst b::2/64;=;OK
+-m inner6 ! --inner6-src fc00:1::/64 ! --inner6-dst fc00:2::/64;=;OK
+-m inner6;=;OK
diff --git a/include/linux/netfilter_ipv6/ip6t_inner6.h b/include/linux/netfilter_ipv6/ip6t_inner6.h
new file mode 100644
index 0000000..f55b9f5
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_inner6.h
@@ -0,0 +1,20 @@
+#ifndef _IP6T_INNER6_H
+#define _IP6T_INNER6_H
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+
+/* Values for "invflags" field in struct ip6t_inner6 */
+#define IP6T_INNER6_INV_SRC	0x01
+#define IP6T_INNER6_INV_DST	0x02
+#define IP6T_INNER6_INV_MASK	0x03
+
+struct ip6t_inner6 {
+	/* Source and destination addr of inner IPv6 packet */
+	struct in6_addr inner_src, inner_dst;
+	/* Mask for src and dest addr of inner IPv6 packet */
+	struct in6_addr inner_smsk, inner_dmsk;
+	__u8		invflags;
+};
+
+#endif /*_IP6T_INNER6_H*/
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [nf-next] netfilter: Add support for inner IPv6 packet match
  2018-01-18 15:13 [iptables] extensions: add support for inner IPv6 packet 'inner6' match Ahmed Abdelsalam
@ 2018-01-18 15:13 ` Ahmed Abdelsalam
  2018-01-25 20:13   ` Pablo Neira Ayuso
  0 siblings, 1 reply; 4+ messages in thread
From: Ahmed Abdelsalam @ 2018-01-18 15:13 UTC (permalink / raw)
  To: pablo, davem, fw, netfilter-devel, coreteam
  Cc: netdev, kadlec, uznet, yoshfuji, amsalam20

As described in the SRv6 network programming document [1], the SRv6
information can be added to a packet in two different modes, insert or encap.

As shown below, you can see the original IPv6 packet and how it is carried in
the two different encapsulation modes.

In the insert mode the SRH header is inserted in the original IPv6 packet,
immediately after the IPv6 header and before the transport level header.
The original IPv6 header is modified, in particular the IPv6 destination
address is replaced with the IPv6 address of the first segment in the
segment list, while the original IPv6 destination address is carried in
the SRH header [2] as the last segment of the segment list.

In the encap mode the original IPv6 packet is carried as the inner packet
of an IPv6-in-IPv6 encapsulated packet. The outer IPv6 packet carries the
SRH header with the segment list.

In case of SRv6 encapsulated packets, we should be able to match the
source and destination address of the original packet since they
represent the end-to-end information.

This patch supports matching source and destination addresses of inner
IPv6 packets. It works for SRv6 and IP6IP6 encapsualted packets.

Original IPv6 packet
+-------------+--------------------+
| IPv6 header |       payload      |
+-------------+--------------------+

SRv6 packet - insert mode
+-------------+---------+--------------------+
| IPv6 header |   SRH   |       payload      |
+-------------+---------+--------------------+

SRv6 packet - encap mode
+-------------+---------+-------------+--------------------+
| IPv6 header |   SRH   | IPv6 header |       payload      |
+-------------+---------+-------------+--------------------+

[1] https://tools.ietf.org/html/draft-filsfils-spring-srv6-network-programming-03
[2] https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-07

Signed-off-by: Ahmed Abdelsalam <amsalam20@gmail.com>
---
 include/uapi/linux/netfilter_ipv6/ip6t_inner6.h |  21 ++++
 net/ipv6/netfilter/Kconfig                      |  10 ++
 net/ipv6/netfilter/Makefile                     |   1 +
 net/ipv6/netfilter/ip6t_inner6.c                | 156 ++++++++++++++++++++++++
 4 files changed, 188 insertions(+)
 create mode 100644 include/uapi/linux/netfilter_ipv6/ip6t_inner6.h
 create mode 100644 net/ipv6/netfilter/ip6t_inner6.c

diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h b/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h
new file mode 100644
index 0000000..7017fa4
--- /dev/null
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _IP6T_INNER6_H
+#define _IP6T_INNER6_H
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+
+/* Values for "invflags" field in struct ip6t_inner6 */
+#define IP6T_INNER6_INV_SRC	0x01
+#define IP6T_INNER6_INV_DST	0x02
+#define IP6T_INNER6_INV_MASK	0x03
+
+struct ip6t_inner6 {
+	/* Source and destination addr of inner IPv6 packet */
+	struct in6_addr inner_src, inner_dst;
+	/* Mask for src and dest addr of inner IPv6 packet */
+	struct in6_addr inner_smsk, inner_dmsk;
+	__u8		invflags;
+};
+
+#endif /*_IP6T_INNER6_H*/
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 4a634b7..58ed2c9 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -250,6 +250,16 @@ config IP6_NF_MATCH_SRH
 
           To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_MATCH_INNER6
+        tristate '"inner6" Inner IPv6 packet match support'
+        depends on NETFILTER_ADVANCED
+        help
+	  inner6 matching allows you to match the source and destination
+	  address of inner IPv6 packet. It works for both SRv6 and IP6IP6
+	  encapsulated packets.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 # The targets
 config IP6_NF_TARGET_HL
 	tristate '"HL" hoplimit target support'
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index d984057..40e332a 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
 obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 obj-$(CONFIG_IP6_NF_MATCH_SRH) += ip6t_srh.o
+obj-$(CONFIG_IP6_NF_MATCH_INNER6) += ip6t_inner6.o
 
 # targets
 obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
diff --git a/net/ipv6/netfilter/ip6t_inner6.c b/net/ipv6/netfilter/ip6t_inner6.c
new file mode 100644
index 0000000..391fd7e
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_inner6.c
@@ -0,0 +1,156 @@
+/* Kernel module to match inner IPv6 packet parameters. */
+
+/* Author:
+ * Ahmed Abdelsalam <amsalam20@gmail.com>
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/ipv6.h>
+#include <net/seg6.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv6/ip6t_inner6.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+/* Test a struct->invflags and a boolean for inequality */
+#define NF_INNER6_INVF(ptr, flag, boolean)	\
+	((boolean) ^ !!((ptr)->invflags & (flag)))
+
+static inline bool
+inner6_mt_encap(const struct sk_buff *skb, int innoff,
+		const struct ip6t_inner6 *inner6info)
+{
+	const struct ipv6hdr *inner_hdr;
+	struct ipv6hdr _inner_hdr;
+
+	inner_hdr = skb_header_pointer(skb, innoff,
+				       sizeof(_inner_hdr), &_inner_hdr);
+	if (!inner_hdr)
+		return false;
+	if (NF_INNER6_INVF(inner6info, IP6T_INNER6_INV_SRC,
+			   ipv6_masked_addr_cmp(&inner_hdr->saddr,
+						&inner6info->inner_smsk,
+						&inner6info->inner_src)) ||
+	    NF_INNER6_INVF(inner6info, IP6T_INNER6_INV_DST,
+			   ipv6_masked_addr_cmp(&inner_hdr->daddr,
+						&inner6info->inner_dmsk,
+						&inner6info->inner_dst)))
+		return false;
+	return true;
+}
+
+static inline bool
+inner6_mt_insert(const struct sk_buff *skb,
+		 int srhoff, const struct ip6t_inner6 *inner6info)
+{
+	const struct ipv6_sr_hdr *srh;
+	struct ipv6_sr_hdr _srh;
+	struct in6_addr _daddr;
+	const struct in6_addr *daddr;
+	int hdrlen;
+
+	srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
+	if (!srh)
+		return false;
+	hdrlen = ipv6_optlen(srh);
+	if (skb->len - srhoff < hdrlen)
+		return false;
+	if (srh->type != IPV6_SRCRT_TYPE_4)
+		return false;
+	if (srh->segments_left > srh->first_segment)
+		return false;
+	daddr = skb_header_pointer(skb, srhoff + sizeof(struct ipv6_sr_hdr),
+				   sizeof(_daddr), &_daddr);
+	WARN_ON(!daddr);
+	if (NF_INNER6_INVF(inner6info, IP6T_INNER6_INV_SRC,
+			   ipv6_masked_addr_cmp(&ipv6_hdr(skb)->saddr,
+						&inner6info->inner_smsk,
+						&inner6info->inner_src)) ||
+	    NF_INNER6_INVF(inner6info, IP6T_INNER6_INV_DST,
+			   ipv6_masked_addr_cmp(daddr,
+						&inner6info->inner_dmsk,
+						&inner6info->inner_dst)))
+		return false;
+	return true;
+}
+
+static inline bool
+inner_match(const struct sk_buff *skb, int srhoff,
+	    int innoff, int encap, const struct ip6t_inner6 *inner6info)
+{
+	if (encap)
+		return inner6_mt_encap(skb, innoff, inner6info);
+	return inner6_mt_insert(skb, srhoff, inner6info);
+}
+
+static inline bool
+sr6_pre_processor(const struct sk_buff *skb,
+		  int *innoff, int *srhoff, int *encap)
+{
+	if (ipv6_find_hdr(skb, innoff, IPPROTO_IPV6,
+			  NULL, NULL) == IPPROTO_IPV6){
+		*encap = 1;
+		return true;
+	}
+	if (ipv6_find_hdr(skb, srhoff, IPPROTO_ROUTING,
+			  NULL, NULL) == IPPROTO_ROUTING)
+		return true;
+	return false;
+}
+
+static bool inner6_mt6(const struct sk_buff *skb, struct xt_action_param *par)
+{
+	int innoff = 0, srhoff = 0, encap = 0;
+	const struct ip6t_inner6 *inner6info = par->matchinfo;
+
+	if (!sr6_pre_processor(skb, &innoff, &srhoff, &encap))
+		return false;
+	if (!inner_match(skb, srhoff, innoff, encap, inner6info))
+		return false;
+	return true;
+}
+
+static int inner6_mt6_check(const struct xt_mtchk_param *par)
+{
+	const struct ip6t_inner6 *inner6info = par->matchinfo;
+
+	if (inner6info->invflags & ~IP6T_INNER6_INV_MASK) {
+		pr_err("unknown inner6 invflags %X\n", inner6info->invflags);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct xt_match inner6_mt6_reg __read_mostly = {
+	.name		= "inner6",
+	.family		= NFPROTO_IPV6,
+	.match		= inner6_mt6,
+	.matchsize	= sizeof(struct ip6t_inner6),
+	.checkentry	= inner6_mt6_check,
+	.me		= THIS_MODULE,
+};
+
+static int __init inner6_mt6_init(void)
+{
+	return xt_register_match(&inner6_mt6_reg);
+}
+
+static void __exit inner6_mt6_exit(void)
+{
+	xt_unregister_match(&inner6_mt6_reg);
+}
+module_init(inner6_mt6_init);
+module_exit(inner6_mt6_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Xtables: Inner IPv6 packet match");
+MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [nf-next] netfilter: Add support for inner IPv6 packet match
  2018-01-18 15:13 ` [nf-next] netfilter: Add support for inner IPv6 packet match Ahmed Abdelsalam
@ 2018-01-25 20:13   ` Pablo Neira Ayuso
  2018-01-26 20:53     ` Ahmed Abdelsalam
  0 siblings, 1 reply; 4+ messages in thread
From: Pablo Neira Ayuso @ 2018-01-25 20:13 UTC (permalink / raw)
  To: Ahmed Abdelsalam
  Cc: davem, fw, netfilter-devel, coreteam, netdev, kadlec, uznet, yoshfuji

Hi Ahmed,

On Thu, Jan 18, 2018 at 04:13:25PM +0100, Ahmed Abdelsalam wrote:
[...]
> diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h b/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h
> new file mode 100644
> index 0000000..7017fa4
> --- /dev/null
> +++ b/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +#ifndef _IP6T_INNER6_H
> +#define _IP6T_INNER6_H
> +
> +#include <linux/types.h>
> +#include <linux/netfilter.h>
> +
> +/* Values for "invflags" field in struct ip6t_inner6 */
> +#define IP6T_INNER6_INV_SRC	0x01
> +#define IP6T_INNER6_INV_DST	0x02
> +#define IP6T_INNER6_INV_MASK	0x03
> +
> +struct ip6t_inner6 {
> +	/* Source and destination addr of inner IPv6 packet */
> +	struct in6_addr inner_src, inner_dst;
> +	/* Mask for src and dest addr of inner IPv6 packet */
> +	struct in6_addr inner_smsk, inner_dmsk;
> +	__u8		invflags;
> +};

Matching at inner headers is a very useful, no doubt. Problem is that
this approach is rather limited since it only allows for matching
source and destination address at the inner header. I suspect someone
else will follow up later on to add more fields to this, and we will
end up having a new version of ip6tables... inside ip6t_inner6 :-).

nf_tables is a much more flexible framework, we can store the offset
of this inner header in nft_pktinfo on demand, add new base to
nft_payload and have access to all matching capabilities from any
arbitrary offset. I really think this new feature belongs there.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [nf-next] netfilter: Add support for inner IPv6 packet match
  2018-01-25 20:13   ` Pablo Neira Ayuso
@ 2018-01-26 20:53     ` Ahmed Abdelsalam
  0 siblings, 0 replies; 4+ messages in thread
From: Ahmed Abdelsalam @ 2018-01-26 20:53 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: davem, fw, netfilter-devel, coreteam, netdev, kadlec, uznet, yoshfuji

Hi Pablo, 

> Hi Ahmed,
> 
> On Thu, Jan 18, 2018 at 04:13:25PM +0100, Ahmed Abdelsalam wrote:
> [...]
> > diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h b/include/uapi/linux/netfilter_ipv6/ip6t_inner6.h
> Matching at inner headers is a very useful, no doubt. Problem is that
> this approach is rather limited since it only allows for matching
> source and destination address at the inner header. I suspect someone
> else will follow up later on to add more fields to this, and we will
> end up having a new version of ip6tables... inside ip6t_inner6 :-).

Most probably it would be me who come to add more features, but i would call it sr6tables :-) 

> 
> nf_tables is a much more flexible framework, we can store the offset
> of this inner header in nft_pktinfo on demand, add new base to
> nft_payload and have access to all matching capabilities from any
> arbitrary offset. I really think this new feature belongs there.

Indeed, I started looking into the nftables implemenation and really convienced it's more convienent. Moreover, I had many issues with the ip6tables performance specially with the increae in the number of rules. However, why don't we have these patches in the kernel? since we have them implemented (some folks still like ip6tables). 

P.S. I'm looking into nftables exthdrs to support SRH.
Thanks, 
Ahmed 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-01-26 20:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-18 15:13 [iptables] extensions: add support for inner IPv6 packet 'inner6' match Ahmed Abdelsalam
2018-01-18 15:13 ` [nf-next] netfilter: Add support for inner IPv6 packet match Ahmed Abdelsalam
2018-01-25 20:13   ` Pablo Neira Ayuso
2018-01-26 20:53     ` Ahmed Abdelsalam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).