On Monday 25 February 2002 09:51, Harald Welte wrote:

> Well, as you know, it is now resolved - the mangle5hooks patch has
> made it into 2.4.18-preX and is definitely working since
> 2.4.18-rc1.

I am not referring to what hooks mangle shold hook into, but it's 
priorities.

When I last proposed this patch your were thinking of moving mangle 
infront of conntrack, to be able to exclude packets from conntrack I 
think. Moving mangle infront of conntrack breaks parts of this patch 
as the most common use of this patch is to mark packets on their 
conntrack entry for use in routing.

> > I would certainly not mind having it in patch-o-matic/extra if
> > possible.
>
> sure. Please send me a patch to put it cleanly in patch-o-matic.
> Thanks.

Attached.

The .??*-test and libipt_* files goes into extensions (4 in total, 
one match and one target), the CONNMARK.* files into patch-o-matic (8 
in total).

Regards
Henrik

Attachment: .connmark-test
Description: extensions/.connmark-test condition on when to build the connmark userspace match module

/* Shared library add-on to iptables to add CONNMARK matching support. */
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <iptables.h>
#include <linux/netfilter_ipv4/ipt_connmark.h>

/* Function which prints out usage message. */
static void
help(void)
{
	printf(
"CONNMARK match v%s options:\n"
"[!] --mark value[/mask]         Match nfmark value with optional mask\n"
"\n",
NETFILTER_VERSION);
}

static struct option opts[] = {
	{ "mark", 1, 0, '1' },
	{0}
};

/* Initialize the match. */
static void
init(struct ipt_entry_match *m, unsigned int *nfcache)
{
	/* Can't cache this. */
	*nfcache |= NFC_UNKNOWN;
}

/* Function which parses command options; returns true if it
   ate an option */
static int
parse(int c, char **argv, int invert, unsigned int *flags,
      const struct ipt_entry *entry,
      unsigned int *nfcache,
      struct ipt_entry_match **match)
{
	struct ipt_connmark_info *markinfo = (struct ipt_connmark_info *)(*match)->data;

	switch (c) {
		char *end;
	case '1':
		if (check_inverse(optarg, &invert))
			optind++;
		markinfo->mark = strtoul(optarg, &end, 0);
		if (*end == '/') {
			markinfo->mask = strtoul(end+1, &end, 0);
		} else
			markinfo->mask = 0xffffffff;
		if (*end != '\0' || end == optarg)
			exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
		if (invert)
			markinfo->invert = 1;
		*flags = 1;
		break;

	default:
		return 0;
	}
	return 1;
}

static void
print_mark(unsigned long mark, unsigned long mask, int invert, int numeric)
{
	if (invert)
		fputc('!', stdout);

	if(mask != 0xffffffff)
		printf("0x%lx/0x%lx ", mark, mask);
	else
		printf("0x%lx ", mark);
}

/* Final check; must have specified --mark. */
static void
final_check(unsigned int flags)
{
	if (!flags)
		exit_error(PARAMETER_PROBLEM,
			   "MARK match: You must specify `--mark'");
}

/* Prints out the matchinfo. */
static void
print(const struct ipt_ip *ip,
      const struct ipt_entry_match *match,
      int numeric)
{
	printf("CONNMARK match ");
	print_mark(((struct ipt_connmark_info *)match->data)->mark,
		  ((struct ipt_connmark_info *)match->data)->mask,
		  ((struct ipt_connmark_info *)match->data)->invert, numeric);
}

/* Saves the union ipt_matchinfo in parsable form to stdout. */
static void
save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
	printf("--mark ");
	print_mark(((struct ipt_connmark_info *)match->data)->mark,
		  ((struct ipt_connmark_info *)match->data)->mask,
		  ((struct ipt_connmark_info *)match->data)->invert, 0);
}

struct iptables_match mark
= { NULL,
    "connmark",
    NETFILTER_VERSION,
    IPT_ALIGN(sizeof(struct ipt_connmark_info)),
    IPT_ALIGN(sizeof(struct ipt_connmark_info)),
    &help,
    &init,
    &parse,
    &final_check,
    &print,
    &save,
    opts
};

void _init(void)
{
	register_match(&mark);
}

Attachment: .CONNMARK-test
Description: extensions/.CONNMARK-test userspace test on when to build the userspace CONNMARK target module

