├── go.mod ├── .gitignore ├── README.md └── hakip2host.go /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hakluke/hakip2host 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | hakip2host 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | # vendor/ 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hakip2host 2 | hakip2host takes a list of IP addresses via stdin, then does a series of checks to return associated domain names. 3 | 4 | Current supported checks are: 5 | 6 | - DNS PTR lookups 7 | - Subject Alternative Names (SANs) on SSL certificates 8 | - Common Names (CNs) on SSL certificates 9 | 10 | ## Installation 11 | 12 | Install golang, then: 13 | 14 | ``` 15 | go install github.com/hakluke/hakip2host@latest 16 | ``` 17 | 18 | ## Help 19 | 20 | ``` 21 | ./hakip2host --help 22 | ``` 23 | 24 | ## Example usage 25 | 26 | ``` 27 | hakluke$ prips 173.0.84.0/24 | ./hakip2host 28 | [DNS-PTR] 173.0.84.23 new-creditcenter.paypal.com. 29 | [DNS-PTR] 173.0.84.11 slc-a-origin-www-1.paypal.com. 30 | [DNS-PTR] 173.0.84.10 admin.paypal.com. 31 | [DNS-PTR] 173.0.84.30 ss-www.paypal.com. 32 | [DNS-PTR] 173.0.84.5 www.gejscript-paypal.com. 33 | [DNS-PTR] 173.0.84.24 slc-a-origin-demo.paypal.com. 34 | [DNS-PTR] 173.0.84.20 origin-merchantweb.paypal.com. 35 | [SSL-SAN] 173.0.84.67 uptycspay.paypal.com 36 | [SSL-SAN] 173.0.84.67 a.paypal.com 37 | [SSL-CN] 173.0.84.67 api.paypal.com 38 | [SSL-SAN] 173.0.84.76 svcs.paypal.com 39 | [SSL-SAN] 173.0.84.76 uptycshon.paypal.com 40 | [SSL-SAN] 173.0.84.76 uptycshap.paypal.com 41 | [SSL-SAN] 173.0.84.76 uptycsven.paypal.com 42 | [SSL-SAN] 173.0.84.76 uptycsize.paypal.com 43 | [SSL-SAN] 173.0.84.76 uptycspay.paypal.com 44 | [SSL-CN] 173.0.84.76 svcs.paypal.com 45 | ``` 46 | -------------------------------------------------------------------------------- /hakip2host.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "crypto/tls" 7 | "flag" 8 | "fmt" 9 | "log" 10 | "net" 11 | "net/http" 12 | "os" 13 | "strings" 14 | "sync" 15 | "time" 16 | ) 17 | 18 | // This function grabs the SSL certificate, then dumps the SAN and CommonName 19 | func sslChecks(ip string, resChan chan<- string, client *http.Client) { 20 | 21 | url := ip 22 | 23 | // make sure we use https as we're doing SSL checks 24 | if strings.HasPrefix(ip, "http://") { 25 | url = strings.Replace(ip, "http://", "https://", 1) 26 | } else if !strings.HasPrefix(ip, "https://") { 27 | url = "https://" + ip 28 | } 29 | 30 | req, reqErr := http.NewRequest("HEAD", url, nil) 31 | if reqErr != nil { 32 | return 33 | } 34 | 35 | resp, clientErr := client.Do(req) 36 | if clientErr != nil { 37 | return 38 | } 39 | 40 | if resp.TLS != nil && len(resp.TLS.PeerCertificates) > 0 { 41 | dnsNames := resp.TLS.PeerCertificates[0].DNSNames 42 | for _, name := range dnsNames { 43 | resChan <- "[SSL-SAN] " + ip + " " + string(name) 44 | } 45 | resChan <- "[SSL-CN] " + ip + " " + resp.TLS.PeerCertificates[0].Subject.CommonName 46 | } 47 | } 48 | 49 | // Do a DNS PTR lookup on the IP 50 | func dnsChecks(ip string, resChan chan<- string, resolver *net.Resolver) { 51 | 52 | addr, err := resolver.LookupAddr(context.Background(), ip) 53 | if err != nil { 54 | return 55 | } 56 | 57 | for _, a := range addr { 58 | resChan <- "[DNS-PTR] " + ip + " " + a 59 | } 60 | } 61 | 62 | func worker(jobChan <-chan string, resChan chan<- string, wg *sync.WaitGroup, transport *http.Transport, client *http.Client, resolver *net.Resolver) { 63 | defer wg.Done() 64 | 65 | for job := range jobChan { 66 | sslChecks(job, resChan, client) 67 | dnsChecks(job, resChan, resolver) 68 | } 69 | 70 | } 71 | func main() { 72 | workers := flag.Int("t", 32, "numbers of threads") 73 | resolverIP := flag.String("r", "", "IP of DNS resolver for lookups") 74 | dnsProtocol := flag.String("protocol", "udp", "Protocol for DNS lookups (tcp or udp)") 75 | resolverPort := flag.Int("p", 53, "Port to bother the specified DNS resolver on") 76 | flag.Parse() 77 | 78 | scanner := bufio.NewScanner(os.Stdin) 79 | jobChan := make(chan string) 80 | resChan := make(chan string) 81 | done := make(chan struct{}) 82 | 83 | // Set up TLS transport 84 | var transport = &http.Transport{ 85 | Dial: (&net.Dialer{ 86 | Timeout: 5 * time.Second, 87 | }).Dial, 88 | TLSHandshakeTimeout: 5 * time.Second, 89 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 90 | } 91 | 92 | // Set up HTTP client 93 | var client = &http.Client{ 94 | Timeout: time.Second * 10, 95 | Transport: transport, 96 | } 97 | 98 | // Set up DNS resolver 99 | var resolver *net.Resolver 100 | 101 | if *resolverIP != "" { 102 | resolver = &net.Resolver{ 103 | PreferGo: true, 104 | Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 105 | d := net.Dialer{} 106 | return d.DialContext(ctx, *dnsProtocol, fmt.Sprintf("%s:%d", *resolverIP, *resolverPort)) 107 | }, 108 | } 109 | } 110 | 111 | var wg sync.WaitGroup 112 | wg.Add(*workers) 113 | 114 | go func() { 115 | wg.Wait() 116 | close(done) 117 | }() 118 | 119 | for i := 0; i < *workers; i++ { 120 | 121 | go worker(jobChan, resChan, &wg, transport, client, resolver) 122 | } 123 | 124 | go func() { 125 | for scanner.Scan() { 126 | jobChan <- scanner.Text() 127 | } 128 | if err := scanner.Err(); err != nil { 129 | log.Println(err) 130 | } 131 | close(jobChan) 132 | }() 133 | 134 | for { 135 | select { 136 | case <-done: 137 | return 138 | case res := <-resChan: 139 | if strings.HasSuffix(res, ".") { 140 | res = res[:len(res)-1] 141 | } 142 | fmt.Println(res) 143 | } 144 | } 145 | } 146 | --------------------------------------------------------------------------------