From 03b19df115ed0c456cd5fa56bcd092d590a9f8f5 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Mon, 16 Dec 2024 12:19:48 +0100 Subject: [PATCH] Implement 'vpn public-address' subcommands --- go/cmd/entrypoint/vpn.go | 1 + go/cmd/entrypoint/vpn_public_addr.go | 93 ++++++++++++++++++++++++++++ tasks/soon/code/set-config-cas.md | 8 +++ tasks/v0.0.3/code/public-addr.md | 7 --- 4 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 go/cmd/entrypoint/vpn_public_addr.go create mode 100644 tasks/soon/code/set-config-cas.md delete mode 100644 tasks/v0.0.3/code/public-addr.md diff --git a/go/cmd/entrypoint/vpn.go b/go/cmd/entrypoint/vpn.go index 9d25694..75e27af 100644 --- a/go/cmd/entrypoint/vpn.go +++ b/go/cmd/entrypoint/vpn.go @@ -70,6 +70,7 @@ var subCmdVPN = subCmd{ return ctx.doSubCmd( subCmdVPNCreateCert, subCmdVPNFirewall, + subCmdVPNPublicAddress, ) }, } diff --git a/go/cmd/entrypoint/vpn_public_addr.go b/go/cmd/entrypoint/vpn_public_addr.go new file mode 100644 index 0000000..d51d357 --- /dev/null +++ b/go/cmd/entrypoint/vpn_public_addr.go @@ -0,0 +1,93 @@ +package main + +import ( + "errors" + "fmt" + "net" +) + +var subCmdVPNPublicAddressGet = subCmd{ + name: "get", + descr: "Display the currently configured public address", + do: doWithOutput(func(ctx subCmdCtx) (any, error) { + ctx, err := ctx.withParsedFlags(nil) + if err != nil { + return nil, fmt.Errorf("parsing flags: %w", err) + } + + config, err := ctx.daemonRPC.GetConfig(ctx) + if err != nil { + return nil, fmt.Errorf("getting network config: %w", err) + } + + if config.VPN.PublicAddr == "" { + return nil, errors.New("No public address configured") + } + + return config.VPN.PublicAddr, nil + }), +} + +var subCmdVPNPublicAddressSet = subCmd{ + name: "set", + descr: "Set the public address of the host, or overwrite the already configured one", + do: func(ctx subCmdCtx) error { + publicAddr := ctx.flags.String( + "public-addr", + "", + "Public address (host:port) that this host is publicly available on", + ) + + ctx, err := ctx.withParsedFlags(nil) + if err != nil { + return fmt.Errorf("parsing flags: %w", err) + } + + if *publicAddr == "" { + return errors.New("--public-addr is required") + } else if _, _, err := net.SplitHostPort(*publicAddr); err != nil { + return fmt.Errorf("invalid --public-addr: %w", err) + } + + config, err := ctx.daemonRPC.GetConfig(ctx) + if err != nil { + return fmt.Errorf("getting network config: %w", err) + } + + config.VPN.PublicAddr = *publicAddr + + return ctx.daemonRPC.SetConfig(ctx, config) + }, +} + +var subCmdVPNPublicAddressUnset = subCmd{ + name: "unset", + descr: "Unset the public address", + do: func(ctx subCmdCtx) error { + ctx, err := ctx.withParsedFlags(nil) + if err != nil { + return fmt.Errorf("parsing flags: %w", err) + } + + config, err := ctx.daemonRPC.GetConfig(ctx) + if err != nil { + return fmt.Errorf("getting network config: %w", err) + } + + config.VPN.PublicAddr = "" + + return ctx.daemonRPC.SetConfig(ctx, config) + }, +} + +var subCmdVPNPublicAddress = subCmd{ + name: "public-address", + descr: "Configure the public address of this host, allowing other hosts to use it in order to find and communicate directly with each other", + do: func(ctx subCmdCtx) error { + return ctx.doSubCmd( + subCmdVPNPublicAddressGet, + subCmdVPNPublicAddressSet, + subCmdVPNPublicAddressUnset, + ) + }, +} diff --git a/tasks/soon/code/set-config-cas.md b/tasks/soon/code/set-config-cas.md new file mode 100644 index 0000000..9b89ca4 --- /dev/null +++ b/tasks/soon/code/set-config-cas.md @@ -0,0 +1,8 @@ +--- +type: task +--- + +# Add a Compare-and-Swap mechanism to SetConfig + +This way we can avoid having issues if two different callers are doing a +GetConfig-then-SetConfig. diff --git a/tasks/v0.0.3/code/public-addr.md b/tasks/v0.0.3/code/public-addr.md deleted file mode 100644 index e4f476b..0000000 --- a/tasks/v0.0.3/code/public-addr.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: task ---- - -# Add `vpn public-addr set`, and `get` Sub-Commands. - -`get` should return an error if no public address is set.