-
Notifications
You must be signed in to change notification settings - Fork 10
/
ipaddr.go
executable file
·177 lines (154 loc) · 4.19 KB
/
ipaddr.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package main
import (
"fmt"
"net"
"regexp"
"runtime"
"strings"
"time"
)
var _ = runtime.GOOS
var validIPv4addr = regexp.MustCompile(`^[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+$`)
var privateIPv4addr = regexp.MustCompile(`(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)`)
// IsRoutableIPv4 returns true if the string in ip represents an IPv4 address that is not
// private. See http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
// for the numeric ranges that are private. 127.0.0.1, 192.168.0.1, and 172.16.0.1 are
// examples of non-routables IP addresses.
func IsRoutableIPv4(ip string) bool {
match := privateIPv4addr.FindStringSubmatch(ip)
if match != nil {
return false
}
return true
}
// GetExternalIP tries to determine the external IP address
// used on this host.
func GetExternalIP() string {
//if runtime.GOOS == "windows" {
// return "127.0.0.1"
//}
addrs, err := net.InterfaceAddrs()
if err != nil {
panic(err)
}
valid := []string{}
for _, a := range addrs {
if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
addr := ipnet.IP.String()
match := validIPv4addr.FindStringSubmatch(addr)
if match != nil {
if addr != "127.0.0.1" {
valid = append(valid, addr)
}
}
}
}
switch len(valid) {
case 0:
return "127.0.0.1"
case 1:
return valid[0]
default:
// try to get a routable ip if possible.
for _, ip := range valid {
if IsRoutableIPv4(ip) {
return ip
}
}
// give up, just return the first.
return valid[0]
}
}
// GetExternalIPAsInt calls GetExternalIP() and then converts
// the resulting IPv4 string into an integer.
func GetExternalIPAsInt() int {
s := GetExternalIP()
ip := net.ParseIP(s).To4()
if ip == nil {
return 0
}
sum := 0
for i := 0; i < 4; i++ {
mult := 1 << (8 * uint64(3-i))
//fmt.Printf("mult = %d\n", mult)
sum += int(mult) * int(ip[i])
//fmt.Printf("sum = %d\n", sum)
}
//fmt.Printf("GetExternalIPAsInt() returns %d\n", sum)
return sum
}
// GetAvailPort asks the OS for an unused port.
// There's a race here, where the port could be grabbed by someone else
// before the caller gets to Listen on it, but in practice such races
// are rare. Uses net.Listen("tcp", ":0") to determine a free port, then
// releases it back to the OS with Listener.Close().
func GetAvailPort() int {
l, _ := net.Listen("tcp", ":0")
r := l.Addr()
l.Close()
return r.(*net.TCPAddr).Port
}
// GenAddress generates a local address by calling GetAvailPort() and
// GetExternalIP(), then prefixing them with 'tcp://'.
func GenAddress() string {
port := GetAvailPort()
ip := GetExternalIP()
s := fmt.Sprintf("tcp://%s:%d", ip, port)
//fmt.Printf("GenAddress returning '%s'\n", s)
return s
}
// reduce `tcp://blah:port` to `blah:port`
var validSplitOffProto = regexp.MustCompile(`^[^:]*://(.*)$`)
// StripNanomsgAddressPrefix removes the 'tcp://' prefix from
// nanomsgAddr.
func StripNanomsgAddressPrefix(nanomsgAddr string) (suffix string, err error) {
match := validSplitOffProto.FindStringSubmatch(nanomsgAddr)
if match == nil || len(match) != 2 {
return "", fmt.Errorf("could not strip prefix tcp:// from nanomsg address '%s'", nanomsgAddr)
}
return match[1], nil
}
func WaitUntilCanConnect(addr string) {
stripped, err := StripNanomsgAddressPrefix(addr)
if err != nil {
panic(err)
}
t0 := time.Now()
for {
cn, err := net.Dial("tcp", stripped)
if err != nil {
time.Sleep(50 * time.Millisecond)
continue
}
cn.Close()
break
}
vv("WaitUntilCanConnect finished after %v", time.Since(t0))
}
func removeNetworkPrefix(address string) string {
// Split the address into two parts, at the first occurrence of "://"
parts := strings.SplitN(address, "://", 2)
// If the split resulted in two parts, return the second part (i.e., address without prefix)
if len(parts) == 2 {
return parts[1]
}
// Otherwise, return the original address (no prefix found)
return address
}
// if it needs [] ipv6 brackets, add them
func WrapWithBrackets(local string) string {
if local == "" {
return local
}
if local[0] == '[' {
return local
}
ip := net.ParseIP(local)
if ip != nil {
if ip.To4() == nil {
// is IP v6
return "[" + local + "]"
}
}
return local
}