v1.79.0rc2
Pre-release
Pre-release
[1.79.0] - 2026-08-18
- ADDED: A UDP action that leaves matched packets alone - a set that matched UDP had three actions to choose from, all of which interfered with the traffic, so a set that matches QUIC only so that b4 can learn a site's addresses from it, or so that a routing set carries that traffic somewhere else, had to fake and fragment packets it had no reason to touch. The Off action passes matched UDP through unchanged while the match itself, the address learning and the routing all keep working.
- CHANGED: The QUIC matching setting offered a value that read as turning QUIC matching off and another that read as merely parsing, and neither did what its name said - both parsed the QUIC ClientHello and matched the set by the server name in it, because that is the only way a set with domain targets matches UDP at all and the only way b4 learns which address belongs to which name from QUIC. The two are one value, By SNI, and the third, By SNI or matched destination, still widens the match to any long-header QUIC packet sent to a destination the set already matches by address or by port. Stored sets carrying the old values are converted on the first start.
- ADDED: A Block QUIC switch on a set's UDP tab - forcing a browser off QUIC and back onto TCP is the one countermeasure that reliably works against a censor that blackholes UDP port 443, and it took two separate settings to arrange, in two places on the tab, with nothing saying they belonged together. Only the QUIC Initial carries a server name and every QUIC packet is authenticated, so b4 cannot desync QUIC the way it desyncs TCP; decoys and fragmenting the Initial are all it has, and they are weak. The switch sets the match to By SNI or matched destination and the action to Reject in one place, and the individual controls stay available for everything else.
- FIXED: An IPv6 packet carrying extension headers could crash b4 - the length of each header was added to the offset without checking it against the length of the packet, so a header claiming more bytes than were there sent the read past the end of the buffer, and a fragment header was walked through as if the bytes behind it were the transport header of a whole packet. Extension header walking stops at the end of the packet, and a fragmented IPv6 packet is left alone rather than parsed as though it were complete.
- ADDED: IPv6 addresses are removed from DNS answers for names a set matched, while IPv6 support is off - b4 processes IPv4 only until IPv6 support is turned on under Settings, Core, so a dual-stack site a set targets was reached over IPv6, where b4 has no rules at all, and the set was bypassed with nothing in the log to say so. A records are kept, AAAA records are dropped, and the client falls back to IPv4 on its own; names no set matched keep their full answers and IPv6 on the network is untouched. It applies only to lookups b4 can see, so a client resolving through its own DoH still reaches the site over IPv6. The switch is Force IPv4 for matched domains, under Settings, Core, DNS, and it is greyed out once IPv6 support is on.
- FIXED: A DNS answer that b4 rewrote never cleared the failure count for that name - the answer was judged, and the escalation counters updated, before the rewrite rather than after, so a good answer that had addresses replaced or records removed was recorded against a name whose run of failures then never reset. A site that recovered kept the failures it had accumulated and was moved to its backup set on the next single failure instead of after the configured run.
- ADDED: An egress IP for a set, which rewrites the source address of its traffic instead of leaving the output interface's own address in place - a set could only be steered somewhere by naming an interface or an upstream SOCKS5 proxy. Where the tunnels are terminated by a router above b4, neither was free: the tunnel had to be brought onto b4's own host as an interface with a routing table behind it, once per destination, or every packet had to be relayed through a proxy that costs CPU the kernel does not. A router that already picks a path by source address needed nothing from b4 except the right source, and there was no way to set one. b4 puts the address on the interface itself and takes it back when the set stops using it, so there is nothing to add by hand and nothing that a reboot forgets; it ARP-probes first and keeps masquerading, rather than claiming an address another host already answers for.
- FIXED: A set bound to a manually added source device stopped taking its route - a device added by hand has no MAC address on the network, so b4 gives it a placeholder built from its IP, and the firewall rule that limits a set to its source devices was built from that placeholder. Nothing on the wire carries such an address, so the rule matched no packet and the traffic left over the normal link, while the connection log still named the set, because the matching done outside the kernel resolves the placeholder from the source IP and succeeds. The same placeholder quietly disarmed block sets, the QUIC rejection that pushes a client back to TCP, and the "all devices except selected" option, which kept routing the one device it was told to leave alone. A device added by hand is matched by the IP address entered for it, devices found in the ARP table keep being matched by MAC, and a device filter that resolves to nothing leaves the set without a rule and says so in the log instead of letting everything through unmarked.
- CHANGED: The global device filter skipped devices added by hand - ticking only manually added devices under Settings, Device Filtering left the filter inert and routing kept applying to every device on the network rather than to the ones that were ticked. Such devices count towards the routing side of the filter, matched by the IP address entered for them, so a list containing only them confines routing to those addresses. The allow and deny list still selects traffic for DPI bypass by MAC address alone, so that half remains inert for them.
- FIXED: An MSS clamp attached to a device added by hand clamped nothing, and pulled every other forwarded connection down with it - the clamp rule was built from the placeholder MAC address b4 derives from such a device's IP, so it matched no packet. On iptables the reply direction cannot be narrowed by MAC at all, so b4 covered it with one catch-all rule that clamped every returning connection through the router down to the smallest configured size, and that catch-all was installed on the strength of rules that were already dead. A set combining destination addresses with a source device also lost the reply half of its clamp, leaving the incoming SYN-ACK unclamped. Devices added by hand are matched by the IP address entered for them in both directions, and the catch-all reply rule is kept only where a device really is matched by MAC and cannot be narrowed.
- FIXED: On a router with working IPv6, Discovery stopped after about twenty tests and reported that no bypass was needed - the test connections Discovery makes were free to use either version of the protocol, and a router with working IPv6 uses that one, while b4 acts on IPv4 alone unless IPv6 is switched on. Censorship reaches IPv6 far less often, so the opening test, the one that decides whether anything is blocked at all, succeeded over a route nothing was interfering with, and Discovery ended right there rather than working through the hundreds of strategy combinations that follow. A strategy found that way was also saved for a version of the protocol b4 was never going to act on. Test connections now use the version b4 is set to handle, and the log names it at the start of every run.
- FIXED: A routing set limited to source devices also diverted traffic the router itself sent - the rules on the router's own outgoing traffic carried no device filter, so a set scoped to one phone steered the router's connections to the same destinations as well. Traffic the router originates arrives from no device and from no interface, so no source filter could ever have matched it, and pairing such a set with "Match any IP address" pulled the router's whole outbound path into the tunnel, which on the interface mode has no protocol filter at all and took LAN reachability with it. Sets scoped by source device or source interface leave the router's own traffic on the normal route.
- FIXED: A routing set with no domain or IP target was built in full and quietly matched nothing - a mark, a routing table, two kernel address sets, three chains and the firewall jumps were all installed for a set that could never match a packet, because every routing rule matches a destination address and the set had none. Nothing was written to the log above trace level, so a set limited to source devices alone looked configured and did nothing. Such a set is skipped with a warning naming it, which block mode already did.
- FIXED: A set matched only by TCP or UDP port ignored the source devices it was limited to - the port match ran before any source check, so a port-only set applied to every device on the network rather than the ones selected. The same set also claimed its traffic was being diverted, which switched off every DPI countermeasure while the firewall steered nothing, leaving that traffic with neither.
What's Changed
- B4 mcp server by @DanielLavrushin in #312
Full Changelog: v1.78.0rc1...v1.79.0rc2