Skip to content

Commit 2428d68

Browse files
committed
feat(netutil): Add AllLocalIPv4 to get all non-loopback IPv4 addresses
1 parent b7a8632 commit 2428d68

File tree

4 files changed

+156
-106
lines changed

4 files changed

+156
-106
lines changed

netutil/iputil.go

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,112 @@
11
package netutil
22

3-
import "net"
3+
import (
4+
"fmt"
5+
"net"
6+
"os"
7+
)
8+
9+
// AllLocalIPv4 Get all non-loop IPv4 addresses. 获取所有非回环 IPv4 地址
10+
func AllLocalIPv4() ([]string, error) {
11+
addrs, err := net.InterfaceAddrs()
12+
if err != nil {
13+
return nil, err
14+
}
15+
16+
ips := filterIpv4(addrs)
17+
18+
if len(ips) == 0 {
19+
return nil, fmt.Errorf("no IPv4 addresses found")
20+
}
21+
return ips, nil
22+
}
23+
24+
func filterIpv4(addrs []net.Addr) []string {
25+
var ips []string
26+
for _, addr := range addrs {
27+
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
28+
if ip4 := ipnet.IP.To4(); ip4 != nil {
29+
ips = append(ips, ip4.String())
30+
}
31+
}
32+
}
33+
return ips
34+
}
35+
36+
// GetLocalIPs get local IPs(ipv4+ipv6), will panic on error.
37+
func GetLocalIPs() (ips []string) {
38+
addrs, err := net.InterfaceAddrs()
39+
if err != nil {
40+
panic("get local IPs error: " + err.Error())
41+
}
42+
43+
for _, a := range addrs {
44+
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
45+
ips = append(ips, ipNet.IP.String())
46+
}
47+
}
48+
return
49+
}
50+
51+
// InternalIP get local first internal IP v4/v6 addr.
52+
func InternalIP() string { return getLocalIP(0) }
53+
54+
// InternalIPv4 get internal IPv4 for host.
55+
func InternalIPv4() string { return IPv4() }
56+
57+
// IPv4 get local first internal IPv4 addr.
58+
func IPv4() string { return getLocalIP(4) }
59+
60+
// InternalIPv6 get first internal IPv6 addr
61+
func InternalIPv6() string { return IPv6() }
62+
63+
// IPv6 get local first internal IPv6 addr
64+
func IPv6() string { return getLocalIP(6) }
65+
66+
// MustIPv4 get first internal IP v4 addr, will panic on error.
67+
func MustIPv4() (ip string) {
68+
addrs, err := net.InterfaceAddrs()
69+
if err != nil {
70+
panic("MustIPv4: " + err.Error())
71+
}
72+
return getFirstIP(4, addrs)
73+
}
74+
75+
// get local first internal IP v4/v6 addr.
76+
//
77+
// ver: 4, 6 or not limit
78+
func getLocalIP(ver uint8) string {
79+
addrs, err := net.InterfaceAddrs()
80+
if err != nil {
81+
return ""
82+
}
83+
return getFirstIP(ver, addrs)
84+
}
85+
86+
func getFirstIP(ver uint8, addrs []net.Addr) string {
87+
for _, addr := range addrs {
88+
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
89+
// need ip v4
90+
if ver == 4 {
91+
if ip4 := ipnet.IP.To4(); ip4 != nil {
92+
return ip4.String()
93+
}
94+
} else {
95+
return addr.String()
96+
}
97+
}
98+
}
99+
return ""
100+
}
101+
102+
// HostIP returns the IP addresses of the local hostname.
103+
func HostIP() ([]string, error) {
104+
name, err := os.Hostname()
105+
if err != nil {
106+
return nil, err
107+
}
108+
return net.LookupHost(name)
109+
}
4110

5111
// IncrIP 将IP地址递增1 eg: 192.168.1.1 -> 192.168.1.2
6112
func IncrIP(ip net.IP) {
@@ -11,4 +117,3 @@ func IncrIP(ip net.IP) {
11117
}
12118
}
13119
}
14-

netutil/iputil_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,62 @@
11
package netutil_test
22

33
import (
4+
"fmt"
45
"net"
56
"testing"
67

8+
"github.com/gookit/goutil/dump"
79
"github.com/gookit/goutil/netutil"
810
"github.com/gookit/goutil/testutil/assert"
911
)
1012

