182 lines
3.7 KiB
Go
Raw Normal View History

2021-11-22 16:05:02 +00:00
package x
import (
"encoding/binary"
"errors"
"net"
"strconv"
"strings"
)
// IP2Decimal0 transform ip format like x.x.x.x to decimal.
// ref: https://zh.wikipedia.org/wiki/IPv4
func IP2Decimal0(ip string) (n int64, err error) {
ss := strings.Split(ip, ".")
var b string
var s string
var i int64
if len(ss) != 4 {
err = errors.New("IP Invalid")
return
}
for _, s = range ss {
i, err = strconv.ParseInt(s, 10, 64)
if err != nil {
return
}
s = strconv.FormatInt(i, 2)
var j int
need := 8 - len(s)
for j = 0; j < need; j++ {
s = "0" + s
}
b += s
}
n, _ = strconv.ParseInt(b, 2, 64)
return
}
// IP2Decimal1 transform ip format like x.x.x.x to decimal.
func IP2Decimal1(ipstr string) (int64, error) {
ip := net.ParseIP(ipstr)
if ip == nil {
return 0, errors.New("ParseIP error")
}
// ip is 16 bytes, but ipv4 is only in last 4 bytes
d := uint32(ip[12])<<24 | uint32(ip[13])<<16 | uint32(ip[14])<<8 | uint32(ip[15])
return int64(d), nil
}
// IP2Decimal transform ip format like x.x.x.x to decimal.
func IP2Decimal(ipstr string) (int64, error) {
ip := net.ParseIP(ipstr)
if ip == nil {
return 0, errors.New("ParseIP error")
}
// ip is 16 bytes, but ipv4 is only in last 4 bytes
d := binary.BigEndian.Uint32(ip[12:16])
return int64(d), nil
}
// Decimal2IP0 transform a decimal IP to x.x.x.x format.
// ref: https://zh.wikipedia.org/wiki/IPv4
func Decimal2IP0(n int64) (ip string, err error) {
ips := make([]string, 4)
var b string
var i int64
b = strconv.FormatInt(n, 2)
need := 32 - len(b)
var j int
for j = 0; j < need; j++ {
b = "0" + b
}
i, _ = strconv.ParseInt(b[0:8], 2, 64)
ips[0] = strconv.FormatInt(i, 10)
i, _ = strconv.ParseInt(b[8:16], 2, 64)
ips[1] = strconv.FormatInt(i, 10)
i, _ = strconv.ParseInt(b[16:24], 2, 64)
ips[2] = strconv.FormatInt(i, 10)
i, _ = strconv.ParseInt(b[24:32], 2, 64)
ips[3] = strconv.FormatInt(i, 10)
ip = strings.Join(ips, ".")
return
}
// Decimal2IP1 transform a decimal IP to x.x.x.x format.
func Decimal2IP1(n int64) string {
ui := uint32(n)
ip := ""
for i := 0; i < 4; i++ {
offset := 8 * (3 - i)
tmp := (ui >> uint32(offset)) & 0xff
if ip != "" {
ip += "."
}
ip += strconv.Itoa(int(tmp))
}
return ip
}
// Decimal2IP transform a decimal IP to x.x.x.x format.
func Decimal2IP(n int64) string {
ip := make(net.IP, 4)
binary.BigEndian.PutUint32(ip, uint32(n))
return ip.String()
}
// CIDRInfo is the struct of CIDR
type CIDRInfo struct {
First string
Last string
Block int64
Network string
Count int64
}
// CIDR return *CIDRInfo from like this x.x.x.x/x
// ref: http://goo.gl/AEUIi8
func CIDR(cidr string) (c *CIDRInfo, err error) {
c = new(CIDRInfo)
cs := strings.Split(cidr, "/")
if len(cs) != 2 {
err = errors.New("CIDR Invalid")
return
}
var ipd int64
ipd, err = IP2Decimal(cs[0])
if err != nil {
return
}
var ipb string
ipb = strconv.FormatInt(ipd, 2)
need := 32 - len(ipb)
var j int
for j = 0; j < need; j++ {
ipb = "0" + ipb
}
var n int64
n, err = strconv.ParseInt(cs[1], 10, 64)
if err != nil {
return
}
if n < 0 || n > 32 {
err = errors.New("CIDR Invalid")
return
}
c.Block = n
var network string
var networkI int64
for j = 0; j < int(n); j++ {
network += "1"
}
for j = 0; j < 32-int(n); j++ {
network += "0"
}
networkI, _ = strconv.ParseInt(network, 2, 64)
network = Decimal2IP(networkI)
c.Network = network
first := ipb[0:n]
var firstI int64
for j = 0; j < 32-int(n); j++ {
first = first + "0"
}
firstI, _ = strconv.ParseInt(first, 2, 64)
first = Decimal2IP(firstI)
c.First = first
last := ipb[0:n]
var lastI int64
for j = 0; j < 32-int(n); j++ {
last = last + "1"
}
lastI, _ = strconv.ParseInt(last, 2, 64)
last = Decimal2IP(lastI)
c.Last = last
c.Count = lastI - firstI + 1
return
}