From: Florian Fainelli Date: Sun, 17 Dec 2006 14:54:13 +0000 (+0000) Subject: Add TARPIT target (#1046) X-Git-Tag: whiterussian_0.9~41 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=e80d9d08ad37d1fca04b37b53bc3c2c531ba9e8e;p=openwrt%2Fsvn-archive%2Fopenwrt.git Add TARPIT target (#1046) SVN-Revision: 5819 --- diff --git a/openwrt/package/iptables/Config.in b/openwrt/package/iptables/Config.in index 7c5e136c70..d5171c09d1 100644 --- a/openwrt/package/iptables/Config.in +++ b/openwrt/package/iptables/Config.in @@ -49,6 +49,7 @@ config BR2_PACKAGE_IPTABLES_MOD_EXTRA * libipt_physdev * libipt_pkttype * libipt_recent + * libipt_TARPIT config BR2_PACKAGE_IPTABLES_MOD_FILTER tristate "iptables-mod-filter - Iptables extension for packet content inspection" diff --git a/openwrt/target/linux/linux-2.4/config/brcm b/openwrt/target/linux/linux-2.4/config/brcm index e5c9bb28d9..5318be549e 100644 --- a/openwrt/target/linux/linux-2.4/config/brcm +++ b/openwrt/target/linux/linux-2.4/config/brcm @@ -392,6 +392,7 @@ CONFIG_IP_NF_MATCH_PHYSDEV=m CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_TARGET_TARPIT=m CONFIG_IP_NF_NAT=y CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y diff --git a/openwrt/target/linux/linux-2.4/patches/generic/122-netfilter_TARPIT.patch b/openwrt/target/linux/linux-2.4/patches/generic/122-netfilter_TARPIT.patch new file mode 100644 index 0000000000..7580b5ad24 --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/generic/122-netfilter_TARPIT.patch @@ -0,0 +1,340 @@ +diff -urN linux-2.4-brcm.orig/Documentation/Configure.help linux-2.4-brcm/Documentation/Configure.help +--- linux-2.4-brcm.orig/Documentation/Configure.help 2006-12-08 20:40:01.000000000 +0000 ++++ linux-2.4-brcm/Documentation/Configure.help 2006-12-08 21:01:59.000000000 +0000 +@@ -3025,6 +3025,21 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++TARPIT target support ++CONFIG_IP_NF_TARGET_TARPIT ++ Adds a TARPIT target to iptables, which captures and holds ++ incoming TCP connections using no local per-connection resources. ++ Connections are accepted, but immediately switched to the persist ++ state (0 byte window), in which the remote side stops sending data ++ and asks to continue every 60-240 seconds. Attempts to close the ++ connection are ignored, forcing the remote side to time out the ++ connection in 12-24 minutes. ++ ++ This offers similar functionality to LaBrea ++ but doesn't require dedicated ++ hardware or IPs. Any TCP port that you would normally DROP or REJECT ++ can instead become a tarpit. ++ + REJECT target support + CONFIG_IP_NF_TARGET_REJECT + The REJECT target allows a filtering rule to specify that an ICMP +diff -urN linux-2.4-brcm.orig/net/ipv4/netfilter/Config.in linux-2.4-brcm/net/ipv4/netfilter/Config.in +--- linux-2.4-brcm.orig/net/ipv4/netfilter/Config.in 2006-12-08 20:39:48.000000000 +0000 ++++ linux-2.4-brcm/net/ipv4/netfilter/Config.in 2006-12-08 21:01:59.000000000 +0000 +@@ -68,6 +68,7 @@ + dep_tristate ' REJECT target support' CONFIG_IP_NF_TARGET_REJECT $CONFIG_IP_NF_FILTER + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' MIRROR target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_MIRROR $CONFIG_IP_NF_FILTER ++ dep_tristate ' TARPIT target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_TARPIT $CONFIG_IP_NF_FILTER + fi + fi + +diff -urN linux-2.4-brcm.orig/net/ipv4/netfilter/ipt_TARPIT.c linux-2.4-brcm/net/ipv4/netfilter/ipt_TARPIT.c +--- linux-2.4-brcm.orig/net/ipv4/netfilter/ipt_TARPIT.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4-brcm/net/ipv4/netfilter/ipt_TARPIT.c 2006-12-08 21:01:58.000000000 +0000 +@@ -0,0 +1,284 @@ ++/* ++ * Kernel module to capture and hold incoming TCP connections using ++ * no local per-connection resources. ++ * ++ * Based on ipt_REJECT.c and offering functionality similar to ++ * LaBrea . ++ * ++ * Copyright (c) 2002 Aaron Hopkins ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Goal: ++ * - Allow incoming TCP connections to be established. ++ * - Passing data should result in the connection being switched to the ++ * persist state (0 byte window), in which the remote side stops sending ++ * data and asks to continue every 60 seconds. ++ * - Attempts to shut down the connection should be ignored completely, so ++ * the remote side ends up having to time it out. ++ * ++ * This means: ++ * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes ++ * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing ++ * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++struct in_device; ++#include ++#include ++#include ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++ ++/* Stolen from ip_finish_output2 */ ++static int ip_direct_send(struct sk_buff *skb) ++{ ++ struct dst_entry *dst = skb->dst; ++ struct hh_cache *hh = dst->hh; ++ ++ if (hh) { ++ read_lock_bh(&hh->hh_lock); ++ memcpy(skb->data - 16, hh->hh_data, 16); ++ read_unlock_bh(&hh->hh_lock); ++ skb_push(skb, hh->hh_len); ++ return hh->hh_output(skb); ++ } else if (dst->neighbour) ++ return dst->neighbour->output(skb); ++ ++ if (net_ratelimit()) ++ printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n"); ++ kfree_skb(skb); ++ return -EINVAL; ++} ++ ++ ++/* Send reply */ ++static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local) ++{ ++ struct sk_buff *nskb; ++ struct rtable *nrt; ++ struct tcphdr *otcph, *ntcph; ++ unsigned int otcplen; ++ u_int16_t tmp; ++ ++ /* A truncated TCP header isn't going to be useful */ ++ if (oskb->len < (oskb->nh.iph->ihl*4) + sizeof(struct tcphdr)) ++ return; ++ ++ otcph = (struct tcphdr *)((u_int32_t*)oskb->nh.iph ++ + oskb->nh.iph->ihl); ++ otcplen = oskb->len - oskb->nh.iph->ihl*4; ++ ++ /* No replies for RST or FIN */ ++ if (otcph->rst || otcph->fin) ++ return; ++ ++ /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */ ++ if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ))) ++ return; ++ ++ /* Check checksum. */ ++ if (tcp_v4_check(otcph, otcplen, oskb->nh.iph->saddr, ++ oskb->nh.iph->daddr, ++ csum_partial((char *)otcph, otcplen, 0)) != 0) ++ return; ++ ++ /* Copy skb (even if skb is about to be dropped, we can't just ++ clone it because there may be other things, such as tcpdump, ++ interested in it) */ ++ nskb = skb_copy(oskb, GFP_ATOMIC); ++ if (!nskb) ++ return; ++ ++ /* This packet will not be the same as the other: clear nf fields */ ++ nf_conntrack_put(nskb->nfct); ++ nskb->nfct = NULL; ++ nskb->nfcache = 0; ++#ifdef CONFIG_NETFILTER_DEBUG ++ nskb->nf_debug = 0; ++#endif ++ ++ ntcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); ++ ++ /* Truncate to length (no data) */ ++ ntcph->doff = sizeof(struct tcphdr)/4; ++ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); ++ nskb->nh.iph->tot_len = htons(nskb->len); ++ ++ /* Swap source and dest */ ++ nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); ++ tmp = ntcph->source; ++ ntcph->source = ntcph->dest; ++ ntcph->dest = tmp; ++ ++ /* Use supplied sequence number or make a new one */ ++ ntcph->seq = otcph->ack ? otcph->ack_seq ++ : htonl(secure_tcp_sequence_number(nskb->nh.iph->saddr, ++ nskb->nh.iph->daddr, ++ ntcph->source, ++ ntcph->dest)); ++ ++ /* Our SYN-ACKs must have a >0 window */ ++ ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0; ++ ++ ntcph->urg_ptr = 0; ++ ++ /* Reset flags */ ++ ((u_int8_t *)ntcph)[13] = 0; ++ ++ if (otcph->syn && otcph->ack) { ++ ntcph->rst = 1; ++ ntcph->ack_seq = 0; ++ } else { ++ ntcph->syn = otcph->syn; ++ ntcph->ack = 1; ++ ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn); ++ } ++ ++ /* Adjust TCP checksum */ ++ ntcph->check = 0; ++ ntcph->check = tcp_v4_check(ntcph, sizeof(struct tcphdr), ++ nskb->nh.iph->saddr, ++ nskb->nh.iph->daddr, ++ csum_partial((char *)ntcph, ++ sizeof(struct tcphdr), 0)); ++ ++ /* Adjust IP TTL */ ++ nskb->nh.iph->ttl = sysctl_ip_default_ttl; ++ ++ /* Set DF, id = 0 */ ++ nskb->nh.iph->frag_off = htons(IP_DF); ++ nskb->nh.iph->id = 0; ++ ++ /* Adjust IP checksum */ ++ nskb->nh.iph->check = 0; ++ nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, ++ nskb->nh.iph->ihl); ++ ++ if (ip_route_output(&nrt, nskb->nh.iph->daddr, ++ local ? nskb->nh.iph->saddr : 0, ++ RT_TOS(nskb->nh.iph->tos) | RTO_CONN, ++ 0) != 0) ++ goto free_nskb; ++ ++ dst_release(nskb->dst); ++ nskb->dst = &nrt->u.dst; ++ ++ /* "Never happens" */ ++ if (nskb->len > nskb->dst->pmtu) ++ goto free_nskb; ++ ++ ip_direct_send (nskb); ++ ++ return; ++ ++ free_nskb: ++ kfree_skb(nskb); ++} ++ ++ ++static unsigned int tarpit(struct sk_buff **pskb, ++ unsigned int hooknum, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *targinfo, ++ void *userinfo) ++{ ++ struct sk_buff *skb = *pskb; ++ struct rtable *rt = (struct rtable*)skb->dst; ++ ++ /* Do we have an input route cache entry? */ ++ if (!rt) ++ return NF_DROP; ++ ++ /* No replies to physical multicast/broadcast */ ++ if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST) ++ return NF_DROP; ++ ++ /* Now check at the protocol level */ ++ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) ++ return NF_DROP; ++ ++ /* Our naive response construction doesn't deal with IP ++ options, and probably shouldn't try. */ ++ if (skb->nh.iph->ihl*4 != sizeof(struct iphdr)) ++ return NF_DROP; ++ ++ /* We aren't interested in fragments */ ++ if (skb->nh.iph->frag_off & htons(IP_OFFSET)) ++ return NF_DROP; ++ ++ tarpit_tcp(skb,rt,hooknum == NF_IP_LOCAL_IN); ++ ++ return NF_DROP; ++} ++ ++ ++static int check(const char *tablename, ++ const struct ipt_entry *e, ++ void *targinfo, ++ unsigned int targinfosize, ++ unsigned int hook_mask) ++{ ++ /* Only allow these for input/forward packet filtering. */ ++ if (strcmp(tablename, "filter") != 0) { ++ DEBUGP("TARPIT: bad table %s'.\n", tablename); ++ return 0; ++ } ++ if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) ++ | (1 << NF_IP_FORWARD))) != 0) { ++ DEBUGP("TARPIT: bad hook mask %X\n", hook_mask); ++ return 0; ++ } ++ ++ /* Must specify that it's a TCP packet */ ++ if (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO)) { ++ DEBUGP("TARPIT: not valid for non-tcp\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_target ipt_tarpit_reg ++= { { NULL, NULL }, "TARPIT", tarpit, check, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ if (ipt_register_target(&ipt_tarpit_reg)) ++ return -EINVAL; ++ return 0; ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_target(&ipt_tarpit_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4-brcm.orig/net/ipv4/netfilter/Makefile linux-2.4-brcm/net/ipv4/netfilter/Makefile +--- linux-2.4-brcm.orig/net/ipv4/netfilter/Makefile 2006-12-08 20:39:48.000000000 +0000 ++++ linux-2.4-brcm/net/ipv4/netfilter/Makefile 2006-12-08 21:01:59.000000000 +0000 +@@ -118,6 +118,7 @@ + obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o + obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o + obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o ++obj-$(CONFIG_IP_NF_TARGET_TARPIT) += ipt_TARPIT.o + obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o + obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o + obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o +Package: iptables-mod-tarpit +Priority: optional +Section: net +Depends: kmod-ipt-tarpit +Description: Iptables (IPv4) extension for tarpit diff --git a/openwrt/target/linux/netfilter.mk b/openwrt/target/linux/netfilter.mk index 36820f561c..632ea30cc4 100644 --- a/openwrt/target/linux/netfilter.mk +++ b/openwrt/target/linux/netfilter.mk @@ -17,6 +17,7 @@ IPT_EXTRA-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev IPT_EXTRA-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype IPT_EXTRA-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent IPT_EXTRA-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT +IPT_EXTRA-$(CONFIG_IP_NF_TARGET_TARPIT) += ipt_TARPIT IPT_FILTER-m := IPT_FILTER-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p