WIP: rebase fork onto upstream/main (v1.103.0) #15
@@ -30,6 +30,7 @@ import (
|
||||
"tailscale.com/tka"
|
||||
"tailscale.com/tstest"
|
||||
"tailscale.com/tstest/deptest"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/types/persist"
|
||||
@@ -769,7 +770,22 @@ func TestPrefsFromUpArgs(t *testing.T) {
|
||||
args: upArgsT{
|
||||
exitNodeIP: "foo",
|
||||
},
|
||||
wantErr: `invalid value "foo" for --exit-node; must be IP or hostname`,
|
||||
st: &ipnstate.Status{
|
||||
Peer: map[key.NodePublic]*ipnstate.PeerStatus{
|
||||
key.NewNode().Public(): {
|
||||
DNSName: "example.com.",
|
||||
TailscaleIPs: []netip.Addr{netip.MustParseAddr("1.0.0.2")},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: `invalid value "foo" for --exit-node; must be IP or peer hostname`,
|
||||
},
|
||||
{
|
||||
name: "error_exit_node_not_started",
|
||||
args: upArgsT{
|
||||
exitNodeIP: "foo",
|
||||
},
|
||||
wantErr: `cannot resolve exit node by hostname while Tailscale is starting up; please use its Tailscale IP address instead`,
|
||||
},
|
||||
{
|
||||
name: "error_exit_node_allow_lan_without_exit_node",
|
||||
|
||||
+12
-1
@@ -872,10 +872,14 @@ func (e ExitNodeLocalIPError) Error() string {
|
||||
return fmt.Sprintf("cannot use %s as an exit node as it is a local IP address to this machine", e.hostOrIP)
|
||||
}
|
||||
|
||||
// exitNodeIPOfArg returns the IP address of the exit node based on the
|
||||
// user-provided string.
|
||||
func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netip.Addr, err error) {
|
||||
if s == "" {
|
||||
return ip, os.ErrInvalid
|
||||
}
|
||||
|
||||
// If the string is a valid IP address, that's the exit node.
|
||||
ip, err = netip.ParseAddr(s)
|
||||
if err == nil {
|
||||
if !isRemoteIP(st, ip) {
|
||||
@@ -894,6 +898,13 @@ func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netip.Addr, err error) {
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// If the string is not a valid IP address, assume it's a hostname.
|
||||
// Search the list of peers for a matching hostname.
|
||||
if len(st.Peer) == 0 {
|
||||
return ip, errors.New("cannot resolve exit node by hostname while Tailscale is starting up; " +
|
||||
"please use its Tailscale IP address instead")
|
||||
}
|
||||
match := 0
|
||||
for _, ps := range st.Peer {
|
||||
// Compare to the peer name in three forms:
|
||||
@@ -920,7 +931,7 @@ func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netip.Addr, err error) {
|
||||
}
|
||||
switch match {
|
||||
case 0:
|
||||
return ip, fmt.Errorf("invalid value %q for --exit-node; must be IP or hostname", s)
|
||||
return ip, fmt.Errorf("invalid value %q for --exit-node; must be IP or peer hostname", s)
|
||||
case 1:
|
||||
if !isRemoteIP(st, ip) {
|
||||
return ip, ExitNodeLocalIPError{s}
|
||||
|
||||
+20
-5
@@ -1006,10 +1006,19 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
want: mustIP("1.2.3.4"),
|
||||
},
|
||||
{
|
||||
name: "no_match",
|
||||
arg: "unknown",
|
||||
st: &ipnstate.Status{MagicDNSSuffix: ".foo"},
|
||||
wantErr: `invalid value "unknown" for --exit-node; must be IP or hostname`,
|
||||
name: "no_match",
|
||||
arg: "unknown",
|
||||
st: &ipnstate.Status{
|
||||
MagicDNSSuffix: ".foo",
|
||||
Peer: map[key.NodePublic]*ipnstate.PeerStatus{
|
||||
key.NewNode().Public(): {
|
||||
DNSName: "skippy.foo.",
|
||||
TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
|
||||
ExitNodeOption: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: `invalid value "unknown" for --exit-node; must be IP or peer hostname`,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
@@ -1056,6 +1065,12 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
},
|
||||
want: mustIP("1.0.0.2"),
|
||||
},
|
||||
{
|
||||
name: "hostname_no_peer",
|
||||
arg: "skippy.foo",
|
||||
st: &ipnstate.Status{},
|
||||
wantErr: `cannot resolve exit node by hostname while Tailscale is starting up; please use its Tailscale IP address instead`,
|
||||
},
|
||||
{
|
||||
name: "name_not_exit",
|
||||
arg: "skippy",
|
||||
@@ -1082,7 +1097,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: `invalid value "skippy.bar." for --exit-node; must be IP or hostname`,
|
||||
wantErr: `invalid value "skippy.bar." for --exit-node; must be IP or peer hostname`,
|
||||
},
|
||||
{
|
||||
name: "ambiguous",
|
||||
|
||||
Reference in New Issue
Block a user