bilibili-backup/library/net/ip/ip.go
2019-04-22 02:59:20 +00:00

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()
}