diff --git a/cmd/root.go b/cmd/root.go index bf722a7..e9eef05 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -49,7 +49,7 @@ var versionCmd = &cobra.Command{ } var upCmd = &cobra.Command{ - Use: "up [ config_file | interface ]", + Use: "up [config_file|interface]", Short: "Bringing interface up", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { @@ -61,7 +61,7 @@ var upCmd = &cobra.Command{ } var downCmd = &cobra.Command{ - Use: "down [ config_file | interface ]", + Use: "down [config_file|interface]", Short: "Bringing interface down", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { @@ -73,7 +73,7 @@ var downCmd = &cobra.Command{ } var syncCmd = &cobra.Command{ - Use: "sync [ config_file | interface ]", + Use: "sync [config_file|interface]", Short: "Sync interface", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { @@ -84,6 +84,22 @@ var syncCmd = &cobra.Command{ }, } +var showCmd = &cobra.Command{ + Use: "show [interface]", + Short: "Show current configuration", + Args: cobra.MaximumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + device := "" + if len(args) == 1 { + device = args[0] + } + + if err := wgquick.Show(device); err != nil { + logrus.WithError(err).Errorln("cannot show configuration") + } + }, +} + func loadConfig(cfg string) (*wgquick.Config, logrus.FieldLogger) { log := logrus.WithField("iface", iface) _, err := os.Stat(cfg) @@ -133,6 +149,7 @@ func init() { rootCmd.AddCommand(downCmd) rootCmd.AddCommand(syncCmd) rootCmd.AddCommand(versionCmd) + rootCmd.AddCommand(showCmd) } func Execute() { diff --git a/wgquick/show.go b/wgquick/show.go new file mode 100644 index 0000000..092a8b3 --- /dev/null +++ b/wgquick/show.go @@ -0,0 +1,93 @@ +// Mostly taken from: https://github.com/WireGuard/wgctrl-go/blob/master/cmd/wgctrl/main.go +// +// nolint: forbidigo, godox +package wgquick + +import ( + "fmt" + "net" + "strings" + + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +func Show(iface string) error { + c, err := wgctrl.New() + if err != nil { + return fmt.Errorf("failed to open wgctrl: %w", err) + } + defer c.Close() + + var devices []*wgtypes.Device + + if iface != "" { + d, err := c.Device(iface) + if err != nil { + return fmt.Errorf("failed to get device %s: %w", iface, err) + } + + devices = append(devices, d) + } else { + devices, err = c.Devices() + if err != nil { + return fmt.Errorf("failed to get devices: %w", err) + } + } + + for _, d := range devices { + printDevice(d) + + for _, p := range d.Peers { + printPeer(p) + } + } + + return nil +} + +func printDevice(d *wgtypes.Device) { + const f = `interface: %s (%s) + public key: %s + private key: (hidden) + listening port: %d + +` + + fmt.Printf( + f, + d.Name, + d.Type.String(), + d.PublicKey.String(), + d.ListenPort) +} + +func printPeer(p wgtypes.Peer) { + const f = `peer: %s + endpoint: %s + allowed ips: %s + latest handshake: %s + transfer: %d B received, %d B sent + +` + + fmt.Printf( + f, + p.PublicKey.String(), + // TODO(mdlayher): get right endpoint with getnameinfo. + p.Endpoint.String(), + ipsString(p.AllowedIPs), + p.LastHandshakeTime.String(), + p.ReceiveBytes, + p.TransmitBytes, + ) +} + +func ipsString(ipns []net.IPNet) string { + ss := make([]string, 0, len(ipns)) + for _, ipn := range ipns { + ss = append(ss, ipn.String()) + } + + return strings.Join(ss, ", ") +}