Skip to content

Commit 5317357

Browse files
authored
e2e: Support testing on MacOS without requiring firewall exceptions (ava-labs#1613)
1 parent eb6e797 commit 5317357

File tree

5 files changed

+46
-26
lines changed

5 files changed

+46
-26
lines changed

config/config.go

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -603,18 +603,22 @@ func getIPConfig(v *viper.Viper) (node.IPConfig, error) {
603603
return node.IPConfig{}, fmt.Errorf("only one of --%s and --%s can be given", PublicIPKey, PublicIPResolutionServiceKey)
604604
}
605605

606+
// Define default configuration
607+
ipConfig := node.IPConfig{
608+
IPUpdater: dynamicip.NewNoUpdater(),
609+
IPResolutionFreq: ipResolutionFreq,
610+
Nat: nat.NewNoRouter(),
611+
ListenHost: v.GetString(StakingHostKey),
612+
}
613+
606614
if publicIP != "" {
607615
// User specified a specific public IP to use.
608616
ip := net.ParseIP(publicIP)
609617
if ip == nil {
610618
return node.IPConfig{}, fmt.Errorf("invalid IP Address %s", publicIP)
611619
}
612-
return node.IPConfig{
613-
IPPort: ips.NewDynamicIPPort(ip, stakingPort),
614-
IPUpdater: dynamicip.NewNoUpdater(),
615-
IPResolutionFreq: ipResolutionFreq,
616-
Nat: nat.NewNoRouter(),
617-
}, nil
620+
ipConfig.IPPort = ips.NewDynamicIPPort(ip, stakingPort)
621+
return ipConfig, nil
618622
}
619623
if ipResolutionService != "" {
620624
// User specified to use dynamic IP resolution.
@@ -630,18 +634,9 @@ func getIPConfig(v *viper.Viper) (node.IPConfig, error) {
630634
if err != nil {
631635
return node.IPConfig{}, fmt.Errorf("couldn't resolve public IP: %w", err)
632636
}
633-
ipPort := ips.NewDynamicIPPort(ip, stakingPort)
634-
635-
return node.IPConfig{
636-
IPPort: ipPort,
637-
IPUpdater: dynamicip.NewUpdater(
638-
ipPort,
639-
resolver,
640-
ipResolutionFreq,
641-
),
642-
IPResolutionFreq: ipResolutionFreq,
643-
Nat: nat.NewNoRouter(),
644-
}, nil
637+
ipConfig.IPPort = ips.NewDynamicIPPort(ip, stakingPort)
638+
ipConfig.IPUpdater = dynamicip.NewUpdater(ipConfig.IPPort, resolver, ipResolutionFreq)
639+
return ipConfig, nil
645640
}
646641

647642
// User didn't specify a public IP to use, and they didn't specify a public IP resolution
@@ -651,13 +646,10 @@ func getIPConfig(v *viper.Viper) (node.IPConfig, error) {
651646
if err != nil {
652647
return node.IPConfig{}, fmt.Errorf("public IP / IP resolution service not given and failed to resolve IP with NAT: %w", err)
653648
}
654-
return node.IPConfig{
655-
Nat: nat,
656-
AttemptedNATTraversal: true,
657-
IPPort: ips.NewDynamicIPPort(ip, stakingPort),
658-
IPUpdater: dynamicip.NewNoUpdater(),
659-
IPResolutionFreq: ipResolutionFreq,
660-
}, nil
649+
ipConfig.IPPort = ips.NewDynamicIPPort(ip, stakingPort)
650+
ipConfig.Nat = nat
651+
ipConfig.AttemptedNATTraversal = true
652+
return ipConfig, nil
661653
}
662654

663655
func getProfilerConfig(v *viper.Viper) (profiler.Config, error) {

config/flags.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ func addNodeFlags(fs *pflag.FlagSet) {
258258
fs.Duration(NetworkHealthMaxOutstandingDurationKey, 5*time.Minute, "Node reports unhealthy if there has been a request outstanding for this duration")
259259

260260
// Staking
261+
fs.String(StakingHostKey, "", "Address of the consensus server") // Bind to all interfaces by default.
261262
fs.Uint(StakingPortKey, DefaultStakingPort, "Port of the consensus server")
262263
// TODO: Remove this flag in the future
263264
fs.Bool(StakingEnabledKey, true, "Enable staking. If enabled, Network TLS is required")

config/keys.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const (
6868
StateSyncIDsKey = "state-sync-ids"
6969
BootstrapIPsKey = "bootstrap-ips"
7070
BootstrapIDsKey = "bootstrap-ids"
71+
StakingHostKey = "staking-host"
7172
StakingPortKey = "staking-port"
7273
StakingEnabledKey = "staking-enabled" // TODO: deprecated, remove this
7374
StakingEphemeralCertEnabledKey = "staking-ephemeral-cert-enabled"

node/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ type IPConfig struct {
8181
AttemptedNATTraversal bool `json:"attemptedNATTraversal"`
8282
// Tries to perform network address translation
8383
Nat nat.Router `json:"-"`
84+
// The host portion of the address to listen on. The port to
85+
// listen on will be sourced from IPPort.
86+
//
87+
// - If empty, listen on all interfaces (both ipv4 and ipv6).
88+
// - If populated, listen only on the specified address.
89+
ListenHost string `json:"listenHost"`
8490
}
8591

8692
type StakingConfig struct {

node/node.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,27 @@ type Node struct {
212212
// Assumes [n.CPUTracker] and [n.CPUTargeter] have been initialized.
213213
func (n *Node) initNetworking(primaryNetVdrs validators.Set) error {
214214
currentIPPort := n.Config.IPPort.IPPort()
215-
listener, err := net.Listen(constants.NetworkType, fmt.Sprintf(":%d", currentIPPort.Port))
215+
216+
// Providing either loopback address - `::1` for ipv6 and `127.0.0.1` for ipv4 - as the listen
217+
// host will avoid the need for a firewall exception on recent MacOS:
218+
//
219+
// - MacOS requires a manually-approved firewall exception [1] for each version of a given
220+
// binary that wants to bind to all interfaces (i.e. with an address of `:[port]`). Each
221+
// compiled version of avalanchego requires a separate exception to be allowed to bind to all
222+
// interfaces.
223+
//
224+
// - A firewall exception is not required to bind to a loopback interface, but the only way for
225+
// Listen() to bind to loopback for both ipv4 and ipv6 is to bind to all interfaces [2] which
226+
// requires an exception.
227+
//
228+
// - Thus, the only way to start a node on MacOS without approving a firewall exception for the
229+
// avalanchego binary is to bind to loopback by specifying the host to be `::1` or `127.0.0.1`.
230+
//
231+
// 1: https://apple.stackexchange.com/questions/393715/do-you-want-the-application-main-to-accept-incoming-network-connections-pop
232+
// 2: https://github.com/golang/go/issues/56998
233+
listenAddress := net.JoinHostPort(n.Config.ListenHost, fmt.Sprintf("%d", currentIPPort.Port))
234+
235+
listener, err := net.Listen(constants.NetworkType, listenAddress)
216236
if err != nil {
217237
return err
218238
}

0 commit comments

Comments
 (0)