| Both sides previous revision Previous revision Next revision | Previous revision |
| products:software:edgeos:api [2020/06/07 10:44] – matthew1471 | products:software:edgeos:api [2025/05/12 13:37] (current) – external edit 127.0.0.1 |
|---|
| ====== EdgeOS API Guide ====== | ====== EdgeOS API Guide ====== |
| |
| The EdgeOS API is largely undocumented. However as the requests and responses can be monitored in a web-browser a lot of information on how it works can be derived. | The EdgeOS API is not publicly documented. However as the requests and responses can be monitored in a web-browser along with the JavaScript source being available, a lot of information on how it works can be derived. |
| | |
| | A subset of the information here was taken from https://github.com/matthew1471/EdgeOS-API/tree/master/Documentation |
| |
| ===== Authentication ===== | ===== Authentication ===== |
| ===== Websocket - Stats ===== | ===== Websocket - Stats ===== |
| |
| You can get streaming statistical data from the endpoint ''<nowiki>wss://host-or-ip/ws/stats</nowiki>''. The data from the WebSocket is framed oddly, it's actually a streaming protocol that has been sent and received over WebSocket. The data will not arrive like you might expect. You *MUST* reassemble the web socket data fragments since the frames may not align with data boundaries. Commands must be sent with a valid SESSION_ID. | You can get streaming statistical data from the endpoint ''<nowiki>wss://host-or-ip/ws/stats</nowiki>''. The data from the WebSocket is framed oddly, it's actually a streaming protocol that has been sent and received over WebSocket. The data will not arrive like you might expect. You *MUST* reassemble the web socket data fragments since the frames may not align with data boundaries. Commands must be sent with a valid SESSION_ID. Origin header is not needed for the 2.x branch of the firmware but is needed for 1.x branches. |
| |
| The format of data to and from the WebSocket stream is "LENGTH\nJSON_PAYLOAD". Failure of sending properly formed messages to start the streaming will result in no messages from server aka "dead air". | The format of data to and from the WebSocket stream is "LENGTH\nJSON_PAYLOAD". Failure of sending properly formed messages to start the streaming will result in no messages from server aka "dead air". |
| The webUI sends a non-standard ping every 30 seconds which consists of the following string with NO length prefix <code>{"CLIENT_PING"}</code> | The webUI sends a non-standard ping every 30 seconds which consists of the following string with NO length prefix <code>{"CLIENT_PING"}</code> |
| |
| ==== Websocket Endpoints: JSON Based ==== | ==== WebSocket Subscriptions: JSON Based ==== |
| |
| Each one of these subscriptions will output data with a headers indicating what datapoint they are returning. | Each one of these subscriptions will output data with the response being full JSON objects: |
| |
| * system-stats: Returns cpu, memory and uptime <code>{'system-stats': {'cpu': '35', 'mem': '22', 'uptime': '3321154'}} | * system-stats: Returns cpu, memory and uptime <code>{'system-stats': {'cpu': '35', 'mem': '22', 'uptime': '3321154'}} |
| * udapi-statistics: System information formatted for udapi, odd dialect | * udapi-statistics: System information formatted for udapi, odd dialect |
| |
| ==== Websocket Endpoint: RAW ==== | ==== WebSocket Subscriptions: RAW Console Output ==== |
| |
| Each one of these endpoints just dumps data with the dict <code>{'': '<line of text>\n' }</code> | Each one of these endpoints just dumps the raw console output data within a string <code>{'<<Request sub_id>>': '<line of text>\n' }</code> |
| |
| * log-feed: Basically tail -f /var/log/messages | These are subscribed to in the same way as the JSON subscriptions above but some additional parameters may need to be specified. |
| * fw-stats: Returns per-rule firewall stats | |
| * pf-stats: Not sure | |
| * nat-stats: Returns per-rule nat stats | |
| |
| Example fw-stats. | === Log File ("log-feed") === |
| | Basically a ''tail -f /var/log/messages'' |
| | |
| | === Firewall Statistics ("fw-stats") === |
| | Returns per-rule firewall stats: |
| | |
| | Request: |
| | <code>142 |
| | {"SUBSCRIBE":[{"name":"fw-stats","sub_id":"fwstat:WAN_IN","chain":"WAN_IN"}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> |
| |
| <code> | <code> |
| {'': 'MGT_IN 10 11604461 1380173884 ACCEPT ""\n'} | {'fwstat:WAN_IN': 'MGT_IN 10 11604461 1380173884 ACCEPT ""\n'} |
| {'': 'MGT_IN 20 0 0 DROP "drop direct stun"\n'} | {'fwstat:WAN_IN': 'MGT_IN 20 0 0 DROP "drop direct stun"\n'} |
| {'': 'MGT_IN 30 24 1152 ACCEPT "stun"\n'} | {'fwstat:WAN_IN': 'MGT_IN 30 24 1152 ACCEPT "stun"\n'} |
| {'': 'MGT_IN 10000 8417 670074 DROP "DEFAULT ACTION"\n\n'} | {'fwstat:WAN_IN': 'MGT_IN 10000 8417 670074 DROP "DEFAULT ACTION"\n\n'} |
| {'': 'WAN_IN 10 747540714 999952823643 ACCEPT "Allow established/related"\n'} | {'fwstat:WAN_IN': 'WAN_IN 10 747540714 999952823643 ACCEPT "Allow established/related"\n'} |
| {'': 'WAN_IN 20 0 0 DROP "Drop invalid state"\n'} | {'fwstat:WAN_IN': 'WAN_IN 20 0 0 DROP "Drop invalid state"\n'} |
| {'': 'WAN_IN 30 1095 52610 DROP "block ET"\n'} | {'fwstat:WAN_IN': 'WAN_IN 30 1095 52610 DROP "block ET"\n'} |
| {'': 'WAN_IN 40 0 0 DROP "block TOR"\n'} | {'fwstat:WAN_IN': 'WAN_IN 40 0 0 DROP "block TOR"\n'} |
| {'': 'WAN_IN 50 0 0 DROP "block EDROP"\n'} | {'fwstat:WAN_IN': 'WAN_IN 50 0 0 DROP "block EDROP"\n'} |
| {'': 'WAN_IN 60 0 0 DROP "block China" DISABLED\n'} | {'fwstat:WAN_IN': 'WAN_IN 60 0 0 DROP "block China" DISABLED\n'} |
| {'': 'WAN_IN 70 92712 5078903 ACCEPT "server - web ports - tcp"\n'} | {'fwstat:WAN_IN': 'WAN_IN 70 92712 5078903 ACCEPT "server - web ports - tcp"\n'} |
| {'': 'WAN_IN 80 65556 3923195 ACCEPT "server - ssh"\n'} | {'fwstat:WAN_IN': 'WAN_IN 80 65556 3923195 ACCEPT "server - ssh"\n'} |
| {'': 'WAN_IN 90 877 52516 ACCEPT "server - gitlab ssh"\n'} | {'fwstat:WAN_IN': 'WAN_IN 90 877 52516 ACCEPT "server - gitlab ssh"\n'} |
| {'': 'WAN_IN 100 142 33791 ACCEPT "server - mosh"\n'} | {'fwstat:WAN_IN': 'WAN_IN 100 142 33791 ACCEPT "server - mosh"\n'} |
| {'': 'WAN_IN 110 3926 143574 ACCEPT "server - unifi stun"\n'} | {'fwstat:WAN_IN': 'WAN_IN 110 3926 143574 ACCEPT "server - unifi stun"\n'} |
| {'': 'WAN_IN 10000 259 136357 DROP "DEFAULT ACTION"\n\n'} | {'fwstat:WAN_IN': 'WAN_IN 10000 259 136357 DROP "DEFAULT ACTION"\n\n'} |
| {'': 'WAN_LOCAL 10 55434 36097276 ACCEPT "Allow established/related"\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 10 55434 36097276 ACCEPT "Allow established/related"\n'} |
| {'': 'WAN_LOCAL 20 87599 17248696 DROP "Drop invalid state"\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 20 87599 17248696 DROP "Drop invalid state"\n'} |
| {'': 'WAN_LOCAL 61 41787 1761510 DROP "block ET"\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 61 41787 1761510 DROP "block ET"\n'} |
| {'': 'WAN_LOCAL 62 0 0 DROP "block TOR"\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 62 0 0 DROP "block TOR"\n'} |
| {'': 'WAN_LOCAL 63 100 4160 DROP "block EDROP"\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 63 100 4160 DROP "block EDROP"\n'} |
| {'': 'WAN_LOCAL 64 0 0 DROP "block China" DISABLED\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 64 0 0 DROP "block China" DISABLED\n'} |
| {'': 'WAN_LOCAL 65 21894 1372976 ACCEPT "ICMP"\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 65 21894 1372976 ACCEPT "ICMP"\n'} |
| {'': 'WAN_LOCAL 10000 241941 37301536 DROP "DEFAULT ACTION"\n\n'} | {'fwstat:WAN_IN': 'WAN_LOCAL 10000 241941 37301536 DROP "DEFAULT ACTION"\n\n'}</code> |
| </code> | |
| |
| ===== Websockets: Action Endpoints ===== | === Port Forwarding Statistics ("pf-stats") === |
| | Contains the statistics from Port Forwarding. |
| |
| Each one of these endpoints performs a toolbox action. | === NAT Statistics ("nat-stats") === |
| | Returns per-rule NAT stats: |
| |
| * ping-feed | <code>1115 |
| * traceroute-feed | { |
| * packets-feed | "nat-stats": "1 15 DST eth0 \"Allow OpenVPN To VPN\"\n2 0 DST eth1 \"Allow OpenVPN To VPN (Hairpin)\"\n3 28 DST eth0 \"Allow qBittorrent\"\n4 0 DST eth0 \"Allow Emergency iLO (HTTP)\" DISABLED\n5 0 DST eth0 \"Allow Emergency iLO (Console)\" DISABLED\n6 7192 DST eth1 \"Redirect Google DNS To Router\"\n7 3920 DST eth1 \"Redirect Google ICMP To Router\"\n5001 46501 MASQ eth0 \"Masquerade For WAN\"\n5002 0 MASQ eth1 \"Allow OpenVPN To VPN (Hairpin)\"\n1 15 DST eth0 \"Allow OpenVPN To VPN\"\n2 0 DST eth1 \"Allow OpenVPN To VPN (Hairpin)\"\n3 28 DST eth0 \"Allow qBittorrent\"\n4 0 DST eth0 \"Allow Emergency iLO (HTTP)\" DISABLED\n5 0 DST eth0 \"Allow Emergency iLO (Console)\" DISABLED\n6 7192 DST eth1 \"Redirect Google DNS To Router\"\n7 3920 DST eth1 \"Redirect Google ICMP To Router\"\n5001 46501 MASQ eth0 \"Masquerade For WAN\"\n5002 0 MASQ eth1 \"Allow OpenVPN To VPN (Hairpin)\"\n1 15 DST eth0 \"Allow OpenVPN To VPN\"\n2 0 DST eth1 \"Allow OpenVPN To VPN (Hairpin)\"\n3 28 DST eth0 \"Allow qBittorrent\"\n4 0 DST eth0 \"Allow Emergency iLO (HTTP)\" DISABLED\n5 0 DST eth0 \"Allow Emergency iLO " |
| * bwtest-feed | }</code> |
| |
| These are subscribed to in the same way as the JSON subscriptions above but additional parameters must be specified: | === Ping ("ping-feed") === |
| |
| <code>163 | <code>163 |
| {"SUBSCRIBE":[{"name":"ping-feed","sub_id":"ping1","target":"192.168.0.1","count":"1","size":""}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> | {"SUBSCRIBE":[{"name":"ping-feed","sub_id":"ping1","target":"192.168.0.1","count":"1","size":""}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> |
| | |
| | with the response being pretty similar to a raw feed: |
| | |
| | <code>76 |
| | { |
| | "ping1": "PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.\n\n" |
| | }</code> |
| | |
| | === Traceroute ("traceroute-feed") === |
| | |
| | <code>165 |
| | {"SUBSCRIBE":[{"name":"traceroute-feed","sub_id":"trace6","target":"192.168.0.254","resolve":true}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> |
| | |
| | with the response being pretty similar to a raw feed: |
| | |
| | <code>98 |
| | { |
| | "trace6": "traceroute to 192.168.0.254 (192.168.0.254), 30 hops max, 38 byte packets\n 1" |
| | }</code> |
| | |
| | === Packet Capture ("packets-feed") === |
| | |
| | <code>224 |
| | {"SUBSCRIBE":[{"name":"packets-feed","sub_id":"packets4","interface":"1","pkt_count":"1","resolve":true,"f_proto":"","f_address":"","f_port":"","f_neg":true}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> |
| | |
| | === Bandwidth Test ("bwtest-feed") === |
| | Client: |
| | |
| | <code>150 |
| | {"SUBSCRIBE":[{"name":"bwtest-feed","sub_id":"bandwidth5","server":"192.168.0.253"}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> |
| | |
| | or with advanced properties set: |
| | |
| | <code>273 |
| | {"SUBSCRIBE":[{"name":"bwtest-feed","sub_id":"bandwidth2","server":"192.168.0.254","duration":"1","protocol":"udp","udp-bandwidth":"500","parallel-flows":"1","tcp-window-size":"64","reverse-direction":true}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> |
| | |
| | Server: |
| | <code>144 |
| | {"SUBSCRIBE":[{"name":"bwtest-feed","sub_id":"bandwidth5","server-mode":true}],"UNSUBSCRIBE":[],"SESSION_ID":"9a00126c5bf04e29835f7c13fe5ab155"}</code> |
| |
| ===== Websockets: Other Endpoints ===== | ===== Websockets: Other Endpoints ===== |
| ===== Third Party Unofficial APIs ===== | ===== Third Party Unofficial APIs ===== |
| There are a few developers who have worked on creating unofficial APIs: | There are a few developers who have worked on creating unofficial APIs: |
| * https://github.com/matthew1471/EdgeOS-API (written in C#) | * https://github.com/matthew1471/EdgeOS-API : C# |
| * https://github.com/andrewstuart/edgeos-rest (written in Go) | * https://github.com/andrewstuart/edgeos-rest : Go |
| | * https://github.com/brontide/aioedgeos : Python with influx collector including DPI |
| |