/* Shared library add-on to iptables to add CONNMARK target support. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <iptables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_CONNMARK.h>

#if 0
struct markinfo {
	struct ipt_entry_target t;
	struct ipt_connmark_target_info mark;
};
#endif

/* Function which prints out usage message. */
static void
help(void)
{
	printf(
"CONNMARK target v%s options:\n"
"  --set-mark value              Set conntrack mark value\n"
"  --save-mark                   Save the packet nfmark on the connection\n"
"  --restore-mark                Restore saved nfmark value\n"
"\n",
NETFILTER_VERSION);
}

static struct option opts[] = {
	{ "set-mark", 1, 0, '1' },
	{ "save-mark", 0, 0, '2' },
	{ "restore-mark", 0, 0, '3' },
	{ 0 }
};

/* Initialize the target. */
static void
init(struct ipt_entry_target *t, unsigned int *nfcache)
{
}

/* Function which parses command options; returns true if it
   ate an option */
static int
parse(int c, char **argv, int invert, unsigned int *flags,
      const struct ipt_entry *entry,
      struct ipt_entry_target **target)
{
	struct ipt_connmark_target_info *markinfo
		= (struct ipt_connmark_target_info *)(*target)->data;

	switch (c) {
		char *end;
	case '1':
		markinfo->mode = IPT_CONNMARK_SET;
		markinfo->mark = strtoul(optarg, &end, 0);
		if (*end != '\0' || end == optarg)
			exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
		if (*flags)
			exit_error(PARAMETER_PROBLEM,
			           "CONNMARK target: Can't specify --set-mark twice");
		*flags = 1;
		break;
	case '2':
		markinfo->mode = IPT_CONNMARK_SAVE;
		if (*flags)
			exit_error(PARAMETER_PROBLEM,
			           "CONNMARK target: Can't specify --save-mark twice");
		*flags = 1;
		break;
	case '3':
		markinfo->mode = IPT_CONNMARK_RESTORE;
		if (*flags)
			exit_error(PARAMETER_PROBLEM,
			           "CONNMARK target: Can't specify --restore-mark twice");
		*flags = 1;
		break;
	default:
		return 0;
	}

	return 1;
}

static void
final_check(unsigned int flags)
{
	if (!flags)
		exit_error(PARAMETER_PROBLEM,
		           "CONNMARK target: Parameter --set-mark is required");
}

static void
print_mark(unsigned long mark, int numeric)
{
	printf("0x%lx ", mark);
}

/* Prints out the targinfo. */
static void
print(const struct ipt_ip *ip,
      const struct ipt_entry_target *target,
      int numeric)
{
	const struct ipt_connmark_target_info *markinfo =
		(const struct ipt_connmark_target_info *)target->data;
	switch (markinfo->mode) {
	case IPT_CONNMARK_SET:
	    printf("CONNMARK set ");
	    print_mark(markinfo->mark, numeric);
	    break;
	case IPT_CONNMARK_SAVE:
	    printf("CONNMARK save ");
	    break;
	case IPT_CONNMARK_RESTORE:
	    printf("CONNMARK restore ");
	    break;
	default:
	    printf("ERROR: UNKNOWN CONNMARK MODE ");
	    break;
	}
}

/* Saves the union ipt_targinfo in parsable form to stdout. */
static void
save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
{
	const struct ipt_connmark_target_info *markinfo =
		(const struct ipt_connmark_target_info *)target->data;

	switch (markinfo->mode) {
	case IPT_CONNMARK_SET:
	    printf("--set-mark 0x%lx ", markinfo->mark);
	    break;
	case IPT_CONNMARK_SAVE:
	    printf("--save-mark ");
	    break;
	case IPT_CONNMARK_RESTORE:
	    printf("--restore-mark ");
	    break;
	default:
	    printf("ERROR: UNKNOWN CONNMARK MODE ");
	    break;
	}
}

struct iptables_target mark
= { NULL,
    "CONNMARK",
    NETFILTER_VERSION,
    IPT_ALIGN(sizeof(struct ipt_connmark_target_info)),
    IPT_ALIGN(sizeof(struct ipt_connmark_target_info)),
    &help,
    &init,
    &parse,
    &final_check,
    &print,
    &save,
    opts
};

void _init(void)
{
	register_target(&mark);
}
diff -uN linux-2.4.3-pre3/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.3-pre3-uml/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.4.3-pre3/include/linux/netfilter_ipv4/ip_conntrack.h	Fri Mar  9 21:43:28 2001
+++ linux-2.4.3-pre3-uml/include/linux/netfilter_ipv4/ip_conntrack.h	Wed Mar 21 13:20:37 2001
@@ -147,6 +147,9 @@
 	} nat;
 #endif /* CONFIG_IP_NF_NAT_NEEDED */
 
