====== Monitoring and Control via MQTT ======

Synchronet v3.20 can publish and subscribe to message "topics" on a configured MQTT [[http://mosquitto.org/|broker]].

As enabled and configured in [[util:SCFG]]->Networks->MQTT:

  ╔══════════════════════════════════════╗
  ║   Message Queue Telemetry Transport  ║
  ╠══════════════════════════════════════╣
  ║ │Enabled             Yes             ║
  ║ │Broker Address      192.168.1.2     ║
  ║ │Broker Port         1883            ║
  ║ │Username                            ║
  ║ │Password                            ║
  ║ │Keep-alive          60 seconds      ║
  ║ │Protocol Version    5               ║
  ║ │Publish Verbosity   High            ║
  ║ │Publish QOS         0: At most once ║
  ║ │Subscribe QOS       2: Exactly once ║
  ║ │Log Level           Informational   ║
  ║ │TLS (encryption)    Off             ║
  ╚══════════════════════════════════════╝

===== Retention =====
Most Synchronet MQTT messages are published with the //retain// flag enabled. Retained messages published before a client/subscriber connects will still be received (upon new client connection) until until the broker is restarted or the retained messages are explicitly removed from the broker.

===== Topics =====
Synchronet MQTT message topics start with ''**sbbs/BBSID**'' where ''BBSID'' is the System's BBS ID (for QWK Packets) as configured in [[util:SCFG]]->Message Options. It's possible for a single MQTT broker to serve multiple Synchronet BBSes in this way. The full BBS name is published to this topic level (not a leaf topic). For example:
  sbbs/MYBBS = My Brand-new BBS
  
All leaf topics are published as children of the ''sbbs/BBSID'' topic under 3 main branches:
  * ''sbbs/BBSID/**node**'' - BBS nodes
  * ''sbbs/BBSID/**host**'' - Server hosts
  * ''sbbs/BBSID/**action**'' - Client actions (events)

{{:ref:mqtt_explorer_top-level_example.png?700}}

All MQTT messages published by Synchronet contain just plain text (US-ASCII characters), the one exception being ''sbbs/+/node/+/output'' topics that include terminal control characters/sequences. Numeric values, unless otherwise are specified, are represented in US-ASCII //decimal// characters.

===== Nodes =====

The BBS's [[server:terminal]] server nodes (servicing terminal connections via Telnet, SSH, RLogin, Raw TCP) can be monitored and controlled via MQTT.

Under the ''sbbs/BBSID/**node**'' hierarchy, you'll find a sub-topic for each BBS node, with the total node count published to the ''node'' topic, for example:
  sbbs/MYBBS/node = 4 total

In "High" Publish Verbosity mode, human-readable node status messages are published directly to ''node/+'' topics. For example:

  sbbs/MYBBS/node/1 = Bubbaboy at external program menu via telnet
  sbbs/MYBBS/node/2 = At login prompt via telnet
  sbbs/MYBBS/node/3 = At login prompt via telnet
  sbbs/MYBBS/node/4 = Waiting for connection


Sub-topics of each ''node/+'' topic include:

  * sbbs/+/node/+/**status** - tab-delimited node status values (see ''[[dir:load]]/nodedefs.js'' for details)
  * sbbs/+/node/+/**terminal** - tab-delimited current (or last) connected-terminal definition
  * sbbs/+/node/+/**output** - live output to connected-terminal (for spying)

Example:

  sbbs/VERT/node/1/status = 0       0       1       65535   0       0       0       7
  sbbs/VERT/node/1/terminal = 80    24      syncterm        ANSI    CP437   6       0       2005
  
==== Control ====

Nodes can be controlled by publishing messages to the following topics:
  * sbbs/+/node/+/**input** - keyboard input to inject into connected-node
  * sbbs/+/node/+/**msg** - send a short text message to the node (message should be terminated with a newline character)
  * sbbs/+/node/+/**set/status** - set the node's status value (to an integer value: "0" is waiting for connection, "5" is off-line)
  * sbbs/+/node/+/**set/errors** - set the node's error counter value (to an integer value, e.g. "0" to clear the error counter)
  * sbbs/+/node/+/**set/misc** - set the node's miscellaneous attribute flags (to an integer value, "0x" prefix for hexadecimal values)
  * sbbs/+/node/+/**set/lock** - only a sysop can login (publish "0" to clear this flag)
  * sbbs/+/node/+/**set/intr** - interrupt (disconnect) a user's session (publish "0" to clear this flag)
  * sbbs/+/node/+/**set/down** - make the node not available for connections (status = 5) (publish "0" to clear this flag)
  * sbbs/+/node/+/**set/rerun** - have the node reload its configuration upon next connection (publish "0" to clear this flag)

===== Hosts =====

A single Synchronet BBS can be split across multiple instances running on separate inter-networked host computers. Each host will be represented with its own sub-topic of the ''sbbs/BBSID/host'' topic. For example:

  sbbs/MYBBS/host/MYCOMPUTER
  sbbs/MYBBS/host/rPi
  sbbs/MYBBS/host/ubuntu

The public host name (configured in ''[[dir:ctrl]]/[[config:sbbs.ini]]'') of the host is published to this topic level (not a leaf). For example:
  sbbs/MYBBS/host/MYCOMPUTER = mybbs.synchro.net

The control and monitoring of a specific Synchronet instance is done through this "host sub-topic" tree. 

^ Host sub-topic ^ Description  ^
| recycle        | Publishing any message to the **recycle** sub-topic of any host topic will initiate a recycling of that host's servers (all of them). |
| pause          | Publishing any message to the **pause** sub-topic of any host topic will initiate pause that host's servers (all of them), preventing the acceptance of any new incoming client connections. |
| resume         | Publishing any message to the **resume** sub-topic of any host topic will un-pause that host's servers (all of them), that we previously paused via the **pause** topic. |
| clear          | Publishing to the **clear** sub-topic of any host topic clears the failed-login attempt list (host-shared across all of that host's servers) and that host's terminal server's max-concurrent-connection strike list. Payload may be empty (clear everything) or a numeric IPv4/IPv6 address (clear only entries for that IP). The same effect can be triggered locally by creating ''[[dir:ctrl]]/clear'' (or ''ctrl/clear.term'', ''ctrl/clear.ftp'', etc.) optionally containing an IP address as its first line. |

===== Servers =====

Each Synchronet instance (host) contains the following servers, each represented by its own sub-topic of ''sbbs/BBSID/host/hostname/server'':

  * sbbs/+/host/+/server/**term** - Terminal Server
  * sbbs/+/host/+/server/**mail** - Mail Server
  * sbbs/+/host/+/server/**ftp** - FTP Server
  * sbbs/+/host/+/server/**web** - Web Server
  * sbbs/+/host/+/server/**srvc** - Services

The //status// of each server is published to its server topic, for example:
  sbbs/MYBBS/host/MYCOMPUTER/server/term = ready   1/5 clients     223 served

The //state// (first field of status) for each server is one of:
  * stopped
  * initializing
  * ready
  * paused
  * reloading
  * stopping
  * disconnected

The server status contains more details/statistics and is published more often when "High" MQTT->Publish Verbosity is enabled in [[util:SCFG]].

^ Server sub-topic ^ Description  ^
| recycle          | Publishing any message to the **recycle** sub-topic of any server topic will initiate a recycling of that server. |
| pause            | Publishing any message to the **pause** sub-topic of any server topic will prevent that server from accepting any new incoming client connections. |
| resume           | Publishing any message to the **resume** sub-topic of any server topic will un-pause that server, returning to the "ready" state, accepting incoming client connections. |
| clear            | Publishing to the **clear** sub-topic of any server topic clears that server's view of the failed-login attempt list (and, for the terminal server, its max-concurrent-connection strike list). Payload may be empty (clear all) or a numeric IPv4/IPv6 address (clear only that IP). |

Each server topic has the following sub-topics for status reporting:

  * sbbs/+/host/+/server/+/**version** - name, version/revision, and build date/time/tool of server
  * sbbs/+/host/+/server/+/**state/#** - server state change events
  * sbbs/+/host/+/server/+/**client** - current count of connected clients and maximum number of concurrent clients supported by this server
  * sbbs/+/host/+/server/+/**client/list** - tab-delimited details of all connected clients, one client per line
  * sbbs/+/host/+/server/+/**client/action/#** - client actions (e.g. connect, disconnect)
  * sbbs/+/host/+/server/+/**served** - total clients served since server was started
  * sbbs/+/host/+/server/+/**highwater** - highest concurrent client count since server was started
  * sbbs/+/host/+/server/+/**error_count** - total errors logged since server was started

==== Logs ====

Each ''server/+'' and ''event'' sub-topics has a **log** child topic where //all// messages of all log levels (severity) will be published as well as a grandchild topic for each log level (0-7, decreasing in severity) of logged messages.
Log messages published directly to the "log" topic also have a MQTT v5 user property that specifies the log level of each message (for indication / sorting by the receiving client).

  * sbbs/+/host/+/server/+/**log**
  * sbbs/+/host/+/server/+/**log/#**
  * sbbs/+/host/+/event/**log**
  * sbbs/+/host/+/event/**log/#**

===== Login Attempts =====

Synchronet maintains two per-IP lists for surveilling unsuccessful logins and connection-limit hits, both published as //retained// MQTT messages so subscribers see live state immediately on connect.

==== Failed Login Attempts ====

Each source IP with one or more unsuccessful login attempts to any of the BBS's protocol servers (terminal/FTP/mail/services/web) is published as a retained message at:

  * sbbs/+/host/+/**login_attempts**/IP

Fields are tab-delimited:

  * date/time of first failed attempt (ISO-8601)
  * date/time of latest failed attempt (ISO-8601)
  * total attempt count
  * duplicate-attempt count (consecutive same username+password)
  * protocol of the latest attempt (e.g. ''SSH'', ''POP3'', ''FTP'')
  * username tried in the latest attempt

For example:

<code>
sbbs/VERT/host/vert/login_attempts/27.79.1.152 = 20260502T141018-0700	20260502T141023-0700	2	0	SSH	ftp
</code>

The plaintext password (kept internally for sysop inspection on the running host) is //not// published, since MQTT publishes may be visible to off-host subscribers.

Entries are removed (an empty retained payload is published, which the broker treats as a delete of the retained topic) when:
  * the user successfully authenticates from that IP, or
  * the sysop publishes that IP as the payload to a host-level or server-level ''clear'' control topic, or
  * the sysop publishes an empty payload to ''clear'' (removes every entry).

The list is shared across all of a host's servers, so failed FTP, mail, web, and services attempts share the same ''login_attempts/IP'' topic; the protocol of the latest attempt is recorded in the payload.

This topic is //complementary to// the per-event ''[[#actions|action/login_fail]]'' topic, not a replacement. ''login_fail'' is an event stream: one message fires for each individual failed authentication, and the broker keeps no record after delivery. ''login_attempts/IP'' is the aggregated retained state: one message per IP, overwritten on each new attempt, deleted on success or sysop clear. A subscriber to ''login_fail'' sees every attempt as it happens but knows nothing on first connect; a subscriber to ''login_attempts/+'' sees the current per-IP state of every tracked IP immediately (via retained-message replay) and updates as state changes. Use ''login_fail'' for a live feed or alerting, ''login_attempts/+'' for a "current bad-IP state" dashboard or to enumerate the IPs your tooling can pass to ''clear''.

==== Max-Concurrent-Connection Strikes ====

The Terminal Server tracks each source IP that hits the //maximum concurrent connections without login// limit (configured in [[util:SCFG]]->Servers->Terminal Server). The current strike count for each tracked IP is published as a retained message at:

  * sbbs/+/host/+/server/term/**max_concurrent**/IP

The payload is the bare decimal strike count.

Entries are removed when:
  * the sysop publishes a host- or terminal-server ''clear'' control message (empty or matching IP payload), or
  * the strike count reaches the //filter threshold// and Synchronet automatically adds the IP to the IP filter, or
  * a successful login from that IP arrives.

===== Actions =====

Client actions are published to the following BBS-wide topics:
  * sbbs/+/action/**hack**/METHOD - suspected hack attempt
  * sbbs/+/action/**spam**/ACTION - suspected SPAM received
  * sbbs/+/action/**error**/LEVEL - unexpected condition
  * sbbs/+/action/**exec**/PROGCODE - external program executed
  * sbbs/+/action/**login**/PROTOCOL - successful user authentication
  * sbbs/+/action/**login_fail**/PROTOCOL - unsuccessful user authentication
  * sbbs/+/action/**logout**/PROTOCOL - user logged-out
  * sbbs/+/action/**download**/DIRCODE - file downloaded
  * sbbs/+/action/**upload**/DIRCODE - file uploaded
  * sbbs/+/action/**post**/SUBCODE - message posted
  * sbbs/+/action/**newuser**/PROTOCOL - new user created
  * sbbs/+/action/**page**/node/NODE_NUM - sysop paged for chat

Fields are tab-delimited and begin with a date/time stamp in ISO-8601 format.

===== Triggers =====

The Terminal Server's //event thread// can be instructed to executed Timed Events or initiate QWKnet call-outs by posting a message to the following topics:
  * sbbs/+/**exec** - send the internal code of the timed event to execute (case-insensitive)
  * sbbs/+/**call** - send the QWK-ID of the QWKnet node to force a call-out to (case-insensitive)
===== See Also =====
  * [[:ref:|ref index]]
  * [[:monitor:|Monitoring]]

{{tag>mqtt}}
