1// SPDX-License-Identifier: ISC 2// Copyright (c) 2014-2020 Bitmark Inc. 3// Use of this source code is governed by an ISC 4// license that can be found in the LICENSE file. 5 6package util 7 8import ( 9 "encoding/hex" 10 "strings" 11 "testing" 12 13 "github.com/bitmark-inc/bitmarkd/fault" 14) 15 16// Test IP address detection 17func TestCanonical(t *testing.T) { 18 19 type item struct { 20 in string 21 out string 22 } 23 24 testData := []item{ 25 {"127.0.0.1:1234", "127.0.0.1:1234"}, 26 {"127.0.0.1:1", "127.0.0.1:1"}, 27 {" 127.0.0.1 : 1 ", "127.0.0.1:1"}, 28 {"127.0.0.1:65535", "127.0.0.1:65535"}, 29 {"0.0.0.0:1234", "0.0.0.0:1234"}, 30 {"[::1]:1234", "[::1]:1234"}, 31 {"[::]:1234", "[::]:1234"}, 32 {"*:1234", "[::]:1234"}, 33 {"[0:0::0:0]:1234", "[::]:1234"}, 34 {"[0:0:0:0::1]:1234", "[::1]:1234"}, 35 {"[2404:6800:4008:c07::66]:443", "[2404:6800:4008:c07::66]:443"}, 36 {"[2404:6800:4008:0c07:0000:0000:0000:0066]:443", "[2404:6800:4008:c07::66]:443"}, 37 } 38 39 for i, d := range testData { 40 41 // create a connection item 42 c, err := NewConnection(d.in) 43 if nil != err { 44 t.Fatalf("NewConnection failed on:[%d] %q error: %s", i, d.in, err) 45 } 46 47 // convert to text 48 s, v6 := c.CanonicalIPandPort("") 49 if s != d.out { 50 t.Fatalf("failed on:[%d] %q actual: %q expected: %q", i, d.in, s, d.out) 51 } 52 53 t.Logf("converted:[%d]: %q to(%t): %q", i, d.in, v6, s) 54 55 // check packing/unpacking 56 pk := c.Pack() 57 cu, n := pk.Unpack() 58 if len(pk) != n { 59 t.Fatalf("Unpack failed on:[%d] %q only read: %d of: %d bytes", i, d.in, n, len(pk)) 60 } 61 su, v6u := cu.CanonicalIPandPort("") 62 if su != s { 63 t.Fatalf("failed on:[%d] %x actual: %q expected: %q", i, pk, su, s) 64 } 65 if v6u != v6 { 66 t.Fatalf("failed on:[%d] %x actual v6: %t expected v6: %t", i, pk, v6u, v6) 67 } 68 } 69} 70 71// Test IP address 72func TestCanonicalIP(t *testing.T) { 73 74 type item struct { 75 ip string 76 err string 77 } 78 79 testData := []item{ 80 {"256.0.0.0:1234", "no such host"}, 81 {"0.256.0.0:1234", "no such host"}, 82 {"0.0.256.0:1234", "no such host"}, 83 {"0.0.0.256:1234", "no such host"}, 84 {"0:0:1234", "too many colons in address"}, 85 {"[]:1234", "no such host"}, 86 {"[as34::]:1234", "no such host"}, 87 {"[1ffff::]:1234", "no such host"}, 88 {"[2404:6800:4008:0c07:0000:0000:0000:0066:1234]:443", "no such host"}, 89 {"!:1234", "no such host"}, 90 {"#:1234", "no such host"}, 91 {"127.0.0.1", "missing port in address"}, 92 {"[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]", "missing port in address"}, 93 } 94 95 for i, d := range testData { 96 c, err := NewConnection(d.ip) 97 if nil == err { 98 s, v6 := c.CanonicalIPandPort("") 99 t.Fatalf("eroneoulssly converted:[%d]: %q to(%t): %q", i, d.ip, v6, s) 100 } 101 if !strings.Contains(err.Error(), d.err) { 102 t.Fatalf("NewConnection failed on:[%d] %q error: %s", i, d, err) 103 } 104 } 105} 106 107// Test port range 108func TestCanonicalPort(t *testing.T) { 109 110 testData := []string{ 111 "127.0.0.1:0", 112 "127.0.0.1:65536", 113 "127.0.0.1:-1", 114 } 115 116 for i, d := range testData { 117 c, err := NewConnection(d) 118 if nil == err { 119 s, v6 := c.CanonicalIPandPort("") 120 t.Fatalf("eroneoulssly converted:[%d]: %q to(%t): %q", i, d, v6, s) 121 } 122 if fault.InvalidPortNumber != err { 123 t.Fatalf("NewConnection failed on:[%d] %q error: %s", i, d, err) 124 } 125 } 126} 127 128// helper 129func makePacked(h string) PackedConnection { 130 b, err := hex.DecodeString(h) 131 if nil != err { 132 panic(err) 133 } 134 return b 135} 136 137// Test of unpack 138func TestCanonicalUnpack(t *testing.T) { 139 140 type item struct { 141 packed PackedConnection 142 addresses []string 143 v4 string 144 v6 string 145 } 146 147 testData := []item{ 148 { 149 packed: makePacked("1304d200000000000000000000ffff7f0000011304d200000000000000000000000000000001"), 150 addresses: []string{ 151 "127.0.0.1:1234", 152 "[::1]:1234", 153 }, 154 v4: "127.0.0.1:1234", 155 v6: "[::1]:1234", 156 }, 157 { 158 packed: makePacked("1304d2000000000000000000000000000000011304d200000000000000000000ffff7f000001"), 159 addresses: []string{ 160 "[::1]:1234", 161 "127.0.0.1:1234", 162 }, 163 v4: "127.0.0.1:1234", 164 v6: "[::1]:1234", 165 }, 166 { 167 packed: makePacked("1301bb2404680040080c0700000000000000661301bb2404680040080c070000000000000066"), 168 addresses: []string{ 169 "[2404:6800:4008:c07::66]:443", 170 "[2404:6800:4008:c07::66]:443", 171 }, 172 v4: "<nil>", 173 v6: "[2404:6800:4008:c07::66]:443", 174 }, 175 { // extraneous data 176 packed: makePacked("1301bb2404680040080c0700000000000000661301bb2404680040080c0700000000000000660000000000000000000000000000000000000000"), 177 addresses: []string{ 178 "[2404:6800:4008:c07::66]:443", 179 "[2404:6800:4008:c07::66]:443", 180 }, 181 v4: "<nil>", 182 v6: "[2404:6800:4008:c07::66]:443", 183 }, 184 { // bad data -> no items 185 packed: makePacked("1401bb2404680040080c0700000000000000661001bb2404680040080c0700000000000000660000000000000000000000000000000000000000"), 186 addresses: []string{}, 187 v4: "<nil>", 188 v6: "<nil>", 189 }, 190 { // bad data followed by good addresses -> consider as all bad 191 packed: makePacked("01221304d200000000000000000000ffff7f0000011304d200000000000000000000000000000001"), 192 addresses: []string{}, 193 v4: "<nil>", 194 v6: "<nil>", 195 }, 196 } 197 198 for i, data := range testData { 199 p := data.packed 200 a := data.addresses 201 al := len(a) 202 203 v4, v6 := p.Unpack46() 204 v4s := "<nil>" 205 if nil != v4 { 206 v4s, _ = v4.CanonicalIPandPort("") 207 } 208 v6s := "<nil>" 209 if nil != v6 { 210 v6s, _ = v6.CanonicalIPandPort("") 211 } 212 if data.v4 != v4s { 213 t.Errorf("unpack46:[%d]: v4 actual: %q expected: %q", i, v4s, data.v4) 214 } 215 if data.v6 != v6s { 216 t.Errorf("unpack66:[%d]: v6 actual: %q expected: %q", i, v6s, data.v6) 217 } 218 219 inner: 220 for k := 0; k < 10; k += 1 { 221 l := len(p) 222 c, n := p.Unpack() 223 p = p[n:] 224 225 if nil == c { 226 // only signal error if nil was not just after last address 227 if k != al { 228 t.Errorf("unpack:[%d]: nil connection, n: %d", i, n) 229 } 230 231 } else { 232 s, v6 := c.CanonicalIPandPort("") 233 if k >= al { 234 t.Errorf("unpack:[%d]: bytes: %d of %d result: (%t) %q", i, n, l, v6, s) 235 } else if s != a[k] { 236 t.Errorf("unpack:[%d]: bytes: %d of %d result: (%t) %q expected: %s", i, n, l, v6, s, a[k]) 237 } 238 } 239 if n <= 0 { 240 break inner 241 } 242 } 243 } 244} 245