+#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+	unsigned long mark;
+#endif
 };
 
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
diff -uN --exclude .* --exclude *.o linux-2.4.3-pre3/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.3-pre3-uml/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.4.3-pre3/net/ipv4/netfilter/ip_conntrack_standalone.c	Thu Aug 10 21:35:15 2000
+++ linux-2.4.3-pre3-uml/net/ipv4/netfilter/ip_conntrack_standalone.c	Wed Mar 21 13:04:19 2001
@@ -92,6 +92,9 @@
 		len += sprintf(buffer + len, "[UNCONFIRMED] ");
 	len += sprintf(buffer + len, "use=%u ",
 		       atomic_read(&conntrack->ct_general.use));
+#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+	len += sprintf(buffer + len, "mark=%d ", conntrack->mark);
+#endif
 	len += sprintf(buffer + len, "\n");
 
 	return len;
--- linux-2.4.4-pre1-hno/net/ipv4/netfilter/ip_conntrack_core.c	Tue Apr 10 22:33:21 2001
+++ linux-2.4.4-pre1-uml/net/ipv4/netfilter/ip_conntrack_core.c	Mon Apr 16 00:23:00 2001
@@ -523,6 +523,9 @@
 		conntrack->status = IPS_EXPECTED;
 		conntrack->master.master = &expected->expectant->ct_general;
 		IP_NF_ASSERT(conntrack->master.master);
+#if CONFIG_IP_NF_CONNTRACK_MARK
+		conntrack->mark = expected->expectant->mark;
+#endif
 		LIST_DELETE(&expect_list, expected);
 		expected->expectant = NULL;
 		nf_conntrack_get(&conntrack->master);
