176 Commits
Author SHA1 Message Date
omarandClaude Fable 5 026bba904f feat: real random strategy over the live pool; sweep becomes an honest knob; multi-WAN egress gateway
- random is a REAL urltest mode (lx SPEC 019 v2): uniform draw over LIVE
  slots only, pool sized to every member; dead slots keep their place
  (never-shrink) but are never picked, for random AND round_robin AND
  sticky (degrade-to-live). All-dead pools fall back to Select.
- Globals.SweepInterval + Globals.GroupHealth master switch, resolved by
  one pure function (model.SweepSchedule) shared by validator and apply;
  unparseable is warned-and-ON, never silently off. ConfigureSweep no
  longer resets the cursor on every cron reconcile (release blocker:
  a ~6-min cycle was restarted every 60s and never completed).
- multi-WAN egress gateway: ubus netifd status -> uci static -> main
  table; a gatewayless non-P2P egress warns CRITICAL instead of silently
  blackholing the second uplink.
- endpoint resolver (route.default_domain_resolver): bootstrap-direct
  clone of a named resolver, profile override beats globals.
- chains are composable: chain: hops flatten recursively, cycle-guarded,
  entry egress lifts only at position 0 (fail-closed mid-path).
- group test publishes its scope so "measuring" lights only the cards a
  run covers; health run is explicitly global (all_nodes).
- panel: biased-sample honesty (no ratio until a failure CAN be on
  record), profiles auto-pin plate, sweep/GroupHealth settings UI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 18:20:26 +03:00
Leadaxe 9dc758e43c Merge upstream/testing (L3-forwarding, snell, bridge) into lx-1.14
Merges 14 upstream commits including L3-forwarding support (which bumped
wireguard-go v0.0.3->v0.0.5, already re-grafted in the prior commit),
snell protocol, bridge outbound, flow-tracking/sniff improvements, and
DNS/dialer fixes.

lx conflict resolutions:
- protocol/wireguard/endpoint.go: took upstream's new flow API
  (PreMatchFlow/PortAddresses/PortMTU/AttachReturn/DetachReturn/JudgeFlow),
  dropped our old PrepareConnection/NewDirectRouteConnection. SPEC 020
  idle-suspend wake guard (resumeOnDial) moved to WritePackets — the single
  point every L3-forwarded packet transits, incl. established flows that
  bypass DialContext.
- adapter/outbound.go: kept lx IdleSuspendable/ReachabilityInvalidator,
  restored 'time' import dropped by auto-merge.
- go.mod/go.sum + test/: took upstream dependency bumps (tailscale, sing,
  sing-tun); wireguard-go stays v0.0.5 with local submodule replace.

Green: full sing-box CLI with LX_TAGS (Go 1.24.7), libbox, wireguard/
adapter/dns/daemon packages, transport+protocol/wireguard tests, AWG
config validation.
2026-07-08 15:10:38 +03:00
世界 c7fe778cae Add bridge outbound 2026-07-08 00:34:26 +08:00
世界 5af56d2cfd Add snell protocol 2026-07-05 12:47:42 +08:00
Leadaxe 0f41d00ac6 feat(masque): SPEC 021 — MASQUE CONNECT-IP outbound (Cloudflare WARP)
CONNECT-IP (RFC 9484) outbound tunnelling whole IP packets over HTTP/3 and
HTTP/2, targeting Cloudflare WARP. One `type: masque` outbound with a
`profile` field (cloudflare default | standard) and `network` (h3 | h2).

- transport/masque/connectip: vendored connect-ip-go (client subset) ported
  onto sagernet/quic-go — no second quic-go, no external dependency.
- transport/masque: cloudflare/standard profiles (ECDSA pubkey pinning), h3
  ConnectTunnel (Extended CONNECT cf-connect-ip + advertiseDefaultRoute), and
  h2 capsule-DATAGRAM over stdlib net/http (no http fork needed).
- protocol/masque: adapter.Outbound reusing transport/wireguard gVisor
  stackDevice via NewDevice(System:false); lazy tunnel + two IP pumps;
  DialContext/ListenPacket/Close.
- constant/option/include wiring (with_quic + with_gvisor); graceful
  ErrGVisorNotIncluded without gvisor.

