diff options
Diffstat (limited to 'net/ipv4/icmp.c')
-rw-r--r-- | net/ipv4/icmp.c | 322 |
1 files changed, 154 insertions, 168 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index a0d847c7cba5..5395e45dcce6 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -83,6 +83,7 @@ | |||
83 | #include <net/tcp.h> | 83 | #include <net/tcp.h> |
84 | #include <net/udp.h> | 84 | #include <net/udp.h> |
85 | #include <net/raw.h> | 85 | #include <net/raw.h> |
86 | #include <net/ping.h> | ||
86 | #include <linux/skbuff.h> | 87 | #include <linux/skbuff.h> |
87 | #include <net/sock.h> | 88 | #include <net/sock.h> |
88 | #include <linux/errno.h> | 89 | #include <linux/errno.h> |
@@ -108,8 +109,7 @@ struct icmp_bxm { | |||
108 | __be32 times[3]; | 109 | __be32 times[3]; |
109 | } data; | 110 | } data; |
110 | int head_len; | 111 | int head_len; |
111 | struct ip_options replyopts; | 112 | struct ip_options_data replyopts; |
112 | unsigned char optbuf[40]; | ||
113 | }; | 113 | }; |
114 | 114 | ||
115 | /* An array of errno for error messages from dest unreach. */ | 115 | /* An array of errno for error messages from dest unreach. */ |
@@ -233,48 +233,11 @@ static inline void icmp_xmit_unlock(struct sock *sk) | |||
233 | * Send an ICMP frame. | 233 | * Send an ICMP frame. |
234 | */ | 234 | */ |
235 | 235 | ||
236 | /* | 236 | static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, |
237 | * Check transmit rate limitation for given message. | 237 | struct flowi4 *fl4, int type, int code) |
238 | * The rate information is held in the destination cache now. | ||
239 | * This function is generic and could be used for other purposes | ||
240 | * too. It uses a Token bucket filter as suggested by Alexey Kuznetsov. | ||
241 | * | ||
242 | * Note that the same dst_entry fields are modified by functions in | ||
243 | * route.c too, but these work for packet destinations while xrlim_allow | ||
244 | * works for icmp destinations. This means the rate limiting information | ||
245 | * for one "ip object" is shared - and these ICMPs are twice limited: | ||
246 | * by source and by destination. | ||
247 | * | ||
248 | * RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate | ||
249 | * SHOULD allow setting of rate limits | ||
250 | * | ||
251 | * Shared between ICMPv4 and ICMPv6. | ||
252 | */ | ||
253 | #define XRLIM_BURST_FACTOR 6 | ||
254 | int xrlim_allow(struct dst_entry *dst, int timeout) | ||
255 | { | ||
256 | unsigned long now, token = dst->rate_tokens; | ||
257 | int rc = 0; | ||
258 | |||
259 | now = jiffies; | ||
260 | token += now - dst->rate_last; | ||
261 | dst->rate_last = now; | ||
262 | if (token > XRLIM_BURST_FACTOR * timeout) | ||
263 | token = XRLIM_BURST_FACTOR * timeout; | ||
264 | if (token >= timeout) { | ||
265 | token -= timeout; | ||
266 | rc = 1; | ||
267 | } | ||
268 | dst->rate_tokens = token; | ||
269 | return rc; | ||
270 | } | ||
271 | EXPORT_SYMBOL(xrlim_allow); | ||
272 | |||
273 | static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt, | ||
274 | int type, int code) | ||
275 | { | 238 | { |
276 | struct dst_entry *dst = &rt->dst; | 239 | struct dst_entry *dst = &rt->dst; |
277 | int rc = 1; | 240 | bool rc = true; |
278 | 241 | ||
279 | if (type > NR_ICMP_TYPES) | 242 | if (type > NR_ICMP_TYPES) |
280 | goto out; | 243 | goto out; |
@@ -288,8 +251,12 @@ static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt, | |||
288 | goto out; | 251 | goto out; |
289 | 252 | ||
290 | /* Limit if icmp type is enabled in ratemask. */ | 253 | /* Limit if icmp type is enabled in ratemask. */ |
291 | if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) | 254 | if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) { |
292 | rc = xrlim_allow(dst, net->ipv4.sysctl_icmp_ratelimit); | 255 | if (!rt->peer) |
256 | rt_bind_peer(rt, fl4->daddr, 1); | ||
257 | rc = inet_peer_xrlim_allow(rt->peer, | ||
258 | net->ipv4.sysctl_icmp_ratelimit); | ||
259 | } | ||
293 | out: | 260 | out: |
294 | return rc; | 261 | return rc; |
295 | } | 262 | } |
@@ -324,13 +291,14 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, | |||
324 | } | 291 | } |
325 | 292 | ||
326 | static void icmp_push_reply(struct icmp_bxm *icmp_param, | 293 | static void icmp_push_reply(struct icmp_bxm *icmp_param, |
294 | struct flowi4 *fl4, | ||
327 | struct ipcm_cookie *ipc, struct rtable **rt) | 295 | struct ipcm_cookie *ipc, struct rtable **rt) |
328 | { | 296 | { |
329 | struct sock *sk; | 297 | struct sock *sk; |
330 | struct sk_buff *skb; | 298 | struct sk_buff *skb; |
331 | 299 | ||
332 | sk = icmp_sk(dev_net((*rt)->dst.dev)); | 300 | sk = icmp_sk(dev_net((*rt)->dst.dev)); |
333 | if (ip_append_data(sk, icmp_glue_bits, icmp_param, | 301 | if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param, |
334 | icmp_param->data_len+icmp_param->head_len, | 302 | icmp_param->data_len+icmp_param->head_len, |
335 | icmp_param->head_len, | 303 | icmp_param->head_len, |
336 | ipc, rt, MSG_DONTWAIT) < 0) { | 304 | ipc, rt, MSG_DONTWAIT) < 0) { |
@@ -349,7 +317,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, | |||
349 | icmp_param->head_len, csum); | 317 | icmp_param->head_len, csum); |
350 | icmph->checksum = csum_fold(csum); | 318 | icmph->checksum = csum_fold(csum); |
351 | skb->ip_summed = CHECKSUM_NONE; | 319 | skb->ip_summed = CHECKSUM_NONE; |
352 | ip_push_pending_frames(sk); | 320 | ip_push_pending_frames(sk, fl4); |
353 | } | 321 | } |
354 | } | 322 | } |
355 | 323 | ||
@@ -362,11 +330,12 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) | |||
362 | struct ipcm_cookie ipc; | 330 | struct ipcm_cookie ipc; |
363 | struct rtable *rt = skb_rtable(skb); | 331 | struct rtable *rt = skb_rtable(skb); |
364 | struct net *net = dev_net(rt->dst.dev); | 332 | struct net *net = dev_net(rt->dst.dev); |
333 | struct flowi4 fl4; | ||
365 | struct sock *sk; | 334 | struct sock *sk; |
366 | struct inet_sock *inet; | 335 | struct inet_sock *inet; |
367 | __be32 daddr; | 336 | __be32 daddr; |
368 | 337 | ||
369 | if (ip_options_echo(&icmp_param->replyopts, skb)) | 338 | if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb)) |
370 | return; | 339 | return; |
371 | 340 | ||
372 | sk = icmp_xmit_lock(net); | 341 | sk = icmp_xmit_lock(net); |
@@ -377,32 +346,120 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) | |||
377 | icmp_param->data.icmph.checksum = 0; | 346 | icmp_param->data.icmph.checksum = 0; |
378 | 347 | ||
379 | inet->tos = ip_hdr(skb)->tos; | 348 | inet->tos = ip_hdr(skb)->tos; |
380 | daddr = ipc.addr = rt->rt_src; | 349 | daddr = ipc.addr = ip_hdr(skb)->saddr; |
381 | ipc.opt = NULL; | 350 | ipc.opt = NULL; |
382 | ipc.shtx.flags = 0; | 351 | ipc.tx_flags = 0; |
383 | if (icmp_param->replyopts.optlen) { | 352 | if (icmp_param->replyopts.opt.opt.optlen) { |
384 | ipc.opt = &icmp_param->replyopts; | 353 | ipc.opt = &icmp_param->replyopts.opt; |
385 | if (ipc.opt->srr) | 354 | if (ipc.opt->opt.srr) |
386 | daddr = icmp_param->replyopts.faddr; | 355 | daddr = icmp_param->replyopts.opt.opt.faddr; |
387 | } | 356 | } |
388 | { | 357 | memset(&fl4, 0, sizeof(fl4)); |
389 | struct flowi fl = { .nl_u = { .ip4_u = | 358 | fl4.daddr = daddr; |
390 | { .daddr = daddr, | 359 | fl4.saddr = rt->rt_spec_dst; |
391 | .saddr = rt->rt_spec_dst, | 360 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); |
392 | .tos = RT_TOS(ip_hdr(skb)->tos) } }, | 361 | fl4.flowi4_proto = IPPROTO_ICMP; |
393 | .proto = IPPROTO_ICMP }; | 362 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
394 | security_skb_classify_flow(skb, &fl); | 363 | rt = ip_route_output_key(net, &fl4); |
395 | if (ip_route_output_key(net, &rt, &fl)) | 364 | if (IS_ERR(rt)) |
396 | goto out_unlock; | 365 | goto out_unlock; |
397 | } | 366 | if (icmpv4_xrlim_allow(net, rt, &fl4, icmp_param->data.icmph.type, |
398 | if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, | ||
399 | icmp_param->data.icmph.code)) | 367 | icmp_param->data.icmph.code)) |
400 | icmp_push_reply(icmp_param, &ipc, &rt); | 368 | icmp_push_reply(icmp_param, &fl4, &ipc, &rt); |
401 | ip_rt_put(rt); | 369 | ip_rt_put(rt); |
402 | out_unlock: | 370 | out_unlock: |
403 | icmp_xmit_unlock(sk); | 371 | icmp_xmit_unlock(sk); |
404 | } | 372 | } |
405 | 373 | ||
374 | static struct rtable *icmp_route_lookup(struct net *net, | ||
375 | struct flowi4 *fl4, | ||
376 | struct sk_buff *skb_in, | ||
377 | const struct iphdr *iph, | ||
378 | __be32 saddr, u8 tos, | ||
379 | int type, int code, | ||
380 | struct icmp_bxm *param) | ||
381 | { | ||
382 | struct rtable *rt, *rt2; | ||
383 | int err; | ||
384 | |||
385 | memset(fl4, 0, sizeof(*fl4)); | ||
386 | fl4->daddr = (param->replyopts.opt.opt.srr ? | ||
387 | param->replyopts.opt.opt.faddr : iph->saddr); | ||
388 | fl4->saddr = saddr; | ||
389 | fl4->flowi4_tos = RT_TOS(tos); | ||
390 | fl4->flowi4_proto = IPPROTO_ICMP; | ||
391 | fl4->fl4_icmp_type = type; | ||
392 | fl4->fl4_icmp_code = code; | ||
393 | security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4)); | ||
394 | rt = __ip_route_output_key(net, fl4); | ||
395 | if (IS_ERR(rt)) | ||
396 | return rt; | ||
397 | |||
398 | /* No need to clone since we're just using its address. */ | ||
399 | rt2 = rt; | ||
400 | |||
401 | rt = (struct rtable *) xfrm_lookup(net, &rt->dst, | ||
402 | flowi4_to_flowi(fl4), NULL, 0); | ||
403 | if (!IS_ERR(rt)) { | ||
404 | if (rt != rt2) | ||
405 | return rt; | ||
406 | } else if (PTR_ERR(rt) == -EPERM) { | ||
407 | rt = NULL; | ||
408 | } else | ||
409 | return rt; | ||
410 | |||
411 | err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(fl4), AF_INET); | ||
412 | if (err) | ||
413 | goto relookup_failed; | ||
414 | |||
415 | if (inet_addr_type(net, fl4->saddr) == RTN_LOCAL) { | ||
416 | rt2 = __ip_route_output_key(net, fl4); | ||
417 | if (IS_ERR(rt2)) | ||
418 | err = PTR_ERR(rt2); | ||
419 | } else { | ||
420 | struct flowi4 fl4_2 = {}; | ||
421 | unsigned long orefdst; | ||
422 | |||
423 | fl4_2.daddr = fl4->saddr; | ||
424 | rt2 = ip_route_output_key(net, &fl4_2); | ||
425 | if (IS_ERR(rt2)) { | ||
426 | err = PTR_ERR(rt2); | ||
427 | goto relookup_failed; | ||
428 | } | ||
429 | /* Ugh! */ | ||
430 | orefdst = skb_in->_skb_refdst; /* save old refdst */ | ||
431 | err = ip_route_input(skb_in, fl4->daddr, fl4->saddr, | ||
432 | RT_TOS(tos), rt2->dst.dev); | ||
433 | |||
434 | dst_release(&rt2->dst); | ||
435 | rt2 = skb_rtable(skb_in); | ||
436 | skb_in->_skb_refdst = orefdst; /* restore old refdst */ | ||
437 | } | ||
438 | |||
439 | if (err) | ||
440 | goto relookup_failed; | ||
441 | |||
442 | rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, | ||
443 | flowi4_to_flowi(fl4), NULL, | ||
444 | XFRM_LOOKUP_ICMP); | ||
445 | if (!IS_ERR(rt2)) { | ||
446 | dst_release(&rt->dst); | ||
447 | rt = rt2; | ||
448 | } else if (PTR_ERR(rt2) == -EPERM) { | ||
449 | if (rt) | ||
450 | dst_release(&rt->dst); | ||
451 | return rt2; | ||
452 | } else { | ||
453 | err = PTR_ERR(rt2); | ||
454 | goto relookup_failed; | ||
455 | } | ||
456 | return rt; | ||
457 | |||
458 | relookup_failed: | ||
459 | if (rt) | ||
460 | return rt; | ||
461 | return ERR_PTR(err); | ||
462 | } | ||
406 | 463 | ||
407 | /* | 464 | /* |
408 | * Send an ICMP message in response to a situation | 465 | * Send an ICMP message in response to a situation |
@@ -422,6 +479,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
422 | struct icmp_bxm icmp_param; | 479 | struct icmp_bxm icmp_param; |
423 | struct rtable *rt = skb_rtable(skb_in); | 480 | struct rtable *rt = skb_rtable(skb_in); |
424 | struct ipcm_cookie ipc; | 481 | struct ipcm_cookie ipc; |
482 | struct flowi4 fl4; | ||
425 | __be32 saddr; | 483 | __be32 saddr; |
426 | u8 tos; | 484 | u8 tos; |
427 | struct net *net; | 485 | struct net *net; |
@@ -506,9 +564,9 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
506 | struct net_device *dev = NULL; | 564 | struct net_device *dev = NULL; |
507 | 565 | ||
508 | rcu_read_lock(); | 566 | rcu_read_lock(); |
509 | if (rt->fl.iif && | 567 | if (rt_is_input_route(rt) && |
510 | net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) | 568 | net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) |
511 | dev = dev_get_by_index_rcu(net, rt->fl.iif); | 569 | dev = dev_get_by_index_rcu(net, rt->rt_iif); |
512 | 570 | ||
513 | if (dev) | 571 | if (dev) |
514 | saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); | 572 | saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); |
@@ -521,7 +579,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
521 | IPTOS_PREC_INTERNETCONTROL) : | 579 | IPTOS_PREC_INTERNETCONTROL) : |
522 | iph->tos; | 580 | iph->tos; |
523 | 581 | ||
524 | if (ip_options_echo(&icmp_param.replyopts, skb_in)) | 582 | if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in)) |
525 | goto out_unlock; | 583 | goto out_unlock; |
526 | 584 | ||
527 | 585 | ||
@@ -537,96 +595,15 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
537 | icmp_param.offset = skb_network_offset(skb_in); | 595 | icmp_param.offset = skb_network_offset(skb_in); |
538 | inet_sk(sk)->tos = tos; | 596 | inet_sk(sk)->tos = tos; |
539 | ipc.addr = iph->saddr; | 597 | ipc.addr = iph->saddr; |
540 | ipc.opt = &icmp_param.replyopts; | 598 | ipc.opt = &icmp_param.replyopts.opt; |
541 | ipc.shtx.flags = 0; | 599 | ipc.tx_flags = 0; |
542 | |||
543 | { | ||
544 | struct flowi fl = { | ||
545 | .nl_u = { | ||
546 | .ip4_u = { | ||
547 | .daddr = icmp_param.replyopts.srr ? | ||
548 | icmp_param.replyopts.faddr : | ||
549 | iph->saddr, | ||
550 | .saddr = saddr, | ||
551 | .tos = RT_TOS(tos) | ||
552 | } | ||
553 | }, | ||
554 | .proto = IPPROTO_ICMP, | ||
555 | .uli_u = { | ||
556 | .icmpt = { | ||
557 | .type = type, | ||
558 | .code = code | ||
559 | } | ||
560 | } | ||
561 | }; | ||
562 | int err; | ||
563 | struct rtable *rt2; | ||
564 | |||
565 | security_skb_classify_flow(skb_in, &fl); | ||
566 | if (__ip_route_output_key(net, &rt, &fl)) | ||
567 | goto out_unlock; | ||
568 | |||
569 | /* No need to clone since we're just using its address. */ | ||
570 | rt2 = rt; | ||
571 | |||
572 | err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0); | ||
573 | switch (err) { | ||
574 | case 0: | ||
575 | if (rt != rt2) | ||
576 | goto route_done; | ||
577 | break; | ||
578 | case -EPERM: | ||
579 | rt = NULL; | ||
580 | break; | ||
581 | default: | ||
582 | goto out_unlock; | ||
583 | } | ||
584 | |||
585 | if (xfrm_decode_session_reverse(skb_in, &fl, AF_INET)) | ||
586 | goto relookup_failed; | ||
587 | |||
588 | if (inet_addr_type(net, fl.fl4_src) == RTN_LOCAL) | ||
589 | err = __ip_route_output_key(net, &rt2, &fl); | ||
590 | else { | ||
591 | struct flowi fl2 = {}; | ||
592 | unsigned long orefdst; | ||
593 | 600 | ||
594 | fl2.fl4_dst = fl.fl4_src; | 601 | rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, |
595 | if (ip_route_output_key(net, &rt2, &fl2)) | 602 | type, code, &icmp_param); |
596 | goto relookup_failed; | 603 | if (IS_ERR(rt)) |
597 | 604 | goto out_unlock; | |
598 | /* Ugh! */ | ||
599 | orefdst = skb_in->_skb_refdst; /* save old refdst */ | ||
600 | err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src, | ||
601 | RT_TOS(tos), rt2->dst.dev); | ||
602 | |||
603 | dst_release(&rt2->dst); | ||
604 | rt2 = skb_rtable(skb_in); | ||
605 | skb_in->_skb_refdst = orefdst; /* restore old refdst */ | ||
606 | } | ||
607 | |||
608 | if (err) | ||
609 | goto relookup_failed; | ||
610 | |||
611 | err = xfrm_lookup(net, (struct dst_entry **)&rt2, &fl, NULL, | ||
612 | XFRM_LOOKUP_ICMP); | ||
613 | switch (err) { | ||
614 | case 0: | ||
615 | dst_release(&rt->dst); | ||
616 | rt = rt2; | ||
617 | break; | ||
618 | case -EPERM: | ||
619 | goto ende; | ||
620 | default: | ||
621 | relookup_failed: | ||
622 | if (!rt) | ||
623 | goto out_unlock; | ||
624 | break; | ||
625 | } | ||
626 | } | ||
627 | 605 | ||
628 | route_done: | 606 | if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code)) |
629 | if (!icmpv4_xrlim_allow(net, rt, type, code)) | ||
630 | goto ende; | 607 | goto ende; |
631 | 608 | ||
632 | /* RFC says return as much as we can without exceeding 576 bytes. */ | 609 | /* RFC says return as much as we can without exceeding 576 bytes. */ |
@@ -634,7 +611,7 @@ route_done: | |||
634 | room = dst_mtu(&rt->dst); | 611 | room = dst_mtu(&rt->dst); |
635 | if (room > 576) | 612 | if (room > 576) |
636 | room = 576; | 613 | room = 576; |
637 | room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen; | 614 | room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; |
638 | room -= sizeof(struct icmphdr); | 615 | room -= sizeof(struct icmphdr); |
639 | 616 | ||
640 | icmp_param.data_len = skb_in->len - icmp_param.offset; | 617 | icmp_param.data_len = skb_in->len - icmp_param.offset; |
@@ -642,7 +619,7 @@ route_done: | |||
642 | icmp_param.data_len = room; | 619 | icmp_param.data_len = room; |
643 | icmp_param.head_len = sizeof(struct icmphdr); | 620 | icmp_param.head_len = sizeof(struct icmphdr); |
644 | 621 | ||
645 | icmp_push_reply(&icmp_param, &ipc, &rt); | 622 | icmp_push_reply(&icmp_param, &fl4, &ipc, &rt); |
646 | ende: | 623 | ende: |
647 | ip_rt_put(rt); | 624 | ip_rt_put(rt); |
648 | out_unlock: | 625 | out_unlock: |
@@ -658,7 +635,7 @@ EXPORT_SYMBOL(icmp_send); | |||
658 | 635 | ||
659 | static void icmp_unreach(struct sk_buff *skb) | 636 | static void icmp_unreach(struct sk_buff *skb) |
660 | { | 637 | { |
661 | struct iphdr *iph; | 638 | const struct iphdr *iph; |
662 | struct icmphdr *icmph; | 639 | struct icmphdr *icmph; |
663 | int hash, protocol; | 640 | int hash, protocol; |
664 | const struct net_protocol *ipprot; | 641 | const struct net_protocol *ipprot; |
@@ -677,7 +654,7 @@ static void icmp_unreach(struct sk_buff *skb) | |||
677 | goto out_err; | 654 | goto out_err; |
678 | 655 | ||
679 | icmph = icmp_hdr(skb); | 656 | icmph = icmp_hdr(skb); |
680 | iph = (struct iphdr *)skb->data; | 657 | iph = (const struct iphdr *)skb->data; |
681 | 658 | ||
682 | if (iph->ihl < 5) /* Mangled header, drop. */ | 659 | if (iph->ihl < 5) /* Mangled header, drop. */ |
683 | goto out_err; | 660 | goto out_err; |
@@ -725,7 +702,7 @@ static void icmp_unreach(struct sk_buff *skb) | |||
725 | */ | 702 | */ |
726 | 703 | ||
727 | /* | 704 | /* |
728 | * Check the other end isnt violating RFC 1122. Some routers send | 705 | * Check the other end isn't violating RFC 1122. Some routers send |
729 | * bogus responses to broadcast frames. If you see this message | 706 | * bogus responses to broadcast frames. If you see this message |
730 | * first check your netmask matches at both ends, if it does then | 707 | * first check your netmask matches at both ends, if it does then |
731 | * get the other vendor to fix their kit. | 708 | * get the other vendor to fix their kit. |
@@ -750,7 +727,7 @@ static void icmp_unreach(struct sk_buff *skb) | |||
750 | if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) | 727 | if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) |
751 | goto out; | 728 | goto out; |
752 | 729 | ||
753 | iph = (struct iphdr *)skb->data; | 730 | iph = (const struct iphdr *)skb->data; |
754 | protocol = iph->protocol; | 731 | protocol = iph->protocol; |
755 | 732 | ||
756 | /* | 733 | /* |
@@ -779,7 +756,7 @@ out_err: | |||
779 | 756 | ||
780 | static void icmp_redirect(struct sk_buff *skb) | 757 | static void icmp_redirect(struct sk_buff *skb) |
781 | { | 758 | { |
782 | struct iphdr *iph; | 759 | const struct iphdr *iph; |
783 | 760 | ||
784 | if (skb->len < sizeof(struct iphdr)) | 761 | if (skb->len < sizeof(struct iphdr)) |
785 | goto out_err; | 762 | goto out_err; |
@@ -790,7 +767,7 @@ static void icmp_redirect(struct sk_buff *skb) | |||
790 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 767 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
791 | goto out; | 768 | goto out; |
792 | 769 | ||
793 | iph = (struct iphdr *)skb->data; | 770 | iph = (const struct iphdr *)skb->data; |
794 | 771 | ||
795 | switch (icmp_hdr(skb)->code & 7) { | 772 | switch (icmp_hdr(skb)->code & 7) { |
796 | case ICMP_REDIR_NET: | 773 | case ICMP_REDIR_NET: |
@@ -805,6 +782,15 @@ static void icmp_redirect(struct sk_buff *skb) | |||
805 | iph->saddr, skb->dev); | 782 | iph->saddr, skb->dev); |
806 | break; | 783 | break; |
807 | } | 784 | } |
785 | |||
786 | /* Ping wants to see redirects. | ||
787 | * Let's pretend they are errors of sorts... */ | ||
788 | if (iph->protocol == IPPROTO_ICMP && | ||
789 | iph->ihl >= 5 && | ||
790 | pskb_may_pull(skb, (iph->ihl<<2)+8)) { | ||
791 | ping_err(skb, icmp_hdr(skb)->un.gateway); | ||
792 | } | ||
793 | |||
808 | out: | 794 | out: |
809 | return; | 795 | return; |
810 | out_err: | 796 | out_err: |
@@ -954,12 +940,12 @@ static void icmp_address_reply(struct sk_buff *skb) | |||
954 | BUG_ON(mp == NULL); | 940 | BUG_ON(mp == NULL); |
955 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { | 941 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { |
956 | if (*mp == ifa->ifa_mask && | 942 | if (*mp == ifa->ifa_mask && |
957 | inet_ifa_match(rt->rt_src, ifa)) | 943 | inet_ifa_match(ip_hdr(skb)->saddr, ifa)) |
958 | break; | 944 | break; |
959 | } | 945 | } |
960 | if (!ifa && net_ratelimit()) { | 946 | if (!ifa && net_ratelimit()) { |
961 | printk(KERN_INFO "Wrong address mask %pI4 from %s/%pI4\n", | 947 | printk(KERN_INFO "Wrong address mask %pI4 from %s/%pI4\n", |
962 | mp, dev->name, &rt->rt_src); | 948 | mp, dev->name, &ip_hdr(skb)->saddr); |
963 | } | 949 | } |
964 | } | 950 | } |
965 | } | 951 | } |
@@ -1065,7 +1051,7 @@ error: | |||
1065 | */ | 1051 | */ |
1066 | static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { | 1052 | static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { |
1067 | [ICMP_ECHOREPLY] = { | 1053 | [ICMP_ECHOREPLY] = { |
1068 | .handler = icmp_discard, | 1054 | .handler = ping_rcv, |
1069 | }, | 1055 | }, |
1070 | [1] = { | 1056 | [1] = { |
1071 | .handler = icmp_discard, | 1057 | .handler = icmp_discard, |