[1.74.1] - 2026-07-31
-
FIXED: A domain added to the watchdog was listed as Healthy before anything had checked it - the entry was created green and counted toward the healthy total, so a site the user already knows is blocked read as fine until the first check landed, and with the watchdog switched off it read that way forever. A domain waiting for its first check is marked Queued, and the force-check button is disabled while the watchdog is off, where it did nothing.
-
FIXED: The watchdog reported a site as healed while it was still unreachable - a healing run crowned a strategy after one successful fetch, and against a filter that blocks intermittently one of the twenty strategies it tries lands in a gap by chance. That result went straight into the set and the domain was marked healthy, with nothing checking whether ordinary traffic to the site worked afterwards. A healed strategy has to reproduce the fetch several times and survive a re-check through the live engine, or the configuration is put back.
-
FIXED: A healing run could quietly replace a hand-tuned set - it overwrote the whole tcp, udp, fragmentation and faking section while logging only the fragmentation strategy name, so a switch between two combo variants read as "combo -> combo" and every other tuned value disappeared without a trace.
-
FIXED: A fetch that returned nothing counted as a working strategy during discovery - a response without a declared length was accepted as complete even when zero bytes of the page arrived.
-
FIXED: The fake packet sent before a blocked greeting did not resemble the greeting it shadowed - it carried whatever length the fake payload happened to be, in one common case more than twice the real greeting, leaving a filter that reassembles the connection an untouched copy of the real bytes to read. Per-set
fake_len_mode: "match"sizes it to the greeting. -
FIXED: The fake greeting's TTL was ignored unless the faking strategy was set to "ttl" - a set could carry a TTL value while its fake ClientHello still went out at the full system TTL and reached the far end. The SYN fakes read the same value whatever the strategy is, so the setting looked live while doing nothing on the path that mattered. Per-set
apply_ttlapplies it to the greeting alongside any faking strategy. -
ADDED: The TCP MD5 option on the fake greeting itself -
md5_on_fakemakes the far end discard the fake while a filter in between still reads it. The option only ever went on a separate fake connection opening, and only alongside a fragmentation strategy. -
CHANGED: The fake and the real packet no longer share an IP identification number - one field gave away that both came from the same source.
-
ADDED: Fake-only discovery strategies - a low-TTL fake with no fragmentation at all, signed and unsigned, and the same shape across the per-family TTL sweep. Every strategy that carried a fake also split the greeting, and the family sweep is built on a base whose fragmentation strategy is combo, so against a filter that reassembles TCP well enough to see through any split, this shape was out of reach at every phase of discovery.
-
CHANGED: The TLS split position can follow the domain name -
middle_snion a set using thetlsfragmentation strategy places the split inside the domain name instead of a fixed offset from the record header. -
ADDED: The STUN fake payload ships with b4 -
tls_stun.binis built in and picked as "Preset: STUN" underFake Payload Type. It had to be uploaded as a capture file on every device, and a set shared with someone else arrived pointing at a.binthey did not have. -
ADDED: Import of a shared set said nothing when the set referenced a payload file the device does not have - the set pointed at a
.bincapture that only existed on the machine it came from, the fake packets silently fell back to a built-in payload, and the set behaved differently than for the person who shared it. The import screen names the missing files and links to the Payloads settings. -
FIXED: b4 would not start on an OpenWRT router whose kernel has no packet-queue module - startup ended with a raw firewall error that pointed nowhere near the missing kernel module. #275
-
FIXED: The installer reported the router as ready when it could not run b4 at all - the check passed if any one of three queue modules was present, so a router carrying the wrong one installed cleanly and failed at first start.
-
FIXED: The diagnostics report showed no queue number, worker count or queue mode - it read them from config keys b4 has never written, so those lines were skipped on every router.
-
FIXED: A failed start left part of b4's firewall rules on the router - when applying the rules stopped partway, the table, chains and hooks created up to that point stayed behind after b4 exited.
-
FIXED: A kernel without connection packet counters stopped b4 from starting at all - the whole queue rule was rejected and startup failed, over an optimisation that was never required.
-
CHANGED: System Info listed the wrong kernel modules on nftables-only routers - it marked the iptables-era modules as missing and said nothing about the nftables ones b4 depends on there.
-
FIXED: Telegram on Android could sit at "Connecting" when a set routed it through the built-in Telegram bridge - the bridge closed connections that stayed silent for five seconds, though Telegram opens them before it has anything to send. #277
-
FIXED: The "already exists in other sets" warning missed overlaps that do change routing - it compared entries character for character while traffic is matched by domain suffix, so
example.comin another set drew no warning forwww.example.com. #273 -
FIXED: The DC Relay socat helper generated commands that pointed at the wrong Telegram servers - it built them from Telegram's published proxy list, whose addresses drop the connection right after the handshake.
-
FIXED: The first request to a domain after an idle spell could hang for twenty seconds or time out, and YouTube on Android could sit for minutes before its interface appeared - when a client sent a TLS ClientHello too large for one packet, the domain name could land in the second one; b4 read each packet on its own and never joined them, so the set did not match and the connection went out with no bypass strategy at all. Chrome reorders the fields inside that greeting on every connection, which is why the same domain failed on one attempt and loaded on the next. #279 #280
-
FIXED: The first connection to an address b4 had just resolved for a client went out without the set that owned the domain - nothing linked a DNS answer, or a domain seen in a rejected QUIC attempt, to the connection that followed it, so until some connection produced a readable domain name the traffic was treated as unknown. That gap was the one place where a domain b4 had already seen went unrecognised, and on Android YouTube it could leave the app retrying for minutes. The link is remembered per client and destination and is discarded when two domains on one address belong to different sets. #279
-
FIXED: One device could decide which set another device's traffic went through - the domain learned for a shared CDN address was stored once for the whole network and overwritten by whichever device connected last, so on an address serving both YouTube previews and video, one phone's choice was applied to everyone else. Evidence a device produced itself, from its own DNS answers or QUIC attempts, is preferred over the shared record. #279
-
FIXED: A plain connection opening handshake was taken apart and re-sent for no reason - any set with fragmentation or fake-SNI turned on pulled every packet without content out of the kernel and pushed it back through a raw socket, including the opening SYN, although none of those techniques act on a packet that carries no data.
-
FIXED: A set built from a large geosite category took several times more memory than its domains - reading a few categories out of a 51 MB file needed around 90 MB, and the matcher and a switched-off SOCKS5 server each kept a spare copy of every domain.
What's Changed
- fix: update changelog for version 1.74.1 and fix watchdog status hand… by @DanielLavrushin in #286
Full Changelog: v1.74.0...v1.74.1