Skip to content

finalmask/fragment: implement CloseWrite to satisfy reality.CloseWriteConn (#6509)#6510

Closed
skvarovski wants to merge 1 commit into
XTLS:mainfrom
skvarovski:fix/fragment-closewrite
Closed

finalmask/fragment: implement CloseWrite to satisfy reality.CloseWriteConn (#6509)#6510
skvarovski wants to merge 1 commit into
XTLS:mainfrom
skvarovski:fix/fragment-closewrite

Conversation

@skvarovski

Copy link
Copy Markdown

Fixes #6509.

Root cause

Since #6331 reversed the finalmask TCP mask wrapping order (slices.Backward), fragmentConn is the outermost wrapper for {fragment, sudoku} configs. The external github.com/xtls/reality library performs a hard type assertion on the connection handed to reality.Server:

// github.com/xtls/reality/tls.go:186
underlying := raw.(CloseWriteConn) // *net.TCPConn or *net.UnixConn

fragmentConn does not implement CloseWrite(), so any REALITY server inbound combined with finalmask containing fragment panics on every client connection:

panic: interface conversion: *fragment.fragmentConn is not reality.CloseWriteConn: missing method CloseWrite

sudoku.wrappedConn already implements CloseWrite() (delegating to the underlying conn), which is why the panic only surfaced after #6331 made fragment the outer wrapper.

Fix

Add CloseWrite() to fragmentConn, mirroring sudoku/conn_tcp.go:

type closeWriteConn interface {
	CloseWrite() error
}

func (c *fragmentConn) CloseWrite() error {
	if raw, ok := c.Conn.(closeWriteConn); ok {
		return raw.CloseWrite()
	}
	return net.ErrClosed
}

Additive and non-breaking (+11 lines). Does not touch the wrapping order or the UDP path introduced by #6331.

Verification

Deployed to a production bridge and tested end-to-end (VLESS + XHTTP + REALITY + finalmask fragment+sudoku):

  • Live client traffic: stable, 0 restarts, 0 panics over several minutes.
  • Explicit handshake test against a dedicated finalmask+REALITY inbound: HTTP 301/302 through the tunnel, 0 server panics.
  • Stock build (without this patch) with the identical config crash-loops on the first client connection.

…TLS#6509)

After XTLS#6331 reversed the TCP mask wrapping order (slices.Backward), fragmentConn
became the outermost finalmask wrapper for {fragment, sudoku} configs. The
external github.com/xtls/reality library performs a hard type assertion
'raw.(CloseWriteConn)' (tls.go) on the connection passed to reality.Server, so a
REALITY server inbound combined with finalmask fragment+sudoku panics on every
client connection (crash-loop with Restart=always).

Add CloseWrite(), mirroring sudoku/conn_tcp.go, so fragmentConn satisfies
reality.CloseWriteConn. Additive and non-breaking.
@skvarovski
skvarovski force-pushed the fix/fragment-closewrite branch from 9de921a to c64c910 Compare July 16, 2026 22:50
@Fangliding Fangliding closed this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: fragmentConn missing CloseWrite method when used with REALITY server (v26.7.11, regression from v26.6.1)

2 participants