@ -22,7 +22,9 @@ import (
"inet.af/netaddr"
"inet.af/netaddr"
"tailscale.com/client/tailscale"
"tailscale.com/client/tailscale"
"tailscale.com/ipn"
"tailscale.com/ipn"
"tailscale.com/ipn/ipnstate"
"tailscale.com/tailcfg"
"tailscale.com/tailcfg"
"tailscale.com/types/logger"
"tailscale.com/types/preftype"
"tailscale.com/types/preftype"
"tailscale.com/version/distro"
"tailscale.com/version/distro"
)
)
@ -84,7 +86,7 @@ func defaultNetfilterMode() string {
return "on"
return "on"
}
}
var upArgs struct {
type upArgsT struct {
reset bool
reset bool
server string
server string
acceptRoutes bool
acceptRoutes bool
@ -104,6 +106,8 @@ var upArgs struct {
hostname string
hostname string
}
}
var upArgs upArgsT
func warnf ( format string , args ... interface { } ) {
func warnf ( format string , args ... interface { } ) {
fmt . Printf ( "Warning: " + format + "\n" , args ... )
fmt . Printf ( "Warning: " + format + "\n" , args ... )
}
}
@ -113,29 +117,13 @@ var (
ipv6default = netaddr . MustParseIPPrefix ( "::/0" )
ipv6default = netaddr . MustParseIPPrefix ( "::/0" )
)
)
func runUp ( ctx context . Context , args [ ] string ) error {
// prefsFromUpArgs returns the ipn.Prefs for the provided args.
if len ( args ) > 0 {
//
fatalf ( "too many non-flag arguments: %q" , args )
// Note that the parameters upArgs and warnf are named intentionally
}
// to shadow the globals to prevent accidental misuse of them. This
// function exists for testing and should have no side effects or
st , err := tailscale . Status ( ctx )
// outside interactions (e.g. no making Tailscale local API calls).
if err != nil {
func prefsFromUpArgs ( upArgs upArgsT , warnf logger . Logf , st * ipnstate . Status , goos string ) ( * ipn . Prefs , error ) {
fatalf ( "can't fetch status from tailscaled: %v" , err )
}
if distro . Get ( ) == distro . Synology {
notSupported := "not yet supported on Synology; see https://github.com/tailscale/tailscale/issues/451"
if upArgs . acceptRoutes {
return errors . New ( "--accept-routes is " + notSupported )
}
if upArgs . exitNodeIP != "" {
return errors . New ( "--exit-node is " + notSupported )
}
if upArgs . netfilterMode != "off" {
return errors . New ( "--netfilter-mode values besides \"off\" " + notSupported )
}
}
routeMap := map [ netaddr . IPPrefix ] bool { }
routeMap := map [ netaddr . IPPrefix ] bool { }
var default4 , default6 bool
var default4 , default6 bool
if upArgs . advertiseRoutes != "" {
if upArgs . advertiseRoutes != "" {
@ -143,10 +131,10 @@ func runUp(ctx context.Context, args []string) error {
for _ , s := range advroutes {
for _ , s := range advroutes {
ipp , err := netaddr . ParseIPPrefix ( s )
ipp , err := netaddr . ParseIPPrefix ( s )
if err != nil {
if err != nil {
fatal f( "%q is not a valid IP address or CIDR prefix" , s )
return nil , fmt . Error f( "%q is not a valid IP address or CIDR prefix" , s )
}
}
if ipp != ipp . Masked ( ) {
if ipp != ipp . Masked ( ) {
fatal f( "%s has non-address bits set; expected %s" , ipp , ipp . Masked ( ) )
return nil , fmt . Error f( "%s has non-address bits set; expected %s" , ipp , ipp . Masked ( ) )
}
}
if ipp == ipv4default {
if ipp == ipv4default {
default4 = true
default4 = true
@ -156,20 +144,15 @@ func runUp(ctx context.Context, args []string) error {
routeMap [ ipp ] = true
routeMap [ ipp ] = true
}
}
if default4 && ! default6 {
if default4 && ! default6 {
fatal f( "%s advertised without its IPv6 counterpart, please also advertise %s" , ipv4default , ipv6default )
return nil , fmt . Error f( "%s advertised without its IPv6 counterpart, please also advertise %s" , ipv4default , ipv6default )
} else if default6 && ! default4 {
} else if default6 && ! default4 {
fatal f( "%s advertised without its IPv6 counterpart, please also advertise %s" , ipv6default , ipv4default )
return nil , fmt . Error f( "%s advertised without its IPv6 counterpart, please also advertise %s" , ipv6default , ipv4default )
}
}
}
}
if upArgs . advertiseDefaultRoute {
if upArgs . advertiseDefaultRoute {
routeMap [ netaddr . MustParseIPPrefix ( "0.0.0.0/0" ) ] = true
routeMap [ netaddr . MustParseIPPrefix ( "0.0.0.0/0" ) ] = true
routeMap [ netaddr . MustParseIPPrefix ( "::/0" ) ] = true
routeMap [ netaddr . MustParseIPPrefix ( "::/0" ) ] = true
}
}
if len ( routeMap ) > 0 {
if err := tailscale . CheckIPForwarding ( context . Background ( ) ) ; err != nil {
warnf ( "%v" , err )
}
}
routes := make ( [ ] netaddr . IPPrefix , 0 , len ( routeMap ) )
routes := make ( [ ] netaddr . IPPrefix , 0 , len ( routeMap ) )
for r := range routeMap {
for r := range routeMap {
routes = append ( routes , r )
routes = append ( routes , r )
@ -186,16 +169,16 @@ func runUp(ctx context.Context, args []string) error {
var err error
var err error
exitNodeIP , err = netaddr . ParseIP ( upArgs . exitNodeIP )
exitNodeIP , err = netaddr . ParseIP ( upArgs . exitNodeIP )
if err != nil {
if err != nil {
fatal f( "invalid IP address %q for --exit-node: %v" , upArgs . exitNodeIP , err )
return nil , fmt . Error f( "invalid IP address %q for --exit-node: %v" , upArgs . exitNodeIP , err )
}
}
} else if upArgs . exitNodeAllowLANAccess {
} else if upArgs . exitNodeAllowLANAccess {
fatal f( "--exit-node-allow-lan-access can only be used with --exit-node" )
return nil , fmt . Error f( "--exit-node-allow-lan-access can only be used with --exit-node" )
}
}
if ! exitNodeIP . IsZero ( ) {
if upArgs . exitNodeIP != "" {
for _ , ip := range st . TailscaleIPs {
for _ , ip := range st . TailscaleIPs {
if exitNodeIP == ip {
if exitNodeIP == ip {
fatal f( "cannot use %s as the exit node as it is a local IP address to this machine, did you mean --advertise-exit-node?" , exitNodeIP )
return nil , fmt . Error f( "cannot use %s as the exit node as it is a local IP address to this machine, did you mean --advertise-exit-node?" , upArgs . exitNodeIP )
}
}
}
}
}
}
@ -206,13 +189,13 @@ func runUp(ctx context.Context, args []string) error {
for _ , tag := range tags {
for _ , tag := range tags {
err := tailcfg . CheckTag ( tag )
err := tailcfg . CheckTag ( tag )
if err != nil {
if err != nil {
fatal f( "tag: %q: %s" , tag , err )
return nil , fmt . Error f( "tag: %q: %s" , tag , err )
}
}
}
}
}
}
if len ( upArgs . hostname ) > 256 {
if len ( upArgs . hostname ) > 256 {
fatal f( "hostname too long: %d bytes (max 256)" , len ( upArgs . hostname ) )
return nil , fmt . Error f( "hostname too long: %d bytes (max 256)" , len ( upArgs . hostname ) )
}
}
prefs := ipn . NewPrefs ( )
prefs := ipn . NewPrefs ( )
@ -230,7 +213,7 @@ func runUp(ctx context.Context, args []string) error {
prefs . Hostname = upArgs . hostname
prefs . Hostname = upArgs . hostname
prefs . ForceDaemon = upArgs . forceDaemon
prefs . ForceDaemon = upArgs . forceDaemon
if runtime. GOOS == "linux" {
if goos == "linux" {
switch upArgs . netfilterMode {
switch upArgs . netfilterMode {
case "on" :
case "on" :
prefs . NetfilterMode = preftype . NetfilterOn
prefs . NetfilterMode = preftype . NetfilterOn
@ -241,7 +224,43 @@ func runUp(ctx context.Context, args []string) error {
prefs . NetfilterMode = preftype . NetfilterOff
prefs . NetfilterMode = preftype . NetfilterOff
warnf ( "netfilter=off; configure iptables yourself." )
warnf ( "netfilter=off; configure iptables yourself." )
default :
default :
fatalf ( "invalid value --netfilter-mode: %q" , upArgs . netfilterMode )
return nil , fmt . Errorf ( "invalid value --netfilter-mode=%q" , upArgs . netfilterMode )
}
}
return prefs , nil
}
func runUp ( ctx context . Context , args [ ] string ) error {
if len ( args ) > 0 {
fatalf ( "too many non-flag arguments: %q" , args )
}
st , err := tailscale . Status ( ctx )
if err != nil {
fatalf ( "can't fetch status from tailscaled: %v" , err )
}
if distro . Get ( ) == distro . Synology {
notSupported := "not yet supported on Synology; see https://github.com/tailscale/tailscale/issues/451"
if upArgs . acceptRoutes {
return errors . New ( "--accept-routes is " + notSupported )
}
if upArgs . exitNodeIP != "" {
return errors . New ( "--exit-node is " + notSupported )
}
if upArgs . netfilterMode != "off" {
return errors . New ( "--netfilter-mode values besides \"off\" " + notSupported )
}
}
prefs , err := prefsFromUpArgs ( upArgs , warnf , st , runtime . GOOS )
if err != nil {
fatalf ( "%s" , err )
}
if len ( prefs . AdvertiseRoutes ) > 0 {
if err := tailscale . CheckIPForwarding ( context . Background ( ) ) ; err != nil {
warnf ( "%v" , err )
}
}
}
}