Skip to content

Commit

Permalink
xds: only try to create an ipv6 expose checks listener if ipv6 is sup…
Browse files Browse the repository at this point in the history
…ported by the kernel (#9765)

Fixes #9311

This only fails if the kernel has ipv6 hard-disabled. It is not sufficient to merely not provide an ipv6 address for a network interface.
  • Loading branch information
rboyer authored and dizzyup committed Apr 21, 2021
1 parent 6f72841 commit 44534bc
Show file tree
Hide file tree
Showing 15 changed files with 674 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .changelog/9765.txt
@@ -0,0 +1,3 @@
```release-note:improvement
xds: only try to create an ipv6 expose checks listener if ipv6 is supported by the kernel
```
20 changes: 15 additions & 5 deletions agent/xds/listeners.go
Expand Up @@ -688,12 +688,22 @@ func (s *Server) makeExposedCheckListener(cfgSnap *proxycfg.ConfigSnapshot, clus
advertiseLen = 128
}

ranges := make([]*envoycore.CidrRange, 0, 3)
ranges = append(ranges,
&envoycore.CidrRange{AddressPrefix: "127.0.0.1", PrefixLen: &wrappers.UInt32Value{Value: 8}},
&envoycore.CidrRange{AddressPrefix: advertise, PrefixLen: &wrappers.UInt32Value{Value: uint32(advertiseLen)}},
)

if ok, err := kernelSupportsIPv6(); err != nil {
return nil, err
} else if ok {
ranges = append(ranges,
&envoycore.CidrRange{AddressPrefix: "::1", PrefixLen: &wrappers.UInt32Value{Value: 128}},
)
}

chain.FilterChainMatch = &envoylistener.FilterChainMatch{
SourcePrefixRanges: []*envoycore.CidrRange{
{AddressPrefix: "127.0.0.1", PrefixLen: &wrappers.UInt32Value{Value: 8}},
{AddressPrefix: "::1", PrefixLen: &wrappers.UInt32Value{Value: 128}},
{AddressPrefix: advertise, PrefixLen: &wrappers.UInt32Value{Value: uint32(advertiseLen)}},
},
SourcePrefixRanges: ranges,
}
}

