This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -30,14 +31,21 @@ import (
|
||||
"tailscale.com/wgengine/router"
|
||||
|
||||
"tsrun/internal/oauth"
|
||||
base "tsrun/internal/runtime"
|
||||
"tsrun/internal/vault"
|
||||
)
|
||||
|
||||
func Run(ctx context.Context, payload vault.Payload) error {
|
||||
return RunWithReporter(ctx, payload, nil)
|
||||
}
|
||||
|
||||
func RunWithReporter(ctx context.Context, payload vault.Payload, report base.Reporter) error {
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "full", Message: "starting full mode"})
|
||||
if err := requireRoot(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "full", Message: "creating ephemeral auth key"})
|
||||
authKey, err := oauth.CreateEphemeralAuthKey(ctx, payload, "tsrun temporary access")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -49,7 +57,11 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
}
|
||||
defer os.RemoveAll(varRoot)
|
||||
|
||||
logf := log.New(os.Stderr, "", log.LstdFlags).Printf
|
||||
logWriter := io.Writer(os.Stderr)
|
||||
if report != nil {
|
||||
logWriter = io.Discard
|
||||
}
|
||||
logf := log.New(logWriter, "", log.LstdFlags).Printf
|
||||
sys := tsd.NewSystem()
|
||||
|
||||
netMon, err := netmon.New(sys.Bus.Get(), logf)
|
||||
@@ -139,6 +151,7 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
if err := lb.Start(ipn.Options{AuthKey: authKey, UpdatePrefs: prefs}); err != nil {
|
||||
return err
|
||||
}
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "full", Message: "waiting for tailscale network"})
|
||||
if st := lb.State(); st == ipn.NeedsLogin || st == ipn.NoState {
|
||||
if err := lb.StartLoginInteractive(ctx); err != nil {
|
||||
return err
|
||||
@@ -150,7 +163,18 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
return err
|
||||
}
|
||||
|
||||
printStatus(lb)
|
||||
if report == nil {
|
||||
printStatus(lb)
|
||||
}
|
||||
ipv4, ipv6 := tailscaleIPs(lb)
|
||||
report.Send(base.Event{
|
||||
Kind: base.EventRunning,
|
||||
Mode: "full",
|
||||
Message: "connected",
|
||||
Hostname: prefs.Hostname,
|
||||
IPv4: ipv4,
|
||||
IPv6: ipv6,
|
||||
})
|
||||
<-ctx.Done()
|
||||
|
||||
logoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
@@ -199,6 +223,24 @@ func printStatus(lb *ipnlocal.LocalBackend) {
|
||||
fmt.Printf("connected: %v\n", ips)
|
||||
}
|
||||
|
||||
func tailscaleIPs(lb *ipnlocal.LocalBackend) (string, string) {
|
||||
nm := lb.NetMapNoPeers()
|
||||
if nm == nil {
|
||||
return "", ""
|
||||
}
|
||||
var ip4, ip6 string
|
||||
for _, p := range nm.GetAddresses().All() {
|
||||
addr := p.Addr()
|
||||
if addr.Is4() && ip4 == "" {
|
||||
ip4 = addr.String()
|
||||
}
|
||||
if addr.Is6() && ip6 == "" {
|
||||
ip6 = addr.String()
|
||||
}
|
||||
}
|
||||
return ip4, ip6
|
||||
}
|
||||
|
||||
func requireRoot() error {
|
||||
if os.Geteuid() != 0 {
|
||||
return errors.New("full client mode requires root on linux; use sudo or run with --proxy for low-privilege mode")
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -32,17 +33,23 @@ import (
|
||||
"tailscale.com/wgengine/router"
|
||||
|
||||
"tsrun/internal/oauth"
|
||||
base "tsrun/internal/runtime"
|
||||
"tsrun/internal/vault"
|
||||
)
|
||||
|
||||
var startCOMOnce sync.Once
|
||||
|
||||
func Run(ctx context.Context, payload vault.Payload) error {
|
||||
return RunWithReporter(ctx, payload, nil)
|
||||
}
|
||||
|
||||
func RunWithReporter(ctx context.Context, payload vault.Payload, report base.Reporter) error {
|
||||
startCOMOnce.Do(func() {
|
||||
if err := com.StartRuntime(com.ConsoleApp); err != nil {
|
||||
log.Printf("wingoes.com.StartRuntime failed: %v", err)
|
||||
}
|
||||
})
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "full", Message: "starting full mode"})
|
||||
|
||||
if err := requireElevation(); err != nil {
|
||||
return err
|
||||
@@ -51,6 +58,7 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
return err
|
||||
}
|
||||
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "full", Message: "creating ephemeral auth key"})
|
||||
authKey, err := oauth.CreateEphemeralAuthKey(ctx, payload, "tsrun temporary access")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -62,7 +70,11 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
}
|
||||
defer os.RemoveAll(varRoot)
|
||||
|
||||
logf := log.New(os.Stderr, "", log.LstdFlags).Printf
|
||||
logWriter := io.Writer(os.Stderr)
|
||||
if report != nil {
|
||||
logWriter = io.Discard
|
||||
}
|
||||
logf := log.New(logWriter, "", log.LstdFlags).Printf
|
||||
sys := tsd.NewSystem()
|
||||
|
||||
netMon, err := netmon.New(sys.Bus.Get(), logf)
|
||||
@@ -149,6 +161,7 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
if err := lb.Start(ipn.Options{AuthKey: authKey, UpdatePrefs: prefs}); err != nil {
|
||||
return err
|
||||
}
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "full", Message: "waiting for tailscale network"})
|
||||
if st := lb.State(); st == ipn.NeedsLogin || st == ipn.NoState {
|
||||
if err := lb.StartLoginInteractive(ctx); err != nil {
|
||||
return err
|
||||
@@ -160,7 +173,18 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
return err
|
||||
}
|
||||
|
||||
printStatus(lb)
|
||||
if report == nil {
|
||||
printStatus(lb)
|
||||
}
|
||||
ipv4, ipv6 := tailscaleIPs(lb)
|
||||
report.Send(base.Event{
|
||||
Kind: base.EventRunning,
|
||||
Mode: "full",
|
||||
Message: "connected",
|
||||
Hostname: prefs.Hostname,
|
||||
IPv4: ipv4,
|
||||
IPv6: ipv6,
|
||||
})
|
||||
<-ctx.Done()
|
||||
|
||||
logoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
@@ -209,6 +233,24 @@ func printStatus(lb *ipnlocal.LocalBackend) {
|
||||
fmt.Printf("connected: %v\n", ips)
|
||||
}
|
||||
|
||||
func tailscaleIPs(lb *ipnlocal.LocalBackend) (string, string) {
|
||||
nm := lb.NetMapNoPeers()
|
||||
if nm == nil {
|
||||
return "", ""
|
||||
}
|
||||
var ip4, ip6 string
|
||||
for _, p := range nm.GetAddresses().All() {
|
||||
addr := p.Addr()
|
||||
if addr.Is4() && ip4 == "" {
|
||||
ip4 = addr.String()
|
||||
}
|
||||
if addr.Is6() && ip6 == "" {
|
||||
ip6 = addr.String()
|
||||
}
|
||||
}
|
||||
return ip4, ip6
|
||||
}
|
||||
|
||||
func requireElevation() error {
|
||||
adminSID, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,10 +11,16 @@ import (
|
||||
_ "tailscale.com/feature/condregister/oauthkey"
|
||||
"tailscale.com/tsnet"
|
||||
|
||||
base "tsrun/internal/runtime"
|
||||
"tsrun/internal/vault"
|
||||
)
|
||||
|
||||
func Run(ctx context.Context, payload vault.Payload) error {
|
||||
return RunWithReporter(ctx, payload, nil)
|
||||
}
|
||||
|
||||
func RunWithReporter(ctx context.Context, payload vault.Payload, report base.Reporter) error {
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "proxy", Message: "starting proxy mode"})
|
||||
baseDir, err := os.MkdirTemp("", "tsrun-proxy-*")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -34,6 +40,7 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
if _, err := srv.Up(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
report.Send(base.Event{Kind: base.EventStage, Mode: "proxy", Message: "tailscale connected"})
|
||||
|
||||
proxyListener, err := startProxyListener(ctx, srv)
|
||||
if err != nil {
|
||||
@@ -41,11 +48,22 @@ func Run(ctx context.Context, payload vault.Payload) error {
|
||||
}
|
||||
defer proxyListener.closeFn()
|
||||
|
||||
fmt.Printf("proxy mode active\n")
|
||||
fmt.Printf("%s\n", directRequestHint())
|
||||
fmt.Printf("Proxy: %s\n", formatProxyURL(proxyListener.addr))
|
||||
fmt.Printf("Username: tsnet\n")
|
||||
fmt.Printf("Password: %s\n", proxyListener.proxyCred)
|
||||
if report == nil {
|
||||
fmt.Printf("proxy mode active\n")
|
||||
fmt.Printf("%s\n", directRequestHint())
|
||||
fmt.Printf("Proxy: %s\n", formatProxyURL(proxyListener.addr))
|
||||
fmt.Printf("Username: tsnet\n")
|
||||
fmt.Printf("Password: %s\n", proxyListener.proxyCred)
|
||||
}
|
||||
report.Send(base.Event{
|
||||
Kind: base.EventRunning,
|
||||
Mode: "proxy",
|
||||
Message: "proxy ready",
|
||||
Hostname: hostname,
|
||||
ProxyAddr: proxyListener.addr,
|
||||
ProxyUser: "tsnet",
|
||||
ProxyPass: proxyListener.proxyCred,
|
||||
})
|
||||
|
||||
waitCtx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package runtime
|
||||
|
||||
type EventKind string
|
||||
|
||||
const (
|
||||
EventStage EventKind = "stage"
|
||||
EventRunning EventKind = "running"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Kind EventKind
|
||||
Message string
|
||||
Mode string
|
||||
Hostname string
|
||||
IPv4 string
|
||||
IPv6 string
|
||||
ProxyAddr string
|
||||
ProxyUser string
|
||||
ProxyPass string
|
||||
}
|
||||
|
||||
type Reporter func(Event)
|
||||
|
||||
func (r Reporter) Send(event Event) {
|
||||
if r != nil {
|
||||
r(event)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user