MondoNode

MondoNode is SystemHalted's modular Android network and system monitoring platform — a minimal host with a rich plugin ecosystem covering monitoring, transformation, routing, output, storage, events, management, and sentinel-based access control.

MondoNode

MondoNode is SystemHalted’s modular Android network and system monitoring platform. The core host is intentionally minimal — almost everything useful happens inside plugin APKs that snap together into pipelines. The result is a system you can extend without rebuilding, audit one plugin at a time, and run entirely on a handset or tablet.

Every plugin is a separate, signed APK. The host discovers them at runtime, authenticates them through a three-layer trust model (OS signature permission → APK cert pinning → ECDSA challenge-response), and wires their inputs and outputs into a visual pipeline graph. Monitoring data flows through transformers, routers, storage, and output sinks exactly as you arrange them.

This page catalogs the current plugin ecosystem. Status notes (shipped / planned) reflect the snapshot dated 2026-05-22.


Architecture at a glance

  • Host appmondonode-app: plugin manager, pipeline executor, trust-tier evaluator.
  • Plugin categories — Monitoring, Transformer, Router, Output, Storage, Event, Management, Sentinel. Each category has its own AIDL contract and signature-protected bind permission.
  • Pipeline graph — nodes connected by typed ports. Trigger events flow into monitors; metrics flow out through transformers and routers into storage and output sinks.
  • Trust model — OS-enforced signature permission (Layer 0), APK cert pinning against an official fingerprint set (Layer 1), and per-bind ECDSA nonce challenge-response on secp256r1 (Layer 2). Per-call UID verification on every AIDL method as defence-in-depth.
  • Encrypted storage — all SharedPreferences stores use EncryptedSharedPreferences backed by Android Keystore (hardware TEE where available).
  • Timezone policy — internal time is always UTC epoch milliseconds; display formatting uses an explicit user preference.

Monitoring plugins

The producers. Each one is a source node with no input data port — it runs when a true arrives on its trigger port (from an event plugin or a management API call) and emits a metric.

mondonode-plugin-icmp

ICMP ping reachability and latency monitor. Shells out to the system ping binary, parses Android toybox and Linux output formats (min/avg/max/stddev RTT), and falls back to InetAddress.isReachable() if the binary is unavailable. Capability: icmp_ping. Parameters: host, count (1–20, default 3), timeout_seconds (1–60, default 5). Output: host, sent, received, loss_percent, reachable, method, RTT keys.

mondonode-plugin-dns

DNS resolution monitor using the dnsjava library, with Android’s active resolver list registered via AndroidResolverConfigProvider so VPN, Wi-Fi, and mobile data settings are honoured. Capability: dns_lookup. Parameters: hostname, record_type (A, AAAA, MX, TXT, CNAME, NS, SRV, PTR, CAA, SOA…), dns_server, timeout_seconds (1–30), max_retries (0–10). Output: resolved, resolved_count, resolved_records, resolution_time_ms, attempts.

mondonode-plugin-http

HTTP/HTTPS probe with a full OkHttp EventListener-derived per-phase timing breakdown: DNS, TCP connect, TLS handshake, request headers, request body, TTFB, response headers, response body, total. Connection pooling is forced off so every probe measures a fresh path. Capability: http_request. Parameters: url, method, timeout_seconds, follow_redirects, expected_status_min/max, request_headers, request_body, content_type.

Planned monitoring plugins

  • mondonode-plugin-snmp-poll — SNMPv1/v2c/v3 GET/GETNEXT/GETBULK with MD5/SHA-1/SHA-256 auth and DES/AES privacy.
  • mondonode-plugin-snmp-trap — passive UDP listener for SNMP traps and informs.
  • mondonode-plugin-ldap — periodic LDAP/LDAPS probe (AD, FreeIPA, OpenLDAP).
  • mondonode-plugin-radius — RADIUS Access-Request probe (PAP/CHAP/EAP-MD5).
  • mondonode-plugin-rest — multi-call REST monitor with OAuth 2.0 / SAML 2.0.
  • mondonode-plugin-ring-events — Ring API event source (motion, ding, alarm state).
  • mondonode-plugin-weather — forecast and severe-weather alerts via Open-Meteo, NWS/NOAA, or OpenWeatherMap.

