github.com/DerekStrickland/consul@v1.4.5/agent/consul/util.go (about)

     1  package consul
     2  
     3  import (
     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   */
    25  var privateBlocks []*net.IPNet
    26  
    27  func 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.
    71  func 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.
    99  func 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
   107  func 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
   118  func 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
   155  func 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  
   164  func 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
   201  func 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  
   210  func isUniqueLocalAddress(ip net.IP) bool {
   211  	return len(ip) == net.IPv6len && ip[0] == 0xfc && ip[1] == 0x00
   212  }
   213  
   214  func 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
   250  func bytesToUint64(b []byte) uint64 {
   251  	return binary.BigEndian.Uint64(b)
   252  }
   253  
   254  // Converts a uint to a byte slice
   255  func 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
   262  func 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  // ServersMeetMinimumVersion returns whether the given alive servers are at least on the
   274  // given Consul version
   275  func ServersMeetMinimumVersion(members []serf.Member, minVersion *version.Version) bool {
   276  	for _, member := range members {
   277  		if valid, parts := metadata.IsConsulServer(member); valid && parts.Status == serf.StatusAlive {
   278  			if parts.Build.LessThan(minVersion) {
   279  				return false
   280  			}
   281  		}
   282  	}
   283  
   284  	return true
   285  }
   286  
   287  func ServersGetACLMode(members []serf.Member, leader string, datacenter string) (numServers int, mode structs.ACLMode, leaderMode structs.ACLMode) {
   288  	numServers = 0
   289  	mode = structs.ACLModeEnabled
   290  	leaderMode = structs.ACLModeUnknown
   291  	for _, member := range members {
   292  		if valid, parts := metadata.IsConsulServer(member); valid {
   293  
   294  			if datacenter != "" && parts.Datacenter != datacenter {
   295  				continue
   296  			}
   297  
   298  			numServers += 1
   299  
   300  			if memberAddr := (&net.TCPAddr{IP: member.Addr, Port: parts.Port}).String(); memberAddr == leader {
   301  				leaderMode = parts.ACLs
   302  			}
   303  
   304  			switch parts.ACLs {
   305  			case structs.ACLModeDisabled:
   306  				// anything disabled means we cant enable ACLs
   307  				mode = structs.ACLModeDisabled
   308  			case structs.ACLModeEnabled:
   309  				// do nothing
   310  			case structs.ACLModeLegacy:
   311  				// This covers legacy mode and older server versions that don't advertise ACL support
   312  				if mode != structs.ACLModeDisabled && mode != structs.ACLModeUnknown {
   313  					mode = structs.ACLModeLegacy
   314  				}
   315  			default:
   316  				if mode != structs.ACLModeDisabled {
   317  					mode = structs.ACLModeUnknown
   318  				}
   319  			}
   320  		}
   321  	}
   322  
   323  	return
   324  }