# Netrinos Edgenode API Documentation # Authentication ## Login to Obtain Access Token To access the API, you must first log in to the device and obtain an access token. The account used also needs the API role assigned in the portal. The token will be valid for the duration of the client login. Alternatively, if the reqest is received on localhost (127.0.0.1) the token requirement will be ignored. ### Request ```json POST http://edgedevice:88/api/login { "Username": "username", "Password": "password" } ``` ### Response ```json Status: 200 OK { "success": "Login successful", "error": "", "data": { "AuthToken": "e0db2c0d81...d52cd273db", "Username": "username" } } ``` ### Error Response ```json Status: 401 Unauthorized { "success": "", "error": "Invalid username or password", "data": null } ``` Use `AuthToken` as a Bearer token in the header of API requests: ``` Authorization: Bearer e0db2c0d81...d52cd273db ``` ## Test the Token Check if the token is valid, send a ping request to the API. ### Request ```json GET http://edgedevice:88/api/ping ``` ### Response ```json Status: 200 OK { "success": "Success", "error": "", "data": null } ``` ### Error Response ```json Status: 401 Unauthorized Unauthorized - Invalid token ``` # Networks ## Create or Update ### Request ```json POST http://edgedevice:88/api/edge/network/192.168.2.0-24 POST http://edgedevice:88/api/edge/network/192.168.2.0 ``` ### Response ```json Status: 200 OK { "success": "Network created", "error": "", "data": { "Network": { "Name": "192.168.2.0/24", "IFname": "", "HostIPMask": "", "HostIP": "", "HostMask": 0, "NetIPMask": "192.168.2.0/24", "NetIP": "192.168.2.0", "NetMask": 24, "IPint": 3232236032, "LastScan": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" } } } ``` ## Get Network(s) Manipulate networks registered on the device. Specify CIDR notation in URLs with a `-` in place of a `/`. ### Request ```json GET http://edgedevice:88/api/edge/network/192.168.2.0-24 GET http://edgedevice:88/api/edge/network/192.168.2.0 ``` ### Response ```json Status: 200 OK { "success": "Network found", "error": "", "data": { "Network": { "Name": "192.168.2.0/24", "IFname": "", "HostIPMask": "", "HostIP": "", "HostMask": 0, "NetIPMask": "192.168.2.0/24", "NetIP": "192.168.2.0", "NetMask": 24, "IPint": 3232236032, "LastScan": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" } } } ``` ### Request ```json GET http://edgedevice:88/api/edge/network ``` ### Response ```json Status: 200 OK { "success": "Networks found", "error": "", "data": { "Count": 2, "Networks": [ { "Name": "192.168.2.0/24", "IFname": "", "HostIPMask": "", "HostIP": "", "HostMask": 0, "NetIPMask": "192.168.2.0/24", "NetIP": "192.168.2.0", "NetMask": 24, "IPint": 3232236032, "LastScan": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" }, ... ] } } ``` ### Error Response ```json Status: 404 Not Found { "success": "", "error": "Network not found", "data": null } ``` ## Delete ### Request ```json DELETE http://edgedevice:88/api/edge/network/192.168.2.0-24 DELETE http://edgedevice:88/api/edge/network/192.168.2.0 ``` ### Response ```json Status: 200 OK { "success": "Network deleted", "error": "", "data": null } ``` ### Error Response ```json Status: 404 Not Found { "success": "", "error": "Network not found", "data": null } ``` # Devices ## Create or Update Device Create or update a device in the network. ### Request ```json POST http://edgedevice:88/api/edge/device/192.168.8.10 { "Name": "Brother MFC", "Hostname": "brother", "IP": "192.168.8.10", "Network": "192.168.8.0/24", "Vendor": "Brother Industries Ltd." } ``` ### Response ```json Status: 200 OK { "success": "Network updated", "error": "", "data": { "Device": { "Name": "Brother MFC", "Hostname": "brother", "IP": "192.168.8.10", "IPint": 3232237578, "Network": "192.168.8.0/24", "MAC": "", "Vendor": "Brother Industries Ltd.", "Notes": "", "Ports": null, "Forwards": null, "ProxyMap": null, "ForwardsMap": null, "Created": "0001-01-01T00:00:00Z", "Updated": "0001-01-01T00:00:00Z" } } } ``` ## Get Device Information Retrieve information about a specific device (node) in a network. ### Request ```json GET http://edgedevice:88/api/edge/device/192.168.8.10 ``` ### Response ```json Status: 200 OK { "success": "Device found", "error": "", "data": { "Node": { "Name": "brother", "Hostname": "brother", "IP": "192.168.8.10", "IPint": 3232237578, "Network": "192.168.8.0/24", "MAC": "e8:65:38:28:7d:53", "Vendor": "CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD.", "Notes": "", "Ports": null, "Forwards": [ { "Name": "Admin UI", "Nodename": "", "IP": "192.168.8.10", "IPint": 3232237578, "PortNum": 443, "Protocol": "tcp", "Method": "Forward", "Service": "", "SourceIP": "0.0.0.0", "SourcePort": 10000, "OpenAs": "https", "Command": "https://device.account.2ho.ca:10000", "Enabled": true, "Updated": "0001-01-01T00:00:00Z" } ], "ProxyMap": null, "ForwardsMap": null, "Created": "0001-01-01T00:00:00Z", "Updated": "2024-12-11T10:55:33.768678777-05:00" } } } ``` ## Get All Devices Retrieve a list of all devices in the network. Specify the network CIDR in the URL. If the network is not specified, all devices are returned. Use a `-` in place of a `/` in the CIDR notation. ### Request ```json GET http://edgedevice:88/api/edge/devices GET http://edgedevice:88/api/edge/devices/192.168.8.0-24 ``` ### Response ```json Status: 200 OK { "success": "Devices found", "error": "", "data": { "Count": 19, "Network": [ { "Name": "unifi", "Hostname": "unifi", "IP": "192.168.8.1", "IPint": 3232237569, "Network": "192.168.8.0/24", "MAC": "0e:ea:14:4d:1a:cc", "Vendor": "Unknown Vendor", "Notes": "", "Ports": null, "Forwards": [...], "ProxyMap": null, "ForwardsMap": null, "Created": "0001-01-01T00:00:00Z", "Updated": "2024-12-13T14:18:11.800682015-05:00" }, ... ] } } ``` ## Delete Device Delete a device from the network. ### Request ```json DELETE http://edgedevice:88/api/edge/device/192.168.8.10 ``` ### Response ```json Status: 200 OK { "success": "Device deleted", "error": "", "data": null } ``` ## Forwarding Rules ## Create or Update a Rule Creates a new forwarding rule or updates an existing one if the port already exists. If the device does not exist, it is automatically created. ### Request ```json POST http://edgedevice:88/api/edge/forward { "Name": "Admin UI", "IP": "192.168.8.10", "PortNum": 80, "Protocol": "tcp", "OpenAs": "http", "Enabled": true } ``` ### Response ```json { "success": "Forward created successfully", "error": "", "data": { "Forward": { "Name": "Admin UI", "Nodename": "", "IP": "192.168.8.10", "IPint": 3232237578, "PortNum": 80, "Protocol": "tcp", "Method": "Forward", "Service": "", "SourceIP": "0.0.0.0", "SourcePort": 10000, "OpenAs": "http", "Command": "", "Enabled": true, "Updated": "0001-01-01T00:00:00Z" } } } ``` ## Read One Read a specified forwarding rule by port. ### Request ```json GET http://edgedevice:88/api/edge/forward/192.168.8.10/443 ``` ### Response ```json Status: 200 OK { "success": "Forward found", "error": "", "data": { "Forward": { "Name": "Admin UI", "Nodename": "", "IP": "192.168.8.10", "IPint": 3232237578, "PortNum": 80, "Protocol": "tcp", "Method": "Forward", "Service": "", "SourceIP": "0.0.0.0", "SourcePort": 10000, "OpenAs": "http", "Command": "", "Enabled": true, "Updated": "0001-01-01T00:00:00Z" } } } ``` ## Read All Read all the forwarded ports from a device. ### Request ```json GET http://edgedevice:88/api/edge/forward/192.168.8.10 ``` ### Response ```json Status: 200 OK { "success": "Forwards found", "error": "", "data": { "Forwards": [ { "Name": "Admin UI", "Nodename": "", "IP": "192.168.8.10", "IPint": 3232237578, "PortNum": 80, "Protocol": "tcp", "Method": "Forward", "Service": "", "SourceIP": "0.0.0.0", "SourcePort": 10000, "OpenAs": "http", "Command": "", "Enabled": true, "Updated": "0001-01-01T00:00:00Z" }, ... ] } } ``` ## Delete a Forward Delete a forwarding rule from the device. ### Request ```json DELETE http://edgedevice:88/api/edge/forward/192.168.8.10/80 ``` ### Response ```json Status: 200 OK { "success": true, "error": "", "message": "Forward deleted successfully" } ``` # Scanner ## Start a Network Scan Start a network scan. Request ```json GET http://edgedevice:88/api/edge/scan/start ``` Response ```json Status: 200 OK { "success": "Continuous scanning started", "error": "", "data": null } ``` ## Stop a Network Scan Stop a network scan. Request ```json GET http://edgedevice:88/api/edge/scan/stop ``` Response ```json Status: 200 OK { "success": "Scanning stopped", "error": "", "data": null } ``` ## Scan Once Scan a network once. i.e. Not continuously. Request ```json GET http://edgedevice:88/api/edge/scan/once ``` Response ```json Status: 200 OK { "success": "Single scan initiated", "error": "", "data": null } ``` ## Scan with ONVIF Scan a network for ONVIF devices using the ONVIF protocol only. ### Request ```json GET http://edgedevice:88/api/edge/scan/onvif ``` ### Response ```json Status: 200 OK { "success": "ONVIF scan initiated", "error": "", "data": null } ``` ## Scan a Specific Host Scan a single host for open ports. ### Request ```json GET http://edgedevice:88/api/edge/scan/192.168.8.1 ``` ### Response ```json Status: 200 OK { "success": "Host scan initiated", "error": "", "data": null } ``` # Configuration ## Get Configuration Get the configuration of the Netrinos Edge Services ### Request ```json GET http://edgedevice:88/api/edge/config ``` ### Response ```json Status: 200 OK { "success": "Edge config found", "error": "", "data": { "Config": { "LocalNet": { "Hostname": "", "IsStatic": false, "LocalIPn": "", "Gateway": "", "DNS": "" }, "Server": { "IP": "0.0.0.0", "Port": "88" }, "Proxy": { "IP": "0.0.0.0", "ServeIP": "192.168.8.20", "PortStart": 10000, "PortRange": 1000 }, "Socks": { "IP": "0.0.0.0", "Port": 1080 }, "Scan": { "Auto": false, "Interval": 0, "Workers": 0, "Continuous": false, "NoScanSubnets": "", "OnvifScan": false }, "Monitor": { "Auto": false, "Target": "" } } } } ``` ## Get Scan Configuration Get the scan configuration of the Netrinos Edge Services ### Request ```json GET http://edgedevice:88/api/edge/config/config ``` ### Response ```json Status: 200 OK { "success": "Scanner config found", "error": "", "data": { "Scan": { "Auto": false, "Interval": 0, "Workers": 0, "Continuous": false, "NoScanSubnets": "", "OnvifScan": false } } } ``` ## Set Scanner Configuration Set parameters of the scan configuration ### Request ```json POST http://edgedevice:88/api/edge/scan/config { "Auto": false } ``` ### Response ```json Status: 200 OK { "success": "Scan configuration updated", "error": "", "data": { "Scanner": { "Auto": false, "Interval": 0, "Workers": 0, "Continuous": false, "NoScanSubnets": "", "OnvifScan": false } } } ``` ### Request ```json POST http://edgedevice:88/api/edge/config { "Continuous": true } ``` ### Response ```json Status: 200 OK { "success": "Scan configuration updated", "error": "", "data": { "Scanner": { "Auto": false, "Interval": 0, "Workers": 0, "Continuous": true, "NoScanSubnets": "", "OnvifScan": false } } } ``` # Example Usage These examples are far from optimal. They are meant as simplified examples of how to use the API. ## Login and set a forward rule ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) const apiURL = "http://localhost:88" // API URL var client *http.Client // Global HTTP client func main() { client = &http.Client{} // Previously authenticated token. May not be current. token := "1234abcdthismayormaynotbeavalidtokenab6abcd1234" // Login credentials - be sure the account has the API role in the admin portal credentials := map[string]string{ "Username": "username", "Password": "password", } // Check if the token is valid req, _ := http.NewRequest("GET", apiURL+"/api/ping", nil) req.Header.Set("Authorization", "Bearer "+token) tokenResp, _ := client.Do(req) if tokenResp.StatusCode == http.StatusOK { fmt.Printf("Token is valid.") } else { fmt.Println("Token is invalid. Logging in to get a new token.") // Login to get a new token jsonData, _ := json.Marshal(credentials) resp, _ := http.Post(apiURL+"/api/login", "application/json", bytes.NewBuffer(jsonData)) body, _ := io.ReadAll(resp.Body) defer resp.Body.Close() // Check that the login was successful if resp.StatusCode != http.StatusOK { fmt.Printf("Login failed. Status code: %d\n", resp.StatusCode) return } var loginResp map[string]interface{} json.Unmarshal(body, &loginResp) // Get the auth token from the nested response structure loginData := loginResp["data"].(map[string]interface{}) token = loginData["AuthToken"].(string) fmt.Printf("Received token: %s\n", token) } // Create forward rule IP := "192.168.8.254" forwardRule := map[string]interface{}{ "Name": "RTSP Stream", "IP": IP, "PortNum": 554, "Protocol": "tcp", "OpenAs": "rtsp", "Enabled": true, } ruleJSON, _ := json.Marshal(forwardRule) req, _ = http.NewRequest("POST", apiURL+"/api/edge/forward/"+IP, bytes.NewBuffer(ruleJSON)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") resp, _ := client.Do(req) body, _ := io.ReadAll(resp.Body) defer resp.Body.Close() fmt.Printf("Forward rule response: %s\n", string(body)) } ``` ### Result ```json Token is invalid. Logging in to get a new token. Received token: 1fbcc8daf8d212ca91285a7ee4772b6208b3cb6d56a14e682847616aaab6490a Forward rule response: { "success": "Forward created successfully", "error": "", "data": { "Forward": { "Name": "RTSP Stream", "Nodename": "unknown", "IP": "192.168.8.254", "IPint": 3232237822, "PortNum": 554, "Protocol": "tcp", "Method": "Forward", "Service": "rtsp", "SourceIP": "0.0.0.0", "SourcePort": 10000, "OpenAs": "rtsp", "Command": "", "Enabled": true, "Updated": "2024-12-16T19:36:06.642964426-05:00" } } } ``` ## Perform an ONVIF Scan Scan the network for ONVIF devices and list the results ### Example Code ```go package main import ( "encoding/json" "fmt" "io" "net/http" "time" ) const apiURL = "http://edgedevice:88" func main() { // Known token from previous authentication token := "1234abcdthismayormaynotbeavalidtokenab6abcd1234" client := &http.Client{} // Start ONVIF scan req, _ := http.NewRequest("GET", apiURL+"/api/edge/scan/onvif", nil) req.Header.Set("Authorization", "Bearer "+token) resp, _ := client.Do(req) body, _ := io.ReadAll(resp.Body) resp.Body.Close() fmt.Printf("Scan initiated: %s\n", string(body)) // Poll scan status until complete for { req, _ = http.NewRequest("GET", apiURL+"/api/edge/scan", nil) req.Header.Set("Authorization", "Bearer "+token) resp, _ = client.Do(req) body, _ = io.ReadAll(resp.Body) resp.Body.Close() var respData map[string]interface{} json.Unmarshal(body, &respData) data := respData["data"].(map[string]interface{}) if !data["running"].(bool) { break } time.Sleep(3 * time.Second) } fmt.Println() // Get discovered devices req, _ = http.NewRequest("GET", apiURL+"/api/edge/devices", nil) req.Header.Set("Authorization", "Bearer "+token) resp, _ = client.Do(req) body, _ = io.ReadAll(resp.Body) resp.Body.Close() var result map[string]interface{} json.Unmarshal(body, &result) fmt.Println("\nDiscovered devices:") devices := result["data"].(map[string]interface{})["Network"].([]interface{}) for _, device := range devices { dev := device.(map[string]interface{}) fmt.Printf("Name: %s\nIP: %s\nVendor: %s\n\n", dev["Name"], dev["IP"], dev["Vendor"]) } } ``` ### Result ```json Scan initiated: { "success": "Onvif scan initiated", "error": "", "data": null } Discovered devices: Name: unknown IP: 192.168.8.254 Vendor: Speco Technologies ```