@@ -5,31 +5,30 @@ import (
55 "crypto/x509"
66 "flag"
77 "fmt"
8- "os"
98 "net"
9+ "os"
1010 "sort"
1111 "strings"
12+ "sync"
1213 "syscall"
1314 "time"
14- "sync"
1515)
1616
1717/* TODO
18- follow http redirects
19- starttls
20- add www, mx, mail....
18+ follow http redirects
19+ starttls
20+ add www, mx, mail....
2121*/
2222
23+ // structure to store a domain and its edges
2324type DomainNode struct {
24- Domain string
25- Depth int
26- Neighbors * []string
25+ Domain string
26+ Depth int
27+ Neighbors * []string
2728}
2829
2930// vars
30- var conf = & tls.Config {
31- InsecureSkipVerify : true ,
32- }
31+ var conf = & tls.Config {InsecureSkipVerify : true }
3332var markedDomains = make (map [string ]bool )
3433var domainGraph = make (map [string ]* DomainNode )
3534var timeout time.Duration
@@ -39,13 +38,39 @@ var depth int
3938var maxDepth int
4039var parallel int
4140
41+ func main () {
42+ host := flag .String ("host" , "localhost" , "Host to Scan" )
43+ flag .StringVar (& port , "port" , "443" , "Port to connect to" )
44+ timeoutPtr := flag .Int ("timeout" , 5 , "TCP Timeout in seconds" )
45+ flag .BoolVar (& verbose , "verbose" , false , "Verbose logging" )
46+ flag .IntVar (& maxDepth , "depth" , 20 , "Maximum BFS depth to go" )
47+ flag .IntVar (& parallel , "parallel" , 10 , "Number of certificates to retrieve in parallel" )
48+
49+ flag .Parse ()
50+ if parallel < 1 {
51+ fmt .Fprintln (os .Stderr , "Must enter a positive number of parallel threads" )
52+ return
53+ }
54+ timeout = time .Duration (* timeoutPtr ) * time .Second
55+ startDomain := strings .ToLower (* host )
56+
57+ BFS (startDomain )
58+
59+ v ("Done..." )
60+
61+ printGraph ()
62+ v ("Found" , len (domainGraph ), "domains" )
63+ v ("Graph Depth:" , depth )
64+ }
65+
66+ // Verbose Log
4267func v (a ... interface {}) {
4368 if verbose {
4469 fmt .Fprintln (os .Stderr , a ... )
4570 }
4671}
4772
48-
73+ // Check for errors, print if network related
4974func checkNetErr (err error , domain string ) bool {
5075 if err == nil {
5176 return false
@@ -70,9 +95,7 @@ func checkNetErr(err error, domain string) bool {
7095 return true
7196}
7297
73- /*
74- * given a domain returns the non-wildecard version of that domain
75- */
98+ // given a domain returns the non-wildcard version of that domain
7699func directDomain (domain string ) string {
77100 if len (domain ) < 3 {
78101 return domain
@@ -83,8 +106,8 @@ func directDomain(domain string) string {
83106 return domain
84107}
85108
109+ // prints the adjacency list in sorted order
86110func printGraph () {
87- // print map in sorted order
88111 domains := make ([]string , 0 , len (domainGraph ))
89112 for domain , _ := range domainGraph {
90113 domains = append (domains , domain )
@@ -96,51 +119,23 @@ func printGraph() {
96119 }
97120}
98121
99-
100- func main () {
101- host := flag .String ("host" , "localhost" , "Host to Scan" )
102- flag .StringVar (& port , "port" , "443" , "Port to connect to" )
103- timeoutPtr := flag .Int ("timeout" , 5 , "TCP Timeout in seconds" )
104- flag .BoolVar (& verbose , "verbose" , false , "Verbose logging" )
105- flag .IntVar (& maxDepth , "depth" , 20 , "Maximum BFS depth to go" )
106- flag .IntVar (& parallel , "parallel" , 10 , "Number of certificates to retrieve in parallel" )
107-
108- flag .Parse ()
109- if parallel < 1 {
110- fmt .Fprintln (os .Stderr , "Must enter a positive number of parallel threads" )
111- return
112- }
113- timeout = time .Duration (* timeoutPtr ) * time .Second
114- startDomain := strings .ToLower (* host )
115-
116- BFS (startDomain )
117-
118- v ("Done..." )
119-
120- printGraph ()
121-
122- v ("Found" , len (domainGraph ), "domains" ) // todo verify
123- v ("Graph Depth:" , depth )
124-
125- }
126-
122+ // perform Breadth-first_search to build the graph
127123func BFS (root string ) {
128- // parallel code
129124 var wg sync.WaitGroup
130125 domainChan := make (chan * DomainNode , 5 )
131126 domainGraphChan := make (chan * DomainNode , 5 )
132127
133128 // thread limit code
134129 threadPass := make (chan bool , parallel )
135- for i := 0 ; i < parallel ; i ++ {
136- threadPass <- true
130+ for i := 0 ; i < parallel ; i ++ {
131+ threadPass <- true
137132 }
138133
139134 wg .Add (1 )
140135 domainChan <- & DomainNode {root , 0 , nil }
141136 go func () {
142137 for {
143- domainNode := <- domainChan
138+ domainNode := <- domainChan
144139
145140 // depth check
146141 if domainNode .Depth > maxDepth {
@@ -156,10 +151,10 @@ func BFS(root string) {
156151 if ! markedDomains [dDomain ] {
157152 markedDomains [dDomain ] = true
158153 go func (domainNode * DomainNode ) {
159- defer wg .Done ()
160- // wait for pass
161- <- threadPass
162- defer func () {threadPass <- true }()
154+ defer wg .Done ()
155+ // wait for pass
156+ <- threadPass
157+ defer func () { threadPass <- true }()
163158
164159 // do things
165160 dDomain := directDomain (domainNode .Domain )
@@ -182,7 +177,7 @@ func BFS(root string) {
182177 done := make (chan bool )
183178 go func () {
184179 for {
185- domainNode , more := <- domainGraphChan
180+ domainNode , more := <- domainGraphChan
186181 if more {
187182 dDomain := directDomain (domainNode .Domain )
188183 domainGraph [dDomain ] = domainNode // not thread safe
@@ -198,6 +193,7 @@ func BFS(root string) {
198193 <- done // wait for save to finish
199194}
200195
196+ // visit each node and get its neighbors
201197func BFSPeers (host string ) []string {
202198 domains := make ([]string , 0 )
203199 certs := getPeerCerts (host )
@@ -234,6 +230,7 @@ func BFSPeers(host string) []string {
234230
235231}
236232
233+ // gets the certificats found for a given domain
237234func getPeerCerts (host string ) []* x509.Certificate {
238235 addr := net .JoinHostPort (host , port )
239236 dialer := & net.Dialer {Timeout : timeout }
0 commit comments