int sysctl_icmp_ratelimit = 1 * HZ;
int sysctl_icmp_ratemask = 0x1818;
+int sysctl_icmp_errors_use_inbound_ifaddr;
/*
* ICMP control array. This specifies what to do with each ICMP.
* Checksum each fragment, and on the first include the headers and final
* checksum.
*/
-int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
- struct sk_buff *skb)
+static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
+ struct sk_buff *skb)
{
struct icmp_bxm *icmp_param = (struct icmp_bxm *)from;
unsigned int csum;
to, len, 0);
skb->csum = csum_block_add(skb->csum, csum, odd);
+ if (icmp_pointers[icmp_param->data.icmph.type].error)
+ nf_ct_attach(skb, icmp_param->skb);
return 0;
}
static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
{
struct sock *sk = icmp_socket->sk;
- struct inet_opt *inet = inet_sk(sk);
+ struct inet_sock *inet = inet_sk(sk);
struct ipcm_cookie ipc;
struct rtable *rt = (struct rtable *)skb->dst;
u32 daddr;
* ICMP error
*/
if (iph->protocol == IPPROTO_ICMP) {
- u8 inner_type;
-
- if (skb_copy_bits(skb_in,
- skb_in->nh.raw + (iph->ihl << 2) +
- offsetof(struct icmphdr, type) -
- skb_in->data, &inner_type, 1))
+ u8 _inner_type, *itp;
+
+ itp = skb_header_pointer(skb_in,
+ skb_in->nh.raw +
+ (iph->ihl << 2) +
+ offsetof(struct icmphdr,
+ type) -
+ skb_in->data,
+ sizeof(_inner_type),
+ &_inner_type);
+ if (itp == NULL)
goto out;
/*
* Assume any unknown ICMP type is an error. This
* isn't specified by the RFC, but think about it..
*/
- if (inner_type > NR_ICMP_TYPES ||
- icmp_pointers[inner_type].error)
+ if (*itp > NR_ICMP_TYPES ||
+ icmp_pointers[*itp].error)
goto out;
}
}
* Construct source address and options.
*/
-#ifdef CONFIG_IP_ROUTE_NAT
- /*
- * Restore original addresses if packet has been translated.
- */
- if (rt->rt_flags & RTCF_NAT && IPCB(skb_in)->flags & IPSKB_TRANSLATED) {
- iph->daddr = rt->fl.fl4_dst;
- iph->saddr = rt->fl.fl4_src;
- }
-#endif
-
saddr = iph->daddr;
- if (!(rt->rt_flags & RTCF_LOCAL))
- saddr = 0;
+ if (!(rt->rt_flags & RTCF_LOCAL)) {
+ if (sysctl_icmp_errors_use_inbound_ifaddr)
+ saddr = inet_select_addr(skb_in->dev, 0, RT_SCOPE_LINK);
+ else
+ saddr = 0;
+ }
tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
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;
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;
}
/* RFC says return as much as we can without exceeding 576 bytes. */
- room = dst_pmtu(&rt->u.dst);
+ room = dst_mtu(&rt->u.dst);
if (room > 576)
room = 576;
room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
read_unlock(&raw_v4_lock);
rcu_read_lock();
- ipprot = inet_protos[hash];
- smp_read_barrier_depends();
+ ipprot = rcu_dereference(inet_protos[hash]);
if (ipprot && ipprot->err_handler)
ipprot->err_handler(skb, info);
rcu_read_unlock();
struct net_device *dev = skb->dev;
struct in_device *in_dev;
struct in_ifaddr *ifa;
- u32 mask;
if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
goto out;
in_dev = in_dev_get(dev);
if (!in_dev)
goto out;
- read_lock(&in_dev->lock);
+ rcu_read_lock();
if (in_dev->ifa_list &&
IN_DEV_LOG_MARTIANS(in_dev) &&
IN_DEV_FORWARD(in_dev)) {
- if (skb_copy_bits(skb, 0, &mask, 4))
+ u32 _mask, *mp;
+
+ mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask);
+ if (mp == NULL)
BUG();
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
- if (mask == ifa->ifa_mask &&
+ if (*mp == ifa->ifa_mask &&
inet_ifa_match(rt->rt_src, ifa))
break;
}
if (!ifa && net_ratelimit()) {
printk(KERN_INFO "Wrong address mask %u.%u.%u.%u from "
"%s/%u.%u.%u.%u\n",
- NIPQUAD(mask), dev->name, NIPQUAD(rt->rt_src));
+ NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src));
}
}
- read_unlock(&in_dev->lock);
+ rcu_read_unlock();
in_dev_put(in_dev);
out:;
}
void __init icmp_init(struct net_proto_family *ops)
{
- struct inet_opt *inet;
+ struct inet_sock *inet;
int i;
for (i = 0; i < NR_CPUS; i++) {