Fix protocol input validation

This commit is contained in:
世界
2026-10-09 12:36:03 +08:00
parent a0d775ea66
commit 52f9bad034
22 changed files with 165 additions and 71 deletions
+13 -5
View File
@@ -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:]
+4 -1
View File
@@ -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++
+5 -1
View File
@@ -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
}
+10 -10
View File
@@ -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
+20 -20
View File
@@ -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=
+7
View File
@@ -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)))
+14 -1
View File
@@ -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{
+22 -9
View File
@@ -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 {
+8 -2
View File
@@ -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 {
+1 -1
View File
@@ -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 {
+2 -2
View File
@@ -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) {
+3
View File
@@ -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
}
-1
View File
@@ -811,7 +811,6 @@ func (r *Router) actionSniff(
}
goto finally
}
packetBuffers = inputPacketBuffers
for {
var (
sniffBuffer = buf.NewPacket()
@@ -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{}
+6
View File
@@ -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{}
+2 -1
View File
@@ -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)
+7 -8
View File
@@ -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
}
+8
View File
@@ -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
+2 -1
View File
@@ -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
}
+14 -1
View File
@@ -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)
}
+4 -2
View File
@@ -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
+7 -5
View File
@@ -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