* [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support
@ 2012-09-17 12:55 Florian Westphal
2012-09-17 12:55 ` [PATCH 1/7] xt_psd: remove unneeded variables, make hash unsigned Florian Westphal
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 UTC (permalink / raw)
To: netfilter-devel
Changes since v1:
- rebased on top of xt-addons.git psd branch
- patch1: convert all int hash declarations to unsigned int
- patch7: use if (foo != NULL) instead of (!foo) where appropriate
There are no other changes.
The following changes since commit 093f3b0a975d2be97ba33426ceead8d205bca2f6:
xt_psd: move match functionality to helpers (2012-09-17 04:44:29 +0200)
are available in the git repository at:
git://git.breakpoint.cc/fw/xtables-addons.git psd_12
Florian Westphal (7):
xt_psd: remove unneeded variables, make hash unsigned
xt_psd: split struct host into generic and af-dependent structure
xt_psd: move table cleanup into helper
xt_psd: use tcph->dest directly
xt_psd: move l4 header fetching into helper
xt_psd: move ipv4 state locking responsibility to caller
psd: add ipv6 support
extensions/libxt_psd.c | 2 +-
extensions/xt_psd.c | 463 +++++++++++++++++++++++++++++++++++-------------
2 files changed, 340 insertions(+), 125 deletions(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/7] xt_psd: remove unneeded variables, make hash unsigned
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
@ 2012-09-17 12:55 ` Florian Westphal
2012-09-17 12:55 ` [PATCH 2/7] xt_psd: split struct host into generic and af-dependent structure Florian Westphal
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 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 | 28 +++++++++++-----------------
1 files changed, 11 insertions(+), 17 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index dbe422b..dc9b006 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;
+ unsigned int hash;
- value = addr.s_addr;
+ value = (unsigned int) addr;
hash = 0;
do {
hash ^= value;
@@ -182,12 +181,12 @@ 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;
- int hash, count = 0;
+ int count = 0;
+ unsigned int hash;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
@@ -198,10 +197,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;
}
@@ -213,14 +211,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");
@@ -228,7 +224,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);
@@ -236,7 +232,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);
@@ -279,7 +275,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;
@@ -310,10 +306,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] 9+ messages in thread
* [PATCH 2/7] xt_psd: split struct host into generic and af-dependent structure
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
2012-09-17 12:55 ` [PATCH 1/7] xt_psd: remove unneeded variables, make hash unsigned Florian Westphal
@ 2012-09-17 12:55 ` Florian Westphal
2012-09-17 12:55 ` [PATCH 3/7] xt_psd: move table cleanup into helper Florian Westphal
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 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 dc9b006..7eaf91a 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;
@@ -185,6 +197,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 count = 0;
unsigned int hash;
/* Parameters from userspace */
@@ -232,7 +245,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);
@@ -254,7 +268,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;
}
@@ -274,14 +289,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;
@@ -296,7 +312,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;
@@ -306,7 +323,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] 9+ messages in thread
* [PATCH 3/7] xt_psd: move table cleanup into helper
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
2012-09-17 12:55 ` [PATCH 1/7] xt_psd: remove unneeded variables, make hash unsigned Florian Westphal
2012-09-17 12:55 ` [PATCH 2/7] xt_psd: split struct host into generic and af-dependent structure Florian Westphal
@ 2012-09-17 12:55 ` Florian Westphal
2012-09-17 12:55 ` [PATCH 4/7] xt_psd: use tcph->dest directly Florian Westphal
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 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 7eaf91a..352c11a 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -183,6 +183,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)
{
@@ -284,36 +303,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] 9+ messages in thread
* [PATCH 4/7] xt_psd: use tcph->dest directly
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
` (2 preceding siblings ...)
2012-09-17 12:55 ` [PATCH 3/7] xt_psd: move table cleanup into helper Florian Westphal
@ 2012-09-17 12:55 ` Florian Westphal
2012-09-17 12:55 ` [PATCH 5/7] xt_psd: move l4 header fetching into helper Florian Westphal
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 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 352c11a..09251e7 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -137,15 +137,22 @@ static uint16_t get_port_weight(const struct xt_psd_info *psd, __be16 port)
static bool
is_portscan(struct host *host, const struct xt_psd_info *psdinfo,
- uint8_t proto, __be16 dest_port)
+ 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, 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)
@@ -153,7 +160,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++;
}
@@ -207,12 +214,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;
@@ -241,15 +246,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;
@@ -274,13 +275,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;
}
@@ -325,8 +320,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] 9+ messages in thread
* [PATCH 5/7] xt_psd: move l4 header fetching into helper
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
` (3 preceding siblings ...)
2012-09-17 12:55 ` [PATCH 4/7] xt_psd: use tcph->dest directly Florian Westphal
@ 2012-09-17 12:55 ` Florian Westphal
2012-09-17 12:55 ` [PATCH 6/7] xt_psd: move ipv4 state locking responsibility to caller Florian Westphal
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 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 09251e7..9c52426 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -209,52 +209,36 @@ 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 count = 0;
unsigned int hash;
- /* 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);
@@ -275,7 +259,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;
}
@@ -289,7 +273,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
@@ -322,7 +306,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);
@@ -333,6 +317,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] 9+ messages in thread
* [PATCH 6/7] xt_psd: move ipv4 state locking responsibility to caller
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
` (4 preceding siblings ...)
2012-09-17 12:55 ` [PATCH 5/7] xt_psd: move l4 header fetching into helper Florian Westphal
@ 2012-09-17 12:55 ` Florian Westphal
2012-09-17 12:55 ` [PATCH 7/7] psd: add ipv6 support Florian Westphal
2012-09-18 5:33 ` [PATCH v2 0/7][xt-addons] xt_psd: " Jan Engelhardt
7 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 UTC (permalink / raw)
To: netfilter-devel
former psd_match function is now < 72 lines.
---
extensions/xt_psd.c | 32 +++++++++++++-------------------
1 files changed, 13 insertions(+), 19 deletions(-)
diff --git a/extensions/xt_psd.c b/extensions/xt_psd.c
index 9c52426..fbb9e22 100644
--- a/extensions/xt_psd.c
+++ b/extensions/xt_psd.c
@@ -232,20 +232,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, unsigned int hash)
{
unsigned long now;
struct host *curr, *last = NULL, **head;
struct host4 *curr4;
int count = 0;
- unsigned int hash;
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) {
@@ -258,11 +254,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. */
@@ -274,7 +268,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
@@ -307,14 +301,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
@@ -323,6 +310,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;
+ unsigned int hash;
/* Parameters from userspace */
const struct xt_psd_info *psdinfo = match->matchinfo;
@@ -342,7 +331,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] 9+ messages in thread
* [PATCH 7/7] psd: add ipv6 support
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
` (5 preceding siblings ...)
2012-09-17 12:55 ` [PATCH 6/7] xt_psd: move ipv4 state locking responsibility to caller Florian Westphal
@ 2012-09-17 12:55 ` Florian Westphal
2012-09-18 5:33 ` [PATCH v2 0/7][xt-addons] xt_psd: " Jan Engelhardt
7 siblings, 0 replies; 9+ messages in thread
From: Florian Westphal @ 2012-09-17 12:55 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 fbb9e22..53eeb66 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 != NULL)
+ return true;
+
+ state6.list = vzalloc(LIST_SIZE * sizeof(struct host6));
+ if (state6.list == NULL)
+ return false;
+
+ state6.hash = vzalloc(HASH_SIZE * sizeof(struct host*));
+ if (state6.hash == NULL) {
+ 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, uint8_t proto, uint16_t port)
{
unsigned int i;
@@ -339,6 +395,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_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;
@@ -360,25 +536,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);
--
1.7.8.6
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
` (6 preceding siblings ...)
2012-09-17 12:55 ` [PATCH 7/7] psd: add ipv6 support Florian Westphal
@ 2012-09-18 5:33 ` Jan Engelhardt
7 siblings, 0 replies; 9+ messages in thread
From: Jan Engelhardt @ 2012-09-18 5:33 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Monday 2012-09-17 14:55, Florian Westphal wrote:
>The following changes since commit 093f3b0a975d2be97ba33426ceead8d205bca2f6:
>
> xt_psd: move match functionality to helpers (2012-09-17 04:44:29 +0200)
>
>are available in the git repository at:
> git://git.breakpoint.cc/fw/xtables-addons.git psd_12
>
>Florian Westphal (7):
all done.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2012-09-18 5:33 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-17 12:55 [PATCH v2 0/7][xt-addons] xt_psd: ipv6 support Florian Westphal
2012-09-17 12:55 ` [PATCH 1/7] xt_psd: remove unneeded variables, make hash unsigned Florian Westphal
2012-09-17 12:55 ` [PATCH 2/7] xt_psd: split struct host into generic and af-dependent structure Florian Westphal
2012-09-17 12:55 ` [PATCH 3/7] xt_psd: move table cleanup into helper Florian Westphal
2012-09-17 12:55 ` [PATCH 4/7] xt_psd: use tcph->dest directly Florian Westphal
2012-09-17 12:55 ` [PATCH 5/7] xt_psd: move l4 header fetching into helper Florian Westphal
2012-09-17 12:55 ` [PATCH 6/7] xt_psd: move ipv4 state locking responsibility to caller Florian Westphal
2012-09-17 12:55 ` [PATCH 7/7] psd: add ipv6 support Florian Westphal
2012-09-18 5:33 ` [PATCH v2 0/7][xt-addons] xt_psd: " Jan Engelhardt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).