package cmd import ( "errors" "fmt" "io/ioutil" "log" "net" "net/http" "os" "strings" "text/tabwriter" "github.com/robfig/cron/v3" "github.com/spf13/cobra" ) var ( port string host string name string showTitle bool showList bool showAll bool showCell bool noPub bool secure bool cronMode bool cronSpec string ) var ClientCmd = &cobra.Command{ Use: "myip", Short: "myip is a easy way to get public ip of current system.", Run: func(cmd *cobra.Command, args []string) { if name == "" { name, _ = os.Hostname() } if cronMode { block := make(chan struct{}, 1) c := cron.New() c.AddFunc(cronSpec, func() { Scan() fmt.Println() }) c.Start() <-block } else { Scan() } }, } func init() { ClientCmd.Flags().StringVarP(&port, "port", "p", "5080", "server port to connect") ClientCmd.Flags().StringVarP(&host, "host", "u", "kumoly.io", "hostname to connect") ClientCmd.Flags().StringVarP(&name, "name", "n", "", "tell the server who you are") ClientCmd.Flags().BoolVarP(&showList, "list", "l", false, "show list") ClientCmd.Flags().BoolVarP(&showTitle, "title", "t", false, "show title, used with --list") ClientCmd.Flags().BoolVarP(&showCell, "cell", "c", false, "show cell, must used with --list") ClientCmd.Flags().BoolVarP(&showAll, "all", "a", false, "show local ip") ClientCmd.Flags().BoolVar(&noPub, "no-pub", false, "disable PublicIP") ClientCmd.Flags().BoolVar(&secure, "secure", false, "use https") ClientCmd.Flags().BoolVar(&cronMode, "cron", false, "run as cron service") ClientCmd.Flags().StringVarP(&cronSpec, "spec", "s", "0 */5 * * * *", "hostname to connect") } func Scan() error { // fmt.Printf("title: %v\nlist: %v\nall: %v\ntab: %v\n", showTitle, showList, showAll, showCell) if !showAll { if noPub { return errors.New("`--no-pub` can only be used with `--all`") } ip, err := GetPublicIP() if err != nil { return err } fmt.Println(ip) } else { var ip string var err error if !noPub { ip, err = GetPublicIP() if err != nil { return err } } local, err := GetLocalIP() if err != nil { return err } if showList { var wFlag uint = 0 if showCell { wFlag = tabwriter.Debug } w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', wFlag) if showTitle { fmt.Fprintln(w, "\tInterface\tIP\t") if showCell { fmt.Fprintln(w, "\t\t\t") } } if !noPub { fmt.Fprintf(w, "\t%v\t%v\t\n", "PublicIP", ip) } for k, v := range local { fmt.Fprintf(w, "\t%v\t%v\t\n", k, v) } return w.Flush() } else { if !noPub { fmt.Printf("%v ", ip) } for _, v := range local { fmt.Printf("%v ", v) } fmt.Printf("\n") } } return nil } func GetLocalIP() (map[string]string, error) { ret := map[string]string{} ifaces, err := net.Interfaces() if err != nil { log.Println(err) return ret, err } for _, i := range ifaces { addrs, err := i.Addrs() if err != nil { log.Println(err) return ret, err } for _, addr := range addrs { var ip net.IP switch v := addr.(type) { case *net.IPNet: ip = v.IP if ip.IsLoopback() { continue } if ip.To4() == nil { continue } case *net.IPAddr: continue // ip = v.IP // if ip.IsLoopback() { // continue // } } ret[i.Name] = ip.String() break } } return ret, nil } func GetPublicIP() (string, error) { protocol := "http://" if secure { protocol = "https://" } res, err := http.Get(protocol + host + ":" + port + "?name=" + name) if err != nil { log.Println(err) return "", err } if res.StatusCode != 200 { err = errors.New("http status error: " + res.Status) log.Println(err) return "", err } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { log.Println(err) return "", err } return strings.TrimRight(string(body), "\r\n"), nil }