-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathstore.go
147 lines (126 loc) · 4.12 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package main
import (
"database/sql"
"flag"
"fmt"
"net"
"os"
"strings"
"sync"
"time"
_ "github.com/mattn/go-sqlite3" // Import go-sqlite3 library
)
type StoreArgs struct {
Concurrency int
Ports []string
Timeout int
PortList string
Help bool
Input string
Database string
}
// struct to hold data for a database write operation
type dbWriteRequest struct {
ip string
organization string
commonName string
san string
}
func runCloudStore(clArgs []string) {
args := parseStoreCLI(clArgs)
if _, err := os.Stat(args.Database); err == nil {
fmt.Printf("Using database file %s\n", args.Database)
} else {
//Create DB file if it doesn't exist
CreateDatabase(args.Database)
}
sqliteDatabase, _ := sql.Open("sqlite3", args.Database) // Open the created SQLite File
createTable(sqliteDatabase) // Create Database Tables if needed
defer sqliteDatabase.Close() // Ensure the database is closed when done
dialer := &net.Dialer{
Timeout: time.Duration(args.Timeout) * time.Second,
}
// create a channel for these requests
writeRequests := make(chan dbWriteRequest, 100) // Buffered channel
//Channel for input
inputChannel := make(chan string)
// Start the dedicated database writer goroutine
go func(db *sql.DB) {
for req := range writeRequests {
_, err := db.Exec("INSERT INTO certificates (ip, organization, common_name, san) VALUES (?, ?, ?, ?) ON CONFLICT(ip) DO UPDATE SET organization = excluded.organization, common_name = excluded.common_name, san = excluded.san", req.ip, req.organization, req.commonName, req.san)
if err != nil {
panic(err) // Or handle the error more gracefully
}
}
}(sqliteDatabase)
var inputwg sync.WaitGroup
for i := 0; i < args.Concurrency; i++ {
inputwg.Add(1)
go func() {
defer inputwg.Done()
for ip := range inputChannel {
cert, err := getSSLCert(ip, dialer)
if err != nil {
continue
}
names := extractNames(cert)
org := "NONE" // Default value if org is not available
if len(cert.Subject.Organization) > 0 {
org = cert.Subject.Organization[0]
}
// Send the write request to the channel
writeRequests <- dbWriteRequest{
ip: ip,
organization: org,
commonName: names[0], // Assuming names[0] is the common name
san: strings.Join(names[1:], ","),
}
}
}()
}
intakeFunction(inputChannel, args.Ports, args.Input)
close(inputChannel)
inputwg.Wait()
sqliteDatabase.Close()
}
func parseStoreCLI(clArgs []string) StoreArgs {
args := StoreArgs{}
storeUsage := "store [options] -i <IPs/CIDRs or File>"
storeCommand := flag.NewFlagSet("scrape", flag.ContinueOnError)
storeCommand.IntVar(&args.Concurrency, "c", 100, "How many goroutines running concurrently")
storeCommand.StringVar(&args.PortList, "p", "443", "TLS ports to check for certificates")
storeCommand.IntVar(&args.Timeout, "t", 4, "Timeout for TLS handshake")
storeCommand.BoolVar(&args.Help, "h", false, "print usage!")
storeCommand.StringVar(&args.Input, "i", "NONE", "Either IPs & CIDRs separated by commas, or a file with IPs/CIDRs on each line")
storeCommand.StringVar(&args.Database, "db", "certificates.db", "String of the DB you want to connect to and save certs!")
storeCommand.Parse(clArgs)
if args.Input == "NONE" {
fmt.Print("No input detected, please use the -i flag to add input!\n\n")
fmt.Println(storeUsage)
storeCommand.PrintDefaults()
os.Exit(1)
}
if args.Help {
fmt.Println(storeUsage)
storeCommand.PrintDefaults()
}
args.Ports = strings.Split(args.PortList, ",")
return args
}
func CreateDatabase(databaseName string) {
os.Remove(databaseName) // I delete the file to avoid duplicated records.
fmt.Println("Creating db...")
file, err := os.Create(databaseName) // Create SQLite file
if err != nil {
panic(err.Error())
}
file.Close()
fmt.Println("db created")
}
func createTable(db *sql.DB) {
statement, err := db.Prepare("CREATE TABLE IF NOT EXISTS certificates (ip TEXT PRIMARY KEY NOT NULL, organization TEXT, common_name TEXT, san TEXT)")
if err != nil {
panic(err)
}
statement.Exec()
}