Skip to content

Commit dd5e713

Browse files
authored
RF: getIP (#46)
1 parent d9e2e28 commit dd5e713

File tree

6 files changed

+108
-37
lines changed

6 files changed

+108
-37
lines changed

checks/checks.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
type Checks struct {
1111
Carbon *Carbon
12+
IpAddress *Ip
1213
LegacyRank *LegacyRank
1314
Rank *Rank
1415
SocialTags *SocialTags
@@ -21,6 +22,7 @@ func NewChecks() *Checks {
2122
}
2223
return &Checks{
2324
Carbon: NewCarbon(client),
25+
IpAddress: NewIp(NewNetIp()),
2426
LegacyRank: NewLegacyRank(legacyrank.NewInMemoryStore()),
2527
Rank: NewRank(client),
2628
SocialTags: NewSocialTags(client),

checks/getIP.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package checks
2+
3+
import (
4+
"context"
5+
"net"
6+
)
7+
8+
type IpAddress struct {
9+
Address net.IP `json:"ip"`
10+
Family int `json:"family"`
11+
}
12+
13+
type IpGetter interface {
14+
GetIp(ctx context.Context, host string) ([]IpAddress, error)
15+
}
16+
17+
type IpGetterFunc func(ctx context.Context, host string) ([]IpAddress, error)
18+
19+
func (f IpGetterFunc) GetIp(ctx context.Context, host string) ([]IpAddress, error) {
20+
return f(ctx, host)
21+
}
22+
23+
type NetIp struct{}
24+
25+
func NewNetIp() *NetIp {
26+
return &NetIp{}
27+
}
28+
29+
func (l *NetIp) GetIp(ctx context.Context, host string) ([]IpAddress, error) {
30+
resolver := &net.Resolver{
31+
PreferGo: true,
32+
}
33+
ip4, err := resolver.LookupIP(ctx, "ip4", host)
34+
if err != nil {
35+
return nil, err
36+
}
37+
ip6, err := resolver.LookupIP(ctx, "ip6", host)
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
var ipAddresses []IpAddress
43+
for _, ip := range ip4 {
44+
ipAddresses = append(ipAddresses, IpAddress{Address: ip, Family: 4})
45+
}
46+
for _, ip := range ip6 {
47+
ipAddresses = append(ipAddresses, IpAddress{Address: ip, Family: 6})
48+
}
49+
50+
return ipAddresses, nil
51+
}
52+
53+
type Ip struct {
54+
getter IpGetter
55+
}
56+
57+
func NewIp(l IpGetter) *Ip {
58+
return &Ip{getter: l}
59+
}
60+
61+
func (i *Ip) Lookup(ctx context.Context, host string) ([]IpAddress, error) {
62+
return i.getter.GetIp(ctx, host)
63+
}

checks/getIP_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package checks
2+
3+
import (
4+
"context"
5+
"net"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestLookup(t *testing.T) {
12+
t.Parallel()
13+
14+
ipAddresses := []IpAddress{
15+
{net.ParseIP("216.58.201.110"), 4},
16+
{net.ParseIP("2a00:1450:4009:826::200e"), 6},
17+
}
18+
i := NewIp(IpGetterFunc(func(ctx context.Context, host string) ([]IpAddress, error) {
19+
return ipAddresses, nil
20+
}))
21+
actual, err := i.Lookup(context.Background(), "google.com")
22+
assert.NoError(t, err)
23+
24+
assert.Equal(t, ipAddresses[0].Address, actual[0].Address)
25+
assert.Equal(t, 4, actual[0].Family)
26+
27+
assert.Equal(t, ipAddresses[1].Address, actual[1].Address)
28+
assert.Equal(t, 6, actual[1].Family)
29+
}

handlers/getIP.go

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,20 @@
11
package handlers
22

33
import (
4-
"net"
54
"net/http"
6-
)
7-
8-
func lookupAsync(address string) (map[string]interface{}, error) {
9-
ip, err := net.LookupIP(address)
10-
if err != nil {
11-
return nil, err
12-
}
13-
14-
result := make(map[string]interface{})
15-
if len(ip) > 0 {
16-
result["ip"] = ip[0].String()
17-
result["family"] = 4
18-
} else {
19-
result["ip"] = ""
20-
result["family"] = nil
21-
}
225

23-
return result, nil
24-
}
6+
"github.com/xray-web/web-check-api/checks"
7+
)
258

26-
func HandleGetIP() http.Handler {
9+
func HandleGetIP(i *checks.Ip) http.Handler {
2710
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2811
rawURL, err := extractURL(r)
2912
if err != nil {
3013
JSONError(w, ErrMissingURLParameter, http.StatusBadRequest)
3114
return
3215
}
3316

34-
result, err := lookupAsync(rawURL.Hostname())
17+
result, err := i.Lookup(r.Context(), rawURL.Hostname())
3518
if err != nil {
3619
JSONError(w, err, http.StatusInternalServerError)
3720
return

handlers/getIP_test.go

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package handlers
22

33
import (
4-
"encoding/json"
54
"net/http"
65
"net/http/httptest"
76
"testing"
@@ -10,21 +9,16 @@ import (
109
)
1110

1211
func TestHandleGetIP(t *testing.T) {
13-
req := httptest.NewRequest("GET", "/get-ip?url=example.com", nil)
14-
rec := httptest.NewRecorder()
15-
HandleGetIP().ServeHTTP(rec, req)
12+
t.Parallel()
1613

17-
assert.Equal(t, http.StatusOK, rec.Code)
14+
t.Run("missing URL parameter", func(t *testing.T) {
15+
t.Parallel()
16+
req := httptest.NewRequest(http.MethodGet, "/get-ip", nil)
17+
rec := httptest.NewRecorder()
1818

19-
var response map[string]interface{}
20-
err := json.Unmarshal(rec.Body.Bytes(), &response)
21-
assert.NoError(t, err)
19+
HandleGetIP(nil).ServeHTTP(rec, req)
2220

23-
ip, ok := response["ip"].(string)
24-
assert.True(t, ok, "IP address not found in response")
25-
assert.NotEmpty(t, ip, "IP address is empty")
26-
27-
family, ok := response["family"].(float64)
28-
assert.True(t, ok, "Family field not found in response")
29-
assert.Equal(t, float64(4), family, "Family field should be 4")
21+
assert.Equal(t, http.StatusBadRequest, rec.Code)
22+
assert.JSONEq(t, `{"error": "missing URL parameter"}`, rec.Body.String())
23+
})
3024
}

server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (s *Server) routes() {
3636
s.mux.Handle("GET /api/dns", handlers.HandleDNS())
3737
s.mux.Handle("GET /api/dnssec", handlers.HandleDnsSec())
3838
s.mux.Handle("GET /api/firewall", handlers.HandleFirewall())
39-
s.mux.Handle("GET /api/get-ip", handlers.HandleGetIP())
39+
s.mux.Handle("GET /api/get-ip", handlers.HandleGetIP(s.checks.IpAddress))
4040
s.mux.Handle("GET /api/headers", handlers.HandleGetHeaders())
4141
s.mux.Handle("GET /api/hsts", handlers.HandleHsts())
4242
s.mux.Handle("GET /api/http-security", handlers.HandleHttpSecurity())

0 commit comments

Comments
 (0)