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
+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
}