Skip to content

Commit f0ce914

Browse files
committed
add ip type check v4 or v6 for both external and internal interfaces. refactor code. add comments.
1 parent 0ccaa27 commit f0ce914

File tree

5 files changed

+111
-19
lines changed

5 files changed

+111
-19
lines changed

data/external.go

+13-7
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ import (
1010

1111
// ExternalData struct is a external any api resource where data comes from
1212
type ExternalData struct {
13-
ExtIP string `json:"ip"`
14-
Country string `json:"country"`
15-
CountryCode string `json:"cc"`
16-
Region string `json:"region"`
13+
ExtIP string `json:"ip"`
14+
Country string `json:"country"`
15+
CountryCode string `json:"cc"`
16+
Region string `json:"region"`
17+
IPAddressType IPType
1718
}
1819

1920
// GetExternalIP method get response from url and return new ExternalData struct what is for???
2021
func (e *ExternalData) GetExternalIP(url string, timeout time.Duration) error {
2122

22-
t := time.Duration(timeout)
2323
client := http.Client{
24-
Timeout: t,
24+
Timeout: time.Duration(timeout),
2525
}
2626

2727
resp, err := client.Get(url)
@@ -30,7 +30,7 @@ func (e *ExternalData) GetExternalIP(url string, timeout time.Duration) error {
3030
}
3131
defer resp.Body.Close()
3232

33-
if resp.StatusCode != 200 {
33+
if resp.StatusCode != http.StatusOK {
3434
return errors.New("Bad response (not 200 status) from host!")
3535
}
3636

@@ -44,5 +44,11 @@ func (e *ExternalData) GetExternalIP(url string, timeout time.Duration) error {
4444
return err
4545
}
4646

47+
// add ip address type
48+
ipType, err := getIPType(e.ExtIP)
49+
checkErr(err)
50+
51+
e.IPAddressType = ipType
52+
4753
return nil
4854
}

data/internal.go

+25-10
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ package data
33
import (
44
"errors"
55
"net"
6-
"strings"
76
)
87

98
// InternalData struct is a local adapter and local ip data.
109
type InternalData struct {
11-
AdapterName string
12-
IntIP string
10+
AdapterName string
11+
IntIP string
12+
IPAddressType IPType
1313
}
1414

1515
// GetInternalIP get internal local ip addess.
@@ -31,21 +31,36 @@ func (i *InternalData) GetInternalIP() {
3131
// GetAdapterName get the current local adapter name.
3232
func (i *InternalData) GetAdapterName() {
3333

34-
l, err := net.Interfaces()
34+
// get all network interfaces
35+
networkInterfaces, err := net.Interfaces()
3536
checkErr(err)
3637

37-
for _, f := range l {
38+
// loop through all network interfaces
39+
for _, networkInterface := range networkInterfaces {
3840

39-
byNameInterface, err := net.InterfaceByName(f.Name)
41+
// get interface info
42+
interfaceInfo, err := net.InterfaceByName(networkInterface.Name)
4043
checkErr(err)
4144

42-
addr, err := byNameInterface.Addrs()
45+
addresses, err := interfaceInfo.Addrs()
4346
checkErr(err)
4447

45-
for _, v := range addr {
48+
// loop through all addresses of the current interface
49+
for _, address := range addresses {
4650

47-
if v.String()[:strings.Index(v.String(), "/")] == i.IntIP {
48-
i.AdapterName = f.Name
51+
// parse ip address
52+
ipAddr, _, err := net.ParseCIDR(address.String())
53+
checkErr(err)
54+
55+
// get type of ip address (IPv4 or IPv6)
56+
ipType, err := getIPType(ipAddr.String())
57+
checkErr(err)
58+
59+
// check if ip address match local ip address
60+
if ipAddr.String() == i.IntIP {
61+
i.AdapterName = networkInterface.Name
62+
i.IPAddressType = ipType
63+
return
4964
}
5065
}
5166
}

data/ip_type.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package data
2+
3+
import (
4+
"errors"
5+
"net"
6+
)
7+
8+
type IPType string
9+
10+
const (
11+
IPv4 IPType = "IPv4"
12+
IPv6 IPType = "IPv6"
13+
)
14+
15+
func getIPType(ipStr string) (IPType, error) {
16+
17+
ip := net.ParseIP(ipStr)
18+
if ip == nil {
19+
return "", errors.New("Invalid IP address!")
20+
}
21+
22+
if ip.To4() != nil {
23+
return IPv4, nil
24+
}
25+
return IPv6, nil
26+
}

data/ip_type_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package data
2+
3+
import (
4+
"errors"
5+
"testing"
6+
)
7+
8+
func TestGetIPType(t *testing.T) {
9+
10+
// arrange
11+
tests := []struct {
12+
name string
13+
ipStr string
14+
expected IPType
15+
err error
16+
}{
17+
{"Valid IPv4", "192.168.0.1", IPv4, nil},
18+
{"Valid IPv6", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", IPv6, nil},
19+
{"Invalid IP", "invalid", "", errors.New("Invalid IP address!")},
20+
}
21+
22+
for _, tt := range tests {
23+
24+
t.Run(tt.name, func(t *testing.T) {
25+
26+
// act
27+
ipType, err := getIPType(tt.ipStr)
28+
29+
// assert
30+
if ipType != tt.expected {
31+
t.Errorf("Expected IP type %s, but got %s", tt.expected, ipType)
32+
}
33+
34+
if tt.err != nil {
35+
if err == nil || err.Error() != tt.err.Error() {
36+
t.Errorf("Expected error %s, but got %s", tt.err, err)
37+
}
38+
} else {
39+
if err != nil {
40+
t.Errorf("Expected no error, but got %s", err)
41+
}
42+
}
43+
})
44+
}
45+
}

view/ui.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ var out io.Writer = os.Stdout
1515
// PrintInternal print all internal ip data
1616
func PrintInternal(d *data.IPData) {
1717
color.New(color.FgMagenta).Fprintln(out, "Local interface name:", d.AdapterName)
18-
fmt.Fprintln(out, " Internal IP:", d.IntIP)
18+
fmt.Fprintf(out, " Internal IP (%s): %s \n", d.InternalData.IPAddressType, d.IntIP)
1919
}
2020

2121
// PrintExternal print all external ip data
2222
func PrintExternal(d *data.IPData) {
2323

2424
if d.ExtIP != "" {
25-
color.New(color.FgGreen).Fprintln(out, " External IP:", d.ExtIP)
25+
color.New(color.FgGreen).Fprintf(out, " External IP (%s): %s \n", d.ExternalData.IPAddressType, d.ExtIP)
2626
}
2727

2828
if d.Country != "" {

0 commit comments

Comments
 (0)