| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package netutils
- import (
- "encoding/binary"
- "fmt"
- "math/bits"
- "math/rand"
- "net"
- "sort"
- "strconv"
- "strings"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/pkg/util/sortutils"
- )
- const macChars = "0123456789abcdef"
- const macCapChars = "ABCDEF"
- func FormatMacAddr(macAddr string) string {
- buf := make([]byte, 12)
- bufIdx := 0
- for i := 0; i < len(macAddr) && bufIdx < len(buf); i += 1 {
- c := macAddr[i]
- if strings.IndexByte(macChars, c) >= 0 {
- buf[bufIdx] = c
- bufIdx += 1
- } else if strings.IndexByte(macCapChars, c) >= 0 {
- buf[bufIdx] = c - 'A' + 'a'
- bufIdx += 1
- }
- }
- if len(buf) == bufIdx {
- return fmt.Sprintf("%c%c:%c%c:%c%c:%c%c:%c%c:%c%c", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
- buf[6], buf[7], buf[8], buf[9], buf[10], buf[11])
- } else {
- return ""
- }
- }
- func IP2Number(ipstr string) (uint32, error) {
- parts := strings.Split(ipstr, ".")
- if len(parts) == 4 {
- bytes := make([]byte, 4)
- for i := 0; i < 4; i += 1 {
- n, e := strconv.Atoi(strings.TrimSpace(parts[i]))
- if e != nil {
- return 0, ErrInvalidNumber // fmt.Errorf("invalid number %s", parts[i])
- }
- if n < 0 || n > 255 {
- return 0, ErrOutOfRange
- }
- bytes[i] = byte(n)
- }
- return binary.BigEndian.Uint32(bytes), nil
- }
- return 0, ErrInvalidIPAddr // fmt.Errorf("invalid ip address %s", ipstr)
- }
- func Number2Bytes(num uint32) []byte {
- ret := make([]byte, 4)
- binary.BigEndian.PutUint32(ret, num)
- return ret
- }
- func Number2IP(num uint32) string {
- bytes := Number2Bytes(num)
- return fmt.Sprintf("%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3])
- }
- type IPV4Addr uint32
- func NewIPV4Addr(ipstr string) (IPV4Addr, error) {
- var addr IPV4Addr
- if len(ipstr) > 0 {
- num, err := IP2Number(ipstr)
- if err != nil {
- return addr, errors.Wrap(err, "IP2Number")
- }
- addr = IPV4Addr(num)
- }
- return addr, nil
- }
- func (addr IPV4Addr) StepDown() IPV4Addr {
- naddr := addr - 1
- return naddr
- }
- func (addr IPV4Addr) StepUp() IPV4Addr {
- naddr := addr + 1
- return naddr
- }
- func (addr IPV4Addr) NetAddr(maskLen int8) IPV4Addr {
- mask := Masklen2Mask(maskLen)
- return IPV4Addr(mask & addr)
- }
- func (addr IPV4Addr) BroadcastAddr(maskLen int8) IPV4Addr {
- mask := Masklen2Mask(maskLen)
- return IPV4Addr(addr | (0xffffffff - mask))
- }
- func (addr IPV4Addr) CliAddr(maskLen int8) IPV4Addr {
- mask := Masklen2Mask(maskLen)
- return IPV4Addr(addr - (addr & mask))
- }
- func (addr IPV4Addr) String() string {
- return Number2IP(uint32(addr))
- }
- func (addr IPV4Addr) ToBytes() []byte {
- return Number2Bytes(uint32(addr))
- }
- func (addr IPV4Addr) ToIP() net.IP {
- return net.IP(addr.ToBytes())
- }
- func (addr IPV4Addr) ToMac(prefix string) string {
- bytes := addr.ToBytes()
- return fmt.Sprintf("%s%02x:%02x:%02x:%02x", prefix, bytes[0], bytes[1], bytes[2], bytes[3])
- }
- func (addr IPV4Addr) IsZero() bool {
- return addr == 0
- }
- type IPV4AddrRange struct {
- start IPV4Addr
- end IPV4Addr
- }
- func NewIPV4AddrRange(ip1 IPV4Addr, ip2 IPV4Addr) IPV4AddrRange {
- ar := IPV4AddrRange{}
- ar.Set(ip1, ip2)
- return ar
- }
- func (ar *IPV4AddrRange) Set(ip1 IPV4Addr, ip2 IPV4Addr) {
- if ip1 < ip2 {
- ar.start = ip1
- ar.end = ip2
- } else {
- ar.start = ip2
- ar.end = ip1
- }
- }
- // n.IP and n.Mask must be ipv4 type. n.Mask must be canonical
- func NewIPV4AddrRangeFromIPNet(n *net.IPNet) IPV4AddrRange {
- pref, err := NewIPV4Prefix(n.String())
- if err != nil {
- panic("unexpected IPNet: " + n.String())
- }
- return pref.ToIPRange()
- }
- func (ar IPV4AddrRange) Contains(ip IPV4Addr) bool {
- return (ip >= ar.start) && (ip <= ar.end)
- }
- func (ar IPV4AddrRange) ContainsRange(ar2 IPV4AddrRange) bool {
- return ar.start <= ar2.start && ar.end >= ar2.end
- }
- func (ar IPV4AddrRange) Random() IPV4Addr {
- return IPV4Addr(uint32(ar.start) + uint32(rand.Intn(int(uint32(ar.end)-uint32(ar.start)))))
- }
- func (ar IPV4AddrRange) AddressCount() int {
- return int(uint32(ar.end) - uint32(ar.start) + 1)
- }
- func (ar IPV4AddrRange) String() string {
- return fmt.Sprintf("%s-%s", ar.start, ar.end)
- }
- func (ar IPV4AddrRange) StartIp() IPV4Addr {
- return ar.start
- }
- func (ar IPV4AddrRange) EndIp() IPV4Addr {
- return ar.end
- }
- func (ar IPV4AddrRange) Merge(ar2 IPV4AddrRange) (IPV4AddrRange, bool) {
- if ar.IsOverlap(ar2) || ar.end+1 == ar2.start || ar2.end+1 == ar.start {
- if ar2.start < ar.start {
- ar.start = ar2.start
- }
- if ar2.end > ar.end {
- ar.end = ar2.end
- }
- return ar, true
- }
- return ar, false
- }
- func (ar IPV4AddrRange) IsOverlap(ar2 IPV4AddrRange) bool {
- if ar.start > ar2.end || ar.end < ar2.start {
- return false
- } else {
- return true
- }
- }
- func (pref IPV4Prefix) ToIPNet() *net.IPNet {
- return &net.IPNet{
- IP: pref.Address.ToIP(),
- Mask: net.CIDRMask(int(pref.MaskLen), 32),
- }
- }
- func (ar IPV4AddrRange) ToIPNets() []*net.IPNet {
- r := []*net.IPNet{}
- mms := ar.ToPrefixes()
- for _, mm := range mms {
- r = append(r, mm.ToIPNet())
- }
- return r
- }
- /*func (ar IPV4AddrRange) ToIPNets() []*net.IPNet {
- r := []*net.IPNet{}
- mms := ar.ToMaskMatches()
- for _, mm := range mms {
- a := mm[0]
- m := mm[1]
- addr := net.IPv4(byte((a>>24)&0xff), byte((a>>16)&0xff), byte((a>>8)&0xff), byte(a&0xff))
- mask := net.IPv4Mask(byte((m>>24)&0xff), byte((m>>16)&0xff), byte((m>>8)&0xff), byte(m&0xff))
- r = append(r, &net.IPNet{
- IP: addr,
- Mask: mask,
- })
- }
- return r
- }
- func (ar IPV4AddrRange) ToMaskMatches() [][2]uint32 {
- r := [][2]uint32{}
- s := uint32(ar.start)
- e := uint32(ar.end)
- if s == e {
- r = append(r, [2]uint32{s, ^uint32(0)})
- return r
- }
- sp, ep := uint64(s), uint64(e)
- ep = ep + 1
- for sp < ep {
- b := uint64(1)
- for (sp+b) <= ep && (sp&(b-1)) == 0 {
- b <<= 1
- }
- b >>= 1
- r = append(r, [2]uint32{uint32(sp), uint32(^(b - 1))})
- sp = sp + b
- }
- return r
- }*/
- func (ar IPV4AddrRange) ToPrefixes() []IPV4Prefix {
- prefixes := make([]IPV4Prefix, 0)
- sp := ar.StartIp()
- ep := ar.EndIp()
- for sp <= ep {
- masklen := int8(32)
- for masklen > 0 && sp.NetAddr(masklen-1) == sp && sp.BroadcastAddr(masklen-1) <= ep {
- masklen--
- }
- if masklen == 0 {
- prefixes = append(prefixes, NewIPV4PrefixFromAddr(sp, 0))
- break
- }
- prefixes = append(prefixes, NewIPV4PrefixFromAddr(sp, masklen))
- sp = sp.BroadcastAddr(masklen).StepUp()
- }
- return prefixes
- }
- func (ar IPV4AddrRange) Substract(ar2 IPV4AddrRange) ([]IPV4AddrRange, *IPV4AddrRange) {
- lefts, overlap, sub := ar.Substract2(ar2)
- var subp *IPV4AddrRange
- if overlap {
- subp = &sub
- }
- return lefts, subp
- }
- func (ar IPV4AddrRange) Substract2(ar2 IPV4AddrRange) ([]IPV4AddrRange, bool, IPV4AddrRange) {
- lefts := []IPV4AddrRange{}
- // no intersection, no substract
- if ar.end < ar2.start || ar.start > ar2.end {
- lefts = append(lefts, ar)
- return lefts, false, IPV4AddrRange{}
- }
- // ar contains ar2
- if ar.ContainsRange(ar2) {
- if ar.start == ar2.start && ar.end == ar2.end {
- // lefts empty
- } else if ar.start < ar2.start && ar.end == ar2.end {
- lefts = append(lefts,
- NewIPV4AddrRange(ar.start, ar2.start.StepDown()),
- )
- } else if ar.start == ar2.start && ar.end > ar2.end {
- lefts = append(lefts,
- NewIPV4AddrRange(ar2.end.StepUp(), ar.end),
- )
- } else {
- lefts = append(lefts,
- NewIPV4AddrRange(ar.start, ar2.start.StepDown()),
- NewIPV4AddrRange(ar2.end.StepUp(), ar.end),
- )
- }
- return lefts, true, ar2
- }
- // ar contained by ar2
- if ar2.ContainsRange(ar) {
- return lefts, true, ar
- }
- // intersect, ar on the left
- if ar.start < ar2.start && ar.end >= ar2.start {
- lefts = append(lefts, NewIPV4AddrRange(ar.start, ar2.start.StepDown()))
- sub_ := NewIPV4AddrRange(ar2.start, ar.end)
- return lefts, true, sub_
- }
- // intersect, ar on the right
- if ar.start <= ar2.end && ar.end > ar2.end {
- lefts = append(lefts, NewIPV4AddrRange(ar2.end.StepUp(), ar.end))
- sub_ := NewIPV4AddrRange(ar.start, ar2.end)
- return lefts, true, sub_
- }
- // no intersection
- return lefts, false, IPV4AddrRange{}
- }
- func (ar IPV4AddrRange) equals(ar2 IPV4AddrRange) bool {
- return ar.start == ar2.start && ar.end == ar2.end
- }
- func Masklen2Mask(maskLen int8) IPV4Addr {
- if maskLen < 0 {
- panic("negative masklen")
- }
- return IPV4Addr(^(uint32(1<<(32-uint8(maskLen))) - 1))
- }
- type IPV4Prefix struct {
- Address IPV4Addr
- MaskLen int8
- ipRange IPV4AddrRange
- }
- func (pref *IPV4Prefix) String() string {
- if pref.MaskLen == 32 {
- return pref.Address.String()
- } else {
- return fmt.Sprintf("%s/%d", pref.Address.NetAddr(pref.MaskLen).String(), pref.MaskLen)
- }
- }
- func (pref *IPV4Prefix) Equals(pref1 *IPV4Prefix) bool {
- if pref1 == nil {
- return false
- }
- return pref.ipRange.equals(pref1.ipRange)
- }
- func Mask2Len(mask IPV4Addr) int8 {
- return int8(bits.LeadingZeros32(^uint32(mask)))
- }
- func ParsePrefix(prefix string) (IPV4Addr, int8, error) {
- slash := strings.IndexByte(prefix, '/')
- if slash > 0 {
- addr, err := NewIPV4Addr(prefix[:slash])
- if err != nil {
- return 0, 0, errors.Wrap(err, "NewIPV4Addr")
- }
- if regutils.MatchIP4Addr(prefix[slash+1:]) {
- mask, err := NewIPV4Addr(prefix[slash+1:])
- if err != nil {
- return 0, 0, errors.Wrap(err, "NewIPV4Addr")
- }
- maskLen := Mask2Len(mask)
- return addr.NetAddr(maskLen), maskLen, nil
- } else {
- maskLen, err := strconv.Atoi(prefix[slash+1:])
- if err != nil {
- return 0, 0, ErrInvalidMask // fmt.Errorf("invalid masklen %s", err)
- }
- if maskLen < 0 || maskLen > 32 {
- return 0, 0, ErrOutOfRangeMask // fmt.Errorf("out of range masklen")
- }
- return addr.NetAddr(int8(maskLen)), int8(maskLen), nil
- }
- } else {
- addr, err := NewIPV4Addr(prefix)
- if err != nil {
- return 0, 0, errors.Wrap(err, "NewIPV4Addr")
- }
- return addr, 32, nil
- }
- }
- func NewIPV4Prefix(prefix string) (IPV4Prefix, error) {
- addr, maskLen, err := ParsePrefix(prefix)
- if err != nil {
- return IPV4Prefix{}, errors.Wrap(err, "ParsePrefix")
- }
- pref := IPV4Prefix{
- Address: addr,
- MaskLen: maskLen,
- }
- pref.ipRange = pref.ToIPRange()
- return pref, nil
- }
- func NewIPV4PrefixFromAddr(addr IPV4Addr, masklen int8) IPV4Prefix {
- pref := IPV4Prefix{
- Address: addr.NetAddr(masklen),
- MaskLen: masklen,
- }
- pref.ipRange = pref.ToIPRange()
- return pref
- }
- func (prefix IPV4Prefix) ToIPRange() IPV4AddrRange {
- start := prefix.Address.NetAddr(prefix.MaskLen)
- end := prefix.Address.BroadcastAddr(prefix.MaskLen)
- return IPV4AddrRange{start: start, end: end}
- }
- func (prefix IPV4Prefix) Contains(ip IPV4Addr) bool {
- return prefix.ipRange.Contains(ip)
- }
- const (
- hostlocalPrefix = "127.0.0.0/8"
- linklocalPrefix = "169.254.0.0/16"
- multicastPrefix = "224.0.0.0/4"
- )
- var privateIPRanges []IPV4AddrRange
- var customizedPrivateIPRanges []IPV4AddrRange
- var hostLocalIPRange IPV4AddrRange
- var linkLocalIPRange IPV4AddrRange
- var multicastIPRange IPV4AddrRange
- func init() {
- initPrivateIPRanges()
- prefix, _ := NewIPV4Prefix(hostlocalPrefix)
- hostLocalIPRange = prefix.ToIPRange()
- prefix, _ = NewIPV4Prefix(linklocalPrefix)
- linkLocalIPRange = prefix.ToIPRange()
- prefix, _ = NewIPV4Prefix(multicastPrefix)
- multicastIPRange = prefix.ToIPRange()
- }
- func initPrivateIPRanges() {
- // https://zh.wikipedia.org/wiki/%E4%BF%9D%E7%95%99IP%E5%9C%B0%E5%9D%80
- prefs := []string{
- "10.0.0.0/8",
- "100.64.0.0/10",
- "172.16.0.0/12",
- "192.0.0.0/24",
- "198.18.0.0/15",
- "192.168.0.0/16",
- }
- privateIPRanges = make([]IPV4AddrRange, len(prefs))
- for i, prefix := range prefs {
- prefix, err := NewIPV4Prefix(prefix)
- if err != nil {
- continue
- }
- privateIPRanges[i] = prefix.ToIPRange()
- }
- }
- func SetPrivatePrefixes(pref []string) {
- customizedPrivateIPRanges = make([]IPV4AddrRange, 0)
- for _, prefix := range pref {
- prefix, err := NewIPV4Prefix(prefix)
- if err != nil {
- continue
- }
- customizedPrivateIPRanges = append(customizedPrivateIPRanges, prefix.ToIPRange())
- }
- }
- func GetPrivateIPRanges() []IPV4AddrRange {
- return append(privateIPRanges, customizedPrivateIPRanges...)
- }
- func IsPrivate(addr IPV4Addr) bool {
- for _, ipRange := range GetPrivateIPRanges() {
- if ipRange.Contains(addr) {
- return true
- }
- }
- return false
- }
- func IsHostLocal(addr IPV4Addr) bool {
- return hostLocalIPRange.Contains(addr)
- }
- func IsLinkLocal(addr IPV4Addr) bool {
- return linkLocalIPRange.Contains(addr)
- }
- func IsMulticast(addr IPV4Addr) bool {
- return multicastIPRange.Contains(addr)
- }
- func IsExitAddress(addr IPV4Addr) bool {
- return !IsPrivate(addr) && !IsHostLocal(addr) && !IsLinkLocal(addr) && !IsMulticast(addr)
- }
- func MacUnpackHex(mac string) string {
- if regutils.MatchCompactMacAddr(mac) {
- parts := make([]string, 6)
- for i := 0; i < 12; i += 2 {
- parts[i/2] = strings.ToLower(mac[i : i+2])
- }
- return strings.Join(parts, ":")
- }
- return ""
- }
- func GetFreePort() (int, error) {
- addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
- if err != nil {
- return 0, err
- }
- l, err := net.ListenTCP("tcp", addr)
- if err != nil {
- return 0, err
- }
- defer l.Close()
- return l.Addr().(*net.TCPAddr).Port, nil
- }
- var MASKS = []string{"0", "128", "192", "224", "240", "248", "252", "254", "255"}
- func Netlen2Mask(netmasklen int) string {
- var mask = ""
- var segCnt = 0
- for netmasklen > 0 {
- var m string
- if netmasklen > 8 {
- m = MASKS[8]
- netmasklen -= 8
- } else {
- m = MASKS[netmasklen]
- netmasklen = 0
- }
- if mask != "" {
- mask += "."
- }
- mask += m
- segCnt += 1
- }
- for i := 0; i < (4 - segCnt); i++ {
- if mask != "" {
- mask += "."
- }
- mask += "0"
- }
- return mask
- }
- type IPV4AddrRangeList []IPV4AddrRange
- func (rl IPV4AddrRangeList) Len() int {
- return len(rl)
- }
- func (rl IPV4AddrRangeList) Swap(i, j int) {
- rl[i], rl[j] = rl[j], rl[i]
- }
- func (rl IPV4AddrRangeList) Less(i, j int) bool {
- return rl[i].Compare(rl[j]) == sortutils.Less
- }
- func (v4range IPV4AddrRange) Compare(r2 IPV4AddrRange) sortutils.CompareResult {
- if v4range.start < r2.start {
- return sortutils.Less
- } else if v4range.start > r2.start {
- return sortutils.More
- } else {
- // start equals, compare ends
- if v4range.end > r2.end {
- return sortutils.Less
- } else if v4range.end < r2.end {
- return sortutils.More
- } else {
- return sortutils.Equal
- }
- }
- }
- func (rl IPV4AddrRangeList) Merge() []IPV4AddrRange {
- sort.Sort(rl)
- ret := make([]IPV4AddrRange, 0, len(rl))
- for i := range rl {
- if i == 0 {
- ret = append(ret, rl[i])
- } else {
- result, isMerged := ret[len(ret)-1].Merge(rl[i])
- if isMerged {
- ret[len(ret)-1] = result
- } else {
- ret = append(ret, rl[i])
- }
- }
- }
- return ret
- }
- func (rl IPV4AddrRangeList) String() string {
- strs := make([]string, len(rl))
- for i := range rl {
- strs[i] = rl[i].String()
- }
- return strings.Join(strs, ",")
- }
- var IPV4Zero = IPV4Addr(0)
- var IPV4Ones = IPV4Addr(0xffffffff)
- var AllIPV4AddrRange = IPV4AddrRange{
- start: IPV4Zero,
- end: IPV4Ones,
- }
- func (r IPV4AddrRange) IsAll() bool {
- return r.start == IPV4Zero && r.end == IPV4Ones
- }
- func (rl IPV4AddrRangeList) Substract(addrRange IPV4AddrRange) []IPV4AddrRange {
- ret := make([]IPV4AddrRange, 0)
- for i := range rl {
- lefts, _ := rl[i].Substract(addrRange)
- ret = append(ret, lefts...)
- }
- return ret
- }
|