Conversation
Phase A) The allowlist deferred from the unified-blocklist arc. A new core module (a stripped-down sibling of core/blocklist.lua: same bucketed radix cache, hex .tbl store, v4-mapped-v6 lookup; no source-priority / stealth / rollup) exposes whitelist.is_whitelisted(ip) as a sandbox global so every IP-blocking path can consult it. blocklist.check_ip applies Model-A precedence: a whitelisted IP overrides an AUTOMATED block (geoip / proxycheck / external feed) but NOT a manual pin (source="manual" wins) - an operator can still block a specific IP inside a whitelisted range. The whitelist call is pcall-guarded on the accept path (fail closed - an error keeps the block). - core/whitelist.lua (new): store + buckets + matcher + add/remove/list/ count/reload/init; IPv4/IPv6/CIDR, expires_at TTL, cfg-reload listener. - core/blocklist.lua: precedence hook + local pcall = use "pcall". - core/init.lua: register whitelist in _core (after ipmatch, before blocklist). - core/scripts.lua: expose the whitelist sandbox global. - core/cfg_defaults.lua: whitelist_enabled (default true) + whitelist_store_path. - tests/unit/whitelist_test.lua (63 checks incl. a blocklist-integration block proving Model-A precedence; provably fails pre-fix, §1a.7); registered on both smoke.yml legs. blocklist_test stub gains pcall. Phase A of a 4-PR feature (B: +whitelist plugin + hublist-pinger seed; C: per-plugin guards; D: HTTP /v1/whitelist). 3.2.x only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…llowlist, Phase B) Operator-facing chat command over the Phase A engine (core/whitelist.lua): +whitelist show/add/del/count/export/import. Mirrors etc_blocklist's structure (verb dispatch, by_level hierarchy guard, JSONL export/import with control-byte stripping + master-only import gate, opchat report + audit fire-sites) minus stealth and HTTP. Bundled seed: on the first run (store .tbl missing) the plugin seeds a small set of known hublist-pinger IPs (source="pinger", v6 /64, v4 /32) so pingers are exempt from the automated blockers out of the box. Seed-on-missing only; operator edits are never re-seeded. Disable with etc_whitelist_seed=false. - scripts/etc_whitelist.lua (new) + lang en/de. - core/cfg_defaults.lua: etc_whitelist_* keys. - examples/cfg/cfg.tbl: settings block + ships enabled. - tests/unit/etc_whitelist_test.lua (53 checks) + a +whitelist roundtrip smoke that validates the seed on first boot; both smoke.yml legs. §1a.6 review: no blockers; addressed a dedicated msg_save_failed (vs the doubled "failed:" message), the /64 co-tenant breadth caveat in the seed comment, and a de i18n capitalisation. Phase B of the 4-PR feature. 3.2.x. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…allowlist, Phase C) etc_geoip / etc_proxydetect / usr_hubs each gain a one-line `if whitelist.is_whitelisted(ip) then return end` guard at the top of their per-connection decision, so a whitelisted IP (hublist pinger / trusted infra) is exempt. For etc_proxydetect the guard sits before the cache/quota/HTTP so a trusted IP never costs a paid provider query. This silences the recurring PROXYDETECT/GEOIP/USER-HUBS log lines for whitelisted IPs. - scripts/etc_geoip.lua: guard before classify(). - scripts/etc_proxydetect.lua: guard before cache/quota/query. - scripts/usr_hubs.lua: guard before both the invalid-hubcount kick and the hub-limit ban. - etc_geoip_test + etc_proxydetect_test: whitelist-exemption regressions that provably fail without the guard (§1a.7). usr_hubs has no harness; its guard is the identical one-line mirror (diff-is-self-evidence). - docs/DEVELOPMENT.md: the "auto-kick plugins consult the whitelist" convention for plugin authors. Scope: covers the IP-reputation blockers + hub-limit ban; the share/slots/nick-policy plugins are not yet whitelist-aware (follow-up). Phase C of the 4-PR feature. 3.2.x. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t, Phase D)
etc_whitelist v0.02 gains four HTTP endpoints mirroring the blocklist API:
GET /v1/whitelist (read, filter/sort/paginate), GET /v1/whitelist/counts
(read), POST /v1/whitelist (admin), DELETE /v1/whitelist/{id} (admin).
Source enum {manual, pinger}, no stealth. HTTP admin tokens bypass the ADC
hierarchy guard (token = trust surface; by_level=100).
- scripts/etc_whitelist.lua: HTTP handlers + onStart registration (guarded
by hub.http_register).
- tests/unit/etc_whitelist_test.lua: +32 HTTP checks (registration, scope,
schema, all four handlers, happy + error).
- tests/smoke/run.py: test_http_phase_d_whitelist - real token-authed
POST -> GET -> DELETE roundtrip, seed-aware baseline capture.
- docs: HTTP_API.md (4 endpoints + footnotes), SCRIPTS.md (etc_whitelist
section), BLOCKLIST.md (allowlist layer), CLAUDE.md §5.
§1a.6 review: no blockers; addressed the HTTP_API.md docs-currency gap.
Completes the 4-PR #78 allowlist arc. 3.2.x.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(whitelist): global IP/CIDR allowlist engine (#78 allowlist, Phase A)
feat(whitelist): +whitelist admin plugin + bundled pinger seed (#78 allowlist, Phase B)
feat(whitelist): IP-blocking plugins consult the whitelist first (#78 allowlist, Phase C)
feat(whitelist): HTTP API /v1/whitelist (#78 allowlist, Phase D)
- CLAUDE.md §5: whitelist arc A-D merged to dev (PRs #427/#431/#429/#430); the Sopor sysinfo CIM->WMI old-Windows fix (#432) + KB2999226/PS-2.0 note. - DEVELOPMENT.md §4: old-Windows hubowner traps (KB2999226 UCRT + Get-WmiObject fallback for PS 2.0; nil-probe-must-degrade rule). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…433) Two hubs run from one install tree share cfg/user.tbl, master.key, the plugin scripts/data/*.tbl stores and the logs; interleaved saveusers()/savetable() writes can corrupt them (data loss). Nothing stopped this - on Windows core/server.lua's pre-bind SO_REUSEADDR (the #128 fast-restart fix) even lets the second process re-bind the same port, so both hubs run and race silently. Add a single-instance lock in the C launcher, before Lua/socket/user.tbl init: a per-install lock file (luadch.lock in the install dir) held for the whole process lifetime. unix flock(LOCK_EX|LOCK_NB) + O_CLOEXEC; Windows exclusive CreateFile (deny-share, non-inheritable, delete-on-close). Released by the OS on crash (no stale-lock cleanup), retained by the daemon child across the -d fork and across +reload. Scope is per directory, so a test hub and a prod hub in separate dirs still run in parallel; only a second copy of the SAME install is refused (non-zero exit + "another instance is already running"). Fail-open: only the definitive already-held signal (unix EWOULDBLOCK, Windows ERROR_SHARING_VIOLATION) blocks boot. Smoke: a new stage starts a second hub against the live staging tree and asserts it exits non-zero with the refusal while the first stays up; provably fails pre-fix (Windows unpatched binary boots the second instance and runs it concurrently). Two-pass review (per the working agreement) caught the missing O_CLOEXEC (a spawned io.popen child could otherwise inherit the fd and brick the next restart) and the ERROR_ACCESS_DENIED-is-not-a-live-instance misclassification. Reported by Sopor. Docs: CHANGELOG + docs/BUILDING.md "Single instance per install". 3.2.x only, not backported. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n Windows (#434) When a listener could not bind its port the hub was unhelpful: on Linux it logged only the cryptic luasocket "...bind: address already in use" line then silently retried every 30s; on Windows the pre-bind SO_REUSEADDR (added for the Linux #128 TIME_WAIT fast-restart) has SO_REUSEPORT semantics, so a second process re-bound the SAME port with no error at all - two hubs silently shared it and any local process could hijack a luadch port. - core/server.lua: set SO_REUSEADDR only on Linux (detected once at module load via util.path_sep()); on Windows it is skipped both pre- and post-bind, so a same-port second bind fails visibly with WSAEADDRINUSE and the port can no longer be hijacked. Linux keeps the #128 fast-restart unchanged. Also fixes a latent post-bind return: a keepalive-only setoption failure now returns the real error (err or err2) instead of nil. - core/hub.lua add_server_handler: log a clear operator line on a port clash ("... change the port in cfg/cfg.tbl ...") and a generic line for any other previously-swallowed listener-start failure. Verified dropping SO_REUSEADDR on Windows does NOT regress the fast restart: the full Windows smoke restart battery (plaintext / tier / +reload / dual-stack same-port #107) stays green (Windows does not hold a listening socket in TIME_WAIT). Smoke: a new stage starts a second hub (separate dir, same ports as the live first hub) and asserts the clear guidance appears; provably fails pre-fix (the assertion is on the new "change the port in cfg/cfg.tbl" phrase the pre-fix cryptic line lacks; pre-fix Windows silently re-binds and logs nothing). Follow-up to the single-instance lock (same Sopor thread): the lock stops a second copy in the SAME dir; this makes a second hub in a DIFFERENT dir with clashing ports fail loudly instead of silently. 3.2.x only. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promote the current
devtomaster. Testhub-validated (whitelist verified live), CI-green ondev(9d676cd), each feature already through its own §1a.6 review.Contents (30 files, +3475/-17)
#78 Allowlist / whitelist arc (Phases A-D) - PRs #427/#431/#429/#430
core/whitelist.luaglobal IP/CIDR allowlist engine (Phase A)+whitelistadmin plugin + bundled hublist-pinger seed (Phase B)GET/POST/DELETE /v1/whitelist(Phase D)+ban/+blockliststill wins.#433 single-instance lock - refuse a second hub from the same install dir (
hub/hub.c).#434 clear "port already in use" message + Windows port-hijack fix (
core/server.luadropsSO_REUSEADDRon Windows;core/hub.lualogs actionable guidance).Docs currency - CLAUDE.md / DEVELOPMENT.md (#78 arc status + old-Windows support).
Merge as a merge commit (not squash) per CLAUDE.md §8. No release tag.