STCP - Skywire TCP (Direct)¶
STCP (Skywire TCP) is a TCP-based transport that uses a locally configured PK-to-IP mapping table for address resolution. It is designed for controlled environments where visor addresses are known in advance.
Overview¶
Unlike STCPR which relies on an external address-resolver service, STCP uses a static configuration table that maps public keys to IP addresses. This makes it ideal for:
- Local/private networks
- Development and testing environments
- Networks with static IP assignments
- Scenarios where external service dependencies are undesirable
Architecture¶
┌─────────────────────────────────────────────────────────────────┐
│ Visor A │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PK Table │ │
│ │ ┌──────────────────────┬──────────────────────────┐ │ │
│ │ │ Public Key │ Address │ │ │
│ │ ├──────────────────────┼──────────────────────────┤ │ │
│ │ │ 02abc... │ 192.168.1.100:7777 │ │ │
│ │ │ 03def... │ 192.168.1.101:7777 │ │ │
│ │ │ 04ghi... │ 10.0.0.50:7777 │ │ │
│ │ └──────────────────────┴──────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
│ Direct TCP
▼
┌─────────────────────────────────────────────────────────────────┐
│ Visor B │
│ (192.168.1.100:7777) │
└─────────────────────────────────────────────────────────────────┘
Connection Flow¶
Server-side (Listening)¶
- Visor reads
listening_addressfrom configuration - Starts TCP listener on the configured address
- Accepts incoming connections
- Performs transport handshake to authenticate remote visor
Client-side (Dialing)¶
- Visor looks up target public key in the PK table
- If found, dials the corresponding IP:port directly via TCP
- Performs transport handshake
- Connection established
Address Resolution¶
If the public key is not found in the table, the dial fails with ErrStcpEntryNotFound.
Configuration¶
In the visor config file, STCP is configured under the "skywire-tcp" key:
{
"skywire-tcp": {
"pk_table": {
"02abc123def456...": "192.168.1.100:7777",
"03def456abc123...": "192.168.1.101:7777",
"04789ghi012jkl...": "10.0.0.50:8888"
},
"listening_address": ":7777"
}
}
| Field | Type | Description |
|---|---|---|
pk_table |
object | Map of public key (66-char hex) to IP:port address |
listening_address |
string | Local address to listen on (e.g., :7777 or 0.0.0.0:7777) |
PK Table Format¶
Each entry in the PK table maps a visor's public key to its network address:
Example:
{
"02a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2": "192.168.1.100:7777",
"03f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5": "10.0.0.50:7777"
}
Transport Handshake¶
The connection is authenticated by a four-frame nonce-challenge exchange — this is not a Noise handshake, and Noise runs only after it succeeds:
- Initiator sends frame 0: the literal string
get_nonce. - Responder replies with frame 1: a freshly generated random nonce.
- Initiator sends frame 2: its
{SrcAddr, DstAddr, Nonce}signed under its secret key. - Responder verifies the signature against the nonce it issued, checks the destination port has a listener, and replies with frame 3: OK, or an error message.
Only once frame 3 reports OK is the connection wrapped in a Noise KK
handshake, which derives the session keys used for all subsequent traffic.
The nonce challenge is what makes the signature non-replayable: because the responder chooses the nonce per connection, a captured frame 2 cannot authenticate a later one.
Error Handling¶
| Error | Cause | Resolution |
|---|---|---|
ErrStcpEntryNotFound |
Public key not in PK table | Add entry to pk_table configuration |
| Connection refused | Target not listening | Ensure target visor is running and listening |
| Handshake failed | Key mismatch or network issue | Verify correct PK in table, check network |
Use Cases¶
Local Development¶
{
"skywire-tcp": {
"pk_table": {
"02dev1a2b3c4d5e6f...": "127.0.0.1:7778",
"02dev2f6e5d4c3b2a...": "127.0.0.1:7779"
},
"listening_address": ":7777"
}
}
Code References¶
- Implementation:
pkg/transport/network/stcp.go - PK Table interface:
pkg/transport/network/stcp/table.go - Transport type constant:
pkg/transport/types/types.go:15