mirror of
https://github.com/go-i2p/go-i2ptunnel.git
synced 2025-12-20 15:15:52 -05:00
SOCKS implementation based on txthinking/socks5
This commit is contained in:
47
lib/socks/client/handle.go
Normal file
47
lib/socks/client/handle.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user