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