feat: add ISP query
All checks were successful
CI / deploy (push) Successful in 1m28s

This commit is contained in:
thehrz 2024-08-20 13:38:32 +08:00
parent 4b89a2d18f
commit 063f32fcbb
Signed by: thehrz
GPG Key ID: C84CBCE7D5F88855
10 changed files with 154 additions and 22 deletions

View File

@ -17,8 +17,8 @@ jobs:
with: with:
submodules: true submodules: true
- name: Install Docker # - name: Install Docker
run: curl -fsSL https://get.docker.com | sh # run: curl -fsSL https://get.docker.com | sh
- name: Deploy with Docker - name: Deploy with Docker
run: docker compose up --build --force-recreate -d run: docker compose up --build --force-recreate -d

5
go.mod
View File

@ -5,6 +5,7 @@ go 1.22
require ( require (
github.com/bytedance/sonic v1.12.1 // indirect github.com/bytedance/sonic v1.12.1 // indirect
github.com/bytedance/sonic/loader v0.2.0 // indirect github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/c-robinson/iplib/v2 v2.0.5 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/gabriel-vasile/mimetype v1.4.5 // indirect
@ -18,6 +19,9 @@ require (
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/likexian/gokit v0.25.15 // indirect
github.com/likexian/whois v1.15.4 // indirect
github.com/likexian/whois-parser v1.24.19 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
@ -31,4 +35,5 @@ require (
golang.org/x/text v0.17.0 // indirect golang.org/x/text v0.17.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
) )

10
go.sum
View File

@ -3,6 +3,8 @@ github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKz
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/c-robinson/iplib/v2 v2.0.5 h1:puzVVzXBv9HjZqj8muiSoQwiMvkMwE9dLUaWCZ52S0g=
github.com/c-robinson/iplib/v2 v2.0.5/go.mod h1:ZfjJB+pR8Guy++ylL+OgGzN9dd4jWAE1CszvwVrjlJI=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
@ -35,6 +37,12 @@ github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY=
github.com/likexian/gokit v0.25.15/go.mod h1:S2QisdsxLEHWeD/XI0QMVeggp+jbxYqUxMvSBil7MRg=
github.com/likexian/whois v1.15.4 h1:r5En62c+S9HKFgJtdh2WsdmRGTcxE4WUtGBdZkSBXmM=
github.com/likexian/whois v1.15.4/go.mod h1:rXFTPcQdNlPQBJCQpPWTSIDGzzmgKBftmhdOOcLpwXk=
github.com/likexian/whois-parser v1.24.19 h1:vT8lWhnV8ogkdaYLyef6IvE5VTHVCwlUDG5BUXCx06k=
github.com/likexian/whois-parser v1.24.19/go.mod h1:rAtaofg2luol09H+ogDzGIfcG8ig1NtM5R16uQADDz4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -141,5 +149,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@ -0,0 +1,5 @@
package protocol
type ISPRequest struct {
Address string `json:"address"`
}

View File

@ -1,6 +1,10 @@
package response package protocol
type MyIPResponse struct { type MyIPResponse struct {
Address string `json:"address"` Address string `json:"address"`
Version string `json:"version"` Version string `json:"version"`
} }
type ISPResponse struct {
ISP string `json:"isp"`
}

View File

@ -0,0 +1,17 @@
package protocol
import (
"net"
)
type IPVersion int32
const (
IPv4 IPVersion = 4
IPv6 IPVersion = 6
)
type IP struct {
Address net.IP
Version IPVersion
}

View File

@ -1,25 +1,87 @@
package utils package utils
import ( import (
"encoding/hex"
"errors" "errors"
"fmt"
"ipv6-test-node/internal/pkg/protocol"
"net" "net"
"strings"
) )
const ( func GetIPVersion(ip net.IP) (protocol.IPVersion, error) {
IPv4 = 4 if ip == nil {
IPv6 = 6
)
func GetIPVersion(ip string) (int, error) {
parsedIP := net.ParseIP(ip)
if parsedIP == nil {
return 0, errors.New("invalid IP address") return 0, errors.New("invalid IP address")
} }
if parsedIP.To4() != nil { if ip.To4() != nil {
return IPv4, nil return protocol.IPv4, nil
} else if parsedIP.To16() != nil { } else if ip.To16() != nil {
return IPv6, nil return protocol.IPv6, nil
} else { } else {
return 0, errors.New("invalid IP address") return 0, errors.New("invalid IP address")
} }
} }
func GetASN(ip protocol.IP) (string, error) {
var query string
if ip.Version == 4 {
query = fmt.Sprintf("%sorigin.asn.cymru.com", reverseIPv4(ip.Address))
} else if ip.Version == 6 {
query = fmt.Sprintf("%sorigin6.asn.cymru.com", reverseIPv6(ip.Address))
}
txtRecords, err := net.LookupTXT(query)
if err != nil {
return "", err
}
if len(txtRecords) > 0 {
parts := strings.Split(txtRecords[0], " | ")
if len(parts) > 0 {
return "AS" + parts[0], nil
}
}
return "", fmt.Errorf("ASN not found")
}
func GetISPName(asn string) (string, error) {
query := fmt.Sprintf("%s.asn.cymru.com", asn)
txtRecords, err := net.LookupTXT(query)
if err != nil {
return "", err
}
if len(txtRecords) > 0 {
parts := strings.Split(txtRecords[0], " | ")
if len(parts) > 0 {
return parts[4], nil
}
}
return "", fmt.Errorf("ISP not found")
}
func ToIP(address net.IP) protocol.IP {
version, err := GetIPVersion(address)
if err != nil {
return protocol.IP{}
}
return protocol.IP{Address: address, Version: version}
}
func reverseIPv4(ip net.IP) string {
return fmt.Sprintf("%d.%d.%d.%d.", ip[3], ip[2], ip[1], ip[0])
}
func reverseIPv6(ip net.IP) string {
var dst []byte
dst = make([]byte, hex.EncodedLen(len(ip)))
hex.Encode(dst, ip)
var reversed string
for i := len(dst) - 1; i >= 0; i-- {
reversed = reversed + string(dst[i]) + "."
}
return reversed
}

View File

@ -12,6 +12,7 @@ func Register() *gin.Engine {
ipGroup := g.Group("ip") ipGroup := g.Group("ip")
ipGroup.GET("myip", ip.MyIP) ipGroup.GET("myip", ip.MyIP)
ipGroup.GET("isp", ip.ISP)
return g return g
} }

View File

@ -0,0 +1,29 @@
package ip
import (
"github.com/gin-gonic/gin"
"ipv6-test-node/internal/pkg/protocol"
"ipv6-test-node/internal/pkg/utils"
"net"
"net/http"
)
func ISP(c *gin.Context) {
var req *protocol.ISPRequest
err := c.BindJSON(&req)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
}
asn, err := utils.GetASN(utils.ToIP(net.ParseIP(req.Address)))
if err != nil {
return
}
name, err := utils.GetISPName(asn)
if err != nil {
return
}
c.JSON(http.StatusOK, protocol.ISPResponse{ISP: name})
}

View File

@ -2,19 +2,18 @@ package ip
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"ipv6-test-node/internal/pkg/response" "ipv6-test-node/internal/pkg/protocol"
"ipv6-test-node/internal/pkg/utils" "ipv6-test-node/internal/pkg/utils"
"net"
"net/http" "net/http"
"strconv" "strconv"
) )
func MyIP(c *gin.Context) { func MyIP(c *gin.Context) {
version, err := utils.GetIPVersion(c.ClientIP()) ip := utils.ToIP(net.ParseIP(c.ClientIP()))
if err != nil {
return c.JSON(http.StatusOK, protocol.MyIPResponse{
}
c.JSON(http.StatusOK, response.MyIPResponse{
Address: c.ClientIP(), Address: c.ClientIP(),
Version: strconv.Itoa(version), Version: strconv.Itoa(int(ip.Version)),
}) })
} }