4
4
"fmt"
5
5
"net"
6
6
"net/netip"
7
+ "strconv"
7
8
)
8
9
9
10
// An Addr is an IPv6 unicast address.
@@ -18,14 +19,16 @@ const (
18
19
)
19
20
20
21
// chooseAddr selects an Addr from the interface based on the specified Addr type.
21
- func chooseAddr (addrs []net.Addr , zone string , addr Addr ) (netip.Addr , error ) {
22
+ func chooseAddr (addrs []net.Addr , zone string , zoneIndex int , addr Addr ) (netip.Addr , error ) {
22
23
// Does the caller want an unspecified address?
23
24
if addr == Unspecified {
24
25
return netip .IPv6Unspecified ().WithZone (zone ), nil
25
26
}
26
27
27
28
// Select an IPv6 address from the interface's addresses.
28
29
var match func (ip netip.Addr ) bool
30
+ var preferred netip.Addr
31
+ var err error
29
32
switch addr {
30
33
case LinkLocal :
31
34
match = (netip .Addr ).IsLinkLocalUnicast
@@ -38,27 +41,30 @@ func chooseAddr(addrs []net.Addr, zone string, addr Addr) (netip.Addr, error) {
38
41
}
39
42
default :
40
43
// Special case: try to match Addr as a literal IPv6 address.
41
- ip , err : = netip .ParseAddr (string (addr ))
44
+ preferred , err = netip .ParseAddr (string (addr ))
42
45
if err != nil {
43
46
return netip.Addr {}, fmt .Errorf ("ndp: invalid IPv6 address: %q" , addr )
44
47
}
45
-
46
- if err := checkIPv6 (ip ); err != nil {
48
+ if err := checkIPv6 (preferred ); err != nil {
47
49
return netip.Addr {}, err
48
50
}
49
-
50
51
match = func (check netip.Addr ) bool {
51
- return ip == check
52
+ return preferred == check ||
53
+ preferred == check .WithZone (zone ) ||
54
+ preferred == check .WithZone (strconv .Itoa (zoneIndex ))
52
55
}
53
56
}
54
57
55
- return findAddr (addrs , addr , zone , match )
58
+ found := findAddr (addrs , preferred , zone , match )
59
+ if ! found .IsValid () {
60
+ return netip.Addr {}, fmt .Errorf ("ndp: no valid IPv6 address found for %q" , addr )
61
+ }
62
+ return found , nil
56
63
}
57
64
58
65
// findAddr searches for a valid IPv6 address in the slice of net.Addr that
59
- // matches the input function. If none is found, the IPv6 unspecified address
60
- // "::" is returned.
61
- func findAddr (addrs []net.Addr , addr Addr , zone string , match func (ip netip.Addr ) bool ) (netip.Addr , error ) {
66
+ // matches the input function. If none is found, it returns an invalid netip.Addr.
67
+ func findAddr (addrs []net.Addr , preferred netip.Addr , zone string , match func (ip netip.Addr ) bool ) netip.Addr {
62
68
for _ , a := range addrs {
63
69
ipn , ok := a .(* net.IPNet )
64
70
if ! ok {
@@ -75,11 +81,18 @@ func findAddr(addrs []net.Addr, addr Addr, zone string, match func(ip netip.Addr
75
81
76
82
// From here on, we can assume that only IPv6 addresses are
77
83
// being checked.
78
- if match (ip ) {
79
- return ip .WithZone (zone ), nil
84
+ if ! match (ip ) {
85
+ continue
86
+ }
87
+ // If a preferred address is set, use it directly.
88
+ if preferred .IsValid () {
89
+ if preferred .Zone () == "" {
90
+ return preferred .WithZone (zone )
91
+ }
92
+ return preferred
80
93
}
94
+ return ip .WithZone (zone )
81
95
}
82
96
83
- // No matching address on this interface.
84
- return netip.Addr {}, fmt .Errorf ("ndp: address %q not found on interface %q" , addr , zone )
97
+ return netip.Addr {}
85
98
}
0 commit comments