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

*: Address security-protocol-in-multiaddr and relay conflict #359

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 50 additions & 6 deletions addressing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ within](#encapsulation) another multiaddr.
For example, the above `p2p` address can be combined with the transport address
on which the node is listening:

```
```
/ip4/7.7.7.7/tcp/1234/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N
```

Expand Down Expand Up @@ -235,7 +235,7 @@ appreciated.

Most libp2p transports use the IP protocol as a foundational layer, and as a
result, most transport multiaddrs will begin with a component that represents an
IPv4 or IPv6 address.
IPv4 or IPv6 address.

This may be an actual address, such as `/ip4/7.7.7.7` or
`/ip6/fe80::883:a581:fff1:833`, or it could be something that resolves to an IP
Expand All @@ -255,7 +255,7 @@ resolvable or "name-based" protocols:

When the `/dns` protocol is used, the lookup may result in both IPv4 and IPv6
addresses, in which case IPv6 will be preferred. To explicitly resolve to IPv4
or IPv6 addresses, use the `/dns4` or `/dns6` protocols, respectively.
or IPv6 addresses, use the `/dns4` or `/dns6` protocols, respectively.

Note that in some restricted environments, such as inside a web browser, libp2p
may not have access to the resolved IP addresses at all, in which case the
Expand Down Expand Up @@ -305,7 +305,7 @@ wherever TCP/IP sockets are accessible.

Addresses for the TCP transport are of the form `<ip-multiaddr>/tcp/<tcp-port>`,
where `<ip-multiaddr>` is a multiaddr that resolves to an IP address, as
described in the [IP and Name Resolution section](#ip-and-name-resolution).
described in the [IP and Name Resolution section](#ip-and-name-resolution).
The `<tcp-port>` argument must be a 16-bit unsigned integer.

### WebSockets
Expand All @@ -324,7 +324,7 @@ multiaddr format mirrors this arrangement.

A libp2p QUIC multiaddr is of the form `<ip-multiaddr>/udp/<udp-port>/quic`,
where `<ip-multiaddr>` is a multiaddr that resolves to an IP address, as
described in the [IP and Name Resolution section](#ip-and-name-resolution).
described in the [IP and Name Resolution section](#ip-and-name-resolution).
The `<udp-port>` argument must be a 16-bit unsigned integer in network byte order.


Expand Down Expand Up @@ -354,7 +354,7 @@ destination peer.

A full example would be:

```
```
/ip4/127.0.0.1/tcp/5002/p2p/QmdPU7PfRyKehdrP5A3WqmjyD6bhVpU1mLGKppa2FjGDjZ/p2p-circuit/p2p/QmVT6GYwjeeAF5TR485Yc58S3xRF5EFsZ5YAF4VcP3URHt
```

Expand All @@ -363,6 +363,50 @@ Here, the destination peer has the peer id
relay node with peer id `QmdPU7PfRyKehdrP5A3WqmjyD6bhVpU1mLGKppa2FjGDjZ` running
on TCP port 5002 of the IPv4 loopback interface.

#### Relay addresses and multiaddr security component

Instead of negotiating the security protocol in-band, security protocols should
be encapsulated in the multiaddr (see [The multiaddr security component
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to make this a prerequisite for circuit v2, or does that clash with our experimental deployment of v2?

Suggested change
be encapsulated in the multiaddr (see [The multiaddr security component
Instead of negotiating the security protocol in-band, security protocols are
encapsulated in the multiaddr (see [The multiaddr security component

Copy link
Member Author

Choose a reason for hiding this comment

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

That would make Project Flare dependent on security-protocol-in-multiaddr. Given the large number of live libp2p networks, I would prefer to keep the two decoupled to allow flexible roll-outs.

Do you see issues with the decoupled approach @marten-seemann?

section](#the-multiaddr-security-component)). Establishing a single relayed
connection involves 3 security protocol upgrades:

1. Upgrading the connection from the source to the relay.

The security protocol is specified in the relay multiaddr (before
`p2p-circuit`).

Example: `/ip4/6.6.6.6/tcp/1234/tls/p2p/QmRelay/p2p-circuit/<destination-multiaddr>`

2. Upgrading the connection from the relay to the destination.

The security protocol is specified in the destination multiaddr (after
`p2p-circuit`).

Note: Specifying this security protocol is only necessary for active
relaying. In the case of passive relaying the connection established by the
destination to the relay will be used to relay the connection.

Example:
- Passive relaying: `<relay-multiaddr>/p2p-circuit/p2p/QmDestination`
- Active relaying: `<relay-multiaddr>/p2p-circuit/ip4/6.6.6.6/tcp/1234/tls/p2p/QmDestination`

3. Upgrading the relayed connection from the source to the destination.

The security protocol is specified by appending
`/p2p-circuit-inner/<relayed-connection-security-protocol>` to the full
address.

<!-- TODO: Is `p2p-circuit-inner` the ideal name? Up for alternative
suggestions. -->

Example: `<relay-mulitaddr>/p2p-circuit/<destination-multiaddr>/p2p-circuit-inner/tls`

Note: One might be tempted to not specify (3) and simply use the security
protocol in (2). This would break if the security protocol used for (2) can
not be used for (3), e.g. in the case where the relay establishes a QUIC
connection to the destination secured via TLS and the source only supports
Noise.


[peer-id-spec]: ../peer-ids/peer-ids.md
[identify-spec]: ../identify/README.md
Expand Down
60 changes: 57 additions & 3 deletions relay/circuit-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,42 @@ Common failure status codes are:

***Note: implementations _should not_ accept connection initiations over already relayed connections***

##### Security protocol selection for the relayed connection

Instead of negotiating the security protocol in-band, security protocols should
be encapsulated in the multiaddr (see [The multiaddr security component
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

section](../addressing/README.md#the-multiaddr-security-component)). A relayed
connection is not an exception. A target advertises the support for a security
protocol for relayed connections by appending
`/p2p-circuit-inner/<security-protocol>` to its relayed multiaddresses. An
initiator may include any set of relayed multiaddr in the `peer` field of
`HopMessage` on type `CONNECT` in which all addresses end with the same
`/p2p-circuit-inner/<security-protocol>`. The initiator is thus signaling to the
target which security protocol, out of all advertised security protocols
by the target, the initiator chose to use on the relayed connection.

As an example, let's say the target listens for incoming relayed connections via
relay `R1` and relay `R2`. In addition it supports both TLS Noise as security
protocols. It would then advertise the following relayed multiaddresses:

- `<relay-R1-multiaddr>/p2p-circuit/p2p/QmTarget/p2p-circuit-inner/tls`
- `<relay-R1-multiaddr>/p2p-circuit/p2p/QmTarget/p2p-circuit-inner/noise`
- `<relay-R2-multiaddr>/p2p-circuit/p2p/QmTarget/p2p-circuit-inner/tls`
- `<relay-R2-multiaddr>/p2p-circuit/p2p/QmTarget/p2p-circuit-inner/noise`

Once the initiator received the above multiaddresses and decides to initiate a
relayed connection to the target, it needs to decide whether it wants to secure
the relayed connection via TLS or Noise. Say it decides for Noise it would then
include the multiaddresses below in it `HopMessage` with type `Connect` in the
`peer` field:

- `<relay-R1-multiaddr>/p2p-circuit/p2p/QmTarget/p2p-circuit-inner/noise`
- `<relay-R2-multiaddr>/p2p-circuit/p2p/QmTarget/p2p-circuit-inner/noise`

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we say that the relay SHOULD abort the connection if it receives a CONNECT with different security protocols, and the target MUST abort the connection attempt (i.e. reset the stream) if it receives such a CONNECT?

Copy link
Member Author

Choose a reason for hiding this comment

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

Should we say that the relay SHOULD abort the connection if it receives a CONNECT with different security protocols,

I would go by Be strict when sending and tolerant when receiving (RFC 1958). We might have a case in the future where sending a CONNECT with different security protocols is a valid use-case. Say we take the relaxed approach today, we would only have to roll-out an upgrade to the endpoints, not the relays, in the future.

the target MUST abort the connection attempt (i.e. reset the stream) if it receives such a CONNECT?

Sounds good to me.

Copy link
Member Author

Choose a reason for hiding this comment

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

Second suggestion applied via 7844421.

Note that all addresses sent by the initiator in the `peer` field MUST share the
same security protocol for the relayed connection
(`/p2p-circuit-inner/<security-protocol>`).

### Stop Protocol

The Stop protocol governs connection termination between the relay and the target peer;
Expand All @@ -309,11 +345,13 @@ The relay sends a `StopMessage` with `type = CONNECT` and the following form:
```
StopMessage {
type = CONNECT
peer = Peer { ID = ...}
initiator = Peer { ID = ...}
target = Peer { addrs = ...}
limit = Limit { ...}
}
```
- the `peer` field contains a `Peer` struct with the peer `ID` of the connection initiator.
- the `initiator` field contains a `Peer` struct with the peer `ID` of the connection initiator.
- the `target` field contains a `Peer` struct with the peer `addrs` of the target that the initiator included in its `HopMessage`.
- the `limit` field, if present, conveys the limits applied to the relayed connection with the semantics described [above](#reservation).

If the target peer accepts the connection it responds to the relay with a `StopMessage` of `type = STATUS` and `status = OK`:
Expand All @@ -330,6 +368,21 @@ If the target fails to terminate the connection for some reason, then it respond
Common failure status codes are:
- `CONNECTION_FAILED` if the target internally failed to create the relayed connection for some reason.

#### Security protocol selection for the relayed connection

A target may advertise support for different security protocols by advertising
multiple multiaddresses with different `/p2p-circuit-inner/<security-protocol>`
suffixes. A target needs some mechanism to determine which of the advertised
security protocols the initiator intends to use to secure an incoming relayed
connection. The target can use the addresses included in the `target` field of
the `StopMessage` to determine which security protocol the initiator chose to
secure the relayed connection.

Note that all addresses sent by the initiator MUST share the same security
protocol for the relayed connection (`/p2p-circuit-inner/<security-protocol>`).
Thus a target MUST abort the connection attempt (i.e. reset the stream) if it
receives a `CONNECT` with varying security protocols for the relay connection.

### Reservation Vouchers

Successful relay slot reservations should come with _Reservation Vouchers_.
Expand Down Expand Up @@ -383,7 +436,8 @@ message StopMessage {

required Type type = 1;

optional Peer peer = 2;
optional Peer initiator = 2;
optional Peer target = 5;
optional Limit limit = 3;

optional Status status = 4;
Expand Down