oniontransport

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2020 License: MIT Imports: 17 Imported by: 1

README

go-onion-transport

This library contains a Tor transport implementation for libp2p (v0.8.3) that uses an embedded Tor client.

Usage

import (
	"context"
	"crypto/ed25519"
	"crypto/rand"
	"fmt"
	oniontransport "github.com/cpacia/go-onion-transport"
	"github.com/cretz/bine/tor"
	"github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
	"github.com/ipsn/go-libtor"
	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/peerstore"
	"github.com/libp2p/go-libp2p/config"
	"github.com/multiformats/go-multiaddr"
	madns "github.com/multiformats/go-multiaddr-dns"
	"path"
)

func main() {

	// First create the private key that will be used for the onion address.
	// You will need to persist this key between sessions if you want to use
	// the same onion address each time.
	_, privateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		log.Fatal(err)
	}

	// Define a directory for the tor client to use. Inside your application's
	// data directory will do fine.
	torDir := path.Join(dataDir, "tor")

	// Create the embedded Tor client.
	torClient, err := tor.Start(nil, &tor.StartConf{
		ProcessCreator: libtor.Creator,
		DataDir:         torDir,
		NoAutoSocksPort: true,
		EnableNetwork:   true,
		ExtraArgs:       []string{"--DNSPort", "2121"},
	})
	if err != nil {
		log.Fatal(err)
	}

	// Create the dialer.
	//
	// IMPORTANT: If you are genuinely trying to anonymize your IP you will need to route
	// any non-libp2p traffic through this dialer as well. For example, any HTTP requests
	// you make MUST go through this dialer.
	dialer, err := torClient.Dialer(context.Background(), nil)
	if err != nil {
		log.Fatal(err)
	}

	// Create the onion service.
	onionService, err := torClient.Listen(context.Background(), &tor.ListenConf{
		RemotePorts: []int{9003},
		Version3:    true,
		Key:         privateKey,
	})
	if err != nil {
		log.Fatal(err)
	}
	
	// Override the default lip2p DNS resolver. We need this because libp2p address may contain a 
	// DNS hostname that will be resolved before dialing. If we do not configure the resolver to 
	// use Tor we will blow any anonymity we gained by using Tor.
	// 
	// Note you must enter the DNS resolver address that was used when creating the Tor client.
	madns.DefaultResolver = oniontransport.NewTorResover("localhost:2121")

	// If this option is true then the transport will only attempt to dial out to onion
	// addresses. If libp2p requests to dial out on another type of address, TCP for example,
	// it will respond saying it can't dial that address.
	//
	// If your goal is to use this transport in conjunction with other non-Tor transports,
	// for example in a "dual stack" configuration, then you likely only want to route only
	// outgoing connections to onion addresses through this transport and let outgoing TCP
	// connections go through a faster transport. In this case this option should be true.
	// Note that such a configuration would NOT be anonymous.
	//
	// If this option is set to false then the this transport will attempt to dial out to
	// both onion addresses and TCP addresses.
	dialOnionOnly := false

	// Create the libp2p transport option.
	transportOpt := libp2p.Transport(oniontransport.NewOnionTransportC(dialer, onionService, dialOnionOnly))

	// Create address option.
	onionAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/onion3/%s:9003", onionService.ID))
	if err != nil {
		log.Fatal(err)
	}
	addressOpt := libp2p.ListenAddrs(onionAddr)

	// The transport option is passed in along with the FallbackDefaults options. FallbackDefaults
	// only applies the default options if no other option is provided. In this case we provided
	// the Tor transport so this configuration should ONLY use the Tor transport and no other transports.
	//
	// Using libp2p.Defaults instead of libp2p.FallbackDefaults would append the Tor transport to the
	// the existing list of transports.
	peerHost, err := libp2p.New(context.Background(), transportOpt, addressOpt, libp2p.FallbackDefaults)
	if err != nil {
		log.Fatal(err)
	}

	// Libp2p is now configured to use Tor.

	// If you want to configure IPFS to use Tor you will need to create a new hostOption.
	constructPeerHost := func(ctx context.Context, id peer.ID, ps peerstore.Peerstore, options ...libp2p.Option) (host.Host, error) {
		pkey := ps.PrivKey(id)
		if pkey == nil {
			return nil, fmt.Errorf("missing private key for node ID: %s", id.Pretty())
		}
		options = append([]libp2p.Option{libp2p.Identity(pkey), libp2p.Peerstore(ps)}, options...)

		cfg := &config.Config{}
		if err := cfg.Apply(options...); err != nil {
			return nil, err
		}

		cfg.Transports = nil
		if err := transportOpt(cfg); err != nil {
			return nil, err
		}
		return cfg.NewNode(ctx)
	}

	// You can set the swarm onion address in the config if you want. Or set it here.
	ipfsRepo, err := fsrepo.Open(ipfsDir)
	if err != nil {
		log.Fatal(err)
	}

	ipfsConfig, err := ipfsRepo.Config()
	if err != nil {
		log.Fatal(err)
	}

	ipfsConfig.Addresses.Swarm = []string{fmt.Sprintf("/onion3/%s:9003", onionService.ID)}

	// New IPFS build config
	ncfg := &core.BuildCfg{
		Repo: ipfsRepo,
		Host: constructPeerHost,
	}

	// Construct IPFS node.
	ipfsNode, err := core.NewNode(context.Background(), ncfg)
	if err != nil {
		log.Fatal(err)
	}

	// IPFS is now configured to use Tor.
	
	// WARNING: Passing a hostname into an IPNS Resolve will likely route the the DNS name resolution
	// in the clear and not through Tor. It should be a small change to IPFS to use the madns.DefaultResover
	// but we need to get it merged and released first. 
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewTorResover

