Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Jorropo <[email protected]>
  • Loading branch information
Jorropo committed Dec 17, 2020
1 parent fd47f7e commit 49e3152
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 74 deletions.
25 changes: 17 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
# go-libp2p-tor-transport
Go tor transport is a [go-libp2p](https://github.com/libp2p/go-libp2p) transport targeting mainly \*nix platform.

## WIP
This transport is in very early stages (PoC) many of features enumerated here are just targets.

You can follow the process of the **1.0** [here](https://github.com/berty/go-libp2p-tor-transport/projects/1).

## Usage :
```go
package main
import (
"context"

tor "berty.tech/go-libp2p-tor-transport"
dns "berty.tech/go-libp2p-tor-transport/dns-helpers"
config "berty.tech/go-libp2p-tor-transport/config"
libp2p "github.com/libp2p/go-libp2p"
)

func main() {
builder, err := tor.NewBuilder( // Create a builder
config.EnableEmbeded, // Use the embeded tor instance.
config.EnableEmbeded(), // Use the embeded tor instance.
)
c(err)
host, err := libp2p.New( // Create a libp2p node
context.Background(),
libp2p.Transport(builder), // Use the builder to create a transport instance (you can't reuse the same builder after that).
libp2p.Transport(builder.GetTransportConstructor()), // Use the builder to create a transport instance (you can't reuse the same builder after that).
)
c(err)
}
Expand All @@ -37,26 +36,36 @@ func c(err error) { // Used to check error in this example, replace by whatever

### With config :
```go
package main
import (
"context"
"time"

tor "berty.tech/go-libp2p-tor-transport"
config "berty.tech/go-libp2p-tor-transport/config"
libp2p "github.com/libp2p/go-libp2p"
madns "github.com/multiformats/go-multiaddr-dns"
)

func main() {
builder, err := tor.NewBuilder( // NewBuilder can accept some `config.Configurator`
config.AllowTcpDial, // Some Configurator are already ready to use.
config.AllowTcpDial(), // Some Configurator are already ready to use.
config.SetSetupTimeout(time.Minute), // Some require a parameter, in this case it's a function that will return a Configurator.
config.SetBinaryPath("/usr/bin/tor"),
)
// Evrything else is as previously shown.
c(err)
// Sets the default madns resolver, if you don't do that dns requests will be done clearly over internet.
r, err := dns.CreateDoTMaDNSResolverFromDialContext(
builder.GetDialer().DialContext, // Dialer
"cloudflare-dns.com", // Hostname
"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001", // Addresses
)
c(err)
madns.DefaultResolver = r
// Everything else is as previously shown.
hostWithConfig, err := libp2p.New(
context.Background(),
libp2p.Transport(builder),
libp2p.Transport(builder.GetTransportConstructor()),
)
c(err)
}
Expand Down
69 changes: 69 additions & 0 deletions builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package tor

import (
"context"
"net"
"time"

"github.com/cretz/bine/tor"

"github.com/joomcode/errorx"
"golang.org/x/net/proxy"

"berty.tech/go-libp2p-tor-transport/config"
"berty.tech/go-libp2p-tor-transport/internal/confStore"
)

// Builder is the type holding the starter node, it's used to fetch different ressources.
type Builder struct {
allowTcpDial bool
setupTimeout time.Duration
bridge *tor.Tor
dialer ContextDialer
}

// ContextDialer is a dialler that also support contexted dials.
type ContextDialer interface {
proxy.Dialer
DialContext(ctx context.Context, network string, addr string) (net.Conn, error)
}

func NewBuilder(cs ...config.Configurator) (*Builder, error) {
var conf confStore.Config
{
// Applying configuration
conf = confStore.Config{
SetupTimeout: 5 * time.Minute,
RunningContext: context.Background(),
TorStart: &tor.StartConf{
EnableNetwork: true, // Do Fast Start
},
}
if err := config.Merge(cs...)(&conf); err != nil {
return nil, errorx.Decorate(err, "Can't apply configuration to the tor node")
}
}
t, err := tor.Start(conf.RunningContext, conf.TorStart)
if err != nil {
return nil, errorx.Decorate(err, "Can't start tor node")
}

// Up until this point, we don't need the starting configuration anymore.
conf.TorStart = nil

dialer, err := t.Dialer(conf.RunningContext, nil)
if err != nil {
return nil, errorx.Decorate(err, "Can't create a dialer.")
}
return &Builder{
allowTcpDial: conf.AllowTcpDial,
setupTimeout: conf.SetupTimeout,
bridge: t,
dialer: dialer,
}, nil
}

// GetDialer returns a shared dialer, it is closed once the transport closes.
func (b *Builder) GetDialer() ContextDialer {
return b.dialer
}
38 changes: 21 additions & 17 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"context"
"io"
"time"

Expand All @@ -10,13 +11,6 @@ import (
"berty.tech/go-libp2p-tor-transport/internal/confStore"
)

// Check that all configurator are correctly done :
var _ = []Configurator{
AllowTcpDial,
DoSlowStart,
EnableEmbeded,
}

type Configurator func(*confStore.Config) error

// ConfMerge Merges different configs, starting at the first ending at the last.
Expand All @@ -33,16 +27,20 @@ func Merge(cs ...Configurator) Configurator {

// AllowTcpDial allows the tor transport to dial tcp address.
// By Default TcpDial is off.
func AllowTcpDial(c *confStore.Config) error {
c.AllowTcpDial = true
return nil
func AllowTcpDial() Configurator {
return func(c *confStore.Config) error {
c.AllowTcpDial = true
return nil
}
}

// DoSlowStart set the tor node to bootstrap only when a Dial or a Listen is issued.
// By Default DoSlowStart is off.
func DoSlowStart(c *confStore.Config) error {
c.TorStart.EnableNetwork = false
return nil
func DoSlowStart() Configurator {
return func(c *confStore.Config) error {
c.TorStart.EnableNetwork = false
return nil
}
}

// SetSetupTimeout change the timeout for the bootstrap of the node and the publication of the tunnel.
Expand Down Expand Up @@ -79,13 +77,11 @@ func SetBinaryPath(path string) Configurator {

// SetTemporaryDirectory sets the temporary directory where Tor is gonna put his
// data dir.
// If you want an easy way to find it you can use:
// https://github.com/Jorropo/go-temp-dir
func SetTemporaryDirectory(path string) Configurator {
rpath, err := realpath.Realpath(path)
return func(c *confStore.Config) error {
if err != nil {
errorx.Decorate(err, "Can't resolve path")
return errorx.Decorate(err, "Can't resolve path")
}
c.TorStart.TempDataDirBase = rpath
return nil
Expand All @@ -97,9 +93,17 @@ func SetTorrcPath(path string) Configurator {
rpath, err := realpath.Realpath(path)
return func(c *confStore.Config) error {
if err != nil {
errorx.Decorate(err, "Can't resolve path")
return errorx.Decorate(err, "Can't resolve path")
}
c.TorStart.TorrcFile = rpath
return nil
}
}

// SetRunningContext sets the context used for the running of the node.
func SetRunningContext(ctx context.Context) Configurator {
return func(c *confStore.Config) error {
c.RunningContext = ctx
return nil
}
}
6 changes: 4 additions & 2 deletions config/embeded_disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
// EnableEmbeded setups the node to use a builtin tor node.
// Note: you will need to build with `-tags=embedTor` for this to works.
// Not available on all systems.
func EnableEmbeded(c *confStore.Config) error {
return fmt.Errorf("You havn't enabled the embeded tor instance at compilation. You can enable it with `-tags=embedTor` while building.")
func EnableEmbeded() Configurator {
return func(c *confStore.Config) error {
return fmt.Errorf("You havn't enabled the embeded tor instance at compilation. You can enable it with `-tags=embedTor` while building.")
}
}
14 changes: 8 additions & 6 deletions config/embeded_enabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import (
// EnableEmbeded setups the node to use a builtin tor node.
// Note: you will need to build with `-tags=embedTor` for this to works.
// Not available on all systems.
func EnableEmbeded(c *confStore.Config) error {
if libtor.Available {
c.TorStart.ProcessCreator = libtor.Creator
c.TorStart.UseEmbeddedControlConn = true
return nil
func EnableEmbeded() Configurator {
return func(c *confStore.Config) error {
if libtor.Available {
c.TorStart.ProcessCreator = libtor.Creator
c.TorStart.UseEmbeddedControlConn = true
return nil
}
return fmt.Errorf("The embeded Tor node isn't available. Check your arch and CGO.")
}
return fmt.Errorf("The embeded Tor node isn't available. Check your arch and CGO.")
}
5 changes: 2 additions & 3 deletions conn.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tor

import (
"io"
"net"
"time"

Expand Down Expand Up @@ -99,9 +100,7 @@ func (c *dialConnTcp) LocalMultiaddr() ma.Multiaddr {

// netConnWithoutAddr is a net.Conn like but without LocalAddr and RemoteAddr.
type netConnWithoutAddr interface {
Read(b []byte) (n int, err error)
Write(b []byte) (n int, err error)
Close() error
io.ReadWriteCloser
SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
Expand Down
46 changes: 46 additions & 0 deletions dns-helpers/dot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dns

import (
"crypto/tls"
"crypto/x509"
"net"
"time"

"github.com/joomcode/errorx"
madns "github.com/multiformats/go-multiaddr-dns"
"github.com/ncruces/go-dns"
)

func CreatDoTDNSResolverFromDialContext(dialFunc dns.DialFunc, hostname string, addresses ...string) (*net.Resolver, error) {
certPool, err := x509.SystemCertPool()
if err != nil {
return nil, errorx.Decorate(err, "can't fetch system cert pool")
}
resolver, err := dns.NewDoTResolver(
hostname,
dns.DoTAddresses(addresses...),
dns.DoTCache(
dns.MaxCacheEntries(256),
dns.MaxCacheTTL(time.Hour*24),
dns.MinCacheTTL(time.Minute),
),
dns.DoTConfig(&tls.Config{
RootCAs: certPool,
}),
dns.DoTDialFunc(dialFunc),
)
if err != nil {
return nil, errorx.Decorate(err, "can't create DoT resolver")
}
return resolver, nil
}

func CreateDoTMaDNSResolverFromDialContext(dialFunc dns.DialFunc, hostname string, addresses ...string) (*madns.Resolver, error) {
netResolver, err := CreatDoTDNSResolverFromDialContext(dialFunc, hostname, addresses...)
if err != nil {
return nil, err
}
return &madns.Resolver{
Backend: netResolver,
}, nil
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ require (
github.com/libp2p/go-libp2p-core v0.6.1
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0
github.com/multiformats/go-multiaddr v0.3.1
github.com/multiformats/go-multiaddr-dns v0.2.1-0.20201130213411-dba25a2c0b7a
github.com/multiformats/go-multiaddr-fmt v0.1.0
github.com/ncruces/go-dns v1.0.0
github.com/yookoala/realpath v1.0.0
golang.org/x/net v0.0.0-20200822124328-c89045814202
golang.org/x/tools v0.0.0-20200904185747-39188db58858 // indirect
)

replace github.com/ncruces/go-dns => github.com/berty/go-dns v1.0.1 // temporary, see https://github.com/ncruces/go-dns/pull/8/
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/berty/go-dns v1.0.1 h1:5fyswL5QqJ/78hLUc5Go6e0VA0u7Bww/vyoddZpQyM4=
github.com/berty/go-dns v1.0.1/go.mod h1:su21ON0Nu6vkydXbOgso3ZN05o2jguVv+utey3mKP8A=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
Expand Down Expand Up @@ -132,6 +134,8 @@ github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=
github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I=
github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=
github.com/multiformats/go-multiaddr-dns v0.2.1-0.20201130213411-dba25a2c0b7a h1:Pw459lu1YP0+F78E5fiX+g/DWEyTo+EaTmgrPwU/vW8=
github.com/multiformats/go-multiaddr-dns v0.2.1-0.20201130213411-dba25a2c0b7a/go.mod h1:mNzQ4eTGDg0ll1N9jKPOUogZPoJ30W8a7zk66FQPpdQ=
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multiaddr-net v0.1.5 h1:QoRKvu0xHN1FCFJcMQLbG/yQE2z441L5urvG3+qyz7g=
Expand Down
6 changes: 4 additions & 2 deletions internal/confStore/config.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package confStore

import (
"context"
"time"

"github.com/cretz/bine/tor"
)

// `Config` stores the config, don't use it, you must use Configurator.
type Config struct {
AllowTcpDial bool
SetupTimeout time.Duration
AllowTcpDial bool
SetupTimeout time.Duration
RunningContext context.Context

TorStart *tor.StartConf
}
Loading

0 comments on commit 49e3152

Please sign in to comment.