Draft: draft-ietf-quic-transport

Commentary: Please see the discussion on for the rationale , but in short , SERVERBUSY is renamed as CONNECTIONREFUSED . A server might refuse a connection for various reasons . SERVER_BUSY is one specific reason . Having an error code for that specific case while not having an error code for generic case is awkward . Hence the rename . 
 I 'm not sure if this was an editorial PR . The previous text talked about a situation where a server was too busy to accept a new connection . The new text generalizes this to a connection refusal for any reason . That 's a design change . I also strongly disagree that this issue should There 's still on ongoing discussion if an additional error code should be introduced . I ca n't see how this is not a design issue . 
 There was previously no requirement to send this error code under any particular circumstances nor any requirement to take action upon receipt of this error code , and therefore those requirements can not have been changed . This modifies the prose around an error code the server could use to reject a connection attempt to make the recommendation more narrow . 
 This is spawned from and . The discussion there revealed that  has implied semantics that are n't helpful and it would be better to have a more generic message instead . This tracks that . The resolution might be , depending on how we resolve this . 
 My personal preference is to not merge . A generic error code is more useful . There is a small loss here in that a server has to use a non - intuitive code for the case that it finds it ca n't continue with a connection due to load , but I am comfortable with that . 
 was already merged , and there 's some question about whether it was actually editorial . This issue tracks the question retroactively . The proposal here is to leave merged / The alternative is to merge , reverting the other PR . 
 I prefer the generic message , so I would like to see the current state of affairs retained . That is , use CONNECTIONREFUSED going forward ( instead of SERVERBUSY ) , and do not merge . If there is a need for other more specific error codes , we can deal with that separately . 
 +1 to leaving the current state .  is generic enough to be useful in the situation described , and while it 's nice to have more specific error codes , I do n't think there 's an abundant need for a BUSY - like signal , without also getting into the business of prescribing things like time - based retry for QUIC clients . 
 +1 to retaining the current state . I 'm repeating my comment on , but when QUIC is used as the only transport protocol ( rather than with happy - eyeballing ) , it has to be resilient to MITM attacks as TLS over TCP is . TLS over TCP does not have an unauthenticated error code that tells the client to stop trying to connecting to the server . We can not have such thing in QUIC , because if we do , QUIC becomes more prone to MITM attacker than TLS over TCP is . CONNECTIONREFUSED is fine in this respect , because it does not indicate to the client what the reason was . But error codes like SERVERBUSY or TRY_LATER would have the implications that we can not have . 
 Closing as proposed . 
 Assume that a server has a blacklist of IP addresses , that it does n't accept connections from . One way of implementing this would be to drop all packets from those IP addresses . But this would lead to clients time out , which is sad . Let 's say the server wants to be more helpful and allow the client to quickly recover from this situation . Sending a CONNECTIONCLOSE would seem like the right thing to do in that case . However , we do n't have an error code that fits here . SERVERBUSY is used to reject connection attempts , but it 's a bad fit here . Retrying later is not likely to succeed in this case . APPLICATIONERROR also seems too broad , as it 's used for any application - level error ( in Initial packets ) . Do we need a new error code to cover this use case ? Something like  ? 
 If my reading of our code is correct , we 're using PROTOCOLVIOLATION for that case , but that 's not a very informative choice . In gQUIC , we used public reset for this(as you probably remember ) , but stateless reset is post - handshake only . CONNECTIONREFUSED sounds better , but I think an important question is wether we expect clients to treat this error code differently than other error codes which occur during the handshake . If we 're not going to treat it differently , then it matters less . That being said , I 'm a general fan of more granular error codes for debugging . 
 I guess a reasonable policy regarding errors received during the handshake would be : INVALIDTOKEN : try again immediately SERVERBUSY : try again after a few minutes  : do n't try again for a day / week or so other errors : I can see TRANSPORTPARAMETERERROR and FRAMEENCODINGERROR ( and their generic subsitute , PROTOCOLVIOLATION ) being reasonably sent in response to a ClientHello . So that means that either your or your peer 's implementation is broken , so maybe you should n't speak QUIC at all ? 
 I tend to think that adding an error code that affects client behavior is not a good idea , when that error code is intended to indicate a handshake failure . The signal carried by an Initial packet or a Handshake packet is not authenticated , and we should be wary of using that to convey something that affects more than just that connection . In case of this example , CONNECTIONREFUSED would become an attractive tool for MITM attackers , because it can be used for preventing the client for reconnecting for as long as a day or a week . If we need these signal , I think that they have to be carried at the application - level after the QUIC handshake concludes . In case of HTTP , we already have 503 + Retry - After header field . To summarize , I think my position is : We should not add error codes that affect the client behavior after that connection gets closed . We might want to get rid of SERVER_BUSY , or at least state that a client can not really tell if the server was really busy , as the signal is not authenticated . 
 We accept this risk in QUIC v1 . Removing error codes to mitigate the MITM vulnerability seems like a piecemeal " solution " to a problem that can only be solved by decent cryptography . For the MITM the easiest way is probably injection a Version Negotiation packet that indicates that there are no compatible versions between the client and the server . I 'd expect most client implementations to give up a dial attempt in this case , which in effect would be very similar to the actions taken in response to a CONNECTIONREFUSED . 
 In case of this example , CONNECTIONREFUSED would become an attractive tool for MITM attackers , because it can be used for preventing the client for reconnecting for as long as a day or a week . I disagree with that view . Handshake is never going to be disruption resistant , unless there is a shared secret . There are ways of raising the probability of endpoints having shared secret ( that we discussed and postponed to v2 ) , but there would always be a case where there is no shared secret . We always need to limit the impact of attacker injecting signals to an unauthenticated channel . I 'd also reiterate that in HTTP we already have a way of asking clients to revisit the server after certain amount of time . TLS does not have a way of signaling that . Assuming that HTTP developers are fine with what we have in HTTP + TLS , I do not think there is good justification to add a new feature that has negative impact on security . Giving up one attempt is fine . Having a signal that asks to give up future connection attempts is the problem . 
 HTTP has 503 to reject request when a server is busy , and still we have SERVER_BUSY at the QUIC layer . There 's a value in rejecting connection attempts before spending resources ( and round trips ) on a handshake . Furthermore , there are other application protocols than HTTP . In my use case , nodes in a p2p network want to enforce a local blacklist of IP addresses . In TCP , they can easily do that by resetting the connection , and before spending any resources on the TLS handshake . Having to go through the whole QUIC handshake with a blacklisted peer before being able to reject them would be a serious regression compared to TCP . I 'm not sure how browsers handle a Version Negotiation packet that indicates that there are no matching versions . I doubt that they 'd try QUIC again for the next request just a few seconds later . Intuitively , I 'd say that a longer period combined with an exponential backoff would be a reasonable thing to implement . Maybe and can shed some light on this ? 
 Yes , TCP or TLS can reject one attempt . QUIC is currently aligned to that , and that 's fine . Giving up one attempt is fine . Having a signal that asks to give up future connection attempts is the problem . I 'd point out that how aggressively browsers try connecting in QUIC depends on if they do happy - eyeballing . When browsers do happy - eyeballing , no matter how less you do in QUIC , the probability of establishing a connection always stays higher ( or as high as ) just doing TLS . The question is when browsers start doing just QUIC . Would they prefer to cache previous connection failures , as a way to not even try to reconnect when a user requests doing so ? 
 As a way of moving forward , I 'd propose renaming SERVERBUSY to CONNECTIONREFUSED , with no recommendation on how the client should react to that . The rationale behind providing no recommendation is as stated above . QUIC needs to be strong against MITM attacks , at least as TLS over TCP is . TLS over TCP does not have an error code that tells the client to refrain from retrying for some amount of time . To achieve parity , we can not have that . AFAIK , our experience with HTTPS tells us that there is no need for such an error code . The rationale behind the renaming is that at the moment we do not have a generic error code for refusing connections , even though we have SERVERBUSY , which indicates a specific reason of refusing a connection . Therefore , we need  . We can rename SERVERBUSY to CONNECTIONREFUSED . SERVERBUSY does not need to be preserved , since , as stated , the client behavior can not vary depending on an unauthenticated error code . For debugging purposes , endpoints are free to use the reasonphrase field .  ? 
 I do n't think that renaming an existing error will solve my problem . Otherwise , I would 've just used that error ... The point I was trying to make here is that clients will already make decisions about future connection attempts based on unauthenticated information , both sent in CONNECTION_CLOSE error codes as well as in Version Negotiation packets . Adding one more error does n't seem to exacerbate that situation , while at the same time enabling a way of blacklisting IP addresses that was possible with TCP and is currently not possible using QUIC . 
 As stated , my view is that your problem ( of sending a signal that affects future connections ) should only be solved by sending something after the handshake succeeds . And for HTTP , we already have that signal ( i.e. 503 + Retry - After ) . Therefore , defining such signal does not have to be done in QUICv1 . I disagree with that view . If the specification can be read as such , then I think we need to make changes . A client should refrain from using an unauthenticated signal for determining what to do with future connection attempts . It does not matter what that unauthenticated signal is ( e.g. , an error code in Initial packet , failed version negotiation ) . Any unsuccessful handshake attempt should be considered as an error of that particular attempt . Otherwise , QUIC handshake becomes prone to MITM attacks than TLS over TCP . If we are to agree that clients should not use an unauthenticated error code in determining what to do in the future , there is no point in having multiple error codes indicating that the server has deliberately refused a handshake . It is sufficient to have just one error code that let 's the server say , hey , nothing is wrong with us , but I refuse to accept a connection . 
 I believe it 's up to the client as to how unauthenticated signals are used . There are a lot of ways to interrupt a QUIC handshake early on , and this is one of many . Chrome does exponential backoff with a 5 minute time period anytime the handshake fails , whether it 's due to VN , connection close , handshake timeout , etc . In practice , VN and    typically agree , so VN is very rare and connection closes are more common . I ca n't argue  's algorithm is optimal , but if handshakes failed in the recent past , it seems sub - optimal to try QUIC again immediately . 
 I think that is a fine thing to do as long as  is happy - eyeballing with TLS - over - TCP . But as a specification , it is my understanding that happy - eyeballing is not a prerequisite . I 'd assume that we 'd want applications that use QUIC only to be as ignorant against unauthenticated signals as those using TLS - over - TCP is . 
 If only QUIC is used , then I agree the behavior should match that of TLS over TCP . 
 I like , but it is a semantic change . It makes the existing code more general , which is appropriate . We would need to make this issue a design issue to do that though . 
 This is practically impossible . To function reliably on the internet a client has to use heuristics and unauthenticated information in order to provide a good user experience and not overwhelm server resources . As a trivial example , if I wrote a client which completely ignores things like VN and immediately retries a QUIC connection , I am locked into supporting that version on my server indefinitely , since my client will now effectively DOS me if I remove support for this version from the server . This is unacceptable for internet scale . Additionally , rejecting a connection post - handshake makes fallback to TCP more complicated -- it is much simpler to use a happy eyeballs mechanism and " race " TCP and QUIC , stopping the TCP connection once the handshake is successful . I am highly sympathetic to point here . As has been said already , we already have 100 % reliable and trivially implementable way to interrupt the handshake in v1 with version negotiation . Having an additional signal which is more explicit can only help clients making new connection decisions . We do n't necessarily have to prescribe what the client does , but we can say why a server may issue certain errors during the handshake . 
 I 'd emphasize that the specification does not talk about happy eyeballing . We should concentrate on discussing what to do when only QUIC is being used . Having that said , I 'd hope that we can agree on one principle : QUIC can not respect unauthenticated information any more than TLS over TCP does . Otherwise , QUIC becomes more prone to MITM attacks that TLS over TCP is - a disobedience to our charter . That might be true , but our experience with TLS over TCP is that we do not need an error code for the purpose . FWIW , you do not need a version negotiation packet . Per my understanding , any server can send a private error code . Or a reason phrase explaining things . Am I correct to understand that the reason you are advocating for having more error codes is to allow a server to control the behavior of client for future connection attempts ? Assuming that is the case , I 'd oppose to having such error codes regardless of how we would describe them . Because IMO that is effectively about making QUIC more prone to attacks than TLS over TCP is . 
 I think that is entirely right here . The renaming of the error code is useful as it removes the implication of a semantic that would be destructive . That implication is that the code is like a 503 , which comes with the further implication that holding back for some time is desirable ( due to the common use of Retry - After with 503 ) . QUIC has no Retry - After , so any implied time delay is bogus . As mentioned , that browsers might sit and wait is a policy decision that makes sense in the current state of the world . I 'm going to merge the PR . But I get the sense that this is not directly addressing the issue . For the issue itself , I think that the only real resolution is : that 's tough , but too bad . As numerous people have said , this phase of connection establishment is ripe for DoS and we have chosen to accept that risk in QUIC version 1 . 
 Based on a request on . I have also opened . 
 I can see why this issue being classified as a design change , though at the same time , I think that was a good editorial change . made things betterWe now have an error code for server indicating that it rejected the connection even though nothing seemed to be wrong with the handshake . Without having CONNECTIONREFUSEDERROR , a client had to guess if PROTOCOLVIOLATION meant a problem in the handshake , or if it was simply a refusal . From now on , on this issue , I hope that we can concentrate on discussing if we want to have more than one error code indicating the specifics of connection refusals ( e.g. , SERVERBUSY ) . Unsurprisingly , my position is that we can not have specific codes due to the reasons laid out above . 
 I agree with in that was good ( and I do n't want to revert it ) . I also do n't think we need anything more than an appropriately generic error code for the stated problem , so I believe that that PR was adequate . 
 I agree with I think we should and I would argue that we should do a new issue if anyone wants more specific error codes . 
 I love more specific error codes , but many in the WG do not , so I still like given the constraints we 're working with . 
 No introduction of error codes can possibly make QUIC more prone to this than TCP + TLS . A TCP connection can be completely interrupted at any time with an unauthenticated RST . In that sense I do n't think it 's possible to make QUIC more prone to MITM attacks than TCP + TLS , since at the very least we only have a small window for the similar MITM interruption . It 's not a fair comparison , as TCP does not have an opportunity to fallback to anything . You posit that we have to view the QUIC specification in isolation from the existence TCP or any " happy eyeballs " mechanism , and I do n't totally disagree but I do n't think it follows we should make decision ignoring the realities of deploying QUIC on the Internet . That reality is , today , that QUIC will not work 100 % , whereas we expect TCP to function . If we can add things to the specification which aid in a seamless coexistence of QUIC and alternatives , why would we not ? I do n't think I fully understand your point here . You asserted that the client " should refrain from using an unauthenticated signal for determining what to do with future connection attempts " . I maintain that this is fantastical . The client has to do something with future connection attempts whether we prescribe a behavior or not , and as such it is abundantly useful to be able to influence , if not dictate , the behavior of clients with more explicit signals from the server . As it is I am fine with leaving this discussion with the generic CONNECTION_REFUSED and calling it a day , but I think there 's value in discussing the real - world considerations here , which was original motivation . 
 Is anyone arguing for leaving this issue open ? If folks still want to continue discussing , I propose that we open a new issue to do it . 
 No response to question in ten days ; it looks like this issue is closed . 
 Closing then . 
 Spawned from . typed : " Probably not for this change , but do we really want to encourage people to be estimating delays in the kernel ? Because it seems like the point of some of the other changes is to include that sort of delay in the RTT estimate . What matters here is end - to - end delays - the time between when the packet was consumed and when the packet containing the ACK was sent out . Yes , it 's true that you get a bigger RTT estimate if you do n't correct for delays in the kernel or NIC , but those are just another piece of the plumbing now . If we fail to cover things like scheduling delays in the RTT estimate , we 're just deluding ourselves about where the delays are . " typed : " Yeah , I was thinking about this too , but it 's text that we already had . FWIW , I think it 's useful to separate out these delays , not because they should n't get used for PTO estimates , but because knowing component delays might be helpful . That said , I do n't have a good use case for these component delays yet . OTOH , I 've started that separation between stack - controlled delays and other delays in the text , it might be worth using that distinction here , and arguing that these delays ought to be part of the path RTT since they 're not controlled delays . " 
 : +1 : I share the view with and that ack - delay should represent only the delay introduced intentionally by the QUIC stack . " stack - controlled delay " sounds like a good way of explaining them . 
 +1 to the idea that ack - delay should be intentionally introduced delay , since almost anything on path(including the local host NIC / OS / Firmware ) can delay things without the receiver 's control . 
 From London : Platform delays SHOULD be included in RTT , but ack_delay should only include intentionally introduced delays , not platform delays .
Paragraph (version A):
If a server isn't currently accepting any new connections, it SHOULD
send an Initial packet containing a CONNECTION_CLOSE frame with error
code SERVER_BUSY.
Paragraph (version B):
If a server refuses to accept a new connection, it SHOULD send an
Initial packet containing a CONNECTION_CLOSE frame with error code
CONNECTION_REFUSED.
Paragraph (version A):
The server is currently busy and does not accept any new
connections.
Paragraph (version B):
The server refused to accept a new connection.