Compare commits

..

22 Commits
v1.44 ... v1.47

Author SHA1 Message Date
Jan Engelhardt
2f1e094125 Xtables-addons 1.47 2012-10-15 20:03:02 +02:00
Jan Engelhardt
37b000182f xt_psd: replace vzalloc by vmalloc+memset
The lower support boundary is currently 2.6.32, but vzalloc is only
available since 2.6.37.
2012-10-15 20:02:43 +02:00
Jan Engelhardt
255a310536 Merge branch 'psd' 2012-09-18 07:33:00 +02:00
Florian Westphal
3a6e73e986 xt_psd: add IPv6 support
Because most users will probably only use IPv4 psd, allocate most of the
state6 storage when the first IPv6 psd rule is added, and not at module
load time via .bss.
2012-09-18 03:33:37 +02:00
Florian Westphal
0a97126f5b xt_psd: move IPv4 state locking responsibility to caller
The former psd_match function is now < 72 lines.
2012-09-18 02:53:02 +02:00
Florian Westphal
2ba833fe47 xt_psd: move L4 header fetching into helper
Also start splitting psd_match into two functions, one to do initial
sanity checking and header retrieval, one to do the actual work.
2012-09-18 02:47:30 +02:00
Florian Westphal
77240e0918 xt_psd: use tcph->dest directly
This allows us to move more code away from the main match function.
2012-09-18 02:45:17 +02:00
Florian Westphal
651e60f8d7 xt_psd: move table cleanup into helper 2012-09-18 02:43:04 +02:00
Florian Westphal
54ac2a899a xt_psd: split struct host into generic and AF-dependent structure 2012-09-18 02:42:22 +02:00
Florian Westphal
61d2be172d xt_psd: remove unneeded variables, make hash unsigned
- dest port and dest address were only written, never read
- struct inaddr isn't needed either, just look at iph->saddr
2012-09-18 02:41:15 +02:00
Florian Westphal
093f3b0a97 xt_psd: move match functionality to helpers
Reduce line count and to allow code reuse when IPv6 support will be
introduced.
2012-09-17 04:44:29 +02:00
Florian Westphal
57d25f22f1 xt_psd: avoid if (c=h) do {..} while (c = c->next)
It is aquivalent to c=h; while (c) { ..; c = c->next; }
which is a bit easier to read.
2012-09-17 04:42:56 +02:00
Florian Westphal
2f18ab31ec xt_psd: move parts of main match function to helpers
The match function is way too large, start to split this into smaller
chunks.
2012-09-17 00:02:49 +02:00
Florian Westphal
12d0a8702c xt_psd: consider protocol when searching port list
If we saw a TCP packet on port X, and we receive a UDP packet from the
same host to port X, we counted this as "port X", and did not see this
as a new packet.

Change compare to also consider protocol number and move it to a helper
to de-bloat the overlay large match function.

This change makes psd more aggressive with mixed TCP/UDP traffic.
2012-09-17 00:02:45 +02:00
Jan Engelhardt
35ce1adf5e Xtables-addons 1.46 2012-08-23 15:54:21 +02:00
Jan Engelhardt
e5fe0b9c14 doc: update xt_SYSRQ.man to reflect that the full IPv6 address is needed
xt_SYSRQ uses NIP6_FMT, so requires the expanded form for the digest.

Reported-by: Jan Krcmar <honza801@gmail.com>
2012-08-23 15:27:23 +02:00
Arif Hossain
cd7fc84b29 build: remove extraneous closing bracket in configure.ac
Now autogen.sh will work without complaints.
2012-08-02 17:49:40 +02:00
Josh Hunt
4ff5a8fbf6 TARPIT: fix memory leak when tarpit_generic() fails
Currently tarpit_generic() just returns on failure, but this does not
free nskb.

