Skip to content

Commit 1ab66a5

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 15d573f commit 1ab66a5

3 files changed

Lines changed: 54 additions & 15 deletions

File tree

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ require (
1313
)
1414

1515
require (
16+
github.com/containernetworking/plugins v1.3.0 // indirect
1617
github.com/davecgh/go-spew v1.1.1 // indirect
1718
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
18-
github.com/go-logr/logr v1.2.3 // indirect
19+
github.com/go-logr/logr v1.2.4 // indirect
1920
github.com/go-openapi/jsonpointer v0.19.6 // indirect
2021
github.com/go-openapi/jsonreference v0.20.1 // indirect
2122
github.com/go-openapi/swag v0.22.3 // indirect
@@ -36,7 +37,7 @@ require (
3637
github.com/spf13/pflag v1.0.5 // indirect
3738
golang.org/x/net v0.8.0 // indirect
3839
golang.org/x/oauth2 v0.2.0 // indirect
39-
golang.org/x/sys v0.6.0 // indirect
40+
golang.org/x/sys v0.7.0 // indirect
4041
golang.org/x/term v0.6.0 // indirect
4142
golang.org/x/text v0.8.0 // indirect
4243
golang.org/x/time v0.2.0 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht
1515
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
1616
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
1717
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
18+
github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q6mVDp5H1HnjM=
19+
github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0=
1820
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
1921
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
2022
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -36,6 +38,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
3638
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
3739
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
3840
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
41+
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
42+
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
3943
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
4044
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
4145
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
@@ -210,6 +214,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
210214
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
211215
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
212216
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
217+
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
218+
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
213219
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
214220
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
215221
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=

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)