package cli_client import ( "github.com/spf13/cobra" pb "github.com/mame82/P4wnP1_aloa/proto" "net" "errors" "fmt" "google.golang.org/grpc/status" //"github.com/mame82/P4wnP1_aloa/service" "strings" "strconv" "github.com/mame82/P4wnP1_aloa/common_web" ) //Empty settings used to store cobra flags var ( tmpStrInterface string = "" tmpStrAddress4 string = "" tmpStrNetmask4 string = "" tmpDisabled bool = false tmpDHCPSrvOptions []string = []string{} tmpDHCPSrvRanges []string = []string{} ) /* func init(){ //Configure spew for struct deep printing (disable using printer interface for gRPC structs) spew.Config.Indent="\t" spew.Config.DisableMethods = true spew.Config.DisablePointerAddresses = true } */ var netCmd = &cobra.Command{ Use: "net", Short: "Configure Network settings of ethernet interfaces (including USB ethernet if enabled)", } var netSetCmd = &cobra.Command{ Use: "set", Short: "set ethernet settings", Long: ``, } var netSetManualCmd = &cobra.Command{ Use: "manual", Short: "Configure given interface manually", Long: ``, Run: cobraNetSetManual, } var netSetDHCPClientCmd = &cobra.Command{ Use: "client", Short: "Configure given interface to run a DHCP client", Long: ``, Run: cobraNetSetDHCPClient, } var netSetDHCPServerCmd = &cobra.Command{ Use: "server", Short: "Configure given interface to run a DHCP server", Long: ``, Run: cobraNetSetDHCPServer, } var netGetCmd = &cobra.Command{ Use: "get", Short: "get ethernet settings", Long: ``, Run: cobraNetGet, } func cobraNetGet(cmd *cobra.Command, args []string) { return } func cobraNetSetManual(cmd *cobra.Command, args []string) { settings, err := createManualSettings(tmpStrInterface, tmpStrAddress4, tmpStrNetmask4, tmpDisabled) if err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Deploying ethernet inteface settings:\n\t%v\n", settings) err = ClientDeployEthernetInterfaceSettings(StrRemoteHost, StrRemotePort, settings) if err != nil { fmt.Println(status.Convert(err).Message()) } return } func cobraNetSetDHCPClient(cmd *cobra.Command, args []string) { settings, err := createDHCPClientSettings(tmpStrInterface, tmpDisabled) if err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Deploying ethernet inteface settings:\n\t%v\n", settings) err = ClientDeployEthernetInterfaceSettings(StrRemoteHost, StrRemotePort, settings) if err != nil { fmt.Println(status.Convert(err).Message()) } return } func cobraNetSetDHCPServer(cmd *cobra.Command, args []string) { settings, err := createDHCPServerSettings(tmpStrInterface, tmpStrAddress4, tmpStrNetmask4, tmpDisabled, tmpDHCPSrvRanges, tmpDHCPSrvOptions) if err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Deploying ethernet inteface settings:\n\t%v\n", settings) err = ClientDeployEthernetInterfaceSettings(StrRemoteHost, StrRemotePort, settings) if err != nil { fmt.Println(status.Convert(err).Message()) } return } func createManualSettings(iface string, ip4 string, mask4 string, disabled bool) (settings *pb.EthernetInterfaceSettings, err error) { if len(iface) == 0 { return nil,errors.New("Please provide a network interface name") } err = checkIPv4(ip4) if err != nil { return nil,errors.New("Please provide a valid IPv4 address for the interface") } err = checkIPv4(mask4) if err != nil { return nil,errors.New("Please provide a valid IPv4 netmask for the interface") } settings = &pb.EthernetInterfaceSettings { Mode: pb.EthernetInterfaceSettings_MANUAL, Name: iface, IpAddress4: ip4, Netmask4: mask4, Enabled: !disabled, DhcpServerSettings: nil, } return } func parseDhcpServerOptions(strOptions []string) (options map[uint32]string, err error) { options = map[uint32]string{} for _, strOpt := range strOptions { splOpt := strings.SplitN(strOpt,":", 2) if len(splOpt) == 0 { //return nil,errors.New(fmt.Sprintf("Invalid DHCP option: %s\nOption format is \"<DHCPOptionNumber>:[DHCPOptionValue]\"", strOpt)) //ignore empty options continue } optNum, err := strconv.Atoi(splOpt[0]) if err != nil || optNum < 0 { return nil,errors.New(fmt.Sprintf("Invalid DHCP option Number: %s\nOption format is \"<DHCPOptionNumber>:[DHCPOptionValue]\"", splOpt[0])) } uOptNum := uint32(optNum) if len(splOpt) == 1 { options[uOptNum] = "" // fmt.Printf("Setting DHCP server option %d to empty value (disabeling option %d)\n", uOptNum, uOptNum) } else { //Replace '|' with ',' (a comma couldn't be used as it'd be interpreted as slice delimiter) strOptNew := strings.Replace(splOpt[1], "|", ",",-1) options[uOptNum] = strOptNew // fmt.Printf("Setting DHCP server option %d to '%s'\n", uOptNum, splOpt[1]) } } return options,nil } func parseDhcpServerRanges(strRanges []string) (ranges []*pb.DHCPServerRange, err error) { ranges = []*pb.DHCPServerRange{} if len(strRanges) == 0 { return nil,errors.New(fmt.Sprintf("Missing DHCP range: At least one range should be provided to allow assigning IP addresses to clients\n")) } for _,strRange := range strRanges { splRange := strings.Split(strRange, "|") if len(splRange) != 3 && len(splRange) != 2 { return nil,errors.New(fmt.Sprintf("Invalid DHCP range: %s\nformat is \"<first IPv4>|<last IPv4>[|leaseTime]\"", strRange)) } if net.ParseIP(splRange[0]) == nil { return nil, errors.New(fmt.Sprintf("%s in range '%s' is no valid IP address", splRange[0], strRange)) } if net.ParseIP(splRange[1]) == nil { return nil, errors.New(fmt.Sprintf("%s in range '%s' is no valid IP address", splRange[1], strRange)) } pRange := &pb.DHCPServerRange{ RangeLower: splRange[0], RangeUpper: splRange[1], } if len(splRange) > 2 { //ToDo: Regex check lease time to be valid [0-9]+[mh] pRange.LeaseTime = splRange[2] } ranges = append(ranges, pRange) } return ranges,nil } func createDHCPServerSettings(iface string, ip4 string, mask4 string, disabled bool, strRanges []string, strOptions []string) (settings *pb.EthernetInterfaceSettings, err error) { if len(iface) == 0 { return nil,errors.New("Please provide a network interface name") } err = checkIPv4(ip4) if err != nil { return nil,errors.New("Please provide a valid IPv4 address for the interface") } err = checkIPv4(mask4) if err != nil { return nil,errors.New("Please provide a valid IPv4 netmask for the interface") } options, err := parseDhcpServerOptions(strOptions) if err != nil { return nil, err } ranges, err := parseDhcpServerRanges(strRanges) if err != nil { return nil, err } settings = &pb.EthernetInterfaceSettings { Mode: pb.EthernetInterfaceSettings_DHCP_SERVER, Name: iface, IpAddress4: ip4, Netmask4: mask4, Enabled: !disabled, DhcpServerSettings: &pb.DHCPServerSettings{ ListenInterface:iface, LeaseFile: common_web.NameLeaseFileDHCPSrv(iface), CallbackScript: "", ListenPort: 0, //Disable DNS DoNotBindInterface: false, //only listen on given interface NotAuthoritative: false, // be authoritative Ranges: ranges, Options: options, }, } return } func createDHCPClientSettings(iface string, disabled bool) (settings *pb.EthernetInterfaceSettings, err error) { if len(iface) == 0 { return nil,errors.New("Please provide a network interface name") } settings = &pb.EthernetInterfaceSettings { Mode: pb.EthernetInterfaceSettings_DHCP_CLIENT, Name: iface, Enabled: !disabled, DhcpServerSettings: nil, } return } func checkIPv4(ip4 string) error { ip := net.ParseIP(ip4) if ip == nil { return errors.New(fmt.Sprintf("Error parsing IP address '%s'\n",ip4)) } if ip.To4() == nil { return errors.New(fmt.Sprintf("Not an IPv4 address '%s'\n",ip4)) } return nil } func init() { rootCmd.AddCommand(netCmd) // netCmd.AddCommand(netGetCmd) netCmd.AddCommand(netSetCmd) netSetCmd.AddCommand(netSetManualCmd) netSetCmd.AddCommand(netSetDHCPClientCmd) netSetCmd.AddCommand(netSetDHCPServerCmd) netSetCmd.PersistentFlags().StringVarP(&tmpStrInterface, "interface","i", "", "The name of the ethernet interface to work on") netSetCmd.PersistentFlags().BoolVarP(&tmpDisabled, "disable","d", false, "The flag disables the given interface (omitting the flag enables the interface") netSetManualCmd.Flags().StringVarP(&tmpStrAddress4, "address","a", "", "The IPv4 address to use for the interface") netSetManualCmd.Flags().StringVarP(&tmpStrNetmask4, "netmask","m", "", "The IPv4 netmask to use for the interface") netSetDHCPServerCmd.Flags().StringVarP(&tmpStrAddress4, "address","a", "", "The IPv4 address to use for the interface") netSetDHCPServerCmd.Flags().StringVarP(&tmpStrNetmask4, "netmask","m", "", "The IPv4 netmask to use for the interface") netSetDHCPServerCmd.Flags().StringSliceVarP(&tmpDHCPSrvRanges, "range", "r",[]string{}, "A DHCP Server range in form \"<lowest IPv4>|<highest IPv4>[|lease time]\" (the flag could be used multiple times)") netSetDHCPServerCmd.Flags().StringSliceVarP(&tmpDHCPSrvOptions, "option", "o",[]string{}, "A DHCP Server option in form \"<option number>:<value1|value2>\" (Option values have to be separated by '|' not by ','. The flag could be used multiple times)") }