mirror of
https://github.com/maride/pancap.git
synced 2024-11-24 17:54:24 +00:00
Add support for HTTP packets
This commit is contained in:
parent
56b493283e
commit
cd01dc7664
52
protocol/http/http.go
Normal file
52
protocol/http/http.go
Normal file
@ -0,0 +1,52 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"git.darknebu.la/maride/pancap/common"
|
||||
"git.darknebu.la/maride/pancap/output"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/tcpassembly"
|
||||
)
|
||||
|
||||
type Protocol struct {
|
||||
initialized bool
|
||||
requestFactory *httpRequestFactory
|
||||
responseFactory *httpResponseFactory
|
||||
requestPool *tcpassembly.StreamPool
|
||||
responsePool *tcpassembly.StreamPool
|
||||
requestAssembler *tcpassembly.Assembler
|
||||
responseAssembler *tcpassembly.Assembler
|
||||
}
|
||||
|
||||
// Checks if the given packet is an HTTP packet we can process
|
||||
func (p *Protocol) CanAnalyze(packet gopacket.Packet) bool {
|
||||
return packet.Layer(layers.LayerTypeTCP) != nil && packet.Layer(layers.LayerTypeTLS) == nil
|
||||
}
|
||||
|
||||
// Analyzes the given HTTP packet
|
||||
func (p *Protocol) Analyze(packet gopacket.Packet) error {
|
||||
// Check if we need to init
|
||||
if !p.initialized {
|
||||
// Initialize
|
||||
p.requestFactory = &httpRequestFactory{}
|
||||
p.responseFactory = &httpResponseFactory{}
|
||||
p.requestPool = tcpassembly.NewStreamPool(p.requestFactory)
|
||||
p.responsePool = tcpassembly.NewStreamPool(p.responseFactory)
|
||||
p.requestAssembler = tcpassembly.NewAssembler(p.requestPool)
|
||||
p.responseAssembler = tcpassembly.NewAssembler(p.responsePool)
|
||||
p.initialized = true
|
||||
}
|
||||
|
||||
// Try to cast packet and assemble HTTP stream
|
||||
tcp := packet.TransportLayer().(*layers.TCP)
|
||||
p.requestAssembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp)
|
||||
p.responseAssembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Print a summary after all packets are processed
|
||||
func (p *Protocol) PrintSummary() {
|
||||
output.PrintBlock("HTTP Requests", common.GenerateTree(requestSummaryLines))
|
||||
output.PrintBlock("HTTP Responses", common.GenerateTree(responseSummaryLines))
|
||||
}
|
67
protocol/http/httpRequestFactory.go
Normal file
67
protocol/http/httpRequestFactory.go
Normal file
@ -0,0 +1,67 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/tcpassembly"
|
||||
"github.com/google/gopacket/tcpassembly/tcpreader"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
requestSummaryLines []string
|
||||
)
|
||||
|
||||
type httpRequestFactory struct{}
|
||||
|
||||
type httpRequestStream struct {
|
||||
net, transport gopacket.Flow
|
||||
r tcpreader.ReaderStream
|
||||
}
|
||||
|
||||
// Creates a new HTTPRequestStream for the given packet flow, and analyzes it in a separate thread
|
||||
func (h *httpRequestFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
|
||||
hstream := &httpRequestStream{
|
||||
net: net,
|
||||
transport: transport,
|
||||
r: tcpreader.NewReaderStream(),
|
||||
}
|
||||
|
||||
// Start analyzer as thread and return TCP reader stream
|
||||
go hstream.run()
|
||||
return &hstream.r
|
||||
}
|
||||
|
||||
// Analyzes the given request
|
||||
func (h *httpRequestStream) run() {
|
||||
iobuf := bufio.NewReader(&h.r)
|
||||
|
||||
for {
|
||||
req, reqErr := http.ReadRequest(iobuf)
|
||||
|
||||
if reqErr == io.EOF {
|
||||
// That's ok, we can ignore EOF errors
|
||||
return
|
||||
} else if reqErr != nil {
|
||||
// Ignore, because it may be a response
|
||||
} else {
|
||||
// Try to process assembled request
|
||||
tcpreader.DiscardBytesToEOF(req.Body)
|
||||
req.Body.Close()
|
||||
|
||||
// Build summary
|
||||
line := fmt.Sprintf("Request %s http://%s%s", req.Method, req.Host, req.RequestURI)
|
||||
requestSummaryLines = append(requestSummaryLines, line)
|
||||
|
||||
// Check for file uploads
|
||||
if req.MultipartForm != nil && req.MultipartForm.File != nil {
|
||||
for k, v := range req.MultipartForm.File {
|
||||
log.Println(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
59
protocol/http/httpResponseFactory.go
Normal file
59
protocol/http/httpResponseFactory.go
Normal file
@ -0,0 +1,59 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/tcpassembly"
|
||||
"github.com/google/gopacket/tcpassembly/tcpreader"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
responseSummaryLines []string
|
||||
)
|
||||
|
||||
type httpResponseFactory struct{}
|
||||
|
||||
type httpResponseStream struct {
|
||||
net, transport gopacket.Flow
|
||||
r tcpreader.ReaderStream
|
||||
}
|
||||
|
||||
// Creates a new HTTPResponseStream for the given packet flow, and analyzes it in a separate thread
|
||||
func (h *httpResponseFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
|
||||
hstream := &httpResponseStream{
|
||||
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
|
||||
}
|
||||
|
||||
// Analyzes the given response
|
||||
func (h *httpResponseStream) run() {
|
||||
iobuf := bufio.NewReader(&h.r)
|
||||
|
||||
for {
|
||||
resp, respErr := http.ReadResponse(iobuf, nil)
|
||||
|
||||
if respErr == io.EOF {
|
||||
// That's ok, we can ignore EOF errors
|
||||
return
|
||||
} else if respErr != nil {
|
||||
// Ignore, because it may be a request
|
||||
} else {
|
||||
// Try to process assembled request
|
||||
tcpreader.DiscardBytesToEOF(resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
// Build summary
|
||||
line := fmt.Sprintf("Response %s, Type %s, Size %d bytes", resp.Status, resp.Header.Get("Content-Type"), resp.ContentLength)
|
||||
responseSummaryLines = append(responseSummaryLines, line)
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import (
|
||||
"git.darknebu.la/maride/pancap/protocol/arp"
|
||||
"git.darknebu.la/maride/pancap/protocol/dhcpv4"
|
||||
"git.darknebu.la/maride/pancap/protocol/dns"
|
||||
"git.darknebu.la/maride/pancap/protocol/http"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -11,5 +12,6 @@ var (
|
||||
&arp.Protocol{},
|
||||
&dhcpv4.Protocol{},
|
||||
&dns.Protocol{},
|
||||
&http.Protocol{},
|
||||
}
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user