Files
olm/API.md
2026-01-23 10:22:21 -08:00

10 KiB

API

Olm can be controlled with an embedded API server when using --enable-api. This allows you to start it as a daemon and trigger it with the following endpoints. The API can listen on either a TCP address or a Unix socket/Windows named pipe.

Socket vs TCP

When --enable-api is used, Olm can listen on a TCP address when configured via --http-addr (like :9452). Alternatively, Olm can listen on a Unix socket (Linux/macOS) or Windows named pipe for local-only communication with better security when using --socket-path (like /var/run/olm.sock).

Unix Socket (Linux/macOS):

  • Socket path example: /var/run/olm/olm.sock
  • The directory is created automatically if it doesn't exist
  • Socket permissions are set to 0666 to allow access
  • Existing socket files are automatically removed on startup
  • Socket file is cleaned up when Olm stops

Windows Named Pipe:

  • Pipe path example: \\.\pipe\olm
  • If the path doesn't start with \, it's automatically prefixed with \\.\pipe\
  • Security descriptor grants full access to Everyone and the current owner
  • Named pipes are automatically cleaned up by Windows

Connecting to the Socket:

# Linux/macOS - using curl with Unix socket
curl --unix-socket /var/run/olm/olm.sock http://localhost/status

---

### POST /connect
Initiates a new connection request to a Pangolin server.

