mirror of
https://github.com/fosrl/olm.git
synced 2026-02-08 05:56:41 +00:00
Add some more fields to the http api
This commit is contained in:
103
README.md
103
README.md
@@ -121,6 +121,109 @@ You can view the Windows Event Log using Event Viewer or PowerShell:
|
|||||||
Get-EventLog -LogName Application -Source "OlmWireguardService" -Newest 10
|
Get-EventLog -LogName Application -Source "OlmWireguardService" -Newest 10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## HTTP Endpoints
|
||||||
|
|
||||||
|
Olm can be controlled with an embedded http server when using `--enable-http`. This allows you to start it as a daemon and trigger it with the following endpoints:
|
||||||
|
|
||||||
|
### POST /connect
|
||||||
|
Initiates a new connection request.
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "string",
|
||||||
|
"secret": "string",
|
||||||
|
"endpoint": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Required Fields:**
|
||||||
|
- `id`: Connection identifier
|
||||||
|
- `secret`: Authentication secret
|
||||||
|
- `endpoint`: Target endpoint URL
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
- **Status Code:** `202 Accepted`
|
||||||
|
- **Content-Type:** `application/json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "connection request accepted"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error Responses:**
|
||||||
|
- `405 Method Not Allowed` - Non-POST requests
|
||||||
|
- `400 Bad Request` - Invalid JSON or missing required fields
|
||||||
|
|
||||||
|
### GET /status
|
||||||
|
Returns the current connection status and peer information.
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
- **Status Code:** `200 OK`
|
||||||
|
- **Content-Type:** `application/json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "connected",
|
||||||
|
"connected": true,
|
||||||
|
"tunnelIP": "100.89.128.3/20",
|
||||||
|
"version": "version_replaceme",
|
||||||
|
"peers": {
|
||||||
|
"10": {
|
||||||
|
"siteId": 10,
|
||||||
|
"connected": true,
|
||||||
|
"rtt": 145338339,
|
||||||
|
"lastSeen": "2025-08-13T14:39:17.208334428-07:00",
|
||||||
|
"endpoint": "p.fosrl.io:21820",
|
||||||
|
"isRelay": true
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"siteId": 8,
|
||||||
|
"connected": false,
|
||||||
|
"rtt": 0,
|
||||||
|
"lastSeen": "2025-08-13T14:39:19.663823645-07:00",
|
||||||
|
"endpoint": "p.fosrl.io:21820",
|
||||||
|
"isRelay": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fields:**
|
||||||
|
- `status`: Overall connection status ("connected" or "disconnected")
|
||||||
|
- `connected`: Boolean connection state
|
||||||
|
- `tunnelIP`: IP address and subnet of the tunnel (when connected)
|
||||||
|
- `version`: Olm version string
|
||||||
|
- `peers`: Map of peer statuses by site ID
|
||||||
|
- `siteId`: Peer site identifier
|
||||||
|
- `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)
|
||||||
|
|
||||||
|
**Error Responses:**
|
||||||
|
- `405 Method Not Allowed` - Non-GET requests
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Connect to a peer
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8080/connect \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"id": "31frd0uzbjvp721",
|
||||||
|
"secret": "h51mmlknrvrwv8s4r1i210azhumt6isgbpyavxodibx1k2d6",
|
||||||
|
"endpoint": "https://example.com"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check connection status
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8080/status
|
||||||
|
```
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
### Container
|
### Container
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ type PeerStatus struct {
|
|||||||
Connected bool `json:"connected"`
|
Connected bool `json:"connected"`
|
||||||
RTT time.Duration `json:"rtt"`
|
RTT time.Duration `json:"rtt"`
|
||||||
LastSeen time.Time `json:"lastSeen"`
|
LastSeen time.Time `json:"lastSeen"`
|
||||||
|
Endpoint string `json:"endpoint,omitempty"`
|
||||||
|
IsRelay bool `json:"isRelay"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatusResponse is returned by the status endpoint
|
// StatusResponse is returned by the status endpoint
|
||||||
@@ -30,6 +32,7 @@ type StatusResponse struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Connected bool `json:"connected"`
|
Connected bool `json:"connected"`
|
||||||
TunnelIP string `json:"tunnelIP,omitempty"`
|
TunnelIP string `json:"tunnelIP,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
PeerStatuses map[int]*PeerStatus `json:"peers,omitempty"`
|
PeerStatuses map[int]*PeerStatus `json:"peers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +45,8 @@ type HTTPServer struct {
|
|||||||
peerStatuses map[int]*PeerStatus
|
peerStatuses map[int]*PeerStatus
|
||||||
connectedAt time.Time
|
connectedAt time.Time
|
||||||
isConnected bool
|
isConnected bool
|
||||||
|
tunnelIP string
|
||||||
|
version string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHTTPServer creates a new HTTP server
|
// NewHTTPServer creates a new HTTP server
|
||||||
@@ -87,8 +92,8 @@ func (s *HTTPServer) GetConnectionChannel() <-chan ConnectionRequest {
|
|||||||
return s.connectionChan
|
return s.connectionChan
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePeerStatus updates the status of a peer
|
// UpdatePeerStatus updates the status of a peer including endpoint and relay info
|
||||||
func (s *HTTPServer) UpdatePeerStatus(siteID int, connected bool, rtt time.Duration) {
|
func (s *HTTPServer) UpdatePeerStatus(siteID int, connected bool, rtt time.Duration, endpoint string, isRelay bool) {
|
||||||
s.statusMu.Lock()
|
s.statusMu.Lock()
|
||||||
defer s.statusMu.Unlock()
|
defer s.statusMu.Unlock()
|
||||||
|
|
||||||
@@ -103,6 +108,8 @@ func (s *HTTPServer) UpdatePeerStatus(siteID int, connected bool, rtt time.Durat
|
|||||||
status.Connected = connected
|
status.Connected = connected
|
||||||
status.RTT = rtt
|
status.RTT = rtt
|
||||||
status.LastSeen = time.Now()
|
status.LastSeen = time.Now()
|
||||||
|
status.Endpoint = endpoint
|
||||||
|
status.IsRelay = isRelay
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConnectionStatus sets the overall connection status
|
// SetConnectionStatus sets the overall connection status
|
||||||
@@ -120,6 +127,37 @@ func (s *HTTPServer) SetConnectionStatus(isConnected bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTunnelIP sets the tunnel IP address
|
||||||
|
func (s *HTTPServer) SetTunnelIP(tunnelIP string) {
|
||||||
|
s.statusMu.Lock()
|
||||||
|
defer s.statusMu.Unlock()
|
||||||
|
s.tunnelIP = tunnelIP
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVersion sets the olm version
|
||||||
|
func (s *HTTPServer) SetVersion(version string) {
|
||||||
|
s.statusMu.Lock()
|
||||||
|
defer s.statusMu.Unlock()
|
||||||
|
s.version = version
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePeerRelayStatus updates only the relay status of a peer
|
||||||
|
func (s *HTTPServer) UpdatePeerRelayStatus(siteID int, endpoint string, isRelay bool) {
|
||||||
|
s.statusMu.Lock()
|
||||||
|
defer s.statusMu.Unlock()
|
||||||
|
|
||||||
|
status, exists := s.peerStatuses[siteID]
|
||||||
|
if !exists {
|
||||||
|
status = &PeerStatus{
|
||||||
|
SiteID: siteID,
|
||||||
|
}
|
||||||
|
s.peerStatuses[siteID] = status
|
||||||
|
}
|
||||||
|
|
||||||
|
status.Endpoint = endpoint
|
||||||
|
status.IsRelay = isRelay
|
||||||
|
}
|
||||||
|
|
||||||
// handleConnect handles the /connect endpoint
|
// handleConnect handles the /connect endpoint
|
||||||
func (s *HTTPServer) handleConnect(w http.ResponseWriter, r *http.Request) {
|
func (s *HTTPServer) handleConnect(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method != http.MethodPost {
|
if r.Method != http.MethodPost {
|
||||||
@@ -163,6 +201,8 @@ func (s *HTTPServer) handleStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
resp := StatusResponse{
|
resp := StatusResponse{
|
||||||
Connected: s.isConnected,
|
Connected: s.isConnected,
|
||||||
|
TunnelIP: s.tunnelIP,
|
||||||
|
Version: s.version,
|
||||||
PeerStatuses: s.peerStatuses,
|
PeerStatuses: s.peerStatuses,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
87
main.go
87
main.go
@@ -331,6 +331,7 @@ func runOlmMainWithArgs(ctx context.Context, args []string) {
|
|||||||
var httpServer *httpserver.HTTPServer
|
var httpServer *httpserver.HTTPServer
|
||||||
if enableHTTP {
|
if enableHTTP {
|
||||||
httpServer = httpserver.NewHTTPServer(httpAddr)
|
httpServer = httpserver.NewHTTPServer(httpAddr)
|
||||||
|
httpServer.SetVersion(olmVersion)
|
||||||
if err := httpServer.Start(); err != nil {
|
if err := httpServer.Start(); err != nil {
|
||||||
logger.Fatal("Failed to start HTTP server: %v", err)
|
logger.Fatal("Failed to start HTTP server: %v", err)
|
||||||
}
|
}
|
||||||
@@ -372,31 +373,31 @@ func runOlmMainWithArgs(ctx context.Context, args []string) {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // wait until we have a client id and secret and endpoint
|
// wait until we have a client id and secret and endpoint
|
||||||
// waitCount := 0
|
waitCount := 0
|
||||||
// for id == "" || secret == "" || endpoint == "" {
|
for id == "" || secret == "" || endpoint == "" {
|
||||||
// select {
|
select {
|
||||||
// case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
// logger.Info("Context cancelled while waiting for credentials")
|
logger.Info("Context cancelled while waiting for credentials")
|
||||||
// return
|
return
|
||||||
// default:
|
default:
|
||||||
// missing := []string{}
|
missing := []string{}
|
||||||
// if id == "" {
|
if id == "" {
|
||||||
// missing = append(missing, "id")
|
missing = append(missing, "id")
|
||||||
// }
|
}
|
||||||
// if secret == "" {
|
if secret == "" {
|
||||||
// missing = append(missing, "secret")
|
missing = append(missing, "secret")
|
||||||
// }
|
}
|
||||||
// if endpoint == "" {
|
if endpoint == "" {
|
||||||
// missing = append(missing, "endpoint")
|
missing = append(missing, "endpoint")
|
||||||
// }
|
}
|
||||||
// waitCount++
|
waitCount++
|
||||||
// if waitCount%10 == 1 { // Log every 10 seconds instead of every second
|
if waitCount%10 == 1 { // Log every 10 seconds instead of every second
|
||||||
// logger.Debug("Waiting for missing parameters: %v (waiting %d seconds)", missing, waitCount)
|
logger.Debug("Waiting for missing parameters: %v (waiting %d seconds)", missing, waitCount)
|
||||||
// }
|
}
|
||||||
// time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// parse the mtu string into an int
|
// parse the mtu string into an int
|
||||||
mtuInt, err = strconv.Atoi(mtu)
|
mtuInt, err = strconv.Atoi(mtu)
|
||||||
@@ -644,10 +645,27 @@ func runOlmMainWithArgs(ctx context.Context, args []string) {
|
|||||||
logger.Error("Failed to configure interface: %v", err)
|
logger.Error("Failed to configure interface: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set tunnel IP in HTTP server
|
||||||
|
if httpServer != nil {
|
||||||
|
httpServer.SetTunnelIP(wgData.TunnelIP)
|
||||||
|
}
|
||||||
|
|
||||||
peerMonitor = peermonitor.NewPeerMonitor(
|
peerMonitor = peermonitor.NewPeerMonitor(
|
||||||
func(siteID int, connected bool, rtt time.Duration) {
|
func(siteID int, connected bool, rtt time.Duration) {
|
||||||
if httpServer != nil {
|
if httpServer != nil {
|
||||||
httpServer.UpdatePeerStatus(siteID, connected, rtt)
|
// Find the site config to get endpoint information
|
||||||
|
var endpoint string
|
||||||
|
var isRelay bool
|
||||||
|
for _, site := range wgData.Sites {
|
||||||
|
if site.SiteId == siteID {
|
||||||
|
endpoint = site.Endpoint
|
||||||
|
// TODO: We'll need to track relay status separately
|
||||||
|
// For now, assume not using relay unless we get relay data
|
||||||
|
isRelay = !doHolepunch
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpServer.UpdatePeerStatus(siteID, connected, rtt, endpoint, isRelay)
|
||||||
}
|
}
|
||||||
if connected {
|
if connected {
|
||||||
logger.Info("Peer %d is now connected (RTT: %v)", siteID, rtt)
|
logger.Info("Peer %d is now connected (RTT: %v)", siteID, rtt)
|
||||||
@@ -664,7 +682,7 @@ func runOlmMainWithArgs(ctx context.Context, args []string) {
|
|||||||
// loop over the sites and call ConfigurePeer for each one
|
// loop over the sites and call ConfigurePeer for each one
|
||||||
for _, site := range wgData.Sites {
|
for _, site := range wgData.Sites {
|
||||||
if httpServer != nil {
|
if httpServer != nil {
|
||||||
httpServer.UpdatePeerStatus(site.SiteId, false, 0)
|
httpServer.UpdatePeerStatus(site.SiteId, false, 0, site.Endpoint, false)
|
||||||
}
|
}
|
||||||
err = ConfigurePeer(dev, site, privateKey, endpoint)
|
err = ConfigurePeer(dev, site, privateKey, endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -893,18 +911,23 @@ func runOlmMainWithArgs(ctx context.Context, args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var removeData RelayPeerData
|
var relayData RelayPeerData
|
||||||
if err := json.Unmarshal(jsonData, &removeData); err != nil {
|
if err := json.Unmarshal(jsonData, &relayData); err != nil {
|
||||||
logger.Error("Error unmarshaling remove data: %v", err)
|
logger.Error("Error unmarshaling relay data: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
primaryRelay, err := resolveDomain(removeData.Endpoint)
|
primaryRelay, err := resolveDomain(relayData.Endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn("Failed to resolve primary relay endpoint: %v", err)
|
logger.Warn("Failed to resolve primary relay endpoint: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
peerMonitor.HandleFailover(removeData.SiteId, primaryRelay)
|
// Update HTTP server to mark this peer as using relay
|
||||||
|
if httpServer != nil {
|
||||||
|
httpServer.UpdatePeerRelayStatus(relayData.SiteId, relayData.Endpoint, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
peerMonitor.HandleFailover(relayData.SiteId, primaryRelay)
|
||||||
})
|
})
|
||||||
|
|
||||||
olm.RegisterHandler("olm/register/no-sites", func(msg websocket.WSMessage) {
|
olm.RegisterHandler("olm/register/no-sites", func(msg websocket.WSMessage) {
|
||||||
|
|||||||
Reference in New Issue
Block a user