github.com/aaabigfish/gopkg@v1.1.0/net/ip/ip.go (about)

     1  package ip
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  	"net"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  // IP ip struct info.
    13  type IP struct {
    14  	Begin        uint32
    15  	End          uint32
    16  	ISPCode      int
    17  	ISP          string
    18  	CountryCode  int
    19  	Country      string
    20  	ProvinceCode int
    21  	Province     string
    22  	CityCode     int
    23  	City         string
    24  	DistrictCode int
    25  	District     string
    26  	Latitude     float64
    27  	Longitude    float64
    28  }
    29  
    30  // Zone ip struct info.
    31  type Zone struct {
    32  	ID          int64   `json:"id"`
    33  	Addr        string  `json:"addr"`
    34  	ISP         string  `json:"isp"`
    35  	Country     string  `json:"country"`
    36  	Province    string  `json:"province"`
    37  	City        string  `json:"city"`
    38  	Latitude    float64 `json:"latitude"`
    39  	Longitude   float64 `json:"longitude"`
    40  	CountryCode int     `json:"country_code,omitempty"`
    41  }
    42  
    43  // List struct info list.
    44  type List struct {
    45  	IPs []*IP
    46  }
    47  
    48  // New create Xip instance and return.
    49  func New(path string) (list *List, err error) {
    50  	var (
    51  		ip   *IP
    52  		file *os.File
    53  		line []byte
    54  	)
    55  	list = new(List)
    56  	if file, err = os.Open(path); err != nil {
    57  		return
    58  	}
    59  	defer file.Close()
    60  	reader := bufio.NewReader(file)
    61  	for {
    62  		if line, _, err = reader.ReadLine(); err != nil {
    63  			if err == io.EOF {
    64  				err = nil
    65  				break
    66  			}
    67  			continue
    68  		}
    69  		lines := strings.Fields(string(line))
    70  		if len(lines) < 13 {
    71  			continue
    72  		}
    73  		// lines[2]:country  lines[3]:province  lines[4]:city  lines[5]:unit
    74  		if lines[3] == "香港" || lines[3] == "澳门" || lines[3] == "台湾" {
    75  			lines[2] = lines[3]
    76  			lines[3] = lines[4]
    77  			lines[4] = "*"
    78  		}
    79  		// ex.: from 中国 中国 *  to 中国 ”“ ”“
    80  		if lines[2] == lines[3] || lines[3] == "*" {
    81  			lines[3] = ""
    82  			lines[4] = ""
    83  		} else if lines[3] == lines[4] || lines[4] == "*" {
    84  			// ex.: from 中国 北京 北京  to 中国 北京 ”“
    85  			lines[4] = ""
    86  		}
    87  		ip = &IP{
    88  			Begin:    InetAtoN(lines[0]),
    89  			End:      InetAtoN(lines[1]),
    90  			Country:  lines[2],
    91  			Province: lines[3],
    92  			City:     lines[4],
    93  			ISP:      lines[6],
    94  		}
    95  		ip.Latitude, _ = strconv.ParseFloat(lines[7], 64)
    96  		ip.Longitude, _ = strconv.ParseFloat(lines[8], 64)
    97  		ip.CountryCode, _ = strconv.Atoi(lines[12])
    98  		list.IPs = append(list.IPs, ip)
    99  	}
   100  	return
   101  }
   102  
   103  // IP ip zone info by ip
   104  func (l *List) IP(ipStr string) (ip *IP) {
   105  	addr := InetAtoN(ipStr)
   106  	i, j := 0, len(l.IPs)
   107  	for i < j {
   108  		h := i + (j-i)/2 // avoid overflow when computing h
   109  		ip = l.IPs[h]
   110  		// i ≤ h < j
   111  		if addr < ip.Begin {
   112  			j = h
   113  		} else if addr > ip.End {
   114  			i = h + 1
   115  		} else {
   116  			break
   117  		}
   118  	}
   119  	return
   120  }
   121  
   122  // Zone get ip info from ip
   123  func (l *List) Zone(addr string) (zone *Zone) {
   124  	ip := l.IP(addr)
   125  	if ip == nil {
   126  		return
   127  	}
   128  	return &Zone{
   129  		ID:          ZoneID(ip.Country, ip.Province, ip.City),
   130  		Addr:        addr,
   131  		ISP:         ip.ISP,
   132  		Country:     ip.Country,
   133  		Province:    ip.Province,
   134  		City:        ip.City,
   135  		Latitude:    ip.Latitude,
   136  		Longitude:   ip.Longitude,
   137  		CountryCode: ip.CountryCode,
   138  	}
   139  }
   140  
   141  // All return ipInfos.
   142  func (l *List) All() []*IP {
   143  	return l.IPs
   144  }
   145  
   146  // ExternalIP get external ip.
   147  func ExternalIP() (res []string) {
   148  	inters, err := net.Interfaces()
   149  	if err != nil {
   150  		return
   151  	}
   152  	for _, inter := range inters {
   153  		if !strings.HasPrefix(inter.Name, "lo") {
   154  			addrs, err := inter.Addrs()
   155  			if err != nil {
   156  				continue
   157  			}
   158  			for _, addr := range addrs {
   159  				if ipnet, ok := addr.(*net.IPNet); ok {
   160  					if ipnet.IP.IsLoopback() || ipnet.IP.IsLinkLocalMulticast() || ipnet.IP.IsLinkLocalUnicast() {
   161  						continue
   162  					}
   163  					if ip4 := ipnet.IP.To4(); ip4 != nil {
   164  						switch true {
   165  						case ip4[0] == 10:
   166  							continue
   167  						case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
   168  							continue
   169  						case ip4[0] == 192 && ip4[1] == 168:
   170  							continue
   171  						default:
   172  							res = append(res, ipnet.IP.String())
   173  						}
   174  					}
   175  				}
   176  			}
   177  		}
   178  	}
   179  	return
   180  }
   181  
   182  // InternalIP get internal ip.
   183  func InternalIP() string {
   184  	inters, err := net.Interfaces()
   185  	if err != nil {
   186  		return ""
   187  	}
   188  	for _, inter := range inters {
   189  		if !strings.HasPrefix(inter.Name, "lo") {
   190  			addrs, err := inter.Addrs()
   191  			if err != nil {
   192  				continue
   193  			}
   194  			for _, addr := range addrs {
   195  				if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
   196  					if ipnet.IP.To4() != nil {
   197  						return ipnet.IP.String()
   198  					}
   199  				}
   200  			}
   201  		}
   202  	}
   203  	return ""
   204  }
   205  
   206  // InetAtoN conver ip addr to uint32.
   207  func InetAtoN(s string) (sum uint32) {
   208  	ip := net.ParseIP(s)
   209  	if ip == nil {
   210  		return
   211  	}
   212  	ip = ip.To4()
   213  	if ip == nil {
   214  		return
   215  	}
   216  	sum += uint32(ip[0]) << 24
   217  	sum += uint32(ip[1]) << 16
   218  	sum += uint32(ip[2]) << 8
   219  	sum += uint32(ip[3])
   220  	return sum
   221  }
   222  
   223  // InetNtoA conver uint32 to ip addr.
   224  func InetNtoA(sum uint32) string {
   225  	ip := make(net.IP, net.IPv4len)
   226  	ip[0] = byte((sum >> 24) & 0xFF)
   227  	ip[1] = byte((sum >> 16) & 0xFF)
   228  	ip[2] = byte((sum >> 8) & 0xFF)
   229  	ip[3] = byte(sum & 0xFF)
   230  	return ip.String()
   231  }