Expand Down
54 changes: 54 additions & 0 deletions agent/xds/listeners_test.go
Expand Up @@ -6,6 +6,7 @@ import (
"sort"
"testing"
"text/template"
"time"

envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
"github.com/envoyproxy/go-control-plane/pkg/wellknown"
Expand All @@ -16,6 +17,7 @@ import (
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/agent/xds/proxysupport"
"github.com/hashicorp/consul/sdk/testutil"
"github.com/hashicorp/consul/types"
)

func TestListenersFromSnapshot(t *testing.T) {
Expand All @@ -28,6 +30,7 @@ func TestListenersFromSnapshot(t *testing.T) {
// test input.
setup func(snap *proxycfg.ConfigSnapshot)
overrideGoldenName string
serverSetup func(*Server)
}{
{
name: "defaults",
Expand Down Expand Up @@ -292,6 +295,38 @@ func TestListenersFromSnapshot(t *testing.T) {
}
},
},
{
// NOTE: if IPv6 is not supported in the kernel per
// kernelSupportsIPv6() then this test will fail because the golden
// files were generated assuming ipv6 support was present
name: "expose-checks",
create: proxycfg.TestConfigSnapshotExposeConfig,
setup: func(snap *proxycfg.ConfigSnapshot) {
snap.Proxy.Expose = structs.ExposeConfig{
Checks: true,
}
},
serverSetup: func(s *Server) {
s.CfgFetcher = configFetcherFunc(func() string {
return "192.0.2.1"
})

s.CheckFetcher = httpCheckFetcherFunc(func(sid structs.ServiceID) []structs.CheckType {
if sid != structs.NewServiceID("web", nil) {
return nil
}
return []structs.CheckType{{
CheckID: types.CheckID("http"),
Name: "http",
HTTP: "http://127.0.0.1:8181/debug",
ProxyHTTP: "http://:21500/debug",
Method: "GET",
Interval: 10 * time.Second,
Timeout: 1 * time.Second,
}}
})
},
},
{
name: "mesh-gateway",
create: proxycfg.TestConfigSnapshotMeshGateway,
Expand Down Expand Up @@ -507,6 +542,9 @@ func TestListenersFromSnapshot(t *testing.T) {

// Need server just for logger dependency
s := Server{Logger: testutil.Logger(t)}
if tt.serverSetup != nil {
tt.serverSetup(&s)
}

cInfo := connectionInfo{
Token: "my-token",
Expand Down Expand Up @@ -765,3 +803,19 @@ func customHTTPListenerJSON(t *testing.T, opts customHTTPListenerJSONOptions) st
require.NoError(t, customHTTPListenerJSONTemplate.Execute(&buf, opts))
return buf.String()
}

type httpCheckFetcherFunc func(serviceID structs.ServiceID) []structs.CheckType

var _ HTTPCheckFetcher = (httpCheckFetcherFunc)(nil)

func (f httpCheckFetcherFunc) ServiceHTTPBasedChecks(serviceID structs.ServiceID) []structs.CheckType {
return f(serviceID)
}

type configFetcherFunc func() string

var _ ConfigFetcher = (configFetcherFunc)(nil)

func (f configFetcherFunc) AdvertiseAddrLAN() string {
return f()
}
7 changes: 7 additions & 0 deletions agent/xds/net_fallback.go
@@ -0,0 +1,7 @@
// +build !linux

package xds

func kernelSupportsIPv6() (bool, error) {
return true, nil
}
35 changes: 35 additions & 0 deletions agent/xds/net_linux.go
@@ -0,0 +1,35 @@
// +build linux

package xds

import (
"fmt"
"os"
"sync"
)

const ipv6SupportProcFile = "/proc/net/if_inet6"

var (
ipv6SupportOnce sync.Once
ipv6Supported bool
ipv6SupportedErr error
)

func kernelSupportsIPv6() (bool, error) {
ipv6SupportOnce.Do(func() {
ipv6Supported, ipv6SupportedErr = checkIfKernelSupportsIPv6()
})
return ipv6Supported, ipv6SupportedErr
}

func checkIfKernelSupportsIPv6() (bool, error) {
_, err := os.Stat(ipv6SupportProcFile)
if os.IsNotExist(err) {
return false, nil
} else if err != nil {
return false, fmt.Errorf("error checking for ipv6 support file %s: %w", ipv6SupportProcFile, err)
}

return true, nil
}
109 changes: 109 additions & 0 deletions agent/xds/testdata/listeners/expose-checks.envoy-1-13-x.golden
@@ -0,0 +1,109 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.api.v2.Listener",
"name": "exposed_path_debug:1.2.3.4:21500",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 21500
}
},
"filterChains": [
{
"filterChainMatch": {
"sourcePrefixRanges": [
{
"addressPrefix": "127.0.0.1",
"prefixLen": 8
},
{
"addressPrefix": "192.0.2.1",
"prefixLen": 32
},
{
"addressPrefix": "::1",
"prefixLen": 128
}
]
},
"filters": [
{
"name": "envoy.http_connection_manager",
"config": {
"http_filters": [
{
"name": "envoy.router"
}
],
"route_config": {
"name": "exposed_path_filter_debug_21500",
"virtual_hosts": [
{
"domains": [
"*"
],
"name": "exposed_path_filter_debug_21500",
"routes": [
{
"match": {
"path": "/debug"
},
"route": {
"cluster": "exposed_cluster_8181"
}
}
]
}
]
},
"stat_prefix": "exposed_path_filter_debug_21500",
"tracing": {
"random_sampling": {
}
}
}
}
]
}
]
},
{
"@type": "type.googleapis.com/envoy.api.v2.Listener",
"name": "public_listener:1.2.3.4:8080",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8080
}
},
"filterChains": [
{
"tlsContext": {
"requireClientCertificate": true
},
"filters": [
{
"name": "envoy.filters.network.rbac",
"config": {
"rules": {
},
"stat_prefix": "connect_authz"
}
},
{
"name": "envoy.tcp_proxy",
"config": {
"cluster": "local_app",
"stat_prefix": "public_listener"
}
}
]
}
]
}
],
"typeUrl": "type.googleapis.com/envoy.api.v2.Listener",
"nonce": "00000001"
}
109 changes: 109 additions & 0 deletions agent/xds/testdata/listeners/expose-checks.envoy-1-14-x.golden
@@ -0,0 +1,109 @@
{
"versionInfo": "00000001",
"resources": [
{
"@type": "type.googleapis.com/envoy.api.v2.Listener",
"name": "exposed_path_debug:1.2.3.4:21500",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 21500
}
},
"filterChains": [
{
"filterChainMatch": {
"sourcePrefixRanges": [
{
"addressPrefix": "127.0.0.1",
"prefixLen": 8
},
{
"addressPrefix": "192.0.2.1",
"prefixLen": 32
},
{
"addressPrefix": "::1",
"prefixLen": 128
}
]
},
"filters": [
{
"name": "envoy.http_connection_manager",
"config": {
"http_filters": [
{
"name": "envoy.router"
}
],
"route_config": {
"name": "exposed_path_filter_debug_21500",
"virtual_hosts": [
{
"domains": [
"*"
],
"name": "exposed_path_filter_debug_21500",
"routes": [
{
"match": {
"path": "/debug"
},
"route": {
"cluster": "exposed_cluster_8181"
}
}
]
}
]
},
"stat_prefix": "exposed_path_filter_debug_21500",
"tracing": {
"random_sampling": {
}
}
}
}
]
}
]
},
{
"@type": "type.googleapis.com/envoy.api.v2.Listener",
"name": "public_listener:1.2.3.4:8080",
"address": {
"socketAddress": {
"address": "1.2.3.4",
"portValue": 8080
}
},
"filterChains": [
{
"tlsContext": {
"requireClientCertificate": true
},
"filters": [
{
"name": "envoy.filters.network.rbac",
"config": {
"rules": {
},
"stat_prefix": "connect_authz"
}
},
{
"name": "envoy.tcp_proxy",
"config": {
"cluster": "local_app",
"stat_prefix": "public_listener"
}
}
]
}
]
}
],
"typeUrl": "type.googleapis.com/envoy.api.v2.Listener",
"nonce": "00000001"
}

0 comments on commit 44534bc

Please sign in to comment.