-
Notifications
You must be signed in to change notification settings - Fork 1
/
addr.go
162 lines (141 loc) · 4.13 KB
/
addr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
© 2020–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
ISC License
*/
package pnet
import (
"net/netip"
"strconv"
"github.com/haraldrudell/parl/perrors"
)
// IsNonGlobalIPv6 returns if addr is an IPv6 address that should have zone
func IsNonGlobalIPv6(addr netip.Addr) (needsZone bool) {
return addr.Is6() && ( //
addr.IsInterfaceLocalMulticast() || // 0xffx1::
addr.IsLinkLocalMulticast() || // 0xffx2::
addr.IsLinkLocalUnicast() || // 0xfe8::
addr.IsPrivate())
}
// EnsureZone adds IPv6 zone as applicable
// - only non-global IPv6 should have zone
// - if acceptNumeric true no index to interface-name translation attempts take place.
// otherwise interface-name zone is preferred
// - a non-numeric zone is attempted from: addr, ifName
// - number cinversion to interfa e is attempted: addr, ifIndex
// - acceptNumeric true leaves an existing numeric zone
func EnsureZone(addr netip.Addr, ifName string, ifIndex IfIndex, acceptNumeric ...bool) (addr2 netip.Addr, didChange, isNumeric bool, err error) {
addr2 = addr
var doNumeric bool
if len(acceptNumeric) > 0 {
doNumeric = acceptNumeric[0]
}
// does addr need zone?
if !IsNonGlobalIPv6(addr) {
return // this IPv6 address does not need zone return
}
// does addr already have non-numeric zone?
var zone = addr.Zone()
var ifi IfIndex
var hasNumericZone bool
if zone != "" {
var number int
var e error
number, e = strconv.Atoi(zone)
if e != nil {
return // addr already has non-numeric zone
}
var ifiTry IfIndex
ifiTry, e = NewIfIndexInt(number)
if hasNumericZone = e == nil && ifiTry.IsValid(); hasNumericZone {
if doNumeric {
isNumeric = true
return // zone is numeric and that should be used return
}
ifi = ifiTry
}
}
// - addr should have zone
// - addr has no zone or has numeric zone with doNumeric false
// use ifName
if didChange = ifName != ""; didChange {
addr2 = netip.Addr.WithZone(addr, ifName)
return
}
// use ifIndex if donumeric is true
if doNumeric {
if didChange = ifIndex.IsValid(); didChange {
isNumeric = true
addr2 = netip.Addr.WithZone(addr, ifIndex.String())
return
}
err = perrors.NewPF("no zone in addr ifIndex ifName")
return
}
// attempt translation of ifi ifIndex
// translate addr numeric zone
if hasNumericZone {
var z string
var isNo bool
var e error
if z, isNo, e = ifi.Zone(); z != "" && !isNo && e == nil {
didChange = true
addr2 = netip.Addr.WithZone(addr, z)
return
}
}
// translate ifIndex
if ifIndex.IsValid() {
var z string
var isNo bool
var e error
if z, isNo, e = ifIndex.Zone(); z != "" && !isNo && e == nil {
didChange = true
addr2 = netip.Addr.WithZone(addr, z)
return
}
}
// no translation is available
// doNumeric is false
// fallback to any numeric
// numeric addr.Zone
if hasNumericZone {
return // best is the numeric zone already in addr return
}
// numeric ifIndex
if didChange = ifIndex.IsValid(); didChange {
isNumeric = true
addr2 = addr.WithZone(ifIndex.String())
return
}
// it’s a failure
err = perrors.NewPF("no successful translation or zone in addr ifIndex ifName")
return
}
//var isDigits = regexp.MustCompile(`^[0-9]+$`).MatchString
// Zone examines the zone included in addr
// - no zone: hasZone: false, isNumeric: false
// - numeric zone “1”: hasZone: true, isNumeric: true.
// Number is network interface index.
// - interface-name zone “eth0”: hasZone: true, isNumeric false
func Zone(addr netip.Addr) (zone string, znum int, hasZone, isNumeric bool) {
zone = addr.Zone()
if hasZone = zone != ""; !hasZone {
return
}
var err error
znum, err = strconv.Atoi(zone)
isNumeric = err == nil
return
}
// Addr46 converts 4in6 IPv6 addresses to IPv4 for consistent IPv4/IPv6
// - IPv6 has a special class of addresses represnting an IPv4 address
// - IPv6 “::ffff:192.0.2.128” represents the IPv4 address “192.0.2.128”
// - Addr46 converts such addresses to IPv4
func Addr46(addr netip.Addr) (addr46 netip.Addr) {
if addr.Is4In6() {
addr46 = netip.AddrFrom4(addr.As4())
} else {
addr46 = addr
}
return
}