Commit 2c7ec252 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[IPV4]: Make ipt_REJECT use icmp_send again.

As it is ipt_REJECT doesn't work at all with IPsec.  Despite my efforts
previously in making the policy lookups work there I neglected to change
the final call to dst_output so the policy lookup is useless.

ipt_REJECT also had a number of deviations from icmp_send which seems to
be unjustified.  For examples it ignored source routing IP options.

There was a bug in icmp_send too :) It didn't set the ICMP type/code
values for the policy lookup.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dbbd405f
......@@ -518,14 +518,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
IPTOS_PREC_INTERNETCONTROL) :
iph->tos;
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
.saddr = saddr,
.tos = RT_TOS(tos) } },
.proto = IPPROTO_ICMP };
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
if (ip_options_echo(&icmp_param.replyopts, skb_in))
goto ende;
......@@ -544,13 +536,26 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
inet_sk(icmp_socket->sk)->tos = tos;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
if (icmp_param.replyopts.srr) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = icmp_param.replyopts.faddr,
.saddr = saddr,
.tos = RT_TOS(tos) } },
.proto = IPPROTO_ICMP };
ip_rt_put(rt);
{
struct flowi fl = {
.nl_u = {
.ip4_u = {
.daddr = icmp_param.replyopts.srr ?
icmp_param.replyopts.faddr :
iph->saddr,
.saddr = saddr,
.tos = RT_TOS(tos)
}
},
.proto = IPPROTO_ICMP,
.uli_u = {
.icmpt = {
.type = type,
.code = code
}
}
};
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
......
......@@ -220,146 +220,9 @@ static void send_reset(struct sk_buff *oldskb, int hook)
kfree_skb(nskb);
}
static void send_unreach(struct sk_buff *skb_in, int code)
static inline void send_unreach(struct sk_buff *skb_in, int code)
{
struct iphdr *iph;
struct icmphdr *icmph;
struct sk_buff *nskb;
u32 saddr;
u8 tos;
int hh_len, length;
struct rtable *rt = (struct rtable*)skb_in->dst;
unsigned char *data;
if (!rt)
return;
/* FIXME: Use sysctl number. --RR */
if (!xrlim_allow(&rt->u.dst, 1*HZ))
return;
iph = skb_in->nh.iph;
/* No replies to physical multicast/broadcast */
if (skb_in->pkt_type!=PACKET_HOST)
return;
/* Now check at the protocol level */
if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
return;
/* Only reply to fragment 0. */
if (iph->frag_off&htons(IP_OFFSET))
return;
/* If we send an ICMP error to an ICMP error a mess would result.. */
if (iph->protocol == IPPROTO_ICMP) {
struct icmphdr ihdr;
icmph = skb_header_pointer(skb_in, skb_in->nh.iph->ihl*4,
sizeof(ihdr), &ihdr);
if (!icmph)
return;
/* Between echo-reply (0) and timestamp (13),
everything except echo-request (8) is an error.
Also, anything greater than NR_ICMP_TYPES is
unknown, and hence should be treated as an error... */
if ((icmph->type < ICMP_TIMESTAMP
&& icmph->type != ICMP_ECHOREPLY
&& icmph->type != ICMP_ECHO)
|| icmph->type > NR_ICMP_TYPES)
return;
}
saddr = iph->daddr;
if (!(rt->rt_flags & RTCF_LOCAL))
saddr = 0;
tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
{
struct flowi fl = {
.nl_u = {
.ip4_u = {
.daddr = skb_in->nh.iph->saddr,
.saddr = saddr,
.tos = RT_TOS(tos)
}
},
.proto = IPPROTO_ICMP,
.uli_u = {
.icmpt = {
.type = ICMP_DEST_UNREACH,
.code = code
}
}
};
if (ip_route_output_key(&rt, &fl))
return;
}
/* RFC says return as much as we can without exceeding 576 bytes. */
length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
if (length > dst_pmtu(&rt->u.dst))
length = dst_pmtu(&rt->u.dst);
if (length > 576)
length = 576;
hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
nskb = alloc_skb(hh_len + length, GFP_ATOMIC);
if (!nskb) {
ip_rt_put(rt);
return;
}
nskb->priority = 0;
nskb->dst = &rt->u.dst;
skb_reserve(nskb, hh_len);
/* Set up IP header */
iph = nskb->nh.iph
= (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
iph->version=4;
iph->ihl=5;
iph->tos=tos;
iph->tot_len = htons(length);
/* PMTU discovery never applies to ICMP packets. */
iph->frag_off = 0;
iph->ttl = MAXTTL;
ip_select_ident(iph, &rt->u.dst, NULL);
iph->protocol=IPPROTO_ICMP;
iph->saddr=rt->rt_src;
iph->daddr=rt->rt_dst;
iph->check=0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
/* Set up ICMP header. */
icmph = nskb->h.icmph
= (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
icmph->type = ICMP_DEST_UNREACH;
icmph->code = code;
icmph->un.gateway = 0;
icmph->checksum = 0;
/* Copy as much of original packet as will fit */
data = skb_put(nskb,
length - sizeof(struct iphdr) - sizeof(struct icmphdr));
skb_copy_bits(skb_in, 0, data,
length - sizeof(struct iphdr) - sizeof(struct icmphdr));
icmph->checksum = ip_compute_csum((unsigned char *)icmph,
length - sizeof(struct iphdr));
nf_ct_attach(nskb, skb_in);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
}
static unsigned int reject(struct sk_buff **pskb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment