-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement reliable transport (#57)
# Checklist * [x] I have read the contribution guidelines * [x] Iff you changed code related to services, or inter-service communication, make sure you update the diagrams in `ARCHITECTURE.md`. * [x] Reference issue for this pull request: #47 # Description In this PR I implement the reliability algorithm for the OpenVPN protocol: - Each reliable packet emitted is subject to retransmission if it's not acked in time. Retransmission follows an exponential backoff - beginning at 2 seconds, with a cap at 60s. - Incoming packets are subject to reordering before being passed to TLS. - Incoming packets are passed to reliable.moveDownWorker to send ACKs if there's a packet in the outgoing queue. --------- Co-authored-by: Simone Basso <bassosimone@gmail.com>
- Loading branch information
1 parent
f359d87
commit 86b9861
Showing
17 changed files
with
2,016 additions
and
255 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package reliabletransport | ||
|
||
const ( | ||
// Capacity for the array of packets that we're tracking at any given moment (outgoing). | ||
// This is defined by OpenVPN in ssl_pkt.h | ||
RELIABLE_SEND_BUFFER_SIZE = 6 | ||
|
||
// Capacity for the array of packets that we're tracking at any given moment (incoming). | ||
// This is defined by OpenVPN in ssl_pkt.h | ||
RELIABLE_RECV_BUFFER_SIZE = 12 | ||
|
||
// The maximum numbers of ACKs that we put in an array for an outgoing packet. | ||
MAX_ACKS_PER_OUTGOING_PACKET = 4 | ||
|
||
// How many IDs pending to be acked can we store. | ||
ACK_SET_CAPACITY = 8 | ||
|
||
// Initial timeout for TLS retransmission, in seconds. | ||
INITIAL_TLS_TIMEOUT_SECONDS = 2 | ||
|
||
// Maximum backoff interval, in seconds. | ||
MAX_BACKOFF_SECONDS = 60 | ||
|
||
// Default sender ticker period, in milliseconds. | ||
SENDER_TICKER_MS = 1000 * 60 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Package reliabletransport implements the reliable transport module for OpenVPN. | ||
// See [the official documentation](https://community.openvpn.net/openvpn/wiki/SecurityOverview) for a detailed explanation | ||
// of why this is needed, and how it relates to the requirements of the control channel. | ||
// It is worth to mention that, even though the original need is to have a reliable control channel | ||
// on top of UDP, this is also used when tunneling over TCP. | ||
package reliabletransport |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package reliabletransport | ||
|
||
import ( | ||
"github.com/ooni/minivpn/internal/model" | ||
) | ||
|
||
// sequentialPacket is a packet that can return a [model.PacketID]. | ||
type sequentialPacket interface { | ||
ID() model.PacketID | ||
ExtractACKs() []model.PacketID | ||
Packet() *model.Packet | ||
} | ||
|
||
// retransmissionPacket is a packet that can be scheduled for retransmission. | ||
type retransmissionPacket interface { | ||
ScheduleForRetransmission() | ||
} | ||
|
||
type outgoingPacketWriter interface { | ||
// TryInsertOutgoingPacket attempts to insert a packet into the | ||
// inflight queue. If return value is false, insertion was not successful (e.g., too many | ||
// packets in flight). | ||
TryInsertOutgoingPacket(*model.Packet) bool | ||
} | ||
|
||
type seenPacketHandler interface { | ||
// OnIncomingPacketSeen processes a notification received in the shared lateral channel where receiver | ||
// notifies sender of incoming packets. There are two side-effects expected from this call: | ||
// 1. The ID in incomingPacketSeen needs to be appended to the array of packets pending to be acked, if not already | ||
// there. This insertion needs to be reflected by NextPacketIDsToACK() | ||
// 2. Any ACK values in the incomingPacketSeen need to: | ||
// a) evict the matching packet, if existing in the in flight queue, and | ||
// b) increment the counter of acks-with-higher-pid for each packet with a lesser | ||
// packet id (used for fast retransmission) | ||
OnIncomingPacketSeen(incomingPacketSeen) | ||
} | ||
|
||
type outgoingPacketHandler interface { | ||
// NextPacketIDsToACK returns an array of pending IDs to ACK to | ||
// our remote. The length of this array MUST NOT be larger than CONTROL_SEND_ACK_MAX. | ||
// This is used to append it to the ACK array of the outgoing packet. | ||
NextPacketIDsToACK() []model.PacketID | ||
} | ||
|
||
// incomingPacketHandler knows how to deal with incoming packets (going up). | ||
type incomingPacketHandler interface { | ||
// MaybeInsertIncoming will insert a given packet in the reliable | ||
// incoming queue if it passes a series of sanity checks. | ||
MaybeInsertIncoming(*model.Packet) bool | ||
|
||
// NextIncomingSequence gets the largest sequence of packets ready to be passed along | ||
// to the control channel above us. | ||
NextIncomingSequence() incomingSequence | ||
} |
Oops, something went wrong.