-
Notifications
You must be signed in to change notification settings - Fork 0
/
addr.go
145 lines (129 loc) · 3.39 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
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
package ice
import (
"fmt"
"net"
"net/netip"
)
func addrWithOptionalZone(addr netip.Addr, zone string) netip.Addr {
if zone == "" {
return addr
}
if addr.Is6() && (addr.IsLinkLocalUnicast() || addr.IsLinkLocalMulticast()) {
return addr.WithZone(zone)
}
return addr
}
// parseAddrFromIface should only be used when it's known the address belongs to that interface.
// e.g. it's LocalAddress on a listener.
func parseAddrFromIface(in net.Addr, ifcName string) (netip.Addr, int, NetworkType, error) {
addr, port, nt, err := parseAddr(in)
if err != nil {
return netip.Addr{}, 0, 0, err
}
if _, ok := in.(*net.IPNet); ok {
// net.IPNet does not have a Zone but we provide it from the interface
addr = addrWithOptionalZone(addr, ifcName)
}
return addr, port, nt, nil
}
func parseAddr(in net.Addr) (netip.Addr, int, NetworkType, error) {
switch addr := in.(type) {
case *net.IPNet:
ipAddr, err := ipAddrToNetIP(addr.IP, "")
if err != nil {
return netip.Addr{}, 0, 0, err
}
return ipAddr, 0, 0, nil
case *net.IPAddr:
ipAddr, err := ipAddrToNetIP(addr.IP, addr.Zone)
if err != nil {
return netip.Addr{}, 0, 0, err
}
return ipAddr, 0, 0, nil
case *net.UDPAddr:
ipAddr, err := ipAddrToNetIP(addr.IP, addr.Zone)
if err != nil {
return netip.Addr{}, 0, 0, err
}
var nt NetworkType
if ipAddr.Is4() {
nt = NetworkTypeUDP4
} else {
nt = NetworkTypeUDP6
}
return ipAddr, addr.Port, nt, nil
case *net.TCPAddr:
ipAddr, err := ipAddrToNetIP(addr.IP, addr.Zone)
if err != nil {
return netip.Addr{}, 0, 0, err
}
var nt NetworkType
if ipAddr.Is4() {
nt = NetworkTypeTCP4
} else {
nt = NetworkTypeTCP6
}
return ipAddr, addr.Port, nt, nil
default:
return netip.Addr{}, 0, 0, addrParseError{in}
}
}
type addrParseError struct {
addr net.Addr
}
func (e addrParseError) Error() string {
return fmt.Sprintf("do not know how to parse address type %T", e.addr)
}
type ipConvertError struct {
ip []byte
}
func (e ipConvertError) Error() string {
return fmt.Sprintf("failed to convert IP '%s' to netip.Addr", e.ip)
}
func ipAddrToNetIP(ip []byte, zone string) (netip.Addr, error) {
netIPAddr, ok := netip.AddrFromSlice(ip)
if !ok {
return netip.Addr{}, ipConvertError{ip}
}
// we'd rather have an IPv4-mapped IPv6 become IPv4 so that it is usable.
netIPAddr = netIPAddr.Unmap()
netIPAddr = addrWithOptionalZone(netIPAddr, zone)
return netIPAddr, nil
}
func createAddr(network NetworkType, ip netip.Addr, port int) net.Addr {
switch {
case network.IsTCP():
return &net.TCPAddr{IP: ip.AsSlice(), Port: port, Zone: ip.Zone()}
default:
return &net.UDPAddr{IP: ip.AsSlice(), Port: port, Zone: ip.Zone()}
}
}
func addrEqual(a, b net.Addr) bool {
aIP, aPort, aType, aErr := parseAddr(a)
if aErr != nil {
return false
}
bIP, bPort, bType, bErr := parseAddr(b)
if bErr != nil {
return false
}
return aType == bType && aIP.Compare(bIP) == 0 && aPort == bPort
}
// AddrPort is an IP and a port number.
type AddrPort [18]byte
func toAddrPort(addr net.Addr) AddrPort {
var ap AddrPort
switch addr := addr.(type) {
case *net.UDPAddr:
copy(ap[:16], addr.IP.To16())
ap[16] = uint8(addr.Port >> 8)
ap[17] = uint8(addr.Port)
case *net.TCPAddr:
copy(ap[:16], addr.IP.To16())
ap[16] = uint8(addr.Port >> 8)
ap[17] = uint8(addr.Port)
}
return ap
}