diff --git a/common/ja3/parser.go b/common/ja3/parser.go index a4bd7123..421e51c2 100644 --- a/common/ja3/parser.go +++ b/common/ja3/parser.go @@ -264,16 +264,24 @@ func (j *ClientHello) parseExtensions(exs []byte) error { return &ParseError{LengthErr, 19} } versionsLen := int(sex[0]) - for i := 0; i < versionsLen; i += 2 { - versions = append(versions, binary.BigEndian.Uint16(sex[1:][i:])) + sex = sex[versionExtensionHeaderLen:] + if len(sex) < versionsLen { + return &ParseError{LengthErr, 21} + } + for i := range versionsLen / 2 { + versions = append(versions, binary.BigEndian.Uint16(sex[i*2:])) } case signatureAlgorithmsExtensionType: if len(sex) < signatureAlgorithmsExtensionHeaderLen { return &ParseError{LengthErr, 20} } - ssaLen := binary.BigEndian.Uint16(sex) - for i := 0; i < int(ssaLen); i += 2 { - signatureAlgorithms = append(signatureAlgorithms, binary.BigEndian.Uint16(sex[2:][i:])) + ssaLen := int(binary.BigEndian.Uint16(sex)) + sex = sex[signatureAlgorithmsExtensionHeaderLen:] + if len(sex) < ssaLen { + return &ParseError{LengthErr, 22} + } + for i := range ssaLen / 2 { + signatureAlgorithms = append(signatureAlgorithms, binary.BigEndian.Uint16(sex[i*2:])) } } exs = exs[4+exLen:] diff --git a/common/sniff/quic.go b/common/sniff/quic.go index 049bd2c1..4f6dcf06 100644 --- a/common/sniff/quic.go +++ b/common/sniff/quic.go @@ -245,6 +245,9 @@ func QUICClientHello(ctx context.Context, metadata *adapter.InboundContext, pack if err != nil { return err } + if length > uint64(decryptedReader.Len()) { + return os.ErrInvalid + } index := len(decrypted) - decryptedReader.Len() fragments = append(fragments, qCryptoFragment{offset, length, decrypted[index : index+int(length)]}) _, err = decryptedReader.Seek(int64(length), io.SeekCurrent) @@ -291,7 +294,7 @@ func QUICClientHello(ctx context.Context, metadata *adapter.InboundContext, pack find: for { for _, fragment := range fragments { - if fragment.offset == index { + if fragment.offset == index && fragment.length > 0 { buffer.Write(fragment.payload) index = fragment.offset + fragment.length length++ diff --git a/dns/transport/fakeip/fakeip.go b/dns/transport/fakeip/fakeip.go index 75db1cf8..025ddecf 100644 --- a/dns/transport/fakeip/fakeip.go +++ b/dns/transport/fakeip/fakeip.go @@ -67,7 +67,11 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, if question.Qtype == mDNS.TypeA && !t.inet4Enabled || question.Qtype == mDNS.TypeAAAA && !t.inet6Enabled { return dns.FixedResponseStatus(message, mDNS.RcodeSuccess), nil } - address, err := t.store.Create(dns.FqdnToDomain(question.Name), question.Qtype == mDNS.TypeAAAA) + domain := dns.FqdnToDomain(question.Name) + if len(domain) > 255 { + return nil, E.New("domain name too long for fakeip") + } + address, err := t.store.Create(domain, question.Qtype == mDNS.TypeAAAA) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index c9868858..56567a99 100644 --- a/go.mod +++ b/go.mod @@ -45,19 +45,19 @@ require ( github.com/sagernet/netlink v0.0.0-20260814022025-64455d367bbf github.com/sagernet/nftables v0.3.0-mod.4 github.com/sagernet/quic-go v0.61.0-sing-box-mod.7 - github.com/sagernet/sing v0.9.6 - github.com/sagernet/sing-cloudflared v0.1.3 - github.com/sagernet/sing-mux v0.3.9 - github.com/sagernet/sing-openconnect v0.1.0 - github.com/sagernet/sing-openvpn v0.1.0 + github.com/sagernet/sing v0.9.7-0.20260929145605-8d939df03478 + github.com/sagernet/sing-cloudflared v0.1.4-0.20260929150702-b3a1e8f3018c + github.com/sagernet/sing-mux v0.3.10-0.20260929204512-caf09fe32475 + github.com/sagernet/sing-openconnect v0.1.1-0.20260929151225-cbd68c45de58 + github.com/sagernet/sing-openvpn v0.1.1-0.20260929151220-7c3045dbddce github.com/sagernet/sing-quic v0.7.2-0.20261002084117-75c3ac4fa12b - github.com/sagernet/sing-shadowsocks v0.2.8 - github.com/sagernet/sing-shadowsocks2 v0.2.1 - github.com/sagernet/sing-shadowtls v0.2.1 + github.com/sagernet/sing-shadowsocks v0.2.9-0.20260929204512-65740e0f0e3e + github.com/sagernet/sing-shadowsocks2 v0.2.2-0.20260929152114-a69d1086332b + github.com/sagernet/sing-shadowtls v0.2.2-0.20260928201441-a9c0127d5c99 github.com/sagernet/sing-snell v0.0.0-20260904135315-bc5a12ac736f - github.com/sagernet/sing-tun v0.9.7-0.20260928080829-8ab0e83967b4 + github.com/sagernet/sing-tun v0.9.7-0.20260929152151-0bdadeb4c934 github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca - github.com/sagernet/sing-vmess v0.2.8 + github.com/sagernet/sing-vmess v0.2.9-0.20260929152519-9b95ab8c9478 github.com/sagernet/smux v1.5.50-sing-box-mod.1 github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5 github.com/sagernet/wireguard-go v0.0.7 diff --git a/go.sum b/go.sum index 02e9953b..7988d55b 100644 --- a/go.sum +++ b/go.sum @@ -318,32 +318,32 @@ github.com/sagernet/nftables v0.3.0-mod.4 h1:vnOtcDYeSXv2e5RoRuGH0lrpttQFJ8iC4IC github.com/sagernet/nftables v0.3.0-mod.4/go.mod h1:8kslHG4VvYNihcco+i6uxIX7qbT8A56T0y5q7U44ZaQ= github.com/sagernet/quic-go v0.61.0-sing-box-mod.7 h1:sW2O+DoNF+my1PGlSZ3zG2N+fdxLR3DC0l4sXCM0lBE= github.com/sagernet/quic-go v0.61.0-sing-box-mod.7/go.mod h1:hmLC8GJPp+BrpBgrgJnacvI4fZGIhasuy1ROJJ8GR4E= -github.com/sagernet/sing v0.9.6 h1:LXTpEMbr4G/65PSjopjfg+Zp1Xq1ilJnGWq47y/eObI= -github.com/sagernet/sing v0.9.6/go.mod h1:K3Owt3xPhHugvlnlPPxZJ/exXdaJfEPOTNorGk4AXjo= -github.com/sagernet/sing-cloudflared v0.1.3 h1:J5v401QFvUzzamw0udgs1kOPgnmPyPjo9jbPUiJgBXo= -github.com/sagernet/sing-cloudflared v0.1.3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg= -github.com/sagernet/sing-mux v0.3.9 h1:fhk1tA1OHkDXHedXLanyu/mUepykCXENM9s6sEymo84= -github.com/sagernet/sing-mux v0.3.9/go.mod h1:jricpwCOndDsTEM1TM3piJvhL/2Mm7OhLkm+JadJJ1Q= -github.com/sagernet/sing-openconnect v0.1.0 h1:nen3Hhr52CHASJtduUwZfMhqgLD30A1LE+SN6Ju2X0Y= -github.com/sagernet/sing-openconnect v0.1.0/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg= -github.com/sagernet/sing-openvpn v0.1.0 h1:bmULMzzDP0EsO0UMkbiiNLIvEIKBlozM+ZD3GiJ2Vtg= -github.com/sagernet/sing-openvpn v0.1.0/go.mod h1:PWX7WygD8jpwfqfaGNySXpJYTn0SOwjBI1BKHHC2+Bw= +github.com/sagernet/sing v0.9.7-0.20260929145605-8d939df03478 h1:c3Jpk13MOAc516zCuqAGBr7ok9UcpGjCjgWWOQslL0w= +github.com/sagernet/sing v0.9.7-0.20260929145605-8d939df03478/go.mod h1:K3Owt3xPhHugvlnlPPxZJ/exXdaJfEPOTNorGk4AXjo= +github.com/sagernet/sing-cloudflared v0.1.4-0.20260929150702-b3a1e8f3018c h1:36zXD/qnDk7sh/J4zSEJsnHf4W3TYNCbmjo9MNIlrE4= +github.com/sagernet/sing-cloudflared v0.1.4-0.20260929150702-b3a1e8f3018c/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg= +github.com/sagernet/sing-mux v0.3.10-0.20260929204512-caf09fe32475 h1:aG0DqHEOjax7DyfE1GTAXZotOg3QGVCz3/8rCSua2kg= +github.com/sagernet/sing-mux v0.3.10-0.20260929204512-caf09fe32475/go.mod h1:jricpwCOndDsTEM1TM3piJvhL/2Mm7OhLkm+JadJJ1Q= +github.com/sagernet/sing-openconnect v0.1.1-0.20260929151225-cbd68c45de58 h1:WOPVlvbw3zGl4IzpRcfqB901blgDKuiplVrpptf/TOY= +github.com/sagernet/sing-openconnect v0.1.1-0.20260929151225-cbd68c45de58/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg= +github.com/sagernet/sing-openvpn v0.1.1-0.20260929151220-7c3045dbddce h1:uB2DkIJLZ9waR/ZLBO9IF/ws5BWg0FEegLi90ibhX5I= +github.com/sagernet/sing-openvpn v0.1.1-0.20260929151220-7c3045dbddce/go.mod h1:PWX7WygD8jpwfqfaGNySXpJYTn0SOwjBI1BKHHC2+Bw= github.com/sagernet/sing-quic v0.7.2-0.20261002084117-75c3ac4fa12b h1:2Jx/URJAPt32MEbLmAR5nzH87tO6NQZLRfRFvFqBWuk= github.com/sagernet/sing-quic v0.7.2-0.20261002084117-75c3ac4fa12b/go.mod h1:rJFeVxbEej2iuyeCJ3drKW+p5rOgtLIW3XhZ6ty7Fig= -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 h1:ZiHZdnEnP+YS73NMsxiZmIFCwNd0M4k7PkGCKNXhbaM= -github.com/sagernet/sing-shadowtls v0.2.1/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= +github.com/sagernet/sing-shadowsocks v0.2.9-0.20260929204512-65740e0f0e3e h1:LKgE/uuqp/D2kgxYViOz8vf4slaCUfpFywXjtuwD5gU= +github.com/sagernet/sing-shadowsocks v0.2.9-0.20260929204512-65740e0f0e3e/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= +github.com/sagernet/sing-shadowsocks2 v0.2.2-0.20260929152114-a69d1086332b h1:VH65QNqSHat2b+N3Rlzo5Qe44gRmQGwzY5atuy3D0A8= +github.com/sagernet/sing-shadowsocks2 v0.2.2-0.20260929152114-a69d1086332b/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= +github.com/sagernet/sing-shadowtls v0.2.2-0.20260928201441-a9c0127d5c99 h1:l/tdZjaoDp3iqEG4NVrFHtphy1+Qjt9bpWAgNbF8iGg= +github.com/sagernet/sing-shadowtls v0.2.2-0.20260928201441-a9c0127d5c99/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= github.com/sagernet/sing-snell v0.0.0-20260904135315-bc5a12ac736f h1:tbTCI+iis5sTmua7a6Q7vebcSRURok/LGgnEafnQAsc= github.com/sagernet/sing-snell v0.0.0-20260904135315-bc5a12ac736f/go.mod h1:et8Lws4f5QbOrY65DmjevHGup3mijJkhswkto6cwciM= -github.com/sagernet/sing-tun v0.9.7-0.20260928080829-8ab0e83967b4 h1:8LMh5gE8agrhOqeaTg9xML99oVeP8ApxqC0uKeS+ruk= -github.com/sagernet/sing-tun v0.9.7-0.20260928080829-8ab0e83967b4/go.mod h1:3EgPst7agntRO7D6GOsiZ1l9FoqdLeuWmKT5TnWkmf0= +github.com/sagernet/sing-tun v0.9.7-0.20260929152151-0bdadeb4c934 h1:CC1NMvo1hpRY33IJCwXldUOSgCLjYh0T4vq9pX30+tM= +github.com/sagernet/sing-tun v0.9.7-0.20260929152151-0bdadeb4c934/go.mod h1:3EgPst7agntRO7D6GOsiZ1l9FoqdLeuWmKT5TnWkmf0= github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca h1:5wA+IE0Fq1CGVLOgSpm0gKKZ03HzugcJ2JyhmDqeX6A= github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca/go.mod h1:ADAZZU85MnM91XNhd2TdZRTaIbA7RjTZuQ1KCHcUbNg= -github.com/sagernet/sing-vmess v0.2.8 h1:xd5nnDOMlC76RgrLksS4jlk3eMt3c3CvQY3NsjWPWeI= -github.com/sagernet/sing-vmess v0.2.8/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY= +github.com/sagernet/sing-vmess v0.2.9-0.20260929152519-9b95ab8c9478 h1:q2eQn4nq8oWGxRm9zXesXSlPr9GEgPrOGzf4iPtzG9A= +github.com/sagernet/sing-vmess v0.2.9-0.20260929152519-9b95ab8c9478/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.102.1-sing-box-1.14-mod.5 h1:mGLWVgj2Pl2NlgE1+sEUIDIMB42JdWEPwYmxTnVWg44= diff --git a/protocol/bridge/packet.go b/protocol/bridge/packet.go index 47f089e4..0247c2e6 100644 --- a/protocol/bridge/packet.go +++ b/protocol/bridge/packet.go @@ -75,6 +75,9 @@ func fixReturnChecksum(packet []byte) { return } ipHdr := header.IPv6(packet) + if !ipHdr.IsValid(len(packet)) { + return + } recomputeTransportChecksum(ipHdr.TransportProtocol(), ipHdr.Payload(), ipHdr.SourceAddressSlice(), ipHdr.DestinationAddressSlice()) } } @@ -86,6 +89,10 @@ func recomputeTransportChecksum(protocol tcpip.TransportProtocolNumber, transpor return } tcpHdr := header.TCP(transport) + dataOffset := int(tcpHdr.DataOffset()) + if dataOffset < header.TCPMinimumSize || dataOffset > len(transport) { + return + } tcpHdr.SetChecksum(0) payloadChecksum := checksum.Checksum(tcpHdr.Payload(), 0) pseudoChecksum := header.PseudoHeaderChecksum(header.TCPProtocolNumber, source, destination, uint16(len(transport))) diff --git a/protocol/naive/inbound.go b/protocol/naive/inbound.go index 9da0cf08..dfa022b1 100644 --- a/protocol/naive/inbound.go +++ b/protocol/naive/inbound.go @@ -18,6 +18,8 @@ import ( "github.com/sagernet/sing-box/transport/v2rayhttp" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/auth" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" @@ -184,11 +186,22 @@ func (n *Inbound) ServeHTTP(writer http.ResponseWriter, request *http.Request) { destination := M.ParseSocksaddr(hostPort).Unwrap() if hijacker, isHijacker := writer.(http.Hijacker); isHijacker { - conn, _, err := hijacker.Hijack() + conn, reader, err := hijacker.Hijack() if err != nil { n.badRequest(ctx, request, E.New("hijack failed")) return } + if cacheLen := reader.Reader.Buffered(); cacheLen > 0 { + cache := buf.NewSize(cacheLen) + _, err = cache.ReadFullFrom(reader.Reader, cacheLen) + if err != nil { + cache.Release() + conn.Close() + n.badRequest(ctx, request, E.Cause(err, "read cache")) + return + } + conn = bufio.NewCachedConn(conn, cache) + } n.newConnection(ctx, false, &naiveConn{Conn: conn}, userName, source, destination) } else { n.newConnection(ctx, true, &naiveH2Conn{ diff --git a/protocol/shadowsocks/inbound_multi.go b/protocol/shadowsocks/inbound_multi.go index 706243e2..9233c749 100644 --- a/protocol/shadowsocks/inbound_multi.go +++ b/protocol/shadowsocks/inbound_multi.go @@ -4,6 +4,7 @@ import ( "context" "net" "os" + "sync" "time" "github.com/sagernet/sing-box/adapter" @@ -35,13 +36,14 @@ var ( type MultiInbound struct { inbound.Adapter - ctx context.Context - router adapter.ConnectionRouterEx - logger logger.ContextLogger - listener *listener.Listener - service shadowsocks.MultiService[int] - users []option.ShadowsocksUser - tracker adapter.SSMTracker + ctx context.Context + router adapter.ConnectionRouterEx + logger logger.ContextLogger + listener *listener.Listener + service shadowsocks.MultiService[int] + usersAccess sync.RWMutex + users []option.ShadowsocksUser + tracker adapter.SSMTracker } func newMultiInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (*MultiInbound, error) { @@ -123,6 +125,8 @@ func (h *MultiInbound) SetTracker(tracker adapter.SSMTracker) { } func (h *MultiInbound) UpdateUsers(users []string, uPSKs []string) error { + h.usersAccess.Lock() + defer h.usersAccess.Unlock() err := h.service.UpdateUsersWithPasswords(common.MapIndexed(users, func(index int, user string) int { return index }), uPSKs) @@ -137,6 +141,15 @@ func (h *MultiInbound) UpdateUsers(users []string, uPSKs []string) error { return nil } +func (h *MultiInbound) userName(userIndex int) string { + h.usersAccess.RLock() + defer h.usersAccess.RUnlock() + if userIndex >= len(h.users) { + return "" + } + return h.users[userIndex].Name +} + //nolint:staticcheck func (h *MultiInbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) { err := h.service.NewConnection(ctx, conn, adapter.UpstreamMetadata(metadata)) @@ -163,7 +176,7 @@ func (h *MultiInbound) newConnection(ctx context.Context, conn net.Conn, metadat if !loaded { return os.ErrInvalid } - user := h.users[userIndex].Name + user := h.userName(userIndex) if user == "" { user = F.ToString(userIndex) } else { @@ -186,7 +199,7 @@ func (h *MultiInbound) newPacketConnection(ctx context.Context, conn N.PacketCon if !loaded { return os.ErrInvalid } - user := h.users[userIndex].Name + user := h.userName(userIndex) if user == "" { user = F.ToString(userIndex) } else { diff --git a/protocol/tailscale/dns_transport.go b/protocol/tailscale/dns_transport.go index b48aa823..fecbf702 100644 --- a/protocol/tailscale/dns_transport.go +++ b/protocol/tailscale/dns_transport.go @@ -186,16 +186,22 @@ func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dn myDialer = dialer.NewResolveDialer(t.ctx, myDialer, false, "", t.endpoint.queryOptions, 0) } if isHTTPScheme { + if serverURL.Hostname() == "" { + return nil, E.New("missing host in resolver address: ", resolver.Addr) + } serverAddr := M.ParseSocksaddrHostPortStr(serverURL.Hostname(), serverURL.Port()) switch serverURL.Scheme { case "https": if serverAddr.Port == 0 { serverAddr.Port = 443 } - tlsConfig := common.Must1(tls.NewClient(t.ctx, t.logger, serverAddr.AddrString(), option.OutboundTLSOptions{ + tlsConfig, err := tls.NewClient(t.ctx, t.logger, serverAddr.AddrString(), option.OutboundTLSOptions{ Enabled: true, ALPN: []string{http2.NextProtoTLS, "http/1.1"}, - })) + }) + if err != nil { + return nil, E.Cause(err, "create TLS config for resolver ", resolver.Addr) + } return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, tlsConfig), nil case "http": if serverAddr.Port == 0 { diff --git a/protocol/tailscale/taildrop.go b/protocol/tailscale/taildrop.go index 8c7f5d2d..78359a6b 100644 --- a/protocol/tailscale/taildrop.go +++ b/protocol/tailscale/taildrop.go @@ -361,7 +361,7 @@ func validateTaildropFileName(name string) error { var ( taildropExtensionSuffix = regexp.MustCompile(`(\.[a-zA-Z0-9]{0,3}[a-zA-Z][a-zA-Z0-9]{0,3})*$`) - taildropNumberSuffix = regexp.MustCompile(` \([0-9]+\)`) + taildropNumberSuffix = regexp.MustCompile(` \([0-9]+\)$`) ) func nextFileName(name string) string { diff --git a/protocol/tailscale/taildrop_send.go b/protocol/tailscale/taildrop_send.go index ef7d8fd4..cdd7d112 100644 --- a/protocol/tailscale/taildrop_send.go +++ b/protocol/tailscale/taildrop_send.go @@ -55,7 +55,7 @@ func (t *Endpoint) SendTaildropFile(ctx context.Context, peerStableID string, fi if !peer.Valid() { return E.New("taildrop: peer not found: ", peerStableID) } - if peer.Hostinfo().OS() == "tvOS" { + if !peer.Hostinfo().Valid() || peer.Hostinfo().OS() == "tvOS" { return E.New("taildrop: peer cannot receive files") } if self.User() != peer.User() && !nodeBackend.PeerHasCap(peer, tailcfg.PeerCapabilityFileSharingTarget) { @@ -187,7 +187,7 @@ func (t *Endpoint) taildropTargets() (canShareFiles bool, targets map[string]boo } targets = make(map[string]bool) for _, peer := range nodeBackend.Peers() { - if !peer.Valid() || peer.Hostinfo().OS() == "tvOS" { + if !peer.Valid() || !peer.Hostinfo().Valid() || peer.Hostinfo().OS() == "tvOS" { continue } if self.User() != peer.User() && !nodeBackend.PeerHasCap(peer, tailcfg.PeerCapabilityFileSharingTarget) { diff --git a/protocol/tailscale/tailssh/server.go b/protocol/tailscale/tailssh/server.go index 476f06b7..8ba3ba95 100644 --- a/protocol/tailscale/tailssh/server.go +++ b/protocol/tailscale/tailssh/server.go @@ -334,6 +334,9 @@ func (s *Server) authenticate(ctx gliderssh.Context, conn gossh.ConnMetadata) (* func (s *Server) evaluatePolicy(policy *tailcfg.SSHPolicy, sshUser string, node tailcfg.NodeView, userProfile tailcfg.UserProfile, srcIP netip.Addr) (*sshConnInfo, error) { now := time.Now() for _, rule := range policy.Rules { + if rule == nil { + continue + } if rule.RuleExpires != nil && now.After(*rule.RuleExpires) { continue } diff --git a/route/route.go b/route/route.go index 62f1c865..8dddb043 100644 --- a/route/route.go +++ b/route/route.go @@ -811,7 +811,6 @@ func (r *Router) actionSniff( } goto finally } - packetBuffers = inputPacketBuffers for { var ( sniffBuffer = buf.NewPacket() diff --git a/transport/openconnect/device_system_stack.go b/transport/openconnect/device_system_stack.go index 2042881e..d97fbb0c 100644 --- a/transport/openconnect/device_system_stack.go +++ b/transport/openconnect/device_system_stack.go @@ -103,8 +103,14 @@ func (d *systemStackDevice) writeBuffers(packetBuffers []*buf.Buffer) error { func packetDestination(packet []byte) netip.Addr { switch header.IPVersion(packet) { case header.IPv4Version: + if len(packet) < header.IPv4MinimumSize { + return netip.Addr{} + } return header.IPv4(packet).DestinationAddr() case header.IPv6Version: + if len(packet) < header.IPv6MinimumSize { + return netip.Addr{} + } return header.IPv6(packet).DestinationAddr() default: return netip.Addr{} diff --git a/transport/openvpn/device_system_stack.go b/transport/openvpn/device_system_stack.go index d0d9a977..41cad658 100644 --- a/transport/openvpn/device_system_stack.go +++ b/transport/openvpn/device_system_stack.go @@ -104,8 +104,14 @@ func (d *systemStackDevice) writeBuffers(packetBuffers []*buf.Buffer) error { func packetDestination(packet []byte) netip.Addr { switch header.IPVersion(packet) { case header.IPv4Version: + if len(packet) < header.IPv4MinimumSize { + return netip.Addr{} + } return header.IPv4(packet).DestinationAddr() case header.IPv6Version: + if len(packet) < header.IPv6MinimumSize { + return netip.Addr{} + } return header.IPv6(packet).DestinationAddr() default: return netip.Addr{} diff --git a/transport/trojan/mux.go b/transport/trojan/mux.go index 72d5a776..e1d98813 100644 --- a/transport/trojan/mux.go +++ b/transport/trojan/mux.go @@ -60,8 +60,9 @@ func newMuxConnection0(ctx context.Context, conn net.Conn, source M.Socksaddr, h } if reader.Buffered() > 0 { buffer := buf.NewSize(reader.Buffered()) - _, err = buffer.ReadFullFrom(reader, buffer.Len()) + _, err = buffer.ReadFullFrom(reader, buffer.FreeLen()) if err != nil { + buffer.Release() return err } conn = bufio.NewCachedConn(conn, buffer) diff --git a/transport/v2raygrpclite/conn.go b/transport/v2raygrpclite/conn.go index 52911e62..7080d63c 100644 --- a/transport/v2raygrpclite/conn.go +++ b/transport/v2raygrpclite/conn.go @@ -29,7 +29,7 @@ type GunConn struct { create chan struct{} err error cancel context.CancelFunc - readRemaining int + readRemaining uint64 onClose func() } @@ -73,11 +73,11 @@ func (c *GunConn) read(b []byte) (n int, err error) { } if c.readRemaining > 0 { - if len(b) > c.readRemaining { + if uint64(len(b)) > c.readRemaining { b = b[:c.readRemaining] } n, err = c.reader.Read(b) - c.readRemaining -= n + c.readRemaining -= uint64(n) return } @@ -91,14 +91,13 @@ func (c *GunConn) read(b []byte) (n int, err error) { return } - readLen := int(dataLen) - c.readRemaining = readLen - if len(b) > readLen { - b = b[:readLen] + c.readRemaining = dataLen + if uint64(len(b)) > dataLen { + b = b[:dataLen] } n, err = c.reader.Read(b) - c.readRemaining -= n + c.readRemaining -= uint64(n) return } diff --git a/transport/v2rayhttp/server.go b/transport/v2rayhttp/server.go index de03c40c..0f3abcc5 100644 --- a/transport/v2rayhttp/server.go +++ b/transport/v2rayhttp/server.go @@ -105,11 +105,16 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { source := sHttp.SourceAddress(request) if h, ok := writer.(http.Hijacker); ok { + if request.ContentLength > buf.MaxPooledBufferSize { + s.invalidRequest(writer, request, http.StatusRequestEntityTooLarge, E.New("request body too large: ", request.ContentLength)) + return + } var requestBody *buf.Buffer if contentLength := int(request.ContentLength); contentLength > 0 { requestBody = buf.NewSize(contentLength) _, err := requestBody.ReadFullFrom(request.Body, contentLength) if err != nil { + requestBody.Release() s.invalidRequest(writer, request, 0, E.Cause(err, "read request")) return } @@ -118,6 +123,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { writer.(http.Flusher).Flush() conn, reader, err := h.Hijack() if err != nil { + requestBody.Release() s.invalidRequest(writer, request, 0, E.Cause(err, "hijack conn")) return } @@ -125,6 +131,8 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { cache := buf.NewSize(cacheLen) _, err = cache.ReadFullFrom(reader.Reader, cacheLen) if err != nil { + cache.Release() + requestBody.Release() conn.Close() s.invalidRequest(writer, request, 0, E.Cause(err, "read cache")) return diff --git a/transport/v2rayhttpupgrade/client.go b/transport/v2rayhttpupgrade/client.go index 27ef8758..ea4c425b 100644 --- a/transport/v2rayhttpupgrade/client.go +++ b/transport/v2rayhttpupgrade/client.go @@ -105,8 +105,9 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { } if bufReader.Buffered() > 0 { buffer := buf.NewSize(bufReader.Buffered()) - _, err = buffer.ReadFullFrom(bufReader, buffer.Len()) + _, err = buffer.ReadFullFrom(bufReader, buffer.FreeLen()) if err != nil { + buffer.Release() conn.Close() return nil, err } diff --git a/transport/v2rayhttpupgrade/server.go b/transport/v2rayhttpupgrade/server.go index 338b7248..2b58bc2a 100644 --- a/transport/v2rayhttpupgrade/server.go +++ b/transport/v2rayhttpupgrade/server.go @@ -14,6 +14,8 @@ import ( "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/v2rayhttp" "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" @@ -107,11 +109,22 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { s.invalidRequest(writer, request, http.StatusInternalServerError, E.New("invalid connection, maybe HTTP/2")) return } - conn, _, err := hijacker.Hijack() + conn, reader, err := hijacker.Hijack() if err != nil { s.invalidRequest(writer, request, http.StatusInternalServerError, E.Cause(err, "hijack failed")) return } + if cacheLen := reader.Reader.Buffered(); cacheLen > 0 { + cache := buf.NewSize(cacheLen) + _, err = cache.ReadFullFrom(reader.Reader, cacheLen) + if err != nil { + cache.Release() + conn.Close() + s.invalidRequest(writer, request, 0, E.Cause(err, "read cache")) + return + } + conn = bufio.NewCachedConn(conn, cache) + } s.handler.NewConnectionEx(v2rayhttp.DupContext(request.Context()), conn, sHttp.SourceAddress(request), M.Socksaddr{}, nil) } diff --git a/transport/v2raywebsocket/client.go b/transport/v2raywebsocket/client.go index d1bce75e..54d748f1 100644 --- a/transport/v2raywebsocket/client.go +++ b/transport/v2raywebsocket/client.go @@ -97,8 +97,10 @@ func (c *Client) upgrade(conn net.Conn, requestURL *url.URL, headers http.Header } deadlineConn.SetDeadline(time.Now().Add(C.TCPTimeout)) var protocols []string - if protocolHeader := headers.Get("Sec-WebSocket-Protocol"); protocolHeader != "" { + protocolHeader := headers.Get("Sec-WebSocket-Protocol") + if protocolHeader != "" { protocols = []string{protocolHeader} + headers = headers.Clone() headers.Del("Sec-WebSocket-Protocol") } reader, _, err := ws.Dialer{Header: ws.HandshakeHeaderHTTP(headers), Protocols: protocols}.Upgrade(deadlineConn, requestURL) @@ -109,7 +111,7 @@ func (c *Client) upgrade(conn net.Conn, requestURL *url.URL, headers http.Header } if reader != nil { buffer := buf.NewSize(reader.Buffered()) - _, err = buffer.ReadFullFrom(reader, buffer.Len()) + _, err = buffer.ReadFullFrom(reader, buffer.FreeLen()) if err != nil { conn.Close() return nil, err diff --git a/transport/v2raywebsocket/conn.go b/transport/v2raywebsocket/conn.go index ef277233..ecea3c55 100644 --- a/transport/v2raywebsocket/conn.go +++ b/transport/v2raywebsocket/conn.go @@ -29,7 +29,13 @@ type WebsocketConn struct { } func NewConn(conn net.Conn, remoteAddr net.Addr, state ws.State) *WebsocketConn { - controlHandler := wsutil.ControlFrameHandler(conn, state) + defaultControlHandler := wsutil.ControlFrameHandler(conn, state) + controlHandler := func(header ws.Header, reader io.Reader) error { + if header.Length > ws.MaxControlFramePayloadSize { + return ws.ErrProtocolControlPayloadOverflow + } + return defaultControlHandler(header, reader) + } return &WebsocketConn{ Conn: conn, state: state, @@ -75,10 +81,6 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) { return } if header.OpCode.IsControl() { - if header.Length > 128 { - err = wsutil.ErrFrameTooLarge - return - } err = wrapWsError(c.controlHandler(header, c.reader)) if err != nil { return