diff -uN linux-2.4.3-pre3/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.4.3-pre3-uml/include/linux/netfilter_ipv4/ipt_connmark.h
--- linux-2.4.3-pre3/include/linux/netfilter_ipv4/ipt_connmark.h	Thu Jan  1 01:00:00 1970
+++ linux-2.4.3-pre3-uml/include/linux/netfilter_ipv4/ipt_connmark.h	Wed Mar 21 11:38:46 2001
@@ -0,0 +1,9 @@
+#ifndef _IPT_CONNMARK_H
+#define _IPT_CONNMARK_H
+
+struct ipt_connmark_info {
+    unsigned long mark, mask;
+    u_int8_t invert;
+};
+
+#endif /*_IPT_CONNMARK_H*/
diff -uN --exclude .* --exclude *.o linux-2.4.3-pre3/net/ipv4/netfilter/ipt_connmark.c linux-2.4.3-pre3-uml/net/ipv4/netfilter/ipt_connmark.c
--- linux-2.4.3-pre3/net/ipv4/netfilter/ipt_connmark.c	Thu Jan  1 01:00:00 1970
+++ linux-2.4.3-pre3-uml/net/ipv4/netfilter/ipt_connmark.c	Wed Mar 21 13:23:33 2001
@@ -0,0 +1,55 @@
+/* Kernel module to match connection mark values. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_connmark.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_connmark_info *info = matchinfo;
+	enum ip_conntrack_info ctinfo;
+	struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+	if (!ct)
+	    return 0;
+
+	return ((ct->mark & info->mask) == info->mark) ^ info->invert;
+}
+
+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_connmark_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match connmark_match
+= { { NULL, NULL }, "connmark", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&connmark_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&connmark_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -uN linux-2.4.3-pre3/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.4.3-pre3-uml/include/linux/netfilter_ipv4/ipt_CONNMARK.h
--- linux-2.4.3-pre3/include/linux/netfilter_ipv4/ipt_CONNMARK.h	Thu Jan  1 01:00:00 1970
+++ linux-2.4.3-pre3-uml/include/linux/netfilter_ipv4/ipt_CONNMARK.h	Wed Mar 21 12:25:20 2001
@@ -0,0 +1,15 @@
+#ifndef _IPT_CONNMARK_H_target
+#define _IPT_CONNMARK_H_target
+
+enum {
+    IPT_CONNMARK_SET = 0,
+    IPT_CONNMARK_SAVE,
+    IPT_CONNMARK_RESTORE
+};
+
+struct ipt_connmark_target_info {
+	unsigned long mark;
+	u_int8_t mode;
+};
+
+#endif /*_IPT_CONNMARK_H_target*/
diff -uN --exclude .* --exclude *.o linux-2.4.3-pre3/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.4.3-pre3-uml/net/ipv4/netfilter/ipt_CONNMARK.c
--- linux-2.4.3-pre3/net/ipv4/netfilter/ipt_CONNMARK.c	Thu Jan  1 01:00:00 1970
+++ linux-2.4.3-pre3-uml/net/ipv4/netfilter/ipt_CONNMARK.c	Wed May 20 17:49:10 2001
@@ -0,0 +1,87 @@
+/* This is a module which is used for setting/remembering the mark field of
+ * an connection, or optionally restore it to the skb
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+static unsigned int
+target(struct sk_buff **pskb,
+       unsigned int hooknum,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *targinfo,
+       void *userinfo)
+{
+	const struct ipt_connmark_target_info *markinfo = targinfo;
+
+	enum ip_conntrack_info ctinfo;
+	struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
+	if (ct) {
+	    switch(markinfo->mode) {
+	    case IPT_CONNMARK_SET:
+		ct->mark = markinfo->mark;
+		break;
+	    case IPT_CONNMARK_SAVE:
+		ct->mark = (*pskb)->nfmark;
+		break;
+	    case IPT_CONNMARK_RESTORE:
+		if (ct->mark != (*pskb)->nfmark) {
+		    (*pskb)->nfmark = ct->mark;
+		    (*pskb)->nfcache |= NFC_ALTERED;
+		}
+		break;
+	    }
+	}
+
+	return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+	   const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	struct ipt_connmark_target_info *matchinfo = targinfo;
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) {
+		printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_connmark_target_info)));
+		return 0;
+	}
+
+	if (matchinfo->mode == IPT_CONNMARK_RESTORE) {
+	    if (strcmp(tablename, "mangle") != 0) {
+		    printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		    return 0;
+	    }
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_connmark_reg
+= { { NULL, NULL }, "CONNMARK", target, checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_connmark_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_connmark_reg);
+}
+
+module_init(init);
+module_exit(fini);
    dep_tristate '  Connection state match support' CONFIG_IP_NF_MATCH_STATE 
$CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
    if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then
      dep_tristate '  Connection mark match support' CONFIG_IP_NF_MATCH_CONNMARK 
$CONFIG_IP_NF_IPTABLES
    fi
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
Author: Henrik Nordstrom <[EMAIL PROTECTED]>
Status: working

This patch adds per connection marks, and a target (CONNMARK)
respective a match (connmark) for using these.

Usage:

   connmark
       This  module  matches  the netfilter mark field associated
       with a connection (which can be  set  using  the  CONNMARK
       target below).

       --mark value[/mask]
              Matches  packets  in  connections  with  the  given
              unsigned mark value (if a mask is  specified,  this
              is logically ANDed with the mark before the compar­
              ison).


   CONNMARK
       This  is  used  to set the netfilter mark value associated
       with the connection

       --set-mark mark
              Set connection mark

       --save-mark
              Set connection mark to the same as the one  on  the
              packet

       --restore-mark
              Set  the  netfilter  packet  mark  value to the one
              associated with the connection. This is only  valid
              in the mangle table.
  dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
  if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then
    dep_tristate '  CONNMARK target support' CONFIG_IP_NF_TARGET_CONNMARK 
$CONFIG_IP_NF_IPTABLES
  fi
  dep_tristate '  FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
  bool '  Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK
CONFIG_IP_NF_FTP
Per connection mark support
CONFIG_IP_NF_CONNTRACK_MARK
  This option enables support for connection marks, used by the
  `CONNMARK' target and `connmark' match. Similar to the mark value
  of packets, but this mark value is kept in the conntrack session
  instead of the individual packets.

CONNMARK target support
CONFIG_IP_NF_TARGET_CONNMARK
  This option adds a `CONNMARK' target, which allows one to manipulate
  the connection mark value.  Similar to the MARK target, but
  affects the connection mark value rather than the packet mark value.

  If you want to compile it as a module, say M here and read
  Documentation/modules.txt.  The module will be called
  ipt_CONNMARK.o.  If unsure, say `N'.

connmark match support
CONFIP_IP_NF_MATCH_CONNMARK
  This option adds a `connmark' match, which allows you to match the
  connection mark value previously set for the session by `CONNMARK'. 

Reply via email to