**Request Body:**
```json
{
  "id": "string",
  "secret": "string",
  "endpoint": "string",
  "userToken": "string",
  "mtu": 1280,
  "dns": "8.8.8.8",
  "dnsProxyIP": "string",
  "upstreamDNS": ["8.8.8.8:53", "1.1.1.1:53"],
  "interfaceName": "olm",
  "holepunch": false,
  "tlsClientCert": "string",
  "pingInterval": "3s",
  "pingTimeout": "5s",
  "orgId": "string",
  "fingerprint": {
    "username": "string",
    "hostname": "string",
    "platform": "string",
    "osVersion": "string",
    "kernelVersion": "string",
    "arch": "string",
    "deviceModel": "string",
    "serialNumber": "string"
  },
  "postures": {}
}

Required Fields:

  • id: Olm ID generated by Pangolin
  • secret: Authentication secret for the Olm ID
  • endpoint: Target Pangolin endpoint URL

Optional Fields:

  • userToken: User authentication token
  • mtu: MTU for the internal WireGuard interface (default: 1280)
  • dns: DNS server to use for resolving the endpoint
  • dnsProxyIP: DNS proxy IP address
  • upstreamDNS: Array of upstream DNS servers
  • interfaceName: Name of the WireGuard interface (default: olm)
  • holepunch: Enable NAT hole punching (default: false)
  • tlsClientCert: TLS client certificate
  • pingInterval: Interval for pinging the server (default: 3s)
  • pingTimeout: Timeout for each ping (default: 5s)
  • orgId: Organization ID to connect to
  • fingerprint: Device fingerprinting information (should be set before connecting)
    • username: Current username on the device
    • hostname: Device hostname
    • platform: Operating system platform (macos, windows, linux, ios, android, unknown)
    • osVersion: Operating system version
    • kernelVersion: Kernel version
    • arch: System architecture (e.g., amd64, arm64)
    • deviceModel: Device model identifier
    • serialNumber: Device serial number
  • postures: Device posture/security information

Response:

  • Status Code: 202 Accepted
  • Content-Type: application/json
{
  "status": "connection request accepted"
}

Error Responses:

  • 405 Method Not Allowed - Non-POST requests
  • 400 Bad Request - Invalid JSON or missing required fields
  • 409 Conflict - Already connected to a server (disconnect first)

GET /status

Returns the current connection status, registration state, and peer information.

Response:

  • Status Code: 200 OK
  • Content-Type: application/json
{
  "connected": true,
  "registered": true,
  "terminated": false,
  "version": "1.0.0",
  "agent": "olm",
  "orgId": "org_123",
  "peers": {
    "10": {
      "siteId": 10,
      "name": "Site A",
      "connected": true,
      "rtt": 145338339,
      "lastSeen": "2025-08-13T14:39:17.208334428-07:00",
      "endpoint": "p.fosrl.io:21820",
      "isRelay": true,
      "peerAddress": "100.89.128.5",
      "holepunchConnected": false
    },
    "8": {
      "siteId": 8,
      "name": "Site B",
      "connected": false,
      "rtt": 0,
      "lastSeen": "2025-08-13T14:39:19.663823645-07:00",
      "endpoint": "p.fosrl.io:21820",
      "isRelay": true,
      "peerAddress": "100.89.128.10",
      "holepunchConnected": false
    }
  },
  "networkSettings": {
    "tunnelIP": "100.89.128.3/20"
  }
}

Fields:

  • connected: Boolean indicating if connected to Pangolin
  • registered: Boolean indicating if registered with the server
  • terminated: Boolean indicating if the connection was terminated
  • version: Olm version string
  • agent: Agent identifier
  • orgId: Current organization ID
  • peers: Map of peer statuses by site ID
    • siteId: Peer site identifier
    • name: Site name
    • connected: Boolean peer connection state
    • rtt: Peer round-trip time (integer, nanoseconds)
    • lastSeen: Last time peer was seen (RFC3339 timestamp)
    • endpoint: Peer endpoint address
    • isRelay: Whether the peer is relayed (true) or direct (false)
    • peerAddress: Peer's IP address in the tunnel
    • holepunchConnected: Whether holepunch connection is established
  • networkSettings: Current network configuration including tunnel IP

Error Responses:

  • 405 Method Not Allowed - Non-GET requests

POST /disconnect

Disconnects from the current Pangolin server and tears down the WireGuard tunnel.

Request Body: None required

Response:

  • Status Code: 200 OK
  • Content-Type: application/json
{
  "status": "disconnect initiated"
}

Error Responses:

  • 405 Method Not Allowed - Non-POST requests
  • 409 Conflict - Not currently connected to a server

POST /switch-org

Switches to a different organization while maintaining the connection.

Request Body:

{
  "orgId": "string"
}

Required Fields:

  • orgId: The organization ID to switch to

Response:

  • Status Code: 200 OK
  • Content-Type: application/json
{
  "status": "org switch request accepted"
}

Error Responses:

  • 405 Method Not Allowed - Non-POST requests
  • 400 Bad Request - Invalid JSON or missing orgId field
  • 500 Internal Server Error - Org switch failed

PUT /metadata

Updates device fingerprinting and posture information. This endpoint can be called at any time to update metadata, but it's recommended to provide this information in the initial /connect request or immediately before connecting.

Request Body:

{
  "fingerprint": {
    "username": "string",
    "hostname": "string",
    "platform": "string",
    "osVersion": "string",
    "kernelVersion": "string",
    "arch": "string",
    "deviceModel": "string",
    "serialNumber": "string"
  },
  "postures": {}
}

Optional Fields:

  • fingerprint: Device fingerprinting information
    • username: Current username on the device
    • hostname: Device hostname
    • platform: Operating system platform (macos, windows, linux, ios, android, unknown)
    • osVersion: Operating system version
    • kernelVersion: Kernel version
    • arch: System architecture (e.g., amd64, arm64)
    • deviceModel: Device model identifier
    • serialNumber: Device serial number
  • postures: Device posture/security information (object with arbitrary key-value pairs)

Response:

  • Status Code: 200 OK
  • Content-Type: application/json
{
  "status": "metadata updated"
}

Error Responses:

  • 405 Method Not Allowed - Non-PUT requests
  • 400 Bad Request - Invalid JSON

Note: It's recommended to call this endpoint BEFORE /connect to ensure fingerprinting information is available during the initial connection handshake.


POST /exit

Initiates a graceful shutdown of the Olm process.

Request Body: None required

Response:

  • Status Code: 200 OK
  • Content-Type: application/json
{
  "status": "shutdown initiated"
}

Note: The response is sent before shutdown begins. There is a 100ms delay before the actual shutdown to ensure the response is delivered.

Error Responses:

  • 405 Method Not Allowed - Non-POST requests

GET /health

Simple health check endpoint to verify the API server is running.

Response:

  • Status Code: 200 OK
  • Content-Type: application/json
{
  "status": "ok"
}

Error Responses:

  • 405 Method Not Allowed - Non-GET requests

Usage Examples

curl -X PUT http://localhost:9452/metadata \
  -H "Content-Type: application/json" \
  -d '{
    "fingerprint": {
      "username": "john",
      "hostname": "johns-laptop",
      "platform": "macos",
      "osVersion": "14.2.1",
      "arch": "arm64",
      "deviceModel": "MacBookPro18,3"
    }
  }'

Connect to a peer

curl -X POST http://localhost:9452/connect \
  -H "Content-Type: application/json" \
  -d '{
    "id": "31frd0uzbjvp721",
    "secret": "h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6",
    "endpoint": "https://example.com"
  }'

Connect with additional options

curl -X POST http://localhost:9452/connect \
  -H "Content-Type: application/json" \
  -d '{
    "id": "31frd0uzbjvp721",
    "secret": "h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6",
    "endpoint": "https://example.com",
    "mtu": 1400,
    "holepunch": true,
    "pingInterval": "5s"
  }'

Check connection status

curl http://localhost:9452/status

Switch organization

curl -X POST http://localhost:9452/switch-org \
  -H "Content-Type: application/json" \
  -d '{"orgId": "org_456"}'

Disconnect from server

curl -X POST http://localhost:9452/disconnect

Health check

curl http://localhost:9452/health

Shutdown Olm

curl -X POST http://localhost:9452/exit

Using Unix socket (Linux/macOS)

curl --unix-socket /var/run/olm/olm.sock http://localhost/status
curl --unix-socket /var/run/olm/olm.sock -X POST http://localhost/disconnect