* [PATCH 01/11] xt_psd: consider protocol when searching port list
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 02/11] xt_psd: move parts of main match function to helpers Florian Westphal
` (9 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
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 didn't 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.
---
extensions/xt_psd.c | 24 +++++++++++++++---------
1 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index b67b64e..1588631 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -106,6 +106,18 @@ static inline int hashfunc(struct in_addr addr)
return hash & (HASH_SIZE - 1);
}
+static bool port_in_list(struct host *host, u8 proto, u16 port)
+{
+ 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 bool
xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
{
@@ -121,7 +133,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
u_int8_t proto;
unsigned long now;
struct host *curr, *last, **head;
- int hash, index, count;
+ int hash, count;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
@@ -182,14 +194,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
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;
- }
- }
-
+ if (port_in_list(curr, proto, dest_port))
+ 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;
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 02/11] xt_psd: move parts of main match function to helpers
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
2012-09-16 21:29 ` [PATCH 01/11] xt_psd: consider protocol when searching port list Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 03/11] xt_psd: avoid if (c=h) do {..} while (c = c->next) Florian Westphal
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
the match function is way too large, start to split this
into smaller chunks.
---
extensions/xt_psd.c | 55 +++++++++++++++++++++++++++++---------------------
1 files changed, 32 insertions(+), 23 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index 1588631..442c05a 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -118,6 +118,36 @@ static bool port_in_list(struct host *host, u8 proto, u16 port)
return false;
}
+static u16 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,
+ u8 proto, __be16 dest_port)
+{
+ host->timestamp = jiffies;
+
+ if (host->weight >= psdinfo->weight_threshold) /* already matched */
+ return true;
+
+ /* Update the total weight */
+ host->weight += get_port_weight(psdinfo, dest_port);
+
+ /* 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 = dest_port;
+ host->ports[host->count].proto = proto;
+ host->count++;
+ }
+ return false;
+}
+
static bool
xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
{
@@ -200,31 +230,10 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
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)
+ if (is_portscan(curr, psdinfo, proto, dest_port))
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;
}
-
/* 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. */
@@ -287,7 +296,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
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->weight = get_port_weight(psdinfo, dest_port);
curr->ports[0].number = dest_port;
curr->ports[0].proto = proto;
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 03/11] xt_psd: avoid if (c=h) do {..} while (c = c->next)
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
2012-09-16 21:29 ` [PATCH 01/11] xt_psd: consider protocol when searching port list Florian Westphal
2012-09-16 21:29 ` [PATCH 02/11] xt_psd: move parts of main match function to helpers Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 04/11] xt_psd: move match functionality to helpers Florian Westphal
` (7 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
its aquivalent to c=h; while (c) { ..; c = c->next; }
which is a bit easier to read.
---
extensions/xt_psd.c | 38 ++++++++++++++++++++------------------
1 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index 442c05a..e803052 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -162,8 +162,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
u_int16_t src_port,dest_port;
u_int8_t proto;
unsigned long now;
- struct host *curr, *last, **head;
- int hash, count;
+ struct host *curr, *last = NULL, **head;
+ int hash, count = 0;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
@@ -204,20 +204,21 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
}
now = jiffies;
+ hash = hashfunc(addr);
+ head = &state.hash[hash];
spin_lock(&state.lock);
/* 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) {
+ if (curr->src_addr.s_addr == addr.s_addr)
+ break;
+ count++;
+ if (curr->next != NULL)
+ last = curr;
+ curr = curr->next;
+ }
if (curr != NULL) {
/* We know this address, and the entry isn't too old. Update it. */
@@ -265,12 +266,13 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
else
head = &last;
last = NULL;
- if ((curr = *head) != NULL)
- do {
- if (curr == &state.list[state.index])
- break;
- last = curr;
- } while ((curr = curr->next) != NULL);
+ curr = *head;
+ while (curr != NULL) {
+ if (curr == &state.list[state.index])
+ break;
+ last = curr;
+ curr = curr->next;
+ }
/* Then, remove it */
if (curr != NULL) {
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 04/11] xt_psd: move match functionality to helpers
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (2 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 03/11] xt_psd: avoid if (c=h) do {..} while (c = c->next) Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 05/11] xt_psd: remove unneeded variables Florian Westphal
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
... reduce line count and to allow code reuse when ipv6 support is introduced.
---
extensions/xt_psd.c | 36 ++++++++++++++++++++++++++----------
1 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index e803052..df04277 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -148,6 +148,29 @@ is_portscan(struct host *host, const struct xt_psd_info *psdinfo,
return false;
}
+static struct host *host_get_next(struct host *h, struct host **last)
+{
+ if (h->next)
+ *last = h;
+ return h->next;
+}
+
+static void ht_unlink(struct host **head, struct host *last)
+{
+ if (last)
+ last->next = last->next->next;
+ else if (*head)
+ *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 bool
xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
{
@@ -215,16 +238,12 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
if (curr->src_addr.s_addr == addr.s_addr)
break;
count++;
- if (curr->next != NULL)
- last = curr;
- curr = curr->next;
+ 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)) {
-
+ if (entry_is_recent(curr, psdinfo->delay_threshold, now)) {
if (port_in_list(curr, proto, dest_port))
goto out_no_match;
/* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
@@ -239,10 +258,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
* 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;
+ ht_unlink(head, last);
last = NULL;
}
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 05/11] xt_psd: remove unneeded variables
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (3 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 04/11] xt_psd: move match functionality to helpers Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-17 2:57 ` Jan Engelhardt
2012-09-16 21:29 ` [PATCH 06/11] xt_psd: split struct host into generic and af-dependent structure Florian Westphal
` (5 subsequent siblings)
10 siblings, 1 reply; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
- dest port and dest address were only written, never read
- struct inaddr isn't needed either, just look at iph->saddr
---
extensions/xt_psd.c | 23 ++++++++---------------
1 files changed, 8 insertions(+), 15 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index df04277..e66ea56 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -69,7 +69,6 @@ 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;
@@ -92,12 +91,12 @@ static struct {
/*
* 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;
- value = addr.s_addr;
+ value = (unsigned int) addr;
hash = 0;
do {
hash ^= value;
@@ -181,8 +180,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
struct tcphdr tcph;
struct udphdr udph;
} _buf;
- struct in_addr addr;
- u_int16_t src_port,dest_port;
+ u_int16_t dest_port;
u_int8_t proto;
unsigned long now;
struct host *curr, *last = NULL, **head;
@@ -197,10 +195,9 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
}
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) {
+ if (iph->saddr == 0) {
pr_debug("spoofed source address (0.0.0.0)\n");
return false;
}
@@ -212,14 +209,12 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
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");
@@ -227,7 +222,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
}
now = jiffies;
- hash = hashfunc(addr);
+ hash = hashfunc(iph->saddr);
head = &state.hash[hash];
spin_lock(&state.lock);
@@ -235,7 +230,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
/* Do we know this source address already? */
curr = *head;
while (curr != NULL) {
- if (curr->src_addr.s_addr == addr.s_addr)
+ if (curr->src_addr.s_addr == iph->saddr)
break;
count++;
curr = host_get_next(curr, &last);
@@ -278,7 +273,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
/* First, find it */
if (state.list[state.index].src_addr.s_addr != 0)
- head = &state.hash[hashfunc(state.list[state.index].src_addr)];
+ head = &state.hash[hashfunc(state.list[state.index].src_addr.s_addr)];
else
head = &last;
last = NULL;
@@ -309,10 +304,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
*head = curr;
/* And fill in the fields */
+ curr->src_addr.s_addr = 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 = get_port_weight(psdinfo, dest_port);
curr->ports[0].number = dest_port;
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 05/11] xt_psd: remove unneeded variables
2012-09-16 21:29 ` [PATCH 05/11] xt_psd: remove unneeded variables Florian Westphal
@ 2012-09-17 2:57 ` Jan Engelhardt
2012-09-17 7:35 ` Florian Westphal
0 siblings, 1 reply; 14+ messages in thread
From: Jan Engelhardt @ 2012-09-17 2:57 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Sunday 2012-09-16 23:29, Florian Westphal wrote:
>
>- dest port and dest address were only written, never read
>- struct inaddr isn't needed either, just look at iph->saddr
I have applied 01..04, with some redactional changes (diff
975f017..093f3b0).
>-static inline int hashfunc(struct in_addr addr)
>+static unsigned int hashfunc(__be32 addr)
You are changing the type of hash here. While I concur with using an
unsigned quantity for a hash value, this is not done consistenly - there
are some (signed) "int hash"s left in the code. Can I get a patch that
rectifies this consistently across the entire .c file as well?
BTW, does the _10 in your branch name have any significance? :)
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 05/11] xt_psd: remove unneeded variables
2012-09-17 2:57 ` Jan Engelhardt
@ 2012-09-17 7:35 ` Florian Westphal
0 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-17 7:35 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Florian Westphal, netfilter-devel
Jan Engelhardt <jengelh@inai.de> wrote:
> On Sunday 2012-09-16 23:29, Florian Westphal wrote:
> >
> >- dest port and dest address were only written, never read
> >- struct inaddr isn't needed either, just look at iph->saddr
>
>
> I have applied 01..04, with some redactional changes (diff
> 975f017..093f3b0).
Alright, the changes are ok; I'll update the remaining
patches to use stdint-types.
> >-static inline int hashfunc(struct in_addr addr)
> >+static unsigned int hashfunc(__be32 addr)
>
> You are changing the type of hash here. While I concur with using an
> unsigned quantity for a hash value, this is not done consistenly - there
> are some (signed) "int hash"s left in the code. Can I get a patch that
> rectifies this consistently across the entire .c file as well?
Sure; I'll rebase to remaining patches on top of your tree.
> BTW, does the _10 in your branch name have any significance? :)
Not really; I usually start out with foo_01 and then increment the
number when rebasing/structuring the changeset.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 06/11] xt_psd: split struct host into generic and af-dependent structure
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (4 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 05/11] xt_psd: remove unneeded variables Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 07/11] xt_psd: move table cleanup into helper Florian Westphal
` (4 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
---
extensions/xt_psd.c | 36 +++++++++++++++++++++++++++---------
1 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index e66ea56..2baec8e 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -68,7 +68,6 @@ struct port {
struct host {
struct host *next;
unsigned long timestamp;
- struct in_addr src_addr;
__be16 src_port;
uint16_t count;
uint8_t weight;
@@ -76,6 +75,19 @@ struct host {
};
/**
+ * 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;
+}
+
+/**
* State information.
* @list: list of source addresses
* @hash: pointers into the list
@@ -83,7 +95,7 @@ struct host {
*/
static struct {
spinlock_t lock;
- struct host list[LIST_SIZE];
+ struct host4 list[LIST_SIZE];
struct host *hash[HASH_SIZE];
int index;
} state;
@@ -184,6 +196,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
u_int8_t proto;
unsigned long now;
struct host *curr, *last = NULL, **head;
+ struct host4 *curr4;
int hash, count = 0;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
@@ -230,7 +243,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
/* Do we know this source address already? */
curr = *head;
while (curr != NULL) {
- if (curr->src_addr.s_addr == iph->saddr)
+ curr4 = host_to_host4(curr);
+ if (curr4->saddr == iph->saddr)
break;
count++;
curr = host_get_next(curr, &last);
@@ -252,7 +266,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
/* 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;
+ curr4 = host_to_host4(curr);
+ curr4->saddr = 0;
ht_unlink(head, last);
last = NULL;
}
@@ -272,14 +287,15 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
* 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.s_addr)];
+ if (state.list[state.index].saddr != 0)
+ head = &state.hash[hashfunc(state.list[state.index].saddr)];
else
head = &last;
last = NULL;
curr = *head;
while (curr != NULL) {
- if (curr == &state.list[state.index])
+ curr4 = host_to_host4(curr);
+ if (curr4 == &state.list[state.index])
break;
last = curr;
curr = curr->next;
@@ -294,7 +310,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
}
/* Get our list entry */
- curr = &state.list[state.index++];
+ curr4 = &state.list[state.index++];
+ curr = &curr4->host;
if (state.index >= LIST_SIZE)
state.index = 0;
@@ -304,7 +321,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
*head = curr;
/* And fill in the fields */
- curr->src_addr.s_addr = iph->saddr;
+ curr4 = host_to_host4(curr);
+ curr4->saddr = iph->saddr;
curr->timestamp = now;
curr->count = 1;
curr->weight = get_port_weight(psdinfo, dest_port);
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 07/11] xt_psd: move table cleanup into helper
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (5 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 06/11] xt_psd: split struct host into generic and af-dependent structure Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 08/11] xt_psd: use tcph->dest directly Florian Westphal
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
---
extensions/xt_psd.c | 42 ++++++++++++++++++++----------------------
1 files changed, 20 insertions(+), 22 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index 2baec8e..a3f1168 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -182,6 +182,25 @@ entry_is_recent(const struct host *h, unsigned long delay_threshold,
time_after_eq(now, h->timestamp);
}
+static void remove_oldest(struct host **head, struct host *curr)
+{
+ struct host *h, *last = 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 */
+ 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 bool
xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
{
@@ -282,36 +301,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].saddr != 0)
head = &state.hash[hashfunc(state.list[state.index].saddr)];
else
head = &last;
- last = NULL;
- curr = *head;
- while (curr != NULL) {
- curr4 = host_to_host4(curr);
- if (curr4 == &state.list[state.index])
- break;
- last = curr;
- curr = curr->next;
- }
-
- /* 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 */
curr4 = &state.list[state.index++];
curr = &curr4->host;
+ remove_oldest(head, curr);
if (state.index >= LIST_SIZE)
state.index = 0;
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 08/11] xt_psd: use tcph->dest directly
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (6 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 07/11] xt_psd: move table cleanup into helper Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 09/11] xt_psd: move l4 header fetching into helper Florian Westphal
` (2 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
allows us to move more code away from the main match function.
---
extensions/xt_psd.c | 35 +++++++++++++++--------------------
1 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index a3f1168..7acb47b 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -136,15 +136,22 @@ static u16 get_port_weight(const struct xt_psd_info *psd, __be16 port)
static bool
is_portscan(struct host *host, const struct xt_psd_info *psdinfo,
- u8 proto, __be16 dest_port)
+ const struct tcphdr *tcph, u8 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, dest_port);
+ 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)
@@ -152,7 +159,7 @@ is_portscan(struct host *host, const struct xt_psd_info *psdinfo,
/* Remember the new port */
if (host->count < ARRAY_SIZE(host->ports)) {
- host->ports[host->count].number = dest_port;
+ host->ports[host->count].number = tcph->dest;
host->ports[host->count].proto = proto;
host->count++;
}
@@ -206,12 +213,10 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
{
const struct iphdr *iph;
const struct tcphdr *tcph = NULL;
- const struct udphdr *udph;
union {
struct tcphdr tcph;
struct udphdr udph;
} _buf;
- u_int16_t dest_port;
u_int8_t proto;
unsigned long now;
struct host *curr, *last = NULL, **head;
@@ -239,15 +244,11 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
sizeof(_buf.tcph), &_buf.tcph);
if (tcph == NULL)
return false;
-
- /* Yep, it's dirty */
- dest_port = tcph->dest;
} else if (proto == IPPROTO_UDP || proto == IPPROTO_UDPLITE) {
- udph = skb_header_pointer(pskb, match->thoff,
+ tcph = skb_header_pointer(pskb, match->thoff,
sizeof(_buf.udph), &_buf.udph);
- if (udph == NULL)
+ if (tcph == NULL)
return false;
- dest_port = udph->dest;
} else {
pr_debug("protocol not supported\n");
return false;
@@ -272,13 +273,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
if (curr != NULL) {
/* We know this address, and the entry isn't too old. Update it. */
if (entry_is_recent(curr, psdinfo->delay_threshold, now)) {
- if (port_in_list(curr, proto, dest_port))
- 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;
-
- if (is_portscan(curr, psdinfo, proto, dest_port))
+ if (is_portscan(curr, psdinfo, tcph, proto))
goto out_match;
goto out_no_match;
}
@@ -323,8 +318,8 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
curr4->saddr = iph->saddr;
curr->timestamp = now;
curr->count = 1;
- curr->weight = get_port_weight(psdinfo, dest_port);
- curr->ports[0].number = dest_port;
+ curr->weight = get_port_weight(psdinfo, tcph->dest);
+ curr->ports[0].number = tcph->dest;
curr->ports[0].proto = proto;
out_no_match:
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 09/11] xt_psd: move l4 header fetching into helper
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (7 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 08/11] xt_psd: use tcph->dest directly Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 10/11] xt_psd: move ipv4 state locking responsibility to caller Florian Westphal
2012-09-16 21:29 ` [PATCH 11/11] psd: add ipv6 support Florian Westphal
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
also start splitting psd_match into two functions, one
to do initial sanity checking and header retrieval, one
to do the actual work.
---
extensions/xt_psd.c | 96 ++++++++++++++++++++++++++++----------------------
1 files changed, 54 insertions(+), 42 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index 7acb47b..6ca1bd6 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -208,51 +208,35 @@ static void remove_oldest(struct host **head, struct host *curr)
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
-xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
+handle_packet4(const struct iphdr *iph, const struct tcphdr *tcph,
+ const struct xt_psd_info *psdinfo)
{
- const struct iphdr *iph;
- const struct tcphdr *tcph = NULL;
- union {
- struct tcphdr tcph;
- struct udphdr udph;
- } _buf;
- u_int8_t proto;
unsigned long now;
struct host *curr, *last = NULL, **head;
struct host4 *curr4;
int hash, count = 0;
- /* 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;
- /* 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 (iph->saddr == 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;
- } else if (proto == IPPROTO_UDP || proto == IPPROTO_UDPLITE) {
- tcph = skb_header_pointer(pskb, match->thoff,
- sizeof(_buf.udph), &_buf.udph);
- if (tcph == NULL)
- return false;
- } else {
- pr_debug("protocol not supported\n");
- return false;
- }
now = jiffies;
hash = hashfunc(iph->saddr);
@@ -273,7 +257,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
if (curr != NULL) {
/* We know this address, and the entry isn't too old. Update it. */
if (entry_is_recent(curr, psdinfo->delay_threshold, now)) {
- if (is_portscan(curr, psdinfo, tcph, proto))
+ if (is_portscan(curr, psdinfo, tcph, iph->protocol))
goto out_match;
goto out_no_match;
}
@@ -287,7 +271,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
}
/* We don't need an ACK from a new source address */
- if (proto == IPPROTO_TCP && tcph->ack)
+ if (iph->protocol == IPPROTO_TCP && tcph->ack)
goto out_no_match;
/* Got too many source addresses with the same hash value? Then remove the
@@ -320,7 +304,7 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
curr->count = 1;
curr->weight = get_port_weight(psdinfo, tcph->dest);
curr->ports[0].number = tcph->dest;
- curr->ports[0].proto = proto;
+ curr->ports[0].proto = iph->protocol;
out_no_match:
spin_unlock(&state.lock);
@@ -331,6 +315,34 @@ out_match:
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;
+ /* 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'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 (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;
+
+ return handle_packet4(iph, tcph, psdinfo);
+}
+
static int psd_mt_check(const struct xt_mtchk_param *par)
{
const struct xt_psd_info *info = par->matchinfo;
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 10/11] xt_psd: move ipv4 state locking responsibility to caller
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (8 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 09/11] xt_psd: move l4 header fetching into helper Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
2012-09-16 21:29 ` [PATCH 11/11] psd: add ipv6 support Florian Westphal
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
former psd_match function is now < 72 lines.
---
extensions/xt_psd.c | 33 ++++++++++++++-------------------
1 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index 6ca1bd6..a5729e1 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -231,19 +231,16 @@ get_header_pointer4(const struct sk_buff *skb, unsigned int thoff, void *mem)
static bool
handle_packet4(const struct iphdr *iph, const struct tcphdr *tcph,
- const struct xt_psd_info *psdinfo)
+ const struct xt_psd_info *psdinfo, int hash)
{
unsigned long now;
struct host *curr, *last = NULL, **head;
struct host4 *curr4;
- int hash, count = 0;
+ int count = 0;
now = jiffies;
- hash = hashfunc(iph->saddr);
head = &state.hash[hash];
- spin_lock(&state.lock);
-
/* Do we know this source address already? */
curr = *head;
while (curr != NULL) {
@@ -256,11 +253,9 @@ handle_packet4(const struct iphdr *iph, const struct tcphdr *tcph,
if (curr != NULL) {
/* We know this address, and the entry isn't too old. Update it. */
- if (entry_is_recent(curr, psdinfo->delay_threshold, now)) {
- if (is_portscan(curr, psdinfo, tcph, iph->protocol))
- goto out_match;
- 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. */
@@ -272,7 +267,7 @@ handle_packet4(const struct iphdr *iph, const struct tcphdr *tcph,
/* We don't need an ACK from a new source address */
if (iph->protocol == IPPROTO_TCP && tcph->ack)
- goto out_no_match;
+ 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
@@ -305,14 +300,7 @@ handle_packet4(const struct iphdr *iph, const struct tcphdr *tcph,
curr->weight = get_port_weight(psdinfo, tcph->dest);
curr->ports[0].number = tcph->dest;
curr->ports[0].proto = iph->protocol;
-
-out_no_match:
- spin_unlock(&state.lock);
return false;
-
-out_match:
- spin_unlock(&state.lock);
- return true;
}
static bool
@@ -321,6 +309,8 @@ 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;
+ int hash;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
@@ -340,7 +330,12 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
if (tcph == NULL)
return false;
- return handle_packet4(iph, tcph, psdinfo);
+ hash = hashfunc(iph->saddr);
+
+ spin_lock(&state.lock);
+ matched = handle_packet4(iph, tcph, psdinfo, hash);
+ spin_unlock(&state.lock);
+ return matched;
}
static int psd_mt_check(const struct xt_mtchk_param *par)
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 11/11] psd: add ipv6 support
2012-09-16 21:29 [PATCH 00/11][xt-addons] xt_psd: ipv6 support Florian Westphal
` (9 preceding siblings ...)
2012-09-16 21:29 ` [PATCH 10/11] xt_psd: move ipv4 state locking responsibility to caller Florian Westphal
@ 2012-09-16 21:29 ` Florian Westphal
10 siblings, 0 replies; 14+ messages in thread
From: Florian Westphal @ 2012-09-16 21:29 UTC (permalink / raw)
To: netfilter-devel
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.
---
extensions/libxt_psd.c | 2 +-
extensions/xt_psd.c | 234 ++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 220 insertions(+), 16 deletions(-)
diff --git a/extensions/libxt_psd.c b/extensions/libxt_psd.c
index bd03480..3f88ac4 100644
--- a/extensions/libxt_psd.c
+++ b/extensions/libxt_psd.c
@@ -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,
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index a5729e1..0b72477 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -22,13 +22,13 @@
#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 <net/ip.h>
+#include <net/ipv6.h>
#include "xt_psd.h"
#include "compat_xtables.h"
@@ -39,6 +39,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 +51,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
*/
@@ -87,8 +92,13 @@ 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.
+ * State information for IPv4 portscan detection.
* @list: list of source addresses
* @hash: pointers into the list
* @index: oldest entry to be replaced
@@ -100,6 +110,46 @@ static struct {
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)
+ return true;
+
+ state6.list = vzalloc(LIST_SIZE * sizeof(struct host6));
+ if (!state6.list)
+ return false;
+
+ state6.hash = vzalloc(HASH_SIZE * sizeof(struct host*));
+ if (!state6.hash) {
+ vfree(state6.list);
+ return false;
+ }
+ return true;
+}
+#endif
+
/*
* Convert an IP address into a hash table index.
*/
@@ -117,6 +167,12 @@ static unsigned int hashfunc(__be32 addr)
return hash & (HASH_SIZE - 1);
}
+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, u8 proto, u16 port)
{
int i;
@@ -338,6 +394,126 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
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_IPV6, IPPROTO_IPIP, 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;
@@ -359,25 +535,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);
+#ifdef WITH_IPV6
+ vfree(state6.list);
+ vfree(state6.hash);
+#endif
+ xt_unregister_matches(xt_psd_reg, ARRAY_SIZE(xt_psd_reg));
}
module_init(xt_psd_init);
--
1.7.8.6
^ permalink raw reply related [flat|nested] 14+ messages in thread