Просмотр исходного кода

RunNetworkConfigCommand: move to common package

Rod Hynes 5 лет назад
Родитель
Сommit
e945a3148e

+ 72 - 0
psiphon/common/networkConfig.go

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package common
+
+import (
+	"fmt"
+	"os/exec"
+
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
+)
+
+// RunNetworkConfigCommand execs a network config command, such as "ifconfig"
+// or "iptables". On platforms that support capabilities, the network config
+// capabilities of the current process is made available to the command
+// subprocess. Alternatively, "sudo" will be used when useSudo is true.
+func RunNetworkConfigCommand(
+	logger Logger,
+	useSudo bool,
+	commandName string, commandArgs ...string) error {
+
+	// configureSubprocessCapabilities will set inheritable
+	// capabilities on platforms which support that (Linux).
+	// Specifically, CAP_NET_ADMIN will be transferred from
+	// this process to the child command.
+
+	err := configureNetworkConfigSubprocessCapabilities()
+	if err != nil {
+		return errors.Trace(err)
+	}
+
+	// TODO: use CommandContext to interrupt on process shutdown?
+	// (the commands currently being issued shouldn't block...)
+
+	if useSudo {
+		commandArgs = append([]string{commandName}, commandArgs...)
+		commandName = "sudo"
+	}
+
+	cmd := exec.Command(commandName, commandArgs...)
+	output, err := cmd.CombinedOutput()
+
+	logger.WithTraceFields(LogFields{
+		"command": commandName,
+		"args":    commandArgs,
+		"output":  string(output),
+		"error":   err,
+	}).Debug("exec")
+
+	if err != nil {
+		err := fmt.Errorf(
+			"command %s %+v failed with %s", commandName, commandArgs, string(output))
+		return errors.Trace(err)
+	}
+	return nil
+}

+ 55 - 0
psiphon/common/networkConfig_linux.go

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package common
+
+import (
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
+	"github.com/syndtr/gocapability/capability"
+)
+
+func configureNetworkConfigSubprocessCapabilities() error {
+
+	// If this process has CAP_NET_ADMIN, make it available to be inherited
+	// be child processes via ambient mechanism described here:
+	// https://github.com/torvalds/linux/commit/58319057b7847667f0c9585b9de0e8932b0fdb08
+	//
+	// The ambient mechanism is available in Linux kernel 4.3 and later.
+
+	// When using capabilities, this process should have CAP_NET_ADMIN in order
+	// to create tun devices. And the subprocess operations such as using "ifconfig"
+	// and "iptables" for network config require the same CAP_NET_ADMIN capability.
+
+	cap, err := capability.NewPid(0)
+	if err != nil {
+		return errors.Trace(err)
+	}
+
+	if cap.Get(capability.EFFECTIVE, capability.CAP_NET_ADMIN) {
+
+		cap.Set(capability.INHERITABLE|capability.AMBIENT, capability.CAP_NET_ADMIN)
+
+		err = cap.Apply(capability.AMBIENT)
+		if err != nil {
+			return errors.Trace(err)
+		}
+	}
+
+	return nil
+}

+ 27 - 0
psiphon/common/networkConfig_other.go

@@ -0,0 +1,27 @@
+// +build !linux
+
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package common
+
+func configureNetworkConfigSubprocessCapabilities() error {
+	// No-op on this platform
+	return nil
+}

+ 9 - 14
psiphon/common/tun/tun_darwin.go

@@ -247,11 +247,6 @@ func (device *Device) writeTunPacket(packet []byte) error {
 	return nil
 }
 
