diff --git a/common/windivert/filter.go b/common/windivert/filter.go index 5c8fb5adc..4f5a60c2c 100644 --- a/common/windivert/filter.go +++ b/common/windivert/filter.go @@ -21,27 +21,39 @@ const ( filterMaxInsts = 256 fieldZero = 0 + fieldInbound = 1 fieldOutbound = 2 fieldIP = 5 fieldIPv6 = 6 + fieldICMP = 7 fieldTCP = 8 + fieldUDP = 9 + fieldICMPv6 = 10 fieldIPSrcAddr = 21 fieldIPDstAddr = 22 fieldIPv6SrcAddr = 28 fieldIPv6DstAddr = 29 + fieldICMPType = 30 + fieldICMPv6Type = 34 fieldTCPSrcPort = 38 fieldTCPDstPort = 39 + fieldUDPSrcPort = 53 + fieldUDPDstPort = 54 - testEQ = 0 + testEQ = 0 + testLEQ = 3 + testGEQ = 5 resultAccept uint16 = 0x7FFE resultReject uint16 = 0x7FFF ) // Filter flags passed to IOCTL_WINDIVERT_STARTUP alongside the compiled -// filter. These tell the driver what *kinds* of packets the filter might -// match, used as a kernel-side fast-reject. +// filter. The driver installs WFP callouts only for the directions and +// address families named here (windivert_install_callouts), so a filter +// missing its direction flag never sees a packet. const ( + filterFlagInbound uint64 = 0x0010 filterFlagOutbound uint64 = 0x0020 filterFlagIP uint64 = 0x0040 filterFlagIPv6 uint64 = 0x0080 @@ -104,6 +116,80 @@ func OutboundTCP(src, dst netip.AddrPort) (*Filter, error) { return f, nil } +func inboundTo(destination netip.Addr) (*Filter, error) { + if !destination.IsValid() { + return nil, E.New("windivert: filter: invalid address") + } + f := &Filter{ + flags: filterFlagInbound, + } + f.add(fieldInbound, testEQ, argUint32(1)) + if destination.Is4() { + f.flags |= filterFlagIP + f.add(fieldIP, testEQ, argUint32(1)) + f.add(fieldIPDstAddr, testEQ, argIPv4(destination)) + } else { + f.flags |= filterFlagIPv6 + f.add(fieldIPv6, testEQ, argUint32(1)) + f.add(fieldIPv6DstAddr, testEQ, argIPv6(destination)) + } + return f, nil +} + +func InboundTCPPortRange(destination netip.Addr, portLow, portHigh uint16) (*Filter, error) { + f, err := inboundTo(destination) + if err != nil { + return nil, err + } + f.add(fieldTCP, testEQ, argUint32(1)) + f.add(fieldTCPDstPort, testGEQ, argUint32(uint32(portLow))) + f.add(fieldTCPDstPort, testLEQ, argUint32(uint32(portHigh))) + return f, nil +} + +func InboundUDPPortRange(destination netip.Addr, portLow, portHigh uint16) (*Filter, error) { + f, err := inboundTo(destination) + if err != nil { + return nil, err + } + f.add(fieldUDP, testEQ, argUint32(1)) + f.add(fieldUDPDstPort, testGEQ, argUint32(uint32(portLow))) + f.add(fieldUDPDstPort, testLEQ, argUint32(uint32(portHigh))) + return f, nil +} + +func InboundICMPEchoReply(destination netip.Addr) (*Filter, error) { + f, err := inboundTo(destination) + if err != nil { + return nil, err + } + if destination.Is4() { + f.add(fieldICMP, testEQ, argUint32(1)) + f.add(fieldICMPType, testEQ, argUint32(0)) + } else { + f.add(fieldICMPv6, testEQ, argUint32(1)) + f.add(fieldICMPv6Type, testEQ, argUint32(129)) + } + return f, nil +} + +func InboundICMPError(destination netip.Addr) (*Filter, error) { + f, err := inboundTo(destination) + if err != nil { + return nil, err + } + if destination.Is4() { + f.add(fieldICMP, testEQ, argUint32(1)) + f.add(fieldICMPType, testGEQ, argUint32(3)) + f.add(fieldICMPType, testLEQ, argUint32(12)) + } else { + f.add(fieldICMPv6, testEQ, argUint32(1)) + f.add(fieldICMPv6Type, testGEQ, argUint32(1)) + f.add(fieldICMPv6Type, testLEQ, argUint32(4)) + } + return f, nil +} + func (f *Filter) add(field uint16, test uint8, arg [4]uint32) { f.insts = append(f.insts, filterInst{field: field, test: test, arg: arg}) } diff --git a/common/windivert/handle_windows.go b/common/windivert/handle_windows.go index 1d7aebfde..7d6cfc4a1 100644 --- a/common/windivert/handle_windows.go +++ b/common/windivert/handle_windows.go @@ -26,11 +26,14 @@ import ( // because Go's escape analysis does not see the pointer through the // unsafe.Pointer → uintptr → bytes conversion. type Handle struct { - device windows.Handle - event windows.Handle - closing sync.Once - closeErr error - addr Address + device windows.Handle + event windows.Handle + closing sync.Once + closeErr error + addr Address + recvAddrs []Address + recvAddrsLen uint32 + sendAddrs []Address } // Filter may be nil for "reject all", suitable for send-only handles. @@ -169,10 +172,60 @@ func (h *Handle) Recv(buf []byte) (int, Address, error) { return int(n), h.addr, nil } +// BatchMax is WINDIVERT_BATCH_MAX: the driver caps both directions at 255 +// packets per ioctl. +const BatchMax = 255 + +const addressSize = uint32(unsafe.Sizeof(Address{})) + +// RecvBatch receives up to BatchMax packets in one ioctl. The driver packs +// packets back-to-back into buf with no padding and copies exactly each +// packet's IP total length, so boundaries are recovered by walking the IP +// length fields. It returns as soon as at least one packet is available; +// it never waits to fill the batch. The returned Address slice is owned by +// the Handle and is overwritten by the next RecvBatch. +func (h *Handle) RecvBatch(buf []byte) (int, []Address, error) { + if len(buf) < MTUMax { + return 0, nil, E.New("windivert: recv batch: buffer smaller than MTUMax") + } + if h.recvAddrs == nil { + h.recvAddrs = make([]Address, BatchMax) + } + h.recvAddrsLen = uint32(len(h.recvAddrs)) * addressSize + in := buildIoctlRecvBatch(&h.recvAddrs[0], &h.recvAddrsLen) + n, err := doIoctl(h.device, ioctlRecv, in[:], buf, h.event) + runtime.KeepAlive(h) + if err != nil { + return 0, nil, err + } + return int(n), h.recvAddrs[:h.recvAddrsLen/addressSize], nil +} + +// SendBatch injects the packets packed back-to-back in buf, one Address per +// packet. The driver recovers packet boundaries from the IP total-length +// fields and rejects the whole batch if they do not add up to len(buf). +func (h *Handle) SendBatch(buf []byte, addrs []Address) (int, error) { + if len(addrs) == 0 || len(addrs) > BatchMax { + return 0, E.New("windivert: send batch: invalid packet count ", len(addrs)) + } + if len(buf) == 0 { + return 0, E.New("windivert: send batch: empty buffer") + } + if h.sendAddrs == nil { + h.sendAddrs = make([]Address, BatchMax) + } + copy(h.sendAddrs, addrs) + in := buildIoctlSend(&h.sendAddrs[0], uint32(len(addrs))*addressSize) + n, err := doIoctl(h.device, ioctlSend, in[:], buf, h.event) + runtime.KeepAlive(h) + if err != nil { + return 0, err + } + return int(n), nil +} + // The address's Outbound flag controls whether the packet is sent toward // the wire (outbound=true) or delivered up the stack (outbound=false). -// IfIdx and SubIfIdx can stay zero — the driver uses the routing table -// when IfIdx=0. func (h *Handle) Send(packet []byte, addr *Address) (int, error) { if len(packet) == 0 { return 0, E.New("windivert: send: empty packet") @@ -181,7 +234,7 @@ func (h *Handle) Send(packet []byte, addr *Address) (int, error) { return 0, E.New("windivert: send: nil address") } h.addr = *addr - in := buildIoctlSend(&h.addr) + in := buildIoctlSend(&h.addr, addressSize) n, err := doIoctl(h.device, ioctlSend, in[:], packet, h.event) runtime.KeepAlive(h) if err != nil { @@ -316,9 +369,20 @@ func buildIoctlRecv(addr *Address) [ioctlSize]byte { return buf } -func buildIoctlSend(addr *Address) [ioctlSize]byte { +// buildIoctlRecvBatch additionally passes addr_len_ptr, a pointer to the +// Address array capacity in bytes; the driver overwrites it with the bytes +// actually written (packet count × 80). Caller must keep both pointees +// alive via runtime.KeepAlive. +func buildIoctlRecvBatch(addrs *Address, addrsLen *uint32) [ioctlSize]byte { var buf [ioctlSize]byte - binary.LittleEndian.PutUint64(buf[0:8], uint64(uintptr(unsafe.Pointer(addr)))) - binary.LittleEndian.PutUint64(buf[8:16], uint64(unsafe.Sizeof(Address{}))) + binary.LittleEndian.PutUint64(buf[0:8], uint64(uintptr(unsafe.Pointer(addrs)))) + binary.LittleEndian.PutUint64(buf[8:16], uint64(uintptr(unsafe.Pointer(addrsLen)))) + return buf +} + +func buildIoctlSend(addrs *Address, addrsLen uint32) [ioctlSize]byte { + var buf [ioctlSize]byte + binary.LittleEndian.PutUint64(buf[0:8], uint64(uintptr(unsafe.Pointer(addrs)))) + binary.LittleEndian.PutUint64(buf[8:16], uint64(addrsLen)) return buf } diff --git a/common/windivert/handle_windows_test.go b/common/windivert/handle_windows_test.go index 73dfbb166..149550741 100644 --- a/common/windivert/handle_windows_test.go +++ b/common/windivert/handle_windows_test.go @@ -72,7 +72,7 @@ func TestBuildIoctlRecvEmbedsAddressPointer(t *testing.T) { func TestBuildIoctlSendEmbedsAddressPointerAndSize(t *testing.T) { t.Parallel() addr := &Address{} - buf := buildIoctlSend(addr) + buf := buildIoctlSend(addr, addressSize) require.Equal(t, uint64(uintptr(unsafe.Pointer(addr))), binary.LittleEndian.Uint64(buf[0:8])) require.Equal(t, uint64(unsafe.Sizeof(Address{})), diff --git a/common/windivert/windivert.go b/common/windivert/windivert.go index 619e41b61..280d11f63 100644 --- a/common/windivert/windivert.go +++ b/common/windivert/windivert.go @@ -55,9 +55,11 @@ var _ [80]byte = [unsafe.Sizeof(Address{})]byte{} // Bit positions inside the Address's packed flags word. const ( + addrBitOutbound = 17 addrBitIPv6 = 20 addrBitIPChecksum = 21 addrBitTCPChecksum = 22 + addrBitUDPChecksum = 23 ) func getFlagBit(bits uint32, pos uint) bool { return bits&(1< 0 { + b.unregister = func() { + for _, unregisterFunc := range unregisterFuncs { + unregisterFunc() + } + } + } +} + func (b *backendBase) syncSessionEgress() { b.egressAccess.Lock() defer b.egressAccess.Unlock() diff --git a/protocol/bridge/backend_stub.go b/protocol/bridge/backend_stub.go index 31712dc80..83cbc47b1 100644 --- a/protocol/bridge/backend_stub.go +++ b/protocol/bridge/backend_stub.go @@ -1,4 +1,4 @@ -//go:build !linux && !darwin +//go:build !linux && !darwin && !(windows && (amd64 || 386)) package bridge @@ -12,5 +12,5 @@ import ( ) func newBackend(ctx context.Context, logger logger.ContextLogger, networkManager adapter.NetworkManager, tag string, options option.BridgeOutboundOptions) (Backend, error) { - return nil, E.New("bridge outbound is only supported on Linux, macOS, Android with ROOT and jailbroken iOS") + return nil, E.New("bridge outbound is only supported on Linux, macOS, Windows (x86 and x64), rooted Android and jailbroken iOS") } diff --git a/protocol/bridge/backend_windows.go b/protocol/bridge/backend_windows.go new file mode 100644 index 000000000..12f858eaf --- /dev/null +++ b/protocol/bridge/backend_windows.go @@ -0,0 +1,892 @@ +//go:build windows && (amd64 || 386) + +package bridge + +import ( + "context" + "encoding/binary" + "errors" + "net/netip" + "sync" + "sync/atomic" + "time" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/windivert" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing-tun/gtcpip" + "github.com/sagernet/sing-tun/gtcpip/header" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + + "golang.org/x/sys/windows" +) + +const ( + bridgeReservedPortCount uint16 = 1024 + + bridgeICMPFlowTimeout = time.Minute + + bridgeDivertPriority int16 = 0 + + bridgeDivertRetryDelayMin = 100 * time.Millisecond + bridgeDivertRetryDelayMax = 2 * time.Second + + bridgeBatchBufferSize = 256 * 1024 +) + +type divertKind uint8 + +const ( + divertTransport divertKind = iota + divertICMPEcho + divertICMPError +) + +type egressState struct { + inet4 netip.Addr + inet6 netip.Addr + mtu uint32 +} + +type diverter struct { + handle *windivert.Handle + done chan struct{} +} + +type backendWindows struct { + backendBase + + writeAccess sync.Mutex + injectHandle *windivert.Handle + sendBuffer []byte + sendAddrs []windivert.Address + + deliverAccess sync.Mutex + deliverBuffer []byte + deliverBuffered [][]byte + + egress atomic.Pointer[egressState] + + reservation *portReservation + reservedStart uint16 + + icmp4, icmp6 *icmpTable + + diverters []*diverter +} + +func newBackend(ctx context.Context, logger logger.ContextLogger, networkManager adapter.NetworkManager, tag string, options option.BridgeOutboundOptions) (Backend, error) { + instance := &backendWindows{} + err := instance.init(ctx, logger, networkManager, tag, options) + if err != nil { + return nil, err + } + return instance, nil +} + +func (b *backendWindows) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } + err := b.start() + if err != nil { + b.Close() + return err + } + return nil +} + +func (b *backendWindows) start() error { + b.closed = make(chan struct{}) + + state := b.currentEgressState() + if !(b.inet4Port.IsValid() && state.inet4.IsValid()) { + b.inet4Port = netip.Addr{} + } + if !(b.inet6Port.IsValid() && state.inet6.IsValid()) { + b.inet6Port = netip.Addr{} + b.logger.Debug("bridge IPv6 egress unavailable, disabling IPv6 forwarding") + } + if !b.inet4Port.IsValid() && !b.inet6Port.IsValid() { + return E.New("bridge: no usable egress address; requires an interface with a routable address and Administrator") + } + b.egress.Store(state) + + err := b.acquireReservations() + if err != nil { + return err + } + + injectHandle, err := windivert.Open(nil, windivert.LayerNetwork, windivert.PriorityHighest, windivert.FlagSendOnly) + if err != nil { + return E.Cause(err, "bridge: open injection handle (Administrator required)") + } + b.injectHandle = injectHandle + b.sendBuffer = make([]byte, 0, bridgeBatchBufferSize) + b.sendAddrs = make([]windivert.Address, 0, windivert.BatchMax) + + b.egressAccess.Lock() + err = b.rebuildDivertersLocked(state) + b.egressAccess.Unlock() + if err != nil { + return err + } + + b.registerMonitors(b.syncEgress) + b.logger.Info("bridge started (WinDivert, egress ", b.egressLabel(), ")") + return nil +} + +func (b *backendWindows) egressLabel() string { + if b.boundInterface != "" { + return b.boundInterface + } + return "auto" +} + +func (b *backendWindows) acquireReservations() error { + family := windows.AF_INET + if !b.inet4Port.IsValid() { + family = windows.AF_INET6 + } + reservation, err := acquirePortReservation(family, windows.SOCK_STREAM, windows.IPPROTO_TCP, bridgeReservedPortCount) + if err != nil { + return E.Cause(err, "bridge: reserve ports") + } + b.reservation = reservation + b.reservedStart = reservation.startPort + if b.inet4Port.IsValid() { + b.icmp4 = newICMPTable(bridgeICMPFlowTimeout) + } + if b.inet6Port.IsValid() { + b.icmp6 = newICMPTable(bridgeICMPFlowTimeout) + } + return nil +} + +func (b *backendWindows) PortSelectorRange() (uint16, uint16) { + return b.reservedStart, bridgeReservedPortCount +} + +func (b *backendWindows) rebuildDivertersLocked(state *egressState) error { + for _, existing := range b.diverters { + existing.handle.Close() + <-existing.done + } + b.diverters = nil + + if b.inet4Port.IsValid() && state.inet4.IsValid() { + err := b.openFamilyDiverters(state.inet4, false) + if err != nil { + return err + } + } + if b.inet6Port.IsValid() && state.inet6.IsValid() { + err := b.openFamilyDiverters(state.inet6, true) + if err != nil { + return err + } + } + return nil +} + +func (b *backendWindows) openFamilyDiverters(egressAddr netip.Addr, isV6 bool) error { + portHigh := uint16(uint32(b.reservedStart) + uint32(bridgeReservedPortCount) - 1) + entries := []struct { + what string + kind divertKind + build func() (*windivert.Filter, error) + }{ + {"TCP", divertTransport, func() (*windivert.Filter, error) { + return windivert.InboundTCPPortRange(egressAddr, b.reservedStart, portHigh) + }}, + {"UDP", divertTransport, func() (*windivert.Filter, error) { + return windivert.InboundUDPPortRange(egressAddr, b.reservedStart, portHigh) + }}, + {"ICMP echo", divertICMPEcho, func() (*windivert.Filter, error) { + return windivert.InboundICMPEchoReply(egressAddr) + }}, + {"ICMP error", divertICMPError, func() (*windivert.Filter, error) { + return windivert.InboundICMPError(egressAddr) + }}, + } + for _, entry := range entries { + filter, err := entry.build() + if err != nil { + return E.Cause(err, "bridge: build ", entry.what, " divert filter") + } + err = b.openDiverter(filter, entry.kind, isV6) + if err != nil { + return err + } + } + return nil +} + +func (b *backendWindows) openDiverter(filter *windivert.Filter, kind divertKind, isV6 bool) error { + handle, err := windivert.Open(filter, windivert.LayerNetwork, bridgeDivertPriority, 0) + if err != nil { + return E.Cause(err, "bridge: open divert handle") + } + d := &diverter{handle: handle, done: make(chan struct{})} + b.diverters = append(b.diverters, d) + go b.divertLoop(d, kind, isV6) + return nil +} + +func (b *backendWindows) divertLoop(d *diverter, kind divertKind, isV6 bool) { + defer close(d.done) + buffer := make([]byte, bridgeBatchBufferSize) + deliverBatch := make([][]byte, 0, windivert.BatchMax) + retryDelay := bridgeDivertRetryDelayMin + for { + n, addrs, err := d.handle.RecvBatch(buffer) + if err != nil { + if errors.Is(err, windows.ERROR_OPERATION_ABORTED) || errors.Is(err, windows.ERROR_NO_DATA) || errors.Is(err, windows.ERROR_INVALID_HANDLE) { + return + } + select { + case <-b.closed: + return + default: + } + b.logger.Debug(E.Cause(err, "bridge divert recv")) + select { + case <-b.closed: + return + case <-time.After(retryDelay): + } + retryDelay = min(retryDelay*2, bridgeDivertRetryDelayMax) + continue + } + retryDelay = bridgeDivertRetryDelayMin + deliverBatch = deliverBatch[:0] + offset := 0 + for i := range addrs { + packetLength := ipPacketLength(buffer[offset:n]) + if packetLength <= 0 || offset+packetLength > n { + break + } + packet := buffer[offset : offset+packetLength] + offset += packetLength + if b.classifyInbound(packet, kind, isV6) { + deliverBatch = append(deliverBatch, packet) + } else { + b.reinject(d.handle, packet, &addrs[i]) + } + } + if len(deliverBatch) > 0 { + b.deliver(deliverBatch) + } + } +} + +func ipPacketLength(packet []byte) int { + switch header.IPVersion(packet) { + case header.IPv4Version: + if len(packet) < header.IPv4MinimumSize { + return 0 + } + return int(header.IPv4(packet).TotalLength()) + case header.IPv6Version: + if len(packet) < header.IPv6MinimumSize { + return 0 + } + return header.IPv6MinimumSize + int(header.IPv6(packet).PayloadLength()) + default: + return 0 + } +} + +func (b *backendWindows) classifyInbound(packet []byte, kind divertKind, isV6 bool) bool { + portAddress := b.inet4Port + if isV6 { + portAddress = b.inet6Port + } + if !portAddress.IsValid() { + return false + } + switch kind { + case divertTransport: + return rewriteAddress(packet, portAddress, false) + case divertICMPEcho: + table := b.icmpFor(isV6) + if table == nil { + return false + } + info, valid := parseTransport(packet, isV6) + if !valid || info.transport == nil { + return false + } + identifier, identifierValid := icmpIdentifier(info.transport, isV6) + if !identifierValid || !table.isActive(identifier, packetRemoteAddress(packet, isV6, true)) { + return false + } + return rewriteAddress(packet, portAddress, false) + case divertICMPError: + return b.classifyICMPError(packet, portAddress, isV6) + default: + return false + } +} + +// classifyICMPError claims an inbound ICMP error whose embedded packet is +// one of our translated outbound packets, and prepares it for the +// dispatcher: only the embedded source address is rewritten back to the +// port address; the dispatcher's ICMP error return path matches the flow +// by the embedded tuple, rewrites everything else, and recomputes the +// outer checksums. +func (b *backendWindows) classifyICMPError(packet []byte, portAddress netip.Addr, isV6 bool) bool { + info, valid := parseTransport(packet, isV6) + if !valid || info.transport == nil || info.fragmented { + return false + } + var inner []byte + if isV6 { + if len(info.transport) < header.ICMPv6ErrorHeaderSize { + return false + } + if !header.ICMPv6(info.transport).Type().IsErrorType() { + return false + } + inner = info.transport[header.ICMPv6ErrorHeaderSize:] + } else { + if len(info.transport) < header.ICMPv4MinimumSize { + return false + } + switch header.ICMPv4(info.transport).Type() { + case header.ICMPv4DstUnreachable, header.ICMPv4SrcQuench, header.ICMPv4Redirect, header.ICMPv4TimeExceeded, header.ICMPv4ParamProblem: + default: + return false + } + inner = info.transport[header.ICMPv4MinimumSize:] + } + if isV6 { + return b.rewriteICMPErrorInner6(packet, inner, portAddress) + } + return b.rewriteICMPErrorInner4(packet, inner, portAddress) +} + +func (b *backendWindows) rewriteICMPErrorInner4(packet, inner []byte, portAddress netip.Addr) bool { + if len(inner) < header.IPv4MinimumSize { + return false + } + innerHdr := header.IPv4(inner) + headerLength := int(innerHdr.HeaderLength()) + if headerLength < header.IPv4MinimumSize || headerLength > len(inner) { + return false + } + outerDestination := header.IPv4(packet).DestinationAddr() + innerSource := innerHdr.SourceAddr() + if innerSource != outerDestination { + return false + } + transport := inner[headerLength:] + if !b.embeddedFlowActive(innerHdr.TransportProtocol(), transport, innerHdr.DestinationAddr(), false) { + return false + } + oldAddress := innerSource.As4() + newAddress := portAddress.As4() + innerHdr.SetSourceAddressWithChecksumUpdate(tcpip.AddrFrom4(newAddress)) + adjustTransportChecksum(innerHdr.TransportProtocol(), transport, oldAddress[:], newAddress[:]) + return true +} + +func (b *backendWindows) rewriteICMPErrorInner6(packet, inner []byte, portAddress netip.Addr) bool { + if len(inner) < header.IPv6MinimumSize { + return false + } + innerHdr := header.IPv6(inner) + outerDestination := header.IPv6(packet).DestinationAddr() + innerSource := innerHdr.SourceAddr() + if innerSource != outerDestination { + return false + } + transport := inner[header.IPv6MinimumSize:] + if !b.embeddedFlowActive(innerHdr.TransportProtocol(), transport, innerHdr.DestinationAddr(), true) { + return false + } + oldAddress := innerSource.As16() + newAddress := portAddress.As16() + innerHdr.SetSourceAddress(tcpip.AddrFrom16(newAddress)) + adjustTransportChecksum(innerHdr.TransportProtocol(), transport, oldAddress[:], newAddress[:]) + return true +} + +func (b *backendWindows) embeddedFlowActive(protocol tcpip.TransportProtocolNumber, transport []byte, remote netip.Addr, isV6 bool) bool { + switch protocol { + case header.TCPProtocolNumber, header.UDPProtocolNumber: + if len(transport) < 4 { + return false + } + return b.portReserved(binary.BigEndian.Uint16(transport[0:2])) + case header.ICMPv4ProtocolNumber: + if isV6 || len(transport) < header.ICMPv4MinimumSize { + return false + } + icmpHdr := header.ICMPv4(transport) + if icmpHdr.Type() != header.ICMPv4Echo { + return false + } + table := b.icmpFor(false) + return table != nil && table.isActive(icmpHdr.Ident(), remote) + case header.ICMPv6ProtocolNumber: + if !isV6 || len(transport) < header.ICMPv6MinimumSize { + return false + } + icmpHdr := header.ICMPv6(transport) + if icmpHdr.Type() != header.ICMPv6EchoRequest { + return false + } + table := b.icmpFor(true) + return table != nil && table.isActive(icmpHdr.Ident(), remote) + default: + return false + } +} + +func (b *backendWindows) portReserved(port uint16) bool { + return port >= b.reservedStart && uint32(port) < uint32(b.reservedStart)+uint32(bridgeReservedPortCount) +} + +func (b *backendWindows) deliver(packets [][]byte) { + b.deliverAccess.Lock() + defer b.deliverAccess.Unlock() + + b.returnAccess.Lock() + returnPaths := b.returnPaths + b.returnAccess.Unlock() + if len(returnPaths) == 0 { + return + } + headroom := returnPaths[0].ReturnHeadroom() + + // The return-path writeback copies synchronously, so the staging buffer is + // safe to reuse on the next batch. + total := 0 + for _, packet := range packets { + total += headroom + len(packet) + } + if cap(b.deliverBuffer) < total { + b.deliverBuffer = make([]byte, total) + } + staging := b.deliverBuffer[:total] + buffered := b.deliverBuffered[:0] + offset := 0 + for _, packet := range packets { + segment := staging[offset : offset+headroom+len(packet)] + copy(segment[headroom:], packet) + buffered = append(buffered, segment) + offset += headroom + len(packet) + } + b.deliverBuffered = buffered + + unconsumed := buffered + currentHeadroom := headroom + for _, returnPath := range returnPaths { + if len(unconsumed) == 0 { + break + } + nextHeadroom := returnPath.ReturnHeadroom() + if nextHeadroom != currentHeadroom { + rebuffered := make([][]byte, 0, len(unconsumed)) + for _, packet := range unconsumed { + payload := packet[currentHeadroom:] + buffer := make([]byte, nextHeadroom+len(payload)) + copy(buffer[nextHeadroom:], payload) + rebuffered = append(rebuffered, buffer) + } + unconsumed = rebuffered + currentHeadroom = nextHeadroom + } + unconsumed = returnPath.ReturnPackets(unconsumed) + } +} + +func (b *backendWindows) reinject(handle *windivert.Handle, packet []byte, addr *windivert.Address) { + _, err := handle.Send(packet, addr) + if err != nil { + select { + case <-b.closed: + default: + b.logger.Debug(E.Cause(err, "bridge reinject")) + } + } +} + +func (b *backendWindows) icmpFor(isV6 bool) *icmpTable { + if isV6 { + return b.icmp6 + } + return b.icmp4 +} + +func (b *backendWindows) PortMTU() uint32 { + state := b.egress.Load() + if state == nil { + return 0 + } + return state.mtu +} + +func (b *backendWindows) WritePackets(packets [][]byte) error { + state := b.egress.Load() + if state == nil { + return nil + } + b.writeAccess.Lock() + defer b.writeAccess.Unlock() + for _, packet := range packets { + if len(packet) == 0 || len(packet) > maxPacketLength { + continue + } + if !b.prepareOutbound(packet, state) { + continue + } + if len(b.sendAddrs) == windivert.BatchMax || len(b.sendBuffer)+len(packet) > cap(b.sendBuffer) { + b.flushOutboundLocked() + } + b.sendBuffer = append(b.sendBuffer, packet...) + var addr windivert.Address + addr.SetOutbound(true) + addr.SetIPv6(header.IPVersion(packet) == header.IPv6Version) + addr.SetIPChecksum(true) + addr.SetTCPChecksum(true) + addr.SetUDPChecksum(true) + b.sendAddrs = append(b.sendAddrs, addr) + } + b.flushOutboundLocked() + return nil +} + +func (b *backendWindows) flushOutboundLocked() { + if len(b.sendAddrs) == 0 { + return + } + _, err := b.injectHandle.SendBatch(b.sendBuffer, b.sendAddrs) + if err != nil { + select { + case <-b.closed: + default: + b.logger.Debug(E.Cause(err, "bridge inject")) + } + } + b.sendBuffer = b.sendBuffer[:0] + b.sendAddrs = b.sendAddrs[:0] +} + +func (b *backendWindows) prepareOutbound(packet []byte, state *egressState) bool { + var ( + isV6 bool + egressAddr netip.Addr + ) + switch header.IPVersion(packet) { + case header.IPv4Version: + egressAddr = state.inet4 + case header.IPv6Version: + isV6 = true + egressAddr = state.inet6 + default: + return false + } + if !egressAddr.IsValid() { + return false + } + // The batched injection ioctl walks the buffer by IP total length; a + // packet with trailing bytes would desynchronize the walk and fail the + // whole batch. + if ipPacketLength(packet) != len(packet) { + return false + } + info, valid := parseTransport(packet, isV6) + if !valid { + return false + } + switch info.protocol { + case header.TCPProtocolNumber, header.UDPProtocolNumber: + if info.transport != nil { + if len(info.transport) < 4 { + return false + } + if !b.portReserved(binary.BigEndian.Uint16(info.transport[0:2])) { + b.logger.Debug("bridge: dropping outbound packet with source port outside the reserved block") + return false + } + } + case header.ICMPv4ProtocolNumber, header.ICMPv6ProtocolNumber: + table := b.icmpFor(isV6) + if table == nil { + return false + } + if info.transport != nil { + identifier, identifierValid := icmpIdentifier(info.transport, isV6) + if !identifierValid { + return false + } + table.register(identifier, packetRemoteAddress(packet, isV6, false)) + } + default: + return false + } + return rewriteAddressWithInfo(packet, info, egressAddr, true) +} + +func (b *backendWindows) syncEgress() { + b.egressAccess.Lock() + defer b.egressAccess.Unlock() + select { + case <-b.closed: + return + default: + } + state := b.currentEgressState() + previous := b.egress.Load() + if previous != nil && previous.inet4 == state.inet4 && previous.inet6 == state.inet6 { + if *previous != *state { + b.egress.Store(state) + } + return + } + if (b.inet4Port.IsValid() && !state.inet4.IsValid()) || (b.inet6Port.IsValid() && !state.inet6.IsValid()) { + b.logger.Debug("bridge egress address unavailable, dropping affected traffic") + } + err := b.rebuildDivertersLocked(state) + if err != nil { + b.egress.Store(&egressState{}) + b.logger.Debug(E.Cause(err, "bridge rebuild diverters")) + return + } + b.egress.Store(state) + b.logger.Debug("bridge egress ", b.egressLabel(), " updated") +} + +func (b *backendWindows) currentEgressState() *egressState { + state := &egressState{} + egressName := b.resolveEgress() + if egressName == "" { + return state + } + finder := b.networkManager.InterfaceFinder() + if finder == nil { + return state + } + egressInterface, err := finder.ByName(egressName) + if err != nil { + return state + } + if egressInterface.MTU > 0 { + state.mtu = uint32(egressInterface.MTU) + } + for _, prefix := range egressInterface.Addresses { + address := prefix.Addr().Unmap() + if address.Is4() { + if !state.inet4.IsValid() && address.IsGlobalUnicast() { + state.inet4 = address + } + } else if !state.inet6.IsValid() && address.IsGlobalUnicast() { + state.inet6 = address + } + } + return state +} + +func (b *backendWindows) Close() error { + b.closeOnce.Do(func() { + if b.closed != nil { + close(b.closed) + } + if b.unregister != nil { + b.unregister() + } + b.egressAccess.Lock() + for _, d := range b.diverters { + d.handle.Close() + <-d.done + } + b.diverters = nil + b.egressAccess.Unlock() + if b.injectHandle != nil { + b.injectHandle.Close() + } + b.reservation.Close() + b.reservation = nil + releaseBridgeIndex(b.index) + }) + return nil +} + +type transportInfo struct { + protocol tcpip.TransportProtocolNumber + transport []byte + fragmented bool +} + +func parseTransport(packet []byte, isV6 bool) (transportInfo, bool) { + if !isV6 { + if len(packet) < header.IPv4MinimumSize { + return transportInfo{}, false + } + ipHdr := header.IPv4(packet) + if !ipHdr.IsValid(len(packet)) { + return transportInfo{}, false + } + info := transportInfo{ + protocol: ipHdr.TransportProtocol(), + fragmented: ipHdr.More() || ipHdr.FragmentOffset() != 0, + } + if ipHdr.FragmentOffset() == 0 { + info.transport = ipHdr.Payload() + } + return info, true + } + if len(packet) < header.IPv6MinimumSize { + return transportInfo{}, false + } + ipHdr := header.IPv6(packet) + payloadLength := int(ipHdr.PayloadLength()) + if payloadLength > len(packet)-header.IPv6MinimumSize { + return transportInfo{}, false + } + payload := packet[header.IPv6MinimumSize:][:payloadLength] + var info transportInfo + nextHeader := ipHdr.NextHeader() + offset := 0 + for { + switch header.IPv6ExtensionHeaderIdentifier(nextHeader) { + case header.IPv6HopByHopOptionsExtHdrIdentifier, header.IPv6RoutingExtHdrIdentifier, header.IPv6DestinationOptionsExtHdrIdentifier: + if len(payload)-offset < 2 { + return transportInfo{}, false + } + extensionLength := (int(payload[offset+1]) + 1) * 8 + if len(payload)-offset < extensionLength { + return transportInfo{}, false + } + nextHeader = payload[offset] + offset += extensionLength + case header.IPv6FragmentExtHdrIdentifier: + if len(payload)-offset < header.IPv6FragmentHeaderSize { + return transportInfo{}, false + } + fragmentHdr := header.IPv6Fragment(payload[offset : offset+header.IPv6FragmentHeaderSize]) + info.fragmented = true + if fragmentHdr.FragmentOffset() != 0 { + info.protocol = fragmentHdr.TransportProtocol() + return info, true + } + nextHeader = fragmentHdr.NextHeader() + offset += header.IPv6FragmentHeaderSize + case header.IPv6NoNextHeaderIdentifier: + return transportInfo{}, false + default: + info.protocol = tcpip.TransportProtocolNumber(nextHeader) + info.transport = payload[offset:] + return info, true + } + } +} + +func packetRemoteAddress(packet []byte, isV6, inbound bool) netip.Addr { + if isV6 { + ipHdr := header.IPv6(packet) + if inbound { + return ipHdr.SourceAddr() + } + return ipHdr.DestinationAddr() + } + ipHdr := header.IPv4(packet) + if inbound { + return ipHdr.SourceAddr() + } + return ipHdr.DestinationAddr() +} + +func icmpIdentifier(transport []byte, isV6 bool) (uint16, bool) { + if isV6 { + if len(transport) < header.ICMPv6MinimumSize { + return 0, false + } + return header.ICMPv6(transport).Ident(), true + } + if len(transport) < header.ICMPv4MinimumSize { + return 0, false + } + return header.ICMPv4(transport).Ident(), true +} + +func rewriteAddress(packet []byte, address netip.Addr, source bool) bool { + info, valid := parseTransport(packet, header.IPVersion(packet) == header.IPv6Version) + if !valid { + return false + } + return rewriteAddressWithInfo(packet, info, address, source) +} + +func rewriteAddressWithInfo(packet []byte, info transportInfo, address netip.Addr, source bool) bool { + switch header.IPVersion(packet) { + case header.IPv4Version: + ipHdr := header.IPv4(packet) + newAddress := address.As4() + var oldAddress [4]byte + if source { + copy(oldAddress[:], ipHdr.SourceAddressSlice()) + } else { + copy(oldAddress[:], ipHdr.DestinationAddressSlice()) + } + if info.transport != nil { + adjustTransportChecksum(info.protocol, info.transport, oldAddress[:], newAddress[:]) + } + if source { + ipHdr.SetSourceAddressWithChecksumUpdate(tcpip.AddrFrom4(newAddress)) + } else { + ipHdr.SetDestinationAddressWithChecksumUpdate(tcpip.AddrFrom4(newAddress)) + } + return true + case header.IPv6Version: + ipHdr := header.IPv6(packet) + newAddress := address.As16() + var oldAddress [16]byte + if source { + copy(oldAddress[:], ipHdr.SourceAddressSlice()) + ipHdr.SetSourceAddress(tcpip.AddrFrom16(newAddress)) + } else { + copy(oldAddress[:], ipHdr.DestinationAddressSlice()) + ipHdr.SetDestinationAddress(tcpip.AddrFrom16(newAddress)) + } + if info.transport != nil { + adjustTransportChecksum(info.protocol, info.transport, oldAddress[:], newAddress[:]) + } + return true + default: + return false + } +} + +func adjustTransportChecksum(protocol tcpip.TransportProtocolNumber, transport []byte, oldData, newData []byte) { + oldAddress := tcpip.AddrFromSlice(oldData) + newAddress := tcpip.AddrFromSlice(newData) + switch protocol { + case header.TCPProtocolNumber: + if len(transport) < header.TCPMinimumSize { + return + } + header.TCP(transport).UpdateChecksumPseudoHeaderAddress(oldAddress, newAddress, true) + case header.UDPProtocolNumber: + if len(transport) < header.UDPMinimumSize { + return + } + udpHdr := header.UDP(transport) + if udpHdr.Checksum() == 0 { + return + } + udpHdr.UpdateChecksumPseudoHeaderAddress(oldAddress, newAddress, true) + if udpHdr.Checksum() == 0 { + udpHdr.SetChecksum(0xffff) + } + case header.ICMPv6ProtocolNumber: + if len(transport) < header.ICMPv6MinimumSize { + return + } + header.ICMPv6(transport).UpdateChecksumPseudoHeaderAddress(oldAddress, newAddress) + } +} diff --git a/protocol/bridge/nat_windows.go b/protocol/bridge/nat_windows.go new file mode 100644 index 000000000..c5e4bce71 --- /dev/null +++ b/protocol/bridge/nat_windows.go @@ -0,0 +1,66 @@ +//go:build windows && (amd64 || 386) + +package bridge + +import ( + "net/netip" + "sync" + "time" +) + +// icmpTable records liveness of ICMP echo flows by (identifier, remote +// address). The identifier passes through untranslated — the dispatcher NAT +// already set it to the selector — and Windows ping.exe uses a constant +// identifier, so the remote address is needed to tell a bridged reply from the +// host's own ping. +type icmpTable struct { + access sync.Mutex + timeout time.Duration + active map[icmpFlowKey]time.Time + lastSweep time.Time +} + +type icmpFlowKey struct { + identifier uint16 + remote netip.Addr +} + +func newICMPTable(timeout time.Duration) *icmpTable { + return &icmpTable{ + timeout: timeout, + active: make(map[icmpFlowKey]time.Time), + } +} + +func (t *icmpTable) register(identifier uint16, remote netip.Addr) { + now := time.Now() + key := icmpFlowKey{identifier: identifier, remote: remote} + t.access.Lock() + defer t.access.Unlock() + if now.Sub(t.lastSweep) >= t.timeout { + t.lastSweep = now + for flow, lastActive := range t.active { + if now.Sub(lastActive) >= t.timeout { + delete(t.active, flow) + } + } + } + t.active[key] = now +} + +func (t *icmpTable) isActive(identifier uint16, remote netip.Addr) bool { + now := time.Now() + key := icmpFlowKey{identifier: identifier, remote: remote} + t.access.Lock() + defer t.access.Unlock() + lastActive, loaded := t.active[key] + if !loaded { + return false + } + if now.Sub(lastActive) >= t.timeout { + delete(t.active, key) + return false + } + t.active[key] = now + return true +} diff --git a/protocol/bridge/outbound.go b/protocol/bridge/outbound.go index a85340d6b..cd952841d 100644 --- a/protocol/bridge/outbound.go +++ b/protocol/bridge/outbound.go @@ -110,6 +110,13 @@ func (o *Outbound) PortMTU() uint32 { return o.backend.PortMTU() } +func (o *Outbound) PortSelectorRange() (uint16, uint16) { + if rangedBackend, isRanged := o.backend.(tun.PortWithSelectorRange); isRanged { + return rangedBackend.PortSelectorRange() + } + return 0, 0 +} + func (o *Outbound) AttachReturn(returnPath tun.Return) error { return o.backend.AttachReturn(returnPath) } diff --git a/protocol/bridge/packet.go b/protocol/bridge/packet.go index 64466d63d..1e6a28ebe 100644 --- a/protocol/bridge/packet.go +++ b/protocol/bridge/packet.go @@ -1,4 +1,4 @@ -//go:build linux || darwin +//go:build linux || darwin || (windows && (amd64 || 386)) package bridge diff --git a/protocol/bridge/reservation_windows.go b/protocol/bridge/reservation_windows.go new file mode 100644 index 000000000..22f848cb3 --- /dev/null +++ b/protocol/bridge/reservation_windows.go @@ -0,0 +1,73 @@ +//go:build windows && (amd64 || 386) + +package bridge + +import ( + "encoding/binary" + + E "github.com/sagernet/sing/common/exceptions" + + "golang.org/x/sys/windows" +) + +// SIO_ACQUIRE_PORT_RESERVATION = _WSAIOW(IOC_VENDOR, 100): +// IOC_IN | IOC_VENDOR | 100. Despite the write-only direction code, the +// reservation result is written to the WSAIoctl output buffer; using +// _WSAIORW instead is rejected with WSAEOPNOTSUPP. +const sioAcquirePortReservation uint32 = 0x80000000 | 0x18000000 | 100 + +// portReservation holds a runtime port block acquired from the host TCP/IP +// stack. Runtime reservation records are protocol- and family-agnostic: +// one reservation excludes the block from ephemeral auto-assignment for +// TCP and UDP sockets of both address families (and a specific reservation +// request for numbers covered by any existing record fails with +// WSAEADDRINUSE, whatever its protocol). Explicit binds inside the block +// are rejected for the reserving protocol but still allowed for others. +// Closing the socket releases the reservation. +type portReservation struct { + socket windows.Handle + startPort uint16 +} + +func acquirePortReservation(family, socketType, protocol int, count uint16) (*portReservation, error) { + socket, err := windows.Socket(family, socketType, protocol) + if err != nil { + return nil, E.Cause(err, "create reservation socket") + } + // INET_PORT_RANGE { USHORT StartPort; USHORT NumberOfPorts; }. + // StartPort 0 requests a runtime (wildcard) reservation. + var in [4]byte + binary.LittleEndian.PutUint16(in[0:2], 0) + binary.LittleEndian.PutUint16(in[2:4], count) + // INET_PORT_RESERVATION_INSTANCE { + // INET_PORT_RESERVATION { USHORT StartPort; USHORT NumberOfPorts; }; + // INET_PORT_RESERVATION_TOKEN { ULONG64 Token; }; + // } — the ULONG64 forces 8-byte alignment, so Token sits at offset 8. + var out [16]byte + var returned uint32 + err = windows.WSAIoctl(socket, sioAcquirePortReservation, + &in[0], uint32(len(in)), &out[0], uint32(len(out)), &returned, nil, 0) + if err != nil { + windows.Closesocket(socket) + return nil, E.Cause(err, "acquire port reservation") + } + // StartPort is returned in network byte order (as documented for + // INET_PORT_RANGE); NumberOfPorts is a plain host-order count. + startPort := binary.BigEndian.Uint16(out[0:2]) + reservedCount := binary.LittleEndian.Uint16(out[2:4]) + if startPort == 0 || reservedCount < count { + windows.Closesocket(socket) + return nil, E.New("acquire port reservation: stack returned ", reservedCount, " of ", count, " ports") + } + return &portReservation{ + socket: socket, + startPort: startPort, + }, nil +} + +func (r *portReservation) Close() { + if r == nil { + return + } + windows.Closesocket(r.socket) +} diff --git a/test/go.mod b/test/go.mod index 7d6d9edcf..e141e9aac 100644 --- a/test/go.mod +++ b/test/go.mod @@ -10,15 +10,15 @@ require ( github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/gofrs/uuid/v5 v5.4.0 - github.com/sagernet/quic-go v0.59.0-sing-box-mod.2 - github.com/sagernet/sing v0.8.0-beta.16 - github.com/sagernet/sing-quic v0.6.0-beta.11 + github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 + github.com/sagernet/sing v0.8.12-0.20260702081104-2ded2af32d3d + github.com/sagernet/sing-quic v0.6.2-0.20260525051024-9467ede27fb7 github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/spyzhov/ajson v0.9.4 github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 - golang.org/x/net v0.48.0 + golang.org/x/net v0.50.0 ) require ( @@ -28,35 +28,40 @@ require ( github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/andybalholm/brotli v1.1.0 // indirect - github.com/anthropics/anthropic-sdk-go v1.19.0 // indirect + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect + github.com/anthropics/anthropic-sdk-go v1.26.0 // indirect github.com/anytls/sing-anytls v0.0.11 // indirect - github.com/caddyserver/certmagic v0.25.0 // indirect - github.com/caddyserver/zerossl v0.1.3 // indirect + github.com/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6 // indirect + github.com/caddyserver/zerossl v0.1.5 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coder/websocket v1.8.14 // indirect github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect + github.com/coreos/go-oidc/v3 v3.17.0 // indirect + github.com/creack/pty v1.1.24 // indirect github.com/cretz/bine v0.2.0 // indirect github.com/database64128/netx-go v0.1.1 // indirect - github.com/database64128/tfo-go/v2 v2.3.1 // indirect + github.com/database64128/tfo-go/v2 v2.3.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/ebitengine/purego v0.9.1 // indirect + github.com/ebitengine/purego v0.10.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/florianl/go-nfqueue/v2 v2.0.2 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gaissmai/bart v0.18.0 // indirect - github.com/go-chi/chi/v5 v5.2.3 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/go-chi/render v1.0.3 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect - github.com/godbus/dbus/v5 v5.2.1 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.3 // indirect @@ -65,72 +70,85 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect - github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 // indirect + github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 // indirect github.com/jsimonetti/rtnetlink v1.4.0 // indirect github.com/keybase/go-keychain v0.0.1 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/kr/fs v0.1.0 // indirect github.com/libdns/acmedns v0.5.0 // indirect - github.com/libdns/alidns v1.0.6-beta.3 // indirect + github.com/libdns/alidns v1.0.6 // indirect github.com/libdns/cloudflare v0.2.2 // indirect github.com/libdns/libdns v1.1.1 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect + github.com/mdlayher/netlink v1.9.0 // indirect github.com/mdlayher/socket v0.5.1 // indirect github.com/metacubex/utls v1.8.4 // indirect - github.com/mholt/acmez/v3 v3.1.4 // indirect - github.com/miekg/dns v1.1.69 // indirect + github.com/mholt/acmez/v3 v3.1.6 // indirect + github.com/miekg/dns v1.1.72 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/openai/openai-go/v3 v3.15.0 // indirect + github.com/openai/openai-go/v3 v3.26.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pires/go-proxyproto v0.8.1 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/sftp v1.13.10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/cors v1.2.1 // indirect - github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287 // indirect - github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287 // indirect - github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f // indirect - github.com/sagernet/fswatch v0.1.1 // indirect + github.com/sagernet/cronet-go v0.0.0-20260620140045-05ab0dc17597 // indirect + github.com/sagernet/cronet-go/all v0.0.0-20260620140045-05ab0dc17597 // indirect + github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect + github.com/sagernet/fswatch v0.1.2 // indirect + github.com/sagernet/gliderssh v0.3.4-0.20260531100337-2194faca5648 // indirect github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect - github.com/sagernet/nftables v0.3.0-beta.4 // indirect - github.com/sagernet/sing-mux v0.3.4 // indirect - github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect - github.com/sagernet/sing-tun v0.8.0-beta.17 // indirect + github.com/sagernet/nftables v0.3.0-mod.3 // indirect + github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 // indirect + github.com/sagernet/sing-mux v0.3.5 // indirect + github.com/sagernet/sing-shadowtls v0.2.1 // indirect + github.com/sagernet/sing-snell v0.0.0-20260705044717-4e9e73be7814 // indirect + github.com/sagernet/sing-tun v0.8.12-0.20260708091449-be1a05a4c962 // indirect + github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb // indirect github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 // indirect github.com/sagernet/smux v1.5.50-sing-box-mod.1 // indirect - github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6 // indirect - github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 // indirect + github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7.0.20260706062137-ae2dde1295a3 // indirect + github.com/sagernet/wireguard-go v0.0.5-0.20260706153856-2c27bbf4f97f // indirect github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect @@ -149,31 +167,32 @@ require ( github.com/zeebo/blake3 v0.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.uber.org/zap/exp v0.3.0 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.46.0 // indirect + golang.org/x/crypto v0.48.0 // indirect golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect - golang.org/x/mod v0.31.0 // indirect - golang.org/x/oauth2 v0.32.0 // indirect + golang.org/x/mod v0.33.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/term v0.38.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect + golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.40.0 // indirect + golang.org/x/tools v0.42.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect - google.golang.org/grpc v1.77.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/grpc v1.79.1 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect + zombiezen.com/go/capnproto2 v2.18.2+incompatible // indirect ) diff --git a/test/go.sum b/test/go.sum index 34f8d9970..0b49c32c4 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,3 +1,5 @@ +code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE= +code.pfad.fr/check v1.1.0/go.mod h1:NiUH13DtYsb7xp5wll0U4SXx7KhXQVCtRgdC96IPfoM= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= @@ -12,16 +14,20 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/anthropics/anthropic-sdk-go v1.19.0 h1:mO6E+ffSzLRvR/YUH9KJC0uGw0uV8GjISIuzem//3KE= -github.com/anthropics/anthropic-sdk-go v1.19.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/anthropics/anthropic-sdk-go v1.26.0 h1:oUTzFaUpAevfuELAP1sjL6CQJ9HHAfT7CoSYSac11PY= +github.com/anthropics/anthropic-sdk-go v1.26.0/go.mod h1:qUKmaW+uuPB64iy1l+4kOSvaLqPXnHTTBKH6RVZ7q5Q= github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc= github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= -github.com/caddyserver/certmagic v0.25.0 h1:VMleO/XA48gEWes5l+Fh6tRWo9bHkhwAEhx63i+F5ic= -github.com/caddyserver/certmagic v0.25.0/go.mod h1:m9yB7Mud24OQbPHOiipAoyKPn9pKHhpSJxXR1jydBxA= -github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= -github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= +github.com/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6 h1:LYSB6VgWzKtNrcxElw3c97BP40Oc7bizKxA9K1Vi/5k= +github.com/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6/go.mod h1:llW/CvsNmza8S6hmsuggsZeiX+uS27dkqY27wDIuBWg= +github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE= +github.com/caddyserver/zerossl v0.1.5/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= @@ -30,12 +36,16 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= +github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/database64128/netx-go v0.1.1 h1:dT5LG7Gs7zFZBthFBbzWE6K8wAHjSNAaK7wCYZT7NzM= github.com/database64128/netx-go v0.1.1/go.mod h1:LNlYVipaYkQArRFDNNJ02VkNV+My9A5XR/IGS7sIBQc= -github.com/database64128/tfo-go/v2 v2.3.1 h1:EGE+ELd5/AQ0X6YBlQ9RgKs8+kciNhgN3d8lRvfEJQw= -github.com/database64128/tfo-go/v2 v2.3.1/go.mod h1:k9wcpg/8i5zenspBkc9jUEYehpZZccBnCElzOJB++bU= +github.com/database64128/tfo-go/v2 v2.3.2 h1:UhZMKiMq3swZGUiETkLBDzQnZBPSAeBMClpJGlnJ5Fw= +github.com/database64128/tfo-go/v2 v2.3.2/go.mod h1:GC3uB5oa4beGpCUbRb2ZOWP73bJJFmMyAVgQSO7r724= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -43,30 +53,34 @@ github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbww github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= -github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/florianl/go-nfqueue/v2 v2.0.2 h1:FL5lQTeetgpCvac1TRwSfgaXUn0YSO7WzGvWNIp3JPE= github.com/florianl/go-nfqueue/v2 v2.0.2/go.mod h1:VA09+iPOT43OMoCKNfXHyzujQUty2xmzyCRkBOlmabc= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= -github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= -github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -80,8 +94,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/godbus/dbus/v5 v5.2.1 h1:I4wwMdWSkmI57ewd+elNGwLRf2/dtSaFz1DujfWYvOk= -github.com/godbus/dbus/v5 v5.2.1/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0= github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -104,8 +118,8 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8 github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= -github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 h1:MEufgJohwIjFi2n3eJv4c/8UdRLQVUwPwSWQPoER+eU= -github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo= +github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 h1:u9i04mGE3iliBh0EFuWaKsmcwrLacqGmq1G3XoaM7gY= +github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo= github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I= github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= @@ -116,30 +130,38 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU= +github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk= +github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U= +github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ= github.com/libdns/acmedns v0.5.0 h1:5pRtmUj4Lb/QkNJSl1xgOGBUJTWW7RjpNaIhjpDXjPE= github.com/libdns/acmedns v0.5.0/go.mod h1:X7UAFP1Ep9NpTwWpVlrZzJLR7epynAy0wrIxSPFgKjQ= -github.com/libdns/alidns v1.0.6-beta.3 h1:KAmb7FQ1tRzKsaAUGa7ZpGKAMRANwg7+1c7tUbSELq8= -github.com/libdns/alidns v1.0.6-beta.3/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec= +github.com/libdns/alidns v1.0.6 h1:/Ii428ty6WHFJmE24rZxq2taq++gh7rf9jhgLfp8PmM= +github.com/libdns/alidns v1.0.6/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec= github.com/libdns/cloudflare v0.2.2 h1:XWHv+C1dDcApqazlh08Q6pjytYLgR2a+Y3xrXFu0vsI= github.com/libdns/cloudflare v0.2.2/go.mod h1:w9uTmRCDlAoafAsTPnn2nJ0XHK/eaUMh86DUk8BWi60= github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg= -github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o= +github.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKco= +github.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg= github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= -github.com/mholt/acmez/v3 v3.1.4 h1:DyzZe/RnAzT3rpZj/2Ii5xZpiEvvYk3cQEN/RmqxwFQ= -github.com/mholt/acmez/v3 v3.1.4/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= -github.com/miekg/dns v1.1.69 h1:Kb7Y/1Jo+SG+a2GtfoFUfDkG//csdRPwRLkCsxDG9Sc= -github.com/miekg/dns v1.1.69/go.mod h1:7OyjD9nEba5OkqQ/hB4fy3PIoxafSZJtducccIelz3g= +github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk= +github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -150,18 +172,22 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/openai/openai-go/v3 v3.15.0 h1:hk99rM7YPz+M99/5B/zOQcVwFRLLMdprVGx1vaZ8XMo= -github.com/openai/openai-go/v3 v3.15.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= +github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE= +github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0= github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.10 h1:+5FbKNTe5Z9aspU88DPIKJ9z2KZoaGCu6Sr6kKR/5mU= +github.com/pkg/sftp v1.13.10/go.mod h1:bJ1a7uDhrX/4OII+agvy28lzRvQrmIQuaHrcI1HbeGA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -177,86 +203,108 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= -github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287 h1:0BYNmr0ptjsII948U0oBFmrbo4qEaCFcrE2JPRg3Zlk= -github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw= -github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287 h1:ghxhYSBQpzkakqWqJDvXr/Zmxe0WjTjKuALEGbjGiGY= -github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287/go.mod h1:M+4ZjPhLJXIvoxcQsbDofmc19Wrig59hZ+hLvj6S3To= -github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f h1:8jZbZ4KBTdcXDFLwUBNQt5Xci6ZuAKh255S8TwuBCaM= -github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw= -github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f h1:tG0hCx+0u5zca7qQ7AMkcv4DCrBG/DKW1ggs/P+BRRI= -github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM= -github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f h1:ZXp5hKJIA7iJ52ZShJCKMQEPLpp/7dDIVZmPGV9Il40= -github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc= -github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f h1:gL7H8HS8s38adz4/HZtRHh79qMwsbLTRRPz4GQ9LcWI= -github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ= -github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f h1:Dchgc0pAY5Jwb5lzUlE+1nhHIzqLx+YOurXLHgvWd/0= -github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs= -github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f h1:+MOLSQoduuKDxF410i1LcSPaQGaiP0eZb0INvMlmjM4= -github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0= -github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f h1:lIZna05Vn6n8k21p8OpSUnhwGm+E57PrMjiI4ZUfMSg= -github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0= -github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f h1:B2aFQ5CRHI20t8YsEizvtguS5W2QfK7D5XV/NzTIxPE= -github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4= -github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f h1:qpSwJ1rFGYCfJDenNCZoWYjoG7N+xEa6ke+E7/JO1i4= -github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo= -github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f h1:cx7Ipg0tSvTDjS4maMEYz4vuzz93BMPAysmZ1YLrz80= -github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ= -github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f h1:4jOHuUiBxD8pJEpBBVQfJqyLmxjpd3t4MLRzU7YLFyg= -github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU= -github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f h1:OpXBa2WlRU+Mam9oRe9Nn4/zf7gQ+qiBTNK8A5RwbfQ= -github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI= -github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f h1:nJpGFi+6hI85tl4zoyNFEnFEQ5+xEV5gyvsUoMvd8g0= -github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ= -github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f h1:SEy2rpmgOJgrqcEryJI/RSnqUWIsEsp0cfYoA8y21jc= -github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0= -github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f h1:EW2TuFMLm0iBGqRZtuGwIZdeYmDtDsDmRcRRJQOMxUo= -github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s= -github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f h1:3U5woxrNCkzfv1+UX+mVoWh1228AE1qAiMG02F9oFbY= -github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ= -github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f h1:YwFTfuWG3mmctroeDYtFZ6LHjGsedVO+5wInYbbUuUY= -github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow= -github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f h1:r4V0ddPCRLgGu0VdgR3aUsO9NjpmyjAf+h+3oTD9D6E= -github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4= -github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f h1:B8yf4gFvEYUnwWmtVK9sdwUsflYZ387MhYmlOP2ohFQ= -github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc= -github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f h1:9YyaMg4rO1/jIgrxmNb0LKH+X7frSYWfX2pFgW5JUVM= -github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc= -github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f h1:B0fnGu0sh9yT/9JDN5u/GqThGoOzNN/daOAuGWFLXEk= -github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8= -github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f h1:lxPcIXKSSI5JDhc7rx/6yufISWM4vtBS2FY9PavWQTs= -github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw= -github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= -github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= +github.com/sagernet/cronet-go v0.0.0-20260620140045-05ab0dc17597 h1:QkwE/ZFnShDuPF+ExmAyZlQaMwFNgkYZMekrabiStfg= +github.com/sagernet/cronet-go v0.0.0-20260620140045-05ab0dc17597/go.mod h1:T/mwtrpC4JlWfScw73CmSBvHzIvc7BatQ1MhRr+cYNw= +github.com/sagernet/cronet-go/all v0.0.0-20260620140045-05ab0dc17597 h1:cLALmGKP9eOS8622gWQIiVbZlOfH29PGNsoxbEloIdk= +github.com/sagernet/cronet-go/all v0.0.0-20260620140045-05ab0dc17597/go.mod h1:zVHZ5tgDTwbNvUGffAgLmouYs4in0grEzhSdaggoZOw= +github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260620135226-def9ff0fb992 h1:J9l8PP4vb79Wm5zKaMO6LNZ/AiP1FvyAWJBlkKHrRBU= +github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw= +github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:wXDjUNeKuihv85Kg51FomkiEH7xGsDgRcfRLiyZxacQ= +github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM= +github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260620135226-def9ff0fb992 h1:IF04nGyY3Q6Nbk9XJwTX1mckwhf12iIx4RhZ4TLOZIU= +github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260620135226-def9ff0fb992/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc= +github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:dlnG1E42xx8ms2fyZigYwsYJ1Gqoj2QT8WeGlpOAWK8= +github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ= +github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:aYAQQN3jZP89MmT1ZzpJz52jAsXx1WApmv5Qidc+ez4= +github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs= +github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:n81+aLphvjLpL2M6lI+BC8Ldw4S/FPA3CFDXTWL4g3I= +github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0= +github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:mOseesF+CxgPG2U1a2Yh2fUUMdOaPxSuk4eIL6g7EU8= +github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0= +github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:JK9kP72IxAoyVQTnh9gGkh8S9RjP4FBkj95WjrLPyKs= +github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4= +github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:3EtgLRsUpmeRaOBynTARxVC8tDegykigutmpAow2ayc= +github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo= +github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260620135226-def9ff0fb992 h1:Vr3I2sC9E/1FurpZwJXAL29C7jJROyN3JfulQWjhKuA= +github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ= +github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260620135226-def9ff0fb992 h1:flxwC8loz0C4LQ/tLK7LvNMKx4iqaXayPggzzCxCevI= +github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU= +github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:G4vwPmOVR/jXDngIUC9owbEtMKXLZl/BgUHhEWWl8ec= +github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI= +github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260620135226-def9ff0fb992 h1:zHIxR2FlJOW5GRmgwyA2Gjgx7potOCtlOmdl8k4mwJI= +github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ= +github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260620135226-def9ff0fb992 h1:U1OrR5zP+lkOPqrDpZsn8sPK1XBWZ84isXaFBZLsOfs= +github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260620135226-def9ff0fb992/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0= +github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:F59ptY4AdtKEg73OWaL+lTb5yoxp5b/gTuDbvA6xMyg= +github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s= +github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260620135226-def9ff0fb992 h1:Y5axK4sCWXH+2OCpKYPI8nX3OSBuRb/6yC+5xBi9/uo= +github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ= +github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260620135226-def9ff0fb992 h1:QCBwCdv9y+RJj7p0b9Db2p9fFt1wtnawD0sn9oV3vRs= +github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow= +github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260620135226-def9ff0fb992 h1:6gXFFaAMiGCPZdfUs64qzj9cl7EleVs9HsNfRi8jWWw= +github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk= +github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260620135226-def9ff0fb992 h1:VGoIX2u4CWVg9kiyjQdIpFMaFUNCW3yz0pyrEKI5X0o= +github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E= +github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260620135226-def9ff0fb992 h1:SjPuqtUNCzIDaEm7iY86JZ7L+ixTmai4i2DIC++eUvw= +github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260620135226-def9ff0fb992/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8= +github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260620135226-def9ff0fb992 h1:ao2FrDzTYhu2MYsMri9nzqIdnAL7ooUWQN6/FFr+Lbk= +github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260620135226-def9ff0fb992/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w= +github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260620135226-def9ff0fb992 h1:5gPMu6EUlX6gqCRTOJrJk1FMILO6ugtnopQF1c2R/lY= +github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0= +github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260620135226-def9ff0fb992 h1:UaLOQKbjnLrO943Sm+ff/jm+NmemRuJXiImmtqShd8s= +github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs= +github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260620135226-def9ff0fb992 h1:wxlsDfxDowVk99Ay2hzfuIXPpXH1lGQxSL/2sX/D7jw= +github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc= +github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:pgRpWh2JPE73mtedovPPu3gmmAqHz3Rfz79QVxciu2o= +github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4= +github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:9jtXyxukTS2ZdhMy3u1hg4StkZpgP48BOfgYhXf835w= +github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc= +github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:gKgD1LJZbZzacaaqBQX/YKy4dyomhn8xtfmDKayVLW4= +github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc= +github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:Lv8gtKP4QRn6Yjv3h5L215aGQBgwCyAE5YqejmN9Bqc= +github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8= +github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:2wsRAcqJHOTlj6zGc3oQyxAZHDnGwyB/pTdAOUtLgHY= +github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw= +github.com/sagernet/fswatch v0.1.2 h1:/TT7k4mkce1qFPxamLO842WjqBgbTBiXP2mlUjp9PFk= +github.com/sagernet/fswatch v0.1.2/go.mod h1:5BpGmpUQVd3Mc5r313HRpvADHRg3/rKn5QbwFteB880= +github.com/sagernet/gliderssh v0.3.4-0.20260531100337-2194faca5648 h1:IWVjKBARzVjdmH0VUaeTBOBli1qkwKmTG4XfbkpSS20= +github.com/sagernet/gliderssh v0.3.4-0.20260531100337-2194faca5648/go.mod h1:FmW0l0t/PzGIdJMr3iXOL+KuxvJTt6XAfF4GxbMlfZc= github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 h1:SUPFNB+vSP4RBPrSEgNII+HkfqC8hKMpYLodom4o4EU= github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237/go.mod h1:QkkPEJLw59/tfxgapHta14UL5qMUah5NXhO0Kw2Kan4= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= -github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= -github.com/sagernet/quic-go v0.59.0-sing-box-mod.2 h1:hJUL+HtxEOjxsa0CsucbBVqI/AMS4k52NwNU637zmdw= -github.com/sagernet/quic-go v0.59.0-sing-box-mod.2/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= -github.com/sagernet/sing v0.8.0-beta.16 h1:Fe+6E9VHYky9Mx4cf0ugbZPWDcXRflpAu7JQ5bWXvaA= -github.com/sagernet/sing v0.8.0-beta.16/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= -github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= -github.com/sagernet/sing-quic v0.6.0-beta.11 h1:eUusxITKKRedhWC2ScUYFUvD96h/QfbKLaS3N6/7in4= -github.com/sagernet/sing-quic v0.6.0-beta.11/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8= +github.com/sagernet/nftables v0.3.0-mod.3 h1:CVfbVTd3Z/LQVc1Z3c1hpiriplJ4xDVHjfQCETiN9RA= +github.com/sagernet/nftables v0.3.0-mod.3/go.mod h1:8kslHG4VvYNihcco+i6uxIX7qbT8A56T0y5q7U44ZaQ= +github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o= +github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= +github.com/sagernet/sing v0.8.12-0.20260702081104-2ded2af32d3d h1:BhsQU0Iug1tU4xR52cjm8Sc+LBo+KwdyLTRn3ie9moo= +github.com/sagernet/sing v0.8.12-0.20260702081104-2ded2af32d3d/go.mod h1:olXxWQNqRW/l2Q6JI3b2Qmz8iQnIFlOeeH8bx6JhgUA= +github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 h1:3y6++yIa8XlDhxPkpR4p+7RUHVY2KTP9CPIGnWmOlO8= +github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg= +github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI= +github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= +github.com/sagernet/sing-quic v0.6.2-0.20260525051024-9467ede27fb7 h1:hFLPJ21uNZSbRnzhOKz4Zv0b4F93mpDorWyN93BeRcM= +github.com/sagernet/sing-quic v0.6.2-0.20260525051024-9467ede27fb7/go.mod h1:+oqD54aHel4ALKkp1hVXWCgLU/EjLojvm6AUzDfvj0I= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= -github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= -github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= -github.com/sagernet/sing-tun v0.8.0-beta.17 h1:6DdbNXeTFYj8Tb4FCh8Mp2boA3rVY6VNqzTOObj7Xis= -github.com/sagernet/sing-tun v0.8.0-beta.17/go.mod h1:+HAK/y9GZljdT0KYKMYDR8MjjqnqDDQZYp5ZZQoRzS8= +github.com/sagernet/sing-shadowtls v0.2.1 h1:ZiHZdnEnP+YS73NMsxiZmIFCwNd0M4k7PkGCKNXhbaM= +github.com/sagernet/sing-shadowtls v0.2.1/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= +github.com/sagernet/sing-snell v0.0.0-20260705044717-4e9e73be7814 h1:xfnkRpjVRVeJhVvDZA8PzTLlKGTb1o2kdI4uv1YymXo= +github.com/sagernet/sing-snell v0.0.0-20260705044717-4e9e73be7814/go.mod h1:PcwzX/Xvqky0EP3kGt8OCjYb3R1pydenPHNQZcPZmXY= +github.com/sagernet/sing-tun v0.8.12-0.20260708091449-be1a05a4c962 h1:dmJoWdTQygt4P2rAwScy2IvHnFp1mKrW6OsI0qig6O8= +github.com/sagernet/sing-tun v0.8.12-0.20260708091449-be1a05a4c962/go.mod h1:QvarqUtHfj1ULaRR+6kZOS/OoCE+pYGq67A5tyIy+dQ= +github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb h1:KEMbfexD4DvrQGYWwx6r+AwH9Veh8z6cnBZmtCS2G+0= +github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb/go.mod h1:D4CnJX3MNAAANhbQUxfIRgBdnvlTEaV7h6ojedcs+pw= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY= github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478= github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8= -github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6 h1:eYz/OpMqWCvO2++iw3dEuzrlfC2xv78GdlGvprIM6O8= -github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc= -github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 h1:E2tZFeg9mGYGQ7E7BbxMv1cU35HxwgRm6tPKI2Pp7DA= -github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0= +github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7.0.20260706062137-ae2dde1295a3 h1:eczvica8YiS5j3GfpHg6JG1Icur4Z2D6ffSrLZTfD1E= +github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7.0.20260706062137-ae2dde1295a3/go.mod h1:p8Ms8FbGlwQJyHb862XmdShTS50fFJ8C71VdO6xvWyk= +github.com/sagernet/wireguard-go v0.0.5-0.20260706153856-2c27bbf4f97f h1:TzN97RL07xWb3gZtmqFhsdkud4f6G/pohiaOLiqSBj4= +github.com/sagernet/wireguard-go v0.0.5-0.20260706153856-2c27bbf4f97f/go.mod h1:hEqi4y5czEg6LYtX2Bpjg+lV0b/J1n+5rA885Z66Mx0= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -293,6 +341,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= +github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= @@ -312,20 +362,20 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -344,26 +394,26 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= -golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= -golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -379,24 +429,24 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -407,17 +457,19 @@ golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= -google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= +google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -427,3 +479,5 @@ lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= +zombiezen.com/go/capnproto2 v2.18.2+incompatible h1:v3BD1zbruvffn7zjJUU5Pn8nZAB11bhZSQC4W+YnnKo= +zombiezen.com/go/capnproto2 v2.18.2+incompatible/go.mod h1:XO5Pr2SbXgqZwn0m0Ru54QBqpOf4K5AYBO+8LAOBQEQ=