Skip to content

Commit

Permalink
e2e: Support testing on MacOS without requiring firewall exceptions (a…
Browse files Browse the repository at this point in the history
  • Loading branch information
marun committed Jun 15, 2023
1 parent eb6e797 commit 5317357
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 26 deletions.
42 changes: 17 additions & 25 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,18 +603,22 @@ func getIPConfig(v *viper.Viper) (node.IPConfig, error) {
return node.IPConfig{}, fmt.Errorf("only one of --%s and --%s can be given", PublicIPKey, PublicIPResolutionServiceKey)
}

// Define default configuration
ipConfig := node.IPConfig{
IPUpdater: dynamicip.NewNoUpdater(),
IPResolutionFreq: ipResolutionFreq,
Nat: nat.NewNoRouter(),
ListenHost: v.GetString(StakingHostKey),
}

if publicIP != "" {
// User specified a specific public IP to use.
ip := net.ParseIP(publicIP)
if ip == nil {
return node.IPConfig{}, fmt.Errorf("invalid IP Address %s", publicIP)
}
return node.IPConfig{
IPPort: ips.NewDynamicIPPort(ip, stakingPort),
IPUpdater: dynamicip.NewNoUpdater(),
IPResolutionFreq: ipResolutionFreq,
Nat: nat.NewNoRouter(),
}, nil
ipConfig.IPPort = ips.NewDynamicIPPort(ip, stakingPort)
return ipConfig, nil
}
if ipResolutionService != "" {
// User specified to use dynamic IP resolution.
Expand All @@ -630,18 +634,9 @@ func getIPConfig(v *viper.Viper) (node.IPConfig, error) {
if err != nil {
return node.IPConfig{}, fmt.Errorf("couldn't resolve public IP: %w", err)
}
ipPort := ips.NewDynamicIPPort(ip, stakingPort)

return node.IPConfig{
IPPort: ipPort,
IPUpdater: dynamicip.NewUpdater(
ipPort,
resolver,
ipResolutionFreq,
),
IPResolutionFreq: ipResolutionFreq,
Nat: nat.NewNoRouter(),
}, nil
ipConfig.IPPort = ips.NewDynamicIPPort(ip, stakingPort)
ipConfig.IPUpdater = dynamicip.NewUpdater(ipConfig.IPPort, resolver, ipResolutionFreq)
return ipConfig, nil
}

// User didn't specify a public IP to use, and they didn't specify a public IP resolution
Expand All @@ -651,13 +646,10 @@ func getIPConfig(v *viper.Viper) (node.IPConfig, error) {
if err != nil {
return node.IPConfig{}, fmt.Errorf("public IP / IP resolution service not given and failed to resolve IP with NAT: %w", err)
}
return node.IPConfig{
Nat: nat,
AttemptedNATTraversal: true,
IPPort: ips.NewDynamicIPPort(ip, stakingPort),
IPUpdater: dynamicip.NewNoUpdater(),
IPResolutionFreq: ipResolutionFreq,
}, nil
ipConfig.IPPort = ips.NewDynamicIPPort(ip, stakingPort)
ipConfig.Nat = nat
ipConfig.AttemptedNATTraversal = true
return ipConfig, nil
}

func getProfilerConfig(v *viper.Viper) (profiler.Config, error) {
Expand Down
1 change: 1 addition & 0 deletions config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ func addNodeFlags(fs *pflag.FlagSet) {
fs.Duration(NetworkHealthMaxOutstandingDurationKey, 5*time.Minute, "Node reports unhealthy if there has been a request outstanding for this duration")

// Staking
fs.String(StakingHostKey, "", "Address of the consensus server") // Bind to all interfaces by default.
fs.Uint(StakingPortKey, DefaultStakingPort, "Port of the consensus server")
// TODO: Remove this flag in the future
fs.Bool(StakingEnabledKey, true, "Enable staking. If enabled, Network TLS is required")
Expand Down
1 change: 1 addition & 0 deletions config/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const (
StateSyncIDsKey = "state-sync-ids"
BootstrapIPsKey = "bootstrap-ips"
BootstrapIDsKey = "bootstrap-ids"
StakingHostKey = "staking-host"
StakingPortKey = "staking-port"
StakingEnabledKey = "staking-enabled" // TODO: deprecated, remove this
StakingEphemeralCertEnabledKey = "staking-ephemeral-cert-enabled"
Expand Down
6 changes: 6 additions & 0 deletions node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ type IPConfig struct {
AttemptedNATTraversal bool `json:"attemptedNATTraversal"`
// Tries to perform network address translation
Nat nat.Router `json:"-"`
// The host portion of the address to listen on. The port to
// listen on will be sourced from IPPort.
//
// - If empty, listen on all interfaces (both ipv4 and ipv6).
// - If populated, listen only on the specified address.
ListenHost string `json:"listenHost"`
}

type StakingConfig struct {
Expand Down
22 changes: 21 additions & 1 deletion node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,27 @@ type Node struct {
// Assumes [n.CPUTracker] and [n.CPUTargeter] have been initialized.
func (n *Node) initNetworking(primaryNetVdrs validators.Set) error {
currentIPPort := n.Config.IPPort.IPPort()
listener, err := net.Listen(constants.NetworkType, fmt.Sprintf(":%d", currentIPPort.Port))

// Providing either loopback address - `::1` for ipv6 and `127.0.0.1` for ipv4 - as the listen
// host will avoid the need for a firewall exception on recent MacOS:
//
// - MacOS requires a manually-approved firewall exception [1] for each version of a given
// binary that wants to bind to all interfaces (i.e. with an address of `:[port]`). Each
// compiled version of avalanchego requires a separate exception to be allowed to bind to all
// interfaces.
//
// - A firewall exception is not required to bind to a loopback interface, but the only way for
// Listen() to bind to loopback for both ipv4 and ipv6 is to bind to all interfaces [2] which
// requires an exception.
//
// - Thus, the only way to start a node on MacOS without approving a firewall exception for the
// avalanchego binary is to bind to loopback by specifying the host to be `::1` or `127.0.0.1`.
//
// 1: https://apple.stackexchange.com/questions/393715/do-you-want-the-application-main-to-accept-incoming-network-connections-pop
// 2: https://github.com/golang/go/issues/56998
listenAddress := net.JoinHostPort(n.Config.ListenHost, fmt.Sprintf("%d", currentIPPort.Port))

listener, err := net.Listen(constants.NetworkType, listenAddress)
if err != nil {
return err
}
Expand Down

0 comments on commit 5317357

Please sign in to comment.