Key material (ECDSA priv/pub, ip/ipv6) is taken ready from config — WARP
device registration is done client-side (Dart), out of core scope.

Unit-tested (profiles, TLS pinning, EC key round-trip, capsule round-trip,
IPv4 checksum vector, prefix parsing, config decode via registry). NOT yet
device-verified against live WARP (needs real key material).

Refs: SPEC 021, SagerNet/sing-box#4000
2026-07-02 00:24:00 +03:00
Leadaxe a531879e02 fix(SPEC 019 v2): three sticky/pool bugs found by device verification
Device verification of round_robin on a real 51-node pool surfaced three bugs,
all fixed here. Listed by impact.

1. sticky key 'domain' was always empty -> all traffic collapsed to one node.
   The router resolves a domain destination to an IP and overwrites
   metadata.Destination before a group's DialContext runs, so destination.Fqdn
   is empty when the balancer builds the key. stickyComponent("domain") read
   that empty Fqdn, so a single process's key was process+NUL for every site
   -> one fixed slot. On device this measured 28/1/1 across a 3-node pool
   (uniformity 0.27). Fix: read metadata.Domain (survives the resolve), fall
   back to destination.Fqdn only for a direct dial. After: spread 0.95+.

2. living pool nodes could change slot index during a health-check, moving
   sticky keys. balancePoolFirstLive compacted with a filtering append (a
   transiently-dead slot shifted every later live node left); planTolerantPool
   did delete(inPool, occupant) (an evicted-but-living node re-entered a later
   slot, cascading); manual URLTest rebuild ran the tolerant planner even at
   pool_tolerance==0. All now replace-in-slot (fixed-length copy(current), only
   dead/empty slots rewritten by index; dedicated planFirstLivePool for the
   tolerance==0 rebuild).

3. stickiness could not be disabled via sticky_hash: [] -- the config decoder
   (badjson.UnmarshallExcludedContext) re-marshals the struct and collapses an
   empty array to nil, indistinguishable from omitted, so the default always
   applied. Disabling now uses the explicit sentinel sticky_hash: ["none"].

Tests: domain-from-metadata + fallback, replace-in-slot survivor/cascade/
first-live regressions (fail against pre-fix code), ["none"] disable + []
defaults + none-mixed error. All green under -race; gofmt clean.
2026-06-28 21:48:31 +03:00
Leadaxe 5997b1812a lx(1.14): SPEC 019 v2 — round_robin pool, lazy health-check, slot-hash sticky, GetPool
Reworks urltest round_robin to scale to large node lists. v1 rotated over ALL live nodes,
which meant URL-testing every node each interval (unworkable at 1000 nodes). v2:

- Fixed-size pool of slots (balancer.pool, default 3). Slot indices never move; a
  replacement takes the exact slot it evicts. round_robin rotates only within the pool.
- Lazy health-check: pool_tolerance=0 tests no more nodes than needed to keep the pool
  full of live nodes, then stops; pool_tolerance>0 tests all and keeps the fastest with a
  per-slot eviction threshold. Dead pool node keeps its slot until a live replacement is
  found (pool never empties). A dial error never changes the pool — only the health-check.
- sticky = slot-hash (slot[hash(key)%pool], FNV-64a). Binds to a fixed slot index, so a
  living node keeps ALL its keys when other slots churn: strict zero reconnects, zero
  per-key state. Default sticky_hash ["process","domain"]; explicit [] disables.
- Removes v1 jumphash (broke on mid-list eviction), ttl_map, and least_connection (dropped
  from the roadmap — round_robin is statistically even).
- GetPool RPC: CommandClient.GetPool(tag) -> []PoolSlot{slot,tag,delay} so clients can show
  the N nodes actually in rotation. delay clamped 0->1 for live nodes; non-round_robin
  group -> empty. Additive proto/daemon/libbox, behind with_lx_command.

Config moved under a `balancer` object (breaking for the rc.11/12 round_robin shape; no
prod configs, tests only). least_test (default) is byte-for-byte unchanged.

