Home | History | Annotate | Download | only in net
      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 		},
     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 	for i, tt := range tests {
    122 		inCopy := make([]IPAddr, len(tt.in))
    123 		copy(inCopy, tt.in)
    124 		srcCopy := make([]IP, len(tt.in))
    125 		copy(srcCopy, tt.srcs)
    126 		sortByRFC6724withSrcs(inCopy, srcCopy)
    127 		if !reflect.DeepEqual(inCopy, tt.want) {
    128 			t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
    129 		}
    130 		if tt.reverse {
    131 			copy(inCopy, tt.in)
    132 			copy(srcCopy, tt.srcs)
    133 			for j := 0; j < len(inCopy)/2; j++ {
    134 				k := len(inCopy) - j - 1
    135 				inCopy[j], inCopy[k] = inCopy[k], inCopy[j]
    136 				srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j]
    137 			}
    138 			sortByRFC6724withSrcs(inCopy, srcCopy)
    139 			if !reflect.DeepEqual(inCopy, tt.want) {
    140 				t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
    141 			}
    142 		}
    143 
    144 	}
    145 
    146 }
    147 
    148 func TestRFC6724PolicyTableClassify(t *testing.T) {
    149 	tests := []struct {
    150 		ip   IP
    151 		want policyTableEntry
    152 	}{
    153 		{
    154 			ip: ParseIP("127.0.0.1"),
    155 			want: policyTableEntry{
    156 				Prefix:     &IPNet{IP: ParseIP("::ffff:0:0"), Mask: CIDRMask(96, 128)},
    157 				Precedence: 35,
    158 				Label:      4,
    159 			},
    160 		},
    161 		{
    162 			ip: ParseIP("2601:645:8002:a500:986f:1db8:c836:bd65"),
    163 			want: policyTableEntry{
    164 				Prefix:     &IPNet{IP: ParseIP("::"), Mask: CIDRMask(0, 128)},
    165 				Precedence: 40,
    166 				Label:      1,
    167 			},
    168 		},
    169 		{
    170 			ip: ParseIP("::1"),
    171 			want: policyTableEntry{
    172 				Prefix:     &IPNet{IP: ParseIP("::1"), Mask: CIDRMask(128, 128)},
    173 				Precedence: 50,
    174 				Label:      0,
    175 			},
    176 		},
    177 		{
    178 			ip: ParseIP("2002::ab12"),
    179 			want: policyTableEntry{
    180 				Prefix:     &IPNet{IP: ParseIP("2002::"), Mask: CIDRMask(16, 128)},
    181 				Precedence: 30,
    182 				Label:      2,
    183 			},
    184 		},
    185 	}
    186 	for i, tt := range tests {
    187 		got := rfc6724policyTable.Classify(tt.ip)
    188 		if !reflect.DeepEqual(got, tt.want) {
    189 			t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want)
    190 		}
    191 	}
    192 }
    193 
    194 func TestRFC6724ClassifyScope(t *testing.T) {
    195 	tests := []struct {
    196 		ip   IP
    197 		want scope
    198 	}{
    199 		{ParseIP("127.0.0.1"), scopeLinkLocal},   // rfc6724#section-3.2
    200 		{ParseIP("::1"), scopeLinkLocal},         // rfc4007#section-4
    201 		{ParseIP("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2
    202 		{ParseIP("fec0::1"), scopeSiteLocal},
    203 		{ParseIP("8.8.8.8"), scopeGlobal},
    204 
    205 		{ParseIP("ff02::"), scopeLinkLocal},  // IPv6 multicast
    206 		{ParseIP("ff05::"), scopeSiteLocal},  // IPv6 multicast
    207 		{ParseIP("ff04::"), scopeAdminLocal}, // IPv6 multicast
    208 		{ParseIP("ff0e::"), scopeGlobal},     // IPv6 multicast
    209 
    210 		{IPv4(0xe0, 0, 0, 0), scopeGlobal},       // IPv4 link-local multicast as 16 bytes
    211 		{IPv4(0xe0, 2, 2, 2), scopeGlobal},       // IPv4 global multicast as 16 bytes
    212 		{IPv4(0xe0, 0, 0, 0).To4(), scopeGlobal}, // IPv4 link-local multicast as 4 bytes
    213 		{IPv4(0xe0, 2, 2, 2).To4(), scopeGlobal}, // IPv4 global multicast as 4 bytes
    214 	}
    215 	for i, tt := range tests {
    216 		got := classifyScope(tt.ip)
    217 		if got != tt.want {
    218 			t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want)
    219 		}
    220 	}
    221 }
    222 
    223 func TestRFC6724CommonPrefixLength(t *testing.T) {
    224 	tests := []struct {
    225 		a, b IP
    226 		want int
    227 	}{
    228 		{ParseIP("fe80::1"), ParseIP("fe80::2"), 64},
    229 		{ParseIP("fe81::1"), ParseIP("fe80::2"), 15},
    230 		{ParseIP("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size
    231 		{IPv4(1, 2, 3, 4), IP{1, 2, 3, 4}, 32},
    232 		{IP{1, 2, 255, 255}, IP{1, 2, 0, 0}, 16},
    233 		{IP{1, 2, 127, 255}, IP{1, 2, 0, 0}, 17},
    234 		{IP{1, 2, 63, 255}, IP{1, 2, 0, 0}, 18},
    235 		{IP{1, 2, 31, 255}, IP{1, 2, 0, 0}, 19},
    236 		{IP{1, 2, 15, 255}, IP{1, 2, 0, 0}, 20},
    237 		{IP{1, 2, 7, 255}, IP{1, 2, 0, 0}, 21},
    238 		{IP{1, 2, 3, 255}, IP{1, 2, 0, 0}, 22},
    239 		{IP{1, 2, 1, 255}, IP{1, 2, 0, 0}, 23},
    240 		{IP{1, 2, 0, 255}, IP{1, 2, 0, 0}, 24},
    241 	}
    242 	for i, tt := range tests {
    243 		got := commonPrefixLen(tt.a, tt.b)
    244 		if got != tt.want {
    245 			t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want)
    246 		}
    247 	}
    248 
    249 }
    250