Commit e42d291d authored by Harald Welte's avatar Harald Welte Committed by David S. Miller

[NETFILTER]: Add iptables CONNMARK match+target

This is the first patch, adding something similar like nfmark, but on a
per-conntrack (as opposed to per-skb) level.  Very useful especially for
asymmatric routing in combination with MASQUERADE, as often found on
home DSL setups with dymamic IP address that also have e.g. a tunnel
device with static IP.
Signed-off-by: default avatarHenrik Nordstrom <hno@marasystems.com>
Signed-off-by: default avatarHarald Welte <laforge@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bd03dca4
......@@ -212,6 +212,10 @@ struct ip_conntrack
} nat;
#endif /* CONFIG_IP_NF_NAT_NEEDED */
#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
unsigned long mark;
#endif
/* Traversed often, so hopefully in different cacheline to top */
/* These are my tuples; original and reply */
struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
......
#ifndef _IPT_CONNMARK_H_target
#define _IPT_CONNMARK_H_target
/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.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.
*/
enum {
IPT_CONNMARK_SET = 0,
IPT_CONNMARK_SAVE,
IPT_CONNMARK_RESTORE
};
struct ipt_connmark_target_info {
unsigned long mark;
unsigned long mask;
u_int8_t mode;
};
#endif /*_IPT_CONNMARK_H_target*/
#ifndef _IPT_CONNMARK_H
#define _IPT_CONNMARK_H
/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.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.
*/
struct ipt_connmark_info {
unsigned long mark, mask;
u_int8_t invert;
};
#endif /*_IPT_CONNMARK_H*/
......@@ -32,6 +32,14 @@ config IP_NF_CT_ACCT
If unsure, say `N'.
config IP_NF_CONNTRACK_MARK
bool 'Connection mark tracking support'
help
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.
config IP_NF_CT_PROTO_SCTP
tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)'
depends on IP_NF_CONNTRACK && EXPERIMENTAL
......@@ -342,6 +350,17 @@ config IP_NF_MATCH_COMMENT
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
config IP_NF_MATCH_CONNMARK
tristate 'Connection mark match support'
depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES
help
This option adds a `connmark' match, which allows you to match the
connection mark value previously set for the session by `CONNMARK'.
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'.
# `filter', generic and specific targets
config IP_NF_FILTER
tristate "Packet filtering"
......@@ -597,6 +616,18 @@ config IP_NF_TARGET_CLASSIFY
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_TARGET_CONNMARK
tristate 'CONNMARK target support'
depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE
help
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'.
# raw + specific targets
config IP_NF_RAW
tristate 'raw table support (required for NOTRACK/TRACE)'
......
......@@ -61,6 +61,7 @@ obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
......@@ -81,6 +82,7 @@ obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
......
......@@ -594,6 +594,9 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
conntrack->master = expected;
expected->sibling = conntrack;
#if CONFIG_IP_NF_CONNTRACK_MARK
conntrack->mark = expected->expectant->mark;
#endif
LIST_DELETE(&ip_conntrack_expect_list, expected);
expected->expectant->expecting--;
nf_conntrack_get(&master_ct(conntrack)->ct_general);
......
......@@ -146,6 +146,11 @@ static int ct_seq_real_show(const struct ip_conntrack_tuple_hash *hash,
if (seq_printf(s, "[ASSURED] "))
return 1;
#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
if (seq_printf(s, "mark=%ld ", conntrack->mark))
return 1;
#endif
if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
return 1;
......
/* This kernel module is used to modify the connection mark values, or
* to optionally restore the skb nfmark from the connection mark
*
* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.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.
*
* 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
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/checksum.h>
MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
MODULE_DESCRIPTION("IP tables CONNMARK matching module");
MODULE_LICENSE("GPL");
#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,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const void *targinfo,
void *userinfo)
{
const struct ipt_connmark_target_info *markinfo = targinfo;
unsigned long diff;
unsigned long nfmark;
unsigned long newmark;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
if (ct) {
switch(markinfo->mode) {
case IPT_CONNMARK_SET:
newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
if (newmark != ct->mark)
ct->mark = newmark;
break;
case IPT_CONNMARK_SAVE:
newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
if (ct->mark != newmark)
ct->mark = newmark;
break;
case IPT_CONNMARK_RESTORE:
nfmark = (*pskb)->nfmark;
diff = (ct->mark ^ nfmark & markinfo->mask);
if (diff != 0) {
(*pskb)->nfmark = nfmark ^ diff;
(*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 = {
.name = "CONNMARK",
.target = &target,
.checkentry = &checkentry,
.me = THIS_MODULE
};
static int __init init(void)
{
return ipt_register_target(&ipt_connmark_reg);
}
static void __exit fini(void)
{
ipt_unregister_target(&ipt_connmark_reg);
}
module_init(init);
module_exit(fini);
/* This kernel module matches connection mark values set by the
* CONNMARK target
*
* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.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.
*
* 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
*/
#include <linux/module.h>
#include <linux/skbuff.h>
MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
MODULE_DESCRIPTION("IP tables connmark match module");
MODULE_LICENSE("GPL");
#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,
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 = {
.name = "connmark",
.match = &match,
.checkentry = &checkentry,
.me = 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment