232 lines
4.7 KiB
Go
232 lines
4.7 KiB
Go
package ip
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// IP ip struct info.
|
|
type IP struct {
|
|
Begin uint32
|
|
End uint32
|
|
ISPCode int
|
|
ISP string
|
|
CountryCode int
|
|
Country string
|
|
ProvinceCode int
|
|
Province string
|
|
CityCode int
|
|
City string
|
|
DistrictCode int
|
|
District string
|
|
Latitude float64
|
|
Longitude float64
|
|
}
|
|
|
|
// Zone ip struct info.
|
|
type Zone struct {
|
|
ID int64 `json:"id"`
|
|
Addr string `json:"addr"`
|
|
ISP string `json:"isp"`
|
|
Country string `json:"country"`
|
|
Province string `json:"province"`
|
|
City string `json:"city"`
|
|
Latitude float64 `json:"latitude"`
|
|
Longitude float64 `json:"longitude"`
|
|
CountryCode int `json:"country_code,omitempty"`
|
|
}
|
|
|
|
// List struct info list.
|
|
type List struct {
|
|
IPs []*IP
|
|
}
|
|
|
|
// New create Xip instance and return.
|
|
func New(path string) (list *List, err error) {
|
|
var (
|
|
ip *IP
|
|
file *os.File
|
|
line []byte
|
|
)
|
|
list = new(List)
|
|
if file, err = os.Open(path); err != nil {
|
|
return
|
|
}
|
|
defer file.Close()
|
|
reader := bufio.NewReader(file)
|
|
for {
|
|
if line, _, err = reader.ReadLine(); err != nil {
|
|
if err == io.EOF {
|
|
err = nil
|
|
break
|
|
}
|
|
continue
|
|
}
|
|
lines := strings.Fields(string(line))
|
|
if len(lines) < 13 {
|
|
continue
|
|
}
|
|
// lines[2]:country lines[3]:province lines[4]:city lines[5]:unit
|
|
if lines[3] == "香港" || lines[3] == "澳门" || lines[3] == "台湾" {
|
|
lines[2] = lines[3]
|
|
lines[3] = lines[4]
|
|
lines[4] = "*"
|
|
}
|
|
// ex.: from 中国 中国 * to 中国 ”“ ”“
|
|
if lines[2] == lines[3] || lines[3] == "*" {
|
|
lines[3] = ""
|
|
lines[4] = ""
|
|
} else if lines[3] == lines[4] || lines[4] == "*" {
|
|
// ex.: from 中国 北京 北京 to 中国 北京 ”“
|
|
lines[4] = ""
|
|
}
|
|
ip = &IP{
|
|
Begin: InetAtoN(lines[0]),
|
|
End: InetAtoN(lines[1]),
|
|
Country: lines[2],
|
|
Province: lines[3],
|
|
City: lines[4],
|
|
ISP: lines[6],
|
|
}
|
|
ip.Latitude, _ = strconv.ParseFloat(lines[7], 64)
|
|
ip.Longitude, _ = strconv.ParseFloat(lines[8], 64)
|
|
ip.CountryCode, _ = strconv.Atoi(lines[12])
|
|
list.IPs = append(list.IPs, ip)
|
|
}
|
|
return
|
|
}
|
|
|
|
// IP ip zone info by ip
|
|
func (l *List) IP(ipStr string) (ip *IP) {
|
|
addr := InetAtoN(ipStr)
|
|
i, j := 0, len(l.IPs)
|
|
for i < j {
|
|
h := i + (j-i)/2 // avoid overflow when computing h
|
|
ip = l.IPs[h]
|
|
// i ≤ h < j
|
|
if addr < ip.Begin {
|
|
j = h
|
|
} else if addr > ip.End {
|
|
i = h + 1
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Zone get ip info from ip
|
|
func (l *List) Zone(addr string) (zone *Zone) {
|
|
ip := l.IP(addr)
|
|
if ip == nil {
|
|
return
|
|
}
|
|
return &Zone{
|
|
ID: ZoneID(ip.Country, ip.Province, ip.City),
|
|
Addr: addr,
|
|
ISP: ip.ISP,
|
|
Country: ip.Country,
|
|
Province: ip.Province,
|
|
City: ip.City,
|
|
Latitude: ip.Latitude,
|
|
Longitude: ip.Longitude,
|
|
CountryCode: ip.CountryCode,
|
|
}
|
|
}
|
|
|
|
// All return ipInfos.
|
|
func (l *List) All() []*IP {
|
|
return l.IPs
|
|
}
|
|
|
|
// ExternalIP get external ip.
|
|
func ExternalIP() (res []string) {
|
|
inters, err := net.Interfaces()
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, inter := range inters {
|
|
if !strings.HasPrefix(inter.Name, "lo") {
|
|
addrs, err := inter.Addrs()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, addr := range addrs {
|
|
if ipnet, ok := addr.(*net.IPNet); ok {
|
|
if ipnet.IP.IsLoopback() || ipnet.IP.IsLinkLocalMulticast() || ipnet.IP.IsLinkLocalUnicast() {
|
|
continue
|
|
}
|
|
if ip4 := ipnet.IP.To4(); ip4 != nil {
|
|
switch true {
|
|
case ip4[0] == 10:
|
|
continue
|
|
case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
|
|
continue
|
|
case ip4[0] == 192 && ip4[1] == 168:
|
|
continue
|
|
default:
|
|
res = append(res, ipnet.IP.String())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// InternalIP get internal ip.
|
|
func InternalIP() string {
|
|
inters, err := net.Interfaces()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
for _, inter := range inters {
|
|
if !strings.HasPrefix(inter.Name, "lo") {
|
|
addrs, err := inter.Addrs()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, addr := range addrs {
|
|
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
if ipnet.IP.To4() != nil {
|
|
return ipnet.IP.String()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// InetAtoN conver ip addr to uint32.
|
|
func InetAtoN(s string) (sum uint32) {
|
|
ip := net.ParseIP(s)
|
|
if ip == nil {
|
|
return
|
|
}
|
|
ip = ip.To4()
|
|
if ip == nil {
|
|
return
|
|
}
|
|
sum += uint32(ip[0]) << 24
|
|
sum += uint32(ip[1]) << 16
|
|
sum += uint32(ip[2]) << 8
|
|
sum += uint32(ip[3])
|
|
return sum
|
|
}
|
|
|
|
// InetNtoA conver uint32 to ip addr.
|
|
func InetNtoA(sum uint32) string {
|
|
ip := make(net.IP, net.IPv4len)
|
|
ip[0] = byte((sum >> 24) & 0xFF)
|
|
ip[1] = byte((sum >> 16) & 0xFF)
|
|
ip[2] = byte((sum >> 8) & 0xFF)
|
|
ip[3] = byte(sum & 0xFF)
|
|
return ip.String()
|
|
}
|