-
Notifications
You must be signed in to change notification settings - Fork 0
Client Server Communication
BigLan clients (Windows BigLanService) talk to the server over two independent channels, each with its own direction, port, and authentication mechanism:
graph LR
C[BigLanService client] -- "HTTPS :443<br/>client → server<br/>API Token" --> S[BigLan server]
S -- "TCP :8080<br/>server → client<br/>per-workstation AES key" --> C
| Status/Event Reporting | Console (Remote Commands) | |
|---|---|---|
| Port | 443 (HTTPS) | 8080 (TCP) |
| Initiated by | Client | Server |
| Auth | API Token (shared secret) | Per-workstation AES key (ws_keys) |
| Endpoint |
POST /api/v2 → ApiController::payload()
|
WorkstationsController::command() |
All client → server traffic goes through a single endpoint: POST /api/v2, handled by ApiController::payload().
Every request must include a token field (the plaintext API Token). This is checked in ApiController::__construct(), before payload() runs — meaning if the token check fails, none of the event/action logic below ever executes:
-
hash('sha256', $plainToken)is compared againstapi_tokens.token_hash - Rejected (
"ERROR") if: token not found,is_active = 0, orexpires_atis in the past (which also deactivates it) - If
max_usesis set,uses_countis incremented; once it reachesmax_uses, the token is deactivated -
last_used_atis updated on every valid request -
One-time binding: on the first request that includes a real
wsid, the token is bound to that workstation (tokenable_type = "Workstations",tokenable_id = $wsid). This binding is not updated again afterwards — if the same token is shared across many workstations (e.g. a bulk-deployment token),tokenable_idonly ever reflects the first machine that used it, not all of them.
Note: the API Token authenticates a sender, not a specific machine. Workstation identity is established independently — see Workstation Identification below.
payload() branches on two possible top-level fields:
-
action— used for the Command Center polling flow (getWaitingCommandsCounter,getCommand,saveCommandResult,update) -
event— used for all state/status reporting (heartbeat, boot, shutdown, etc.)
For event-type requests, unless the event is in a fixed exemption list (identification, basic, refresh, heartbeat, external, print, register, key exchange), it is first logged via storeEvent() (feeds the workstation's Events tab), and then dispatched:
| Event(s) sent by client | Handler method | Purpose |
|---|---|---|
identification |
identifyWorkstation() |
Matches/creates the workstation by hardware identifiers — see below |
key exchange |
keyExchange() |
Stores the client's AES key for the Console channel — see Section 2 |
basic |
refresh() |
Full hardware/OS inventory refresh |
external |
external() |
Dispatches to sub-savers: IPs, DNS, user accounts, printers, monitors, memory, disks (see saveIPAddresses(), saveUserAccounts(), etc.) |
shutdown, service stopped, suspend
|
shutdown() |
Marks workstation offline, resets connection flags |
boot, resume
|
boot() |
Marks workstation online, sets startup_at
|
lock, unlock, logon, logoff
|
idle() |
Toggles the idle flag |
heartbeat |
heartbeat() |
Updates heartbeat timestamp (sent every minute) |
anydesk connected/disconnected
|
anydesk() |
Toggles AnyDesk security-risk flag |
teamviewer connected/disconnected
|
teamviewer() |
Toggles TeamViewer security-risk flag |
vnc connected/disconnected
|
vnc() |
Toggles VNC security-risk flag |
usb connected/removed
|
usb() |
Increments/decrements the connected-USB-storage counter |
print |
printing() |
Records a print job/statistic |
identifyWorkstation($uuid, $board, $product, $mac, $hostname) is the mechanism that decides which database row a client's data belongs to — independent of the API Token used:
- Four identifiers are validated by regex:
uuid,product_serial,mboard_serial,first_mac - Each is looked up individually against existing
workstationsrows - If any single identifier matches exactly one existing row, that row's ID is reused (with a
scorerecording how many of the 4 identifiers matched, out of 4 = 100%) - If none match any existing row, a new
workstationsrow is created - If some identifiers match zero rows and none match exactly, the request is rejected (
"ERROR") — this is the "at least 25% must be unique" rule from the User Guide
Unlike Section 1, this channel is server-initiated: the server opens an outbound TCP connection to the workstation. It does not use the API Token at all — it uses a separate, per-workstation AES-256 key.
sequenceDiagram
participant C as BigLanService client
participant S as BigLan server
Note over C: On service start, client generates<br/>a random 32-char password
C->>S: event: "key exchange" (token, wsid, key=password)
Note over S: keyExchange() in ApiController
S-->>S: Encrypt password with MASTER_KEY,<br/>store in ws_keys (unique per wsid)
S-->>C: OK
- Client-side:
Service1.cs, staticpasswordfield (generated once per service run) → AES key =SHA256(password), used by the client's ownTcpListeneron port 8080 - Server-side:
ApiController::keyExchange()— stores the password (not the derived key) encrypted withMASTER_KEYinws_keys.encryption_key, one row perwsid(unique constraint)
sequenceDiagram
participant U as Admin (Console UI)
participant S as BigLan server
participant C as BigLanService client
U->>S: Submit command (Workstation → Console tab)
Note over S: WorkstationsController::command()
S-->>S: Load ws_keys row for wsid, decrypt with MASTER_KEY
S-->>S: Derive AES key = SHA256(password),<br/>encrypt command (fixed IV)
S->>C: fsockopen(workstation_ip, 8080), send encrypted command
C-->>C: Decrypt, execute via cmd/PowerShell
C-->>S: Encrypted result
S-->>U: Display result in Console UI
- Requires
write-workstation-commandpermission - Every command attempt is logged to
ws_control_logs(WsControlLog) regardless of outcome - The Console tab is only shown at all if the workstation's IP falls inside a subnet registered under IP Table → New Subnet — see Known Limitations
- Connection timeout is 15 seconds (
fsockopen4th argument); if the workstation's OS firewall silently drops the connection (the common case with the Windows Firewall, which doesn't send a "connection refused" but just drops the packet), the request will visibly hang for close to 15 seconds before failing
- The AES IV is a fixed constant (
0x30× 16) on both the client and server side, not randomized per message — see Known Limitations for the security implication - This channel requires the workstation to be reachable on the same registered subnet as the server (LAN only) and the Windows Firewall must allow inbound TCP 8080 on the client — neither is automatic; the installer does not create a firewall rule
- Because this channel is independent of the API Token, it still works even if the workstation's API Token has been revoked — it can be used to push a new token remotely via the
Change-Tokenconsole command