13+
func TestInternalIP(t *testing.T) {
14+
t.Run("InternalIP", func(t *testing.T) {
15+
ip := netutil.InternalIP()
16+
assert.NotEmpty(t, ip)
17+
dump.P(ip)
18+
})
19+
20+
t.Run("InternalIPv4", func(t *testing.T) {
21+
assert.NotEmpty(t, netutil.MustIPv4())
22+
23+
ipv4 := netutil.InternalIPv4()
24+
assert.NotEmpty(t, ipv4)
25+
dump.P(ipv4)
26+
})
27+
28+
t.Run("InternalIPv6", func(t *testing.T) {
29+
ipv6 := netutil.InternalIPv6()
30+
assert.NotEmpty(t, ipv6)
31+
dump.P(ipv6)
32+
})
33+
34+
t.Run("AllLocalIPv4", func(t *testing.T) {
35+
ips, err := netutil.AllLocalIPv4()
36+
assert.NoError(t, err)
37+
assert.NotEmpty(t, ips)
38+
dump.P(ips)
39+
})
40+
41+
t.Run("GetLocalIPs", func(t *testing.T) {
42+
ips := netutil.GetLocalIPs()
43+
assert.NotEmpty(t, ips)
44+
dump.P(ips)
45+
})
46+
}
47+
48+
func TestHostIP(t *testing.T) {
49+
addrs, err := netutil.HostIP()
50+
if err != nil {
51+
t.Skip("skip test for error: " + err.Error())
52+
return
53+
}
54+
55+
assert.NoError(t, err)
56+
assert.NotEmpty(t, addrs)
57+
fmt.Println(addrs)
58+
}
59+
1160
func TestIncrIP(t *testing.T) {
1261
ip := net.IP{192, 168, 1, 1}
1362
netutil.IncrIP(ip)

netutil/netutil.go

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3,91 +3,8 @@ package netutil
33

44
import (
55
"net"
6-
"net/netip"
7-
"os"
86
)
97

10-
// InternalIPv1 get internal IP buy old logic
11-
func InternalIPv1() (ip string) {
12-
addrs, err := net.InterfaceAddrs()
13-
if err != nil {
14-
panic("Oops: " + err.Error())
15-
}
16-
17-
for _, a := range addrs {
18-
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
19-
if ipNet.IP.To4() != nil {
20-
ip = ipNet.IP.String()
21-
return
22-
}
23-
}
24-
}
25-
return
26-
}
27-
28-
// GetLocalIPs get local IPs, will panic if error.
29-
func GetLocalIPs() (ips []string) {
30-
addrs, err := net.InterfaceAddrs()
31-
if err != nil {
32-
panic("get local IPs error: " + err.Error())
33-
}
34-
35-
for _, a := range addrs {
36-
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
37-
ips = append(ips, ipNet.IP.String())
38-
}
39-
}
40-
return
41-
}
42-
43-
// InternalIP get internal IP for host.
44-
func InternalIP() (ip string) {
45-
addr := netip.IPv4Unspecified()
46-
if addr.IsValid() {
47-
return addr.String()
48-
}
49-
50-
addr = netip.IPv6Unspecified()
51-
if addr.IsValid() {
52-
return addr.String()
53-
}
54-
return ""
55-
}
56-
57-
// InternalIPv4 get internal IPv4 for host.
58-
func InternalIPv4() string { return IPv4() }
59-
60-
// IPv4 get internal IPv4 for host.
61-
func IPv4() (ip string) {
62-
addr := netip.IPv4Unspecified()
63-
if addr.IsValid() {
64-
return addr.String()
65-
}
66-
return ""
67-
}
68-
69-
// InternalIPv6 get internal IPv6
70-
func InternalIPv6() string { return IPv6() }
71-
72-
// IPv6 get internal IPv6
73-
func IPv6() (ip string) {
74-
addr := netip.IPv6Unspecified()
75-
if addr.IsValid() {
76-
return addr.String()
77-
}
78-
return ""
79-
}
80-
81-
// HostIP returns the IP addresses of the localhost.
82-
func HostIP() ([]string, error) {
83-
name, err := os.Hostname()
84-
if err != nil {
85-
return nil, err
86-
}
87-
88-
return net.LookupHost(name)
89-
}
90-
918
// FreePort returns a free port.
929
func FreePort() (port int, err error) {
9310
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")

netutil/netutil_test.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,12 @@
11
package netutil_test
22

33
import (
4-
"fmt"
54
"testing"
65

76
"github.com/gookit/goutil/netutil"
87
"github.com/gookit/goutil/testutil/assert"
98
)
109

11-
func TestInternalIP(t *testing.T) {
12-
assert.NotEmpty(t, netutil.InternalIPv1())
13-
assert.NotEmpty(t, netutil.InternalIP())
14-
assert.NotEmpty(t, netutil.InternalIPv4())
15-
assert.NotEmpty(t, netutil.InternalIPv6())
16-
assert.NotEmpty(t, netutil.GetLocalIPs())
17-
}
18-
19-
func TestHostIP(t *testing.T) {
20-
addrs, err := netutil.HostIP()
21-
if err != nil {
22-
t.Skip("skip test for error: " + err.Error())
23-
return
24-
}
25-
26-
assert.NoError(t, err)
27-
assert.NotEmpty(t, addrs)
28-
fmt.Println(addrs)
29-
}
30-
3110
func TestFreePort(t *testing.T) {
3211
port, err := netutil.FreePort()
3312
assert.NoError(t, err)

0 commit comments

Comments
 (0)