Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection ID DT output #1742

Merged
merged 14 commits into from Sep 25, 2018
Merged

Connection ID DT output #1742

merged 14 commits into from Sep 25, 2018

Conversation

erickinnear
Copy link
Contributor

  • Add new text around Connection IDs
  • Add CONNECTION_ID_FINISHED frame
  • Remove sequence number for Connection IDs

Short summary:
An endpoint can issue as many CIDs to its peer as it chooses. It must always allow incoming packets on all outstanding CIDs. The only way to get rid of one from that "pool" is for the peer to indicate that the CID may be forgotten via the CONNECTION_ID_FINISHED frame.

On the receiving side, you remember all the CIDs you get from your peer and can generally use any that you like at any time. If you get more than you think you need, you can ignore some.
You're only allowed to use a CID on a single path, so you should probably retire any that you've moved away from via a _FINISHED frame.

Receiving a _FINISHED frame indicates that you should generally "replace" the retired CID. There are a few recommendations in this area, mostly to ensure that it's straightforward to keep your peer from running out of CIDs to use.

@MikeBishop MikeBishop added design An issue that affects the design of the protocol; resolution requires consensus. -transport labels Sep 12, 2018
previously used SHOULD also switch to sending with a different connection ID.
This can help to ensure that different connection IDs will be used in both
directions when an endpoint migrates to a new path or changes connection ID on
an existing path.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, it doesn't do anything for changes on the existing path, but that's okay because the session is linkable anyway if you're on an existing path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the problem is that this paragraph implies the remote peer did not change CID but the address changed (perhaps NAT binding). If we switch CIDs, does it really require the remote end to switch CIDs? The likability problem is still there, I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not always the case that use of an existing path implies linkability. Though it might be a strong signal, if I'm behind a NAT with a large number of other people, I can imagine the NAT being used as an mixing point. Changing connection ID in that context might re-establish anonymity within that set. Especially if the NAT understands connection IDs and I am able to use one for packets I receive as well. In many cases we think about, the NAT is small and the value of re-mixing low, but you can imagine building that sort of aggregator for privacy purposes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, that recommendation amounts to the server initiating a migration upon receiving packets from a new client address, so that a given pair of CID is tied to a single pair of addresses. That can work, but we have to consider security issues. Addresses are outside the cryptographic envelope, attackers can take good packets and just replace the address by something else. That mean attackers can easily trick servers into starting migrations.

I am not sure of the balance between aggravated DOD risk and moderate privacy gain. The beans are already spilled in the packet from the client with the changed address and the constant CID. If we do nothing, the client will notice that its own address changed upon receiving the first reply from the server. It can then chose to start a migration. That seems more robust.

@MikeBishop
Copy link
Contributor

One item to note is that we've adopted EKR's suggestion to use IP:port (collectively "address" as in the migration section) changes instead of CID changes as the trigger to change your own CID. Here's why:

  • If you switch CIDs without changing addresses they're already linked to any observers, so it doesn't matter whether the remote side changes.
  • If you switch addresses without changing CIDs, they're already linked to any observers, so it doesn't matter whether the remote side changes.
  • If you switch addresses and CIDs at the same time, you have an opportunity not to be linked.

The case we actually need to cover is ensuring that, if an endpoint changes address and CID at the same time, the peer absolutely does not respond with the old CID. Any rule that produces this is sufficient, even if it also produces some gratuitous changes along the way.

Part of what led to the changes in -13 is that switching on CID change makes it hard to avoid looping. Switching on endpoint address covers the scenario we need without requiring a fixed ordering of CIDs.

@mikkelfj
Copy link
Contributor

@MikeBishop this make sense, but in symmetric settings, both sides could have NAT rebindings, so there could a case for preemptive CID change at either endpoint after idletime - but perhaps that is a separate issue.

@MikeBishop
Copy link
Contributor

