From 0acef7959238cbe669904655d395a94d40bada06 Mon Sep 17 00:00:00 2001 From: Mingye Chen Date: Wed, 26 Jul 2023 23:47:53 +0400 Subject: [PATCH] DTLS transport (#164) DTLS transport implementation including transport establishment and tunneling as well as UDP packet handling in the rust detector portion of the station. --- cmd/application/connectingStats.go | 158 ++++ cmd/application/conns.go | 12 +- cmd/application/main.go | 35 +- cmd/registration-server/main.go | 2 + go.mod | 15 +- go.sum | 74 +- on-reboot.sh | 2 +- pkg/core/interfaces/interfaces.go | 19 + pkg/dtls/config.go | 17 + pkg/dtls/dial.go | 83 +++ pkg/dtls/examples/dial/.gitignore | 1 + pkg/dtls/examples/dial/main.go | 38 + pkg/dtls/examples/listen/.gitignore | 1 + pkg/dtls/examples/listen/main.go | 52 ++ pkg/dtls/heartbeat.go | 123 ++++ pkg/dtls/heartbeatConfig.go | 34 + pkg/dtls/heartbeat_test.go | 124 ++++ pkg/dtls/listener.go | 258 +++++++ pkg/dtls/not1reader.go | 19 + pkg/dtls/not1reader_test.go | 27 + pkg/dtls/sctpconn.go | 122 ++++ pkg/dtls/seedtocert.go | 124 ++++ pkg/dtls/server.go | 80 ++ pkg/dtls/server_test.go | 49 ++ .../dns-registrar/requester/config.go | 6 +- .../dns-registrar/requester/requester.go | 16 +- pkg/registrars/registration/api-registrar.go | 2 - pkg/registrars/registration/config.go | 2 + .../registration/decoy-registrar.go | 14 +- pkg/registrars/registration/dns-registrar.go | 11 - pkg/station/lib/registration.go | 28 +- pkg/station/lib/registration_config.go | 3 + pkg/station/lib/registration_ingest.go | 81 ++ pkg/station/lib/transports.go | 3 + pkg/transports/client/transports.go | 2 + pkg/transports/connecting/dtls/client.go | 167 +++++ pkg/transports/connecting/dtls/dnat.go | 149 ++++ pkg/transports/connecting/dtls/dtls.go | 165 +++++ pkg/transports/connecting/dtls/nat.go | 113 +++ pkg/transports/wrapping/min/client.go | 5 + pkg/transports/wrapping/obfs4/client.go | 5 + pkg/transports/wrapping/prefix/client.go | 5 + proto/signalling.pb.go | 690 ++++++++++-------- proto/signalling.proto | 4 + 44 files changed, 2576 insertions(+), 364 deletions(-) create mode 100644 cmd/application/connectingStats.go create mode 100644 pkg/dtls/config.go create mode 100644 pkg/dtls/dial.go create mode 100644 pkg/dtls/examples/dial/.gitignore create mode 100644 pkg/dtls/examples/dial/main.go create mode 100644 pkg/dtls/examples/listen/.gitignore create mode 100644 pkg/dtls/examples/listen/main.go create mode 100644 pkg/dtls/heartbeat.go create mode 100644 pkg/dtls/heartbeatConfig.go create mode 100644 pkg/dtls/heartbeat_test.go create mode 100644 pkg/dtls/listener.go create mode 100644 pkg/dtls/not1reader.go create mode 100644 pkg/dtls/not1reader_test.go create mode 100644 pkg/dtls/sctpconn.go create mode 100644 pkg/dtls/seedtocert.go create mode 100644 pkg/dtls/server.go create mode 100644 pkg/dtls/server_test.go create mode 100644 pkg/transports/connecting/dtls/client.go create mode 100644 pkg/transports/connecting/dtls/dnat.go create mode 100644 pkg/transports/connecting/dtls/dtls.go create mode 100644 pkg/transports/connecting/dtls/nat.go diff --git a/cmd/application/connectingStats.go b/cmd/application/connectingStats.go new file mode 100644 index 00000000..45c99f88 --- /dev/null +++ b/cmd/application/connectingStats.go @@ -0,0 +1,158 @@ +package main + +import ( + "fmt" + "sync/atomic" + + cj "github.com/refraction-networking/conjure/pkg/station/lib" +) + +var _ cj.ConnectingTpStats = &connStats{} + +type connectingCounts struct { + numCreatedConnecting int64 + numDialSuccessfulConnecting int64 + numListenSuccessfulConnecting int64 + numSuccessfulConnecting int64 + numTimeoutConnecting int64 + numAuthFailConnecting int64 + numOtherFailConnecting int64 +} + +func (c *connStats) AddCreatedConnecting(asn uint, cc string, tp string) { + atomic.AddInt64(&c.numCreatedConnecting, 1) + + if isValidCC(cc) { + c.m.Lock() + defer c.m.Unlock() + if _, ok := c.v4geoIPMap[asn]; !ok { + // We haven't seen asn before, so add it to the map + c.v4geoIPMap[asn] = &asnCounts{} + c.v4geoIPMap[asn].cc = cc + } + atomic.AddInt64(&c.v4geoIPMap[asn].numCreatedConnecting, 1) + } +} + +func (c *connStats) AddCreatedToListenSuccessfulConnecting(asn uint, cc string, tp string) { + atomic.AddInt64(&c.numCreatedConnecting, -1) + atomic.AddInt64(&c.numListenSuccessfulConnecting, 1) + + if isValidCC(cc) { + c.m.Lock() + defer c.m.Unlock() + if _, ok := c.v4geoIPMap[asn]; !ok { + // We haven't seen asn before, so add it to the map + c.v4geoIPMap[asn] = &asnCounts{} + c.v4geoIPMap[asn].cc = cc + } + atomic.AddInt64(&c.v4geoIPMap[asn].numCreatedConnecting, -1) + atomic.AddInt64(&c.v4geoIPMap[asn].numListenSuccessfulConnecting, 1) + } +} + +func (c *connStats) AddCreatedToDialSuccessfulConnecting(asn uint, cc string, tp string) { + atomic.AddInt64(&c.numCreatedConnecting, -1) + atomic.AddInt64(&c.numDialSuccessfulConnecting, 1) + + if isValidCC(cc) { + c.m.Lock() + defer c.m.Unlock() + if _, ok := c.v4geoIPMap[asn]; !ok { + // We haven't seen asn before, so add it to the map + c.v4geoIPMap[asn] = &asnCounts{} + c.v4geoIPMap[asn].cc = cc + } + atomic.AddInt64(&c.v4geoIPMap[asn].numCreatedConnecting, -1) + atomic.AddInt64(&c.v4geoIPMap[asn].numDialSuccessfulConnecting, 1) + } +} + +func (c *connStats) AddCreatedToSuccessfulConnecting(asn uint, cc string, tp string) { + atomic.AddInt64(&c.numCreatedConnecting, -1) + atomic.AddInt64(&c.numSuccessfulConnecting, 1) + + if isValidCC(cc) { + c.m.Lock() + defer c.m.Unlock() + if _, ok := c.v4geoIPMap[asn]; !ok { + // We haven't seen asn before, so add it to the map + c.v4geoIPMap[asn] = &asnCounts{} + c.v4geoIPMap[asn].cc = cc + } + atomic.AddInt64(&c.v4geoIPMap[asn].numCreatedConnecting, -1) + atomic.AddInt64(&c.v4geoIPMap[asn].numSuccessfulConnecting, 1) + } +} + +func (c *connStats) AddCreatedToTimeoutConnecting(asn uint, cc string, tp string) { + atomic.AddInt64(&c.numCreatedConnecting, -1) + atomic.AddInt64(&c.numTimeoutConnecting, 1) + + if isValidCC(cc) { + c.m.Lock() + defer c.m.Unlock() + if _, ok := c.v4geoIPMap[asn]; !ok { + // We haven't seen asn before, so add it to the map + c.v4geoIPMap[asn] = &asnCounts{} + c.v4geoIPMap[asn].cc = cc + } + atomic.AddInt64(&c.v4geoIPMap[asn].numCreatedConnecting, -1) + atomic.AddInt64(&c.v4geoIPMap[asn].numTimeoutConnecting, 1) + } +} + +func (c *connStats) AddSuccessfulToDiscardedConnecting(asn uint, cc string, tp string) { +} + +func (c *connStats) AddAuthFailConnecting(asn uint, cc string, tp string) { + atomic.AddInt64(&c.numAuthFailConnecting, 1) + + if isValidCC(cc) { + c.m.Lock() + defer c.m.Unlock() + if _, ok := c.v4geoIPMap[asn]; !ok { + // We haven't seen asn before, so add it to the map + c.v4geoIPMap[asn] = &asnCounts{} + c.v4geoIPMap[asn].cc = cc + } + atomic.AddInt64(&c.v4geoIPMap[asn].numAuthFailConnecting, 1) + } + +} + +func (c *connStats) AddOtherFailConnecting(asn uint, cc string, tp string) { + atomic.AddInt64(&c.numOtherFailConnecting, 1) + + if isValidCC(cc) { + c.m.Lock() + defer c.m.Unlock() + if _, ok := c.v4geoIPMap[asn]; !ok { + // We haven't seen asn before, so add it to the map + c.v4geoIPMap[asn] = &asnCounts{} + c.v4geoIPMap[asn].cc = cc + } + atomic.AddInt64(&c.v4geoIPMap[asn].numOtherFailConnecting, 1) + } + +} + +func (c *connStats) resetConnecting() { + c.connectingCounts = connectingCounts{} +} + +func (c *connectingCounts) string() string { + totalEndStates := atomic.LoadInt64(&c.numDialSuccessfulConnecting) + atomic.LoadInt64(&c.numListenSuccessfulConnecting) + atomic.LoadInt64(&c.numTimeoutConnecting) + atomic.LoadInt64(&c.numAuthFailConnecting) + atomic.LoadInt64(&c.numOtherFailConnecting) + if totalEndStates < 1 { + totalEndStates = 0 + } + return fmt.Sprintf("%d %d %d %d %d %d %d", + atomic.LoadInt64(&c.numCreatedConnecting), + atomic.LoadInt64(&c.numDialSuccessfulConnecting), + atomic.LoadInt64(&c.numListenSuccessfulConnecting), + atomic.LoadInt64(&c.numTimeoutConnecting), + atomic.LoadInt64(&c.numAuthFailConnecting), + atomic.LoadInt64(&c.numOtherFailConnecting), + totalEndStates, + ) +} diff --git a/cmd/application/conns.go b/cmd/application/conns.go index 2d1cb2d0..3d40bf7f 100644 --- a/cmd/application/conns.go +++ b/cmd/application/conns.go @@ -404,6 +404,8 @@ type statCounts struct { totalTransitions int64 // Number of all transitions tracked numNewConns int64 // Number new connections potentially handshaking numResolved int64 // Number connections that have reached a terminal state. + + connectingCounts } type asnCounts struct { @@ -418,6 +420,8 @@ type connStats struct { ipv6 statCounts v4geoIPMap map[uint]*asnCounts v6geoIPMap map[uint]*asnCounts + + connectingCounts } func (c *connStats) PrintAndReset(logger *log.Logger) { @@ -433,7 +437,7 @@ func (c *connStats) PrintAndReset(logger *log.Logger) { } if numASNs > 0 { - logger.Infof("conn-stats (IPv4): %d %d %d %d %d %.3f %d %.3f %d %.3f %d %.3f %d %.3f %d", + logger.Infof("conn-stats (IPv4): %d %d %d %d %d %.3f %d %.3f %d %.3f %d %.3f %d %.3f %d %s", atomic.LoadInt64(&c.ipv4.numCreated), atomic.LoadInt64(&c.ipv4.numReading), atomic.LoadInt64(&c.ipv4.numChecking), @@ -449,6 +453,7 @@ func (c *connStats) PrintAndReset(logger *log.Logger) { atomic.LoadInt64(&c.ipv4.numClosed), 1000*float64(atomic.LoadInt64(&c.ipv4.numClosed))/epochDur, numASNs, + c.connectingCounts.string(), ) } @@ -484,7 +489,7 @@ func (c *connStats) PrintAndReset(logger *log.Logger) { } for asn, counts := range val { var tt = math.Max(1, float64(atomic.LoadInt64(&counts.totalTransitions))) - logger.Infof("conn-stats-verbose (IPv%d): %d %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %d %d %d %d", + logger.Infof("conn-stats-verbose (IPv%d): %d %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %d %d %d %d %s", ip_ver, asn, counts.cc, @@ -530,6 +535,7 @@ func (c *connStats) PrintAndReset(logger *log.Logger) { atomic.LoadInt64(&counts.numNewConns), atomic.LoadInt64(&c.ipv6.numResolved), atomic.LoadInt64(&counts.numResolved), + counts.connectingCounts.string(), ) } } @@ -602,6 +608,8 @@ func (c *connStats) reset() { c.v6geoIPMap = make(map[uint]*asnCounts) c.epochStart = time.Now() + + c.resetConnecting() } func (c *connStats) addCreated(asn uint, cc string, isIPv4 bool) { diff --git a/cmd/application/main.go b/cmd/application/main.go index 06b98eb5..72b04a3b 100644 --- a/cmd/application/main.go +++ b/cmd/application/main.go @@ -3,6 +3,7 @@ package main import ( "context" "flag" + "net" "os" "os/signal" "strconv" @@ -12,6 +13,7 @@ import ( cj "github.com/refraction-networking/conjure/pkg/station/lib" "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/transports/connecting/dtls" "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" "github.com/refraction-networking/conjure/pkg/transports/wrapping/obfs4" "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" @@ -53,7 +55,38 @@ func main() { } log.SetLevel(logLevel) + connManager := newConnManager(nil) + + conf.RegConfig.ConnectingStats = connManager + regManager := cj.NewRegistrationManager(conf.RegConfig) + + logIPDTLS := func(logger func(asn uint, cc, tp string)) func(*net.IP) { + return func(ip *net.IP) { + cc, err := regManager.GeoIP.CC(*ip) + if err != nil { + return + } + + var asn uint = 0 + if cc != "unk" { + asn, err = regManager.GeoIP.ASN(*ip) + if err != nil { + return + } + } + + logger(asn, cc, "dtls") + } + } + + dtlsTransport, err := dtls.NewTransport(logIPDTLS(connManager.AddAuthFailConnecting), logIPDTLS(connManager.AddOtherFailConnecting), logIPDTLS(connManager.AddCreatedToDialSuccessfulConnecting), logIPDTLS(connManager.AddCreatedToListenSuccessfulConnecting)) + + if err != nil { + log.Fatalf("failed to setup dtls: %v", err) + } + enabledTransports[pb.TransportType_DTLS] = dtlsTransport + sharedLogger = regManager.Logger logger := sharedLogger defer regManager.Cleanup() @@ -98,8 +131,6 @@ func main() { logger.Fatal("error creating ZMQ Ingest: %w", err) } - connManager := newConnManager(nil) - cj.Stat().AddStatsModule(zmqIngester, false) cj.Stat().AddStatsModule(regManager.LivenessTester, false) cj.Stat().AddStatsModule(cj.GetProxyStats(), false) diff --git a/cmd/registration-server/main.go b/cmd/registration-server/main.go index 03e17bc0..3ac34b12 100644 --- a/cmd/registration-server/main.go +++ b/cmd/registration-server/main.go @@ -18,6 +18,7 @@ import ( "github.com/refraction-networking/conjure/pkg/regserver/apiregserver" "github.com/refraction-networking/conjure/pkg/regserver/dnsregserver" "github.com/refraction-networking/conjure/pkg/station/lib" + "github.com/refraction-networking/conjure/pkg/transports/connecting/dtls" "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" "github.com/refraction-networking/conjure/pkg/transports/wrapping/obfs4" "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" @@ -52,6 +53,7 @@ var defaultTransports = map[pb.TransportType]lib.Transport{ pb.TransportType_Min: min.Transport{}, pb.TransportType_Obfs4: obfs4.Transport{}, pb.TransportType_Prefix: prefix.DefaultSet(), + pb.TransportType_DTLS: dtls.Transport{}, // [transports:enable] } diff --git a/go.mod b/go.mod index d58cfbc8..b3775923 100644 --- a/go.mod +++ b/go.mod @@ -4,22 +4,25 @@ go 1.18 require ( github.com/BurntSushi/toml v1.2.1 - github.com/Psiphon-Labs/psiphon-tunnel-core v0.0.14-beta-ios.0.20230714185657-14bf1ee6651a github.com/flynn/noise v1.0.0 github.com/go-redis/redis/v8 v8.11.5 github.com/gorilla/mux v1.8.0 github.com/hashicorp/golang-lru v0.6.0 + github.com/libp2p/go-reuseport v0.3.0 + github.com/mingyech/transport v0.1.1 github.com/mroth/weightedrand v1.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/pebbe/zmq4 v1.2.9 github.com/pelletier/go-toml v1.9.5 + github.com/pion/logging v0.2.2 + github.com/pion/sctp v1.8.7 github.com/pion/stun v0.3.5 github.com/refraction-networking/ed25519 v0.1.2 - github.com/refraction-networking/gotapdance v1.5.6 + github.com/refraction-networking/gotapdance v1.6.0-dtlsbeta github.com/refraction-networking/obfs4 v0.1.1 github.com/refraction-networking/utls v1.2.0 github.com/sirupsen/logrus v1.9.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.4 gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.4.0 golang.org/x/crypto v0.11.0 golang.org/x/net v0.12.0 @@ -27,6 +30,8 @@ require ( google.golang.org/protobuf v1.31.0 ) +require github.com/pion/randutil v0.1.0 // indirect + require ( github.com/andybalholm/brotli v1.0.5-0.20220518190645-786ec621f618 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -34,11 +39,13 @@ require ( github.com/dchest/siphash v1.2.3 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/gopacket v1.1.19 github.com/klauspost/compress v1.15.12 // indirect + github.com/mingyech/dtls v0.1.0 github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sergeyfrolov/bsbuffer v0.0.0-20180903213811-94e85abb8507 // indirect - golang.org/x/sys v0.10.0 // indirect + golang.org/x/sys v0.10.0 golang.org/x/text v0.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 9cf93743..3b953ac6 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Psiphon-Labs/psiphon-tunnel-core v0.0.14-beta-ios.0.20230714185657-14bf1ee6651a h1:FACbqrEyP6lrMZ8NpoS2QZjyXFSmHMrLmzaTAIGxo6U= -github.com/Psiphon-Labs/psiphon-tunnel-core v0.0.14-beta-ios.0.20230714185657-14bf1ee6651a/go.mod h1:dgL9i0nZxGWwKStlEuEli73d0zY2JxM0bdo1MIf5mxs= github.com/andybalholm/brotli v1.0.5-0.20220518190645-786ec621f618 h1:kaHHkLhLE0tRP2uiqVdNtOkQ82XMPDH/SE2ixiXdAYs= github.com/andybalholm/brotli v1.0.5-0.20220518190645-786ec621f618/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -23,17 +21,26 @@ 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/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= +github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= +github.com/mingyech/dtls v0.1.0 h1:AdYeTIbgBK+gPquewN1HdZ6EM7GkuHoa5UNU77Ob1Ns= +github.com/mingyech/dtls v0.1.0/go.mod h1:YStHDz+DrppG95Sruyv/ohTLpFupgFZW9xqYlzJ7vSs= +github.com/mingyech/transport v0.1.1 h1:nvIMoQIe48xM/K30G6WIhsCEti7B+FodMhKiLgk3YXk= +github.com/mingyech/transport v0.1.1/go.mod h1:PPGxXJJy8BpXZWuBWM6Nf1Xze6vWOMSuoKrZFVAEX7c= 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/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -47,15 +54,23 @@ github.com/pebbe/zmq4 v1.2.9 h1:JlHcdgq6zpppNR1tH0wXJq0XK03pRUc4lBlHTD7aj/4= github.com/pebbe/zmq4 v1.2.9/go.mod h1:nqnPueOapVhE2wItZ0uOErngczsJdLOGkebMxaO8r48= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/sctp v1.8.7 h1:JnABvFakZueGAn4KU/4PSKg+GWbF6QWbKTWZOSGJjXw= +github.com/pion/sctp v1.8.7/go.mod h1:g1Ul+ARqZq5JEmoFy87Q/4CePtKnTJ1QCL9dBBdN6AU= github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= +github.com/pion/transport/v2 v2.1.0 h1:tLBmDy/sfPu4UG9QsiKiI7Zav+i9zhUYvg7VlCUpIV8= +github.com/pion/transport/v2 v2.1.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.5.6 h1:Hu09SmlPmQW4Bcq1/Jk9ziHrR2XfTZ+775n2Hsk8KNM= -github.com/refraction-networking/gotapdance v1.5.6/go.mod h1:ztEZmIuA0CXcTaiKz3mvUHMpLfk0eElXXbr3uHmXcdg= +github.com/refraction-networking/gotapdance v1.6.0-dtlsbeta h1:fKbDVKcgTfLReUZXt2E6LzNgVSDksdDWWggxBChJ6JQ= +github.com/refraction-networking/gotapdance v1.6.0-dtlsbeta/go.mod h1:ZPCynd9re3CbvXTXqNHu4EU01Ve5Z2wexy76XC0b1No= github.com/refraction-networking/obfs4 v0.1.1 h1:9AmxHFbafOZzXTGidKI2EeL0FGkIramIlB4dPLg3d+4= github.com/refraction-networking/obfs4 v0.1.1/go.mod h1:wAl/+gWiLsrcykJA3nKJHx89f5/gXGM8UKvty7+mvbM= github.com/refraction-networking/utls v1.2.0 h1:U5f8wkij2NVinfLuJdFP3gCMwIHs+EzvhxmYdXgiapo= @@ -70,25 +85,71 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.4.0 h1:Y7fHDMy11yyjM+YlHfcM3svaujdL+m5DqS444wbj8o4= gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.4.0/go.mod h1:70bhd4JKW/+1HLfm+TMrgHJsUHG4coelMWwiVEJ2gAg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= @@ -97,6 +158,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/on-reboot.sh b/on-reboot.sh index 5ce00291..c2189576 100755 --- a/on-reboot.sh +++ b/on-reboot.sh @@ -132,7 +132,7 @@ build_or_rebuild_iptables filter CJ_INPUT INPUT # The tunnel numbers do not match the core index per the OS, # but instead match the count of cores being used by conjure. echo "Setting up devices tun{${OFFSET}..$((OFFSET + CORE_COUNT -1 ))}, adding rules for them, and turning off RP filters." -for CORE in `seq $OFFSET $((OFFSET + CORE_COUNT -1 ))` +for CORE in `seq $OFFSET $((OFFSET + CORE_COUNT -1 +1 ))` # +1 for connecting UDP transport DNAT injection do tun_setup_fn ${CORE} ${rule_table_name} done diff --git a/pkg/core/interfaces/interfaces.go b/pkg/core/interfaces/interfaces.go index 4faed378..26bcf988 100644 --- a/pkg/core/interfaces/interfaces.go +++ b/pkg/core/interfaces/interfaces.go @@ -1,6 +1,7 @@ package interfaces import ( + "context" "io" "net" @@ -9,6 +10,8 @@ import ( "google.golang.org/protobuf/types/known/anypb" ) +type dialFunc = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) + // Transport provides a generic interface for utilities that allow the client to dial and connect to // a phantom address when creating a Conjure connection. type Transport interface { @@ -36,6 +39,10 @@ type Transport interface { // handle, but are outside of the clients sanity checks. (see prefix transport for an example) SetParams(any, ...bool) error + // Prepare lets the transport use the dialer to prepare. This is called before GetParams to let the + // transport prepare stuff such as nat traversal. + Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error + // GetDstPort returns the destination port that the client should open the phantom connection with. GetDstPort(seed []byte) (uint16, error) @@ -43,11 +50,23 @@ type Transport interface { // as well as bytes from the deterministic random generator associated with the registration // that this ClientTransport is attached to. PrepareKeys(pubkey [32]byte, sharedSecret []byte, dRand io.Reader) error +} + +type WrappingTransport interface { + Transport // Connect returns a net.Conn connection given a context and ConjureReg WrapConn(conn net.Conn) (net.Conn, error) } +type ConnectingTransport interface { + Transport + + WrapDial(dialer dialFunc) (dialFunc, error) + + DisableRegDelay() bool +} + // Overrides makes it possible to treat an array of overrides as a single override note that the // subsequent overrides are not aware of those that come before so they may end up undoing their // changes. diff --git a/pkg/dtls/config.go b/pkg/dtls/config.go new file mode 100644 index 00000000..a56a33ca --- /dev/null +++ b/pkg/dtls/config.go @@ -0,0 +1,17 @@ +package dtls + +import "net" + +type Config struct { + PSK []byte + SCTP SCTPType + LogAuthFail func(*net.IP) + LogOther func(*net.IP) +} + +type SCTPType int + +const ( + ServerAccept SCTPType = iota + ClientOpen +) diff --git a/pkg/dtls/dial.go b/pkg/dtls/dial.go new file mode 100644 index 00000000..788ee1e6 --- /dev/null +++ b/pkg/dtls/dial.go @@ -0,0 +1,83 @@ +package dtls + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + "net" + + "github.com/mingyech/dtls" + "github.com/mingyech/dtls/pkg/protocol/handshake" +) + +// Dial creates a DTLS connection to the given network address using the given shared secret +func Dial(remoteAddr *net.UDPAddr, config *Config) (net.Conn, error) { + return DialWithContext(context.Background(), remoteAddr, config) +} + +// DialWithContext like Dial, but includes context for cancellation and timeouts. +func DialWithContext(ctx context.Context, remoteAddr *net.UDPAddr, config *Config) (net.Conn, error) { + conn, err := net.DialUDP("udp", nil, remoteAddr) + if err != nil { + return nil, err + } + + return ClientWithContext(ctx, conn, config) +} + +// Client establishes a DTLS connection using an existing connection and a seed. +func Client(conn net.Conn, config *Config) (net.Conn, error) { + return ClientWithContext(context.Background(), conn, config) +} + +// DialWithContext creates a DTLS connection to the given network address using the given shared secret +func ClientWithContext(ctx context.Context, conn net.Conn, config *Config) (net.Conn, error) { + clientCert, serverCert, err := certsFromSeed(config.PSK) + + if err != nil { + return nil, fmt.Errorf("error generating certs: %v", err) + } + + clientHelloRandom, err := clientHelloRandomFromSeed(config.PSK) + if err != nil { + return nil, fmt.Errorf("error generating client hello random: %v", err) + } + + verifyServerCertificate := func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if len(rawCerts) != 1 { + return fmt.Errorf("expected 1 peer certificate, got %v", len(rawCerts)) + } + + err := verifyCert(rawCerts[0], serverCert.Certificate[0]) + if err != nil { + return fmt.Errorf("error verifying server certificate: %v", err) + } + + return nil + } + + // Prepare the configuration of the DTLS connection + dtlsConf := &dtls.Config{ + Certificates: []tls.Certificate{*clientCert}, + ExtendedMasterSecret: dtls.RequireExtendedMasterSecret, + CustomClientHelloRandom: func() [handshake.RandomBytesLength]byte { return clientHelloRandom }, + + // We use VerifyPeerCertificate to authenticate the peer's certificate. This is necessary as Go's non-deterministic ECDSA signatures and hash comparison method for self-signed certificates can cause verification failure. + InsecureSkipVerify: true, + VerifyPeerCertificate: verifyServerCertificate, + } + + dtlsConn, err := dtls.ClientWithContext(ctx, conn, dtlsConf) + + if err != nil { + return nil, fmt.Errorf("error creating dtls connection: %v", err) + } + + wrappedConn, err := wrapSCTP(dtlsConn, config) + if err != nil { + return nil, err + } + + return wrappedConn, nil +} diff --git a/pkg/dtls/examples/dial/.gitignore b/pkg/dtls/examples/dial/.gitignore new file mode 100644 index 00000000..a40fc1f7 --- /dev/null +++ b/pkg/dtls/examples/dial/.gitignore @@ -0,0 +1 @@ +dial diff --git a/pkg/dtls/examples/dial/main.go b/pkg/dtls/examples/dial/main.go new file mode 100644 index 00000000..e85ddd9b --- /dev/null +++ b/pkg/dtls/examples/dial/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "context" + "flag" + "fmt" + "net" + + "github.com/mingyech/dtls/examples/util" + "github.com/refraction-networking/conjure/pkg/dtls" +) + +func main() { + var remoteAddr = flag.String("saddr", "127.0.0.1:6666", "remote address") + var localAddr = flag.String("laddr", "", "source address") + var secret = flag.String("secret", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "shared secret") + flag.Parse() + // Prepare the IP to connect to + laddr, err := net.ResolveUDPAddr("udp", *localAddr) + util.Check(err) + + addr, err := net.ResolveUDPAddr("udp", *remoteAddr) + util.Check(err) + + sharedSecret := []byte(*secret) + + udpConn, err := net.DialUDP("udp", laddr, addr) + util.Check(err) + + dtlsConn, err := dtls.ClientWithContext(context.Background(), udpConn, &dtls.Config{PSK: sharedSecret, SCTP: dtls.ClientOpen}) + util.Check(err) + + fmt.Println("Connected; type 'exit' to shutdown gracefully") + + // Simulate a chat session + util.Chat(dtlsConn) + +} diff --git a/pkg/dtls/examples/listen/.gitignore b/pkg/dtls/examples/listen/.gitignore new file mode 100644 index 00000000..a3796127 --- /dev/null +++ b/pkg/dtls/examples/listen/.gitignore @@ -0,0 +1 @@ +listen diff --git a/pkg/dtls/examples/listen/main.go b/pkg/dtls/examples/listen/main.go new file mode 100644 index 00000000..7723eab1 --- /dev/null +++ b/pkg/dtls/examples/listen/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "flag" + "fmt" + "net" + + "github.com/mingyech/dtls/examples/util" + "github.com/refraction-networking/conjure/pkg/dtls" +) + +func main() { + var localAddr = flag.String("laddr", "127.0.0.1:6666", "source address") + var secret = flag.String("secret", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "shared secret") + flag.Parse() + + // Prepare the IP to connect to + laddr, err := net.ResolveUDPAddr("udp", *localAddr) + util.Check(err) + + listener, err := dtls.Listen("udp", laddr, &dtls.Config{LogAuthFail: func(*net.IP) { fmt.Println("err ip") }, LogOther: func(*net.IP) { fmt.Println("err other") }}) + if err != nil { + fmt.Printf("error creating dtls listner: %v\n", err) + } + + fmt.Println("Listening") + + // Simulate a chat session + hub := util.NewHub() + + sharedSecret := []byte(*secret) + go func() { + for { + // Wait for a connection. + conn, err := listener.Accept(&dtls.Config{PSK: sharedSecret, SCTP: dtls.ServerAccept}) + util.Check(err) + + fmt.Println("new connection") + // defer conn.Close() // TODO: graceful shutdown + + // `conn` is of type `net.Conn` but may be casted to `dtls.Conn` + // using `dtlsConn := conn.(*dtls.Conn)` in order to to expose + // functions like `ConnectionState` etc. + + // Register the connection with the chat hub + hub.Register(conn) + } + }() + + // Start chatting + hub.Chat() +} diff --git a/pkg/dtls/heartbeat.go b/pkg/dtls/heartbeat.go new file mode 100644 index 00000000..23bc9a1e --- /dev/null +++ b/pkg/dtls/heartbeat.go @@ -0,0 +1,123 @@ +package dtls + +import ( + "bytes" + "net" + "sync/atomic" + "time" +) + +var maxMessageSize = 65535 + +type hbConn struct { + conn net.Conn + recvCh chan errBytes + waiting uint32 + hb []byte + timeout time.Duration +} + +type errBytes struct { + b []byte + err error +} + +// heartbeatServer listens for heartbeat over conn with config +func heartbeatServer(conn net.Conn, config *heartbeatConfig) (net.Conn, error) { + conf := validate(config) + + c := &hbConn{conn: conn, + recvCh: make(chan errBytes), + timeout: conf.Interval, + hb: conf.Heartbeat, + } + + atomic.StoreUint32(&c.waiting, 2) + + go c.recvLoop() + go c.hbLoop() + + return c, nil +} + +func (c *hbConn) hbLoop() { + for { + if atomic.LoadUint32(&c.waiting) == 0 { + c.conn.Close() + return + } + + atomic.StoreUint32(&c.waiting, 0) + time.Sleep(c.timeout) + } + +} + +func (c *hbConn) recvLoop() { + for { + // create a buffer to hold your data + buffer := make([]byte, maxMessageSize) + + n, err := c.conn.Read(buffer) + + if bytes.Equal(c.hb, buffer[:n]) { + atomic.AddUint32(&c.waiting, 1) + continue + } + + c.recvCh <- errBytes{buffer[:n], err} + } + +} + +func (c *hbConn) Close() error { + return c.conn.Close() +} + +func (c *hbConn) Write(b []byte) (n int, err error) { + return c.conn.Write(b) +} + +func (c *hbConn) Read(b []byte) (n int, err error) { + readBytes := <-c.recvCh + copy(b, readBytes.b) + + return len(readBytes.b), readBytes.err +} + +func (c *hbConn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +func (c *hbConn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +func (c *hbConn) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} + +func (c *hbConn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +func (c *hbConn) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +} + +// heartbeatClient sends heartbeats over conn with config +func heartbeatClient(conn net.Conn, config *heartbeatConfig) error { + conf := validate(config) + go func() { + for { + _, err := conn.Write(conf.Heartbeat) + if err != nil { + return + } + + time.Sleep(conf.Interval / 2) + } + + }() + return nil +} diff --git a/pkg/dtls/heartbeatConfig.go b/pkg/dtls/heartbeatConfig.go new file mode 100644 index 00000000..ffef47cc --- /dev/null +++ b/pkg/dtls/heartbeatConfig.go @@ -0,0 +1,34 @@ +package dtls + +import "time" + +type heartbeatConfig struct { + + // Heartbeat is the payload to sent as the heartbeat + Heartbeat []byte + + // Interval is the checking interval of each heartbeat + Interval time.Duration +} + +func validate(conf *heartbeatConfig) heartbeatConfig { + if conf == nil { + return defaultConfig + } + c := *conf + + if c.Interval == 0 { + c.Interval = defaultConfig.Interval + } + + if c.Heartbeat == nil { + c.Heartbeat = defaultConfig.Heartbeat + } + + return c +} + +var defaultConfig = heartbeatConfig{ + Heartbeat: []byte("6v3jyM521GkBo1lsMyVLcRyzdZ7FKEM3"), + Interval: 30 * time.Second, +} diff --git a/pkg/dtls/heartbeat_test.go b/pkg/dtls/heartbeat_test.go new file mode 100644 index 00000000..03374205 --- /dev/null +++ b/pkg/dtls/heartbeat_test.go @@ -0,0 +1,124 @@ +package dtls + +import ( + "net" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +var conf = &heartbeatConfig{Interval: 1 * time.Second, Heartbeat: []byte("hihihihihihihihihi")} + +func TestHeartbeatReadWrite(t *testing.T) { + server, client := net.Pipe() + + s, err := heartbeatServer(server, conf) + require.Nil(t, err) + + err = heartbeatClient(client, conf) + require.Nil(t, err) + + sent := uint32(0) + recvd := uint32(0) + toSend := []byte("testtt") + stop := time.After(conf.Interval * 2) + + go func() { + for { + select { + case <-stop: + return + default: + buffer := make([]byte, 4096) + n, err := s.Read(buffer) + if err != nil { + continue + } + require.Equal(t, toSend, buffer[:n]) + atomic.AddUint32(&recvd, 1) + } + } + }() + + go func() { + for { + select { + case <-stop: + return + default: + _, err := client.Write(toSend) + require.Nil(t, err) + atomic.AddUint32(&sent, 1) + time.Sleep(10 * time.Millisecond) + } + } + }() + + <-stop + + require.Equal(t, atomic.LoadUint32(&sent), atomic.LoadUint32(&recvd)) +} + +func TestHeartbeatSend(t *testing.T) { + server, client := net.Pipe() + + readCh := make(chan []byte) + + go func() { + for { + buffer := make([]byte, 4096) + n, err := server.Read(buffer) + if err != nil { + continue + } + + readCh <- buffer[:n] + } + }() + + err := heartbeatClient(client, conf) + require.Nil(t, err) + + duration := 2 + stop := time.After(conf.Interval*time.Duration(duration) + 10*time.Millisecond) + + hbCount := 0 + for { + select { + case b := <-readCh: + require.Equal(t, conf.Heartbeat, b) + hbCount++ + case <-stop: + require.Equal(t, duration*2+1, hbCount) + return + } + } + +} + +func TestHeartbeatTimeout(t *testing.T) { + server, client := net.Pipe() + go func() { + for { + buffer := make([]byte, 4096) + _, err := client.Read(buffer) + if err != nil { + return + } + } + }() + + s, err := heartbeatServer(server, conf) + require.Nil(t, err) + + _, err = s.Write([]byte("123")) + require.Nil(t, err) + + stop := time.After(conf.Interval + 10*time.Millisecond) + <-stop + _, err = s.Write([]byte("123")) + require.NotNil(t, err) + +} diff --git a/pkg/dtls/listener.go b/pkg/dtls/listener.go new file mode 100644 index 00000000..eeb3d2a3 --- /dev/null +++ b/pkg/dtls/listener.go @@ -0,0 +1,258 @@ +// SPDX-FileCopyrightText: 2023 The Pion community +// SPDX-License-Identifier: MIT + +package dtls + +import ( + "context" + "crypto/rand" + "crypto/tls" + "errors" + "fmt" + "net" + "sync" + + "github.com/mingyech/dtls" + "github.com/mingyech/dtls/pkg/protocol/handshake" + "github.com/mingyech/transport/udp" +) + +// Listen creates a listener and starts listening +func Listen(network string, laddr *net.UDPAddr, config *Config) (*Listener, error) { + lc := udp.ListenConfig{} + parent, err := lc.Listen(network, laddr) + if err != nil { + return nil, err + } + + return NewListener(parent, config) +} + +func (l *Listener) acceptLoop() { + // Prepare the configuration of the DTLS connection + config := &dtls.Config{ + ExtendedMasterSecret: dtls.RequireExtendedMasterSecret, + ClientAuth: dtls.RequireAnyClientCert, + GetCertificate: l.getCertificateFromClientHello, + VerifyConnection: l.verifyConnection, + InsecureSkipVerifyHello: true, + } + + for { + c, err := l.parent.Accept() + if err != nil { + continue + } + + go func() { + newDTLSConn, err := dtls.Server(c, config) + if err != nil { + switch addr := c.RemoteAddr().(type) { + case *net.UDPAddr: + l.logIP(err, &addr.IP) + case *net.TCPAddr: + l.logIP(err, &addr.IP) + case *net.IPAddr: + l.logIP(err, &addr.IP) + } + + return + } + + connState := newDTLSConn.ConnectionState() + connID := connState.RemoteRandomBytes() + + l.connMapMutex.RLock() + defer l.connMapMutex.RUnlock() + + acceptCh, ok := l.connMap[connID] + + if !ok { + return + } + + acceptCh <- newDTLSConn + + close(acceptCh) + }() + } +} + +func (l *Listener) logIP(err error, ip *net.IP) { + var terr *dtls.TemporaryError + if errors.As(err, &terr) { + l.logOther(ip) + } + l.logAuthFail(ip) +} + +// NewListener creates a DTLS listener which accepts connections from an inner Listener. +func NewListener(inner net.Listener, config *Config) (*Listener, error) { + // the default cert is only used for checking avaliable cipher suites + defaultCert, err := randomCertificate() + if err != nil { + return nil, fmt.Errorf("error generating default random cert: %v", err) + } + + newDTLSListner := Listener{ + parent: inner, + connMap: map[[handshake.RandomBytesLength]byte](chan net.Conn){}, + connToCert: map[[handshake.RandomBytesLength]byte]*certPair{}, + defaultCert: defaultCert, + logAuthFail: config.LogAuthFail, + logOther: config.LogOther, + } + + go newDTLSListner.acceptLoop() + + return &newDTLSListner, nil +} + +// Listener represents a DTLS Listener +type Listener struct { + parent net.Listener + connMap map[[handshake.RandomBytesLength]byte](chan net.Conn) + connMapMutex sync.RWMutex + connToCert map[[handshake.RandomBytesLength]byte]*certPair + connToCertMutex sync.RWMutex + defaultCert *tls.Certificate + logAuthFail func(*net.IP) + logOther func(*net.IP) +} + +// Close closes the listener. +// Any blocked Accept operations will be unblocked and return errors. +// Already Accepted connections are not closed. +func (l *Listener) Close() error { + return l.parent.Close() +} + +// Addr returns the listener's network address. +func (l *Listener) Addr() net.Addr { + return l.parent.Addr() +} + +func (l *Listener) verifyConnection(state *dtls.State) error { + + certs, ok := l.connToCert[state.RemoteRandomBytes()] + if !ok { + return fmt.Errorf("no matching certificate found with client hello random") + } + + if len(state.PeerCertificates) != 1 { + return fmt.Errorf("expected 1 peer certificate, got %v", len(state.PeerCertificates)) + } + + err := verifyCert(state.PeerCertificates[0], certs.clientCert.Certificate[0]) + if err != nil { + return fmt.Errorf("error verifying peer certificate: %v", err) + } + + return nil +} + +// Accept accepts a connection with shared secret +func (l *Listener) Accept(config *Config) (net.Conn, error) { + // Call the new function with a background context + return l.AcceptWithContext(context.Background(), config) +} + +// AcceptWithContext accepts a connection with shared secret, with a context +func (l *Listener) AcceptWithContext(ctx context.Context, config *Config) (net.Conn, error) { + clientCert, serverCert, err := certsFromSeed(config.PSK) + if err != nil { + return &dtls.Conn{}, fmt.Errorf("error generating certificatess from seed: %v", err) + } + + connID, err := clientHelloRandomFromSeed(config.PSK) + if err != nil { + return &dtls.Conn{}, err + } + + l.registerCert(connID, clientCert, serverCert) + defer l.removeCert(connID) + + connCh, err := l.registerChannel(connID) + if err != nil { + return nil, fmt.Errorf("error registering channel: %v", err) + } + defer l.removeChannel(connID) + + select { + case conn := <-connCh: + wrappedConn, err := wrapSCTP(conn, config) + if err != nil { + return nil, err + } + return wrappedConn, nil + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +func (l *Listener) registerCert(connID [handshake.RandomBytesLength]byte, clientCert, serverCert *tls.Certificate) { + l.connToCertMutex.Lock() + defer l.connToCertMutex.Unlock() + l.connToCert[connID] = &certPair{clientCert: clientCert, serverCert: serverCert} +} + +func (l *Listener) removeCert(connID [handshake.RandomBytesLength]byte) { + l.connToCertMutex.Lock() + defer l.connToCertMutex.Unlock() + delete(l.connToCert, connID) +} + +func (l *Listener) registerChannel(connID [handshake.RandomBytesLength]byte) (<-chan net.Conn, error) { + l.connMapMutex.Lock() + defer l.connMapMutex.Unlock() + + if l.connMap[connID] != nil { + return nil, fmt.Errorf("seed already registered") + } + + connChan := make(chan net.Conn) + l.connMap[connID] = connChan + + return connChan, nil +} + +func (l *Listener) removeChannel(connID [handshake.RandomBytesLength]byte) { + l.connMapMutex.Lock() + defer l.connMapMutex.Unlock() + + delete(l.connMap, connID) +} + +func (l *Listener) getCertificateFromClientHello(clientHello *dtls.ClientHelloInfo) (*tls.Certificate, error) { + // This function is sometimes called by the dtls library to get the availiable ciphersuites, + // respond with a default certificate with the availible ciphersuites + if clientHello.CipherSuites == nil { + return l.defaultCert, nil + } + + l.connToCertMutex.RLock() + defer l.connToCertMutex.RUnlock() + + certs, ok := l.connToCert[clientHello.RandomBytes] + + if !ok { + // Respond with random server certificate if not registered, will reject client cert later during handshake + randomCert, err := randomCertificate() + if err != nil { + return nil, fmt.Errorf("failed to generate random certificate: %v", err) + } + + return randomCert, nil + } + + return certs.serverCert, nil +} + +func randomCertificate() (*tls.Certificate, error) { + seedBytes := []byte{} + _, err := rand.Read(seedBytes) + if err != nil { + return nil, err + } + return newCertificate(seedBytes) +} diff --git a/pkg/dtls/not1reader.go b/pkg/dtls/not1reader.go new file mode 100644 index 00000000..37d72a2e --- /dev/null +++ b/pkg/dtls/not1reader.go @@ -0,0 +1,19 @@ +package dtls + +import ( + "io" +) + +type Not1Reader struct { + r io.Reader +} + +func (n1r *Not1Reader) Read(p []byte) (n int, err error) { + + if len(p) == 1 { + // err = io.EOF + return 1, nil + } + + return n1r.r.Read(p) +} diff --git a/pkg/dtls/not1reader_test.go b/pkg/dtls/not1reader_test.go new file mode 100644 index 00000000..8365c49c --- /dev/null +++ b/pkg/dtls/not1reader_test.go @@ -0,0 +1,27 @@ +package dtls + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFakeReader(t *testing.T) { + msg := "test byte string for read" + + n1r := &Not1Reader{ + r: bytes.NewReader([]byte(msg)), + } + + var buf1 [1]byte + n, err := n1r.Read(buf1[:]) + require.Nil(t, err) + require.Equal(t, 1, n) + + buf := make([]byte, len(msg)) + n, err = n1r.Read(buf) + require.Nil(t, err) + require.Equal(t, len(msg), n) + require.Equal(t, msg, string(buf)) +} diff --git a/pkg/dtls/sctpconn.go b/pkg/dtls/sctpconn.go new file mode 100644 index 00000000..88bfa8ea --- /dev/null +++ b/pkg/dtls/sctpconn.go @@ -0,0 +1,122 @@ +package dtls + +import ( + "fmt" + "net" + "time" + + "github.com/pion/logging" + "github.com/pion/sctp" +) + +// SCTPConn implements the net.Conn interface using sctp stream and DTLS conn +type SCTPConn struct { + stream *sctp.Stream + conn net.Conn +} + +func newSCTPConn(stream *sctp.Stream, conn net.Conn) *SCTPConn { + return &SCTPConn{stream: stream, conn: conn} +} + +func (s *SCTPConn) Close() error { + err := s.stream.Close() + if err != nil { + return err + } + return s.conn.Close() +} + +func (s *SCTPConn) Write(b []byte) (int, error) { + return s.stream.Write(b) +} + +func (s *SCTPConn) Read(b []byte) (int, error) { + return s.stream.Read(b) +} + +func (s *SCTPConn) LocalAddr() net.Addr { + return s.conn.LocalAddr() +} + +func (s *SCTPConn) RemoteAddr() net.Addr { + return s.conn.RemoteAddr() +} + +func (s *SCTPConn) SetDeadline(t time.Time) error { + return s.conn.SetDeadline(t) +} + +func (s *SCTPConn) SetWriteDeadline(t time.Time) error { + return s.conn.SetWriteDeadline(t) +} + +func (s *SCTPConn) SetReadDeadline(t time.Time) error { + return s.stream.SetReadDeadline(t) +} + +func openSCTP(conn net.Conn) (net.Conn, error) { + // Start SCTP + sctpConf := sctp.Config{ + NetConn: conn, + LoggerFactory: logging.NewDefaultLoggerFactory(), + } + + sctpClient, err := sctp.Client(sctpConf) + + if err != nil { + return nil, fmt.Errorf("error creating sctp client: %v", err) + } + + sctpStream, err := sctpClient.OpenStream(0, sctp.PayloadTypeWebRTCString) + + if err != nil { + return nil, fmt.Errorf("error setting up stream: %v", err) + } + + sctpConn := newSCTPConn(sctpStream, conn) + + err = heartbeatClient(sctpConn, &heartbeatConfig{Interval: 10 * time.Second}) + if err != nil { + return nil, fmt.Errorf("error opening heartbeat client: %v", err) + } + + return sctpConn, nil +} + +func acceptSCTP(conn net.Conn) (net.Conn, error) { + + // Start SCTP over DTLS connection + sctpConfig := sctp.Config{ + NetConn: conn, + LoggerFactory: logging.NewDefaultLoggerFactory(), + } + + sctpServer, err := sctp.Server(sctpConfig) + if err != nil { + return nil, err + } + + sctpStream, err := sctpServer.AcceptStream() + if err != nil { + return nil, err + } + + sctpConn := newSCTPConn(sctpStream, conn) + + heartbeatConn, err := heartbeatServer(sctpConn, nil) + if err != nil { + return nil, fmt.Errorf("error starting heartbeat server: %v", err) + } + + return heartbeatConn, nil + +} + +func wrapSCTP(conn net.Conn, config *Config) (net.Conn, error) { + if config.SCTP == ServerAccept { + return acceptSCTP(conn) + } + + return openSCTP(conn) +} diff --git a/pkg/dtls/seedtocert.go b/pkg/dtls/seedtocert.go new file mode 100644 index 00000000..f8a3e6d5 --- /dev/null +++ b/pkg/dtls/seedtocert.go @@ -0,0 +1,124 @@ +package dtls + +//Adapted from https://github.com/gaukas/seed2sdp/blob/master/dtlsCertificate.go + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/hex" + "fmt" + "io" + "math/big" + "time" + + "github.com/mingyech/dtls/pkg/protocol/handshake" + "golang.org/x/crypto/hkdf" +) + +func clientHelloRandomFromSeed(seed []byte) ([handshake.RandomBytesLength]byte, error) { + randSource := hkdf.New(sha256.New, seed, nil, nil) + randomBytes := [handshake.RandomBytesLength]byte{} + + _, err := io.ReadFull(randSource, randomBytes[:]) + if err != nil { + return [handshake.RandomBytesLength]byte{}, err + } + + return randomBytes, nil +} + +// getPrivkey creates ECDSA private key used in DTLS Certificates +func getPrivkey(seed []byte) (*ecdsa.PrivateKey, error) { + randSource := hkdf.New(sha256.New, seed, nil, nil) + + privkey, err := ecdsa.GenerateKey(elliptic.P256(), &Not1Reader{r: randSource}) + if err != nil { + return &ecdsa.PrivateKey{}, err + } + return privkey, nil +} + +// getX509Tpl creates x509 template for x509 Certificates generation used in DTLS Certificates. +func getX509Tpl(seed []byte) (*x509.Certificate, error) { + randSource := hkdf.New(sha256.New, seed, nil, nil) + + maxBigInt := new(big.Int) + maxBigInt.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxBigInt, big.NewInt(1)) + serialNumber, err := rand.Int(randSource, maxBigInt) + if err != nil { + return &x509.Certificate{}, err + } + + // Make the Certificate valid from UTC today till next month. + utcNow := time.Now().UTC() + validFrom := time.Date(utcNow.Year(), utcNow.Month(), utcNow.Day(), 0, 0, 0, 0, time.UTC) + validUntil := validFrom.AddDate(0, 1, 0) + + // random CN + cnBytes := make([]byte, 8) + _, err = io.ReadFull(randSource, cnBytes) + if err != nil { + return &x509.Certificate{}, fmt.Errorf("failed to generate common name: %w", err) + } + cn := hex.EncodeToString(cnBytes) + + return &x509.Certificate{ + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageClientAuth, + x509.ExtKeyUsageServerAuth, + }, + BasicConstraintsValid: true, + NotBefore: validFrom, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + NotAfter: validUntil, + SerialNumber: serialNumber, + SignatureAlgorithm: x509.ECDSAWithSHA256, + Version: 2, + Subject: pkix.Name{CommonName: cn}, + DNSNames: []string{cn}, + IsCA: true, + }, nil +} + +func newCertificate(seed []byte) (*tls.Certificate, error) { + privkey, err := getPrivkey(seed) + if err != nil { + return &tls.Certificate{}, err + } + + tpl, err := getX509Tpl(seed) + if err != nil { + return &tls.Certificate{}, err + } + + randSource := hkdf.New(sha256.New, seed, nil, nil) + + certDER, err := x509.CreateCertificate(randSource, tpl, tpl, privkey.Public(), privkey) + if err != nil { + return &tls.Certificate{}, err + } + + return &tls.Certificate{ + Certificate: [][]byte{certDER}, + PrivateKey: privkey, + }, nil +} + +func certsFromSeed(seed []byte) (*tls.Certificate, *tls.Certificate, error) { + clientCert, err := newCertificate(seed) + if err != nil { + return &tls.Certificate{}, &tls.Certificate{}, fmt.Errorf("error generate cert: %v", err) + } + + // serverCert, err := newCertificate(seed) + // if err != nil { + // return &tls.Certificate{}, &tls.Certificate{}, fmt.Errorf("error generate cert: %v", err) + // } + + return clientCert, clientCert, nil +} diff --git a/pkg/dtls/server.go b/pkg/dtls/server.go new file mode 100644 index 00000000..94b89478 --- /dev/null +++ b/pkg/dtls/server.go @@ -0,0 +1,80 @@ +package dtls + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + "net" + + "github.com/mingyech/dtls" +) + +type certPair struct { + clientCert *tls.Certificate + serverCert *tls.Certificate +} + +// Server establishes DTLS connection on the given conn using the sharedSecert +func Server(conn net.Conn, config *Config) (net.Conn, error) { + return ServerWithContext(context.Background(), conn, config) +} + +// ServerWithContext establishes DTLS connection on the given conn using the sharedSecert and context +func ServerWithContext(ctx context.Context, conn net.Conn, config *Config) (net.Conn, error) { + + clientCert, serverCert, err := certsFromSeed(config.PSK) + if err != nil { + return nil, fmt.Errorf("error generating certificatess from seed: %v", err) + } + + VerifyPeerCertificate := func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + + err := verifyCert(rawCerts[0], clientCert.Certificate[0]) + if err != nil { + return fmt.Errorf("error verifying peer certificate: %v", err) + } + + return nil + } + + dtlsConf := &dtls.Config{ + ExtendedMasterSecret: dtls.RequireExtendedMasterSecret, + ClientAuth: dtls.RequireAnyClientCert, + Certificates: []tls.Certificate{*serverCert}, + VerifyPeerCertificate: VerifyPeerCertificate, + InsecureSkipVerifyHello: true, + } + + dtlsConn, err := dtls.ServerWithContext(ctx, conn, dtlsConf) + if err != nil { + return nil, err + } + + wrappedConn, err := wrapSCTP(dtlsConn, config) + if err != nil { + return nil, err + } + + return wrappedConn, nil +} + +func verifyCert(cert, correct []byte) error { + incommingCert, err := x509.ParseCertificate(cert) + if err != nil { + return fmt.Errorf("error parsing peer certificate: %v", err) + } + + correctCert, err := x509.ParseCertificate(correct) + if err != nil { + return fmt.Errorf("error parsing correct certificate: %v", err) + } + + correctCert.KeyUsage = x509.KeyUsageCertSign // CheckSignature have requirements for the KeyUsage field + err = incommingCert.CheckSignatureFrom(correctCert) + if err != nil { + return fmt.Errorf("error verifying certificate signature: %v", err) + } + + return nil +} diff --git a/pkg/dtls/server_test.go b/pkg/dtls/server_test.go new file mode 100644 index 00000000..febf05a8 --- /dev/null +++ b/pkg/dtls/server_test.go @@ -0,0 +1,49 @@ +package dtls + +import ( + "crypto/rand" + "net" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +var sharedSecret = []byte("hihihihihihihihihihihihihihihihi") + +func TestSend(t *testing.T) { + size := 65535 + toSend := make([]byte, size) + + _, err := rand.Read(toSend) + require.Nil(t, err) + + server, client := net.Pipe() + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + s, err := Server(server, &Config{PSK: sharedSecret, SCTP: ServerAccept}) + require.Nil(t, err) + + received := make([]byte, size) + _, err = s.Read(received) + require.Nil(t, err) + + require.Equal(t, toSend, received) + }() + + time.Sleep(1 * time.Second) + + c, err := Client(client, &Config{PSK: sharedSecret, SCTP: ClientOpen}) + require.Nil(t, err) + + n, err := c.Write(toSend) + require.Nil(t, err) + require.Equal(t, len(toSend), n) + + wg.Wait() +} diff --git a/pkg/registrars/dns-registrar/requester/config.go b/pkg/registrars/dns-registrar/requester/config.go index 1384fb42..5d78c55d 100644 --- a/pkg/registrars/dns-registrar/requester/config.go +++ b/pkg/registrars/dns-registrar/requester/config.go @@ -22,7 +22,7 @@ type Config struct { UtlsDistribution string // DialTransport allows for a custom dialer to be used for the underlying TCP/UDP transport - DialTransport DialFunc + DialTransport dialFunc } // TransportMethodType declares the transport method to be used @@ -34,12 +34,12 @@ const ( UDP ) -func defaultDialTransport() DialFunc { +func defaultDialTransport() dialFunc { dialer := net.Dialer{} return dialer.DialContext } -func (c *Config) dialTransport() DialFunc { +func (c *Config) dialTransport() dialFunc { if c.DialTransport == nil { return defaultDialTransport() } diff --git a/pkg/registrars/dns-registrar/requester/requester.go b/pkg/registrars/dns-registrar/requester/requester.go index 5cff6829..e8272e68 100644 --- a/pkg/registrars/dns-registrar/requester/requester.go +++ b/pkg/registrars/dns-registrar/requester/requester.go @@ -15,7 +15,7 @@ import ( utls "github.com/refraction-networking/utls" ) -type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) +type dialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) type Requester struct { // transport is the underlying transport used for the dns request @@ -23,10 +23,10 @@ type Requester struct { // dialTransport is used for constructing the transport on the first request // this allows us to not dial anything until the first request, while avoid storing // a lot of internal state in Requester - dialTransport func(dialer DialFunc) (net.PacketConn, error) + dialTransport func(dialer dialFunc) (net.PacketConn, error) // dialer is the dialer to be used for the underlying TCP/UDP transport - dialer DialFunc + dialer dialFunc // remote address remoteAddr net.Addr @@ -36,7 +36,7 @@ type Requester struct { } // New Requester using DoT as transport -func dialDoT(dotaddr string, utlsDistribution string, dialTransport DialFunc) (net.Conn, error) { +func dialDoT(dotaddr string, utlsDistribution string, dialTransport dialFunc) (net.Conn, error) { utlsClientHelloID, err := sampleUTLSDistribution(utlsDistribution) if err != nil { return nil, err @@ -65,7 +65,7 @@ func dialDoT(dotaddr string, utlsDistribution string, dialTransport DialFunc) (n } // New Requester using DoH as transport -func dialDoH(dohurl string, utlsDistribution string, dialTransport DialFunc) (net.Conn, error) { +func dialDoH(dohurl string, utlsDistribution string, dialTransport dialFunc) (net.Conn, error) { utlsClientHelloID, err := sampleUTLSDistribution(utlsDistribution) if err != nil { return nil, err @@ -95,7 +95,7 @@ func dialDoH(dohurl string, utlsDistribution string, dialTransport DialFunc) (ne } // New Requester using UDP as transport -func dialUDP(remoteAddr string, dialContext DialFunc) (net.Conn, error) { +func dialUDP(remoteAddr string, dialContext dialFunc) (net.Conn, error) { udpConn, err := dialContext(context.Background(), "udp", remoteAddr) if err != nil { return nil, fmt.Errorf("error dialing udp connection: %v", err) @@ -135,7 +135,7 @@ func NewRequester(config *Config) (*Requester, error) { return nil, fmt.Errorf("error resolving addr from config: %v", err) } - dialTransport := func(dialer DialFunc) (net.PacketConn, error) { + dialTransport := func(dialer dialFunc) (net.PacketConn, error) { switch config.TransportMethod { case DoT: conn, err := dialDoT(config.Target, config.UtlsDistribution, dialer) @@ -196,7 +196,7 @@ func (r *Requester) sendHandshake(payload []byte) (*noise.CipherState, *noise.Ci } // SetDialer sets a custom dialer for the underlying TCP/UDP transport -func (r *Requester) SetDialer(dialer DialFunc) error { +func (r *Requester) SetDialer(dialer dialFunc) error { if dialer == nil { return fmt.Errorf("no dialer provided") } diff --git a/pkg/registrars/registration/api-registrar.go b/pkg/registrars/registration/api-registrar.go index f1cedef5..a8ef5105 100644 --- a/pkg/registrars/registration/api-registrar.go +++ b/pkg/registrars/registration/api-registrar.go @@ -164,8 +164,6 @@ func (r *APIRegistrar) setHTTPClient(reg *tapdance.ConjureReg) { } func (r APIRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context.Context) (*tapdance.ConjureReg, error) { - defer sleepWithContext(ctx, r.connectionDelay) - if r.bidirectional { return r.registerBidirectional(cjSession, ctx) } diff --git a/pkg/registrars/registration/config.go b/pkg/registrars/registration/config.go index 49311afd..75dec8ac 100644 --- a/pkg/registrars/registration/config.go +++ b/pkg/registrars/registration/config.go @@ -28,6 +28,8 @@ type Config struct { MaxRetries int // Delay is the delay duration between retries + // + // Deprecated: Use tapdance.Dialer.RegDelay instead. Delay time.Duration // STUNAddr is the address of STUN server used to determine the client's IPv4 address for the DNS registrar diff --git a/pkg/registrars/registration/decoy-registrar.go b/pkg/registrars/registration/decoy-registrar.go index b74ddc63..9f87122b 100644 --- a/pkg/registrars/registration/decoy-registrar.go +++ b/pkg/registrars/registration/decoy-registrar.go @@ -9,13 +9,13 @@ import ( "github.com/sirupsen/logrus" ) -type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) +type dialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) type DecoyRegistrar struct { // dialContex is a custom dailer to use when establishing TCP connections // to decoys. When nil, Dialer.dialContex will be used. - dialContex DialFunc + dialContex dialFunc logger logrus.FieldLogger } @@ -26,7 +26,10 @@ func NewDecoyRegistrar() *DecoyRegistrar { } } -func NewDecoyRegistrarWithDialer(dialer DialFunc) *DecoyRegistrar { +// NewDecoyRegistrarWithDialer returns a decoy registrar with custom dialer. +// +// Deprecated: Set dialer in tapdace.Dialer.DialerWithLaddr instead. +func NewDecoyRegistrarWithDialer(dialer dialFunc) *DecoyRegistrar { return &DecoyRegistrar{ dialContex: dialer, logger: tapdance.Logger(), @@ -98,10 +101,5 @@ func (r DecoyRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context return nil, tapdance.NewRegError(tapdance.Unreachable, "All decoys failed to register -- Dial Unreachable") } - // randomized sleeping here to break the intraflow signal - toSleep := reg.GetRandomDuration(3000, 212, 3449) - logger.Debugf("Successfully sent registrations, sleeping for: %v", toSleep) - sleepWithContext(ctx, toSleep) - return reg, nil } diff --git a/pkg/registrars/registration/dns-registrar.go b/pkg/registrars/registration/dns-registrar.go index f2329de8..0e1e7ba7 100644 --- a/pkg/registrars/registration/dns-registrar.go +++ b/pkg/registrars/registration/dns-registrar.go @@ -193,8 +193,6 @@ func (r *DNSRegistrar) registerBidirectional(cjSession *tapdance.ConjureSession) // Register prepares and sends the registration request. func (r *DNSRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context.Context) (*tapdance.ConjureReg, error) { - defer sleepWithContext(ctx, r.connectionDelay) - if r.bidirectional { return r.registerBidirectional(cjSession) } @@ -233,12 +231,3 @@ func getPublicIp(server string) ([]byte, error) { return ip.To4(), nil } - -func sleepWithContext(ctx context.Context, duration time.Duration) { - timer := time.NewTimer(duration) - defer timer.Stop() - select { - case <-timer.C: - case <-ctx.Done(): - } -} diff --git a/pkg/station/lib/registration.go b/pkg/station/lib/registration.go index 4f527833..9c5fd0bd 100644 --- a/pkg/station/lib/registration.go +++ b/pkg/station/lib/registration.go @@ -41,6 +41,9 @@ type RegistrationManager struct { LivenessTester liveness.Tester GeoIP geoip.Database + // ConnectingStats records stats related to connecting transports + connectingStats ConnectingTpStats + // ingestChan is included here so that the capacity and use is available to // stats ingestChan <-chan interface{} @@ -79,6 +82,7 @@ func NewRegistrationManager(conf *RegConfig) *RegistrationManager { PhantomSelector: p, LivenessTester: lt, GeoIP: geoipDB, + connectingStats: conf.ConnectingStats, } } @@ -279,6 +283,7 @@ type DecoyRegistration struct { DecoyListVersion uint32 regCount int32 clientLibVer uint32 + clientPort uint16 tunnelCount int64 @@ -420,11 +425,9 @@ func (reg *DecoyRegistration) GetDstPort() uint16 { return reg.PhantomPort } -// GetSrcPort returns a source port if one was registered. Currently this is not -// supported -- for now this is intended as plumbing for potentially supporting -// seeded source port selection for the client. +// GetSrcPort returns a source port if one was registered. func (reg *DecoyRegistration) GetSrcPort() uint16 { - return 0 + return reg.clientPort } type regStatus int @@ -831,3 +834,20 @@ func clearDetector() { ctx := context.Background() client.Publish(ctx, DETECTOR_REG_CHANNEL, string(s2d)) } + +// GetConnectingTransports Returns a map of the connecting transport types to their transports. This return value +// can be mutated freely. +func (regManager *RegistrationManager) GetConnectingTransports() map[pb.TransportType]ConnectingTransport { + m := make(map[pb.TransportType]ConnectingTransport) + regManager.registeredDecoys.m.RLock() + defer regManager.registeredDecoys.m.RUnlock() + + for k, v := range regManager.registeredDecoys.transports { + ct, ok := v.(ConnectingTransport) + if ok { + m[k] = ct + } + } + + return m +} diff --git a/pkg/station/lib/registration_config.go b/pkg/station/lib/registration_config.go index 2456733f..4eb76816 100644 --- a/pkg/station/lib/registration_config.go +++ b/pkg/station/lib/registration_config.go @@ -45,6 +45,9 @@ type RegConfig struct { // Local list of disallowed subnets patterns for phantom addresses. PhantomBlocklist []string `toml:"phantom_blocklist"` phantomBlocklist []*net.IPNet + + // ConnectingStats records stats related to connecting transports + ConnectingStats ConnectingTpStats } // ParseBlocklists converts string arrays of blocklisted domains, addresses and diff --git a/pkg/station/lib/registration_ingest.go b/pkg/station/lib/registration_ingest.go index 3a0a2056..f5299925 100644 --- a/pkg/station/lib/registration_ingest.go +++ b/pkg/station/lib/registration_ingest.go @@ -231,6 +231,7 @@ func (rm *RegistrationManager) ingestRegistration(reg *DecoyRegistration) { logger.Debugf("Adding registration %v\n", reg.IDString()) Stat().AddReg(reg.DecoyListVersion, reg.RegistrationSource) rm.AddRegStats(reg) + handleConnectingTpReg(rm, reg, logger) } func tryShareRegistrationOverAPI(reg *DecoyRegistration, apiEndpoint string, logger *log.Logger) { @@ -368,6 +369,11 @@ func (rm *RegistrationManager) NewRegistration(c2s *pb.ClientToStation, conjureK return nil, fmt.Errorf("error determining phantom connection proto: %s", err) } + srcPort, err := rm.getClientSrcPort(c2s.GetTransport(), transportParams, conjureKeys.ConjureSeed, clientLibVer) + if err != nil { + return nil, fmt.Errorf("error determining client source port: %s", err) + } + reg := DecoyRegistration{ DecoyListVersion: c2s.GetDecoyListGeneration(), Keys: conjureKeys, @@ -376,6 +382,7 @@ func (rm *RegistrationManager) NewRegistration(c2s *pb.ClientToStation, conjureK TransportPtr: &transport, TransportParams: transportParams, Flags: c2s.Flags, + clientPort: srcPort, PhantomIp: phantomAddr, PhantomPort: phantomPort, @@ -492,3 +499,77 @@ func (rm *RegistrationManager) getPhantomDstPort(t pb.TransportType, params any, // transport selection algorithms themselves. return transport.GetDstPort(libVer, seed, params) } + +// getPhantomDstPort returns the proper phantom port based on registration type, transport +// parameters provided by the client and session details (also provided by the client). +func (rm *RegistrationManager) getClientSrcPort(t pb.TransportType, params any, seed []byte, libVer uint) (uint16, error) { + var transport, ok = rm.registeredDecoys.transports[t].(ConnectingTransport) + if !ok { + // non-connecting transports do not have a set source port + return 0, nil + } + + // GetDstPort Given the library version, a seed, and a generic object containing parameters the + // transport should be able to return the destination port that a clients phantom connection + // will attempt to reach. The libVersion is provided incase of version dependent changes in the + // transport selection algorithms themselves. + return transport.GetSrcPort(libVer, seed, params) +} + +// Handle new registration from client for UDP Transports +// NOTE: this is called within a goroutine in get_zmq_updates +func handleConnectingTpReg(regManager *RegistrationManager, reg *DecoyRegistration, logger *log.Logger) { + // using a Connecting Transport + for tptype, tp := range regManager.GetConnectingTransports() { + if tptype == reg.Transport { // correct transport name + ctx, cancelFunc := context.WithTimeout(context.Background(), 15*time.Second) + go func(transport ConnectingTransport) { + defer cancelFunc() + + cc, err := regManager.GeoIP.CC(reg.registrationAddr) + if err != nil { + logger.Errorln("Failed to get CC:", err) + return + } + + var asn uint = 0 + if cc != "unk" { + asn, err = regManager.GeoIP.ASN(reg.registrationAddr) + if err != nil { + logger.Errorln("Failed to get ASN:", err) + return + } + } + + regManager.connectingStats.AddCreatedConnecting(asn, cc, transport.Name()) + + conn, err := transport.Connect(ctx, reg) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) { + regManager.connectingStats.AddCreatedToTimeoutConnecting(asn, cc, transport.Name()) + } else { + regManager.connectingStats.AddOtherFailConnecting(asn, cc, transport.Name()) + } + return + } + + // regManager.connectingStats.AddCreatedToSuccessfulConnecting(asn, cc, transport.Name()) + + Stat().AddConn() + Proxy(reg, conn, logger) + Stat().CloseConn() + + regManager.connectingStats.AddSuccessfulToDiscardedConnecting(asn, cc, transport.Name()) + + }(tp) + } + } +} + +type ConnectingTpStats interface { + AddCreatedConnecting(asn uint, cc string, tp string) + AddCreatedToSuccessfulConnecting(asn uint, cc string, tp string) + AddCreatedToTimeoutConnecting(asn uint, cc string, tp string) + AddSuccessfulToDiscardedConnecting(asn uint, cc string, tp string) + AddOtherFailConnecting(asn uint, cc string, tp string) +} diff --git a/pkg/station/lib/transports.go b/pkg/station/lib/transports.go index c9cab7b3..39249578 100644 --- a/pkg/station/lib/transports.go +++ b/pkg/station/lib/transports.go @@ -79,4 +79,7 @@ type ConnectingTransport interface { // Connect attempts to connect to the client from the phantom address derived in the // registration. Connect(context.Context, *DecoyRegistration) (net.Conn, error) + + // GetSrcPort reads client source port from transport parameters + GetSrcPort(libVersion uint, seed []byte, parameters any) (uint16, error) } diff --git a/pkg/transports/client/transports.go b/pkg/transports/client/transports.go index 2f277ac3..914f1567 100644 --- a/pkg/transports/client/transports.go +++ b/pkg/transports/client/transports.go @@ -4,6 +4,7 @@ import ( "errors" cj "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/transports/connecting/dtls" "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" "github.com/refraction-networking/conjure/pkg/transports/wrapping/obfs4" "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" @@ -60,6 +61,7 @@ var defaultTransports = []cj.Transport{ &min.ClientTransport{}, &obfs4.ClientTransport{}, &prefix.ClientTransport{}, + &dtls.ClientTransport{}, } // AddTransport adds new transport diff --git a/pkg/transports/connecting/dtls/client.go b/pkg/transports/connecting/dtls/client.go new file mode 100644 index 00000000..9ab326d5 --- /dev/null +++ b/pkg/transports/connecting/dtls/client.go @@ -0,0 +1,167 @@ +package dtls + +import ( + "context" + "fmt" + "io" + "net" + "time" + + "github.com/refraction-networking/conjure/pkg/dtls" + "github.com/refraction-networking/conjure/pkg/transports" + pb "github.com/refraction-networking/conjure/proto" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" +) + +type dialFunc = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) + +const ( + // port range boundaries for min when randomizing + portRangeMin = 1024 + portRangeMax = 65535 + defaultPort = 443 + defaultSTUNServer = "stun.voip.blackberry.com:3478" +) + +// ClientTransport implements the client side transport interface for the DTLS transport. The +// significant difference is that there is an instance of this structure per client session, where +// the station side Transport struct has one instance to be re-used for all sessions. +type ClientTransport struct { + // Parameters are fields that will be shared with the station in the registration + Parameters *pb.DTLSTransportParams + + // // state tracks fields internal to the registrar that survive for the lifetime + // // of the transport session without being shared - i.e. local derived keys. + // state any + privPort int + pubPort int + psk []byte +} + +// Name returns a string identifier for the Transport for logging +func (*ClientTransport) Name() string { + return "dtls" +} + +// String returns a string identifier for the Transport for logging (including string formatters) +func (*ClientTransport) String() string { + return "dtls" +} + +// ID provides an identifier that will be sent to the conjure station during the registration so +// that the station knows what transport to expect connecting to the chosen phantom. +func (*ClientTransport) ID() pb.TransportType { + return pb.TransportType_DTLS +} + +// GetParams returns a generic protobuf with any parameters from both the registration and the +// transport. +func (t *ClientTransport) GetParams() (proto.Message, error) { + return t.Parameters, nil +} + +// SetParams allows the caller to set parameters associated with the transport, returning an +// error if the provided generic message is not compatible. +// +// DTLS transport currently has no caller controlled params +func (*ClientTransport) SetParams(any, ...bool) error { + return nil +} + +// Prepare lets the transport use the dialer to prepare. This is called before GetParams to let the +// transport prepare stuff such as nat traversal. +func (t *ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { + privePort, pubPort, err := publicAddr(defaultSTUNServer, dialer) + if err != nil { + return fmt.Errorf("error finding public port: %v", err) + } + + t.privPort = privePort + t.pubPort = pubPort + t.Parameters = &pb.DTLSTransportParams{SrcPort: proto.Uint32(uint32(pubPort))} + + return nil +} + +func (*ClientTransport) DisableRegDelay() bool { + return true +} + +// GetDstPort returns the destination port that the client should open the phantom connection to +func (t *ClientTransport) GetDstPort(seed []byte) (uint16, error) { + return transports.PortSelectorRange(portRangeMin, portRangeMax, seed) +} + +func (t *ClientTransport) WrapDial(dialer dialFunc) (dialFunc, error) { + dtlsDialer := func(ctx context.Context, network, localAddr, address string) (net.Conn, error) { + // Create a context that will automatically cancel after 5 seconds or when the existing context is cancelled, whichever comes first. + parentctx, parentcancel := context.WithTimeout(context.Background(), 10*time.Second) + defer parentcancel() + ctxtimeout, cancel := context.WithTimeout(parentctx, 5*time.Second) + defer cancel() + + conn, errListen := t.listen(ctxtimeout, dialer, address) + if errListen != nil { + // fallback to dial + conn, errDial := t.dial(parentctx, dialer, address) + if errDial != nil { + return nil, fmt.Errorf("error listening: %v, error dialing: %v", errListen, errDial) + } + + return conn, nil + } + + return conn, nil + } + + return dtlsDialer, nil +} + +func (t *ClientTransport) listen(ctx context.Context, dialer dialFunc, address string) (net.Conn, error) { + laddr := &net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: t.privPort} + err := openUDP(ctx, laddr.String(), address, dialer) + if err != nil { + return nil, fmt.Errorf("error opening UDP port from gateway: %v", err) + } + + udpConn, err := dialer(ctx, "udp", laddr.String(), address) + if err != nil { + return nil, fmt.Errorf("error dialing udp: %v", err) + } + + conn, err := dtls.ServerWithContext(ctx, udpConn, &dtls.Config{PSK: t.psk, SCTP: dtls.ClientOpen}) + if err != nil { + return nil, fmt.Errorf("error listening for phantom: %v", err) + } + + return conn, err +} + +func (t *ClientTransport) dial(ctx context.Context, dialer dialFunc, address string) (net.Conn, error) { + udpConn, err := dialer(ctx, "udp", "", address) + if err != nil { + return nil, fmt.Errorf("error dialing udp: %v", err) + } + + conn, err := dtls.ClientWithContext(ctx, udpConn, &dtls.Config{PSK: t.psk, SCTP: dtls.ClientOpen}) + if err != nil { + return nil, fmt.Errorf("error dialing as client: %v", err) + } + + return conn, err +} + +// PrepareKeys provides an opportunity for the transport to integrate the station public key +// as well as bytes from the deterministic random generator associated with the registration +// that this ClientTransport is attached t +func (t *ClientTransport) PrepareKeys(pubkey [32]byte, sharedSecret []byte, dRand io.Reader) error { + t.psk = sharedSecret + return nil +} + +// ParseParams gives the specific transport an option to parse a generic object into parameters +// provided by the station in the registration response during registration. +func (ClientTransport) ParseParams(*anypb.Any) (any, error) { + return nil, nil +} diff --git a/pkg/transports/connecting/dtls/dnat.go b/pkg/transports/connecting/dtls/dnat.go new file mode 100644 index 00000000..a08770b7 --- /dev/null +++ b/pkg/transports/connecting/dtls/dnat.go @@ -0,0 +1,149 @@ +package dtls + +import ( + "bytes" + "encoding/binary" + "fmt" + "net" + "os" + "strconv" + "syscall" + "unsafe" + + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "golang.org/x/sys/unix" +) + +func newDNAT() (*dnat, error) { + const ( + IFF_TUN = 0x0001 + IFF_NO_PI = 0x1000 + TUNSETIFF = 0x400454ca + ) + + tun, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0) + if err != nil { + return nil, err + } + + var ifreq [0x28]byte + + coreCountStr := os.Getenv("CJ_CORECOUNT") + coreCount, err := strconv.Atoi(coreCountStr) + if err != nil { + + return nil, fmt.Errorf("error parsing core count: %v", err) + } + + offsetStr := os.Getenv("OFFSET") + offset, err := strconv.Atoi(offsetStr) + if err != nil { + return nil, fmt.Errorf("error parsing offset: %v", err) + } + + copy(ifreq[:], "tun"+strconv.Itoa(offset+coreCount)) + + flags := IFF_TUN | IFF_NO_PI + binary.LittleEndian.PutUint16(ifreq[0x10:], uint16(flags)) + + fmt.Printf("fd: %v\n", tun.Fd()) + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, tun.Fd(), uintptr(TUNSETIFF), uintptr(unsafe.Pointer(&ifreq[0]))) + if errno != 0 { + tun.Close() + return nil, errno + } + fmt.Printf("fd after tun: %v\n", tun.Fd()) + + // Get the interface name + name := string(ifreq[:bytes.IndexByte(ifreq[:], 0)]) + + fmt.Println("Interface Name:", name) + + // Bring the interface up + err = setUp(tun, name) + if err != nil { + return nil, fmt.Errorf("error bring the interface up: %v", err) + } + + return &dnat{ + tun: tun, + }, nil +} + +// setUp brings up a network interface represented by the given name. +func setUp(tun *os.File, name string) error { + ifreq, err := unix.NewIfreq(name) + if err != nil { + return fmt.Errorf("error creating ifreq: %v", err) + } + + fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP) + if err != nil { + return fmt.Errorf("error creating socket: %v", err) + } + + // Get the current interface flags + err = unix.IoctlIfreq(fd, syscall.SIOCGIFFLAGS, ifreq) + if err != nil { + return fmt.Errorf("error getting interface flags: %v", err) + } + + ifreq.SetUint16(ifreq.Uint16() | syscall.IFF_UP) + + // Set the new interface flags + err = unix.IoctlIfreq(fd, syscall.SIOCSIFFLAGS, ifreq) + if err != nil { + return fmt.Errorf("error setting interface flags: %v", err) + } + + return nil +} + +type dnat struct { + tun *os.File +} + +func (d *dnat) addEntry(src net.IP, sport uint16, dst net.IP, dport uint16) error { + ipLayer := &layers.IPv4{ + Version: 4, + IHL: 5, + TTL: 64, + SrcIP: src, + DstIP: dst, + Protocol: layers.IPProtocolUDP, + } + + udpLayer := &layers.UDP{ + SrcPort: layers.UDPPort(sport), + DstPort: layers.UDPPort(dport), + } + + err := udpLayer.SetNetworkLayerForChecksum(ipLayer) + if err != nil { + return err + } + + payload := []byte("Hello world") + + buffer := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{ + ComputeChecksums: true, + FixLengths: true, + } + err = gopacket.SerializeLayers(buffer, opts, + ipLayer, + udpLayer, + gopacket.Payload(payload), + ) + if err != nil { + return fmt.Errorf("error serializing injected packet: %v", err) + } + + pkt := buffer.Bytes() + _, err = d.tun.Write(pkt) + if err != nil { + return fmt.Errorf("error writing to tun interface: %v", err) + } + return nil +} diff --git a/pkg/transports/connecting/dtls/dtls.go b/pkg/transports/connecting/dtls/dtls.go new file mode 100644 index 00000000..43d40ed5 --- /dev/null +++ b/pkg/transports/connecting/dtls/dtls.go @@ -0,0 +1,165 @@ +package dtls + +import ( + "context" + "fmt" + "net" + "strings" + + "github.com/libp2p/go-reuseport" + "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/dtls" + dd "github.com/refraction-networking/conjure/pkg/station/lib" + "github.com/refraction-networking/conjure/pkg/transports" + pb "github.com/refraction-networking/conjure/proto" + "google.golang.org/protobuf/types/known/anypb" +) + +const listenPort = 41245 + +type Transport struct { + dnat *dnat + dtlsListener *dtls.Listener + unregLogger func(*net.IP) + logDialSuccess func(*net.IP) + logListenSuccess func(*net.IP) +} + +// Name returns name of the transport +func (Transport) Name() string { + return "dtls" +} + +// LogPrefix returns log prefix of the transport +func (Transport) LogPrefix() string { + return "DTLS" +} + +// GetIdentifier returns an identifier unique a registration +func (Transport) GetIdentifier(reg *dd.DecoyRegistration) string { + return string(core.ConjureHMAC(reg.Keys.SharedSecret, "dtlsTrasportHMACString")) +} + +// NewTransport creates a new dtls transport +func NewTransport(logAuthFail func(*net.IP), logOtherFail func(*net.IP), logDialSuccess func(*net.IP), logListenSuccess func(*net.IP)) (*Transport, error) { + addr := &net.UDPAddr{Port: listenPort} + + listener, err := dtls.Listen("udp", addr, &dtls.Config{LogAuthFail: logAuthFail, LogOther: logAuthFail}) + if err != nil { + return nil, fmt.Errorf("error creating dtls listner: %v", err) + } + + dnat, err := newDNAT() + + if err != nil { + return nil, fmt.Errorf("error connecting to tun device for DNAT: %v", err) + } + + return &Transport{ + dnat: dnat, + dtlsListener: listener, + unregLogger: logAuthFail, + }, nil +} + +// Connect takes a registraion and returns a dtls Conn connected to the client +func (t *Transport) Connect(ctx context.Context, reg *dd.DecoyRegistration) (net.Conn, error) { + if reg.Transport != pb.TransportType_DTLS { + return nil, transports.ErrNotTransport + } + + clientAddr := net.UDPAddr{IP: net.ParseIP(reg.GetRegistrationAddress()), Port: int(reg.GetSrcPort())} + + err := t.dnat.addEntry(clientAddr.IP, uint16(clientAddr.Port), reg.PhantomIp, reg.PhantomPort) + if err != nil { + return nil, fmt.Errorf("error adding DNAT entry: %v", err) + } + + laddr := net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: listenPort} + + connCh := make(chan net.Conn, 2) + errCh := make(chan error, 2) + + go func() { + udpConn, err := reuseport.Dial("udp", laddr.String(), clientAddr.String()) + if err != nil { + errCh <- fmt.Errorf("error connecting to dtls client: %v", err) + return + } + + dtlsConn, err := dtls.ClientWithContext(ctx, udpConn, &dtls.Config{PSK: reg.Keys.SharedSecret, SCTP: dtls.ServerAccept}) + if err != nil { + errCh <- fmt.Errorf("error connecting to dtls client: %v", err) + return + } + t.logDialSuccess(&clientAddr.IP) + + connCh <- dtlsConn + }() + + go func() { + conn, err := t.dtlsListener.AcceptWithContext(ctx, &dtls.Config{PSK: reg.Keys.SharedSecret, SCTP: dtls.ServerAccept}) + if err != nil { + errCh <- fmt.Errorf("error accepting dtls connection from secret: %v", err) + return + } + t.logListenSuccess(&clientAddr.IP) + + connCh <- conn + }() + + var errs []error + for i := 0; i < 2; i++ { + select { + case conn := <-connCh: + if conn != nil { + return conn, nil // success, so return the connection + } + case err := <-errCh: + if err != nil { // store the error + errs = append(errs, err) + } + } + } + + // combine errors into a single error + var combinedErr error + if len(errs) > 0 { + errStrings := make([]string, len(errs)) + for i, err := range errs { + errStrings[i] = err.Error() + } + combinedErr = fmt.Errorf(strings.Join(errStrings, "; ")) + } + + return nil, combinedErr // if we reached here, both attempts failed +} + +func (Transport) GetSrcPort(libVersion uint, seed []byte, params any) (uint16, error) { + parameters, ok := params.(*pb.DTLSTransportParams) + if !ok { + return 0, fmt.Errorf("bad parameters provided") + } + + return uint16(parameters.GetSrcPort()), nil +} + +func (Transport) GetDstPort(libVersion uint, seed []byte, params any) (uint16, error) { + return transports.PortSelectorRange(portRangeMin, portRangeMax, seed) +} + +func (Transport) GetProto() pb.IPProto { + return pb.IPProto_Udp +} + +func (Transport) ParseParams(libVersion uint, data *anypb.Any) (any, error) { + var m = &pb.DTLSTransportParams{} + err := transports.UnmarshalAnypbTo(data, m) + return m, err +} + +// ParamStrings returns an array of tag string that will be added to tunStats when a proxy +// session is closed. For now, no params of interest. +func (t Transport) ParamStrings(p any) []string { + return nil +} diff --git a/pkg/transports/connecting/dtls/nat.go b/pkg/transports/connecting/dtls/nat.go new file mode 100644 index 00000000..1a5db59d --- /dev/null +++ b/pkg/transports/connecting/dtls/nat.go @@ -0,0 +1,113 @@ +package dtls + +import ( + "context" + "fmt" + "net" + "os" + "syscall" + + "github.com/pion/stun" +) + +const ttl = 5 +const defaultTTL = 64 + +type fileConn interface { + File() (*os.File, error) +} + +func openUDP(ctx context.Context, laddr, addr string, dialer dialFunc) error { + // Create a UDP connection + conn, err := dialer(ctx, "udp", laddr, addr) + if err != nil { + return err + } + defer conn.Close() + + fileConn, ok := conn.(fileConn) + if !ok { + return fmt.Errorf("dialed conn does not implement File()") + } + + // Get the file descriptor + fd, err := fileConn.File() + if err != nil { + return err + } + defer fd.Close() + + // Set the TTL + err = syscall.SetsockoptInt(int(fd.Fd()), syscall.IPPROTO_IP, syscall.IP_TTL, ttl) + if err != nil { + return err + } + + // Write data to the connection + _, err = conn.Write([]byte("")) + if err != nil { + return err + } + + // reset TTL + err = syscall.SetsockoptInt(int(fd.Fd()), syscall.IPPROTO_IP, syscall.IP_TTL, defaultTTL) + if err != nil { + return err + } + + // No error + return nil +} + +var ( + privPortSingle int + pubPortSingle int +) + +func publicAddr(stunServer string, dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) (privatePort int, publicPort int, err error) { + + if privPortSingle != 0 && pubPortSingle != 0 { + return privPortSingle, pubPortSingle, nil + } + + udpConn, err := dialer(context.Background(), "udp", "", stunServer) + if err != nil { + return 0, 0, fmt.Errorf("error connecting to STUN server: %v", err) + } + defer udpConn.Close() + + localAddr, err := net.ResolveUDPAddr(udpConn.LocalAddr().Network(), udpConn.LocalAddr().String()) + if err != nil { + return 0, 0, fmt.Errorf("error resolving local address: %v", err) + } + + client, err := stun.NewClient(udpConn) + if err != nil { + return 0, 0, fmt.Errorf("error creating STUN client: %v", err) + } + + message := stun.MustBuild(stun.TransactionID, stun.BindingRequest) + + var xorAddr stun.XORMappedAddress + + err = client.Do(message, func(res stun.Event) { + if res.Error != nil { + err = res.Error + return + } + + err = xorAddr.GetFrom(res.Message) + if err != nil { + return + } + }) + + if err != nil { + return 0, 0, fmt.Errorf("error getting address from STUN: %v", err) + } + + privPortSingle = localAddr.Port + pubPortSingle = xorAddr.Port + + return localAddr.Port, xorAddr.Port, nil +} diff --git a/pkg/transports/wrapping/min/client.go b/pkg/transports/wrapping/min/client.go index 3036b416..e3474a37 100644 --- a/pkg/transports/wrapping/min/client.go +++ b/pkg/transports/wrapping/min/client.go @@ -1,6 +1,7 @@ package min import ( + "context" "fmt" "io" "net" @@ -38,6 +39,10 @@ func (*ClientTransport) ID() pb.TransportType { return pb.TransportType_Min } +func (*ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { + return nil +} + // GetParams returns a generic protobuf with any parameters from both the registration and the // transport. func (t *ClientTransport) GetParams() (proto.Message, error) { diff --git a/pkg/transports/wrapping/obfs4/client.go b/pkg/transports/wrapping/obfs4/client.go index 6e5386ce..9912c553 100644 --- a/pkg/transports/wrapping/obfs4/client.go +++ b/pkg/transports/wrapping/obfs4/client.go @@ -1,6 +1,7 @@ package obfs4 import ( + "context" "fmt" "io" "net" @@ -37,6 +38,10 @@ func (*ClientTransport) ID() pb.TransportType { return pb.TransportType_Obfs4 } +func (*ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { + return nil +} + // GetParams returns a generic protobuf with any parameters from both the registration and the // transport. func (t *ClientTransport) GetParams() (proto.Message, error) { diff --git a/pkg/transports/wrapping/prefix/client.go b/pkg/transports/wrapping/prefix/client.go index 8422cb88..5bc17ec8 100644 --- a/pkg/transports/wrapping/prefix/client.go +++ b/pkg/transports/wrapping/prefix/client.go @@ -2,6 +2,7 @@ package prefix import ( "bufio" + "context" "crypto/rand" "fmt" "io" @@ -71,6 +72,10 @@ func (*ClientTransport) ID() pb.TransportType { return pb.TransportType_Prefix } +func (*ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { + return nil +} + // GetParams returns a generic protobuf with any parameters from both the registration and the // transport. func (t *ClientTransport) GetParams() (proto.Message, error) { diff --git a/proto/signalling.pb.go b/proto/signalling.pb.go index 72d40594..fa5b0701 100644 --- a/proto/signalling.pb.go +++ b/proto/signalling.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v3.20.3 +// protoc-gen-go v1.30.0 +// protoc v4.23.3 // source: signalling.proto // TODO: We're using proto2 because it's the default on Ubuntu 16.04. @@ -1309,6 +1309,53 @@ func (x *WebRTCSignal) GetSdp() *WebRTCSDP { return nil } +type DTLSTransportParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SrcPort *uint32 `protobuf:"varint,1,opt,name=src_port,json=srcPort" json:"src_port,omitempty"` +} + +func (x *DTLSTransportParams) Reset() { + *x = DTLSTransportParams{} + if protoimpl.UnsafeEnabled { + mi := &file_signalling_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DTLSTransportParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DTLSTransportParams) ProtoMessage() {} + +func (x *DTLSTransportParams) ProtoReflect() protoreflect.Message { + mi := &file_signalling_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DTLSTransportParams.ProtoReflect.Descriptor instead. +func (*DTLSTransportParams) Descriptor() ([]byte, []int) { + return file_signalling_proto_rawDescGZIP(), []int{10} +} + +func (x *DTLSTransportParams) GetSrcPort() uint32 { + if x != nil && x.SrcPort != nil { + return *x.SrcPort + } + return 0 +} + type StationToClient struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1335,7 +1382,7 @@ type StationToClient struct { func (x *StationToClient) Reset() { *x = StationToClient{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[10] + mi := &file_signalling_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1348,7 +1395,7 @@ func (x *StationToClient) String() string { func (*StationToClient) ProtoMessage() {} func (x *StationToClient) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[10] + mi := &file_signalling_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1361,7 +1408,7 @@ func (x *StationToClient) ProtoReflect() protoreflect.Message { // Deprecated: Use StationToClient.ProtoReflect.Descriptor instead. func (*StationToClient) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{10} + return file_signalling_proto_rawDescGZIP(), []int{11} } func (x *StationToClient) GetProtocolVersion() uint32 { @@ -1428,7 +1475,7 @@ type RegistrationFlags struct { func (x *RegistrationFlags) Reset() { *x = RegistrationFlags{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[11] + mi := &file_signalling_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1441,7 +1488,7 @@ func (x *RegistrationFlags) String() string { func (*RegistrationFlags) ProtoMessage() {} func (x *RegistrationFlags) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[11] + mi := &file_signalling_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1454,7 +1501,7 @@ func (x *RegistrationFlags) ProtoReflect() protoreflect.Message { // Deprecated: Use RegistrationFlags.ProtoReflect.Descriptor instead. func (*RegistrationFlags) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{11} + return file_signalling_proto_rawDescGZIP(), []int{12} } func (x *RegistrationFlags) GetUploadOnly() bool { @@ -1544,7 +1591,7 @@ type ClientToStation struct { func (x *ClientToStation) Reset() { *x = ClientToStation{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[12] + mi := &file_signalling_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1557,7 +1604,7 @@ func (x *ClientToStation) String() string { func (*ClientToStation) ProtoMessage() {} func (x *ClientToStation) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[12] + mi := &file_signalling_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1570,7 +1617,7 @@ func (x *ClientToStation) ProtoReflect() protoreflect.Message { // Deprecated: Use ClientToStation.ProtoReflect.Descriptor instead. func (*ClientToStation) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{12} + return file_signalling_proto_rawDescGZIP(), []int{13} } func (x *ClientToStation) GetProtocolVersion() uint32 { @@ -1712,7 +1759,7 @@ type PrefixTransportParams struct { func (x *PrefixTransportParams) Reset() { *x = PrefixTransportParams{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[13] + mi := &file_signalling_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1725,7 +1772,7 @@ func (x *PrefixTransportParams) String() string { func (*PrefixTransportParams) ProtoMessage() {} func (x *PrefixTransportParams) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[13] + mi := &file_signalling_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1738,7 +1785,7 @@ func (x *PrefixTransportParams) ProtoReflect() protoreflect.Message { // Deprecated: Use PrefixTransportParams.ProtoReflect.Descriptor instead. func (*PrefixTransportParams) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{13} + return file_signalling_proto_rawDescGZIP(), []int{14} } func (x *PrefixTransportParams) GetPrefixId() int32 { @@ -1783,7 +1830,7 @@ type GenericTransportParams struct { func (x *GenericTransportParams) Reset() { *x = GenericTransportParams{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[14] + mi := &file_signalling_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1796,7 +1843,7 @@ func (x *GenericTransportParams) String() string { func (*GenericTransportParams) ProtoMessage() {} func (x *GenericTransportParams) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[14] + mi := &file_signalling_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1809,7 +1856,7 @@ func (x *GenericTransportParams) ProtoReflect() protoreflect.Message { // Deprecated: Use GenericTransportParams.ProtoReflect.Descriptor instead. func (*GenericTransportParams) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{14} + return file_signalling_proto_rawDescGZIP(), []int{15} } func (x *GenericTransportParams) GetRandomizeDstPort() bool { @@ -1849,7 +1896,7 @@ type C2SWrapper struct { func (x *C2SWrapper) Reset() { *x = C2SWrapper{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[15] + mi := &file_signalling_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1862,7 +1909,7 @@ func (x *C2SWrapper) String() string { func (*C2SWrapper) ProtoMessage() {} func (x *C2SWrapper) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[15] + mi := &file_signalling_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1875,7 +1922,7 @@ func (x *C2SWrapper) ProtoReflect() protoreflect.Message { // Deprecated: Use C2SWrapper.ProtoReflect.Descriptor instead. func (*C2SWrapper) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{15} + return file_signalling_proto_rawDescGZIP(), []int{16} } func (x *C2SWrapper) GetSharedSecret() []byte { @@ -1951,7 +1998,7 @@ type SessionStats struct { func (x *SessionStats) Reset() { *x = SessionStats{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[16] + mi := &file_signalling_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1964,7 +2011,7 @@ func (x *SessionStats) String() string { func (*SessionStats) ProtoMessage() {} func (x *SessionStats) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[16] + mi := &file_signalling_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1977,7 +2024,7 @@ func (x *SessionStats) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionStats.ProtoReflect.Descriptor instead. func (*SessionStats) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{16} + return file_signalling_proto_rawDescGZIP(), []int{17} } func (x *SessionStats) GetFailedDecoysAmount() uint32 { @@ -2032,7 +2079,7 @@ type StationToDetector struct { func (x *StationToDetector) Reset() { *x = StationToDetector{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[17] + mi := &file_signalling_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2045,7 +2092,7 @@ func (x *StationToDetector) String() string { func (*StationToDetector) ProtoMessage() {} func (x *StationToDetector) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[17] + mi := &file_signalling_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2058,7 +2105,7 @@ func (x *StationToDetector) ProtoReflect() protoreflect.Message { // Deprecated: Use StationToDetector.ProtoReflect.Descriptor instead. func (*StationToDetector) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{17} + return file_signalling_proto_rawDescGZIP(), []int{18} } func (x *StationToDetector) GetPhantomIp() string { @@ -2135,7 +2182,7 @@ type RegistrationResponse struct { func (x *RegistrationResponse) Reset() { *x = RegistrationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[18] + mi := &file_signalling_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2148,7 +2195,7 @@ func (x *RegistrationResponse) String() string { func (*RegistrationResponse) ProtoMessage() {} func (x *RegistrationResponse) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[18] + mi := &file_signalling_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2161,7 +2208,7 @@ func (x *RegistrationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegistrationResponse.ProtoReflect.Descriptor instead. func (*RegistrationResponse) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{18} + return file_signalling_proto_rawDescGZIP(), []int{19} } func (x *RegistrationResponse) GetIpv4Addr() uint32 { @@ -2227,7 +2274,7 @@ type DnsResponse struct { func (x *DnsResponse) Reset() { *x = DnsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[19] + mi := &file_signalling_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2240,7 +2287,7 @@ func (x *DnsResponse) String() string { func (*DnsResponse) ProtoMessage() {} func (x *DnsResponse) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[19] + mi := &file_signalling_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2253,7 +2300,7 @@ func (x *DnsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DnsResponse.ProtoReflect.Descriptor instead. func (*DnsResponse) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{19} + return file_signalling_proto_rawDescGZIP(), []int{20} } func (x *DnsResponse) GetSuccess() bool { @@ -2367,258 +2414,262 @@ var file_signalling_proto_rawDesc = []byte{ 0x0a, 0x04, 0x73, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, - 0x43, 0x53, 0x44, 0x50, 0x52, 0x03, 0x73, 0x64, 0x70, 0x22, 0xcb, 0x02, 0x0a, 0x0f, 0x53, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, - 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, 0x10, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x53, 0x32, - 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, - 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x37, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x73, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, - 0x6e, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53, - 0x32, 0x43, 0x52, 0x09, 0x65, 0x72, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, - 0x0b, 0x74, 0x6d, 0x70, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6d, 0x70, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, - 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xaf, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x1f, 0x0a, - 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, - 0x0a, 0x0a, 0x64, 0x61, 0x72, 0x6b, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x09, 0x64, 0x61, 0x72, 0x6b, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x12, 0x21, 0x0a, - 0x0c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x54, 0x49, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x54, 0x49, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x65, - 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x70, - 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x22, 0xb7, 0x06, 0x0a, 0x0f, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, - 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x6f, - 0x79, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x4c, 0x69, - 0x73, 0x74, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, 0x10, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, - 0x65, 0x2e, 0x43, 0x32, 0x53, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x79, 0x6e, 0x63, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x79, - 0x6e, 0x63, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x62, - 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x3e, 0x0a, 0x1b, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x72, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, - 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, - 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x44, - 0x65, 0x63, 0x6f, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, - 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x6d, 0x61, 0x73, 0x6b, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x63, - 0x6f, 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x15, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6d, 0x61, 0x73, 0x6b, 0x65, 0x64, 0x44, 0x65, 0x63, 0x6f, - 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x76, - 0x36, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x09, 0x76, 0x36, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x34, - 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, - 0x76, 0x34, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x66, 0x6c, 0x61, - 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, - 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x3b, 0x0a, 0x0d, - 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x1f, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x57, - 0x65, 0x62, 0x52, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x0c, 0x77, 0x65, 0x62, - 0x72, 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, - 0x64, 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, - 0x69, 0x6e, 0x67, 0x22, 0xa8, 0x01, 0x0a, 0x15, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1b, 0x0a, - 0x09, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, - 0x69, 0x78, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x5f, 0x61, 0x66, 0x74, 0x65, - 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, - 0x66, 0x6c, 0x75, 0x73, 0x68, 0x41, 0x66, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, 0x73, - 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x61, - 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x46, - 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, - 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, - 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, - 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0xcb, 0x03, 0x0a, 0x0a, 0x43, 0x32, 0x53, 0x57, 0x72, - 0x61, 0x70, 0x70, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, - 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x68, - 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x4c, 0x0a, 0x14, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, - 0x6e, 0x63, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x4d, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, - 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x12, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, - 0x63, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x53, 0x0a, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, - 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x14, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x52, 0x65, 0x67, 0x52, - 0x65, 0x73, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x52, - 0x65, 0x73, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x10, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, - 0x64, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x12, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x44, 0x65, 0x63, 0x6f, 0x79, - 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, - 0x65, 0x54, 0x6f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x74, - 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x21, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0c, 0x72, 0x74, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6c, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, - 0x18, 0x26, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6c, 0x73, 0x54, 0x6f, 0x44, 0x65, 0x63, - 0x6f, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x63, 0x70, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x63, - 0x6f, 0x79, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x63, 0x70, 0x54, 0x6f, 0x44, - 0x65, 0x63, 0x6f, 0x79, 0x22, 0x88, 0x02, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x54, 0x6f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x68, - 0x61, 0x6e, 0x74, 0x6f, 0x6d, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x70, 0x68, 0x61, 0x6e, 0x74, 0x6f, 0x6d, 0x49, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x4e, 0x73, 0x12, 0x39, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, - 0x6e, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, - 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, - 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, - 0x2e, 0x49, 0x50, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0x9a, 0x02, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, 0x76, 0x34, - 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x52, 0x08, 0x69, 0x70, 0x76, 0x34, - 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, 0x64, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, 0x64, 0x72, - 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x64, - 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x52, - 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x3f, 0x0a, 0x10, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0f, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0xaf, 0x01, 0x0a, - 0x0b, 0x44, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x6f, 0x75, 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x63, 0x6f, 0x6e, 0x66, 0x4f, - 0x75, 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x55, 0x0a, 0x16, 0x62, 0x69, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, - 0x63, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x15, 0x62, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x2b, - 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, - 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x5a, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, - 0x53, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x5b, 0x2a, 0x29, 0x0a, 0x0c, 0x44, - 0x6e, 0x73, 0x52, 0x65, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x07, 0x0a, 0x03, 0x55, - 0x44, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x54, 0x10, 0x02, 0x12, 0x07, 0x0a, - 0x03, 0x44, 0x4f, 0x48, 0x10, 0x03, 0x2a, 0xe7, 0x01, 0x0a, 0x0e, 0x43, 0x32, 0x53, 0x5f, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x32, 0x53, - 0x5f, 0x4e, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, - 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x49, 0x54, - 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, - 0x4e, 0x5f, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x0b, 0x12, - 0x18, 0x0a, 0x14, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, - 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x32, 0x53, - 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x03, - 0x12, 0x14, 0x0a, 0x10, 0x43, 0x32, 0x53, 0x5f, 0x59, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x55, 0x50, - 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x32, 0x53, 0x5f, 0x41, 0x43, - 0x51, 0x55, 0x49, 0x52, 0x45, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x05, 0x12, 0x20, - 0x0a, 0x1c, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, 0x55, 0x50, 0x4c, - 0x4f, 0x41, 0x44, 0x4f, 0x4e, 0x4c, 0x59, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x10, 0x06, - 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xff, 0x01, - 0x2a, 0x98, 0x01, 0x0a, 0x0e, 0x53, 0x32, 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x32, 0x43, 0x5f, 0x4e, 0x4f, 0x5f, 0x43, 0x48, - 0x41, 0x4e, 0x47, 0x45, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, - 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, - 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x56, 0x45, - 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x32, 0x43, - 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x45, - 0x43, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, 0x53, 0x53, - 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x53, - 0x32, 0x43, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xff, 0x01, 0x2a, 0xac, 0x01, 0x0a, 0x0e, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53, 0x32, 0x43, 0x12, 0x0c, - 0x0a, 0x08, 0x4e, 0x4f, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, - 0x43, 0x4f, 0x56, 0x45, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x01, 0x12, - 0x13, 0x0a, 0x0f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x52, 0x54, - 0x45, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x50, - 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x41, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x04, 0x12, - 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x43, 0x4f, 0x59, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, 0x4f, 0x41, - 0x44, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, - 0x52, 0x45, 0x41, 0x4d, 0x10, 0x64, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, - 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x65, 0x2a, 0x82, 0x01, 0x0a, 0x0d, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, - 0x4e, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x69, 0x6e, 0x10, 0x01, 0x12, - 0x09, 0x0a, 0x05, 0x4f, 0x62, 0x66, 0x73, 0x34, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x54, - 0x4c, 0x53, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x10, 0x04, - 0x12, 0x08, 0x0a, 0x04, 0x75, 0x54, 0x4c, 0x53, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x6f, - 0x72, 0x6d, 0x61, 0x74, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x53, 0x4d, 0x10, 0x07, - 0x12, 0x07, 0x0a, 0x03, 0x46, 0x54, 0x45, 0x10, 0x08, 0x12, 0x08, 0x0a, 0x04, 0x51, 0x75, 0x69, - 0x63, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x57, 0x65, 0x62, 0x72, 0x74, 0x63, 0x10, 0x63, 0x2a, - 0x86, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x65, 0x74, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x10, 0x02, 0x12, 0x13, - 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x73, 0x63, 0x61, - 0x6e, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x50, 0x49, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4e, 0x53, - 0x10, 0x05, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x61, 0x6c, 0x44, 0x4e, 0x53, 0x10, 0x06, 0x2a, 0x40, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0b, 0x0a, - 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x65, - 0x77, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x10, 0x02, 0x12, - 0x09, 0x0a, 0x05, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x10, 0x03, 0x2a, 0x24, 0x0a, 0x07, 0x49, 0x50, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x6e, 0x6b, 0x10, 0x00, 0x12, 0x07, - 0x0a, 0x03, 0x54, 0x63, 0x70, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x64, 0x70, 0x10, 0x02, + 0x43, 0x53, 0x44, 0x50, 0x52, 0x03, 0x73, 0x64, 0x70, 0x22, 0x30, 0x0a, 0x13, 0x44, 0x54, 0x4c, + 0x53, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x22, 0xcb, 0x02, 0x0a, 0x0f, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, + 0x29, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, 0x10, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, + 0x53, 0x32, 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x35, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x37, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x72, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x74, 0x61, 0x70, + 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x53, 0x32, 0x43, 0x52, 0x09, 0x65, 0x72, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, + 0x1f, 0x0a, 0x0b, 0x74, 0x6d, 0x70, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6d, 0x70, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xaf, 0x01, 0x0a, 0x11, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, + 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, + 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x72, 0x6b, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x64, 0x61, 0x72, 0x6b, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x12, + 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x54, 0x49, 0x4c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x54, 0x49, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x70, + 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x70, 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x22, 0xb7, 0x06, 0x0a, 0x0f, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x29, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x64, 0x65, + 0x63, 0x6f, 0x79, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x64, 0x65, 0x63, 0x6f, 0x79, + 0x4c, 0x69, 0x73, 0x74, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x43, + 0x0a, 0x10, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, + 0x6e, 0x63, 0x65, 0x2e, 0x43, 0x32, 0x53, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x79, + 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, + 0x69, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x10, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x1b, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x72, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, + 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x63, + 0x6f, 0x79, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, + 0x65, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, + 0x6e, 0x63, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3f, 0x0a, 0x10, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0f, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x25, 0x0a, + 0x0e, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x6d, 0x61, 0x73, 0x6b, 0x65, 0x64, 0x5f, 0x64, + 0x65, 0x63, 0x6f, 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6d, 0x61, 0x73, 0x6b, 0x65, 0x64, 0x44, 0x65, + 0x63, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x76, 0x36, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x76, 0x36, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, + 0x76, 0x34, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x76, 0x34, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x66, + 0x6c, 0x61, 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x61, 0x70, + 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x3b, + 0x0a, 0x0d, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, + 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, + 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x0c, 0x77, + 0x65, 0x62, 0x72, 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xa8, 0x01, 0x0a, 0x15, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, + 0x1b, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, + 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x5f, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x10, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x41, 0x66, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, + 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, + 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, + 0x22, 0x46, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, + 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, + 0x65, 0x44, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0xcb, 0x03, 0x0a, 0x0a, 0x43, 0x32, 0x53, + 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x64, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x4c, 0x0a, 0x14, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x61, 0x70, + 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x4d, 0x0a, 0x13, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, + 0x63, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x12, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x14, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, + 0x64, 0x65, 0x63, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x53, 0x0a, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x52, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x52, 0x65, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x52, 0x65, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x44, 0x65, 0x63, + 0x6f, 0x79, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x54, + 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x24, 0x0a, 0x0e, + 0x72, 0x74, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x21, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x72, 0x74, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6c, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x63, + 0x6f, 0x79, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6c, 0x73, 0x54, 0x6f, 0x44, + 0x65, 0x63, 0x6f, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x63, 0x70, 0x5f, 0x74, 0x6f, 0x5f, 0x64, + 0x65, 0x63, 0x6f, 0x79, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x63, 0x70, 0x54, + 0x6f, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x22, 0x88, 0x02, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x6f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, + 0x70, 0x68, 0x61, 0x6e, 0x74, 0x6f, 0x6d, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x70, 0x68, 0x61, 0x6e, 0x74, 0x6f, 0x6d, 0x49, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4e, 0x73, 0x12, 0x39, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x74, 0x61, 0x70, + 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, + 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x27, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x64, 0x61, 0x6e, + 0x63, 0x65, 0x2e, 0x49, 0x50, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x9a, 0x02, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, + 0x76, 0x34, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x52, 0x08, 0x69, 0x70, + 0x76, 0x34, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, + 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, + 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, + 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x64, 0x6f, + 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x61, + 0x70, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x3f, 0x0a, + 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0f, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0xaf, + 0x01, 0x0a, 0x0b, 0x44, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x6f, 0x75, 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x63, 0x6f, 0x6e, + 0x66, 0x4f, 0x75, 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x55, 0x0a, 0x16, 0x62, 0x69, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x61, 0x70, 0x64, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x15, 0x62, 0x69, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2a, 0x2b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x41, + 0x45, 0x53, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x5a, 0x12, 0x0f, 0x0a, 0x0b, + 0x41, 0x45, 0x53, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x5b, 0x2a, 0x29, 0x0a, + 0x0c, 0x44, 0x6e, 0x73, 0x52, 0x65, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x07, 0x0a, + 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x54, 0x10, 0x02, 0x12, + 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x48, 0x10, 0x03, 0x2a, 0xe7, 0x01, 0x0a, 0x0e, 0x43, 0x32, 0x53, + 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x43, + 0x32, 0x53, 0x5f, 0x4e, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x00, 0x12, 0x14, + 0x0a, 0x10, 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, + 0x49, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, + 0x0b, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, + 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x43, + 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, + 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x32, 0x53, 0x5f, 0x59, 0x49, 0x45, 0x4c, 0x44, 0x5f, + 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x32, 0x53, 0x5f, + 0x41, 0x43, 0x51, 0x55, 0x49, 0x52, 0x45, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x05, + 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, 0x55, + 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x4f, 0x4e, 0x4c, 0x59, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, + 0x10, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, + 0xff, 0x01, 0x2a, 0x98, 0x01, 0x0a, 0x0e, 0x53, 0x32, 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x32, 0x43, 0x5f, 0x4e, 0x4f, 0x5f, + 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x32, 0x43, 0x5f, + 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x01, 0x12, 0x1b, + 0x0a, 0x17, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, + 0x56, 0x45, 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, + 0x32, 0x43, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, + 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, + 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x03, 0x12, 0x0e, 0x0a, + 0x09, 0x53, 0x32, 0x43, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xff, 0x01, 0x2a, 0xac, 0x01, + 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53, 0x32, 0x43, + 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x11, + 0x0a, 0x0d, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, + 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x50, 0x4f, + 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, + 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x53, + 0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, + 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x43, 0x4f, 0x59, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, + 0x4f, 0x41, 0x44, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x64, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x49, 0x45, + 0x4e, 0x54, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x65, 0x2a, 0x82, 0x01, 0x0a, + 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, + 0x0a, 0x04, 0x4e, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x69, 0x6e, 0x10, + 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x62, 0x66, 0x73, 0x34, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, + 0x44, 0x54, 0x4c, 0x53, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x75, 0x54, 0x4c, 0x53, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, + 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x53, 0x4d, + 0x10, 0x07, 0x12, 0x07, 0x0a, 0x03, 0x46, 0x54, 0x45, 0x10, 0x08, 0x12, 0x08, 0x0a, 0x04, 0x51, + 0x75, 0x69, 0x63, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x57, 0x65, 0x62, 0x72, 0x74, 0x63, 0x10, + 0x63, 0x2a, 0x86, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x65, 0x74, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x10, 0x02, + 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x73, + 0x63, 0x61, 0x6e, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x50, 0x49, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x44, + 0x4e, 0x53, 0x10, 0x05, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x4e, 0x53, 0x10, 0x06, 0x2a, 0x40, 0x0a, 0x11, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, + 0x4e, 0x65, 0x77, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x10, + 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x10, 0x03, 0x2a, 0x24, 0x0a, 0x07, + 0x49, 0x50, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x6e, 0x6b, 0x10, 0x00, + 0x12, 0x07, 0x0a, 0x03, 0x54, 0x63, 0x70, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x64, 0x70, + 0x10, 0x02, } var ( @@ -2634,7 +2685,7 @@ func file_signalling_proto_rawDescGZIP() []byte { } var file_signalling_proto_enumTypes = make([]protoimpl.EnumInfo, 9) -var file_signalling_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_signalling_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_signalling_proto_goTypes = []interface{}{ (KeyType)(0), // 0: tapdance.KeyType (DnsRegMethod)(0), // 1: tapdance.DnsRegMethod @@ -2655,17 +2706,18 @@ var file_signalling_proto_goTypes = []interface{}{ (*WebRTCICECandidate)(nil), // 16: tapdance.WebRTCICECandidate (*WebRTCSDP)(nil), // 17: tapdance.WebRTCSDP (*WebRTCSignal)(nil), // 18: tapdance.WebRTCSignal - (*StationToClient)(nil), // 19: tapdance.StationToClient - (*RegistrationFlags)(nil), // 20: tapdance.RegistrationFlags - (*ClientToStation)(nil), // 21: tapdance.ClientToStation - (*PrefixTransportParams)(nil), // 22: tapdance.PrefixTransportParams - (*GenericTransportParams)(nil), // 23: tapdance.GenericTransportParams - (*C2SWrapper)(nil), // 24: tapdance.C2SWrapper - (*SessionStats)(nil), // 25: tapdance.SessionStats - (*StationToDetector)(nil), // 26: tapdance.StationToDetector - (*RegistrationResponse)(nil), // 27: tapdance.RegistrationResponse - (*DnsResponse)(nil), // 28: tapdance.DnsResponse - (*anypb.Any)(nil), // 29: google.protobuf.Any + (*DTLSTransportParams)(nil), // 19: tapdance.DTLSTransportParams + (*StationToClient)(nil), // 20: tapdance.StationToClient + (*RegistrationFlags)(nil), // 21: tapdance.RegistrationFlags + (*ClientToStation)(nil), // 22: tapdance.ClientToStation + (*PrefixTransportParams)(nil), // 23: tapdance.PrefixTransportParams + (*GenericTransportParams)(nil), // 24: tapdance.GenericTransportParams + (*C2SWrapper)(nil), // 25: tapdance.C2SWrapper + (*SessionStats)(nil), // 26: tapdance.SessionStats + (*StationToDetector)(nil), // 27: tapdance.StationToDetector + (*RegistrationResponse)(nil), // 28: tapdance.RegistrationResponse + (*DnsResponse)(nil), // 29: tapdance.DnsResponse + (*anypb.Any)(nil), // 30: google.protobuf.Any } var file_signalling_proto_depIdxs = []int32{ 0, // 0: tapdance.PubKey.type:type_name -> tapdance.KeyType @@ -2684,19 +2736,19 @@ var file_signalling_proto_depIdxs = []int32{ 11, // 13: tapdance.StationToClient.config_info:type_name -> tapdance.ClientConf 4, // 14: tapdance.StationToClient.err_reason:type_name -> tapdance.ErrorReasonS2C 2, // 15: tapdance.ClientToStation.state_transition:type_name -> tapdance.C2S_Transition - 25, // 16: tapdance.ClientToStation.stats:type_name -> tapdance.SessionStats + 26, // 16: tapdance.ClientToStation.stats:type_name -> tapdance.SessionStats 5, // 17: tapdance.ClientToStation.transport:type_name -> tapdance.TransportType - 29, // 18: tapdance.ClientToStation.transport_params:type_name -> google.protobuf.Any - 20, // 19: tapdance.ClientToStation.flags:type_name -> tapdance.RegistrationFlags + 30, // 18: tapdance.ClientToStation.transport_params:type_name -> google.protobuf.Any + 21, // 19: tapdance.ClientToStation.flags:type_name -> tapdance.RegistrationFlags 18, // 20: tapdance.ClientToStation.webrtc_signal:type_name -> tapdance.WebRTCSignal - 21, // 21: tapdance.C2SWrapper.registration_payload:type_name -> tapdance.ClientToStation + 22, // 21: tapdance.C2SWrapper.registration_payload:type_name -> tapdance.ClientToStation 6, // 22: tapdance.C2SWrapper.registration_source:type_name -> tapdance.RegistrationSource - 27, // 23: tapdance.C2SWrapper.registration_response:type_name -> tapdance.RegistrationResponse + 28, // 23: tapdance.C2SWrapper.registration_response:type_name -> tapdance.RegistrationResponse 7, // 24: tapdance.StationToDetector.operation:type_name -> tapdance.StationOperations 8, // 25: tapdance.StationToDetector.proto:type_name -> tapdance.IPProto 11, // 26: tapdance.RegistrationResponse.clientConf:type_name -> tapdance.ClientConf - 29, // 27: tapdance.RegistrationResponse.transport_params:type_name -> google.protobuf.Any - 27, // 28: tapdance.DnsResponse.bidirectional_response:type_name -> tapdance.RegistrationResponse + 30, // 27: tapdance.RegistrationResponse.transport_params:type_name -> google.protobuf.Any + 28, // 28: tapdance.DnsResponse.bidirectional_response:type_name -> tapdance.RegistrationResponse 29, // [29:29] is the sub-list for method output_type 29, // [29:29] is the sub-list for method input_type 29, // [29:29] is the sub-list for extension type_name @@ -2831,7 +2883,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StationToClient); i { + switch v := v.(*DTLSTransportParams); i { case 0: return &v.state case 1: @@ -2843,7 +2895,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegistrationFlags); i { + switch v := v.(*StationToClient); i { case 0: return &v.state case 1: @@ -2855,7 +2907,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClientToStation); i { + switch v := v.(*RegistrationFlags); i { case 0: return &v.state case 1: @@ -2867,7 +2919,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrefixTransportParams); i { + switch v := v.(*ClientToStation); i { case 0: return &v.state case 1: @@ -2879,7 +2931,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GenericTransportParams); i { + switch v := v.(*PrefixTransportParams); i { case 0: return &v.state case 1: @@ -2891,7 +2943,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*C2SWrapper); i { + switch v := v.(*GenericTransportParams); i { case 0: return &v.state case 1: @@ -2903,7 +2955,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SessionStats); i { + switch v := v.(*C2SWrapper); i { case 0: return &v.state case 1: @@ -2915,7 +2967,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StationToDetector); i { + switch v := v.(*SessionStats); i { case 0: return &v.state case 1: @@ -2927,7 +2979,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegistrationResponse); i { + switch v := v.(*StationToDetector); i { case 0: return &v.state case 1: @@ -2939,6 +2991,18 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegistrationResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signalling_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DnsResponse); i { case 0: return &v.state @@ -2957,7 +3021,7 @@ func file_signalling_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_signalling_proto_rawDesc, NumEnums: 9, - NumMessages: 20, + NumMessages: 21, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/signalling.proto b/proto/signalling.proto index fb2713ae..37ed8985 100644 --- a/proto/signalling.proto +++ b/proto/signalling.proto @@ -191,6 +191,10 @@ message WebRTCSignal { required WebRTCSDP sdp = 2; } +message DTLSTransportParams { + optional uint32 src_port = 1; +} + message StationToClient { // Should accompany (at least) SESSION_INIT and CONFIRM_RECONNECT. optional uint32 protocol_version = 1;