Skip to content

Commit

Permalink
iptables: test real world roundtrip of iptables rules
Browse files Browse the repository at this point in the history
  • Loading branch information
howardjohn committed Aug 26, 2024
1 parent f5199d8 commit f32eaf4
Showing 4 changed files with 98 additions and 4 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/howardjohn/unshare-go v0.4.0
github.com/howardjohn/unshare-go v0.5.0
github.com/lestrrat-go/jwx v1.2.30
github.com/mattn/go-isatty v0.0.20
github.com/miekg/dns v1.1.62
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -225,8 +225,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/howardjohn/unshare-go v0.4.0 h1:gqPNhMC5Ng4sJPv3XfIxKDjE7cyXRsRh+sPFPbesTgo=
github.com/howardjohn/unshare-go v0.4.0/go.mod h1:cJjyFAN6qTA70ovC2VR23iAZuJ8X3J/ibAbT693pJ8g=
github.com/howardjohn/unshare-go v0.5.0 h1:pHDqBG4bWRjs18IC+axJb3Tmcuau5sx9j1ODaSHUlyI=
github.com/howardjohn/unshare-go v0.5.0/go.mod h1:cJjyFAN6qTA70ovC2VR23iAZuJ8X3J/ibAbT693pJ8g=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ func shouldUseBinaryForCurrentContext(iptablesBin string) (IptablesVersion, erro
// does the "xx-save" binary exist?
rulesDump, binExistsErr := exec.Command(iptablesSaveBin).CombinedOutput()
if binExistsErr != nil {
return IptablesVersion{}, fmt.Errorf("binary %s not found in path: %w", iptablesSaveBin, binExistsErr)
return IptablesVersion{}, fmt.Errorf("failed to execute %s: %w %v", iptablesSaveBin, binExistsErr, string(rulesDump))
}

// Binary is there, so try to parse version
94 changes: 94 additions & 0 deletions tools/istio-iptables/pkg/e2e/e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"testing"

// Create a new mount namespace.
"github.com/howardjohn/unshare-go/mountns"
// Create a new network namespace. This will have the 'lo' interface ready but nothing else.
_ "github.com/howardjohn/unshare-go/netns"
"github.com/howardjohn/unshare-go/userns"

"istio.io/istio/pkg/log"
"istio.io/istio/pkg/test/util/assert"
cleancmd "istio.io/istio/tools/istio-clean-iptables/pkg/cmd"
iptablescmd "istio.io/istio/tools/istio-iptables/pkg/cmd"
)

func TestIptablesCleanRoundTrip(t *testing.T) {
setup(t)
// We only have UID 0 in our namespace, so always set it to that
const proxyUID = "--proxy-uid=0"
t.Run("basic", func(t *testing.T) {
assert.NoError(t, runIptables(proxyUID))
assert.NoError(t, runIptablesClean(proxyUID))
validateIptablesClean(t)
})
t.Run("dns", func(t *testing.T) {
t.Skip("https://github.com/istio/istio/issues/52835")
assert.NoError(t, runIptables(proxyUID, "--redirect-dns"))
assert.NoError(t, runIptablesClean(proxyUID, "--redirect-dns"))
validateIptablesClean(t)
})
}

func validateIptablesClean(t *testing.T) {
cur := iptablesSave(t)
if strings.Contains(cur, "ISTIO") {
t.Fatalf("Istio rules leftover: %v", cur)
}
}

var initialized = &sync.Once{}

func setup(t *testing.T) {
initialized.Do(func() {
// Setup group namespace so iptables --gid-owner will work
assert.NoError(t, userns.WriteGroupMap(map[uint32]uint32{userns.OriginalGID(): 0}))
// Istio iptables expects to find a non-localhost IP in some interface
assert.NoError(t, exec.Command("ip", "addr", "add", "240.240.240.240/32", "dev", "lo").Run())
// Put a new file we have permission to access over xtables.lock
xtables := filepath.Join(t.TempDir(), "xtables.lock")
_, err := os.Create(xtables)
assert.NoError(t, err)
_ = os.Mkdir("/run", 0o777)
assert.NoError(t, mountns.BindMount(xtables, "/run/xtables.lock"))
})
}

func runIptables(args ...string) error {
c := iptablescmd.GetCommand(log.DefaultOptions())
c.SetArgs(args)
return c.Execute()
}

func runIptablesClean(args ...string) error {
c := cleancmd.GetCommand(log.DefaultOptions())
c.SetArgs(args)
return c.Execute()
}

func iptablesSave(t *testing.T) string {
res, err := exec.Command("iptables-save").CombinedOutput()
assert.NoError(t, err)
return string(res)
}

0 comments on commit f32eaf4

Please sign in to comment.