Skip to content

Commit

Permalink
allow autonat v2 to dial all ips (#542)
Browse files Browse the repository at this point in the history
  • Loading branch information
sukunrt authored May 3, 2023
1 parent 3e57202 commit f6def9a
Showing 1 changed file with 44 additions and 27 deletions.
71 changes: 44 additions & 27 deletions autonat/autonat-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Compared to `autonat v1` there are two major differences
testing reachability for an individual address
2. `autonat v2` provides a mechanism for nodes to verify whether the peer
actually successfully dialled an address.
3. `autonat v2` provides a mechanism for nodes to dial an IP address different
from the requesting node's observed IP address without risking amplification
attacks. `autonat v1` disallowed such dials to prevent amplification attacks.



## AutoNAT V2 Protocol
Expand All @@ -62,10 +66,19 @@ of priority for verfication.

Upon receiving this message the peer selects the first candidate from the list
of candidates that it is capable of dialing. The peer MUST NOT dial any
candidate other than this selected candidate. It dials the selected candidate's
address, opens a stream with Protocol ID `/libp2p/autonat/2.0.0/attempt` and
sends a `DialAttempt` message with the candidate nonce. The peer MUST close this
stream after sending the `DialAttempt` message.
candidate other than this selected candidate. If this selected candidate address
has an IP address different from the requesting node's observed IP address, peer
initiates the Amplification attack prevention mechanism (see [Amplification
Attack Prevention](#amplification-attack-prevention) ). On completion, the peer
proceeds to the next step. If the selected address has the same IP address as
the requesting node's observed IP address, peer directly proceeds to the next
step skipping Amplification Attack prevention steps.


The peer dials the selected candidate's address, opens a stream with Protocol ID
`/libp2p/autonat/2.0.0/attempt` and sends a `DialAttempt` message with the
candidate nonce. The peer MUST close this stream after sending the `DialAttempt`
message.

Upon completion of the dial attempt, the peer sends a `DialResponse` message to
the initiator node on the `/libp2p/autonat/2.0.0/dial` stream with the index(0
Expand Down Expand Up @@ -107,26 +120,24 @@ peer that prevented it from completing the request.

Implementations MUST discard responses with status codes they do not understand

### Consideration for DDOS Prevention
### Amplification Attack Prevention

In order to prevent attacks like the one described in [RFC 3489, Section
12.1.1](https://www.rfc-editor.org/rfc/rfc3489#section-12.1.1) (see excerpt
below), implementations MUST NOT dial any multiaddress unless it is based on the
IP address the requesting node is observed as. This restriction as well implies
that implementations MUST NOT accept dial requests via relayed connections as
one can not validate the IP address of the requesting node.
When a client asks a server to dial an address that is not the client's observed
IP address, the server asks the client to send him some non trivial amount of
bytes as a cost to dial a different IP address. To make amplification attacks
unattractive, the number of bytes is decided such that it's sufficiently larger
than a new connection handshake cost.

> RFC 3489 12.1.1 Attack I: DDOS Against a Target
>
> In this case, the attacker provides a large number of clients with the same
> faked MAPPED-ADDRESS that points to the intended target. This will trick all
> the STUN clients into thinking that their addresses are equal to that of the
> target. The clients then hand out that address in order to receive traffic on
> it (for example, in SIP or H.323 messages). However, all of that traffic
> becomes focused at the intended target. The attack can provide substantial
> amplification, especially when used with clients that are using STUN to enable
> multimedia applications.
On receiving a `DialRequest`, the server selects the first address it is capable
of dialing. If this selected address has a IP different from the client's
observed ip, the server sends a `DialDataRequest` message with `numBytes` set to
a sufficiently large value on the `/libp2p/autonat/2.0.0/dial-request` stream

Upon receiving a `DialDataRequest` message, the client decides whether to accept
or reject the cost of dial. If the client rejects the cost, the client resets
the stream and the `DialRequest` is considered aborted. If the client accepts
the cost, the client starts transferring `numBytes` bytes to the server. The
server on receiving `numBytes` bytes proceeds to dial the candidate address.

## Implementation Suggestions

Expand Down Expand Up @@ -154,7 +165,7 @@ bytes, encoded as an unsigned variable length integer as defined by the
All RPC messages on stream `/libp2p/autonat/2.0.0/dial` are of type
`DialMessage`. A `DialRequest` message is sent as a `DialMessage` with the
`dialRequest` field set and the `type` field set to `DIAL_REQUEST`.
`DialResponse` is handled similarly.
`DialResponse` and `DialDataRequest` are handled similarly.

On stream `/libp2p/autonat/2.0.0/attempt`, there is a single message type
`AttemptMessage`
Expand All @@ -164,13 +175,15 @@ syntax = "proto3";
message DialMessage {
enum Type {
DIAL_REQUEST = 0;
DIAL_RESPONSE = 1;
DIAL_REQUEST = 0;
DIAL_RESPONSE = 1;
DIAL_DATA_REQUEST = 2;
}
Type type = 1;
DialRequest dialRequest = 2;
DialResponse dialResponse = 3;
DialDataRequest dialDataRequest = 4;
}
message Candidate {
Expand All @@ -182,6 +195,10 @@ message DialRequest {
repeated Candidate candidates = 1;
}
message DialDataRequest {
uint64 numBytes = 1;
}
message DialResponse {
enum ResponseStatus {
OK = 0;
Expand All @@ -190,10 +207,10 @@ message DialResponse {
E_TRANSPORT_NOT_SUPPORTED = 102;
E_BAD_REQUEST = 200;
E_INTERNAL_ERROR = 300;
}
}
ResponseStatus status = 1;
int32 addrIdx = 2;
ResponseStatus status = 1;
int32 addrIdx = 2;
}
message AttemptMessage {
Expand Down

0 comments on commit f6def9a

Please sign in to comment.