-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhttpstream.go
106 lines (96 loc) · 2.45 KB
/
httpstream.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
package nfp
import (
"bufio"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"strings"
"github.com/bradleyfalzon/tlsx"
"github.com/google/gopacket"
"github.com/google/gopacket/tcpassembly"
"github.com/google/gopacket/tcpassembly/tcpreader"
)
// HTTPStreamFactory implements tcpassembly.StreamFactory
type HTTPStreamFactory struct{}
// httpStream will handle the actual decoding of http requests.
type httpStream struct {
net, transport gopacket.Flow
r tcpreader.ReaderStream
}
// New - make a new instance of an httpStream
func (h *HTTPStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
hstream := &httpStream{
net: net,
transport: transport,
r: tcpreader.NewReaderStream(),
}
go hstream.run() // Important... we must guarantee that data from the reader stream is read.
// ReaderStream implements tcpassembly.Stream, so we can return a pointer to it.
return &hstream.r
}
// IsHTTP Returns 0 for not HTTP, 1 for HTTP Request, and 2 for HTTP Response
func IsHTTP(prefix []byte) int {
stb := string(prefix)
if stb[:4] == "HTTP" {
return 2 // response found
}
token := strings.Split(stb, " ")[0]
verbs := []string{"GET", "OPTIONS", "POST", "TRACE", "TRACK",
"PUT", "PATCH", "DELETE", "CONNECT", "HEAD"}
for _, b := range verbs {
if b == token {
return 1 //request found
}
}
return 0 // dunno
}
func (h *httpStream) run() {
var record HTTPStreamRecord
buf := bufio.NewReader(&h.r)
for {
tb, err := buf.Peek(10)
if err != nil {
if err != io.EOF {
log.Println(err.Error())
}
break
}
rType := IsHTTP(tb)
if rType == 1 {
req, err := http.ReadRequest(buf)
if err == io.EOF {
break
} else {
b, _ := httputil.DumpRequest(req, true)
record.Dump = append(record.Dump, b...)
record.Net = h.net
record.Transport = h.transport
metrics.HTTPStreams.PushBack(record)
}
} else if rType == 2 {
resp, err := http.ReadResponse(buf, nil)
if err == io.EOF {
break
} else {
b, _ := httputil.DumpResponse(resp, true)
record.Dump = append(record.Dump, b...)
record.Net = h.net
record.Transport = h.transport
metrics.HTTPStreams.PushBack(record)
}
} else {
b, err := ioutil.ReadAll(buf)
if err != nil {
log.Println(err.Error())
} else {
var hello = tlsx.ClientHello{}
if err := hello.Unmarshall(b); err != nil && hello.HandshakeType == 1 {
metrics.TLSClientHellos.PushBack(hello)
}
break
}
}
}
}