- 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
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 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.
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
tfo-go caches the "unsupported" status when fallback mode is enabled.
In other words, if the hysteria server is started with
net.ipv4.tcp_fastopen=0 and it fails once, the tfo will not be enabled
until it is restarted, even if the user later sets sysctl
net.ipv4.tcp_fastopen=3.