summaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-15 03:32:22 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-15 03:32:22 +0000
commitf1da2c3860e301527d56a1ef0b56c649ee7c4b1b (patch)
tree562b5d2e8b9cb62eb983d78ff6bcf9789e08fcf6 /net/ipv4
parent00f11569ac8ca73cbcdef8822de1583e79aee571 (diff)
Merge with Linux 2.4.0-test5-pre1. This works again on Origin UP.
The IP22 cache bugs which are plaguing some machines are still unfixed.
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c19
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c11
-rw-r--r--net/ipv4/netfilter/ip_fw_compat.c3
-rw-r--r--net/ipv4/netfilter/ip_fw_compat_masq.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_core.c20
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c5
-rw-r--r--net/ipv4/netfilter/ip_queue.c5
-rw-r--r--net/ipv4/netfilter/ip_tables.c2
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c131
-rw-r--r--net/ipv4/tcp_ipv4.c6
10 files changed, 186 insertions, 18 deletions
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 47e7fb01b..14ebb46e1 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -551,6 +551,7 @@ static inline struct ip_conntrack *
resolve_normal_ct(struct sk_buff *skb,
struct ip_conntrack_protocol *proto,
int *set_reply,
+ unsigned int hooknum,
enum ip_conntrack_info *ctinfo)
{
struct ip_conntrack_tuple tuple;
@@ -573,6 +574,21 @@ resolve_normal_ct(struct sk_buff *skb,
if (DIRECTION(h) == IP_CT_DIR_REPLY) {
/* Reply on unconfirmed connection => unclassifiable */
if (!(h->ctrack->status & IPS_CONFIRMED)) {
+ /* Exception: local TCP RSTs (generated by
+ REJECT target). */
+ if (hooknum == NF_IP_LOCAL_OUT
+ && h->tuple.dst.protonum == IPPROTO_TCP) {
+ const struct tcphdr *tcph
+ = (const struct tcphdr *)
+ ((u_int32_t *)skb->nh.iph
+ + skb->nh.iph->ihl);
+ if (tcph->rst) {
+ *ctinfo = IP_CT_ESTABLISHED
+ + IP_CT_IS_REPLY;
+ *set_reply = 0;
+ goto set_skb;
+ }
+ }
DEBUGP("Reply on unconfirmed connection\n");
ip_conntrack_put(h->ctrack);
return NULL;
@@ -598,6 +614,7 @@ resolve_normal_ct(struct sk_buff *skb,
}
*set_reply = 0;
}
+ set_skb:
skb->nfct = &h->ctrack->infos[*ctinfo];
return h->ctrack;
}
@@ -669,7 +686,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
&& icmp_error_track(*pskb, &ctinfo, hooknum))
return NF_ACCEPT;
- if (!(ct = resolve_normal_ct(*pskb, proto, &set_reply, &ctinfo)))
+ if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
/* Not valid part of a connection */
return NF_ACCEPT;
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index 77db6572f..486683bec 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -169,11 +169,15 @@ static unsigned int ip_confirm(unsigned int hooknum,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- /* We've seen it coming out the other side: confirm */
+ /* We've seen it coming out the other side: confirm (only if
+ new packet: REJECT can generate TCP RESET response, or ICMP
+ errors) */
if ((*pskb)->nfct) {
struct ip_conntrack *ct
= (struct ip_conntrack *)(*pskb)->nfct->master;
- if (!(ct->status & IPS_CONFIRMED))
+ /* ctinfo is the index of the nfct inside the conntrack */
+ if ((*pskb)->nfct - ct->infos == IP_CT_NEW
+ && !(ct->status & IPS_CONFIRMED))
ip_conntrack_confirm(ct);
}
return NF_ACCEPT;
@@ -191,7 +195,8 @@ static unsigned int ip_refrag(unsigned int hooknum,
if ((*pskb)->nfct) {
struct ip_conntrack *ct
= (struct ip_conntrack *)(*pskb)->nfct->master;
- if (!(ct->status & IPS_CONFIRMED))
+ if ((*pskb)->nfct - ct->infos == IP_CT_NEW
+ && !(ct->status & IPS_CONFIRMED))
ip_conntrack_confirm(ct);
}
diff --git a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c
index 6f0503e05..3c8c2e851 100644
--- a/net/ipv4/netfilter/ip_fw_compat.c
+++ b/net/ipv4/netfilter/ip_fw_compat.c
@@ -71,7 +71,8 @@ confirm_connection(struct sk_buff *skb)
struct ip_conntrack *ct
= (struct ip_conntrack *)skb->nfct->master;
- if (!(ct->status & IPS_CONFIRMED))
+ if (skb->nfct - ct->infos == IP_CT_NEW
+ && !(ct->status & IPS_CONFIRMED))
ip_conntrack_confirm(ct);
}
}
diff --git a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c
index 1e6721174..ce3180d39 100644
--- a/net/ipv4/netfilter/ip_fw_compat_masq.c
+++ b/net/ipv4/netfilter/ip_fw_compat_masq.c
@@ -105,7 +105,7 @@ check_for_masq_error(struct sk_buff *skb)
/* Wouldn't be here if not tracked already => masq'ed ICMP
ping or error related to masq'd connection */
IP_NF_ASSERT(ct);
- if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
+ if (ctinfo == IP_CT_RELATED) {
icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING,
CTINFO2DIR(ctinfo));
icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING,
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
index a07749ecb..c8bf259b9 100644
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -735,7 +735,7 @@ do_bindings(struct ip_conntrack *ct,
} else return NF_ACCEPT;
}
-void
+unsigned int
icmp_reply_translation(struct sk_buff *skb,
struct ip_conntrack *conntrack,
unsigned int hooknum,
@@ -749,6 +749,22 @@ icmp_reply_translation(struct sk_buff *skb,
struct ip_nat_info *info = &conntrack->nat.info;
IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
+ /* Must be RELATED */
+ IP_NF_ASSERT(skb->nfct - (struct ip_conntrack *)skb->nfct->master
+ == IP_CT_RELATED
+ || skb->nfct - (struct ip_conntrack *)skb->nfct->master
+ == IP_CT_RELATED+IP_CT_IS_REPLY);
+
+ /* Redirects on non-null nats must be dropped, else they'll
+ start talking to each other without our translation, and be
+ confused... --RR */
+ if (hdr->type == ICMP_REDIRECT) {
+ /* Don't care about races here. */
+ if (info->initialized
+ != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
+ || info->num_manips != 0)
+ return NF_DROP;
+ }
DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
@@ -810,6 +826,8 @@ icmp_reply_translation(struct sk_buff *skb,
hdr->checksum = 0;
hdr->checksum = ip_compute_csum((unsigned char *)hdr,
sizeof(*hdr) + datalen);
+
+ return NF_ACCEPT;
}
int ip_nat_helper_register(struct ip_nat_helper *me)
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 11e16e25e..3334a64c2 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -84,9 +84,8 @@ ip_nat_fn(unsigned int hooknum,
case IP_CT_RELATED:
case IP_CT_RELATED+IP_CT_IS_REPLY:
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
- icmp_reply_translation(*pskb, ct, hooknum,
- CTINFO2DIR(ctinfo));
- return NF_ACCEPT;
+ return icmp_reply_translation(*pskb, ct, hooknum,
+ CTINFO2DIR(ctinfo));
}
/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
case IP_CT_NEW:
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 792ae1552..39574b7d4 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -244,7 +244,7 @@ static int ipq_set_verdict(ipq_queue_t *q,
{
ipq_queue_element_t *e;
- if (v->value < 0 || v->value > NF_MAX_VERDICT)
+ if (v->value > NF_MAX_VERDICT)
return -EINVAL;
e = ipq_dequeue(q, id_cmp, v->id);
if (e == NULL)
@@ -309,10 +309,9 @@ static inline int dev_cmp(ipq_queue_element_t *e, unsigned long ifindex)
if (e->info->indev->ifindex == ifindex)
return 1;
if (e->info->outdev)
- if (e->info->outdev->ifindex == ifindex);
+ if (e->info->outdev->ifindex == ifindex)
return 1;
return 0;
-
}
/* Drop any queued packets associated with device ifindex */
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 3105f5a18..40b19760b 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1029,7 +1029,7 @@ get_entries(const struct ipt_get_entries *entries,
t->private->number);
if (entries->size == t->private->size)
ret = copy_entries_to_user(t->private->size,
- t, uptr->entries);
+ t, uptr->entrytable);
else {
duprintf("get_entries: I've got %u not %u!\n",
t->private->size,
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 220cdb568..c63e95fe8 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -7,6 +7,7 @@
#include <linux/ip.h>
#include <net/icmp.h>
#include <net/ip.h>
+#include <net/tcp.h>
struct in_device;
#include <net/route.h>
#include <linux/netfilter_ipv4/ip_tables.h>
@@ -18,6 +19,113 @@ struct in_device;
#define DEBUGP(format, args...)
#endif
+/* Send RST reply */
+static void send_reset(struct sk_buff *oldskb)
+{
+ struct sk_buff *nskb;
+ struct tcphdr *tcph;
+ struct rtable *rt;
+ unsigned int tcplen;
+ int needs_ack;
+
+ /* Clone skb (skb is about to be dropped, so we don't care) */
+ nskb = skb_clone(oldskb, 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
+
+ /* IP header checks: fragment, too short. */
+ if (nskb->nh.iph->frag_off & htons(IP_OFFSET)
+ || nskb->len < (nskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
+ goto free_nskb;
+
+ tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
+ tcplen = nskb->len - nskb->nh.iph->ihl*4;
+
+ /* Check checksum. */
+ if (tcp_v4_check(tcph, tcplen, nskb->nh.iph->saddr,
+ nskb->nh.iph->daddr,
+ csum_partial((char *)tcph, tcplen, 0)) != 0)
+ goto free_nskb;
+
+ /* No RST for RST. */
+ if (tcph->rst)
+ goto free_nskb;
+
+ nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
+ tcph->source = xchg(&tcph->dest, tcph->source);
+
+ /* Truncate to length (no data) */
+ tcph->doff = sizeof(struct tcphdr)/4;
+ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
+
+ if (tcph->ack) {
+ needs_ack = 0;
+ tcph->seq = tcph->ack_seq;
+ tcph->ack_seq = 0;
+ } else {
+ needs_ack = 1;
+ tcph->seq = 0;
+ tcph->ack_seq = htonl(ntohl(tcph->seq) + tcph->syn + tcph->fin
+ + tcplen - (tcph->doff<<2));
+ }
+
+ /* Reset flags */
+ ((u_int8_t *)tcph)[13] = 0;
+ tcph->rst = 1;
+ if (needs_ack)
+ tcph->ack = 1;
+
+ tcph->window = 0;
+ tcph->urg_ptr = 0;
+
+ /* Adjust TCP checksum */
+ tcph->check = 0;
+ tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
+ nskb->nh.iph->saddr,
+ nskb->nh.iph->daddr,
+ csum_partial((char *)tcph,
+ sizeof(struct tcphdr), 0));
+
+ /* Adjust IP TTL, DF */
+ nskb->nh.iph->ttl = MAXTTL;
+ /* 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);
+
+ /* Routing */
+ if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
+ RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
+ 0) != 0)
+ goto free_nskb;
+
+ dst_release(nskb->dst);
+ nskb->dst = &rt->u.dst;
+
+ /* "Never happens" */
+ if (nskb->len > nskb->dst->pmtu)
+ goto free_nskb;
+
+ NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
+ ip_finish_output);
+ return;
+
+ free_nskb:
+ kfree_skb(nskb);
+}
+
static unsigned int reject(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
@@ -43,6 +151,12 @@ static unsigned int reject(struct sk_buff **pskb,
case IPT_ICMP_PORT_UNREACHABLE:
icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
break;
+ case IPT_ICMP_NET_PROHIBITED:
+ icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
+ break;
+ case IPT_ICMP_HOST_PROHIBITED:
+ icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
+ break;
case IPT_ICMP_ECHOREPLY: {
struct icmphdr *icmph = (struct icmphdr *)
((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
@@ -64,6 +178,9 @@ static unsigned int reject(struct sk_buff **pskb,
}
}
break;
+ case IPT_TCP_RESET:
+ send_reset(*pskb);
+ break;
}
return NF_DROP;
@@ -96,7 +213,7 @@ static int check(const char *tablename,
/* Only allow these for packet filtering. */
if (strcmp(tablename, "filter") != 0) {
- DEBUGP("REJECT: bad table `%s'.\n", table);
+ DEBUGP("REJECT: bad table `%s'.\n", tablename);
return 0;
}
if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
@@ -118,6 +235,18 @@ static int check(const char *tablename,
DEBUGP("REJECT: ECHOREPLY illegal for non-ping\n");
return 0;
}
+ } else if (rejinfo->with == IPT_TCP_RESET) {
+ /* Must specify that it's a TCP packet */
+ if (e->ip.proto != IPPROTO_TCP
+ || (e->ip.invflags & IPT_INV_PROTO)) {
+ DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
+ return 0;
+ }
+ /* Only for local input. Rest is too dangerous. */
+ if ((hook_mask & ~(1 << NF_IP_LOCAL_IN)) != 0) {
+ DEBUGP("REJECT: TCP_RESET only from INPUT\n");
+ return 0;
+ }
}
return 1;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 282024cc9..46f5e57e8 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.208 2000/05/03 06:37:06 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.209 2000/07/12 03:49:30 davem Exp $
*
* IPv4 specific functions
*
@@ -69,8 +69,8 @@ extern int sysctl_ip_dynaddr;
#define ICMP_MIN_LENGTH 8
/* Socket used for sending RSTs */
-struct inode tcp_inode;
-struct socket *tcp_socket=&tcp_inode.u.socket_i;
+static struct inode tcp_inode;
+static struct socket *tcp_socket=&tcp_inode.u.socket_i;
void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
struct sk_buff *skb);