Signed-off-by: Josh Hunt <johunt@akamai.com>
2012-08-02 17:48:05 +02:00
Florian Westphal
37e3a543a9 extensions: fix ipv6_find_hdr upstream change fallout
Upstream commit v3.5-rc1~109^2~138^2~4 ("netfilter: ip6_tables: add
flags parameter to ipv6_find_hdr()") changed the offset parameter of
ipv6_find_hdr() to be an input-output value. Moreover, if it is
non-zero, it MUST point to a valid IPv6 header embedded in the
packet.
2012-07-21 15:42:02 +02:00
Jan Engelhardt
5f6cbbc663 Xtables-addons 1.45 2012-07-16 05:39:32 +02:00
Jan Engelhardt
a2676585da build: avoid use of unexported functions
Fixes: "WARNING 'ipv6_find_hdr' [xt_TARPIT.ko] not found" in
<= linux-2.6.37.
2012-07-16 05:36:41 +02:00
Jan Engelhardt
4a8aab6aed fix: "WARNING 'xtnu_ipv6_find_hdr' [.ko] not found" 2012-07-16 05:34:24 +02:00
11 changed files with 478 additions and 188 deletions

View File

@@ -1,4 +1,4 @@
AC_INIT([xtables-addons], [1.44])
AC_INIT([xtables-addons], [1.47])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
@@ -31,7 +31,7 @@ xtlibdir="$(pkg-config --variable=xtlibdir xtables)"
AC_ARG_WITH([xtlibdir],
AS_HELP_STRING([--with-xtlibdir=PATH],
[Path where to install Xtables extensions [[autodetect]]]]),
[Path where to install Xtables extensions [[autodetect]]]),
[xtlibdir="$withval"])
AC_MSG_CHECKING([Xtables module directory])
AC_MSG_RESULT([$xtlibdir])
@@ -63,8 +63,8 @@ if test -n "$kbuilddir"; then
echo "WARNING: Version detection did not succeed. Continue at own luck.";
else
echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
if test "$kmajor" -gt 3 -o "$kmajor" -eq 3 -a "$kminor" -gt 4; then
echo "WARNING: You are trying a newer kernel. Results may vary. :-)";
if test "$kmajor" -gt 3 -o "$kmajor" -eq 3 -a "$kminor" -gt 6; then
echo "WARNING: That kernel version is not officially supported.";
elif test "$kmajor" -eq 3; then
:;
elif test "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -ge 32; then

View File

@@ -3,6 +3,35 @@ HEAD
====
v1.47 (2010-10-15)
==================
Enhancements:
- xt_psd gained IPv6 support
Notes for this release:
- Linux 3.7+ is expressly unsupported by this release.
v1.46 (2012-08-23)
==================
Fixes:
- length2, SYSRQ, RAWNAT: preinitialize values for ipv6_find_hdr
- TARPIT: fix memory leak when tarpit_generic() fails
- build: remove extraneous closing bracket in configure.ac
- doc: update xt_SYSRQ.man to reflect that the full IPv6 address is needed
Enhancements:
- Support for Linux 3.6
v1.45 (2012-07-16)
==================
Fixes:
- build: export missing functions
(fixes: "WARNING 'xtnu_ipv6_find_hdr' [xt_TARPIT.ko] not found")
- build: avoid use of unexported functions
(fixes: "WARNING 'ipv6_find_hdr' [xt_TARPIT.ko] not found"
in <= linux-2.6.37)
v1.44 (2012-07-15)
==================
Fixes:

View File

@@ -623,6 +623,7 @@ int xtnu_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
{
return ipv6_skip_exthdr(skb, start, nexthdrp);
}
EXPORT_SYMBOL_GPL(xtnu_ipv6_skip_exthdr);
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) && defined(WITH_IPV6)
@@ -631,6 +632,7 @@ int xtnu_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
{
return ipv6_find_hdr(skb, offset, target, fragoff);
}
EXPORT_SYMBOL_GPL(xtnu_ipv6_find_hdr);
#endif
MODULE_LICENSE("GPL");

View File

