diff --git a/net/cidr/range-v4.go b/net/cidr/range-v4.go new file mode 100644 index 0000000..6bbf41c --- /dev/null +++ b/net/cidr/range-v4.go @@ -0,0 +1,128 @@ +package cidr + +import ( + "fmt" + "net" + + "git.loafle.net/overflow/util-go/net/converter" +) + +type cidrRangeIPv4 struct { + cidrNet *net.IPNet +} + +func (cr *cidrRangeIPv4) Contains(ip net.IP) bool { + return cr.cidrNet.Contains(ip) +} + +func (cr *cidrRangeIPv4) First() net.IP { + nIP := cr.Network() + return cr.Next(nIP) +} + +func (cr *cidrRangeIPv4) Last() net.IP { + bIP := cr.Broadcast() + return cr.Previous(bIP) +} + +func (cr *cidrRangeIPv4) Range() []net.IP { + fIP := cr.First() + if nil == fIP { + return nil + } + lIP := cr.Last() + if nil == lIP { + return nil + } + fNum := converter.IPv4ToInt(fIP.To4()) + lNum := converter.IPv4ToInt(lIP.To4()) + + r := make([]net.IP, 0) + for i := fNum; i <= lNum; i++ { + r = append(r, converter.IntToIPv4(i)) + } + return r +} + +// (!Contains(startIP) || !Contains(endIP)) return nil +// (startIP > endIP) return nil +// (nil != startIP && nil != endIP) return (startIP ~ endIP) + include - exclude +// (nil == startIP || nil == endIP) return include - exclude +func (cr *cidrRangeIPv4) Ranges(startIP net.IP, endIP net.IP, include []net.IP, exclude []net.IP) ([]net.IP, error) { + + res := make(map[int32]bool) + + if nil != startIP && nil != endIP { + if !cr.Contains(startIP) { + return nil, fmt.Errorf("CIDR Range: CIDR not contains start ip[%v]", startIP) + } + if !cr.Contains(endIP) { + return nil, fmt.Errorf("CIDR Range: CIDR not contains end ip[%v]", endIP) + } + sNum := converter.IPv4ToInt(startIP.To4()) + eNum := converter.IPv4ToInt(endIP.To4()) + if sNum > eNum { + return nil, fmt.Errorf("CIDR Range: Start IP[%v] must smaller then End IP[%v]", startIP, endIP) + } + for i := sNum; i <= eNum; i++ { + res[i] = true + } + } + + if nil != include { + for _, in := range include { + iNum := converter.IPv4ToInt(in.To4()) + if _, ok := res[iNum]; !ok { + res[iNum] = true + } + } + } + + if nil != exclude { + for _, ex := range exclude { + iNum := converter.IPv4ToInt(ex.To4()) + if _, ok := res[iNum]; ok { + delete(res, iNum) + } + } + } + + r := make([]net.IP, 0) + for k, _ := range res { + r = append(r, converter.IntToIPv4(k)) + } + + return r, nil +} + +func (cr *cidrRangeIPv4) Broadcast() net.IP { + ip := cr.cidrNet.IP.To4() + bIP := net.IPv4(0, 0, 0, 0).To4() + for i := 0; i < len(bIP); i++ { + bIP[i] = ip[i] | ^cr.cidrNet.Mask[i] + } + return bIP +} + +func (cr *cidrRangeIPv4) Network() net.IP { + ip := cr.cidrNet.IP.To4() + return ip.Mask(cr.cidrNet.Mask) +} + +func (cr *cidrRangeIPv4) Next(ip net.IP) net.IP { + nNum := converter.IPv4ToInt(ip.To4()) + 1 + nIP := converter.IntToIPv4(nNum) + if cr.Contains(nIP) { + return nIP + } + return nil +} + +func (cr *cidrRangeIPv4) Previous(ip net.IP) net.IP { + nNum := converter.IPv4ToInt(ip.To4()) - 1 + nIP := converter.IntToIPv4(nNum) + if cr.Contains(nIP) { + return nIP + } + return nil +} diff --git a/net/cidr/range-v6.go b/net/cidr/range-v6.go new file mode 100644 index 0000000..440ad0b --- /dev/null +++ b/net/cidr/range-v6.go @@ -0,0 +1,43 @@ +package cidr + +import "net" + +type cidrRangeIPv6 struct { + cidrNet *net.IPNet +} + +func (cr *cidrRangeIPv6) Contains(ip net.IP) bool { + return cr.cidrNet.Contains(ip) +} + +func (cr *cidrRangeIPv6) First() net.IP { + return nil +} + +func (cr *cidrRangeIPv6) Last() net.IP { + return nil +} + +func (cr *cidrRangeIPv6) Range() []net.IP { + return nil +} + +func (cr *cidrRangeIPv6) Ranges(startIP net.IP, endIP net.IP, include []net.IP, exclude []net.IP) ([]net.IP, error) { + return nil, nil +} + +func (cr *cidrRangeIPv6) Broadcast() net.IP { + return nil +} + +func (cr *cidrRangeIPv6) Network() net.IP { + return nil +} + +func (cr *cidrRangeIPv6) Next(ip net.IP) net.IP { + return nil +} + +func (cr *cidrRangeIPv6) Previous(ip net.IP) net.IP { + return nil +} diff --git a/net/cidr/range.go b/net/cidr/range.go new file mode 100644 index 0000000..9d908ee --- /dev/null +++ b/net/cidr/range.go @@ -0,0 +1,44 @@ +package cidr + +import ( + "fmt" + "net" +) + +func NewCIDRRanger(cidr string) (CIDRRanger, error) { + _, nIPNet, err := net.ParseCIDR(cidr) + if nil != err { + return nil, err + } + + switch len(nIPNet.IP) { + case net.IPv4len: + cr := &cidrRangeIPv4{ + cidrNet: nIPNet, + } + return cr, nil + case net.IPv6len: + cr := &cidrRangeIPv6{ + cidrNet: nIPNet, + } + return cr, nil + default: + return nil, fmt.Errorf("Net: not supported IP length") + } +} + +type CIDRRanger interface { + Contains(ip net.IP) bool + First() net.IP + Last() net.IP + Range() []net.IP + // (!Contains(startIP) || !Contains(endIP)) return error + // (startIP > endIP) return error + // (nil != startIP && nil != endIP) return (startIP ~ endIP) + include - exclude + // (nil == startIP || nil == endIP) return include - exclude + Ranges(startIP net.IP, endIP net.IP, include []net.IP, exclude []net.IP) ([]net.IP, error) + Broadcast() net.IP + Network() net.IP + Next(ip net.IP) net.IP + Previous(ip net.IP) net.IP +} diff --git a/net/converter/ip-v4.go b/net/converter/ip-v4.go new file mode 100644 index 0000000..694e778 --- /dev/null +++ b/net/converter/ip-v4.go @@ -0,0 +1,16 @@ +package converter + +import ( + "encoding/binary" + "net" +) + +func IPv4ToInt(ip net.IP) int32 { + return int32(binary.BigEndian.Uint32(ip.To4())) +} + +func IntToIPv4(n int32) net.IP { + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, uint32(n)) + return net.IP(b) +} diff --git a/net/converter/ip-v6.go b/net/converter/ip-v6.go new file mode 100644 index 0000000..676ad64 --- /dev/null +++ b/net/converter/ip-v6.go @@ -0,0 +1,15 @@ +package converter + +import ( + "net" +) + +// Not implemented +func IPv6ToInt(ip net.IP) int32 { + return 0 +} + +// Not implemented +func IntToIPv6(n int32) net.IP { + return nil +} diff --git a/net/converter/ip.go b/net/converter/ip.go new file mode 100644 index 0000000..5768225 --- /dev/null +++ b/net/converter/ip.go @@ -0,0 +1,17 @@ +package converter + +import ( + "fmt" + "net" +) + +func IPToInt(ip net.IP) (int32, error) { + switch len(ip) { + case net.IPv4len: + return IPv4ToInt(ip), nil + case net.IPv6len: + return IPv6ToInt(ip), nil + default: + return 0, fmt.Errorf("Net: not supported IP length") + } +} diff --git a/net/converter/mac.go b/net/converter/mac.go new file mode 100644 index 0000000..45777b5 --- /dev/null +++ b/net/converter/mac.go @@ -0,0 +1,18 @@ +package converter + +import ( + "net" + "regexp" + "strconv" +) + +var ( + macStripRegexp = regexp.MustCompile(`[^a-fA-F0-9]`) +) + +func MacToUint64(hwAddr net.HardwareAddr) (uint64, error) { + mac := hwAddr.String() + hex := macStripRegexp.ReplaceAllLiteralString(mac, "") + + return strconv.ParseUint(hex, 16, 64) +}