package myip import ( "errors" "fmt" "io/ioutil" "log" "net" "net/http" "os" "sort" "strings" "time" "github.com/jedib0t/go-pretty/v6/table" "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 ) type Iface struct { IP string HardwareAddr string Name 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 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, "pretty", "c", false, "show table 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") ClientCmd.AddCommand(ServerCmd) ClientCmd.AddCommand(LocalIPCmd) } func Scan() error { // fmt.Printf("title: %v\nlist: %v\nall: %v\ntab: %v\n", showTitle, showList, showAll, showCell) if name == "" { name, _ = os.Hostname() } 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 { t := table.NewWriter() t.SetOutputMirror(os.Stdout) if showCell { t.SetStyle(table.StyleLight) } else { t.Style().Options.DrawBorder = false t.Style().Options.SeparateColumns = false t.Style().Options.SeparateFooter = false t.Style().Options.SeparateHeader = false t.Style().Options.SeparateRows = false } if showTitle { t.AppendHeader(table.Row{"Interface", "IP"}) if showCell { t.AppendSeparator() } } if !noPub { t.AppendRow([]interface{}{"PublicIP", ip}) } for _, iface := range local { t.AppendRow([]interface{}{iface.Name, iface.IP}) } t.Render() // fmt.Println(t.Render()) return nil } else { if !noPub { fmt.Printf("%v ", ip) } for _, v := range local { fmt.Printf("%v ", v.IP) } fmt.Printf("\n") } } return nil } func GetLocalIP() ([]Iface, error) { ret := []Iface{} 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 = append(ret, Iface{ IP: ip.String(), Name: i.Name, HardwareAddr: i.HardwareAddr.String(), }) break } } sort.Slice(ret, func(i, j int) bool { return ret[i].Name < ret[j].Name }) return ret, nil } func GetPublicIP() (string, error) { protocol := "http://" if secure { protocol = "https://" } req, _ := http.NewRequest("GET", protocol+host+":"+port+"?name="+name, nil) client := &http.Client{ Timeout: time.Second * 10, } res, err := client.Do(req) 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 }