|
|
@ -129,11 +129,16 @@ func main() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
st, daemonPid, err := startAndAuthTailscaled(ctx, cfg)
|
|
|
|
client, daemonPid, err := startTailscaled(ctx, cfg)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to bring up tailscale: %v", err)
|
|
|
|
log.Fatalf("failed to bring up tailscale: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st, err := authTailscaled(ctx, client, cfg)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Fatalf("failed to auth tailscale: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if cfg.ProxyTo != "" {
|
|
|
|
if cfg.ProxyTo != "" {
|
|
|
|
if err := installIPTablesRule(ctx, cfg.ProxyTo, st.TailscaleIPs); err != nil {
|
|
|
|
if err := installIPTablesRule(ctx, cfg.ProxyTo, st.TailscaleIPs); err != nil {
|
|
|
|
log.Fatalf("installing proxy rules: %v", err)
|
|
|
|
log.Fatalf("installing proxy rules: %v", err)
|
|
|
@ -173,10 +178,7 @@ func main() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// startAndAuthTailscaled starts the tailscale daemon and attempts to
|
|
|
|
func startTailscaled(ctx context.Context, cfg *settings) (*tailscale.LocalClient, int, error) {
|
|
|
|
// auth it, according to the settings in cfg. If successful, returns
|
|
|
|
|
|
|
|
// tailscaled's Status and pid.
|
|
|
|
|
|
|
|
func startAndAuthTailscaled(ctx context.Context, cfg *settings) (*ipnstate.Status, int, error) {
|
|
|
|
|
|
|
|
args := tailscaledArgs(cfg)
|
|
|
|
args := tailscaledArgs(cfg)
|
|
|
|
sigCh := make(chan os.Signal, 1)
|
|
|
|
sigCh := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(sigCh, unix.SIGTERM, unix.SIGINT)
|
|
|
|
signal.Notify(sigCh, unix.SIGTERM, unix.SIGINT)
|
|
|
@ -198,8 +200,7 @@ func startAndAuthTailscaled(ctx context.Context, cfg *settings) (*ipnstate.Statu
|
|
|
|
cmd.Process.Signal(unix.SIGTERM)
|
|
|
|
cmd.Process.Signal(unix.SIGTERM)
|
|
|
|
}()
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for the socket file to appear, otherwise 'tailscale up'
|
|
|
|
// Wait for the socket file to appear, otherwise API ops will racily fail.
|
|
|
|
// can fail.
|
|
|
|
|
|
|
|
log.Printf("Waiting for tailscaled socket")
|
|
|
|
log.Printf("Waiting for tailscaled socket")
|
|
|
|
for {
|
|
|
|
for {
|
|
|
|
if ctx.Err() != nil {
|
|
|
|
if ctx.Err() != nil {
|
|
|
@ -215,39 +216,46 @@ func startAndAuthTailscaled(ctx context.Context, cfg *settings) (*ipnstate.Statu
|
|
|
|
break
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tsClient := &tailscale.LocalClient{
|
|
|
|
|
|
|
|
Socket: cfg.Socket,
|
|
|
|
|
|
|
|
UseSocketOnly: true,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return tsClient, cmd.Process.Pid, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// startAndAuthTailscaled starts the tailscale daemon and attempts to
|
|
|
|
|
|
|
|
// auth it, according to the settings in cfg. If successful, returns
|
|
|
|
|
|
|
|
// tailscaled's Status and pid.
|
|
|
|
|
|
|
|
func authTailscaled(ctx context.Context, client *tailscale.LocalClient, cfg *settings) (*ipnstate.Status, error) {
|
|
|
|
didLogin := false
|
|
|
|
didLogin := false
|
|
|
|
if !cfg.AuthOnce {
|
|
|
|
if !cfg.AuthOnce {
|
|
|
|
if err := tailscaleUp(ctx, cfg); err != nil {
|
|
|
|
if err := tailscaleUp(ctx, cfg); err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("couldn't log in: %v", err)
|
|
|
|
return nil, fmt.Errorf("couldn't log in: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
didLogin = true
|
|
|
|
didLogin = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tsClient := tailscale.LocalClient{
|
|
|
|
|
|
|
|
Socket: cfg.Socket,
|
|
|
|
|
|
|
|
UseSocketOnly: true,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Poll for daemon state until it goes to either Running or
|
|
|
|
// Poll for daemon state until it goes to either Running or
|
|
|
|
// NeedsLogin. The latter only happens if cfg.AuthOnce is true,
|
|
|
|
// NeedsLogin. The latter only happens if cfg.AuthOnce is true,
|
|
|
|
// because in that case we only try to auth when it's necessary to
|
|
|
|
// because in that case we only try to auth when it's necessary to
|
|
|
|
// reach the running state.
|
|
|
|
// reach the running state.
|
|
|
|
for {
|
|
|
|
for {
|
|
|
|
if ctx.Err() != nil {
|
|
|
|
if ctx.Err() != nil {
|
|
|
|
return nil, 0, ctx.Err()
|
|
|
|
return nil, ctx.Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
loopCtx, cancel := context.WithTimeout(ctx, time.Second)
|
|
|
|
loopCtx, cancel := context.WithTimeout(ctx, time.Second)
|
|
|
|
st, err := tsClient.Status(loopCtx)
|
|
|
|
st, err := client.Status(loopCtx)
|
|
|
|
cancel()
|
|
|
|
cancel()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("Getting tailscaled state: %w", err)
|
|
|
|
return nil, fmt.Errorf("Getting tailscaled state: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch st.BackendState {
|
|
|
|
switch st.BackendState {
|
|
|
|
case "Running":
|
|
|
|
case "Running":
|
|
|
|
if len(st.TailscaleIPs) > 0 {
|
|
|
|
if len(st.TailscaleIPs) > 0 {
|
|
|
|
return st, cmd.Process.Pid, nil
|
|
|
|
return st, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Printf("No Tailscale IPs assigned yet")
|
|
|
|
log.Printf("No Tailscale IPs assigned yet")
|
|
|
|
case "NeedsLogin":
|
|
|
|
case "NeedsLogin":
|
|
|
@ -256,7 +264,7 @@ func startAndAuthTailscaled(ctx context.Context, cfg *settings) (*ipnstate.Statu
|
|
|
|
// LocalAPI, so we still have to shell out to the
|
|
|
|
// LocalAPI, so we still have to shell out to the
|
|
|
|
// tailscale CLI for this bit.
|
|
|
|
// tailscale CLI for this bit.
|
|
|
|
if err := tailscaleUp(ctx, cfg); err != nil {
|
|
|
|
if err := tailscaleUp(ctx, cfg); err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("couldn't log in: %v", err)
|
|
|
|
return nil, fmt.Errorf("couldn't log in: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
didLogin = true
|
|
|
|
didLogin = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|