aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2007-10-04 17:52:28 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:54:38 -0400
commit4a5409a5a850c84505d658ddf36f98b2c542ec07 (patch)
tree2cc197e3e942513eca7126bac67ea67dafbacc79
parent2bfd754d1bf29d3324270e52ef11ce6367bb0685 (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.c11
-rw-r--r--net/dccp/ipv6.c7
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);
639drop: 637drop:
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);
465drop: 465drop:
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