diff --git a/go.mod b/go.mod index e3658e7..a2d596d 100644 --- a/go.mod +++ b/go.mod @@ -15,8 +15,8 @@ require ( github.com/xjasonlyu/clash v0.15.1-0.20201105074459-aa45c8b56cf6 go.uber.org/atomic v1.7.0 golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect - golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 // indirect + golang.org/x/sys v0.0.0-20201106081118-db71ae66460a // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect - gvisor.dev/gvisor v0.0.0-20201105065002-ab9a79fe812a + gvisor.dev/gvisor v0.0.0-20201107070040-22fc22ad6ef7 ) diff --git a/go.sum b/go.sum index 23a6c2f..5e1e9fc 100644 --- a/go.sum +++ b/go.sum @@ -336,8 +336,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM= golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201106081118-db71ae66460a h1:ALUFBKlIyeY7y5ZgPJmblk/vKz+zBQSnNiPkt41sgeg= +golang.org/x/sys v0.0.0-20201106081118-db71ae66460a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -432,8 +432,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gvisor.dev/gvisor v0.0.0-20201105065002-ab9a79fe812a h1:io3nR9e7V26iORClxbTxnrNBhxAvdvgMKU8E+at6idc= -gvisor.dev/gvisor v0.0.0-20201105065002-ab9a79fe812a/go.mod h1:t4GUXJhnQEPtYSvrvRNW5CNdBQ2oWZBy7P+FbCVKBFY= +gvisor.dev/gvisor v0.0.0-20201107070040-22fc22ad6ef7 h1:JKZNg4wnh94dWyhXSNOQ4jkliNbcRJt1Vs5NPyMOo48= +gvisor.dev/gvisor v0.0.0-20201107070040-22fc22ad6ef7/go.mod h1:t4GUXJhnQEPtYSvrvRNW5CNdBQ2oWZBy7P+FbCVKBFY= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/core/stack.go b/internal/core/stack.go index f92098a..e60faf0 100644 --- a/internal/core/stack.go +++ b/internal/core/stack.go @@ -77,6 +77,17 @@ func NewDefaultStack(linkEp stack.LinkEndpoint, th tcpHandleFunc, uh udpHandleFu // Ref: https://github.com/majek/slirpnetstack/blob/master/stack.go WithPromiscuousMode(defaultNICID, nicPromiscuousModeEnabled), + // Enable spoofing if a stack may send packets from unowned addresses. + // This change required changes to some netgophers since previously, + // promiscuous mode was enough to let the netstack respond to all + // incoming packets regardless of the packet's destination address. Now + // that a stack.Route is not held for each incoming packet, finding a route + // may fail with local addresses we don't own but accepted packets for + // while in promiscuous mode. Since we also want to be able to send from + // any address (in response the received promiscuous mode packets), we need + // to enable spoofing. + // + // Ref: https://github.com/google/gvisor/commit/8c0701462a84ff77e602f1626aec49479c308127 WithSpoofing(defaultNICID, nicSpoofingEnabled), ) } diff --git a/internal/core/udp.go b/internal/core/udp.go index 10847b3..a763838 100644 --- a/internal/core/udp.go +++ b/internal/core/udp.go @@ -11,6 +11,7 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/transport/udp" "github.com/xjasonlyu/tun2socks/internal/adapter" + "github.com/xjasonlyu/tun2socks/pkg/log" ) const udpNoChecksum = true @@ -19,16 +20,16 @@ type udpHandleFunc func(adapter.UDPPacket) func WithUDPHandler(handle udpHandleFunc) Option { return func(s *stack.Stack) error { - udpHandlePacket := func(r *stack.Route, id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool { + udpHandlePacket := func(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool { // Ref: gVisor pkg/tcpip/transport/udp/endpoint.go HandlePacket - hdr := header.UDP(pkt.TransportHeader().View()) - if int(hdr.Length()) > pkt.Data.Size()+header.UDPMinimumSize { + udpHdr := header.UDP(pkt.TransportHeader().View()) + if int(udpHdr.Length()) > pkt.Data.Size()+header.UDPMinimumSize { // Malformed packet. s.Stats().UDP.MalformedPacketsReceived.Increment() return true } - if !verifyChecksum(r, hdr, pkt) { + if !verifyChecksum(udpHdr, pkt) { // Checksum error. s.Stats().UDP.ChecksumErrors.Increment() return true @@ -36,8 +37,14 @@ func WithUDPHandler(handle udpHandleFunc) Option { s.Stats().UDP.PacketsReceived.Increment() - // make a clone here. - route := r.Clone() + netHdr := pkt.Network() + route, err := s.FindRoute(pkt.NICID, netHdr.DestinationAddress(), netHdr.SourceAddress(), pkt.NetworkProtocolNumber, false /* multicastLoop */) + if err != nil { + log.Warnf("[STACK] find route error: %v", err) + return true + } + route.ResolveWith(pkt.SourceLinkAddress()) + packet := &udpPacket{ id: id, r: &route, @@ -138,7 +145,7 @@ func sendUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort u // On IPv4, UDP checksum is optional, and a zero value indicates the // transmitter skipped the checksum generation (RFC768). // On IPv6, UDP checksum is not optional (RFC2460 Section 8.1). - if r.Capabilities()&stack.CapabilityTXChecksumOffload == 0 && + if r.RequiresTXTransportChecksum() && (!noChecksum || r.NetProto == header.IPv6ProtocolNumber) { xsum := r.PseudoHeaderChecksum(udp.ProtocolNumber, length) for _, v := range data.Views() { @@ -166,10 +173,11 @@ func sendUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort u // On IPv4, UDP checksum is optional, and a zero value means the transmitter // omitted the checksum generation (RFC768). // On IPv6, UDP checksum is not optional (RFC2460 Section 8.1). -func verifyChecksum(r *stack.Route, hdr header.UDP, pkt *stack.PacketBuffer) bool { - if r.Capabilities()&stack.CapabilityRXChecksumOffload == 0 && - (hdr.Checksum() != 0 || r.NetProto == header.IPv6ProtocolNumber) { - xsum := r.PseudoHeaderChecksum(udp.ProtocolNumber, hdr.Length()) +func verifyChecksum(hdr header.UDP, pkt *stack.PacketBuffer) bool { + if !pkt.RXTransportChecksumValidated && + (hdr.Checksum() != 0 || pkt.NetworkProtocolNumber == header.IPv6ProtocolNumber) { + netHdr := pkt.Network() + xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, netHdr.DestinationAddress(), netHdr.SourceAddress(), hdr.Length()) for _, v := range pkt.Data.Views() { xsum = header.Checksum(v, xsum) }