A subscription renders an inbound's stream and remark once per client
and per external proxy, and every client holding its subId, all values
a node chooses: an inbound with a megabyte stream and thousands of
external proxies, or many clients sharing one subId, made a single
unauthenticated request cost gigabytes of memory and minutes of CPU.
A reported inbound whose streamSettings exceeds 64 KiB, sniffing 16 KiB
or remark 1 KiB, or that lists more than 64 external proxies, is no
longer taken in (an existing one keeps its stored values), and a node
can no longer give a client a subId another client already holds,
including another one in the same snapshot.
The set that kept a refused node claim's warning to one line was keyed
by the reported email and never forgot one. Some refused emails, such
as a padded one or a new client holding a foreign subId, match no row
on the master, so a node rotating them grew the set without bound; a
snapshot made only of padded entries also skipped the warning.
Each node now keeps just the emails its latest snapshot was refused,
both return paths log, and the logged email is cut to 64 characters.
A node snapshot was merged into the master's client records by email, and
the only ownership check filtered one derived copy of it: the node's
settings were still stored and re-synced later, its stats still merged,
and a record linked to the master as well as the node took every value
the node reported, including credentials rendered into the master's own
Xray config.
Each snapshot now passes one gate before anything is written. A record
also linked to the master or another node keeps the master's values
apart from per-link fields and the lifecycle the merge already settles;
a record linked only elsewhere, a detached record, a padded or
case-variant email and a new client holding another client's subId are
dropped from the stored settings as well. A soft-orphaned record can be
taken back only by the node whose merge orphaned it, which the new
clients.sync_orphaned_by column records. A node tunnel no longer owns
the peer keys of a client a master-local tunnel also serves.
The sync adopts each node's reported clients through SyncInbound, which resolves
a client record by email alone — and clients.email is globally unique. A node
reporting a colliding email therefore overwrote that client's UUID even when the
client is attached only to a master inbound, and the master then rebuilt its own
Xray config with the node-supplied credential: the real user locked out.
Skip a reported client whose record is attached only to inbounds of other nodes.
A record attached nowhere stays adoptable, so the soft-orphan reattach path a
flapping node depends on is unaffected.