@@ -62,7 +62,7 @@ password="password"
seqno="$(date +%s)"
salt="$(dd bs=12 count=1 if=/dev/urandom 2>/dev/null |
openssl enc \-base64)"
ipaddr=10.10.25.7
ipaddr="2001:0db8:0000:0000:0000:ff00:0042:8329"
req="$sysrq_key,$seqno,$salt"
req="$req,$(echo \-n "$req,$ipaddr,$password" | sha1sum | cut \-c1\-40)"
@@ -75,8 +75,8 @@ sysrq key can be used at once, but bear in mind that, for example, a sync may
not complete before a subsequent reboot or poweroff.
.PP
An IPv4 address should have no leading zeros, an IPv6 address should
be in the form recommended by RFC 5952. The debug option will log the
correct form of the address.
be in the full expanded form (as shown above). The debug option will cause
output to be emitted in the same form.
.PP
The hashing scheme should be enough to prevent mis-use of SYSRQ in many
environments, but it is not perfect: take reasonable precautions to

View File

@@ -142,7 +142,7 @@ static struct xtables_match psd_mt_reg = {
.name = "psd",
.version = XTABLES_VERSION,
.revision = 1,
.family = NFPROTO_IPV4,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_psd_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_psd_info)),
.help = psd_mt_help,

View File

