-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
161 lines (134 loc) · 3.56 KB
/
main.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package main
import (
"bufio"
"encoding/hex"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/google/gopacket"
"github.com/google/gopacket/pcap"
)
const OffsetContentType = 0
const OffsetHandshakeType = 13
const OffsetMajorVersion = 25
const ClientHelloType = 1
const ServerHelloType = 2
const HelloVerifyRequest = 3
const HandshakeType = 22
func appendFingerprint(fingerprint string, version string) error {
var fileStrings []string
file := "./pkg/fingerprints/fingerprints.go"
readFile, err := os.Open(file)
if err != nil {
return err
}
fileScanner := bufio.NewScanner(readFile)
fileScanner.Split(bufio.ScanLines)
var isDone bool
var hasVersion bool
for fileScanner.Scan() {
line := fileScanner.Text()
if line == ")" && !hasVersion {
fileStrings = append(fileStrings, fmt.Sprintf(" %s ClientHelloFingerprint = \"%s\" //nolint:revive,stylecheck", version, fingerprint))
} else if strings.Contains(line, "}") && !isDone && !hasVersion {
fileStrings = append(fileStrings, fmt.Sprintf(" %s, //nolint:revive,stylecheck", version))
isDone = true
} else if strings.Contains(line, "ClientHelloFingerprint =") {
slist := strings.Split(line, "ClientHelloFingerprint")
if len(slist) > 1 {
fversion := slist[0]
fversion = strings.Trim(fversion, " ")
fversion = strings.Trim(fversion, "\t")
fmt.Println(fversion)
if fversion == version {
hasVersion = true
}
}
}
fileStrings = append(fileStrings, line)
}
readFile.Close()
f, err := os.Create(file)
if err != nil {
f.Close()
return err
}
for _, v := range fileStrings {
_, err = fmt.Fprintln(f, v)
if err != nil {
f.Close()
return err
}
}
err = f.Close()
return err
}
func parsePcap(path string, filename string) error {
fmt.Printf("Parsing %s\n", filename)
var parsedClientHello bool
tmp := strings.Split(filename, "-")
version := tmp[len(tmp)-1]
version = strings.TrimSuffix(version, ".pcap")
version = strings.Trim(version, "_")
version = strings.ToUpper(version[:1]) + version[1:]
handle, err := pcap.OpenOffline(path)
if err != nil {
return err
}
defer handle.Close()
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
dtls := packet.ApplicationLayer().LayerContents()
if len(dtls) < OffsetContentType {
return errors.New("parsed packet is empty")
}
if dtls[OffsetContentType] == HandshakeType {
if len(dtls) < OffsetHandshakeType {
return errors.New("parsed packet does not contain a handshake")
}
handshakeType := uint(dtls[OffsetHandshakeType])
switch handshakeType {
case ClientHelloType:
if len(dtls) < OffsetMajorVersion {
return errors.New("parsed client hello does not have any fields")
}
fingerprintRaw := dtls[OffsetMajorVersion:]
fingerprintString := hex.EncodeToString(fingerprintRaw)
// Only parse one client hello per handshake
if !parsedClientHello {
err = appendFingerprint(fingerprintString, version)
if err != nil {
return err
}
parsedClientHello = true
}
default:
}
}
}
return nil
}
func main() {
if len(os.Args) < 1 {
fmt.Println("Please provide pcaps")
os.Exit(1)
}
err := filepath.Walk(os.Args[1], func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.Contains(info.Name(), ".pcap") {
err = parsePcap(path, info.Name())
if err != nil {
return err
}
}
return nil
})
if err != nil {
fmt.Fprintf(os.Stderr, "failed during parsing of pcap: %v\n", err)
os.Exit(1)
}
}