diff --git a/adapter/outbound/mitm.go b/adapter/outbound/mitm.go index 4532b6b6..53b99ff7 100644 --- a/adapter/outbound/mitm.go +++ b/adapter/outbound/mitm.go @@ -33,7 +33,7 @@ func (m *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...diale metadata.Type = C.MITM - c, err := dialer.DialContext(ctx, "tcp", m.serverAddr, []dialer.Option{dialer.WithInterface(""), dialer.WithRoutingMark(0)}...) + c, err := dialer.DialContext(ctx, "tcp", m.serverAddr, []dialer.Option{dialer.WithInterface(""), dialer.WithRoutingMark(0), dialer.WithDirect()}...) if err != nil { return nil, err } diff --git a/constant/metadata.go b/constant/metadata.go index df08f377..2e5332bb 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -88,11 +88,7 @@ type Metadata struct { } func (m *Metadata) RemoteAddress() string { - if m.DstIP.IsValid() { - return net.JoinHostPort(m.DstIP.String(), m.DstPort) - } else { - return net.JoinHostPort(m.String(), m.DstPort) - } + return net.JoinHostPort(m.String(), m.DstPort) } func (m *Metadata) SourceAddress() string { diff --git a/listener/mitm/client.go b/listener/mitm/client.go index a9ef56d1..b20d8586 100644 --- a/listener/mitm/client.go +++ b/listener/mitm/client.go @@ -48,5 +48,6 @@ func newClient(source net.Addr, userAgent string, in chan<- C.ConnContext) *http CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, + Timeout: 120 * time.Second, } } diff --git a/listener/mitm/proxy.go b/listener/mitm/proxy.go index d24de227..98323e9a 100644 --- a/listener/mitm/proxy.go +++ b/listener/mitm/proxy.go @@ -32,10 +32,6 @@ func HandleConn(c net.Conn, opt *Option, in chan<- C.ConnContext, cache *cache.C }() startOver: - if tcpConn, ok := c.(*net.TCPConn); ok { - _ = tcpConn.SetKeepAlive(true) - } - var conn *N.BufferedConn if bufConn, ok := c.(*N.BufferedConn); ok { conn = bufConn @@ -47,8 +43,8 @@ startOver: readLoop: for { - // use SetDeadline instead of Proxy-Connection keep-alive - if err := conn.SetDeadline(time.Now().Add(30 * time.Second)); err != nil { + // use SetReadDeadline instead of Proxy-Connection keep-alive + if err := conn.SetReadDeadline(time.Now().Add(95 * time.Second)); err != nil { break readLoop } @@ -190,7 +186,7 @@ func writeResponse(session *Session, keepAlive bool) error { if keepAlive { session.response.Header.Set("Connection", "keep-alive") - session.response.Header.Set("Keep-Alive", "timeout=25") + session.response.Header.Set("Keep-Alive", "timeout=90") } return session.writeResponse() diff --git a/listener/tun/ipstack/gvisor/handler.go b/listener/tun/ipstack/gvisor/handler.go index d7bdb189..9560937c 100644 --- a/listener/tun/ipstack/gvisor/handler.go +++ b/listener/tun/ipstack/gvisor/handler.go @@ -16,16 +16,17 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -var _ adapter.Handler = (*GVHandler)(nil) +var _ adapter.Handler = (*gvHandler)(nil) -type GVHandler struct { - DNSAdds []netip.AddrPort +type gvHandler struct { + gateway netip.Addr + dnsHijack []netip.AddrPort - TCPIn chan<- C.ConnContext - UDPIn chan<- *inbound.PacketAdapter + tcpIn chan<- C.ConnContext + udpIn chan<- *inbound.PacketAdapter } -func (gh *GVHandler) HandleTCP(tunConn adapter.TCPConn) { +func (gh *gvHandler) HandleTCP(tunConn adapter.TCPConn) { id := tunConn.ID() rAddr := &net.UDPAddr{ @@ -34,11 +35,11 @@ func (gh *GVHandler) HandleTCP(tunConn adapter.TCPConn) { Zone: "", } - addrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort) + rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort) - if D.ShouldHijackDns(gh.DNSAdds, addrPort) { + if D.ShouldHijackDns(gh.dnsHijack, rAddrPort) { go func() { - log.Debugln("[TUN] hijack dns tcp: %s", addrPort.String()) + log.Debugln("[TUN] hijack dns tcp: %s", rAddrPort.String()) buf := pool.Get(pool.UDPBufferSize) defer func() { @@ -77,10 +78,10 @@ func (gh *GVHandler) HandleTCP(tunConn adapter.TCPConn) { return } - gh.TCPIn <- inbound.NewSocket(socks5.ParseAddrToSocksAddr(rAddr), tunConn, C.TUN) + gh.tcpIn <- inbound.NewSocket(socks5.ParseAddrToSocksAddr(rAddr), tunConn, C.TUN) } -func (gh *GVHandler) HandleUDP(tunConn adapter.UDPConn) { +func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) { id := tunConn.ID() rAddr := &net.UDPAddr{ @@ -89,7 +90,13 @@ func (gh *GVHandler) HandleUDP(tunConn adapter.UDPConn) { Zone: "", } - addrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort) + rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort) + + if rAddrPort.Addr() == gh.gateway { + _ = tunConn.Close() + return + } + target := socks5.ParseAddrToSocksAddr(rAddr) go func() { @@ -104,7 +111,7 @@ func (gh *GVHandler) HandleUDP(tunConn adapter.UDPConn) { payload := buf[:n] - if D.ShouldHijackDns(gh.DNSAdds, addrPort) { + if D.ShouldHijackDns(gh.dnsHijack, rAddrPort) { go func() { defer func() { _ = pool.Put(buf) @@ -130,7 +137,7 @@ func (gh *GVHandler) HandleUDP(tunConn adapter.UDPConn) { } select { - case gh.UDPIn <- inbound.NewPacket(target, gvPacket, C.TUN): + case gh.udpIn <- inbound.NewPacket(target, gvPacket, C.TUN): default: } } diff --git a/listener/tun/ipstack/gvisor/stack.go b/listener/tun/ipstack/gvisor/stack.go index c762e6a2..1307bc71 100644 --- a/listener/tun/ipstack/gvisor/stack.go +++ b/listener/tun/ipstack/gvisor/stack.go @@ -2,9 +2,12 @@ package gvisor import ( + "net/netip" + + "github.com/Dreamacro/clash/adapter/inbound" + C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/ipstack" - "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/adapter" "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option" "gvisor.dev/gvisor/pkg/tcpip" @@ -34,7 +37,7 @@ func (s *gvStack) Close() error { } // New allocates a new *gvStack with given options. -func New(device device.Device, handler adapter.Handler, opts ...option.Option) (ipstack.Stack, error) { +func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter, opts ...option.Option) (ipstack.Stack, error) { s := &gvStack{ Stack: stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocolFactory{ @@ -52,6 +55,13 @@ func New(device device.Device, handler adapter.Handler, opts ...option.Option) ( device: device, } + handler := &gvHandler{ + gateway: tunAddress.Masked().Addr().Next(), + dnsHijack: dnsHijack, + tcpIn: tcpIn, + udpIn: udpIn, + } + // Generate unique NIC id. nicID := tcpip.NICID(s.Stack.UniqueID()) diff --git a/listener/tun/ipstack/system/stack.go b/listener/tun/ipstack/system/stack.go index 16fd37d0..92751d36 100644 --- a/listener/tun/ipstack/system/stack.go +++ b/listener/tun/ipstack/system/stack.go @@ -169,7 +169,7 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port)) - if rAddrPort.Addr().IsLoopback() { + if rAddrPort.Addr().IsLoopback() || rAddrPort.Addr() == gateway { _ = pool.Put(buf) continue diff --git a/listener/tun/tun_adapter.go b/listener/tun/tun_adapter.go index fd02cb9c..7461a492 100644 --- a/listener/tun/tun_adapter.go +++ b/listener/tun/tun_adapter.go @@ -67,13 +67,7 @@ func New(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan<- C.Con return nil, fmt.Errorf("can't attach endpoint to tun: %w", err) } - tunStack, err = gvisor.New(tunDevice, - &gvisor.GVHandler{ - DNSAdds: tunConf.DNSHijack, - TCPIn: tcpIn, UDPIn: udpIn, - }, - option.WithDefault(), - ) + tunStack, err = gvisor.New(tunDevice, tunConf.DNSHijack, tunAddress, tcpIn, udpIn, option.WithDefault()) if err != nil { _ = tunDevice.Close() diff --git a/rule/user_gent.go b/rule/user_agent.go similarity index 100% rename from rule/user_gent.go rename to rule/user_agent.go