Coder Social home page Coder Social logo

go-onion-transport's Introduction

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. 
}

go-onion-transport's People

Contributors

cpacia avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.