That's already a recommendation in the existing text -- this is strictly talking about how to ensure that the CID coming back from the peer doesn't link, but also doesn't trigger a new CID rotation, which triggers a rotation, which triggers....

draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
the connection with at least one connection ID to use when sending. An endpoint
SHOULD supply its peer with additional connection IDs via NEW_CONNECTION_ID
frames. While each endpoint can choose how many connection IDs to issue, a
recommended number of outstanding connection IDs is eight.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if recommending a specific number is helpful. Do we have any operation experience about suggesting 8?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that 8 is the right recommendation, but we should contextualize it more. The primary consideration being that it is important to support a number of failed connection migrations on the way to a successful migration.

That context is later, so I think we should just move this recommendation.

previously used SHOULD also switch to sending with a different connection ID.
This can help to ensure that different connection IDs will be used in both
directions when an endpoint migrates to a new path or changes connection ID on
an existing path.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the problem is that this paragraph implies the remote peer did not change CID but the address changed (perhaps NAT binding). If we switch CIDs, does it really require the remote end to switch CIDs? The likability problem is still there, I think.

Copy link
Member

@martinthomson martinthomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously, I think that this is a good balance of the concerns, because I was involved with the decision. I do have some editorial concerns that.

I'm willing to help address these. I suggest that we start with a round of discussion, during which we might decide to split off some new issues.

the connection with at least one connection ID to use when sending. An endpoint
SHOULD supply its peer with additional connection IDs via NEW_CONNECTION_ID
frames. While each endpoint can choose how many connection IDs to issue, a
recommended number of outstanding connection IDs is eight.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that 8 is the right recommendation, but we should contextualize it more. The primary consideration being that it is important to support a number of failed connection migrations on the way to a successful migration.

That context is later, so I think we should just move this recommendation.

previously used SHOULD also switch to sending with a different connection ID.
This can help to ensure that different connection IDs will be used in both
directions when an endpoint migrates to a new path or changes connection ID on
an existing path.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not always the case that use of an existing path implies linkability. Though it might be a strong signal, if I'm behind a NAT with a large number of other people, I can imagine the NAT being used as an mixing point. Changing connection ID in that context might re-establish anonymity within that set. Especially if the NAT understands connection IDs and I am able to use one for packets I receive as well. In many cases we think about, the NAT is small and the value of re-mixing low, but you can imagine building that sort of aggregator for privacy purposes.

draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
use by the endpoint when sending packets until the connection ID is retired by
the endpoint. Endpoints can choose to stop using a given connection ID to send
packets at any time and signal this to the issuing endpoint via a
CONNECTION_ID_FINISHED frame. This frame indicates the connection ID that is no
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this name (never have). But until I read this text again and saw it use "retire", I didn't have an alternative I liked enough to suggest. RETIRE_CONNECTION_ID is better (not awesome, but certainly better).

Yes, that's opinion. Also, don't bother changing it. I am prepared to do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, RETIRE_CONNECTION_ID works just as well. 😄

draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
NEW_CONNECTION_ID frame ({{frame-new-connection-id}}).

Retiring a connection ID using the CONNECTION_ID_FINISHED frame invalidates any
stateless reset tokens associated with that connection ID.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an open issue, we should decide how long to allow the old token to be effective. I would suggest that we use the same 3xRTO timer for that as well. Then we have 3xRTO everywhere in this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, I like moving towards 3xRTO for everything

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's correct as written, actually, though we could make it more explicit if needed. This is the complementary case of when the recipient should stop accepting packets with the old CID.