Transformer plugins

Stateless pure-function nodes: one input port in, one or more output ports out. Validators add a dedicated fail port so the graph can route invalid input separately.

mondonode-transformer-network-validators

validate_ipv4, validate_ipv4_cidr, validate_ipv6, validate_ipv6_cidr, validate_mac_address, validate_hostname_fqdn, validate_port_number, validate_asn, validate_url. All emit {"value": "true"} or {"value": "false", "reason": "..."}.

mondonode-transformer-validate-types

validate_json, validate_hex, validate_integer, validate_float, validate_base64, validate_uuid, validate_semver. Same validator convention.

mondonode-transformer-parsers

json_extract_path (dot-notation extraction with found flag), string_split (indexed-array output), array_get (positive/negative index), array_slice, string_match (regex/exact/contains), array_match (filter a JSON array), regex_capture (named + positional groups).

mondonode-transformer-string-join

join, concat, repeat, pad_start, pad_end. Building blocks for composing output messages from upstream metric values.

mondonode-transformer-converters

to_integer (base 2–36), to_float, to_boolean, date_convert (explicit input/output timezone — compliant with the project-wide UTC policy), bytes_format (binary/decimal units), duration_format, to_hex, from_hex, to_base64, from_base64.

mondonode-transformer-printf

sprintf (printf-style formatting with up to four auxiliary args), number_format (decimal places, thousands separators, unit suffix), pad (left/right/center alignment), truncate (with optional ellipsis from either end). Locale fixed to Locale.US for deterministic output.

mondonode-transformer-regex

regex_match, regex_capture, regex_replace (with back-references $1, ${name}), regex_find_all. All capabilities share pattern and flags parameters (i/m/s).

mondonode-transformer-validate-formats

validate_email (RFC 5321/5322 practical regex), validate_iso8601 (delegates to java.time parsers in order), validate_custom_date_format (user-supplied DateTimeFormatter pattern under ResolverStyle.STRICT).

Planned transformer plugins

  • mondonode-transformer-format-convertersjson_to_yaml, yaml_to_json, json_to_xml, xml_to_json via Jackson.
  • mondonode-transformer-aggregate — stateful counting via IPluginHostBridge → KV storage; json_path_unique_count, regex_match_count. State lives in the KV store so the transformer itself stays stateless.

Router plugins

Conditional fan-out. Each router evaluates a list of conditions against an input value and fires the matching case_N output port (or default).

mondonode-router-switch

switch_evaluate — ordered case list with FIRST or MULTIPLE match modes. Supports StringCondition (EQUALS / NOT_EQUALS / STARTS_WITH / ENDS_WITH / CONTAINS), NumericCondition (six comparison operators), RegexCondition (full match), and CompoundCondition (AND/OR/NOT, recursive).

mondonode-router-ifelifelse

if_evaluate — same condition algebra as switch_evaluate but with implicit FIRST semantics. Models a clean if/elif/else chain.

Both routers delegate to the SDK’s shared RouterConditionEvaluator, so condition semantics are identical across the two plugins.


Output plugins

Sinks. They receive a value and do not produce output edges.

mondonode-output-file

file_write — appends or overwrites files under the plugin’s getExternalFilesDir(null). Per-path ReentrantLock serialises concurrent writes within the plugin process. Canonical path is checked against the base directory to prevent path traversal. Configurable ISO 8601 timestamp prefix and per-key or full-map writing.

mondonode-output-notification

post_notification — Android system notifications via NotificationManager. Lazy channel creation per channel_id. Optional fixed notification_id for in-place updates (live status); otherwise an AtomicInteger increments per write. Requires runtime POST_NOTIFICATIONS grant on Android 13+.

mondonode-output-syslog