Tests: newBalancer validation/defaults, rotation distribution, slot-hash stable +
living-node-keeps-keys-across-other-slot-churn, empty-key fixed slot, planTolerantPool
top-N / keep-in-tolerance / evict-beyond / dead-slot-replace. go build (+with_lx_command),
go test -race ./protocol/group/, gofmt all clean. Not yet device-verified.
2026-06-28 17:50:43 +03:00
Leadaxe 5ebff914fc lx(1.14): SPEC 019 urltest mode + sticky load-balancing
Add a `mode` to the urltest group so it can distribute traffic instead of only
picking the lowest-delay node, with optional per-flow stickiness.

- mode: least_test (default, unchanged) | round_robin (rotate across live nodes)
  | least_connection (reserved, phase 2 — rejected at config time).
- round_robin selects once per connection over the tag-sorted live set (nodes with
  a fresh URL-test result supporting the network); UDP/QUIC sessions stay on one
  node; first usable outbound is the fallback when nothing is live. The legacy
  selectedOutbound* cache path is untouched — balancing is a separate branch in
  DialContext/ListenPacket.
- sticky {mode, timeout, cap, hash}: binds one flow to one node. hash components
  process|domain|source_ip|dest_ip|dest_port concatenate in order; absent -> "",
  all-empty key -> one fixed node (keyless flows never rotate). mode jumphash
  (default, stateless consistent hash — ~1/n remap on node-set change) or ttlmap
  (key->node table, lazy + ticker eviction, 2000 LRU cap, 10m TTL, dead-node re-pin).

Reuses the existing urltest health ticker/history as the single liveness source;
no new probing. Now() reports the last-picked tag in balanced modes.

Tests (go test -race, 15 cases): distribution, dead-node skip, all-dead fallback,
jumphash stability + empty-key fixed node, ttlmap stick/expire/cap/dead-repick,
key building, validation. The race detector caught a real bug in the sticky
sweeper (read t.ticker unlocked while close() nilled it) — fixed by passing the
channels into the goroutine, mirroring URLTestGroup.loopCheck.

Also folds the SPEC 016 connections-map mutex (ebf9cc07) into the rc.11 changelog
section, which had not yet shipped in a release.
2026-06-28 01:10:17 +03:00
世界 36e92fc7a9 Add USB/IP service 2026-06-25 17:39:02 +08:00
世界 95c37c138a Add sing-box API service 2026-06-25 17:38:53 +08:00
世界 d0ef5c028d hysteria2: Add gecko obfs 2026-06-25 17:38:51 +08:00
世界 094808a4fa Add hysteria2 realm service and support 2026-06-25 17:38:11 +08:00
世界 ce360eece8 dns: Add mDNS server 2026-06-25 17:38:10 +08:00
nekohasekai a37fcd59bb Add Windows TLS engine 2026-06-25 17:38:07 +08:00
世界 cfe83a5dcc Refactor: HTTP clients, unified HTTP2/QUIC options, Apple engines 2026-06-25 17:37:59 +08:00
世界 fd7bc21175 Add cloudflared inbound 2026-06-25 17:37:08 +08:00
世界 dec919e0ca Add package_name_regex route, DNS and headless rule item 2026-06-25 17:35:30 +08:00
nekohasekai 92118b594c Add evaluate DNS rule action and related rule items 2026-06-25 17:35:25 +08:00
nekohasekai 1d523907cb Refactor ACME support to certificate provider 2026-06-25 17:35:24 +08:00
Leadaxe 514a9e74ff lx(1.14): merge upstream v1.14.0-alpha.33 into lx (sing-box layer)
Full 1.14 migration, step 1 of 2 (sing-box repo layer). Three conflicts
resolved, all as predicted by the feasibility analysis:

- route/rule/rule_item_package_name_regex.go (add/add): took upstream's
  canonical version (slices.ContainsFunc) — our lx.15 backport collapses
  back into upstream, so the file no longer diverges going forward.
- route/rule_conds.go: kept our package_name_regex in isProcess{,DNS}Rule
  and took upstream's new isNeighbor{,DNS}Rule additions.
- cmd/internal/build_libbox/main.go: kept lx with_xhttp/with_awg append and
  the no-tailscale block; deliberately dropped upstream's new with_usbip
  (server-side USB/IP, contradicts client-trim).

