Files
kubeshark/tap/tcp_reader.go

127 lines
3.1 KiB
Go

package tap
import (
"bufio"
"fmt"
"io"
"log"
"strconv"
"sync"
"time"
"github.com/bradleyfalzon/tlsx"
"github.com/up9inc/mizu/tap/api"
)
const checkTLSPacketAmount = 100
type httpReaderDataMsg struct {
bytes []byte
timestamp time.Time
}
type tcpID struct {
srcIP string
dstIP string
srcPort string
dstPort string
}
type ConnectionInfo struct {
ClientIP string
ClientPort string
ServerIP string
ServerPort string
IsOutgoing bool
}
func (tid *tcpID) String() string {
return fmt.Sprintf("%s->%s %s->%s", tid.srcIP, tid.dstIP, tid.srcPort, tid.dstPort)
}
/* httpReader gets reads from a channel of bytes of tcp payload, and parses it into HTTP/1 requests and responses.
* The payload is written to the channel by a tcpStream object that is dedicated to one tcp connection.
* An httpReader object is unidirectional: it parses either a client stream or a server stream.
* Implements io.Reader interface (Read)
*/
type tcpReader struct {
ident string
tcpID *api.TcpID
isClient bool
isHTTP2 bool
isOutgoing bool
msgQueue chan httpReaderDataMsg // Channel of captured reassembled tcp payload
data []byte
captureTime time.Time
hexdump bool
parent *tcpStream
messageCount uint
packetsSeen uint
outboundLinkWriter *OutboundLinkWriter
Emitter api.Emitter
}
func (h *tcpReader) Read(p []byte) (int, error) {
var msg httpReaderDataMsg
ok := true
for ok && len(h.data) == 0 {
msg, ok = <-h.msgQueue
h.data = msg.bytes
h.captureTime = msg.timestamp
if len(h.data) > 0 {
h.packetsSeen += 1
}
if h.packetsSeen < checkTLSPacketAmount && len(msg.bytes) > 5 { // packets with less than 5 bytes cause tlsx to panic
clientHello := tlsx.ClientHello{}
err := clientHello.Unmarshall(msg.bytes)
if err == nil {
fmt.Printf("Detected TLS client hello with SNI %s\n", clientHello.SNI)
numericPort, _ := strconv.Atoi(h.tcpID.DstPort)
h.outboundLinkWriter.WriteOutboundLink(h.tcpID.SrcIP, h.tcpID.DstIP, numericPort, clientHello.SNI, TLSProtocol)
}
}
}
if !ok || len(h.data) == 0 {
return 0, io.EOF
}
l := copy(p, h.data)
h.data = h.data[l:]
return l, nil
}
func containsPort(ports []string, port string) bool {
for _, x := range ports {
if x == port {
return true
}
}
return false
}
func (h *tcpReader) run(wg *sync.WaitGroup) {
defer wg.Done()
log.Printf("Called run h.isClient: %v\n", h.isClient)
b := bufio.NewReader(h)
if h.isClient {
extensions[1].Dissector.Dissect(b, h.isClient, h.tcpID, h.Emitter)
} else {
extensions[1].Dissector.Dissect(b, h.isClient, h.tcpID, h.Emitter)
}
// for _, extension := range extensions {
// var subjectPorts []string
// if h.isClient {
// subjectPorts = extension.OutboundPorts
// } else {
// subjectPorts = extension.InboundPorts
// }
// if containsPort(subjectPorts, "80") {
// extension.Dissector.Ping()
// fmt.Printf("h.isClient: %v\n", h.isClient)
// extension.Dissector.Dissect(b, h.isClient, h.tcpID, h.Emitter)
// }
// }
}