Skip to content

Commit

Permalink
Adding --external-ip-map and --dns-resolver-address and shorthand fla…
Browse files Browse the repository at this point in the history
…gs (netbirdio#652)

Adding --external-ip-map and --dns-resolver-address to up command and shorthand option to global flags.

Refactor get and read config functions with new ConfigInput type.

updated cobra package to latest release.
  • Loading branch information
mlsmaycon authored Jan 17, 2023
1 parent 12ae2e9 commit dcf6533
Show file tree
Hide file tree
Showing 21 changed files with 608 additions and 553 deletions.
2 changes: 1 addition & 1 deletion client/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM gcr.io/distroless/base:debug
ENV WT_LOG_FILE=console
ENV NB_FOREGROUND_MODE=true
ENV PATH=/sbin:/usr/sbin:/bin:/usr/bin:/busybox
SHELL ["/busybox/sh","-c"]
RUN sed -i -E 's/(^root:.+)\/sbin\/nologin/\1\/busybox\/sh/g' /etc/passwd
Expand Down
2 changes: 1 addition & 1 deletion client/cmd/down.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var downCmd = &cobra.Command{
Use: "down",
Short: "down netbird connections",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down
2 changes: 1 addition & 1 deletion client/cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var loginCmd = &cobra.Command{
Use: "login",
Short: "login to the Netbird Management Service (first run)",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down
34 changes: 27 additions & 7 deletions client/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ import (
"github.com/netbirdio/netbird/client/internal"
)

const (
externalIPMapFlag = "external-ip-map"
dnsResolverAddress = "dns-resolver-address"
)

var (
configPath string
defaultConfigPathDir string
Expand All @@ -41,6 +46,8 @@ var (
adminURL string
setupKey string
preSharedKey string
natExternalIPs []string
customDNSAddress string
rootCmd = &cobra.Command{
Use: "netbird",
Short: "",
Expand Down Expand Up @@ -80,13 +87,13 @@ func init() {
defaultDaemonAddr = "tcp://127.0.0.1:41731"
}
rootCmd.PersistentFlags().StringVar(&daemonAddr, "daemon-addr", defaultDaemonAddr, "Daemon service address to serve CLI requests [unix|tcp]://[path|host:port]")
rootCmd.PersistentFlags().StringVar(&managementURL, "management-url", "", fmt.Sprintf("Management Service URL [http|https]://[host]:[port] (default \"%s\")", internal.ManagementURLDefault().String()))
rootCmd.PersistentFlags().StringVarP(&managementURL, "management-url", "m", "", fmt.Sprintf("Management Service URL [http|https]://[host]:[port] (default \"%s\")", internal.ManagementURLDefault().String()))
rootCmd.PersistentFlags().StringVar(&adminURL, "admin-url", "https://app.netbird.io", "Admin Panel URL [http|https]://[host]:[port]")
rootCmd.PersistentFlags().StringVar(&configPath, "config", defaultConfigPath, "Netbird config file location")
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "sets Netbird log level")
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", defaultConfigPath, "Netbird config file location")
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "info", "sets Netbird log level")
rootCmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, "sets Netbird log path. If console is specified the the log will be output to stdout")
rootCmd.PersistentFlags().StringVar(&setupKey, "setup-key", "", "Setup key obtained from the Management Service Dashboard (used to register peer)")
rootCmd.PersistentFlags().StringVar(&preSharedKey, "preshared-key", "", "Sets Wireguard PreSharedKey property. If set, then only peers that have the same key can communicate.")
rootCmd.PersistentFlags().StringVarP(&setupKey, "setup-key", "k", "", "Setup key obtained from the Management Service Dashboard (used to register peer)")
rootCmd.PersistentFlags().StringVarP(&preSharedKey, "preshared-key", "p", "", "Sets Wireguard PreSharedKey property. If set, then only peers that have the same key can communicate.")
rootCmd.AddCommand(serviceCmd)
rootCmd.AddCommand(upCmd)
rootCmd.AddCommand(downCmd)
Expand All @@ -96,6 +103,19 @@ func init() {
rootCmd.AddCommand(sshCmd)
serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd) // service control commands are subcommands of service
serviceCmd.AddCommand(installCmd, uninstallCmd) // service installer commands are subcommands of service
upCmd.PersistentFlags().StringSliceVar(&natExternalIPs, externalIPMapFlag, nil,
`Sets external IPs maps between local addresses and interfaces.`+
`You can specify a comma-separated list with a single IP and IP/IP or IP/Interface Name. `+
`An empty string "" clears the previous configuration. `+
`E.g. --external-ip-map 12.34.56.78/10.0.0.1 or --external-ip-map 12.34.56.200,12.34.56.78/10.0.0.1,12.34.56.80/eth1 `+
`or --external-ip-map ""`,
)
upCmd.PersistentFlags().StringVar(&customDNSAddress, dnsResolverAddress, "",
`Sets a custom address for NetBird's local DNS resolver. `+
`If set, the agent won't attempt to discover the best ip and port to listen on. `+
`An empty string "" clears the previous configuration. `+
`E.g. --dns-resolver-address 127.0.0.1:5053 or --dns-resolver-address ""`,
)
}

// SetupCloseHandler handles SIGTERM signal and exits with success
Expand All @@ -115,8 +135,8 @@ func SetupCloseHandler(ctx context.Context, cancel context.CancelFunc) {
}

// SetFlagsFromEnvVars reads and updates flag values from environment variables with prefix WT_
func SetFlagsFromEnvVars() {
flags := rootCmd.PersistentFlags()
func SetFlagsFromEnvVars(cmd *cobra.Command) {
flags := cmd.PersistentFlags()
flags.VisitAll(func(f *pflag.Flag) {
oldEnvVar := FlagNameToEnvVar(f.Name, "WT_")

Expand Down
8 changes: 4 additions & 4 deletions client/cmd/service_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ var runCmd = &cobra.Command{
Use: "run",
Short: "runs Netbird as service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down Expand Up @@ -118,7 +118,7 @@ var startCmd = &cobra.Command{
Use: "start",
Short: "starts Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down Expand Up @@ -153,7 +153,7 @@ var stopCmd = &cobra.Command{
Use: "stop",
Short: "stops Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down Expand Up @@ -186,7 +186,7 @@ var restartCmd = &cobra.Command{
Use: "restart",
Short: "restarts Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down
4 changes: 2 additions & 2 deletions client/cmd/service_installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var installCmd = &cobra.Command{
Use: "install",
Short: "installs Netbird service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down Expand Up @@ -86,7 +86,7 @@ var uninstallCmd = &cobra.Command{
Use: "uninstall",
Short: "uninstalls Netbird service from system",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down
3 changes: 2 additions & 1 deletion client/cmd/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ var sshCmd = &cobra.Command{
},
Short: "connect to a remote SSH server",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)
SetFlagsFromEnvVars(cmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down
2 changes: 1 addition & 1 deletion client/cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var statusCmd = &cobra.Command{
Use: "status",
Short: "status of the Netbird Service",
RunE: func(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)

cmd.SetOut(cmd.OutOrStdout())

Expand Down
132 changes: 124 additions & 8 deletions client/cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import (
"github.com/spf13/cobra"
"google.golang.org/grpc/codes"
gstatus "google.golang.org/grpc/status"
"net"
"net/netip"
"strings"
)

const (
invalidInputType int = iota
ipInputType
interfaceInputType
)

var (
Expand All @@ -27,7 +36,8 @@ func init() {
}

func upFunc(cmd *cobra.Command, args []string) error {
SetFlagsFromEnvVars()
SetFlagsFromEnvVars(rootCmd)
SetFlagsFromEnvVars(cmd)

cmd.SetOut(cmd.OutOrStdout())

Expand All @@ -36,6 +46,11 @@ func upFunc(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed initializing log %v", err)
}

err = validateNATExternalIPs(natExternalIPs)
if err != nil {
return err
}

ctx := internal.CtxInitState(cmd.Context())

if foregroundMode {
Expand All @@ -50,11 +65,18 @@ func runInForegroundMode(ctx context.Context, cmd *cobra.Command) error {
return err
}

customDNSAddressConverted, err := parseCustomDNSAddress(cmd.Flag(dnsResolverAddress).Changed)
if err != nil {
return err
}

config, err := internal.GetConfig(internal.ConfigInput{
ManagementURL: managementURL,
AdminURL: adminURL,
ConfigPath: configPath,
PreSharedKey: &preSharedKey,
ManagementURL: managementURL,
AdminURL: adminURL,
ConfigPath: configPath,
PreSharedKey: &preSharedKey,
NATExternalIPs: natExternalIPs,
CustomDNSAddress: customDNSAddressConverted,
})
if err != nil {
return fmt.Errorf("get config file: %v", err)
Expand All @@ -75,6 +97,11 @@ func runInForegroundMode(ctx context.Context, cmd *cobra.Command) error {

func runInDaemonMode(ctx context.Context, cmd *cobra.Command) error {

customDNSAddressConverted, err := parseCustomDNSAddress(cmd.Flag(dnsResolverAddress).Changed)
if err != nil {
return err
}

conn, err := DialClientGRPCServer(ctx, daemonAddr)
if err != nil {
return fmt.Errorf("failed to connect to daemon error: %v\n"+
Expand Down Expand Up @@ -102,9 +129,12 @@ func runInDaemonMode(ctx context.Context, cmd *cobra.Command) error {
}

loginRequest := proto.LoginRequest{
SetupKey: setupKey,
PreSharedKey: preSharedKey,
ManagementUrl: managementURL,
SetupKey: setupKey,
PreSharedKey: preSharedKey,
ManagementUrl: managementURL,
NatExternalIPs: natExternalIPs,
CleanNATExternalIPs: natExternalIPs != nil && len(natExternalIPs) == 0,
CustomDNSAddress: customDNSAddressConverted,
}

var loginErr error
Expand Down Expand Up @@ -147,3 +177,89 @@ func runInDaemonMode(ctx context.Context, cmd *cobra.Command) error {
cmd.Println("Connected")
return nil
}

func validateNATExternalIPs(list []string) error {
for _, element := range list {
if element == "" {
return fmt.Errorf("empty string is not a valid input for %s", externalIPMapFlag)
}

subElements := strings.Split(element, "/")
if len(subElements) > 2 {
return fmt.Errorf("%s is not a valid input for %s. it should be formated as \"String\" or \"String/String\"", element, externalIPMapFlag)
}

if len(subElements) == 1 && !isValidIP(subElements[0]) {
return fmt.Errorf("%s is not a valid input for %s. it should be formated as \"IP\" or \"IP/IP\", or \"IP/Interface Name\"", element, externalIPMapFlag)
}

last := 0
for _, singleElement := range subElements {
inputType, err := validateElement(singleElement)
if err != nil {
return fmt.Errorf("%s is not a valid input for %s. it should be an IP string or a network name", singleElement, externalIPMapFlag)
}
if last == interfaceInputType && inputType == interfaceInputType {
return fmt.Errorf("%s is not a valid input for %s. it should not contain two interface names", element, externalIPMapFlag)
}
last = inputType
}
}
return nil
}

func validateElement(element string) (int, error) {
if isValidIP(element) {
return ipInputType, nil
}
validIface, err := isValidInterface(element)
if err != nil {
return invalidInputType, fmt.Errorf("unable to validate the network interface name, error: %s", err)
}

if validIface {
return interfaceInputType, nil
}

return interfaceInputType, fmt.Errorf("invalid IP or network interface name not found")
}

func isValidIP(ip string) bool {
return net.ParseIP(ip) != nil
}

func isValidInterface(name string) (bool, error) {
netInterfaces, err := net.Interfaces()
if err != nil {
return false, err
}
for _, iface := range netInterfaces {
if iface.Name == name {
return true, nil
}
}
return false, nil
}

func parseCustomDNSAddress(modified bool) ([]byte, error) {
var parsed []byte
if modified {
if !isValidAddrPort(customDNSAddress) {
return nil, fmt.Errorf("%s is invalid, it should be formated as IP:Port string or as an empty string like \"\"", customDNSAddress)
}
if customDNSAddress == "" && logFile != "console" {
parsed = []byte("empty")
} else {
parsed = []byte(customDNSAddress)
}
}
return parsed, nil
}

func isValidAddrPort(input string) bool {
if input == "" {
return true
}
_, err := netip.ParseAddrPort(input)
return err == nil
}
Loading

0 comments on commit dcf6533

Please sign in to comment.