Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | // +build darwin dragonfly freebsd linux netbsd openbsd solaris |
| 6 | |
| 7 | package net |
| 8 | |
| 9 | import ( |
| 10 | "reflect" |
| 11 | "testing" |
| 12 | ) |
| 13 | |
| 14 | func TestSortByRFC6724(t *testing.T) { |
| 15 | tests := []struct { |
| 16 | in []IPAddr |
| 17 | srcs []IP |
| 18 | want []IPAddr |
| 19 | reverse bool // also test it starting backwards |
| 20 | }{ |
| 21 | // Examples from RFC 6724 section 10.2: |
| 22 | |
| 23 | // Prefer matching scope. |
| 24 | { |
| 25 | in: []IPAddr{ |
| 26 | {IP: ParseIP("2001:db8:1::1")}, |
| 27 | {IP: ParseIP("198.51.100.121")}, |
| 28 | }, |
| 29 | srcs: []IP{ |
| 30 | ParseIP("2001:db8:1::2"), |
| 31 | ParseIP("169.254.13.78"), |
| 32 | }, |
| 33 | want: []IPAddr{ |
| 34 | {IP: ParseIP("2001:db8:1::1")}, |
| 35 | {IP: ParseIP("198.51.100.121")}, |
| 36 | }, |
| 37 | reverse: true, |
| 38 | }, |
| 39 | |
| 40 | // Prefer matching scope. |
| 41 | { |
| 42 | in: []IPAddr{ |
| 43 | {IP: ParseIP("2001:db8:1::1")}, |
| 44 | {IP: ParseIP("198.51.100.121")}, |
| 45 | }, |
| 46 | srcs: []IP{ |
| 47 | ParseIP("fe80::1"), |
| 48 | ParseIP("198.51.100.117"), |
| 49 | }, |
| 50 | want: []IPAddr{ |
| 51 | {IP: ParseIP("198.51.100.121")}, |
| 52 | {IP: ParseIP("2001:db8:1::1")}, |
| 53 | }, |
| 54 | reverse: true, |
| 55 | }, |
| 56 | |
| 57 | // Prefer higher precedence. |
| 58 | { |
| 59 | in: []IPAddr{ |
| 60 | {IP: ParseIP("2001:db8:1::1")}, |
| 61 | {IP: ParseIP("10.1.2.3")}, |
| 62 | }, |
| 63 | srcs: []IP{ |
| 64 | ParseIP("2001:db8:1::2"), |
| 65 | ParseIP("10.1.2.4"), |
| 66 | }, |
| 67 | want: []IPAddr{ |
| 68 | {IP: ParseIP("2001:db8:1::1")}, |
| 69 | {IP: ParseIP("10.1.2.3")}, |
| 70 | }, |
| 71 | reverse: true, |
| 72 | }, |
| 73 | |
| 74 | // Prefer smaller scope. |
| 75 | { |
| 76 | in: []IPAddr{ |
| 77 | {IP: ParseIP("2001:db8:1::1")}, |
| 78 | {IP: ParseIP("fe80::1")}, |
| 79 | }, |
| 80 | srcs: []IP{ |
| 81 | ParseIP("2001:db8:1::2"), |
| 82 | ParseIP("fe80::2"), |
| 83 | }, |
| 84 | want: []IPAddr{ |
| 85 | {IP: ParseIP("fe80::1")}, |
| 86 | {IP: ParseIP("2001:db8:1::1")}, |
| 87 | }, |
| 88 | reverse: true, |
| 89 | }, |
Matthew Dempsky | 4d4a266 | 2015-11-16 20:26:24 -0800 | [diff] [blame] | 90 | |
| 91 | // Issue 13283. Having a 10/8 source address does not |
| 92 | // mean we should prefer 23/8 destination addresses. |
| 93 | { |
| 94 | in: []IPAddr{ |
| 95 | {IP: ParseIP("54.83.193.112")}, |
| 96 | {IP: ParseIP("184.72.238.214")}, |
| 97 | {IP: ParseIP("23.23.172.185")}, |
| 98 | {IP: ParseIP("75.101.148.21")}, |
| 99 | {IP: ParseIP("23.23.134.56")}, |
| 100 | {IP: ParseIP("23.21.50.150")}, |
| 101 | }, |
| 102 | srcs: []IP{ |
| 103 | ParseIP("10.2.3.4"), |
| 104 | ParseIP("10.2.3.4"), |
| 105 | ParseIP("10.2.3.4"), |
| 106 | ParseIP("10.2.3.4"), |
| 107 | ParseIP("10.2.3.4"), |
| 108 | ParseIP("10.2.3.4"), |
| 109 | }, |
| 110 | want: []IPAddr{ |
| 111 | {IP: ParseIP("54.83.193.112")}, |
| 112 | {IP: ParseIP("184.72.238.214")}, |
| 113 | {IP: ParseIP("23.23.172.185")}, |
| 114 | {IP: ParseIP("75.101.148.21")}, |
| 115 | {IP: ParseIP("23.23.134.56")}, |
| 116 | {IP: ParseIP("23.21.50.150")}, |
| 117 | }, |
| 118 | reverse: false, |
| 119 | }, |
| 120 | |
| 121 | // Prefer longer common prefixes, but only for IPv4 address |
| 122 | // pairs in the same special-purpose block. |
| 123 | { |
| 124 | in: []IPAddr{ |
| 125 | {IP: ParseIP("1.2.3.4")}, |
| 126 | {IP: ParseIP("10.55.0.1")}, |
| 127 | {IP: ParseIP("10.66.0.1")}, |
| 128 | }, |
| 129 | srcs: []IP{ |
| 130 | ParseIP("1.2.3.5"), |
| 131 | ParseIP("10.66.1.2"), |
| 132 | ParseIP("10.66.1.2"), |
| 133 | }, |
| 134 | want: []IPAddr{ |
| 135 | {IP: ParseIP("10.66.0.1")}, |
| 136 | {IP: ParseIP("10.55.0.1")}, |
| 137 | {IP: ParseIP("1.2.3.4")}, |
| 138 | }, |
| 139 | reverse: true, |
| 140 | }, |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 141 | } |
| 142 | for i, tt := range tests { |
| 143 | inCopy := make([]IPAddr, len(tt.in)) |
| 144 | copy(inCopy, tt.in) |
| 145 | srcCopy := make([]IP, len(tt.in)) |
| 146 | copy(srcCopy, tt.srcs) |
| 147 | sortByRFC6724withSrcs(inCopy, srcCopy) |
| 148 | if !reflect.DeepEqual(inCopy, tt.want) { |
| 149 | t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want) |
| 150 | } |
| 151 | if tt.reverse { |
| 152 | copy(inCopy, tt.in) |
| 153 | copy(srcCopy, tt.srcs) |
| 154 | for j := 0; j < len(inCopy)/2; j++ { |
| 155 | k := len(inCopy) - j - 1 |
| 156 | inCopy[j], inCopy[k] = inCopy[k], inCopy[j] |
| 157 | srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j] |
| 158 | } |
| 159 | sortByRFC6724withSrcs(inCopy, srcCopy) |
| 160 | if !reflect.DeepEqual(inCopy, tt.want) { |
| 161 | t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want) |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | } |
| 166 | |
| 167 | } |
| 168 | |
| 169 | func TestRFC6724PolicyTableClassify(t *testing.T) { |
| 170 | tests := []struct { |
| 171 | ip IP |
| 172 | want policyTableEntry |
| 173 | }{ |
| 174 | { |
| 175 | ip: ParseIP("127.0.0.1"), |
| 176 | want: policyTableEntry{ |
| 177 | Prefix: &IPNet{IP: ParseIP("::ffff:0:0"), Mask: CIDRMask(96, 128)}, |
| 178 | Precedence: 35, |
| 179 | Label: 4, |
| 180 | }, |
| 181 | }, |
| 182 | { |
| 183 | ip: ParseIP("2601:645:8002:a500:986f:1db8:c836:bd65"), |
| 184 | want: policyTableEntry{ |
| 185 | Prefix: &IPNet{IP: ParseIP("::"), Mask: CIDRMask(0, 128)}, |
| 186 | Precedence: 40, |
| 187 | Label: 1, |
| 188 | }, |
| 189 | }, |
| 190 | { |
| 191 | ip: ParseIP("::1"), |
| 192 | want: policyTableEntry{ |
| 193 | Prefix: &IPNet{IP: ParseIP("::1"), Mask: CIDRMask(128, 128)}, |
| 194 | Precedence: 50, |
| 195 | Label: 0, |
| 196 | }, |
| 197 | }, |
| 198 | { |
| 199 | ip: ParseIP("2002::ab12"), |
| 200 | want: policyTableEntry{ |
| 201 | Prefix: &IPNet{IP: ParseIP("2002::"), Mask: CIDRMask(16, 128)}, |
| 202 | Precedence: 30, |
| 203 | Label: 2, |
| 204 | }, |
| 205 | }, |
| 206 | } |
| 207 | for i, tt := range tests { |
| 208 | got := rfc6724policyTable.Classify(tt.ip) |
| 209 | if !reflect.DeepEqual(got, tt.want) { |
| 210 | t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want) |
| 211 | } |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | func TestRFC6724ClassifyScope(t *testing.T) { |
| 216 | tests := []struct { |
| 217 | ip IP |
| 218 | want scope |
| 219 | }{ |
| 220 | {ParseIP("127.0.0.1"), scopeLinkLocal}, // rfc6724#section-3.2 |
| 221 | {ParseIP("::1"), scopeLinkLocal}, // rfc4007#section-4 |
| 222 | {ParseIP("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2 |
Mikio Hara | aadd84e | 2015-07-17 17:31:49 +0900 | [diff] [blame] | 223 | {ParseIP("fec0::1"), scopeSiteLocal}, |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 224 | {ParseIP("8.8.8.8"), scopeGlobal}, |
| 225 | |
| 226 | {ParseIP("ff02::"), scopeLinkLocal}, // IPv6 multicast |
| 227 | {ParseIP("ff05::"), scopeSiteLocal}, // IPv6 multicast |
| 228 | {ParseIP("ff04::"), scopeAdminLocal}, // IPv6 multicast |
| 229 | {ParseIP("ff0e::"), scopeGlobal}, // IPv6 multicast |
| 230 | |
| 231 | {IPv4(0xe0, 0, 0, 0), scopeGlobal}, // IPv4 link-local multicast as 16 bytes |
| 232 | {IPv4(0xe0, 2, 2, 2), scopeGlobal}, // IPv4 global multicast as 16 bytes |
| 233 | {IPv4(0xe0, 0, 0, 0).To4(), scopeGlobal}, // IPv4 link-local multicast as 4 bytes |
| 234 | {IPv4(0xe0, 2, 2, 2).To4(), scopeGlobal}, // IPv4 global multicast as 4 bytes |
| 235 | } |
| 236 | for i, tt := range tests { |
| 237 | got := classifyScope(tt.ip) |
| 238 | if got != tt.want { |
| 239 | t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want) |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | func TestRFC6724CommonPrefixLength(t *testing.T) { |
| 245 | tests := []struct { |
| 246 | a, b IP |
| 247 | want int |
| 248 | }{ |
| 249 | {ParseIP("fe80::1"), ParseIP("fe80::2"), 64}, |
| 250 | {ParseIP("fe81::1"), ParseIP("fe80::2"), 15}, |
| 251 | {ParseIP("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size |
| 252 | {IPv4(1, 2, 3, 4), IP{1, 2, 3, 4}, 32}, |
| 253 | {IP{1, 2, 255, 255}, IP{1, 2, 0, 0}, 16}, |
| 254 | {IP{1, 2, 127, 255}, IP{1, 2, 0, 0}, 17}, |
| 255 | {IP{1, 2, 63, 255}, IP{1, 2, 0, 0}, 18}, |
| 256 | {IP{1, 2, 31, 255}, IP{1, 2, 0, 0}, 19}, |
| 257 | {IP{1, 2, 15, 255}, IP{1, 2, 0, 0}, 20}, |
| 258 | {IP{1, 2, 7, 255}, IP{1, 2, 0, 0}, 21}, |
| 259 | {IP{1, 2, 3, 255}, IP{1, 2, 0, 0}, 22}, |
| 260 | {IP{1, 2, 1, 255}, IP{1, 2, 0, 0}, 23}, |
| 261 | {IP{1, 2, 0, 255}, IP{1, 2, 0, 0}, 24}, |
| 262 | } |
| 263 | for i, tt := range tests { |
| 264 | got := commonPrefixLen(tt.a, tt.b) |
| 265 | if got != tt.want { |
| 266 | t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want) |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | } |
Matthew Dempsky | 4d4a266 | 2015-11-16 20:26:24 -0800 | [diff] [blame] | 271 | |
| 272 | func mustParseCIDRs(t *testing.T, blocks ...string) []*IPNet { |
| 273 | res := make([]*IPNet, len(blocks)) |
| 274 | for i, block := range blocks { |
| 275 | var err error |
| 276 | _, res[i], err = ParseCIDR(block) |
| 277 | if err != nil { |
| 278 | t.Fatalf("ParseCIDR(%s) failed: %v", block, err) |
| 279 | } |
| 280 | } |
| 281 | return res |
| 282 | } |
| 283 | |
| 284 | func TestSameIPv4SpecialPurposeBlock(t *testing.T) { |
| 285 | blocks := mustParseCIDRs(t, |
| 286 | "10.0.0.0/8", |
| 287 | "127.0.0.0/8", |
| 288 | "169.254.0.0/16", |
| 289 | "172.16.0.0/12", |
| 290 | "192.168.0.0/16", |
| 291 | ) |
| 292 | |
| 293 | addrs := []struct { |
| 294 | ip IP |
| 295 | block int // index or -1 |
| 296 | }{ |
| 297 | {IP{1, 2, 3, 4}, -1}, |
| 298 | {IP{2, 3, 4, 5}, -1}, |
| 299 | {IP{10, 2, 3, 4}, 0}, |
| 300 | {IP{10, 6, 7, 8}, 0}, |
| 301 | {IP{127, 0, 0, 1}, 1}, |
| 302 | {IP{127, 255, 255, 255}, 1}, |
| 303 | {IP{169, 254, 77, 99}, 2}, |
| 304 | {IP{169, 254, 44, 22}, 2}, |
| 305 | {IP{169, 255, 0, 1}, -1}, |
| 306 | {IP{172, 15, 5, 6}, -1}, |
| 307 | {IP{172, 16, 32, 41}, 3}, |
| 308 | {IP{172, 31, 128, 9}, 3}, |
| 309 | {IP{172, 32, 88, 100}, -1}, |
| 310 | {IP{192, 168, 1, 1}, 4}, |
| 311 | {IP{192, 168, 128, 42}, 4}, |
| 312 | {IP{192, 169, 1, 1}, -1}, |
| 313 | } |
| 314 | |
| 315 | for i, addr := range addrs { |
| 316 | for j, block := range blocks { |
| 317 | got := block.Contains(addr.ip) |
| 318 | want := addr.block == j |
| 319 | if got != want { |
| 320 | t.Errorf("%d/%d. %s.Contains(%s): got %v, want %v", i, j, block, addr.ip, got, want) |
| 321 | } |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | for i, addr1 := range addrs { |
| 326 | for j, addr2 := range addrs { |
| 327 | got := sameIPv4SpecialPurposeBlock(addr1.ip, addr2.ip) |
| 328 | want := addr1.block >= 0 && addr1.block == addr2.block |
| 329 | if got != want { |
| 330 | t.Errorf("%d/%d. sameIPv4SpecialPurposeBlock(%s, %s): got %v, want %v", i, j, addr1.ip, addr2.ip, got, want) |
| 331 | } |
| 332 | } |
| 333 | } |
| 334 | } |