mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-16 23:27:14 +00:00
d5ab84e8d5
* feat(amneziawg): add AmneziaWG as an outbound protocol - AmneziaWG outbound protocol end-to-end: config schema, socks bridge, netstack, panel UI - Route amneziawg outbounds to HTTP probe in TCP mode (backend + frontend classifiers) with pinning test - Add 2-minute idle read deadline to pumpUDPEgress to reap idle egress sessions - Require SOCKS5 username/password auth on the egress server (reject NO-AUTH with 0xFF) with test - Bound the egress TCP tunnel dial with portForwardDialTimeout (10s), matching portfwd.go - Resolve UDP domain targets off the association's reader loop via deliverUDPDatagram; race-safe getOrDial starts the reply pump at session creation; client passed by value into resolver goroutines (pinned by TestEgressUDPDatagramDomainInterleavedClients) - Reconcile early-returns on an empty desired set and closes the egress listener; EgressBasePort (64900) is reserved against local inbound port conflicts like the internal API port, with pinning tests for both the port reservation (TestCheckPortConflict_EgressPortBlockedLocal) and the Reconcile empty-desired Close/Listen lifecycle (TestOutboundManagerReconcileEmptyDesiredClosesEgress) - Eliminate acceptLoop shutdown race by validating listener != nil and registering to tracked under s.mu before wg.Add; bound pre-auth handshake with deadline (pinned by TestEgressServerCloseDuringConcurrentAccepts) - Support AAAA and dual-stack domain resolution in tunnel DNS resolver with v6 default fallback (DefaultTunnelDNSServerV6); add DNS field to frontend protocol form; avoid unneeded cache flushes on unchanged SetStack ticks * fix(amneziawg): resolve IPv6-only DNS default fallback and validate required keys - Default to IPv6 tunnel DNS on IPv6-only outbounds with blank dns - Require non-empty secretKey and peer publicKey in ValidateAmneziaWGOutbound - Add end-to-end IPv6 tunnel domain resolution test and test empty key rejection - Trim comment blocks exceeding 2 lines across modified files - Fix Storybook test execution on environments with POSIX locale Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: rqzbeh <rqzbeh@users.noreply.github.com> Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
package amneziawgnet
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn"
|
|
)
|
|
|
|
// endpointResolveTimeout bounds the one-time DNS lookup in ParseEndpoint.
|
|
const endpointResolveTimeout = 5 * time.Second
|
|
|
|
// resolvingBind lets peer endpoints be hostnames: StdNetBind has no DNS and
|
|
// an unresolved name kills the whole IpcSet. Resolved once at configure.
|
|
type resolvingBind struct {
|
|
awgconn.Bind
|
|
}
|
|
|
|
var lookupEndpointHost = defaultLookupEndpointHost
|
|
|
|
func defaultLookupEndpointHost(ctx context.Context, host string) ([]netip.Addr, error) {
|
|
addrs, err := net.DefaultResolver.LookupNetIP(ctx, "ip", host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := make([]netip.Addr, 0, len(addrs))
|
|
for _, a := range addrs {
|
|
out = append(out, a.Unmap())
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func newResolvingBind() *resolvingBind {
|
|
return &resolvingBind{Bind: awgconn.NewDefaultBind()}
|
|
}
|
|
|
|
// ParseEndpoint resolves hostnames before handing the address to amneziawg-go
|
|
// (whose own implementation accepts literal IPs only).
|
|
func (b *resolvingBind) ParseEndpoint(s string) (awgconn.Endpoint, error) {
|
|
host, portStr, err := net.SplitHostPort(strings.TrimSpace(s))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("endpoint %q: %w", s, err)
|
|
}
|
|
port64, err := strconv.ParseUint(portStr, 10, 16)
|
|
if err != nil || port64 == 0 {
|
|
return nil, fmt.Errorf("endpoint %q: bad port", s)
|
|
}
|
|
addr, err := netip.ParseAddr(host)
|
|
if err != nil {
|
|
ctx, cancel := context.WithTimeout(context.Background(), endpointResolveTimeout)
|
|
defer cancel()
|
|
addrs, rerr := lookupEndpointHost(ctx, host)
|
|
if rerr != nil {
|
|
return nil, fmt.Errorf("endpoint %q: resolve host: %w", s, rerr)
|
|
}
|
|
if len(addrs) == 0 {
|
|
return nil, fmt.Errorf("endpoint %q: host resolved to no addresses", s)
|
|
}
|
|
addr = addrs[0]
|
|
}
|
|
return &awgconn.StdNetEndpoint{AddrPort: netip.AddrPortFrom(addr.Unmap(), uint16(port64))}, nil
|
|
}
|