summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--consensus.go63
-rw-r--r--consensus_test.go58
2 files changed, 109 insertions, 12 deletions
diff --git a/consensus.go b/consensus.go
index 863ee61..f7b9f0a 100644
--- a/consensus.go
+++ b/consensus.go
@@ -11,6 +11,7 @@ import (
"io"
"net"
"os"
+ "regexp"
"strconv"
"strings"
"time"
@@ -38,6 +39,15 @@ type RouterFlags struct {
V2Dir bool
}
+type RouterAddress struct {
+ IPv4Address net.IP
+ IPv4ORPort uint16
+ IPv4DirPort uint16
+
+ IPv6Address net.IP
+ IPv6ORPort uint16
+}
+
type RouterStatus struct {
// The single fields of an "r" line.
@@ -45,9 +55,9 @@ type RouterStatus struct {
Fingerprint Fingerprint
Digest string
Publication time.Time
- Address net.IP
- ORPort uint16
- DirPort uint16
+
+ // The IPv4 and IPv6 fields of "a" line
+ Address RouterAddress
// The single fields of an "s" line.
Flags RouterFlags
@@ -87,12 +97,10 @@ type Consensus struct {
// the status' string representation.
func (s *RouterStatus) String() string {
- return fmt.Sprintf("%s,%s,%s,%d,%d,%s,%s,%s",
+ return fmt.Sprintf("%s,%s,%+v,%s,%s,%s",
s.Fingerprint,
s.Nickname,
s.Address,
- s.ORPort,
- s.DirPort,
s.Flags,
s.Publication.Format(time.RFC3339),
strings.Replace(s.TorVersion, ",", "", -1))
@@ -233,6 +241,29 @@ func (a *Consensus) Intersect(b *Consensus) *Consensus {
}
// Implement the Stringer interface for pretty printing.
+func (address RouterAddress) String() string {
+ var ipV4stringAddress []string
+ var ipV6stringAddress []string
+
+ if address.IPv4Address != nil {
+ ipV4stringAddress = append(ipV4stringAddress, address.IPv4Address.String())
+ }
+ ipV4stringAddress = append(ipV4stringAddress, fmt.Sprintf("%v", address.IPv4ORPort))
+ ipV4stringAddress = append(ipV4stringAddress, fmt.Sprintf("%v", address.IPv4DirPort))
+ ipV4Join := fmt.Sprintf(strings.Join(ipV4stringAddress, "|"))
+
+ if address.IPv6Address == nil {
+ return ipV4Join
+ }
+
+ ipV6stringAddress = append(ipV6stringAddress, address.IPv6Address.String())
+ ipV6stringAddress = append(ipV6stringAddress, fmt.Sprintf("%v", address.IPv6ORPort))
+
+ ipV6Join := fmt.Sprintf(strings.Join(ipV6stringAddress, "|"))
+ return ipV4Join + "," + ipV6Join
+}
+
+// Implement the Stringer interface for pretty printing.
func (flags RouterFlags) String() string {
var stringFlags []string
@@ -313,6 +344,15 @@ func parseRouterFlags(flags []string) *RouterFlags {
return routerFlags
}
+func parseIPv6AddressAndPort(addressAndPort string) (address net.IP, port uint16) {
+ var ipV6regex = regexp.MustCompile(`\[(.*?)\]`)
+ var ipV6portRegex = regexp.MustCompile(`\]:(.*)`)
+ address = net.ParseIP(ipV6regex.FindStringSubmatch(addressAndPort)[1])
+ port = StringToPort(ipV6portRegex.FindStringSubmatch(addressAndPort)[1])
+
+ return address, port
+}
+
// LazyParseRawStatus parses a raw router status (in string format) and returns
// the router's fingerprint, a function which returns a RouterStatus, and an
// error if there were any during parsing. Parsing of the given string is
@@ -371,9 +411,12 @@ func ParseRawStatus(rawStatus string) (Fingerprint, GetStatus, error) {
time, _ := time.Parse(publishedTimeLayout, strings.Join(words[4:6], " "))
status.Publication = time
- status.Address = net.ParseIP(words[6])
- status.ORPort = StringToPort(words[7])
- status.DirPort = StringToPort(words[8])
+ status.Address.IPv4Address = net.ParseIP(words[6])
+ status.Address.IPv4ORPort = StringToPort(words[7])
+ status.Address.IPv4DirPort = StringToPort(words[8])
+
+ case "a":
+ status.Address.IPv6Address, status.Address.IPv6ORPort = parseIPv6AddressAndPort(words[1])
case "s":
status.Flags = *parseRouterFlags(words[1:])
@@ -527,7 +570,7 @@ func extractMetaInfo(r io.Reader, c *Consensus) error {
// object filter.
func (filter *ObjectFilter) MatchesRouterStatus(status *RouterStatus) bool {
- if filter.HasIPAddr(status.Address) {
+ if filter.HasIPAddr(status.Address.IPv4Address) || (filter.HasIPAddr(status.Address.IPv6Address)) {
return true
}
diff --git a/consensus_test.go b/consensus_test.go
index efe356d..fdedc2a 100644
--- a/consensus_test.go
+++ b/consensus_test.go
@@ -102,7 +102,7 @@ func TestConsensusOperations(t *testing.T) {
t.Error("Could not retrieve fingerprint which should be available.")
}
- if status.ORPort != 0 {
+ if status.Address.IPv4ORPort != 0 {
t.Error("Field ORPort should be 0.")
}
@@ -123,6 +123,7 @@ func TestStatusParsing(t *testing.T) {
func TestConsensusSetOperations(t *testing.T) {
fingerprint0, getStatus0, err := ParseRawStatus(`r Karlstad0 m5TNC3uAV+ryG6fwI7ehyMqc5kU f1g9KQhgS0r6+H/7dzAJOpi6lG8 2014-12-08 06:57:54 193.11.166.194 9000 80
+a [2002:470:6e:80d::2]:22
s Fast Guard HSDir Running Stable V2Dir Valid
v Tor 0.2.4.23
w Bandwidth=2670
@@ -132,6 +133,7 @@ p reject 1-65535`)
}
fingerprint1, getStatus1, err := ParseRawStatus(`r Karlstad1 zO8CqkVMCrD+GsaDBPbYxCIMGRI pR21zIq4gZQmZOj2FvRwNO5U+K0 2014-12-08 06:57:49 193.11.166.194 9001 0
+a [2a02:2430:3:2500::5fa3:1ef5]:9001
s Fast Guard Running Stable Valid
v Tor 0.2.4.23
w Bandwidth=2290
@@ -141,6 +143,7 @@ p reject 1-65535`)
}
fingerprint2, getStatus2, err := ParseRawStatus(`r Karlstad2 e9hMtjhF4NYcHPqDkUobjJaEgrE eu8/9NajsgwD6+/vlObfyk2bZjo 2014-12-08 12:24:43 81.170.149.212 9001 0
+a [2a02:418:1007:b::48]:443
s Fast Running Stable Valid
v Tor 0.2.3.25
w Bandwidth=778
@@ -153,7 +156,7 @@ p reject 1-65535`)
t.Error("Unexpected fingerprint for router status.")
}
- if getStatus1().ORPort != 9001 {
+ if getStatus1().Address.IPv4ORPort != 9001 {
t.Error("Unexpected ORPort.")
}
@@ -360,6 +363,57 @@ func TestConsensusToSlice(t *testing.T) {
}
}
+func TestParseIPv6AddressAndPort(t *testing.T) {
+
+ _, getStatus, err := ParseRawStatus(`r Karlstad0 m5TNC3uAV+ryG6fwI7ehyMqc5kU f1g9KQhgS0r6+H/7dzAJOpi6lG8 2014-12-08 06:57:54 193.11.166.194 9000 80
+a [2002:470:6e:80d::2]:22
+s Fast Guard HSDir Running Stable V2Dir Valid
+v Tor 0.2.4.23
+w Bandwidth=2670
+p reject 1-65535`)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if getStatus().Address.IPv6Address.String() != "2002:470:6e:80d::2" {
+ t.Error("Failes to Parse IPv6 Address correctly.")
+ }
+
+ if getStatus().Address.IPv6ORPort != StringToPort("22") {
+ t.Error("Failes to Parse IPv6 Port correctly.")
+ }
+}
+
+func TestPrintIPv6AddressAndPort(t *testing.T) {
+
+ _, getStatus0, err := ParseRawStatus(`r Karlstad0 m5TNC3uAV+ryG6fwI7ehyMqc5kU f1g9KQhgS0r6+H/7dzAJOpi6lG8 2014-12-08 06:57:54 193.11.166.194 9000 80
+a [2002:470:6e:80d::2]:22
+s Fast Guard HSDir Running Stable V2Dir Valid
+v Tor 0.2.4.23
+w Bandwidth=2670
+p reject 1-65535`)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if getStatus0().Address.String() != "193.11.166.194|9000|80,2002:470:6e:80d::2|22" {
+ t.Error("Failed to pretty print IP addresses", getStatus0().Address.String())
+ }
+
+ _, getStatus1, err := ParseRawStatus(`r Karlstad0 m5TNC3uAV+ryG6fwI7ehyMqc5kU f1g9KQhgS0r6+H/7dzAJOpi6lG8 2014-12-08 06:57:54 193.11.166.194 9000 80
+s Fast Guard HSDir Running Stable V2Dir Valid
+v Tor 0.2.4.23
+w Bandwidth=2670
+p reject 1-65535`)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if getStatus1().Address.String() != "193.11.166.194|9000|80" {
+ t.Error("Failed to pretty print IP addresses", getStatus1().Address.String())
+ }
+}
+
func TestParseRawConsensus(t *testing.T) {
// Only run this test if the consensus file is there.
if _, err := os.Stat(consensusFile); os.IsNotExist(err) {