Add AMP Cache registration Method to Conjure

Adds an AMP Cache registration method to the Conjure client

This essentially just adds commandline flags to specify the AMP Cache URL and preferred STUN address to use for the registration method and then calls the appropriate station method.

To use ampcache as an alternative registration method, simply append the -ampcache flag to the ClientTransportPlugin line in your torrc file along with an ampcache address such as https://cdn.ampproject.org/

The work to implement this for the station is more involved

Edited by onyinyang

Merge request reports

Loading
+24 −8
Changes for client/conjure/registration.go: 24 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -24,10 +24,12 @@ import (
type ConjureConfig struct {
	RegisterURL   string // URL of the conjure bidirectional registration API endpoint
	Fronts        []string
	AMPCacheURL   string
	BridgeAddress string // IP address of the Tor Conjure PT bridge
	UTLSClientID  string
	UTLSRemoveSNI bool
	Transport     string
	STUNAddr      string
}

type Rendezvous struct {
@@ -98,6 +100,9 @@ func Register(config *ConjureConfig) (net.Conn, error) {

	}

	var registrar tapdance.Registrar
	var err error

	// APIRegistrarBidirectional expects an HTTP client for sending the registration request.
	// The http.RoundTripper associated with this client dictates the censorship-resistant
	// rendezvous method used to establish a connection with the registration server.
@@ -114,14 +119,18 @@ func Register(config *ConjureConfig) (net.Conn, error) {
	}

	// The registration step connects a client with a phantom IP address.
	// There are currently two options for registration:
	//   1) APIRegistrarBidirectional: this is a bidirectional registration process that allows a
	// There are currently three options for registration:
	//   1) APIRegistrarBidirectional: this is a bidirectional registration process that allows
	//        a client to submit a REST API request over HTTP for the phantom IP
	//   2) DecoyRegistrar: this is a unidirectional registration process used by the
	//   2) AMPCacheRegistrarBidirectional: this is a bidirectional registration process that
	//       allows a client to use AMPCache as a proxy to submit a request to the registration
	//       server for the phantom IP
	//   3) DecoyRegistrar: this is a unidirectional registration process used by the
	//        original TapDance protocol in which the client essentially tells the refraction
	//        station which phantom IP to use
	// For simplicity, we use the bidirectional registration process. Different censorship
	// resistant transport methods can be used to tunnel the HTTP requests, such as domain fronting
	// For simplicity, we implement support for the bidirectional
	// registration and ampcache registration processes. Different censorship resistant
	// transport methods can be used to tunnel the HTTP requests, such as domain fronting
	regConfig := &registration.Config{
		Target: config.RegisterURL + "/api/register-bidirectional", //Note: this goes in the HTTP request
		// TODO: reach out and ask what a reasonable value to set this to is
@@ -130,8 +139,16 @@ func Register(config *ConjureConfig) (net.Conn, error) {
		Bidirectional: true,
		HTTPClient:    client,
	}

	registrar, err := registration.NewAPIRegistrar(regConfig)
	if config.AMPCacheURL != "" {
		regConfig.Target = config.RegisterURL + "/amp/register-bidirectional" //Note: this goes in the HTTP request
		regConfig.AMPCacheURL = config.AMPCacheURL
		regConfig.STUNAddr = config.STUNAddr
		log.Println("Register through AMP cache at:", regConfig.Target)
		registrar, err = registration.NewAMPCacheRegistrar(regConfig)
	} else {
		log.Println("Register through API with:", regConfig.Target)
		registrar, err = registration.NewAPIRegistrar(regConfig)
	}
	if err != nil {
		return nil, err
	}
@@ -162,7 +179,6 @@ func Register(config *ConjureConfig) (net.Conn, error) {
		return nil, err
	}

	log.Printf("Using the registration API at %s", regConfig.Target)
	// Make a connection to the bridge through the phantom
	// This will register the client, obtaining a phantom address and connect
	// to that phantom address all in one go
+13 −3
Changes for client/conjure.go: 13 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ import (
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
@@ -28,6 +27,10 @@ const RetryInterval = 10 * time.Second

// Get SOCKS arguments and populate config
func getSOCKSArgs(conn *pt.SocksConn, config *conjure.ConjureConfig) {
	// Check to see if our command line options are overriden by SOCKS options
	if arg, ok := conn.Req.Args.Get("ampcache"); ok {
		config.AMPCacheURL = arg
	}
	if arg, ok := conn.Req.Args.Get("url"); ok {
		config.RegisterURL = arg
	}
@@ -52,6 +55,9 @@ func getSOCKSArgs(conn *pt.SocksConn, config *conjure.ConjureConfig) {
	if arg, ok := conn.Req.Args.Get("transport"); ok {
		config.Transport = arg
	}
	if arg, ok := conn.Req.Args.Get("stun"); ok {
		config.STUNAddr = arg
	}
}

// handle the SOCKS conn
@@ -158,10 +164,12 @@ func main() {
		"resolve the log file relative to tor's pt state dir")
	unsafeLogging := flag.Bool("unsafe-logging", false, "prevent logs from being scrubbed")
	frontDomainsCommas := flag.String("fronts", "", "comma-separated list of front domains")
	ampCacheURL := flag.String("ampcache", "", "URL of AMP cache to use as a proxy for signaling")
	registerURL := flag.String("registerURL", "", "URL of the conjure registration station")
	uTLSClientHelloID := flag.String("utls-imitate", "", "type of TLS client to imitate with utls")
	uTLSRemoveSNI := flag.Bool("utls-nosni", false, "remove SNI from client hello(ignored if uTLS is not used)")
	defaultTransport := flag.String("transport", "min", "default transport to connect to phantom proxies")
	stunAddr := flag.String("stun", "stun.antisip.com:3478", "STUN server address needed for IP retrieval, use with ampCacheURL specified")

	flag.Parse()

@@ -172,7 +180,7 @@ func main() {

	// Set up logging
	var logFile io.Writer
	logFile = ioutil.Discard
	logFile = io.Discard
	if *logFilename != "" {
		if *logToStateDir {
			*logFilename = filepath.Join(stateDir, *logFilename)
@@ -210,9 +218,11 @@ func main() {
	config := &conjure.ConjureConfig{
		RegisterURL:   *registerURL,
		Fronts:        frontDomains,
		AMPCacheURL:   *ampCacheURL,
		UTLSClientID:  *uTLSClientHelloID,
		UTLSRemoveSNI: *uTLSRemoveSNI,
		Transport:     *defaultTransport,
		STUNAddr:      *stunAddr,
	}

	// Tor client-side transport setup
@@ -250,7 +260,7 @@ func main() {
	// https://gitweb.torproject.org/torspec.git/tree/pt-spec.txt#n203
	if os.Getenv("TOR_PT_EXIT_ON_STDIN_CLOSE") == "1" {
		go func() {
			if _, err := io.Copy(ioutil.Discard, os.Stdin); err != nil {
			if _, err := io.Copy(io.Discard, os.Stdin); err != nil {
				log.Printf("Error copying os.Stdin to ioutil.Discard: %v", err)
			}
			log.Printf("Terminating because of stdin close")
+8 −4
Changes for go.mod: 8 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ toolchain go1.24.2

require (
	github.com/pires/go-proxyproto v0.8.0
	github.com/refraction-networking/conjure v0.7.11
	github.com/refraction-networking/conjure v0.7.12-0.20250507182851-8676ab6282b8
	github.com/refraction-networking/gotapdance v1.7.10
	github.com/refraction-networking/utls v1.6.7
	gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.6.0
@@ -22,7 +22,7 @@ require (
	github.com/dchest/siphash v1.2.3 // indirect
	github.com/flynn/noise v1.1.0 // indirect
	github.com/gaukas/godicttls v0.0.4 // indirect
	github.com/golang/protobuf v1.5.3 // indirect
	github.com/golang/protobuf v1.5.4 // indirect
	github.com/klauspost/compress v1.17.11 // indirect
	github.com/libp2p/go-reuseport v0.4.0 // indirect
	github.com/mroth/weightedrand v1.0.0 // indirect
@@ -43,7 +43,11 @@ require (
	golang.org/x/net v0.35.0 // indirect
	golang.org/x/sys v0.30.0 // indirect
	golang.org/x/text v0.22.0 // indirect
	google.golang.org/protobuf v1.36.1 // indirect
	google.golang.org/protobuf v1.36.5 // indirect
)

replace github.com/pion/dtls/v2 => github.com/mingyech/dtls/v2 v2.0.0
replace (
	github.com/pion/dtls/v2 => github.com/mingyech/dtls/v2 v2.0.0
	github.com/refraction-networking/conjure v0.7.11 => github.com/refraction-networking/conjure v0.7.12-0.20250507182851-8676ab6282b8

)
+9 −0
Changes for go.sum: 9 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
@@ -63,6 +64,10 @@ github.com/mingyech/dtls/v2 v2.0.0 h1:RKN1CjBs8wct3JnrcRmqnfH3BO0ocYLEhmg62uaHq+
github.com/mingyech/dtls/v2 v2.0.0/go.mod h1:Jvjs/Mzb6dWhNbhnobeR2HC8nmjF5AaLezvpVo+PQ1U=
github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E=
github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
github.com/onyiny-ang/conjure v0.0.0-20250317175424-41a057df91b7 h1:598WINoujUMvCdQNPBM8TCQIqFep9YqWgChyFomIJWA=
github.com/onyiny-ang/conjure v0.0.0-20250317175424-41a057df91b7/go.mod h1:LHOLcsHb+48BQkRynGa3vq3XkoTuqj+/pKcbhbY2vEM=
github.com/onyiny-ang/conjure v0.0.0-20250403172743-ee6762c91e71 h1:/YIJTFmGdzyh2XaA7P3cuUR5Y9zeDh0npejXoi3VjRA=
github.com/onyiny-ang/conjure v0.0.0-20250403172743-ee6762c91e71/go.mod h1:LHOLcsHb+48BQkRynGa3vq3XkoTuqj+/pKcbhbY2vEM=
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0=
@@ -107,6 +112,8 @@ github.com/refraction-networking/conjure v0.7.10 h1:QGH2wna/9cxu760a/RbE6GhEaElG
github.com/refraction-networking/conjure v0.7.10/go.mod h1:7KuAtYfSL0K0WpCScjN9YKiOZ4AQ/8IzSjUtVwWbSv8=
github.com/refraction-networking/conjure v0.7.11 h1:snX4pbaE6RPjEQEa6SOyvDJ+zZSl5ZNOFang9nrbpZ8=
github.com/refraction-networking/conjure v0.7.11/go.mod h1:RkuBcC7pJOBFT78erDnM23sd2Uxygtt47h8jbcbyS10=
github.com/refraction-networking/conjure v0.7.12-0.20250507182851-8676ab6282b8 h1:R791aFlIZQG/8M5nEPeNSKqpeOP4e4l6CzIWpZX3gp0=
github.com/refraction-networking/conjure v0.7.12-0.20250507182851-8676ab6282b8/go.mod h1:LHOLcsHb+48BQkRynGa3vq3XkoTuqj+/pKcbhbY2vEM=
github.com/refraction-networking/ed25519 v0.1.2 h1:08kJZUkAlY7a7cZGosl1teGytV+QEoNxPO7NnRvAB+g=
github.com/refraction-networking/ed25519 v0.1.2/go.mod h1:nxYLUAYt/hmNpAh64PNSQ/tQ9gTIB89wCaGKJlRtZ9I=
github.com/refraction-networking/gotapdance v1.6.8 h1:Niv2zjJB3sxrvrM/vbp/q9W+Ch11rBJ08tMOrOLdbBQ=
@@ -243,6 +250,8 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Loading