// 2020 Rackspace, Inc. // // 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 common import ( "fmt" "net" "strconv" "strings" ) // IsStrNil will check if the string contains one of our // preset values we consider to be nil func IsStrNil(s string) bool { return strings.EqualFold(s, "") } // IContains function will perform a case-insensitive partial search for a substring // within a string. func IContains(s, sub string) bool { return strings.Contains(strings.ToLower(s), strings.ToLower(sub)) } // AtoI is a helper function to return either the converted number to integer // format, or return a -999 if there was an error. func Atoi(s string) int { if strInt, err := strconv.Atoi(s); err == nil { return strInt } return -999 } // IsNil will check to see if the int value is set to what we defined as // a nil value for the int type. func IsNil(i int) bool { return i == -999 } // StringInSlice will find if an element exist in a slice of elements func StringInSlice(s string, sl []string) bool { for _, item := range sl { if item == s { return true } } return false } // UniqueStrings takes a slice that contains duplicates and returns // a slice containing only the unique values. func UniqueStrings(slice []string) []string { r := make([]string, 0) for i := range slice { found := false for _, ni := range r { if ni == slice[i] { found = true break } } if !found { r = append(r, slice[i]) } } return r } // UniqueInts takes a slice that contains duplicates and returns // a slice containing only the unique values. func UniqueInts(slice []int) []int { r := make([]int, 0) for i := range slice { found := false for _, ni := range r { if ni == slice[i] { found = true break } } if !found { r = append(r, slice[i]) } } return r } // IntInSlice function is a helper to determine if a single integer exist // with a slice of integers func IntInSlice(i int, sl []int) bool { for k := range sl { if sl[k] == i { return true } } return false } // IPNetToCIDR will take two strings containing the network address and network mask of // an IP block, then return the CIDR representation of that network. func IPNetToCIDR(network, netmask string) (string, error) { ip := net.ParseIP(network) if ip == nil { return "", fmt.Errorf("IPNetToCIDR:%s:unable to parse", network) } nm := net.ParseIP(netmask).To4() if nm == nil { return "", fmt.Errorf("IPNetToCIDR:%s:unable to parse", network) } ones, bits := net.IPv4Mask(nm[0], nm[1], nm[2], nm[3]).Size() return fmt.Sprintf("%s/%d", ip.Mask(net.CIDRMask(ones, bits)), ones), nil } // ExpandBlock will take a IP block CIDR string and return a list of all IP addresses within // that CIDR. func ExpandBlock(cidr string) ([]string, error) { r := make([]string, 0) ip, ipNet, err := net.ParseCIDR(cidr) if err != nil { return nil, fmt.Errorf("ExpandBlock:%s", err) } for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); expBlockInc(ip) { r = append(r, ip.String()) } return r, nil } func expBlockInc(ip net.IP) { for j := len(ip) - 1; j >= 0; j-- { ip[j]++ if ip[j] > 0 { break } } } var ( _, rfc1918A, _ = net.ParseCIDR("10.0.0.0/8") // RFC1918: Private-Use _, rfc1918B, _ = net.ParseCIDR("172.16.0.0/12") // RFC1918: Private-Use _, rfc1918C, _ = net.ParseCIDR("192.168.0.0/16") // RFC1918: Private-Use _, rfc6598, _ = net.ParseCIDR("100.64.0.0/10") // RFC6598: Shared Address Space _, rfc1122A, _ = net.ParseCIDR("127.0.0.0/8") // RFC1122: Loopback _, rfc1122B, _ = net.ParseCIDR("240.0.0.0/4") // RFC1122: Reserved _, rfc3927, _ = net.ParseCIDR("169.254.0.0/16") // RFC3927: Link Local _, rfc5737A, _ = net.ParseCIDR("192.0.2.0/24") // RFC5737: Documentation (TEST-NET-1) _, rfc5737B, _ = net.ParseCIDR("198.51.100.0/24") // RFC5737: Documentation (TEST-NET-2) _, rfc5737C, _ = net.ParseCIDR("203.0.113.0/24") // RFC5737: Documentation (TEST-NET-3) _, rfc3068, _ = net.ParseCIDR("192.88.99.0/24") // RFC3068: 6to4 Relay Anycast _, rfc2544, _ = net.ParseCIDR("198.18.0.0/15") // RFC2544: Benchmarking _, rfc5736, _ = net.ParseCIDR("192.0.0.0/24") // RFC5736: IETF Protocol Assignments ) // IsPublicIP is a helper function to check if an IP address is internet routable // based on known reservations func IsPublicIP(ip net.IP) bool { if rfc1918A.Contains(ip) { return false } if rfc1918B.Contains(ip) { return false } if rfc1918C.Contains(ip) { return false } if rfc6598.Contains(ip) { return false } if rfc1122A.Contains(ip) { return false } if rfc1122B.Contains(ip) { return false } if rfc3927.Contains(ip) { return false } if rfc5737A.Contains(ip) { return false } if rfc5737B.Contains(ip) { return false } if rfc5737C.Contains(ip) { return false } if rfc3068.Contains(ip) { return false } if rfc2544.Contains(ip) { return false } if rfc5736.Contains(ip) { return false } return true }