diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2007-10-04 17:52:28 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:54:38 -0400 |
commit | 4a5409a5a850c84505d658ddf36f98b2c542ec07 (patch) | |
tree | 2cc197e3e942513eca7126bac67ea67dafbacc79 | |
parent | 2bfd754d1bf29d3324270e52ef11ce6367bb0685 (diff) |
[DCCP]: Twice the wrong reset code in receiving connection-Requests
This fixes two bugs in processing of connection-Requests in
v{4,6}_conn_request:
1. Due to using the variable `reset_code', the Reset code generated
internally by dccp_parse_options() is overwritten with the
initialised value ("Too Busy") of reset_code, which is not what is
intended.
2. When receiving a connection-Request on a multicast or broadcast
address, no Reset should be generated, to avoid storms of such
packets. Instead of jumping to the `drop' label, the
v{4,6}_conn_request functions now return 0. Below is why in my
understanding this is correct:
When the conn_request function returns < 0, then the caller,
dccp_rcv_state_process(), returns 1. In all instances where
dccp_rcv_state_process is called (dccp_v4_do_rcv, dccp_v6_do_rcv,
and dccp_child_process), a return value of != 0 from
dccp_rcv_state_process() means that a Reset is generated.
If on the other hand the conn_request function returns 0, the
packet is discarded and no Reset is generated.
Note: There may be a related problem when sending the Response, due to
the following.
if (dccp_v6_send_response(sk, req, NULL))
goto drop_and_free;
/* ... */
drop_and_free:
return -1;
In this case, if send_response fails due to transmission errors, the
next thing that is generated is a Reset with a code "Too Busy". I
haven't been able to conjure up such a condition, but it might be good
to change the behaviour here also (not done by this patch).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/dccp/ipv4.c | 11 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 7 |
2 files changed, 7 insertions, 11 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2312b9f4d7af..44f6e17e105f 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -568,17 +568,14 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
568 | struct dccp_request_sock *dreq; | 568 | struct dccp_request_sock *dreq; |
569 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; | 569 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; |
570 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 570 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
571 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
572 | 571 | ||
573 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | 572 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ |
574 | if (((struct rtable *)skb->dst)->rt_flags & | 573 | if (((struct rtable *)skb->dst)->rt_flags & |
575 | (RTCF_BROADCAST | RTCF_MULTICAST)) { | 574 | (RTCF_BROADCAST | RTCF_MULTICAST)) |
576 | reset_code = DCCP_RESET_CODE_NO_CONNECTION; | 575 | return 0; /* discard, don't send a reset here */ |
577 | goto drop; | ||
578 | } | ||
579 | 576 | ||
580 | if (dccp_bad_service_code(sk, service)) { | 577 | if (dccp_bad_service_code(sk, service)) { |
581 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | 578 | dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; |
582 | goto drop; | 579 | goto drop; |
583 | } | 580 | } |
584 | /* | 581 | /* |
@@ -586,6 +583,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
586 | * limitations, they conserve resources and peer is | 583 | * limitations, they conserve resources and peer is |
587 | * evidently real one. | 584 | * evidently real one. |
588 | */ | 585 | */ |
586 | dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
589 | if (inet_csk_reqsk_queue_is_full(sk)) | 587 | if (inet_csk_reqsk_queue_is_full(sk)) |
590 | goto drop; | 588 | goto drop; |
591 | 589 | ||
@@ -638,7 +636,6 @@ drop_and_free: | |||
638 | reqsk_free(req); | 636 | reqsk_free(req); |
639 | drop: | 637 | drop: |
640 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 638 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
641 | dcb->dccpd_reset_code = reset_code; | ||
642 | return -1; | 639 | return -1; |
643 | } | 640 | } |
644 | 641 | ||
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index b7c0f66e2834..006a3834fbcd 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -390,21 +390,21 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
390 | struct ipv6_pinfo *np = inet6_sk(sk); | 390 | struct ipv6_pinfo *np = inet6_sk(sk); |
391 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; | 391 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; |
392 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 392 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
393 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
394 | 393 | ||
395 | if (skb->protocol == htons(ETH_P_IP)) | 394 | if (skb->protocol == htons(ETH_P_IP)) |
396 | return dccp_v4_conn_request(sk, skb); | 395 | return dccp_v4_conn_request(sk, skb); |
397 | 396 | ||
398 | if (!ipv6_unicast_destination(skb)) | 397 | if (!ipv6_unicast_destination(skb)) |
399 | goto drop; | 398 | return 0; /* discard, don't send a reset here */ |
400 | 399 | ||
401 | if (dccp_bad_service_code(sk, service)) { | 400 | if (dccp_bad_service_code(sk, service)) { |
402 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | 401 | dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; |
403 | goto drop; | 402 | goto drop; |
404 | } | 403 | } |
405 | /* | 404 | /* |
406 | * There are no SYN attacks on IPv6, yet... | 405 | * There are no SYN attacks on IPv6, yet... |
407 | */ | 406 | */ |
407 | dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
408 | if (inet_csk_reqsk_queue_is_full(sk)) | 408 | if (inet_csk_reqsk_queue_is_full(sk)) |
409 | goto drop; | 409 | goto drop; |
410 | 410 | ||
@@ -464,7 +464,6 @@ drop_and_free: | |||
464 | reqsk_free(req); | 464 | reqsk_free(req); |
465 | drop: | 465 | drop: |
466 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 466 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
467 | dcb->dccpd_reset_code = reset_code; | ||
468 | return -1; | 467 | return -1; |
469 | } | 468 | } |
470 | 469 | ||