1// Copyright 2015 CoreOS, Inc. 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// Package netutil implements network-related utility functions. 16package netutil 17 18import ( 19 "net" 20 "net/url" 21 "reflect" 22 "sort" 23 24 "github.com/coreos/etcd/Godeps/_workspace/src/github.com/coreos/pkg/capnslog" 25 "github.com/coreos/etcd/pkg/types" 26) 27 28var ( 29 plog = capnslog.NewPackageLogger("github.com/coreos/etcd/pkg", "netutil") 30 31 // indirection for testing 32 resolveTCPAddr = net.ResolveTCPAddr 33) 34 35// resolveTCPAddrs is a convenience wrapper for net.ResolveTCPAddr. 36// resolveTCPAddrs return a new set of url.URLs, in which all DNS hostnames 37// are resolved. 38func resolveTCPAddrs(urls [][]url.URL) ([][]url.URL, error) { 39 newurls := make([][]url.URL, 0) 40 for _, us := range urls { 41 nus := make([]url.URL, len(us)) 42 for i, u := range us { 43 nu, err := url.Parse(u.String()) 44 if err != nil { 45 return nil, err 46 } 47 nus[i] = *nu 48 } 49 for i, u := range nus { 50 host, _, err := net.SplitHostPort(u.Host) 51 if err != nil { 52 plog.Errorf("could not parse url %s during tcp resolving", u.Host) 53 return nil, err 54 } 55 if host == "localhost" { 56 continue 57 } 58 if net.ParseIP(host) != nil { 59 continue 60 } 61 tcpAddr, err := resolveTCPAddr("tcp", u.Host) 62 if err != nil { 63 plog.Errorf("could not resolve host %s", u.Host) 64 return nil, err 65 } 66 plog.Infof("resolving %s to %s", u.Host, tcpAddr.String()) 67 nus[i].Host = tcpAddr.String() 68 } 69 newurls = append(newurls, nus) 70 } 71 return newurls, nil 72} 73 74// urlsEqual checks equality of url.URLS between two arrays. 75// This check pass even if an URL is in hostname and opposite is in IP address. 76func urlsEqual(a []url.URL, b []url.URL) bool { 77 if len(a) != len(b) { 78 return false 79 } 80 urls, err := resolveTCPAddrs([][]url.URL{a, b}) 81 if err != nil { 82 return false 83 } 84 a, b = urls[0], urls[1] 85 sort.Sort(types.URLs(a)) 86 sort.Sort(types.URLs(b)) 87 for i := range a { 88 if !reflect.DeepEqual(a[i], b[i]) { 89 return false 90 } 91 } 92 93 return true 94} 95 96func URLStringsEqual(a []string, b []string) bool { 97 if len(a) != len(b) { 98 return false 99 } 100 urlsA := make([]url.URL, 0) 101 for _, str := range a { 102 u, err := url.Parse(str) 103 if err != nil { 104 return false 105 } 106 urlsA = append(urlsA, *u) 107 } 108 urlsB := make([]url.URL, 0) 109 for _, str := range b { 110 u, err := url.Parse(str) 111 if err != nil { 112 return false 113 } 114 urlsB = append(urlsB, *u) 115 } 116 117 return urlsEqual(urlsA, urlsB) 118} 119