Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CloseWrite() method to rwcConn in cnet/conn_rwc.go to support proper TCP connection closure in SOCKS5 mode. #548

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

threatexpert
Copy link

I encountered an issue while using Chisel in SOCKS5 mode, where the following connection flow caused unexpected behavior:

tcpclient ---use-socks5--> chisel-client --> chisel-server --> tcpserver
When the tcpserver actively closes the TCP connection, the chisel-server is notified correctly. However, the chisel-client does not receive the closure notification, which I believe is a bug.
If the tcpclient actively closes the TCP connection, the chisel-server successfully closes the connection with tcpserver, and everything works as expected.
Root Cause: Upon investigation, I found that when a channel object is passed through the go-socks5 process, the conversion to NewRWCConn(stream) prevents the CloseWrite method from being called on the connection.

In go-socks5/request.go, the following code is responsible for handling the connection closure:

type closeWriter interface {
    CloseWrite() error
}

// proxy is used to shuffle data from src to destination, and sends errors down a dedicated channel
func proxy(dst io.Writer, src io.Reader, errCh chan error) {
    _, err := io.Copy(dst, src)
    if tcpConn, ok := dst.(closeWriter); ok {
        tcpConn.CloseWrite()
    }
    errCh <- err
}

Here, the dst object needs to implement the closeWriter interface. When tcpserver actively closes the TCP connection, the chisel-server attempts to close the channel. However, since the object net.Conn from NewRWCConn does not implement CloseWrite, the connection closure does not propagate properly.

Solution: I believe adding a CloseWrite() method to cnet/conn_rwc.go would resolve this issue. The method would attempt to call CloseWrite on the underlying ReadWriteCloser object, if it supports it.

The proposed method is:

type closeWriter interface {
    CloseWrite() error
}

func (c *rwcConn) CloseWrite() error {
    if cw, ok := c.ReadWriteCloser.(closeWriter); ok {
        return cw.CloseWrite()
    }
    return nil
}

This change ensures that the rwcConn type can correctly close connections when necessary, especially when the connection involves a channel object that supports the CloseWrite() method. This will fix the issue where chisel-client fails to receive the connection closure notification when tcpserver closes the connection.

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.

1 participant