syslog_send — UDP, plain TCP, or TLS (RFC 5425), in RFC 3164 or RFC 5424 format. RFC 6587 octet-count framing for TCP/TLS. UTF-8-safe length policies: TRUNCATE or SPLIT (multi-message). Trust model: system trust store, or trust-all + SHA-256 leaf-cert pin, or trust-all (insecure, dev-only). Configurable facility, severity, app name, hostname, and per-message size limit.

Planned output plugins

  • mondonode-output-http — simple webhook POST, no auth.
  • mondonode-output-rest — OAuth 2.0 / SAML 2.0, multi-call, optional WebSocket delivery.
  • mondonode-output-smtp — email.
  • mondonode-output-nsca — Nagios passive checks.
  • mondonode-output-elasticsearch — document indexing.
  • mondonode-output-datadog — metrics/events.
  • mondonode-output-slack — chat posting.
  • mondonode-output-audio-alarm — local audio alert.
  • mondonode-output-cloudwatch — AWS CloudWatch Logs.
  • mondonode-output-gcp-logging — GCP Cloud Logging.

Storage plugins

Persistent or in-memory data stores. Storage plugins are distinct from output plugins because they can return data back into the pipeline. Permission level (read vs write) is structural — declared by the capability type, not a runtime parameter.

mondonode-storage-kv

SQLite-backed key/value store with ACID guarantees. Capabilities:

  • stream_write_single (STREAM_WRITE)
  • stream_write_map (STREAM_WRITE, transactional bulk write)
  • kv_get (QUERY_READ)
  • kv_get_all (QUERY_READ, namespace scan)
  • kv_set (QUERY_WRITE)
  • kv_delete (QUERY_WRITE)
  • kv_compare_and_set (QUERY_WRITE, atomic CAS via beginTransactionNonExclusive())

mondonode-storage-timeseries

Multi-resolution time-series store inspired by RRD: pre-aggregated circular archives with AVERAGE / MIN / MAX / LAST consolidation functions. Default tiers: 60 s × 1440 (one day at 1-min), 300 s × 2016 (~7 days at 5-min), 3600 s × 8784 (~1 year at 1-hour). Capabilities:

  • ts_update (STREAM_WRITE) — inserts a numeric point; initialises archives on first call.
  • ts_fetch (QUERY_READ) — windowed JSON array of {ts, v} points, gaps omitted.
  • ts_last (QUERY_READ) — most recent raw data point.
  • ts_info (QUERY_READ) — archive definitions for a namespace.
  • ts_stream (STREAM_OUTPUT) — pushes each new point downstream, with optional LATEST / FROM_BEGINNING / FROM_TIME replay modes.

This is the primary backend for trend graphs in connector-ui.

mondonode-plugin-queue

In-memory trigger-gated queue, categorised as storage in the SDK. Buffers items between producer and consumer with overflow policies and trigger-driven flush semantics.

  • queue_write (STREAM_WRITE) — appends to a named buffer; DROP_OLDEST (default) or DROP_NEWEST on overflow.
  • queue_drain (STREAM_OUTPUT) — emits buffered items one at a time. Auto-flush mode (no trigger) or trigger-gated mode (each true flushes to a low-water mark, then pauses). Each emission includes diagnostic counters (depth, hwm, warn, crit).

Planned storage plugins

  • mondonode-storage-mongodbmongo_insert, mongo_find_one, mongo_update, mongo_aggregate, mongo_change_stream (tailable). Uses the officially Android-supported MongoDB Kotlin coroutine driver.

Event plugins

Autonomous sources. They have no input data port and emit boolean values that drive connected monitor nodes via their trigger ports. The event plugin model is the replacement for AlarmManager scheduling: a monitor only runs when something true arrives on its trigger.

mondonode-plugin-simple-timer

simple_timer — coroutine-based fixed-interval emitter. No WakeLock, no BroadcastReceiver. Accepts a human-readable interval (30s, 5m, 1h30m, or bare seconds) and an optional ISO-8601 start_at instant.