go.mod auto-merged: wireguard-go require bumped to v0.0.3, lx replace block
(=> ./submodules/wireguard-go) preserved. Submodule pointer unchanged here —
the AmneziaWG graft rebase onto v0.0.3 is step 2 (next commit). This commit
does NOT build yet (submodule still on the old wireguard-go base).
2026-06-23 02:09:53 +03:00
世界 0c7707ca9e Add USB/IP service 2026-06-20 22:24:55 +08:00
世界 3a5d654463 Add sing-box API service 2026-06-20 22:24:42 +08:00
世界 940fb6d8c7 hysteria2: Add gecko obfs 2026-06-20 22:23:44 +08:00
世界 d776e2db4f Add hysteria2 realm service and support 2026-06-20 22:22:43 +08:00
世界 a33c92a2de dns: Add mDNS server 2026-06-20 22:22:32 +08:00
nekohasekai 1226d744b7 Add Windows TLS engine 2026-06-20 22:22:28 +08:00
世界 716541b61c Refactor: HTTP clients, unified HTTP2/QUIC options, Apple engines 2026-06-20 22:22:22 +08:00
世界 31bbb536b4 Add cloudflared inbound 2026-06-20 22:21:09 +08:00
世界 941ce58b8e Add package_name_regex route, DNS and headless rule item 2026-06-20 22:20:58 +08:00
nekohasekai 31bea69a23 Add evaluate DNS rule action and related rule items 2026-06-20 22:20:31 +08:00
nekohasekai 3b36eeab84 Refactor ACME support to certificate provider 2026-06-20 22:20:22 +08:00
Leadaxe 2d97ff5684 lx(xhttp): wire registry into NewClientTransport + xhttp constant
// lx: edits to upstream files (isolated for clean rebases):
- transport/v2ray/transport.go: NewClientTransport switch -> registry lookup
- constant/v2ray.go: V2RayTransportTypeXHTTP = "xhttp"
Behavior identical for built-in transports; build+vet+check green.
2026-06-09 14:40:35 +03:00
世界 da0cd68115 Fix ping timeout 2026-06-03 12:56:36 +08:00
世界 93b7328c3f Fix missing Tailscale in ProxyDisplayName 2026-02-27 19:39:52 +08:00
世界 cf4791f1ad platform: Improve iOS OOM killer 2026-02-26 14:13:32 +08:00
Balthild 60a1e4c866 Add acmedns support 2026-01-17 20:52:43 +08:00
世界 78b4eac974 Add pre-match support for auto redirect 2026-01-17 05:48:39 +08:00
世界 cba18635c8 Add Chrome Root Store certificate option
Adds `chrome` as a new certificate store option alongside `mozilla`.
Both stores filter out China-based CA certificates.
2026-01-17 05:47:54 +08:00
世界 e8620587dd Add OpenAI Codex Multiplexer service 2026-01-17 05:47:42 +08:00
世界 a930356b04 Revert "Stop using DHCP on iOS and tvOS" 2026-01-17 05:47:32 +08:00
世界 cd56eaaba2 Add more tcp keep alive options
Also update default TCP keep-alive initial period from 10 minutes to 5 minutes.
2026-01-17 05:47:04 +08:00
世界 0f5cda4169 Add claude code multiplexer service 2026-01-17 05:46:23 +08:00
世界 f84129ca79 Add proxy support for ICMP echo request 2026-01-17 05:44:41 +08:00
世界 65264afdf9 Add interface address rule items 2026-01-17 05:44:26 +08:00
世界 0146fbfc40 Add SSM API service 2025-07-08 13:14:42 +08:00
世界 6ee3117755 Add resolved service and DNS server 2025-07-08 13:14:41 +08:00
世界 e2440a569e Add DERP service 2025-07-08 13:14:41 +08:00
世界 b97947e8ac Move predefined DNS server to rule action 2025-07-08 13:12:23 +08:00
Zephyruso 803811568e Fix missing AnyTLS display name 2025-07-08 13:12:22 +08:00
anytls 1699a7ce33 Add AnyTLS protocol 2025-07-08 13:12:19 +08:00