This SBD spec defines the protocol for SBD servers and clients to communicate. SBD is a simple websocket-based message relay protocol.
The SBD protocol is built upon websockets.
The maximum SBD message size (including 32 byte header) is 20000 bytes.
SBD clients and servers MAY set the max message size in the websocket library to 20000 to help enforce this.
The maximum frame size MUST be set larger than 20000 so that sbd messages always fit in a single websocket frame.
Generally over the WAN SBD servers SHOULD be available over TLS (wss://), and on a LAN without (ws://).
Clients will be identified by ed25519 public key. Client sessions will be validated by ed25519 signature.
Clients MUST specify exactly 1 http path item on the websocket connection url. This item must be the base64url encoded public key that this client will be identified by. This public key SHOULD be unique to this new connection.
SBD messages always contain first a 32 byte header. Messages less than 32 bytes are invalid.
If the header starts with 28 zero bytes, the message is a "command". Otherwise, the message is a "forward".
If the header is a "command" the next four literal ascii bytes are interpreted as the command type:
lbrt
- limit byte nanos - 4 byte i32be limit - server sentlidl
- limit idle millis - 4 byte i32be limit - server sentareq
- authentication request - 32 byte nonce - server sentares
- authentication response - 64 byte signature - client sentsrdy
- server ready - no additional data - server sentkeep
- keepalive - no additional data - client sentnone
- unknown - arbitary additional data - reserved to repr unknown msg
If the header is a "forward" type, the 32 byte header is interpreted as the public key to forward the message to. The remaining bytes in the message are the data to forward.
When a client sends a "forward" message to the server, the first 32 bytes represent the peer the message should be forwarded to.
When a server sends a "forward" message to the client the message should be forwarded to the first 32 bytes will be altered to represent the peer from which the message originated.
- If the server is in an overload state, it MAY drop incoming tcp connections immediately with no response even before doing any TLS handshaking.
- The server MUST send
areq
with a random nonce once for every newly opened connection. The server MAY send any limit messages before or after thisareq
, but it MUST come before thesrdy
. - The client MUST respond with a signature over the nonce by the private key associated with the public key sent in the url path segment websocket request
- If the signature is valid the server MUST send the
srdy
message. - After receiving
srdy
the client MAY begin sending "forward" type messages. - At any point, the server MAY send an updated
lbrt
message. - At any point after
srdy
, the server MAY send "forward" type messages to the client. - At any point after
srdy
, the client MAY send akeep
message.
sequenceDiagram
S->>C: lbrt
S->>C: lidl
S->>C: areq
C->>S: ares
S->>C: srdy
C->>S: "forward"
S->>C: "forward"
S->>C: lbrt
C->>S: keep
The lidl
"Limit Idle Millis" message is the millisecond count the server will keep a connection around
without having seen any messages sent from that client. If a client does not have any forward messages
to send within this time period and wishes to keep the connection open they SHOULD send a keep
message
to maintain the connection. Note this keep message will be counted against rate limiting.
The lbrt
"Limit Byte Nanos" message indicates the nanoseconds of rate limiting used up by a single byte sent.
This is intuitively backwards of a "limit" because higher values indicate you need to send data more slowly,
but this direction is easier to work with in code. That is, if lbrt
is 1, you can send one byte every nanosecond.
A more reasonable librt
value of 8000 means you can send 1 byte every 8000 nanoseconds. Or more reasonably,
if you send a 16000 byte message, you should wait 8000 * 16000 nanoseconds before sending the next message.
A server MUST provide a "burst" grace window to account for message size.
A server MAY track rate limiting by some metric other than individual connection. IP address, for example. Then, if additional connections are established from the same other metric, all connections could be notified of needing to send data more slowly.
A client MAY wish to honor a slightly increased rate (e.g. lbrt * 1.1) to account for clock skew or network backlogs being dumped all at once.
In order to make this protocol extensible without versioning, clients and servers MUST ignore unknown command types. (With the exception that servers should still count the raw bytes in rate limiting.)
If a server receives an invalid message from a client it MUST immediately drop the connection with no closing frame.
If a server receives a message that violates the rate limit, the connection MUST similarly be dropped with no closing frame. The server MAY also block connections (perhaps by IP address) for an unspecified amount of time.