-func configureNetworkConfigSubprocessCapabilities() error {
-	// Not supported on Darwin
-	return nil
-}
-
 func resetNATTables(_ *ServerConfig, _ net.IP) error {
 	// Not supported on Darwin
 	// TODO: could use pfctl -K?
@@ -272,7 +267,7 @@ func configureServerInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -289,7 +284,7 @@ func configureServerInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -309,7 +304,7 @@ func configureServerInterface(
 		egressInterface = DEFAULT_PUBLIC_INTERFACE_NAME
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"sysctl",
@@ -318,7 +313,7 @@ func configureServerInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"sysctl",
@@ -359,14 +354,14 @@ func configureServerInterface(
 	}).Debug("pf.conf")
 
 	// Disable first to avoid "pfctl: pf already enabled"
-	_ = runNetworkConfigCommand(
+	_ = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"pfctl",
 		"-q",
 		"-d")
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"pfctl",
@@ -394,7 +389,7 @@ func configureClientInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -412,7 +407,7 @@ func configureClientInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -429,7 +424,7 @@ func configureClientInterface(
 
 		// TODO: IPv6
 
-		err = runNetworkConfigCommand(
+		err = common.RunNetworkConfigCommand(
 			config.Logger,
 			config.SudoNetworkConfigCommands,
 			"route",

+ 19 - 44
psiphon/common/tun/tun_linux.go

@@ -30,7 +30,6 @@ import (
 
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
-	"github.com/syndtr/gocapability/capability"
 )
 
 const (
@@ -140,36 +139,6 @@ func (device *Device) writeTunPacket(packet []byte) error {
 	return nil
 }
 
-func configureNetworkConfigSubprocessCapabilities() error {
-
-	// If this process has CAP_NET_ADMIN, make it available to be inherited
-	// be child processes via ambient mechanism described here:
-	// https://github.com/torvalds/linux/commit/58319057b7847667f0c9585b9de0e8932b0fdb08
-	//
-	// The ambient mechanism is available in Linux kernel 4.3 and later.
-
-	// When using capabilities, this process should have CAP_NET_ADMIN in order
-	// to create tun devices. And the subprocess operations such as using "ifconfig"
-	// and "iptables" for network config require the same CAP_NET_ADMIN capability.
-
-	cap, err := capability.NewPid(0)
-	if err != nil {
-		return errors.Trace(err)
-	}
-
-	if cap.Get(capability.EFFECTIVE, capability.CAP_NET_ADMIN) {
-
-		cap.Set(capability.INHERITABLE|capability.AMBIENT, capability.CAP_NET_ADMIN)
-
-		err = cap.Apply(capability.AMBIENT)
-		if err != nil {
-			return errors.Trace(err)
-		}
-	}
-
-	return nil
-}
-
 func resetNATTables(
 	config *ServerConfig,
 	IPAddress net.IP) error {
@@ -182,7 +151,7 @@ func resetNATTables(
 	// the already unlikely event that there's still in-flight traffic when the address is
 	// recycled.
 
-	err := runNetworkConfigCommand(
+	err := common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"conntrack",
@@ -215,7 +184,7 @@ func configureServerInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -227,7 +196,7 @@ func configureServerInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -253,7 +222,7 @@ func configureServerInterface(
 
 	// TODO: need only set forwarding for specific interfaces?
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"sysctl",
@@ -262,7 +231,7 @@ func configureServerInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"sysctl",
@@ -282,7 +251,7 @@ func configureServerInterface(
 
 	for _, mode := range []string{"-D", "-A"} {
 
-		err = runNetworkConfigCommand(
+		err = common.RunNetworkConfigCommand(
 			config.Logger,
 			config.SudoNetworkConfigCommands,
 			"iptables",
@@ -295,7 +264,7 @@ func configureServerInterface(
 			return errors.Trace(err)
 		}
 
-		err = runNetworkConfigCommand(
+		err = common.RunNetworkConfigCommand(
 			config.Logger,
 			config.SudoNetworkConfigCommands,
 			"ip6tables",
@@ -330,7 +299,7 @@ func configureClientInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -343,7 +312,7 @@ func configureClientInterface(
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		config.Logger,
 		config.SudoNetworkConfigCommands,
 		"ifconfig",
@@ -384,7 +353,7 @@ func configureClientInterface(
 		// Note: use "replace" instead of "add" as route from
 		// previous run (e.g., tun_test case) may not yet be cleared.
 
-		err = runNetworkConfigCommand(
+		err = common.RunNetworkConfigCommand(
 			config.Logger,
 			config.SudoNetworkConfigCommands,
 			"ip",
@@ -419,8 +388,14 @@ func fixBindToDevice(logger common.Logger, useSudo bool, tunDeviceName string) e
 
 	// Fix the problem described here:
 	// https://stackoverflow.com/questions/24011205/cant-perform-tcp-handshake-through-a-nat-between-two-nics-with-so-bindtodevice/
+	//
+	// > the linux kernel is configured on certain mainstream distributions
+	// > (Ubuntu...) to act as a router and drop packets where the source
+	// > address is suspect in order to prevent spoofing (search "rp_filter" on
+	// > https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt and
+	// > RFC3704)
 
-	err := runNetworkConfigCommand(
+	err := common.RunNetworkConfigCommand(
 		logger,
 		useSudo,
 		"sysctl",
@@ -429,7 +404,7 @@ func fixBindToDevice(logger common.Logger, useSudo bool, tunDeviceName string) e
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		logger,
 		useSudo,
 		"sysctl",
@@ -438,7 +413,7 @@ func fixBindToDevice(logger common.Logger, useSudo bool, tunDeviceName string) e
 		return errors.Trace(err)
 	}
 
-	err = runNetworkConfigCommand(
+	err = common.RunNetworkConfigCommand(
 		logger,
 		useSudo,
 		"sysctl",

+ 0 - 47
psiphon/common/tun/utils.go

@@ -23,60 +23,13 @@ import (
 	std_errors "errors"
 	"fmt"
 	"net"
-	"os/exec"
 	"strconv"
 
-	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
 )
 
 var errUnsupported = std_errors.New("operation unsupported on this platform")
 
-// runNetworkConfigCommand execs a network config command, such as "ifconfig"
-// or "iptables". On platforms that support capabilities, the network config
-// capabilities of the current process is made available to the command
-// subprocess. Alternatively, "sudo" will be used when useSudo is true.
-func runNetworkConfigCommand(
-	logger common.Logger,
-	useSudo bool,
-	commandName string, commandArgs ...string) error {
-
-	// configureSubprocessCapabilities will set inheritable
-	// capabilities on platforms which support that (Linux).
-	// Specifically, CAP_NET_ADMIN will be transferred from
-	// this process to the child command.
-
-	err := configureNetworkConfigSubprocessCapabilities()
-	if err != nil {
-		return errors.Trace(err)
-	}
-
-	// TODO: use CommandContext to interrupt on server shutdown?
-	// (the commands currently being issued shouldn't block...)
-
-	if useSudo {
-		commandArgs = append([]string{commandName}, commandArgs...)
-		commandName = "sudo"
-	}
-
-	cmd := exec.Command(commandName, commandArgs...)
-	output, err := cmd.CombinedOutput()
-
-	logger.WithTraceFields(common.LogFields{
-		"command": commandName,
-		"args":    commandArgs,
-		"output":  string(output),
-		"error":   err,
-	}).Debug("exec")
-
-	if err != nil {
-		err := fmt.Errorf(
-			"command %s %+v failed with %s", commandName, commandArgs, string(output))
-		return errors.Trace(err)
-	}
-	return nil
-}
-
 func splitIPMask(IPAddressCIDR string) (string, string, error) {
 
 	IP, IPNet, err := net.ParseCIDR(IPAddressCIDR)