If a packet with the old CID was delayed and the recipient drops the CID immediately upon receipt, you'll get a SR that you ought to ignore. So unless we're also adding a 3xRTO requirement on the server to continue accepting the retired CID, the sender needs to immediately stop recognizing the SRT associated with the CID. You might miss a SR from an old packet if the race lands wrong. But the packet being sent now has a new, still-valid CID and will presumably elicit a current SR of its own, so that's okay.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would actually disable the reset token asap. The only down side of doing that is to fall back to timer based termination if the connection breaks. But we probably need more text on the behavior of the reset token. Assume that a path is defined by a pair of CID. At any given point, a node will have a "main path" on which it is sending data, and a set of paths in various alternate paths in different stages of validation. Let's look at the following scenarios:

  1. Node sends a normal packet, on the main path, and receives back a reset.
  2. Node sends a probe with a fresh CID and new addresses and receives back a reset
  3. Node sends a probe response with a fresh CID in response to a probe and receives back a reset
  4. Node has parked an old path that it does not actively use and receives a reset on that path.

Do we want to treat all these scenarios the same, as in tear down the connection? Or do we want to just accept resets on the path that is actively used?

draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
Copy link
Contributor

@huitema huitema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will have an interesting conversation. My main concern is whether to introduce a concept of paths, i.e. pairs o connection IDs. It would simplify my code significantly, rather than trying to implement paths using low level components like NEW CONNECTION ID, PATH CHALLENGE and PATH RESPONSE.

previously used SHOULD also switch to sending with a different connection ID.
This can help to ensure that different connection IDs will be used in both
directions when an endpoint migrates to a new path or changes connection ID on
an existing path.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, that recommendation amounts to the server initiating a migration upon receiving packets from a new client address, so that a given pair of CID is tied to a single pair of addresses. That can work, but we have to consider security issues. Addresses are outside the cryptographic envelope, attackers can take good packets and just replace the address by something else. That mean attackers can easily trick servers into starting migrations.

I am not sure of the balance between aggravated DOD risk and moderate privacy gain. The beans are already spilled in the packet from the client with the changed address and the constant CID. If we do nothing, the client will notice that its own address changed upon receiving the first reply from the server. It can then chose to start a migration. That seems more robust.


An endpoint that retires a connection ID should retain knowledge of that
connection ID for a reasonable time after sending the CONNECTION_ID_FINISHED
frame, or until that frame is acknowledged. A recommended time is three times
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@martinthomson do we still have a reset risk if the client retires the stateless reset value that it received with the retired connection ID?

NEW_CONNECTION_ID frame ({{frame-new-connection-id}}).

Retiring a connection ID using the CONNECTION_ID_FINISHED frame invalidates any
stateless reset tokens associated with that connection ID.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would actually disable the reset token asap. The only down side of doing that is to fall back to timer based termination if the connection breaks. But we probably need more text on the behavior of the reset token. Assume that a path is defined by a pair of CID. At any given point, a node will have a "main path" on which it is sending data, and a set of paths in various alternate paths in different stages of validation. Let's look at the following scenarios:

  1. Node sends a normal packet, on the main path, and receives back a reset.
  2. Node sends a probe with a fresh CID and new addresses and receives back a reset
  3. Node sends a probe response with a fresh CID in response to a probe and receives back a reset
  4. Node has parked an old path that it does not actively use and receives a reset on that path.

Do we want to treat all these scenarios the same, as in tear down the connection? Or do we want to just accept resets on the path that is actively used?

draft-ietf-quic-transport.md Outdated Show resolved Hide resolved
@erickinnear
Copy link
Contributor Author

erickinnear commented Sep 24, 2018

Added max_connection_ids TP as discussed in NYC. This allows the consumer of CIDs to put a cap on how many the issuer will send.

@erickinnear
Copy link
Contributor Author

The remaining issue here is the re-introduction of a sequence number, which will work as follows:

  • Each CID comes with a sequence number, every CID that you send must have a sequence number higher than any you've previously sent
  • This does not requiring anything to happen in lockstep as before, however this solves a big edge case in that you can now forget CIDs immediately instead of waiting for 3xRTO when you retire them, since any NEW_CONNECTION_ID frame crossing paths with the retirement frame will contain a sequence number. Instead, you just remember the highest sequence number NEW_CONNECTION_ID that you've received.

