Allow [::] as a bind address (binds to first public IPv6 address)
This commit is contained in:
parent
4c3b2edfed
commit
508bc796a8
|
@ -142,10 +142,16 @@ func Create(config *Config, logOutput io.Writer) (*Agent, error) {
|
|||
if ip := net.ParseIP(config.AdvertiseAddr); ip == nil {
|
||||
return nil, fmt.Errorf("Failed to parse advertise address: %v", config.AdvertiseAddr)
|
||||
}
|
||||
} else if config.BindAddr != "0.0.0.0" && config.BindAddr != "" {
|
||||
} else if config.BindAddr != "0.0.0.0" && config.BindAddr != "" && config.BindAddr != "[::]" {
|
||||
config.AdvertiseAddr = config.BindAddr
|
||||
} else {
|
||||
ip, err := consul.GetPrivateIP()
|
||||
var err error
|
||||
var ip net.IP
|
||||
if config.BindAddr == "[::]" {
|
||||
ip, err = consul.GetPublicIPv6()
|
||||
} else {
|
||||
ip, err = consul.GetPrivateIP()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to get advertise address: %v", err)
|
||||
}
|
||||
|
|
|
@ -264,6 +264,52 @@ func getPrivateIP(addresses []net.Addr) (net.IP, error) {
|
|||
|
||||
}
|
||||
|
||||
// GetPublicIPv6 is used to return the first public IP address
|
||||
// associated with an interface on the machine
|
||||
func GetPublicIPv6() (net.IP, error) {
|
||||
addresses, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to get interface addresses: %v", err)
|
||||
}
|
||||
|
||||
return getPublicIPv6(addresses)
|
||||
}
|
||||
|
||||
func getPublicIPv6(addresses []net.Addr) (net.IP, error) {
|
||||
var candidates []net.IP
|
||||
|
||||
// Find public IPv6 address
|
||||
for _, rawAddr := range addresses {
|
||||
var ip net.IP
|
||||
switch addr := rawAddr.(type) {
|
||||
case *net.IPAddr:
|
||||
ip = addr.IP
|
||||
case *net.IPNet:
|
||||
ip = addr.IP
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
if ip.To4() != nil {
|
||||
continue
|
||||
}
|
||||
// do not bind link-local (fe80::/10) / ULA (fc00::/7) / loopback (::1)
|
||||
if ip[0]|0xf == 0xff || ip[0]|0 == 0 {
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, ip)
|
||||
}
|
||||
numIps := len(candidates)
|
||||
switch numIps {
|
||||
case 0:
|
||||
return nil, fmt.Errorf("No public IPv6 address found")
|
||||
case 1:
|
||||
return candidates[0], nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Multiple public IPv6 addresses found. Please configure one.")
|
||||
}
|
||||
}
|
||||
|
||||
// Converts bytes to an integer
|
||||
func bytesToUint64(b []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(b)
|
||||
|
|
|
@ -275,3 +275,85 @@ func TestGenerateUUID(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPublicIPv6(t *testing.T) {
|
||||
ip, _, err := net.ParseCIDR("fe80::1/128")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse link-local cidr: %v", err)
|
||||
}
|
||||
|
||||
ip2, _, err := net.ParseCIDR("::1/128")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse loopback cidr: %v", err)
|
||||
}
|
||||
|
||||
pubIP, _, err := net.ParseCIDR("2001:0db8:85a3::8a2e:0370:7334/128")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse public cidr: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
addrs []net.Addr
|
||||
expected net.IP
|
||||
err error
|
||||
}{
|
||||
{
|
||||
addrs: []net.Addr{
|
||||
&net.IPAddr{
|
||||
IP: ip,
|
||||
},
|
||||
&net.IPAddr{
|
||||
IP: ip2,
|
||||
},
|
||||
&net.IPAddr{
|
||||
IP: pubIP,
|
||||
},
|
||||
},
|
||||
expected: pubIP,
|
||||
},
|
||||
{
|
||||
addrs: []net.Addr{
|
||||
&net.IPAddr{
|
||||
IP: ip,
|
||||
},
|
||||
&net.IPAddr{
|
||||
IP: ip2,
|
||||
},
|
||||
},
|
||||
err: errors.New("No public IPv6 address found"),
|
||||
},
|
||||
{
|
||||
addrs: []net.Addr{
|
||||
&net.IPAddr{
|
||||
IP: ip,
|
||||
},
|
||||
&net.IPAddr{
|
||||
IP: ip,
|
||||
},
|
||||
&net.IPAddr{
|
||||
IP: pubIP,
|
||||
},
|
||||
&net.IPAddr{
|
||||
IP: pubIP,
|
||||
},
|
||||
},
|
||||
err: errors.New("Multiple public IPv6 addresses found. Please configure one."),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
ip, err := getPublicIPv6(test.addrs)
|
||||
switch {
|
||||
case test.err != nil && err != nil:
|
||||
if err.Error() != test.err.Error() {
|
||||
t.Fatalf("unexpected error: %v != %v", test.err, err)
|
||||
}
|
||||
case (test.err == nil && err != nil) || (test.err != nil && err == nil):
|
||||
t.Fatalf("unexpected error: %v != %v", test.err, err)
|
||||
default:
|
||||
if !test.expected.Equal(ip) {
|
||||
t.Fatalf("unexpected ip: %v != %v", ip, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,8 @@ The options below are all specified on the command-line.
|
|||
for internal cluster communications.
|
||||
This is an IP address that should be reachable by all other nodes in the cluster.
|
||||
By default, this is "0.0.0.0", meaning Consul will use the first available private
|
||||
IP address. Consul uses both TCP and UDP and the same port for both. If you
|
||||
IPv4 address. If you specify "[::]", Consul will use the first available public IPv6 address.
|
||||
Consul uses both TCP and UDP and the same port for both. If you
|
||||
have any firewalls, be sure to allow both protocols.
|
||||
|
||||
* <a name="_client"></a><a href="#_client">`-client`</a> - The address to which
|
||||
|
|
Loading…
Reference in New Issue