diff --git a/.gitignore b/.gitignore index d3d5892ac..d5bd301ea 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ .vscode/settings.json kern/bpf/x86/vmlinux.h + +bin/* \ No newline at end of file diff --git a/cli/cmd/bash.go b/cli/cmd/bash.go index afe9f8a27..5122dfcbb 100644 --- a/cli/cmd/bash.go +++ b/cli/cmd/bash.go @@ -50,7 +50,7 @@ func bashCommandFunc(command *cobra.Command, args []string) { mod := user.GetModuleByName(user.MODULE_NAME_BASH) - logger := log.Default() + logger := log.New(os.Stdout, "bash_", log.LstdFlags) logger.Printf("start to run %s module", mod.Name()) @@ -65,7 +65,7 @@ func bashCommandFunc(command *cobra.Command, args []string) { bc.Debug = gConf.Debug bc.IsHex = gConf.IsHex - log.Printf("pid info :%d", os.Getpid()) + logger.Printf("pid info :%d", os.Getpid()) //bc.Pid = globalFlags.Pid if e := bc.Check(); e != nil { logger.Fatal(e) diff --git a/cli/cmd/global.go b/cli/cmd/global.go index 7b22bd7b1..1c0c440dd 100644 --- a/cli/cmd/global.go +++ b/cli/cmd/global.go @@ -11,11 +11,12 @@ import ( // GlobalFlags are flags that defined globally // and are inherited to all sub-commands. type GlobalFlags struct { - IsHex bool - Debug bool - Pid uint64 // PID - Uid uint64 // UID - NoSearch bool // No lib search + IsHex bool + Debug bool + Pid uint64 // PID + Uid uint64 // UID + NoSearch bool // No lib search + loggerFile string // save file } func getGlobalConf(command *cobra.Command) (conf GlobalFlags, err error) { @@ -43,5 +44,10 @@ func getGlobalConf(command *cobra.Command) (conf GlobalFlags, err error) { if err != nil { return } + + conf.loggerFile, err = command.Flags().GetString("write-file") + if err != nil { + return + } return } diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 70978db8e..41ead1267 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -80,4 +80,5 @@ func init() { rootCmd.PersistentFlags().BoolVar(&globalFlags.NoSearch, "nosearch", false, "no lib search") rootCmd.PersistentFlags().Uint64VarP(&globalFlags.Pid, "pid", "p", defaultPid, "if pid is 0 then we target all pids") rootCmd.PersistentFlags().Uint64VarP(&globalFlags.Uid, "uid", "u", defaultUid, "if uid is 0 then we target all users") + rootCmd.PersistentFlags().StringVarP(&globalFlags.loggerFile, "write-file", "w", "", "-w file Write the packets to file") } diff --git a/cli/cmd/tls.go b/cli/cmd/tls.go index 7aeca2e92..8fd74a603 100644 --- a/cli/cmd/tls.go +++ b/cli/cmd/tls.go @@ -50,14 +50,22 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { signal.Notify(stopper, os.Interrupt, syscall.SIGTERM) ctx, cancelFun := context.WithCancel(context.TODO()) - logger := log.Default() + logger := log.New(os.Stdout, "tls_", log.LstdFlags) // save global config gConf, e := getGlobalConf(command) if e != nil { logger.Fatal(e) } - log.Printf("pid info :%d", os.Getpid()) + if gConf.loggerFile != "" { + f, e := os.Create(gConf.loggerFile) + if e != nil { + logger.Fatal(e) + return + } + logger.SetOutput(f) + } + logger.Printf("pid info :%d", os.Getpid()) modNames := []string{user.MODULE_NAME_OPENSSL, user.MODULE_NAME_GNUTLS, user.MODULE_NAME_NSPR, user.MODULE_NAME_GOSSL} @@ -65,10 +73,9 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { for _, modName := range modNames { mod := user.GetModuleByName(modName) if mod == nil { - logger.Printf("cant found module: %s", modName) + logger.Printf("[eCapture]\tcant found module: %s", modName) break } - logger.Printf("start to run %s module", mod.Name()) var conf user.IConfig switch mod.Name() { @@ -84,7 +91,7 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { } if conf == nil { - logger.Printf("cant found module %s config info.", mod.Name()) + logger.Printf("[eCapture]\tcant found module %s config info.", mod.Name()) break } @@ -94,15 +101,16 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { conf.SetHex(gConf.IsHex) conf.SetNoSearch(gConf.NoSearch) + logger.Printf("%s\tmodule initialization", mod.Name()) if e := conf.Check(); e != nil { - logger.Printf("%v", e) + logger.Printf("%s\tmodule initialization failed. [skip it]. error:%+v", mod.Name(), e) continue } //初始化 err := mod.Init(ctx, logger, conf) if err != nil { - logger.Printf("%v", err) + logger.Printf("%s\tmodule initialization failed, [skip it]. error:%+v", mod.Name(), err) continue } @@ -110,10 +118,11 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { go func(module user.IModule) { err := module.Run() if err != nil { - logger.Printf("%v", err) + logger.Printf("%s\tmodule run failed, [skip it]. error:%+v", module.Name(), err) return } }(mod) + logger.Printf("%s\tmodule started successfully.", mod.Name()) runMods++ } diff --git a/go.mod b/go.mod index f5b80b544..976b21f34 100644 --- a/go.mod +++ b/go.mod @@ -25,5 +25,8 @@ require ( github.com/stretchr/testify v1.7.0 // indirect github.com/vishvananda/netlink v1.1.0 // indirect github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect ) diff --git a/go.sum b/go.sum index 265a2896f..ced8d2c8b 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.8.1 h1:bLSSEbBLqGPXxls55pGr5qWZaTqcmfDJHhou7t254ao= github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= @@ -69,6 +70,7 @@ github.com/mdlayher/netlink v1.4.1 h1:I154BCU+mKlIf7BgcAJB2r7QjveNPty6uNY1g9ChVf github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00 h1:qEtkL8n1DAHpi5/AOgAckwGQUlMe4+jhL/GMt+GKIks= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -92,10 +94,24 @@ github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -105,8 +121,11 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -126,7 +145,9 @@ golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/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= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= @@ -136,12 +157,19 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +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= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/event_processor/base_event.go b/pkg/event_processor/base_event.go new file mode 100644 index 000000000..0521ca1ce --- /dev/null +++ b/pkg/event_processor/base_event.go @@ -0,0 +1,216 @@ +package event_processor + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +type AttachType int64 + +const ( + PROBE_ENTRY AttachType = iota + PROBE_RET +) + +// 格式化输出相关 + +const CHUNK_SIZE = 16 +const CHUNK_SIZE_HALF = CHUNK_SIZE / 2 + +const MAX_DATA_SIZE = 1024 * 4 +const SA_DATA_LEN = 14 + +const ( + SSL2_VERSION = 0x0002 + SSL3_VERSION = 0x0300 + TLS1_VERSION = 0x0301 + TLS1_1_VERSION = 0x0302 + TLS1_2_VERSION = 0x0303 + TLS1_3_VERSION = 0x0304 + DTLS1_VERSION = 0xFEFF + DTLS1_2_VERSION = 0xFEFD +) + +type tls_version struct { + version int32 +} + +func (t tls_version) String() string { + switch t.version { + case SSL2_VERSION: + return "SSL2_VERSION" + case SSL3_VERSION: + return "SSL3_VERSION" + case TLS1_VERSION: + return "TLS1_VERSION" + case TLS1_1_VERSION: + return "TLS1_1_VERSION" + case TLS1_2_VERSION: + return "TLS1_2_VERSION" + case TLS1_3_VERSION: + return "TLS1_3_VERSION" + case DTLS1_VERSION: + return "DTLS1_VERSION" + case DTLS1_2_VERSION: + return "DTLS1_2_VERSION" + } + return fmt.Sprintf("TLS_VERSION_UNKNOW_%d", t.version) +} + +type BaseEvent struct { + event_type EVENT_TYPE + DataType int64 + Timestamp_ns uint64 + Pid uint32 + Tid uint32 + Data [MAX_DATA_SIZE]byte + Data_len int32 + Comm [16]byte + Fd uint32 + Version int32 +} + +func (this *BaseEvent) Decode(payload []byte) (err error) { + buf := bytes.NewBuffer(payload) + if err = binary.Read(buf, binary.LittleEndian, &this.DataType); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Timestamp_ns); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Pid); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Tid); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Data); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Data_len); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Comm); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Fd); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.Version); err != nil { + return + } + + return nil +} + +func (this *BaseEvent) GetUUID() string { + return fmt.Sprintf("%d_%d_%s_%d_%d", this.Pid, this.Tid, CToGoString(this.Comm[:]), this.Fd, this.DataType) +} + +func (this *BaseEvent) Payload() []byte { + return this.Data[:this.Data_len] +} + +func (this *BaseEvent) PayloadLen() int { + return int(this.Data_len) +} + +func (this *BaseEvent) StringHex() string { + + var perfix, connInfo string + switch AttachType(this.DataType) { + case PROBE_ENTRY: + connInfo = fmt.Sprintf("Recived %d bytes", this.Data_len) + case PROBE_RET: + connInfo = fmt.Sprintf("Send %d bytes", this.Data_len) + default: + perfix = fmt.Sprintf("UNKNOW_%d", this.DataType) + } + + b := dumpByteSlice(this.Data[:this.Data_len], perfix) + + v := tls_version{version: this.Version} + s := fmt.Sprintf("PID:%d, Comm:%s, TID:%d, %s, Version:%s, Payload:\n%s", this.Pid, CToGoString(this.Comm[:]), this.Tid, connInfo, v.String(), b.String()) + return s +} + +func (this *BaseEvent) String() string { + + var connInfo string + switch AttachType(this.DataType) { + case PROBE_ENTRY: + connInfo = fmt.Sprintf("Recived %dbytes", this.Data_len) + case PROBE_RET: + connInfo = fmt.Sprintf("Send %d bytes", this.Data_len) + default: + connInfo = fmt.Sprintf("UNKNOW_%d", this.DataType) + } + v := tls_version{version: this.Version} + s := fmt.Sprintf("PID:%d, Comm:%s, TID:%d, Version:%s, %s, Payload:\n%s", this.Pid, bytes.TrimSpace(this.Comm[:]), this.Tid, v.String(), connInfo, string(this.Data[:this.Data_len])) + return s +} + +func (this *BaseEvent) Clone() IEventStruct { + event := new(BaseEvent) + event.event_type = EVENT_TYPE_OUTPUT + return event +} + +func (this *BaseEvent) EventType() EVENT_TYPE { + return this.event_type +} + +func CToGoString(c []byte) string { + n := -1 + for i, b := range c { + if b == 0 { + break + } + n = i + } + return string(c[:n+1]) +} + +func dumpByteSlice(b []byte, perfix string) *bytes.Buffer { + var a [CHUNK_SIZE]byte + bb := new(bytes.Buffer) + n := (len(b) + (CHUNK_SIZE - 1)) &^ (CHUNK_SIZE - 1) + + for i := 0; i < n; i++ { + + // 序号列 + if i%CHUNK_SIZE == 0 { + bb.WriteString(perfix) + bb.WriteString(fmt.Sprintf("%04d", i)) + } + + // 长度的一半,则输出4个空格 + if i%CHUNK_SIZE_HALF == 0 { + bb.WriteString(" ") + } else if i%(CHUNK_SIZE_HALF/2) == 0 { + bb.WriteString(" ") + } + + if i < len(b) { + bb.WriteString(fmt.Sprintf(" %02X", b[i])) + } else { + bb.WriteString(" ") + } + + // 非ASCII 改为 . + if i >= len(b) { + a[i%CHUNK_SIZE] = ' ' + } else if b[i] < 32 || b[i] > 126 { + a[i%CHUNK_SIZE] = '.' + } else { + a[i%CHUNK_SIZE] = b[i] + } + + // 如果到达size长度,则换行 + if i%CHUNK_SIZE == (CHUNK_SIZE - 1) { + bb.WriteString(fmt.Sprintf(" %s\n", string(a[:]))) + } + } + return bb +} diff --git a/pkg/event_processor/http_request.go b/pkg/event_processor/http_request.go new file mode 100644 index 000000000..76128c91b --- /dev/null +++ b/pkg/event_processor/http_request.go @@ -0,0 +1,103 @@ +package event_processor + +import ( + "bufio" + "bytes" + "log" + "net/http" + "net/http/httputil" +) + +type HTTPRequest struct { + request *http.Request + packerType PACKET_TYPE + isDone bool + isInit bool + reader *bytes.Buffer + bufReader *bufio.Reader +} + +func (this *HTTPRequest) Init() { + this.reader = bytes.NewBuffer(nil) + this.bufReader = bufio.NewReader(this.reader) +} + +func (this *HTTPRequest) Name() string { + return "HTTPRequest" +} + +func (this *HTTPRequest) PacketType() PACKET_TYPE { + return this.packerType +} + +func (this *HTTPRequest) ParserType() PARSER_TYPE { + return PARSER_TYPE_HTTP_REQUEST +} + +func (this *HTTPRequest) Write(b []byte) (int, error) { + // 如果未初始化 + if !this.isInit { + n, e := this.reader.Write(b) + if e != nil { + return n, e + } + req, err := http.ReadRequest(this.bufReader) + if err != nil { + return 0, err + } + this.request = req + this.isInit = true + return n, nil + } + + // 如果已初始化 + l, e := this.reader.Write(b) + if e != nil { + return 0, e + } + + // TODO 检测是否接收完整个包 + if false { + this.isDone = true + } + + return l, nil +} + +func (this *HTTPRequest) detect(payload []byte) error { + //this.Init() + rd := bytes.NewReader(payload) + buf := bufio.NewReader(rd) + req, err := http.ReadRequest(buf) + if err != nil { + return err + } + this.request = req + return nil +} + +func (this *HTTPRequest) IsDone() bool { + return this.isDone +} + +func (this *HTTPRequest) Reset() { + this.isDone = false + this.isInit = false + this.reader.Reset() + this.bufReader.Reset(this.reader) +} + +func (this *HTTPRequest) Display() []byte { + b, e := httputil.DumpRequest(this.request, true) + if e != nil { + log.Println("DumpRequest error:", e) + return nil + } + return b +} + +func init() { + hr := &HTTPRequest{} + hr.Init() + Register(hr) +} diff --git a/pkg/event_processor/http_response.go b/pkg/event_processor/http_response.go new file mode 100644 index 000000000..3d497bd88 --- /dev/null +++ b/pkg/event_processor/http_response.go @@ -0,0 +1,124 @@ +package event_processor + +import ( + "bufio" + "bytes" + "compress/gzip" + "io" + "log" + "net/http" + "net/http/httputil" +) + +type HTTPResponse struct { + response *http.Response + packerType PACKET_TYPE + isDone bool + isInit bool + reader *bytes.Buffer + bufReader *bufio.Reader +} + +func (this *HTTPResponse) Init() { + this.reader = bytes.NewBuffer(nil) + this.bufReader = bufio.NewReader(this.reader) +} + +func (this *HTTPResponse) Name() string { + return "HTTPResponse" +} + +func (this *HTTPResponse) PacketType() PACKET_TYPE { + return this.packerType +} + +func (this *HTTPResponse) ParserType() PARSER_TYPE { + return PARSER_TYPE_HTTP_RESPONSE +} + +func (this *HTTPResponse) Write(b []byte) (int, error) { + // 如果未初始化 + if !this.isInit { + n, e := this.reader.Write(b) + if e != nil { + return n, e + } + req, err := http.ReadResponse(this.bufReader, nil) + if err != nil { + return 0, err + } + this.response = req + this.isInit = true + return n, nil + } + + // 如果已初始化 + l, e := this.reader.Write(b) + if e != nil { + return 0, e + } + + // TODO 检测是否接收完整个包 + if false { + this.isDone = true + } + + return l, nil +} + +func (this *HTTPResponse) detect(payload []byte) error { + rd := bytes.NewReader(payload) + buf := bufio.NewReader(rd) + res, err := http.ReadResponse(buf, nil) + if err != nil { + return err + } + this.response = res + return nil +} + +func (this *HTTPResponse) IsDone() bool { + return this.isDone +} + +func (this *HTTPResponse) Reset() { + this.isDone = false + this.isInit = false + this.reader.Reset() + this.bufReader.Reset(this.reader) +} + +func (this *HTTPResponse) Display() []byte { + var reader io.ReadCloser + var err error + switch this.response.Header.Get("Content-Encoding") { + case "gzip": + reader, err = gzip.NewReader(this.response.Body) + if err != nil { + log.Println(err) + break + } + + // gzip uncompressed success + this.response.Body = reader + defer reader.Close() + default: + //reader = this.response.Body + + //TODO for debug + //return []byte("") + } + + b, e := httputil.DumpResponse(this.response, true) + if e != nil { + log.Println("DumpResponse error:", e) + return []byte("") + } + return b +} + +func init() { + hr := &HTTPResponse{} + hr.Init() + Register(hr) +} diff --git a/user/ievent.go b/pkg/event_processor/ievent.go similarity index 72% rename from user/ievent.go rename to pkg/event_processor/ievent.go index 3ce396bc1..c8b9e5bdc 100644 --- a/user/ievent.go +++ b/pkg/event_processor/ievent.go @@ -1,4 +1,4 @@ -package user +package event_processor type EVENT_TYPE uint8 @@ -12,10 +12,13 @@ const ( type IEventStruct interface { Decode(payload []byte) (err error) + Payload() []byte + PayloadLen() int String() string StringHex() string Clone() IEventStruct - Module() IModule - SetModule(IModule) + //Module() IModule + //SetModule(IModule) EventType() EVENT_TYPE + GetUUID() string } diff --git a/pkg/event_processor/iparser.go b/pkg/event_processor/iparser.go new file mode 100644 index 000000000..38d10a4dc --- /dev/null +++ b/pkg/event_processor/iparser.go @@ -0,0 +1,134 @@ +package event_processor + +import ( + "bytes" + "fmt" +) + +type PROCESS_STATUS uint8 +type PACKET_TYPE uint8 +type PARSER_TYPE uint8 + +const ( + PROCESS_STATE_INIT PROCESS_STATUS = iota + PROCESS_STATE_PROCESSING + PROCESS_STATE_DONE +) + +const ( + PACKET_TYPE_NULL PACKET_TYPE = iota + PACKET_TYPE_UNKNOW + PACKET_TYPE_GZIP + PACKET_TYPE_WEB_SOCKET +) + +const ( + PARSER_TYPE_NULL PARSER_TYPE = iota + PARSER_TYPE_HTTP_REQUEST + PARSER_TYPE_HTTP_RESPONSE + PARSER_TYPE_WEB_SOCKET +) + +type IParser interface { + detect(b []byte) error + Write(b []byte) (int, error) + ParserType() PARSER_TYPE + PacketType() PACKET_TYPE + //Body() []byte + Name() string + IsDone() bool + Init() + Display() []byte + Reset() +} + +var parsers = make(map[string]IParser) + +func Register(p IParser) { + if p == nil { + panic("Register Parser is nil") + } + name := p.Name() + if _, dup := parsers[name]; dup { + panic(fmt.Sprintf("Register called twice for Parser %s", name)) + } + parsers[name] = p +} + +// GetModules 获取modules列表 +func GetAllModules() map[string]IParser { + return parsers +} + +// GetModules 获取modules列表 +func GetModuleByName(name string) IParser { + return parsers[name] +} + +func NewParser(payload []byte) IParser { + if len(payload) > 0 { + for _, parser := range GetAllModules() { + err := parser.detect(payload) + if err == nil { + var newParser IParser + switch parser.ParserType() { + case PARSER_TYPE_NULL: + newParser = new(DefaultParser) + case PARSER_TYPE_HTTP_REQUEST: + newParser = new(HTTPRequest) + case PARSER_TYPE_HTTP_RESPONSE: + newParser = new(HTTPResponse) + } + newParser.Init() + return newParser + } + } + } + var np = &DefaultParser{} + np.reader = bytes.NewBuffer(nil) + return np +} + +type DefaultParser struct { + reader *bytes.Buffer + isdone bool +} + +func (this *DefaultParser) ParserType() PARSER_TYPE { + return PARSER_TYPE_NULL +} + +func (this *DefaultParser) PacketType() PACKET_TYPE { + return PACKET_TYPE_NULL +} + +func (this *DefaultParser) Write(b []byte) (int, error) { + this.isdone = true + return this.reader.Write(b) +} + +// DefaultParser 检测包类型 +func (this *DefaultParser) detect(b []byte) error { + return nil +} + +func (this *DefaultParser) Name() string { + return "DefaultParser" +} + +func (this *DefaultParser) IsDone() bool { + return this.isdone +} + +func (this *DefaultParser) Init() { + +} + +func (this *DefaultParser) Display() []byte { + return []byte(CToGoString(this.reader.Bytes())) +} + +func (this *DefaultParser) Reset() { + this.isdone = false + this.reader.Reset() +} diff --git a/pkg/event_processor/iworker.go b/pkg/event_processor/iworker.go new file mode 100644 index 000000000..df67e6f49 --- /dev/null +++ b/pkg/event_processor/iworker.go @@ -0,0 +1,132 @@ +package event_processor + +import ( + "time" +) + +type IWorker interface { + + // 定时器1 ,定时判断没有后续包,则解析输出 + + // 定时器2, 定时判断没后续包,则通知上层销毁自己 + + // 收包 + Write(event IEventStruct) error + GetUUID() string +} + +const ( + MAX_TICKER_COUNT = 10 // 1 Sencond/(eventWorker.ticker.C) = 10 + MAX_CHAN_LEN = 16 // 包队列长度 + //MAX_EVENT_LEN = 16 // 事件数组长度 +) + +type eventWorker struct { + incoming chan IEventStruct + //events []user.IEventStruct + status PROCESS_STATUS + packetType PACKET_TYPE + ticker *time.Ticker + tickerCount uint8 + UUID string + processor *EventProcessor + parser IParser +} + +func NewEventWorker(uuid string, processor *EventProcessor) IWorker { + eWorker := &eventWorker{} + eWorker.init(uuid, processor) + go func() { + eWorker.Run() + }() + return eWorker +} + +func (this *eventWorker) init(uuid string, processor *EventProcessor) { + this.ticker = time.NewTicker(time.Millisecond * 100) + this.incoming = make(chan IEventStruct, MAX_CHAN_LEN) + this.status = PROCESS_STATE_INIT + this.UUID = uuid + this.processor = processor +} + +func (this *eventWorker) GetUUID() string { + return this.UUID +} + +func (this *eventWorker) Write(event IEventStruct) error { + this.incoming <- event + return nil +} + +// 输出包内容 +func (this *eventWorker) Display() { + // 解析器类型检测 + if this.parser.ParserType() != PARSER_TYPE_HTTP_RESPONSE { + //临时调试开关 + //return + } + + // 输出包内容 + b := this.parser.Display() + this.processor.GetLogger().Printf("UUID:%s, Name:%s, Length:%d", this.UUID, this.parser.Name(), len(b)) + + // TODO 格式化的终端输出 + this.processor.GetLogger().Println(string(this.parser.Display())) + // 重置状态 + this.parser.Reset() + + // 设定状态、重置包类型 + this.status = PROCESS_STATE_DONE + this.packetType = PACKET_TYPE_NULL + +} + +// 解析类型,输出 +func (this *eventWorker) parserEvent(event IEventStruct) { + if this.status == PROCESS_STATE_INIT { + // 识别包类型,只检测,不把payload设置到parser的属性中,需要重新调用parser.Write()写入 + parser := NewParser(event.Payload()) + this.parser = parser + } + + // 设定当前worker的状态为正在解析 + this.status = PROCESS_STATE_PROCESSING + + // 写入payload到parser + _, err := this.parser.Write(event.Payload()[:event.PayloadLen()]) + if err != nil { + this.processor.GetLogger().Fatalf("eventWorker: detect packet type error, UUID:%s, error:%v", this.UUID, err) + } + + // 是否接收完成,能否输出 + if this.parser.IsDone() { + this.Display() + } +} + +func (this *eventWorker) Run() { + for { + select { + case _ = <-this.ticker.C: + // 输出包 + if this.tickerCount > MAX_TICKER_COUNT { + this.Close() + return + } + this.tickerCount++ + case event := <-this.incoming: + // reset tickerCount + this.tickerCount = 0 + this.parserEvent(event) + } + } + +} + +func (this *eventWorker) Close() { + // 即将关闭, 必须输出结果 + this.Display() + this.tickerCount = 0 + this.processor.delWorkerByUUID(this) +} diff --git a/pkg/event_processor/processor.go b/pkg/event_processor/processor.go new file mode 100644 index 000000000..5825eca2c --- /dev/null +++ b/pkg/event_processor/processor.go @@ -0,0 +1,111 @@ +package event_processor + +import ( + "fmt" + "log" + "sync" +) + +const ( + MAX_INCOMING_CHAN_LEN = 1024 + MAX_PARSER_QUEUE_LEN = 1024 +) + +type EventProcessor struct { + sync.Mutex + // 收包,来自调用者发来的新事件 + incoming chan IEventStruct + + // key为 PID+UID+COMMON等确定唯一的信息 + workerQueue map[string]IWorker + + logger *log.Logger +} + +func (this *EventProcessor) GetLogger() *log.Logger { + return this.logger +} + +func (this *EventProcessor) init() { + this.incoming = make(chan IEventStruct, MAX_INCOMING_CHAN_LEN) + this.workerQueue = make(map[string]IWorker, MAX_PARSER_QUEUE_LEN) +} + +// Write event 处理器读取事件 +func (this *EventProcessor) Serve() { + for { + select { + case event := <-this.incoming: + this.dispatch(event) + } + } +} + +func (this *EventProcessor) dispatch(event IEventStruct) { + //this.logger.Printf("event ID:%s", event.GetUUID()) + var uuid string = event.GetUUID() + found, eWorker := this.getWorkerByUUID(uuid) + if !found { + // ADD a new eventWorker into queue + eWorker = NewEventWorker(event.GetUUID(), this) + this.addWorkerByUUID(eWorker) + } + + err := eWorker.Write(event) + if err != nil { + //... + } +} + +//func (this *EventProcessor) Incoming() chan user.IEventStruct { +// return this.incoming +//} + +func (this *EventProcessor) getWorkerByUUID(uuid string) (bool, IWorker) { + this.Lock() + defer this.Unlock() + var eWorker IWorker + var found bool + eWorker, found = this.workerQueue[uuid] + if !found { + return false, eWorker + } + return true, eWorker +} + +func (this *EventProcessor) addWorkerByUUID(worker IWorker) { + this.Lock() + defer this.Unlock() + this.workerQueue[worker.GetUUID()] = worker +} + +// 每个worker调用该方法,从处理器中删除自己 +func (this *EventProcessor) delWorkerByUUID(worker IWorker) { + this.Lock() + defer this.Unlock() + delete(this.workerQueue, worker.GetUUID()) +} + +// Write event +// 外部调用者调用该方法 +func (this *EventProcessor) Write(event IEventStruct) { + select { + case this.incoming <- event: + return + } +} + +func (this *EventProcessor) Close() error { + if len(this.workerQueue) > 0 { + return fmt.Errorf("EventProcessor.Close(): workerQueue is not empty:%d", len(this.workerQueue)) + } + return nil +} + +func NewEventProcessor(logger *log.Logger) *EventProcessor { + var ep *EventProcessor + ep = &EventProcessor{} + ep.logger = logger + ep.init() + return ep +} diff --git a/pkg/event_processor/processor_test.go b/pkg/event_processor/processor_test.go new file mode 100644 index 000000000..a9393592d --- /dev/null +++ b/pkg/event_processor/processor_test.go @@ -0,0 +1,79 @@ +package event_processor + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "strings" + "testing" + "time" +) + +var ( + testFile = "testdata/all.json" +) + +type SSLDataEventTmp struct { + //Event_type uint8 `json:"Event_type"` + DataType int64 `json:"DataType"` + Timestamp_ns uint64 `json:"Timestamp_ns"` + Pid uint32 `json:"Pid"` + Tid uint32 `json:"Tid"` + Data_len int32 `json:"Data_len"` + Comm [16]byte `json:"Comm"` + Fd uint32 `json:"Fd"` + Version int32 `json:"Version"` + Data [4096]byte `json:"Data"` +} + +func TestEventProcessor_Serve(t *testing.T) { + + logger := log.Default() + /* + f, e := os.Create("./output.log") + if e != nil { + t.Fatal(e) + } + logger.SetOutput(f) + */ + ep := NewEventProcessor(logger) + + go func() { + ep.Serve() + }() + content, err := ioutil.ReadFile(testFile) + if err != nil { + //Do something + log.Fatalf("open file error: %s, file:%s", err.Error(), testFile) + } + lines := strings.Split(string(content), "\n") + + for _, line := range lines { + if line == "" { + continue + } + var event SSLDataEventTmp + err := json.Unmarshal([]byte(line), &event) + if err != nil { + t.Fatalf("json unmarshal error: %s", err.Error()) + } + payloadFile := fmt.Sprintf("testdata/%d.bin", event.Timestamp_ns) + b, e := ioutil.ReadFile(payloadFile) + if e != nil { + t.Fatalf("read payload file error: %s, file:%s", e.Error(), payloadFile) + } + copy(event.Data[:], b) + ep.Write(&BaseEvent{Data_len: event.Data_len, Data: event.Data, DataType: event.DataType, Timestamp_ns: event.Timestamp_ns, Pid: event.Pid, Tid: event.Tid, Comm: event.Comm, Fd: event.Fd, Version: event.Version}) + } + + tick := time.NewTicker(time.Second * 3) + select { + case <-tick.C: + } + err = ep.Close() + if err != nil { + t.Fatalf("close error: %s", err.Error()) + } + t.Log("done") +} diff --git a/pkg/event_processor/testdata/952253291192473.bin b/pkg/event_processor/testdata/952253291192473.bin new file mode 100755 index 000000000..69c40cb09 --- /dev/null +++ b/pkg/event_processor/testdata/952253291192473.bin @@ -0,0 +1,7 @@ +GET / HTTP/1.1 +User-Agent: wget/1.21-1ubuntu3 Ubuntu/21.04 GNU/Linux/5.11.0-49-generic/x86_64 Intel(R)/Core(TM)/i7-9750H/CPU/@/2.60GHz cloud_id/none +Accept: */* +Accept-Encoding: identity +Host: motd.ubuntu.com +Connection: Keep-Alive + diff --git a/pkg/event_processor/testdata/952253597324253.bin b/pkg/event_processor/testdata/952253597324253.bin new file mode 100755 index 000000000..4f8adcb3d --- /dev/null +++ b/pkg/event_processor/testdata/952253597324253.bin @@ -0,0 +1,12 @@ +HTTP/1.1 200 OK +Date: Wed, 29 Jun 2022 09:44:06 GMT +Server: Apache/2.4.18 (Ubuntu) +Last-Modified: Wed, 29 Jun 2022 09:30:37 GMT +ETag: "bf-5e292ce4aa648" +Accept-Ranges: bytes +Content-Length: 191 +Vary: Accept-Encoding +Keep-Alive: timeout=5, max=100 +Connection: Keep-Alive +Content-Type: text/plain + diff --git a/pkg/event_processor/testdata/952253597628796.bin b/pkg/event_processor/testdata/952253597628796.bin new file mode 100755 index 000000000..667c43aa9 --- /dev/null +++ b/pkg/event_processor/testdata/952253597628796.bin @@ -0,0 +1,4 @@ + * Super-optimized for small spaces - read how we shrank the memory + footprint of MicroK8s to make it the smallest full K8s around. + + https://ubuntu.com/blog/microk8s-memory-optimisation diff --git a/pkg/event_processor/testdata/952282673103459.bin b/pkg/event_processor/testdata/952282673103459.bin new file mode 100755 index 000000000..0673fdb35 --- /dev/null +++ b/pkg/event_processor/testdata/952282673103459.bin @@ -0,0 +1,5 @@ +GET / HTTP/1.1 +Host: www.cnxct.com +User-Agent: curl/7.74.0 +Accept: */* + diff --git a/pkg/event_processor/testdata/952282712204824.bin b/pkg/event_processor/testdata/952282712204824.bin new file mode 100755 index 000000000..541c9f58d --- /dev/null +++ b/pkg/event_processor/testdata/952282712204824.bin @@ -0,0 +1,47 @@ +HTTP/1.1 200 OK +Server: nginx/1.14.0 (Ubuntu) +Date: Wed, 29 Jun 2022 09:44:35 GMT +Content-Type: text/html; charset=UTF-8 +Content-Length: 74332 +Connection: keep-alive +Vary: Accept-Encoding, Cookie +Cache-Control: max-age=3, must-revalidate +Last-Modified: Wed, 29 Jun 2022 09:27:27 GMT +Strict-Transport-Security: max-age=63072000; includeSubdomains; preload + + + + + + + + + + +CFC4N的博客 – 榫卯江湖,编码人生。 + + + + + + + +