1package consul 2 3import ( 4 "encoding/binary" 5 "fmt" 6 "net" 7 "runtime" 8 "strconv" 9 10 "github.com/hashicorp/consul/agent/metadata" 11 "github.com/hashicorp/consul/agent/structs" 12 "github.com/hashicorp/go-version" 13 "github.com/hashicorp/serf/serf" 14) 15 16/* 17 * Contains an entry for each private block: 18 * 10.0.0.0/8 19 * 100.64.0.0/10 20 * 127.0.0.0/8 21 * 169.254.0.0/16 22 * 172.16.0.0/12 23 * 192.168.0.0/16 24 */ 25var privateBlocks []*net.IPNet 26 27func init() { 28 // Add each private block 29 privateBlocks = make([]*net.IPNet, 6) 30 31 _, block, err := net.ParseCIDR("10.0.0.0/8") 32 if err != nil { 33 panic(fmt.Sprintf("Bad cidr. Got %v", err)) 34 } 35 privateBlocks[0] = block 36 37 _, block, err = net.ParseCIDR("100.64.0.0/10") 38 if err != nil { 39 panic(fmt.Sprintf("Bad cidr. Got %v", err)) 40 } 41 privateBlocks[1] = block 42 43 _, block, err = net.ParseCIDR("127.0.0.0/8") 44 if err != nil { 45 panic(fmt.Sprintf("Bad cidr. Got %v", err)) 46 } 47 privateBlocks[2] = block 48 49 _, block, err = net.ParseCIDR("169.254.0.0/16") 50 if err != nil { 51 panic(fmt.Sprintf("Bad cidr. Got %v", err)) 52 } 53 privateBlocks[3] = block 54 55 _, block, err = net.ParseCIDR("172.16.0.0/12") 56 if err != nil { 57 panic(fmt.Sprintf("Bad cidr. Got %v", err)) 58 } 59 privateBlocks[4] = block 60 61 _, block, err = net.ParseCIDR("192.168.0.0/16") 62 if err != nil { 63 panic(fmt.Sprintf("Bad cidr. Got %v", err)) 64 } 65 privateBlocks[5] = block 66} 67 68// CanServersUnderstandProtocol checks to see if all the servers in the given 69// list understand the given protocol version. If there are no servers in the 70// list then this will return false. 71func CanServersUnderstandProtocol(members []serf.Member, version uint8) (bool, error) { 72 numServers, numWhoGrok := 0, 0 73 for _, m := range members { 74 if m.Tags["role"] != "consul" { 75 continue 76 } 77 numServers++ 78 79 vsnMin, err := strconv.Atoi(m.Tags["vsn_min"]) 80 if err != nil { 81 return false, err 82 } 83 84 vsnMax, err := strconv.Atoi(m.Tags["vsn_max"]) 85 if err != nil { 86 return false, err 87 } 88 89 v := int(version) 90 if (v >= vsnMin) && (v <= vsnMax) { 91 numWhoGrok++ 92 } 93 } 94 return (numServers > 0) && (numWhoGrok == numServers), nil 95} 96 97// Returns if a member is a consul node. Returns a bool, 98// and the datacenter. 99func isConsulNode(m serf.Member) (bool, string) { 100 if m.Tags["role"] != "node" { 101 return false, "" 102 } 103 return true, m.Tags["dc"] 104} 105 106// Returns if the given IP is in a private block 107func isPrivateIP(ipStr string) bool { 108 ip := net.ParseIP(ipStr) 109 for _, priv := range privateBlocks { 110 if priv.Contains(ip) { 111 return true 112 } 113 } 114 return false 115} 116 117// Returns addresses from interfaces that is up 118func activeInterfaceAddresses() ([]net.Addr, error) { 119 var upAddrs []net.Addr 120 var loAddrs []net.Addr 121 122 interfaces, err := net.Interfaces() 123 if err != nil { 124 return nil, fmt.Errorf("Failed to get interfaces: %v", err) 125 } 126 127 for _, iface := range interfaces { 128 // Require interface to be up 129 if iface.Flags&net.FlagUp == 0 { 130 continue 131 } 132 133 addresses, err := iface.Addrs() 134 if err != nil { 135 return nil, fmt.Errorf("Failed to get interface addresses: %v", err) 136 } 137 138 if iface.Flags&net.FlagLoopback != 0 { 139 loAddrs = append(loAddrs, addresses...) 140 continue 141 } 142 143 upAddrs = append(upAddrs, addresses...) 144 } 145 146 if len(upAddrs) == 0 { 147 return loAddrs, nil 148 } 149 150 return upAddrs, nil 151} 152 153// GetPrivateIP is used to return the first private IP address 154// associated with an interface on the machine 155func GetPrivateIP() (net.IP, error) { 156 addresses, err := activeInterfaceAddresses() 157 if err != nil { 158 return nil, fmt.Errorf("Failed to get interface addresses: %v", err) 159 } 160 161 return getPrivateIP(addresses) 162} 163 164func getPrivateIP(addresses []net.Addr) (net.IP, error) { 165 var candidates []net.IP 166 167 // Find private IPv4 address 168 for _, rawAddr := range addresses { 169 var ip net.IP 170 switch addr := rawAddr.(type) { 171 case *net.IPAddr: 172 ip = addr.IP 173 case *net.IPNet: 174 ip = addr.IP 175 default: 176 continue 177 } 178 179 if ip.To4() == nil { 180 continue 181 } 182 if !isPrivateIP(ip.String()) { 183 continue 184 } 185 candidates = append(candidates, ip) 186 } 187 numIps := len(candidates) 188 switch numIps { 189 case 0: 190 return nil, fmt.Errorf("No private IP address found") 191 case 1: 192 return candidates[0], nil 193 default: 194 return nil, fmt.Errorf("Multiple private IPs found. Please configure one.") 195 } 196 197} 198 199// GetPublicIPv6 is used to return the first public IP address 200// associated with an interface on the machine 201func GetPublicIPv6() (net.IP, error) { 202 addresses, err := net.InterfaceAddrs() 203 if err != nil { 204 return nil, fmt.Errorf("Failed to get interface addresses: %v", err) 205 } 206 207 return getPublicIPv6(addresses) 208} 209 210func isUniqueLocalAddress(ip net.IP) bool { 211 return len(ip) == net.IPv6len && ip[0] == 0xfc && ip[1] == 0x00 212} 213 214func getPublicIPv6(addresses []net.Addr) (net.IP, error) { 215 var candidates []net.IP 216 217 // Find public IPv6 address 218 for _, rawAddr := range addresses { 219 var ip net.IP 220 switch addr := rawAddr.(type) { 221 case *net.IPAddr: 222 ip = addr.IP 223 case *net.IPNet: 224 ip = addr.IP 225 default: 226 continue 227 } 228 229 if ip.To4() != nil { 230 continue 231 } 232 233 if ip.IsLinkLocalUnicast() || isUniqueLocalAddress(ip) || ip.IsLoopback() { 234 continue 235 } 236 candidates = append(candidates, ip) 237 } 238 numIps := len(candidates) 239 switch numIps { 240 case 0: 241 return nil, fmt.Errorf("No public IPv6 address found") 242 case 1: 243 return candidates[0], nil 244 default: 245 return nil, fmt.Errorf("Multiple public IPv6 addresses found. Please configure one.") 246 } 247} 248 249// Converts bytes to an integer 250func bytesToUint64(b []byte) uint64 { 251 return binary.BigEndian.Uint64(b) 252} 253 254// Converts a uint to a byte slice 255func uint64ToBytes(u uint64) []byte { 256 buf := make([]byte, 8) 257 binary.BigEndian.PutUint64(buf, u) 258 return buf 259} 260 261// runtimeStats is used to return various runtime information 262func runtimeStats() map[string]string { 263 return map[string]string{ 264 "os": runtime.GOOS, 265 "arch": runtime.GOARCH, 266 "version": runtime.Version(), 267 "max_procs": strconv.FormatInt(int64(runtime.GOMAXPROCS(0)), 10), 268 "goroutines": strconv.FormatInt(int64(runtime.NumGoroutine()), 10), 269 "cpu_count": strconv.FormatInt(int64(runtime.NumCPU()), 10), 270 } 271} 272 273// checkServersProvider exists so that we can unit tests the requirements checking functions 274// without having to spin up a whole agent/server. 275type checkServersProvider interface { 276 CheckServers(datacenter string, fn func(*metadata.Server) bool) 277} 278 279// serverRequirementsFn should inspect the given metadata.Server struct 280// and return two booleans. The first indicates whether the given requirements 281// are met. The second indicates whether this server should be considered filtered. 282// 283// The reason for the two booleans is so that a requirement function could "filter" 284// out the left server members if we only want to consider things which are still 285// around or likely to come back (failed state). 286type serverRequirementFn func(*metadata.Server) (ok bool, filtered bool) 287 288type serversMeetRequirementsState struct { 289 // meetsRequirements is the callback to actual check for some specific requirement 290 meetsRequirements serverRequirementFn 291 292 // ok indicates whether all unfiltered servers meet the desired requirements 293 ok bool 294 295 // found is a boolean indicating that the meetsRequirement function accepted at 296 // least one unfiltered server. 297 found bool 298} 299 300func (s *serversMeetRequirementsState) update(srv *metadata.Server) bool { 301 ok, filtered := s.meetsRequirements(srv) 302 303 if filtered { 304 // keep going but don't update any of the internal state as this server 305 // was filtered by the requirements function 306 return true 307 } 308 309 // mark that at least one server processed was not filtered 310 s.found = true 311 312 if !ok { 313 // mark that at least one server does not meet the requirements 314 s.ok = false 315 316 // prevent continuing server evaluation 317 return false 318 } 319 320 // this should already be set but this will prevent accidentally reusing 321 // the state object from causing false-negatives. 322 s.ok = true 323 324 // continue evaluating servers 325 return true 326} 327 328// ServersInDCMeetRequirements returns whether the given server members meet the requirements as defined by the 329// callback function and whether at least one server remains unfiltered by the requirements function. 330func ServersInDCMeetRequirements(provider checkServersProvider, datacenter string, meetsRequirements serverRequirementFn) (ok bool, found bool) { 331 state := serversMeetRequirementsState{meetsRequirements: meetsRequirements, found: false, ok: true} 332 333 provider.CheckServers(datacenter, state.update) 334 335 return state.ok, state.found 336} 337 338// ServersInDCMeetMinimumVersion returns whether the given alive servers from a particular 339// datacenter are at least on the given Consul version. This also returns whether any 340// alive or failed servers are known in that datacenter (ignoring left and leaving ones) 341func ServersInDCMeetMinimumVersion(provider checkServersProvider, datacenter string, minVersion *version.Version) (ok bool, found bool) { 342 return ServersInDCMeetRequirements(provider, datacenter, func(srv *metadata.Server) (bool, bool) { 343 if srv.Status != serf.StatusAlive && srv.Status != serf.StatusFailed { 344 // filter out the left servers as those should not be factored into our requirements 345 return true, true 346 } 347 348 return !srv.Build.LessThan(minVersion), false 349 }) 350} 351 352// CheckServers implements the checkServersProvider interface for the Server 353func (s *Server) CheckServers(datacenter string, fn func(*metadata.Server) bool) { 354 if datacenter == s.config.Datacenter { 355 // use the ServerLookup type for the local DC 356 s.serverLookup.CheckServers(fn) 357 } else { 358 // use the router for all non-local DCs 359 s.router.CheckServers(datacenter, fn) 360 } 361} 362 363// CheckServers implements the checkServersProvider interface for the Client 364func (c *Client) CheckServers(datacenter string, fn func(*metadata.Server) bool) { 365 if datacenter != c.config.Datacenter { 366 return 367 } 368 369 c.routers.CheckServers(fn) 370} 371 372type serversACLMode struct { 373 // leader is the address of the leader 374 leader string 375 376 // mode indicates the overall ACL mode of the servers 377 mode structs.ACLMode 378 379 // leaderMode is the ACL mode of the leader server 380 leaderMode structs.ACLMode 381 382 // indicates that at least one server was processed 383 found bool 384} 385 386func (s *serversACLMode) init(leader string) { 387 s.leader = leader 388 s.mode = structs.ACLModeEnabled 389 s.leaderMode = structs.ACLModeUnknown 390 s.found = false 391} 392 393func (s *serversACLMode) update(srv *metadata.Server) bool { 394 if srv.Status != serf.StatusAlive && srv.Status != serf.StatusFailed { 395 // they are left or something so regardless we treat these servers as meeting 396 // the version requirement 397 return true 398 } 399 400 // mark that we processed at least one server 401 s.found = true 402 403 if srvAddr := srv.Addr.String(); srvAddr == s.leader { 404 s.leaderMode = srv.ACLs 405 } 406 407 switch srv.ACLs { 408 case structs.ACLModeDisabled: 409 // anything disabled means we cant enable ACLs 410 s.mode = structs.ACLModeDisabled 411 case structs.ACLModeEnabled: 412 // do nothing 413 case structs.ACLModeLegacy: 414 // This covers legacy mode and older server versions that don't advertise ACL support 415 if s.mode != structs.ACLModeDisabled && s.mode != structs.ACLModeUnknown { 416 s.mode = structs.ACLModeLegacy 417 } 418 default: 419 if s.mode != structs.ACLModeDisabled { 420 s.mode = structs.ACLModeUnknown 421 } 422 } 423 424 return true 425} 426 427// ServersGetACLMode checks all the servers in a particular datacenter and determines 428// what the minimum ACL mode amongst them is and what the leaders ACL mode is. 429// The "found" return value indicates whether there were any servers considered in 430// this datacenter. If that is false then the other mode return values are meaningless 431// as they will be ACLModeEnabled and ACLModeUnkown respectively. 432func ServersGetACLMode(provider checkServersProvider, leaderAddr string, datacenter string) (found bool, mode structs.ACLMode, leaderMode structs.ACLMode) { 433 var state serversACLMode 434 state.init(leaderAddr) 435 436 provider.CheckServers(datacenter, state.update) 437 438 return state.found, state.mode, state.leaderMode 439} 440