mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-02-15 02:19:54 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec11b21b51 | ||
|
|
52c9251c00 | ||
|
|
f3a6b3a9d4 |
@@ -51,7 +51,7 @@ require (
|
||||
github.com/beevik/etree v1.1.0 // indirect
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
|
||||
github.com/chanced/dynamic v0.0.0-20211210164248-f8fadb1d735b // indirect
|
||||
github.com/cilium/ebpf v0.8.1 // indirect
|
||||
github.com/cilium/ebpf v0.9.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
@@ -89,6 +89,7 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mertyildiran/gqlparser/v2 v2.4.6 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/moby/moby v20.10.17+incompatible // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
@@ -104,6 +105,7 @@ require (
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect
|
||||
github.com/segmentio/kafka-go v0.4.27 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/spf13/cobra v1.3.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/struCoder/pidusage v0.2.1 // indirect
|
||||
|
||||
11
agent/go.sum
11
agent/go.sum
@@ -128,8 +128,8 @@ github.com/chanced/openapi v0.0.8/go.mod h1:SxE2VMLPw+T7Vq8nwbVVhDF2PigvRF4n5Xyq
|
||||
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/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cilium/ebpf v0.8.1 h1:bLSSEbBLqGPXxls55pGr5qWZaTqcmfDJHhou7t254ao=
|
||||
github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk=
|
||||
github.com/cilium/ebpf v0.9.0 h1:ldiV+FscPCQ/p3mNEV4O02EPbUZJFsoEtHvIr9xLTvk=
|
||||
github.com/cilium/ebpf v0.9.0/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
@@ -517,6 +517,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/moby v20.10.17+incompatible h1:TJJfyk2fLEgK+RzqVpFNkDkm0oEi+MLUfwt9lEYnp5g=
|
||||
github.com/moby/moby v20.10.17+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
||||
@@ -629,6 +631,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
@@ -1249,8 +1253,9 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
|
||||
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package providers
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -36,13 +39,13 @@ type SizeAndEntriesCount struct {
|
||||
|
||||
type AccumulativeStatsCounter struct {
|
||||
Name string `json:"name"`
|
||||
Color string `json:"color"`
|
||||
EntriesCount int `json:"entriesCount"`
|
||||
VolumeSizeBytes int `json:"volumeSizeBytes"`
|
||||
}
|
||||
|
||||
type AccumulativeStatsProtocol struct {
|
||||
AccumulativeStatsCounter
|
||||
Color string `json:"color"`
|
||||
Methods []*AccumulativeStatsCounter `json:"methods"`
|
||||
}
|
||||
|
||||
@@ -52,6 +55,7 @@ type AccumulativeStatsProtocolTime struct {
|
||||
}
|
||||
|
||||
type TrafficStatsResponse struct {
|
||||
Protocols []string `json:"protocols"`
|
||||
PieStats []*AccumulativeStatsProtocol `json:"pie"`
|
||||
TimelineStats []*AccumulativeStatsProtocolTime `json:"timeline"`
|
||||
}
|
||||
@@ -78,20 +82,36 @@ func GetGeneralStats() *GeneralStats {
|
||||
|
||||
func InitProtocolToColor(protocolMap map[string]*api.Protocol) {
|
||||
for item, value := range protocolMap {
|
||||
protocolToColor[strings.Split(item, "/")[2]] = value.BackgroundColor
|
||||
splitted := strings.SplitN(item, "/", 3)
|
||||
protocolToColor[splitted[len(splitted)-1]] = value.BackgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
func GetTrafficStats() *TrafficStatsResponse {
|
||||
bucketsStatsCopy := getBucketStatsCopy()
|
||||
interval := calculateInterval(bucketsStatsCopy[0].BucketTime.Unix(), bucketsStatsCopy[len(bucketsStatsCopy)-1].BucketTime.Unix()) // in seconds
|
||||
|
||||
return &TrafficStatsResponse{
|
||||
Protocols: getAvailableProtocols(bucketsStatsCopy),
|
||||
PieStats: getAccumulativeStats(bucketsStatsCopy),
|
||||
TimelineStats: getAccumulativeStatsTiming(bucketsStatsCopy, interval),
|
||||
TimelineStats: getAccumulativeStatsTiming(bucketsStatsCopy),
|
||||
}
|
||||
}
|
||||
|
||||
func EntryAdded(size int, summery *api.BaseEntry) {
|
||||
generalStats.EntriesCount++
|
||||
generalStats.EntriesVolumeInGB += float64(size) / (1 << 30)
|
||||
|
||||
currentTimestamp := int(time.Now().Unix())
|
||||
|
||||
if reflect.Value.IsZero(reflect.ValueOf(generalStats.FirstEntryTimestamp)) {
|
||||
generalStats.FirstEntryTimestamp = currentTimestamp
|
||||
}
|
||||
|
||||
addToBucketStats(size, summery)
|
||||
|
||||
generalStats.LastEntryTimestamp = currentTimestamp
|
||||
}
|
||||
|
||||
func calculateInterval(firstTimestamp int64, lastTimestamp int64) time.Duration {
|
||||
validDurations := []time.Duration{
|
||||
time.Minute,
|
||||
@@ -140,31 +160,17 @@ func getAccumulativeStats(stats BucketStats) []*AccumulativeStatsProtocol {
|
||||
return convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated)
|
||||
}
|
||||
|
||||
func getAccumulativeStatsTiming(stats BucketStats, interval time.Duration) []*AccumulativeStatsProtocolTime {
|
||||
func getAccumulativeStatsTiming(stats BucketStats) []*AccumulativeStatsProtocolTime {
|
||||
if len(stats) == 0 {
|
||||
return make([]*AccumulativeStatsProtocolTime, 0)
|
||||
}
|
||||
|
||||
methodsPerProtocolPerTimeAggregated := getAggregatedResultTiming(interval, stats)
|
||||
interval := calculateInterval(stats[0].BucketTime.Unix(), stats[len(stats)-1].BucketTime.Unix()) // in seconds
|
||||
methodsPerProtocolPerTimeAggregated := getAggregatedResultTiming(stats, interval)
|
||||
|
||||
return convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggregated)
|
||||
}
|
||||
|
||||
func EntryAdded(size int, summery *api.BaseEntry) {
|
||||
generalStats.EntriesCount++
|
||||
generalStats.EntriesVolumeInGB += float64(size) / (1 << 30)
|
||||
|
||||
currentTimestamp := int(time.Now().Unix())
|
||||
|
||||
if reflect.Value.IsZero(reflect.ValueOf(generalStats.FirstEntryTimestamp)) {
|
||||
generalStats.FirstEntryTimestamp = currentTimestamp
|
||||
}
|
||||
|
||||
addToBucketStats(size, summery)
|
||||
|
||||
generalStats.LastEntryTimestamp = currentTimestamp
|
||||
}
|
||||
|
||||
func addToBucketStats(size int, summery *api.BaseEntry) {
|
||||
entryTimeBucketRounded := getBucketFromTimeStamp(summery.Timestamp)
|
||||
|
||||
@@ -207,11 +213,11 @@ func convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggreg
|
||||
finalResult := make([]*AccumulativeStatsProtocolTime, 0)
|
||||
for timeKey, item := range methodsPerProtocolPerTimeAggregated {
|
||||
protocolsData := make([]*AccumulativeStatsProtocol, 0)
|
||||
for protocolName := range item {
|
||||
for protocolName, value := range item {
|
||||
entriesCount := 0
|
||||
volumeSizeBytes := 0
|
||||
methods := make([]*AccumulativeStatsCounter, 0)
|
||||
for _, methodAccData := range methodsPerProtocolPerTimeAggregated[timeKey][protocolName] {
|
||||
for _, methodAccData := range value {
|
||||
entriesCount += methodAccData.EntriesCount
|
||||
volumeSizeBytes += methodAccData.VolumeSizeBytes
|
||||
methods = append(methods, methodAccData)
|
||||
@@ -219,10 +225,10 @@ func convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggreg
|
||||
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
|
||||
AccumulativeStatsCounter: AccumulativeStatsCounter{
|
||||
Name: protocolName,
|
||||
Color: protocolToColor[protocolName],
|
||||
EntriesCount: entriesCount,
|
||||
VolumeSizeBytes: volumeSizeBytes,
|
||||
},
|
||||
Color: protocolToColor[protocolName],
|
||||
Methods: methods,
|
||||
})
|
||||
}
|
||||
@@ -248,10 +254,10 @@ func convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated map[string
|
||||
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
|
||||
AccumulativeStatsCounter: AccumulativeStatsCounter{
|
||||
Name: protocolName,
|
||||
Color: protocolToColor[protocolName],
|
||||
EntriesCount: entriesCount,
|
||||
VolumeSizeBytes: volumeSizeBytes,
|
||||
},
|
||||
Color: protocolToColor[protocolName],
|
||||
Methods: methods,
|
||||
})
|
||||
}
|
||||
@@ -269,7 +275,7 @@ func getBucketStatsCopy() BucketStats {
|
||||
return bucketStatsCopy
|
||||
}
|
||||
|
||||
func getAggregatedResultTiming(interval time.Duration, stats BucketStats) map[time.Time]map[string]map[string]*AccumulativeStatsCounter {
|
||||
func getAggregatedResultTiming(stats BucketStats, interval time.Duration) map[time.Time]map[string]map[string]*AccumulativeStatsCounter {
|
||||
methodsPerProtocolPerTimeAggregated := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{}
|
||||
|
||||
bucketStatsIndex := len(stats) - 1
|
||||
@@ -289,6 +295,7 @@ func getAggregatedResultTiming(interval time.Duration, stats BucketStats) map[ti
|
||||
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName]; !ok {
|
||||
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName] = &AccumulativeStatsCounter{
|
||||
Name: methodName,
|
||||
Color: getColorForMethod(protocolName, methodName),
|
||||
EntriesCount: 0,
|
||||
VolumeSizeBytes: 0,
|
||||
}
|
||||
@@ -303,9 +310,9 @@ func getAggregatedResultTiming(interval time.Duration, stats BucketStats) map[ti
|
||||
return methodsPerProtocolPerTimeAggregated
|
||||
}
|
||||
|
||||
func getAggregatedStats(bucketStatsCopy BucketStats) map[string]map[string]*AccumulativeStatsCounter {
|
||||
func getAggregatedStats(stats BucketStats) map[string]map[string]*AccumulativeStatsCounter {
|
||||
methodsPerProtocolAggregated := make(map[string]map[string]*AccumulativeStatsCounter, 0)
|
||||
for _, countersOfTimeFrame := range bucketStatsCopy {
|
||||
for _, countersOfTimeFrame := range stats {
|
||||
for protocolName, value := range countersOfTimeFrame.ProtocolStats {
|
||||
for method, countersValue := range value.MethodsStats {
|
||||
if _, found := methodsPerProtocolAggregated[protocolName]; !found {
|
||||
@@ -314,6 +321,7 @@ func getAggregatedStats(bucketStatsCopy BucketStats) map[string]map[string]*Accu
|
||||
if _, found := methodsPerProtocolAggregated[protocolName][method]; !found {
|
||||
methodsPerProtocolAggregated[protocolName][method] = &AccumulativeStatsCounter{
|
||||
Name: method,
|
||||
Color: getColorForMethod(protocolName, method),
|
||||
EntriesCount: 0,
|
||||
VolumeSizeBytes: 0,
|
||||
}
|
||||
@@ -325,3 +333,25 @@ func getAggregatedStats(bucketStatsCopy BucketStats) map[string]map[string]*Accu
|
||||
}
|
||||
return methodsPerProtocolAggregated
|
||||
}
|
||||
|
||||
func getColorForMethod(protocolName string, methodName string) string {
|
||||
hash := md5.Sum([]byte(fmt.Sprintf("%v_%v", protocolName, methodName)))
|
||||
input := hex.EncodeToString(hash[:])
|
||||
return fmt.Sprintf("#%v", input[:6])
|
||||
}
|
||||
|
||||
func getAvailableProtocols(stats BucketStats) []string {
|
||||
protocols := map[string]bool{}
|
||||
for _, countersOfTimeFrame := range stats {
|
||||
for protocolName := range countersOfTimeFrame.ProtocolStats {
|
||||
protocols[protocolName] = true
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]string, 0)
|
||||
for protocol := range protocols {
|
||||
result = append(result, protocol)
|
||||
}
|
||||
result = append(result, "ALL")
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package providers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -110,8 +109,8 @@ func TestGetAggregatedStatsAllTime(t *testing.T) {
|
||||
}
|
||||
actual := getAggregatedStats(bucketStatsForTest)
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("unexpected result - expected: %v, actual: %v", 3, len(actual))
|
||||
if len(actual) != len(expected) {
|
||||
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,10 +194,10 @@ func TestGetAggregatedStatsFromSpecificTime(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
actual := getAggregatedResultTiming(time.Minute*5, bucketStatsForTest)
|
||||
actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute*5)
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("unexpected result - expected: %v, actual: %v", 3, len(actual))
|
||||
if len(actual) != len(expected) {
|
||||
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,9 +290,9 @@ func TestGetAggregatedStatsFromSpecificTimeMultipleBuckets(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
actual := getAggregatedResultTiming(time.Minute, bucketStatsForTest)
|
||||
actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute)
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("unexpected result - expected: %v, actual: %v", 3, len(actual))
|
||||
if len(actual) != len(expected) {
|
||||
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ go 1.17
|
||||
|
||||
require (
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/cilium/ebpf v0.8.1
|
||||
github.com/cilium/ebpf v0.9.0
|
||||
github.com/go-errors/errors v1.4.2
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9
|
||||
github.com/moby/moby v20.10.17+incompatible
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/struCoder/pidusage v0.2.1
|
||||
github.com/up9inc/mizu/logger v0.0.0
|
||||
@@ -28,6 +29,7 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
@@ -36,6 +38,7 @@ require (
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gotest.tools/v3 v3.3.0 // indirect
|
||||
k8s.io/apimachinery v0.23.3 // indirect
|
||||
k8s.io/klog/v2 v2.40.1 // indirect
|
||||
k8s.io/utils v0.0.0-20220127004650-9b3446523e65 // indirect
|
||||
|
||||
15
tap/go.sum
15
tap/go.sum
@@ -7,8 +7,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cilium/ebpf v0.8.1 h1:bLSSEbBLqGPXxls55pGr5qWZaTqcmfDJHhou7t254ao=
|
||||
github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk=
|
||||
github.com/cilium/ebpf v0.9.0 h1:ldiV+FscPCQ/p3mNEV4O02EPbUZJFsoEtHvIr9xLTvk=
|
||||
github.com/cilium/ebpf v0.9.0/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -94,6 +94,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/moby v20.10.17+incompatible h1:TJJfyk2fLEgK+RzqVpFNkDkm0oEi+MLUfwt9lEYnp5g=
|
||||
github.com/moby/moby v20.10.17+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
@@ -123,11 +125,15 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
@@ -186,12 +192,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -221,6 +229,7 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -269,6 +278,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
|
||||
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.23.3 h1:KNrME8KHGr12Ozjf8ytOewKzZh6hl/hHUZeHddT3a38=
|
||||
|
||||
@@ -21,7 +21,7 @@ docker run --rm \
|
||||
-it mizu-ebpf-builder \
|
||||
sh -c "
|
||||
BPF_TARGET=\"$BPF_TARGET\" BPF_CFLAGS=\"$BPF_CFLAGS\" go generate tap/tlstapper/tls_tapper.go
|
||||
chown $(id -u):$(id -g) tap/tlstapper/tlstapper_bpf*
|
||||
chown $(id -u):$(id -g) tap/tlstapper/tlstapper*_bpf*
|
||||
" || exit 1
|
||||
|
||||
popd
|
||||
|
||||
@@ -35,11 +35,12 @@ using `bpf_probe_read` calls in `go_crypto_tls_get_fd_from_tcp_conn` function.
|
||||
|
||||
SOURCES:
|
||||
|
||||
Tracing Go Functions with eBPF (before 1.17): https://www.grant.pizza/blog/tracing-go-functions-with-ebpf-part-2/
|
||||
Tracing Go Functions with eBPF (<=1.16): https://www.grant.pizza/blog/tracing-go-functions-with-ebpf-part-2/
|
||||
Challenges of BPF Tracing Go: https://blog.0x74696d.com/posts/challenges-of-bpf-tracing-go/
|
||||
x86 calling conventions: https://en.wikipedia.org/wiki/X86_calling_conventions
|
||||
Plan 9 from Bell Labs: https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs
|
||||
The issue for calling convention change in Go: https://github.com/golang/go/issues/40724
|
||||
Go ABI0 (<=1.16) specification: https://go.dev/doc/asm
|
||||
Proposal of Register-based Go calling convention: https://go.googlesource.com/proposal/+/master/design/40724-register-calling.md
|
||||
Go internal ABI (1.17) specification: https://go.googlesource.com/go/+/refs/heads/dev.regabi/src/cmd/compile/internal-abi.md
|
||||
Go internal ABI (current) specification: https://go.googlesource.com/go/+/refs/heads/master/src/cmd/compile/abi-internal.md
|
||||
@@ -55,10 +56,60 @@ Capstone Engine: https://www.capstone-engine.org/
|
||||
#include "include/logger_messages.h"
|
||||
#include "include/pids.h"
|
||||
#include "include/common.h"
|
||||
#include "include/go_abi_0.h"
|
||||
#include "include/go_abi_internal.h"
|
||||
#include "include/go_types.h"
|
||||
|
||||
static __always_inline __u32 go_crypto_tls_get_fd_from_tcp_conn(struct pt_regs *ctx) {
|
||||
|
||||
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we build object files per kernel version.
|
||||
// Error: reference to .kconfig: not supported
|
||||
// See: https://github.com/cilium/ebpf/issues/698
|
||||
// extern int LINUX_KERNEL_VERSION __kconfig;
|
||||
|
||||
enum ABI {
|
||||
ABI0=0,
|
||||
ABIInternal=1,
|
||||
};
|
||||
|
||||
#if defined(bpf_target_x86)
|
||||
// get_goid_from_thread_local_storage function is x86 specific
|
||||
static __always_inline __u32 get_goid_from_thread_local_storage(__u64 *goroutine_id) {
|
||||
int zero = 0;
|
||||
int one = 1;
|
||||
struct goid_offsets* offsets = bpf_map_lookup_elem(&goid_offsets_map, &zero);
|
||||
if (offsets == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the task that currently assigned to this thread.
|
||||
struct task_struct *task = (struct task_struct*) bpf_get_current_task();
|
||||
if (task == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read task->thread
|
||||
struct thread_struct *thr;
|
||||
bpf_probe_read(&thr, sizeof(thr), &task->thread);
|
||||
|
||||
// Read task->thread.fsbase
|
||||
u64 fsbase;
|
||||
#ifdef KERNEL_BEFORE_4_6
|
||||
// TODO: if (LINUX_KERNEL_VERSION <= KERNEL_VERSION(4, 6, 0)) {
|
||||
fsbase = BPF_CORE_READ((struct thread_struct___v46 *)thr, fs);
|
||||
#else
|
||||
fsbase = BPF_CORE_READ(thr, fsbase);
|
||||
#endif
|
||||
|
||||
// Get the Goroutine ID (goid) which is stored in thread-local storage.
|
||||
size_t g_addr;
|
||||
bpf_probe_read_user(&g_addr, sizeof(void *), (void*)(fsbase + offsets->g_addr_offset));
|
||||
bpf_probe_read_user(goroutine_id, sizeof(void *), (void*)(g_addr + offsets->goid_offset));
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __always_inline __u32 go_crypto_tls_get_fd_from_tcp_conn(struct pt_regs *ctx, enum ABI abi) {
|
||||
struct go_interface conn;
|
||||
long err;
|
||||
__u64 addr;
|
||||
@@ -67,8 +118,15 @@ static __always_inline __u32 go_crypto_tls_get_fd_from_tcp_conn(struct pt_regs *
|
||||
if (err != 0) {
|
||||
return invalid_fd;
|
||||
}
|
||||
#else
|
||||
addr = GO_ABI_INTERNAL_PT_REGS_R1(ctx);
|
||||
#elif defined(bpf_target_x86)
|
||||
if (abi == ABI0) {
|
||||
err = bpf_probe_read(&addr, sizeof(addr), (void*)GO_ABI_INTERNAL_PT_REGS_SP(ctx)+0x8);
|
||||
if (err != 0) {
|
||||
return invalid_fd;
|
||||
}
|
||||
} else {
|
||||
addr = GO_ABI_INTERNAL_PT_REGS_R1(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
err = bpf_probe_read(&conn, sizeof(conn), (void*)addr);
|
||||
@@ -91,7 +149,7 @@ static __always_inline __u32 go_crypto_tls_get_fd_from_tcp_conn(struct pt_regs *
|
||||
return fd;
|
||||
}
|
||||
|
||||
static __always_inline void go_crypto_tls_uprobe(struct pt_regs *ctx, struct bpf_map_def* go_context) {
|
||||
static __always_inline void go_crypto_tls_uprobe(struct pt_regs *ctx, struct bpf_map_def* go_context, enum ABI abi) {
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
__u64 pid = pid_tgid >> 32;
|
||||
if (!should_tap(pid)) {
|
||||
@@ -107,14 +165,52 @@ static __always_inline void go_crypto_tls_uprobe(struct pt_regs *ctx, struct bpf
|
||||
log_error(ctx, LOG_ERROR_READING_BYTES_COUNT, pid_tgid, err, ORIGIN_SSL_UPROBE_CODE);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
info.buffer_len = GO_ABI_INTERNAL_PT_REGS_R2(ctx);
|
||||
#elif defined(bpf_target_x86)
|
||||
if (abi == ABI0) {
|
||||
err = bpf_probe_read(&info.buffer_len, sizeof(__u32), (void*)GO_ABI_0_PT_REGS_SP(ctx)+0x18);
|
||||
if (err != 0) {
|
||||
log_error(ctx, LOG_ERROR_READING_BYTES_COUNT, pid_tgid, err, ORIGIN_SSL_UPROBE_CODE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
info.buffer_len = GO_ABI_INTERNAL_PT_REGS_R2(ctx);
|
||||
}
|
||||
#endif
|
||||
info.buffer = (void*)GO_ABI_INTERNAL_PT_REGS_R4(ctx);
|
||||
info.fd = go_crypto_tls_get_fd_from_tcp_conn(ctx);
|
||||
|
||||
// GO_ABI_INTERNAL_PT_REGS_GP is Goroutine address
|
||||
__u64 pid_fp = pid << 32 | GO_ABI_INTERNAL_PT_REGS_GP(ctx);
|
||||
#if defined(bpf_target_x86)
|
||||
if (abi == ABI0) {
|
||||
err = bpf_probe_read(&info.buffer, sizeof(__u32), (void*)GO_ABI_0_PT_REGS_SP(ctx)+0x11);
|
||||
if (err != 0) {
|
||||
log_error(ctx, LOG_ERROR_READING_FROM_SSL_BUFFER, pid_tgid, err, ORIGIN_SSL_UPROBE_CODE);
|
||||
return;
|
||||
}
|
||||
// We basically add 00 suffix to the hex address.
|
||||
info.buffer = (void*)((long)info.buffer << 8);
|
||||
} else {
|
||||
#endif
|
||||
info.buffer = (void*)GO_ABI_INTERNAL_PT_REGS_R4(ctx);
|
||||
#if defined(bpf_target_x86)
|
||||
}
|
||||
#endif
|
||||
info.fd = go_crypto_tls_get_fd_from_tcp_conn(ctx, abi);
|
||||
|
||||
__u64 goroutine_id;
|
||||
if (abi == ABI0) {
|
||||
#if defined(bpf_target_arm64)
|
||||
// In case of ABI0 and arm64, it's stored in the Goroutine register
|
||||
goroutine_id = GO_ABI_0_PT_REGS_GP(ctx);
|
||||
#elif defined(bpf_target_x86)
|
||||
// In case of ABI0 and amd64, it's stored in the thread-local storage
|
||||
int status = get_goid_from_thread_local_storage(&goroutine_id);
|
||||
if (!status) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// GO_ABI_INTERNAL_PT_REGS_GP is the Goroutine address in ABIInternal
|
||||
goroutine_id = GO_ABI_INTERNAL_PT_REGS_GP(ctx);
|
||||
}
|
||||
__u64 pid_fp = pid << 32 | goroutine_id;
|
||||
err = bpf_map_update_elem(go_context, &pid_fp, &info, BPF_ANY);
|
||||
|
||||
if (err != 0) {
|
||||
@@ -124,15 +220,30 @@ static __always_inline void go_crypto_tls_uprobe(struct pt_regs *ctx, struct bpf
|
||||
return;
|
||||
}
|
||||
|
||||
static __always_inline void go_crypto_tls_ex_uprobe(struct pt_regs *ctx, struct bpf_map_def* go_context, __u32 flags) {
|
||||
static __always_inline void go_crypto_tls_ex_uprobe(struct pt_regs *ctx, struct bpf_map_def* go_context, __u32 flags, enum ABI abi) {
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
__u64 pid = pid_tgid >> 32;
|
||||
if (!should_tap(pid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// GO_ABI_INTERNAL_PT_REGS_GP is Goroutine address
|
||||
__u64 pid_fp = pid << 32 | GO_ABI_INTERNAL_PT_REGS_GP(ctx);
|
||||
__u64 goroutine_id;
|
||||
if (abi == ABI0) {
|
||||
#if defined(bpf_target_arm64)
|
||||
// In case of ABI0 and arm64, it's stored in the Goroutine register
|
||||
goroutine_id = GO_ABI_0_PT_REGS_GP(ctx);
|
||||
#elif defined(bpf_target_x86)
|
||||
// In case of ABI0 and amd64, it's stored in the thread-local storage
|
||||
int status = get_goid_from_thread_local_storage(&goroutine_id);
|
||||
if (!status) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// GO_ABI_INTERNAL_PT_REGS_GP is the Goroutine address in ABIInternal
|
||||
goroutine_id = GO_ABI_INTERNAL_PT_REGS_GP(ctx);
|
||||
}
|
||||
__u64 pid_fp = pid << 32 | goroutine_id;
|
||||
struct ssl_info *info_ptr = bpf_map_lookup_elem(go_context, &pid_fp);
|
||||
|
||||
if (info_ptr == NULL) {
|
||||
@@ -156,8 +267,17 @@ static __always_inline void go_crypto_tls_ex_uprobe(struct pt_regs *ctx, struct
|
||||
return;
|
||||
}
|
||||
info.buffer_len = GO_ABI_INTERNAL_PT_REGS_R7(ctx); // n in return n, nil
|
||||
#else
|
||||
info.buffer_len = GO_ABI_INTERNAL_PT_REGS_R1(ctx); // n in return n, nil
|
||||
#elif defined(bpf_target_x86)
|
||||
if (abi == ABI0) {
|
||||
// n in return n, nil
|
||||
err = bpf_probe_read(&info.buffer_len, sizeof(__u32), (void*)GO_ABI_0_PT_REGS_SP(ctx)+0x28);
|
||||
if (err != 0) {
|
||||
log_error(ctx, LOG_ERROR_READING_BYTES_COUNT, pid_tgid, err, ORIGIN_SSL_UPROBE_CODE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
info.buffer_len = GO_ABI_INTERNAL_PT_REGS_R1(ctx); // n in return n, nil
|
||||
}
|
||||
#endif
|
||||
// This check achieves ignoring 0 length reads (the reads result with an error)
|
||||
if (info.buffer_len <= 0) {
|
||||
@@ -170,22 +290,50 @@ static __always_inline void go_crypto_tls_ex_uprobe(struct pt_regs *ctx, struct
|
||||
return;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_write")
|
||||
void BPF_KPROBE(go_crypto_tls_write) {
|
||||
go_crypto_tls_uprobe(ctx, &go_write_context);
|
||||
SEC("uprobe/go_crypto_tls_abi0_write")
|
||||
int BPF_KPROBE(go_crypto_tls_abi0_write) {
|
||||
go_crypto_tls_uprobe(ctx, &go_write_context, ABI0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_write_ex")
|
||||
void BPF_KPROBE(go_crypto_tls_write_ex) {
|
||||
go_crypto_tls_ex_uprobe(ctx, &go_write_context, 0);
|
||||
SEC("uprobe/go_crypto_tls_abi0_write_ex")
|
||||
int BPF_KPROBE(go_crypto_tls_abi0_write_ex) {
|
||||
go_crypto_tls_ex_uprobe(ctx, &go_write_context, 0, ABI0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_read")
|
||||
void BPF_KPROBE(go_crypto_tls_read) {
|
||||
go_crypto_tls_uprobe(ctx, &go_read_context);
|
||||
SEC("uprobe/go_crypto_tls_abi0_read")
|
||||
int BPF_KPROBE(go_crypto_tls_abi0_read) {
|
||||
go_crypto_tls_uprobe(ctx, &go_read_context, ABI0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_read_ex")
|
||||
void BPF_KPROBE(go_crypto_tls_read_ex) {
|
||||
go_crypto_tls_ex_uprobe(ctx, &go_read_context, FLAGS_IS_READ_BIT);
|
||||
SEC("uprobe/go_crypto_tls_abi0_read_ex")
|
||||
int BPF_KPROBE(go_crypto_tls_abi0_read_ex) {
|
||||
go_crypto_tls_ex_uprobe(ctx, &go_read_context, FLAGS_IS_READ_BIT, ABI0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_abi_internal_write")
|
||||
int BPF_KPROBE(go_crypto_tls_abi_internal_write) {
|
||||
go_crypto_tls_uprobe(ctx, &go_write_context, ABIInternal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_abi_internal_write_ex")
|
||||
int BPF_KPROBE(go_crypto_tls_abi_internal_write_ex) {
|
||||
go_crypto_tls_ex_uprobe(ctx, &go_write_context, 0, ABIInternal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_abi_internal_read")
|
||||
int BPF_KPROBE(go_crypto_tls_abi_internal_read) {
|
||||
go_crypto_tls_uprobe(ctx, &go_read_context, ABIInternal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("uprobe/go_crypto_tls_abi_internal_read_ex")
|
||||
int BPF_KPROBE(go_crypto_tls_abi_internal_read_ex) {
|
||||
go_crypto_tls_ex_uprobe(ctx, &go_read_context, FLAGS_IS_READ_BIT, ABIInternal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
52
tap/tlstapper/bpf/include/go_abi_0.h
Normal file
52
tap/tlstapper/bpf/include/go_abi_0.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Note: This file is licenced differently from the rest of the project
|
||||
SPDX-License-Identifier: GPL-2.0
|
||||
Copyright (C) UP9 Inc.
|
||||
*/
|
||||
|
||||
#ifndef __GO_ABI_0__
|
||||
#define __GO_ABI_0__
|
||||
|
||||
/*
|
||||
Go ABI0 (<=1.16) specification
|
||||
https://go.dev/doc/asm
|
||||
|
||||
Since ABI0 is a stack-based calling convention we only need the stack pointer and
|
||||
if it's applicable the Goroutine pointer
|
||||
*/
|
||||
|
||||
#include "target_arch.h"
|
||||
|
||||
#if defined(bpf_target_x86)
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#define GO_ABI_0_PT_REGS_SP(x) ((x)->esp)
|
||||
|
||||
#else
|
||||
|
||||
#define GO_ABI_0_PT_REGS_SP(x) ((x)->sp)
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined(bpf_target_arm)
|
||||
|
||||
#define GO_ABI_0_PT_REGS_SP(x) ((x)->uregs[13])
|
||||
#define GO_ABI_0_PT_REGS_GP(x) ((x)->uregs[10])
|
||||
|
||||
#elif defined(bpf_target_arm64)
|
||||
|
||||
/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
struct pt_regs;
|
||||
#define PT_REGS_ARM64 const volatile struct user_pt_regs
|
||||
#define GO_ABI_0_PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp)
|
||||
#define GO_ABI_0_PT_REGS_GP(x) (((PT_REGS_ARM64 *)(x))->regs[18])
|
||||
|
||||
#elif defined(bpf_target_powerpc)
|
||||
|
||||
#define GO_ABI_0_PT_REGS_SP(x) ((x)->sp)
|
||||
#define GO_ABI_0_PT_REGS_GP(x) ((x)->gpr[30])
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __GO_ABI_0__ */
|
||||
@@ -8,54 +8,11 @@ Copyright (C) UP9 Inc.
|
||||
#define __GO_ABI_INTERNAL__
|
||||
|
||||
/*
|
||||
Go internal ABI specification
|
||||
Go internal ABI (1.17/current) specification
|
||||
https://go.googlesource.com/go/+/refs/heads/master/src/cmd/compile/abi-internal.md
|
||||
*/
|
||||
|
||||
/* Scan the ARCH passed in from ARCH env variable */
|
||||
#if defined(__TARGET_ARCH_x86)
|
||||
#define bpf_target_x86
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_s390)
|
||||
#define bpf_target_s390
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_arm)
|
||||
#define bpf_target_arm
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_arm64)
|
||||
#define bpf_target_arm64
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_mips)
|
||||
#define bpf_target_mips
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_powerpc)
|
||||
#define bpf_target_powerpc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_sparc)
|
||||
#define bpf_target_sparc
|
||||
#define bpf_target_defined
|
||||
#else
|
||||
#undef bpf_target_defined
|
||||
#endif
|
||||
|
||||
/* Fall back to what the compiler says */
|
||||
#ifndef bpf_target_defined
|
||||
#if defined(__x86_64__)
|
||||
#define bpf_target_x86
|
||||
#elif defined(__s390__)
|
||||
#define bpf_target_s390
|
||||
#elif defined(__arm__)
|
||||
#define bpf_target_arm
|
||||
#elif defined(__aarch64__)
|
||||
#define bpf_target_arm64
|
||||
#elif defined(__mips__)
|
||||
#define bpf_target_mips
|
||||
#elif defined(__powerpc__)
|
||||
#define bpf_target_powerpc
|
||||
#elif defined(__sparc__)
|
||||
#define bpf_target_sparc
|
||||
#endif
|
||||
#endif
|
||||
#include "target_arch.h"
|
||||
|
||||
#if defined(bpf_target_x86)
|
||||
|
||||
@@ -78,15 +35,15 @@ https://github.com/golang/go/blob/go1.17.6/src/cmd/compile/internal/ssa/gen/AMD6
|
||||
|
||||
#else
|
||||
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R1(x) ((x)->rax)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R2(x) ((x)->rcx)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R3(x) ((x)->rdx)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R4(x) ((x)->rbx)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R5(x) ((x)->rbp)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R6(x) ((x)->rsi)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R7(x) ((x)->rdi)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_SP(x) ((x)->rsp)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_FP(x) ((x)->rbp)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R1(x) ((x)->ax)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R2(x) ((x)->cx)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R3(x) ((x)->dx)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R4(x) ((x)->bx)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R5(x) ((x)->bp)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R6(x) ((x)->si)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_R7(x) ((x)->di)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_SP(x) ((x)->sp)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_FP(x) ((x)->bp)
|
||||
#define GO_ABI_INTERNAL_PT_REGS_GP(x) ((x)->r14)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,9 +8,15 @@ Copyright (C) UP9 Inc.
|
||||
#define __HEADERS__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
#include "target_arch.h"
|
||||
#include "vmlinux_x86.h"
|
||||
#include "vmlinux_arm64.h"
|
||||
|
||||
#include "legacy_kernel.h"
|
||||
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf/bpf_tracing.h"
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
|
||||
#endif /* __HEADERS__ */
|
||||
|
||||
50
tap/tlstapper/bpf/include/legacy_kernel.h
Normal file
50
tap/tlstapper/bpf/include/legacy_kernel.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef __LEGACY_KERNEL_H__
|
||||
#define __LEGACY_KERNEL_H__
|
||||
|
||||
#if defined(bpf_target_x86)
|
||||
|
||||
struct thread_struct___v46 {
|
||||
struct desc_struct tls_array[3];
|
||||
unsigned long sp0;
|
||||
unsigned long sp;
|
||||
unsigned short es;
|
||||
unsigned short ds;
|
||||
unsigned short fsindex;
|
||||
unsigned short gsindex;
|
||||
unsigned long fs;
|
||||
unsigned long gs;
|
||||
struct perf_event ptrace_bps[4];
|
||||
unsigned long debugreg6;
|
||||
unsigned long ptrace_dr7;
|
||||
unsigned long cr2;
|
||||
unsigned long trap_nr;
|
||||
unsigned long error_code;
|
||||
unsigned long io_bitmap_ptr;
|
||||
unsigned long iopl;
|
||||
unsigned io_bitmap_max;
|
||||
long: 63;
|
||||
long: 64;
|
||||
long: 64;
|
||||
long: 64;
|
||||
long: 64;
|
||||
long: 64;
|
||||
struct fpu fpu;
|
||||
};
|
||||
|
||||
#elif defined(bpf_target_arm)
|
||||
|
||||
// Commented out since thread_struct is not used in ARM64 yet.
|
||||
|
||||
// struct thread_struct___v46 {
|
||||
// struct cpu_context cpu_context;
|
||||
// long: 64;
|
||||
// unsigned long tp_value;
|
||||
// struct fpsimd_state fpsimd_state;
|
||||
// unsigned long fault_address;
|
||||
// unsigned long fault_code;
|
||||
// struct debug_info debug;
|
||||
// };
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __LEGACY_KERNEL_H__ */
|
||||
@@ -53,6 +53,13 @@ struct fd_info {
|
||||
__u8 flags;
|
||||
};
|
||||
|
||||
struct goid_offsets {
|
||||
__u64 g_addr_offset;
|
||||
__u64 goid_offset;
|
||||
};
|
||||
|
||||
const struct goid_offsets *unused __attribute__((unused));
|
||||
|
||||
// Heap-like area for eBPF programs - stack size limited to 512 bytes, we must use maps for bigger (chunk) objects.
|
||||
//
|
||||
struct {
|
||||
@@ -91,6 +98,7 @@ BPF_LRU_HASH(openssl_write_context, __u64, struct ssl_info);
|
||||
BPF_LRU_HASH(openssl_read_context, __u64, struct ssl_info);
|
||||
|
||||
// Go specific
|
||||
BPF_HASH(goid_offsets_map, __u32, struct goid_offsets);
|
||||
BPF_LRU_HASH(go_write_context, __u64, struct ssl_info);
|
||||
BPF_LRU_HASH(go_read_context, __u64, struct ssl_info);
|
||||
|
||||
|
||||
55
tap/tlstapper/bpf/include/target_arch.h
Normal file
55
tap/tlstapper/bpf/include/target_arch.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Note: This file is licenced differently from the rest of the project
|
||||
SPDX-License-Identifier: GPL-2.0
|
||||
Copyright (C) UP9 Inc.
|
||||
*/
|
||||
|
||||
#ifndef __TARGET_ARCH__
|
||||
#define __TARGET_ARCH__
|
||||
|
||||
/* Scan the ARCH passed in from ARCH env variable */
|
||||
#if defined(__TARGET_ARCH_x86)
|
||||
#define bpf_target_x86
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_s390)
|
||||
#define bpf_target_s390
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_arm)
|
||||
#define bpf_target_arm
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_arm64)
|
||||
#define bpf_target_arm64
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_mips)
|
||||
#define bpf_target_mips
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_powerpc)
|
||||
#define bpf_target_powerpc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_sparc)
|
||||
#define bpf_target_sparc
|
||||
#define bpf_target_defined
|
||||
#else
|
||||
#undef bpf_target_defined
|
||||
#endif
|
||||
|
||||
/* Fall back to what the compiler says */
|
||||
#ifndef bpf_target_defined
|
||||
#if defined(__x86_64__)
|
||||
#define bpf_target_x86
|
||||
#elif defined(__s390__)
|
||||
#define bpf_target_s390
|
||||
#elif defined(__arm__)
|
||||
#define bpf_target_arm
|
||||
#elif defined(__aarch64__)
|
||||
#define bpf_target_arm64
|
||||
#elif defined(__mips__)
|
||||
#define bpf_target_mips
|
||||
#elif defined(__powerpc__)
|
||||
#define bpf_target_powerpc
|
||||
#elif defined(__sparc__)
|
||||
#define bpf_target_sparc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __TARGET_ARCH__ */
|
||||
157110
tap/tlstapper/bpf/include/vmlinux_arm64.h
Normal file
157110
tap/tlstapper/bpf/include/vmlinux_arm64.h
Normal file
File diff suppressed because it is too large
Load Diff
124048
tap/tlstapper/bpf/include/vmlinux_x86.h
Normal file
124048
tap/tlstapper/bpf/include/vmlinux_x86.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -31,9 +31,32 @@ func (s *goHooks) installUprobes(bpfObjects *tlsTapperObjects, filePath string)
|
||||
func (s *goHooks) installHooks(bpfObjects *tlsTapperObjects, ex *link.Executable, offsets goOffsets) error {
|
||||
var err error
|
||||
|
||||
goCryptoTlsWrite := bpfObjects.GoCryptoTlsAbiInternalWrite
|
||||
goCryptoTlsWriteEx := bpfObjects.GoCryptoTlsAbiInternalWriteEx
|
||||
goCryptoTlsRead := bpfObjects.GoCryptoTlsAbiInternalRead
|
||||
goCryptoTlsReadEx := bpfObjects.GoCryptoTlsAbiInternalReadEx
|
||||
|
||||
if offsets.Abi == ABI0 {
|
||||
goCryptoTlsWrite = bpfObjects.GoCryptoTlsAbi0Write
|
||||
goCryptoTlsWriteEx = bpfObjects.GoCryptoTlsAbi0WriteEx
|
||||
goCryptoTlsRead = bpfObjects.GoCryptoTlsAbi0Read
|
||||
goCryptoTlsReadEx = bpfObjects.GoCryptoTlsAbi0ReadEx
|
||||
|
||||
// Pass goid and g struct offsets to an eBPF map to retrieve it in eBPF context
|
||||
if err := bpfObjects.tlsTapperMaps.GoidOffsetsMap.Put(
|
||||
uint32(0),
|
||||
tlsTapperGoidOffsets{
|
||||
G_addrOffset: offsets.GStructOffset,
|
||||
GoidOffset: offsets.GoidOffset,
|
||||
},
|
||||
); err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Symbol points to
|
||||
// [`crypto/tls.(*Conn).Write`](https://github.com/golang/go/blob/go1.17.6/src/crypto/tls/conn.go#L1099)
|
||||
s.goWriteProbe, err = ex.Uprobe(goWriteSymbol, bpfObjects.GoCryptoTlsWrite, &link.UprobeOptions{
|
||||
s.goWriteProbe, err = ex.Uprobe(goWriteSymbol, goCryptoTlsWrite, &link.UprobeOptions{
|
||||
Offset: offsets.GoWriteOffset.enter,
|
||||
})
|
||||
|
||||
@@ -42,7 +65,7 @@ func (s *goHooks) installHooks(bpfObjects *tlsTapperObjects, ex *link.Executable
|
||||
}
|
||||
|
||||
for _, offset := range offsets.GoWriteOffset.exits {
|
||||
probe, err := ex.Uprobe(goWriteSymbol, bpfObjects.GoCryptoTlsWriteEx, &link.UprobeOptions{
|
||||
probe, err := ex.Uprobe(goWriteSymbol, goCryptoTlsWriteEx, &link.UprobeOptions{
|
||||
Offset: offset,
|
||||
})
|
||||
|
||||
@@ -55,7 +78,7 @@ func (s *goHooks) installHooks(bpfObjects *tlsTapperObjects, ex *link.Executable
|
||||
|
||||
// Symbol points to
|
||||
// [`crypto/tls.(*Conn).Read`](https://github.com/golang/go/blob/go1.17.6/src/crypto/tls/conn.go#L1263)
|
||||
s.goReadProbe, err = ex.Uprobe(goReadSymbol, bpfObjects.GoCryptoTlsRead, &link.UprobeOptions{
|
||||
s.goReadProbe, err = ex.Uprobe(goReadSymbol, goCryptoTlsRead, &link.UprobeOptions{
|
||||
Offset: offsets.GoReadOffset.enter,
|
||||
})
|
||||
|
||||
@@ -64,7 +87,7 @@ func (s *goHooks) installHooks(bpfObjects *tlsTapperObjects, ex *link.Executable
|
||||
}
|
||||
|
||||
for _, offset := range offsets.GoReadOffset.exits {
|
||||
probe, err := ex.Uprobe(goReadSymbol, bpfObjects.GoCryptoTlsReadEx, &link.UprobeOptions{
|
||||
probe, err := ex.Uprobe(goReadSymbol, goCryptoTlsReadEx, &link.UprobeOptions{
|
||||
Offset: offset,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package tlstapper
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"debug/dwarf"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
@@ -13,9 +15,22 @@ import (
|
||||
"github.com/up9inc/mizu/logger"
|
||||
)
|
||||
|
||||
type goAbi int
|
||||
|
||||
const (
|
||||
ABI0 goAbi = iota
|
||||
ABIInternal
|
||||
)
|
||||
|
||||
const PtrSize int = 8
|
||||
|
||||
type goOffsets struct {
|
||||
GoWriteOffset *goExtendedOffset
|
||||
GoReadOffset *goExtendedOffset
|
||||
GoVersion string
|
||||
Abi goAbi
|
||||
GoidOffset uint64
|
||||
GStructOffset uint64
|
||||
}
|
||||
|
||||
type goExtendedOffset struct {
|
||||
@@ -24,30 +39,33 @@ type goExtendedOffset struct {
|
||||
}
|
||||
|
||||
const (
|
||||
minimumSupportedGoVersion = "1.17.0"
|
||||
goVersionSymbol = "runtime.buildVersion.str"
|
||||
goWriteSymbol = "crypto/tls.(*Conn).Write"
|
||||
goReadSymbol = "crypto/tls.(*Conn).Read"
|
||||
minimumABIInternalGoVersion = "1.17.0"
|
||||
goVersionSymbol = "runtime.buildVersion.str" // symbol does not exist in Go (<=1.16)
|
||||
goWriteSymbol = "crypto/tls.(*Conn).Write"
|
||||
goReadSymbol = "crypto/tls.(*Conn).Read"
|
||||
)
|
||||
|
||||
func findGoOffsets(filePath string) (goOffsets, error) {
|
||||
offsets, err := getOffsets(filePath)
|
||||
offsets, goidOffset, gStructOffset, err := getOffsets(filePath)
|
||||
if err != nil {
|
||||
return goOffsets{}, err
|
||||
}
|
||||
|
||||
abi := ABI0
|
||||
var passed bool
|
||||
var goVersion string
|
||||
|
||||
goVersionOffset, err := getOffset(offsets, goVersionSymbol)
|
||||
if err != nil {
|
||||
return goOffsets{}, err
|
||||
if err == nil {
|
||||
// TODO: Replace this logic with https://pkg.go.dev/debug/buildinfo#ReadFile once we upgrade to 1.18
|
||||
passed, goVersion, err = checkGoVersion(filePath, goVersionOffset)
|
||||
if err != nil {
|
||||
return goOffsets{}, fmt.Errorf("Checking Go version: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
passed, goVersion, err := checkGoVersion(filePath, goVersionOffset)
|
||||
if err != nil {
|
||||
return goOffsets{}, fmt.Errorf("Checking Go version: %s", err)
|
||||
}
|
||||
|
||||
if !passed {
|
||||
return goOffsets{}, fmt.Errorf("Unsupported Go version: %s", goVersion)
|
||||
if passed {
|
||||
abi = ABIInternal
|
||||
}
|
||||
|
||||
writeOffset, err := getOffset(offsets, goWriteSymbol)
|
||||
@@ -63,10 +81,139 @@ func findGoOffsets(filePath string) (goOffsets, error) {
|
||||
return goOffsets{
|
||||
GoWriteOffset: writeOffset,
|
||||
GoReadOffset: readOffset,
|
||||
GoVersion: goVersion,
|
||||
Abi: abi,
|
||||
GoidOffset: goidOffset,
|
||||
GStructOffset: gStructOffset,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, err error) {
|
||||
func getSymbol(exe *elf.File, name string) *elf.Symbol {
|
||||
symbols, err := exe.Symbols()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, symbol := range symbols {
|
||||
if symbol.Name == name {
|
||||
s := symbol
|
||||
return &s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getGStructOffset(exe *elf.File) (gStructOffset uint64, err error) {
|
||||
// This is a bit arcane. Essentially:
|
||||
// - If the program is pure Go, it can do whatever it wants, and puts the G
|
||||
// pointer at %fs-8 on 64 bit.
|
||||
// - %Gs is the index of private storage in GDT on 32 bit, and puts the G
|
||||
// pointer at -4(tls).
|
||||
// - Otherwise, Go asks the external linker to place the G pointer by
|
||||
// emitting runtime.tlsg, a TLS symbol, which is relocated to the chosen
|
||||
// offset in libc's TLS block.
|
||||
// - On ARM64 (but really, any architecture other than i386 and 86x64) the
|
||||
// offset is calculate using runtime.tls_g and the formula is different.
|
||||
|
||||
var tls *elf.Prog
|
||||
for _, prog := range exe.Progs {
|
||||
if prog.Type == elf.PT_TLS {
|
||||
tls = prog
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
switch exe.Machine {
|
||||
case elf.EM_X86_64, elf.EM_386:
|
||||
tlsg := getSymbol(exe, "runtime.tlsg")
|
||||
if tlsg == nil || tls == nil {
|
||||
gStructOffset = ^uint64(PtrSize) + 1 //-ptrSize
|
||||
return
|
||||
}
|
||||
|
||||
// According to https://reviews.llvm.org/D61824, linkers must pad the actual
|
||||
// size of the TLS segment to ensure that (tlsoffset%align) == (vaddr%align).
|
||||
// This formula, copied from the lld code, matches that.
|
||||
// https://github.com/llvm-mirror/lld/blob/9aef969544981d76bea8e4d1961d3a6980980ef9/ELF/InputSection.cpp#L643
|
||||
memsz := tls.Memsz + (-tls.Vaddr-tls.Memsz)&(tls.Align-1)
|
||||
|
||||
// The TLS register points to the end of the TLS block, which is
|
||||
// tls.Memsz long. runtime.tlsg is an offset from the beginning of that block.
|
||||
gStructOffset = ^(memsz) + 1 + tlsg.Value // -tls.Memsz + tlsg.Value
|
||||
|
||||
case elf.EM_AARCH64:
|
||||
tlsg := getSymbol(exe, "runtime.tls_g")
|
||||
if tlsg == nil || tls == nil {
|
||||
gStructOffset = 2 * uint64(PtrSize)
|
||||
return
|
||||
}
|
||||
|
||||
gStructOffset = tlsg.Value + uint64(PtrSize*2) + ((tls.Vaddr - uint64(PtrSize*2)) & (tls.Align - 1))
|
||||
|
||||
default:
|
||||
// we should never get here
|
||||
err = fmt.Errorf("architecture not supported")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getGoidOffset(elfFile *elf.File) (goidOffset uint64, gStructOffset uint64, err error) {
|
||||
var dwarfData *dwarf.Data
|
||||
dwarfData, err = elfFile.DWARF()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
entryReader := dwarfData.Reader()
|
||||
|
||||
var runtimeGOffset uint64
|
||||
var seenRuntimeG bool
|
||||
|
||||
for {
|
||||
// Read all entries in sequence
|
||||
var entry *dwarf.Entry
|
||||
entry, err = entryReader.Next()
|
||||
if err == io.EOF || entry == nil {
|
||||
// We've reached the end of DWARF entries
|
||||
break
|
||||
}
|
||||
|
||||
// Check if this entry is a struct
|
||||
if entry.Tag == dwarf.TagStructType {
|
||||
// Go through fields
|
||||
for _, field := range entry.Field {
|
||||
if field.Attr == dwarf.AttrName {
|
||||
val := field.Val.(string)
|
||||
if val == "runtime.g" {
|
||||
runtimeGOffset = uint64(entry.Offset)
|
||||
seenRuntimeG = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this entry is a struct member
|
||||
if seenRuntimeG && entry.Tag == dwarf.TagMember {
|
||||
// Go through fields
|
||||
for _, field := range entry.Field {
|
||||
if field.Attr == dwarf.AttrName {
|
||||
val := field.Val.(string)
|
||||
if val == "goid" {
|
||||
goidOffset = uint64(entry.Offset) - runtimeGOffset - 0x4b
|
||||
gStructOffset, err = getGStructOffset(elfFile)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = fmt.Errorf("goid not found in DWARF")
|
||||
return
|
||||
}
|
||||
|
||||
func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, goidOffset uint64, gStructOffset uint64, err error) {
|
||||
var engine gapstone.Engine
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
@@ -104,13 +251,13 @@ func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, err erro
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
var se *elf.File
|
||||
se, err = elf.NewFile(fd)
|
||||
var elfFile *elf.File
|
||||
elfFile, err = elf.NewFile(fd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
textSection := se.Section(".text")
|
||||
textSection := elfFile.Section(".text")
|
||||
if textSection == nil {
|
||||
err = fmt.Errorf("No text section")
|
||||
return
|
||||
@@ -124,7 +271,7 @@ func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, err erro
|
||||
}
|
||||
|
||||
var syms []elf.Symbol
|
||||
syms, err = se.Symbols()
|
||||
syms, err = elfFile.Symbols()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -132,7 +279,7 @@ func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, err erro
|
||||
offset := sym.Value
|
||||
|
||||
var lastProg *elf.Prog
|
||||
for _, prog := range se.Progs {
|
||||
for _, prog := range elfFile.Progs {
|
||||
if prog.Vaddr <= sym.Value && sym.Value < (prog.Vaddr+prog.Memsz) {
|
||||
offset = sym.Value - prog.Vaddr + prog.Off
|
||||
lastProg = prog
|
||||
@@ -189,6 +336,8 @@ func getOffsets(filePath string) (offsets map[string]*goExtendedOffset, err erro
|
||||
offsets[sym.Name] = extendedOffset
|
||||
}
|
||||
|
||||
goidOffset, gStructOffset, err = getGoidOffset(elfFile)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -229,7 +378,7 @@ func checkGoVersion(filePath string, offset *goExtendedOffset) (bool, string, er
|
||||
return false, goVersionStr, err
|
||||
}
|
||||
|
||||
goVersionConstraint, err := semver.NewConstraint(fmt.Sprintf(">= %s", minimumSupportedGoVersion))
|
||||
goVersionConstraint, err := semver.NewConstraint(fmt.Sprintf(">= %s", minimumABIInternalGoVersion))
|
||||
if err != nil {
|
||||
return false, goVersionStr, err
|
||||
}
|
||||
|
||||
@@ -17,37 +17,37 @@ type syscallHooks struct {
|
||||
func (s *syscallHooks) installSyscallHooks(bpfObjects *tlsTapperObjects) error {
|
||||
var err error
|
||||
|
||||
s.sysEnterRead, err = link.Tracepoint("syscalls", "sys_enter_read", bpfObjects.SysEnterRead)
|
||||
s.sysEnterRead, err = link.Tracepoint("syscalls", "sys_enter_read", bpfObjects.SysEnterRead, nil)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
|
||||
s.sysEnterWrite, err = link.Tracepoint("syscalls", "sys_enter_write", bpfObjects.SysEnterWrite)
|
||||
s.sysEnterWrite, err = link.Tracepoint("syscalls", "sys_enter_write", bpfObjects.SysEnterWrite, nil)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
|
||||
s.sysEnterAccept4, err = link.Tracepoint("syscalls", "sys_enter_accept4", bpfObjects.SysEnterAccept4)
|
||||
s.sysEnterAccept4, err = link.Tracepoint("syscalls", "sys_enter_accept4", bpfObjects.SysEnterAccept4, nil)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
|
||||
s.sysExitAccept4, err = link.Tracepoint("syscalls", "sys_exit_accept4", bpfObjects.SysExitAccept4)
|
||||
s.sysExitAccept4, err = link.Tracepoint("syscalls", "sys_exit_accept4", bpfObjects.SysExitAccept4, nil)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
|
||||
s.sysEnterConnect, err = link.Tracepoint("syscalls", "sys_enter_connect", bpfObjects.SysEnterConnect)
|
||||
s.sysEnterConnect, err = link.Tracepoint("syscalls", "sys_enter_connect", bpfObjects.SysEnterConnect, nil)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
|
||||
s.sysExitConnect, err = link.Tracepoint("syscalls", "sys_exit_connect", bpfObjects.SysExitConnect)
|
||||
s.sysExitConnect, err = link.Tracepoint("syscalls", "sys_exit_connect", bpfObjects.SysExitConnect, nil)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
|
||||
@@ -6,13 +6,18 @@ import (
|
||||
|
||||
"github.com/cilium/ebpf/rlimit"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/moby/moby/pkg/parsers/kernel"
|
||||
"github.com/up9inc/mizu/logger"
|
||||
"github.com/up9inc/mizu/tap/api"
|
||||
)
|
||||
|
||||
const GlobalTapPid = 0
|
||||
|
||||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go@0d0727ef53e2f53b1731c73f4c61e0f58693083a -target $BPF_TARGET -cflags $BPF_CFLAGS -type tls_chunk tlsTapper bpf/tls_tapper.c
|
||||
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we build object files per kernel version.
|
||||
|
||||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go@v0.9.0 -target $BPF_TARGET -cflags $BPF_CFLAGS -type tls_chunk -type goid_offsets tlsTapper bpf/tls_tapper.c
|
||||
|
||||
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go@v0.9.0 -target $BPF_TARGET -cflags "${BPF_CFLAGS} -DKERNEL_BEFORE_4_6" -type tls_chunk -type goid_offsets tlsTapper46 bpf/tls_tapper.c
|
||||
|
||||
type TlsTapper struct {
|
||||
bpfObjects tlsTapperObjects
|
||||
@@ -27,13 +32,30 @@ type TlsTapper struct {
|
||||
func (t *TlsTapper) Init(chunksBufferSize int, logBufferSize int, procfs string, extension *api.Extension) error {
|
||||
logger.Log.Infof("Initializing tls tapper (chunksSize: %d) (logSize: %d)", chunksBufferSize, logBufferSize)
|
||||
|
||||
if err := setupRLimit(); err != nil {
|
||||
var err error
|
||||
err = setupRLimit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var kernelVersion *kernel.VersionInfo
|
||||
kernelVersion, err = kernel.GetKernelVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Log.Infof("Detected Linux kernel version: %s", kernelVersion)
|
||||
|
||||
t.bpfObjects = tlsTapperObjects{}
|
||||
if err := loadTlsTapperObjects(&t.bpfObjects, nil); err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we load object files according to kernel version.
|
||||
if kernel.CompareKernelVersion(*kernelVersion, kernel.VersionInfo{Kernel: 4, Major: 6, Minor: 0}) < 1 {
|
||||
if err := loadTlsTapper46Objects(&t.bpfObjects, nil); err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
} else {
|
||||
if err := loadTlsTapperObjects(&t.bpfObjects, nil); err != nil {
|
||||
return errors.Wrap(err, 0)
|
||||
}
|
||||
}
|
||||
|
||||
t.syscallHooks = syscallHooks{}
|
||||
@@ -48,7 +70,6 @@ func (t *TlsTapper) Init(chunksBufferSize int, logBufferSize int, procfs string,
|
||||
return err
|
||||
}
|
||||
|
||||
var err error
|
||||
t.poller, err = newTlsPoller(t, extension, procfs)
|
||||
|
||||
if err != nil {
|
||||
|
||||
232
tap/tlstapper/tlstapper46_bpfel_arm64.go
Normal file
232
tap/tlstapper/tlstapper46_bpfel_arm64.go
Normal file
@@ -0,0 +1,232 @@
|
||||
// Code generated by bpf2go; DO NOT EDIT.
|
||||
//go:build arm64
|
||||
// +build arm64
|
||||
|
||||
package tlstapper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type tlsTapper46GoidOffsets struct {
|
||||
G_addrOffset uint64
|
||||
GoidOffset uint64
|
||||
}
|
||||
|
||||
type tlsTapper46TlsChunk struct {
|
||||
Pid uint32
|
||||
Tgid uint32
|
||||
Len uint32
|
||||
Start uint32
|
||||
Recorded uint32
|
||||
Fd uint32
|
||||
Flags uint32
|
||||
Address [16]uint8
|
||||
Data [4096]uint8
|
||||
}
|
||||
|
||||
// loadTlsTapper46 returns the embedded CollectionSpec for tlsTapper46.
|
||||
func loadTlsTapper46() (*ebpf.CollectionSpec, error) {
|
||||
reader := bytes.NewReader(_TlsTapper46Bytes)
|
||||
spec, err := ebpf.LoadCollectionSpecFromReader(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't load tlsTapper46: %w", err)
|
||||
}
|
||||
|
||||
return spec, err
|
||||
}
|
||||
|
||||
// loadTlsTapper46Objects loads tlsTapper46 and converts it into a struct.
|
||||
//
|
||||
// The following types are suitable as obj argument:
|
||||
//
|
||||
// *tlsTapper46Objects
|
||||
// *tlsTapper46Programs
|
||||
// *tlsTapper46Maps
|
||||
//
|
||||
// See ebpf.CollectionSpec.LoadAndAssign documentation for details.
|
||||
func loadTlsTapper46Objects(obj interface{}, opts *ebpf.CollectionOptions) error {
|
||||
spec, err := loadTlsTapper46()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return spec.LoadAndAssign(obj, opts)
|
||||
}
|
||||
|
||||
// tlsTapper46Specs contains maps and programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapper46Specs struct {
|
||||
tlsTapper46ProgramSpecs
|
||||
tlsTapper46MapSpecs
|
||||
}
|
||||
|
||||
// tlsTapper46Specs contains programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapper46ProgramSpecs struct {
|
||||
GoCryptoTlsAbi0Read *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
// tlsTapper46MapSpecs contains maps before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapper46MapSpecs struct {
|
||||
AcceptSyscallContext *ebpf.MapSpec `ebpf:"accept_syscall_context"`
|
||||
ChunksBuffer *ebpf.MapSpec `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.MapSpec `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.MapSpec `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.MapSpec `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.MapSpec `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.MapSpec `ebpf:"heap"`
|
||||
LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.MapSpec `ebpf:"openssl_read_context"`
|
||||
OpensslWriteContext *ebpf.MapSpec `ebpf:"openssl_write_context"`
|
||||
PidsMap *ebpf.MapSpec `ebpf:"pids_map"`
|
||||
}
|
||||
|
||||
// tlsTapper46Objects contains all objects after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadTlsTapper46Objects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapper46Objects struct {
|
||||
tlsTapper46Programs
|
||||
tlsTapper46Maps
|
||||
}
|
||||
|
||||
func (o *tlsTapper46Objects) Close() error {
|
||||
return _TlsTapper46Close(
|
||||
&o.tlsTapper46Programs,
|
||||
&o.tlsTapper46Maps,
|
||||
)
|
||||
}
|
||||
|
||||
// tlsTapper46Maps contains all maps after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadTlsTapper46Objects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapper46Maps struct {
|
||||
AcceptSyscallContext *ebpf.Map `ebpf:"accept_syscall_context"`
|
||||
ChunksBuffer *ebpf.Map `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.Map `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.Map `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.Map `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.Map `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.Map `ebpf:"heap"`
|
||||
LogBuffer *ebpf.Map `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.Map `ebpf:"openssl_read_context"`
|
||||
OpensslWriteContext *ebpf.Map `ebpf:"openssl_write_context"`
|
||||
PidsMap *ebpf.Map `ebpf:"pids_map"`
|
||||
}
|
||||
|
||||
func (m *tlsTapper46Maps) Close() error {
|
||||
return _TlsTapper46Close(
|
||||
m.AcceptSyscallContext,
|
||||
m.ChunksBuffer,
|
||||
m.ConnectSyscallInfo,
|
||||
m.FileDescriptorToIpv4,
|
||||
m.GoReadContext,
|
||||
m.GoWriteContext,
|
||||
m.GoidOffsetsMap,
|
||||
m.Heap,
|
||||
m.LogBuffer,
|
||||
m.OpensslReadContext,
|
||||
m.OpensslWriteContext,
|
||||
m.PidsMap,
|
||||
)
|
||||
}
|
||||
|
||||
// tlsTapper46Programs contains all programs after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadTlsTapper46Objects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapper46Programs struct {
|
||||
GoCryptoTlsAbi0Read *ebpf.Program `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.Program `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.Program `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
func (p *tlsTapper46Programs) Close() error {
|
||||
return _TlsTapper46Close(
|
||||
p.GoCryptoTlsAbi0Read,
|
||||
p.GoCryptoTlsAbi0ReadEx,
|
||||
p.GoCryptoTlsAbi0Write,
|
||||
p.GoCryptoTlsAbi0WriteEx,
|
||||
p.GoCryptoTlsAbiInternalRead,
|
||||
p.GoCryptoTlsAbiInternalReadEx,
|
||||
p.GoCryptoTlsAbiInternalWrite,
|
||||
p.GoCryptoTlsAbiInternalWriteEx,
|
||||
p.SslRead,
|
||||
p.SslReadEx,
|
||||
p.SslRetRead,
|
||||
p.SslRetReadEx,
|
||||
p.SslRetWrite,
|
||||
p.SslRetWriteEx,
|
||||
p.SslWrite,
|
||||
p.SslWriteEx,
|
||||
p.SysEnterAccept4,
|
||||
p.SysEnterConnect,
|
||||
p.SysEnterRead,
|
||||
p.SysEnterWrite,
|
||||
p.SysExitAccept4,
|
||||
p.SysExitConnect,
|
||||
)
|
||||
}
|
||||
|
||||
func _TlsTapper46Close(closers ...io.Closer) error {
|
||||
for _, closer := range closers {
|
||||
if err := closer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do not access this directly.
|
||||
//go:embed tlstapper46_bpfel_arm64.o
|
||||
var _TlsTapper46Bytes []byte
|
||||
BIN
tap/tlstapper/tlstapper46_bpfel_arm64.o
Normal file
BIN
tap/tlstapper/tlstapper46_bpfel_arm64.o
Normal file
Binary file not shown.
232
tap/tlstapper/tlstapper46_bpfel_x86.go
Normal file
232
tap/tlstapper/tlstapper46_bpfel_x86.go
Normal file
@@ -0,0 +1,232 @@
|
||||
// Code generated by bpf2go; DO NOT EDIT.
|
||||
//go:build 386 || amd64
|
||||
// +build 386 amd64
|
||||
|
||||
package tlstapper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type tlsTapper46GoidOffsets struct {
|
||||
G_addrOffset uint64
|
||||
GoidOffset uint64
|
||||
}
|
||||
|
||||
type tlsTapper46TlsChunk struct {
|
||||
Pid uint32
|
||||
Tgid uint32
|
||||
Len uint32
|
||||
Start uint32
|
||||
Recorded uint32
|
||||
Fd uint32
|
||||
Flags uint32
|
||||
Address [16]uint8
|
||||
Data [4096]uint8
|
||||
}
|
||||
|
||||
// loadTlsTapper46 returns the embedded CollectionSpec for tlsTapper46.
|
||||
func loadTlsTapper46() (*ebpf.CollectionSpec, error) {
|
||||
reader := bytes.NewReader(_TlsTapper46Bytes)
|
||||
spec, err := ebpf.LoadCollectionSpecFromReader(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't load tlsTapper46: %w", err)
|
||||
}
|
||||
|
||||
return spec, err
|
||||
}
|
||||
|
||||
// loadTlsTapper46Objects loads tlsTapper46 and converts it into a struct.
|
||||
//
|
||||
// The following types are suitable as obj argument:
|
||||
//
|
||||
// *tlsTapper46Objects
|
||||
// *tlsTapper46Programs
|
||||
// *tlsTapper46Maps
|
||||
//
|
||||
// See ebpf.CollectionSpec.LoadAndAssign documentation for details.
|
||||
func loadTlsTapper46Objects(obj interface{}, opts *ebpf.CollectionOptions) error {
|
||||
spec, err := loadTlsTapper46()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return spec.LoadAndAssign(obj, opts)
|
||||
}
|
||||
|
||||
// tlsTapper46Specs contains maps and programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapper46Specs struct {
|
||||
tlsTapper46ProgramSpecs
|
||||
tlsTapper46MapSpecs
|
||||
}
|
||||
|
||||
// tlsTapper46Specs contains programs before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapper46ProgramSpecs struct {
|
||||
GoCryptoTlsAbi0Read *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
// tlsTapper46MapSpecs contains maps before they are loaded into the kernel.
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapper46MapSpecs struct {
|
||||
AcceptSyscallContext *ebpf.MapSpec `ebpf:"accept_syscall_context"`
|
||||
ChunksBuffer *ebpf.MapSpec `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.MapSpec `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.MapSpec `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.MapSpec `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.MapSpec `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.MapSpec `ebpf:"heap"`
|
||||
LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.MapSpec `ebpf:"openssl_read_context"`
|
||||
OpensslWriteContext *ebpf.MapSpec `ebpf:"openssl_write_context"`
|
||||
PidsMap *ebpf.MapSpec `ebpf:"pids_map"`
|
||||
}
|
||||
|
||||
// tlsTapper46Objects contains all objects after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadTlsTapper46Objects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapper46Objects struct {
|
||||
tlsTapper46Programs
|
||||
tlsTapper46Maps
|
||||
}
|
||||
|
||||
func (o *tlsTapper46Objects) Close() error {
|
||||
return _TlsTapper46Close(
|
||||
&o.tlsTapper46Programs,
|
||||
&o.tlsTapper46Maps,
|
||||
)
|
||||
}
|
||||
|
||||
// tlsTapper46Maps contains all maps after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadTlsTapper46Objects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapper46Maps struct {
|
||||
AcceptSyscallContext *ebpf.Map `ebpf:"accept_syscall_context"`
|
||||
ChunksBuffer *ebpf.Map `ebpf:"chunks_buffer"`
|
||||
ConnectSyscallInfo *ebpf.Map `ebpf:"connect_syscall_info"`
|
||||
FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.Map `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.Map `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.Map `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.Map `ebpf:"heap"`
|
||||
LogBuffer *ebpf.Map `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.Map `ebpf:"openssl_read_context"`
|
||||
OpensslWriteContext *ebpf.Map `ebpf:"openssl_write_context"`
|
||||
PidsMap *ebpf.Map `ebpf:"pids_map"`
|
||||
}
|
||||
|
||||
func (m *tlsTapper46Maps) Close() error {
|
||||
return _TlsTapper46Close(
|
||||
m.AcceptSyscallContext,
|
||||
m.ChunksBuffer,
|
||||
m.ConnectSyscallInfo,
|
||||
m.FileDescriptorToIpv4,
|
||||
m.GoReadContext,
|
||||
m.GoWriteContext,
|
||||
m.GoidOffsetsMap,
|
||||
m.Heap,
|
||||
m.LogBuffer,
|
||||
m.OpensslReadContext,
|
||||
m.OpensslWriteContext,
|
||||
m.PidsMap,
|
||||
)
|
||||
}
|
||||
|
||||
// tlsTapper46Programs contains all programs after they have been loaded into the kernel.
|
||||
//
|
||||
// It can be passed to loadTlsTapper46Objects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapper46Programs struct {
|
||||
GoCryptoTlsAbi0Read *ebpf.Program `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.Program `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.Program `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
func (p *tlsTapper46Programs) Close() error {
|
||||
return _TlsTapper46Close(
|
||||
p.GoCryptoTlsAbi0Read,
|
||||
p.GoCryptoTlsAbi0ReadEx,
|
||||
p.GoCryptoTlsAbi0Write,
|
||||
p.GoCryptoTlsAbi0WriteEx,
|
||||
p.GoCryptoTlsAbiInternalRead,
|
||||
p.GoCryptoTlsAbiInternalReadEx,
|
||||
p.GoCryptoTlsAbiInternalWrite,
|
||||
p.GoCryptoTlsAbiInternalWriteEx,
|
||||
p.SslRead,
|
||||
p.SslReadEx,
|
||||
p.SslRetRead,
|
||||
p.SslRetReadEx,
|
||||
p.SslRetWrite,
|
||||
p.SslRetWriteEx,
|
||||
p.SslWrite,
|
||||
p.SslWriteEx,
|
||||
p.SysEnterAccept4,
|
||||
p.SysEnterConnect,
|
||||
p.SysEnterRead,
|
||||
p.SysEnterWrite,
|
||||
p.SysExitAccept4,
|
||||
p.SysExitConnect,
|
||||
)
|
||||
}
|
||||
|
||||
func _TlsTapper46Close(closers ...io.Closer) error {
|
||||
for _, closer := range closers {
|
||||
if err := closer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do not access this directly.
|
||||
//go:embed tlstapper46_bpfel_x86.o
|
||||
var _TlsTapper46Bytes []byte
|
||||
BIN
tap/tlstapper/tlstapper46_bpfel_x86.o
Normal file
BIN
tap/tlstapper/tlstapper46_bpfel_x86.o
Normal file
Binary file not shown.
@@ -13,6 +13,11 @@ import (
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type tlsTapperGoidOffsets struct {
|
||||
G_addrOffset uint64
|
||||
GoidOffset uint64
|
||||
}
|
||||
|
||||
type tlsTapperTlsChunk struct {
|
||||
Pid uint32
|
||||
Tgid uint32
|
||||
@@ -66,24 +71,28 @@ type tlsTapperSpecs struct {
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapperProgramSpecs struct {
|
||||
GoCryptoTlsRead *ebpf.ProgramSpec `ebpf:"go_crypto_tls_read"`
|
||||
GoCryptoTlsReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_read_ex"`
|
||||
GoCryptoTlsWrite *ebpf.ProgramSpec `ebpf:"go_crypto_tls_write"`
|
||||
GoCryptoTlsWriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_write_ex"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
|
||||
GoCryptoTlsAbi0Read *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
// tlsTapperMapSpecs contains maps before they are loaded into the kernel.
|
||||
@@ -96,6 +105,7 @@ type tlsTapperMapSpecs struct {
|
||||
FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.MapSpec `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.MapSpec `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.MapSpec `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.MapSpec `ebpf:"heap"`
|
||||
LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.MapSpec `ebpf:"openssl_read_context"`
|
||||
@@ -128,6 +138,7 @@ type tlsTapperMaps struct {
|
||||
FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.Map `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.Map `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.Map `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.Map `ebpf:"heap"`
|
||||
LogBuffer *ebpf.Map `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.Map `ebpf:"openssl_read_context"`
|
||||
@@ -143,6 +154,7 @@ func (m *tlsTapperMaps) Close() error {
|
||||
m.FileDescriptorToIpv4,
|
||||
m.GoReadContext,
|
||||
m.GoWriteContext,
|
||||
m.GoidOffsetsMap,
|
||||
m.Heap,
|
||||
m.LogBuffer,
|
||||
m.OpensslReadContext,
|
||||
@@ -155,32 +167,40 @@ func (m *tlsTapperMaps) Close() error {
|
||||
//
|
||||
// It can be passed to loadTlsTapperObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapperPrograms struct {
|
||||
GoCryptoTlsRead *ebpf.Program `ebpf:"go_crypto_tls_read"`
|
||||
GoCryptoTlsReadEx *ebpf.Program `ebpf:"go_crypto_tls_read_ex"`
|
||||
GoCryptoTlsWrite *ebpf.Program `ebpf:"go_crypto_tls_write"`
|
||||
GoCryptoTlsWriteEx *ebpf.Program `ebpf:"go_crypto_tls_write_ex"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.Program `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
|
||||
GoCryptoTlsAbi0Read *ebpf.Program `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.Program `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.Program `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
func (p *tlsTapperPrograms) Close() error {
|
||||
return _TlsTapperClose(
|
||||
p.GoCryptoTlsRead,
|
||||
p.GoCryptoTlsReadEx,
|
||||
p.GoCryptoTlsWrite,
|
||||
p.GoCryptoTlsWriteEx,
|
||||
p.GoCryptoTlsAbi0Read,
|
||||
p.GoCryptoTlsAbi0ReadEx,
|
||||
p.GoCryptoTlsAbi0Write,
|
||||
p.GoCryptoTlsAbi0WriteEx,
|
||||
p.GoCryptoTlsAbiInternalRead,
|
||||
p.GoCryptoTlsAbiInternalReadEx,
|
||||
p.GoCryptoTlsAbiInternalWrite,
|
||||
p.GoCryptoTlsAbiInternalWriteEx,
|
||||
p.SslRead,
|
||||
p.SslReadEx,
|
||||
p.SslRetRead,
|
||||
|
||||
Binary file not shown.
@@ -13,6 +13,11 @@ import (
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
type tlsTapperGoidOffsets struct {
|
||||
G_addrOffset uint64
|
||||
GoidOffset uint64
|
||||
}
|
||||
|
||||
type tlsTapperTlsChunk struct {
|
||||
Pid uint32
|
||||
Tgid uint32
|
||||
@@ -66,24 +71,28 @@ type tlsTapperSpecs struct {
|
||||
//
|
||||
// It can be passed ebpf.CollectionSpec.Assign.
|
||||
type tlsTapperProgramSpecs struct {
|
||||
GoCryptoTlsRead *ebpf.ProgramSpec `ebpf:"go_crypto_tls_read"`
|
||||
GoCryptoTlsReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_read_ex"`
|
||||
GoCryptoTlsWrite *ebpf.ProgramSpec `ebpf:"go_crypto_tls_write"`
|
||||
GoCryptoTlsWriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_write_ex"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
|
||||
GoCryptoTlsAbi0Read *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.ProgramSpec `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.ProgramSpec `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.ProgramSpec `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.ProgramSpec `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.ProgramSpec `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.ProgramSpec `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.ProgramSpec `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.ProgramSpec `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.ProgramSpec `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.ProgramSpec `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.ProgramSpec `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.ProgramSpec `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.ProgramSpec `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.ProgramSpec `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.ProgramSpec `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
// tlsTapperMapSpecs contains maps before they are loaded into the kernel.
|
||||
@@ -96,6 +105,7 @@ type tlsTapperMapSpecs struct {
|
||||
FileDescriptorToIpv4 *ebpf.MapSpec `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.MapSpec `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.MapSpec `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.MapSpec `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.MapSpec `ebpf:"heap"`
|
||||
LogBuffer *ebpf.MapSpec `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.MapSpec `ebpf:"openssl_read_context"`
|
||||
@@ -128,6 +138,7 @@ type tlsTapperMaps struct {
|
||||
FileDescriptorToIpv4 *ebpf.Map `ebpf:"file_descriptor_to_ipv4"`
|
||||
GoReadContext *ebpf.Map `ebpf:"go_read_context"`
|
||||
GoWriteContext *ebpf.Map `ebpf:"go_write_context"`
|
||||
GoidOffsetsMap *ebpf.Map `ebpf:"goid_offsets_map"`
|
||||
Heap *ebpf.Map `ebpf:"heap"`
|
||||
LogBuffer *ebpf.Map `ebpf:"log_buffer"`
|
||||
OpensslReadContext *ebpf.Map `ebpf:"openssl_read_context"`
|
||||
@@ -143,6 +154,7 @@ func (m *tlsTapperMaps) Close() error {
|
||||
m.FileDescriptorToIpv4,
|
||||
m.GoReadContext,
|
||||
m.GoWriteContext,
|
||||
m.GoidOffsetsMap,
|
||||
m.Heap,
|
||||
m.LogBuffer,
|
||||
m.OpensslReadContext,
|
||||
@@ -155,32 +167,40 @@ func (m *tlsTapperMaps) Close() error {
|
||||
//
|
||||
// It can be passed to loadTlsTapperObjects or ebpf.CollectionSpec.LoadAndAssign.
|
||||
type tlsTapperPrograms struct {
|
||||
GoCryptoTlsRead *ebpf.Program `ebpf:"go_crypto_tls_read"`
|
||||
GoCryptoTlsReadEx *ebpf.Program `ebpf:"go_crypto_tls_read_ex"`
|
||||
GoCryptoTlsWrite *ebpf.Program `ebpf:"go_crypto_tls_write"`
|
||||
GoCryptoTlsWriteEx *ebpf.Program `ebpf:"go_crypto_tls_write_ex"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.Program `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
|
||||
GoCryptoTlsAbi0Read *ebpf.Program `ebpf:"go_crypto_tls_abi0_read"`
|
||||
GoCryptoTlsAbi0ReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_read_ex"`
|
||||
GoCryptoTlsAbi0Write *ebpf.Program `ebpf:"go_crypto_tls_abi0_write"`
|
||||
GoCryptoTlsAbi0WriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi0_write_ex"`
|
||||
GoCryptoTlsAbiInternalRead *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read"`
|
||||
GoCryptoTlsAbiInternalReadEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_read_ex"`
|
||||
GoCryptoTlsAbiInternalWrite *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write"`
|
||||
GoCryptoTlsAbiInternalWriteEx *ebpf.Program `ebpf:"go_crypto_tls_abi_internal_write_ex"`
|
||||
SslRead *ebpf.Program `ebpf:"ssl_read"`
|
||||
SslReadEx *ebpf.Program `ebpf:"ssl_read_ex"`
|
||||
SslRetRead *ebpf.Program `ebpf:"ssl_ret_read"`
|
||||
SslRetReadEx *ebpf.Program `ebpf:"ssl_ret_read_ex"`
|
||||
SslRetWrite *ebpf.Program `ebpf:"ssl_ret_write"`
|
||||
SslRetWriteEx *ebpf.Program `ebpf:"ssl_ret_write_ex"`
|
||||
SslWrite *ebpf.Program `ebpf:"ssl_write"`
|
||||
SslWriteEx *ebpf.Program `ebpf:"ssl_write_ex"`
|
||||
SysEnterAccept4 *ebpf.Program `ebpf:"sys_enter_accept4"`
|
||||
SysEnterConnect *ebpf.Program `ebpf:"sys_enter_connect"`
|
||||
SysEnterRead *ebpf.Program `ebpf:"sys_enter_read"`
|
||||
SysEnterWrite *ebpf.Program `ebpf:"sys_enter_write"`
|
||||
SysExitAccept4 *ebpf.Program `ebpf:"sys_exit_accept4"`
|
||||
SysExitConnect *ebpf.Program `ebpf:"sys_exit_connect"`
|
||||
}
|
||||
|
||||
func (p *tlsTapperPrograms) Close() error {
|
||||
return _TlsTapperClose(
|
||||
p.GoCryptoTlsRead,
|
||||
p.GoCryptoTlsReadEx,
|
||||
p.GoCryptoTlsWrite,
|
||||
p.GoCryptoTlsWriteEx,
|
||||
p.GoCryptoTlsAbi0Read,
|
||||
p.GoCryptoTlsAbi0ReadEx,
|
||||
p.GoCryptoTlsAbi0Write,
|
||||
p.GoCryptoTlsAbi0WriteEx,
|
||||
p.GoCryptoTlsAbiInternalRead,
|
||||
p.GoCryptoTlsAbiInternalReadEx,
|
||||
p.GoCryptoTlsAbiInternalWrite,
|
||||
p.GoCryptoTlsAbiInternalWriteEx,
|
||||
p.SslRead,
|
||||
p.SslReadEx,
|
||||
p.SslRetRead,
|
||||
|
||||
Binary file not shown.
@@ -12,8 +12,8 @@ import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi/atom";
|
||||
import queryAtom from "../../recoil/query/atom";
|
||||
import useWindowDimensions, { useRequestTextByWidth } from "../../hooks/WindowDimensionsHook";
|
||||
import { TOAST_CONTAINER_ID } from "../../configs/Consts";
|
||||
import spinner from "assets/spinner.svg";
|
||||
import entryDataAtom from "../../recoil/entryData";
|
||||
import { LoadingWrapper } from "../UI/withLoading/withLoading";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
entryTitle: {
|
||||
@@ -135,19 +135,11 @@ export const EntryDetailed = () => {
|
||||
// eslint-disable-next-line
|
||||
}, [focusedEntryId]);
|
||||
|
||||
return <React.Fragment>
|
||||
{isLoading && <div style={{textAlign: "center", width: "100%", marginTop: 50}}><img alt="spinner" src={spinner} style={{height: 60}}/></div>}
|
||||
{!isLoading && entryData && <EntryTitle
|
||||
protocol={entryData.protocol}
|
||||
data={entryData.data}
|
||||
elapsedTime={entryData.data.elapsedTime}
|
||||
/>}
|
||||
{!isLoading && entryData && <EntrySummary entry={entryData.base} namespace={entryData.data.namespace} />}
|
||||
<React.Fragment>
|
||||
{!isLoading && entryData && <EntryViewer
|
||||
representation={entryData.representation}
|
||||
color={entryData.protocol.backgroundColor}
|
||||
/>}
|
||||
</React.Fragment>
|
||||
</React.Fragment>
|
||||
return <LoadingWrapper isLoading={isLoading} loaderMargin={50} loaderHeight={60}>
|
||||
{entryData && <React.Fragment>
|
||||
<EntryTitle protocol={entryData.protocol} data={entryData.data} elapsedTime={entryData.data.elapsedTime} />
|
||||
<EntrySummary entry={entryData.base} namespace={entryData.data.namespace} />
|
||||
<EntryViewer representation={entryData.representation} color={entryData.protocol.backgroundColor} />
|
||||
</React.Fragment>}
|
||||
</LoadingWrapper>
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import CustomModal from "./CustomModal/CustomModal";
|
||||
import { InformationIcon, Link } from "./InformationIcon/InformationIcon";
|
||||
import SelectList from "./SelectList/SelectList";
|
||||
import NoDataMessage from "./NoDataMessage/NoDataMessage";
|
||||
import withLoading from "./withLoading/withLoading";
|
||||
|
||||
export { LoadingOverlay, Select, Tabs, Tooltip, Checkbox, CustomModal, InformationIcon, SelectList, NoDataMessage, Link };
|
||||
export { LoadingOverlay, Select, Tabs, Tooltip, Checkbox, CustomModal, InformationIcon, SelectList, NoDataMessage, withLoading, Link };
|
||||
export { StatusBar }
|
||||
|
||||
6
ui-common/src/components/UI/withLoading/spinner.svg
Normal file
6
ui-common/src/components/UI/withLoading/spinner.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
||||
<circle cx="50" cy="50" fill="none" stroke="#1d3f72" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138" transform="rotate(275.903 50 50)">
|
||||
<animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
|
||||
</circle>
|
||||
<!-- [ldio] generated by https://loading.io/ --></svg>
|
||||
|
After Width: | Height: | Size: 673 B |
33
ui-common/src/components/UI/withLoading/withLoading.tsx
Normal file
33
ui-common/src/components/UI/withLoading/withLoading.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
import spinner from 'spinner.svg';
|
||||
|
||||
export interface WithLoadingProps {
|
||||
isLoading: boolean
|
||||
loaderMargin?: number,
|
||||
loaderHeight?: number
|
||||
}
|
||||
|
||||
const Loader = ({ loaderMargin = 20, loaderHeight = 35 }: Omit<WithLoadingProps, "isLoading">) => {
|
||||
return <div style={{ textAlign: "center", margin: loaderMargin }}>
|
||||
<img alt="spinner" src={spinner} style={{ height: loaderHeight }} />
|
||||
</div>
|
||||
}
|
||||
|
||||
const withLoading = <P extends object>(
|
||||
Component: React.ComponentType<P>
|
||||
): React.FC<P & WithLoadingProps> => ({
|
||||
isLoading,
|
||||
loaderMargin,
|
||||
loaderHeight,
|
||||
...props
|
||||
}: WithLoadingProps) => isLoading ?
|
||||
<Loader loaderMargin={loaderMargin} loaderHeight={loaderHeight} /> :
|
||||
<Component {...props as P} />;
|
||||
|
||||
export const LoadingWrapper: React.FC<WithLoadingProps> = ({ loaderMargin, loaderHeight, isLoading, children }) => {
|
||||
return isLoading ?
|
||||
<Loader loaderMargin={loaderMargin} loaderHeight={loaderHeight} /> :
|
||||
<React.Fragment>{children}</React.Fragment>
|
||||
}
|
||||
|
||||
export default withLoading
|
||||
@@ -12,7 +12,6 @@ import { toast } from "react-toastify";
|
||||
import { TOAST_CONTAINER_ID } from "../../../configs/Consts";
|
||||
import styles from './ReplayRequestModal.module.sass'
|
||||
import closeIcon from "assets/close.svg"
|
||||
import spinnerImg from "assets/spinner.svg"
|
||||
import refreshImg from "assets/refresh.svg"
|
||||
import { formatRequestWithOutError } from "../../EntryDetailed/EntrySections/EntrySections";
|
||||
import entryDataAtom from "../../../recoil/entryData";
|
||||
@@ -20,6 +19,7 @@ import { AutoRepresentation, TabsEnum } from "../../EntryDetailed/EntryViewer/Au
|
||||
import useDebounce from "../../../hooks/useDebounce"
|
||||
import replayRequestModalOpenAtom from "../../../recoil/replayRequestModalOpen";
|
||||
import { Utils } from "../../../helpers/Utils";
|
||||
import { LoadingWrapper } from "../../UI/withLoading/withLoading";
|
||||
|
||||
const modalStyle = {
|
||||
position: 'absolute',
|
||||
@@ -233,15 +233,16 @@ const ReplayRequestModal: React.FC<ReplayRequestModalProps> = ({ isOpen, onClose
|
||||
</div>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
{isLoading && <img alt="spinner" src={spinnerImg} style={{ height: 50 }} />}
|
||||
{response && !isLoading && (<Accordion TransitionProps={{ unmountOnExit: true }} expanded={responseExpanded} onChange={() => setResponseExpanded(!responseExpanded)}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="response-content">
|
||||
<span className={styles.sectionHeader}>RESPONSE</span>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<AutoRepresentation representation={response} color={entryData.protocol.backgroundColor} openedTab={TabsEnum.Response} />
|
||||
</AccordionDetails>
|
||||
</Accordion>)}
|
||||
<LoadingWrapper isLoading={isLoading} loaderMargin={10} loaderHeight={50}>
|
||||
{response && (<Accordion TransitionProps={{ unmountOnExit: true }} expanded={responseExpanded} onChange={() => setResponseExpanded(!responseExpanded)}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls="response-content">
|
||||
<span className={styles.sectionHeader}>RESPONSE</span>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<AutoRepresentation representation={response} color={entryData.protocol.backgroundColor} openedTab={TabsEnum.Response} />
|
||||
</AccordionDetails>
|
||||
</Accordion>)}
|
||||
</LoadingWrapper>
|
||||
</div>
|
||||
</Box>
|
||||
</Fade>
|
||||
|
||||
@@ -96,8 +96,3 @@ $modalMargin-from-edge : 35px
|
||||
|
||||
.servicesFilterList
|
||||
height: calc(100% - 30px - 52px)
|
||||
|
||||
.spinnerContainer
|
||||
display: flex
|
||||
justify-content: center
|
||||
margin-bottom: 10px
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState, useEffect, useCallback, useMemo } from "react";
|
||||
import { Box, Fade, Modal, Backdrop, Button } from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
import spinnerImg from 'assets/spinner.svg';
|
||||
import Graph from "react-graph-vis";
|
||||
import debounce from 'lodash/debounce';
|
||||
import ServiceMapOptions from './ServiceMapOptions'
|
||||
@@ -16,6 +15,7 @@ import { GraphData, ServiceMapGraph } from "./ServiceMapModalTypes"
|
||||
import { Utils } from "../../../helpers/Utils";
|
||||
import { TOAST_CONTAINER_ID } from "../../../configs/Consts";
|
||||
import Resizeable from "../../UI/Resizeable/Resizeable"
|
||||
import { LoadingWrapper } from "../../UI/withLoading/withLoading";
|
||||
|
||||
const modalStyle = {
|
||||
position: 'absolute',
|
||||
@@ -197,14 +197,14 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onClos
|
||||
<Fade in={isOpen}>
|
||||
<Box sx={modalStyle}>
|
||||
<div className={styles.closeIcon}>
|
||||
<img src={closeIcon} alt="close" onClick={() => onClose()} style={{ cursor: "pointer", userSelect: "none" }}/>
|
||||
<img src={closeIcon} alt="close" onClick={() => onClose()} style={{ cursor: "pointer", userSelect: "none" }} />
|
||||
</div>
|
||||
<div className={styles.headerContainer}>
|
||||
<div className={styles.headerSection}>
|
||||
<span className={styles.title}>Services</span>
|
||||
<Button size="medium"
|
||||
variant="contained"
|
||||
startIcon={<img src={isFilterClicked ? filterIconClicked : filterIcon} className="custom" alt="refresh" style={{ height: "26px", width: "26px" }}/>}
|
||||
startIcon={<img src={isFilterClicked ? filterIconClicked : filterIcon} className="custom" alt="refresh" style={{ height: "26px", width: "26px" }} />}
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton + ` ${isFilterClicked ? commonClasses.clickedButton : ""}`}
|
||||
onClick={() => setIsFilterClicked(prevState => !prevState)}
|
||||
style={{ textTransform: 'unset' }}>
|
||||
@@ -243,16 +243,14 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onClos
|
||||
<div className={styles.graphSection}>
|
||||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||
</div>
|
||||
{isLoading && <div className={styles.spinnerContainer}>
|
||||
<img alt="spinner" src={spinnerImg} style={{ height: 50 }} />
|
||||
</div>}
|
||||
{!isLoading && <div style={{ height: "100%", width: "100%" }}>
|
||||
<Graph
|
||||
graph={graphData}
|
||||
options={graphOptions}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
<LoadingWrapper isLoading={isLoading} loaderHeight={50} loaderMargin={20}>
|
||||
<div style={{ height: "100%", width: "100%" }}>
|
||||
<Graph
|
||||
graph={graphData}
|
||||
options={graphOptions}
|
||||
/>
|
||||
</div>
|
||||
</LoadingWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
@@ -19,21 +19,21 @@ interface TimelineBarChartProps {
|
||||
export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarChartMode, data, selectedProtocol }) => {
|
||||
const [protocolStats, setProtocolStats] = useState([]);
|
||||
const [protocolsNamesAndColors, setProtocolsNamesAndColors] = useState([]);
|
||||
const [commandStats, setCommandStats] = useState(null);
|
||||
const [commandNames, setcommandNames] = useState(null);
|
||||
|
||||
const [methodsStats, setMethodsStats] = useState(null);
|
||||
const [methodsNamesAndColors, setMethodsNamesAndColors] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return;
|
||||
const protocolsBarsData = [];
|
||||
const prtcNames = [];
|
||||
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
||||
let newProtocolbj: { [k: string]: any } = {};
|
||||
newProtocolbj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
let newProtocolObj: { [k: string]: any } = {};
|
||||
newProtocolObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
protocolObj.protocols.forEach(protocol => {
|
||||
newProtocolbj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]];
|
||||
newProtocolObj[`${protocol.name}`] = protocol[StatsMode[timeLineBarChartMode]];
|
||||
prtcNames.push({ name: protocol.name, color: protocol.color });
|
||||
})
|
||||
protocolsBarsData.push(newProtocolbj);
|
||||
protocolsBarsData.push(newProtocolObj);
|
||||
})
|
||||
const uniqueObjArray = Utils.creatUniqueObjArrayByProp(prtcNames, "name")
|
||||
setProtocolStats(protocolsBarsData);
|
||||
@@ -42,49 +42,52 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProtocol === ALL_PROTOCOLS) {
|
||||
setCommandStats(null);
|
||||
setcommandNames(null);
|
||||
setMethodsStats(null);
|
||||
setMethodsNamesAndColors(null);
|
||||
return;
|
||||
}
|
||||
const commandsNames = [];
|
||||
const protocolsCommands = [];
|
||||
const protocolsMethodsNamesAndColors = [];
|
||||
const protocolsMethods = [];
|
||||
data.sort((a, b) => a.timestamp < b.timestamp ? -1 : 1).forEach(protocolObj => {
|
||||
let newCommandlbj: { [k: string]: any } = {};
|
||||
newCommandlbj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(command => {
|
||||
newCommandlbj[`${command.name}`] = command[StatsMode[timeLineBarChartMode]]
|
||||
if (commandsNames.indexOf(command.name) === -1)
|
||||
commandsNames.push(command.name);
|
||||
let newMethodObj: { [k: string]: any } = {};
|
||||
newMethodObj.timestamp = Utils.getHoursAndMinutes(protocolObj.timestamp);
|
||||
protocolObj.protocols.find(protocol => protocol.name === selectedProtocol)?.methods.forEach(method => {
|
||||
newMethodObj[`${method.name}`] = method[StatsMode[timeLineBarChartMode]]
|
||||
protocolsMethodsNamesAndColors.push({name: method.name, color: method.color});
|
||||
})
|
||||
protocolsCommands.push(newCommandlbj);
|
||||
protocolsMethods.push(newMethodObj);
|
||||
})
|
||||
setcommandNames(commandsNames);
|
||||
setCommandStats(protocolsCommands);
|
||||
const uniqueObjArray = Utils.creatUniqueObjArrayByProp(protocolsMethodsNamesAndColors, "name")
|
||||
setMethodsNamesAndColors(uniqueObjArray);
|
||||
setMethodsStats(protocolsMethods);
|
||||
}, [data, timeLineBarChartMode, selectedProtocol])
|
||||
|
||||
const bars = useMemo(() => (commandNames || protocolsNamesAndColors).map((entry) => {
|
||||
return <Bar key={entry.name || entry} dataKey={entry.name || entry} stackId="a" fill={entry.color || Utils.stringToColor(entry)} barSize={30} />
|
||||
}), [protocolsNamesAndColors, commandNames])
|
||||
const bars = useMemo(() => (methodsNamesAndColors || protocolsNamesAndColors).map((entry) => {
|
||||
return <Bar key={entry.name} dataKey={entry.name} stackId="a" fill={entry.color} />
|
||||
}), [protocolsNamesAndColors, methodsNamesAndColors])
|
||||
|
||||
const renderTick = (tickProps) => {
|
||||
const { x, y, payload } = tickProps;
|
||||
const { index, value } = payload;
|
||||
|
||||
if (index % 3 === 0) {
|
||||
if (protocolStats.length > 5) {
|
||||
if (index % 3 === 0) {
|
||||
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return <text x={x} y={y + 10} textAnchor="end">{`${value}`}</text>;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.barChartContainer}>
|
||||
{protocolStats.length > 0 && <BarChart
|
||||
width={750}
|
||||
height={250}
|
||||
data={commandStats || protocolStats}
|
||||
barCategoryGap={0}
|
||||
barSize={30}
|
||||
data={methodsStats || protocolStats}
|
||||
barCategoryGap={1}
|
||||
margin={{
|
||||
top: 20,
|
||||
right: 30,
|
||||
@@ -92,8 +95,8 @@ export const TimelineBarChart: React.FC<TimelineBarChartProps> = ({ timeLineBarC
|
||||
bottom: 5
|
||||
}}
|
||||
>
|
||||
<XAxis dataKey="timestamp" tick={renderTick} tickLine={false} />
|
||||
<YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} />
|
||||
<XAxis dataKey="timestamp" tick={renderTick} tickLine={false} interval="preserveStart" />
|
||||
<YAxis tickFormatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value} interval="preserveEnd"/>
|
||||
<Tooltip formatter={(value) => timeLineBarChartMode === "VOLUME" ? Utils.humanFileSize(value) : value + " Requests"} />
|
||||
{bars}
|
||||
</BarChart>}
|
||||
|
||||
@@ -41,7 +41,7 @@ interface TrafficPieChartProps {
|
||||
export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode, data, selectedProtocol }) => {
|
||||
|
||||
const [protocolsStats, setProtocolsStats] = useState([]);
|
||||
const [commandStats, setCommandStats] = useState(null);
|
||||
const [methodsStats, setMethodsStats] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return;
|
||||
@@ -57,16 +57,17 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProtocol === ALL_PROTOCOLS) {
|
||||
setCommandStats(null);
|
||||
setMethodsStats(null);
|
||||
return;
|
||||
}
|
||||
const commandsPieData = data.find(protocol => protocol.name === selectedProtocol)?.methods.map(command => {
|
||||
const methodsPieData = data.find(protocol => protocol.name === selectedProtocol)?.methods.map(method => {
|
||||
return {
|
||||
name: command.name,
|
||||
value: command[PieChartMode[pieChartMode]]
|
||||
name: method.name,
|
||||
value: method[PieChartMode[pieChartMode]],
|
||||
color: method.color
|
||||
}
|
||||
})
|
||||
setCommandStats(commandsPieData);
|
||||
setMethodsStats(methodsPieData);
|
||||
}, [selectedProtocol, pieChartMode, data])
|
||||
|
||||
const pieLegend = useMemo(() => {
|
||||
@@ -82,7 +83,7 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
} else {
|
||||
legend = data.find(protocol => protocol.name === selectedProtocol)?.methods.map((method) => <div
|
||||
style={{ marginBottom: 5, display: "flex" }}>
|
||||
<div style={{ height: 15, width: 30, background: Utils.stringToColor(method.name)}} />
|
||||
<div style={{ height: 15, width: 30, background: method.color}} />
|
||||
<span style={{ marginLeft: 5 }}>
|
||||
{method.name}
|
||||
</span>
|
||||
@@ -96,7 +97,7 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
{protocolsStats?.length > 0 && <div style={{ width: "100%", display: "flex", justifyContent: "center" }}>
|
||||
<PieChart width={300} height={300}>
|
||||
<Pie
|
||||
data={commandStats || protocolsStats}
|
||||
data={methodsStats || protocolsStats}
|
||||
dataKey="value"
|
||||
cx={150}
|
||||
cy={125}
|
||||
@@ -104,8 +105,8 @@ export const TrafficPieChart: React.FC<TrafficPieChartProps> = ({ pieChartMode,
|
||||
label={renderCustomizedLabel}
|
||||
outerRadius={125}
|
||||
fill="#8884d8">
|
||||
{(commandStats || protocolsStats).map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={entry.color || Utils.stringToColor(entry.name)} />)
|
||||
{(methodsStats || protocolsStats).map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={entry.color} />)
|
||||
)}
|
||||
</Pie>
|
||||
<Legend wrapperStyle={{ position: "absolute", width: "auto", height: "auto", right: -150, top: 0 }} content={pieLegend} />
|
||||
|
||||
@@ -4,9 +4,9 @@ import styles from "./TrafficStatsModal.module.sass";
|
||||
import closeIcon from "assets/close.svg";
|
||||
import { TrafficPieChart } from "./TrafficPieChart/TrafficPieChart";
|
||||
import { TimelineBarChart } from "./TimelineBarChart/TimelineBarChart";
|
||||
import spinnerImg from "assets/spinner.svg";
|
||||
import refreshIcon from "assets/refresh.svg";
|
||||
import { useCommonStyles } from "../../../helpers/commonStyle";
|
||||
import { LoadingWrapper } from "../../UI/withLoading/withLoading";
|
||||
|
||||
const modalStyle = {
|
||||
position: 'absolute',
|
||||
@@ -33,9 +33,7 @@ interface TrafficStatsModalProps {
|
||||
getTrafficStatsDataApi: () => Promise<any>
|
||||
}
|
||||
|
||||
|
||||
export const PROTOCOLS = ["ALL", "gRPC", "REDIS", "HTTP", "GQL", "AMQP", "KAFKA"];
|
||||
export const ALL_PROTOCOLS = PROTOCOLS[0];
|
||||
export const ALL_PROTOCOLS = "ALL";
|
||||
|
||||
export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, onClose, getTrafficStatsDataApi }) => {
|
||||
|
||||
@@ -44,6 +42,7 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
|
||||
const [selectedProtocol, setSelectedProtocol] = useState(ALL_PROTOCOLS);
|
||||
const [pieStatsData, setPieStatsData] = useState(null);
|
||||
const [timelineStatsData, setTimelineStatsData] = useState(null);
|
||||
const [protocols, setProtocols] = useState([])
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const commonClasses = useCommonStyles();
|
||||
|
||||
@@ -55,6 +54,7 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
|
||||
const statsData = await getTrafficStatsDataApi();
|
||||
setPieStatsData(statsData.pie);
|
||||
setTimelineStatsData(statsData.timeline);
|
||||
setProtocols(statsData.protocols)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
@@ -109,18 +109,17 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
|
||||
<div>
|
||||
<span style={{ marginRight: 15 }}>Protocol</span>
|
||||
<select className={styles.select} value={selectedProtocol} onChange={(e) => setSelectedProtocol(e.target.value)}>
|
||||
{PROTOCOLS.map(protocol => <option key={protocol} value={protocol}>{protocol}</option>)}
|
||||
{protocols.map(protocol => <option key={protocol} value={protocol}>{protocol}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{isLoading ? <div style={{ textAlign: "center", marginTop: 20 }}>
|
||||
<img alt="spinner" src={spinnerImg} style={{ height: 50 }} />
|
||||
</div> :
|
||||
<LoadingWrapper isLoading={isLoading} loaderMargin={20} loaderHeight={50}>
|
||||
<div>
|
||||
<TrafficPieChart pieChartMode={statsMode} data={pieStatsData} selectedProtocol={selectedProtocol}/>
|
||||
<TimelineBarChart timeLineBarChartMode={statsMode} data={timelineStatsData} selectedProtocol={selectedProtocol}/>
|
||||
</div>}
|
||||
<TrafficPieChart pieChartMode={statsMode} data={pieStatsData} selectedProtocol={selectedProtocol} />
|
||||
<TimelineBarChart timeLineBarChartMode={statsMode} data={timelineStatsData} selectedProtocol={selectedProtocol} />
|
||||
</div>
|
||||
</LoadingWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
@@ -51,17 +51,4 @@ export class Utils {
|
||||
return true;
|
||||
}
|
||||
|
||||
static stringToColor = (str) => {
|
||||
let colors = ["#e51c23", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#5677fc", "#03a9f4", "#00bcd4", "#009688", "#259b24", "#8bc34a", "#afb42b", "#ff9800", "#ff5722", "#795548", "#607d8b"]
|
||||
|
||||
let hash = 0;
|
||||
if (str.length === 0) return hash;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||
hash = hash & hash;
|
||||
}
|
||||
hash = ((hash % colors.length) + colors.length) % colors.length;
|
||||
return colors[hash];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user