mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-07 05:05:12 +02:00
xt_TARPIT: honeypot and reset modes
Honeypot mode attempts to maintain a normal connection for the purpose of capturing payload packets. Reset mode provides the ability to send a reset packet in lieu of using the DROP or REJECT targets.
This commit is contained in:

committed by
Jan Engelhardt

parent
1a5c079e6b
commit
fa1348455d
@@ -48,12 +48,15 @@
|
||||
#include <net/route.h>
|
||||
#include <net/tcp.h>
|
||||
#include "compat_xtables.h"
|
||||
#include "xt_TARPIT.h"
|
||||
|
||||
static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct tcphdr _otcph, *oth, *tcph;
|
||||
unsigned int addr_type = RTN_UNSPEC;
|
||||
struct sk_buff *nskb;
|
||||
const struct iphdr *oldhdr;
|
||||
struct iphdr *niph;
|
||||
u_int16_t tmp;
|
||||
|
||||
@@ -66,16 +69,28 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
if (oth == NULL)
|
||||
return;
|
||||
|
||||
/* No replies for RST, FIN or !SYN,!ACK */
|
||||
if (oth->rst || oth->fin || (!oth->syn && !oth->ack))
|
||||
return;
|
||||
|
||||
/* Rate-limit replies to !SYN,ACKs */
|
||||
#if 0
|
||||
if (!oth->syn && oth->ack)
|
||||
if (!xrlim_allow(rt_dst(ort), HZ))
|
||||
if (mode == XTTARPIT_TARPIT) {
|
||||
/* No replies for RST, FIN or !SYN,!ACK */
|
||||
if (oth->rst || oth->fin || (!oth->syn && !oth->ack))
|
||||
return;
|
||||
#if 0
|
||||
/* Rate-limit replies to !SYN,ACKs */
|
||||
if (!oth->syn && oth->ack)
|
||||
if (!xrlim_allow(rt_dst(ort), HZ))
|
||||
return;
|
||||
#endif
|
||||
} else if (mode == XTTARPIT_HONEYPOT) {
|
||||
/* Do not answer any resets regardless of combination */
|
||||
if (oth->rst || oth->seq == 0xDEADBEEF)
|
||||
return;
|
||||
} else if (mode == XTTARPIT_RESET) {
|
||||
tcph->window = 0;
|
||||
tcph->ack = false;
|
||||
tcph->syn = false;
|
||||
tcph->rst = true;
|
||||
tcph->seq = oth->ack_seq;
|
||||
tcph->ack_seq = oth->seq;
|
||||
}
|
||||
|
||||
/* Check checksum. */
|
||||
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
|
||||
@@ -102,6 +117,7 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
skb_shinfo(nskb)->gso_type = 0;
|
||||
#endif
|
||||
|
||||
oldhdr = ip_hdr(oldskb);
|
||||
tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));
|
||||
|
||||
/* Swap source and dest */
|
||||
@@ -115,24 +131,63 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
tcph->doff = sizeof(struct tcphdr) / 4;
|
||||
skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
|
||||
niph->tot_len = htons(nskb->len);
|
||||
|
||||
/* Use supplied sequence number or make a new one */
|
||||
tcph->seq = oth->ack ? oth->ack_seq : 0;
|
||||
|
||||
/* Our SYN-ACKs must have a >0 window */
|
||||
tcph->window = (oth->syn && !oth->ack) ? htons(5) : 0;
|
||||
tcph->urg_ptr = 0;
|
||||
|
||||
/* Reset flags */
|
||||
((u_int8_t *)tcph)[13] = 0;
|
||||
|
||||
if (oth->syn && oth->ack) {
|
||||
tcph->rst = true;
|
||||
tcph->ack_seq = false;
|
||||
} else {
|
||||
tcph->syn = oth->syn;
|
||||
tcph->ack = 1;
|
||||
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
|
||||
if (mode == XTTARPIT_TARPIT) {
|
||||
/* Use supplied sequence number or make a new one */
|
||||
tcph->seq = oth->ack ? oth->ack_seq : 0;
|
||||
|
||||
/* Our SYN-ACKs must have a >0 window */
|
||||
tcph->window = (oth->syn && !oth->ack) ? htons(5) : 0;
|
||||
if (oth->syn && oth->ack) {
|
||||
tcph->rst = true;
|
||||
tcph->ack_seq = false;
|
||||
} else {
|
||||
tcph->syn = oth->syn;
|
||||
tcph->ack = true;
|
||||
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
|
||||
}
|
||||
} else if (mode == XTTARPIT_HONEYPOT) {
|
||||
/* Send a reset to scanners. They like that. */
|
||||
if (oth->syn && oth->ack) {
|
||||
tcph->window = 0;
|
||||
tcph->ack = false;
|
||||
tcph->psh = true;
|
||||
tcph->ack_seq = 0xdeadbeef; /* see if they ack it */
|
||||
tcph->seq = oth->ack_seq;
|
||||
tcph->rst = true;
|
||||
}
|
||||
/* SYN > SYN-ACK */
|
||||
if (oth->syn && !oth->ack) {
|
||||
tcph->syn = true;
|
||||
tcph->ack = true;
|
||||
tcph->window = oth->window;
|
||||
tcph->ack_seq = oth->seq;
|
||||
tcph->seq = htonl(net_random() | ~oth->seq);
|
||||
}
|
||||
/* ACK > ACK */
|
||||
if (oth->ack && !oth->fin && !oth->syn) {
|
||||
tcph->syn = false;
|
||||
tcph->ack = true;
|
||||
tcph->window = oth->window &
|
||||
((net_random() & 0x1f) - 0xf);
|
||||
tcph->ack_seq = htonl(ntohl(oth->seq) + 1);
|
||||
tcph->seq = oth->ack_seq;
|
||||
}
|
||||
/*
|
||||
* FIN > RST.
|
||||
* We cannot terminate gracefully so just be abrupt.
|
||||
*/
|
||||
if (oth->fin) {
|
||||
tcph->window = 0;
|
||||
tcph->seq = oth->ack_seq;
|
||||
tcph->ack_seq = oth->ack_seq;
|
||||
tcph->fin = false;
|
||||
tcph->ack = false;
|
||||
tcph->rst = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust TCP checksum */
|
||||
@@ -149,7 +204,10 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
|
||||
/* Set DF, id = 0 */
|
||||
niph->frag_off = htons(IP_DF);
|
||||
niph->id = 0;
|
||||
if (mode == XTTARPIT_TARPIT)
|
||||
niph->id = 0;
|
||||
else if (mode == XTTARPIT_HONEYPOT)
|
||||
niph->id = ~oldhdr->id + 1;
|
||||
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
|
||||
@@ -193,6 +251,7 @@ tarpit_tg(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
const struct sk_buff *skb = *pskb;
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
const struct rtable *rt = skb_rtable(skb);
|
||||
const struct xt_tarpit_tginfo *info = par->targinfo;
|
||||
|
||||
/* Do we have an input route cache entry? (Not in PREROUTING.) */
|
||||
if (rt == NULL)
|
||||
@@ -218,19 +277,20 @@ tarpit_tg(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
if (iph->frag_off & htons(IP_OFFSET))
|
||||
return NF_DROP;
|
||||
|
||||
tarpit_tcp(*pskb, par->hooknum);
|
||||
tarpit_tcp(*pskb, par->hooknum, info->variant);
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
static struct xt_target tarpit_tg_reg __read_mostly = {
|
||||
.name = "TARPIT",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.table = "filter",
|
||||
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
|
||||
.proto = IPPROTO_TCP,
|
||||
.target = tarpit_tg,
|
||||
.me = THIS_MODULE,
|
||||
.name = "TARPIT",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.table = "filter",
|
||||
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
|
||||
.proto = IPPROTO_TCP,
|
||||
.target = tarpit_tg,
|
||||
.targetsize = sizeof(struct xt_tarpit_tginfo),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init tarpit_tg_init(void)
|
||||
|
Reference in New Issue
Block a user