tor.go raw

   1  // Package tor provides a Tor hidden service transport for the relay.
   2  // It wraps the existing pkg/tor service as a pluggable transport.
   3  package tor
   4  
   5  import (
   6  	"context"
   7  	"net/http"
   8  
   9  	"next.orly.dev/pkg/lol/log"
  10  
  11  	torservice "next.orly.dev/pkg/tor"
  12  )
  13  
  14  // Config holds Tor transport configuration.
  15  type Config struct {
  16  	// Port is the internal port for the hidden service.
  17  	Port int
  18  	// DataDir is the directory for Tor data (torrc, keys, hostname, etc.).
  19  	DataDir string
  20  	// Binary is the path to the tor executable.
  21  	Binary string
  22  	// SOCKSPort is the port for outbound SOCKS connections (0 = disabled).
  23  	SOCKSPort int
  24  	// Handler is the HTTP handler to serve.
  25  	Handler http.Handler
  26  }
  27  
  28  // Transport serves the relay as a Tor hidden service.
  29  type Transport struct {
  30  	cfg     *Config
  31  	service *torservice.Service
  32  }
  33  
  34  // New creates a new Tor transport.
  35  func New(cfg *Config) *Transport {
  36  	return &Transport{cfg: cfg}
  37  }
  38  
  39  func (t *Transport) Name() string { return "tor" }
  40  
  41  func (t *Transport) Start(ctx context.Context) error {
  42  	svcCfg := &torservice.Config{
  43  		Port:      t.cfg.Port,
  44  		DataDir:   t.cfg.DataDir,
  45  		Binary:    t.cfg.Binary,
  46  		SOCKSPort: t.cfg.SOCKSPort,
  47  		Handler:   t.cfg.Handler,
  48  	}
  49  
  50  	var err error
  51  	t.service, err = torservice.New(svcCfg)
  52  	if err != nil {
  53  		return err
  54  	}
  55  
  56  	if err = t.service.Start(); err != nil {
  57  		t.service = nil
  58  		return err
  59  	}
  60  
  61  	if addr := t.service.OnionWSAddress(); addr != "" {
  62  		log.I.F("Tor hidden service listening on port %d, address: %s", t.cfg.Port, addr)
  63  	} else {
  64  		log.I.F("Tor hidden service listening on port %d (waiting for .onion address)", t.cfg.Port)
  65  	}
  66  
  67  	return nil
  68  }
  69  
  70  func (t *Transport) Stop(ctx context.Context) error {
  71  	if t.service == nil {
  72  		return nil
  73  	}
  74  	return t.service.Stop()
  75  }
  76  
  77  func (t *Transport) Addresses() []string {
  78  	if t.service == nil {
  79  		return nil
  80  	}
  81  	if addr := t.service.OnionWSAddress(); addr != "" {
  82  		return []string{addr}
  83  	}
  84  	return nil
  85  }
  86  
  87  // Service returns the underlying Tor service for access to Tor-specific
  88  // functionality (e.g., OnionAddress, DataDir).
  89  func (t *Transport) Service() *torservice.Service {
  90  	return t.service
  91  }
  92