SOCKS implementation based on txthinking/socks5

This commit is contained in:
eyedeekay
2025-02-07 12:17:18 -05:00
parent 916b545ac8
commit 11fba0d9ab
2 changed files with 99 additions and 3 deletions

View File

@@ -0,0 +1,47 @@
package socks
import (
"net"
"github.com/go-i2p/go-forward/config"
"github.com/go-i2p/go-forward/packet"
"github.com/go-i2p/go-forward/stream"
"github.com/txthinking/socks5"
)
var socksHandler socks5.Handler = &SOCKS{}
// TCPHandle implements socks5.Handler.
func (s *SOCKS) TCPHandle(_ *socks5.Server, conn *net.TCPConn, req *socks5.Request) error {
// Connect to destination through I2P
i2pConn, err := s.Garlic.Dial("tcp", req.Address())
if err != nil {
return err
}
defer i2pConn.Close()
// Forward data between TCP and I2P connections
err = stream.Forward(nil, conn, i2pConn, config.DefaultConfig())
return err
}
// UDPHandle implements socks5.Handler.
func (s *SOCKS) UDPHandle(_ *socks5.Server, addr *net.UDPAddr, d *socks5.Datagram) error {
// Connect to destination through I2P
i2pConn, err := s.Garlic.DialRemote("udp", d.Address())
if err != nil {
return err
}
defer i2pConn.Close()
// Create UDP connection back to client
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
return err
}
defer conn.Close()
// Forward packets between UDP and I2P connections
err = packet.Forward(nil, conn, i2pConn, config.DefaultConfig())
return err
}

View File

@@ -40,11 +40,16 @@ When a client connects to this SOCKS5 proxy:
**/
import (
"context"
"fmt"
"net"
"strconv"
"sync"
i2pconv "github.com/go-i2p/go-i2ptunnel-config/lib"
i2ptunnel "github.com/go-i2p/go-i2ptunnel/lib/core"
"github.com/go-i2p/onramp"
"github.com/txthinking/socks5"
)
var implementSOCKS i2ptunnel.I2PTunnel = &SOCKS{}
@@ -56,11 +61,17 @@ type SOCKS struct {
i2pconv.TunnelConfig
// The tunnel status
i2ptunnel.I2PTunnelStatus
// SOCKS5 server instance
*socks5.Server
// Channel for shutdown signaling
done chan struct{}
// Mutex for server operations
mu sync.Mutex
// Error history of the tunnel
Errors []i2ptunnel.I2PTunnelError
// Context for cleanup
ctx context.Context
cancel context.CancelFunc
}
func (s *SOCKS) recordError(err error) {
@@ -97,7 +108,31 @@ func (s *SOCKS) Options() map[string]string {
// Start the tunnel
func (s *SOCKS) Start() error {
panic("unimplemented")
s.mu.Lock()
defer s.mu.Unlock()
if s.Server != nil {
return nil // Already started
}
// Create context for managing goroutines
s.ctx, s.cancel = context.WithCancel(context.Background())
s.done = make(chan struct{})
// Create SOCKS5 server
addr := net.JoinHostPort(s.TunnelConfig.Interface, strconv.Itoa(s.TunnelConfig.Port))
server, err := socks5.NewClassicServer(addr, "", "", "", 0, 0)
if err != nil {
s.recordError(err)
return fmt.Errorf("failed to create SOCKS5 server: %w", err)
}
s.Server = server
s.I2PTunnelStatus = i2ptunnel.I2PTunnelStatusStarting
s.Server.Handle = s
s.Server.ListenAndServe(s)
return nil
}
// Get the tunnel's status
@@ -107,7 +142,21 @@ func (s *SOCKS) Status() i2ptunnel.I2PTunnelStatus {
// Stop the tunnel
func (s *SOCKS) Stop() error {
panic("unimplemented")
s.mu.Lock()
defer s.mu.Unlock()
if s.Server != nil {
s.I2PTunnelStatus = i2ptunnel.I2PTunnelStatusStopping
close(s.done)
s.cancel()
if err := s.Server.Shutdown(); err != nil {
s.recordError(err)
return err
}
s.Server = nil
s.I2PTunnelStatus = i2ptunnel.I2PTunnelStatusStopped
}
return nil
}
// Get the tunnel's I2P target. Nil in the case of one-to-many clients like SOCKS5 and HTTP