mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-06-25 07:45:01 +00:00
TRA-3420 inform user of tls traffic (#149)
* Update passive_tapper.go and tls_utils.go * Update go.mod, go.sum, and 18 more files... * go fmt * Update http_reader.go, passive_tapper.go, and 3 more files... * Update status_controller.go and status_provider.go Co-authored-by: RamiBerm <rami.berman@up9.com>
This commit is contained in:
parent
8d8310ee02
commit
ceb8d714e3
@ -22,6 +22,7 @@ require (
|
|||||||
k8s.io/api v0.21.0
|
k8s.io/api v0.21.0
|
||||||
k8s.io/apimachinery v0.21.0
|
k8s.io/apimachinery v0.21.0
|
||||||
k8s.io/client-go v0.21.0
|
k8s.io/client-go v0.21.0
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
||||||
|
@ -45,6 +45,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l
|
|||||||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
||||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||||
|
github.com/bradleyfalzon/tlsx v0.0.0-20170624122154-28fd0e59bac4 h1:NJOOlc6ZJjix0A1rAU+nxruZtR8KboG1848yqpIUo4M=
|
||||||
|
github.com/bradleyfalzon/tlsx v0.0.0-20170624122154-28fd0e59bac4/go.mod h1:DQPxZS994Ld1Y8uwnJT+dRL04XPD0cElP/pHH/zEBHM=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
@ -245,6 +247,8 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
|
|||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 h1:fa50YL1pzKW+1SsBnJDOHppJN9stOEwS+CRWyUtyYGU=
|
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 h1:fa50YL1pzKW+1SsBnJDOHppJN9stOEwS+CRWyUtyYGU=
|
||||||
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
@ -62,8 +62,8 @@ func main() {
|
|||||||
panic(fmt.Sprintf("Error connecting to socket server at %s %v", *apiServerAddress, err))
|
panic(fmt.Sprintf("Error connecting to socket server at %s %v", *apiServerAddress, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
go pipeChannelToSocket(socketConnection, harOutputChannel)
|
go pipeTapChannelToSocket(socketConnection, harOutputChannel)
|
||||||
go api.StartReadingOutbound(outboundLinkOutputChannel)
|
go pipeOutboundLinksChannelToSocket(socketConnection, outboundLinkOutputChannel)
|
||||||
} else if *apiServer {
|
} else if *apiServer {
|
||||||
socketHarOutChannel := make(chan *tap.OutputChannelItem, 1000)
|
socketHarOutChannel := make(chan *tap.OutputChannelItem, 1000)
|
||||||
filteredHarChannel := make(chan *tap.OutputChannelItem)
|
filteredHarChannel := make(chan *tap.OutputChannelItem)
|
||||||
@ -177,7 +177,7 @@ func isHealthCheckByUserAgent(message *tap.OutputChannelItem) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipeChannelToSocket(connection *websocket.Conn, messageDataChannel <-chan *tap.OutputChannelItem) {
|
func pipeTapChannelToSocket(connection *websocket.Conn, messageDataChannel <-chan *tap.OutputChannelItem) {
|
||||||
if connection == nil {
|
if connection == nil {
|
||||||
panic("Websocket connection is nil")
|
panic("Websocket connection is nil")
|
||||||
}
|
}
|
||||||
@ -200,3 +200,21 @@ func pipeChannelToSocket(connection *websocket.Conn, messageDataChannel <-chan *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pipeOutboundLinksChannelToSocket(connection *websocket.Conn, outboundLinkChannel <-chan *tap.OutboundLink) {
|
||||||
|
for outboundLink := range outboundLinkChannel {
|
||||||
|
if outboundLink.SuggestedProtocol == tap.TLSProtocol {
|
||||||
|
marshaledData, err := models.CreateWebsocketOutboundLinkMessage(outboundLink)
|
||||||
|
if err != nil {
|
||||||
|
rlog.Infof("Error converting outbound link to json %s, (%v,%+v)", err, err, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = connection.WriteMessage(websocket.TextMessage, marshaledData)
|
||||||
|
if err != nil {
|
||||||
|
rlog.Infof("error sending outbound link message through socket server %s, (%v,%+v)", err, err, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,8 +6,8 @@ import (
|
|||||||
"github.com/romana/rlog"
|
"github.com/romana/rlog"
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
"github.com/up9inc/mizu/tap"
|
"github.com/up9inc/mizu/tap"
|
||||||
"mizuserver/pkg/controllers"
|
|
||||||
"mizuserver/pkg/models"
|
"mizuserver/pkg/models"
|
||||||
|
"mizuserver/pkg/providers"
|
||||||
"mizuserver/pkg/routes"
|
"mizuserver/pkg/routes"
|
||||||
"mizuserver/pkg/up9"
|
"mizuserver/pkg/up9"
|
||||||
"sync"
|
"sync"
|
||||||
@ -80,15 +80,46 @@ func (h *RoutesEventHandlers) WebSocketMessage(_ int, message []byte) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
rlog.Infof("Could not unmarshal message of message type %s %v\n", socketMessageBase.MessageType, err)
|
rlog.Infof("Could not unmarshal message of message type %s %v\n", socketMessageBase.MessageType, err)
|
||||||
} else {
|
} else {
|
||||||
controllers.TapStatus = statusMessage.TappingStatus
|
providers.TapStatus.Pods = statusMessage.TappingStatus.Pods
|
||||||
broadcastToBrowserClients(message)
|
broadcastToBrowserClients(message)
|
||||||
}
|
}
|
||||||
|
case shared.WebsocketMessageTypeOutboundLink:
|
||||||
|
var outboundLinkMessage models.WebsocketOutboundLinkMessage
|
||||||
|
err := json.Unmarshal(message, &outboundLinkMessage)
|
||||||
|
if err != nil {
|
||||||
|
rlog.Infof("Could not unmarshal message of message type %s %v\n", socketMessageBase.MessageType, err)
|
||||||
|
} else {
|
||||||
|
handleTLSLink(outboundLinkMessage)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
rlog.Infof("Received socket message of type %s for which no handlers are defined", socketMessageBase.MessageType)
|
rlog.Infof("Received socket message of type %s for which no handlers are defined", socketMessageBase.MessageType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleTLSLink(outboundLinkMessage models.WebsocketOutboundLinkMessage) {
|
||||||
|
resolvedName := k8sResolver.Resolve(outboundLinkMessage.Data.DstIP)
|
||||||
|
if resolvedName != "" {
|
||||||
|
outboundLinkMessage.Data.DstIP = resolvedName
|
||||||
|
} else if outboundLinkMessage.Data.SuggestedResolvedName != "" {
|
||||||
|
outboundLinkMessage.Data.DstIP = outboundLinkMessage.Data.SuggestedResolvedName
|
||||||
|
}
|
||||||
|
cacheKey := fmt.Sprintf("%s -> %s:%d", outboundLinkMessage.Data.Src, outboundLinkMessage.Data.DstIP, outboundLinkMessage.Data.DstPort)
|
||||||
|
_, isInCache := providers.RecentTLSLinks.Get(cacheKey)
|
||||||
|
if isInCache {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
providers.RecentTLSLinks.SetDefault(cacheKey, outboundLinkMessage.Data)
|
||||||
|
}
|
||||||
|
marshaledMessage, err := json.Marshal(outboundLinkMessage)
|
||||||
|
if err != nil {
|
||||||
|
rlog.Errorf("Error marshaling outbound link message for broadcasting: %v", err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Broadcasting outboundlink message %s\n", string(marshaledMessage))
|
||||||
|
broadcastToBrowserClients(marshaledMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func removeSocketUUIDFromBrowserSlice(uuidToRemove int) {
|
func removeSocketUUIDFromBrowserSlice(uuidToRemove int) {
|
||||||
newUUIDSlice := make([]int, 0, len(browserClientSocketUUIDs))
|
newUUIDSlice := make([]int, 0, len(browserClientSocketUUIDs))
|
||||||
for _, uuid := range browserClientSocketUUIDs {
|
for _, uuid := range browserClientSocketUUIDs {
|
||||||
|
@ -2,17 +2,19 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/up9inc/mizu/shared"
|
"mizuserver/pkg/providers"
|
||||||
"mizuserver/pkg/up9"
|
"mizuserver/pkg/up9"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TapStatus shared.TapStatus
|
|
||||||
|
|
||||||
func GetTappingStatus(c *gin.Context) {
|
func GetTappingStatus(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, TapStatus)
|
c.JSON(http.StatusOK, providers.TapStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AnalyzeInformation(c *gin.Context) {
|
func AnalyzeInformation(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, up9.GetAnalyzeInfo())
|
c.JSON(http.StatusOK, up9.GetAnalyzeInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRecentTLSLinks(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, providers.GetAllRecentTLSAddresses())
|
||||||
|
}
|
||||||
|
@ -132,6 +132,11 @@ type WebSocketTappedEntryMessage struct {
|
|||||||
Data *tap.OutputChannelItem
|
Data *tap.OutputChannelItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsocketOutboundLinkMessage struct {
|
||||||
|
*shared.WebSocketMessageMetadata
|
||||||
|
Data *tap.OutboundLink
|
||||||
|
}
|
||||||
|
|
||||||
func CreateBaseEntryWebSocketMessage(base *BaseEntryDetails) ([]byte, error) {
|
func CreateBaseEntryWebSocketMessage(base *BaseEntryDetails) ([]byte, error) {
|
||||||
message := &WebSocketEntryMessage{
|
message := &WebSocketEntryMessage{
|
||||||
WebSocketMessageMetadata: &shared.WebSocketMessageMetadata{
|
WebSocketMessageMetadata: &shared.WebSocketMessageMetadata{
|
||||||
@ -152,6 +157,16 @@ func CreateWebsocketTappedEntryMessage(base *tap.OutputChannelItem) ([]byte, err
|
|||||||
return json.Marshal(message)
|
return json.Marshal(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateWebsocketOutboundLinkMessage(base *tap.OutboundLink) ([]byte, error) {
|
||||||
|
message := &WebsocketOutboundLinkMessage{
|
||||||
|
WebSocketMessageMetadata: &shared.WebSocketMessageMetadata{
|
||||||
|
MessageType: shared.WebsocketMessageTypeOutboundLink,
|
||||||
|
},
|
||||||
|
Data: base,
|
||||||
|
}
|
||||||
|
return json.Marshal(message)
|
||||||
|
}
|
||||||
|
|
||||||
// ExtendedHAR is the top level object of a HAR log.
|
// ExtendedHAR is the top level object of a HAR log.
|
||||||
type ExtendedHAR struct {
|
type ExtendedHAR struct {
|
||||||
Log *ExtendedLog `json:"log"`
|
Log *ExtendedLog `json:"log"`
|
||||||
|
28
agent/pkg/providers/status_provider.go
Normal file
28
agent/pkg/providers/status_provider.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
|
"github.com/up9inc/mizu/shared"
|
||||||
|
"github.com/up9inc/mizu/tap"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const tlsLinkRetainmentTime = time.Minute * 15
|
||||||
|
|
||||||
|
var (
|
||||||
|
TapStatus shared.TapStatus
|
||||||
|
RecentTLSLinks = cache.New(tlsLinkRetainmentTime, tlsLinkRetainmentTime)
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAllRecentTLSAddresses() []string {
|
||||||
|
recentTLSLinks := make([]string, 0)
|
||||||
|
|
||||||
|
for _, outboundLinkItem := range RecentTLSLinks.Items() {
|
||||||
|
outboundLink, castOk := outboundLinkItem.Object.(*tap.OutboundLink)
|
||||||
|
if castOk {
|
||||||
|
recentTLSLinks = append(recentTLSLinks, outboundLink.DstIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recentTLSLinks
|
||||||
|
}
|
@ -22,4 +22,5 @@ func EntriesRoutes(ginApp *gin.Engine) {
|
|||||||
|
|
||||||
routeGroup.GET("/tapStatus", controllers.GetTappingStatus) // get tapping status
|
routeGroup.GET("/tapStatus", controllers.GetTappingStatus) // get tapping status
|
||||||
routeGroup.GET("/analyzeStatus", controllers.AnalyzeInformation)
|
routeGroup.GET("/analyzeStatus", controllers.AnalyzeInformation)
|
||||||
|
routeGroup.GET("/recentTLSLinks", controllers.GetRecentTLSLinks)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ const (
|
|||||||
WebSocketMessageTypeTappedEntry WebSocketMessageType = "tappedEntry"
|
WebSocketMessageTypeTappedEntry WebSocketMessageType = "tappedEntry"
|
||||||
WebSocketMessageTypeUpdateStatus WebSocketMessageType = "status"
|
WebSocketMessageTypeUpdateStatus WebSocketMessageType = "status"
|
||||||
WebSocketMessageTypeAnalyzeStatus WebSocketMessageType = "analyzeStatus"
|
WebSocketMessageTypeAnalyzeStatus WebSocketMessageType = "analyzeStatus"
|
||||||
|
WebsocketMessageTypeOutboundLink WebSocketMessageType = "outboundLink"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocketMessageMetadata struct {
|
type WebSocketMessageMetadata struct {
|
||||||
@ -32,6 +33,7 @@ type WebSocketStatusMessage struct {
|
|||||||
|
|
||||||
type TapStatus struct {
|
type TapStatus struct {
|
||||||
Pods []PodInfo `json:"pods"`
|
Pods []PodInfo `json:"pods"`
|
||||||
|
TLSLinks []TLSLinkInfo `json:"tlsLinks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PodInfo struct {
|
type PodInfo struct {
|
||||||
@ -39,6 +41,13 @@ type PodInfo struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TLSLinkInfo struct {
|
||||||
|
SourceIP string `json:"sourceIP"`
|
||||||
|
DestinationAddress string `json:"destinationAddress"`
|
||||||
|
ResolvedDestinationName string `json:"resolvedDestinationName"`
|
||||||
|
ResolvedSourceName string `json:"resolvedSourceName"`
|
||||||
|
}
|
||||||
|
|
||||||
func CreateWebSocketStatusMessage(tappingStatus TapStatus) WebSocketStatusMessage {
|
func CreateWebSocketStatusMessage(tappingStatus TapStatus) WebSocketStatusMessage {
|
||||||
return WebSocketStatusMessage{
|
return WebSocketStatusMessage{
|
||||||
WebSocketMessageMetadata: &WebSocketMessageMetadata{
|
WebSocketMessageMetadata: &WebSocketMessageMetadata{
|
||||||
|
@ -8,4 +8,5 @@ require (
|
|||||||
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231
|
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231
|
||||||
github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7
|
github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7
|
||||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758
|
golang.org/x/net v0.0.0-20210421230115-4e50805a0758
|
||||||
|
github.com/bradleyfalzon/tlsx v0.0.0-20170624122154-28fd0e59bac4
|
||||||
)
|
)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
github.com/bradleyfalzon/tlsx v0.0.0-20170624122154-28fd0e59bac4 h1:NJOOlc6ZJjix0A1rAU+nxruZtR8KboG1848yqpIUo4M=
|
||||||
|
github.com/bradleyfalzon/tlsx v0.0.0-20170624122154-28fd0e59bac4/go.mod h1:DQPxZS994Ld1Y8uwnJT+dRL04XPD0cElP/pHH/zEBHM=
|
||||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||||
|
@ -5,13 +5,17 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/bradleyfalzon/tlsx"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const checkTLSPacketAmount = 100
|
||||||
|
|
||||||
type httpReaderDataMsg struct {
|
type httpReaderDataMsg struct {
|
||||||
bytes []byte
|
bytes []byte
|
||||||
timestamp time.Time
|
timestamp time.Time
|
||||||
@ -55,15 +59,31 @@ type httpReader struct {
|
|||||||
grpcAssembler GrpcAssembler
|
grpcAssembler GrpcAssembler
|
||||||
messageCount uint
|
messageCount uint
|
||||||
harWriter *HarWriter
|
harWriter *HarWriter
|
||||||
|
packetsSeen uint
|
||||||
|
outboundLinkWriter *OutboundLinkWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpReader) Read(p []byte) (int, error) {
|
func (h *httpReader) Read(p []byte) (int, error) {
|
||||||
var msg httpReaderDataMsg
|
var msg httpReaderDataMsg
|
||||||
|
|
||||||
ok := true
|
ok := true
|
||||||
for ok && len(h.data) == 0 {
|
for ok && len(h.data) == 0 {
|
||||||
msg, ok = <-h.msgQueue
|
msg, ok = <-h.msgQueue
|
||||||
h.data = msg.bytes
|
h.data = msg.bytes
|
||||||
|
|
||||||
h.captureTime = msg.timestamp
|
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 {
|
if !ok || len(h.data) == 0 {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
package tap
|
package tap
|
||||||
|
|
||||||
|
type OutboundLinkProtocol string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TLSProtocol OutboundLinkProtocol = "tls"
|
||||||
|
)
|
||||||
|
|
||||||
type OutboundLink struct {
|
type OutboundLink struct {
|
||||||
Src string
|
Src string
|
||||||
DstIP string
|
DstIP string
|
||||||
DstPort int
|
DstPort int
|
||||||
|
SuggestedResolvedName string
|
||||||
|
SuggestedProtocol OutboundLinkProtocol
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutboundLinkWriter() *OutboundLinkWriter {
|
func NewOutboundLinkWriter() *OutboundLinkWriter {
|
||||||
@ -16,11 +24,13 @@ type OutboundLinkWriter struct {
|
|||||||
OutChan chan *OutboundLink
|
OutChan chan *OutboundLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (olw *OutboundLinkWriter) WriteOutboundLink(src string, DstIP string, DstPort int) {
|
func (olw *OutboundLinkWriter) WriteOutboundLink(src string, DstIP string, DstPort int, SuggestedResolvedName string, SuggestedProtocol OutboundLinkProtocol) {
|
||||||
olw.OutChan <- &OutboundLink{
|
olw.OutChan <- &OutboundLink{
|
||||||
Src: src,
|
Src: src,
|
||||||
DstIP: DstIP,
|
DstIP: DstIP,
|
||||||
DstPort: DstPort,
|
DstPort: DstPort,
|
||||||
|
SuggestedResolvedName: SuggestedResolvedName,
|
||||||
|
SuggestedProtocol: SuggestedProtocol,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T
|
|||||||
dstPort := int(tcp.DstPort)
|
dstPort := int(tcp.DstPort)
|
||||||
|
|
||||||
if factory.shouldNotifyOnOutboundLink(dstIp, dstPort) {
|
if factory.shouldNotifyOnOutboundLink(dstIp, dstPort) {
|
||||||
factory.outbountLinkWriter.WriteOutboundLink(net.Src().String(), dstIp, dstPort)
|
factory.outbountLinkWriter.WriteOutboundLink(net.Src().String(), dstIp, dstPort, "", "")
|
||||||
}
|
}
|
||||||
props := factory.getStreamProps(srcIp, dstIp, dstPort)
|
props := factory.getStreamProps(srcIp, dstIp, dstPort)
|
||||||
isHTTP := props.isTapTarget
|
isHTTP := props.isTapTarget
|
||||||
@ -62,6 +62,7 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T
|
|||||||
isClient: true,
|
isClient: true,
|
||||||
isOutgoing: props.isOutgoing,
|
isOutgoing: props.isOutgoing,
|
||||||
harWriter: factory.harWriter,
|
harWriter: factory.harWriter,
|
||||||
|
outboundLinkWriter: factory.outbountLinkWriter,
|
||||||
}
|
}
|
||||||
stream.server = httpReader{
|
stream.server = httpReader{
|
||||||
msgQueue: make(chan httpReaderDataMsg),
|
msgQueue: make(chan httpReaderDataMsg),
|
||||||
@ -76,6 +77,7 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T
|
|||||||
parent: stream,
|
parent: stream,
|
||||||
isOutgoing: props.isOutgoing,
|
isOutgoing: props.isOutgoing,
|
||||||
harWriter: factory.harWriter,
|
harWriter: factory.harWriter,
|
||||||
|
outboundLinkWriter: factory.outbountLinkWriter,
|
||||||
}
|
}
|
||||||
factory.wg.Add(2)
|
factory.wg.Add(2)
|
||||||
// Start reading from channels stream.client.bytes and stream.server.bytes
|
// Start reading from channels stream.client.bytes and stream.server.bytes
|
||||||
@ -133,4 +135,3 @@ type streamProps struct {
|
|||||||
isTapTarget bool
|
isTapTarget bool
|
||||||
isOutgoing bool
|
isOutgoing bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22900
ui/package-lock.json
generated
22900
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.11.3",
|
"@material-ui/core": "^4.11.3",
|
||||||
|
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||||
"@testing-library/jest-dom": "^5.11.10",
|
"@testing-library/jest-dom": "^5.11.10",
|
||||||
"@testing-library/react": "^11.2.6",
|
"@testing-library/react": "^11.2.6",
|
||||||
"@testing-library/user-event": "^12.8.3",
|
"@testing-library/user-event": "^12.8.3",
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import React, {useState} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import './App.sass';
|
import './App.sass';
|
||||||
import logo from './components/assets/Mizu-logo.svg';
|
import logo from './components/assets/Mizu-logo.svg';
|
||||||
import {Button} from "@material-ui/core";
|
import {Button, Snackbar} from "@material-ui/core";
|
||||||
import {HarPage} from "./components/HarPage";
|
import {HarPage} from "./components/HarPage";
|
||||||
import Tooltip from "./components/Tooltip";
|
import Tooltip from "./components/Tooltip";
|
||||||
import {makeStyles} from "@material-ui/core/styles";
|
import {makeStyles} from "@material-ui/core/styles";
|
||||||
|
import MuiAlert from '@material-ui/lab/Alert';
|
||||||
|
import Api from "./helpers/api";
|
||||||
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
@ -15,11 +17,37 @@ const useStyles = makeStyles(() => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const api = new Api();
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const [analyzeStatus, setAnalyzeStatus] = useState(null);
|
const [analyzeStatus, setAnalyzeStatus] = useState(null);
|
||||||
|
const [showTLSWarning, setShowTLSWarning] = useState(false);
|
||||||
|
const [userDismissedTLSWarning, setUserDismissedTLSWarning] = useState(false);
|
||||||
|
const [addressesWithTLS, setAddressesWithTLS] = useState(new Set());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const recentTLSLinks = await api.getRecentTLSLinks();
|
||||||
|
|
||||||
|
if (recentTLSLinks?.length > 0) {
|
||||||
|
setAddressesWithTLS(new Set([...addressesWithTLS, ...recentTLSLinks]));
|
||||||
|
setShowTLSWarning(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onTLSDetected = (destAddress: string) => {
|
||||||
|
addressesWithTLS.add(destAddress);
|
||||||
|
setAddressesWithTLS(new Set(addressesWithTLS));
|
||||||
|
|
||||||
|
if (!userDismissedTLSWarning) {
|
||||||
|
setShowTLSWarning(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const analysisMessage = analyzeStatus?.isRemoteReady ?
|
const analysisMessage = analyzeStatus?.isRemoteReady ?
|
||||||
<span>
|
<span>
|
||||||
@ -88,7 +116,12 @@ const App = () => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<HarPage setAnalyzeStatus={setAnalyzeStatus}/>
|
<HarPage setAnalyzeStatus={setAnalyzeStatus} onTLSDetected={onTLSDetected}/>
|
||||||
|
<Snackbar open={showTLSWarning && !userDismissedTLSWarning}>
|
||||||
|
<MuiAlert elevation={6} variant="filled" onClose={() => setUserDismissedTLSWarning(true)} severity="warning">
|
||||||
|
Mizu is detecting TLS traffic{addressesWithTLS.size ? ` (directed to ${Array.from(addressesWithTLS).join(", ")})` : ''}, this type of traffic will not be displayed.
|
||||||
|
</MuiAlert>
|
||||||
|
</Snackbar>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,12 @@ enum ConnectionStatus {
|
|||||||
|
|
||||||
interface HarPageProps {
|
interface HarPageProps {
|
||||||
setAnalyzeStatus: (status: any) => void;
|
setAnalyzeStatus: (status: any) => void;
|
||||||
|
onTLSDetected: (destAddress: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const api = new Api();
|
const api = new Api();
|
||||||
|
|
||||||
export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus}) => {
|
export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected}) => {
|
||||||
|
|
||||||
const classes = useLayoutStyles();
|
const classes = useLayoutStyles();
|
||||||
|
|
||||||
@ -93,6 +94,9 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus}) => {
|
|||||||
case "analyzeStatus":
|
case "analyzeStatus":
|
||||||
setAnalyzeStatus(message.analyzeStatus);
|
setAnalyzeStatus(message.analyzeStatus);
|
||||||
break
|
break
|
||||||
|
case "outboundLink":
|
||||||
|
onTLSDetected(message.Data.DstIP);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error(`unsupported websocket message type, Got: ${message.messageType}`)
|
console.error(`unsupported websocket message type, Got: ${message.messageType}`)
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,9 @@ export default class Api {
|
|||||||
const response = await this.client.get(`/entries?limit=50&operator=${operator}×tamp=${timestamp}`);
|
const response = await this.client.get(`/entries?limit=50&operator=${operator}×tamp=${timestamp}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRecentTLSLinks = async () => {
|
||||||
|
const response = await this.client.get("/recentTLSLinks");
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user