[prev in list] [next in list] [prev in thread] [next in thread] 

List:       netfilter-devel
Subject:    [PATCH, RFC]: new match 'secpath'
From:       Patrick McHardy <kaber () trash ! net>
Date:       2003-08-25 13:36:55
[Download RAW message or body]

This patch adds a new match secpath which can be used to
match if a packet came out of an ipsec tunnel and various
other related stuff (please see the helptext for more info).
Comments are welcome.

Bye
Patrick

["pom-secpath.diff" (text/plain)]

diff -urN a/patch-o-matic_2.5/extra/secpath.patch b/patch-o-matic_2.5/extra/secpath.patch
--- a/patch-o-matic_2.5/extra/secpath.patch	1970-01-01 01:00:00.000000000 +0100
+++ b/patch-o-matic_2.5/extra/secpath.patch	2003-08-25 15:07:40.000000000 +0200
@@ -0,0 +1,188 @@
+diff -Nru a/include/linux/netfilter_ipv4/ipt_secpath.h b/include/linux/netfilter_ipv4/ipt_secpath.h
+--- /dev/null	Wed Dec 31 16:00:00 1969
++++ b/include/linux/netfilter_ipv4/ipt_secpath.h	Mon Aug 25 15:07:40 2003
+@@ -0,0 +1,41 @@
++#ifndef _IPT_SECPATH_H
++#define _IPT_SECPATH_H
++
++#define SECPATH_MAX_DEPTH	4		/* must match XFRM_MAX_DEPTH */
++
++#define MATCH_PATH		0x1
++
++#define SECPATH_MODE_TRANSPORT	0
++#define SECPATH_MODE_TUNNEL	1
++
++struct ipt_secpath_flags
++{
++	u_int8_t saddr:1,
++	         daddr:1,
++	         spi:1,
++	         proto:1,
++	         mode:1;
++};
++
++struct ipt_secpath_elem
++{
++	u_int32_t saddr;
++	u_int32_t smask;
++	u_int32_t daddr;
++	u_int32_t dmask;
++	u_int32_t spi;
++	u_int8_t proto;
++	u_int8_t mode;
++
++	struct ipt_secpath_flags match;
++	struct ipt_secpath_flags invert;
++};
++
++struct ipt_secpath_info
++{
++	struct ipt_secpath_elem path[SECPATH_MAX_DEPTH];
++	u_int16_t len;
++	u_int16_t flags;
++};
++
++#endif
+diff -Nru a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
+--- a/net/ipv4/netfilter/Kconfig	Mon Aug 25 15:07:40 2003
++++ b/net/ipv4/netfilter/Kconfig	Mon Aug 25 15:07:40 2003
+@@ -301,6 +301,17 @@
+ 	  If you want to compile it as a module, say M here and read
+ 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+ 
++config IP_NF_MATCH_SECPATH
++	tristate "Secpath match support"
++	depends on EXPERIMENTAL && IP_NF_IPTABLES
++	help
++	  Secpath packet matching allows you to match various attributes
++	  of a packets secpath which describes the path a packet took through
++	  the (ipsec) transformers during decapsulation.
++
++	  If you want to compile it as a module, say M here and read
++	  <file:Documentation/modules.txt>.  If unsure, say `N'.
++
+ # The targets
+ config IP_NF_FILTER
+ 	tristate "Packet filtering"
+diff -Nru a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
+--- a/net/ipv4/netfilter/Makefile	Mon Aug 25 15:07:40 2003
++++ b/net/ipv4/netfilter/Makefile	Mon Aug 25 15:07:40 2003
+@@ -65,6 +65,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+ 
+ obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
++obj-$(CONFIG_IP_NF_MATCH_SECPATH) += ipt_secpath.o
+ 
+ # targets
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+diff -Nru a/net/ipv4/netfilter/ipt_secpath.c b/net/ipv4/netfilter/ipt_secpath.c
+--- /dev/null	Wed Dec 31 16:00:00 1969
++++ b/net/ipv4/netfilter/ipt_secpath.c	Mon Aug 25 15:07:40 2003
+@@ -0,0 +1,107 @@
++/* IP tables module for matching various secpath attributes
++ *
++ * (C) 2003 by Patrick McHardy <kaber@trash.net>
++ *
++ * This software is distributed under the terms  GNU GPL
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <net/xfrm.h>
++
++#include <linux/netfilter_ipv4/ipt_secpath.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
++MODULE_DESCRIPTION("IP secpath atttribute matching module");
++MODULE_LICENSE("GPL");
++
++static int secpath_match(struct xfrm_state *x, const struct ipt_secpath_elem *e)
++{
++	if (e->match.saddr) {
++		if ((e->saddr != ((u32) x->props.saddr.a4 & e->smask)) ^
++		    e->invert.saddr)
++			return 0;
++	}
++	if (e->match.daddr) {
++		if ((e->daddr != ((u32) x->id.daddr.a4 & e->dmask)) ^
++		    e->invert.daddr)
++			return 0;
++	}
++	if (e->match.spi) {
++		if ((e->spi != x->id.spi) ^ e->invert.spi)
++			return 0;
++	}
++	if (e->match.proto) {
++		if ((e->proto != x->id.proto) ^ e->invert.proto)
++			return 0;
++	}
++	if (e->match.mode) {
++		if ((e->mode != x->props.mode) ^ e->invert.mode)
++			return 0;
++	}
++	return 1;
++}
++
++static int match(const struct sk_buff *skb,
++                 const struct net_device *in,
++                 const struct net_device *out,
++                 const void *matchinfo,
++		 int offset, int *hotdrop)
++{
++	const struct ipt_secpath_info *info = matchinfo;
++	struct sec_path *sp = skb->sp;
++	unsigned int i;
++	int strict = info->flags & MATCH_PATH;
++
++	if (sp == NULL)
++		return 0;
++
++	if (strict && info->len != sp->len)
++		return 0;
++	
++	for (i = 0; i < sp->len; i++) {
++		if (secpath_match(sp->x[i].xvec, &info->path[strict ? i : 0])) {
++			if (!strict)
++				return 1;
++		} else if (strict)
++			return 0;
++	}
++
++	return strict ? 1 : 0;
++}
++
++static int checkentry(const char *tablename, const struct ipt_ip *ip,
++		      void *matchinfo, unsigned int matchsize,
++		      unsigned int hook_mask)
++{
++	if (matchsize != IPT_ALIGN(sizeof(struct ipt_secpath_info))) {
++		printk(KERN_ERR "ipt_secpath: matchsize %u != %u.\n",
++		       matchsize, IPT_ALIGN(sizeof(struct ipt_secpath_info)));
++		return 0;
++	}
++
++	return 1;
++}
++
++static struct ipt_match secpath_match = {
++	.name		= "secpath",
++	.match		= &match,
++	.checkentry	= &checkentry,
++	.me		= THIS_MODULE,
++};
++
++static int __init init(void)
++{
++	return ipt_register_match(&secpath_match);
++}
++
++static void __exit fini(void)
++{
++	ipt_unregister_match(&secpath_match);
++
++}
++
++module_init(init);
++module_exit(fini);
diff -urN a/patch-o-matic_2.5/extra/secpath.patch.help b/patch-o-matic_2.5/extra/secpath.patch.help
--- a/patch-o-matic_2.5/extra/secpath.patch.help	1970-01-01 01:00:00.000000000 +0100
+++ b/patch-o-matic_2.5/extra/secpath.patch.help	2003-08-25 15:23:31.000000000 +0200
@@ -0,0 +1,45 @@
+Author: Patrick McHardy <kaber@trash.net>
+Status: Experimental
+
+This patch adds a new match 'secpath' which is used to match attributes of the
+secpath of a decapsulated packet. The secpath describes a packets path through
+the (ipsec) transformers during decapsulation.
+
+Options:
+
+	--spi SPI			Match SPI
+	--proto ah/esp/ipcomp		Match protocol
+	--mode transport/tunnel		Match mode
+	--local IP			Match local tunnel endpoint
+	--remote IP			Match remote tunnel endpoint
+
+	--path 				Match path instead of single element
+					at any position
+	--next 				Begin next element in path
+
+Examples:
+
+	# accept everything coming out of an esp tunnel from 
+	# 192.168.0.0/24 to 192.168.0.1
+
+	iptables -I INPUT -m secpath --proto esp \
+				     --mode tunnel \
+	                             --local 192.168.0.1 \
+				     --remote 192.168.0.0/24 \
+				     -j ACCEPT
+	
+	# accept all tcp packets coming out of a tunnel from 192.168.0.0/24 
+	# to 192.168.0.1 which looks like this:
+	# <ip> <ah> <esp> <ip>
+
+	iptables -I INPUT -p tcp \
+			  -m secpath --path \
+				     --proto ah \
+				     --mode transport \
+				     --next \
+				     --proto esp \
+				     --mode tunnel \
+				     --local 192.168.0.1 \
+				     --remote 192.168.0.0/24 \
+				     -j ACCEPT
+
diff -urN a/userspace/extensions/libipt_secpath.c b/userspace/extensions/libipt_secpath.c
--- a/userspace/extensions/libipt_secpath.c	1970-01-01 01:00:00.000000000 +0100
+++ b/userspace/extensions/libipt_secpath.c	2003-08-25 15:06:23.000000000 +0200
@@ -0,0 +1,331 @@
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <iptables.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_secpath.h>
+
+static void help(void)
+{
+	printf(
+"secpath v%s options:\n"
+" --spi SPI			Match SPI\n"
+" --proto ah/esp/ipcomp		Match protocol\n"
+" --mode transport/tunnel	Match mode\n"
+" --local IP			Match local tunnel endpoint\n"
+" --remote IP			Match remote tunnel endpoint\n"
+" --path			Match path instead of single element at any position\n"
+" --next			Begin next element in path\n",
+	IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+	{
+		.name		= "spi",
+		.has_arg	= 1,
+		.flag		= 0,
+		.val		= '1'
+	},
+	{
+		.name		= "local",
+		.has_arg	= 1,
+		.flag		= 0,
+		.val		= '2'
+	},
+	{
+		.name		= "remote",
+		.has_arg	= 1,
+		.flag		= 0,
+		.val		= '3'
+	},
+	{
+		.name		= "proto",
+		.has_arg	= 1,
+		.flag		= 0,
+		.val		= '4'
+	},
+	{
+		.name		= "mode",
+		.has_arg	= 1,
+		.flag		= 0,
+		.val		= '5'
+	},
+	{
+		.name		= "path",
+		.has_arg	= 0,
+		.flag		= 0,
+		.val		= '6'
+	},
+	{
+		.name		= "next",
+		.has_arg	= 0,
+		.flag		= 0,
+		.val		= '7'
+	},
+	{ 0 }
+};
+
+static void init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+	*nfcache |= NFC_UNKNOWN;
+}
+
+static int parse_mode(char *s)
+{
+	if (strcmp(s, "transport") == 0)
+		return SECPATH_MODE_TRANSPORT;
+	if (strcmp(s, "tunnel") == 0)
+		return SECPATH_MODE_TUNNEL;
+	return -EINVAL;
+}
+
+static int parse(int c, char **argv, int invert, unsigned int *i,
+                 const struct ipt_entry *entry,
+                 unsigned int *nfcache,
+                 struct ipt_entry_match **match)
+{
+	struct ipt_secpath_info *info = (void *)(*match)->data;
+	struct ipt_secpath_elem *e = &info->path[*i];
+	struct in_addr *addr = NULL, mask;
+	struct protoent *p;
+	unsigned int naddr = 0;
+	int mode, proto;
+
+	check_inverse(optarg, &invert, &optind, 0);
+
+	switch (c) {
+	case '1':
+		if (e->match.spi)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't specify --spi twice");
+		
+		e->match.spi = 1;
+		e->invert.spi = invert;
+		e->spi = strtol(argv[optind-1], NULL, 0x10);
+		break;
+	case '2':
+		if (e->match.daddr)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't specify --local twice");
+		
+		parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
+		if (naddr > 1)
+			exit_error(PARAMETER_PROBLEM,
+			           "Multiple IP addresses are not allowed");
+
+		e->match.daddr = 1;
+		e->invert.daddr = invert;
+		e->daddr = addr[0].s_addr;
+		e->dmask = mask.s_addr;
+		break;
+	case '3':
+		if (e->match.saddr)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't specify --remote twice");
+
+		parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
+		if (naddr > 1)
+			exit_error(PARAMETER_PROBLEM,
+			           "Multiple IP addresses are not allowed");
+
+		e->match.saddr = 1;
+		e->invert.saddr = invert;
+		e->saddr = addr[0].s_addr;
+		e->smask = mask.s_addr;
+                break;
+	case '4':
+		if (e->match.proto)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't specify --proto twice");
+
+		p = getprotobyname(argv[optind-1]);
+		if (p != NULL)
+			proto = p->p_proto;
+		else if (!(proto = atoi(argv[optind-1])))
+			exit_error(PARAMETER_PROBLEM,
+			           "Unknown protocol `%s'\n",
+			           argv[optind-1]);
+
+		e->match.proto = 1;
+		e->invert.proto = invert;
+		e->proto = proto;
+		break;
+	case '5':
+		if (e->match.mode)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't specify --mode twice");
+		
+		mode = parse_mode(argv[optind-1]);
+		if (mode < 0)
+			exit_error(PARAMETER_PROBLEM,
+			           "Unknown mode `%s'\n",
+			           argv[optind-1]);
+
+		e->match.mode = 1;
+		e->invert.mode = invert;
+		e->mode = mode;
+		break;
+	case '6':
+		if (info->flags & MATCH_PATH)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't specify --path twice");
+
+		if (invert)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't invert `--path' option");
+
+		info->flags |= MATCH_PATH;
+		break;
+	case '7':
+		if (invert)
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't invert `--next' option");
+
+		if (++(*i) == SECPATH_MAX_DEPTH)
+			exit_error(PARAMETER_PROBLEM,
+			           "Maximum path depth reached");
+
+		break;
+	default:
+		return 0;
+	}
+
+	info->len = *i + 1;
+	return 1;
+}
+
+static void final_check(unsigned int flags)
+{
+	return;
+}
+
+static void print_proto(char *prefix, u_int8_t proto, int numeric)
+{
+	struct protoent *p = NULL;
+
+	if (!numeric)
+		p = getprotobynumber(proto);
+	if (p == NULL)
+		printf("%sproto %u ", prefix, proto);
+	else
+		printf("%sproto %s ", prefix, p->p_name);
+}
+
+static void print_mode(char *prefix, u_int8_t mode, int numeric)
+{
+	printf("%smode ", prefix);
+
+	switch (mode) {
+	case SECPATH_MODE_TRANSPORT:
+		printf("transport ");
+		break;
+	case SECPATH_MODE_TUNNEL:
+		printf("tunnel ");
+		break;
+	default:
+		printf("??? ");
+		break;
+	}
+}
+
+#define PRINT_INVERT(x)		\
+do {				\
+	if (x)			\
+		printf("! ");	\
+} while(0)
+
+static void print_entry(char *prefix, const struct ipt_secpath_elem *e,
+                        int numeric)
+{
+	if (e->match.spi) {
+		PRINT_INVERT(e->invert.spi);
+		printf("%sspi 0x%x ", prefix, e->spi);
+	}
+	if (e->match.proto) {
+		PRINT_INVERT(e->invert.proto);
+		print_proto(prefix, e->proto, numeric);
+	}
+	if (e->match.mode) {
+		PRINT_INVERT(e->invert.mode);
+		print_mode(prefix, e->mode, numeric);
+	}
+	if (e->match.daddr) {
+		PRINT_INVERT(e->invert.daddr);
+		printf("%slocal %s%s ", prefix,
+		       addr_to_dotted((struct in_addr *)&e->daddr),
+		       mask_to_dotted((struct in_addr *)&e->dmask));
+	}
+	if (e->match.saddr) {
+		PRINT_INVERT(e->invert.saddr);
+		printf("%sremote %s%s ", prefix,
+		       addr_to_dotted((struct in_addr *)&e->saddr),
+		       mask_to_dotted((struct in_addr *)&e->smask));
+	}
+}
+
+static void print(const struct ipt_ip *ip,
+                  const struct ipt_entry_match *match,
+		  int numeric)
+{
+	const struct ipt_secpath_info *info = (void *)match->data;
+	unsigned int i;
+
+	printf ("secpath match ");
+	if (info->flags & MATCH_PATH)
+		printf("path ");
+
+	for (i = 0; i < info->len; i++) {
+		if (info->len > 1)
+			printf("[%u] ", i);
+		print_entry("", &info->path[i], numeric);
+	}
+
+	printf("\n");
+}
+
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+	const struct ipt_secpath_info *info = (void *)match->data;
+	unsigned int i;
+
+	if (info->flags & MATCH_PATH)
+		printf("--path ");
+
+	for (i = 0; i < info->len; i++) {
+		print_entry("--", &info->path[i], 0);
+		if (i + 1 < info->len)
+			printf("--next ");
+	}
+
+	printf("\n");
+}
+
+struct iptables_match secpath =
+{
+	NULL,
+	"secpath",
+	IPTABLES_VERSION,
+	IPT_ALIGN(sizeof(struct ipt_secpath_info)),
+	IPT_ALIGN(sizeof(struct ipt_secpath_info)),
+	&help,
+	&init,
+	&parse,
+	&final_check,
+	&print,
+	&save,
+	opts
+};
+
+void _init(void)
+{
+	register_match(&secpath);
+}
diff -urN a/userspace/extensions/.secpath-test b/userspace/extensions/.secpath-test
--- a/userspace/extensions/.secpath-test	1970-01-01 01:00:00.000000000 +0100
+++ b/userspace/extensions/.secpath-test	2003-08-25 15:06:53.000000000 +0200
@@ -0,0 +1,3 @@
+#!/bin/sh
+# True if secpath match patch is applied.
+[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_secpath.h ] && echo secpath


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic