Skip to content

Commit 2ea820c

Browse files
committed
Use Go net ns switcher instead of nsenter
This commit swaps out the previous implementation of using the command `nsenter` to switch networking namespaces. By using the Go impl of network namespace switching, read-only filesystems and OSs without the `nsenter` command (such as Talos) should still work.
1 parent 1ba375b commit 2ea820c

File tree

3 files changed

+50
-15
lines changed

3 files changed

+50
-15
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.21
44

55
require (
66
github.com/containernetworking/cni v1.1.2
7+
github.com/containernetworking/plugins v1.3.0
78
github.com/mitchellh/mapstructure v1.5.0
89
github.com/sirupsen/logrus v1.9.3
910
github.com/spf13/cobra v1.7.0

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
33
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
44
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
55
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
6+
github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q6mVDp5H1HnjM=
7+
github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0=
68
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
79
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
810
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -50,8 +52,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
5052
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
5153
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
5254
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
53-
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
54-
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
55+
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk=
56+
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
5557
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
5658
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5759
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=

internal/iptables/iptables.go

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"time"
1010

11+
ns "github.com/containernetworking/plugins/pkg/ns"
1112
log "github.com/sirupsen/logrus"
1213

1314
util "github.com/linkerd/linkerd2-proxy-init/internal/util"
@@ -229,28 +230,59 @@ func makeMultiportDestinations(portsToIgnore []string) [][]string {
229230
}
230231

231232
func executeCommand(firewallConfiguration FirewallConfiguration, cmd *exec.Cmd) ([]byte, error) {
232-
if firewallConfiguration.NetNs != "" {
233-
// BusyBox's `nsenter` needs `--` to separate nsenter arguments from the
234-
// command.
235-
//
236-
// See https://github.com/rancher/k3s/issues/1434#issuecomment-629315909
237-
nsArgs := fmt.Sprintf("--net=%s", firewallConfiguration.NetNs)
238-
args := append([]string{nsArgs, "--"}, cmd.Args...)
239-
cmd = exec.Command("nsenter", args...)
240-
}
233+
// Always log the command to apply for tracing purposes
241234
log.Info(cmd.String())
242235

236+
// Short out early if we are just simulating the network
243237
if firewallConfiguration.SimulateOnly {
244238
return nil, nil
245239
}
246240

247-
out, err := cmd.CombinedOutput()
241+
// Helper for reusing code when actually calling out to the command
242+
doCommand := func() ([]byte, error) {
243+
out, err := cmd.CombinedOutput()
248244

249-
if len(out) > 0 {
250-
log.Infof("%s", out)
245+
// Log out the output, if any
246+
if len(out) > 0 {
247+
log.Infof("%s", out)
248+
}
249+
250+
return out, err
251251
}
252252

253-
return out, err
253+
// If we need to run within a target network namespace, then wrap the command
254+
// in that namespace.
255+
//
256+
// Note: Network namespace switching is very volatile in Go. Care should be taken
257+
// to ensure that all namespaced commands be wrapped in `targetNamespace.Do`, as explained in
258+
// the link below.
259+
//
260+
// See: https://pkg.go.dev/github.com/containernetworking/plugins/pkg/ns#readme-do-the-recommended-thing
261+
if firewallConfiguration.NetNs != "" {
262+
// Fetch the target net namespace, ensuring that it exists
263+
netNs, err := ns.GetNS(firewallConfiguration.NetNs)
264+
if err != nil {
265+
log.Errorf("could not switch to target network namespace \"%s\": %s", firewallConfiguration.NetNs, err.Error())
266+
return nil, err
267+
}
268+
269+
// Actually run the command in the namespace
270+
// Note: Try to keep this code short! Goroutine switches might cause the
271+
// namespace to change...
272+
//
273+
// Note: Result needs to be defined here since `netNs.Do` only returns
274+
// an error.
275+
result := make([]byte, 0)
276+
err = netNs.Do(func(_ ns.NetNS) error {
277+
result, err = doCommand()
278+
279+
return err
280+
})
281+
282+
return result, err
283+
} else {
284+
return doCommand()
285+
}
254286
}
255287

256288
func (fc FirewallConfiguration) makeIgnoreUserID(chainName string, uid int, comment string) *exec.Cmd {

0 commit comments

Comments
 (0)