diff options
Diffstat (limited to 'net/ipv6/exthdrs.c')
-rw-r--r-- | net/ipv6/exthdrs.c | 140 |
1 files changed, 24 insertions, 116 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 14be0b9b77a5..c82d4d49f71f 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -42,7 +42,7 @@ | |||
42 | #include <net/ndisc.h> | 42 | #include <net/ndisc.h> |
43 | #include <net/ip6_route.h> | 43 | #include <net/ip6_route.h> |
44 | #include <net/addrconf.h> | 44 | #include <net/addrconf.h> |
45 | #ifdef CONFIG_IPV6_MIP6 | 45 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
46 | #include <net/xfrm.h> | 46 | #include <net/xfrm.h> |
47 | #endif | 47 | #endif |
48 | 48 | ||
@@ -90,6 +90,7 @@ int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | |||
90 | bad: | 90 | bad: |
91 | return -1; | 91 | return -1; |
92 | } | 92 | } |
93 | EXPORT_SYMBOL_GPL(ipv6_find_tlv); | ||
93 | 94 | ||
94 | /* | 95 | /* |
95 | * Parsing tlv encoded headers. | 96 | * Parsing tlv encoded headers. |
@@ -196,7 +197,7 @@ bad: | |||
196 | Destination options header. | 197 | Destination options header. |
197 | *****************************/ | 198 | *****************************/ |
198 | 199 | ||
199 | #ifdef CONFIG_IPV6_MIP6 | 200 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
200 | static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) | 201 | static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) |
201 | { | 202 | { |
202 | struct sk_buff *skb = *skbp; | 203 | struct sk_buff *skb = *skbp; |
@@ -270,7 +271,7 @@ static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) | |||
270 | #endif | 271 | #endif |
271 | 272 | ||
272 | static struct tlvtype_proc tlvprocdestopt_lst[] = { | 273 | static struct tlvtype_proc tlvprocdestopt_lst[] = { |
273 | #ifdef CONFIG_IPV6_MIP6 | 274 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
274 | { | 275 | { |
275 | .type = IPV6_TLV_HAO, | 276 | .type = IPV6_TLV_HAO, |
276 | .func = ipv6_dest_hao, | 277 | .func = ipv6_dest_hao, |
@@ -283,7 +284,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
283 | { | 284 | { |
284 | struct sk_buff *skb = *skbp; | 285 | struct sk_buff *skb = *skbp; |
285 | struct inet6_skb_parm *opt = IP6CB(skb); | 286 | struct inet6_skb_parm *opt = IP6CB(skb); |
286 | #ifdef CONFIG_IPV6_MIP6 | 287 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
287 | __u16 dstbuf; | 288 | __u16 dstbuf; |
288 | #endif | 289 | #endif |
289 | struct dst_entry *dst; | 290 | struct dst_entry *dst; |
@@ -298,7 +299,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
298 | } | 299 | } |
299 | 300 | ||
300 | opt->lastopt = opt->dst1 = skb_network_header_len(skb); | 301 | opt->lastopt = opt->dst1 = skb_network_header_len(skb); |
301 | #ifdef CONFIG_IPV6_MIP6 | 302 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
302 | dstbuf = opt->dst1; | 303 | dstbuf = opt->dst1; |
303 | #endif | 304 | #endif |
304 | 305 | ||
@@ -308,7 +309,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
308 | skb = *skbp; | 309 | skb = *skbp; |
309 | skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; | 310 | skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; |
310 | opt = IP6CB(skb); | 311 | opt = IP6CB(skb); |
311 | #ifdef CONFIG_IPV6_MIP6 | 312 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
312 | opt->nhoff = dstbuf; | 313 | opt->nhoff = dstbuf; |
313 | #else | 314 | #else |
314 | opt->nhoff = opt->dst1; | 315 | opt->nhoff = opt->dst1; |
@@ -371,22 +372,13 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
371 | struct rt0_hdr *rthdr; | 372 | struct rt0_hdr *rthdr; |
372 | int accept_source_route = ipv6_devconf.accept_source_route; | 373 | int accept_source_route = ipv6_devconf.accept_source_route; |
373 | 374 | ||
374 | if (accept_source_route < 0 || | 375 | idev = in6_dev_get(skb->dev); |
375 | ((idev = in6_dev_get(skb->dev)) == NULL)) { | 376 | if (idev) { |
376 | kfree_skb(skb); | 377 | if (accept_source_route > idev->cnf.accept_source_route) |
377 | return -1; | 378 | accept_source_route = idev->cnf.accept_source_route; |
378 | } | ||
379 | if (idev->cnf.accept_source_route < 0) { | ||
380 | in6_dev_put(idev); | 379 | in6_dev_put(idev); |
381 | kfree_skb(skb); | ||
382 | return -1; | ||
383 | } | 380 | } |
384 | 381 | ||
385 | if (accept_source_route > idev->cnf.accept_source_route) | ||
386 | accept_source_route = idev->cnf.accept_source_route; | ||
387 | |||
388 | in6_dev_put(idev); | ||
389 | |||
390 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || | 382 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || |
391 | !pskb_may_pull(skb, (skb_transport_offset(skb) + | 383 | !pskb_may_pull(skb, (skb_transport_offset(skb) + |
392 | ((skb_transport_header(skb)[1] + 1) << 3)))) { | 384 | ((skb_transport_header(skb)[1] + 1) << 3)))) { |
@@ -398,24 +390,6 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
398 | 390 | ||
399 | hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); | 391 | hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); |
400 | 392 | ||
401 | switch (hdr->type) { | ||
402 | #ifdef CONFIG_IPV6_MIP6 | ||
403 | case IPV6_SRCRT_TYPE_2: | ||
404 | break; | ||
405 | #endif | ||
406 | case IPV6_SRCRT_TYPE_0: | ||
407 | if (accept_source_route > 0) | ||
408 | break; | ||
409 | kfree_skb(skb); | ||
410 | return -1; | ||
411 | default: | ||
412 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | ||
413 | IPSTATS_MIB_INHDRERRORS); | ||
414 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | ||
415 | (&hdr->type) - skb_network_header(skb)); | ||
416 | return -1; | ||
417 | } | ||
418 | |||
419 | if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || | 393 | if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || |
420 | skb->pkt_type != PACKET_HOST) { | 394 | skb->pkt_type != PACKET_HOST) { |
421 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | 395 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
@@ -427,7 +401,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
427 | looped_back: | 401 | looped_back: |
428 | if (hdr->segments_left == 0) { | 402 | if (hdr->segments_left == 0) { |
429 | switch (hdr->type) { | 403 | switch (hdr->type) { |
430 | #ifdef CONFIG_IPV6_MIP6 | 404 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
431 | case IPV6_SRCRT_TYPE_2: | 405 | case IPV6_SRCRT_TYPE_2: |
432 | /* Silently discard type 2 header unless it was | 406 | /* Silently discard type 2 header unless it was |
433 | * processed by own | 407 | * processed by own |
@@ -453,18 +427,10 @@ looped_back: | |||
453 | } | 427 | } |
454 | 428 | ||
455 | switch (hdr->type) { | 429 | switch (hdr->type) { |
456 | case IPV6_SRCRT_TYPE_0: | 430 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
457 | if (hdr->hdrlen & 0x01) { | ||
458 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | ||
459 | IPSTATS_MIB_INHDRERRORS); | ||
460 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | ||
461 | ((&hdr->hdrlen) - | ||
462 | skb_network_header(skb))); | ||
463 | return -1; | ||
464 | } | ||
465 | break; | ||
466 | #ifdef CONFIG_IPV6_MIP6 | ||
467 | case IPV6_SRCRT_TYPE_2: | 431 | case IPV6_SRCRT_TYPE_2: |
432 | if (accept_source_route < 0) | ||
433 | goto unknown_rh; | ||
468 | /* Silently discard invalid RTH type 2 */ | 434 | /* Silently discard invalid RTH type 2 */ |
469 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { | 435 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { |
470 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | 436 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
@@ -474,6 +440,8 @@ looped_back: | |||
474 | } | 440 | } |
475 | break; | 441 | break; |
476 | #endif | 442 | #endif |
443 | default: | ||
444 | goto unknown_rh; | ||
477 | } | 445 | } |
478 | 446 | ||
479 | /* | 447 | /* |
@@ -520,7 +488,7 @@ looped_back: | |||
520 | addr += i - 1; | 488 | addr += i - 1; |
521 | 489 | ||
522 | switch (hdr->type) { | 490 | switch (hdr->type) { |
523 | #ifdef CONFIG_IPV6_MIP6 | 491 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
524 | case IPV6_SRCRT_TYPE_2: | 492 | case IPV6_SRCRT_TYPE_2: |
525 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, | 493 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, |
526 | (xfrm_address_t *)&ipv6_hdr(skb)->saddr, | 494 | (xfrm_address_t *)&ipv6_hdr(skb)->saddr, |
@@ -577,6 +545,12 @@ looped_back: | |||
577 | skb_push(skb, skb->data - skb_network_header(skb)); | 545 | skb_push(skb, skb->data - skb_network_header(skb)); |
578 | dst_input(skb); | 546 | dst_input(skb); |
579 | return -1; | 547 | return -1; |
548 | |||
549 | unknown_rh: | ||
550 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | ||
551 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | ||
552 | (&hdr->type) - skb_network_header(skb)); | ||
553 | return -1; | ||
580 | } | 554 | } |
581 | 555 | ||
582 | static struct inet6_protocol rthdr_protocol = { | 556 | static struct inet6_protocol rthdr_protocol = { |
@@ -590,72 +564,6 @@ void __init ipv6_rthdr_init(void) | |||
590 | printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n"); | 564 | printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n"); |
591 | }; | 565 | }; |
592 | 566 | ||
593 | /* | ||
594 | This function inverts received rthdr. | ||
595 | NOTE: specs allow to make it automatically only if | ||
596 | packet authenticated. | ||
597 | |||
598 | I will not discuss it here (though, I am really pissed off at | ||
599 | this stupid requirement making rthdr idea useless) | ||
600 | |||
601 | Actually, it creates severe problems for us. | ||
602 | Embryonic requests has no associated sockets, | ||
603 | so that user have no control over it and | ||
604 | cannot not only to set reply options, but | ||
605 | even to know, that someone wants to connect | ||
606 | without success. :-( | ||
607 | |||
608 | For now we need to test the engine, so that I created | ||
609 | temporary (or permanent) backdoor. | ||
610 | If listening socket set IPV6_RTHDR to 2, then we invert header. | ||
611 | --ANK (980729) | ||
612 | */ | ||
613 | |||
614 | struct ipv6_txoptions * | ||
615 | ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr) | ||
616 | { | ||
617 | /* Received rthdr: | ||
618 | |||
619 | [ H1 -> H2 -> ... H_prev ] daddr=ME | ||
620 | |||
621 | Inverted result: | ||
622 | [ H_prev -> ... -> H1 ] daddr =sender | ||
623 | |||
624 | Note, that IP output engine will rewrite this rthdr | ||
625 | by rotating it left by one addr. | ||
626 | */ | ||
627 | |||
628 | int n, i; | ||
629 | struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr; | ||
630 | struct rt0_hdr *irthdr; | ||
631 | struct ipv6_txoptions *opt; | ||
632 | int hdrlen = ipv6_optlen(hdr); | ||
633 | |||
634 | if (hdr->segments_left || | ||
635 | hdr->type != IPV6_SRCRT_TYPE_0 || | ||
636 | hdr->hdrlen & 0x01) | ||
637 | return NULL; | ||
638 | |||
639 | n = hdr->hdrlen >> 1; | ||
640 | opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC); | ||
641 | if (opt == NULL) | ||
642 | return NULL; | ||
643 | memset(opt, 0, sizeof(*opt)); | ||
644 | opt->tot_len = sizeof(*opt) + hdrlen; | ||
645 | opt->srcrt = (void*)(opt+1); | ||
646 | opt->opt_nflen = hdrlen; | ||
647 | |||
648 | memcpy(opt->srcrt, hdr, sizeof(*hdr)); | ||
649 | irthdr = (struct rt0_hdr*)opt->srcrt; | ||
650 | irthdr->reserved = 0; | ||
651 | opt->srcrt->segments_left = n; | ||
652 | for (i=0; i<n; i++) | ||
653 | memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16); | ||
654 | return opt; | ||
655 | } | ||
656 | |||
657 | EXPORT_SYMBOL_GPL(ipv6_invert_rthdr); | ||
658 | |||
659 | /********************************** | 567 | /********************************** |
660 | Hop-by-hop options. | 568 | Hop-by-hop options. |
661 | **********************************/ | 569 | **********************************/ |