├── static
└── banner.png
├── LICENSE
├── README.md
└── main.go
/static/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devanshbatham/getsan/HEAD/static/banner.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Devansh Batham
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | getsan
3 |
4 |
5 |
6 | A utility to fetch and display dns names from the SSL/TLS cert data
7 |
8 |
9 |
10 | 🏗️ Installation
11 | ⛏️ Usage
12 |
13 |
14 |
15 |
16 | 
17 |
18 | # Installation
19 | ```sh
20 | go install github.com/devanshbatham/getsan@latest
21 | ```
22 |
23 | # Usage
24 |
25 | - Fetches and displays dns names from the SSL/TLS cert data
26 | - Uses concurrency for efficient and fast lookups (e.g. `-c 200`)
27 |
28 | ```sh
29 | ⚓ echo "cdn.syndication.twitter.com" | getsan | jq
30 |
31 | {
32 | "domain": "cdn.syndication.twitter.com",
33 | "common_name": "syndication.twitter.com",
34 | "org": [
35 | "Twitter, Inc."
36 | ],
37 | "dns_names": [
38 | "syndication.twitter.com",
39 | "syndication.twimg.com",
40 | "cdn.syndication.twitter.com",
41 | "cdn.syndication.twimg.com",
42 | "syndication-o.twitter.com",
43 | "syndication-o.twimg.com"
44 | ]
45 | }
46 | ```
47 |
48 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "crypto/tls"
6 | "encoding/json"
7 | "flag"
8 | "fmt"
9 | "net"
10 | "os"
11 | "strings"
12 | "sync"
13 | "time"
14 | )
15 |
16 | /*
17 | CertData represents the extracted certificate data for a domain.
18 | */
19 | type CertData struct {
20 | Domain string `json:"domain"`
21 | CommonName string `json:"common_name"`
22 | Org []string `json:"org"`
23 | DNSNames []string `json:"dns_names"`
24 | }
25 |
26 | func main() {
27 | /*
28 | Parse command line flags to determine the number of concurrent tasks.
29 | */
30 | concurrency := flag.Int("c", 100, "Number of concurrent tasks")
31 | flag.Parse()
32 |
33 | var wg sync.WaitGroup
34 |
35 | // Create channels to communicate between goroutines.
36 | domains := make(chan string, *concurrency) // Channel to send domain names.
37 | results := make(chan *CertData, *concurrency) // Channel to receive certificate data.
38 |
39 | /*
40 | Start worker goroutines.
41 | */
42 | for i := 0; i < *concurrency; i++ {
43 | wg.Add(1)
44 | go func() {
45 | defer wg.Done()
46 |
47 | /*
48 | Process domain names from the 'domains' channel.
49 | */
50 | for domain := range domains {
51 | func() {
52 | defer recover() // Catch any panics.
53 |
54 | /*
55 | Fetch certificate data for the current domain.
56 | */
57 | data, err := getCertificate(domain)
58 | if err == nil && data != nil {
59 | results <- data // Send the certificate data to the 'results' channel.
60 | }
61 | }()
62 | }
63 | }()
64 | }
65 |
66 | /*
67 | Read domain names from standard input and send them to the 'domains' channel.
68 | */
69 | go func() {
70 | scanner := bufio.NewScanner(os.Stdin)
71 | for scanner.Scan() {
72 | domain := strings.TrimSpace(scanner.Text())
73 | domain = strings.TrimPrefix(domain, "http://")
74 | domain = strings.TrimPrefix(domain, "https://")
75 | domains <- domain // Send the domain to the 'domains' channel.
76 | }
77 | close(domains) // Close the 'domains' channel when all domains are sent.
78 | }()
79 |
80 | /*
81 | Wait for all worker goroutines to finish.
82 | */
83 | go func() {
84 | wg.Wait()
85 | close(results) // Close the 'results' channel when all workers are done.
86 | }()
87 |
88 | first := true
89 |
90 | /*
91 | Process certificate data received from the 'results' channel.
92 | */
93 | for result := range results {
94 | if !first {
95 | fmt.Println() // Print a newline to separate JSON objects.
96 | } else {
97 | first = false
98 | }
99 | output, err := json.Marshal(result)
100 | if err == nil {
101 | fmt.Print(string(output))
102 | }
103 | }
104 | }
105 |
106 | /*
107 | getCertificate fetches SSL/TLS certificate data for the given domain.
108 | */
109 | func getCertificate(domain string) (*CertData, error) {
110 | dialer := &net.Dialer{
111 | Timeout: 5 * time.Second,
112 | }
113 | conn, err := tls.DialWithDialer(dialer, "tcp", domain+":443", &tls.Config{
114 | InsecureSkipVerify: true,
115 | })
116 | if err != nil {
117 | return nil, err
118 | }
119 | defer conn.Close()
120 |
121 | conn.SetDeadline(time.Now().Add(5 * time.Second))
122 |
123 | cert := conn.ConnectionState().PeerCertificates[0]
124 | certData := &CertData{
125 | Domain: domain,
126 | CommonName: cert.Subject.CommonName,
127 | Org: cert.Subject.Organization,
128 | DNSNames: cert.DNSNames,
129 | }
130 | return certData, nil
131 | }
132 |
--------------------------------------------------------------------------------