Network Transport

August 10, 2014 ยท View on GitHub

Telehash can send packets over a variety of network transports, the preferred and most common of which is UDP since it is the most capable of enabling direct connections between peers. All UDP messages map to a packet 1:1 and can be sent/received over IPv4 or IPv6.

There are extensions describing how to also use other network transports:

By default there are only two required packet types on any untrusted network transport, an open and a line, both of which are encrypted by the selected Cipher Set so that only the sender/recipient can read them. Additional packet types may be supported on specific network transports relating to functionality in those networks such as broadcast discovery and routing.

When working with multiple transports a switch often needs to send and receive current network addressing details. Each specific active network address is called a path and there is a common JSON format for exchanging paths.

## `open` - Establishing a Line

A packet read from the network that has a HEAD of length 1 is always an open, with the single HEAD byte being the CSID used by the sender.

The BODY is the encrypted binary that only that selected Cipher Set can process into an "inner" packet. Here's an example of the JSON content of this decrypted inner packet:

{
    "to":"f50f423ce7f94fe98cdd09268c7e57001aed300b23020840a84a881c76739471",
    "from":{"2a":"851042800434dd49c45299c6c3fc69ab427ec49862739b6449e1fcd77b27d3a6",
            "1a": "a5a741fa09b05baaead17fa9932e13cdafc7bcd39db1153fc6bbfe4614c063f3"},
    "at":1375983687346,
    "line":"8b945f90f08940c573c29352d767fee4"
}

The inner packet's required values are defined as:

  • to - the hashname of the recipient
  • from - the fingerprints of the public keys defining the sending hashname, called its parts
  • line - the unique id the recipient must use for sending any line packets, 16 random bytes lower case hex encoded
  • at - an integer timestamp of when the line was initiated, used to verify another incoming open request is newer based on the last received at

The inner packet must also contain a binary BODY that is the sender hashname's public key for the Cipher Set being used to generate the open.

An open is always triggered by the creation of a channel to a hashname, such that when a channel generates its first packet the switch recognizes that a line doesn't exist yet. The initiating channel logic is internally responsible for any retransmission of its own packets, and those retransmissions are the source of re-triggering the sending of any open requests.

When a new line is initiated the switch must also store a local timestamp at that time and send that same value as the at in any subsequent open request for that line. This enables the recipient to recognize retransmissions of the same line initiation request, as well as detect when an open is generated for a new line as it will have a newer at value relative to the existing one. Any subsequent opens with matching or older at values must be ignored.

A switch may have an existing line but believe that the recipient might not have the line open anymore (such as if it reset, has been idle more than 60 seconds, or there's a new incoming connect from the other hashname, etc). In this state it should re-send the same open packet for the current line again, allowing the recipient to re-open the line if so.

If a new open request is validated and there's an existing line, when the new open contains a new line id then the recipient must reset all existing channels and any session state for that hashname as it signifies a complete reset/restart. If the new open contains the same/existing line id as a previous one, it is simply a request to recalculate the line encryption keys but not reset any existing channel state.

## `line` - Packet Encryption

A line is the name for the encrypted session between any two hashnames. The encryption is based on which Cipher Set they're both using, and is established by exchanging an open request as the handshake and session setup.

A packet read from the network that has a HEAD of length 0 is a binary encrypted line packet. The first 16 bytes are always the line ID, and only known line IDs are processed, any packet with an unknown ID is dropped. The remaining bytes are encrypted and processed by the Cipher Set used to create the line, the 16 byte ID should always be added/removed before being processed by any Cipher Set.

Once decrypted, the resulting value is always a channel packet. The channel packets should be verified to match an existing channel id, or if it's a new channel that is has the correct id and a supported type value. The packet should be silently dropped for any incorrect or unsupported type or id values so that other hashnames cannot blindly probe for channel support.

Often a switch may be acting as a bridge where it maps line IDs to other network destinations and doesn't attempt to process/decrypt them.

### Network Paths

To enable the most direct P2P connectivity possible the default network transport between any two switches is UDP. Additional transports are defined below for when UDP is not supported or as a fallback if it's blocked. All UDP packets map 1:1 to a Telehash packet.

Every unique network sender/recipient is called a path and defined by a JSON object that contains a "type":"..." to identify which type of network information it describes. The current path types defined are:

These paths are used often within the protocol to exchange network information, and frequently sent as an array, for example:

[{
  "type": "ipv4",
  "ip": "127.0.0.1",
  "port": 42424
}, {
  "type": "ipv6",
  "ip": "fe80::2a37:37ff:fe02:3c22",
  "port": 42424
}, {
  "type": "http",
  "http": "http://127.0.0.1"
}]