@@ -244,7 +244,7 @@ static unsigned int
rawsnat_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
{
const struct xt_rawnat_tginfo *info = par->targinfo;
unsigned int l4offset, l4proto;
unsigned int l4offset = 0, l4proto;
struct ipv6hdr *iph;
struct in6_addr new_addr;
@@ -265,7 +265,7 @@ static unsigned int
rawdnat_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
{
const struct xt_rawnat_tginfo *info = par->targinfo;
unsigned int l4offset, l4proto;
unsigned int l4offset = 0, l4proto;
struct ipv6hdr *iph;
struct in6_addr new_addr;

View File

@@ -240,7 +240,7 @@ sysrq_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
const struct ipv6hdr *iph;
const struct udphdr *udph;
unsigned short frag_off;
unsigned int th_off;
unsigned int th_off = 0;
uint16_t len;
if (skb_linearize(skb) < 0)

View File

@@ -237,7 +237,7 @@ static void tarpit_tcp4(struct sk_buff *oldskb, unsigned int hook,
((u_int8_t *)tcph)[13] = 0;
if (!tarpit_generic(tcph, oth, payload, mode))
return;
goto free_nskb;
/* Adjust TCP checksum */
tcph->check = 0;
@@ -374,16 +374,15 @@ static void tarpit_tcp6(struct sk_buff *oldskb, unsigned int hook,
ip6h->daddr = oip6h->saddr;
/* Adjust IP TTL */
if (mode == XTTARPIT_HONEYPOT)
if (mode == XTTARPIT_HONEYPOT) {
ip6h->hop_limit = 128;
else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
} else {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
ip6h->hop_limit = ip6_dst_hoplimit(skb_dst(nskb));
#else
ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
if (ip6h->hop_limit < 0)
ip6h->hop_limit = ipv6_get_hoplimit((skb_dst(nskb))->dev).
ip6h->hop_limit = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
#endif
}
tcph = (struct tcphdr *)(skb_network_header(nskb) +
sizeof(struct ipv6hdr));
@@ -399,7 +398,7 @@ static void tarpit_tcp6(struct sk_buff *oldskb, unsigned int hook,
payload = nskb->len - sizeof(struct ipv6hdr) - sizeof(struct tcphdr);
if (!tarpit_generic(&oth, tcph, payload, mode))
return;
goto free_nskb;
ip6h->payload_len = htons(sizeof(struct tcphdr));
tcph->check = 0;

View File

@@ -203,7 +203,8 @@ length2_mt6(const struct sk_buff *skb, struct xt_action_param *par)
const struct xt_length_mtinfo2 *info = par->matchinfo;
const struct ipv6hdr *iph = ipv6_hdr(skb);
unsigned int len = 0, l4proto;
unsigned int thoff = par->thoff;
/* par->thoff would only set if ip6tables -p was used; so just use 0 */
unsigned int thoff = 0;
bool hit = true;
if (info->flags & XT_LENGTH_LAYER3) {

View File

@@ -22,13 +22,14 @@
#define pr_fmt(x) KBUILD_MODNAME ": " x
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/tcp.h>
#include <linux/types.h>
#include <linux/tcp.h>
#include <linux/spinlock.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include "xt_psd.h"
#include "compat_xtables.h"
@@ -39,6 +40,7 @@ MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
MODULE_AUTHOR(" Mohd Nawawi Mohamad Jamili <nawawi@tracenetworkcorporation.com>");
MODULE_DESCRIPTION("Xtables: PSD - portscan detection");
MODULE_ALIAS("ipt_psd");
MODULE_ALIAS("ip6t_psd");
/*
* Keep track of up to LIST_SIZE source addresses, using a hash table of
@@ -50,6 +52,10 @@ MODULE_ALIAS("ipt_psd");
#define HASH_SIZE (1 << HASH_LOG)
#define HASH_MAX 0x10
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
# define WITH_IPV6 1
#endif
/*
* Information we keep per each target port
*/
@@ -68,8 +74,6 @@ struct port {
struct host {
struct host *next;
unsigned long timestamp;
struct in_addr src_addr;
struct in_addr dest_addr;
__be16 src_port;
uint16_t count;
uint8_t weight;
@@ -77,27 +81,87 @@ struct host {
};
/**
* State information.
* Information we keep per ipv4 source address.
*/
struct host4 {
struct host host;
__be32 saddr;
};
static struct host4 *host_to_host4(const struct host *h)
{
return (struct host4 *)h;
}
struct host6 {
struct host host;
struct in6_addr saddr;
};
/**
* State information for IPv4 portscan detection.
* @list: list of source addresses
* @hash: pointers into the list
* @index: oldest entry to be replaced
*/
static struct {
spinlock_t lock;
struct host list[LIST_SIZE];
struct host4 list[LIST_SIZE];
struct host *hash[HASH_SIZE];
int index;
} state;
#ifdef WITH_IPV6
/**
* State information for IPv6 portscan detection.
* @list: list of source addresses
* @hash: pointers into the list
* @index: oldest entry to be replaced
*/
static struct {
spinlock_t lock;
struct host6 *list;
struct host **hash;
int index;
} state6;
static struct host6 *host_to_host6(const struct host *h)
{
return (struct host6 *) h;
}
/**
* allocate state6 memory only when needed
*/
static bool state6_alloc_mem(void)
{
if (state6.hash != NULL)
return true;
state6.list = vmalloc(LIST_SIZE * sizeof(struct host6));
if (state6.list == NULL)
return false;
memset(state6.list, 0, LIST_SIZE * sizeof(struct host6));
state6.hash = vmalloc(HASH_SIZE * sizeof(struct host*));
if (state6.hash == NULL) {
vfree(state6.list);
return false;
}
memset(state6.hash, 0, HASH_SIZE * sizeof(struct host *));
return true;
}
#endif
/*
* Convert an IP address into a hash table index.
*/
static inline int hashfunc(struct in_addr addr)
static unsigned int hashfunc(__be32 addr)
{
unsigned int value;
int hash;
unsigned int hash;
value = addr.s_addr;
value = addr;
hash = 0;
do {
hash ^= value;
@@ -106,133 +170,169 @@ static inline int hashfunc(struct in_addr addr)
return hash & (HASH_SIZE - 1);
}
static bool
xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
static inline unsigned int hashfunc6(const struct in6_addr *addr)
{
__be32 h = addr->s6_addr32[0] ^ addr->s6_addr32[1];
return hashfunc(h ^ addr->s6_addr32[2] ^ addr->s6_addr32[3]);
}
static bool port_in_list(struct host *host, uint8_t proto, uint16_t port)
{
unsigned int i;
for (i = 0; i < host->count; ++i) {
if (host->ports[i].proto != proto)
continue;
if (host->ports[i].number == port)
return true;
}
return false;
}
static uint16_t get_port_weight(const struct xt_psd_info *psd, __be16 port)
{
return ntohs(port) < 1024 ? psd->lo_ports_weight : psd->hi_ports_weight;
}
static bool
is_portscan(struct host *host, const struct xt_psd_info *psdinfo,
const struct tcphdr *tcph, uint8_t proto)
{
if (port_in_list(host, proto, tcph->dest))
return false;
/*
* TCP/ACK and/or TCP/RST to a new port? This could be an
* outgoing connection.
*/
if (proto == IPPROTO_TCP && (tcph->ack || tcph->rst))
return false;
host->timestamp = jiffies;
if (host->weight >= psdinfo->weight_threshold) /* already matched */
return true;
/* Update the total weight */
host->weight += get_port_weight(psdinfo, tcph->dest);
/* Got enough destination ports to decide that this is a scan? */
if (host->weight >= psdinfo->weight_threshold)
return true;
/* Remember the new port */
if (host->count < ARRAY_SIZE(host->ports)) {
host->ports[host->count].number = tcph->dest;
host->ports[host->count].proto = proto;
host->count++;
}
return false;
}
static struct host *host_get_next(struct host *h, struct host **last)
{
if (h->next != NULL)
*last = h;
return h->next;
}
static void ht_unlink(struct host **head, struct host *last)
{
if (last != NULL)
last->next = last->next->next;
else if (*head != NULL)
*head = (*head)->next;
}
static bool
entry_is_recent(const struct host *h, unsigned long delay_threshold,
unsigned long now)
{
return now - h->timestamp <= (delay_threshold * HZ) / 100 &&
time_after_eq(now, h->timestamp);
}
static void remove_oldest(struct host **head, struct host *curr)
{
struct host *h, *last = NULL;
/*
* We are going to re-use the oldest list entry, so remove it from the
* hash table first, if it is really already in use.
*/
h = *head;
while (h != NULL) {
if (curr == h)
break;
last = h;
h = h->next;
}
/* Then, remove it */
if (h != NULL)
ht_unlink(head, last);
}
static void *
get_header_pointer4(const struct sk_buff *skb, unsigned int thoff, void *mem)
{
const struct iphdr *iph = ip_hdr(skb);
int hdrlen;
switch (iph->protocol) {
case IPPROTO_TCP:
hdrlen = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
case IPPROTO_UDPLITE:
hdrlen = sizeof(struct udphdr);
break;
default:
return NULL;
}
return skb_header_pointer(skb, thoff, hdrlen, mem);
}
static bool
handle_packet4(const struct iphdr *iph, const struct tcphdr *tcph,
const struct xt_psd_info *psdinfo, unsigned int hash)
{
const struct iphdr *iph;
const struct tcphdr *tcph = NULL;
const struct udphdr *udph;
union {
struct tcphdr tcph;
struct udphdr udph;
} _buf;
struct in_addr addr;
u_int16_t src_port,dest_port;
u_int8_t proto;
unsigned long now;
struct host *curr, *last, **head;
int hash, index, count;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
iph = ip_hdr(pskb);
if (iph->frag_off & htons(IP_OFFSET)) {
pr_debug("sanity check failed\n");
return false;
}
proto = iph->protocol;
addr.s_addr = iph->saddr;
/* We're using IP address 0.0.0.0 for a special purpose here, so don't let
* them spoof us. [DHCP needs this feature - HW] */
if (addr.s_addr == 0) {
pr_debug("spoofed source address (0.0.0.0)\n");
return false;
}
if (proto == IPPROTO_TCP) {
tcph = skb_header_pointer(pskb, match->thoff,
sizeof(_buf.tcph), &_buf.tcph);
if (tcph == NULL)
return false;
/* Yep, it's dirty */
src_port = tcph->source;
dest_port = tcph->dest;
} else if (proto == IPPROTO_UDP || proto == IPPROTO_UDPLITE) {
udph = skb_header_pointer(pskb, match->thoff,
sizeof(_buf.udph), &_buf.udph);
if (udph == NULL)
return false;
src_port = udph->source;
dest_port = udph->dest;
} else {
pr_debug("protocol not supported\n");
return false;
}
struct host *curr, *last = NULL, **head;
struct host4 *curr4;
int count = 0;
now = jiffies;
spin_lock(&state.lock);
head = &state.hash[hash];
/* Do we know this source address already? */
count = 0;
last = NULL;
if ((curr = *(head = &state.hash[hash = hashfunc(addr)])) != NULL)
do {
if (curr->src_addr.s_addr == addr.s_addr)
break;
count++;
if (curr->next != NULL)
last = curr;
} while ((curr = curr->next) != NULL);
curr = *head;
while (curr != NULL) {
curr4 = host_to_host4(curr);
if (curr4->saddr == iph->saddr)
break;
count++;
curr = host_get_next(curr, &last);
}
if (curr != NULL) {
/* We know this address, and the entry isn't too old. Update it. */
if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
time_after_eq(now, curr->timestamp)) {
/* Just update the appropriate list entry if we've seen this port already */
for (index = 0; index < curr->count; index++) {
if (curr->ports[index].number == dest_port) {
curr->ports[index].proto = proto;
goto out_no_match;
}
}
/* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
if (proto == IPPROTO_TCP && (tcph->ack || tcph->rst))
goto out_no_match;
/* Packet to a new port, and not TCP/ACK: update the timestamp */
curr->timestamp = now;
/* Matched this scan already? Then Leave. */
if (curr->weight >= psdinfo->weight_threshold)
goto out_match;
/* Update the total weight */
curr->weight += (ntohs(dest_port) < 1024) ?
psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
/* Got enough destination ports to decide that this is a scan? */
if (curr->weight >= psdinfo->weight_threshold)
goto out_match;
/* Remember the new port */
if (curr->count < ARRAY_SIZE(curr->ports)) {
curr->ports[curr->count].number = dest_port;
curr->ports[curr->count].proto = proto;
curr->count++;
}
goto out_no_match;
}
if (entry_is_recent(curr, psdinfo->delay_threshold, now))
return is_portscan(curr, psdinfo, tcph, iph->protocol);
/* We know this address, but the entry is outdated. Mark it unused, and
* remove from the hash table. We'll allocate a new entry instead since
* this one might get re-used too soon. */
curr->src_addr.s_addr = 0;
if (last != NULL)
last->next = last->next->next;
else if (*head != NULL)
*head = (*head)->next;
curr4 = host_to_host4(curr);
curr4->saddr = 0;
ht_unlink(head, last);
last = NULL;
}
/* We don't need an ACK from a new source address */
if (proto == IPPROTO_TCP && tcph->ack)
goto out_no_match;
if (iph->protocol == IPPROTO_TCP && tcph->ack)
return false;
/* Got too many source addresses with the same hash value? Then remove the
* oldest one from the hash table, so that they can't take too much of our
@@ -240,33 +340,15 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
if (count >= HASH_MAX && last != NULL)
last->next = NULL;
/* We're going to re-use the oldest list entry, so remove it from the hash
* table first (if it is really already in use, and isn't removed from the
* hash table already because of the HASH_MAX check above). */
/* First, find it */
if (state.list[state.index].src_addr.s_addr != 0)
head = &state.hash[hashfunc(state.list[state.index].src_addr)];
if (state.list[state.index].saddr != 0)
head = &state.hash[hashfunc(state.list[state.index].saddr)];
else
head = &last;
last = NULL;
if ((curr = *head) != NULL)
do {
if (curr == &state.list[state.index])
break;
last = curr;
} while ((curr = curr->next) != NULL);
/* Then, remove it */
if (curr != NULL) {
if (last != NULL)
last->next = last->next->next;
else if (*head != NULL)
*head = (*head)->next;
}
/* Get our list entry */
curr = &state.list[state.index++];
curr4 = &state.list[state.index++];
curr = &curr4->host;
remove_oldest(head, curr);
if (state.index >= LIST_SIZE)
state.index = 0;
@@ -276,24 +358,173 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
*head = curr;
/* And fill in the fields */
curr4 = host_to_host4(curr);
curr4->saddr = iph->saddr;
curr->timestamp = now;
curr->src_addr = addr;
curr->dest_addr.s_addr = iph->daddr;
curr->src_port = src_port;
curr->count = 1;
curr->weight = (ntohs(dest_port) < 1024) ? psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
curr->ports[0].number = dest_port;
curr->ports[0].proto = proto;
out_no_match:
spin_unlock(&state.lock);
curr->weight = get_port_weight(psdinfo, tcph->dest);
curr->ports[0].number = tcph->dest;
curr->ports[0].proto = iph->protocol;
return false;
out_match:
spin_unlock(&state.lock);
return true;
}
static bool
xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
{
struct iphdr *iph = ip_hdr(pskb);
struct tcphdr _tcph;
struct tcphdr *tcph;
bool matched;
unsigned int hash;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
if (iph->frag_off & htons(IP_OFFSET)) {
pr_debug("sanity check failed\n");
return false;
}
/*
* We are using IP address 0.0.0.0 for a special purpose here, so do
* not let them spoof us. [DHCP needs this feature - HW]
*/
if (iph->saddr == 0) {
pr_debug("spoofed source address (0.0.0.0)\n");
return false;
}
tcph = get_header_pointer4(pskb, match->thoff, &_tcph);
if (tcph == NULL)
return false;
hash = hashfunc(iph->saddr);
spin_lock(&state.lock);
matched = handle_packet4(iph, tcph, psdinfo, hash);
spin_unlock(&state.lock);
return matched;
}
#ifdef WITH_IPV6
static bool
handle_packet6(const struct ipv6hdr *ip6h, const struct tcphdr *tcph,
const struct xt_psd_info *psdinfo, uint8_t proto, int hash)
{
unsigned long now;
struct host *curr, *last = NULL, **head;
struct host6 *curr6;
int count = 0;
now = jiffies;
head = &state6.hash[hash];
curr = *head;
while (curr != NULL) {
curr6 = host_to_host6(curr);
if (ipv6_addr_equal(&curr6->saddr, &ip6h->saddr))
break;
count++;
curr = host_get_next(curr, &last);
}
if (curr != NULL) {
if (entry_is_recent(curr, psdinfo->delay_threshold, now))
return is_portscan(curr, psdinfo, tcph, proto);
curr6 = host_to_host6(curr);
memset(&curr6->saddr, 0, sizeof(curr6->saddr));
ht_unlink(head, last);
last = NULL;
}
if (proto == IPPROTO_TCP && tcph->ack)
return false;
if (count >= HASH_MAX && last != NULL)
last->next = NULL;
if (!ipv6_addr_any(&state6.list[state6.index].saddr))
head = &state6.hash[hashfunc6(&state6.list[state6.index].saddr)];
else
head = &last;
curr6 = &state6.list[state6.index++];
curr = &curr6->host;
remove_oldest(head, curr);
if (state6.index >= LIST_SIZE)
state6.index = 0;
head = &state6.hash[hash];
curr->next = *head;
*head = curr;
curr6 = host_to_host6(curr);
curr6->saddr = ip6h->saddr;
curr->timestamp = now;
curr->count = 1;
curr->weight = get_port_weight(psdinfo, tcph->dest);
curr->ports[0].number = tcph->dest;
curr->ports[0].proto = proto;
return false;
}
static void *
get_header_pointer6(const struct sk_buff *skb, void *mem, uint8_t *proto)
{
static const uint8_t types[] = {IPPROTO_TCP,
IPPROTO_UDP, IPPROTO_UDPLITE};
unsigned int i, offset = 0;
int err;
size_t hdrlen;
for (i = 0; i < ARRAY_SIZE(types); ++i) {
err = ipv6_find_hdr(skb, &offset, types[i], NULL, NULL);
if (err < 0)
continue;
switch (types[i]) {
case IPPROTO_TCP:
hdrlen = sizeof(struct tcphdr);
break;
case IPPROTO_UDP:
case IPPROTO_UDPLITE:
hdrlen = sizeof(struct udphdr);
break;
default:
return NULL;
}
*proto = types[i];
return skb_header_pointer(skb, offset, hdrlen, mem);
}
return NULL;
}
static bool
xt_psd_match6(const struct sk_buff *pskb, struct xt_action_param *match)
{
const struct ipv6hdr *ip6h = ipv6_hdr(pskb);
struct tcphdr _tcph;
struct tcphdr *tcph;
uint8_t proto = 0;
bool matched;
int hash;
const struct xt_psd_info *psdinfo = match->matchinfo;
if (ipv6_addr_any(&ip6h->saddr))
return false;
tcph = get_header_pointer6(pskb, &_tcph, &proto);
if (tcph == NULL)
return false;
hash = hashfunc6(&ip6h->saddr);
spin_lock(&state6.lock);
matched = handle_packet6(ip6h, tcph, psdinfo, proto, hash);
spin_unlock(&state6.lock);
return matched;
}
#endif
static int psd_mt_check(const struct xt_mtchk_param *par)
{
const struct xt_psd_info *info = par->matchinfo;
@@ -315,25 +546,53 @@ static int psd_mt_check(const struct xt_mtchk_param *par)
return 0;
}
static struct xt_match xt_psd_reg __read_mostly = {
.name = "psd",
.family = NFPROTO_IPV4,
.revision = 1,
.checkentry = psd_mt_check,
.match = xt_psd_match,
.matchsize = sizeof(struct xt_psd_info),
.me = THIS_MODULE,
#ifdef WITH_IPV6
static int psd_mt_check6(const struct xt_mtchk_param *par)
{
if (!state6_alloc_mem())
return -ENOMEM;
return psd_mt_check(par);
}
#endif
static struct xt_match xt_psd_reg[] __read_mostly = {
{
.name = "psd",
.family = NFPROTO_IPV4,
.revision = 1,
.checkentry = psd_mt_check,
.match = xt_psd_match,
.matchsize = sizeof(struct xt_psd_info),
.me = THIS_MODULE,
#ifdef WITH_IPV6
}, {
.name = "psd",
.family = NFPROTO_IPV6,
.revision = 1,
.checkentry = psd_mt_check6,
.match = xt_psd_match6,
.matchsize = sizeof(struct xt_psd_info),
.me = THIS_MODULE,
#endif
}
};
static int __init xt_psd_init(void)
{
spin_lock_init(&(state.lock));
return xt_register_match(&xt_psd_reg);
#ifdef WITH_IPV6
spin_lock_init(&(state6.lock));
#endif
return xt_register_matches(xt_psd_reg, ARRAY_SIZE(xt_psd_reg));
}
static void __exit xt_psd_exit(void)
{
xt_unregister_match(&xt_psd_reg);
xt_unregister_matches(xt_psd_reg, ARRAY_SIZE(xt_psd_reg));
#ifdef WITH_IPV6
vfree(state6.list);
vfree(state6.hash);
#endif
}
module_init(xt_psd_init);

View File

@@ -1,4 +1,4 @@
.TH xtables-addons 8 "v1.44 (2012-07-15)" "" "v1.44 (2012-07-15)"
.TH xtables-addons 8 "v1.47 (2012-10-15)" "" "v1.47 (2012-10-15)"
.SH Name
Xtables-addons \(em additional extensions for iptables, ip6tables, etc.
.SH Targets