func NewTorResover(proxy string) *madns.Resolver

NewTorResover returns a no madns.Resolver that will resolve IP addresses over Tor.

TODO: This does not seem to work for TXT records. Look into if Tor can resolve TXT records.

Types

type OnionConn

type OnionConn struct {
	net.Conn
	// contains filtered or unexported fields
}

OnionConn implement's go-libp2p-transport's Conn interface

func (*OnionConn) LocalMultiaddr

func (c *OnionConn) LocalMultiaddr() ma.Multiaddr

LocalMultiaddr returns the local multiaddr for this connection

func (*OnionConn) RemoteMultiaddr

func (c *OnionConn) RemoteMultiaddr() ma.Multiaddr

RemoteMultiaddr returns the remote multiaddr for this connection

func (*OnionConn) Transport

func (c *OnionConn) Transport() tpt.Transport

Transport returns the OnionTransport associated with this OnionConn

type OnionListener

type OnionListener struct {
	Upgrader *tptu.Upgrader
	// contains filtered or unexported fields
}

OnionListener implements go-libp2p-transport's Listener interface

func (*OnionListener) Accept

func (l *OnionListener) Accept() (tpt.CapableConn, error)

Accept blocks until a connection is received returning go-libp2p-transport's Conn interface or an error if something went wrong

func (*OnionListener) Addr

func (l *OnionListener) Addr() net.Addr

Addr returns the net.Addr interface which represents the local multiaddr we are listening on

func (*OnionListener) Close

func (l *OnionListener) Close() error

Close shuts down the listener

func (*OnionListener) Multiaddr

func (l *OnionListener) Multiaddr() ma.Multiaddr

Multiaddr returns the local multiaddr we are listening on

type OnionTransport

type OnionTransport struct {

	// Connection upgrader for upgrading insecure stream connections to
	// secure multiplex connections.
	Upgrader *tptu.Upgrader
	// contains filtered or unexported fields
}

OnionTransport implements go-libp2p-transport's Transport interface

func NewOnionTransport

func NewOnionTransport(dialer proxy.Dialer, service *tor.OnionService, dialOnionOnly bool, upgrader *tptu.Upgrader) (*OnionTransport, error)

NewOnionTransport creates a new OnionTransport

func (*OnionTransport) CanDial

func (t *OnionTransport) CanDial(a ma.Multiaddr) bool

CanDial returns true if this transport knows how to dial the given multiaddr.

Returning true does not guarantee that dialing this multiaddr will succeed. This function should *only* be used to preemptively filter out addresses that we can't dial.

func (*OnionTransport) Dial

func (t *OnionTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.CapableConn, error)

Dial dials a remote peer. It should try to reuse local listener addresses if possible but it may choose not to.

func (*OnionTransport) Listen

func (t *OnionTransport) Listen(laddr ma.Multiaddr) (tpt.Listener, error)

Listen listens on the passed multiaddr.

func (*OnionTransport) Protocols

func (t *OnionTransport) Protocols() []int

Protocols returns the list of terminal protocols this transport can dial.

func (*OnionTransport) Proxy

func (t *OnionTransport) Proxy() bool

Proxy always returns false for the onion transport.

type OnionTransportC

type OnionTransportC func(*tptu.Upgrader) (tpt.Transport, error)

OnionTransportC is a type alias for OnionTransport constructors, for use with libp2p.New

func NewOnionTransportC

func NewOnionTransportC(dialer proxy.Dialer, service *tor.OnionService, dialOnionOnly bool) OnionTransportC

NewOnionTransportC is a convenience function that returns a function suitable for passing into libp2p.Transport for host configuration

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL