Skip to content

Commit d97d513

Browse files
committed
check if ipv6 kernel conf file exists before running ip6tables
1 parent a03b20b commit d97d513

File tree

2 files changed

+136
-22
lines changed

2 files changed

+136
-22
lines changed

ecs-init/exec/iptables/iptables.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ const (
4848
iptablesTableFilter = "filter"
4949
iptablesTableNat = "nat"
5050

51-
offhostIntrospectionAccessConfigEnv = "ECS_ALLOW_OFFHOST_INTROSPECTION_ACCESS"
52-
offhostIntrospectonAccessInterfaceEnv = "ECS_OFFHOST_INTROSPECTION_INTERFACE_NAME"
53-
agentIntrospectionServerPort = "51678"
51+
offhostIntrospectionAccessConfigEnv = "ECS_ALLOW_OFFHOST_INTROSPECTION_ACCESS"
52+
agentIntrospectionServerPort = "51678"
53+
ipv6KernelConfigPath = "/proc/sys/net/ipv6"
5454
)
5555

5656
var (
5757
defaultLoopbackInterfaceName = ""
5858
defaultDockerBridgeNetworkName = ""
59+
checkForPath = os.Stat
5960
)
6061

6162
// NetfilterRoute implements the engine.credentialsProxyRoute interface by
@@ -192,7 +193,7 @@ func (route *NetfilterRoute) modifyNetfilterEntry(table string, action iptablesA
192193
}
193194

194195
// Checking if we need to apply the netfilter table action for IPv6 as well.
195-
if useIp6tables {
196+
if checkIpv6KernelConfigExist() && useIp6tables {
196197
_, err = route.cmdExec.LookPath(ip6tablesExecutable)
197198
if err != nil {
198199
log.Warnf("%s unable to be found on the host. Assuming IPv6 isn't available on the host and will not apply %s.", ip6tablesExecutable, getActionName(action))
@@ -304,3 +305,11 @@ func allowOffhostIntrospection() bool {
304305
}
305306
return b
306307
}
308+
309+
// checkIpv6KernelConfig checks if the IPv6 kernel config path exists.
310+
// If the path does not exists then we will assume that the host environment
311+
// has explicitly disabled IPv6 capability
312+
func checkIpv6KernelConfigExist() bool {
313+
_, err := checkForPath(ipv6KernelConfigPath)
314+
return err == nil
315+
}

ecs-init/exec/iptables/iptables_test.go

Lines changed: 123 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ var (
7777
"-j", "REDIRECT",
7878
"--to-ports", localhostCredentialsProxyPort,
7979
}
80+
osStatFileNotFoundError = fmt.Errorf("file not found")
8081
)
8182

8283
func resetDefaultNetworkInterfaceVariables() func() {
@@ -145,24 +146,27 @@ func TestNewNetfilterRoute(t *testing.T) {
145146

146147
}
147148

148-
func appendIpv6Mocks(mockExec *MockExec, mockCmd *MockCmd, mocks []*gomock.Call, table, action, chain string, args []string, useIp6tables bool) []*gomock.Call {
149+
func appendIpv6Mocks(mockExec *MockExec, mockCmd *MockCmd, mocks []*gomock.Call, table, action, chain string, args []string, useIp6tables bool, osStatError error) []*gomock.Call {
149150
mocks = append(mocks,
150151
mockExec.EXPECT().Command(iptablesExecutable,
151152
expectedArgs(table, action, chain, args)).Return(mockCmd),
152153
mockCmd.EXPECT().CombinedOutput().Return([]byte{0}, nil),
153154
)
154-
if useIp6tables {
155-
mocks = append(mocks,
156-
mockExec.EXPECT().LookPath(ip6tablesExecutable).Return("", nil),
157-
mockExec.EXPECT().Command(ip6tablesExecutable,
158-
expectedArgs(table, action, chain, args)).Return(mockCmd),
159-
mockCmd.EXPECT().CombinedOutput().Return([]byte{0}, nil),
160-
)
161-
} else {
162-
mocks = append(mocks,
163-
mockExec.EXPECT().LookPath(ip6tablesExecutable).Return("", errors.New("error")),
164-
)
155+
if osStatError == nil {
156+
if useIp6tables {
157+
mocks = append(mocks,
158+
mockExec.EXPECT().LookPath(ip6tablesExecutable).Return("", nil),
159+
mockExec.EXPECT().Command(ip6tablesExecutable,
160+
expectedArgs(table, action, chain, args)).Return(mockCmd),
161+
mockCmd.EXPECT().CombinedOutput().Return([]byte{0}, nil),
162+
)
163+
} else {
164+
mocks = append(mocks,
165+
mockExec.EXPECT().LookPath(ip6tablesExecutable).Return("", errors.New("error")),
166+
)
167+
}
165168
}
169+
166170
return mocks
167171
}
168172

@@ -171,22 +175,38 @@ func TestCreate(t *testing.T) {
171175
testCases := []struct {
172176
name string
173177
useIp6tables bool
178+
osStatError error
174179
}{
175180
{
176181
name: "create iptables route",
177182
useIp6tables: false,
183+
osStatError: nil,
178184
},
179185
{
180186
name: "create ip6tables route",
181187
useIp6tables: true,
188+
osStatError: nil,
189+
},
190+
{
191+
name: "create ip6tables route when ipv6 kernel configs not found",
192+
useIp6tables: true,
193+
osStatError: osStatFileNotFoundError,
182194
},
183195
}
196+
184197
for _, tc := range testCases {
185198
t.Run(tc.name, func(t *testing.T) {
186199
defer resetDefaultNetworkInterfaceVariables()
187200
ctrl := gomock.NewController(t)
188201
defer ctrl.Finish()
189202

203+
defer func() {
204+
checkForPath = os.Stat
205+
}()
206+
checkForPath = func(name string) (os.FileInfo, error) {
207+
return nil, tc.osStatError
208+
}
209+
190210
mockCmd := NewMockCmd(ctrl)
191211
// Mock a successful execution of the iptables command to create the
192212
// route
@@ -204,8 +224,10 @@ func TestCreate(t *testing.T) {
204224
expectedArgs("filter", "-I", "INPUT", localhostTrafficFilterInputRouteArgs)).Return(mockCmd),
205225
mockCmd.EXPECT().CombinedOutput().Return([]byte{0}, nil),
206226
}
207-
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesInsert), "INPUT", blockIntrospectionOffhostAccessInputRouteArgs, tc.useIp6tables)
208-
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesInsert), "INPUT", allowIntrospectionForDockerArgs, tc.useIp6tables)
227+
228+
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesInsert), "INPUT", blockIntrospectionOffhostAccessInputRouteArgs, tc.useIp6tables, tc.osStatError)
229+
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesInsert), "INPUT", allowIntrospectionForDockerArgs, tc.useIp6tables, tc.osStatError)
230+
209231
mocks = append(mocks,
210232
mockExec.EXPECT().Command(iptablesExecutable,
211233
expectedArgs("nat", "-A", "OUTPUT", outputRouteArgs)).Return(mockCmd),
@@ -233,6 +255,13 @@ func TestCreateSkipLocalTrafficFilter(t *testing.T) {
233255
ctrl := gomock.NewController(t)
234256
defer ctrl.Finish()
235257

258+
defer func() {
259+
checkForPath = os.Stat
260+
}()
261+
checkForPath = func(name string) (os.FileInfo, error) {
262+
return nil, nil
263+
}
264+
236265
mockCmd := NewMockCmd(ctrl)
237266
mockExec := NewMockExec(ctrl)
238267
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)
@@ -351,6 +380,13 @@ func TestCreateBlockOffhostIntrospectionAccessErrors(t *testing.T) {
351380
},
352381
}
353382

383+
defer func() {
384+
checkForPath = os.Stat
385+
}()
386+
checkForPath = func(name string) (os.FileInfo, error) {
387+
return nil, nil
388+
}
389+
354390
for _, tc := range testCases {
355391
t.Run(tc.name, func(t *testing.T) {
356392
defer resetDefaultNetworkInterfaceVariables()
@@ -427,6 +463,13 @@ func TestCreateErrorOnOutputChainCommandError(t *testing.T) {
427463
ctrl := gomock.NewController(t)
428464
defer ctrl.Finish()
429465

466+
defer func() {
467+
checkForPath = os.Stat
468+
}()
469+
checkForPath = func(name string) (os.FileInfo, error) {
470+
return nil, nil
471+
}
472+
430473
mockCmd := NewMockCmd(ctrl)
431474
mockExec := NewMockExec(ctrl)
432475
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)
@@ -470,14 +513,22 @@ func TestRemove(t *testing.T) {
470513
testCases := []struct {
471514
name string
472515
useIp6tables bool
516+
osStatError error
473517
}{
474518
{
475519
name: "test remove with iptables only",
476520
useIp6tables: false,
521+
osStatError: nil,
477522
},
478523
{
479524
name: "test remove with ip6tables",
480525
useIp6tables: true,
526+
osStatError: nil,
527+
},
528+
{
529+
name: "test remove with ip6tables with file not found error",
530+
useIp6tables: true,
531+
osStatError: osStatFileNotFoundError,
481532
},
482533
}
483534

@@ -487,6 +538,13 @@ func TestRemove(t *testing.T) {
487538
ctrl := gomock.NewController(t)
488539
defer ctrl.Finish()
489540

541+
defer func() {
542+
checkForPath = os.Stat
543+
}()
544+
checkForPath = func(name string) (os.FileInfo, error) {
545+
return nil, tc.osStatError
546+
}
547+
490548
mockCmd := NewMockCmd(ctrl)
491549
mockExec := NewMockExec(ctrl)
492550
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)
@@ -505,8 +563,8 @@ func TestRemove(t *testing.T) {
505563
mockCmd.EXPECT().CombinedOutput().Return([]byte{0}, nil),
506564
}
507565

508-
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", blockIntrospectionOffhostAccessInputRouteArgs, tc.useIp6tables)
509-
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", allowIntrospectionForDockerArgs, tc.useIp6tables)
566+
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", blockIntrospectionOffhostAccessInputRouteArgs, tc.useIp6tables, tc.osStatError)
567+
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", allowIntrospectionForDockerArgs, tc.useIp6tables, tc.osStatError)
510568

511569
mocks = append(mocks,
512570
mockExec.EXPECT().Command(iptablesExecutable,
@@ -535,6 +593,14 @@ func TestRemoveSkipLocalTrafficFilter(t *testing.T) {
535593
ctrl := gomock.NewController(t)
536594
defer ctrl.Finish()
537595

596+
defer func() {
597+
checkForPath = os.Stat
598+
}()
599+
600+
checkForPath = func(name string) (os.FileInfo, error) {
601+
return nil, nil
602+
}
603+
538604
mockCmd := NewMockCmd(ctrl)
539605
mockExec := NewMockExec(ctrl)
540606
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)
@@ -578,14 +644,22 @@ func TestRemoveAllowIntrospectionOffhostAccess(t *testing.T) {
578644
testCases := []struct {
579645
name string
580646
useIp6tables bool
647+
osStatError error
581648
}{
582649
{
583650
name: "remove allow instrocpection off-host access with iptables only",
584651
useIp6tables: false,
652+
osStatError: nil,
585653
},
586654
{
587655
name: "remove allow instrocpection off-host access with ip6tables",
588656
useIp6tables: true,
657+
osStatError: nil,
658+
},
659+
{
660+
name: "remove allow instrocpection off-host access with ip6tables and file not found error",
661+
useIp6tables: true,
662+
osStatError: osStatFileNotFoundError,
589663
},
590664
}
591665

@@ -595,6 +669,13 @@ func TestRemoveAllowIntrospectionOffhostAccess(t *testing.T) {
595669
ctrl := gomock.NewController(t)
596670
defer ctrl.Finish()
597671

672+
defer func() {
673+
checkForPath = os.Stat
674+
}()
675+
checkForPath = func(name string) (os.FileInfo, error) {
676+
return nil, tc.osStatError
677+
}
678+
598679
mockCmd := NewMockCmd(ctrl)
599680
mockExec := NewMockExec(ctrl)
600681
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)
@@ -609,8 +690,8 @@ func TestRemoveAllowIntrospectionOffhostAccess(t *testing.T) {
609690
expectedArgs("filter", "-D", "INPUT", localhostTrafficFilterInputRouteArgs)).Return(mockCmd),
610691
mockCmd.EXPECT().CombinedOutput().Return([]byte{0}, nil),
611692
}
612-
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", blockIntrospectionOffhostAccessInputRouteArgs, tc.useIp6tables)
613-
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", allowIntrospectionForDockerArgs, tc.useIp6tables)
693+
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", blockIntrospectionOffhostAccessInputRouteArgs, tc.useIp6tables, tc.osStatError)
694+
mocks = appendIpv6Mocks(mockExec, mockCmd, mocks, "filter", string(iptablesDelete), "INPUT", allowIntrospectionForDockerArgs, tc.useIp6tables, tc.osStatError)
614695
mocks = append(mocks,
615696
mockExec.EXPECT().Command(iptablesExecutable,
616697
expectedArgs("nat", "-D", "OUTPUT", outputRouteArgs)).Return(mockCmd),
@@ -635,6 +716,14 @@ func TestRemoveErrorOnPreroutingChainCommandError(t *testing.T) {
635716
ctrl := gomock.NewController(t)
636717
defer ctrl.Finish()
637718

719+
defer func() {
720+
checkForPath = os.Stat
721+
}()
722+
723+
checkForPath = func(name string) (os.FileInfo, error) {
724+
return nil, nil
725+
}
726+
638727
mockCmd := NewMockCmd(ctrl)
639728
mockExec := NewMockExec(ctrl)
640729
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)
@@ -679,6 +768,14 @@ func TestRemoveErrorOnOutputChainCommandError(t *testing.T) {
679768
ctrl := gomock.NewController(t)
680769
defer ctrl.Finish()
681770

771+
defer func() {
772+
checkForPath = os.Stat
773+
}()
774+
775+
checkForPath = func(name string) (os.FileInfo, error) {
776+
return nil, nil
777+
}
778+
682779
mockCmd := NewMockCmd(ctrl)
683780
mockExec := NewMockExec(ctrl)
684781
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)
@@ -723,6 +820,14 @@ func TestRemoveErrorOnInputChainCommandsErrors(t *testing.T) {
723820
ctrl := gomock.NewController(t)
724821
defer ctrl.Finish()
725822

823+
defer func() {
824+
checkForPath = os.Stat
825+
}()
826+
827+
checkForPath = func(name string) (os.FileInfo, error) {
828+
return nil, nil
829+
}
830+
726831
mockCmd := NewMockCmd(ctrl)
727832
mockExec := NewMockExec(ctrl)
728833
mockNetlink := mock_nlwrapper.NewMockNetLink(ctrl)

0 commit comments

Comments
 (0)