- tlsmimic: wrap QUIC packets in TLS 1.3 record headers
- multi: auto-detect Salamander/TLS-mimic/plain on the same port
- multi: random padding and jitter support for DPI evasion
- reconnect: periodic session recreation via MaxSessionDuration
- client/server: wire tlsmimic/auto/plain obfs types and config
- NEW_FEATURES: translated to English
- Network: Layer 3 IP tunnel over QUIC with TUN interfaces and IP pool
- FileMask: new noise/obfuscation layer masking traffic as encrypted file downloads
- Hysteria outbound: chain Hysteria servers via pluggable outbound
* fix(firewall): 修复 nftables 在绑定特定 IPv6 地址时重定向失效的问题
* fix(firewall): use DNAT for specific IPv6 bind in iptables port redirect
* chore: format fix
---------
Co-authored-by: Toby <tobyxdd@gmail.com>
Adds a new realm "ipMode" config option (v4 | v6 | dual, default dual)
on both client and server that restricts realm connections to a single
IP family end-to-end: the UDP socket is bound to udp4/udp6, STUN only
gathers addresses of that family, and hole punching only tries peer
candidates of that family.
The standardResolver's lookup4/lookup6 methods recursively follow CNAME
chains without any depth limit or cycle detection. A malicious or
misconfigured DNS server returning a self-referential CNAME record
(e.g. loop.example. CNAME loop.example.) causes infinite recursion,
leading to stack overflow and crash.
Add a max depth limit of 16 and a visited-set to detect cycles. The
original lookup4/lookup6 entry points are preserved; they delegate to
lookup4WithCNAMEDepth/lookup6WithCNAMEDepth which track depth and seen
hosts across recursive calls.
The HTTP proxy server's dispatch method decodes the Proxy-Authorization
Basic credential using base64.URLEncoding, but RFC 7617 specifies that
Basic authentication uses standard Base64 encoding (base64.StdEncoding).
The two encodings differ in their use of +/ vs -_ characters, so any
credential containing 0xff or other bytes that encode to / or + in
standard Base64 will fail to decode with URLEncoding, causing valid
authentication attempts to always be rejected with 407.
Additionally, the "Basic " scheme prefix check was case-sensitive, but
RFC 7235 section 2.1 specifies that auth-scheme is case-insensitive.
Fix both issues by switching to base64.StdEncoding and using
strings.ToLower for the scheme comparison.
The httpOutbound.dial() method incorrectly sets tls.Config.ServerName
to o.Addr, which is the "host:port" address string. TLS SNI must be a
pure hostname without a port number. Sending "host:port" as SNI causes
invalid TLS ClientHello messages and may prevent the proxy server from
correctly routing the connection.
Use o.ServerName instead, which is already correctly set to u.Hostname()
in NewHTTPOutbound.
OpenSSL 3.x requires Subject Key Identifier, Authority Key Identifier,
and Key Usage (keyCertSign) extensions for CA certificate chain
validation. The test certificate generator was missing these, causing
test failures on systems with OpenSSL 3.x.
Co-authored-by: Vladislav Tatjanin <l27001@altlinux.org>
The UDP relay treated the destination address as packet-scoped while
applying ACL/outbound policy only once when a new session was created.
After an authenticated client opened a UDP session using a permitted
first destination, later packets carrying a different Addr in the same
SessionID were written via the established outbound socket without
re-checking policy, allowing the client to reach destinations that ACL
should reject — including localhost and RFC1918 from the server's
network perspective. See GHSA-vgrc-hq28-p3xp.
Add a no-I/O CheckUDP method to the Outbound / PluggableOutbound
chain. The UDP session entry now consults CheckUDP for every packet
whose destination differs from the session's first one, dropping
rejected packets before WriteTo. Decisions are cached per destination
within the session (bounded at 256 entries with simple eviction) so
steady-state cost is one map lookup per packet and no extra sockets
or dials. CheckUDP propagates through the existing chain:
- aclEngine routes through the matched outbound's CheckUDP, with
aclRejectOutbound returning the rejection error.
- directOutbound / socks5Outbound / speedtestHandler return nil.
- httpOutbound returns errHTTPUDPNotSupported.
- Resolvers (system / dot / doh) run resolve() then forward to
Next.CheckUDP so IP-based ACL rules keep matching.
Regression tests in core/internal/integration_tests/udp_acl_test.go
use an in-package stub Outbound to assert that a rejected destination
is not relayed after the session is opened on a permitted one, and
that multi-destination sessions over permitted addresses still work.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Cap HTTP sniff reads to a fixed budget so incomplete or
oversized requests can't cause unbounded memory growth
while preserving normal sniff behavior.
Signed-off-by: Cherrling <me@cherr.cc>
* fix(acl): normalize trailing dot in domain matches
The ACL like
```yaml
- reject(example.com)
- reject(suffix:blocked.test)
- reject(*.wild.test)
```
can be easily bypass through by adding a dot to the domain like
example.com.:443
Signed-off-by: Cherrling <me@cherr.cc>
* fix(acl): trim all trailing dots and add tests
Use strings.TrimRight instead of strings.TrimSuffix so domains with
multiple trailing dots (e.g. example.com..) are also normalized and
cannot bypass ACL rules. Add test coverage for trailing-dot handling
on exact, wildcard and suffix domain rules, as well as for trailing
dots in rule patterns.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Signed-off-by: Cherrling <me@cherr.cc>
Co-authored-by: Toby <tobyxdd@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat(wip): hysteria realms
* feat: port prediction for punching symmetric NAT
* feat: add "cert" subcommand for easy self signed cert generation
* refactor: update address scheme from "hysteria2+realm" to just "realm"
* fix: give up on realm register fatal errors
* chore: update formatting (gofumpt)
* perf: realm proxy UDP methods on PunchPacketConn so quic-go and obfs keep DF/PMTU and buffer sizing
* feat: add support for local UDP source port config in realm addresses
* doc: README for realm pkg
* fix(app): invalid priority in output hook when setting redirect with nft
Server startup fails with nftables before v1.0.9, as it doesn't support
dstnat mnemonic in the output hook. Work around this by using the raw
number (-100) as recommended by Florian Westphal [1].
1. https://bugzilla.netfilter.org/show_bug.cgi?id=1694#c1
* chore(app): use "-100" instead of "dstnat" for both chains
---------
Co-authored-by: Toby <tobyxdd@gmail.com>