SAGIRI controller reference implementation
1 Racket bindings
(require sagiri-comm) | package: sagiri-comm |
sagiri-comm provides a convenient Racket interface to SAGIRI. It works by talking with a running SAGIRI instance on the local machine, so make sure that SAGIRI is running before calling the procedures exported by this module.
One thing to note is the URL format: URLs that are passed to "sagiri-connect" and returned from the other two functions are of the following format:
[ IP address ] [ EdDSA Public key (32 bytes) ] |
(###-###-###-###--)aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.edge.sagiri |
When returning a hostname, this library will always include the IP address. It’s up to the application to strip the IP portion out if it wishes to before handing out the address to anybody.
Note: In practice, until SAGIRI’s onion-routing and DHT functionality is completed, the IP address will always be needed.
procedure
(sagiri-connect host port) →
input-port? output-port? host : string? port : exact-integer?
procedure
(sagiri-start-forward #:private-key priv-key #:internal-port int-port #:external-port ext-port)
→
string? exact-integer? priv-key : bytes? int-port : exact-integer? ext-port : exact-integer?
procedure
(sagiri-stop-forward #:private-key priv-key #:external-port ext-port) → boolean? priv-key : bytes? ext-port : exact-integer?
2 SAGIRI IPC specification
2.1 Overview
This document details the binary inter-process communication protocol used to talk with the SAGIRI daemon. All numbers are encoded as big-endian, and all strings are assumed to be in UTF-8 format.
The protocol itself is similar in spirit to HTTP/1.0: it’s stateless, and is based on a single request/response on a TCP connection which is not kept alive. The process goes like this:
The application connects to localhost:12377 over TCP.
The daemon sends a greeting giving general status information about the daemon.
The application sends a request to the daemon.
The daemon sends a response.
The connection is closed.
This document does not cover SOCKS5, which is used to connect to the actual remote hosts. The daemon will tell the application where to find the SOCKS5 server set up by SAGIRI; the application then connects to remote SAGIRI/Kiricom hosts by using the pseudo-hostname and port extracted from the sort of URL described at the beginning of the document. The SAGIRI SOCKS5 server, for obvious reasons, only supports TCP proxying, not port forwarding or UDP proxying.
(The reason why SOCKS5 is used to handle the forwarding part is to reduce complexity of the IPC protocol, and also to more easily enable SAGIRI client functionality in third-party applications which support SOCKS5, who can simply be passed the correct SOCKS5 address by a shim program that implements this protocol to discover the SOCKS5 address.)
2.2 Daemon greeting format
1 byte: major version |
1 byte: minor version |
1 byte: patch |
2 bytes: SOCKS5 port |
2.3 Application request format
1 byte: request code |
32 bytes: private key (Ed25519 format from libsodium) |
2 bytes: internal port |
2 bytes: external port |
The no-op request means the client does not want a response. The connection is immediately closed after sending a request with the NOOP code. The other fields are ignored by the daemon.
The HOST code indicates that the application intends to host a service over SAGIRI. For example, if the application is a Web server listening on port 8080 and intends to offer SAGIRI access from the outside Internet on port 80, it would set the internal port to 80, the external port to 8080, and the private key to a value that should be unique for each service.
Note: Currently, SAGIRI’s onion-routing is not done, so this essentially acts only as a Kiricom provider.
The STOP code indicates that the application wants to stop hosting a service. The external port and private key identify the service that is to be stopped. The internal port field is actually ignored by the daemon.
2.4 Daemon response format
1 byte: response code |
2 bytes: length of message |
variable: message string |
The OKAY code denotes that the request has been fulfilled. If the request was a hosting request, then the message contains the globally routable pseudo-hostname:port URL (see beginning of this document).
The NOPE code denotes that the request cannot be fulfilled. A human-readable message denoting the nature of the error is put in message.