For example:

  1. Peer sends NEW_CONNECTION_ID and you use it, then immediately retire it with RETIRE_CONNECTION_ID.
  2. Ack of NEW_CONNECTION_ID gets lost.
  3. RETIRE_CONNECTION_ID frame is still in flight when the peer retransmits NEW_CONNECTION_ID.

If you've got a sequence number you can keep track of the highest sequence that you've gotten and, since this one will not advance the sequence number, you can safely ignore the duplicate NEW_CONNECTION_ID frame.

during the handshake. Subsequent connection IDs are communicated to the peer
using NEW_CONNECTION_ID frames ({{frame-new-connection-id}}). While each
endpoint independently chooses how many connection IDs to issue, a recommended
number of outstanding connection IDs is eight.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

endpoints SHOULD provide and maintain at least 8 connection IDs......

ID used on different paths. To fulfill this privacy requirement, endpoints that
An endpoint SHOULD ensure that its peer has a sufficient number of available and
unused connection IDs. The endpoint can do this by always supplying a new
connection ID when a connection ID is retired by its peer or when the endpoint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move the recommendation for 8 in between the two sentences here.

An endpoint that receives a packet with a different remote address or
destination connection ID than previously used SHOULD also switch to sending
with a connection ID that has not previously been used. The goal is to ensure
absence of correlation between the pairs of client and server connection ID used
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal is to ensure that traffic on different paths cannot be correlated.

receives a packet with a previously unused connection ID. Endpoints that
initiate migration and require non-zero-length connection IDs SHOULD provide
their peers with new connection IDs before migration, or risk the peer closing
the connection.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

closing the connection...when they run out of connection IDs.

: If both endpoints change connection ID in response to seeing a change in
connection ID from their peer, then this can trigger an infinite sequence
of changes.
An endpoint can arbitrarily change the connection ID it uses for a peer to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/arbitrarily//

connection ID for a period of time after sending the RETIRE_CONNECTION_ID frame,
or until that frame is acknowledged. A recommended time is three times the
current retransmission timeout (RTO) interval as defined in {{QUIC-RECOVERY}}.
This prevents confusion from receiving retransmissions of a NEW_CONNECTION_ID
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prevents a retransmission of a NEW_CONNECTION_ID from incorrectly renewing a previously retired connection ID.

@janaiyengar
Copy link
Contributor

I've made some editorial fixes to the text, and also tried to reflect what we agreed on in NYC.

@janaiyengar janaiyengar merged commit f7d1a25 into quicwg:master Sep 25, 2018
alagoutte added a commit to alagoutte/base-drafts that referenced this pull request Sep 30, 2018
- Merge ACK and ACK_ECN (quicwg#1801)
- Add 2 transport parameters: max_ack_delay(12) and original_connection_id(13) (quicwg#981, quicwg#1710, quicwg#1486)
- Remove sequence field from NEW_CONNECTION_ID (quicwg#1742)
- Add RETIRE_CONNECTION_ID type (quicwg#1742)
MikeBishop pushed a commit that referenced this pull request Oct 2, 2018
- Merge ACK and ACK_ECN (#1801)
- Add 2 transport parameters: max_ack_delay(12) and original_connection_id(13) (#981, #1710, #1486)
- Remove sequence field from NEW_CONNECTION_ID (#1742)
- Add RETIRE_CONNECTION_ID type (#1742)
MikeBishop pushed a commit that referenced this pull request Oct 2, 2018
- Merge ACK and ACK_ECN (#1801)
- Add 2 transport parameters: max_ack_delay(12) and original_connection_id(13) (#981, #1710, #1486)
- Remove sequence field from NEW_CONNECTION_ID (#1742)
- Add RETIRE_CONNECTION_ID type (#1742)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
-transport design An issue that affects the design of the protocol; resolution requires consensus.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants