diff options
| author | gabrix73 <gabriel1@frozenstar.info> | 2026-04-10 16:10:48 +0200 |
|---|---|---|
| committer | gabrix73 <gabriel1@frozenstar.info> | 2026-04-10 16:10:48 +0200 |
| commit | 88375da30ea667ec25c2000874557fcc4785a558 (patch) | |
| tree | 71364a43230977481c6d3280246aa8bb48562bdc /transport/tor/tor.go | |
| download | khimera-88375da30ea667ec25c2000874557fcc4785a558.tar.gz khimera-88375da30ea667ec25c2000874557fcc4785a558.tar.xz khimera-88375da30ea667ec25c2000874557fcc4785a558.zip | |
Initial commit: Veilith v0.9 - P2P Encrypted Messenger
Military-grade secure messenger with:
- End-to-End Encryption (Noise Protocol XX)
- Forward Secrecy (automatic session rotation)
- Anti-Traffic Analysis (padding + cover traffic)
- Secure Deletion (DOD 5220.22-M)
- Tor Integration (embedded with bridge support)
- Portable Mode (no installation required)
Generated with Claude Code
Diffstat (limited to 'transport/tor/tor.go')
| -rw-r--r-- | transport/tor/tor.go | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/transport/tor/tor.go b/transport/tor/tor.go new file mode 100644 index 0000000..a6a1e35 --- /dev/null +++ b/transport/tor/tor.go @@ -0,0 +1,129 @@ +// Package tor implements Tor Hidden Service transport +package tor + +import ( + "fmt" + "net" + "net/url" + + "golang.org/x/net/proxy" + + "veilith/transport" +) + +// TorTransport implements Tor-based networking +type TorTransport struct { + socksProxy string // SOCKS5 proxy address (default: 127.0.0.1:9050) + dialer proxy.Dialer + listener net.Listener + closed bool +} + +// NewTorTransport creates a new Tor transport +func NewTorTransport(socksProxy string) (*TorTransport, error) { + if socksProxy == "" { + socksProxy = "127.0.0.1:9050" // Default Tor SOCKS proxy + } + + // Create SOCKS5 dialer + proxyURL, err := url.Parse("socks5://" + socksProxy) + if err != nil { + return nil, fmt.Errorf("invalid SOCKS proxy address: %w", err) + } + + dialer, err := proxy.FromURL(proxyURL, proxy.Direct) + if err != nil { + return nil, fmt.Errorf("failed to create SOCKS dialer: %w", err) + } + + return &TorTransport{ + socksProxy: socksProxy, + dialer: dialer, + }, nil +} + +// Connect connects to a Tor Hidden Service (.onion address) +func (t *TorTransport) Connect(address string) (net.Conn, error) { + if t.closed { + return nil, fmt.Errorf("tor transport is closed") + } + + // Validate .onion address + if !isOnionAddress(address) { + return nil, fmt.Errorf("invalid .onion address: %s", address) + } + + // Connect via SOCKS proxy + conn, err := t.dialer.Dial("tcp", address) + if err != nil { + return nil, fmt.Errorf("failed to connect to %s: %w", address, err) + } + + return conn, nil +} + +// Listen starts a Tor Hidden Service listener +// Note: This is a simplified implementation. In production, you'd need to: +// 1. Configure torrc to create a hidden service +// 2. Get the .onion address from Tor control port +// 3. Listen on the local port specified in torrc +func (t *TorTransport) Listen(address string) (net.Listener, error) { + if t.closed { + return nil, fmt.Errorf("tor transport is closed") + } + + if t.listener != nil { + return nil, fmt.Errorf("already listening") + } + + // Listen on localhost (Tor will forward to this) + // In production, parse the address to get the port + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, fmt.Errorf("failed to create listener: %w", err) + } + + t.listener = listener + return listener, nil +} + +// Type returns the transport type +func (t *TorTransport) Type() transport.TransportType { + return transport.TransportTor +} + +// Close closes the Tor transport +func (t *TorTransport) Close() error { + if t.closed { + return nil + } + + t.closed = true + + if t.listener != nil { + if err := t.listener.Close(); err != nil { + return fmt.Errorf("failed to close listener: %w", err) + } + t.listener = nil + } + + return nil +} + +// GetSOCKSProxy returns the SOCKS proxy address +func (t *TorTransport) GetSOCKSProxy() string { + return t.socksProxy +} + +// isOnionAddress checks if an address is a valid .onion address +func isOnionAddress(address string) bool { + // Simple validation: check if it contains ".onion" + // In production, use regex to validate v3 onion addresses (56 chars base32) + return len(address) > 6 && address[len(address)-6:] == ".onion" || + len(address) > 13 && address[len(address)-13:len(address)-7] == ".onion:" +} + +// String returns a string representation +func (t *TorTransport) String() string { + return fmt.Sprintf("TorTransport(proxy=%s, closed=%v)", t.socksProxy, t.closed) +} |
