feat(socks): add socks5 user and password

This commit is contained in:
zarazaex69
2026-05-10 13:56:03 +03:00
parent 3100577b0d
commit af49d17e8e
3 changed files with 50 additions and 5 deletions

View File

@@ -40,6 +40,8 @@ type config struct {
clientID string
socksPort int
socksHost string
socksUser string
socksPass string
keyHex string
debug bool
dataDir string
@@ -172,6 +174,8 @@ func parseFlagsFrom(args []string, errorHandling flag.ErrorHandling) (config, er
fs.StringVar(&cfg.clientID, "client-id", "", "Client ID: binds one srv to one cnc (required)")
fs.IntVar(&cfg.socksPort, "socks-port", 0, "SOCKS5 port (client only)")
fs.StringVar(&cfg.socksHost, "socks-host", "", "SOCKS5 listen host (client only)")
fs.StringVar(&cfg.socksUser, "socks-user", "", "SOCKS5 username for incoming connections (client only, optional)")
fs.StringVar(&cfg.socksPass, "socks-pass", "", "SOCKS5 password for incoming connections (client only, optional)")
fs.StringVar(&cfg.keyHex, "key", "", "Shared encryption key (hex)")
fs.BoolVar(&cfg.debug, "debug", false, "Enable verbose logging")
fs.StringVar(&cfg.dataDir, "data", "", "Path to data directory")
@@ -250,6 +254,8 @@ func toSessionConfig(cfg config) session.Config {
KeyHex: cfg.keyHex,
SOCKSHost: cfg.socksHost,
SOCKSPort: cfg.socksPort,
SOCKSUser: cfg.socksUser,
SOCKSPass: cfg.socksPass,
DNSServer: cfg.dnsServer,
SOCKSProxyAddr: cfg.socksProxyAddr,
SOCKSProxyPort: cfg.socksProxyPort,

View File

@@ -118,6 +118,8 @@ type Config struct {
KeyHex string
SOCKSHost string
SOCKSPort int
SOCKSUser string
SOCKSPass string
DNSServer string
SOCKSProxyAddr string
SOCKSProxyPort int
@@ -357,8 +359,8 @@ func Run(ctx context.Context, cfg Config) error {
cfg.ClientID,
fmt.Sprintf("%s:%d", cfg.SOCKSHost, cfg.SOCKSPort),
cfg.DNSServer,
"",
"",
cfg.SOCKSUser,
cfg.SOCKSPass,
cfg.VideoWidth,
cfg.VideoHeight,
cfg.VideoFPS,

View File

@@ -36,6 +36,8 @@ var (
ErrUnsupportedAddressType = errors.New("unsupported address type")
// ErrRemoteNotReady is returned when the server-side stream fails to signal readiness.
ErrRemoteNotReady = errors.New("remote not ready")
// ErrSOCKSAuthFailed is returned when username/password authentication is rejected.
ErrSOCKSAuthFailed = errors.New("SOCKS5 authentication failed")
)
// Client handles local SOCKS5 connections and tunnels them to the server.
@@ -47,6 +49,8 @@ type Client struct {
sessMu sync.RWMutex
clientID string
dnsServer string
socksUser string
socksPass string
}
// Run starts the client with the specified parameters.
@@ -100,8 +104,8 @@ func RunWithReady(
clientID string,
localAddr string,
dnsServer,
_ string,
_ string,
socksUser string,
socksPass string,
onReady func(),
videoWidth int,
videoHeight int,
@@ -128,7 +132,7 @@ func RunWithReady(
return fmt.Errorf("setupCipher failed: %w", err)
}
c := &Client{cipher: cipher, clientID: clientID, dnsServer: dnsServer}
c := &Client{cipher: cipher, clientID: clientID, dnsServer: dnsServer, socksUser: socksUser, socksPass: socksPass}
if err := c.bringUpLink(
runCtx, linkName, transportName, carrierName, roomURL, cancel,
@@ -411,12 +415,45 @@ func (c *Client) socks5Handshake(conn net.Conn) error {
if _, err := io.ReadFull(conn, methods); err != nil {
return fmt.Errorf("read socks5 methods: %w", err)
}
if c.socksUser != "" {
// RFC 1929: method 0x02 = username/password auth.
if _, err := conn.Write([]byte{5, 2}); err != nil {
return fmt.Errorf("write socks5 auth method: %w", err)
}
if err := c.socks5UserPassAuth(conn); err != nil {
return err
}
return nil
}
if _, err := conn.Write([]byte{5, 0}); err != nil {
return fmt.Errorf("write socks5 auth: %w", err)
}
return nil
}
func (c *Client) socks5UserPassAuth(conn net.Conn) error {
user := []byte(c.socksUser)
pass := []byte(c.socksPass)
req := make([]byte, 0, 3+len(user)+len(pass))
req = append(req, 0x01, byte(len(user)))
req = append(req, user...)
req = append(req, byte(len(pass)))
req = append(req, pass...)
if _, err := conn.Write(req); err != nil {
return fmt.Errorf("write socks5 user/pass: %w", err)
}
resp := make([]byte, 2)
if _, err := io.ReadFull(conn, resp); err != nil {
return fmt.Errorf("read socks5 auth response: %w", err)
}
if resp[1] != 0x00 {
return ErrSOCKSAuthFailed
}
return nil
}
func (c *Client) socks5Request(conn net.Conn) (string, int, error) {
header := make([]byte, 4)
if _, err := io.ReadFull(conn, header); err != nil {