mirror of https://github.com/status-im/consul.git
Add support for dual stack IPv4/IPv6 network (#6640)
* Use consts for well known tagged adress keys * Add ipv4 and ipv6 tagged addresses for node lan and wan * Add ipv4 and ipv6 tagged addresses for service lan and wan * Use IPv4 and IPv6 address in DNS
This commit is contained in:
parent
5dc8875bd3
commit
ba8fd8296f
|
@ -2258,6 +2258,26 @@ func (a *Agent) addServiceInternal(req *addServiceRequest) error {
|
|||
a.PauseSync()
|
||||
defer a.ResumeSync()
|
||||
|
||||
// Set default tagged addresses
|
||||
serviceIP := net.ParseIP(service.Address)
|
||||
serviceAddressIs4 := serviceIP != nil && serviceIP.To4() != nil
|
||||
serviceAddressIs6 := serviceIP != nil && serviceIP.To4() == nil
|
||||
if service.TaggedAddresses == nil {
|
||||
service.TaggedAddresses = map[string]structs.ServiceAddress{}
|
||||
}
|
||||
if _, ok := service.TaggedAddresses[structs.TaggedAddressLANIPv4]; !ok && serviceAddressIs4 {
|
||||
service.TaggedAddresses[structs.TaggedAddressLANIPv4] = structs.ServiceAddress{Address: service.Address, Port: service.Port}
|
||||
}
|
||||
if _, ok := service.TaggedAddresses[structs.TaggedAddressWANIPv4]; !ok && serviceAddressIs4 {
|
||||
service.TaggedAddresses[structs.TaggedAddressWANIPv4] = structs.ServiceAddress{Address: service.Address, Port: service.Port}
|
||||
}
|
||||
if _, ok := service.TaggedAddresses[structs.TaggedAddressLANIPv6]; !ok && serviceAddressIs6 {
|
||||
service.TaggedAddresses[structs.TaggedAddressLANIPv6] = structs.ServiceAddress{Address: service.Address, Port: service.Port}
|
||||
}
|
||||
if _, ok := service.TaggedAddresses[structs.TaggedAddressWANIPv6]; !ok && serviceAddressIs6 {
|
||||
service.TaggedAddresses[structs.TaggedAddressWANIPv6] = structs.ServiceAddress{Address: service.Address, Port: service.Port}
|
||||
}
|
||||
|
||||
// Take a snapshot of the current state of checks (if any), and when adding
|
||||
// a check that already existed carry over the state before resuming
|
||||
// anti-entropy.
|
||||
|
@ -2453,6 +2473,34 @@ func (a *Agent) validateService(service *structs.NodeService, chkTypes []*struct
|
|||
}
|
||||
}
|
||||
|
||||
// Check IPv4/IPv6 tagged addresses
|
||||
if service.TaggedAddresses != nil {
|
||||
if sa, ok := service.TaggedAddresses[structs.TaggedAddressLANIPv4]; ok {
|
||||
ip := net.ParseIP(sa.Address)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
return fmt.Errorf("Service tagged address %q must be a valid ipv4 address", structs.TaggedAddressLANIPv4)
|
||||
}
|
||||
}
|
||||
if sa, ok := service.TaggedAddresses[structs.TaggedAddressWANIPv4]; ok {
|
||||
ip := net.ParseIP(sa.Address)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
return fmt.Errorf("Service tagged address %q must be a valid ipv4 address", structs.TaggedAddressWANIPv4)
|
||||
}
|
||||
}
|
||||
if sa, ok := service.TaggedAddresses[structs.TaggedAddressLANIPv6]; ok {
|
||||
ip := net.ParseIP(sa.Address)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
return fmt.Errorf("Service tagged address %q must be a valid ipv6 address", structs.TaggedAddressLANIPv6)
|
||||
}
|
||||
}
|
||||
if sa, ok := service.TaggedAddresses[structs.TaggedAddressLANIPv6]; ok {
|
||||
ip := net.ParseIP(sa.Address)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
return fmt.Errorf("Service tagged address %q must be a valid ipv6 address", structs.TaggedAddressLANIPv6)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -3031,10 +3031,11 @@ func testAgent_RegisterService_UnmanagedConnectProxy(t *testing.T, extraHCL stri
|
|||
|
||||
func testDefaultSidecar(svc string, port int, fns ...func(*structs.NodeService)) *structs.NodeService {
|
||||
ns := &structs.NodeService{
|
||||
ID: svc + "-sidecar-proxy",
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
Service: svc + "-sidecar-proxy",
|
||||
Port: 2222,
|
||||
ID: svc + "-sidecar-proxy",
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
Service: svc + "-sidecar-proxy",
|
||||
Port: 2222,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Weights: &structs.Weights{
|
||||
Passing: 1,
|
||||
Warning: 1,
|
||||
|
@ -3396,9 +3397,10 @@ func testAgent_RegisterServiceDeregisterService_Sidecar(t *testing.T, extraHCL s
|
|||
// Note here that although the registration here didn't register it, we
|
||||
// should still see the NodeService we pre-registered here.
|
||||
wantNS: &structs.NodeService{
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "fake-sidecar",
|
||||
Port: 9999,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "fake-sidecar",
|
||||
Port: 9999,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Weights: &structs.Weights{
|
||||
Passing: 1,
|
||||
Warning: 1,
|
||||
|
@ -3439,6 +3441,7 @@ func testAgent_RegisterServiceDeregisterService_Sidecar(t *testing.T, extraHCL s
|
|||
Service: "web-sidecar-proxy",
|
||||
LocallyRegisteredAsSidecar: true,
|
||||
Port: 6666,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Weights: &structs.Weights{
|
||||
Passing: 1,
|
||||
Warning: 1,
|
||||
|
|
|
@ -718,6 +718,134 @@ func testAgent_AddServiceNoRemoteExec(t *testing.T, extraHCL string) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAddServiceIPv4TaggedDefault(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
defer a.Shutdown()
|
||||
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||
|
||||
srv := &structs.NodeService{
|
||||
Service: "my_service",
|
||||
ID: "my_service_id",
|
||||
Port: 8100,
|
||||
Address: "10.0.1.2",
|
||||
}
|
||||
|
||||
err := a.AddService(srv, []*structs.CheckType{}, false, "", ConfigSourceRemote)
|
||||
require.Nil(t, err)
|
||||
|
||||
ns := a.State.Service(structs.NewServiceID("my_service_id", nil))
|
||||
require.NotNil(t, ns)
|
||||
|
||||
svcAddr := structs.ServiceAddress{Address: srv.Address, Port: srv.Port}
|
||||
require.Equal(t, svcAddr, ns.TaggedAddresses[structs.TaggedAddressLANIPv4])
|
||||
require.Equal(t, svcAddr, ns.TaggedAddresses[structs.TaggedAddressWANIPv4])
|
||||
_, ok := ns.TaggedAddresses[structs.TaggedAddressLANIPv6]
|
||||
require.False(t, ok)
|
||||
_, ok = ns.TaggedAddresses[structs.TaggedAddressWANIPv6]
|
||||
require.False(t, ok)
|
||||
}
|
||||
|
||||
func TestAddServiceIPv6TaggedDefault(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
defer a.Shutdown()
|
||||
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||
|
||||
srv := &structs.NodeService{
|
||||
Service: "my_service",
|
||||
ID: "my_service_id",
|
||||
Port: 8100,
|
||||
Address: "::5",
|
||||
}
|
||||
|
||||
err := a.AddService(srv, []*structs.CheckType{}, false, "", ConfigSourceRemote)
|
||||
require.Nil(t, err)
|
||||
|
||||
ns := a.State.Service(structs.NewServiceID("my_service_id", nil))
|
||||
require.NotNil(t, ns)
|
||||
|
||||
svcAddr := structs.ServiceAddress{Address: srv.Address, Port: srv.Port}
|
||||
require.Equal(t, svcAddr, ns.TaggedAddresses[structs.TaggedAddressLANIPv6])
|
||||
require.Equal(t, svcAddr, ns.TaggedAddresses[structs.TaggedAddressWANIPv6])
|
||||
_, ok := ns.TaggedAddresses[structs.TaggedAddressLANIPv4]
|
||||
require.False(t, ok)
|
||||
_, ok = ns.TaggedAddresses[structs.TaggedAddressWANIPv4]
|
||||
require.False(t, ok)
|
||||
}
|
||||
|
||||
func TestAddServiceIPv4TaggedSet(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
defer a.Shutdown()
|
||||
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||
|
||||
srv := &structs.NodeService{
|
||||
Service: "my_service",
|
||||
ID: "my_service_id",
|
||||
Port: 8100,
|
||||
Address: "10.0.1.2",
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{
|
||||
structs.TaggedAddressWANIPv4: {
|
||||
Address: "10.100.200.5",
|
||||
Port: 8100,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := a.AddService(srv, []*structs.CheckType{}, false, "", ConfigSourceRemote)
|
||||
require.Nil(t, err)
|
||||
|
||||
ns := a.State.Service(structs.NewServiceID("my_service_id", nil))
|
||||
require.NotNil(t, ns)
|
||||
|
||||
svcAddr := structs.ServiceAddress{Address: srv.Address, Port: srv.Port}
|
||||
require.Equal(t, svcAddr, ns.TaggedAddresses[structs.TaggedAddressLANIPv4])
|
||||
require.Equal(t, structs.ServiceAddress{Address: "10.100.200.5", Port: 8100}, ns.TaggedAddresses[structs.TaggedAddressWANIPv4])
|
||||
_, ok := ns.TaggedAddresses[structs.TaggedAddressLANIPv6]
|
||||
require.False(t, ok)
|
||||
_, ok = ns.TaggedAddresses[structs.TaggedAddressWANIPv6]
|
||||
require.False(t, ok)
|
||||
}
|
||||
|
||||
func TestAddServiceIPv6TaggedSet(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
defer a.Shutdown()
|
||||
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
||||
|
||||
srv := &structs.NodeService{
|
||||
Service: "my_service",
|
||||
ID: "my_service_id",
|
||||
Port: 8100,
|
||||
Address: "::5",
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{
|
||||
structs.TaggedAddressWANIPv6: {
|
||||
Address: "::6",
|
||||
Port: 8100,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := a.AddService(srv, []*structs.CheckType{}, false, "", ConfigSourceRemote)
|
||||
require.Nil(t, err)
|
||||
|
||||
ns := a.State.Service(structs.NewServiceID("my_service_id", nil))
|
||||
require.NotNil(t, ns)
|
||||
|
||||
svcAddr := structs.ServiceAddress{Address: srv.Address, Port: srv.Port}
|
||||
require.Equal(t, svcAddr, ns.TaggedAddresses[structs.TaggedAddressLANIPv6])
|
||||
require.Equal(t, structs.ServiceAddress{Address: "::6", Port: 8100}, ns.TaggedAddresses[structs.TaggedAddressWANIPv6])
|
||||
_, ok := ns.TaggedAddresses[structs.TaggedAddressLANIPv4]
|
||||
require.False(t, ok)
|
||||
_, ok = ns.TaggedAddresses[structs.TaggedAddressWANIPv4]
|
||||
require.False(t, ok)
|
||||
}
|
||||
|
||||
func TestAgent_RemoveService(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
@ -1876,12 +2004,13 @@ func testAgent_persistedService_compat(t *testing.T, extraHCL string) {
|
|||
defer a.Shutdown()
|
||||
|
||||
svc := &structs.NodeService{
|
||||
ID: "redis",
|
||||
Service: "redis",
|
||||
Tags: []string{"foo"},
|
||||
Port: 8000,
|
||||
Weights: &structs.Weights{Passing: 1, Warning: 1},
|
||||
EnterpriseMeta: *structs.DefaultEnterpriseMeta(),
|
||||
ID: "redis",
|
||||
Service: "redis",
|
||||
Tags: []string{"foo"},
|
||||
Port: 8000,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Weights: &structs.Weights{Passing: 1, Warning: 1},
|
||||
EnterpriseMeta: *structs.DefaultEnterpriseMeta(),
|
||||
}
|
||||
|
||||
// Encode the NodeService directly. This is what previous versions
|
||||
|
|
|
@ -138,7 +138,7 @@ RETRY_ONCE:
|
|||
}
|
||||
out.ConsistencyLevel = args.QueryOptions.ConsistencyLevel()
|
||||
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.Nodes)
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.Nodes, TranslateAddressAcceptAny)
|
||||
|
||||
// Use empty list instead of nil
|
||||
if out.Nodes == nil {
|
||||
|
@ -284,7 +284,7 @@ func (s *HTTPServer) catalogServiceNodes(resp http.ResponseWriter, req *http.Req
|
|||
}
|
||||
|
||||
out.ConsistencyLevel = args.QueryOptions.ConsistencyLevel()
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.ServiceNodes)
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.ServiceNodes, TranslateAddressAcceptAny)
|
||||
|
||||
// Use empty list instead of nil
|
||||
if out.ServiceNodes == nil {
|
||||
|
@ -340,7 +340,7 @@ RETRY_ONCE:
|
|||
}
|
||||
out.ConsistencyLevel = args.QueryOptions.ConsistencyLevel()
|
||||
if out.NodeServices != nil {
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.NodeServices)
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.NodeServices, TranslateAddressAcceptAny)
|
||||
}
|
||||
|
||||
// TODO: The NodeServices object in IndexedNodeServices is a pointer to
|
||||
|
|
|
@ -415,6 +415,7 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
|
|||
|
||||
bindAddr := bindAddrs[0].(*net.IPAddr)
|
||||
advertiseAddr := b.makeIPAddr(b.expandFirstIP("advertise_addr", c.AdvertiseAddrLAN), bindAddr)
|
||||
|
||||
if ipaddr.IsAny(advertiseAddr) {
|
||||
|
||||
var addrtyp string
|
||||
|
@ -460,7 +461,39 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
|
|||
|
||||
// derive other advertise addresses from the advertise address
|
||||
advertiseAddrLAN := b.makeIPAddr(b.expandFirstIP("advertise_addr", c.AdvertiseAddrLAN), advertiseAddr)
|
||||
advertiseAddrIsV6 := advertiseAddr.IP.To4() == nil
|
||||
var advertiseAddrV4, advertiseAddrV6 *net.IPAddr
|
||||
if !advertiseAddrIsV6 {
|
||||
advertiseAddrV4 = advertiseAddr
|
||||
} else {
|
||||
advertiseAddrV6 = advertiseAddr
|
||||
}
|
||||
advertiseAddrLANIPv4 := b.makeIPAddr(b.expandFirstIP("advertise_addr_ipv4", c.AdvertiseAddrLANIPv4), advertiseAddrV4)
|
||||
if advertiseAddrLANIPv4 != nil && advertiseAddrLANIPv4.IP.To4() == nil {
|
||||
return RuntimeConfig{}, fmt.Errorf("advertise_addr_ipv4 must be an ipv4 address")
|
||||
}
|
||||
advertiseAddrLANIPv6 := b.makeIPAddr(b.expandFirstIP("advertise_addr_ipv6", c.AdvertiseAddrLANIPv6), advertiseAddrV6)
|
||||
if advertiseAddrLANIPv6 != nil && advertiseAddrLANIPv6.IP.To4() != nil {
|
||||
return RuntimeConfig{}, fmt.Errorf("advertise_addr_ipv6 must be an ipv6 address")
|
||||
}
|
||||
|
||||
advertiseAddrWAN := b.makeIPAddr(b.expandFirstIP("advertise_addr_wan", c.AdvertiseAddrWAN), advertiseAddrLAN)
|
||||
advertiseAddrWANIsV6 := advertiseAddrWAN.IP.To4() == nil
|
||||
var advertiseAddrWANv4, advertiseAddrWANv6 *net.IPAddr
|
||||
if !advertiseAddrWANIsV6 {
|
||||
advertiseAddrWANv4 = advertiseAddrWAN
|
||||
} else {
|
||||
advertiseAddrWANv6 = advertiseAddrWAN
|
||||
}
|
||||
advertiseAddrWANIPv4 := b.makeIPAddr(b.expandFirstIP("advertise_addr_wan_ipv4", c.AdvertiseAddrWANIPv4), advertiseAddrWANv4)
|
||||
if advertiseAddrWANIPv4 != nil && advertiseAddrWANIPv4.IP.To4() == nil {
|
||||
return RuntimeConfig{}, fmt.Errorf("advertise_addr_wan_ipv4 must be an ipv4 address")
|
||||
}
|
||||
advertiseAddrWANIPv6 := b.makeIPAddr(b.expandFirstIP("advertise_addr_wan_ipv6", c.AdvertiseAddrWANIPv6), advertiseAddrWANv6)
|
||||
if advertiseAddrWANIPv6 != nil && advertiseAddrWANIPv6.IP.To4() != nil {
|
||||
return RuntimeConfig{}, fmt.Errorf("advertise_addr_wan_ipv6 must be an ipv6 address")
|
||||
}
|
||||
|
||||
rpcAdvertiseAddr := &net.TCPAddr{IP: advertiseAddrLAN.IP, Port: serverPort}
|
||||
serfAdvertiseAddrLAN := &net.TCPAddr{IP: advertiseAddrLAN.IP, Port: serfPortLAN}
|
||||
// Only initialize serf WAN advertise address when its enabled
|
||||
|
@ -509,8 +542,22 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
|
|||
if c.TaggedAddresses == nil {
|
||||
c.TaggedAddresses = make(map[string]string)
|
||||
}
|
||||
c.TaggedAddresses["lan"] = advertiseAddrLAN.IP.String()
|
||||
c.TaggedAddresses["wan"] = advertiseAddrWAN.IP.String()
|
||||
|
||||
c.TaggedAddresses[structs.TaggedAddressLAN] = advertiseAddrLAN.IP.String()
|
||||
if advertiseAddrLANIPv4 != nil {
|
||||
c.TaggedAddresses[structs.TaggedAddressLANIPv4] = advertiseAddrLANIPv4.IP.String()
|
||||
}
|
||||
if advertiseAddrLANIPv6 != nil {
|
||||
c.TaggedAddresses[structs.TaggedAddressLANIPv6] = advertiseAddrLANIPv6.IP.String()
|
||||
}
|
||||
|
||||
c.TaggedAddresses[structs.TaggedAddressWAN] = advertiseAddrWAN.IP.String()
|
||||
if advertiseAddrWANIPv4 != nil {
|
||||
c.TaggedAddresses[structs.TaggedAddressWANIPv4] = advertiseAddrWANIPv4.IP.String()
|
||||
}
|
||||
if advertiseAddrWANIPv6 != nil {
|
||||
c.TaggedAddresses[structs.TaggedAddressWANIPv6] = advertiseAddrWANIPv6.IP.String()
|
||||
}
|
||||
|
||||
// segments
|
||||
var segments []structs.NetworkSegment
|
||||
|
|
|
@ -182,7 +182,11 @@ type Config struct {
|
|||
ACL ACL `json:"acl,omitempty" hcl:"acl" mapstructure:"acl"`
|
||||
Addresses Addresses `json:"addresses,omitempty" hcl:"addresses" mapstructure:"addresses"`
|
||||
AdvertiseAddrLAN *string `json:"advertise_addr,omitempty" hcl:"advertise_addr" mapstructure:"advertise_addr"`
|
||||
AdvertiseAddrLANIPv4 *string `json:"advertise_addr_ipv4,omitempty" hcl:"advertise_addr_ipv4" mapstructure:"advertise_addr_ipv4"`
|
||||
AdvertiseAddrLANIPv6 *string `json:"advertise_addr_ipv6,omitempty" hcl:"advertise_addr_ipv6" mapstructure:"advertise_addr_ipv6"`
|
||||
AdvertiseAddrWAN *string `json:"advertise_addr_wan,omitempty" hcl:"advertise_addr_wan" mapstructure:"advertise_addr_wan"`
|
||||
AdvertiseAddrWANIPv4 *string `json:"advertise_addr_wan_ipv4,omitempty" hcl:"advertise_addr_wan_ipv4" mapstructure:"advertise_addr_wan_ipv4"`
|
||||
AdvertiseAddrWANIPv6 *string `json:"advertise_addr_wan_ipv6,omitempty" hcl:"advertise_addr_wan_ipv6" mapstructure:"advertise_addr_ipv6"`
|
||||
Autopilot Autopilot `json:"autopilot,omitempty" hcl:"autopilot" mapstructure:"autopilot"`
|
||||
BindAddr *string `json:"bind_addr,omitempty" hcl:"bind_addr" mapstructure:"bind_addr"`
|
||||
Bootstrap *bool `json:"bootstrap,omitempty" hcl:"bootstrap" mapstructure:"bootstrap"`
|
||||
|
|
|
@ -70,8 +70,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfAdvertiseAddrLAN = tcpAddr("1.2.3.4:8301")
|
||||
rt.SerfAdvertiseAddrWAN = tcpAddr("1.2.3.4:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "1.2.3.4",
|
||||
"lan_ipv4": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -86,8 +88,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.AdvertiseAddrWAN = ipAddr("1.2.3.4")
|
||||
rt.SerfAdvertiseAddrWAN = tcpAddr("1.2.3.4:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "10.0.0.1",
|
||||
"lan_ipv4": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -106,8 +110,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfAdvertiseAddrLAN = tcpAddr("1.2.3.4:8301")
|
||||
rt.SerfAdvertiseAddrWAN = tcpAddr("5.6.7.8:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "1.2.3.4",
|
||||
"wan": "5.6.7.8",
|
||||
"lan": "1.2.3.4",
|
||||
"lan_ipv4": "1.2.3.4",
|
||||
"wan": "5.6.7.8",
|
||||
"wan_ipv4": "5.6.7.8",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -129,8 +135,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfBindAddrLAN = tcpAddr("1.2.3.4:8301")
|
||||
rt.SerfBindAddrWAN = tcpAddr("1.2.3.4:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "1.2.3.4",
|
||||
"lan_ipv4": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -282,7 +290,12 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfBindAddrWAN = tcpAddr("127.0.0.1:8302")
|
||||
rt.ServerMode = true
|
||||
rt.SkipLeaveOnInt = true
|
||||
rt.TaggedAddresses = map[string]string{"lan": "127.0.0.1", "wan": "127.0.0.1"}
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "127.0.0.1",
|
||||
"lan_ipv4": "127.0.0.1",
|
||||
"wan": "127.0.0.1",
|
||||
"wan_ipv4": "127.0.0.1",
|
||||
}
|
||||
rt.ConsulCoordinateUpdatePeriod = 100 * time.Millisecond
|
||||
rt.ConsulRaftElectionTimeout = 52 * time.Millisecond
|
||||
rt.ConsulRaftHeartbeatTimeout = 35 * time.Millisecond
|
||||
|
@ -836,8 +849,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfBindAddrLAN = tcpAddr("0.0.0.0:8301")
|
||||
rt.SerfBindAddrWAN = tcpAddr("0.0.0.0:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "10.0.0.1",
|
||||
"wan": "10.0.0.1",
|
||||
"lan": "10.0.0.1",
|
||||
"lan_ipv4": "10.0.0.1",
|
||||
"wan": "10.0.0.1",
|
||||
"wan_ipv4": "10.0.0.1",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -858,8 +873,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfBindAddrLAN = tcpAddr("[::]:8301")
|
||||
rt.SerfBindAddrWAN = tcpAddr("[::]:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "dead:beef::1",
|
||||
"wan": "dead:beef::1",
|
||||
"lan": "dead:beef::1",
|
||||
"lan_ipv6": "dead:beef::1",
|
||||
"wan": "dead:beef::1",
|
||||
"wan_ipv6": "dead:beef::1",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -883,8 +900,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfBindAddrLAN = tcpAddr("0.0.0.0:8301")
|
||||
rt.SerfBindAddrWAN = tcpAddr("0.0.0.0:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "1.2.3.4",
|
||||
"lan_ipv4": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -1101,8 +1120,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfAdvertiseAddrLAN = tcpAddr("1.2.3.4:8301")
|
||||
rt.SerfAdvertiseAddrWAN = tcpAddr("1.2.3.4:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "1.2.3.4",
|
||||
"lan_ipv4": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -1116,8 +1137,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.AdvertiseAddrWAN = ipAddr("1.2.3.4")
|
||||
rt.SerfAdvertiseAddrWAN = tcpAddr("1.2.3.4:8302")
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "10.0.0.1",
|
||||
"lan_ipv4": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -1154,8 +1177,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfPortWAN = 3000
|
||||
rt.ServerPort = 1000
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "1.2.3.4",
|
||||
"lan_ipv4": "1.2.3.4",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -1192,8 +1217,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfPortWAN = 3000
|
||||
rt.ServerPort = 1000
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "10.0.0.1",
|
||||
"lan_ipv4": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -1218,8 +1245,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfAdvertiseAddrWAN = nil
|
||||
rt.SerfBindAddrWAN = nil
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"lan": "10.0.0.1",
|
||||
"lan_ipv4": "10.0.0.1",
|
||||
"wan": "1.2.3.4",
|
||||
"wan_ipv4": "1.2.3.4",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
rt.SerfPortWAN = -1
|
||||
|
@ -1430,8 +1459,10 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
|||
rt.SerfBindAddrWAN = tcpAddr("4.4.4.4:8302")
|
||||
rt.StartJoinAddrsLAN = []string{"c", "d", "a", "b"}
|
||||
rt.TaggedAddresses = map[string]string{
|
||||
"lan": "1.1.1.1",
|
||||
"wan": "2.2.2.2",
|
||||
"lan": "1.1.1.1",
|
||||
"lan_ipv4": "1.1.1.1",
|
||||
"wan": "2.2.2.2",
|
||||
"wan_ipv4": "2.2.2.2",
|
||||
}
|
||||
rt.DataDir = dataDir
|
||||
},
|
||||
|
@ -5464,7 +5495,9 @@ func TestFullConfig(t *testing.T) {
|
|||
"7MYgHrYH": "dALJAhLD",
|
||||
"h6DdBy6K": "ebrr9zZ8",
|
||||
"lan": "17.99.29.16",
|
||||
"lan_ipv4": "17.99.29.16",
|
||||
"wan": "78.63.37.19",
|
||||
"wan_ipv4": "78.63.37.19",
|
||||
},
|
||||
TranslateWANAddrs: true,
|
||||
UIContentPath: "/consul/",
|
||||
|
|
69
agent/dns.go
69
agent/dns.go
|
@ -1308,24 +1308,25 @@ RPC:
|
|||
|
||||
// serviceNodeRecords is used to add the node records for a service lookup
|
||||
func (d *DNSServer) serviceNodeRecords(cfg *dnsConfig, dc string, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration, maxRecursionLevel int) {
|
||||
qName := req.Question[0].Name
|
||||
handled := make(map[string]struct{})
|
||||
var answerCNAME []dns.RR = nil
|
||||
|
||||
count := 0
|
||||
for _, node := range nodes {
|
||||
addr := d.serviceNodeAddr(node, dc, qName)
|
||||
|
||||
// Avoid duplicate entries, possible if a node has
|
||||
// the same service on multiple ports, etc.
|
||||
if _, ok := handled[addr]; ok {
|
||||
continue
|
||||
}
|
||||
handled[addr] = struct{}{}
|
||||
|
||||
// Add the node record
|
||||
had_answer := false
|
||||
records, _ := d.nodeServiceRecords(dc, node, req, ttl, cfg, maxRecursionLevel)
|
||||
if len(records) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Avoid duplicate entries, possible if a node has
|
||||
// the same service on multiple ports, etc.
|
||||
if _, ok := handled[records[0].String()]; ok {
|
||||
continue
|
||||
}
|
||||
handled[records[0].String()] = struct{}{}
|
||||
|
||||
if records != nil {
|
||||
switch records[0].(type) {
|
||||
case *dns.CNAME:
|
||||
|
@ -1399,25 +1400,6 @@ func findWeight(node structs.CheckServiceNode) int {
|
|||
}
|
||||
}
|
||||
|
||||
// serviceNodeAddr is used to identify target service address
|
||||
func (d *DNSServer) serviceNodeAddr(serviceNode structs.CheckServiceNode, dc string, dnsQuery string) string {
|
||||
nodeAddress := d.agent.TranslateAddress(dc, serviceNode.Node.Address, serviceNode.Node.TaggedAddresses)
|
||||
serviceAddress := d.agent.TranslateServiceAddress(dc, serviceNode.Service.Address, serviceNode.Service.TaggedAddresses)
|
||||
addr := nodeAddress
|
||||
|
||||
if serviceAddress != "" {
|
||||
addr = serviceAddress
|
||||
}
|
||||
|
||||
// If the service address is a CNAME for the service we are looking
|
||||
// for then use the node address.
|
||||
if dnsQuery == strings.TrimSuffix(addr, ".")+"." {
|
||||
addr = nodeAddress
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func (d *DNSServer) encodeIPAsFqdn(dc string, ip net.IP) string {
|
||||
ipv4 := ip.To4()
|
||||
if ipv4 != nil {
|
||||
|
@ -1460,7 +1442,16 @@ func makeARecord(qType uint16, ip net.IP, ttl time.Duration) dns.RR {
|
|||
// In case of an SRV query the answer will be a IN SRV and additional data will store an IN A to the node IP
|
||||
// Otherwise it will return a IN A record
|
||||
func (d *DNSServer) makeRecordFromNode(dc string, node *structs.Node, qType uint16, qName string, ttl time.Duration, maxRecursionLevel int) []dns.RR {
|
||||
addr := d.agent.TranslateAddress(node.Datacenter, node.Address, node.TaggedAddresses)
|
||||
addrTranslate := TranslateAddressAcceptDomain
|
||||
if qType == dns.TypeA {
|
||||
addrTranslate |= TranslateAddressAcceptIPv4
|
||||
} else if qType == dns.TypeAAAA {
|
||||
addrTranslate |= TranslateAddressAcceptIPv6
|
||||
} else {
|
||||
addrTranslate |= TranslateAddressAcceptAny
|
||||
}
|
||||
|
||||
addr := d.agent.TranslateAddress(node.Datacenter, node.Address, node.TaggedAddresses, addrTranslate)
|
||||
ip := net.ParseIP(addr)
|
||||
|
||||
var res []dns.RR
|
||||
|
@ -1621,8 +1612,20 @@ MORE_REC:
|
|||
}
|
||||
|
||||
func (d *DNSServer) nodeServiceRecords(dc string, node structs.CheckServiceNode, req *dns.Msg, ttl time.Duration, cfg *dnsConfig, maxRecursionLevel int) ([]dns.RR, []dns.RR) {
|
||||
serviceAddr := d.agent.TranslateServiceAddress(dc, node.Service.Address, node.Service.TaggedAddresses)
|
||||
nodeAddr := d.agent.TranslateAddress(node.Node.Datacenter, node.Node.Address, node.Node.TaggedAddresses)
|
||||
addrTranslate := TranslateAddressAcceptDomain
|
||||
if req.Question[0].Qtype == dns.TypeA {
|
||||
addrTranslate |= TranslateAddressAcceptIPv4
|
||||
} else if req.Question[0].Qtype == dns.TypeAAAA {
|
||||
addrTranslate |= TranslateAddressAcceptIPv6
|
||||
} else {
|
||||
addrTranslate |= TranslateAddressAcceptAny
|
||||
}
|
||||
|
||||
serviceAddr := d.agent.TranslateServiceAddress(dc, node.Service.Address, node.Service.TaggedAddresses, addrTranslate)
|
||||
nodeAddr := d.agent.TranslateAddress(node.Node.Datacenter, node.Node.Address, node.Node.TaggedAddresses, addrTranslate)
|
||||
if serviceAddr == "" && nodeAddr == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nodeIPAddr := net.ParseIP(nodeAddr)
|
||||
serviceIPAddr := net.ParseIP(serviceAddr)
|
||||
|
@ -1685,7 +1688,7 @@ func (d *DNSServer) serviceSRVRecords(cfg *dnsConfig, dc string, nodes structs.C
|
|||
for _, node := range nodes {
|
||||
// Avoid duplicate entries, possible if a node has
|
||||
// the same service the same port, etc.
|
||||
serviceAddress := d.agent.TranslateServiceAddress(dc, node.Service.Address, node.Service.TaggedAddresses)
|
||||
serviceAddress := d.agent.TranslateServiceAddress(dc, node.Service.Address, node.Service.TaggedAddresses, TranslateAddressAcceptAny)
|
||||
servicePort := d.agent.TranslateServicePort(dc, node.Service.Port, node.Service.TaggedAddresses)
|
||||
tuple := fmt.Sprintf("%s:%s:%d", node.Node.Node, serviceAddress, servicePort)
|
||||
if _, ok := handled[tuple]; ok {
|
||||
|
|
|
@ -2518,6 +2518,196 @@ func TestDNS_ServiceLookup_WanTranslation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDNS_Lookup_TaggedIPAddresses(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
defer a.Shutdown()
|
||||
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
||||
|
||||
// Register an equivalent prepared query.
|
||||
var id string
|
||||
{
|
||||
args := &structs.PreparedQueryRequest{
|
||||
Datacenter: "dc1",
|
||||
Op: structs.PreparedQueryCreate,
|
||||
Query: &structs.PreparedQuery{
|
||||
Name: "test",
|
||||
Service: structs.ServiceQuery{
|
||||
Service: "db",
|
||||
},
|
||||
},
|
||||
}
|
||||
require.NoError(t, a.RPC("PreparedQuery.Apply", args, &id))
|
||||
}
|
||||
|
||||
type testCase struct {
|
||||
nodeAddress string
|
||||
nodeTaggedAddresses map[string]string
|
||||
serviceAddress string
|
||||
serviceTaggedAddresses map[string]structs.ServiceAddress
|
||||
|
||||
expectedServiceIPv4Address string
|
||||
expectedServiceIPv6Address string
|
||||
expectedNodeIPv4Address string
|
||||
expectedNodeIPv6Address string
|
||||
}
|
||||
|
||||
cases := map[string]testCase{
|
||||
"simple-ipv4": testCase{
|
||||
serviceAddress: "127.0.0.2",
|
||||
nodeAddress: "127.0.0.1",
|
||||
|
||||
expectedServiceIPv4Address: "127.0.0.2",
|
||||
expectedServiceIPv6Address: "",
|
||||
expectedNodeIPv4Address: "127.0.0.1",
|
||||
expectedNodeIPv6Address: "",
|
||||
},
|
||||
"simple-ipv6": testCase{
|
||||
serviceAddress: "::2",
|
||||
nodeAddress: "::1",
|
||||
|
||||
expectedServiceIPv6Address: "::2",
|
||||
expectedServiceIPv4Address: "",
|
||||
expectedNodeIPv6Address: "::1",
|
||||
expectedNodeIPv4Address: "",
|
||||
},
|
||||
"ipv4-with-tagged-ipv6": testCase{
|
||||
serviceAddress: "127.0.0.2",
|
||||
nodeAddress: "127.0.0.1",
|
||||
|
||||
serviceTaggedAddresses: map[string]structs.ServiceAddress{
|
||||
structs.TaggedAddressLANIPv6: {Address: "::2"},
|
||||
},
|
||||
nodeTaggedAddresses: map[string]string{
|
||||
structs.TaggedAddressLANIPv6: "::1",
|
||||
},
|
||||
|
||||
expectedServiceIPv4Address: "127.0.0.2",
|
||||
expectedServiceIPv6Address: "::2",
|
||||
expectedNodeIPv4Address: "127.0.0.1",
|
||||
expectedNodeIPv6Address: "::1",
|
||||
},
|
||||
"ipv6-with-tagged-ipv4": testCase{
|
||||
serviceAddress: "::2",
|
||||
nodeAddress: "::1",
|
||||
|
||||
serviceTaggedAddresses: map[string]structs.ServiceAddress{
|
||||
structs.TaggedAddressLANIPv4: {Address: "127.0.0.2"},
|
||||
},
|
||||
nodeTaggedAddresses: map[string]string{
|
||||
structs.TaggedAddressLANIPv4: "127.0.0.1",
|
||||
},
|
||||
|
||||
expectedServiceIPv4Address: "127.0.0.2",
|
||||
expectedServiceIPv6Address: "::2",
|
||||
expectedNodeIPv4Address: "127.0.0.1",
|
||||
expectedNodeIPv6Address: "::1",
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
name := name
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
args := &structs.RegisterRequest{
|
||||
Datacenter: "dc1",
|
||||
Node: "foo",
|
||||
Address: tc.nodeAddress,
|
||||
TaggedAddresses: tc.nodeTaggedAddresses,
|
||||
Service: &structs.NodeService{
|
||||
Service: "db",
|
||||
Address: tc.serviceAddress,
|
||||
Port: 8080,
|
||||
TaggedAddresses: tc.serviceTaggedAddresses,
|
||||
},
|
||||
}
|
||||
|
||||
var out struct{}
|
||||
require.NoError(t, a.RPC("Catalog.Register", args, &out))
|
||||
|
||||
// Look up the SRV record via service and prepared query.
|
||||
questions := []string{
|
||||
"db.service.consul.",
|
||||
id + ".query.consul.",
|
||||
}
|
||||
for _, question := range questions {
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(question, dns.TypeA)
|
||||
|
||||
c := new(dns.Client)
|
||||
addr := a.config.DNSAddrs[0].String()
|
||||
in, _, err := c.Exchange(m, addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.expectedServiceIPv4Address != "" {
|
||||
require.Len(t, in.Answer, 1)
|
||||
aRec, ok := in.Answer[0].(*dns.A)
|
||||
require.True(t, ok, "Bad: %#v", in.Answer[0])
|
||||
require.Equal(t, question, aRec.Hdr.Name)
|
||||
require.Equal(t, tc.expectedServiceIPv4Address, aRec.A.String())
|
||||
} else {
|
||||
require.Len(t, in.Answer, 0)
|
||||
}
|
||||
|
||||
m = new(dns.Msg)
|
||||
m.SetQuestion(question, dns.TypeAAAA)
|
||||
|
||||
c = new(dns.Client)
|
||||
addr = a.config.DNSAddrs[0].String()
|
||||
in, _, err = c.Exchange(m, addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.expectedServiceIPv6Address != "" {
|
||||
require.Len(t, in.Answer, 1)
|
||||
aRec, ok := in.Answer[0].(*dns.AAAA)
|
||||
require.True(t, ok, "Bad: %#v", in.Answer[0])
|
||||
require.Equal(t, question, aRec.Hdr.Name)
|
||||
require.Equal(t, tc.expectedServiceIPv6Address, aRec.AAAA.String())
|
||||
} else {
|
||||
require.Len(t, in.Answer, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Look up node
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("foo.node.consul.", dns.TypeA)
|
||||
|
||||
c := new(dns.Client)
|
||||
addr := a.config.DNSAddrs[0].String()
|
||||
in, _, err := c.Exchange(m, addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.expectedNodeIPv4Address != "" {
|
||||
require.Len(t, in.Answer, 1)
|
||||
aRec, ok := in.Answer[0].(*dns.A)
|
||||
require.True(t, ok, "Bad: %#v", in.Answer[0])
|
||||
require.Equal(t, "foo.node.consul.", aRec.Hdr.Name)
|
||||
require.Equal(t, tc.expectedNodeIPv4Address, aRec.A.String())
|
||||
} else {
|
||||
require.Len(t, in.Answer, 0)
|
||||
}
|
||||
|
||||
m = new(dns.Msg)
|
||||
m.SetQuestion("foo.node.consul.", dns.TypeAAAA)
|
||||
|
||||
c = new(dns.Client)
|
||||
addr = a.config.DNSAddrs[0].String()
|
||||
in, _, err = c.Exchange(m, addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.expectedNodeIPv6Address != "" {
|
||||
require.Len(t, in.Answer, 1)
|
||||
aRec, ok := in.Answer[0].(*dns.AAAA)
|
||||
require.True(t, ok, "Bad: %#v", in.Answer[0])
|
||||
require.Equal(t, "foo.node.consul.", aRec.Hdr.Name)
|
||||
require.Equal(t, tc.expectedNodeIPv6Address, aRec.AAAA.String())
|
||||
} else {
|
||||
require.Len(t, in.Answer, 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNS_CaseInsensitiveServiceLookup(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := NewTestAgent(t, t.Name(), "")
|
||||
|
|
|
@ -247,7 +247,7 @@ func (s *HTTPServer) healthServiceNodes(resp http.ResponseWriter, req *http.Requ
|
|||
}
|
||||
|
||||
// Translate addresses after filtering so we don't waste effort.
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.Nodes)
|
||||
s.agent.TranslateAddresses(args.Datacenter, out.Nodes, TranslateAddressAcceptAny)
|
||||
|
||||
// Use empty list instead of nil
|
||||
if out.Nodes == nil {
|
||||
|
|
|
@ -163,7 +163,7 @@ func (s *HTTPServer) preparedQueryExecute(id string, resp http.ResponseWriter, r
|
|||
// a query can fail over to a different DC than where the execute request
|
||||
// was sent to. That's why we use the reply's DC and not the one from
|
||||
// the args.
|
||||
s.agent.TranslateAddresses(reply.Datacenter, reply.Nodes)
|
||||
s.agent.TranslateAddresses(reply.Datacenter, reply.Nodes, TranslateAddressAcceptAny)
|
||||
|
||||
// Use empty list instead of nil.
|
||||
if reply.Nodes == nil {
|
||||
|
|
|
@ -986,11 +986,11 @@ func testConfigSnapshotMeshGateway(t testing.T, populateServices bool) *ConfigSn
|
|||
Config: map[string]interface{}{},
|
||||
},
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{
|
||||
"lan": structs.ServiceAddress{
|
||||
structs.TaggedAddressLAN: structs.ServiceAddress{
|
||||
Address: "1.2.3.4",
|
||||
Port: 8443,
|
||||
},
|
||||
"wan": structs.ServiceAddress{
|
||||
structs.TaggedAddressWAN: structs.ServiceAddress{
|
||||
Address: "198.18.0.1",
|
||||
Port: 443,
|
||||
},
|
||||
|
|
|
@ -50,9 +50,10 @@ func TestServiceManager_RegisterService(t *testing.T) {
|
|||
redisService := a.State.Service(structs.NewServiceID("redis", nil))
|
||||
require.NotNil(redisService)
|
||||
require.Equal(&structs.NodeService{
|
||||
ID: "redis",
|
||||
Service: "redis",
|
||||
Port: 8000,
|
||||
ID: "redis",
|
||||
Service: "redis",
|
||||
Port: 8000,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Weights: &structs.Weights{
|
||||
Passing: 1,
|
||||
Warning: 1,
|
||||
|
@ -116,10 +117,11 @@ func TestServiceManager_RegisterSidecar(t *testing.T) {
|
|||
sidecarService := a.State.Service(structs.NewServiceID("web-sidecar-proxy", nil))
|
||||
require.NotNil(sidecarService)
|
||||
require.Equal(&structs.NodeService{
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
DestinationServiceName: "web",
|
||||
DestinationServiceID: "web",
|
||||
|
@ -184,10 +186,11 @@ func TestServiceManager_RegisterMeshGateway(t *testing.T) {
|
|||
gateway := a.State.Service(structs.NewServiceID("mesh-gateway", nil))
|
||||
require.NotNil(gateway)
|
||||
require.Equal(&structs.NodeService{
|
||||
Kind: structs.ServiceKindMeshGateway,
|
||||
ID: "mesh-gateway",
|
||||
Service: "mesh-gateway",
|
||||
Port: 443,
|
||||
Kind: structs.ServiceKindMeshGateway,
|
||||
ID: "mesh-gateway",
|
||||
Service: "mesh-gateway",
|
||||
Port: 443,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
Config: map[string]interface{}{
|
||||
"foo": int64(1),
|
||||
|
@ -276,10 +279,11 @@ func TestServiceManager_PersistService_API(t *testing.T) {
|
|||
}
|
||||
|
||||
expectState := &structs.NodeService{
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
DestinationServiceName: "web",
|
||||
DestinationServiceID: "web",
|
||||
|
@ -487,10 +491,11 @@ func TestServiceManager_PersistService_ConfigFiles(t *testing.T) {
|
|||
svcID := "web-sidecar-proxy"
|
||||
|
||||
expectState := &structs.NodeService{
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
DestinationServiceName: "web",
|
||||
DestinationServiceID: "web",
|
||||
|
@ -637,10 +642,11 @@ func TestServiceManager_Disabled(t *testing.T) {
|
|||
sidecarService := a.State.Service(structs.NewServiceID("web-sidecar-proxy", nil))
|
||||
require.NotNil(sidecarService)
|
||||
require.Equal(&structs.NodeService{
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
Kind: structs.ServiceKindConnectProxy,
|
||||
ID: "web-sidecar-proxy",
|
||||
Service: "web-sidecar-proxy",
|
||||
Port: 21000,
|
||||
TaggedAddresses: map[string]structs.ServiceAddress{},
|
||||
Proxy: structs.ConnectProxyConfig{
|
||||
DestinationServiceName: "web",
|
||||
DestinationServiceID: "web",
|
||||
|
|
|
@ -119,6 +119,15 @@ var (
|
|||
NodeMaintCheckID = NewCheckID(NodeMaint, nil)
|
||||
)
|
||||
|
||||
const (
|
||||
TaggedAddressWAN = "wan"
|
||||
TaggedAddressWANIPv4 = "wan_ipv4"
|
||||
TaggedAddressWANIPv6 = "wan_ipv6"
|
||||
TaggedAddressLAN = "lan"
|
||||
TaggedAddressLANIPv4 = "lan_ipv4"
|
||||
TaggedAddressLANIPv6 = "lan_ipv6"
|
||||
)
|
||||
|
||||
// metaKeyFormat checks if a metadata key string is valid
|
||||
var metaKeyFormat = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`).MatchString
|
||||
|
||||
|
@ -612,7 +621,7 @@ type Node struct {
|
|||
|
||||
func (n *Node) BestAddress(wan bool) string {
|
||||
if wan {
|
||||
if addr, ok := n.TaggedAddresses["wan"]; ok {
|
||||
if addr, ok := n.TaggedAddresses[TaggedAddressWAN]; ok {
|
||||
return addr
|
||||
}
|
||||
}
|
||||
|
@ -919,7 +928,7 @@ func (ns *NodeService) BestAddress(wan bool) (string, int) {
|
|||
port := ns.Port
|
||||
|
||||
if wan {
|
||||
if wan, ok := ns.TaggedAddresses["wan"]; ok {
|
||||
if wan, ok := ns.TaggedAddresses[TaggedAddressWAN]; ok {
|
||||
addr = wan.Address
|
||||
if wan.Port != 0 {
|
||||
port = wan.Port
|
||||
|
|
|
@ -97,8 +97,8 @@ func TestNodeServiceMeshGatewayWithAddrs(t testing.T, address string, port int,
|
|||
},
|
||||
},
|
||||
TaggedAddresses: map[string]ServiceAddress{
|
||||
"lan": lanAddr,
|
||||
"wan": wanAddr,
|
||||
TaggedAddressLAN: lanAddr,
|
||||
TaggedAddressWAN: wanAddr,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,27 @@ package agent
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
)
|
||||
|
||||
type TranslateAddressAccept int
|
||||
|
||||
const (
|
||||
TranslateAddressAcceptDomain TranslateAddressAccept = 1 << iota
|
||||
TranslateAddressAcceptIPv4
|
||||
TranslateAddressAcceptIPv6
|
||||
|
||||
TranslateAddressAcceptAny TranslateAddressAccept = ^0
|
||||
)
|
||||
|
||||
// TranslateServicePort is used to provide the final, translated port for a service,
|
||||
// depending on how the agent and the other node are configured. The dc
|
||||
// parameter is the dc the datacenter this node is from.
|
||||
func (a *Agent) TranslateServicePort(dc string, port int, taggedAddresses map[string]structs.ServiceAddress) int {
|
||||
if a.config.TranslateWANAddrs && (a.config.Datacenter != dc) {
|
||||
if wanAddr, ok := taggedAddresses["wan"]; ok && wanAddr.Port != 0 {
|
||||
if wanAddr, ok := taggedAddresses[structs.TaggedAddressWAN]; ok && wanAddr.Port != 0 {
|
||||
return wanAddr.Port
|
||||
}
|
||||
}
|
||||
|
@ -21,32 +32,78 @@ func (a *Agent) TranslateServicePort(dc string, port int, taggedAddresses map[st
|
|||
// TranslateServiceAddress is used to provide the final, translated address for a node,
|
||||
// depending on how the agent and the other node are configured. The dc
|
||||
// parameter is the dc the datacenter this node is from.
|
||||
func (a *Agent) TranslateServiceAddress(dc string, addr string, taggedAddresses map[string]structs.ServiceAddress) string {
|
||||
if a.config.TranslateWANAddrs && (a.config.Datacenter != dc) {
|
||||
if wanAddr, ok := taggedAddresses["wan"]; ok && wanAddr.Address != "" {
|
||||
return wanAddr.Address
|
||||
func (a *Agent) TranslateServiceAddress(dc string, addr string, taggedAddresses map[string]structs.ServiceAddress, accept TranslateAddressAccept) string {
|
||||
def := addr
|
||||
v4 := taggedAddresses[structs.TaggedAddressLANIPv4].Address
|
||||
v6 := taggedAddresses[structs.TaggedAddressLANIPv6].Address
|
||||
|
||||
shouldUseWan := a.config.TranslateWANAddrs && (a.config.Datacenter != dc)
|
||||
if shouldUseWan {
|
||||
if v, ok := taggedAddresses[structs.TaggedAddressWAN]; ok {
|
||||
def = v.Address
|
||||
}
|
||||
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv4]; ok {
|
||||
v4 = v.Address
|
||||
}
|
||||
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv6]; ok {
|
||||
v6 = v.Address
|
||||
}
|
||||
}
|
||||
return addr
|
||||
|
||||
return translateAddressAccept(accept, def, v4, v6)
|
||||
}
|
||||
|
||||
// TranslateAddress is used to provide the final, translated address for a node,
|
||||
// depending on how the agent and the other node are configured. The dc
|
||||
// parameter is the dc the datacenter this node is from.
|
||||
func (a *Agent) TranslateAddress(dc string, addr string, taggedAddresses map[string]string) string {
|
||||
if a.config.TranslateWANAddrs && (a.config.Datacenter != dc) {
|
||||
wanAddr := taggedAddresses["wan"]
|
||||
if wanAddr != "" {
|
||||
addr = wanAddr
|
||||
func (a *Agent) TranslateAddress(dc string, addr string, taggedAddresses map[string]string, accept TranslateAddressAccept) string {
|
||||
def := addr
|
||||
v4 := taggedAddresses[structs.TaggedAddressLANIPv4]
|
||||
v6 := taggedAddresses[structs.TaggedAddressLANIPv6]
|
||||
|
||||
shouldUseWan := a.config.TranslateWANAddrs && (a.config.Datacenter != dc)
|
||||
if shouldUseWan {
|
||||
if v, ok := taggedAddresses[structs.TaggedAddressWAN]; ok {
|
||||
def = v
|
||||
}
|
||||
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv4]; ok {
|
||||
v4 = v
|
||||
}
|
||||
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv6]; ok {
|
||||
v6 = v
|
||||
}
|
||||
}
|
||||
return addr
|
||||
|
||||
return translateAddressAccept(accept, def, v4, v6)
|
||||
}
|
||||
|
||||
func translateAddressAccept(accept TranslateAddressAccept, def, v4, v6 string) string {
|
||||
switch {
|
||||
case accept&TranslateAddressAcceptIPv6 > 0 && v6 != "":
|
||||
return v6
|
||||
case accept&TranslateAddressAcceptIPv4 > 0 && v4 != "":
|
||||
return v4
|
||||
case accept&TranslateAddressAcceptAny > 0 && def != "":
|
||||
return def
|
||||
default:
|
||||
defIP := net.ParseIP(def)
|
||||
switch {
|
||||
case defIP != nil && defIP.To4() != nil && accept&TranslateAddressAcceptIPv4 > 0:
|
||||
return def
|
||||
case defIP != nil && defIP.To4() == nil && accept&TranslateAddressAcceptIPv6 > 0:
|
||||
return def
|
||||
case defIP == nil && accept&TranslateAddressAcceptDomain > 0:
|
||||
return def
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// TranslateAddresses translates addresses in the given structure into the
|
||||
// final, translated address, depending on how the agent and the other node are
|
||||
// configured. The dc parameter is the datacenter this structure is from.
|
||||
func (a *Agent) TranslateAddresses(dc string, subj interface{}) {
|
||||
func (a *Agent) TranslateAddresses(dc string, subj interface{}, accept TranslateAddressAccept) {
|
||||
// CAUTION - SUBTLE! An agent running on a server can, in some cases,
|
||||
// return pointers directly into the immutable state store for
|
||||
// performance (it's via the in-memory RPC mechanism). It's never safe
|
||||
|
@ -68,28 +125,28 @@ func (a *Agent) TranslateAddresses(dc string, subj interface{}) {
|
|||
switch v := subj.(type) {
|
||||
case structs.CheckServiceNodes:
|
||||
for _, entry := range v {
|
||||
entry.Node.Address = a.TranslateAddress(dc, entry.Node.Address, entry.Node.TaggedAddresses)
|
||||
entry.Service.Address = a.TranslateServiceAddress(dc, entry.Service.Address, entry.Service.TaggedAddresses)
|
||||
entry.Node.Address = a.TranslateAddress(dc, entry.Node.Address, entry.Node.TaggedAddresses, accept)
|
||||
entry.Service.Address = a.TranslateServiceAddress(dc, entry.Service.Address, entry.Service.TaggedAddresses, accept)
|
||||
entry.Service.Port = a.TranslateServicePort(dc, entry.Service.Port, entry.Service.TaggedAddresses)
|
||||
}
|
||||
case *structs.Node:
|
||||
v.Address = a.TranslateAddress(dc, v.Address, v.TaggedAddresses)
|
||||
v.Address = a.TranslateAddress(dc, v.Address, v.TaggedAddresses, accept)
|
||||
case structs.Nodes:
|
||||
for _, node := range v {
|
||||
node.Address = a.TranslateAddress(dc, node.Address, node.TaggedAddresses)
|
||||
node.Address = a.TranslateAddress(dc, node.Address, node.TaggedAddresses, accept)
|
||||
}
|
||||
case structs.ServiceNodes:
|
||||
for _, entry := range v {
|
||||
entry.Address = a.TranslateAddress(dc, entry.Address, entry.TaggedAddresses)
|
||||
entry.ServiceAddress = a.TranslateServiceAddress(dc, entry.ServiceAddress, entry.ServiceTaggedAddresses)
|
||||
entry.Address = a.TranslateAddress(dc, entry.Address, entry.TaggedAddresses, accept)
|
||||
entry.ServiceAddress = a.TranslateServiceAddress(dc, entry.ServiceAddress, entry.ServiceTaggedAddresses, accept)
|
||||
entry.ServicePort = a.TranslateServicePort(dc, entry.ServicePort, entry.ServiceTaggedAddresses)
|
||||
}
|
||||
case *structs.NodeServices:
|
||||
if v.Node != nil {
|
||||
v.Node.Address = a.TranslateAddress(dc, v.Node.Address, v.Node.TaggedAddresses)
|
||||
v.Node.Address = a.TranslateAddress(dc, v.Node.Address, v.Node.TaggedAddresses, accept)
|
||||
}
|
||||
for _, entry := range v.Services {
|
||||
entry.Address = a.TranslateServiceAddress(dc, entry.Address, entry.TaggedAddresses)
|
||||
entry.Address = a.TranslateServiceAddress(dc, entry.Address, entry.TaggedAddresses, accept)
|
||||
entry.Port = a.TranslateServicePort(dc, entry.Port, entry.TaggedAddresses)
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -52,8 +52,10 @@ func TestAPI_CatalogNodes(t *testing.T) {
|
|||
Address: "127.0.0.1",
|
||||
Datacenter: "dc1",
|
||||
TaggedAddresses: map[string]string{
|
||||
"lan": "127.0.0.1",
|
||||
"wan": "127.0.0.1",
|
||||
"lan": "127.0.0.1",
|
||||
"lan_ipv4": "127.0.0.1",
|
||||
"wan": "127.0.0.1",
|
||||
"wan_ipv4": "127.0.0.1",
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"consul-network-segment": "",
|
||||
|
|
|
@ -269,8 +269,10 @@ func TestAPI_ClientTxn(t *testing.T) {
|
|||
Address: "127.0.0.1",
|
||||
Datacenter: "dc1",
|
||||
TaggedAddresses: map[string]string{
|
||||
"lan": s.Config.Bind,
|
||||
"wan": s.Config.Bind,
|
||||
"lan": s.Config.Bind,
|
||||
"lan_ipv4": s.Config.Bind,
|
||||
"wan": s.Config.Bind,
|
||||
"wan_ipv4": s.Config.Bind,
|
||||
},
|
||||
Meta: map[string]string{"consul-network-segment": ""},
|
||||
CreateIndex: ret.Results[1].Node.CreateIndex,
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/agent/xds"
|
||||
"github.com/hashicorp/consul/api"
|
||||
proxyCmd "github.com/hashicorp/consul/command/connect/proxy"
|
||||
|
@ -244,7 +245,7 @@ func (c *cmd) Run(args []string) int {
|
|||
taggedAddrs := make(map[string]api.ServiceAddress)
|
||||
|
||||
if lanAddr != "" {
|
||||
taggedAddrs["lan"] = api.ServiceAddress{Address: lanAddr, Port: lanPort}
|
||||
taggedAddrs[structs.TaggedAddressLAN] = api.ServiceAddress{Address: lanAddr, Port: lanPort}
|
||||
}
|
||||
|
||||
wanAddr := ""
|
||||
|
@ -255,7 +256,7 @@ func (c *cmd) Run(args []string) int {
|
|||
c.UI.Error(fmt.Sprintf("Failed to parse the -wan-address parameter: %v", err))
|
||||
return 1
|
||||
}
|
||||
taggedAddrs["wan"] = api.ServiceAddress{Address: wanAddr, Port: wanPort}
|
||||
taggedAddrs[structs.TaggedAddressWAN] = api.ServiceAddress{Address: wanAddr, Port: wanPort}
|
||||
}
|
||||
|
||||
tcpCheckAddr := lanAddr
|
||||
|
|
Loading…
Reference in New Issue