diff --git a/txeh.go b/txeh.go index f713c85..e6647fe 100644 --- a/txeh.go +++ b/txeh.go @@ -267,7 +267,54 @@ func (h *Hosts) AddHost(addressRaw string, hostRaw string) { h.Unlock() } -// HostAddressLookup returns true is the host is found, a string +// ListHostsByIP returns a list of hostnames associated with a given IP address +func (h *Hosts) ListHostsByIP(address string) []string { + var hosts []string + + for _, hsl := range h.hostFileLines { + if hsl.Address == address { + hosts = append(hosts, hsl.Hostnames...) + } + } + + return hosts +} + +// ListAddressesByHost returns a list of IPs associated with a given hostname +func (h *Hosts) ListAddressesByHost(hostname string, exact bool) [][]string { + var addresses [][]string + + for _, hsl := range h.hostFileLines { + for _, hst := range hsl.Hostnames { + if hst == hostname { + addresses = append(addresses, []string{hsl.Address, hst}) + } + if exact == false && hst != hostname && strings.Contains(hst, hostname) { + addresses = append(addresses, []string{hsl.Address, hst}) + } + } + } + + return addresses +} + +// ListHostsByCIDR returns a list of IPs and hostnames associated with a given CIDR +func (h *Hosts) ListHostsByCIDR(cidr string) [][]string { + var ipHosts [][]string + + _, subnet, _ := net.ParseCIDR(cidr) + for _, hsl := range h.hostFileLines { + if subnet.Contains(net.ParseIP(hsl.Address)) { + for _, hst := range hsl.Hostnames { + ipHosts = append(ipHosts, []string{hsl.Address, hst}) + } + } + } + + return ipHosts +} + +// HostAddressLookup returns true if the host is found, a string // containing the address and the index of the hfl func (h *Hosts) HostAddressLookup(host string, ipFamily IPFamily) (bool, string, int) { h.Lock() diff --git a/util/cmd/list.go b/util/cmd/list.go new file mode 100644 index 0000000..90b75b8 --- /dev/null +++ b/util/cmd/list.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(listCmd) +} + +var listCmd = &cobra.Command{ + Use: "list [BY_TYPE] [IP|CIDR] [IP|CIDR] [IP|CIDR] ...", + Short: "List hostnames for a IP addresses or CIDRs", + Long: `List hostnames for a IP addresses or CIDRs present in /etc/hosts`, + Run: func(cmd *cobra.Command, args []string) { + err := cmd.Help() + if err != nil { + fmt.Printf("Error: can not display help, reason: %s\n", err.Error()) + os.Exit(1) + } + + fmt.Println("Please specify a sub-command such as \"ip\" or \"cidr\"") + os.Exit(1) + }, +} diff --git a/util/cmd/list_cidr.go b/util/cmd/list_cidr.go new file mode 100644 index 0000000..1d36c0e --- /dev/null +++ b/util/cmd/list_cidr.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "errors" + "fmt" + "github.com/spf13/cobra" +) + +func init() { + listCmd.AddCommand(listByCidrCmd) +} + +var listByCidrCmd = &cobra.Command{ + Use: "cidr [CIDR] [CIDR] [CIDR]...", + Short: "List hosts for one or more CIDRs", + Long: `List hosts for one or more CIDRs from /etc/hosts`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("the \"list cidr\" command requires at least one CIDR address") + } + + if ok, cidr := validateCIDRs(args); !ok { + return errors.New(fmt.Sprintf("\"%s\" is not a valid CIDR", cidr)) + } + + return nil + }, + Run: func(cmd *cobra.Command, args []string) { + ListByCIDRs(args) + }, +} + +func ListByCIDRs(cidrs []string) { + for _, cidr := range cidrs { + ipHosts := etcHosts.ListHostsByCIDR(cidr) + for _, ih := range ipHosts { + fmt.Printf("%s %s %s\n", cidr, ih[0], ih[1]) + } + } +} diff --git a/util/cmd/list_hosts.go b/util/cmd/list_hosts.go new file mode 100644 index 0000000..f7085ce --- /dev/null +++ b/util/cmd/list_hosts.go @@ -0,0 +1,43 @@ +package cmd + +import ( + "errors" + "fmt" + "github.com/spf13/cobra" +) + +var exactHost bool + +func init() { + listCmd.AddCommand(listByHostsCmd) + listByHostsCmd.PersistentFlags().BoolVarP(&exactHost, "exact", "e", false, "use -e for exact match") +} + +var listByHostsCmd = &cobra.Command{ + Use: "host [hostname] [hostname] [hostname]...", + Short: "List IP for one or more hostnames", + Long: `List IP for one or more hostnames from /etc/hosts`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("the \"list host\" command requires at least one hostname") + } + + if ok, cidr := validateHostnames(args); !ok { + return errors.New(fmt.Sprintf("\"%s\" is not a valid hostname", cidr)) + } + + return nil + }, + Run: func(cmd *cobra.Command, args []string) { + ListByHostnames(args) + }, +} + +func ListByHostnames(hostnames []string) { + for _, hn := range hostnames { + addrHosts := etcHosts.ListAddressesByHost(hn, exactHost) + for _, addrHost := range addrHosts { + fmt.Printf("%s %s\n", addrHost[0], addrHost[1]) + } + } +} diff --git a/util/cmd/list_ip.go b/util/cmd/list_ip.go new file mode 100644 index 0000000..eb0cea4 --- /dev/null +++ b/util/cmd/list_ip.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "errors" + "fmt" + "github.com/spf13/cobra" +) + +func init() { + listCmd.AddCommand(listByIpCmd) +} + +var listByIpCmd = &cobra.Command{ + Use: "ip [IP] [IP] [IP]...", + Short: "List hosts for one or more IP addresses", + Long: `List hosts for one or more IP addresses from /etc/hosts`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("the \"list ip\" command requires at least one IP address") + } + + if ok, ip := validateIPAddresses(args); !ok { + return errors.New(fmt.Sprintf("\"%s\" is not a valid ip address", ip)) + } + + return nil + }, + Run: func(cmd *cobra.Command, args []string) { + ListByIPs(args) + }, +} + +func ListByIPs(ips []string) { + for _, ip := range ips { + hosts := etcHosts.ListHostsByIP(ip) + for _, h := range hosts { + fmt.Printf("%s %s\n", ip, h) + } + } +} diff --git a/util/cmd/remove_cidr.go b/util/cmd/remove_cidr.go index 7216cf0..78ad7d0 100644 --- a/util/cmd/remove_cidr.go +++ b/util/cmd/remove_cidr.go @@ -23,8 +23,8 @@ var removeCidrCmd = &cobra.Command{ return errors.New("the \"remove cidr\" command requires at least one CIDR range to remove") } - if ok, ip := validateCIDRs(args); !ok { - return errors.New(fmt.Sprintf("\"%s\" is not a valid CIDR", ip)) + if ok, cidr := validateCIDRs(args); !ok { + return errors.New(fmt.Sprintf("\"%s\" is not a valid CIDR", cidr)) } return nil