summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/tcpip/tcpip.go37
-rw-r--r--pkg/tcpip/tcpip_test.go55
2 files changed, 92 insertions, 0 deletions
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go
index a5259341b..61272cb05 100644
--- a/pkg/tcpip/tcpip.go
+++ b/pkg/tcpip/tcpip.go
@@ -666,6 +666,43 @@ func (a Address) String() string {
switch len(a) {
case 4:
return fmt.Sprintf("%d.%d.%d.%d", int(a[0]), int(a[1]), int(a[2]), int(a[3]))
+ case 16:
+ // Find the longest subsequence of hexadecimal zeros.
+ start, end := -1, -1
+ for i := 0; i < len(a); i += 2 {
+ j := i
+ for j < len(a) && a[j] == 0 && a[j+1] == 0 {
+ j += 2
+ }
+ if j > i+2 && j-i > end-start {
+ start, end = i, j
+ }
+ }
+
+ var b strings.Builder
+ for i := 0; i < len(a); i += 2 {
+ if i == start {
+ b.WriteString("::")
+ i = end
+ if end >= len(a) {
+ break
+ }
+ } else if i > 0 {
+ b.WriteByte(':')
+ }
+ v := uint16(a[i+0])<<8 | uint16(a[i+1])
+ if v == 0 {
+ b.WriteByte('0')
+ } else {
+ const digits = "0123456789abcdef"
+ for i := uint(3); i < 4; i-- {
+ if v := v >> (i * 4); v != 0 {
+ b.WriteByte(digits[v&0xf])
+ }
+ }
+ }
+ }
+ return b.String()
default:
return fmt.Sprintf("%x", []byte(a))
}
diff --git a/pkg/tcpip/tcpip_test.go b/pkg/tcpip/tcpip_test.go
index 6bf82d632..9b20c74c6 100644
--- a/pkg/tcpip/tcpip_test.go
+++ b/pkg/tcpip/tcpip_test.go
@@ -15,6 +15,7 @@
package tcpip
import (
+ "net"
"testing"
)
@@ -138,3 +139,57 @@ func TestRouteMatch(t *testing.T) {
}
}
}
+
+func TestAddressString(t *testing.T) {
+ for _, want := range []string{
+ // Taken from stdlib.
+ "2001:db8::123:12:1",
+ "2001:db8::1",
+ "2001:db8:0:1:0:1:0:1",
+ "2001:db8:1:0:1:0:1:0",
+ "2001::1:0:0:1",
+ "2001:db8:0:0:1::",
+ "2001:db8::1:0:0:1",
+ "2001:db8::a:b:c:d",
+
+ // Leading zeros.
+ "::1",
+ // Trailing zeros.
+ "8::",
+ // No zeros.
+ "1:1:1:1:1:1:1:1",
+ // Longer sequence is after other zeros, but not at the end.
+ "1:0:0:1::1",
+ // Longer sequence is at the beginning, shorter sequence is at
+ // the end.
+ "::1:1:1:0:0",
+ // Longer sequence is not at the beginning, shorter sequence is
+ // at the end.
+ "1::1:1:0:0",
+ // Longer sequence is at the beginning, shorter sequence is not
+ // at the end.
+ "::1:1:0:0:1",
+ // Neither sequence is at an end, longer is after shorter.
+ "1:0:0:1::1",
+ // Shorter sequence is at the beginning, longer sequence is not
+ // at the end.
+ "0:0:1:1::1",
+ // Shorter sequence is at the beginning, longer sequence is at
+ // the end.
+ "0:0:1:1:1::",
+ // Short sequences at both ends, longer one in the middle.
+ "0:1:1::1:1:0",
+ // Short sequences at both ends, longer one in the middle.
+ "0:1::1:0:0",
+ // Short sequences at both ends, longer one in the middle.
+ "0:0:1::1:0",
+ // Longer sequence surrounded by shorter sequences, but none at
+ // the end.
+ "1:0:1::1:0:1",
+ } {
+ addr := Address(net.ParseIP(want))
+ if got := addr.String(); got != want {
+ t.Errorf("Address(%x).String() = '%s', want = '%s'", addr, got, want)
+ }
+ }
+}