[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data structures and backend interfaces for the three evil clones ip_tables, ip6_tables and arp_tables. In an ideal world we would never have allowed this kind of copy+paste programming... but well, our world isn't (yet?) ideal. o introduce a new x_tables module o {ip,arp,ip6}_tables depend on this x_tables module o registration functions for tables, matches and targets are only wrappers around x_tables provided functions o all matches/targets that are used from ip_tables and ip6_tables are now implemented as xt_FOOBAR.c files and provide module aliases to ipt_FOOBAR and ip6t_FOOBAR o header files for xt_matches are in include/linux/netfilter/, include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers around the xt_FOOBAR.h headers Based on this patchset we're going to further unify the code, gradually getting rid of all the layer 3 specific assumptions. Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
880b005f29
commit
2e4e6a17af
@@ -103,3 +103,261 @@ config NF_CT_NETLINK
|
||||
This option enables support for a netlink-based userspace interface
|
||||
|
||||
endmenu
|
||||
|
||||
config NETFILTER_XTABLES
|
||||
tristate "Netfilter Xtables support (required for ip_tables)"
|
||||
help
|
||||
This is required if you intend to use any of ip_tables,
|
||||
ip6_tables or arp_tables.
|
||||
|
||||
# alphabetically ordered list of targets
|
||||
|
||||
config NETFILTER_XT_TARGET_CLASSIFY
|
||||
tristate '"CLASSIFY" target support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
This option adds a `CLASSIFY' target, which enables the user to set
|
||||
the priority of a packet. Some qdiscs can use this value for
|
||||
classification, among these are:
|
||||
|
||||
atm, cbq, dsmark, pfifo_fast, htb, prio
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_TARGET_CONNMARK
|
||||
tristate '"CONNMARK" target support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_MANGLE || IP6_NF_MANGLE
|
||||
depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
|
||||
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
|
||||
<file:Documentation/modules.txt>. The module will be called
|
||||
ipt_CONNMARK.o. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_TARGET_MARK
|
||||
tristate '"MARK" target support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
This option adds a `MARK' target, which allows you to create rules
|
||||
in the `mangle' table which alter the netfilter mark (nfmark) field
|
||||
associated with the packet prior to routing. This can change
|
||||
the routing method (see `Use netfilter MARK value as routing
|
||||
key') and can also be used by other subsystems to change their
|
||||
behavior.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_TARGET_NFQUEUE
|
||||
tristate '"NFQUEUE" target Support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
This Target replaced the old obsolete QUEUE target.
|
||||
|
||||
As opposed to QUEUE, it supports 65535 different queues,
|
||||
not just one.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_TARGET_NOTRACK
|
||||
tristate '"NOTRACK" target support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_RAW || IP6_NF_RAW
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
help
|
||||
The NOTRACK target allows a select rule to specify
|
||||
which packets *not* to enter the conntrack/NAT
|
||||
subsystem with all the consequences (no ICMP error tracking,
|
||||
no protocol helpers for the selected packets).
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_COMMENT
|
||||
tristate '"comment" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
This option adds a `comment' dummy-match, which allows you to put
|
||||
comments in your iptables ruleset.
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_CONNBYTES
|
||||
tristate '"connbytes" per-connection counter match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on (IP_NF_CONNTRACK && IP_NF_CT_ACCT) || NF_CT_ACCT
|
||||
help
|
||||
This option adds a `connbytes' match, which allows you to match the
|
||||
number of bytes and/or packets for each direction within a connection.
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_CONNMARK
|
||||
tristate '"connmark" connection mark match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || NF_CONNTRACK_MARK
|
||||
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
|
||||
<file:Documentation/modules.txt>. The module will be called
|
||||
ipt_connmark.o. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_CONNTRACK
|
||||
tristate '"conntrack" connection tracking match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
help
|
||||
This is a general conntrack match module, a superset of the state match.
|
||||
|
||||
It allows matching on additional conntrack information, which is
|
||||
useful in complex configurations, such as NAT gateways with multiple
|
||||
internet links or tunnels.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_DCCP
|
||||
tristate '"DCCP" protocol match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
With this option enabled, you will be able to use the iptables
|
||||
`dccp' match in order to match on DCCP source/destination ports
|
||||
and DCCP flags.
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_HELPER
|
||||
tristate '"helper" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
help
|
||||
Helper matching allows you to match packets in dynamic connections
|
||||
tracked by a conntrack-helper, ie. ip_conntrack_ftp
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say Y.
|
||||
|
||||
config NETFILTER_XT_MATCH_LENGTH
|
||||
tristate '"length" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
This option allows you to match the length of a packet against a
|
||||
specific value or range of values.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_LIMIT
|
||||
tristate '"limit" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
limit matching allows you to control the rate at which a rule can be
|
||||
matched: mainly useful in combination with the LOG target ("LOG
|
||||
target support", below) and to avoid some Denial of Service attacks.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_MAC
|
||||
tristate '"mac" address match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
MAC matching allows you to match packets based on the source
|
||||
Ethernet address of the packet.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_MARK
|
||||
tristate '"mark" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
Netfilter mark matching allows you to match packets based on the
|
||||
`nfmark' value in the packet. This can be set by the MARK target
|
||||
(see below).
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_PHYSDEV
|
||||
tristate '"physdev" match support'
|
||||
depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
|
||||
help
|
||||
Physdev packet matching matches against the physical bridge ports
|
||||
the IP packet arrived on or will leave by.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_PKTTYPE
|
||||
tristate '"pkttype" packet type match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
Packet type matching allows you to match a packet by
|
||||
its "class", eg. BROADCAST, MULTICAST, ...
|
||||
|
||||
Typical usage:
|
||||
iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_REALM
|
||||
tristate '"realm" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
select NET_CLS_ROUTE
|
||||
help
|
||||
This option adds a `realm' match, which allows you to use the realm
|
||||
key from the routing subsystem inside iptables.
|
||||
|
||||
This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option
|
||||
in tc world.
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_SCTP
|
||||
tristate '"sctp" protocol match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
With this option enabled, you will be able to use the
|
||||
`sctp' match in order to match on SCTP source/destination ports
|
||||
and SCTP chunk types.
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config NETFILTER_XT_MATCH_STATE
|
||||
tristate '"state" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
help
|
||||
Connection state matching allows you to match packets based on their
|
||||
relationship to a tracked connection (ie. previous packets). This
|
||||
is a powerful tool for packet classification.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_STRING
|
||||
tristate '"string" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
select TEXTSEARCH
|
||||
select TEXTSEARCH_KMP
|
||||
select TEXTSEARCH_BM
|
||||
select TEXTSEARCH_FSM
|
||||
help
|
||||
This option adds a `string' match, which allows you to look for
|
||||
pattern matchings in packets.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_MATCH_TCPMSS
|
||||
tristate '"tcpmss" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
help
|
||||
This option adds a `tcpmss' match, which allows you to examine the
|
||||
MSS value of TCP SYN packets, which control the maximum packet size
|
||||
for that connection.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
|
||||
nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
|
||||
|
||||
obj-$(CONFIG_NETFILTER) = netfilter.o
|
||||
|
||||
@@ -6,13 +7,43 @@ obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
|
||||
obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
|
||||
obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
|
||||
|
||||
nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
|
||||
|
||||
# connection tracking
|
||||
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
|
||||
obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
|
||||
|
||||
# SCTP protocol connection tracking
|
||||
obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
|
||||
|
||||
# netlink interface for nf_conntrack
|
||||
obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
|
||||
|
||||
# connection tracking helpers
|
||||
obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
|
||||
|
||||
# generic X tables
|
||||
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
|
||||
|
||||
# targets
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
|
||||
|
||||
# matches
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
|
||||
|
@@ -821,7 +821,7 @@ module_exit(fini);
|
||||
|
||||
/* Some modules need us, but don't depend directly on any symbol.
|
||||
They should call this. */
|
||||
void need_nf_conntrack(void)
|
||||
void need_conntrack(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -841,7 +841,7 @@ EXPORT_SYMBOL(nf_conntrack_protocol_unregister);
|
||||
EXPORT_SYMBOL(nf_ct_invert_tuplepr);
|
||||
EXPORT_SYMBOL(nf_conntrack_alter_reply);
|
||||
EXPORT_SYMBOL(nf_conntrack_destroyed);
|
||||
EXPORT_SYMBOL(need_nf_conntrack);
|
||||
EXPORT_SYMBOL(need_conntrack);
|
||||
EXPORT_SYMBOL(nf_conntrack_helper_register);
|
||||
EXPORT_SYMBOL(nf_conntrack_helper_unregister);
|
||||
EXPORT_SYMBOL(nf_ct_iterate_cleanup);
|
||||
|
624
net/netfilter/x_tables.c
Normal file
624
net/netfilter/x_tables.c
Normal file
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* x_tables core - Backend for {ip,ip6,arp}_tables
|
||||
*
|
||||
* Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* Based on existing ip_tables code which is
|
||||
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
|
||||
* Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_arp.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
|
||||
|
||||
#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
|
||||
|
||||
struct xt_af {
|
||||
struct semaphore mutex;
|
||||
struct list_head match;
|
||||
struct list_head target;
|
||||
struct list_head tables;
|
||||
};
|
||||
|
||||
static struct xt_af *xt;
|
||||
|
||||
#ifdef DEBUG_IP_FIREWALL_USER
|
||||
#define duprintf(format, args...) printk(format , ## args)
|
||||
#else
|
||||
#define duprintf(format, args...)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
TABLE,
|
||||
TARGET,
|
||||
MATCH,
|
||||
};
|
||||
|
||||
/* Registration hooks for targets. */
|
||||
int
|
||||
xt_register_target(int af, struct xt_target *target)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = down_interruptible(&xt[af].mutex);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
list_add(&target->list, &xt[af].target);
|
||||
up(&xt[af].mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(xt_register_target);
|
||||
|
||||
void
|
||||
xt_unregister_target(int af, struct xt_target *target)
|
||||
{
|
||||
down(&xt[af].mutex);
|
||||
LIST_DELETE(&xt[af].target, target);
|
||||
up(&xt[af].mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(xt_unregister_target);
|
||||
|
||||
int
|
||||
xt_register_match(int af, struct xt_match *match)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = down_interruptible(&xt[af].mutex);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
list_add(&match->list, &xt[af].match);
|
||||
up(&xt[af].mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(xt_register_match);
|
||||
|
||||
void
|
||||
xt_unregister_match(int af, struct xt_match *match)
|
||||
{
|
||||
down(&xt[af].mutex);
|
||||
LIST_DELETE(&xt[af].match, match);
|
||||
up(&xt[af].mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(xt_unregister_match);
|
||||
|
||||
|
||||
/*
|
||||
* These are weird, but module loading must not be done with mutex
|
||||
* held (since they will register), and we have to have a single
|
||||
* function to use try_then_request_module().
|
||||
*/
|
||||
|
||||
/* Find match, grabs ref. Returns ERR_PTR() on error. */
|
||||
struct xt_match *xt_find_match(int af, const char *name, u8 revision)
|
||||
{
|
||||
struct xt_match *m;
|
||||
int err = 0;
|
||||
|
||||
if (down_interruptible(&xt[af].mutex) != 0)
|
||||
return ERR_PTR(-EINTR);
|
||||
|
||||
list_for_each_entry(m, &xt[af].match, list) {
|
||||
if (strcmp(m->name, name) == 0) {
|
||||
if (m->revision == revision) {
|
||||
if (try_module_get(m->me)) {
|
||||
up(&xt[af].mutex);
|
||||
return m;
|
||||
}
|
||||
} else
|
||||
err = -EPROTOTYPE; /* Found something. */
|
||||
}
|
||||
}
|
||||
up(&xt[af].mutex);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL(xt_find_match);
|
||||
|
||||
/* Find target, grabs ref. Returns ERR_PTR() on error. */
|
||||
struct xt_target *xt_find_target(int af, const char *name, u8 revision)
|
||||
{
|
||||
struct xt_target *t;
|
||||
int err = 0;
|
||||
|
||||
if (down_interruptible(&xt[af].mutex) != 0)
|
||||
return ERR_PTR(-EINTR);
|
||||
|
||||
list_for_each_entry(t, &xt[af].target, list) {
|
||||
if (strcmp(t->name, name) == 0) {
|
||||
if (t->revision == revision) {
|
||||
if (try_module_get(t->me)) {
|
||||
up(&xt[af].mutex);
|
||||
return t;
|
||||
}
|
||||
} else
|
||||
err = -EPROTOTYPE; /* Found something. */
|
||||
}
|
||||
}
|
||||
up(&xt[af].mutex);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL(xt_find_target);
|
||||
|
||||
static const char *xt_prefix[NPROTO] = {
|
||||
[AF_INET] = "ipt_%s",
|
||||
[AF_INET6] = "ip6t_%s",
|
||||
[NF_ARP] = "arpt_%s",
|
||||
};
|
||||
|
||||
struct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
|
||||
{
|
||||
struct xt_target *target;
|
||||
|
||||
target = try_then_request_module(xt_find_target(af, name, revision),
|
||||
xt_prefix[af], name);
|
||||
if (IS_ERR(target) || !target)
|
||||
return NULL;
|
||||
return target;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_request_find_target);
|
||||
|
||||
static int match_revfn(int af, const char *name, u8 revision, int *bestp)
|
||||
{
|
||||
struct xt_match *m;
|
||||
int have_rev = 0;
|
||||
|
||||
list_for_each_entry(m, &xt[af].match, list) {
|
||||
if (strcmp(m->name, name) == 0) {
|
||||
if (m->revision > *bestp)
|
||||
*bestp = m->revision;
|
||||
if (m->revision == revision)
|
||||
have_rev = 1;
|
||||
}
|
||||
}
|
||||
return have_rev;
|
||||
}
|
||||
|
||||
static int target_revfn(int af, const char *name, u8 revision, int *bestp)
|
||||
{
|
||||
struct xt_target *t;
|
||||
int have_rev = 0;
|
||||
|
||||
list_for_each_entry(t, &xt[af].target, list) {
|
||||
if (strcmp(t->name, name) == 0) {
|
||||
if (t->revision > *bestp)
|
||||
*bestp = t->revision;
|
||||
if (t->revision == revision)
|
||||
have_rev = 1;
|
||||
}
|
||||
}
|
||||
return have_rev;
|
||||
}
|
||||
|
||||
/* Returns true or false (if no such extension at all) */
|
||||
int xt_find_revision(int af, const char *name, u8 revision, int target,
|
||||
int *err)
|
||||
{
|
||||
int have_rev, best = -1;
|
||||
|
||||
if (down_interruptible(&xt[af].mutex) != 0) {
|
||||
*err = -EINTR;
|
||||
return 1;
|
||||
}
|
||||
if (target == 1)
|
||||
have_rev = target_revfn(af, name, revision, &best);
|
||||
else
|
||||
have_rev = match_revfn(af, name, revision, &best);
|
||||
up(&xt[af].mutex);
|
||||
|
||||
/* Nothing at all? Return 0 to try loading module. */
|
||||
if (best == -1) {
|
||||
*err = -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*err = best;
|
||||
if (!have_rev)
|
||||
*err = -EPROTONOSUPPORT;
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_find_revision);
|
||||
|
||||
struct xt_table_info *xt_alloc_table_info(unsigned int size)
|
||||
{
|
||||
struct xt_table_info *newinfo;
|
||||
int cpu;
|
||||
|
||||
/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
|
||||
if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
|
||||
return NULL;
|
||||
|
||||
newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
|
||||
if (!newinfo)
|
||||
return NULL;
|
||||
|
||||
newinfo->size = size;
|
||||
|
||||
for_each_cpu(cpu) {
|
||||
if (size <= PAGE_SIZE)
|
||||
newinfo->entries[cpu] = kmalloc_node(size,
|
||||
GFP_KERNEL,
|
||||
cpu_to_node(cpu));
|
||||
else
|
||||
newinfo->entries[cpu] = vmalloc_node(size,
|
||||
cpu_to_node(cpu));
|
||||
|
||||
if (newinfo->entries[cpu] == NULL) {
|
||||
xt_free_table_info(newinfo);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return newinfo;
|
||||
}
|
||||
EXPORT_SYMBOL(xt_alloc_table_info);
|
||||
|
||||
void xt_free_table_info(struct xt_table_info *info)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_cpu(cpu) {
|
||||
if (info->size <= PAGE_SIZE)
|
||||
kfree(info->entries[cpu]);
|
||||
else
|
||||
vfree(info->entries[cpu]);
|
||||
}
|
||||
kfree(info);
|
||||
}
|
||||
EXPORT_SYMBOL(xt_free_table_info);
|
||||
|
||||
/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
|
||||
struct xt_table *xt_find_table_lock(int af, const char *name)
|
||||
{
|
||||
struct xt_table *t;
|
||||
|
||||
if (down_interruptible(&xt[af].mutex) != 0)
|
||||
return ERR_PTR(-EINTR);
|
||||
|
||||
list_for_each_entry(t, &xt[af].tables, list)
|
||||
if (strcmp(t->name, name) == 0 && try_module_get(t->me))
|
||||
return t;
|
||||
up(&xt[af].mutex);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_find_table_lock);
|
||||
|
||||
void xt_table_unlock(struct xt_table *table)
|
||||
{
|
||||
up(&xt[table->af].mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_table_unlock);
|
||||
|
||||
|
||||
struct xt_table_info *
|
||||
xt_replace_table(struct xt_table *table,
|
||||
unsigned int num_counters,
|
||||
struct xt_table_info *newinfo,
|
||||
int *error)
|
||||
{
|
||||
struct xt_table_info *oldinfo, *private;
|
||||
|
||||
/* Do the substitution. */
|
||||
write_lock_bh(&table->lock);
|
||||
private = table->private;
|
||||
/* Check inside lock: is the old number correct? */
|
||||
if (num_counters != private->number) {
|
||||
duprintf("num_counters != table->private->number (%u/%u)\n",
|
||||
num_counters, private->number);
|
||||
write_unlock_bh(&table->lock);
|
||||
*error = -EAGAIN;
|
||||
return NULL;
|
||||
}
|
||||
oldinfo = private;
|
||||
table->private = newinfo;
|
||||
newinfo->initial_entries = oldinfo->initial_entries;
|
||||
write_unlock_bh(&table->lock);
|
||||
|
||||
return oldinfo;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_replace_table);
|
||||
|
||||
int xt_register_table(struct xt_table *table,
|
||||
struct xt_table_info *bootstrap,
|
||||
struct xt_table_info *newinfo)
|
||||
{
|
||||
int ret;
|
||||
struct xt_table_info *private;
|
||||
|
||||
ret = down_interruptible(&xt[table->af].mutex);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* Don't autoload: we'd eat our tail... */
|
||||
if (list_named_find(&xt[table->af].tables, table->name)) {
|
||||
ret = -EEXIST;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Simplifies replace_table code. */
|
||||
table->private = bootstrap;
|
||||
if (!xt_replace_table(table, 0, newinfo, &ret))
|
||||
goto unlock;
|
||||
|
||||
private = table->private;
|
||||
duprintf("table->private->number = %u\n", private->number);
|
||||
|
||||
/* save number of initial entries */
|
||||
private->initial_entries = private->number;
|
||||
|
||||
rwlock_init(&table->lock);
|
||||
list_prepend(&xt[table->af].tables, table);
|
||||
|
||||
ret = 0;
|
||||
unlock:
|
||||
up(&xt[table->af].mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_register_table);
|
||||
|
||||
void *xt_unregister_table(struct xt_table *table)
|
||||
{
|
||||
struct xt_table_info *private;
|
||||
|
||||
down(&xt[table->af].mutex);
|
||||
private = table->private;
|
||||
LIST_DELETE(&xt[table->af].tables, table);
|
||||
up(&xt[table->af].mutex);
|
||||
|
||||
return private;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_unregister_table);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static char *xt_proto_prefix[NPROTO] = {
|
||||
[AF_INET] = "ip",
|
||||
[AF_INET6] = "ip6",
|
||||
[NF_ARP] = "arp",
|
||||
};
|
||||
|
||||
static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
|
||||
{
|
||||
struct list_head *head = list->next;
|
||||
|
||||
if (!head || list_empty(list))
|
||||
return NULL;
|
||||
|
||||
while (pos && (head = head->next)) {
|
||||
if (head == list)
|
||||
return NULL;
|
||||
pos--;
|
||||
}
|
||||
return pos ? NULL : head;
|
||||
}
|
||||
|
||||
static struct list_head *type2list(u_int16_t af, u_int16_t type)
|
||||
{
|
||||
struct list_head *list;
|
||||
|
||||
switch (type) {
|
||||
case TARGET:
|
||||
list = &xt[af].target;
|
||||
break;
|
||||
case MATCH:
|
||||
list = &xt[af].match;
|
||||
break;
|
||||
case TABLE:
|
||||
list = &xt[af].tables;
|
||||
break;
|
||||
default:
|
||||
list = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
|
||||
u_int16_t af = (unsigned long)pde->data & 0xffff;
|
||||
u_int16_t type = (unsigned long)pde->data >> 16;
|
||||
struct list_head *list;
|
||||
|
||||
if (af >= NPROTO)
|
||||
return NULL;
|
||||
|
||||
list = type2list(af, type);
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
if (down_interruptible(&xt[af].mutex) != 0)
|
||||
return NULL;
|
||||
|
||||
return xt_get_idx(list, seq, *pos);
|
||||
}
|
||||
|
||||
static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
struct proc_dir_entry *pde = seq->private;
|
||||
u_int16_t af = (unsigned long)pde->data & 0xffff;
|
||||
u_int16_t type = (unsigned long)pde->data >> 16;
|
||||
struct list_head *list;
|
||||
|
||||
if (af >= NPROTO)
|
||||
return NULL;
|
||||
|
||||
list = type2list(af, type);
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
(*pos)++;
|
||||
return xt_get_idx(list, seq, *pos);
|
||||
}
|
||||
|
||||
static void xt_tgt_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct proc_dir_entry *pde = seq->private;
|
||||
u_int16_t af = (unsigned long)pde->data & 0xffff;
|
||||
|
||||
up(&xt[af].mutex);
|
||||
}
|
||||
|
||||
static int xt_name_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
char *name = (char *)v + sizeof(struct list_head);
|
||||
|
||||
if (strlen(name))
|
||||
return seq_printf(seq, "%s\n", name);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations xt_tgt_seq_ops = {
|
||||
.start = xt_tgt_seq_start,
|
||||
.next = xt_tgt_seq_next,
|
||||
.stop = xt_tgt_seq_stop,
|
||||
.show = xt_name_seq_show,
|
||||
};
|
||||
|
||||
static int xt_tgt_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &xt_tgt_seq_ops);
|
||||
if (!ret) {
|
||||
struct seq_file *seq = file->private_data;
|
||||
struct proc_dir_entry *pde = PDE(inode);
|
||||
|
||||
seq->private = pde;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct file_operations xt_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = xt_tgt_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
#define FORMAT_TABLES "_tables_names"
|
||||
#define FORMAT_MATCHES "_tables_matches"
|
||||
#define FORMAT_TARGETS "_tables_targets"
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
int xt_proto_init(int af)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
char buf[XT_FUNCTION_MAXNAMELEN];
|
||||
struct proc_dir_entry *proc;
|
||||
#endif
|
||||
|
||||
if (af >= NPROTO)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_TABLES, sizeof(buf));
|
||||
proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
|
||||
if (!proc)
|
||||
goto out;
|
||||
proc->data = (void *) ((unsigned long) af | (TABLE << 16));
|
||||
|
||||
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_MATCHES, sizeof(buf));
|
||||
proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
|
||||
if (!proc)
|
||||
goto out_remove_tables;
|
||||
proc->data = (void *) ((unsigned long) af | (MATCH << 16));
|
||||
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_TARGETS, sizeof(buf));
|
||||
proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
|
||||
if (!proc)
|
||||
goto out_remove_matches;
|
||||
proc->data = (void *) ((unsigned long) af | (TARGET << 16));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
out_remove_matches:
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_MATCHES, sizeof(buf));
|
||||
proc_net_remove(buf);
|
||||
|
||||
out_remove_tables:
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_TABLES, sizeof(buf));
|
||||
proc_net_remove(buf);
|
||||
out:
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_proto_init);
|
||||
|
||||
void xt_proto_fini(int af)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
char buf[XT_FUNCTION_MAXNAMELEN];
|
||||
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_TABLES, sizeof(buf));
|
||||
proc_net_remove(buf);
|
||||
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_TARGETS, sizeof(buf));
|
||||
proc_net_remove(buf);
|
||||
|
||||
strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
|
||||
strlcat(buf, FORMAT_MATCHES, sizeof(buf));
|
||||
proc_net_remove(buf);
|
||||
#endif /*CONFIG_PROC_FS*/
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_proto_fini);
|
||||
|
||||
|
||||
static int __init xt_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
|
||||
if (!xt)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < NPROTO; i++) {
|
||||
init_MUTEX(&xt[i].mutex);
|
||||
INIT_LIST_HEAD(&xt[i].target);
|
||||
INIT_LIST_HEAD(&xt[i].match);
|
||||
INIT_LIST_HEAD(&xt[i].tables);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit xt_fini(void)
|
||||
{
|
||||
kfree(xt);
|
||||
}
|
||||
|
||||
module_init(xt_init);
|
||||
module_exit(xt_fini);
|
||||
|
109
net/netfilter/xt_CLASSIFY.c
Normal file
109
net/netfilter/xt_CLASSIFY.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This is a module which is used for setting the skb->priority field
|
||||
* of an skb for qdisc classification.
|
||||
*/
|
||||
|
||||
/* (C) 2001-2002 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/checksum.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_CLASSIFY.h>
|
||||
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("iptables qdisc classification target module");
|
||||
MODULE_ALIAS("ipt_CLASSIFY");
|
||||
|
||||
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 xt_classify_target_info *clinfo = targinfo;
|
||||
|
||||
if ((*pskb)->priority != clinfo->priority)
|
||||
(*pskb)->priority = clinfo->priority;
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *e,
|
||||
void *targinfo,
|
||||
unsigned int targinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (targinfosize != XT_ALIGN(sizeof(struct xt_classify_target_info))){
|
||||
printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n",
|
||||
targinfosize,
|
||||
XT_ALIGN(sizeof(struct xt_classify_target_info)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
|
||||
(1 << NF_IP_POST_ROUTING))) {
|
||||
printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD "
|
||||
"and POST_ROUTING.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(tablename, "mangle") != 0) {
|
||||
printk(KERN_ERR "CLASSIFY: can only be called from "
|
||||
"\"mangle\" table, not \"%s\".\n",
|
||||
tablename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_target classify_reg = {
|
||||
.name = "CLASSIFY",
|
||||
.target = target,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_target classify6_reg = {
|
||||
.name = "CLASSIFY",
|
||||
.target = target,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xt_register_target(AF_INET, &classify_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_target(AF_INET6, &classify6_reg);
|
||||
if (ret)
|
||||
xt_unregister_target(AF_INET, &classify_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_target(AF_INET, &classify_reg);
|
||||
xt_unregister_target(AF_INET6, &classify6_reg);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
141
net/netfilter/xt_CONNMARK.c
Normal file
141
net/netfilter/xt_CONNMARK.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/* 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");
|
||||
MODULE_ALIAS("ipt_CONNMARK");
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_CONNMARK.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.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 xt_connmark_target_info *markinfo = targinfo;
|
||||
u_int32_t diff;
|
||||
u_int32_t nfmark;
|
||||
u_int32_t newmark;
|
||||
u_int32_t ctinfo;
|
||||
u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
|
||||
|
||||
if (ctmark) {
|
||||
switch(markinfo->mode) {
|
||||
case XT_CONNMARK_SET:
|
||||
newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
|
||||
if (newmark != *ctmark)
|
||||
*ctmark = newmark;
|
||||
break;
|
||||
case XT_CONNMARK_SAVE:
|
||||
newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
|
||||
if (*ctmark != newmark)
|
||||
*ctmark = newmark;
|
||||
break;
|
||||
case XT_CONNMARK_RESTORE:
|
||||
nfmark = (*pskb)->nfmark;
|
||||
diff = (*ctmark ^ nfmark) & markinfo->mask;
|
||||
if (diff != 0)
|
||||
(*pskb)->nfmark = nfmark ^ diff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
void *targinfo,
|
||||
unsigned int targinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_connmark_target_info *matchinfo = targinfo;
|
||||
if (targinfosize != XT_ALIGN(sizeof(struct xt_connmark_target_info))) {
|
||||
printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
|
||||
targinfosize,
|
||||
XT_ALIGN(sizeof(struct xt_connmark_target_info)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (matchinfo->mode == XT_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;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
|
||||
printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_target connmark_reg = {
|
||||
.name = "CONNMARK",
|
||||
.target = &target,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
static struct xt_target connmark6_reg = {
|
||||
.name = "CONNMARK",
|
||||
.target = &target,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
need_conntrack();
|
||||
|
||||
ret = xt_register_target(AF_INET, &connmark_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_target(AF_INET6, &connmark6_reg);
|
||||
if (ret)
|
||||
xt_unregister_target(AF_INET, &connmark_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_target(AF_INET, &connmark_reg);
|
||||
xt_unregister_target(AF_INET6, &connmark6_reg);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
191
net/netfilter/xt_MARK.c
Normal file
191
net/netfilter/xt_MARK.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/* This is a module which is used for setting the NFMARK field of an skb. */
|
||||
|
||||
/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/checksum.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_MARK.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
|
||||
MODULE_DESCRIPTION("ip[6]tables MARK modification module");
|
||||
MODULE_ALIAS("ipt_MARK");
|
||||
MODULE_ALIAS("ip6t_MARK");
|
||||
|
||||
static unsigned int
|
||||
target_v0(struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
unsigned int hooknum,
|
||||
const void *targinfo,
|
||||
void *userinfo)
|
||||
{
|
||||
const struct xt_mark_target_info *markinfo = targinfo;
|
||||
|
||||
if((*pskb)->nfmark != markinfo->mark)
|
||||
(*pskb)->nfmark = markinfo->mark;
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
target_v1(struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
unsigned int hooknum,
|
||||
const void *targinfo,
|
||||
void *userinfo)
|
||||
{
|
||||
const struct xt_mark_target_info_v1 *markinfo = targinfo;
|
||||
int mark = 0;
|
||||
|
||||
switch (markinfo->mode) {
|
||||
case XT_MARK_SET:
|
||||
mark = markinfo->mark;
|
||||
break;
|
||||
|
||||
case XT_MARK_AND:
|
||||
mark = (*pskb)->nfmark & markinfo->mark;
|
||||
break;
|
||||
|
||||
case XT_MARK_OR:
|
||||
mark = (*pskb)->nfmark | markinfo->mark;
|
||||
break;
|
||||
}
|
||||
|
||||
if((*pskb)->nfmark != mark)
|
||||
(*pskb)->nfmark = mark;
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
checkentry_v0(const char *tablename,
|
||||
const void *entry,
|
||||
void *targinfo,
|
||||
unsigned int targinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_mark_target_info *markinfo = targinfo;
|
||||
|
||||
if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) {
|
||||
printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
|
||||
targinfosize,
|
||||
XT_ALIGN(sizeof(struct xt_mark_target_info)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(tablename, "mangle") != 0) {
|
||||
printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (markinfo->mark > 0xffffffff) {
|
||||
printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry_v1(const char *tablename,
|
||||
const void *entry,
|
||||
void *targinfo,
|
||||
unsigned int targinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_mark_target_info_v1 *markinfo = targinfo;
|
||||
|
||||
if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){
|
||||
printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
|
||||
targinfosize,
|
||||
XT_ALIGN(sizeof(struct xt_mark_target_info_v1)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(tablename, "mangle") != 0) {
|
||||
printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (markinfo->mode != XT_MARK_SET
|
||||
&& markinfo->mode != XT_MARK_AND
|
||||
&& markinfo->mode != XT_MARK_OR) {
|
||||
printk(KERN_WARNING "MARK: unknown mode %u\n",
|
||||
markinfo->mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (markinfo->mark > 0xffffffff) {
|
||||
printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_target ipt_mark_reg_v0 = {
|
||||
.name = "MARK",
|
||||
.target = target_v0,
|
||||
.checkentry = checkentry_v0,
|
||||
.me = THIS_MODULE,
|
||||
.revision = 0,
|
||||
};
|
||||
|
||||
static struct xt_target ipt_mark_reg_v1 = {
|
||||
.name = "MARK",
|
||||
.target = target_v1,
|
||||
.checkentry = checkentry_v1,
|
||||
.me = THIS_MODULE,
|
||||
.revision = 1,
|
||||
};
|
||||
|
||||
static struct xt_target ip6t_mark_reg_v0 = {
|
||||
.name = "MARK",
|
||||
.target = target_v0,
|
||||
.checkentry = checkentry_v0,
|
||||
.me = THIS_MODULE,
|
||||
.revision = 0,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = xt_register_target(AF_INET, &ipt_mark_reg_v0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = xt_register_target(AF_INET, &ipt_mark_reg_v1);
|
||||
if (err)
|
||||
xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
|
||||
|
||||
err = xt_register_target(AF_INET6, &ip6t_mark_reg_v0);
|
||||
if (err) {
|
||||
xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
|
||||
xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
|
||||
xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
|
||||
xt_unregister_target(AF_INET6, &ip6t_mark_reg_v0);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
107
net/netfilter/xt_NFQUEUE.c
Normal file
107
net/netfilter/xt_NFQUEUE.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/* iptables module for using new netfilter netlink queue
|
||||
*
|
||||
* (C) 2005 by Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_arp.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_NFQUEUE.h>
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("[ip,ip6,arp]_tables NFQUEUE target");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_NFQUEUE");
|
||||
MODULE_ALIAS("ip6t_NFQUEUE");
|
||||
MODULE_ALIAS("arpt_NFQUEUE");
|
||||
|
||||
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 xt_NFQ_info *tinfo = targinfo;
|
||||
|
||||
return NF_QUEUE_NR(tinfo->queuenum);
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
void *targinfo,
|
||||
unsigned int targinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (targinfosize != XT_ALIGN(sizeof(struct xt_NFQ_info))) {
|
||||
printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
|
||||
targinfosize,
|
||||
XT_ALIGN(sizeof(struct xt_NFQ_info)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_target ipt_NFQ_reg = {
|
||||
.name = "NFQUEUE",
|
||||
.target = target,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct xt_target ip6t_NFQ_reg = {
|
||||
.name = "NFQUEUE",
|
||||
.target = target,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct xt_target arpt_NFQ_reg = {
|
||||
.name = "NFQUEUE",
|
||||
.target = target,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_target(AF_INET, &ipt_NFQ_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = xt_register_target(AF_INET6, &ip6t_NFQ_reg);
|
||||
if (ret)
|
||||
goto out_ip;
|
||||
ret = xt_register_target(NF_ARP, &arpt_NFQ_reg);
|
||||
if (ret)
|
||||
goto out_ip6;
|
||||
|
||||
return ret;
|
||||
out_ip6:
|
||||
xt_unregister_target(AF_INET6, &ip6t_NFQ_reg);
|
||||
out_ip:
|
||||
xt_unregister_target(AF_INET, &ipt_NFQ_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_target(NF_ARP, &arpt_NFQ_reg);
|
||||
xt_unregister_target(AF_INET6, &ip6t_NFQ_reg);
|
||||
xt_unregister_target(AF_INET, &ipt_NFQ_reg);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
92
net/netfilter/xt_NOTRACK.c
Normal file
92
net/netfilter/xt_NOTRACK.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/* This is a module which is used for setting up fake conntracks
|
||||
* on packets so that they are not seen by the conntrack/NAT code.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_NOTRACK");
|
||||
|
||||
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)
|
||||
{
|
||||
/* Previously seen (loopback)? Ignore. */
|
||||
if ((*pskb)->nfct != NULL)
|
||||
return XT_CONTINUE;
|
||||
|
||||
/* Attach fake conntrack entry.
|
||||
If there is a real ct entry correspondig to this packet,
|
||||
it'll hang aroun till timing out. We don't deal with it
|
||||
for performance reasons. JK */
|
||||
nf_ct_untrack(*pskb);
|
||||
(*pskb)->nfctinfo = IP_CT_NEW;
|
||||
nf_conntrack_get((*pskb)->nfct);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
void *targinfo,
|
||||
unsigned int targinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (targinfosize != 0) {
|
||||
printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
|
||||
targinfosize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(tablename, "raw") != 0) {
|
||||
printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_target notrack_reg = {
|
||||
.name = "NOTRACK",
|
||||
.target = target,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_target notrack6_reg = {
|
||||
.name = "NOTRACK",
|
||||
.target = target,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xt_register_target(AF_INET, ¬rack_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_target(AF_INET6, ¬rack6_reg);
|
||||
if (ret)
|
||||
xt_unregister_target(AF_INET, ¬rack_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_target(AF_INET6, ¬rack6_reg);
|
||||
xt_unregister_target(AF_INET, ¬rack_reg);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
80
net/netfilter/xt_comment.c
Normal file
80
net/netfilter/xt_comment.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Implements a dummy match to allow attaching comments to rules
|
||||
*
|
||||
* 2003-05-13 Brad Fisher (brad@info-link.net)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_comment.h>
|
||||
|
||||
MODULE_AUTHOR("Brad Fisher <brad@info-link.net>");
|
||||
MODULE_DESCRIPTION("iptables comment match module");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_comment");
|
||||
MODULE_ALIAS("ip6t_comment");
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protooff,
|
||||
int *hotdrop)
|
||||
{
|
||||
/* We always match */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
/* Check the size */
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_comment_info)))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match comment_match = {
|
||||
.name = "comment",
|
||||
.match = match,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
static struct xt_match comment6_match = {
|
||||
.name = "comment",
|
||||
.match = match,
|
||||
.checkentry = checkentry,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xt_register_match(AF_INET, &comment_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &comment6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &comment_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &comment_match);
|
||||
xt_unregister_match(AF_INET6, &comment6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
180
net/netfilter/xt_connbytes.c
Normal file
180
net/netfilter/xt_connbytes.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/* Kernel module to match connection tracking byte counter.
|
||||
* GPL (C) 2002 Martin Devera (devik@cdi.cz).
|
||||
*
|
||||
* 2004-07-20 Harald Welte <laforge@netfilter.org>
|
||||
* - reimplemented to use per-connection accounting counters
|
||||
* - add functionality to match number of packets
|
||||
* - add functionality to match average packet size
|
||||
* - add support to match directions seperately
|
||||
* 2005-10-16 Harald Welte <laforge@netfilter.org>
|
||||
* - Port to x_tables
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_connbytes.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
#include <asm/bitops.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
|
||||
MODULE_ALIAS("ipt_connbytes");
|
||||
|
||||
/* 64bit divisor, dividend and result. dynamic precision */
|
||||
static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
|
||||
{
|
||||
u_int32_t d = divisor;
|
||||
|
||||
if (divisor > 0xffffffffULL) {
|
||||
unsigned int shift = fls(divisor >> 32);
|
||||
|
||||
d = divisor >> shift;
|
||||
dividend >>= shift;
|
||||
}
|
||||
|
||||
do_div(dividend, d);
|
||||
return dividend;
|
||||
}
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_connbytes_info *sinfo = matchinfo;
|
||||
u_int64_t what = 0; /* initialize to make gcc happy */
|
||||
const struct ip_conntrack_counter *counters;
|
||||
|
||||
if (!(counters = nf_ct_get_counters(skb)))
|
||||
return 0; /* no match */
|
||||
|
||||
switch (sinfo->what) {
|
||||
case XT_CONNBYTES_PKTS:
|
||||
switch (sinfo->direction) {
|
||||
case XT_CONNBYTES_DIR_ORIGINAL:
|
||||
what = counters[IP_CT_DIR_ORIGINAL].packets;
|
||||
break;
|
||||
case XT_CONNBYTES_DIR_REPLY:
|
||||
what = counters[IP_CT_DIR_REPLY].packets;
|
||||
break;
|
||||
case XT_CONNBYTES_DIR_BOTH:
|
||||
what = counters[IP_CT_DIR_ORIGINAL].packets;
|
||||
what += counters[IP_CT_DIR_REPLY].packets;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case XT_CONNBYTES_BYTES:
|
||||
switch (sinfo->direction) {
|
||||
case XT_CONNBYTES_DIR_ORIGINAL:
|
||||
what = counters[IP_CT_DIR_ORIGINAL].bytes;
|
||||
break;
|
||||
case XT_CONNBYTES_DIR_REPLY:
|
||||
what = counters[IP_CT_DIR_REPLY].bytes;
|
||||
break;
|
||||
case XT_CONNBYTES_DIR_BOTH:
|
||||
what = counters[IP_CT_DIR_ORIGINAL].bytes;
|
||||
what += counters[IP_CT_DIR_REPLY].bytes;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case XT_CONNBYTES_AVGPKT:
|
||||
switch (sinfo->direction) {
|
||||
case XT_CONNBYTES_DIR_ORIGINAL:
|
||||
what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
|
||||
counters[IP_CT_DIR_ORIGINAL].packets);
|
||||
break;
|
||||
case XT_CONNBYTES_DIR_REPLY:
|
||||
what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
|
||||
counters[IP_CT_DIR_REPLY].packets);
|
||||
break;
|
||||
case XT_CONNBYTES_DIR_BOTH:
|
||||
{
|
||||
u_int64_t bytes;
|
||||
u_int64_t pkts;
|
||||
bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
|
||||
counters[IP_CT_DIR_REPLY].bytes;
|
||||
pkts = counters[IP_CT_DIR_ORIGINAL].packets+
|
||||
counters[IP_CT_DIR_REPLY].packets;
|
||||
|
||||
/* FIXME_THEORETICAL: what to do if sum
|
||||
* overflows ? */
|
||||
|
||||
what = div64_64(bytes, pkts);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sinfo->count.to)
|
||||
return (what <= sinfo->count.to && what >= sinfo->count.from);
|
||||
else
|
||||
return (what >= sinfo->count.from);
|
||||
}
|
||||
|
||||
static int check(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct xt_connbytes_info *sinfo = matchinfo;
|
||||
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info)))
|
||||
return 0;
|
||||
|
||||
if (sinfo->what != XT_CONNBYTES_PKTS &&
|
||||
sinfo->what != XT_CONNBYTES_BYTES &&
|
||||
sinfo->what != XT_CONNBYTES_AVGPKT)
|
||||
return 0;
|
||||
|
||||
if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
|
||||
sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
|
||||
sinfo->direction != XT_CONNBYTES_DIR_BOTH)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match connbytes_match = {
|
||||
.name = "connbytes",
|
||||
.match = &match,
|
||||
.checkentry = &check,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
static struct xt_match connbytes6_match = {
|
||||
.name = "connbytes",
|
||||
.match = &match,
|
||||
.checkentry = &check,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &connbytes_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &connbytes6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &connbytes_match);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &connbytes_match);
|
||||
xt_unregister_match(AF_INET6, &connbytes6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
109
net/netfilter/xt_connmark.c
Normal file
109
net/netfilter/xt_connmark.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/* 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");
|
||||
MODULE_ALIAS("ipt_connmark");
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_connmark.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_connmark_info *info = matchinfo;
|
||||
u_int32_t ctinfo;
|
||||
const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
|
||||
if (!ctmark)
|
||||
return 0;
|
||||
|
||||
return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_connmark_info *cm =
|
||||
(struct xt_connmark_info *)matchinfo;
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_connmark_info)))
|
||||
return 0;
|
||||
|
||||
if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
|
||||
printk(KERN_WARNING "connmark: only support 32bit mark\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match connmark_match = {
|
||||
.name = "connmark",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
static struct xt_match connmark6_match = {
|
||||
.name = "connmark",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
need_conntrack();
|
||||
|
||||
ret = xt_register_match(AF_INET, &connmark_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &connmark6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &connmark_match);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET6, &connmark6_match);
|
||||
xt_unregister_match(AF_INET, &connmark_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
238
net/netfilter/xt_conntrack.c
Normal file
238
net/netfilter/xt_conntrack.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/* Kernel module to match connection tracking information.
|
||||
* Superset of Rusty's minimalistic state match.
|
||||
*
|
||||
* (C) 2001 Marc Boucher (marc@mbsi.ca).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
|
||||
#else
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#endif
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_conntrack.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
|
||||
MODULE_DESCRIPTION("iptables connection tracking match module");
|
||||
MODULE_ALIAS("ipt_conntrack");
|
||||
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_conntrack_info *sinfo = matchinfo;
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
unsigned int statebit;
|
||||
|
||||
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
|
||||
|
||||
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
|
||||
|
||||
if (ct == &ip_conntrack_untracked)
|
||||
statebit = XT_CONNTRACK_STATE_UNTRACKED;
|
||||
else if (ct)
|
||||
statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
|
||||
else
|
||||
statebit = XT_CONNTRACK_STATE_INVALID;
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_STATE) {
|
||||
if (ct) {
|
||||
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
|
||||
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
|
||||
statebit |= XT_CONNTRACK_STATE_SNAT;
|
||||
|
||||
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
|
||||
ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
|
||||
statebit |= XT_CONNTRACK_STATE_DNAT;
|
||||
}
|
||||
|
||||
if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_PROTO) {
|
||||
if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_REPLDST) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_STATUS) {
|
||||
if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
|
||||
unsigned long expires;
|
||||
|
||||
if(!ct)
|
||||
return 0;
|
||||
|
||||
expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
|
||||
|
||||
if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IP_NF_CONNTRACK */
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_conntrack_info *sinfo = matchinfo;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
unsigned int statebit;
|
||||
|
||||
ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
|
||||
|
||||
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
|
||||
|
||||
if (ct == &nf_conntrack_untracked)
|
||||
statebit = XT_CONNTRACK_STATE_UNTRACKED;
|
||||
else if (ct)
|
||||
statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
|
||||
else
|
||||
statebit = XT_CONNTRACK_STATE_INVALID;
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_STATE) {
|
||||
if (ct) {
|
||||
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
|
||||
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
|
||||
statebit |= XT_CONNTRACK_STATE_SNAT;
|
||||
|
||||
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
|
||||
ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
|
||||
statebit |= XT_CONNTRACK_STATE_DNAT;
|
||||
}
|
||||
|
||||
if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_PROTO) {
|
||||
if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_REPLDST) {
|
||||
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_STATUS) {
|
||||
if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
|
||||
unsigned long expires;
|
||||
|
||||
if(!ct)
|
||||
return 0;
|
||||
|
||||
expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
|
||||
|
||||
if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NF_IP_CONNTRACK */
|
||||
|
||||
static int check(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match conntrack_match = {
|
||||
.name = "conntrack",
|
||||
.match = &match,
|
||||
.checkentry = &check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
need_conntrack();
|
||||
ret = xt_register_match(AF_INET, &conntrack_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &conntrack_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
221
net/netfilter/xt_dccp.c
Normal file
221
net/netfilter/xt_dccp.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* iptables module for DCCP protocol header matching
|
||||
*
|
||||
* (C) 2005 by Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/ip.h>
|
||||
#include <linux/dccp.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_dccp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("Match for DCCP protocol packets");
|
||||
MODULE_ALIAS("ipt_dccp");
|
||||
|
||||
#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
|
||||
|| (!!((invflag) & (option)) ^ (cond)))
|
||||
|
||||
static unsigned char *dccp_optbuf;
|
||||
static DEFINE_SPINLOCK(dccp_buflock);
|
||||
|
||||
static inline int
|
||||
dccp_find_option(u_int8_t option,
|
||||
const struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
const struct dccp_hdr *dh,
|
||||
int *hotdrop)
|
||||
{
|
||||
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
|
||||
unsigned char *op;
|
||||
unsigned int optoff = __dccp_hdr_len(dh);
|
||||
unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
|
||||
unsigned int i;
|
||||
|
||||
if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!optlen)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&dccp_buflock);
|
||||
op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf);
|
||||
if (op == NULL) {
|
||||
/* If we don't have the whole header, drop packet. */
|
||||
spin_unlock_bh(&dccp_buflock);
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < optlen; ) {
|
||||
if (op[i] == option) {
|
||||
spin_unlock_bh(&dccp_buflock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (op[i] < 2)
|
||||
i++;
|
||||
else
|
||||
i += op[i+1]?:1;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dccp_buflock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
match_types(const struct dccp_hdr *dh, u_int16_t typemask)
|
||||
{
|
||||
return (typemask & (1 << dh->dccph_type));
|
||||
}
|
||||
|
||||
static inline int
|
||||
match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff,
|
||||
const struct dccp_hdr *dh, int *hotdrop)
|
||||
{
|
||||
return dccp_find_option(option, skb, protoff, dh, hotdrop);
|
||||
}
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_dccp_info *info =
|
||||
(const struct xt_dccp_info *)matchinfo;
|
||||
struct dccp_hdr _dh, *dh;
|
||||
|
||||
if (offset)
|
||||
return 0;
|
||||
|
||||
dh = skb_header_pointer(skb, protoff, sizeof(_dh), &_dh);
|
||||
if (dh == NULL) {
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0])
|
||||
&& (ntohs(dh->dccph_sport) <= info->spts[1])),
|
||||
XT_DCCP_SRC_PORTS, info->flags, info->invflags)
|
||||
&& DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0])
|
||||
&& (ntohs(dh->dccph_dport) <= info->dpts[1])),
|
||||
XT_DCCP_DEST_PORTS, info->flags, info->invflags)
|
||||
&& DCCHECK(match_types(dh, info->typemask),
|
||||
XT_DCCP_TYPE, info->flags, info->invflags)
|
||||
&& DCCHECK(match_option(info->option, skb, protoff, dh,
|
||||
hotdrop),
|
||||
XT_DCCP_OPTION, info->flags, info->invflags);
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *inf,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ipt_ip *ip = inf;
|
||||
const struct xt_dccp_info *info;
|
||||
|
||||
info = (const struct xt_dccp_info *)matchinfo;
|
||||
|
||||
return ip->proto == IPPROTO_DCCP
|
||||
&& !(ip->invflags & XT_INV_PROTO)
|
||||
&& matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
|
||||
&& !(info->flags & ~XT_DCCP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~XT_DCCP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~info->flags);
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry6(const char *tablename,
|
||||
const void *inf,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ip6t_ip6 *ip = inf;
|
||||
const struct xt_dccp_info *info;
|
||||
|
||||
info = (const struct xt_dccp_info *)matchinfo;
|
||||
|
||||
return ip->proto == IPPROTO_DCCP
|
||||
&& !(ip->invflags & XT_INV_PROTO)
|
||||
&& matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
|
||||
&& !(info->flags & ~XT_DCCP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~XT_DCCP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~info->flags);
|
||||
}
|
||||
|
||||
|
||||
static struct xt_match dccp_match =
|
||||
{
|
||||
.name = "dccp",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match dccp6_match =
|
||||
{
|
||||
.name = "dccp",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry6,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* doff is 8 bits, so the maximum option size is (4*256). Don't put
|
||||
* this in BSS since DaveM is worried about locked TLB's for kernel
|
||||
* BSS. */
|
||||
dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
|
||||
if (!dccp_optbuf)
|
||||
return -ENOMEM;
|
||||
ret = xt_register_match(AF_INET, &dccp_match);
|
||||
if (ret)
|
||||
goto out_kfree;
|
||||
ret = xt_register_match(AF_INET6, &dccp6_match);
|
||||
if (ret)
|
||||
goto out_unreg;
|
||||
|
||||
return ret;
|
||||
|
||||
out_unreg:
|
||||
xt_unregister_match(AF_INET, &dccp_match);
|
||||
out_kfree:
|
||||
kfree(dccp_optbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET6, &dccp6_match);
|
||||
xt_unregister_match(AF_INET, &dccp_match);
|
||||
kfree(dccp_optbuf);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
188
net/netfilter/xt_helper.c
Normal file
188
net/netfilter/xt_helper.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/* iptables module to match on related connections */
|
||||
/*
|
||||
* (C) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
|
||||
* - Port to newnat infrastructure
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter.h>
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#else
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
#include <net/netfilter/nf_conntrack_helper.h>
|
||||
#endif
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_helper.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
|
||||
MODULE_DESCRIPTION("iptables helper match module");
|
||||
MODULE_ALIAS("ipt_helper");
|
||||
MODULE_ALIAS("ip6t_helper");
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_helper_info *info = matchinfo;
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
int ret = info->invert;
|
||||
|
||||
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
|
||||
if (!ct) {
|
||||
DEBUGP("xt_helper: Eek! invalid conntrack?\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ct->master) {
|
||||
DEBUGP("xt_helper: conntrack %p has no master\n", ct);
|
||||
return ret;
|
||||
}
|
||||
|
||||
read_lock_bh(&ip_conntrack_lock);
|
||||
if (!ct->master->helper) {
|
||||
DEBUGP("xt_helper: master ct %p has no helper\n",
|
||||
exp->expectant);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
DEBUGP("master's name = %s , info->name = %s\n",
|
||||
ct->master->helper->name, info->name);
|
||||
|
||||
if (info->name[0] == '\0')
|
||||
ret ^= 1;
|
||||
else
|
||||
ret ^= !strncmp(ct->master->helper->name, info->name,
|
||||
strlen(ct->master->helper->name));
|
||||
out_unlock:
|
||||
read_unlock_bh(&ip_conntrack_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IP_NF_CONNTRACK */
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_helper_info *info = matchinfo;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
int ret = info->invert;
|
||||
|
||||
ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
|
||||
if (!ct) {
|
||||
DEBUGP("xt_helper: Eek! invalid conntrack?\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ct->master) {
|
||||
DEBUGP("xt_helper: conntrack %p has no master\n", ct);
|
||||
return ret;
|
||||
}
|
||||
|
||||
read_lock_bh(&nf_conntrack_lock);
|
||||
if (!ct->master->helper) {
|
||||
DEBUGP("xt_helper: master ct %p has no helper\n",
|
||||
exp->expectant);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
DEBUGP("master's name = %s , info->name = %s\n",
|
||||
ct->master->helper->name, info->name);
|
||||
|
||||
if (info->name[0] == '\0')
|
||||
ret ^= 1;
|
||||
else
|
||||
ret ^= !strncmp(ct->master->helper->name, info->name,
|
||||
strlen(ct->master->helper->name));
|
||||
out_unlock:
|
||||
read_unlock_bh(&nf_conntrack_lock);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check(const char *tablename,
|
||||
const void *inf,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_helper_info *info = matchinfo;
|
||||
|
||||
info->name[29] = '\0';
|
||||
|
||||
/* verify size */
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match helper_match = {
|
||||
.name = "helper",
|
||||
.match = &match,
|
||||
.checkentry = &check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match helper6_match = {
|
||||
.name = "helper",
|
||||
.match = &match,
|
||||
.checkentry = &check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
need_conntrack();
|
||||
|
||||
ret = xt_register_match(AF_INET, &helper_match);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &helper6_match);
|
||||
if (ret < 0)
|
||||
xt_unregister_match(AF_INET, &helper_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &helper_match);
|
||||
xt_unregister_match(AF_INET6, &helper6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
||||
|
98
net/netfilter/xt_length.c
Normal file
98
net/netfilter/xt_length.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/* Kernel module to match packet length. */
|
||||
/* (C) 1999-2001 James Morris <jmorros@intercode.com.au>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#include <linux/netfilter/xt_length.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
|
||||
MODULE_DESCRIPTION("IP tables packet length matching module");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_length");
|
||||
MODULE_ALIAS("ip6t_length");
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_length_info *info = matchinfo;
|
||||
u_int16_t pktlen = ntohs(skb->nh.iph->tot_len);
|
||||
|
||||
return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
|
||||
}
|
||||
|
||||
static int
|
||||
match6(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_length_info *info = matchinfo;
|
||||
u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
|
||||
|
||||
return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_length_info)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match length_match = {
|
||||
.name = "length",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match length6_match = {
|
||||
.name = "length",
|
||||
.match = &match6,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &length_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = xt_register_match(AF_INET6, &length6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &length_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &length_match);
|
||||
xt_unregister_match(AF_INET6, &length6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
175
net/netfilter/xt_limit.c
Normal file
175
net/netfilter/xt_limit.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/* Kernel module to control the rate
|
||||
*
|
||||
* 2 September 1999: Changed from the target RATE to the match
|
||||
* `limit', removed logging. Did I mention that
|
||||
* Alexey is a fucking genius?
|
||||
* Rusty Russell (rusty@rustcorp.com.au). */
|
||||
|
||||
/* (C) 1999 J<>r<EFBFBD>me de Vivie <devivie@info.enserb.u-bordeaux.fr>
|
||||
* (C) 1999 Herv<72> Eychenne <eychenne@info.enserb.u-bordeaux.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_limit.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
|
||||
MODULE_DESCRIPTION("iptables rate limit match");
|
||||
MODULE_ALIAS("ipt_limit");
|
||||
MODULE_ALIAS("ip6t_limit");
|
||||
|
||||
/* The algorithm used is the Simple Token Bucket Filter (TBF)
|
||||
* see net/sched/sch_tbf.c in the linux source tree
|
||||
*/
|
||||
|
||||
static DEFINE_SPINLOCK(limit_lock);
|
||||
|
||||
/* Rusty: This is my (non-mathematically-inclined) understanding of
|
||||
this algorithm. The `average rate' in jiffies becomes your initial
|
||||
amount of credit `credit' and the most credit you can ever have
|
||||
`credit_cap'. The `peak rate' becomes the cost of passing the
|
||||
test, `cost'.
|
||||
|
||||
`prev' tracks the last packet hit: you gain one credit per jiffy.
|
||||
If you get credit balance more than this, the extra credit is
|
||||
discarded. Every time the match passes, you lose `cost' credits;
|
||||
if you don't have that many, the test fails.
|
||||
|
||||
See Alexey's formal explanation in net/sched/sch_tbf.c.
|
||||
|
||||
To get the maxmum range, we multiply by this factor (ie. you get N
|
||||
credits per jiffy). We want to allow a rate as low as 1 per day
|
||||
(slowest userspace tool allows), which means
|
||||
CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */
|
||||
#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
|
||||
|
||||
/* Repeated shift and or gives us all 1s, final shift and add 1 gives
|
||||
* us the power of 2 below the theoretical max, so GCC simply does a
|
||||
* shift. */
|
||||
#define _POW2_BELOW2(x) ((x)|((x)>>1))
|
||||
#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
|
||||
#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
|
||||
#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
|
||||
#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
|
||||
#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
|
||||
|
||||
#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
|
||||
|
||||
static int
|
||||
ipt_limit_match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
struct xt_rateinfo *r = ((struct xt_rateinfo *)matchinfo)->master;
|
||||
unsigned long now = jiffies;
|
||||
|
||||
spin_lock_bh(&limit_lock);
|
||||
r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY;
|
||||
if (r->credit > r->credit_cap)
|
||||
r->credit = r->credit_cap;
|
||||
|
||||
if (r->credit >= r->cost) {
|
||||
/* We're not limited. */
|
||||
r->credit -= r->cost;
|
||||
spin_unlock_bh(&limit_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&limit_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Precision saver. */
|
||||
static u_int32_t
|
||||
user2credits(u_int32_t user)
|
||||
{
|
||||
/* If multiplying would overflow... */
|
||||
if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
|
||||
/* Divide first. */
|
||||
return (user / XT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
|
||||
|
||||
return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE;
|
||||
}
|
||||
|
||||
static int
|
||||
ipt_limit_checkentry(const char *tablename,
|
||||
const void *inf,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_rateinfo *r = matchinfo;
|
||||
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_rateinfo)))
|
||||
return 0;
|
||||
|
||||
/* Check for overflow. */
|
||||
if (r->burst == 0
|
||||
|| user2credits(r->avg * r->burst) < user2credits(r->avg)) {
|
||||
printk("Overflow in xt_limit, try lower: %u/%u\n",
|
||||
r->avg, r->burst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
|
||||
128. */
|
||||
r->prev = jiffies;
|
||||
r->credit = user2credits(r->avg * r->burst); /* Credits full. */
|
||||
r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
|
||||
r->cost = user2credits(r->avg);
|
||||
|
||||
/* For SMP, we only want to use one set of counters. */
|
||||
r->master = r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match ipt_limit_reg = {
|
||||
.name = "limit",
|
||||
.match = ipt_limit_match,
|
||||
.checkentry = ipt_limit_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match limit6_reg = {
|
||||
.name = "limit",
|
||||
.match = ipt_limit_match,
|
||||
.checkentry = ipt_limit_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xt_register_match(AF_INET, &ipt_limit_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &limit6_reg);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &ipt_limit_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &ipt_limit_reg);
|
||||
xt_unregister_match(AF_INET6, &limit6_reg);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
100
net/netfilter/xt_mac.c
Normal file
100
net/netfilter/xt_mac.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* Kernel module to match MAC address parameters. */
|
||||
|
||||
/* (C) 1999-2001 Paul `Rusty' Russell
|
||||
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/xt_mac.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
|
||||
MODULE_DESCRIPTION("iptables mac matching module");
|
||||
MODULE_ALIAS("ipt_mac");
|
||||
MODULE_ALIAS("ip6t_mac");
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_mac_info *info = matchinfo;
|
||||
|
||||
/* Is mac pointer valid? */
|
||||
return (skb->mac.raw >= skb->head
|
||||
&& (skb->mac.raw + ETH_HLEN) <= skb->data
|
||||
/* If so, compare... */
|
||||
&& ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
|
||||
^ info->invert));
|
||||
}
|
||||
|
||||
static int
|
||||
ipt_mac_checkentry(const char *tablename,
|
||||
const void *inf,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
/* FORWARD isn't always valid, but it's nice to be able to do --RR */
|
||||
if (hook_mask
|
||||
& ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
|
||||
| (1 << NF_IP_FORWARD))) {
|
||||
printk("xt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_mac_info)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match mac_match = {
|
||||
.name = "mac",
|
||||
.match = &match,
|
||||
.checkentry = &ipt_mac_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match mac6_match = {
|
||||
.name = "mac",
|
||||
.match = &match,
|
||||
.checkentry = &ipt_mac_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &mac_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &mac6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &mac_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &mac_match);
|
||||
xt_unregister_match(AF_INET6, &mac6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
91
net/netfilter/xt_mark.c
Normal file
91
net/netfilter/xt_mark.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/* Kernel module to match NFMARK values. */
|
||||
|
||||
/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter/xt_mark.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
|
||||
MODULE_DESCRIPTION("iptables mark matching module");
|
||||
MODULE_ALIAS("ipt_mark");
|
||||
MODULE_ALIAS("ip6t_mark");
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_mark_info *info = matchinfo;
|
||||
|
||||
return ((skb->nfmark & info->mask) == info->mark) ^ info->invert;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo;
|
||||
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_mark_info)))
|
||||
return 0;
|
||||
|
||||
if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
|
||||
printk(KERN_WARNING "mark: only supports 32bit mark\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match mark_match = {
|
||||
.name = "mark",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct xt_match mark6_match = {
|
||||
.name = "mark",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &mark_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &mark6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &mark_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &mark_match);
|
||||
xt_unregister_match(AF_INET6, &mark6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
155
net/netfilter/xt_physdev.c
Normal file
155
net/netfilter/xt_physdev.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/* Kernel module to match the bridge port in and
|
||||
* out device for IP packets coming into contact with a bridge. */
|
||||
|
||||
/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter/xt_physdev.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#define MATCH 1
|
||||
#define NOMATCH 0
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
|
||||
MODULE_DESCRIPTION("iptables bridge physical device match module");
|
||||
MODULE_ALIAS("ipt_physdev");
|
||||
MODULE_ALIAS("ip6t_physdev");
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
int i;
|
||||
static const char nulldevname[IFNAMSIZ];
|
||||
const struct xt_physdev_info *info = matchinfo;
|
||||
unsigned int ret;
|
||||
const char *indev, *outdev;
|
||||
struct nf_bridge_info *nf_bridge;
|
||||
|
||||
/* Not a bridged IP packet or no info available yet:
|
||||
* LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
|
||||
* the destination device will be a bridge. */
|
||||
if (!(nf_bridge = skb->nf_bridge)) {
|
||||
/* Return MATCH if the invert flags of the used options are on */
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
|
||||
!(info->invert & XT_PHYSDEV_OP_BRIDGED))
|
||||
return NOMATCH;
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
|
||||
!(info->invert & XT_PHYSDEV_OP_ISIN))
|
||||
return NOMATCH;
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
|
||||
!(info->invert & XT_PHYSDEV_OP_ISOUT))
|
||||
return NOMATCH;
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
|
||||
!(info->invert & XT_PHYSDEV_OP_IN))
|
||||
return NOMATCH;
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
|
||||
!(info->invert & XT_PHYSDEV_OP_OUT))
|
||||
return NOMATCH;
|
||||
return MATCH;
|
||||
}
|
||||
|
||||
/* This only makes sense in the FORWARD and POSTROUTING chains */
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
|
||||
(!!(nf_bridge->mask & BRNF_BRIDGED) ^
|
||||
!(info->invert & XT_PHYSDEV_OP_BRIDGED)))
|
||||
return NOMATCH;
|
||||
|
||||
if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
|
||||
(!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
|
||||
(info->bitmask & XT_PHYSDEV_OP_ISOUT &&
|
||||
(!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
|
||||
return NOMATCH;
|
||||
|
||||
if (!(info->bitmask & XT_PHYSDEV_OP_IN))
|
||||
goto match_outdev;
|
||||
indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
|
||||
ret |= (((const unsigned int *)indev)[i]
|
||||
^ ((const unsigned int *)info->physindev)[i])
|
||||
& ((const unsigned int *)info->in_mask)[i];
|
||||
}
|
||||
|
||||
if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN))
|
||||
return NOMATCH;
|
||||
|
||||
match_outdev:
|
||||
if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
|
||||
return MATCH;
|
||||
outdev = nf_bridge->physoutdev ?
|
||||
nf_bridge->physoutdev->name : nulldevname;
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
|
||||
ret |= (((const unsigned int *)outdev)[i]
|
||||
^ ((const unsigned int *)info->physoutdev)[i])
|
||||
& ((const unsigned int *)info->out_mask)[i];
|
||||
}
|
||||
|
||||
return (ret != 0) ^ !(info->invert & XT_PHYSDEV_OP_OUT);
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct xt_physdev_info *info = matchinfo;
|
||||
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info)))
|
||||
return 0;
|
||||
if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
|
||||
info->bitmask & ~XT_PHYSDEV_OP_MASK)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match physdev_match = {
|
||||
.name = "physdev",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct xt_match physdev6_match = {
|
||||
.name = "physdev",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xt_register_match(AF_INET, &physdev_match);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &physdev6_match);
|
||||
if (ret < 0)
|
||||
xt_unregister_match(AF_INET, &physdev_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &physdev_match);
|
||||
xt_unregister_match(AF_INET6, &physdev6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
82
net/netfilter/xt_pkttype.c
Normal file
82
net/netfilter/xt_pkttype.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/* (C) 1999-2001 Michal Ludvig <michal@logix.cz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include <linux/netfilter/xt_pkttype.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michal Ludvig <michal@logix.cz>");
|
||||
MODULE_DESCRIPTION("IP tables match to match on linklayer packet type");
|
||||
MODULE_ALIAS("ipt_pkttype");
|
||||
MODULE_ALIAS("ip6t_pkttype");
|
||||
|
||||
static int match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_pkttype_info *info = matchinfo;
|
||||
|
||||
return (skb->pkt_type == info->pkttype) ^ info->invert;
|
||||
}
|
||||
|
||||
static int checkentry(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_pkttype_info)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match pkttype_match = {
|
||||
.name = "pkttype",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match pkttype6_match = {
|
||||
.name = "pkttype",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &pkttype_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &pkttype6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &pkttype_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &pkttype_match);
|
||||
xt_unregister_match(AF_INET6, &pkttype6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
79
net/netfilter/xt_realm.c
Normal file
79
net/netfilter/xt_realm.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/* IP tables module for matching the routing realm
|
||||
*
|
||||
* $Id: ipt_realm.c,v 1.3 2004/03/05 13:25:40 laforge Exp $
|
||||
*
|
||||
* (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/xt_realm.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("X_tables realm match");
|
||||
MODULE_ALIAS("ipt_realm");
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_realm_info *info = matchinfo;
|
||||
struct dst_entry *dst = skb->dst;
|
||||
|
||||
return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
|
||||
}
|
||||
|
||||
static int check(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (hook_mask
|
||||
& ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
|
||||
(1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) {
|
||||
printk("xt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
|
||||
"LOCAL_IN or FORWARD.\n");
|
||||
return 0;
|
||||
}
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_realm_info))) {
|
||||
printk("xt_realm: invalid matchsize.\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match realm_match = {
|
||||
.name = "realm",
|
||||
.match = match,
|
||||
.checkentry = check,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
return xt_register_match(AF_INET, &realm_match);
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &realm_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
250
net/netfilter/xt_sctp.c
Normal file
250
net/netfilter/xt_sctp.c
Normal file
@@ -0,0 +1,250 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/sctp.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_sctp.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kiran Kumar Immidi");
|
||||
MODULE_DESCRIPTION("Match for SCTP protocol packets");
|
||||
MODULE_ALIAS("ipt_sctp");
|
||||
|
||||
#ifdef DEBUG_SCTP
|
||||
#define duprintf(format, args...) printk(format , ## args)
|
||||
#else
|
||||
#define duprintf(format, args...)
|
||||
#endif
|
||||
|
||||
#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
|
||||
|| (!!((invflag) & (option)) ^ (cond)))
|
||||
|
||||
static int
|
||||
match_flags(const struct xt_sctp_flag_info *flag_info,
|
||||
const int flag_count,
|
||||
u_int8_t chunktype,
|
||||
u_int8_t chunkflags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < flag_count; i++) {
|
||||
if (flag_info[i].chunktype == chunktype) {
|
||||
return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
match_packet(const struct sk_buff *skb,
|
||||
unsigned int offset,
|
||||
const u_int32_t *chunkmap,
|
||||
int chunk_match_type,
|
||||
const struct xt_sctp_flag_info *flag_info,
|
||||
const int flag_count,
|
||||
int *hotdrop)
|
||||
{
|
||||
u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
|
||||
sctp_chunkhdr_t _sch, *sch;
|
||||
|
||||
#ifdef DEBUG_SCTP
|
||||
int i = 0;
|
||||
#endif
|
||||
|
||||
if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
|
||||
SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
|
||||
}
|
||||
|
||||
do {
|
||||
sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
|
||||
if (sch == NULL) {
|
||||
duprintf("Dropping invalid SCTP packet.\n");
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
|
||||
++i, offset, sch->type, htons(sch->length), sch->flags);
|
||||
|
||||
offset += (htons(sch->length) + 3) & ~3;
|
||||
|
||||
duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
|
||||
|
||||
if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) {
|
||||
switch (chunk_match_type) {
|
||||
case SCTP_CHUNK_MATCH_ANY:
|
||||
if (match_flags(flag_info, flag_count,
|
||||
sch->type, sch->flags)) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCTP_CHUNK_MATCH_ALL:
|
||||
if (match_flags(flag_info, flag_count,
|
||||
sch->type, sch->flags)) {
|
||||
SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCTP_CHUNK_MATCH_ONLY:
|
||||
if (!match_flags(flag_info, flag_count,
|
||||
sch->type, sch->flags)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (chunk_match_type) {
|
||||
case SCTP_CHUNK_MATCH_ONLY:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (offset < skb->len);
|
||||
|
||||
switch (chunk_match_type) {
|
||||
case SCTP_CHUNK_MATCH_ALL:
|
||||
return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
|
||||
case SCTP_CHUNK_MATCH_ANY:
|
||||
return 0;
|
||||
case SCTP_CHUNK_MATCH_ONLY:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This will never be reached, but required to stop compiler whine */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_sctp_info *info;
|
||||
sctp_sctphdr_t _sh, *sh;
|
||||
|
||||
info = (const struct xt_sctp_info *)matchinfo;
|
||||
|
||||
if (offset) {
|
||||
duprintf("Dropping non-first fragment.. FIXME\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sh = skb_header_pointer(skb, protoff, sizeof(_sh), &_sh);
|
||||
if (sh == NULL) {
|
||||
duprintf("Dropping evil TCP offset=0 tinygram.\n");
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
|
||||
|
||||
return SCCHECK(((ntohs(sh->source) >= info->spts[0])
|
||||
&& (ntohs(sh->source) <= info->spts[1])),
|
||||
XT_SCTP_SRC_PORTS, info->flags, info->invflags)
|
||||
&& SCCHECK(((ntohs(sh->dest) >= info->dpts[0])
|
||||
&& (ntohs(sh->dest) <= info->dpts[1])),
|
||||
XT_SCTP_DEST_PORTS, info->flags, info->invflags)
|
||||
&& SCCHECK(match_packet(skb, protoff,
|
||||
info->chunkmap, info->chunk_match_type,
|
||||
info->flag_info, info->flag_count,
|
||||
hotdrop),
|
||||
XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *inf,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct xt_sctp_info *info;
|
||||
const struct ipt_ip *ip = inf;
|
||||
|
||||
info = (const struct xt_sctp_info *)matchinfo;
|
||||
|
||||
return ip->proto == IPPROTO_SCTP
|
||||
&& !(ip->invflags & XT_INV_PROTO)
|
||||
&& matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
|
||||
&& !(info->flags & ~XT_SCTP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~XT_SCTP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~info->flags)
|
||||
&& ((!(info->flags & XT_SCTP_CHUNK_TYPES)) ||
|
||||
(info->chunk_match_type &
|
||||
(SCTP_CHUNK_MATCH_ALL
|
||||
| SCTP_CHUNK_MATCH_ANY
|
||||
| SCTP_CHUNK_MATCH_ONLY)));
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry6(const char *tablename,
|
||||
const void *inf,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct xt_sctp_info *info;
|
||||
const struct ip6t_ip6 *ip = inf;
|
||||
|
||||
info = (const struct xt_sctp_info *)matchinfo;
|
||||
|
||||
return ip->proto == IPPROTO_SCTP
|
||||
&& !(ip->invflags & XT_INV_PROTO)
|
||||
&& matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
|
||||
&& !(info->flags & ~XT_SCTP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~XT_SCTP_VALID_FLAGS)
|
||||
&& !(info->invflags & ~info->flags)
|
||||
&& ((!(info->flags & XT_SCTP_CHUNK_TYPES)) ||
|
||||
(info->chunk_match_type &
|
||||
(SCTP_CHUNK_MATCH_ALL
|
||||
| SCTP_CHUNK_MATCH_ANY
|
||||
| SCTP_CHUNK_MATCH_ONLY)));
|
||||
}
|
||||
|
||||
|
||||
static struct xt_match sctp_match =
|
||||
{
|
||||
.name = "sctp",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
static struct xt_match sctp6_match =
|
||||
{
|
||||
.name = "sctp",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry6,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &sctp_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &sctp6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &sctp_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET6, &sctp6_match);
|
||||
xt_unregister_match(AF_INET, &sctp_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
96
net/netfilter/xt_state.c
Normal file
96
net/netfilter/xt_state.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/* Kernel module to match connection tracking information. */
|
||||
|
||||
/* (C) 1999-2001 Paul `Rusty' Russell
|
||||
* (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_state.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
|
||||
MODULE_DESCRIPTION("ip[6]_tables connection tracking state match module");
|
||||
MODULE_ALIAS("ipt_state");
|
||||
MODULE_ALIAS("ip6t_state");
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_state_info *sinfo = matchinfo;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
unsigned int statebit;
|
||||
|
||||
if (nf_ct_is_untracked(skb))
|
||||
statebit = XT_STATE_UNTRACKED;
|
||||
else if (!nf_ct_get_ctinfo(skb, &ctinfo))
|
||||
statebit = XT_STATE_INVALID;
|
||||
else
|
||||
statebit = XT_STATE_BIT(ctinfo);
|
||||
|
||||
return (sinfo->statemask & statebit);
|
||||
}
|
||||
|
||||
static int check(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_state_info)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match state_match = {
|
||||
.name = "state",
|
||||
.match = &match,
|
||||
.checkentry = &check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct xt_match state6_match = {
|
||||
.name = "state",
|
||||
.match = &match,
|
||||
.checkentry = &check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
need_conntrack();
|
||||
|
||||
ret = xt_register_match(AF_INET, &state_match);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &state6_match);
|
||||
if (ret < 0)
|
||||
xt_unregister_match(AF_INET,&state_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &state_match);
|
||||
xt_unregister_match(AF_INET6, &state6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
111
net/netfilter/xt_string.c
Normal file
111
net/netfilter/xt_string.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/* String matching match for iptables
|
||||
*
|
||||
* (C) 2005 Pablo Neira Ayuso <pablo@eurodev.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_string.h>
|
||||
#include <linux/textsearch.h>
|
||||
|
||||
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@eurodev.net>");
|
||||
MODULE_DESCRIPTION("IP tables string match module");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_string");
|
||||
MODULE_ALIAS("ip6t_string");
|
||||
|
||||
static int match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
struct ts_state state;
|
||||
struct xt_string_info *conf = (struct xt_string_info *) matchinfo;
|
||||
|
||||
memset(&state, 0, sizeof(struct ts_state));
|
||||
|
||||
return (skb_find_text((struct sk_buff *)skb, conf->from_offset,
|
||||
conf->to_offset, conf->config, &state)
|
||||
!= UINT_MAX) && !conf->invert;
|
||||
}
|
||||
|
||||
#define STRING_TEXT_PRIV(m) ((struct xt_string_info *) m)
|
||||
|
||||
static int checkentry(const char *tablename,
|
||||
const void *ip,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct xt_string_info *conf = matchinfo;
|
||||
struct ts_config *ts_conf;
|
||||
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_string_info)))
|
||||
return 0;
|
||||
|
||||
/* Damn, can't handle this case properly with iptables... */
|
||||
if (conf->from_offset > conf->to_offset)
|
||||
return 0;
|
||||
|
||||
ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
|
||||
GFP_KERNEL, TS_AUTOLOAD);
|
||||
if (IS_ERR(ts_conf))
|
||||
return 0;
|
||||
|
||||
conf->config = ts_conf;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void destroy(void *matchinfo, unsigned int matchsize)
|
||||
{
|
||||
textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
|
||||
}
|
||||
|
||||
static struct xt_match string_match = {
|
||||
.name = "string",
|
||||
.match = match,
|
||||
.checkentry = checkentry,
|
||||
.destroy = destroy,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
static struct xt_match string6_match = {
|
||||
.name = "string",
|
||||
.match = match,
|
||||
.checkentry = checkentry,
|
||||
.destroy = destroy,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xt_register_match(AF_INET, &string_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = xt_register_match(AF_INET6, &string6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &string_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET, &string_match);
|
||||
xt_unregister_match(AF_INET6, &string6_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
172
net/netfilter/xt_tcpmss.c
Normal file
172
net/netfilter/xt_tcpmss.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/* Kernel module to match TCP MSS values. */
|
||||
|
||||
/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
|
||||
* Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter/xt_tcpmss.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
|
||||
#define TH_SYN 0x02
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
|
||||
MODULE_DESCRIPTION("iptables TCP MSS match module");
|
||||
MODULE_ALIAS("ipt_tcpmss");
|
||||
|
||||
/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */
|
||||
static inline int
|
||||
mssoption_match(u_int16_t min, u_int16_t max,
|
||||
const struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
int invert,
|
||||
int *hotdrop)
|
||||
{
|
||||
struct tcphdr _tcph, *th;
|
||||
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
|
||||
u8 _opt[15 * 4 - sizeof(_tcph)], *op;
|
||||
unsigned int i, optlen;
|
||||
|
||||
/* If we don't have the whole header, drop packet. */
|
||||
th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
goto dropit;
|
||||
|
||||
/* Malformed. */
|
||||
if (th->doff*4 < sizeof(*th))
|
||||
goto dropit;
|
||||
|
||||
optlen = th->doff*4 - sizeof(*th);
|
||||
if (!optlen)
|
||||
goto out;
|
||||
|
||||
/* Truncated options. */
|
||||
op = skb_header_pointer(skb, protoff + sizeof(*th), optlen, _opt);
|
||||
if (op == NULL)
|
||||
goto dropit;
|
||||
|
||||
for (i = 0; i < optlen; ) {
|
||||
if (op[i] == TCPOPT_MSS
|
||||
&& (optlen - i) >= TCPOLEN_MSS
|
||||
&& op[i+1] == TCPOLEN_MSS) {
|
||||
u_int16_t mssval;
|
||||
|
||||
mssval = (op[i+2] << 8) | op[i+3];
|
||||
|
||||
return (mssval >= min && mssval <= max) ^ invert;
|
||||
}
|
||||
if (op[i] < 2) i++;
|
||||
else i += op[i+1]?:1;
|
||||
}
|
||||
out:
|
||||
return invert;
|
||||
|
||||
dropit:
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_tcpmss_match_info *info = matchinfo;
|
||||
|
||||
return mssoption_match(info->mss_min, info->mss_max, skb, protoff,
|
||||
info->invert, hotdrop);
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *ipinfo,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ipt_ip *ip = ipinfo;
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
|
||||
return 0;
|
||||
|
||||
/* Must specify -p tcp */
|
||||
if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
|
||||
printk("tcpmss: Only works on TCP packets\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
checkentry6(const char *tablename,
|
||||
const void *ipinfo,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ip6t_ip6 *ip = ipinfo;
|
||||
|
||||
if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
|
||||
return 0;
|
||||
|
||||
/* Must specify -p tcp */
|
||||
if (ip->proto != IPPROTO_TCP || (ip->invflags & XT_INV_PROTO)) {
|
||||
printk("tcpmss: Only works on TCP packets\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match tcpmss_match = {
|
||||
.name = "tcpmss",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct xt_match tcpmss6_match = {
|
||||
.name = "tcpmss",
|
||||
.match = &match,
|
||||
.checkentry = &checkentry6,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &tcpmss_match);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &tcpmss6_match);
|
||||
if (ret)
|
||||
xt_unregister_match(AF_INET, &tcpmss_match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET6, &tcpmss6_match);
|
||||
xt_unregister_match(AF_INET, &tcpmss_match);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
333
net/netfilter/xt_tcpudp.c
Normal file
333
net/netfilter/xt_tcpudp.c
Normal file
@@ -0,0 +1,333 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/udp.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_tcpudp.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
|
||||
MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("xt_tcp");
|
||||
MODULE_ALIAS("xt_udp");
|
||||
MODULE_ALIAS("ipt_udp");
|
||||
MODULE_ALIAS("ipt_tcp");
|
||||
MODULE_ALIAS("ip6t_udp");
|
||||
MODULE_ALIAS("ip6t_tcp");
|
||||
|
||||
#ifdef DEBUG_IP_FIREWALL_USER
|
||||
#define duprintf(format, args...) printk(format , ## args)
|
||||
#else
|
||||
#define duprintf(format, args...)
|
||||
#endif
|
||||
|
||||
|
||||
/* Returns 1 if the port is matched by the range, 0 otherwise */
|
||||
static inline int
|
||||
port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = (port >= min && port <= max) ^ invert;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
tcp_find_option(u_int8_t option,
|
||||
const struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int optlen,
|
||||
int invert,
|
||||
int *hotdrop)
|
||||
{
|
||||
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
|
||||
u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
|
||||
unsigned int i;
|
||||
|
||||
duprintf("tcp_match: finding option\n");
|
||||
|
||||
if (!optlen)
|
||||
return invert;
|
||||
|
||||
/* If we don't have the whole header, drop packet. */
|
||||
op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr),
|
||||
optlen, _opt);
|
||||
if (op == NULL) {
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < optlen; ) {
|
||||
if (op[i] == option) return !invert;
|
||||
if (op[i] < 2) i++;
|
||||
else i += op[i+1]?:1;
|
||||
}
|
||||
|
||||
return invert;
|
||||
}
|
||||
|
||||
static int
|
||||
tcp_match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
struct tcphdr _tcph, *th;
|
||||
const struct xt_tcp *tcpinfo = matchinfo;
|
||||
|
||||
if (offset) {
|
||||
/* To quote Alan:
|
||||
|
||||
Don't allow a fragment of TCP 8 bytes in. Nobody normal
|
||||
causes this. Its a cracker trying to break in by doing a
|
||||
flag overwrite to pass the direction checks.
|
||||
*/
|
||||
if (offset == 1) {
|
||||
duprintf("Dropping evil TCP offset=1 frag.\n");
|
||||
*hotdrop = 1;
|
||||
}
|
||||
/* Must not be a fragment. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
|
||||
|
||||
th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
|
||||
if (th == NULL) {
|
||||
/* We've been asked to examine this packet, and we
|
||||
can't. Hence, no choice but to drop. */
|
||||
duprintf("Dropping evil TCP offset=0 tinygram.\n");
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
|
||||
ntohs(th->source),
|
||||
!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
|
||||
return 0;
|
||||
if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
|
||||
ntohs(th->dest),
|
||||
!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
|
||||
return 0;
|
||||
if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
|
||||
== tcpinfo->flg_cmp,
|
||||
XT_TCP_INV_FLAGS))
|
||||
return 0;
|
||||
if (tcpinfo->option) {
|
||||
if (th->doff * 4 < sizeof(_tcph)) {
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!tcp_find_option(tcpinfo->option, skb, protoff,
|
||||
th->doff*4 - sizeof(_tcph),
|
||||
tcpinfo->invflags & XT_TCP_INV_OPTION,
|
||||
hotdrop))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called when user tries to insert an entry of this type. */
|
||||
static int
|
||||
tcp_checkentry(const char *tablename,
|
||||
const void *info,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ipt_ip *ip = info;
|
||||
const struct xt_tcp *tcpinfo = matchinfo;
|
||||
|
||||
/* Must specify proto == TCP, and no unknown invflags */
|
||||
return ip->proto == IPPROTO_TCP
|
||||
&& !(ip->invflags & XT_INV_PROTO)
|
||||
&& matchsize == XT_ALIGN(sizeof(struct xt_tcp))
|
||||
&& !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
|
||||
}
|
||||
|
||||
/* Called when user tries to insert an entry of this type. */
|
||||
static int
|
||||
tcp6_checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
void *matchinfo,
|
||||
unsigned int matchsize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ip6t_ip6 *ipv6 = entry;
|
||||
const struct xt_tcp *tcpinfo = matchinfo;
|
||||
|
||||
/* Must specify proto == TCP, and no unknown invflags */
|
||||
return ipv6->proto == IPPROTO_TCP
|
||||
&& !(ipv6->invflags & XT_INV_PROTO)
|
||||
&& matchsize == XT_ALIGN(sizeof(struct xt_tcp))
|
||||
&& !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
udp_match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
struct udphdr _udph, *uh;
|
||||
const struct xt_udp *udpinfo = matchinfo;
|
||||
|
||||
/* Must not be a fragment. */
|
||||
if (offset)
|
||||
return 0;
|
||||
|
||||
uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
|
||||
if (uh == NULL) {
|
||||
/* We've been asked to examine this packet, and we
|
||||
can't. Hence, no choice but to drop. */
|
||||
duprintf("Dropping evil UDP tinygram.\n");
|
||||
*hotdrop = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return port_match(udpinfo->spts[0], udpinfo->spts[1],
|
||||
ntohs(uh->source),
|
||||
!!(udpinfo->invflags & XT_UDP_INV_SRCPT))
|
||||
&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
|
||||
ntohs(uh->dest),
|
||||
!!(udpinfo->invflags & XT_UDP_INV_DSTPT));
|
||||
}
|
||||
|
||||
/* Called when user tries to insert an entry of this type. */
|
||||
static int
|
||||
udp_checkentry(const char *tablename,
|
||||
const void *info,
|
||||
void *matchinfo,
|
||||
unsigned int matchinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ipt_ip *ip = info;
|
||||
const struct xt_udp *udpinfo = matchinfo;
|
||||
|
||||
/* Must specify proto == UDP, and no unknown invflags */
|
||||
if (ip->proto != IPPROTO_UDP || (ip->invflags & XT_INV_PROTO)) {
|
||||
duprintf("ipt_udp: Protocol %u != %u\n", ip->proto,
|
||||
IPPROTO_UDP);
|
||||
return 0;
|
||||
}
|
||||
if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
|
||||
duprintf("ipt_udp: matchsize %u != %u\n",
|
||||
matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
|
||||
return 0;
|
||||
}
|
||||
if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
|
||||
duprintf("ipt_udp: unknown flags %X\n",
|
||||
udpinfo->invflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called when user tries to insert an entry of this type. */
|
||||
static int
|
||||
udp6_checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
void *matchinfo,
|
||||
unsigned int matchinfosize,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ip6t_ip6 *ipv6 = entry;
|
||||
const struct xt_udp *udpinfo = matchinfo;
|
||||
|
||||
/* Must specify proto == UDP, and no unknown invflags */
|
||||
if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & XT_INV_PROTO)) {
|
||||
duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
|
||||
IPPROTO_UDP);
|
||||
return 0;
|
||||
}
|
||||
if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
|
||||
duprintf("ip6t_udp: matchsize %u != %u\n",
|
||||
matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
|
||||
return 0;
|
||||
}
|
||||
if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
|
||||
duprintf("ip6t_udp: unknown flags %X\n",
|
||||
udpinfo->invflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct xt_match tcp_matchstruct = {
|
||||
.name = "tcp",
|
||||
.match = &tcp_match,
|
||||
.checkentry = &tcp_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match tcp6_matchstruct = {
|
||||
.name = "tcp",
|
||||
.match = &tcp_match,
|
||||
.checkentry = &tcp6_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct xt_match udp_matchstruct = {
|
||||
.name = "udp",
|
||||
.match = &udp_match,
|
||||
.checkentry = &udp_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
static struct xt_match udp6_matchstruct = {
|
||||
.name = "udp",
|
||||
.match = &udp_match,
|
||||
.checkentry = &udp6_checkentry,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = xt_register_match(AF_INET, &tcp_matchstruct);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &tcp6_matchstruct);
|
||||
if (ret)
|
||||
goto out_unreg_tcp;
|
||||
|
||||
ret = xt_register_match(AF_INET, &udp_matchstruct);
|
||||
if (ret)
|
||||
goto out_unreg_tcp6;
|
||||
|
||||
ret = xt_register_match(AF_INET6, &udp6_matchstruct);
|
||||
if (ret)
|
||||
goto out_unreg_udp;
|
||||
|
||||
return ret;
|
||||
|
||||
out_unreg_udp:
|
||||
xt_unregister_match(AF_INET, &tcp_matchstruct);
|
||||
out_unreg_tcp6:
|
||||
xt_unregister_match(AF_INET6, &tcp6_matchstruct);
|
||||
out_unreg_tcp:
|
||||
xt_unregister_match(AF_INET, &tcp_matchstruct);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_match(AF_INET6, &udp6_matchstruct);
|
||||
xt_unregister_match(AF_INET, &udp_matchstruct);
|
||||
xt_unregister_match(AF_INET6, &tcp6_matchstruct);
|
||||
xt_unregister_match(AF_INET, &tcp_matchstruct);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
Reference in New Issue
Block a user