github.com/google/cloudprober@v0.11.3/common/iputils/iputils.go (about) 1 // Copyright 2020 The Cloudprober Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 /* 16 Package iputils implements utilities to work with IP addresses. 17 */ 18 package iputils 19 20 import ( 21 "fmt" 22 "net" 23 ) 24 25 // IPVersion tells if an IP address is IPv4 or IPv6. 26 func IPVersion(ip net.IP) int { 27 if len(ip.To4()) == net.IPv4len { 28 return 4 29 } 30 if len(ip) == net.IPv6len { 31 return 6 32 } 33 return 0 34 } 35 36 // Addr is used for tests, allowing net.InterfaceByName to be mocked. 37 type Addr interface { 38 Addrs() ([]net.Addr, error) 39 } 40 41 // InterfaceByName is a mocking point for net.InterfaceByName, used for tests. 42 var InterfaceByName = func(s string) (Addr, error) { return net.InterfaceByName(s) } 43 44 // ResolveIntfAddr takes the name of a network interface and IP version, and 45 // returns the first IP address of the interface that matches the specified IP 46 // version. If no IP version is specified (ipVer is 0), simply the first IP 47 // address is returned. 48 // TODO(manugarg): This functions is currently tested through options_test. We 49 // should fix that. 50 func ResolveIntfAddr(intfName string, ipVer int) (net.IP, error) { 51 i, err := InterfaceByName(intfName) 52 if err != nil { 53 return nil, fmt.Errorf("resolveIntfAddr(%v, %d) got error getting interface: %v", intfName, ipVer, err) 54 } 55 56 addrs, err := i.Addrs() 57 if err != nil { 58 return nil, fmt.Errorf("resolveIntfAddr(%v, %d) got error getting addresses for interface: %v", intfName, ipVer, err) 59 } else if len(addrs) == 0 { 60 return nil, fmt.Errorf("resolveIntfAddr(%v, %d) go 0 addrs for interface", intfName, ipVer) 61 } 62 63 var ip net.IP 64 65 for _, addr := range addrs { 66 // i.Addrs() mostly returns network addresses of the form "172.17.90.252/23". 67 // This bit of code will pull the IP address from this address. 68 switch v := addr.(type) { 69 case *net.IPNet: 70 ip = v.IP 71 case *net.IPAddr: 72 ip = v.IP 73 default: 74 return nil, fmt.Errorf("resolveIntfAddr(%v, %d) found unknown type for first address: %T", intfName, ipVer, v) 75 } 76 77 if ipVer == 0 || IPVersion(ip) == ipVer { 78 return ip, nil 79 } 80 } 81 return nil, fmt.Errorf("resolveIntfAddr(%v, %d) found no apprpriate IP addresses in %v", intfName, ipVer, addrs) 82 }