├── README.md ├── go.mod └── main.go /README.md: -------------------------------------------------------------------------------- 1 | # h2i 2 | 3 | Converts a list of hostnames or URLs to their corresponding IP address 4 | 5 | 6 | ## Install 7 | 8 | If you have Go installed and configured (i.e. with `$GOPATH/bin` in your `$PATH`): 9 | 10 | ``` 11 | go install github.com/cybercdh/h2i@latest 12 | ``` 13 | 14 | ## Usage 15 | 16 | ``` 17 | $ h2i 18 | ``` 19 | or 20 | ``` 21 | $ cat | h2i 22 | ``` 23 | 24 | By default, the code will simply print the list of IP's to the console. For more details, use the -v flag, per below. 25 | 26 | ### Options 27 | 28 | ``` 29 | Usage of h2i: 30 | -c int 31 | set the concurrency level (default 20) 32 | -dns string 33 | Custom DNS server to use for resolution 34 | -dns-tcp 35 | Use DNS over TCP instead of the default UDP. Useful for SOCKS proxy environments where UDP is not supported. 36 | -port string 37 | DNS server port (default "53") 38 | -v Show hostname with the corresponding IP 39 | -vv 40 | Show any errors and relevant info 41 | ``` -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cybercdh/h2i 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "flag" 7 | "fmt" 8 | "io" 9 | "net" 10 | "net/url" 11 | "os" 12 | "strings" 13 | "sync" 14 | ) 15 | 16 | func main() { 17 | var concurrency int 18 | var verbose, v_verbose, dnsTCP bool 19 | var customDNS string 20 | var dnsPort string 21 | 22 | flag.IntVar(&concurrency, "c", 20, "set the concurrency level") 23 | flag.BoolVar(&verbose, "v", false, "Show hostname with the corresponding IP") 24 | flag.BoolVar(&v_verbose, "vv", false, "Show any errors and relevant info") 25 | flag.StringVar(&customDNS, "dns", "", "Custom DNS server to use for resolution") 26 | flag.StringVar(&dnsPort, "port", "53", "DNS server port") 27 | flag.BoolVar(&dnsTCP, "dns-tcp", false, "Use DNS over TCP") 28 | flag.Parse() 29 | 30 | hosts := make(chan string) 31 | var wg sync.WaitGroup 32 | resolver := &net.Resolver{} 33 | 34 | // Use custom DNS server if specified 35 | if customDNS != "" { 36 | resolver = &net.Resolver{ 37 | PreferGo: true, 38 | Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 39 | // Choose network type based on dnsTCP flag 40 | networkType := "udp" 41 | if dnsTCP { 42 | networkType = "tcp" 43 | } 44 | return net.Dial(networkType, customDNS+":"+dnsPort) 45 | }, 46 | } 47 | } 48 | 49 | for i := 0; i < concurrency; i++ { 50 | wg.Add(1) 51 | 52 | go func() { 53 | for host := range hosts { 54 | // Use custom resolver for lookup 55 | addr, err := resolver.LookupIPAddr(context.Background(), host) 56 | if err != nil { 57 | if v_verbose { 58 | fmt.Printf("%s could not be found\n", host) 59 | } 60 | } else { 61 | if verbose { 62 | fmt.Printf("%s,%s\n", host, addr[0].IP.String()) 63 | } else { 64 | fmt.Println(addr[0].IP.String()) 65 | } 66 | } 67 | } 68 | wg.Done() 69 | }() 70 | } 71 | 72 | var input_hosts io.Reader = os.Stdin 73 | arg_hosts := flag.Arg(0) 74 | if arg_hosts != "" { 75 | input_hosts = strings.NewReader(arg_hosts) 76 | } 77 | 78 | sc := bufio.NewScanner(input_hosts) 79 | seen := make(map[string]bool) 80 | 81 | for sc.Scan() { 82 | tmp_host := sc.Text() 83 | if strings.HasPrefix(tmp_host, "http") { 84 | u, err := url.Parse(tmp_host) 85 | if err != nil { 86 | if v_verbose { 87 | fmt.Printf("%s could not be parsed\n", tmp_host) 88 | } 89 | continue 90 | } 91 | tmp_host = u.Hostname() 92 | } 93 | 94 | if _, ok := seen[tmp_host]; ok { 95 | if v_verbose { 96 | fmt.Printf("Already seen %s\n", tmp_host) 97 | } 98 | continue 99 | } 100 | 101 | seen[tmp_host] = true 102 | hosts <- tmp_host 103 | } 104 | 105 | close(hosts) 106 | if err := sc.Err(); err != nil { 107 | fmt.Fprintf(os.Stderr, "[!] failed to read input: %s\n", err) 108 | } 109 | 110 | wg.Wait() 111 | } 112 | --------------------------------------------------------------------------------