Merge pull request 'Introduce new GetInfo API for fetching information about ACN' (#26) from getinfo into master
Reviewed-on: #26
This commit is contained in:
commit
04dec3238b
2
acn.go
2
acn.go
|
@ -57,5 +57,7 @@ type ACN interface {
|
|||
|
||||
Callback() func(int, string)
|
||||
|
||||
GetInfo(onion string) (map[string]string, error)
|
||||
|
||||
Close()
|
||||
}
|
||||
|
|
18
error_acn.go
18
error_acn.go
|
@ -6,6 +6,8 @@ import (
|
|||
"net"
|
||||
)
|
||||
|
||||
const acnError = "error initializing anonymous communication network"
|
||||
|
||||
// ErrorACN - a status-callback safe errored ACN. Use this when ACN construction goes wrong
|
||||
// and you need a safe substitute that can later be replaced with a working ACN without impacting calling clients.
|
||||
type ErrorACN struct {
|
||||
|
@ -16,12 +18,16 @@ func (e ErrorACN) Callback() func(int, string) {
|
|||
return e.statusCallbackCache
|
||||
}
|
||||
|
||||
func (e *ErrorACN) GetInfo(addr string) (map[string]string, error) {
|
||||
return nil, errors.New(acnError)
|
||||
}
|
||||
|
||||
func (e ErrorACN) GetBootstrapStatus() (int, string) {
|
||||
return -1, "error initializing tor"
|
||||
return -1, acnError
|
||||
}
|
||||
|
||||
func (e ErrorACN) WaitTillBootstrapped() error {
|
||||
return errors.New("error initializing tor")
|
||||
return errors.New(acnError)
|
||||
}
|
||||
|
||||
func (e *ErrorACN) SetStatusCallback(callback func(int, string)) {
|
||||
|
@ -32,19 +38,19 @@ func (e ErrorACN) Restart() {
|
|||
}
|
||||
|
||||
func (e ErrorACN) Open(hostname string) (net.Conn, string, error) {
|
||||
return nil, "", fmt.Errorf("error initializing tor")
|
||||
return nil, "", fmt.Errorf(acnError)
|
||||
}
|
||||
|
||||
func (e ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) {
|
||||
return nil, fmt.Errorf("error initializing tor")
|
||||
return nil, fmt.Errorf(acnError)
|
||||
}
|
||||
|
||||
func (e ErrorACN) GetPID() (int, error) {
|
||||
return -1, fmt.Errorf("error initializing tor")
|
||||
return -1, fmt.Errorf(acnError)
|
||||
}
|
||||
|
||||
func (e ErrorACN) GetVersion() string {
|
||||
return "Error Initializing Tor"
|
||||
return acnError
|
||||
}
|
||||
|
||||
func (e ErrorACN) Close() {
|
||||
|
|
|
@ -38,6 +38,10 @@ func (ls *localListenService) Close() {
|
|||
ls.l.Close()
|
||||
}
|
||||
|
||||
func (lp *localProvider) GetInfo(addr string) (map[string]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
|
||||
func (lp *localProvider) GetBootstrapStatus() (int, string) {
|
||||
return 100, "Done"
|
||||
|
|
|
@ -33,6 +33,10 @@ func (p *ProxyACN) ReplaceACN(acn ACN) {
|
|||
p.acn = acn
|
||||
}
|
||||
|
||||
func (p *ProxyACN) GetInfo(addr string) (map[string]string, error) {
|
||||
return p.acn.GetInfo(addr)
|
||||
}
|
||||
|
||||
func (p *ProxyACN) GetBootstrapStatus() (int, string) {
|
||||
return p.acn.GetBootstrapStatus()
|
||||
}
|
||||
|
|
|
@ -91,6 +91,77 @@ func (ols *onionListenService) Close() {
|
|||
ols.os.Close()
|
||||
}
|
||||
|
||||
func (tp *torProvider) GetInfo(onion string) (map[string]string, error) {
|
||||
tp.lock.Lock()
|
||||
defer tp.lock.Unlock()
|
||||
circuits, streams, err := getCircuitInfo(tp.t.Control)
|
||||
if err == nil {
|
||||
|
||||
var circuitID string
|
||||
for _, stream := range streams {
|
||||
if stream.Key == "stream-status" {
|
||||
lines := strings.Split(stream.Val, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Split(line, " ")
|
||||
// StreamID SP StreamStatus SP CircuitID SP Target CRLF
|
||||
if len(parts) == 4 {
|
||||
if strings.HasPrefix(parts[3], onion) {
|
||||
circuitID = parts[2]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if circuitID == "" {
|
||||
return nil, errors.New("could not find circuit")
|
||||
}
|
||||
|
||||
var hops []string
|
||||
for _, circuit := range circuits {
|
||||
if circuit.Key == "circuit-status" {
|
||||
lines := strings.Split(circuit.Val, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Split(line, " ")
|
||||
// CIRCID SP STATUS SP PATH...
|
||||
|
||||
if len(parts) >= 3 && circuitID == parts[0] {
|
||||
//log.Debugf("Found Circuit for Onion %v %v", onion, parts)
|
||||
if parts[1] == "BUILT" {
|
||||
circuitPath := strings.Split(parts[2], ",")
|
||||
for _, hop := range circuitPath {
|
||||
fingerprint := hop[1:41]
|
||||
keyvals, err := tp.t.Control.GetInfo(fmt.Sprintf("ns/id/%s", fingerprint))
|
||||
if err == nil && len(keyvals) == 1 {
|
||||
lines = strings.Split(keyvals[0].Val, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "r") {
|
||||
parts := strings.Split(line, " ")
|
||||
if len(parts) > 6 {
|
||||
keyvals, err := tp.t.Control.GetInfo(fmt.Sprintf("ip-to-country/%s", parts[6]))
|
||||
if err == nil && len(keyvals) >= 1 {
|
||||
hops = append(hops, fmt.Sprintf("%s:%s", strings.ToUpper(keyvals[0].Val), parts[6]))
|
||||
} else {
|
||||
hops = append(hops, fmt.Sprintf("%s:%s", "XX", parts[6]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]string{"circuit": strings.Join(hops, ",")}, nil
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
|
||||
// returns -1 on network disconnected
|
||||
// returns -2 on error
|
||||
|
@ -479,6 +550,15 @@ func (tp *torProvider) monitorRestart() {
|
|||
}
|
||||
}
|
||||
|
||||
func getCircuitInfo(controlport *control.Conn) ([]*control.KeyVal, []*control.KeyVal, error) {
|
||||
circuits, cerr := controlport.GetInfo("circuit-status")
|
||||
streams, serr := controlport.GetInfo("stream-status")
|
||||
if cerr == nil && serr == nil {
|
||||
return circuits, streams, nil
|
||||
}
|
||||
return nil, nil, errors.New("could not fetch circuits or streams")
|
||||
}
|
||||
|
||||
func createFromExisting(controlport *control.Conn, datadir string) *tor.Tor {
|
||||
t := &tor.Tor{
|
||||
Process: nil,
|
||||
|
|
|
@ -43,6 +43,28 @@ func TestTorProvider(t *testing.T) {
|
|||
t.Logf("progress: %v", progress)
|
||||
}
|
||||
|
||||
// Test opening the OP Server
|
||||
_, _, err = acn.Open("isbr2t6bflul2zyi6hjtnuezb2xvfr42svzjg2q3gyqfgg3wmnrbkkqd")
|
||||
|
||||
if err == nil {
|
||||
info, err := acn.GetInfo("isbr2t6bflul2zyi6hjtnuezb2xvfr42svzjg2q3gyqfgg3wmnrbkkqd")
|
||||
if err != nil {
|
||||
t.Fatalf("could not find info for OP server %v", err)
|
||||
}
|
||||
cinfo, exists := info["circuit"]
|
||||
if !exists || len(cinfo) == 0 {
|
||||
t.Fatalf("could not find circuit info for OP server %v", err)
|
||||
}
|
||||
|
||||
_, err = acn.GetInfo("not_a_real_onion")
|
||||
if err == nil {
|
||||
t.Fatalf("GetInfo for non existant onion should have errored")
|
||||
}
|
||||
|
||||
} else {
|
||||
t.Fatalf("could not connect to OP server %v", err)
|
||||
}
|
||||
|
||||
// Should skip without blocking...
|
||||
acn.Restart()
|
||||
acn.Restart()
|
||||
|
|
Loading…
Reference in New Issue