mirror of
https://github.com/jpillora/chisel
synced 2026-06-08 15:07:02 +00:00
Merge branch 'client-socks' of https://github.com/aus/chisel into red
This commit is contained in:
+26
-1
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-socks5"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/jpillora/backoff"
|
||||
"github.com/aus/chisel/share"
|
||||
@@ -42,6 +43,7 @@ type Client struct {
|
||||
running bool
|
||||
runningc chan error
|
||||
connStats chshare.ConnStats
|
||||
socksServer *socks5.Server
|
||||
}
|
||||
|
||||
//NewClient creates a new client instance
|
||||
@@ -68,11 +70,15 @@ func NewClient(config *Config) (*Client, error) {
|
||||
//swap to websockets scheme
|
||||
u.Scheme = strings.Replace(u.Scheme, "http", "ws", 1)
|
||||
shared := &chshare.Config{}
|
||||
createSocksServer := false
|
||||
for _, s := range config.Remotes {
|
||||
r, err := chshare.DecodeRemote(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to decode remote '%s': %s", s, err)
|
||||
}
|
||||
if r.Socks && r.Reverse {
|
||||
createSocksServer = true
|
||||
}
|
||||
shared.Remotes = append(shared.Remotes, r)
|
||||
}
|
||||
config.shared = shared
|
||||
@@ -102,6 +108,14 @@ func NewClient(config *Config) (*Client, error) {
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
if createSocksServer {
|
||||
socksConfig := &socks5.Config{}
|
||||
client.socksServer, err = socks5.New(socksConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
@@ -272,6 +286,12 @@ func (c *Client) Close() error {
|
||||
func (c *Client) connectStreams(chans <-chan ssh.NewChannel) {
|
||||
for ch := range chans {
|
||||
remote := string(ch.ExtraData())
|
||||
socks := remote == "socks"
|
||||
if socks && c.socksServer == nil {
|
||||
c.Debugf("Denied socks request, please enable client socks remote.")
|
||||
ch.Reject(ssh.Prohibited, "SOCKS5 is not enabled on the client")
|
||||
continue
|
||||
}
|
||||
stream, reqs, err := ch.Accept()
|
||||
if err != nil {
|
||||
c.Debugf("Failed to accept stream: %s", err)
|
||||
@@ -279,6 +299,11 @@ func (c *Client) connectStreams(chans <-chan ssh.NewChannel) {
|
||||
}
|
||||
go ssh.DiscardRequests(reqs)
|
||||
l := c.Logger.Fork("conn#%d", c.connStats.New())
|
||||
go chshare.HandleTCPStream(l, &c.connStats, stream, remote)
|
||||
if socks {
|
||||
go chshare.HandleSocksStream(l, c.socksServer, &c.connStats, stream)
|
||||
} else {
|
||||
go chshare.HandleTCPStream(l, &c.connStats, stream, remote)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,8 @@ var clientHelp = `
|
||||
socks
|
||||
5000:socks
|
||||
R:2222:localhost:22
|
||||
R:socks
|
||||
R:5000:socks
|
||||
|
||||
When the chisel server has --socks5 enabled, remotes can
|
||||
specify "socks" in place of remote-host and remote-port.
|
||||
@@ -235,6 +237,8 @@ var clientHelp = `
|
||||
be prefixed with R to denote that they are reversed. That
|
||||
is, the server will listen and accept connections, and they
|
||||
will be proxied through the client which specified the remote.
|
||||
Reverse remotes specifying "R:socks" will terminate a connection
|
||||
at the client's internal SOCKS5 proxy.
|
||||
|
||||
Options:
|
||||
|
||||
|
||||
+1
-15
@@ -2,7 +2,6 @@ package chserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -179,22 +178,9 @@ func (s *Server) handleSSHChannels(clientLog *chshare.Logger, chans <-chan ssh.N
|
||||
//handle stream type
|
||||
connID := s.connStats.New()
|
||||
if socks {
|
||||
go s.handleSocksStream(clientLog.Fork("socksconn#%d", connID), stream)
|
||||
go chshare.HandleSocksStream(clientLog.Fork("socksconn#%d", connID), s.socksServer, &s.connStats, stream)
|
||||
} else {
|
||||
go chshare.HandleTCPStream(clientLog.Fork("conn#%d", connID), &s.connStats, stream, remote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleSocksStream(l *chshare.Logger, src io.ReadWriteCloser) {
|
||||
conn := chshare.NewRWCConn(src)
|
||||
s.connStats.Open()
|
||||
l.Debugf("%s Opening", s.connStats)
|
||||
err := s.socksServer.ServeConn(conn)
|
||||
s.connStats.Close()
|
||||
if err != nil && !strings.HasSuffix(err.Error(), "EOF") {
|
||||
l.Debugf("%s: Closed (error: %s)", s.connStats, err)
|
||||
} else {
|
||||
l.Debugf("%s: Closed", s.connStats)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,6 @@ func DecodeRemote(s string) (*Remote, error) {
|
||||
p := parts[i]
|
||||
//last part "socks"?
|
||||
if i == len(parts)-1 && p == "socks" {
|
||||
if reverse {
|
||||
// TODO allow reverse+socks by having client
|
||||
// automatically start local SOCKS5 server
|
||||
return nil, errors.New("'socks' incompatible with reverse port forwarding")
|
||||
}
|
||||
r.Socks = true
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/armon/go-socks5"
|
||||
"github.com/jpillora/sizestr"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
@@ -56,3 +57,17 @@ func HandleTCPStream(l *Logger, connStats *ConnStats, src io.ReadWriteCloser, re
|
||||
connStats.Close()
|
||||
l.Debugf("%s: Close (sent %s received %s)", connStats, sizestr.ToString(s), sizestr.ToString(r))
|
||||
}
|
||||
|
||||
func HandleSocksStream(l *Logger, server *socks5.Server, connStats *ConnStats, src io.ReadWriteCloser) {
|
||||
conn := NewRWCConn(src)
|
||||
connStats.Open()
|
||||
l.Debugf("%s Opening", connStats)
|
||||
err := server.ServeConn(conn)
|
||||
connStats.Close()
|
||||
|
||||
if err != nil && !strings.HasSuffix(err.Error(), "EOF") {
|
||||
l.Debugf("%s: Closed (error: %s)", connStats, err)
|
||||
} else {
|
||||
l.Debugf("%s: Closed", connStats)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user