check current onion descriptors on old versions of tor to see if they're out-of-sync
This commit is contained in:
parent
9c1c5ef98a
commit
6258396dc7
91
cmd_onion.go
91
cmd_onion.go
|
@ -14,7 +14,11 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"errors"
|
||||
"github.com/yawning/bulb/utils/pkcs1"
|
||||
"golang.org/x/net/proxy"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// OnionInfo is the result of the AddOnion command.
|
||||
|
@ -39,6 +43,7 @@ type OnionPortSpec struct {
|
|||
|
||||
// NewOnionConfig is a configuration for NewOnion command.
|
||||
type NewOnionConfig struct {
|
||||
Onion string
|
||||
PortSpecs []OnionPortSpec
|
||||
PrivateKey crypto.PrivateKey
|
||||
DiscardPK bool
|
||||
|
@ -49,7 +54,7 @@ type NewOnionConfig struct {
|
|||
|
||||
// NewOnion issues an ADD_ONION command using configuration config and
|
||||
// returns the parsed response.
|
||||
func (c *Conn) NewOnion(config *NewOnionConfig) (*OnionInfo, error) {
|
||||
func (c *Conn) NewOnion(config *NewOnionConfig, dontCheckDescriptor bool) (*OnionInfo, error) {
|
||||
const keyTypeRSA = "RSA1024"
|
||||
var err error
|
||||
|
||||
|
@ -109,9 +114,41 @@ func (c *Conn) NewOnion(config *NewOnionConfig) (*OnionInfo, error) {
|
|||
flagsStr = " Flags="
|
||||
flagsStr += strings.Join(flags, ",")
|
||||
}
|
||||
|
||||
request := fmt.Sprintf("ADD_ONION %s:%s%s%s", hsKeyType, hsKeyStr, portStr, flagsStr)
|
||||
resp, err := c.Request(request)
|
||||
if err != nil && fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision" {
|
||||
if err == nil && !dontCheckDescriptor {
|
||||
pi, _ := c.ProtocolInfo()
|
||||
// 0.3.5.1
|
||||
torversion := strings.Split(pi.TorVersion, ".")
|
||||
tva, _ := strconv.Atoi(torversion[0])
|
||||
tvb, _ := strconv.Atoi(torversion[1])
|
||||
tvc, _ := strconv.Atoi(torversion[2])
|
||||
if tva == 0 && (tvb < 3 || (tvb == 3 && tvc < 5)) {
|
||||
// here we need to check if the descriptor upload succeeded
|
||||
log.Println("running a descriptor check because you are on tor version < 0.3.5.1-alpha. this will take a little while but only happens once per tor process--onion service pair")
|
||||
HSFetch(config.Onion)
|
||||
crc, err := c.GetClientRevisionCounter(config.Onion)
|
||||
if err != nil {
|
||||
log.Printf("%v\n", err)
|
||||
}
|
||||
src, err := c.GetServiceRevisionCounter(config.Onion)
|
||||
if err != nil {
|
||||
log.Printf("%v\n", err)
|
||||
}
|
||||
if crc > src {
|
||||
log.Printf("uh oh: your tor process is using a service descriptor revision counter of %d\n", src)
|
||||
log.Printf("whereas the HSDirs have revision %d. this is a bug in tor < 0.3.5.1-alpha\n", crc)
|
||||
log.Printf("your have two options to fix it:\n")
|
||||
log.Printf("- upgrade to tor >= 0.3.5.1-alpha [recommended]\n")
|
||||
log.Printf("- run this listener %d more times [not a great idea but it'll work]\n", crc-src)
|
||||
log.Printf("the revision counter is only reset when the tor process restarts, so try not to do that in order to prevent this problem from reoccurring\n")
|
||||
return nil, errors.New("client descriptor is newer than service descriptor")
|
||||
}
|
||||
fmt.Printf("crc: %v src: %v\n", crc, src)
|
||||
}
|
||||
} else if fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision" {
|
||||
// (don't worry if there is an address collision -- it's a good thing and means we're using the cached circuits)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -171,7 +208,7 @@ func (c *Conn) AddOnion(ports []OnionPortSpec, key crypto.PrivateKey, oneshot bo
|
|||
cfg.PrivateKey = key
|
||||
}
|
||||
cfg.DiscardPK = oneshot
|
||||
return c.NewOnion(cfg)
|
||||
return c.NewOnion(cfg, false)
|
||||
}
|
||||
|
||||
// DeleteOnion issues a DEL_ONION command and returns the parsed response.
|
||||
|
@ -179,3 +216,51 @@ func (c *Conn) DeleteOnion(serviceID string) error {
|
|||
_, err := c.Request("DEL_ONION %s", serviceID)
|
||||
return err
|
||||
}
|
||||
|
||||
// run HSFETCH for an onion, in order to put its onion service descriptor into the client cache
|
||||
// unfortunately we don't actually do this, because HSFETCH doesn't support v3 yet
|
||||
// instead we make a shortlived connection to it, which has a side effect of putting the descriptor into cache
|
||||
// see https://trac.torproject.org/projects/tor/ticket/25417 for details
|
||||
func HSFetch(onion string) error {
|
||||
torDialer, err := proxy.SOCKS5("tcp", "127.0.0.1:9050", nil, proxy.Direct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn, err := torDialer.Dial("tcp", onion+".onion:9878")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) GetClientRevisionCounter(onion string) (uint64, error) {
|
||||
return c.getRevisionCounterHelper(onion, "client")
|
||||
}
|
||||
|
||||
func (c *Conn) GetServiceRevisionCounter(onion string) (uint64, error) {
|
||||
return c.getRevisionCounterHelper(onion, "service")
|
||||
}
|
||||
|
||||
func (c *Conn) getRevisionCounterHelper(onion string, cachetype string) (uint64, error) {
|
||||
_, err := c.conn.Cmd("GETINFO hs/%v/desc/id/%v", cachetype, onion)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var rc uint64
|
||||
reterr := errors.New("could not find revision counter in onion descriptor")
|
||||
for {
|
||||
line, err := c.conn.ReadLine()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if strings.HasPrefix(line, "250 OK") {
|
||||
return rc, reterr
|
||||
} else if strings.HasPrefix(line, "revision-counter ") {
|
||||
rc, reterr = strconv.ParseUint(line[17:], 10, 64)
|
||||
}
|
||||
}
|
||||
|
||||
return rc, reterr
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ func (c *Conn) RecoverListener(config *NewOnionConfig, onion string, vports ...u
|
|||
}
|
||||
cfg.PortSpecs = portSpecs
|
||||
// Create the onion.
|
||||
oi, err := c.NewOnion(&cfg)
|
||||
oi, err := c.NewOnion(&cfg, false)
|
||||
if err != nil {
|
||||
tcpListener.Close()
|
||||
return nil, err
|
||||
|
|
Reference in New Issue