Planned event plugins

mondonode-plugin-ring-events and mondonode-plugin-weather (above) both function as event sources in addition to monitors.


Management plugins

Apps that drive the host — pipeline editors, dashboards, REST/WS bridges.

mondonode-plugin-ui

Separate launcher app, MondoNode UI. Three-tab layout (Dashboard, Results, Pipelines): monitor CRUD, pipeline editor with recursive condition editor, per-monitor metric history (last 100 points), settings gear opening the timezone dialog. Local EncryptedSharedPreferences is authoritative on mutation; on a fresh install the UI pulls the existing pipeline from the host.

mondonode-plugin-connector

Embedded Ktor HTTPS / WSS server exposing the host to remote cross-platform clients on the local network.

  • Split control/data planes — HTTPS REST for CRUD and manifest reads, WSS for real-time metric push and plugin connect/disconnect events.
  • Default port — 7433.
  • TLS — CA-signed PKCS12 in release builds; self-signed EC secp256r1 via BouncyCastle in debug.
  • Client auth — three-step EC challenge-response (/v1/auth/request/challenge/verify) with a 4-word pairing passphrase (single-use on new pairings; known clients bypass) and a 3-state approval mode (REJECT / REQUIRE_APPROVAL / OPEN).
  • mDNS — opt-in advertisement of _mnconnect._tcp..
  • Pairing QRmnconnect://<lan-ip>:7433?fp=<sha256hex>&pw=<passphrase>.

A public, MIT-licensed cross-platform client SDK — mondonode-connector-sdk — is published to Maven Central (com.systemhalted.mondonode:mondonode-connector-sdk:0.1.0) and targets Android, Desktop (JVM), iOS, and WasmJS. Client libraries in Qt6/C++, TypeScript, Python, Go, and possibly Rust are planned, parallel to the KMP SDK.


Sentinel plugins

The pluggable access-control evaluator. The host asks the sentinel chain “should this plugin be allowed to bind?” — the first sentinel to grant wins; if all decline, access is denied.

mondonode-sentinel-builtin

Priority 0 — always consulted first. Replicates the two-layer auth that was previously hard-coded in the host:

  • Layer 1 — SHA-256 APK cert fingerprint must be in the official set for the requesting plugin’s category, or in the dev fingerprints registered at startup.
  • Layer 2 — ECDSA nonce signature verification on secp256r1, using SHA256withECDSA. The plugin’s public key (decoded via X509EncodedKeySpec from the request) must produce a valid signature over the host-issued nonce — proof that the plugin holds the corresponding Android Keystore private key.

Both layers must pass.

Planned sentinels — directory & IdP integrations

  • mondonode-sentinel-ldap — Active Directory, FreeIPA, generic LDAP; group-to-tier mapping per directory type.
  • mondonode-sentinel-keycloak — OAuth2/OIDC/SAML 2.0; realm roles to trust tiers.
  • mondonode-sentinel-radius — RADIUS AAA (PAP/CHAP/EAP-MD5); VSAs map to trust tiers.
  • mondonode-sentinel-entra — Azure Entra ID via Microsoft Graph; group mapping + device compliance checks.
  • mondonode-sentinel-authentik — Authentik OAuth2/OIDC; group membership to trust tiers.

Subscription / enterprise sentinels are planned to authenticate via PSK rather than embedded public keys, eliminating the need to embed each sentinel’s key in the host APK.


Open-source posture

The MondoNode SDK and a substantial portion of the plugin ecosystem are published under the MIT licence. Public Maven Central artifacts include mondonode-sdk, mondonode-sdk-testing, and mondonode-connector-sdk. Each MIT-licensed plugin module is independently buildable from its own GitHub repo — clone one module, run ./gradlew assembleDebug, and you have a working plugin APK without the rest of the superproject.

Trademark notice — “SystemHalted”, “MondoNode”, and the associated logos are © SystemHalted / Jeremy Melanson.


Catalog snapshot: 2026-05-22.