From 85b1580e85bde9bd9104b8d3904b5a2749d72ab7 Mon Sep 17 00:00:00 2001 From: Jose Angel Sanchez Velazquez Date: Fri, 7 Mar 2025 19:20:47 +0100 Subject: [PATCH 01/19] feature: correlation offline mode to avoid rules update --- correlation/rules/update.go | 13 +++++- correlation/utils/configuration.go | 21 ++++++++- correlation/utils/readers.go | 69 ++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/correlation/rules/update.go b/correlation/rules/update.go index f79caabae..a3ec628c9 100644 --- a/correlation/rules/update.go +++ b/correlation/rules/update.go @@ -12,9 +12,20 @@ import ( func Update(updateReady chan bool) { first := true for { - log.Println("Downloading rules") cnf := utils.GetConfig() + if cnf.ConnectionMode == utils.ConnModeOffline { + if _, err := os.Stat(cnf.RulesFolder + "system"); err == nil { + log.Println("Offline mode: rules folder exists, skipping git clone") + if first { + first = false + updateReady <- true + } + time.Sleep(48 * time.Hour) + continue + } + } + f, err := os.Stat(cnf.RulesFolder + "system") if err != nil { if !errors.Is(err, os.ErrNotExist) { diff --git a/correlation/utils/configuration.go b/correlation/utils/configuration.go index 01967734e..8e8037aad 100644 --- a/correlation/utils/configuration.go +++ b/correlation/utils/configuration.go @@ -4,7 +4,7 @@ import ( "sync" ) -type Config struct { +type YamlConfig struct { RulesFolder string `yaml:"rulesFolder"` Elasticsearch string `yaml:"elasticsearch"` Postgres struct { @@ -17,11 +17,28 @@ type Config struct { ErrorLevel string `yaml:"errorLevel"` } +type ConnMode string + +const ( + ConnModeOffline ConnMode = "OFFLINE" + ConnModeOnline ConnMode = "ONLINE" +) + +type EnvVarConfig struct { + ConnectionMode ConnMode `env:"CONNECTION_MODE"` +} + +type Config struct { + YamlConfig + EnvVarConfig +} + var oneConfigRead sync.Once var cnf Config func readConfig() { - ReadYaml("config.yml", &cnf) + ReadYaml("config.yml", &cnf.YamlConfig) + ReadEnvVars(&cnf.EnvVarConfig) } func GetConfig() Config { diff --git a/correlation/utils/readers.go b/correlation/utils/readers.go index c70a0e974..5e4e89732 100644 --- a/correlation/utils/readers.go +++ b/correlation/utils/readers.go @@ -4,6 +4,9 @@ import ( "encoding/csv" "log" "os" + "reflect" + "strconv" + "strings" "gopkg.in/yaml.v3" ) @@ -33,3 +36,69 @@ func ReadCSV(url string) [][]string { } return result } + +func ReadEnvVars(cfg interface{}) { + v := reflect.ValueOf(cfg).Elem() + t := v.Type() + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + envTag := field.Tag.Get("env") + if envTag == "" { + continue + } + + // Check if the environment variable exists + envValue, exists := os.LookupEnv(envTag) + if !exists { + log.Printf("Environment variable %s not set, skipping...", envTag) + continue + } + + fieldValue := v.Field(i) + if !fieldValue.CanSet() { + log.Printf("Cannot set field %s, skipping...", field.Name) + continue + } + + switch fieldValue.Kind() { + case reflect.String: + fieldValue.SetString(envValue) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if intValue, err := strconv.ParseInt(envValue, 10, fieldValue.Type().Bits()); err == nil { + fieldValue.SetInt(intValue) + } else { + log.Printf("Failed to convert %s to int for field %s: %v", envValue, field.Name, err) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if uintValue, err := strconv.ParseUint(envValue, 10, fieldValue.Type().Bits()); err == nil { + fieldValue.SetUint(uintValue) + } else { + log.Printf("Failed to convert %s to uint for field %s: %v", envValue, field.Name, err) + } + case reflect.Float32, reflect.Float64: + if floatValue, err := strconv.ParseFloat(envValue, fieldValue.Type().Bits()); err == nil { + fieldValue.SetFloat(floatValue) + } else { + log.Printf("Failed to convert %s to float for field %s: %v", envValue, field.Name, err) + } + case reflect.Bool: + if boolValue, err := strconv.ParseBool(envValue); err == nil { + fieldValue.SetBool(boolValue) + } else { + log.Printf("Failed to convert %s to bool for field %s: %v", envValue, field.Name, err) + } + case reflect.Slice: + elements := reflect.MakeSlice(fieldValue.Type(), 0, 0) + for _, elem := range strings.Split(envValue, ",") { + elements = reflect.Append(elements, reflect.ValueOf(elem)) + } + fieldValue.Set(elements) + case reflect.Ptr: + ptr := reflect.New(fieldValue.Type().Elem()) + fieldValue.Set(ptr) + default: + log.Printf("Unsupported field type %s for field %s", fieldValue.Kind(), field.Name) + } + } +} From 7e71905a5df9ff178e5060b3667cbe15ec3e8856 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Tue, 11 Mar 2025 00:54:56 -0400 Subject: [PATCH 02/19] integrate dependencies from agent manager --- agent-manager/Dockerfile | 7 ++- .../auth/dependencies_interceptor.go | 45 ++++++++++++++ agent-manager/auth/interceptor.go | 4 +- agent-manager/go.mod | 30 +++++----- agent-manager/go.sum | 60 +++++++++---------- agent-manager/main.go | 2 + agent-manager/updates/updates.go | 42 +++++++++++++ agent-manager/util/files.go | 18 ++++++ 8 files changed, 160 insertions(+), 48 deletions(-) create mode 100644 agent-manager/auth/dependencies_interceptor.go create mode 100644 agent-manager/updates/updates.go create mode 100644 agent-manager/util/files.go diff --git a/agent-manager/Dockerfile b/agent-manager/Dockerfile index 857bbc0a5..b86c1aaea 100644 --- a/agent-manager/Dockerfile +++ b/agent-manager/Dockerfile @@ -1,6 +1,10 @@ FROM ubuntu:22.04 -COPY agent-manager /app/ +COPY ./agent-manager/agent-manager /app/ +COPY ./agent/utmstack_agent /dependencies/agent/ +COPY ./agent/utmstack_agent.exe /dependencies/agent/ +COPY ./agent/dependencies/ /dependencies/agent/ +COPY ./collector/dependencies/ /dependencies/collector/ # Install jq RUN apt-get update && \ @@ -19,6 +23,7 @@ RUN GRPCURL_VERSION=1.8.1 && \ # Expose the gRPC agent-manager port EXPOSE 50051 +EXPOSE 8080 # Set the health check HEALTHCHECK --interval=60s --timeout=5s --start-period=5s --retries=3 CMD grpcurl -insecure -plaintext -d '{"service": ""}' localhost:50051 grpc.health.v1.Health/Check | jq -e '.status == "SERVING"' || exit 1 diff --git a/agent-manager/auth/dependencies_interceptor.go b/agent-manager/auth/dependencies_interceptor.go new file mode 100644 index 000000000..b1bc2980c --- /dev/null +++ b/agent-manager/auth/dependencies_interceptor.go @@ -0,0 +1,45 @@ +package auth + +import ( + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "google.golang.org/grpc/metadata" +) + +func HTTPAuthInterceptor() gin.HandlerFunc { + return func(c *gin.Context) { + connectionKey := c.GetHeader("connection-key") + id := c.GetHeader("id") + key := c.GetHeader("key") + requestURL := c.Request.URL.Path + + if connectionKey == "" && id == "" && key == "" { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "authentication is not provided"}) + return + } else if connectionKey != "" { + if err := authenticateRequest(metadata.New(map[string]string{"connection-key": connectionKey}), "connection-key"); err != nil { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid connection key"}) + return + } + } else if id != "" && key != "" { + idInt, err := strconv.ParseUint(id, 10, 32) + if err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "id is not valid"}) + return + } + + if err := checkKeyAuth(key, idInt, requestURL); err != nil { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid key"}) + return + } + + } else { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid auth type"}) + return + } + + c.Next() + } +} diff --git a/agent-manager/auth/interceptor.go b/agent-manager/auth/interceptor.go index 1f7ea180f..18e9fc894 100644 --- a/agent-manager/auth/interceptor.go +++ b/agent-manager/auth/interceptor.go @@ -124,9 +124,9 @@ type AuthResponse struct { } func getAuthCache(method string) []AuthResponse { - if strings.Contains(method, "agent.AgentService") { + if strings.Contains(method, "agent.AgentService") || strings.Contains(method, "/dependencies/agent") { return convertMapToAuthResponses(agent.CacheAgent) - } else if strings.Contains(method, "agent.CollectorService") { + } else if strings.Contains(method, "agent.CollectorService") || strings.Contains(method, "/dependencies/collector") { return convertMapToAuthResponses(agent.CacheCollector) } else if strings.Contains(method, "agent.PingService") { return append(convertMapToAuthResponses(agent.CacheAgent), convertMapToAuthResponses(agent.CacheCollector)...) diff --git a/agent-manager/go.mod b/agent-manager/go.mod index 3a0689e92..d56a55c96 100644 --- a/agent-manager/go.mod +++ b/agent-manager/go.mod @@ -6,8 +6,10 @@ toolchain go1.23.4 require ( github.com/AtlasInsideCorp/AtlasInsideAES v1.0.0 + github.com/gin-contrib/gzip v1.2.2 + github.com/gin-gonic/gin v1.10.0 github.com/google/uuid v1.6.0 - github.com/threatwinds/logger v1.1.12 + github.com/threatwinds/logger v1.1.13 google.golang.org/grpc v1.70.0 google.golang.org/protobuf v1.36.5 gorm.io/driver/postgres v1.5.11 @@ -15,17 +17,15 @@ require ( ) require ( - github.com/bytedance/sonic v1.12.1 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/bytedance/sonic v1.12.7 // indirect + github.com/bytedance/sonic/loader v0.2.2 // indirect github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.0 // indirect - github.com/goccy/go-json v0.10.3 // indirect + github.com/go-playground/validator/v10 v10.24.0 // indirect + github.com/goccy/go-json v0.10.4 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect @@ -33,21 +33,21 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.30.0 // indirect - golang.org/x/net v0.32.0 // indirect + golang.org/x/arch v0.13.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect diff --git a/agent-manager/go.sum b/agent-manager/go.sum index 82e007443..6919e0286 100644 --- a/agent-manager/go.sum +++ b/agent-manager/go.sum @@ -1,22 +1,23 @@ github.com/AtlasInsideCorp/AtlasInsideAES v1.0.0 h1:TBiBl9KCa4i4epY0/q9WSC4ugavL6+6JUkOXWDnMM6I= github.com/AtlasInsideCorp/AtlasInsideAES v1.0.0/go.mod h1:cRhQ3TS/VEfu/z+qaciyuDZdtxgaXgaX8+G6Wa5NzBk= -github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= -github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q= +github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o= +github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= -github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/gzip v1.2.2 h1:iUU/EYCM8ENfkjmZaVrxbjF/ZC267Iqv5S0MMCMEliI= +github.com/gin-contrib/gzip v1.2.2/go.mod h1:C1a5cacjlDsS20cKnHlZRCPUu57D3qH6B2pV0rl+Y/s= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= @@ -29,10 +30,10 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= -github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg= +github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -55,8 +56,8 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -71,8 +72,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= @@ -87,10 +88,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/threatwinds/logger v1.1.13 h1:hhN3cqWX98td1XX6hGfh5CWq4r274rLfMrtE+bgxn+w= +github.com/threatwinds/logger v1.1.13/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -105,18 +106,17 @@ go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiy go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= -golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= -golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA= +golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= diff --git a/agent-manager/main.go b/agent-manager/main.go index 606b67a71..abb1281d4 100644 --- a/agent-manager/main.go +++ b/agent-manager/main.go @@ -11,6 +11,7 @@ import ( "github.com/utmstack/UTMStack/agent-manager/auth" "github.com/utmstack/UTMStack/agent-manager/config" "github.com/utmstack/UTMStack/agent-manager/migration" + "github.com/utmstack/UTMStack/agent-manager/updates" "github.com/utmstack/UTMStack/agent-manager/util" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -74,6 +75,7 @@ func main() { // Set the health status to SERVING healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING) s.InitPingSync() + updates.InitUpdatesManager() // Start the gRPC server lis, err := net.Listen("tcp", "0.0.0.0:50051") diff --git a/agent-manager/updates/updates.go b/agent-manager/updates/updates.go new file mode 100644 index 000000000..9d8369fc4 --- /dev/null +++ b/agent-manager/updates/updates.go @@ -0,0 +1,42 @@ +package updates + +import ( + "net/http" + + "github.com/gin-contrib/gzip" + "github.com/gin-gonic/gin" + "github.com/utmstack/UTMStack/agent-manager/auth" + "github.com/utmstack/UTMStack/agent-manager/util" +) + +type Version struct { + Version string `json:"version"` +} + +func InitUpdatesManager() { + go ServeDependencies() +} + +func ServeDependencies() { + gin.SetMode(gin.ReleaseMode) + r := gin.New() + r.Use( + gin.Recovery(), + gzip.Gzip(gzip.DefaultCompression), + ) + + r.NoRoute(notFound) + + group := r.Group("/private", auth.HTTPAuthInterceptor()) + group.StaticFS("/dependencies", http.Dir("/dependencies")) + + util.GetLogger().Info("Starting HTTP server on port 8080") + if err := r.RunTLS(":8080", "/cert/utm.crt", "/cert/utm.key"); err != nil { + util.GetLogger().ErrorF("error starting HTTP server: %v", err) + return + } +} + +func notFound(c *gin.Context) { + c.JSON(http.StatusNotFound, gin.H{"error": "not found"}) +} diff --git a/agent-manager/util/files.go b/agent-manager/util/files.go new file mode 100644 index 000000000..c4530ea4d --- /dev/null +++ b/agent-manager/util/files.go @@ -0,0 +1,18 @@ +package util + +import ( + "encoding/json" + "os" +) + +func ReadJson(fileName string, data interface{}) error { + content, err := os.ReadFile(fileName) + if err != nil { + return err + } + err = json.Unmarshal(content, data) + if err != nil { + return err + } + return nil +} From 00a3e7229ce7d0f16382db36d22ba3a2f1758aa1 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Tue, 11 Mar 2025 09:01:29 -0400 Subject: [PATCH 03/19] Add connection checker utility for AWS modules --- aws/configuration/const.go | 3 ++- aws/go.mod | 2 +- aws/go.sum | 4 ++-- aws/main.go | 4 ++++ aws/utils/check.go | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 aws/utils/check.go diff --git a/aws/configuration/const.go b/aws/configuration/const.go index d059ca2e7..253d338a6 100644 --- a/aws/configuration/const.go +++ b/aws/configuration/const.go @@ -3,7 +3,8 @@ package configuration import "github.com/utmstack/UTMStack/aws/utils" const ( - CORRELATIONURL = "http://correlation:8080/v1/newlog" + CORRELATIONURL = "http://correlation:8080/v1/newlog" + URL_CHECK_CONNECTION = "https://sts.amazonaws.com" ) func GetInternalKey() string { diff --git a/aws/go.mod b/aws/go.mod index 5ee3687f3..c1bf274f2 100644 --- a/aws/go.mod +++ b/aws/go.mod @@ -6,7 +6,7 @@ toolchain go1.23.4 require ( github.com/aws/aws-sdk-go v1.53.3 - github.com/threatwinds/logger v1.1.12 + github.com/threatwinds/logger v1.2.1 github.com/utmstack/config-client-go v1.2.5 ) diff --git a/aws/go.sum b/aws/go.sum index bc7b79079..7874aefa5 100644 --- a/aws/go.sum +++ b/aws/go.sum @@ -68,8 +68,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= diff --git a/aws/main.go b/aws/main.go index 9b0578fda..826d2b07d 100644 --- a/aws/main.go +++ b/aws/main.go @@ -23,6 +23,10 @@ func main() { st := time.Now().Add(-600 * time.Second) for { + if err := utils.ConnectionChecker(configuration.URL_CHECK_CONNECTION); err != nil { + utils.Logger.Fatal("Failed to establish connection: %v", err) + } + et := st.Add(299 * time.Second) moduleConfig, err := client.GetUTMConfig(enum.AWS_IAM_USER) if err != nil { diff --git a/aws/utils/check.go b/aws/utils/check.go new file mode 100644 index 000000000..3ff752964 --- /dev/null +++ b/aws/utils/check.go @@ -0,0 +1,38 @@ +package utils + +import ( + "net/http" +) + +func ConnectionChecker(url string) error { + checkConn := func() error { + if err := checkPanelConnection(url); err != nil { + return Logger.ErrorF("connection failed: %v", err) + } + + return nil + } + + if err := Logger.InfiniteRetryIfXError(checkConn, "connection failed"); err != nil { + return Logger.ErrorF("error checking connection: %v", err) + } + + return nil +} + +func checkPanelConnection(url string) error { + client := &http.Client{} + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return err + } + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} From dcfa01edbbe465b43d7cc16712dd1ae367cd293b Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Tue, 11 Mar 2025 09:01:52 -0400 Subject: [PATCH 04/19] Add connection checker utility for Bitdefender modules --- bitdefender/configuration/config.go | 15 ++++------- bitdefender/constants/const.go | 2 ++ bitdefender/go.mod | 2 +- bitdefender/go.sum | 4 +-- bitdefender/utils/check.go | 39 +++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 bitdefender/utils/check.go diff --git a/bitdefender/configuration/config.go b/bitdefender/configuration/config.go index 76f08ccbb..aa121dc17 100644 --- a/bitdefender/configuration/config.go +++ b/bitdefender/configuration/config.go @@ -12,6 +12,7 @@ import ( "github.com/threatwinds/logger" "github.com/utmstack/UTMStack/bitdefender/constants" + "github.com/utmstack/UTMStack/bitdefender/utils" "github.com/utmstack/config-client-go/enum" "github.com/utmstack/config-client-go/types" @@ -29,7 +30,6 @@ const delayCheckConfig = 30 * time.Second var configsSent = make(map[string]ModuleConfig) -// ConfigureModules updates the module configuration every 30 seconds. func ConfigureModules(cnf *types.ConfigurationSection, mutex *sync.Mutex, h *logger.Logger) { intKey := constants.GetInternalKey() panelServ := constants.GetPanelServiceName() @@ -37,7 +37,10 @@ func ConfigureModules(cnf *types.ConfigurationSection, mutex *sync.Mutex, h *log for { time.Sleep(delayCheckConfig) - // Get Bitdefender module configs + if err := utils.ConnectionChecker(constants.URL_CHECK_CONNECTION, h); err != nil { + h.Fatal("Failed to establish connection: %v", err) + } + tempModuleConfig, err := client.GetUTMConfig(enum.BITDEFENDER) if err != nil { if strings.Contains(err.Error(), "invalid character '<'") { @@ -52,7 +55,6 @@ func ConfigureModules(cnf *types.ConfigurationSection, mutex *sync.Mutex, h *log *cnf = *tempModuleConfig mutex.Unlock() - // Configure the group to send data to the syslog server if it is not already configured for _, group := range (*cnf).ConfigurationGroups { isNecessaryConfig := compareConfigs(configsSent, group) if isNecessaryConfig { @@ -84,9 +86,6 @@ func ConfigureModules(cnf *types.ConfigurationSection, mutex *sync.Mutex, h *log } } -// confBDGZApiPush configures the Bitdefender API. -// It checks to check that everything has been configured correctly. -// Send test logs func confBDGZApiPush(config types.ModuleGroup, operation string, h *logger.Logger) error { operationFunc := map[string]func(types.ModuleGroup, *logger.Logger) (*http.Response, error){ "sendConf": sendPushEventSettings, @@ -112,7 +111,6 @@ func confBDGZApiPush(config types.ModuleGroup, operation string, h *logger.Logge h.Info(string(myBody)) if operation == "sendConf" { - // Check if config was sent correctly regex := regexp.MustCompile(`result":true`) match := regex.Match([]byte(string(myBody))) if match { @@ -124,7 +122,6 @@ func confBDGZApiPush(config types.ModuleGroup, operation string, h *logger.Logge return fmt.Errorf("error sending configuration") } -// setPushEventSettings sends the configuration to the Bitdefender API func sendPushEventSettings(config types.ModuleGroup, h *logger.Logger) (*http.Response, error) { h.Info("Sending configuration...") byteTemplate := getTemplateSetPush(config) @@ -136,7 +133,6 @@ func sendPushEventSettings(config types.ModuleGroup, h *logger.Logger) (*http.Re return sendRequest(body, config) } -// getPushEventSettings gets the Bitdefender API settings func getPushEventSettings(config types.ModuleGroup, h *logger.Logger) (*http.Response, error) { h.Info("Checking configuration...") byteTemplate := getTemplateGet() @@ -148,7 +144,6 @@ func getPushEventSettings(config types.ModuleGroup, h *logger.Logger) (*http.Res return sendRequest(body, config) } -// sendTestPushEvent sends a test event to the connector func sendTestPushEvent(config types.ModuleGroup, h *logger.Logger) (*http.Response, error) { h.Info("Sending Event Test...") byteTemplate := getTemplateTest() diff --git a/bitdefender/constants/const.go b/bitdefender/constants/const.go index c4fa37102..16455fc95 100644 --- a/bitdefender/constants/const.go +++ b/bitdefender/constants/const.go @@ -4,6 +4,8 @@ import "github.com/utmstack/UTMStack/bitdefender/utils" const EndpointPush = "/v1.0/jsonrpc/push" +const URL_CHECK_CONNECTION = "https://cloud.gravityzone.bitdefender.com" + func GetInternalKey() string { return utils.Getenv("INTERNAL_KEY") } diff --git a/bitdefender/go.mod b/bitdefender/go.mod index 7216bcc7d..4bd7c06cf 100644 --- a/bitdefender/go.mod +++ b/bitdefender/go.mod @@ -7,7 +7,7 @@ toolchain go1.23.4 require ( github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91 github.com/gorilla/mux v1.8.1 - github.com/threatwinds/logger v1.1.12 + github.com/threatwinds/logger v1.2.1 github.com/utmstack/config-client-go v1.2.6 ) diff --git a/bitdefender/go.sum b/bitdefender/go.sum index 2ffb7bda8..94667b761 100644 --- a/bitdefender/go.sum +++ b/bitdefender/go.sum @@ -66,8 +66,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= diff --git a/bitdefender/utils/check.go b/bitdefender/utils/check.go new file mode 100644 index 000000000..beedaf444 --- /dev/null +++ b/bitdefender/utils/check.go @@ -0,0 +1,39 @@ +package utils + +import ( + "net/http" + + "github.com/threatwinds/logger" +) + +func ConnectionChecker(url string, h *logger.Logger) error { + checkConn := func() error { + if err := CheckConnection(url); err != nil { + return h.ErrorF("connection failed: %v", err) + } + return nil + } + + if err := h.InfiniteRetryIfXError(checkConn, "connection failed"); err != nil { + return h.ErrorF("error checking connection: %v", err) + } + + return nil +} + +func CheckConnection(url string) error { + client := &http.Client{} + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return err + } + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} From 111a9bb833b258d2fbebbb8c49f7c887041f949d Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Tue, 11 Mar 2025 10:32:56 -0400 Subject: [PATCH 05/19] Change fatal logging to error for connection failures in AWS and Bitdefender modules --- aws/main.go | 2 +- bitdefender/configuration/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/main.go b/aws/main.go index 826d2b07d..453e87f67 100644 --- a/aws/main.go +++ b/aws/main.go @@ -24,7 +24,7 @@ func main() { for { if err := utils.ConnectionChecker(configuration.URL_CHECK_CONNECTION); err != nil { - utils.Logger.Fatal("Failed to establish connection: %v", err) + utils.Logger.ErrorF("Failed to establish connection: %v", err) } et := st.Add(299 * time.Second) diff --git a/bitdefender/configuration/config.go b/bitdefender/configuration/config.go index aa121dc17..c5eaf7fd6 100644 --- a/bitdefender/configuration/config.go +++ b/bitdefender/configuration/config.go @@ -38,7 +38,7 @@ func ConfigureModules(cnf *types.ConfigurationSection, mutex *sync.Mutex, h *log time.Sleep(delayCheckConfig) if err := utils.ConnectionChecker(constants.URL_CHECK_CONNECTION, h); err != nil { - h.Fatal("Failed to establish connection: %v", err) + h.ErrorF("Failed to establish connection: %v", err) } tempModuleConfig, err := client.GetUTMConfig(enum.BITDEFENDER) From d7c4b5154dad48dc4d5ae363263960deb09c43c7 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Tue, 11 Mar 2025 16:36:02 -0400 Subject: [PATCH 06/19] add timeout --- aws/utils/check.go | 10 +++++++--- bitdefender/utils/check.go | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/aws/utils/check.go b/aws/utils/check.go index 3ff752964..f7212deb0 100644 --- a/aws/utils/check.go +++ b/aws/utils/check.go @@ -1,27 +1,31 @@ package utils import ( + "fmt" "net/http" + "time" ) func ConnectionChecker(url string) error { checkConn := func() error { if err := checkPanelConnection(url); err != nil { - return Logger.ErrorF("connection failed: %v", err) + return fmt.Errorf("connection failed: %v", err) } return nil } if err := Logger.InfiniteRetryIfXError(checkConn, "connection failed"); err != nil { - return Logger.ErrorF("error checking connection: %v", err) + return err } return nil } func checkPanelConnection(url string) error { - client := &http.Client{} + client := &http.Client{ + Timeout: 30 * time.Second, + } req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { diff --git a/bitdefender/utils/check.go b/bitdefender/utils/check.go index beedaf444..a39840a2f 100644 --- a/bitdefender/utils/check.go +++ b/bitdefender/utils/check.go @@ -1,7 +1,9 @@ package utils import ( + "fmt" "net/http" + "time" "github.com/threatwinds/logger" ) @@ -9,20 +11,22 @@ import ( func ConnectionChecker(url string, h *logger.Logger) error { checkConn := func() error { if err := CheckConnection(url); err != nil { - return h.ErrorF("connection failed: %v", err) + return fmt.Errorf("connection failed: %v", err) } return nil } if err := h.InfiniteRetryIfXError(checkConn, "connection failed"); err != nil { - return h.ErrorF("error checking connection: %v", err) + return err } return nil } func CheckConnection(url string) error { - client := &http.Client{} + client := &http.Client{ + Timeout: 30 * time.Second, + } req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { From a8bf2a211be2d4ba2bcca6b3038ee09d6186589c Mon Sep 17 00:00:00 2001 From: JocLRojas Date: Tue, 11 Mar 2025 16:53:06 -0400 Subject: [PATCH 07/19] Add connection checker utility for office 365 modules. --- office365/configuration/const.go | 4 +-- office365/go.mod | 2 +- office365/go.sum | 4 +-- office365/main.go | 4 +++ office365/utils/check.go | 45 ++++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 office365/utils/check.go diff --git a/office365/configuration/const.go b/office365/configuration/const.go index 1457ee524..05dca1fec 100644 --- a/office365/configuration/const.go +++ b/office365/configuration/const.go @@ -7,7 +7,7 @@ import ( ) const ( - loginUrl = "https://login.microsoftonline.com/" + LoginUrl = "https://login.microsoftonline.com/" GRANTTYPE = "client_credentials" SCOPE = "https://manage.office.com/.default" endPointLogin = "/oauth2/v2.0/token" @@ -26,7 +26,7 @@ func GetPanelServiceName() string { } func GetMicrosoftLoginLink(tenant string) string { - return fmt.Sprintf("%s%s%s", loginUrl, tenant, endPointLogin) + return fmt.Sprintf("%s%s%s", LoginUrl, tenant, endPointLogin) } func GetStartSubscriptionLink(tenant string) string { diff --git a/office365/go.mod b/office365/go.mod index 8f812c791..50cb46971 100644 --- a/office365/go.mod +++ b/office365/go.mod @@ -5,7 +5,7 @@ go 1.22.4 toolchain go1.23.4 require ( - github.com/threatwinds/logger v1.1.12 + github.com/threatwinds/logger v1.2.1 github.com/utmstack/config-client-go v1.2.6 ) diff --git a/office365/go.sum b/office365/go.sum index 42620c96e..7861b7859 100644 --- a/office365/go.sum +++ b/office365/go.sum @@ -62,8 +62,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= diff --git a/office365/main.go b/office365/main.go index 2b0d7d271..d59c98304 100644 --- a/office365/main.go +++ b/office365/main.go @@ -23,6 +23,10 @@ func main() { st := time.Now().Add(-600 * time.Second) for { + if err := utils.ConnectionChecker(configuration.LoginUrl); err != nil { + utils.Logger.ErrorF("External connection failure detected: %v", err) + } + et := st.Add(299 * time.Second) startTime := st.UTC().Format("2006-01-02T15:04:05") endTime := et.UTC().Format("2006-01-02T15:04:05") diff --git a/office365/utils/check.go b/office365/utils/check.go new file mode 100644 index 000000000..5ab7c1ccd --- /dev/null +++ b/office365/utils/check.go @@ -0,0 +1,45 @@ +package utils + +import ( + "context" + "fmt" + "net/http" + "time" +) + +const connectionTimeout = 5 * time.Second + +func ConnectionChecker(url string) error { + checkConn := func() error { + ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout) + defer cancel() + + if err := checkConnection(url, ctx); err != nil { + return fmt.Errorf("connection failed") + } + return nil + } + + if err := Logger.InfiniteRetryIfXError(checkConn, "connection failed"); err != nil { + return err + } + + return nil +} + +func checkConnection(url string, ctx context.Context) error { + client := &http.Client{} + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return err + } + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} From f97476b5ba1ce9e8b4a0bedb27f269c620447bf0 Mon Sep 17 00:00:00 2001 From: JocLRojas Date: Tue, 11 Mar 2025 16:54:07 -0400 Subject: [PATCH 08/19] Add connection checker utility for sophos module. --- sophos/configuration/const.go | 1 + sophos/go.mod | 2 +- sophos/go.sum | 4 ++-- sophos/main.go | 4 ++++ sophos/utils/check.go | 45 +++++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 sophos/utils/check.go diff --git a/sophos/configuration/const.go b/sophos/configuration/const.go index ce3e6275a..769ab4f6c 100644 --- a/sophos/configuration/const.go +++ b/sophos/configuration/const.go @@ -6,6 +6,7 @@ const ( CORRELATIONURL = "http://correlation:8080/v1/newlog" AUTHURL = "https://id.sophos.com/api/v2/oauth2/token" WHOAMIURL = "https://api.central.sophos.com/whoami/v1" + CHECKCON = "https://id.sophos.com" ) func GetInternalKey() string { diff --git a/sophos/go.mod b/sophos/go.mod index 3b23841c2..798453c23 100644 --- a/sophos/go.mod +++ b/sophos/go.mod @@ -5,7 +5,7 @@ go 1.22.4 toolchain go1.23.4 require ( - github.com/threatwinds/logger v1.1.12 + github.com/threatwinds/logger v1.2.1 github.com/utmstack/config-client-go v1.2.6 ) diff --git a/sophos/go.sum b/sophos/go.sum index 42620c96e..7861b7859 100644 --- a/sophos/go.sum +++ b/sophos/go.sum @@ -62,8 +62,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= diff --git a/sophos/main.go b/sophos/main.go index 9ecb81056..2fc387f04 100644 --- a/sophos/main.go +++ b/sophos/main.go @@ -21,6 +21,10 @@ func main() { client := utmconf.NewUTMClient(intKey, "http://"+panelServ) for { + if err := utils.ConnectionChecker(configuration.CHECKCON); err != nil { + utils.Logger.ErrorF("External connection failure detected: %v", err) + } + moduleConfig, err := client.GetUTMConfig(enum.SOPHOS) if err != nil { if strings.Contains(err.Error(), "invalid character '<'") { diff --git a/sophos/utils/check.go b/sophos/utils/check.go new file mode 100644 index 000000000..5ab7c1ccd --- /dev/null +++ b/sophos/utils/check.go @@ -0,0 +1,45 @@ +package utils + +import ( + "context" + "fmt" + "net/http" + "time" +) + +const connectionTimeout = 5 * time.Second + +func ConnectionChecker(url string) error { + checkConn := func() error { + ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout) + defer cancel() + + if err := checkConnection(url, ctx); err != nil { + return fmt.Errorf("connection failed") + } + return nil + } + + if err := Logger.InfiniteRetryIfXError(checkConn, "connection failed"); err != nil { + return err + } + + return nil +} + +func checkConnection(url string, ctx context.Context) error { + client := &http.Client{} + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return err + } + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} From b2ca910286cad2b241cf1efdbccec468926c0f98 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Wed, 12 Mar 2025 20:35:19 -0400 Subject: [PATCH 09/19] Include arm64 agents --- agent-manager/Dockerfile | 2 - agent/{agent => }/README.md | 0 agent/agent/{agent => }/agent.pb.go | 0 agent/agent/agent/agent_config.pb.go | 666 ---------- agent/agent/agent/agent_config_grpc.pb.go | 154 --- agent/agent/agent/agent_malware.pb.go | 1102 ----------------- agent/agent/agent/agent_malware_grpc.pb.go | 262 ---- agent/agent/agent/delete.go | 63 - agent/agent/agent/incident_response.go | 107 -- agent/agent/agent/ping_imp.go | 56 - agent/agent/agent/uninstall.go | 30 - agent/agent/agent/version.go | 30 - agent/agent/{agent => }/agent_grpc.pb.go | 0 agent/agent/beats/beat.go | 69 -- agent/agent/{agent => }/common.pb.go | 0 agent/agent/configuration/const.go | 157 --- agent/agent/conn/conn.go | 63 - agent/agent/delete.go | 44 + agent/agent/filters/beats.go | 54 - agent/agent/filters/cisco.go | 38 - agent/agent/incident_response.go | 132 ++ agent/agent/log-collector-config-sample.json | 71 -- agent/agent/logservice/processor.go | 189 --- agent/agent/main.go | 176 --- agent/agent/modules/template.go | 52 - agent/agent/parser/beats.go | 80 -- agent/agent/{agent => }/ping.pb.go | 0 agent/agent/{agent => }/ping_grpc.pb.go | 0 agent/agent/ping_imp.go | 79 ++ agent/agent/protos/agent_config.proto | 55 - agent/agent/protos/agent_malware.proto | 91 -- agent/agent/redline/redline.go | 56 - agent/agent/{agent => }/register.go | 32 +- agent/agent/serv/run.go | 19 - agent/agent/serv/service.go | 101 -- agent/agent/uninstall.go | 17 + agent/agent/{agent => }/update.go | 19 +- agent/agent/utils/logger.go | 22 - agent/agent/utils/services.go | 184 --- agent/collectors/collectors.go | 68 + agent/{agent/beats => collectors}/filebeat.go | 61 +- .../{agent/beats => collectors}/winlogbeat.go | 51 +- .../{agent/configuration => config}/config.go | 54 +- agent/config/const.go | 132 ++ agent/config/linux_amd64.go | 10 + agent/config/linux_arm64.go | 10 + agent/config/win_amd64.go | 10 + agent/config/win_arm64.go | 10 + agent/conn/conn.go | 118 ++ agent/{agent => }/go.mod | 0 agent/{agent => }/go.sum | 0 agent/installer/README.md | 15 - agent/installer/agent/oldversion.go | 141 --- agent/installer/checkversion/check_version.go | 46 - agent/installer/configuration/const.go | 36 - agent/installer/configuration/env.go | 32 - agent/installer/depend/checkVersions.go | 78 -- agent/installer/depend/dependencies.go | 82 -- agent/installer/depend/schema.go | 35 - agent/installer/go.mod | 43 - agent/installer/go.sum | 98 -- agent/installer/main.go | 120 -- agent/installer/services/configure.go | 48 - agent/installer/services/execBin.go | 31 - agent/installer/utils/beauty.go | 54 - agent/installer/utils/cmd.go | 47 - agent/installer/utils/delay.go | 11 - agent/installer/utils/download.go | 51 - agent/installer/utils/files.go | 96 -- agent/installer/utils/lock.go | 29 - agent/installer/utils/logger.go | 22 - agent/installer/utils/os.go | 30 - agent/installer/utils/ports.go | 19 - agent/installer/utils/process.go | 55 - agent/installer/utils/req.go | 50 - agent/installer/utils/timestamp.go | 8 - agent/installer/utils/tls.go | 27 - agent/{agent => }/logservice/log.pb.go | 0 agent/{agent => }/logservice/log_grpc.pb.go | 0 agent/logservice/processor.go | 190 +++ agent/main.go | 183 +++ agent/models/version.go | 5 + agent/{agent => }/modules/configuration.go | 112 +- agent/{agent => }/modules/modules.go | 50 +- agent/{agent => }/modules/netflow.go | 32 +- agent/{agent => }/modules/syslog.go | 73 +- agent/parser/beats.go | 80 ++ agent/{agent => }/parser/cisco.go | 17 +- agent/{agent => }/parser/netflow.go | 3 +- agent/{agent => }/parser/netflow/dump.go | 4 +- agent/{agent => }/parser/netflow/ipfix.go | 0 agent/{agent => }/parser/netflow/metrics.go | 0 agent/{agent => }/parser/netflow/proto.go | 0 agent/{agent => }/parser/netflow/v1.go | 0 agent/{agent => }/parser/netflow/v5.go | 0 agent/{agent => }/parser/netflow/v6.go | 0 agent/{agent => }/parser/netflow/v7.go | 0 agent/{agent => }/parser/netflow/v9.go | 0 agent/{agent => }/parser/parser.go | 4 +- agent/{agent => }/protos/agent.proto | 0 agent/{agent => }/protos/common.proto | 0 agent/{agent => }/protos/log.proto | 0 agent/{agent => }/protos/ping.proto | 0 agent/redline/README.md | 5 - agent/redline/configuration/const.go | 32 - agent/redline/constants/const.go | 32 - agent/redline/go.mod | 42 - agent/redline/go.sum | 97 -- agent/redline/main.go | 46 - agent/redline/protector/protector.go | 66 - agent/redline/serv/config.go | 17 - agent/redline/serv/install.go | 30 - agent/redline/serv/run.go | 19 - agent/redline/serv/service.go | 54 - agent/redline/serv/uninstall.go | 19 - agent/redline/utils/cmd.go | 47 - agent/redline/utils/files.go | 24 - agent/redline/utils/logger.go | 22 - agent/redline/utils/services.go | 125 -- agent/rsrc_windows_386.syso | Bin 0 -> 29120 bytes agent/rsrc_windows_amd64.syso | Bin 0 -> 29120 bytes agent/self/README.md | 10 - agent/self/config/const.go | 6 + agent/self/config/linux_amd64.go | 8 + agent/self/config/linux_arm64.go | 8 + agent/self/config/win_amd64.go | 8 + agent/self/config/win_arm64.go | 8 + agent/self/configuration/config.go | 32 - agent/self/configuration/const.go | 23 - agent/self/constants/const.go | 23 - agent/self/go.mod | 5 +- agent/self/go.sum | 2 - agent/self/main.go | 57 +- agent/self/rsrc_windows_386.syso | Bin 0 -> 29120 bytes agent/self/rsrc_windows_amd64.syso | Bin 0 -> 29120 bytes agent/self/update/schema.go | 8 - agent/self/update/update.go | 27 +- agent/self/utils/delay.go | 11 - agent/self/utils/download.go | 51 - agent/self/utils/files.go | 47 +- agent/self/utils/lock.go | 18 - agent/self/utils/logger.go | 8 +- agent/self/utils/services.go | 21 +- agent/self/utils/timestamp.go | 8 - agent/serv/clean-old.go | 65 + agent/{agent => }/serv/config.go | 1 + agent/{agent => }/serv/install.go | 16 +- agent/serv/run.go | 19 + agent/serv/service.go | 62 + agent/{agent => }/serv/uninstall.go | 8 +- agent/{agent => }/templates/filebeat.yml | 0 agent/{agent => }/templates/winlogbeat.yml | 0 agent/updater/README.md | 9 - agent/updater/configuration/config.go | 42 - agent/updater/configuration/const.go | 70 -- agent/updater/go.mod | 43 - agent/updater/go.sum | 99 -- agent/updater/main.go | 55 - agent/updater/serv/config.go | 17 - agent/updater/serv/install.go | 31 - agent/updater/serv/run.go | 20 - agent/updater/serv/service.go | 63 - agent/updater/serv/uninstall.go | 20 - agent/updater/updates/schema.go | 29 - agent/updater/updates/service.go | 164 --- agent/updater/updates/update.go | 48 - agent/updater/updates/version.go | 85 -- agent/updater/utils/cmd.go | 50 - agent/updater/utils/delay.go | 12 - agent/updater/utils/download.go | 43 - agent/updater/utils/files.go | 99 -- agent/updater/utils/lock.go | 31 - agent/updater/utils/logger.go | 22 - agent/updater/utils/req.go | 51 - agent/updater/utils/services.go | 146 --- agent/updater/utils/timestamp.go | 9 - agent/updates/dependencies.go | 60 + agent/updates/update.go | 73 ++ agent/{agent => }/utils/address.go | 0 agent/utils/banner.go | 17 + agent/{agent => }/utils/certs.go | 0 agent/{agent => }/utils/cmd.go | 0 agent/{agent => }/utils/crypt.go | 0 agent/{agent => }/utils/delay.go | 0 agent/utils/download.go | 53 + agent/{agent => }/utils/files.go | 40 +- agent/{agent => }/utils/host.go | 0 agent/{agent => }/utils/log.go | 23 - agent/utils/logger.go | 20 + agent/{agent => }/utils/os.go | 0 agent/utils/port.go | 29 + agent/utils/req.go | 58 + .../utils/service.go => utils/services.go} | 62 +- agent/{updater => }/utils/tls.go | 15 +- agent/{agent => }/utils/watcher.go | 14 +- .../utils/unzip.go => utils/zip.go} | 1 - agent/version.json | 3 + agent/versions.json | 5 - 198 files changed, 1960 insertions(+), 7861 deletions(-) rename agent/{agent => }/README.md (100%) rename agent/agent/{agent => }/agent.pb.go (100%) delete mode 100644 agent/agent/agent/agent_config.pb.go delete mode 100644 agent/agent/agent/agent_config_grpc.pb.go delete mode 100644 agent/agent/agent/agent_malware.pb.go delete mode 100644 agent/agent/agent/agent_malware_grpc.pb.go delete mode 100644 agent/agent/agent/delete.go delete mode 100644 agent/agent/agent/incident_response.go delete mode 100644 agent/agent/agent/ping_imp.go delete mode 100644 agent/agent/agent/uninstall.go delete mode 100644 agent/agent/agent/version.go rename agent/agent/{agent => }/agent_grpc.pb.go (100%) delete mode 100644 agent/agent/beats/beat.go rename agent/agent/{agent => }/common.pb.go (100%) delete mode 100644 agent/agent/configuration/const.go delete mode 100644 agent/agent/conn/conn.go create mode 100644 agent/agent/delete.go delete mode 100644 agent/agent/filters/beats.go delete mode 100644 agent/agent/filters/cisco.go create mode 100644 agent/agent/incident_response.go delete mode 100644 agent/agent/log-collector-config-sample.json delete mode 100644 agent/agent/logservice/processor.go delete mode 100644 agent/agent/main.go delete mode 100644 agent/agent/modules/template.go delete mode 100644 agent/agent/parser/beats.go rename agent/agent/{agent => }/ping.pb.go (100%) rename agent/agent/{agent => }/ping_grpc.pb.go (100%) create mode 100644 agent/agent/ping_imp.go delete mode 100644 agent/agent/protos/agent_config.proto delete mode 100644 agent/agent/protos/agent_malware.proto delete mode 100644 agent/agent/redline/redline.go rename agent/agent/{agent => }/register.go (60%) delete mode 100644 agent/agent/serv/run.go delete mode 100644 agent/agent/serv/service.go create mode 100644 agent/agent/uninstall.go rename agent/agent/{agent => }/update.go (51%) delete mode 100644 agent/agent/utils/logger.go delete mode 100644 agent/agent/utils/services.go create mode 100644 agent/collectors/collectors.go rename agent/{agent/beats => collectors}/filebeat.go (67%) rename agent/{agent/beats => collectors}/winlogbeat.go (60%) rename agent/{agent/configuration => config}/config.go (69%) create mode 100644 agent/config/const.go create mode 100644 agent/config/linux_amd64.go create mode 100644 agent/config/linux_arm64.go create mode 100644 agent/config/win_amd64.go create mode 100644 agent/config/win_arm64.go create mode 100644 agent/conn/conn.go rename agent/{agent => }/go.mod (100%) rename agent/{agent => }/go.sum (100%) delete mode 100644 agent/installer/README.md delete mode 100644 agent/installer/agent/oldversion.go delete mode 100644 agent/installer/checkversion/check_version.go delete mode 100644 agent/installer/configuration/const.go delete mode 100644 agent/installer/configuration/env.go delete mode 100644 agent/installer/depend/checkVersions.go delete mode 100644 agent/installer/depend/dependencies.go delete mode 100644 agent/installer/depend/schema.go delete mode 100644 agent/installer/go.mod delete mode 100644 agent/installer/go.sum delete mode 100644 agent/installer/main.go delete mode 100644 agent/installer/services/configure.go delete mode 100644 agent/installer/services/execBin.go delete mode 100644 agent/installer/utils/beauty.go delete mode 100644 agent/installer/utils/cmd.go delete mode 100644 agent/installer/utils/delay.go delete mode 100644 agent/installer/utils/download.go delete mode 100644 agent/installer/utils/files.go delete mode 100644 agent/installer/utils/lock.go delete mode 100644 agent/installer/utils/logger.go delete mode 100644 agent/installer/utils/os.go delete mode 100644 agent/installer/utils/ports.go delete mode 100644 agent/installer/utils/process.go delete mode 100644 agent/installer/utils/req.go delete mode 100644 agent/installer/utils/timestamp.go delete mode 100644 agent/installer/utils/tls.go rename agent/{agent => }/logservice/log.pb.go (100%) rename agent/{agent => }/logservice/log_grpc.pb.go (100%) create mode 100644 agent/logservice/processor.go create mode 100644 agent/main.go create mode 100644 agent/models/version.go rename agent/{agent => }/modules/configuration.go (51%) rename agent/{agent => }/modules/modules.go (60%) rename agent/{agent => }/modules/netflow.go (76%) rename agent/{agent => }/modules/syslog.go (76%) create mode 100644 agent/parser/beats.go rename agent/{agent => }/parser/cisco.go (60%) rename agent/{agent => }/parser/netflow.go (90%) rename agent/{agent => }/parser/netflow/dump.go (76%) rename agent/{agent => }/parser/netflow/ipfix.go (100%) rename agent/{agent => }/parser/netflow/metrics.go (100%) rename agent/{agent => }/parser/netflow/proto.go (100%) rename agent/{agent => }/parser/netflow/v1.go (100%) rename agent/{agent => }/parser/netflow/v5.go (100%) rename agent/{agent => }/parser/netflow/v6.go (100%) rename agent/{agent => }/parser/netflow/v7.go (100%) rename agent/{agent => }/parser/netflow/v9.go (100%) rename agent/{agent => }/parser/parser.go (67%) rename agent/{agent => }/protos/agent.proto (100%) rename agent/{agent => }/protos/common.proto (100%) rename agent/{agent => }/protos/log.proto (100%) rename agent/{agent => }/protos/ping.proto (100%) delete mode 100644 agent/redline/README.md delete mode 100644 agent/redline/configuration/const.go delete mode 100644 agent/redline/constants/const.go delete mode 100644 agent/redline/go.mod delete mode 100644 agent/redline/go.sum delete mode 100644 agent/redline/main.go delete mode 100644 agent/redline/protector/protector.go delete mode 100644 agent/redline/serv/config.go delete mode 100644 agent/redline/serv/install.go delete mode 100644 agent/redline/serv/run.go delete mode 100644 agent/redline/serv/service.go delete mode 100644 agent/redline/serv/uninstall.go delete mode 100644 agent/redline/utils/cmd.go delete mode 100644 agent/redline/utils/files.go delete mode 100644 agent/redline/utils/logger.go delete mode 100644 agent/redline/utils/services.go create mode 100644 agent/rsrc_windows_386.syso create mode 100644 agent/rsrc_windows_amd64.syso delete mode 100644 agent/self/README.md create mode 100644 agent/self/config/const.go create mode 100644 agent/self/config/linux_amd64.go create mode 100644 agent/self/config/linux_arm64.go create mode 100644 agent/self/config/win_amd64.go create mode 100644 agent/self/config/win_arm64.go delete mode 100644 agent/self/configuration/config.go delete mode 100644 agent/self/configuration/const.go delete mode 100644 agent/self/constants/const.go create mode 100644 agent/self/rsrc_windows_386.syso create mode 100644 agent/self/rsrc_windows_amd64.syso delete mode 100644 agent/self/update/schema.go delete mode 100644 agent/self/utils/delay.go delete mode 100644 agent/self/utils/download.go delete mode 100644 agent/self/utils/lock.go delete mode 100644 agent/self/utils/timestamp.go create mode 100644 agent/serv/clean-old.go rename agent/{agent => }/serv/config.go (91%) rename agent/{agent => }/serv/install.go (50%) create mode 100644 agent/serv/run.go create mode 100644 agent/serv/service.go rename agent/{agent => }/serv/uninstall.go (50%) rename agent/{agent => }/templates/filebeat.yml (100%) rename agent/{agent => }/templates/winlogbeat.yml (100%) delete mode 100644 agent/updater/README.md delete mode 100644 agent/updater/configuration/config.go delete mode 100644 agent/updater/configuration/const.go delete mode 100644 agent/updater/go.mod delete mode 100644 agent/updater/go.sum delete mode 100644 agent/updater/main.go delete mode 100644 agent/updater/serv/config.go delete mode 100644 agent/updater/serv/install.go delete mode 100644 agent/updater/serv/run.go delete mode 100644 agent/updater/serv/service.go delete mode 100644 agent/updater/serv/uninstall.go delete mode 100644 agent/updater/updates/schema.go delete mode 100644 agent/updater/updates/service.go delete mode 100644 agent/updater/updates/update.go delete mode 100644 agent/updater/updates/version.go delete mode 100644 agent/updater/utils/cmd.go delete mode 100644 agent/updater/utils/delay.go delete mode 100644 agent/updater/utils/download.go delete mode 100644 agent/updater/utils/files.go delete mode 100644 agent/updater/utils/lock.go delete mode 100644 agent/updater/utils/logger.go delete mode 100644 agent/updater/utils/req.go delete mode 100644 agent/updater/utils/services.go delete mode 100644 agent/updater/utils/timestamp.go create mode 100644 agent/updates/dependencies.go create mode 100644 agent/updates/update.go rename agent/{agent => }/utils/address.go (100%) create mode 100644 agent/utils/banner.go rename agent/{agent => }/utils/certs.go (100%) rename agent/{agent => }/utils/cmd.go (100%) rename agent/{agent => }/utils/crypt.go (100%) rename agent/{agent => }/utils/delay.go (100%) create mode 100644 agent/utils/download.go rename agent/{agent => }/utils/files.go (68%) rename agent/{agent => }/utils/host.go (100%) rename agent/{agent => }/utils/log.go (61%) create mode 100644 agent/utils/logger.go rename agent/{agent => }/utils/os.go (100%) create mode 100644 agent/utils/port.go create mode 100644 agent/utils/req.go rename agent/{installer/utils/service.go => utils/services.go} (53%) rename agent/{updater => }/utils/tls.go (54%) rename agent/{agent => }/utils/watcher.go (85%) rename agent/{installer/utils/unzip.go => utils/zip.go} (92%) create mode 100644 agent/version.json delete mode 100644 agent/versions.json diff --git a/agent-manager/Dockerfile b/agent-manager/Dockerfile index b86c1aaea..ab3514eff 100644 --- a/agent-manager/Dockerfile +++ b/agent-manager/Dockerfile @@ -1,8 +1,6 @@ FROM ubuntu:22.04 COPY ./agent-manager/agent-manager /app/ -COPY ./agent/utmstack_agent /dependencies/agent/ -COPY ./agent/utmstack_agent.exe /dependencies/agent/ COPY ./agent/dependencies/ /dependencies/agent/ COPY ./collector/dependencies/ /dependencies/collector/ diff --git a/agent/agent/README.md b/agent/README.md similarity index 100% rename from agent/agent/README.md rename to agent/README.md diff --git a/agent/agent/agent/agent.pb.go b/agent/agent/agent.pb.go similarity index 100% rename from agent/agent/agent/agent.pb.go rename to agent/agent/agent.pb.go diff --git a/agent/agent/agent/agent_config.pb.go b/agent/agent/agent/agent_config.pb.go deleted file mode 100644 index de13d7db6..000000000 --- a/agent/agent/agent/agent_config.pb.go +++ /dev/null @@ -1,666 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v3.21.12 -// source: agent_config.proto - -package agent - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type AgentModule struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - AgentId uint32 `protobuf:"varint,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` - ShortName string `protobuf:"bytes,3,opt,name=short_name,json=shortName,proto3" json:"short_name,omitempty"` - LargeName string `protobuf:"bytes,4,opt,name=large_name,json=largeName,proto3" json:"large_name,omitempty"` - Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` - Enabled bool `protobuf:"varint,6,opt,name=enabled,proto3" json:"enabled,omitempty"` - AllowDisabled bool `protobuf:"varint,7,opt,name=allow_disabled,json=allowDisabled,proto3" json:"allow_disabled,omitempty"` - ModuleConfigs []*AgentModuleConfiguration `protobuf:"bytes,8,rep,name=module_configs,json=moduleConfigs,proto3" json:"module_configs,omitempty"` -} - -func (x *AgentModule) Reset() { - *x = AgentModule{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_config_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AgentModule) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AgentModule) ProtoMessage() {} - -func (x *AgentModule) ProtoReflect() protoreflect.Message { - mi := &file_agent_config_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AgentModule.ProtoReflect.Descriptor instead. -func (*AgentModule) Descriptor() ([]byte, []int) { - return file_agent_config_proto_rawDescGZIP(), []int{0} -} - -func (x *AgentModule) GetId() uint32 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *AgentModule) GetAgentId() uint32 { - if x != nil { - return x.AgentId - } - return 0 -} - -func (x *AgentModule) GetShortName() string { - if x != nil { - return x.ShortName - } - return "" -} - -func (x *AgentModule) GetLargeName() string { - if x != nil { - return x.LargeName - } - return "" -} - -func (x *AgentModule) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *AgentModule) GetEnabled() bool { - if x != nil { - return x.Enabled - } - return false -} - -func (x *AgentModule) GetAllowDisabled() bool { - if x != nil { - return x.AllowDisabled - } - return false -} - -func (x *AgentModule) GetModuleConfigs() []*AgentModuleConfiguration { - if x != nil { - return x.ModuleConfigs - } - return nil -} - -type UpdateAgentModule struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - AgentModuleShort string `protobuf:"bytes,1,opt,name=agent_module_short,json=agentModuleShort,proto3" json:"agent_module_short,omitempty"` - ConfKey string `protobuf:"bytes,4,opt,name=conf_key,json=confKey,proto3" json:"conf_key,omitempty"` - ConfValue string `protobuf:"bytes,5,opt,name=conf_value,json=confValue,proto3" json:"conf_value,omitempty"` -} - -func (x *UpdateAgentModule) Reset() { - *x = UpdateAgentModule{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_config_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UpdateAgentModule) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateAgentModule) ProtoMessage() {} - -func (x *UpdateAgentModule) ProtoReflect() protoreflect.Message { - mi := &file_agent_config_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateAgentModule.ProtoReflect.Descriptor instead. -func (*UpdateAgentModule) Descriptor() ([]byte, []int) { - return file_agent_config_proto_rawDescGZIP(), []int{1} -} - -func (x *UpdateAgentModule) GetAgentModuleShort() string { - if x != nil { - return x.AgentModuleShort - } - return "" -} - -func (x *UpdateAgentModule) GetConfKey() string { - if x != nil { - return x.ConfKey - } - return "" -} - -func (x *UpdateAgentModule) GetConfValue() string { - if x != nil { - return x.ConfValue - } - return "" -} - -type AgentModuleConfiguration struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - AgentModuleId uint32 `protobuf:"varint,2,opt,name=agent_module_id,json=agentModuleId,proto3" json:"agent_module_id,omitempty"` - ShortName string `protobuf:"bytes,3,opt,name=short_name,json=shortName,proto3" json:"short_name,omitempty"` - ConfKey string `protobuf:"bytes,4,opt,name=conf_key,json=confKey,proto3" json:"conf_key,omitempty"` - ConfValue string `protobuf:"bytes,5,opt,name=conf_value,json=confValue,proto3" json:"conf_value,omitempty"` - ConfName string `protobuf:"bytes,6,opt,name=conf_name,json=confName,proto3" json:"conf_name,omitempty"` - ConfDescription string `protobuf:"bytes,7,opt,name=conf_description,json=confDescription,proto3" json:"conf_description,omitempty"` - ConfDatatype string `protobuf:"bytes,8,opt,name=conf_datatype,json=confDatatype,proto3" json:"conf_datatype,omitempty"` - ConfRequired bool `protobuf:"varint,9,opt,name=conf_required,json=confRequired,proto3" json:"conf_required,omitempty"` - ConfRegex string `protobuf:"bytes,10,opt,name=conf_regex,json=confRegex,proto3" json:"conf_regex,omitempty"` -} - -func (x *AgentModuleConfiguration) Reset() { - *x = AgentModuleConfiguration{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_config_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AgentModuleConfiguration) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AgentModuleConfiguration) ProtoMessage() {} - -func (x *AgentModuleConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_agent_config_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AgentModuleConfiguration.ProtoReflect.Descriptor instead. -func (*AgentModuleConfiguration) Descriptor() ([]byte, []int) { - return file_agent_config_proto_rawDescGZIP(), []int{2} -} - -func (x *AgentModuleConfiguration) GetId() uint32 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *AgentModuleConfiguration) GetAgentModuleId() uint32 { - if x != nil { - return x.AgentModuleId - } - return 0 -} - -func (x *AgentModuleConfiguration) GetShortName() string { - if x != nil { - return x.ShortName - } - return "" -} - -func (x *AgentModuleConfiguration) GetConfKey() string { - if x != nil { - return x.ConfKey - } - return "" -} - -func (x *AgentModuleConfiguration) GetConfValue() string { - if x != nil { - return x.ConfValue - } - return "" -} - -func (x *AgentModuleConfiguration) GetConfName() string { - if x != nil { - return x.ConfName - } - return "" -} - -func (x *AgentModuleConfiguration) GetConfDescription() string { - if x != nil { - return x.ConfDescription - } - return "" -} - -func (x *AgentModuleConfiguration) GetConfDatatype() string { - if x != nil { - return x.ConfDatatype - } - return "" -} - -func (x *AgentModuleConfiguration) GetConfRequired() bool { - if x != nil { - return x.ConfRequired - } - return false -} - -func (x *AgentModuleConfiguration) GetConfRegex() string { - if x != nil { - return x.ConfRegex - } - return "" -} - -type UpdateConfigResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Accepted string `protobuf:"bytes,1,opt,name=accepted,proto3" json:"accepted,omitempty"` -} - -func (x *UpdateConfigResponse) Reset() { - *x = UpdateConfigResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_config_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UpdateConfigResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateConfigResponse) ProtoMessage() {} - -func (x *UpdateConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_config_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateConfigResponse.ProtoReflect.Descriptor instead. -func (*UpdateConfigResponse) Descriptor() ([]byte, []int) { - return file_agent_config_proto_rawDescGZIP(), []int{3} -} - -func (x *UpdateConfigResponse) GetAccepted() string { - if x != nil { - return x.Accepted - } - return "" -} - -// ListAgentsRequest message definition -type ListAgentsModulesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - AgentKey string `protobuf:"bytes,2,opt,name=agent_key,json=agentKey,proto3" json:"agent_key,omitempty"` -} - -func (x *ListAgentsModulesRequest) Reset() { - *x = ListAgentsModulesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_config_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListAgentsModulesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListAgentsModulesRequest) ProtoMessage() {} - -func (x *ListAgentsModulesRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_config_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListAgentsModulesRequest.ProtoReflect.Descriptor instead. -func (*ListAgentsModulesRequest) Descriptor() ([]byte, []int) { - return file_agent_config_proto_rawDescGZIP(), []int{4} -} - -func (x *ListAgentsModulesRequest) GetAgentKey() string { - if x != nil { - return x.AgentKey - } - return "" -} - -// ListAgentsResponse message definition -type ListAgentsModulesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Modules []*AgentModule `protobuf:"bytes,1,rep,name=modules,proto3" json:"modules,omitempty"` -} - -func (x *ListAgentsModulesResponse) Reset() { - *x = ListAgentsModulesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_config_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListAgentsModulesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListAgentsModulesResponse) ProtoMessage() {} - -func (x *ListAgentsModulesResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_config_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListAgentsModulesResponse.ProtoReflect.Descriptor instead. -func (*ListAgentsModulesResponse) Descriptor() ([]byte, []int) { - return file_agent_config_proto_rawDescGZIP(), []int{5} -} - -func (x *ListAgentsModulesResponse) GetModules() []*AgentModule { - if x != nil { - return x.Modules - } - return nil -} - -var File_agent_config_proto protoreflect.FileDescriptor - -var file_agent_config_proto_rawDesc = []byte{ - 0x0a, 0x12, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x22, 0xa1, 0x02, 0x0a, 0x0b, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x6f, 0x72, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x61, 0x72, 0x67, 0x65, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x44, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x46, 0x0a, 0x0e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, - 0x7b, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x10, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x68, 0x6f, - 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, - 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xdc, 0x02, 0x0a, - 0x18, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x49, - 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x63, - 0x6f, 0x6e, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, - 0x6e, 0x66, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, - 0x6f, 0x6e, 0x66, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x5f, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x44, - 0x61, 0x74, 0x61, 0x74, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x5f, - 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, - 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, - 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x67, 0x65, 0x78, 0x22, 0x32, 0x0a, 0x14, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x22, - 0x37, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, - 0x6c, 0x65, 0x73, 0x32, 0xca, 0x01, 0x0a, 0x12, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x55, 0x0a, 0x0e, 0x47, 0x65, - 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1f, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x4d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, - 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x5d, 0x0a, 0x17, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1f, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1b, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, - 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, - 0x74, 0x6d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x55, 0x54, 0x4d, 0x53, 0x74, 0x61, 0x63, 0x6b, - 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_agent_config_proto_rawDescOnce sync.Once - file_agent_config_proto_rawDescData = file_agent_config_proto_rawDesc -) - -func file_agent_config_proto_rawDescGZIP() []byte { - file_agent_config_proto_rawDescOnce.Do(func() { - file_agent_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_agent_config_proto_rawDescData) - }) - return file_agent_config_proto_rawDescData -} - -var file_agent_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_agent_config_proto_goTypes = []interface{}{ - (*AgentModule)(nil), // 0: agent.AgentModule - (*UpdateAgentModule)(nil), // 1: agent.UpdateAgentModule - (*AgentModuleConfiguration)(nil), // 2: agent.AgentModuleConfiguration - (*UpdateConfigResponse)(nil), // 3: agent.UpdateConfigResponse - (*ListAgentsModulesRequest)(nil), // 4: agent.ListAgentsModulesRequest - (*ListAgentsModulesResponse)(nil), // 5: agent.ListAgentsModulesResponse -} -var file_agent_config_proto_depIdxs = []int32{ - 2, // 0: agent.AgentModule.module_configs:type_name -> agent.AgentModuleConfiguration - 0, // 1: agent.ListAgentsModulesResponse.modules:type_name -> agent.AgentModule - 4, // 2: agent.AgentConfigService.GetAgentConfig:input_type -> agent.ListAgentsModulesRequest - 2, // 3: agent.AgentConfigService.AgentModuleUpdateStream:input_type -> agent.AgentModuleConfiguration - 5, // 4: agent.AgentConfigService.GetAgentConfig:output_type -> agent.ListAgentsModulesResponse - 3, // 5: agent.AgentConfigService.AgentModuleUpdateStream:output_type -> agent.UpdateConfigResponse - 4, // [4:6] is the sub-list for method output_type - 2, // [2:4] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name -} - -func init() { file_agent_config_proto_init() } -func file_agent_config_proto_init() { - if File_agent_config_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_agent_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AgentModule); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateAgentModule); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AgentModuleConfiguration); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateConfigResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListAgentsModulesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListAgentsModulesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_agent_config_proto_rawDesc, - NumEnums: 0, - NumMessages: 6, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_agent_config_proto_goTypes, - DependencyIndexes: file_agent_config_proto_depIdxs, - MessageInfos: file_agent_config_proto_msgTypes, - }.Build() - File_agent_config_proto = out.File - file_agent_config_proto_rawDesc = nil - file_agent_config_proto_goTypes = nil - file_agent_config_proto_depIdxs = nil -} diff --git a/agent/agent/agent/agent_config_grpc.pb.go b/agent/agent/agent/agent_config_grpc.pb.go deleted file mode 100644 index 29d3b5235..000000000 --- a/agent/agent/agent/agent_config_grpc.pb.go +++ /dev/null @@ -1,154 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v3.21.12 -// source: agent_config.proto - -package agent - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.64.0 or later. -const _ = grpc.SupportPackageIsVersion9 - -const ( - AgentConfigService_GetAgentConfig_FullMethodName = "/agent.AgentConfigService/GetAgentConfig" - AgentConfigService_AgentModuleUpdateStream_FullMethodName = "/agent.AgentConfigService/AgentModuleUpdateStream" -) - -// AgentConfigServiceClient is the client API for AgentConfigService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type AgentConfigServiceClient interface { - GetAgentConfig(ctx context.Context, in *ListAgentsModulesRequest, opts ...grpc.CallOption) (*ListAgentsModulesResponse, error) - AgentModuleUpdateStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AgentModuleConfiguration, UpdateConfigResponse], error) -} - -type agentConfigServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewAgentConfigServiceClient(cc grpc.ClientConnInterface) AgentConfigServiceClient { - return &agentConfigServiceClient{cc} -} - -func (c *agentConfigServiceClient) GetAgentConfig(ctx context.Context, in *ListAgentsModulesRequest, opts ...grpc.CallOption) (*ListAgentsModulesResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(ListAgentsModulesResponse) - err := c.cc.Invoke(ctx, AgentConfigService_GetAgentConfig_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *agentConfigServiceClient) AgentModuleUpdateStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AgentModuleConfiguration, UpdateConfigResponse], error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - stream, err := c.cc.NewStream(ctx, &AgentConfigService_ServiceDesc.Streams[0], AgentConfigService_AgentModuleUpdateStream_FullMethodName, cOpts...) - if err != nil { - return nil, err - } - x := &grpc.GenericClientStream[AgentModuleConfiguration, UpdateConfigResponse]{ClientStream: stream} - return x, nil -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type AgentConfigService_AgentModuleUpdateStreamClient = grpc.BidiStreamingClient[AgentModuleConfiguration, UpdateConfigResponse] - -// AgentConfigServiceServer is the server API for AgentConfigService service. -// All implementations must embed UnimplementedAgentConfigServiceServer -// for forward compatibility. -type AgentConfigServiceServer interface { - GetAgentConfig(context.Context, *ListAgentsModulesRequest) (*ListAgentsModulesResponse, error) - AgentModuleUpdateStream(grpc.BidiStreamingServer[AgentModuleConfiguration, UpdateConfigResponse]) error - mustEmbedUnimplementedAgentConfigServiceServer() -} - -// UnimplementedAgentConfigServiceServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedAgentConfigServiceServer struct{} - -func (UnimplementedAgentConfigServiceServer) GetAgentConfig(context.Context, *ListAgentsModulesRequest) (*ListAgentsModulesResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAgentConfig not implemented") -} -func (UnimplementedAgentConfigServiceServer) AgentModuleUpdateStream(grpc.BidiStreamingServer[AgentModuleConfiguration, UpdateConfigResponse]) error { - return status.Errorf(codes.Unimplemented, "method AgentModuleUpdateStream not implemented") -} -func (UnimplementedAgentConfigServiceServer) mustEmbedUnimplementedAgentConfigServiceServer() {} -func (UnimplementedAgentConfigServiceServer) testEmbeddedByValue() {} - -// UnsafeAgentConfigServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to AgentConfigServiceServer will -// result in compilation errors. -type UnsafeAgentConfigServiceServer interface { - mustEmbedUnimplementedAgentConfigServiceServer() -} - -func RegisterAgentConfigServiceServer(s grpc.ServiceRegistrar, srv AgentConfigServiceServer) { - // If the following call pancis, it indicates UnimplementedAgentConfigServiceServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&AgentConfigService_ServiceDesc, srv) -} - -func _AgentConfigService_GetAgentConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListAgentsModulesRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AgentConfigServiceServer).GetAgentConfig(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: AgentConfigService_GetAgentConfig_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AgentConfigServiceServer).GetAgentConfig(ctx, req.(*ListAgentsModulesRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _AgentConfigService_AgentModuleUpdateStream_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(AgentConfigServiceServer).AgentModuleUpdateStream(&grpc.GenericServerStream[AgentModuleConfiguration, UpdateConfigResponse]{ServerStream: stream}) -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type AgentConfigService_AgentModuleUpdateStreamServer = grpc.BidiStreamingServer[AgentModuleConfiguration, UpdateConfigResponse] - -// AgentConfigService_ServiceDesc is the grpc.ServiceDesc for AgentConfigService service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var AgentConfigService_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "agent.AgentConfigService", - HandlerType: (*AgentConfigServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetAgentConfig", - Handler: _AgentConfigService_GetAgentConfig_Handler, - }, - }, - Streams: []grpc.StreamDesc{ - { - StreamName: "AgentModuleUpdateStream", - Handler: _AgentConfigService_AgentModuleUpdateStream_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "agent_config.proto", -} diff --git a/agent/agent/agent/agent_malware.pb.go b/agent/agent/agent/agent_malware.pb.go deleted file mode 100644 index c56a676d2..000000000 --- a/agent/agent/agent/agent_malware.pb.go +++ /dev/null @@ -1,1102 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v3.21.12 -// source: agent_malware.proto - -package agent - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type MalwareStatus int32 - -const ( - MalwareStatus_NEW MalwareStatus = 0 - MalwareStatus_DELETED MalwareStatus = 1 - MalwareStatus_EXCLUDED MalwareStatus = 2 - MalwareStatus_RESTORED MalwareStatus = 3 -) - -// Enum value maps for MalwareStatus. -var ( - MalwareStatus_name = map[int32]string{ - 0: "NEW", - 1: "DELETED", - 2: "EXCLUDED", - 3: "RESTORED", - } - MalwareStatus_value = map[string]int32{ - "NEW": 0, - "DELETED": 1, - "EXCLUDED": 2, - "RESTORED": 3, - } -) - -func (x MalwareStatus) Enum() *MalwareStatus { - p := new(MalwareStatus) - *p = x - return p -} - -func (x MalwareStatus) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (MalwareStatus) Descriptor() protoreflect.EnumDescriptor { - return file_agent_malware_proto_enumTypes[0].Descriptor() -} - -func (MalwareStatus) Type() protoreflect.EnumType { - return &file_agent_malware_proto_enumTypes[0] -} - -func (x MalwareStatus) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use MalwareStatus.Descriptor instead. -func (MalwareStatus) EnumDescriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{0} -} - -type ListExclusionResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Exclusions []*AgentMalwareExclusion `protobuf:"bytes,1,rep,name=exclusions,proto3" json:"exclusions,omitempty"` -} - -func (x *ListExclusionResponse) Reset() { - *x = ListExclusionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListExclusionResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListExclusionResponse) ProtoMessage() {} - -func (x *ListExclusionResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListExclusionResponse.ProtoReflect.Descriptor instead. -func (*ListExclusionResponse) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{0} -} - -func (x *ListExclusionResponse) GetExclusions() []*AgentMalwareExclusion { - if x != nil { - return x.Exclusions - } - return nil -} - -type ListExclusionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - AgentId int64 `protobuf:"varint,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` -} - -func (x *ListExclusionRequest) Reset() { - *x = ListExclusionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListExclusionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListExclusionRequest) ProtoMessage() {} - -func (x *ListExclusionRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListExclusionRequest.ProtoReflect.Descriptor instead. -func (*ListExclusionRequest) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{1} -} - -func (x *ListExclusionRequest) GetAgentId() int64 { - if x != nil { - return x.AgentId - } - return 0 -} - -type ChangeStatusRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - MalwareId string `protobuf:"bytes,1,opt,name=malware_id,json=malwareId,proto3" json:"malware_id,omitempty"` - Status MalwareStatus `protobuf:"varint,2,opt,name=status,proto3,enum=agent.MalwareStatus" json:"status,omitempty"` -} - -func (x *ChangeStatusRequest) Reset() { - *x = ChangeStatusRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ChangeStatusRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ChangeStatusRequest) ProtoMessage() {} - -func (x *ChangeStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ChangeStatusRequest.ProtoReflect.Descriptor instead. -func (*ChangeStatusRequest) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{2} -} - -func (x *ChangeStatusRequest) GetMalwareId() string { - if x != nil { - return x.MalwareId - } - return "" -} - -func (x *ChangeStatusRequest) GetStatus() MalwareStatus { - if x != nil { - return x.Status - } - return MalwareStatus_NEW -} - -type AgentMalwareDetection struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - AgentId uint32 `protobuf:"varint,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` - FilePath string `protobuf:"bytes,3,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"` - Sha256 string `protobuf:"bytes,4,opt,name=sha256,proto3" json:"sha256,omitempty"` - Md5 string `protobuf:"bytes,5,opt,name=md5,proto3" json:"md5,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Status MalwareStatus `protobuf:"varint,7,opt,name=status,proto3,enum=agent.MalwareStatus" json:"status,omitempty"` -} - -func (x *AgentMalwareDetection) Reset() { - *x = AgentMalwareDetection{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AgentMalwareDetection) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AgentMalwareDetection) ProtoMessage() {} - -func (x *AgentMalwareDetection) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AgentMalwareDetection.ProtoReflect.Descriptor instead. -func (*AgentMalwareDetection) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{3} -} - -func (x *AgentMalwareDetection) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *AgentMalwareDetection) GetAgentId() uint32 { - if x != nil { - return x.AgentId - } - return 0 -} - -func (x *AgentMalwareDetection) GetFilePath() string { - if x != nil { - return x.FilePath - } - return "" -} - -func (x *AgentMalwareDetection) GetSha256() string { - if x != nil { - return x.Sha256 - } - return "" -} - -func (x *AgentMalwareDetection) GetMd5() string { - if x != nil { - return x.Md5 - } - return "" -} - -func (x *AgentMalwareDetection) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *AgentMalwareDetection) GetStatus() MalwareStatus { - if x != nil { - return x.Status - } - return MalwareStatus_NEW -} - -type AgentMalwareHistory struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - MalwareId uint32 `protobuf:"varint,2,opt,name=malware_id,json=malwareId,proto3" json:"malware_id,omitempty"` - PrevStatus MalwareStatus `protobuf:"varint,3,opt,name=prev_status,json=prevStatus,proto3,enum=agent.MalwareStatus" json:"prev_status,omitempty"` - ToStatus MalwareStatus `protobuf:"varint,4,opt,name=to_status,json=toStatus,proto3,enum=agent.MalwareStatus" json:"to_status,omitempty"` - ChangedBy string `protobuf:"bytes,5,opt,name=changed_by,json=changedBy,proto3" json:"changed_by,omitempty"` -} - -func (x *AgentMalwareHistory) Reset() { - *x = AgentMalwareHistory{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AgentMalwareHistory) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AgentMalwareHistory) ProtoMessage() {} - -func (x *AgentMalwareHistory) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AgentMalwareHistory.ProtoReflect.Descriptor instead. -func (*AgentMalwareHistory) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{4} -} - -func (x *AgentMalwareHistory) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *AgentMalwareHistory) GetMalwareId() uint32 { - if x != nil { - return x.MalwareId - } - return 0 -} - -func (x *AgentMalwareHistory) GetPrevStatus() MalwareStatus { - if x != nil { - return x.PrevStatus - } - return MalwareStatus_NEW -} - -func (x *AgentMalwareHistory) GetToStatus() MalwareStatus { - if x != nil { - return x.ToStatus - } - return MalwareStatus_NEW -} - -func (x *AgentMalwareHistory) GetChangedBy() string { - if x != nil { - return x.ChangedBy - } - return "" -} - -type AgentMalwareExclusion struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - ExcludeFilePath string `protobuf:"bytes,2,opt,name=exclude_file_path,json=excludeFilePath,proto3" json:"exclude_file_path,omitempty"` - ExcludedBy string `protobuf:"bytes,3,opt,name=excluded_by,json=excludedBy,proto3" json:"excluded_by,omitempty"` - ExcludeDescription string `protobuf:"bytes,4,opt,name=exclude_description,json=excludeDescription,proto3" json:"exclude_description,omitempty"` - AgentId int64 `protobuf:"varint,5,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` -} - -func (x *AgentMalwareExclusion) Reset() { - *x = AgentMalwareExclusion{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AgentMalwareExclusion) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AgentMalwareExclusion) ProtoMessage() {} - -func (x *AgentMalwareExclusion) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AgentMalwareExclusion.ProtoReflect.Descriptor instead. -func (*AgentMalwareExclusion) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{5} -} - -func (x *AgentMalwareExclusion) GetId() int64 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *AgentMalwareExclusion) GetExcludeFilePath() string { - if x != nil { - return x.ExcludeFilePath - } - return "" -} - -func (x *AgentMalwareExclusion) GetExcludedBy() string { - if x != nil { - return x.ExcludedBy - } - return "" -} - -func (x *AgentMalwareExclusion) GetExcludeDescription() string { - if x != nil { - return x.ExcludeDescription - } - return "" -} - -func (x *AgentMalwareExclusion) GetAgentId() int64 { - if x != nil { - return x.AgentId - } - return 0 -} - -// ListAgentsRequest message definition -type ListMalwareRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PageNumber int32 `protobuf:"varint,1,opt,name=page_number,json=pageNumber,proto3" json:"page_number,omitempty"` - PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - SearchQuery string `protobuf:"bytes,3,opt,name=search_query,json=searchQuery,proto3" json:"search_query,omitempty"` - SortBy []string `protobuf:"bytes,4,rep,name=sort_by,json=sortBy,proto3" json:"sort_by,omitempty"` - SortDescending bool `protobuf:"varint,5,opt,name=sort_descending,json=sortDescending,proto3" json:"sort_descending,omitempty"` -} - -func (x *ListMalwareRequest) Reset() { - *x = ListMalwareRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListMalwareRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListMalwareRequest) ProtoMessage() {} - -func (x *ListMalwareRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListMalwareRequest.ProtoReflect.Descriptor instead. -func (*ListMalwareRequest) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{6} -} - -func (x *ListMalwareRequest) GetPageNumber() int32 { - if x != nil { - return x.PageNumber - } - return 0 -} - -func (x *ListMalwareRequest) GetPageSize() int32 { - if x != nil { - return x.PageSize - } - return 0 -} - -func (x *ListMalwareRequest) GetSearchQuery() string { - if x != nil { - return x.SearchQuery - } - return "" -} - -func (x *ListMalwareRequest) GetSortBy() []string { - if x != nil { - return x.SortBy - } - return nil -} - -func (x *ListMalwareRequest) GetSortDescending() bool { - if x != nil { - return x.SortDescending - } - return false -} - -// ListAgentsResponse message definition -type ListMalwareResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Malware []*AgentMalwareDetection `protobuf:"bytes,1,rep,name=malware,proto3" json:"malware,omitempty"` - TotalPages int32 `protobuf:"varint,2,opt,name=total_pages,json=totalPages,proto3" json:"total_pages,omitempty"` - TotalResults int32 `protobuf:"varint,3,opt,name=total_results,json=totalResults,proto3" json:"total_results,omitempty"` -} - -func (x *ListMalwareResponse) Reset() { - *x = ListMalwareResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListMalwareResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListMalwareResponse) ProtoMessage() {} - -func (x *ListMalwareResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListMalwareResponse.ProtoReflect.Descriptor instead. -func (*ListMalwareResponse) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{7} -} - -func (x *ListMalwareResponse) GetMalware() []*AgentMalwareDetection { - if x != nil { - return x.Malware - } - return nil -} - -func (x *ListMalwareResponse) GetTotalPages() int32 { - if x != nil { - return x.TotalPages - } - return 0 -} - -func (x *ListMalwareResponse) GetTotalResults() int32 { - if x != nil { - return x.TotalResults - } - return 0 -} - -type ListMalwareHistoryRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PageNumber int32 `protobuf:"varint,1,opt,name=page_number,json=pageNumber,proto3" json:"page_number,omitempty"` - PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` - SearchQuery string `protobuf:"bytes,3,opt,name=search_query,json=searchQuery,proto3" json:"search_query,omitempty"` - SortBy []string `protobuf:"bytes,4,rep,name=sort_by,json=sortBy,proto3" json:"sort_by,omitempty"` - SortDescending bool `protobuf:"varint,5,opt,name=sort_descending,json=sortDescending,proto3" json:"sort_descending,omitempty"` -} - -func (x *ListMalwareHistoryRequest) Reset() { - *x = ListMalwareHistoryRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListMalwareHistoryRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListMalwareHistoryRequest) ProtoMessage() {} - -func (x *ListMalwareHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListMalwareHistoryRequest.ProtoReflect.Descriptor instead. -func (*ListMalwareHistoryRequest) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{8} -} - -func (x *ListMalwareHistoryRequest) GetPageNumber() int32 { - if x != nil { - return x.PageNumber - } - return 0 -} - -func (x *ListMalwareHistoryRequest) GetPageSize() int32 { - if x != nil { - return x.PageSize - } - return 0 -} - -func (x *ListMalwareHistoryRequest) GetSearchQuery() string { - if x != nil { - return x.SearchQuery - } - return "" -} - -func (x *ListMalwareHistoryRequest) GetSortBy() []string { - if x != nil { - return x.SortBy - } - return nil -} - -func (x *ListMalwareHistoryRequest) GetSortDescending() bool { - if x != nil { - return x.SortDescending - } - return false -} - -// ListAgentsResponse message definition -type ListMalwareHistoryResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Malware []*AgentMalwareHistory `protobuf:"bytes,1,rep,name=malware,proto3" json:"malware,omitempty"` - TotalPages int32 `protobuf:"varint,2,opt,name=total_pages,json=totalPages,proto3" json:"total_pages,omitempty"` - TotalResults int32 `protobuf:"varint,3,opt,name=total_results,json=totalResults,proto3" json:"total_results,omitempty"` -} - -func (x *ListMalwareHistoryResponse) Reset() { - *x = ListMalwareHistoryResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_agent_malware_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListMalwareHistoryResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListMalwareHistoryResponse) ProtoMessage() {} - -func (x *ListMalwareHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_agent_malware_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListMalwareHistoryResponse.ProtoReflect.Descriptor instead. -func (*ListMalwareHistoryResponse) Descriptor() ([]byte, []int) { - return file_agent_malware_proto_rawDescGZIP(), []int{9} -} - -func (x *ListMalwareHistoryResponse) GetMalware() []*AgentMalwareHistory { - if x != nil { - return x.Malware - } - return nil -} - -func (x *ListMalwareHistoryResponse) GetTotalPages() int32 { - if x != nil { - return x.TotalPages - } - return 0 -} - -func (x *ListMalwareHistoryResponse) GetTotalResults() int32 { - if x != nil { - return x.TotalResults - } - return 0 -} - -var File_agent_malware_proto protoreflect.FileDescriptor - -var file_agent_malware_proto_rawDesc = []byte{ - 0x0a, 0x13, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x15, - 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0a, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x45, 0x78, - 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0x31, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x78, 0x63, 0x6c, 0x75, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, - 0x0a, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xd9, 0x01, 0x0a, 0x15, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x44, 0x65, 0x74, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, - 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x68, - 0x61, 0x32, 0x35, 0x36, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x64, 0x35, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6d, 0x64, 0x35, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xcd, 0x01, 0x0a, 0x13, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, - 0x0a, 0x0a, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x09, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x49, 0x64, 0x12, 0x35, 0x0a, - 0x0b, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x61, 0x6c, 0x77, 0x61, - 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x31, 0x0a, 0x09, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x74, - 0x6f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x42, 0x79, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x2a, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, - 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x78, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, - 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x42, 0x79, 0x12, 0x2f, 0x0a, - 0x13, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x65, 0x78, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, - 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x12, 0x4c, 0x69, - 0x73, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x21, - 0x0a, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x6f, - 0x72, 0x74, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x22, 0x93, 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6c, 0x77, - 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x6d, - 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, - 0x65, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x6d, 0x61, 0x6c, 0x77, - 0x61, 0x72, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x67, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, - 0x61, 0x67, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x19, 0x4c, 0x69, - 0x73, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x67, 0x65, 0x5f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x61, - 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, - 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, - 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, - 0x5f, 0x62, 0x79, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x72, 0x74, 0x42, - 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x6f, 0x72, 0x74, - 0x44, 0x65, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x98, 0x01, 0x0a, 0x1a, 0x4c, - 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x6d, 0x61, 0x6c, - 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x07, 0x6d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x12, - 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x61, 0x67, 0x65, 0x73, - 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2a, 0x41, 0x0a, 0x0d, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x45, 0x57, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, - 0x45, 0x58, 0x43, 0x4c, 0x55, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, - 0x53, 0x54, 0x4f, 0x52, 0x45, 0x44, 0x10, 0x03, 0x32, 0xc9, 0x03, 0x0a, 0x13, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x51, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x45, 0x78, 0x63, 0x6c, - 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x45, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, - 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1c, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, - 0x65, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1c, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x44, - 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x55, - 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, - 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x4b, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x12, 0x19, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x60, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, - 0x61, 0x6c, 0x77, 0x61, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x20, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6c, 0x77, 0x61, 0x72, - 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x21, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x6c, 0x77, - 0x61, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x75, 0x74, 0x6d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x55, 0x54, 0x4d, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_agent_malware_proto_rawDescOnce sync.Once - file_agent_malware_proto_rawDescData = file_agent_malware_proto_rawDesc -) - -func file_agent_malware_proto_rawDescGZIP() []byte { - file_agent_malware_proto_rawDescOnce.Do(func() { - file_agent_malware_proto_rawDescData = protoimpl.X.CompressGZIP(file_agent_malware_proto_rawDescData) - }) - return file_agent_malware_proto_rawDescData -} - -var file_agent_malware_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_agent_malware_proto_msgTypes = make([]protoimpl.MessageInfo, 10) -var file_agent_malware_proto_goTypes = []interface{}{ - (MalwareStatus)(0), // 0: agent.MalwareStatus - (*ListExclusionResponse)(nil), // 1: agent.ListExclusionResponse - (*ListExclusionRequest)(nil), // 2: agent.ListExclusionRequest - (*ChangeStatusRequest)(nil), // 3: agent.ChangeStatusRequest - (*AgentMalwareDetection)(nil), // 4: agent.AgentMalwareDetection - (*AgentMalwareHistory)(nil), // 5: agent.AgentMalwareHistory - (*AgentMalwareExclusion)(nil), // 6: agent.AgentMalwareExclusion - (*ListMalwareRequest)(nil), // 7: agent.ListMalwareRequest - (*ListMalwareResponse)(nil), // 8: agent.ListMalwareResponse - (*ListMalwareHistoryRequest)(nil), // 9: agent.ListMalwareHistoryRequest - (*ListMalwareHistoryResponse)(nil), // 10: agent.ListMalwareHistoryResponse -} -var file_agent_malware_proto_depIdxs = []int32{ - 6, // 0: agent.ListExclusionResponse.exclusions:type_name -> agent.AgentMalwareExclusion - 0, // 1: agent.ChangeStatusRequest.status:type_name -> agent.MalwareStatus - 0, // 2: agent.AgentMalwareDetection.status:type_name -> agent.MalwareStatus - 0, // 3: agent.AgentMalwareHistory.prev_status:type_name -> agent.MalwareStatus - 0, // 4: agent.AgentMalwareHistory.to_status:type_name -> agent.MalwareStatus - 4, // 5: agent.ListMalwareResponse.malware:type_name -> agent.AgentMalwareDetection - 5, // 6: agent.ListMalwareHistoryResponse.malware:type_name -> agent.AgentMalwareHistory - 2, // 7: agent.AgentMalwareService.GetAgentExclusions:input_type -> agent.ListExclusionRequest - 4, // 8: agent.AgentMalwareService.CreateNewMalwareEntry:input_type -> agent.AgentMalwareDetection - 3, // 9: agent.AgentMalwareService.ChangeMalwareStatus:input_type -> agent.ChangeStatusRequest - 7, // 10: agent.AgentMalwareService.ListAgentMalware:input_type -> agent.ListMalwareRequest - 9, // 11: agent.AgentMalwareService.ListAgentMalwareHistory:input_type -> agent.ListMalwareHistoryRequest - 1, // 12: agent.AgentMalwareService.GetAgentExclusions:output_type -> agent.ListExclusionResponse - 4, // 13: agent.AgentMalwareService.CreateNewMalwareEntry:output_type -> agent.AgentMalwareDetection - 4, // 14: agent.AgentMalwareService.ChangeMalwareStatus:output_type -> agent.AgentMalwareDetection - 8, // 15: agent.AgentMalwareService.ListAgentMalware:output_type -> agent.ListMalwareResponse - 10, // 16: agent.AgentMalwareService.ListAgentMalwareHistory:output_type -> agent.ListMalwareHistoryResponse - 12, // [12:17] is the sub-list for method output_type - 7, // [7:12] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name -} - -func init() { file_agent_malware_proto_init() } -func file_agent_malware_proto_init() { - if File_agent_malware_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_agent_malware_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListExclusionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListExclusionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChangeStatusRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AgentMalwareDetection); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AgentMalwareHistory); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AgentMalwareExclusion); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListMalwareRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListMalwareResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListMalwareHistoryRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_agent_malware_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListMalwareHistoryResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_agent_malware_proto_rawDesc, - NumEnums: 1, - NumMessages: 10, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_agent_malware_proto_goTypes, - DependencyIndexes: file_agent_malware_proto_depIdxs, - EnumInfos: file_agent_malware_proto_enumTypes, - MessageInfos: file_agent_malware_proto_msgTypes, - }.Build() - File_agent_malware_proto = out.File - file_agent_malware_proto_rawDesc = nil - file_agent_malware_proto_goTypes = nil - file_agent_malware_proto_depIdxs = nil -} diff --git a/agent/agent/agent/agent_malware_grpc.pb.go b/agent/agent/agent/agent_malware_grpc.pb.go deleted file mode 100644 index 0349889c9..000000000 --- a/agent/agent/agent/agent_malware_grpc.pb.go +++ /dev/null @@ -1,262 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v3.21.12 -// source: agent_malware.proto - -package agent - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.64.0 or later. -const _ = grpc.SupportPackageIsVersion9 - -const ( - AgentMalwareService_GetAgentExclusions_FullMethodName = "/agent.AgentMalwareService/GetAgentExclusions" - AgentMalwareService_CreateNewMalwareEntry_FullMethodName = "/agent.AgentMalwareService/CreateNewMalwareEntry" - AgentMalwareService_ChangeMalwareStatus_FullMethodName = "/agent.AgentMalwareService/ChangeMalwareStatus" - AgentMalwareService_ListAgentMalware_FullMethodName = "/agent.AgentMalwareService/ListAgentMalware" - AgentMalwareService_ListAgentMalwareHistory_FullMethodName = "/agent.AgentMalwareService/ListAgentMalwareHistory" -) - -// AgentMalwareServiceClient is the client API for AgentMalwareService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type AgentMalwareServiceClient interface { - GetAgentExclusions(ctx context.Context, in *ListExclusionRequest, opts ...grpc.CallOption) (*ListExclusionResponse, error) - CreateNewMalwareEntry(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AgentMalwareDetection, AgentMalwareDetection], error) - ChangeMalwareStatus(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ChangeStatusRequest, AgentMalwareDetection], error) - ListAgentMalware(ctx context.Context, in *ListMalwareRequest, opts ...grpc.CallOption) (*ListMalwareResponse, error) - ListAgentMalwareHistory(ctx context.Context, in *ListMalwareHistoryRequest, opts ...grpc.CallOption) (*ListMalwareHistoryResponse, error) -} - -type agentMalwareServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewAgentMalwareServiceClient(cc grpc.ClientConnInterface) AgentMalwareServiceClient { - return &agentMalwareServiceClient{cc} -} - -func (c *agentMalwareServiceClient) GetAgentExclusions(ctx context.Context, in *ListExclusionRequest, opts ...grpc.CallOption) (*ListExclusionResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(ListExclusionResponse) - err := c.cc.Invoke(ctx, AgentMalwareService_GetAgentExclusions_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *agentMalwareServiceClient) CreateNewMalwareEntry(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AgentMalwareDetection, AgentMalwareDetection], error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - stream, err := c.cc.NewStream(ctx, &AgentMalwareService_ServiceDesc.Streams[0], AgentMalwareService_CreateNewMalwareEntry_FullMethodName, cOpts...) - if err != nil { - return nil, err - } - x := &grpc.GenericClientStream[AgentMalwareDetection, AgentMalwareDetection]{ClientStream: stream} - return x, nil -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type AgentMalwareService_CreateNewMalwareEntryClient = grpc.BidiStreamingClient[AgentMalwareDetection, AgentMalwareDetection] - -func (c *agentMalwareServiceClient) ChangeMalwareStatus(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ChangeStatusRequest, AgentMalwareDetection], error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - stream, err := c.cc.NewStream(ctx, &AgentMalwareService_ServiceDesc.Streams[1], AgentMalwareService_ChangeMalwareStatus_FullMethodName, cOpts...) - if err != nil { - return nil, err - } - x := &grpc.GenericClientStream[ChangeStatusRequest, AgentMalwareDetection]{ClientStream: stream} - return x, nil -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type AgentMalwareService_ChangeMalwareStatusClient = grpc.BidiStreamingClient[ChangeStatusRequest, AgentMalwareDetection] - -func (c *agentMalwareServiceClient) ListAgentMalware(ctx context.Context, in *ListMalwareRequest, opts ...grpc.CallOption) (*ListMalwareResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(ListMalwareResponse) - err := c.cc.Invoke(ctx, AgentMalwareService_ListAgentMalware_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *agentMalwareServiceClient) ListAgentMalwareHistory(ctx context.Context, in *ListMalwareHistoryRequest, opts ...grpc.CallOption) (*ListMalwareHistoryResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(ListMalwareHistoryResponse) - err := c.cc.Invoke(ctx, AgentMalwareService_ListAgentMalwareHistory_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// AgentMalwareServiceServer is the server API for AgentMalwareService service. -// All implementations must embed UnimplementedAgentMalwareServiceServer -// for forward compatibility. -type AgentMalwareServiceServer interface { - GetAgentExclusions(context.Context, *ListExclusionRequest) (*ListExclusionResponse, error) - CreateNewMalwareEntry(grpc.BidiStreamingServer[AgentMalwareDetection, AgentMalwareDetection]) error - ChangeMalwareStatus(grpc.BidiStreamingServer[ChangeStatusRequest, AgentMalwareDetection]) error - ListAgentMalware(context.Context, *ListMalwareRequest) (*ListMalwareResponse, error) - ListAgentMalwareHistory(context.Context, *ListMalwareHistoryRequest) (*ListMalwareHistoryResponse, error) - mustEmbedUnimplementedAgentMalwareServiceServer() -} - -// UnimplementedAgentMalwareServiceServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedAgentMalwareServiceServer struct{} - -func (UnimplementedAgentMalwareServiceServer) GetAgentExclusions(context.Context, *ListExclusionRequest) (*ListExclusionResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAgentExclusions not implemented") -} -func (UnimplementedAgentMalwareServiceServer) CreateNewMalwareEntry(grpc.BidiStreamingServer[AgentMalwareDetection, AgentMalwareDetection]) error { - return status.Errorf(codes.Unimplemented, "method CreateNewMalwareEntry not implemented") -} -func (UnimplementedAgentMalwareServiceServer) ChangeMalwareStatus(grpc.BidiStreamingServer[ChangeStatusRequest, AgentMalwareDetection]) error { - return status.Errorf(codes.Unimplemented, "method ChangeMalwareStatus not implemented") -} -func (UnimplementedAgentMalwareServiceServer) ListAgentMalware(context.Context, *ListMalwareRequest) (*ListMalwareResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListAgentMalware not implemented") -} -func (UnimplementedAgentMalwareServiceServer) ListAgentMalwareHistory(context.Context, *ListMalwareHistoryRequest) (*ListMalwareHistoryResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListAgentMalwareHistory not implemented") -} -func (UnimplementedAgentMalwareServiceServer) mustEmbedUnimplementedAgentMalwareServiceServer() {} -func (UnimplementedAgentMalwareServiceServer) testEmbeddedByValue() {} - -// UnsafeAgentMalwareServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to AgentMalwareServiceServer will -// result in compilation errors. -type UnsafeAgentMalwareServiceServer interface { - mustEmbedUnimplementedAgentMalwareServiceServer() -} - -func RegisterAgentMalwareServiceServer(s grpc.ServiceRegistrar, srv AgentMalwareServiceServer) { - // If the following call pancis, it indicates UnimplementedAgentMalwareServiceServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&AgentMalwareService_ServiceDesc, srv) -} - -func _AgentMalwareService_GetAgentExclusions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListExclusionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AgentMalwareServiceServer).GetAgentExclusions(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: AgentMalwareService_GetAgentExclusions_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AgentMalwareServiceServer).GetAgentExclusions(ctx, req.(*ListExclusionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _AgentMalwareService_CreateNewMalwareEntry_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(AgentMalwareServiceServer).CreateNewMalwareEntry(&grpc.GenericServerStream[AgentMalwareDetection, AgentMalwareDetection]{ServerStream: stream}) -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type AgentMalwareService_CreateNewMalwareEntryServer = grpc.BidiStreamingServer[AgentMalwareDetection, AgentMalwareDetection] - -func _AgentMalwareService_ChangeMalwareStatus_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(AgentMalwareServiceServer).ChangeMalwareStatus(&grpc.GenericServerStream[ChangeStatusRequest, AgentMalwareDetection]{ServerStream: stream}) -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type AgentMalwareService_ChangeMalwareStatusServer = grpc.BidiStreamingServer[ChangeStatusRequest, AgentMalwareDetection] - -func _AgentMalwareService_ListAgentMalware_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListMalwareRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AgentMalwareServiceServer).ListAgentMalware(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: AgentMalwareService_ListAgentMalware_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AgentMalwareServiceServer).ListAgentMalware(ctx, req.(*ListMalwareRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _AgentMalwareService_ListAgentMalwareHistory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListMalwareHistoryRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AgentMalwareServiceServer).ListAgentMalwareHistory(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: AgentMalwareService_ListAgentMalwareHistory_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AgentMalwareServiceServer).ListAgentMalwareHistory(ctx, req.(*ListMalwareHistoryRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// AgentMalwareService_ServiceDesc is the grpc.ServiceDesc for AgentMalwareService service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var AgentMalwareService_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "agent.AgentMalwareService", - HandlerType: (*AgentMalwareServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetAgentExclusions", - Handler: _AgentMalwareService_GetAgentExclusions_Handler, - }, - { - MethodName: "ListAgentMalware", - Handler: _AgentMalwareService_ListAgentMalware_Handler, - }, - { - MethodName: "ListAgentMalwareHistory", - Handler: _AgentMalwareService_ListAgentMalwareHistory_Handler, - }, - }, - Streams: []grpc.StreamDesc{ - { - StreamName: "CreateNewMalwareEntry", - Handler: _AgentMalwareService_CreateNewMalwareEntry_Handler, - ServerStreams: true, - ClientStreams: true, - }, - { - StreamName: "ChangeMalwareStatus", - Handler: _AgentMalwareService_ChangeMalwareStatus_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "agent_malware.proto", -} diff --git a/agent/agent/agent/delete.go b/agent/agent/agent/delete.go deleted file mode 100644 index f812f66d4..000000000 --- a/agent/agent/agent/delete.go +++ /dev/null @@ -1,63 +0,0 @@ -package agent - -import ( - context "context" - "fmt" - "os/user" - "strconv" - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/utils" - grpc "google.golang.org/grpc" - "google.golang.org/grpc/metadata" -) - -const ( - maxConnectionAttempts = 3 - initialReconnectDelay = 10 * time.Second - maxReconnectDelay = 60 * time.Second -) - -func DeleteAgent(conn *grpc.ClientConn, cnf *configuration.Config, h *logger.Logger) error { - connectionAttemps := 0 - reconnectDelay := initialReconnectDelay - - // Create a client for AgentService - agentClient := NewAgentServiceClient(conn) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - ctx = metadata.AppendToOutgoingContext(ctx, "key", cnf.AgentKey) - ctx = metadata.AppendToOutgoingContext(ctx, "id", strconv.Itoa(int(cnf.AgentID))) - - currentUser, err := user.Current() - if err != nil { - return fmt.Errorf("error getting user: %v", err) - } - - delet := &AgentDelete{ - DeletedBy: currentUser.Username, - } - - for { - if connectionAttemps >= maxConnectionAttempts { - return fmt.Errorf("error removing UTMStack Agent from Agent Manager") - } - h.Info("trying to remove UTMStack Agent from Agent Manager...") - - _, err = agentClient.DeleteAgent(ctx, delet) - if err != nil { - connectionAttemps++ - h.Info("error removing UTMStack Agent from Agent Manager, trying again in %.0f seconds", reconnectDelay.Seconds()) - time.Sleep(reconnectDelay) - reconnectDelay = utils.IncrementReconnectDelay(reconnectDelay, maxReconnectDelay) - continue - } - - break - } - - h.Info("UTMStack Agent removed successfully") - return nil -} diff --git a/agent/agent/agent/incident_response.go b/agent/agent/agent/incident_response.go deleted file mode 100644 index 9fec23793..000000000 --- a/agent/agent/agent/incident_response.go +++ /dev/null @@ -1,107 +0,0 @@ -package agent - -import ( - "context" - "io" - "runtime" - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/utils" - "google.golang.org/protobuf/types/known/timestamppb" -) - -func IncidentResponseStream(client AgentServiceClient, ctx context.Context, cnf *configuration.Config, h *logger.Logger) { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - h.Fatal("Failed to get current path: %v", err) - } - - connectionTime := 0 * time.Second - reconnectDelay := configuration.InitialReconnectDelay - var connErrMsgWritten bool - - for { - if connectionTime >= configuration.MaxConnectionTime { - connectionTime = 0 * time.Second - reconnectDelay = configuration.InitialReconnectDelay - continue - } - - stream, err := client.AgentStream(ctx) - if err != nil { - if !connErrMsgWritten { - h.ErrorF("failed to start AgentStream: %v", err) - connErrMsgWritten = true - } - - time.Sleep(reconnectDelay) - connectionTime = utils.IncrementReconnectTime(connectionTime, reconnectDelay, configuration.MaxConnectionTime) - reconnectDelay = utils.IncrementReconnectDelay(reconnectDelay, configuration.MaxReconnectDelay) - continue - } - - connErrMsgWritten = false - - // Handle the bidirectional stream - for { - in, err := stream.Recv() - if err == io.EOF { - // Server closed the stream - break - } - if err != nil { - h.ErrorF("error receiving command from server: %v", err) - break - } - - switch msg := in.StreamMessage.(type) { - case *BidirectionalStream_Command: - // Handle the received command - err = commandProcessor(h, path, stream, cnf, []string{msg.Command.Command, in.GetCommand().CmdId}) - if err == io.EOF { - break - } - if err != nil { - h.ErrorF("failed to send result to server: %v", err) - } - } - } - } -} - -func commandProcessor(h *logger.Logger, path string, stream AgentService_AgentStreamClient, cnf *configuration.Config, commandPair []string) error { - var result string - var errB bool - - h.Info("Received command: %s", commandPair[0]) - - switch runtime.GOOS { - case "windows": - result, errB = utils.ExecuteWithResult("cmd.exe", path, "/C", commandPair[0]) - case "linux": - result, errB = utils.ExecuteWithResult("sh", path, "-c", commandPair[0]) - default: - h.Fatal("unsupported operating system: %s", runtime.GOOS) - } - - if errB { - h.ErrorF("error executing command %s: %s", commandPair[0], result) - } else { - h.Info("Result when executing the command %s: %s", commandPair[0], result) - } - - // Send the result back to the server - if err := stream.Send(&BidirectionalStream{ - StreamMessage: &BidirectionalStream_Result{ - Result: &CommandResult{Result: result, AgentKey: cnf.AgentKey, ExecutedAt: timestamppb.Now(), CmdId: commandPair[1]}, - }, - }); err != nil { - return err - } else { - h.Info("Result sent to server successfully!!!") - } - return nil -} diff --git a/agent/agent/agent/ping_imp.go b/agent/agent/agent/ping_imp.go deleted file mode 100644 index 2bca835cc..000000000 --- a/agent/agent/agent/ping_imp.go +++ /dev/null @@ -1,56 +0,0 @@ -package agent - -import ( - "context" - "io" - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/utils" -) - -// Call this function to start sending Ping requests -func StartPing(client PingServiceClient, ctx context.Context, cnf *configuration.Config, h *logger.Logger) { - connectionTime := 0 * time.Second - reconnectDelay := configuration.InitialReconnectDelay - var connErrMsgWritten bool - - for { - if connectionTime >= configuration.MaxConnectionTime { - connectionTime = 0 * time.Second - reconnectDelay = configuration.InitialReconnectDelay - continue - } - - stream, err := client.Ping(ctx) - if err != nil { - if !connErrMsgWritten { - h.ErrorF("failed to start Ping Stream: %v", err) - connErrMsgWritten = true - } - time.Sleep(reconnectDelay) - connectionTime = utils.IncrementReconnectTime(connectionTime, reconnectDelay, configuration.MaxConnectionTime) - reconnectDelay = utils.IncrementReconnectDelay(reconnectDelay, configuration.MaxReconnectDelay) - continue - } - - connErrMsgWritten = false - - ticker := time.NewTicker(15 * time.Second) - defer ticker.Stop() - - for range ticker.C { - err := stream.Send(&PingRequest{Type: ConnectorType_AGENT}) - if err == io.EOF { - // Server closed the stream - h.ErrorF("Server closed the stream: %v", err) - break - } - if err != nil { - h.ErrorF("Error sending Ping request: %v", err) - break - } - } - } -} diff --git a/agent/agent/agent/uninstall.go b/agent/agent/agent/uninstall.go deleted file mode 100644 index 2716b064f..000000000 --- a/agent/agent/agent/uninstall.go +++ /dev/null @@ -1,30 +0,0 @@ -package agent - -import ( - "fmt" - "path/filepath" - "runtime" - - "github.com/utmstack/UTMStack/agent/agent/utils" -) - -func UninstallAll() error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - var exeName string - switch runtime.GOOS { - case "windows": - exeName = filepath.Join(path, "utmstack-runner-windows.exe") - case "linux": - exeName = filepath.Join(path, "utmstack-runner-linux") - } - - err = utils.Execute(exeName, path, "uninstall") - if err != nil { - return fmt.Errorf("%v", err) - } - return nil -} diff --git a/agent/agent/agent/version.go b/agent/agent/agent/version.go deleted file mode 100644 index 1ee56332c..000000000 --- a/agent/agent/agent/version.go +++ /dev/null @@ -1,30 +0,0 @@ -package agent - -import ( - "fmt" - "path/filepath" - - "github.com/utmstack/UTMStack/agent/agent/utils" -) - -type Version struct { - MasterVersion string `json:"master_version"` - AgentVersion string `json:"agent_version"` - UpdaterVersion string `json:"updater_version"` - RedlineVersion string `json:"redline_version"` -} - -func GetVersion() (string, error) { - path, err := utils.GetMyPath() - if err != nil { - return "", fmt.Errorf("failed to get current path: %v", err) - } - - versions := &Version{} - err = utils.ReadJson(filepath.Join(path, "versions.json"), &versions) - if err != nil { - return "", fmt.Errorf("error reading current versions.json: %v", err) - } - - return versions.AgentVersion, nil -} diff --git a/agent/agent/agent/agent_grpc.pb.go b/agent/agent/agent_grpc.pb.go similarity index 100% rename from agent/agent/agent/agent_grpc.pb.go rename to agent/agent/agent_grpc.pb.go diff --git a/agent/agent/beats/beat.go b/agent/agent/beats/beat.go deleted file mode 100644 index 52e84d71a..000000000 --- a/agent/agent/beats/beat.go +++ /dev/null @@ -1,69 +0,0 @@ -package beats - -import ( - "fmt" - "runtime" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" -) - -type BeatConfig struct { - LogsPath string - LogFileName string -} - -type Beat interface { - Install() error - SendSystemLogs(h *logger.Logger) - Uninstall() error -} - -func getBeatsInstances() []Beat { - var beatsInstance []Beat - switch runtime.GOOS { - case "windows": - beatsInstance = append(beatsInstance, Winlogbeat{}) - beatsInstance = append(beatsInstance, Filebeat{}) - case "linux": - beatsInstance = append(beatsInstance, Filebeat{}) - } - - return beatsInstance -} - -func InstallBeats(cnf configuration.Config, h *logger.Logger) error { - beatsInstances := getBeatsInstances() - - for _, beat := range beatsInstances { - err := beat.Install() - if err != nil { - return fmt.Errorf("%v", err) - } - } - - h.Info("beats installed correctly") - - return nil -} - -func BeatsLogsReader(h *logger.Logger) { - beatsInstances := getBeatsInstances() - for _, beat := range beatsInstances { - go beat.SendSystemLogs(h) - } -} - -func UninstallBeats(h *logger.Logger) error { - beatsInstances := getBeatsInstances() - - for _, beat := range beatsInstances { - err := beat.Uninstall() - if err != nil { - return fmt.Errorf("%v", err) - } - } - - h.Info("beats uninstalled correctly") - return nil -} diff --git a/agent/agent/agent/common.pb.go b/agent/agent/common.pb.go similarity index 100% rename from agent/agent/agent/common.pb.go rename to agent/agent/common.pb.go diff --git a/agent/agent/configuration/const.go b/agent/agent/configuration/const.go deleted file mode 100644 index 5f3f1f08d..000000000 --- a/agent/agent/configuration/const.go +++ /dev/null @@ -1,157 +0,0 @@ -package configuration - -import ( - "path/filepath" - "runtime" - "time" - - "github.com/utmstack/UTMStack/agent/agent/utils" -) - -const REPLACE_KEY string = "" - -const ( - AGENTMANAGERPORT string = "9000" - AUTHLOGSPORT string = "50051" - BatchCapacity = 100 - MaxConnectionTime = 120 * time.Second - InitialReconnectDelay = 10 * time.Second - MaxReconnectDelay = 120 * time.Second - - SERV_NAME = "UTMStackAgent" - SERV_LOG = "utmstack_agent.log" - ModulesServName = "UTMStackModulesLogsCollector" - WinServName = "UTMStackWindowsLogsCollector" - ModulesLockName = "utmstack_modules_collector.lock" - WinLockName = "utmstack_windows_collector.lock" - RedlineLockName = "utmstack_redline.lock" - RedlineServName = "UTMStackRedline" - CollectorFileName = "log-collector-configuration.json" - CollectorFileNameOld = "log-collector-config.json" - UUIDFileName = "uuid.yml" - MESSAGE_HEADER = "utm_stack_agent_ds" - BatchToSend = 5 - PortRangeMin = "7000" - PortRangeMax = "9000" -) - -type LogType string - -const ( - LogTypeWindowsAgent LogType = "beats_windows_agent" - LogTypeSyslog LogType = "syslog" - LogTypeVmware LogType = "vmware" - LogTypeLinuxAgent LogType = "beats_linux_agent" - LogTypeEset LogType = "antivirus_eset" - LogTypeKaspersky LogType = "antivirus_kaspersky" - LogTypeTraefikModule LogType = "beats_traefik_module" - LogTypeMongodbModule LogType = "beats_mongodb_module" - LogTypeMysqlModule LogType = "beats_mysql_module" - LogTypePostgresqlModule LogType = "beats_postgresql_module" - LogTypeRedisModule LogType = "beats_redis_module" - LogTypeElasticsearchModule LogType = "beats_elasticsearch_module" - LogTypeKafkaModule LogType = "beats_kafka_module" - LogTypeKibanaModule LogType = "beats_kibana_module" - LogTypeLogstashModule LogType = "beats_logstash_module" - LogTypeCiscoAsa LogType = "cisco_asa" - LogTypeCiscoMeraki LogType = "cisco_meraki" - LogTypeFortinet LogType = "firewall_fortinet" - LogTypePaloalto LogType = "firewall_paloalto" - LogTypeMikrotik LogType = "firewall_mikrotik" - LogTypeCiscoFirepower LogType = "cisco_firepower" - LogTypeSophosXG LogType = "firewall_sophos" - LogTypeCiscoSwitch LogType = "cisco_switch" - LogTypeSonicwall LogType = "firewall_sonicwall" - LogTypeNatsModule LogType = "beats_nats_module" - LogTypeDeceptivebytes LogType = "antivirus_deceptivebytes" - LogTypeOsqueryModule LogType = "beats_osquery_module" - LogTypeLinuxAuditdModule LogType = "beats_auditd_module" - LogTypeHaproxyModule LogType = "beats_haproxy_module" - LogTypeNginxModule LogType = "beats_nginx_module" - LogTypeIisModule LogType = "beats_iis_module" - LogTypeApacheModule LogType = "beats_apache_module" - LogTypeSentinelOne LogType = "antivirus_sentinel_one" - LogTypeCiscoGeneric LogType = "cisco" - LogTypeMacOs LogType = "macos_logs" - LogTypeGeneric LogType = "generic" - LogTypeNetflow LogType = "netflow" - LogTypeAix LogType = "ibm_aix" - LogTypePfsense LogType = "firewall_pfsense" - LogTypeFortiweb LogType = "firewall_fortiweb" -) - -type ProtoPort struct { - UDP string - TCP string -} - -var ( - ProtoPorts = map[LogType]ProtoPort{ - LogTypeSyslog: {UDP: "7014", TCP: "7014"}, - LogTypeVmware: {UDP: "7002", TCP: "7002"}, - LogTypeEset: {UDP: "7003", TCP: "7003"}, - LogTypeKaspersky: {UDP: "7004", TCP: "7004"}, - LogTypeCiscoGeneric: {UDP: "514", TCP: "1470"}, - LogTypeFortinet: {UDP: "7005", TCP: "7005"}, - LogTypePaloalto: {UDP: "7006", TCP: "7006"}, - LogTypeMikrotik: {UDP: "7007", TCP: "7007"}, - LogTypeSophosXG: {UDP: "7008", TCP: "7008"}, - LogTypeSonicwall: {UDP: "7009", TCP: "7009"}, - LogTypeDeceptivebytes: {UDP: "7010", TCP: "7010"}, - LogTypeSentinelOne: {UDP: "7012", TCP: "7012"}, - LogTypeMacOs: {UDP: "7015", TCP: "7015"}, - LogTypeAix: {UDP: "7016", TCP: "7016"}, - LogTypePfsense: {UDP: "7017", TCP: "7017"}, - LogTypeFortiweb: {UDP: "7018", TCP: "7018"}, - LogTypeNetflow: {UDP: "2055", TCP: ""}, - } - - ProhibitedPortsChange = []LogType{LogTypeCiscoGeneric, LogTypeNetflow} -) - -func GetCaPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "ca.crt") -} - -func GetCollectorConfigPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, CollectorFileName) -} - -func GetCollectorConfigPathOld() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, CollectorFileNameOld) -} - -func GetAgentBin() string { - var bin string - switch runtime.GOOS { - case "windows": - bin = "utmstack_agent_service.exe" - case "linux": - bin = "utmstack_agent_service" - } - return bin -} - -func GetMessageFormated(host string, msg string) string { - return "[" + MESSAGE_HEADER + "=" + host + "]-" + msg -} - -func ValidateModuleType(typ LogType) string { - switch typ { - case LogTypeSyslog, LogTypeVmware, LogTypeEset, LogTypeKaspersky, LogTypeFortinet, LogTypePaloalto, - LogTypeMikrotik, LogTypeSophosXG, LogTypeSonicwall, LogTypeSentinelOne, LogTypeCiscoGeneric, LogTypeMacOs, - LogTypeDeceptivebytes, LogTypeAix, LogTypePfsense, LogTypeFortiweb: - return "syslog" - case LogTypeNetflow: - return "netflow" - case LogTypeWindowsAgent, LogTypeLinuxAgent, LogTypeTraefikModule, LogTypeMongodbModule, LogTypeMysqlModule, LogTypePostgresqlModule, - LogTypeRedisModule, LogTypeElasticsearchModule, LogTypeKafkaModule, LogTypeKibanaModule, LogTypeLogstashModule, LogTypeNatsModule, - LogTypeOsqueryModule, LogTypeLinuxAuditdModule, LogTypeHaproxyModule, LogTypeNginxModule, LogTypeIisModule, LogTypeApacheModule: - return "beats" - default: - return "nil" - } -} diff --git a/agent/agent/conn/conn.go b/agent/agent/conn/conn.go deleted file mode 100644 index a0d059061..000000000 --- a/agent/agent/conn/conn.go +++ /dev/null @@ -1,63 +0,0 @@ -package conn - -import ( - "crypto/tls" - "fmt" - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/utils" - grpc "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -const ( - maxMessageSize = 1024 * 1024 * 1024 - maxConnectionAttempts = 3 - initialReconnectDelay = 10 * time.Second - maxReconnectDelay = 60 * time.Second -) - -func ConnectToServer(cnf *configuration.Config, h *logger.Logger, addrs, port string) (*grpc.ClientConn, error) { - connectionAttemps := 0 - reconnectDelay := initialReconnectDelay - - // Connect to the gRPC server - serverAddress := addrs + ":" + port - var conn *grpc.ClientConn - var err error - - for { - if connectionAttemps >= maxConnectionAttempts { - return nil, fmt.Errorf("failed to connect to Server") - } - - h.Info("trying to connect to Server...") - var opts grpc.DialOption - if !cnf.SkipCertValidation { - creds, err := credentials.NewClientTLSFromFile(configuration.GetCaPath(), "") - if err != nil { - return nil, fmt.Errorf("failed to load CA trust certificate: %v", err) - } - opts = grpc.WithTransportCredentials(creds) - } else { - tlsConfig := &tls.Config{InsecureSkipVerify: true} - creds := credentials.NewTLS(tlsConfig) - opts = grpc.WithTransportCredentials(creds) - } - - conn, err = grpc.NewClient(serverAddress, opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMessageSize))) - if err != nil { - connectionAttemps++ - h.Info("error connecting to Server, trying again in %.0f seconds", reconnectDelay.Seconds()) - time.Sleep(reconnectDelay) - reconnectDelay = utils.IncrementReconnectDelay(reconnectDelay, maxReconnectDelay) - continue - } - - break - } - - return conn, nil -} diff --git a/agent/agent/delete.go b/agent/agent/delete.go new file mode 100644 index 000000000..1e1255185 --- /dev/null +++ b/agent/agent/delete.go @@ -0,0 +1,44 @@ +package agent + +import ( + context "context" + "fmt" + "os/user" + "strconv" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/conn" + "github.com/utmstack/UTMStack/agent/agent/utils" + "google.golang.org/grpc/metadata" +) + +func DeleteAgent(cnf *config.Config) error { + connection, err := conn.GetAgentManagerConnection(cnf) + if err != nil { + return fmt.Errorf("error connecting to Agent Manager: %v", err) + } + + agentClient := NewAgentServiceClient(connection) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx = metadata.AppendToOutgoingContext(ctx, "key", cnf.AgentKey) + ctx = metadata.AppendToOutgoingContext(ctx, "id", strconv.Itoa(int(cnf.AgentID))) + ctx = metadata.AppendToOutgoingContext(ctx, "type", "agent") + + currentUser, err := user.Current() + if err != nil { + return fmt.Errorf("error getting user: %v", err) + } + + delet := &AgentDelete{ + DeletedBy: currentUser.Username, + } + + _, err = agentClient.DeleteAgent(ctx, delet) + if err != nil { + utils.Logger.ErrorF("error removing UTMStack Agent from Agent Manager %v", err) + } + + utils.Logger.Info("UTMStack Agent removed successfully") + return nil +} diff --git a/agent/agent/filters/beats.go b/agent/agent/filters/beats.go deleted file mode 100644 index e0f351f46..000000000 --- a/agent/agent/filters/beats.go +++ /dev/null @@ -1,54 +0,0 @@ -package filters - -import ( - "regexp" - - "github.com/utmstack/UTMStack/agent/agent/configuration" -) - -var RegexspBeats = map[configuration.LogType]string{ - configuration.LogTypeApacheModule: `"type":"apache"|"module":"apache"`, - configuration.LogTypeLinuxAuditdModule: `"type":"auditd"|"module":"auditd"`, - configuration.LogTypeElasticsearchModule: `"type":"elasticsearch"|"module":"elasticsearch"`, - configuration.LogTypeKafkaModule: `"type":"kafka"|"module":"kafka"`, - configuration.LogTypeKibanaModule: `"type":"kibana"|"module":"kibana"`, - configuration.LogTypeLogstashModule: `"type":"logstash"|"module":"logstash"`, - configuration.LogTypeMongodbModule: `"type":"mongodb"|"module":"mongodb"`, - configuration.LogTypeMysqlModule: `"type":"mysql"|"module":"mysql"`, - configuration.LogTypeNginxModule: `"type":"nginx"|"module":"nginx"`, - configuration.LogTypeOsqueryModule: `"type":"osquery"|"module":"osquery"`, - configuration.LogTypePostgresqlModule: `"type":"postgresql"|"module":"postgresql"`, - configuration.LogTypeRedisModule: `"type":"redis"|"module":"redis"`, - configuration.LogTypeLinuxAgent: `"type":"system"|"module":"system"`, - configuration.LogTypeIisModule: `"type":"iis"|"module":"iis"`, - configuration.LogTypeTraefikModule: `"type":"traefik"|"module":"traefik"`, - configuration.LogTypeNatsModule: `"type":"nats"|"module":"nats"`, - configuration.LogTypeHaproxyModule: `"type":"haproxy"|"module":"haproxy"`, -} - -func indentifyBeatLogSource(log string) (configuration.LogType, error) { - for logType, regp := range RegexspBeats { - regExpCompiled, err := regexp.Compile(string(regp)) - if err != nil { - return "", err - } - if regExpCompiled.MatchString(log) { - return logType, nil - } - } - return configuration.LogTypeGeneric, nil -} - -func ProcessBeatData(logBatch []string) (map[string][]string, error) { - classifiedLogs := make(map[string][]string) - for _, log := range logBatch { - if logType, err := indentifyBeatLogSource(log); err != nil { - return nil, err - } else { - if logType != "" { - classifiedLogs[string(logType)] = append(classifiedLogs[string(logType)], log) - } - } - } - return classifiedLogs, nil -} diff --git a/agent/agent/filters/cisco.go b/agent/agent/filters/cisco.go deleted file mode 100644 index e2b9f65c4..000000000 --- a/agent/agent/filters/cisco.go +++ /dev/null @@ -1,38 +0,0 @@ -package filters - -import ( - "regexp" - - "github.com/utmstack/UTMStack/agent/agent/configuration" -) - -var RegexspCisco = map[configuration.LogType]string{ - configuration.LogTypeCiscoAsa: `%ASA-`, - configuration.LogTypeCiscoFirepower: `%FTD-`, - configuration.LogTypeCiscoSwitch: `%(\w|_)+-((\b\w+\b-\b\w+\b-)?)(\d)-([A-Z]|_)+`, -} - -func indentifyCiscoLogSource(log string) (configuration.LogType, error) { - for logType, regp := range RegexspCisco { - regExpCompiled, err := regexp.Compile(string(regp)) - if err != nil { - return "", err - } - if regExpCompiled.MatchString(log) { - return logType, nil - } - } - return configuration.LogTypeCiscoMeraki, nil -} - -func ProcessCiscoData(logBatch []string) (map[string][]string, error) { - classifiedLogs := make(map[string][]string) - for _, log := range logBatch { - if logType, err := indentifyCiscoLogSource(log); err != nil { - return nil, err - } else { - classifiedLogs[string(logType)] = append(classifiedLogs[string(logType)], log) - } - } - return classifiedLogs, nil -} diff --git a/agent/agent/incident_response.go b/agent/agent/incident_response.go new file mode 100644 index 000000000..cb1fea151 --- /dev/null +++ b/agent/agent/incident_response.go @@ -0,0 +1,132 @@ +package agent + +import ( + "context" + "runtime" + "strings" + "time" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/conn" + "github.com/utmstack/UTMStack/agent/agent/utils" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func IncidentResponseStream(cnf *config.Config, ctx context.Context) { + path := utils.GetMyPath() + var connErrMsgWritten, errorLogged bool + + for { + connection, err := conn.GetAgentManagerConnection(cnf) + if err != nil { + if !connErrMsgWritten { + utils.Logger.ErrorF("error connecting to Agent Manager: %v", err) + connErrMsgWritten = true + } + time.Sleep(timeToSleep) + continue + } + + client := NewAgentServiceClient(connection) + stream, err := client.AgentStream(ctx) + if err != nil { + if !connErrMsgWritten { + utils.Logger.ErrorF("failed to start AgentStream: %v", err) + connErrMsgWritten = true + } + time.Sleep(timeToSleep) + continue + } + + connErrMsgWritten = false + + for { + in, err := stream.Recv() + if err != nil { + if strings.Contains(err.Error(), "EOF") { + time.Sleep(timeToSleep) + break + } + st, ok := status.FromError(err) + if ok && (st.Code() == codes.Unavailable || st.Code() == codes.Canceled) { + if !errorLogged { + utils.Logger.ErrorF("error receiving command from server: %v", err) + errorLogged = true + } + time.Sleep(timeToSleep) + break + } else { + if !errorLogged { + utils.Logger.ErrorF("error receiving command from server: %v", err) + errorLogged = true + } + time.Sleep(timeToSleep) + continue + } + } + + switch msg := in.StreamMessage.(type) { + case *BidirectionalStream_Command: + err = commandProcessor(path, stream, cnf, []string{msg.Command.Command, in.GetCommand().CmdId}) + if err != nil { + if strings.Contains(err.Error(), "EOF") { + time.Sleep(timeToSleep) + break + } + st, ok := status.FromError(err) + if ok && (st.Code() == codes.Unavailable || st.Code() == codes.Canceled) { + if !errorLogged { + utils.Logger.ErrorF("error sending result to server: %v", err) + errorLogged = true + } + time.Sleep(timeToSleep) + break + } else { + if !errorLogged { + utils.Logger.ErrorF("error sending result to server: %v", err) + errorLogged = true + } + time.Sleep(timeToSleep) + continue + } + } + } + errorLogged = false + } + } +} + +func commandProcessor(path string, stream AgentService_AgentStreamClient, cnf *config.Config, commandPair []string) error { + var result string + var errB bool + + utils.Logger.Info("Received command: %s", commandPair[0]) + + switch runtime.GOOS { + case "windows": + result, errB = utils.ExecuteWithResult("cmd.exe", path, "/C", commandPair[0]) + case "linux": + result, errB = utils.ExecuteWithResult("sh", path, "-c", commandPair[0]) + default: + utils.Logger.Fatal("unsupported operating system: %s", runtime.GOOS) + } + + if errB { + utils.Logger.ErrorF("error executing command %s: %s", commandPair[0], result) + } else { + utils.Logger.Info("Result when executing the command %s: %s", commandPair[0], result) + } + + if err := stream.Send(&BidirectionalStream{ + StreamMessage: &BidirectionalStream_Result{ + Result: &CommandResult{Result: result, AgentKey: cnf.AgentKey, ExecutedAt: timestamppb.Now(), CmdId: commandPair[1]}, + }, + }); err != nil { + return err + } else { + utils.Logger.Info("Result sent to server successfully!!!") + } + return nil +} diff --git a/agent/agent/log-collector-config-sample.json b/agent/agent/log-collector-config-sample.json deleted file mode 100644 index 340e1e0ee..000000000 --- a/agent/agent/log-collector-config-sample.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "integrations": { - "syslog": { - "tcp_port": { "enabled": false, "value": "7014" }, - "udp_port": { "enabled": false, "value": "7014" } - }, - "antivirus_deceptivebytes": { - "tcp_port": { "enabled": false, "value": "7010" }, - "udp_port": { "enabled": false, "value": "7010" } - }, - "antivirus_eset": { - "tcp_port": { "enabled": false, "value": "7003" }, - "udp_port": { "enabled": false, "value": "7003" } - }, - "antivirus_kaspersky": { - "tcp_port": { "enabled": false, "value": "7004" }, - "udp_port": { "enabled": false, "value": "7004" } - }, - "antivirus_sentinel_one": { - "tcp_port": { "enabled": false, "value": "7012" }, - "udp_port": { "enabled": false, "value": "7012" } - }, - "cisco": { - "tcp_port": { "enabled": false, "value": "1470" }, - "udp_port": { "enabled": false, "value": "514" } - }, - "firewall_fortinet": { - "tcp_port": { "enabled": false, "value": "7005" }, - "udp_port": { "enabled": false, "value": "7005" } - }, - "firewall_mikrotik": { - "tcp_port": { "enabled": false, "value": "7007" }, - "udp_port": { "enabled": false, "value": "7007" } - }, - "firewall_paloalto": { - "tcp_port": { "enabled": false, "value": "7006" }, - "udp_port": { "enabled": false, "value": "7006" } - }, - "firewall_sonicwall": { - "tcp_port": { "enabled": false, "value": "7009" }, - "udp_port": { "enabled": false, "value": "7009" } - }, - "firewall_sophos": { - "tcp_port": { "enabled": false, "value": "7008" }, - "udp_port": { "enabled": false, "value": "7008" } - }, - "macos": { - "tcp_port": { "enabled": false, "value": "7015" }, - "udp_port": { "enabled": false, "value": "7015" } - }, - "vmware": { - "tcp_port": { "enabled": false, "value": "7002" }, - "udp_port": { "enabled": false, "value": "7002" } - }, - "netflow": { - "udp_port": { "enabled": false, "value": "2055" } - }, - "aix": { - "tcp_port": { "enabled": false, "value": "7016" }, - "udp_port": { "enabled": false, "value": "7016" } - }, - "firewall_pfsense": { - "tcp_port": { "enabled": false, "value": "7017" }, - "udp_port": { "enabled": false, "value": "7017" } - }, - "firewall_fortiweb": { - "tcp_port": { "enabled": false, "value": "7018" }, - "udp_port": { "enabled": false, "value": "7018" } - } - } -} \ No newline at end of file diff --git a/agent/agent/logservice/processor.go b/agent/agent/logservice/processor.go deleted file mode 100644 index 03c01cb02..000000000 --- a/agent/agent/logservice/processor.go +++ /dev/null @@ -1,189 +0,0 @@ -package logservice - -import ( - "bufio" - context "context" - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/agent" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/utils" -) - -type LogProcessor struct { -} - -type LogPipe struct { - Src string - Logs []string -} - -var ( - processor LogProcessor - processorOnce sync.Once - LogQueue = make(chan LogPipe, 1000) - MinutesForCleanLog = 10080 // 7 days in minutes(7*24*60) - MinutesForReportLogsCounted = time.Duration(5 * time.Minute) -) - -func GetLogProcessor() LogProcessor { - processorOnce.Do(func() { - processor = LogProcessor{} - }) - return processor -} - -func (l *LogProcessor) ProcessLogs(client LogServiceClient, ctx context.Context, cnf *configuration.Config, h *logger.Logger) { - connectionTime := 0 * time.Second - reconnectDelay := configuration.InitialReconnectDelay - invalidKeyCounter := 0 - - logsProcessCounter := map[string]int{} - go func() { - for { - time.Sleep(MinutesForReportLogsCounted) - SaveCountedLogs(h, logsProcessCounter) - logsProcessCounter = map[string]int{} - } - }() - - for { - if connectionTime >= configuration.MaxConnectionTime { - connectionTime = 0 * time.Second - reconnectDelay = configuration.InitialReconnectDelay - continue - } - - newLog := <-LogQueue - rcv, err := client.ProcessLogs(ctx, &LogMessage{Type: agent.ConnectorType_AGENT, LogType: newLog.Src, Data: newLog.Logs}) - if err != nil { - h.ErrorF("Error sending logs to Log Auth Proxy: %v", err) - for _, log := range newLog.Logs { - h.ErrorF("log with errors: %s", log) - } - if strings.Contains(err.Error(), "invalid agent key") { - invalidKeyCounter++ - if invalidKeyCounter >= 20 { - h.Info("Uninstalling agent: reason: agent has been removed from the panel...") - err := agent.UninstallAll() - if err != nil { - h.ErrorF("Error uninstalling agent: %s", err) - } - } - } else { - invalidKeyCounter = 0 - } - - time.Sleep(reconnectDelay) - connectionTime = utils.IncrementReconnectTime(connectionTime, reconnectDelay, configuration.MaxConnectionTime) - reconnectDelay = utils.IncrementReconnectDelay(reconnectDelay, configuration.MaxReconnectDelay) - continue - } else if !rcv.Received { - h.ErrorF("Error sending logs to Log Auth Proxy: %s", rcv.Message) - h.Info("logs with errors: ") - for _, log := range newLog.Logs { - h.Info("log: %s", log) - } - if strings.Contains(rcv.Message, "invalid agent key") { - invalidKeyCounter++ - if invalidKeyCounter >= 20 { - h.Info("Uninstalling agent: reason: agent has been removed from the panel...") - err := agent.UninstallAll() - if err != nil { - h.ErrorF("Error uninstalling agent: %s", err) - } - } - } else { - invalidKeyCounter = 0 - } - - time.Sleep(reconnectDelay) - connectionTime = utils.IncrementReconnectTime(connectionTime, reconnectDelay, configuration.MaxConnectionTime) - reconnectDelay = utils.IncrementReconnectDelay(reconnectDelay, configuration.MaxReconnectDelay) - continue - } - - logsProcessCounter[newLog.Src] += len(newLog.Logs) - invalidKeyCounter = 0 - } -} - -func (l *LogProcessor) ProcessLogsWithHighPriority(msg string, client LogServiceClient, ctx context.Context, cnf *configuration.Config, h *logger.Logger) error { - host, err := os.Hostname() - if err != nil { - return fmt.Errorf("error getting hostname: %v", err) - } - - rcv, err := client.ProcessLogs(ctx, &LogMessage{Type: agent.ConnectorType_AGENT, LogType: string(configuration.LogTypeGeneric), Data: []string{configuration.GetMessageFormated(host, msg)}}) - if err != nil { - return fmt.Errorf("error sending logs to Log Auth Proxy: %v", err) - } - if !rcv.Received { - return fmt.Errorf("error sending logs to Log Auth Proxy: %s", rcv.Message) - } - return nil -} - -func SaveCountedLogs(h *logger.Logger, logsProcessCounter map[string]int) { - path, err := utils.GetMyPath() - if err != nil { - h.Fatal("Failed to get current path: %v", err) - } - - filePath := filepath.Join(path, "logs_process") - logFile := filepath.Join(filePath, "processed_logs.txt") - utils.CreatePathIfNotExist(filePath) - - file, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - h.ErrorF("error opening processed_logs.txt file: %s", err) - return - } - defer file.Close() - - var firstLogTime time.Time - var firstLine string - scanner := bufio.NewScanner(file) - for scanner.Scan() { - firstLine = scanner.Text() - break - } - - if firstLine != "" { - firstLogTime, err = time.Parse("2006/01/02 15:04:05.9999999 -0700 MST", strings.Split(firstLine, " - ")[0]) - if err != nil { - h.ErrorF("error parsing first log time: %s", err) - return - } - - if !firstLogTime.IsZero() && time.Since(firstLogTime).Minutes() >= float64(MinutesForCleanLog) { - file.Close() - if err := os.Remove(logFile); err != nil { - h.ErrorF("error removing processed_logs.txt file: %s", err) - return - } - file, err = os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - h.ErrorF("error opening processed_logs.txt file: %s", err) - return - } - } - } - - for name, counter := range logsProcessCounter { - if counter > 0 { - _, err = file.WriteString(fmt.Sprintf("%v - %d logs from %s have been processed\n", time.Now().Format("2006/01/02 15:04:05.9999999 -0700 MST"), counter, name)) - if err != nil { - h.ErrorF("error writing to processed_logs.txt file: %s", err) - continue - } - } - } - -} diff --git a/agent/agent/main.go b/agent/agent/main.go deleted file mode 100644 index a0289ae5f..000000000 --- a/agent/agent/main.go +++ /dev/null @@ -1,176 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "os" - "path/filepath" - "time" - - pb "github.com/utmstack/UTMStack/agent/agent/agent" - "github.com/utmstack/UTMStack/agent/agent/beats" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/logservice" - "github.com/utmstack/UTMStack/agent/agent/modules" - "github.com/utmstack/UTMStack/agent/agent/serv" - "github.com/utmstack/UTMStack/agent/agent/utils" - "google.golang.org/grpc/metadata" -) - -func main() { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - log.Fatalf("Failed to get current path: %v", err) - } - - // Configuring log saving - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) - - if len(os.Args) > 1 { - arg := os.Args[1] - switch arg { - case "run": - serv.RunService(h) - case "install": - h.Info("Installing UTMStack Agent service...") - - // Generate Certificates - certsPath := filepath.Join(path, "certs") - err = utils.CreatePathIfNotExist(certsPath) - if err != nil { - h.Fatal("error creating path: %s", err) - } - - err = utils.GenerateCerts(certsPath) - if err != nil { - h.Fatal("error generating certificates: %v", err) - } - - cnf, utmKey := configuration.GetInitialConfig() - - // Connect to Agent Manager - conn, err := conn.ConnectToServer(cnf, h, cnf.Server, configuration.AGENTMANAGERPORT) - if err != nil { - h.Fatal("error connecting to Agent Manager: %v", err) - } - defer conn.Close() - h.Info("Connection to Agent Manager successful!!!") - - // Register Agent - if err = pb.RegisterAgent(conn, cnf, utmKey, h); err != nil { - h.Fatal("%v", err) - } - - // Write config in config.yml - if err = configuration.SaveConfig(cnf); err != nil { - h.Fatal("error writing config file: %v", err) - } - - if err = modules.ConfigureCollectorFirstTime(); err != nil { - h.Fatal("error configuring syslog server: %v", err) - } - - // Install Beats - if err = beats.InstallBeats(*cnf, h); err != nil { - h.Fatal("error installing beats: %v", err) - } - - serv.InstallService(h) - h.Info("UTMStack Agent service installed correctly") - - case "send-log": - msg := os.Args[2] - logp := logservice.GetLogProcessor() - - // Read config - cnf, err := configuration.GetCurrentConfig() - if err != nil { - os.Exit(0) - } - - // Connect to log-auth-proxy - connLogServ, err := conn.ConnectToServer(cnf, h, cnf.Server, configuration.AUTHLOGSPORT) - if err != nil { - h.ErrorF("error connecting to Log Auth Proxy: %v", err) - } - defer connLogServ.Close() - - // Create a client for LogService - logClient := logservice.NewLogServiceClient(connLogServ) - ctxLog, cancelLog := context.WithCancel(context.Background()) - defer cancelLog() - ctxLog = metadata.AppendToOutgoingContext(ctxLog, "agent-key", cnf.AgentKey) - - err = logp.ProcessLogsWithHighPriority(msg, logClient, ctxLog, cnf, h) - if err != nil { - h.ErrorF("error sending High Priority Log to Log Auth Proxy: %v", err) - } - case "enable-integration", "disable-integration": - integration := os.Args[2] - proto := os.Args[3] - - port, err := modules.ChangeIntegrationStatus(integration, proto, (arg == "enable-integration")) - if err != nil { - fmt.Printf("error trying to %s: %v", arg, err) - h.ErrorF("error trying to %s: %v", arg, err) - os.Exit(0) - } - fmt.Printf("%s %s done correctly in port %s %s", arg, integration, port, proto) - time.Sleep(5 * time.Second) - - case "change-port": - integration := os.Args[2] - proto := os.Args[3] - port := os.Args[4] - - old, err := modules.ChangePort(integration, proto, port) - if err != nil { - fmt.Printf("error trying to change port: %v", err) - h.ErrorF("error trying to change port: %v", err) - os.Exit(0) - } - fmt.Printf("change port done correctly from %s to %s in %s for %s integration", old, port, proto, integration) - time.Sleep(5 * time.Second) - - case "uninstall": - h.Info("Uninstalling UTMStack Agent service...") - - // Read config - cnf, err := configuration.GetCurrentConfig() - if err != nil { - h.Fatal("error getting config: %v", err) - } - - // Connect to Agent Manager - conn, err := conn.ConnectToServer(cnf, h, cnf.Server, configuration.AGENTMANAGERPORT) - if err != nil { - h.ErrorF("error connecting to Agent Manager: %v", err) - } else { - h.Info("Connection to Agent Manager successful!!!") - - // Delete agent - if err = pb.DeleteAgent(conn, cnf, h); err != nil { - h.ErrorF("error deleting agent: %v", err) - } - } - defer conn.Close() - - // Uninstall Beats - if err = beats.UninstallBeats(h); err != nil { - h.Fatal("error uninstalling beats: %v", err) - } - os.Remove(filepath.Join(path, "config.yml")) - - serv.UninstallService(h) - h.Info("UTMStack Agent service uninstalled correctly") - os.Exit(0) - default: - fmt.Println("unknown option") - } - } else { - serv.RunService(h) - } -} diff --git a/agent/agent/modules/template.go b/agent/agent/modules/template.go deleted file mode 100644 index 2c41f0d1e..000000000 --- a/agent/agent/modules/template.go +++ /dev/null @@ -1,52 +0,0 @@ -package modules - -import ( - "fmt" - "os" - "strings" -) - -func WriteCollectorConfig(integrations map[string]Integration, filename string) error { - fileContent := "{\n \"integrations\": {\n" - for name, integration := range integrations { - fileContent += fmt.Sprintf(" \"%s\": {\n", name) - if integration.TCP.Port != "" { - fileContent += fmt.Sprintf(" \"tcp_port\": {\"enabled\": %t, \"value\": \"%s\"},\n", integration.TCP.IsListen, integration.TCP.Port) - } - if integration.UDP.Port != "" { - fileContent += fmt.Sprintf(" \"udp_port\": {\"enabled\": %t, \"value\": \"%s\"},\n", integration.UDP.IsListen, integration.UDP.Port) - } - if strings.HasSuffix(fileContent, ",\n") { - fileContent = fileContent[:len(fileContent)-2] + "\n" - } - fileContent += " },\n" - } - if strings.HasSuffix(fileContent, ",\n") { - fileContent = fileContent[:len(fileContent)-2] + "\n" - } - fileContent += " }\n}\n" - - err := os.WriteFile(filename, []byte(fileContent), 0644) - if err != nil { - return err - } - - return nil -} - -func WriteCollectorConfigFromModules(mod []Module, filename string) error { - integrations := make(map[string]Integration) - for _, m := range mod { - integrations[string(m.GetDataType())] = Integration{ - TCP: Port{ - IsListen: m.IsPortListen("tcp"), - Port: m.GetPort("tcp"), - }, - UDP: Port{ - IsListen: m.IsPortListen("udp"), - Port: m.GetPort("udp"), - }, - } - } - return WriteCollectorConfig(integrations, filename) -} diff --git a/agent/agent/parser/beats.go b/agent/agent/parser/beats.go deleted file mode 100644 index b10ac9ebd..000000000 --- a/agent/agent/parser/beats.go +++ /dev/null @@ -1,80 +0,0 @@ -package parser - -import ( - "fmt" - "regexp" - "sync" - - "github.com/threatwinds/logger" - "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/configuration" -) - -var ( - beatsParser = BeatsParser{} - beatsParserOnce sync.Once - RegexspBeats = map[configuration.LogType]string{ - configuration.LogTypeApacheModule: `"type":"apache"|"module":"apache"`, - configuration.LogTypeLinuxAuditdModule: `"type":"auditd"|"module":"auditd"`, - configuration.LogTypeElasticsearchModule: `"type":"elasticsearch"|"module":"elasticsearch"`, - configuration.LogTypeKafkaModule: `"type":"kafka"|"module":"kafka"`, - configuration.LogTypeKibanaModule: `"type":"kibana"|"module":"kibana"`, - configuration.LogTypeLogstashModule: `"type":"logstash"|"module":"logstash"`, - configuration.LogTypeMongodbModule: `"type":"mongodb"|"module":"mongodb"`, - configuration.LogTypeMysqlModule: `"type":"mysql"|"module":"mysql"`, - configuration.LogTypeNginxModule: `"type":"nginx"|"module":"nginx"`, - configuration.LogTypeOsqueryModule: `"type":"osquery"|"module":"osquery"`, - configuration.LogTypePostgresqlModule: `"type":"postgresql"|"module":"postgresql"`, - configuration.LogTypeRedisModule: `"type":"redis"|"module":"redis"`, - configuration.LogTypeLinuxAgent: `"type":"system"|"module":"system"`, - configuration.LogTypeIisModule: `"type":"iis"|"module":"iis"`, - configuration.LogTypeTraefikModule: `"type":"traefik"|"module":"traefik"`, - configuration.LogTypeNatsModule: `"type":"nats"|"module":"nats"`, - configuration.LogTypeHaproxyModule: `"type":"haproxy"|"module":"haproxy"`, - } -) - -type BeatsParser struct{} - -func GetBeatsParser() *BeatsParser { - beatsParserOnce.Do(func() { - beatsParser = BeatsParser{} - }) - return &beatsParser -} - -func (p *BeatsParser) IdentifySource(log string) (configuration.LogType, error) { - for logType, regp := range RegexspBeats { - regExpCompiled, err := regexp.Compile(string(regp)) - if err != nil { - return "", err - } - if regExpCompiled.MatchString(log) { - return logType, nil - } - } - return configuration.LogTypeGeneric, nil -} - -func (p *BeatsParser) ProcessData(logBatch interface{}, h *logger.Logger) (map[string][]string, error) { - classifiedLogs := make(map[string][]string) - batch, ok := logBatch.([]string) - if !ok { - return nil, fmt.Errorf("invalid log batch type") - } - for _, log := range batch { - if logType, err := p.IdentifySource(log); err != nil { - return nil, err - } else { - if logType != "" { - validatedLog, _, err := validations.ValidateString(log, false) - if err != nil { - h.ErrorF("error validating log: %s: %v", log, err) - continue - } - classifiedLogs[string(logType)] = append(classifiedLogs[string(logType)], validatedLog) - } - } - } - return classifiedLogs, nil -} diff --git a/agent/agent/agent/ping.pb.go b/agent/agent/ping.pb.go similarity index 100% rename from agent/agent/agent/ping.pb.go rename to agent/agent/ping.pb.go diff --git a/agent/agent/agent/ping_grpc.pb.go b/agent/agent/ping_grpc.pb.go similarity index 100% rename from agent/agent/agent/ping_grpc.pb.go rename to agent/agent/ping_grpc.pb.go diff --git a/agent/agent/ping_imp.go b/agent/agent/ping_imp.go new file mode 100644 index 000000000..45463440f --- /dev/null +++ b/agent/agent/ping_imp.go @@ -0,0 +1,79 @@ +package agent + +import ( + "context" + "strings" + "time" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/conn" + "github.com/utmstack/UTMStack/agent/agent/utils" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +var ( + timeToSleep = 10 * time.Second + pingInterval = 15 * time.Second +) + +func StartPing(cnf *config.Config, ctx context.Context) { + var connErrMsgWritten, errorLogged bool + + for { + connection, err := conn.GetAgentManagerConnection(cnf) + if err != nil { + if !connErrMsgWritten { + utils.Logger.ErrorF("error connecting to Agent Manager: %v", err) + connErrMsgWritten = true + } + time.Sleep(timeToSleep) + continue + } + + client := NewPingServiceClient(connection) + stream, err := client.Ping(ctx) + if err != nil { + if !connErrMsgWritten { + utils.Logger.ErrorF("failed to start Ping Stream: %v", err) + connErrMsgWritten = true + } + time.Sleep(timeToSleep) + continue + } + + connErrMsgWritten = false + + ticker := time.NewTicker(pingInterval) + + for range ticker.C { + err := stream.Send(&PingRequest{Type: ConnectorType_AGENT}) + if err != nil { + if strings.Contains(err.Error(), "EOF") { + time.Sleep(timeToSleep) + break + } + st, ok := status.FromError(err) + if ok && (st.Code() == codes.Unavailable || st.Code() == codes.Canceled) { + if !errorLogged { + utils.Logger.ErrorF("error sending Ping request: %v", err) + errorLogged = true + } + time.Sleep(timeToSleep) + break + } else { + if !errorLogged { + utils.Logger.ErrorF("error sending Ping request: %v", err) + errorLogged = true + } + time.Sleep(timeToSleep) + continue + } + } + + errorLogged = false + } + + ticker.Stop() + } +} diff --git a/agent/agent/protos/agent_config.proto b/agent/agent/protos/agent_config.proto deleted file mode 100644 index b824c5dd4..000000000 --- a/agent/agent/protos/agent_config.proto +++ /dev/null @@ -1,55 +0,0 @@ -syntax = "proto3"; - -option go_package = "github.com/utmstack/UTMStack/agent-manager/agent"; - -package agent; - -service AgentConfigService { - rpc GetAgentConfig(ListAgentsModulesRequest) returns (ListAgentsModulesResponse) {} - rpc AgentModuleUpdateStream(stream AgentModuleConfiguration) returns (stream UpdateConfigResponse) {} -} - -message AgentModule { - uint32 id = 1; - uint32 agent_id = 2; - string short_name = 3; - string large_name = 4; - string description = 5; - bool enabled = 6; - bool allow_disabled = 7; - repeated AgentModuleConfiguration module_configs = 8; -} - -message UpdateAgentModule { - string agent_module_short = 1; - string conf_key = 4; - string conf_value = 5; -} - -message AgentModuleConfiguration { - uint32 id = 1; - uint32 agent_module_id = 2; - string short_name = 3; - string conf_key = 4; - string conf_value = 5; - string conf_name = 6; - string conf_description = 7; - string conf_datatype = 8; - bool conf_required = 9; - string conf_regex = 10; -} - -message UpdateConfigResponse{ - string accepted = 1; -} - -// ListAgentsRequest message definition -message ListAgentsModulesRequest { - string agent_key = 2; -} - -// ListAgentsResponse message definition -message ListAgentsModulesResponse { - repeated AgentModule modules = 1; -} - diff --git a/agent/agent/protos/agent_malware.proto b/agent/agent/protos/agent_malware.proto deleted file mode 100644 index 8fc630bec..000000000 --- a/agent/agent/protos/agent_malware.proto +++ /dev/null @@ -1,91 +0,0 @@ -syntax = "proto3"; - -option go_package = "github.com/utmstack/UTMStack/agent-manager/agent"; - -package agent; - -service AgentMalwareService { - rpc GetAgentExclusions(ListExclusionRequest) returns (ListExclusionResponse) {} - rpc CreateNewMalwareEntry(stream AgentMalwareDetection) returns (stream AgentMalwareDetection) {} - rpc ChangeMalwareStatus(stream ChangeStatusRequest) returns (stream AgentMalwareDetection) {} - rpc ListAgentMalware(ListMalwareRequest) returns (ListMalwareResponse) {} - rpc ListAgentMalwareHistory(ListMalwareHistoryRequest) returns (ListMalwareHistoryResponse) {} -} - - -message ListExclusionResponse { - repeated AgentMalwareExclusion exclusions = 1; -} - -message ListExclusionRequest { - int64 agent_id = 1; -} - -message ChangeStatusRequest { - string malware_id = 1; - MalwareStatus status = 2; -} - -enum MalwareStatus { - NEW = 0; - DELETED = 1; - EXCLUDED = 2; - RESTORED = 3; -} - -message AgentMalwareDetection { - int64 id = 1; - uint32 agent_id = 2; - string file_path = 3; - string sha256 = 4; - string md5 = 5; - string description = 6; - MalwareStatus status = 7; -} - -message AgentMalwareHistory { - int64 id = 1; - uint32 malware_id = 2; - MalwareStatus prev_status = 3; - MalwareStatus to_status = 4; - string changed_by = 5; -} - -message AgentMalwareExclusion { - int64 id = 1; - string exclude_file_path = 2; - string excluded_by = 3; - string exclude_description = 4; - int64 agent_id = 5; -} - -// ListAgentsRequest message definition -message ListMalwareRequest { - int32 page_number = 1; - int32 page_size = 2; - string search_query = 3; - repeated string sort_by = 4; - bool sort_descending = 5; -} - -// ListAgentsResponse message definition -message ListMalwareResponse { - repeated AgentMalwareDetection malware = 1; - int32 total_pages = 2; - int32 total_results = 3; -} - -message ListMalwareHistoryRequest { - int32 page_number = 1; - int32 page_size = 2; - string search_query = 3; - repeated string sort_by = 4; - bool sort_descending = 5; -} - -// ListAgentsResponse message definition -message ListMalwareHistoryResponse { - repeated AgentMalwareHistory malware = 1; - int32 total_pages = 2; - int32 total_results = 3; -} \ No newline at end of file diff --git a/agent/agent/redline/redline.go b/agent/agent/redline/redline.go deleted file mode 100644 index 6cac121a3..000000000 --- a/agent/agent/redline/redline.go +++ /dev/null @@ -1,56 +0,0 @@ -package redline - -import ( - "fmt" - "path/filepath" - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/utils" -) - -func CheckRedlineService(h *logger.Logger) { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - h.Fatal("Failed to get current path: %v", err) - } - - bin := configuration.GetAgentBin() - - time.Sleep(5 * time.Minute) - attempts := 0 - for { - if attempts >= 3 { - h.Info("Redline service has been stopped") - if err := utils.Execute(filepath.Join(path, bin), path, "send-log", fmt.Sprintf("%s service has been stopped", configuration.RedlineServName)); err != nil { - h.ErrorF("error checking %s: error sending log : %v", configuration.RedlineServName, err) - time.Sleep(time.Second * 5) - continue - } - if err := utils.RestartService(configuration.RedlineServName); err != nil { - h.ErrorF("error restarting %s service: %v", configuration.RedlineServName, err) - time.Sleep(time.Second * 5) - continue - } - - h.Info("%s restarted correctly", configuration.RedlineServName) - time.Sleep(time.Second * 5) - attempts = 0 - continue - } - - if isRunning, err := utils.CheckIfServiceIsActive(configuration.RedlineServName); err != nil { - h.ErrorF("error checking if %s is running: %v", configuration.RedlineServName, err) - time.Sleep(time.Second * 5) - } else if isRunning { - time.Sleep(time.Second * 5) - continue - } - if !utils.CheckIfPathExist(filepath.Join(path, "locks", configuration.RedlineLockName)) { - attempts++ - time.Sleep(time.Second * 30) - } - } -} diff --git a/agent/agent/agent/register.go b/agent/agent/register.go similarity index 60% rename from agent/agent/agent/register.go rename to agent/agent/register.go index 3b4f5f7d6..993f4a115 100644 --- a/agent/agent/agent/register.go +++ b/agent/agent/register.go @@ -3,22 +3,25 @@ package agent import ( context "context" "fmt" - "strings" - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/conn" + "github.com/utmstack/UTMStack/agent/agent/models" "github.com/utmstack/UTMStack/agent/agent/utils" - "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) -func RegisterAgent(conn *grpc.ClientConn, cnf *configuration.Config, UTMKey string, h *logger.Logger) error { - // Create a client for AgentService - agentClient := NewAgentServiceClient(conn) +func RegisterAgent(cnf *config.Config, UTMKey string) error { + connection, err := conn.GetAgentManagerConnection(cnf) + if err != nil { + return fmt.Errorf("error connecting to Agent Manager: %v", err) + } + + agentClient := NewAgentServiceClient(connection) ctx, cancel := context.WithCancel(context.Background()) + ctx = metadata.AppendToOutgoingContext(ctx, "connection-key", UTMKey) defer cancel() - // Register the agent and store the result in a file ip, err := utils.GetIPAddress() if err != nil { return err @@ -29,9 +32,10 @@ func RegisterAgent(conn *grpc.ClientConn, cnf *configuration.Config, UTMKey stri return fmt.Errorf("error getting os info: %v", err) } - version, err := GetVersion() + version := models.Version{} + err = utils.ReadJson(config.VersionPath, &version) if err != nil { - return fmt.Errorf("error getting agent version: %v", err) + return fmt.Errorf("error reading version file: %v", err) } request := &AgentRequest{ @@ -39,7 +43,7 @@ func RegisterAgent(conn *grpc.ClientConn, cnf *configuration.Config, UTMKey stri Hostname: osInfo.Hostname, Os: osInfo.OsType, Platform: osInfo.Platform, - Version: version, + Version: version.Version, RegisterBy: osInfo.CurrentUser, Mac: osInfo.Mac, OsMajorVersion: osInfo.OsMajorVersion, @@ -48,19 +52,13 @@ func RegisterAgent(conn *grpc.ClientConn, cnf *configuration.Config, UTMKey stri Addresses: osInfo.Addresses, } - ctx = metadata.AppendToOutgoingContext(ctx, "connection-key", UTMKey) response, err := agentClient.RegisterAgent(ctx, request) if err != nil { - if strings.Contains(err.Error(), "hostname has already been registered") { - return fmt.Errorf("failed to register agent: hostname has already been registered") - } return fmt.Errorf("failed to register agent: %v", err) } cnf.AgentID = uint(response.Id) cnf.AgentKey = response.Key - h.Info("successfully registered agent") - return nil } diff --git a/agent/agent/serv/run.go b/agent/agent/serv/run.go deleted file mode 100644 index 1706b223a..000000000 --- a/agent/agent/serv/run.go +++ /dev/null @@ -1,19 +0,0 @@ -package serv - -import ( - "github.com/kardianos/service" - "github.com/threatwinds/logger" -) - -func RunService(h *logger.Logger) { - svcConfig := GetConfigServ() - prg := new(program) - newService, err := service.New(prg, svcConfig) - if err != nil { - h.Fatal("error creating new service: %v", err) - } - err = newService.Run() - if err != nil { - h.Fatal("error running new service: %v", err) - } -} diff --git a/agent/agent/serv/service.go b/agent/agent/serv/service.go deleted file mode 100644 index 7b2278833..000000000 --- a/agent/agent/serv/service.go +++ /dev/null @@ -1,101 +0,0 @@ -package serv - -import ( - "context" - "log" - "os" - "os/signal" - "path/filepath" - "strconv" - "syscall" - - "github.com/kardianos/service" - pb "github.com/utmstack/UTMStack/agent/agent/agent" - "github.com/utmstack/UTMStack/agent/agent/beats" - "github.com/utmstack/UTMStack/agent/agent/configuration" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/logservice" - "github.com/utmstack/UTMStack/agent/agent/modules" - "github.com/utmstack/UTMStack/agent/agent/redline" - "github.com/utmstack/UTMStack/agent/agent/utils" - "google.golang.org/grpc/metadata" -) - -type program struct{} - -func (p *program) Start(s service.Service) error { - go p.run() - return nil -} - -func (p *program) Stop(s service.Service) error { - return nil -} - -func (p *program) run() { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - log.Fatalf("Failed to get current path: %v", err) - } - - // Configuring log saving - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) - // Read config - cnf, err := configuration.GetCurrentConfig() - if err != nil { - h.Fatal("error getting config: %v", err) - } - - // Connect to Agent Manager - connAgentmanager, err := conn.ConnectToServer(cnf, h, cnf.Server, configuration.AGENTMANAGERPORT) - if err != nil { - h.Fatal("error connecting to Agent Manager: %v", err) - } - defer connAgentmanager.Close() - h.Info("Connection to Agent Manager successful!!!") - - // Connect to log-auth-proxy - connLogServ, err := conn.ConnectToServer(cnf, h, cnf.Server, configuration.AUTHLOGSPORT) - if err != nil { - h.Fatal("error connecting to Log Auth Proxy: %v", err) - } - defer connLogServ.Close() - h.Info("Connection to Log Auth Proxy successful!!!") - - // Create a client for AgentService - agentClient := pb.NewAgentServiceClient(connAgentmanager) - ctxAgent, cancelAgent := context.WithCancel(context.Background()) - defer cancelAgent() - ctxAgent = metadata.AppendToOutgoingContext(ctxAgent, "key", cnf.AgentKey) - ctxAgent = metadata.AppendToOutgoingContext(ctxAgent, "id", strconv.Itoa(int(cnf.AgentID))) - - // Create a client for PingService - pingClient := pb.NewPingServiceClient(connAgentmanager) - ctxPing, cancelPing := context.WithCancel(context.Background()) - defer cancelPing() - ctxPing = metadata.AppendToOutgoingContext(ctxPing, "key", cnf.AgentKey) - ctxPing = metadata.AppendToOutgoingContext(ctxPing, "id", strconv.Itoa(int(cnf.AgentID))) - - // Create a client for LogService - logClient := logservice.NewLogServiceClient(connLogServ) - ctxLog, cancelLog := context.WithCancel(context.Background()) - defer cancelLog() - ctxLog = metadata.AppendToOutgoingContext(ctxLog, "key", cnf.AgentKey) - ctxLog = metadata.AppendToOutgoingContext(ctxLog, "id", strconv.Itoa(int(cnf.AgentID))) - - logp := logservice.GetLogProcessor() - go logp.ProcessLogs(logClient, ctxLog, cnf, h) - - beats.BeatsLogsReader(h) - go redline.CheckRedlineService(h) - - go pb.UpdateAgent(agentClient, ctxAgent) - go modules.ModulesUp(h) - go pb.StartPing(pingClient, ctxPing, cnf, h) - go pb.IncidentResponseStream(agentClient, ctxAgent, cnf, h) - - signals := make(chan os.Signal, 1) - signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) - <-signals -} diff --git a/agent/agent/uninstall.go b/agent/agent/uninstall.go new file mode 100644 index 000000000..f1d28f2cc --- /dev/null +++ b/agent/agent/uninstall.go @@ -0,0 +1,17 @@ +package agent + +import ( + "fmt" + "path/filepath" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +func UninstallAll() error { + err := utils.Execute(filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.ServiceFile, "")), utils.GetMyPath(), "uninstall") + if err != nil { + return fmt.Errorf("%v", err) + } + return nil +} diff --git a/agent/agent/agent/update.go b/agent/agent/update.go similarity index 51% rename from agent/agent/agent/update.go rename to agent/agent/update.go index 62239f057..3301b468b 100644 --- a/agent/agent/agent/update.go +++ b/agent/agent/update.go @@ -4,23 +4,34 @@ import ( context "context" "fmt" + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/conn" + "github.com/utmstack/UTMStack/agent/agent/models" "github.com/utmstack/UTMStack/agent/agent/utils" ) -func UpdateAgent(client AgentServiceClient, ctx context.Context) error { +func UpdateAgent(cnf *config.Config, ctx context.Context) error { + connection, err := conn.GetAgentManagerConnection(cnf) + if err != nil { + return fmt.Errorf("error connecting to Agent Manager: %v", err) + } + + client := NewAgentServiceClient(connection) + osInfo, err := utils.GetOsInfo() if err != nil { return fmt.Errorf("error getting os info: %v", err) } - version, err := GetVersion() + version := models.Version{} + err = utils.ReadJson(config.VersionPath, &version) if err != nil { - return fmt.Errorf("error getting agent version: %v", err) + utils.Logger.Fatal("error reading version file: %v", err) } request := &AgentRequest{ Hostname: osInfo.Hostname, - Version: version, + Version: version.Version, Mac: osInfo.Mac, OsMajorVersion: osInfo.OsMajorVersion, OsMinorVersion: osInfo.OsMinorVersion, diff --git a/agent/agent/utils/logger.go b/agent/agent/utils/logger.go deleted file mode 100644 index 213f64a69..000000000 --- a/agent/agent/utils/logger.go +++ /dev/null @@ -1,22 +0,0 @@ -package utils - -import ( - "sync" - - "github.com/threatwinds/logger" -) - -var ( - agentLogger *logger.Logger - loggerOnceInstance sync.Once -) - -// CreateLogger returns a single instance of a Logger configured to save logs to a rotating file. -func CreateLogger(filename string) *logger.Logger { - loggerOnceInstance.Do(func() { - agentLogger = logger.NewLogger( - &logger.Config{Format: "text", Level: 100, Output: filename, Retries: 3, Wait: 5}, - ) - }) - return agentLogger -} diff --git a/agent/agent/utils/services.go b/agent/agent/utils/services.go deleted file mode 100644 index b9fe53ab0..000000000 --- a/agent/agent/utils/services.go +++ /dev/null @@ -1,184 +0,0 @@ -package utils - -import ( - "fmt" - "os" - "runtime" - "strings" -) - -// CheckIfServiceIsActive checks if a service is active or running -func CheckIfServiceIsActive(serv string) (bool, error) { - var errB bool - var output string - - path, err := GetMyPath() - if err != nil { - return false, fmt.Errorf("error getting current path: %v", err) - } - - switch runtime.GOOS { - case "windows": - output, errB = ExecuteWithResult("sc", path, "query", serv) - case "linux": - output, errB = ExecuteWithResult("systemctl", path, "is-active", serv) - default: - return false, fmt.Errorf("unknown operating system") - } - - if errB { - return false, nil - } - - serviceStatus := strings.ToLower(strings.TrimSpace(string(output))) - if runtime.GOOS == "linux" { - return serviceStatus == "active", nil - } else if runtime.GOOS == "windows" { - return strings.Contains(serviceStatus, "running"), nil - } - - return false, fmt.Errorf("unsupported operating system") -} - -// RestartService restarts a service -func RestartService(serv string) error { - path, err := GetMyPath() - if err != nil { - return fmt.Errorf("error getting current path: %v", err) - } - - isRunning, err := CheckIfServiceIsActive(serv) - if err != nil { - return fmt.Errorf("error checking if %s service is active: %v", serv, err) - } - - switch runtime.GOOS { - case "windows": - if isRunning { - err := Execute("sc", path, "stop", serv) - if err != nil { - return fmt.Errorf("error stopping service: %v", err) - } - } - err := Execute("sc", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - - case "linux": - if isRunning { - err := Execute("systemctl", path, "restart", serv) - if err != nil { - return fmt.Errorf("error restarting service: %v", err) - } - } else { - err := Execute("systemctl", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - } - } - return nil -} - -func StopService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } - switch runtime.GOOS { - case "windows": - err := Execute("sc", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - case "linux": - err := Execute("systemctl", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - } - return nil -} - -func UninstallService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } - switch runtime.GOOS { - case "windows": - err := Execute("sc", path, "delete", name) - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - case "linux": - err := Execute("systemctl", path, "disable", name) - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - err = Execute("rm", "/etc/systemd/system/", "/etc/systemd/system/"+name+".service") - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - } - return nil -} - -// CheckIfServiceIsInstalled checks if a service is installed -func CheckIfServiceIsInstalled(serv string) (bool, error) { - path, err := GetMyPath() - if err != nil { - return false, err - } - switch runtime.GOOS { - case "windows": - err = Execute("sc", path, "query", serv) - case "linux": - err = Execute("systemctl", path, "status", serv) - default: - return false, fmt.Errorf("operative system unknown") - } - - if err != nil { - return false, nil - } - return true, nil -} - -func CreateLinuxService(serviceName string, execStart string) error { - servicePath := "/etc/systemd/system/" + serviceName + ".service" - if !CheckIfPathExist(servicePath) { - file, err := os.Create(servicePath) - if err != nil { - return fmt.Errorf("error creating %s file: %v", servicePath, err) - } - defer file.Close() - - serviceContent := fmt.Sprintf(`[Unit] -Description=%s -After=network.target - -[Service] -ExecStart=%s -Restart=always - -[Install] -WantedBy=multi-user.target -`, serviceName, execStart) - - _, err = file.WriteString(serviceContent) - if err != nil { - return err - } - - err = file.Sync() - if err != nil { - return err - } - } else { - return fmt.Errorf("service %s already exists", serviceName) - } - - return nil -} diff --git a/agent/collectors/collectors.go b/agent/collectors/collectors.go new file mode 100644 index 000000000..ab1e39b40 --- /dev/null +++ b/agent/collectors/collectors.go @@ -0,0 +1,68 @@ +package collectors + +import ( + "fmt" + "runtime" + + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +type CollectorConfig struct { + LogsPath string + LogFileName string +} + +type Collector interface { + Install() error + SendSystemLogs() + Uninstall() error +} + +func getCollectorsInstances() []Collector { + var collectors []Collector + switch runtime.GOOS { + case "windows": + collectors = append(collectors, Winlogbeat{}) + collectors = append(collectors, Filebeat{}) + case "linux": + collectors = append(collectors, Filebeat{}) + } + + return collectors +} + +func InstallCollectors() error { + collectors := getCollectorsInstances() + + for _, collector := range collectors { + err := collector.Install() + if err != nil { + return fmt.Errorf("%v", err) + } + } + + utils.Logger.Info("collector installed correctly") + + return nil +} + +func LogsReader() { + collectors := getCollectorsInstances() + for _, collector := range collectors { + go collector.SendSystemLogs() + } +} + +func UninstallCollectors() error { + collectors := getCollectorsInstances() + + for _, collector := range collectors { + err := collector.Uninstall() + if err != nil { + return fmt.Errorf("%v", err) + } + } + + utils.Logger.Info("collectors uninstalled correctly") + return nil +} diff --git a/agent/agent/beats/filebeat.go b/agent/collectors/filebeat.go similarity index 67% rename from agent/agent/beats/filebeat.go rename to agent/collectors/filebeat.go index ebea2d4c8..d6aeec440 100644 --- a/agent/agent/beats/filebeat.go +++ b/agent/collectors/filebeat.go @@ -1,12 +1,11 @@ -package beats +package collectors import ( "fmt" "path/filepath" "runtime" - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" "github.com/utmstack/UTMStack/agent/agent/logservice" "github.com/utmstack/UTMStack/agent/agent/parser" "github.com/utmstack/UTMStack/agent/agent/utils" @@ -15,19 +14,16 @@ import ( type Filebeat struct{} func (f Filebeat) Install() error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("error getting current path: %v", err) - } + path := utils.GetMyPath() filebLogPath := filepath.Join(path, "beats", "filebeat") - beatConfig := BeatConfig{ + beatConfig := CollectorConfig{ LogsPath: filepath.Join(filebLogPath, "logs"), LogFileName: "modulescollector", } - if isInstalled, err := utils.CheckIfServiceIsInstalled(configuration.ModulesServName); err != nil { - return fmt.Errorf("error checking if %s service is installed: %v", configuration.ModulesServName, err) + if isInstalled, err := utils.CheckIfServiceIsInstalled(config.ModulesServName); err != nil { + return fmt.Errorf("error checking if %s service is installed: %v", config.ModulesServName, err) } else if !isInstalled { if err = utils.CreatePathIfNotExist(beatConfig.LogsPath); err != nil { return fmt.Errorf("error creating %s folder", beatConfig.LogsPath) @@ -43,23 +39,23 @@ func (f Filebeat) Install() error { err = utils.Execute("sc", filebLogPath, "create", - configuration.ModulesServName, + config.ModulesServName, "binPath=", fmt.Sprintf("\"%s\\filebeat.exe\" --environment=windows_service -c \"%s\\filebeat.yml\" --path.home \"%s\" --path.data \"C:\\ProgramData\\filebeat\" --path.logs \"C:\\ProgramData\\filebeat\\logs\" -E logging.files.redirect_stderr=true", filebLogPath, filebLogPath, filebLogPath), "DisplayName=", - configuration.ModulesServName, + config.ModulesServName, "start=", "auto") if err != nil { - return fmt.Errorf("error installing %s service: %s", configuration.ModulesServName, err) + return fmt.Errorf("error installing %s service: %s", config.ModulesServName, err) } - err = utils.Execute("sc", filebLogPath, "start", configuration.ModulesServName) + err = utils.Execute("sc", filebLogPath, "start", config.ModulesServName) if err != nil { - return fmt.Errorf("error starting %s service: %s", configuration.ModulesServName, err) + return fmt.Errorf("error starting %s service: %s", config.ModulesServName, err) } case "linux": - if err = utils.CreateLinuxService(configuration.ModulesServName, fmt.Sprintf( + if err = utils.CreateLinuxService(config.ModulesServName, fmt.Sprintf( "%s -c %s -path.home %s -path.config %s -path.data /var/lib/filebeat -path.logs /var/log/filebeat", filepath.Join(filebLogPath, "filebeat"), filepath.Join(filebLogPath, "filebeat.yml"), @@ -67,7 +63,7 @@ func (f Filebeat) Install() error { filebLogPath, ), ); err != nil { - return fmt.Errorf("error creating %s service: %v", configuration.ModulesServName, err) + return fmt.Errorf("error creating %s service: %v", config.ModulesServName, err) } if err = utils.Execute("chmod", filebLogPath, "-R", "777", "filebeat"); err != nil { @@ -84,12 +80,12 @@ func (f Filebeat) Install() error { } if family == "debian" || family == "rhel" { - err := utils.Execute("systemctl", filebLogPath, "enable", configuration.ModulesServName) + err := utils.Execute("systemctl", filebLogPath, "enable", config.ModulesServName) if err != nil { return fmt.Errorf("%s", err) } - err = utils.Execute("systemctl", filebLogPath, "start", configuration.ModulesServName) + err = utils.Execute("systemctl", filebLogPath, "start", config.ModulesServName) if err != nil { return fmt.Errorf("%s", err) } @@ -104,7 +100,7 @@ func (f Filebeat) Install() error { return fmt.Errorf("%s", err) } - err = utils.Execute("systemctl", filebLogPath, "restart", configuration.ModulesServName) + err = utils.Execute("systemctl", filebLogPath, "restart", config.ModulesServName) if err != nil { return fmt.Errorf("%s", err) } @@ -115,21 +111,18 @@ func (f Filebeat) Install() error { return nil } -func (f Filebeat) SendSystemLogs(h *logger.Logger) { +func (f Filebeat) SendSystemLogs() { logLinesChan := make(chan []string) - path, err := utils.GetMyPath() - if err != nil { - h.ErrorF("error getting current path: %v", err) - } + path := utils.GetMyPath() filebLogPath := filepath.Join(path, "beats", "filebeat", "logs") parser := parser.GetParser("beats") - go utils.WatchFolder("modulescollector", filebLogPath, logLinesChan, configuration.BatchCapacity, h) + go utils.WatchFolder("modulescollector", filebLogPath, logLinesChan, config.BatchCapacity) for logLine := range logLinesChan { - beatsData, err := parser.ProcessData(logLine, h) + beatsData, err := parser.ProcessData(logLine) if err != nil { - h.ErrorF("error processing beats data: %v", err) + utils.Logger.ErrorF("error processing beats data: %v", err) continue } for typ, logB := range beatsData { @@ -142,17 +135,17 @@ func (f Filebeat) SendSystemLogs(h *logger.Logger) { } func (f Filebeat) Uninstall() error { - if isInstalled, err := utils.CheckIfServiceIsInstalled(configuration.ModulesServName); err != nil { - return fmt.Errorf("error checking if %s is running: %v", configuration.ModulesServName, err) + if isInstalled, err := utils.CheckIfServiceIsInstalled(config.ModulesServName); err != nil { + return fmt.Errorf("error checking if %s is running: %v", config.ModulesServName, err) } else if isInstalled { - err = utils.StopService(configuration.ModulesServName) + err = utils.StopService(config.ModulesServName) if err != nil { - return fmt.Errorf("error stopping %s: %v", configuration.ModulesServName, err) + return fmt.Errorf("error stopping %s: %v", config.ModulesServName, err) } - err = utils.UninstallService(configuration.ModulesServName) + err = utils.UninstallService(config.ModulesServName) if err != nil { - return fmt.Errorf("error uninstalling %s: %v", configuration.ModulesServName, err) + return fmt.Errorf("error uninstalling %s: %v", config.ModulesServName, err) } } return nil diff --git a/agent/agent/beats/winlogbeat.go b/agent/collectors/winlogbeat.go similarity index 60% rename from agent/agent/beats/winlogbeat.go rename to agent/collectors/winlogbeat.go index 75ae5404a..ef65a48c0 100644 --- a/agent/agent/beats/winlogbeat.go +++ b/agent/collectors/winlogbeat.go @@ -1,12 +1,11 @@ -package beats +package collectors import ( "fmt" "path/filepath" - "github.com/threatwinds/logger" "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" "github.com/utmstack/UTMStack/agent/agent/logservice" "github.com/utmstack/UTMStack/agent/agent/utils" ) @@ -14,19 +13,16 @@ import ( type Winlogbeat struct{} func (w Winlogbeat) Install() error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("error getting current path: %v", err) - } + path := utils.GetMyPath() winlogPath := filepath.Join(path, "beats", "winlogbeat") - beatConfig := BeatConfig{ + beatConfig := CollectorConfig{ LogsPath: filepath.Join(winlogPath, "logs"), LogFileName: "windowscollector", } - if isInstalled, err := utils.CheckIfServiceIsInstalled(configuration.WinServName); err != nil { - return fmt.Errorf("error checking if %s service is installed: %v", configuration.WinServName, err) + if isInstalled, err := utils.CheckIfServiceIsInstalled(config.WinServName); err != nil { + return fmt.Errorf("error checking if %s service is installed: %v", config.WinServName, err) } else if !isInstalled { err = utils.CreatePathIfNotExist(beatConfig.LogsPath) if err != nil { @@ -43,63 +39,60 @@ func (w Winlogbeat) Install() error { err = utils.Execute("sc", winlogPath, "create", - configuration.WinServName, + config.WinServName, "binPath=", fmt.Sprintf("\"%s\\winlogbeat.exe\" --environment=windows_service -c \"%s\\winlogbeat.yml\" --path.home \"%s\" --path.data \"C:\\ProgramData\\winlogbeat\" --path.logs \"C:\\ProgramData\\winlogbeat\\logs\" -E logging.files.redirect_stderr=true", winlogPath, winlogPath, winlogPath), "DisplayName=", - configuration.WinServName, + config.WinServName, "start=", "auto") if err != nil { - return fmt.Errorf("error installing %s service: %s", configuration.WinServName, err) + return fmt.Errorf("error installing %s service: %s", config.WinServName, err) } - err = utils.Execute("sc", winlogPath, "start", configuration.WinServName) + err = utils.Execute("sc", winlogPath, "start", config.WinServName) if err != nil { - return fmt.Errorf("error starting %s service: %s", configuration.WinServName, err) + return fmt.Errorf("error starting %s service: %s", config.WinServName, err) } } return nil } -func (w Winlogbeat) SendSystemLogs(h *logger.Logger) { +func (w Winlogbeat) SendSystemLogs() { logLinesChan := make(chan []string) - path, err := utils.GetMyPath() - if err != nil { - h.ErrorF("error getting current path: %v", err) - } + path := utils.GetMyPath() winbLogPath := filepath.Join(path, "beats", "winlogbeat", "logs") - go utils.WatchFolder("windowscollector", winbLogPath, logLinesChan, configuration.BatchCapacity, h) + go utils.WatchFolder("windowscollector", winbLogPath, logLinesChan, config.BatchCapacity) for logLine := range logLinesChan { validatedLogs := []string{} for _, log := range logLine { validatedLog, _, err := validations.ValidateString(log, false) if err != nil { - h.ErrorF("error validating log: %s: %v", log, err) + utils.Logger.ErrorF("error validating log: %s: %v", log, err) continue } validatedLogs = append(validatedLogs, validatedLog) } logservice.LogQueue <- logservice.LogPipe{ - Src: string(configuration.LogTypeWindowsAgent), + Src: string(config.DataTypeWindowsAgent), Logs: validatedLogs, } } } func (w Winlogbeat) Uninstall() error { - if isInstalled, err := utils.CheckIfServiceIsInstalled(configuration.WinServName); err != nil { - return fmt.Errorf("error checking if %s is running: %v", configuration.WinServName, err) + if isInstalled, err := utils.CheckIfServiceIsInstalled(config.WinServName); err != nil { + return fmt.Errorf("error checking if %s is running: %v", config.WinServName, err) } else if isInstalled { - err = utils.StopService(configuration.WinServName) + err = utils.StopService(config.WinServName) if err != nil { - return fmt.Errorf("error stopping %s: %v", configuration.WinServName, err) + return fmt.Errorf("error stopping %s: %v", config.WinServName, err) } - err = utils.UninstallService(configuration.WinServName) + err = utils.UninstallService(config.WinServName) if err != nil { - return fmt.Errorf("error uninstalling %s: %v", configuration.WinServName, err) + return fmt.Errorf("error uninstalling %s: %v", config.WinServName, err) } } diff --git a/agent/agent/configuration/config.go b/agent/config/config.go similarity index 69% rename from agent/agent/configuration/config.go rename to agent/config/config.go index 38ed72fbf..4e1061c87 100644 --- a/agent/agent/configuration/config.go +++ b/agent/config/config.go @@ -1,9 +1,8 @@ -package configuration +package config import ( "fmt" "os" - "path/filepath" "sync" aesCrypt "github.com/AtlasInsideCorp/AtlasInsideAES" @@ -45,30 +44,24 @@ var ( func GetCurrentConfig() (*Config, error) { var errR error confOnce.Do(func() { - path, err := utils.GetMyPath() - if err != nil { - errR = fmt.Errorf("failed to get current path: %v", err) - return - } - - uuidExists := utils.CheckIfPathExist(filepath.Join(path, UUIDFileName)) + uuidExists := utils.CheckIfPathExist(UUIDFileName) var encryptConfig Config - if err = utils.ReadYAML(filepath.Join(path, "config.yml"), &encryptConfig); err != nil { + if err := utils.ReadYAML(ConfigurationFile, &encryptConfig); err != nil { errR = fmt.Errorf("error reading config file: %v", err) return } - // Get key var key []byte + var err error if uuidExists { - uuid, err := GetUUID() + id, err := GetUUID() if err != nil { errR = fmt.Errorf("failed to get uuid: %v", err) return } - key, err = utils.GenerateKeyByUUID(REPLACE_KEY, uuid) + key, err = utils.GenerateKeyByUUID(REPLACE_KEY, id) if err != nil { errR = fmt.Errorf("error geneating key: %v", err) return @@ -81,7 +74,6 @@ func GetCurrentConfig() (*Config, error) { } } - // Decrypt config agentKey, err := aesCrypt.AESDecrypt(encryptConfig.AgentKey, key) if err != nil { errR = fmt.Errorf("error encoding agent key: %v", err) @@ -107,24 +99,16 @@ func GetCurrentConfig() (*Config, error) { } func SaveConfig(cnf *Config) error { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - uuid, err := GenerateNewUUID() + id, err := GenerateNewUUID() if err != nil { return fmt.Errorf("failed to generate uuid: %v", err) } - // Get key - key, err := utils.GenerateKeyByUUID(REPLACE_KEY, uuid) + key, err := utils.GenerateKeyByUUID(REPLACE_KEY, id) if err != nil { return fmt.Errorf("error geneating key: %v", err) } - // Encrypt config agentKey, err := aesCrypt.AESEncrypt(cnf.AgentKey, key) if err != nil { return fmt.Errorf("error encoding agent key: %v", err) @@ -137,8 +121,7 @@ func SaveConfig(cnf *Config) error { SkipCertValidation: cnf.SkipCertValidation, } - // Write config in config.yml - if err := utils.WriteYAML(filepath.Join(path, "config.yml"), encryptConf); err != nil { + if err := utils.WriteYAML(ConfigurationFile, encryptConf); err != nil { return err } return nil @@ -154,12 +137,7 @@ func GenerateNewUUID() (string, error) { UUID: uuid.String(), } - path, err := utils.GetMyPath() - if err != nil { - return "", fmt.Errorf("failed to get current path: %v", err) - } - - if err = utils.WriteYAML(filepath.Join(path, UUIDFileName), InstallationUUID); err != nil { + if err = utils.WriteYAML(UUIDFileName, InstallationUUID); err != nil { return "", fmt.Errorf("error writing uuid file: %v", err) } @@ -169,19 +147,13 @@ func GenerateNewUUID() (string, error) { func GetUUID() (string, error) { var errR error instuuidOnce.Do(func() { - path, err := utils.GetMyPath() - if err != nil { - errR = fmt.Errorf("failed to get current path: %v", err) - return - } - - var uuid = InstallationUUID{} - if err = utils.ReadYAML(filepath.Join(path, UUIDFileName), &uuid); err != nil { + var id = InstallationUUID{} + if err := utils.ReadYAML(UUIDFileName, &id); err != nil { errR = fmt.Errorf("error reading uuid file: %v", err) return } - instuuid = uuid.UUID + instuuid = id.UUID }) if errR != nil { diff --git a/agent/config/const.go b/agent/config/const.go new file mode 100644 index 000000000..c4b6ce04b --- /dev/null +++ b/agent/config/const.go @@ -0,0 +1,132 @@ +package config + +import ( + "path/filepath" + + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +const REPLACE_KEY string = "" + +type DataType string + +type ProtoPort struct { + UDP string + TCP string +} + +var ( + DependUrl = "https://%s:%s/private/dependencies/agent/%s" + AgentManagerPort = "9000" + LogAuthProxyPort = "50051" + DependenciesPort = "9001" + + ServiceLogFile = filepath.Join(utils.GetMyPath(), "logs", "utmstack_agent.log") + ModulesServName = "UTMStackModulesLogsCollector" + WinServName = "UTMStackWindowsLogsCollector" + CollectorFileName = filepath.Join(utils.GetMyPath(), "log-collector-config.json") + CollectorFileNameOld = filepath.Join(utils.GetMyPath(), "log-collector-configuration.json") + UUIDFileName = filepath.Join(utils.GetMyPath(), "uuid.yml") + ConfigurationFile = filepath.Join(utils.GetMyPath(), "config.yml") + PortRangeMin = "7000" + PortRangeMax = "9000" + RetentionConfigFile = filepath.Join(utils.GetMyPath(), "retention.json") + LogsDBFile = filepath.Join(utils.GetMyPath(), "logs_process", "logs.db") + CertPath = filepath.Join(utils.GetMyPath(), "certs", "utm.crt") + VersionPath = filepath.Join(utils.GetMyPath(), "version.json") + MESSAGE_HEADER = "utm_stack_agent_ds" + BatchCapacity = 100 + + // MaxConnectionTime = 120 * time.Second + // SERV_NAME = "UTMStackAgent" + // SERV_LOG = "utmstack_agent.log" + // ModulesLockName = "utmstack_modules_collector.lock" + // WinLockName = "utmstack_windows_collector.lock" + // RedlineLockName = "utmstack_redline.lock" + // RedlineServName = "UTMStackRedline" + // BatchToSend = 5 + + DataTypeWindowsAgent DataType = "wineventlog" + DataTypeSyslog DataType = "syslog" + DataTypeVmware DataType = "vmware-esxi" + DataTypeLinuxAgent DataType = "linux" + DataTypeEset DataType = "antivirus-esmc-eset" + DataTypeKaspersky DataType = "antivirus-kaspersky" + DataTypeTraefikModule DataType = "traefik" + DataTypeMongodbModule DataType = "mongodb" + DataTypeMysqlModule DataType = "mysql" + DataTypePostgresqlModule DataType = "postgresql" + DataTypeRedisModule DataType = "redis" + DataTypeElasticsearchModule DataType = "elasticsearch" + DataTypeKafkaModule DataType = "kafka" + DataTypeKibanaModule DataType = "kibana" + DataTypeLogstashModule DataType = "logstash" + DataTypeCiscoAsa DataType = "firewall-cisco-asa" + DataTypeCiscoMeraki DataType = "firewall-meraki" + DataTypeFortinet DataType = "firewall-fortigate-traffic" + DataTypePaloalto DataType = "firewall-paloalto" + DataTypeMikrotik DataType = "firewall-mikrotik" + DataTypeCiscoFirepower DataType = "firewall-cisco-firepower" + DataTypeSophosXG DataType = "firewall-sophos-xg" + DataTypeCiscoSwitch DataType = "cisco-switch" + DataTypeSonicwall DataType = "firewall-sonicwall" + DataTypeNatsModule DataType = "nats" + DataTypeDeceptivebytes DataType = "deceptive-bytes" + DataTypeOsqueryModule DataType = "osquery" + DataTypeLinuxAuditdModule DataType = "auditd" + DataTypeHaproxyModule DataType = "haproxy" + DataTypeNginxModule DataType = "nginx" + DataTypeIisModule DataType = "iis" + DataTypeApacheModule DataType = "apache" + DataTypeSentinelOne DataType = "antivirus-sentinel-one" + DataTypeCiscoGeneric DataType = "cisco" + DataTypeMacOs DataType = "macos" + DataTypeGeneric DataType = "generic" + DataTypeNetflow DataType = "netflow" + DataTypeAix DataType = "ibm-aix" + DataTypePfsense DataType = "firewall-pfsense" + DataTypeFortiweb DataType = "firewall-fortiweb" + + ProtoPorts = map[DataType]ProtoPort{ + DataTypeSyslog: {UDP: "7014", TCP: "7014"}, + DataTypeVmware: {UDP: "7002", TCP: "7002"}, + DataTypeEset: {UDP: "7003", TCP: "7003"}, + DataTypeKaspersky: {UDP: "7004", TCP: "7004"}, + DataTypeCiscoGeneric: {UDP: "514", TCP: "1470"}, + DataTypeFortinet: {UDP: "7005", TCP: "7005"}, + DataTypePaloalto: {UDP: "7006", TCP: "7006"}, + DataTypeMikrotik: {UDP: "7007", TCP: "7007"}, + DataTypeSophosXG: {UDP: "7008", TCP: "7008"}, + DataTypeSonicwall: {UDP: "7009", TCP: "7009"}, + DataTypeDeceptivebytes: {UDP: "7010", TCP: "7010"}, + DataTypeSentinelOne: {UDP: "7012", TCP: "7012"}, + DataTypeMacOs: {UDP: "7015", TCP: "7015"}, + DataTypeAix: {UDP: "7016", TCP: "7016"}, + DataTypePfsense: {UDP: "7017", TCP: "7017"}, + DataTypeFortiweb: {UDP: "7018", TCP: "7018"}, + DataTypeNetflow: {UDP: "2055", TCP: ""}, + } + + ProhibitedPortsChange = []DataType{DataTypeCiscoGeneric, DataTypeNetflow} +) + +func GetMessageFormated(host string, msg string) string { + return "[" + MESSAGE_HEADER + "=" + host + "]-" + msg +} + +func ValidateModuleType(typ string) string { + switch DataType(typ) { + case DataTypeSyslog, DataTypeVmware, DataTypeEset, DataTypeKaspersky, DataTypeFortinet, DataTypePaloalto, + DataTypeMikrotik, DataTypeSophosXG, DataTypeSonicwall, DataTypeSentinelOne, DataTypeCiscoGeneric, DataTypeMacOs, + DataTypeDeceptivebytes, DataTypeAix, DataTypePfsense, DataTypeFortiweb: + return "syslog" + case DataTypeNetflow: + return "netflow" + case DataTypeWindowsAgent, DataTypeLinuxAgent, DataTypeTraefikModule, DataTypeMongodbModule, DataTypeMysqlModule, DataTypePostgresqlModule, + DataTypeRedisModule, DataTypeElasticsearchModule, DataTypeKafkaModule, DataTypeKibanaModule, DataTypeLogstashModule, DataTypeNatsModule, + DataTypeOsqueryModule, DataTypeLinuxAuditdModule, DataTypeHaproxyModule, DataTypeNginxModule, DataTypeIisModule, DataTypeApacheModule: + return "beats" + default: + return "nil" + } +} diff --git a/agent/config/linux_amd64.go b/agent/config/linux_amd64.go new file mode 100644 index 000000000..76c777a2b --- /dev/null +++ b/agent/config/linux_amd64.go @@ -0,0 +1,10 @@ +//go:build linux && amd64 +// +build linux,amd64 + +package config + +var ( + UpdaterSelf = "utmstack_updater_self%s" + ServiceFile = "utmstack_agent_service%s" + DependFiles = []string{"utmstack_agent_dependencies_linux.zip"} +) diff --git a/agent/config/linux_arm64.go b/agent/config/linux_arm64.go new file mode 100644 index 000000000..138c70002 --- /dev/null +++ b/agent/config/linux_arm64.go @@ -0,0 +1,10 @@ +//go:build linux && arm64 +// +build linux,arm64 + +package config + +var ( + UpdaterSelf = "utmstack_updater_self_arm64%s" + ServiceFile = "utmstack_agent_service_arm64%s" + DependFiles = []string{"utmstack_agent_dependencies_linux_arm64.zip"} +) diff --git a/agent/config/win_amd64.go b/agent/config/win_amd64.go new file mode 100644 index 000000000..af4490cd0 --- /dev/null +++ b/agent/config/win_amd64.go @@ -0,0 +1,10 @@ +//go:build windows && amd64 +// +build windows,amd64 + +package config + +var ( + UpdaterSelf = "utmstack_updater_self%s.exe" + ServiceFile = "utmstack_agent_service%s.exe" + DependFiles = []string{"utmstack_agent_dependencies_windows.zip"} +) diff --git a/agent/config/win_arm64.go b/agent/config/win_arm64.go new file mode 100644 index 000000000..aa136d400 --- /dev/null +++ b/agent/config/win_arm64.go @@ -0,0 +1,10 @@ +//go:build windows && arm64 +// +build windows,arm64 + +package config + +var ( + UpdaterSelf = "utmstack_updater_self_arm64%s.exe" + ServiceFile = "utmstack_agent_service_arm64%s.exe" + DependFiles = []string{"utmstack_agent_dependencies_windows_arm64.zip"} +) diff --git a/agent/conn/conn.go b/agent/conn/conn.go new file mode 100644 index 000000000..87396fd23 --- /dev/null +++ b/agent/conn/conn.go @@ -0,0 +1,118 @@ +package conn + +import ( + "crypto/tls" + "fmt" + "sync" + "time" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/utils" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" +) + +const ( + maxMessageSize = 1024 * 1024 * 1024 + maxConnectionAttempts = 3 + initialReconnectDelay = 10 * time.Second + maxReconnectDelay = 60 * time.Second +) + +var ( + correlationConn *grpc.ClientConn + correlationConnOnce sync.Once + agentManagerConn *grpc.ClientConn + agentManagerConnOnce sync.Once +) + +func GetAgentManagerConnection(cnf *config.Config) (*grpc.ClientConn, error) { + var err error + agentManagerConnOnce.Do(func() { + agentManagerConn, err = connectToServer(cnf.Server, config.AgentManagerPort, cnf.SkipCertValidation) + if err != nil { + err = fmt.Errorf("error connecting to Agent Manager: %v", err) + } + }) + if err != nil { + return nil, err + } + + state := agentManagerConn.GetState() + if state == connectivity.Shutdown || state == connectivity.TransientFailure { + agentManagerConn.Close() + agentManagerConn, err = connectToServer(cnf.Server, config.AgentManagerPort, cnf.SkipCertValidation) + if err != nil { + return nil, fmt.Errorf("error connecting to Agent Manager: %v", err) + } + } + + return agentManagerConn, nil +} + +func GetCorrelationConnection(cnf *config.Config) (*grpc.ClientConn, error) { + var err error + correlationConnOnce.Do(func() { + correlationConn, err = connectToServer(cnf.Server, config.LogAuthProxyPort, cnf.SkipCertValidation) + if err != nil { + err = fmt.Errorf("error connecting to Correlation: %v", err) + } + }) + if err != nil { + return nil, err + } + + state := correlationConn.GetState() + if state == connectivity.Shutdown || state == connectivity.TransientFailure { + correlationConn.Close() + correlationConn, err = connectToServer(cnf.Server, config.LogAuthProxyPort, cnf.SkipCertValidation) + if err != nil { + return nil, fmt.Errorf("error connecting to Correlation: %v", err) + } + } + + return correlationConn, nil +} + +func connectToServer(addrs, port string, skip bool) (*grpc.ClientConn, error) { + connectionAttemps := 0 + reconnectDelay := initialReconnectDelay + + serverAddress := addrs + ":" + port + var conn *grpc.ClientConn + var err error + + for { + if connectionAttemps >= maxConnectionAttempts { + return nil, fmt.Errorf("failed to connect to Server: %v", err) + } + + dialOptions := []grpc.DialOption{ + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMessageSize)), + } + + if !skip { + tlsCredentials, err := utils.LoadGRPCTLSCredentials(config.CertPath) + if err != nil { + return nil, fmt.Errorf("failed to load TLS credentials: %v", err) + } + dialOptions = append(dialOptions, grpc.WithTransportCredentials(tlsCredentials)) + } else { + dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))) + } + + conn, err = grpc.NewClient(serverAddress, dialOptions...) + if err != nil { + connectionAttemps++ + utils.Logger.ErrorF("error connecting to Server, trying again in %.0f seconds", reconnectDelay.Seconds()) + time.Sleep(reconnectDelay) + reconnectDelay = utils.IncrementReconnectDelay(reconnectDelay, maxReconnectDelay) + continue + } + + break + } + + return conn, nil +} diff --git a/agent/agent/go.mod b/agent/go.mod similarity index 100% rename from agent/agent/go.mod rename to agent/go.mod diff --git a/agent/agent/go.sum b/agent/go.sum similarity index 100% rename from agent/agent/go.sum rename to agent/go.sum diff --git a/agent/installer/README.md b/agent/installer/README.md deleted file mode 100644 index eeb85263a..000000000 --- a/agent/installer/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# UTMStack Agent Installer -The UTMStack Agent Installer is a Go application that is part of the UTMStack. It is responsible for various tasks including checking versions, managing configurations, handling dependencies, managing services, and providing utility functions. -This installer is designed to install the services that make up the UTMStack agent. These services include UTMStackAgent, UTMStackRedline, UTMStackUpdater, UTMStackWindowsLogsCollector, and UTMStackModulesLogsCollector. - -### Logging -The UTMStack Agent Installer uses a custom logger, referred to as the "beauty logger". This logger is used to print messages to the console in a more readable and aesthetically pleasing format. It also writes error messages and fatal errors to a log file located at path/logs/utmstack_agent_installer.log. - -### Error Handling -If the UTMStack Agent Installer encounters an error during execution, it will log the error and then terminate the program. For example, if it fails to get the current path, or if the required ports (9000 and 50051) are not open, it will log an error message and then call log.Fatalf to terminate the program. - -### Dependencies -The UTMStack Agent Installer has several dependencies that are managed through the depend package. These dependencies are service binaries that the agent needs to function properly. - -### Version Checking -The UTMStack Agent Installer uses the checkversion package to check if the current version of the agent is up to date. If it is not, the agent will update itself to the latest version. diff --git a/agent/installer/agent/oldversion.go b/agent/installer/agent/oldversion.go deleted file mode 100644 index 8019c1641..000000000 --- a/agent/installer/agent/oldversion.go +++ /dev/null @@ -1,141 +0,0 @@ -package agent - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -func CleanOldAgent(h *logger.Logger) { - servName := "utmstack" - if isOldInstalled, err := utils.CheckIfServiceIsInstalled(servName); err != nil { - fmt.Printf("error checking utmstack service: %v", err) - h.ErrorF("error checking utmstack service: %v", err) - } else if isOldInstalled { - fmt.Println("Uninstalling UTMStack Agent old version...") - h.Info("Uninstalling UTMStack Agent old version...") - - // Stopping and uninstalling UTMStack Agent old version - err := utils.StopService(servName) - if err != nil { - h.ErrorF("error stopping %s: %v", servName, err) - } - - err = utils.UninstallService(servName) - if err != nil { - h.ErrorF("error uninstalling %s: %v", servName, err) - } - - err = stopWazuh() - if err != nil { - h.ErrorF("error stopping wazuh: %v", err) - } - - // Stopping and uninstalling beats - switch runtime.GOOS { - case "windows": - err := stopWinlogbeat() - if err != nil { - h.ErrorF("%v", err) - } - pathOld := "C:\\Program Files\\UTMStack\\UTMStackAgent" - err = os.RemoveAll(pathOld) - if err != nil { - h.ErrorF("error deleting old agent folder: %v", err) - } - - case "linux": - err := uninstallFilebeat() - if err != nil { - h.ErrorF("%v", err) - } - pathOld := "/opt/linux-agent" - err = os.RemoveAll(pathOld) - if err != nil { - h.ErrorF("error deleting old agent folder: %v", err) - } - } - } -} - -func stopWazuh() error { - servName := "WazuhSvc" - if isInstalled, err := utils.CheckIfServiceIsInstalled(servName); err != nil { - return fmt.Errorf("error checking UTMStackAgent service: %v", err) - } else if isInstalled { - err := utils.StopService(servName) - if err != nil { - return fmt.Errorf("error stopping %s: %v", servName, err) - } - err = utils.UninstallService(servName) - if err != nil { - return fmt.Errorf("error uninstalling %s: %v", servName, err) - } - } - - return nil -} - -func stopWinlogbeat() error { - isRunning, err := utils.IsProcessRunning("winlogbeat") - if err != nil { - return fmt.Errorf("error checking if winlogbeat is running: %v", err) - } else if isRunning { - err = utils.StopProcess("winlogbeat") - if err != nil { - return fmt.Errorf("error stopping winlogbeat: %v", err) - } - } - - return nil -} - -func uninstallFilebeat() error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("error getting current path: %v", err) - } - - err = utils.Execute("systemctl", path, "stop", "filebeat") - if err != nil { - return fmt.Errorf("%s", err) - } - - family, err := utils.DetectLinuxFamily() - if err != nil { - return err - } - - switch family { - case "debian": - err = utils.Execute("apt-get", path, "remove", "--purge", "-y", "filebeat") - if err != nil { - return fmt.Errorf("%s", err) - } - case "rhel": - err = utils.Execute("systemctl", filepath.Join(path, "beats", "filebeat"), "stop", "filebeat") - if err != nil { - return fmt.Errorf("%s", err) - } - err = utils.Execute("systemctl", filepath.Join(path, "beats", "filebeat"), "disable", "filebeat") - if err != nil { - return fmt.Errorf("%s", err) - } - err = utils.Execute("echo", filepath.Join(path, "beats", "filebeat"), "y", "|", "yum", "remove", "filebeat") - if err != nil { - return fmt.Errorf("%s", err) - } - - } - - err = utils.Execute("rm", path, "-rf", "/etc/filebeat") - if err != nil { - return fmt.Errorf("%s", err) - } - - return nil -} diff --git a/agent/installer/checkversion/check_version.go b/agent/installer/checkversion/check_version.go deleted file mode 100644 index 305b72c29..000000000 --- a/agent/installer/checkversion/check_version.go +++ /dev/null @@ -1,46 +0,0 @@ -package checkversion - -import ( - "fmt" - "path/filepath" - "runtime" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/runner/agent" - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -func CleanOldVersions(h *logger.Logger) error { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - // Clean UTMStackAgent v9 version - agent.CleanOldAgent(h) - - var exeName string - switch runtime.GOOS { - case "windows": - exeName = filepath.Join(path, "utmstackagent-windows.exe") - case "linux": - exeName = filepath.Join(path, "utmstackagent-linux") - } - - // Check if UTMStackAgent is installed - if isInstalled, err := utils.CheckIfServiceIsInstalled("UTMStackAgent"); err != nil { - return fmt.Errorf("error checking UTMStackAgent service: %v", err) - } else if isInstalled { - if utils.CheckIfPathExist(filepath.Join(path, "version.json")) { - result, errB := utils.ExecuteWithResult(exeName, path, "uninstall") - if errB { - return fmt.Errorf("%s", result) - } - } else { - return fmt.Errorf("UTMStackAgent is already installed") - } - } - - return nil -} diff --git a/agent/installer/configuration/const.go b/agent/installer/configuration/const.go deleted file mode 100644 index eae21173e..000000000 --- a/agent/installer/configuration/const.go +++ /dev/null @@ -1,36 +0,0 @@ -package configuration - -import ( - "path/filepath" - - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -type ServicesBin struct { - AgentServiceBin string - RedlineServiceBin string - UpdaterServiceBin string -} - -const ( - MASTERVERSIONENDPOINT = "/management/info" - INSTALLER_LOG_FILE = "utmstack_agent_installer.log" - Bucket = "https://cdn.utmstack.com/agent_updates/" - AgentManagerPort = "9000" - LogAuthProxyPort = "50051" -) - -func GetCertPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "utm.crt") -} - -func GetKeyPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "utm.key") -} - -func GetCaPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "ca.crt") -} diff --git a/agent/installer/configuration/env.go b/agent/installer/configuration/env.go deleted file mode 100644 index 54a08c444..000000000 --- a/agent/installer/configuration/env.go +++ /dev/null @@ -1,32 +0,0 @@ -package configuration - -import ( - "os" - "path/filepath" - - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -type Environment struct { - Branch string `yaml:"branch"` -} - -func ReadEnv() (*Environment, error) { - var env Environment - path, err := utils.GetMyPath() - if err != nil { - return nil, err - } - - path = filepath.Join(path, "env.yml") - - if _, err = os.Stat(path); os.IsNotExist(err) { - return &Environment{Branch: "release"}, nil - } else { - err = utils.ReadYAML(path, &env) - if err != nil { - return nil, err - } - } - return &env, nil -} diff --git a/agent/installer/depend/checkVersions.go b/agent/installer/depend/checkVersions.go deleted file mode 100644 index 6036e970e..000000000 --- a/agent/installer/depend/checkVersions.go +++ /dev/null @@ -1,78 +0,0 @@ -package depend - -import ( - "crypto/tls" - "fmt" - "net/http" - "path/filepath" - "strings" - - "github.com/utmstack/UTMStack/agent/runner/configuration" - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -func getMasterVersion(ip string, skip bool) (string, error) { - config := &tls.Config{InsecureSkipVerify: skip} - if !skip { - var err error - config, err = utils.LoadTLSCredentials(configuration.GetCertPath()) - if err != nil { - return "", fmt.Errorf("error loading tls credentials: %v", err) - } - } - resp, status, err := utils.DoReq[InfoResponse]("https://"+ip+configuration.MASTERVERSIONENDPOINT, nil, http.MethodGet, map[string]string{}, config) - if err != nil { - return "", err - } else if status != http.StatusOK { - return "", fmt.Errorf("status code %d: %v", status, resp) - } - return resp.Build.Version, nil -} - -func getCurrentVersion(ip string, env string, skip string) (Version, error) { - currentVersion := Version{} - - // Get master version - skipB := skip == "yes" - mastVers, err := getMasterVersion(ip, skipB) - if err != nil { - return currentVersion, fmt.Errorf("error getting master version: %v", err) - } - - path, err := utils.GetMyPath() - if err != nil { - return currentVersion, fmt.Errorf("failed to get current path: %v", err) - } - - err = utils.DownloadFile(configuration.Bucket+env+"/versions.json?time="+utils.GetCurrentTime(), filepath.Join(path, "versions.json")) - if err != nil { - return currentVersion, fmt.Errorf("error downloading versions.json: %v", err) - } - - // Save data from versions.json - var dataVersions DataVersions - err = utils.ReadJson(filepath.Join(path, "versions.json"), &dataVersions) - if err != nil { - return currentVersion, fmt.Errorf("error reading versions.json: %v", err) - } - - versionExist := false - for _, vers := range dataVersions.Versions { - versParts := strings.Split(vers.MasterVersion, ".") - masterParts := strings.Split(mastVers, ".") - - if versParts[0] == masterParts[0] && versParts[1] == masterParts[1] { - versionExist = true - currentVersion = vers - } - } - - if versionExist { - err = utils.WriteJSON(filepath.Join(path, "versions.json"), ¤tVersion) - if err != nil { - return currentVersion, fmt.Errorf("error writing versions.json: %v", err) - } - return currentVersion, nil - } - return currentVersion, fmt.Errorf("error: master version not exist in versions.json") -} diff --git a/agent/installer/depend/dependencies.go b/agent/installer/depend/dependencies.go deleted file mode 100644 index fe6900aaa..000000000 --- a/agent/installer/depend/dependencies.go +++ /dev/null @@ -1,82 +0,0 @@ -package depend - -import ( - "fmt" - "log" - "os" - "path/filepath" - "runtime" - - "github.com/utmstack/UTMStack/agent/runner/configuration" - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -func DownloadDependencies(servBins ServicesBin, ip string, skip string) error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - // Select environment - env, err := configuration.ReadEnv() - if err != nil { - return fmt.Errorf("error reading environment configuration: %v", err) - } - - currentVersion, err := getCurrentVersion(ip, env.Branch, skip) - if err != nil { - return fmt.Errorf("error getting current version: %v", err) - } - - urlFiles := map[string]string{ - "dependencies.zip": configuration.Bucket + env.Branch + "/agent_service/v" + currentVersion.AgentVersion + "/" + runtime.GOOS + "_dependencies.zip?time=" + utils.GetCurrentTime(), - servBins.AgentServiceBin: configuration.Bucket + env.Branch + "/agent_service/v" + currentVersion.AgentVersion + "/" + servBins.AgentServiceBin + "?time=" + utils.GetCurrentTime(), - servBins.UpdaterServiceBin: configuration.Bucket + env.Branch + "/updater_service/v" + currentVersion.UpdaterVersion + "/" + servBins.UpdaterServiceBin + "?time=" + utils.GetCurrentTime(), - servBins.RedlineServiceBin: configuration.Bucket + env.Branch + "/redline_service/v" + currentVersion.RedlineVersion + "/" + servBins.RedlineServiceBin + "?time=" + utils.GetCurrentTime(), - } - - for filename, url := range urlFiles { - err = utils.DownloadFile(url, filepath.Join(path, filename)) - if err != nil { - return fmt.Errorf("error downloading dependencies and binaries: %v", err) - } - if runtime.GOOS == "linux" { - if err = utils.Execute("chmod", path, "-R", "777", filename); err != nil { - return fmt.Errorf("error executing chmod: %v", err) - } - } - } - - err = utils.Unzip(filepath.Join(path, "dependencies.zip"), filepath.Join(path)) - if err != nil { - return fmt.Errorf("error unzipping dependencies.zip: %v", err) - } - - if runtime.GOOS == "linux" { - if err = utils.Execute("chmod", path, "-R", "777", "utmstack_updater_self"); err != nil { - return fmt.Errorf("error executing chmod: %v", err) - } - } - - err = os.Remove(filepath.Join(path, "dependencies.zip")) - if err != nil { - log.Printf("error deleting dependencies.zip file: %v\n", err) - } - - return nil -} - -func GetServicesBins() ServicesBin { - servBins := ServicesBin{} - switch runtime.GOOS { - case "windows": - servBins.AgentServiceBin = "utmstack_agent_service.exe" - servBins.UpdaterServiceBin = "utmstack_updater_service.exe" - servBins.RedlineServiceBin = "utmstack_redline_service.exe" - case "linux": - servBins.AgentServiceBin = "utmstack_agent_service" - servBins.UpdaterServiceBin = "utmstack_updater_service" - servBins.RedlineServiceBin = "utmstack_redline_service" - } - return servBins -} diff --git a/agent/installer/depend/schema.go b/agent/installer/depend/schema.go deleted file mode 100644 index 70b2e5605..000000000 --- a/agent/installer/depend/schema.go +++ /dev/null @@ -1,35 +0,0 @@ -package depend - -import "encoding/json" - -type InfoResponse struct { - Display string `json:"display-ribbon-on-profiles"` - Git json.RawMessage `json:"git"` - Build Build `json:"build"` - Profiles []string `json:"activeProfiles"` -} - -type Build struct { - Artifact string `json:"artifact"` - Name string `json:"name"` - Time string `json:"time"` - Version string `json:"version"` - Group string `json:"group"` -} - -type DataVersions struct { - Versions []Version `json:"versions"` -} - -type Version struct { - MasterVersion string `json:"master_version"` - AgentVersion string `json:"agent_version"` - UpdaterVersion string `json:"updater_version"` - RedlineVersion string `json:"redline_version"` -} - -type ServicesBin struct { - AgentServiceBin string - RedlineServiceBin string - UpdaterServiceBin string -} diff --git a/agent/installer/go.mod b/agent/installer/go.mod deleted file mode 100644 index d1409fc66..000000000 --- a/agent/installer/go.mod +++ /dev/null @@ -1,43 +0,0 @@ -module github.com/utmstack/UTMStack/agent/runner - -go 1.22.4 - -toolchain go1.23.4 - -require ( - github.com/logrusorgru/aurora v2.0.3+incompatible - github.com/threatwinds/logger v1.1.12 - gopkg.in/yaml.v2 v2.4.0 -) - -require ( - github.com/bytedance/sonic v1.12.1 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.0 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/agent/installer/go.sum b/agent/installer/go.sum deleted file mode 100644 index bd1e6438a..000000000 --- a/agent/installer/go.sum +++ /dev/null @@ -1,98 +0,0 @@ -github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= -github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= -github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= -github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= -github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= -github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= -github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= -github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -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= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= -golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/agent/installer/main.go b/agent/installer/main.go deleted file mode 100644 index 65dbe9869..000000000 --- a/agent/installer/main.go +++ /dev/null @@ -1,120 +0,0 @@ -package main - -import ( - "log" - "os" - "path/filepath" - "strings" - "time" - - "github.com/utmstack/UTMStack/agent/runner/checkversion" - "github.com/utmstack/UTMStack/agent/runner/configuration" - "github.com/utmstack/UTMStack/agent/runner/depend" - "github.com/utmstack/UTMStack/agent/runner/services" - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -func main() { - beautyLogger := utils.GetBeautyLogger() - beautyLogger.PrintBanner() - - path, err := utils.GetMyPath() - if err != nil { - beautyLogger.WriteError("failed to get current path", err) - log.Fatalf("Failed to get current path: %v", err) - } - - servBins := depend.GetServicesBins() - - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.INSTALLER_LOG_FILE)) - - if len(os.Args) > 1 { - mode := os.Args[1] - switch mode { - case "install": - ip, utmKey, skip := os.Args[2], os.Args[3], os.Args[4] - - if strings.Count(utmKey, "*") == len(utmKey) { - beautyLogger.WriteError("The connection key provided is incorrect. Please make sure you use the 'copy' icon from the integrations section to get the value of the masked key value.", nil) - h.Fatal("The connection key provided is incorrect. Please make sure you use the 'copy' icon from the integrations section to get the value of the masked key value.") - } - - beautyLogger.WriteSimpleMessage("Installing UTMStack Agent...") - if !utils.IsPortOpen(ip, configuration.AgentManagerPort) || !utils.IsPortOpen(ip, configuration.LogAuthProxyPort) { - beautyLogger.WriteError("one or more of the requiered ports are closed. Please open ports 9000 and 50051.", nil) - h.Fatal("Error installing the UTMStack Agent: one or more of the requiered ports are closed. Please open ports 9000 and 50051.") - } - - err := utils.CreatePathIfNotExist(filepath.Join(path, "locks")) - if err != nil { - beautyLogger.WriteError("error creating locks path", err) - h.Fatal("error creating locks path: %v", err) - } - - err = utils.SetLock(filepath.Join(path, "locks", "setup.lock")) - if err != nil { - beautyLogger.WriteError("error setting setup.lock", err) - h.Fatal("error setting setup.lock: %v", err) - } - - err = checkversion.CleanOldVersions(h) - if err != nil { - beautyLogger.WriteError("error cleaning old versions", err) - h.Fatal("error cleaning old versions: %v", err) - } - - beautyLogger.WriteSimpleMessage("Downloading UTMStack dependencies...") - err = depend.DownloadDependencies(servBins, ip, skip) - if err != nil { - beautyLogger.WriteError("error downloading dependencies", err) - h.Fatal("error downloading dependencies: %v", err) - } - beautyLogger.WriteSuccessfull("UTMStack dependencies downloaded correctly.") - - beautyLogger.WriteSimpleMessage("Installing services...") - err = services.ConfigureServices(servBins, ip, utmKey, skip, "install") - if err != nil { - beautyLogger.WriteError("error installing UTMStack services", err) - h.Fatal("error installing UTMStack services: %v", err) - } - - err = utils.RemoveLock(filepath.Join(path, "locks", "setup.lock")) - if err != nil { - beautyLogger.WriteError("error removing setup.lock", err) - h.Fatal("error removing setup.lock: %v", err) - } - - beautyLogger.WriteSuccessfull("Services installed correctly") - beautyLogger.WriteSuccessfull("UTMStack Agent installed correctly.") - - time.Sleep(5 * time.Second) - os.Exit(0) - - case "uninstall": - beautyLogger.WriteSimpleMessage("Uninstalling UTMStack Agent...") - - if isInstalled, err := utils.CheckIfServiceIsInstalled("UTMStackAgent"); err != nil { - beautyLogger.WriteError("error checking UTMStackAgent service", err) - h.Fatal("error checking UTMStackAgent service: %v", err) - } else if isInstalled { - beautyLogger.WriteSimpleMessage("Uninstalling UTMStack services...") - err = services.ConfigureServices(servBins, "", "", "", "uninstall") - if err != nil { - beautyLogger.WriteError("error uninstalling UTMStack services", err) - h.Fatal("error uninstalling UTMStack services: %v", err) - } - - beautyLogger.WriteSuccessfull("UTMStack services uninstalled correctly.") - time.Sleep(5 * time.Second) - os.Exit(0) - - } else { - beautyLogger.WriteError("UTMStackAgent not installed", nil) - h.Fatal("UTMStackAgent not installed") - } - - default: - beautyLogger.WriteError("unknown option", nil) - } - } -} diff --git a/agent/installer/services/configure.go b/agent/installer/services/configure.go deleted file mode 100644 index ad5a3cf60..000000000 --- a/agent/installer/services/configure.go +++ /dev/null @@ -1,48 +0,0 @@ -package services - -import ( - "fmt" - "strings" - - "github.com/utmstack/UTMStack/agent/runner/depend" - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -func ConfigureServices(bins depend.ServicesBin, ip, utmKey, skip, config string) error { - err := execBin(bins.AgentServiceBin, config, ip, utmKey, skip) - if err != nil { - if strings.Contains(err.Error(), "exit status 1") { - return fmt.Errorf("error %sing UTMStackAgent service: Check the file /logs/utmstack_agent.log for more details", config) - } - return fmt.Errorf("error %sing UTMStackAgent service: %v", config, err) - } - - if config == "install" { - err = execBin(bins.RedlineServiceBin, config) - if err != nil { - if strings.Contains(err.Error(), "exit status 1") { - return fmt.Errorf("error %sing UTMStackRedline service: Check the file /logs/utmstack_redline.log for more details", config) - } - return fmt.Errorf("error %sing UTMStackRedline service: %v", config, err) - } - - err = execBin(bins.UpdaterServiceBin, config) - if err != nil { - if strings.Contains(err.Error(), "exit status 1") { - return fmt.Errorf("error %sing UTMStackUpdater service: Check the file /logs/utmstack_updater.log for more details", config) - } - return fmt.Errorf("error %sing UTMStackUpdater service: %v", config, err) - } - } else if config == "uninstall" { - err = utils.UninstallService("UTMStackRedline") - if err != nil { - return fmt.Errorf("error %sing UTMStackRedline service: %v", config, err) - } - err = utils.UninstallService("UTMStackUpdater") - if err != nil { - return fmt.Errorf("error %sing UTMStackUpdater service: %v", config, err) - } - } - - return err -} diff --git a/agent/installer/services/execBin.go b/agent/installer/services/execBin.go deleted file mode 100644 index d59b264ec..000000000 --- a/agent/installer/services/execBin.go +++ /dev/null @@ -1,31 +0,0 @@ -package services - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - - "github.com/utmstack/UTMStack/agent/runner/utils" -) - -func execBin(binName string, arg ...string) error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - if runtime.GOOS == "linux" { - err = os.Chmod(filepath.Join(path, binName), 0755) - if err != nil { - return err - } - } - - result, errB := utils.ExecuteWithResult(filepath.Join(path, binName), path, arg...) - if errB { - return fmt.Errorf("%s", result) - } - - return nil -} diff --git a/agent/installer/utils/beauty.go b/agent/installer/utils/beauty.go deleted file mode 100644 index 46757c4dc..000000000 --- a/agent/installer/utils/beauty.go +++ /dev/null @@ -1,54 +0,0 @@ -package utils - -import ( - "fmt" - "sync" - - "github.com/logrusorgru/aurora" -) - -var ( - beautyLogger *BeautyLogger - beautyLoggerOnce sync.Once -) - -type BeautyLogger struct { -} - -func GetBeautyLogger() *BeautyLogger { - beautyLoggerOnce.Do(func() { - beautyLogger = &BeautyLogger{} - }) - return beautyLogger -} - -func (b *BeautyLogger) WriteError(msg string, err error) { - if err == nil { - fmt.Printf("%s: %s: %s\n", "UTMStack", aurora.Red("error").String(), msg) - } else { - fmt.Printf("%s: %s: %s: %v\n", "UTMStack", aurora.Red("error").String(), msg, err) - } -} - -func (b *BeautyLogger) WriteSuccessfull(msg string) { - fmt.Printf("%s: %s: %s\n", "UTMStack", aurora.Green("success").String(), msg) -} - -func (b *BeautyLogger) WriteSimpleMessage(msg string) { - fmt.Println(msg) -} - -func (b *BeautyLogger) PrintBanner() { - banner := "\n" + - "..........................................................................\n" + - " _ _ _ _____ _ _ \n" + - " | | | | | | / ____| | | | | \n" + - " | | | | | |_ _ __ ___ | (___ | |_ __ _ ___ | | __ \n" + - " | | | | | __| | '_ ` _ \\ \\___ \\ | __| / _` | / __| | |/ / \n" + - " | |__| | | |_ | | | | | | ____) | | |_ | (_| | | (__ | < \n" + - " \\____/ \\__| |_| |_| |_| |_____/ \\__| \\__,_| \\___| |_|\\_\\ \n" + - "..........................................................................\n" + - "\n" - - fmt.Println(banner) -} diff --git a/agent/installer/utils/cmd.go b/agent/installer/utils/cmd.go deleted file mode 100644 index b1881855f..000000000 --- a/agent/installer/utils/cmd.go +++ /dev/null @@ -1,47 +0,0 @@ -package utils - -import ( - "errors" - "os/exec" - "unicode/utf8" -) - -func CleanString(s string) string { - v := make([]rune, 0, len(s)) - for i, r := range s { - if r == utf8.RuneError { - _, size := utf8.DecodeRuneInString(s[i:]) - if size == 1 { - v = append(v, '?') - continue - } - } - v = append(v, r) - } - return string(v) -} - -func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { - cmd := exec.Command(c, arg...) - - cmd.Dir = dir - if errors.Is(cmd.Err, exec.ErrDot) { - cmd.Err = nil - } - - out, err := cmd.Output() - if err != nil { - return string(out[:]) + err.Error(), true - } - - validUtf8Out := CleanString(string(out[:])) - - return validUtf8Out, false -} - -func Execute(c string, dir string, arg ...string) error { - cmd := exec.Command(c, arg...) - cmd.Dir = dir - - return cmd.Run() -} diff --git a/agent/installer/utils/delay.go b/agent/installer/utils/delay.go deleted file mode 100644 index e3000ea71..000000000 --- a/agent/installer/utils/delay.go +++ /dev/null @@ -1,11 +0,0 @@ -package utils - -import "time" - -func IncrementReconnectDelay(delay time.Duration, maxReconnectDelay time.Duration) time.Duration { - delay *= 2 - if delay > maxReconnectDelay { - delay = maxReconnectDelay - } - return delay -} diff --git a/agent/installer/utils/download.go b/agent/installer/utils/download.go deleted file mode 100644 index a0d578eb0..000000000 --- a/agent/installer/utils/download.go +++ /dev/null @@ -1,51 +0,0 @@ -package utils - -import ( - "fmt" - "io" - "net/http" - "os" - "time" -) - -const ( - maxConnectionAttempts = 3 - initialReconnectDelay = 10 * time.Second - maxReconnectDelay = 60 * time.Second -) - -// DownloadFile downloads a file from a URL and saves it to disk. Returns an error on failure. -func DownloadFile(url string, fileName string) error { - connectionAttemps := 0 - reconnectDelay := initialReconnectDelay - - var resp *http.Response - var err error - - for { - if connectionAttemps >= maxConnectionAttempts { - return fmt.Errorf("error downloading file after %d attemps: %v", maxConnectionAttempts, err) - } - resp, err = http.Get(url) - if err != nil || resp.StatusCode != http.StatusOK { - if resp != nil { - resp.Body.Close() - } - connectionAttemps++ - time.Sleep(reconnectDelay) - reconnectDelay = IncrementReconnectDelay(reconnectDelay, maxReconnectDelay) - continue - } - break - } - defer resp.Body.Close() - - out, err := os.Create(fileName) - if err != nil { - return err - } - defer out.Close() - - _, err = io.Copy(out, resp.Body) - return err -} diff --git a/agent/installer/utils/files.go b/agent/installer/utils/files.go deleted file mode 100644 index 70597446f..000000000 --- a/agent/installer/utils/files.go +++ /dev/null @@ -1,96 +0,0 @@ -package utils - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "gopkg.in/yaml.v2" -) - -// GetMyPath returns the directory path where the currently running executable is located. -// Returns a string representing the directory path, and an error if any error occurs during the process. -func GetMyPath() (string, error) { - ex, err := os.Executable() - if err != nil { - return "", err - } - exPath := filepath.Dir(ex) - return exPath, nil -} - -// ReadJson reads the json data from the specified file URL and unmarshal it into the provided result interface{}. -// Returns an error if any error occurs during the process. -func ReadJson(fileName string, data interface{}) error { - content, err := os.ReadFile(fileName) - if err != nil { - return err - } - err = json.Unmarshal(content, data) - if err != nil { - return err - } - return nil -} - -// ReadYAML reads the YAML data from the specified file URL and deserializes it into the provided result interface{}. -// Returns an error if any error occurs during the process. -func ReadYAML(path string, result interface{}) error { - file, err := os.Open(path) - if err != nil { - return err - } - defer file.Close() - d := yaml.NewDecoder(file) - if err := d.Decode(result); err != nil { - return err - } - return nil -} - -func CheckIfPathExist(path string) bool { - if _, err := os.Stat(path); os.IsNotExist(err) { - return false - } - return true -} - -func writeToFile(fileName string, body string) error { - file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) - - if err != nil { - return err - } - - defer file.Close() - - _, err = file.WriteString(body) - return err -} - -func WriteJSON(path string, data interface{}) error { - jsonData, err := json.MarshalIndent(data, "", " ") - if err != nil { - return err - } - - err = writeToFile(path, string(jsonData[:])) - if err != nil { - return err - } - - return nil -} - -// CreatePathIfNotExist creates a specific path if not exist -func CreatePathIfNotExist(path string) error { - if _, err := os.Stat(path); os.IsNotExist(err) { - if err := os.Mkdir(path, 0755); err != nil { - return fmt.Errorf("error creating path: %v", err) - } - } else if err != nil { - return fmt.Errorf("error checking path: %v", err) - } - return nil -} diff --git a/agent/installer/utils/lock.go b/agent/installer/utils/lock.go deleted file mode 100644 index 1f7e8ce54..000000000 --- a/agent/installer/utils/lock.go +++ /dev/null @@ -1,29 +0,0 @@ -package utils - -import ( - "fmt" - "os" -) - -func SetLock(lockdir string) error { - if !CheckIfPathExist(lockdir) { - file, err := os.OpenFile(lockdir, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) - if err != nil { - return err - } - defer file.Close() - } - return nil -} - -func RemoveLock(lockdir string) error { - if CheckIfPathExist(lockdir) { - err := os.Remove(lockdir) - if err != nil { - return err - } - } else { - return fmt.Errorf("lock file %s not exists", lockdir) - } - return nil -} diff --git a/agent/installer/utils/logger.go b/agent/installer/utils/logger.go deleted file mode 100644 index e91de3c1f..000000000 --- a/agent/installer/utils/logger.go +++ /dev/null @@ -1,22 +0,0 @@ -package utils - -import ( - "sync" - - "github.com/threatwinds/logger" -) - -var ( - installerLogger *logger.Logger - loggerOnceInstance sync.Once -) - -// CreateLogger returns a single instance of a Logger configured to save logs to a rotating file. -func CreateLogger(filename string) *logger.Logger { - loggerOnceInstance.Do(func() { - installerLogger = logger.NewLogger( - &logger.Config{Format: "text", Level: 100, Output: filename, Retries: 3, Wait: 5}, - ) - }) - return installerLogger -} diff --git a/agent/installer/utils/os.go b/agent/installer/utils/os.go deleted file mode 100644 index 3fd7dff40..000000000 --- a/agent/installer/utils/os.go +++ /dev/null @@ -1,30 +0,0 @@ -package utils - -import ( - "fmt" - "os/exec" - "strings" -) - -func DetectLinuxFamily() (string, error) { - var pmCommands map[string]string = map[string]string{ - "debian": "apt list", - "rhel": "yum list", - } - - for dist, command := range pmCommands { - cmd := strings.Split(command, " ") - var err error - - if len(cmd) > 1 { - _, err = exec.Command(cmd[0], cmd[1:]...).Output() - } else { - _, err = exec.Command(cmd[0]).Output() - } - - if err == nil { - return dist, nil - } - } - return "", fmt.Errorf("unknown distribution") -} diff --git a/agent/installer/utils/ports.go b/agent/installer/utils/ports.go deleted file mode 100644 index 9f17c01b4..000000000 --- a/agent/installer/utils/ports.go +++ /dev/null @@ -1,19 +0,0 @@ -package utils - -import ( - "fmt" - "net" - "time" -) - -func IsPortOpen(ip, port string) bool { - for i := 0; i < 3; i++ { - conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", ip, port), 5*time.Second) - if err == nil { - defer conn.Close() - return true - } - time.Sleep(5 * time.Second) - } - return false -} diff --git a/agent/installer/utils/process.go b/agent/installer/utils/process.go deleted file mode 100644 index 124a3adf1..000000000 --- a/agent/installer/utils/process.go +++ /dev/null @@ -1,55 +0,0 @@ -package utils - -import ( - "os/exec" - "runtime" - "strings" -) - -// IsProcessRunning checks if a process is active -func IsProcessRunning(processName string) (bool, error) { - var cmd *exec.Cmd - if runtime.GOOS == "windows" { - cmd = exec.Command("tasklist") - } else { - cmd = exec.Command("ps", "aux") - } - - output, err := cmd.Output() - if err != nil { - return false, err - } - - processes := strings.Split(string(output), "\n") - for _, process := range processes { - if strings.Contains(process, processName) { - return true, nil - } - } - - return false, nil -} - -// StopProcess checks if a process is active, if so it stops it -func StopProcess(processName string) error { - running, err := IsProcessRunning(processName) - if err != nil { - return err - } - - if running { - var cmd *exec.Cmd - if runtime.GOOS == "windows" { - cmd = exec.Command("taskkill", "/IM", processName, "/F") - } else { - cmd = exec.Command("pkill", processName) - } - - err := cmd.Run() - if err != nil { - return err - } - } - - return nil -} diff --git a/agent/installer/utils/req.go b/agent/installer/utils/req.go deleted file mode 100644 index 7b3a88ca6..000000000 --- a/agent/installer/utils/req.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import ( - "bytes" - "crypto/tls" - "encoding/json" - "io" - "net/http" -) - -func DoReq[response any](url string, data []byte, method string, headers map[string]string, config *tls.Config) (response, int, error) { - req, err := http.NewRequest(method, url, bytes.NewBuffer(data)) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - - for k, v := range headers { - req.Header.Add(k, v) - } - - transp := &http.Transport{ - TLSClientConfig: config, - } - - client := &http.Client{Transport: transp} - - resp, err := client.Do(req) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - - var result response - - err = json.Unmarshal(body, &result) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - - if resp.StatusCode != http.StatusAccepted && resp.StatusCode != http.StatusOK { - return *new(response), http.StatusInternalServerError, err - } - - return result, resp.StatusCode, nil -} diff --git a/agent/installer/utils/timestamp.go b/agent/installer/utils/timestamp.go deleted file mode 100644 index e33aa0f2a..000000000 --- a/agent/installer/utils/timestamp.go +++ /dev/null @@ -1,8 +0,0 @@ -package utils - -import "time" - -func GetCurrentTime() string { - t := time.Now() - return t.Format("20060102150405") -} diff --git a/agent/installer/utils/tls.go b/agent/installer/utils/tls.go deleted file mode 100644 index 77fc7470e..000000000 --- a/agent/installer/utils/tls.go +++ /dev/null @@ -1,27 +0,0 @@ -package utils - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "os" -) - -func LoadTLSCredentials(crtName string) (*tls.Config, error) { - // Load the server's certificate - serverCert, err := os.ReadFile(crtName) - if err != nil { - return nil, err - } - - certPool := x509.NewCertPool() - if !certPool.AppendCertsFromPEM(serverCert) { - return nil, fmt.Errorf("failed to add server certificate to the certificate pool") - } - - config := &tls.Config{ - RootCAs: certPool, - } - - return config, nil -} diff --git a/agent/agent/logservice/log.pb.go b/agent/logservice/log.pb.go similarity index 100% rename from agent/agent/logservice/log.pb.go rename to agent/logservice/log.pb.go diff --git a/agent/agent/logservice/log_grpc.pb.go b/agent/logservice/log_grpc.pb.go similarity index 100% rename from agent/agent/logservice/log_grpc.pb.go rename to agent/logservice/log_grpc.pb.go diff --git a/agent/logservice/processor.go b/agent/logservice/processor.go new file mode 100644 index 000000000..50475168b --- /dev/null +++ b/agent/logservice/processor.go @@ -0,0 +1,190 @@ +package logservice + +import ( + "bufio" + context "context" + "fmt" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/utmstack/UTMStack/agent/agent/agent" + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/conn" + "github.com/utmstack/UTMStack/agent/agent/utils" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +type LogProcessor struct { + connErrWritten bool + sendErrWritten bool +} + +type LogPipe struct { + Src string + Logs []string +} + +var ( + processor LogProcessor + processorOnce sync.Once + LogQueue = make(chan LogPipe, 1000) + MinutesForCleanLog = 10080 + MinutesForReportLogsCounted = time.Duration(5 * time.Minute) + timeToSleep = 10 * time.Second + logsProcessCounter = map[string]int{} +) + +func GetLogProcessor() LogProcessor { + processorOnce.Do(func() { + processor = LogProcessor{ + connErrWritten: false, + sendErrWritten: false, + } + }) + return processor +} + +func (l *LogProcessor) ProcessLogs(cnf *config.Config, ctx context.Context) { + go func() { + for { + time.Sleep(MinutesForReportLogsCounted) + SaveCountedLogs() + logsProcessCounter = map[string]int{} + } + }() + + for { + ctxEof, cancelEof := context.WithCancel(context.Background()) + connection, err := conn.GetCorrelationConnection(cnf) + if err != nil { + if !l.connErrWritten { + utils.Logger.ErrorF("error connecting to Correlation: %v", err) + l.connErrWritten = true + } + time.Sleep(10 * time.Second) + continue + } + + client := NewLogServiceClient(connection) + l.connErrWritten = false + l.processLogs(client, ctxEof, cancelEof) + } +} + +func (l *LogProcessor) processLogs(client LogServiceClient, ctx context.Context, cancel context.CancelFunc) { + invalidKeyCounter := 0 + + for { + select { + case <-ctx.Done(): + utils.Logger.Info("LogProcessor: Context done, exiting...") + return + case newLog := <-LogQueue: + rcv, err := client.ProcessLogs(ctx, &LogMessage{Type: agent.ConnectorType_AGENT, LogType: newLog.Src, Data: newLog.Logs}) + if err != nil { + if strings.Contains(err.Error(), "EOF") { + time.Sleep(timeToSleep) + cancel() + return + } + st, ok := status.FromError(err) + if ok && (st.Code() == codes.Unavailable || st.Code() == codes.Canceled) { + if !l.sendErrWritten { + utils.Logger.ErrorF("failed to send log: %v", err) + l.sendErrWritten = true + } + time.Sleep(timeToSleep) + cancel() + return + } else { + if !l.sendErrWritten { + utils.Logger.ErrorF("failed to send log: %v ", err) + l.sendErrWritten = true + } + time.Sleep(timeToSleep) + continue + } + } else if !rcv.Received { + utils.Logger.ErrorF("Error sending logs to Log Auth Proxy: %s", rcv.Message) + if strings.Contains(rcv.Message, "invalid agent key") { + invalidKeyCounter++ + if invalidKeyCounter >= 20 { + utils.Logger.Info("Uninstalling agent: reason: agent has been removed from the panel...") + err := agent.UninstallAll() + if err != nil { + utils.Logger.ErrorF("Error uninstalling agent: %s", err) + } + } + } else { + invalidKeyCounter = 0 + } + + time.Sleep(timeToSleep) + continue + } + + l.sendErrWritten = false + logsProcessCounter[newLog.Src] += len(newLog.Logs) + invalidKeyCounter = 0 + } + + } +} + +func SaveCountedLogs() { + path := utils.GetMyPath() + filePath := filepath.Join(path, "logs_process") + logFile := filepath.Join(filePath, "processed_logs.txt") + utils.CreatePathIfNotExist(filePath) + + file, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + utils.Logger.ErrorF("error opening processed_logs.txt file: %s", err) + return + } + defer file.Close() + + var firstLogTime time.Time + var firstLine string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + firstLine = scanner.Text() + break + } + + if firstLine != "" { + firstLogTime, err = time.Parse("2006/01/02 15:04:05.9999999 -0700 MST", strings.Split(firstLine, " - ")[0]) + if err != nil { + utils.Logger.ErrorF("error parsing first log time: %s", err) + return + } + + if !firstLogTime.IsZero() && time.Since(firstLogTime).Minutes() >= float64(MinutesForCleanLog) { + file.Close() + if err := os.Remove(logFile); err != nil { + utils.Logger.ErrorF("error removing processed_logs.txt file: %s", err) + return + } + file, err = os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + utils.Logger.ErrorF("error opening processed_logs.txt file: %s", err) + return + } + } + } + + for name, counter := range logsProcessCounter { + if counter > 0 { + _, err = file.WriteString(fmt.Sprintf("%v - %d logs from %s have been processed\n", time.Now().Format("2006/01/02 15:04:05.9999999 -0700 MST"), counter, name)) + if err != nil { + utils.Logger.ErrorF("error writing to processed_logs.txt file: %s", err) + continue + } + } + } + +} diff --git a/agent/main.go b/agent/main.go new file mode 100644 index 000000000..0e707c939 --- /dev/null +++ b/agent/main.go @@ -0,0 +1,183 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "time" + + pb "github.com/utmstack/UTMStack/agent/agent/agent" + "github.com/utmstack/UTMStack/agent/agent/collectors" + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/modules" + "github.com/utmstack/UTMStack/agent/agent/serv" + "github.com/utmstack/UTMStack/agent/agent/updates" + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +func main() { + utils.InitLogger(config.ServiceLogFile) + + if len(os.Args) > 1 { + arg := os.Args[1] + + isInstalled, err := utils.CheckIfServiceIsInstalled("UTMStackAgent") + if err != nil { + fmt.Println("Error checking if service is installed: ", err) + os.Exit(1) + } + if arg != "install" && !isInstalled { + fmt.Println("UTMStackAgent service is not installed") + os.Exit(1) + } else if arg == "install" && isInstalled { + fmt.Println("UTMStackAgent service is already installed") + os.Exit(1) + } + + switch arg { + case "run": + serv.RunService() + case "install": + utils.PrintBanner() + fmt.Println("Installing UTMStackAgent service ...") + + cnf, utmKey := config.GetInitialConfig() + + fmt.Print("Checking server connection ... ") + if err := utils.ArePortsReachable(cnf.Server, config.AgentManagerPort, config.LogAuthProxyPort, config.DependenciesPort); err != nil { + fmt.Println("\nError trying to connect to server: ", err) + os.Exit(1) + } + fmt.Println("[OK]") + + fmt.Print("Creating certificates ... ") + certsPath := filepath.Join(utils.GetMyPath(), "certs") + err = utils.CreatePathIfNotExist(certsPath) + if err != nil { + fmt.Println("\nError creating certs path: ", err) + os.Exit(1) + } + err = utils.GenerateCerts(certsPath) + if err != nil { + fmt.Println("\nError generating certs: ", err) + os.Exit(1) + } + fmt.Println("[OK]") + + fmt.Print("Downloading dependencies ... ") + if err := updates.DownloadFirstDependencies(cnf.Server, utmKey, cnf.SkipCertValidation); err != nil { + fmt.Println("\nError downloading dependencies: ", err) + os.Exit(1) + } + fmt.Println("[OK]") + + fmt.Print("Configuring agent ... ") + err = pb.RegisterAgent(cnf, utmKey) + if err != nil { + fmt.Println("\nError registering agent: ", err) + os.Exit(1) + } + if err = config.SaveConfig(cnf); err != nil { + fmt.Println("\nError saving config: ", err) + os.Exit(1) + } + if err = modules.ConfigureCollectorFirstTime(); err != nil { + fmt.Println("\nError configuring collector: ", err) + os.Exit(1) + } + if err = collectors.InstallCollectors(); err != nil { + fmt.Println("\nError installing collectors: ", err) + os.Exit(1) + } + fmt.Println("[OK]") + + fmt.Print(("Creating service ... ")) + serv.InstallService() + fmt.Println("[OK]") + fmt.Println("UTMStackAgent service installed correctly") + + case "enable-integration", "disable-integration": + fmt.Println("Changing integration status ...") + integration := os.Args[2] + proto := os.Args[3] + + port, err := modules.ChangeIntegrationStatus(integration, proto, (arg == "enable-integration")) + if err != nil { + fmt.Println("Error trying to change integration status: ", err) + os.Exit(1) + } + fmt.Printf("Action %s %s %s correctly in port %s\n", arg, integration, proto, port) + time.Sleep(5 * time.Second) + + case "change-port": + fmt.Println("Changing integration port ...") + integration := os.Args[2] + proto := os.Args[3] + port := os.Args[4] + + old, err := modules.ChangePort(integration, proto, port) + if err != nil { + fmt.Println("Error trying to change integration port: ", err) + os.Exit(1) + } + fmt.Printf("Port changed correctly from %s to %s\n", old, port) + time.Sleep(5 * time.Second) + + case "uninstall": + fmt.Println("Uninstalling UTMStackAgent service ...") + + cnf, err := config.GetCurrentConfig() + if err != nil { + fmt.Println("Error getting config: ", err) + os.Exit(1) + } + + fmt.Print("Deleting agent ... ") + if err = pb.DeleteAgent(cnf); err != nil { + utils.Logger.ErrorF("error deleting agent: %v", err) + } + if err = collectors.UninstallCollectors(); err != nil { + utils.Logger.Fatal("error uninstalling collectors: %v", err) + } + os.Remove(config.ConfigurationFile) + + serv.UninstallService() + utils.Logger.Info("UTMStackAgent service uninstalled correctly") + os.Exit(1) + case "help": + Help() + default: + fmt.Println("unknown option") + } + } else { + serv.RunService() + } +} + +func Help() { + fmt.Println("### UTMStackAgent ###") + fmt.Println("Usage:") + fmt.Println(" To run the service: ./utmstack_agent run") + fmt.Println(" To install the service: ./utmstack_agent install") + fmt.Println(" To enable integration: ./utmstack_agent enable-integration ") + fmt.Println(" To disable integration: ./utmstack_agent disable-integration ") + fmt.Println(" To change integration port: ./utmstack_agent change-port ") + fmt.Println(" To uninstall the service: ./utmstack_agent uninstall") + fmt.Println(" For help (this message): ./utmstack_agent help") + fmt.Println() + fmt.Println("Options:") + fmt.Println(" run Run the UTMStackAgent service") + fmt.Println(" install Install the UTMStackAgent service") + fmt.Println(" enable-integration Enable integration for a specific and ") + fmt.Println(" disable-integration Disable integration for a specific and ") + fmt.Println(" change-port Change the port for a specific and to ") + fmt.Println(" uninstall Uninstall the UTMStackAgent service") + fmt.Println(" help Display this help message") + fmt.Println() + fmt.Println("Note:") + fmt.Println(" - Make sure to run commands with appropriate permissions.") + fmt.Println(" - All commands require administrative privileges.") + fmt.Println(" - For detailed logs, check the service log file.") + fmt.Println() + os.Exit(0) +} diff --git a/agent/models/version.go b/agent/models/version.go new file mode 100644 index 000000000..ed01f06e4 --- /dev/null +++ b/agent/models/version.go @@ -0,0 +1,5 @@ +package models + +type Version struct { + Version string `json:"version"` +} diff --git a/agent/agent/modules/configuration.go b/agent/modules/configuration.go similarity index 51% rename from agent/agent/modules/configuration.go rename to agent/modules/configuration.go index cb90ec591..f926df588 100644 --- a/agent/agent/modules/configuration.go +++ b/agent/modules/configuration.go @@ -4,8 +4,9 @@ import ( "fmt" "net" "os" + "strings" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" "github.com/utmstack/UTMStack/agent/agent/utils" ) @@ -23,34 +24,20 @@ type CollectorConfiguration struct { Integrations map[string]Integration `json:"integrations"` } -type ProtocolListenOld struct { - Enabled bool `json:"enabled"` - UDP string `json:"UDP,omitempty"` - TCP string `json:"TCP,omitempty"` - TLS string `json:"TLS,omitempty"` -} - -type CollectorConfigurationOld struct { - LogCollectorIsenabled bool `json:"log_collector_enabled"` - Integrations map[string]ProtocolListenOld `json:"integrations"` -} - func ReadCollectorConfig() (CollectorConfiguration, error) { cnf := CollectorConfiguration{} - if !utils.CheckIfPathExist(configuration.GetCollectorConfigPath()) { - cnfOld := CollectorConfigurationOld{} - err := utils.ReadJson(configuration.GetCollectorConfigPathOld(), &cnfOld) + if !utils.CheckIfPathExist(config.CollectorFileName) { + err := utils.ReadJson(config.CollectorFileNameOld, &cnf) if err != nil { return CollectorConfiguration{}, err } - cnf = MigrateOldConfig(cnfOld) - err = WriteCollectorConfig(cnf.Integrations, configuration.GetCollectorConfigPath()) + err = WriteCollectorConfig(cnf.Integrations, config.CollectorFileName) if err != nil { return CollectorConfiguration{}, err } - os.Remove(configuration.GetCollectorConfigPathOld()) + os.Remove(config.CollectorFileNameOld) } else { - err := utils.ReadJson(configuration.GetCollectorConfigPath(), &cnf) + err := utils.ReadJson(config.CollectorFileName, &cnf) if err != nil { return cnf, err } @@ -61,7 +48,7 @@ func ReadCollectorConfig() (CollectorConfiguration, error) { func ConfigureCollectorFirstTime() error { integrations := make(map[string]Integration) - for logTyp, ports := range configuration.ProtoPorts { + for logTyp, ports := range config.ProtoPorts { newIntegration := Integration{} newIntegration.TCP.IsListen = false newIntegration.TCP.Port = ports.TCP @@ -69,7 +56,7 @@ func ConfigureCollectorFirstTime() error { newIntegration.UDP.Port = ports.UDP integrations[string(logTyp)] = newIntegration } - return WriteCollectorConfig(integrations, configuration.GetCollectorConfigPath()) + return WriteCollectorConfig(integrations, config.CollectorFileName) } func ChangeIntegrationStatus(logTyp string, proto string, isEnabled bool) (string, error) { @@ -82,7 +69,7 @@ func ChangeIntegrationStatus(logTyp string, proto string, isEnabled bool) (strin if proto != "tcp" && proto != "udp" { return "", fmt.Errorf("invalid protocol: %s", proto) } - if valid := configuration.ValidateModuleType(configuration.LogType(logTyp)); valid == "nil" { + if valid := config.ValidateModuleType(logTyp); valid == "nil" { return "", fmt.Errorf("invalid integration: %s", logTyp) } @@ -97,7 +84,7 @@ func ChangeIntegrationStatus(logTyp string, proto string, isEnabled bool) (strin } cnf.Integrations[logTyp] = integration - return port, WriteCollectorConfig(cnf.Integrations, configuration.GetCollectorConfigPath()) + return port, WriteCollectorConfig(cnf.Integrations, config.CollectorFileName) } func ChangePort(logTyp string, proto string, port string) (string, error) { @@ -110,11 +97,11 @@ func ChangePort(logTyp string, proto string, port string) (string, error) { if proto != "tcp" && proto != "udp" { return "", fmt.Errorf("invalid protocol: %s", proto) } - if valid := configuration.ValidateModuleType(configuration.LogType(logTyp)); valid == "nil" { + if valid := config.ValidateModuleType(logTyp); valid == "nil" { return "", fmt.Errorf("invalid integration: %s", logTyp) } - if changeValid := ValidateChangeInPort(port, configuration.LogType(logTyp)); !changeValid { - return "", fmt.Errorf("change in port %s protocol %s not allowed for %s or out range %s-%s", port, proto, logTyp, configuration.PortRangeMin, configuration.PortRangeMax) + if changeValid := ValidateChangeInPort(port, logTyp); !changeValid { + return "", fmt.Errorf("change in port %s protocol %s not allowed for %s or out range %s-%s", port, proto, logTyp, config.PortRangeMin, config.PortRangeMax) } if !IsPortAvailable(port, proto, &cnf, logTyp) { return "", fmt.Errorf("port %s is already in use", port) @@ -131,52 +118,69 @@ func ChangePort(logTyp string, proto string, port string) (string, error) { } cnf.Integrations[logTyp] = integration - return old, WriteCollectorConfig(cnf.Integrations, configuration.GetCollectorConfigPath()) + return old, WriteCollectorConfig(cnf.Integrations, config.CollectorFileName) } func IsPortAvailable(port string, proto string, cnf *CollectorConfiguration, currentIntegration string) bool { - for integration, config := range cnf.Integrations { + for integration, integrationConfig := range cnf.Integrations { if integration != currentIntegration { - if config.TCP.Port == port || config.UDP.Port == port { + if integrationConfig.TCP.Port == port || integrationConfig.UDP.Port == port { return false } } } - ln, err := net.Listen(proto, ":"+port) + listener, err := net.Listen(proto, ":"+port) if err != nil { return false } - ln.Close() + + listener.Close() return true } -func MigrateOldConfig(old CollectorConfigurationOld) CollectorConfiguration { - integrations := make(map[string]Integration) - for logTyp, ports := range configuration.ProtoPorts { - newIntegration := Integration{} - if logTyp == "syslog" && old.LogCollectorIsenabled { - newIntegration.TCP.IsListen = true - } else { - newIntegration.TCP.IsListen = false +func WriteCollectorConfig(integrations map[string]Integration, filename string) error { + fileContent := "{\n \"integrations\": {\n" + for name, integration := range integrations { + fileContent += fmt.Sprintf(" \"%s\": {\n", name) + if integration.TCP.Port != "" { + fileContent += fmt.Sprintf(" \"tcp_port\": {\"enabled\": %t, \"value\": \"%s\"},\n", integration.TCP.IsListen, integration.TCP.Port) } - newIntegration.TCP.Port = ports.TCP - newIntegration.UDP.IsListen = false - newIntegration.UDP.Port = ports.UDP - integrations[string(logTyp)] = newIntegration + if integration.UDP.Port != "" { + fileContent += fmt.Sprintf(" \"udp_port\": {\"enabled\": %t, \"value\": \"%s\"},\n", integration.UDP.IsListen, integration.UDP.Port) + } + if strings.HasSuffix(fileContent, ",\n") { + fileContent = fileContent[:len(fileContent)-2] + "\n" + } + fileContent += " },\n" + } + if strings.HasSuffix(fileContent, ",\n") { + fileContent = fileContent[:len(fileContent)-2] + "\n" } + fileContent += " }\n}\n" - for logTyp, port := range old.Integrations { - if _, ok := integrations[logTyp]; ok { - if old.LogCollectorIsenabled && port.Enabled { - integration := integrations[logTyp] - integration.TCP.IsListen = true - integration.UDP.IsListen = false - integrations[logTyp] = integration - } - } + err := os.WriteFile(filename, []byte(fileContent), 0644) + if err != nil { + return err } - return CollectorConfiguration{Integrations: integrations} + return nil +} + +func WriteCollectorConfigFromModules(mod []Module, filename string) error { + integrations := make(map[string]Integration) + for _, m := range mod { + integrations[string(m.GetDataType())] = Integration{ + TCP: Port{ + IsListen: m.IsPortListen("tcp"), + Port: m.GetPort("tcp"), + }, + UDP: Port{ + IsListen: m.IsPortListen("udp"), + Port: m.GetPort("udp"), + }, + } + } + return WriteCollectorConfig(integrations, filename) } diff --git a/agent/agent/modules/modules.go b/agent/modules/modules.go similarity index 60% rename from agent/agent/modules/modules.go rename to agent/modules/modules.go index 95610f505..33eb0be04 100644 --- a/agent/agent/modules/modules.go +++ b/agent/modules/modules.go @@ -3,8 +3,8 @@ package modules import ( "time" - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/utils" ) const ( @@ -12,7 +12,7 @@ const ( ) var ( - moCache = []Module{} + moCache = make([]Module, 0, 10) ) type Module interface { @@ -24,26 +24,26 @@ type Module interface { DisablePort(proto string) } -func GetModule(typ configuration.LogType, h *logger.Logger) Module { - switch configuration.ValidateModuleType(typ) { +func GetModule(typ string) Module { + switch config.ValidateModuleType(typ) { case "syslog": - return GetSyslogModule(string(typ), configuration.ProtoPorts[typ], h) + return GetSyslogModule(typ, config.ProtoPorts[config.DataType(typ)]) case "netflow": - return GetNetflowModule(h) + return GetNetflowModule() default: return nil } } -func ModulesUp(h *logger.Logger) { +func StartModules() { for { time.Sleep(delayCheckSyslogCnfig) logCollectorConfig, err := ReadCollectorConfig() if err != nil { - h.Fatal("error reading collector configuration: %v", err) + utils.Logger.Fatal("error reading collector configuration: %v", err) } - for intType, config := range logCollectorConfig.Integrations { + for intType, cnf := range logCollectorConfig.Integrations { index := -1 for i, mod := range moCache { if mod.GetDataType() == intType { @@ -53,14 +53,18 @@ func ModulesUp(h *logger.Logger) { } if index == -1 { - newModule := GetModule(configuration.LogType(intType), h) + newModule := GetModule(intType) + if newModule == nil { + utils.Logger.ErrorF("error getting module %s", intType) + continue + } moCache = append(moCache, newModule) index = len(moCache) - 1 } - configs, err := processConfigs(moCache[index], config) + configs, err := processConfigs(moCache[index], cnf) if err != nil { - h.ErrorF("error processing configs: %v", err) + utils.Logger.ErrorF("error processing configs: %v", err) continue } @@ -70,13 +74,13 @@ func ModulesUp(h *logger.Logger) { switch proto { case "tcp": - port = config.TCP.Port + port = cnf.TCP.Port case "udp": - port = config.UDP.Port + port = cnf.UDP.Port } if port != "" && moCache[index].GetPort(proto) != port { - changeAllowed = ValidateChangeInPort(port, configuration.LogType(intType)) + changeAllowed = ValidateChangeInPort(port, intType) } if conf[0] { moCache[index].DisablePort(proto) @@ -87,10 +91,10 @@ func ModulesUp(h *logger.Logger) { moCache[index].EnablePort(proto) } } else { - h.Info("change in port %s protocol %s not allowed for %s or out range %s-%s", port, proto, intType, configuration.PortRangeMin, configuration.PortRangeMax) - err := WriteCollectorConfigFromModules(moCache, configuration.GetCollectorConfigPath()) + utils.Logger.Info("change in port %s protocol %s not allowed for %s or out range %s-%s", port, proto, intType, config.PortRangeMin, config.PortRangeMax) + err := WriteCollectorConfigFromModules(moCache, config.CollectorFileName) if err != nil { - h.ErrorF("error fixing collector configuration: %v", err) + utils.Logger.ErrorF("error fixing collector configuration: %v", err) continue } } @@ -131,11 +135,11 @@ func processConfigs(mod Module, cnf Integration) (map[string][]bool, error) { } // Return true if the port change is allowed -func ValidateChangeInPort(newPort string, dataType configuration.LogType) bool { - for _, logType := range configuration.ProhibitedPortsChange { - if logType == dataType { +func ValidateChangeInPort(newPort string, dataType string) bool { + for _, logType := range config.ProhibitedPortsChange { + if string(logType) == dataType { return false } } - return configuration.PortRangeMin <= newPort && newPort <= configuration.PortRangeMax + return config.PortRangeMin <= newPort && newPort <= config.PortRangeMax } diff --git a/agent/agent/modules/netflow.go b/agent/modules/netflow.go similarity index 76% rename from agent/agent/modules/netflow.go rename to agent/modules/netflow.go index 82d324938..94ca5f0e1 100644 --- a/agent/agent/modules/netflow.go +++ b/agent/modules/netflow.go @@ -11,11 +11,11 @@ import ( "github.com/tehmaze/netflow" "github.com/tehmaze/netflow/session" - "github.com/threatwinds/logger" "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" "github.com/utmstack/UTMStack/agent/agent/logservice" "github.com/utmstack/UTMStack/agent/agent/parser" + "github.com/utmstack/UTMStack/agent/agent/utils" ) var ( @@ -31,16 +31,14 @@ type NetflowModule struct { CTX context.Context Cancel context.CancelFunc IsEnabled bool - h *logger.Logger } -func GetNetflowModule(h *logger.Logger) *NetflowModule { +func GetNetflowModule() *NetflowModule { netflowOnce.Do(func() { netflowModule = &NetflowModule{ Parser: parser.GetParser("netflow"), DataType: "netflow", IsEnabled: false, - h: h, Decoders: make(map[string]*netflow.Decoder), } }) @@ -49,12 +47,12 @@ func GetNetflowModule(h *logger.Logger) *NetflowModule { func (m *NetflowModule) EnablePort(proto string) { if proto == "udp" && !m.IsEnabled { - m.h.Info("Server %s listening in port: %s protocol: UDP", m.DataType, configuration.ProtoPorts[configuration.LogTypeNetflow].UDP) + utils.Logger.Info("Server %s listening in port: %s protocol: UDP", m.DataType, config.ProtoPorts[config.DataTypeNetflow].UDP) m.IsEnabled = true - port, err := strconv.Atoi(configuration.ProtoPorts[configuration.LogTypeNetflow].UDP) + port, err := strconv.Atoi(config.ProtoPorts[config.DataTypeNetflow].UDP) if err != nil { - m.h.ErrorF("error converting port to int: %v", err) + utils.Logger.ErrorF("error converting port to int: %v", err) return } @@ -63,7 +61,7 @@ func (m *NetflowModule) EnablePort(proto string) { IP: net.ParseIP("0.0.0.0"), }) if err != nil { - m.h.ErrorF("error listening netflow: %v", err) + utils.Logger.ErrorF("error listening netflow: %v", err) return } @@ -93,7 +91,7 @@ func (m *NetflowModule) EnablePort(proto string) { continue } - m.h.ErrorF("error connecting with netflow listener: %v", err) + utils.Logger.ErrorF("error connecting with netflow listener: %v", err) continue } @@ -106,16 +104,16 @@ func (m *NetflowModule) EnablePort(proto string) { message, err := d.Read(bytes.NewBuffer(buffer[:length])) if err != nil { - m.h.ErrorF("error decoding NetFlow message: %v", err) + utils.Logger.ErrorF("error decoding NetFlow message: %v", err) continue } logs, err := m.Parser.ProcessData(parser.NetflowObject{ Remote: addr.String(), Message: message, - }, m.h) + }) if err != nil { - m.h.ErrorF("error parsing netflow: %v", err) + utils.Logger.ErrorF("error parsing netflow: %v", err) } for _, bulk := range logs { msgChannel <- bulk @@ -128,7 +126,7 @@ func (m *NetflowModule) EnablePort(proto string) { func (m *NetflowModule) DisablePort(proto string) { if proto == "udp" && m.IsEnabled { - m.h.Info("Server %s closed in port: %s protocol: UDP", m.DataType, configuration.ProtoPorts[configuration.LogTypeNetflow].UDP) + utils.Logger.Info("Server %s closed in port: %s protocol: UDP", m.DataType, config.ProtoPorts[config.DataTypeNetflow].UDP) m.Cancel() m.Listener.Close() m.IsEnabled = false @@ -154,7 +152,7 @@ func (m *NetflowModule) SetNewPort(proto string, port string) { func (m *NetflowModule) GetPort(proto string) string { switch proto { case "udp": - return configuration.ProtoPorts[configuration.LogTypeNetflow].UDP + return config.ProtoPorts[config.DataTypeNetflow].UDP default: return "" } @@ -180,12 +178,12 @@ func (m *NetflowModule) handleConnection(logsChannel chan []string) { for _, message := range messages { msg, _, err := validations.ValidateString(message, false) if err != nil { - m.h.ErrorF("error validating string: %v: message: %s", err, message) + utils.Logger.ErrorF("error validating string: %v: message: %s", err, message) } logBatch = append(logBatch, msg) } - if len(logBatch) >= configuration.BatchCapacity { + if len(logBatch) >= config.BatchCapacity { logservice.LogQueue <- logservice.LogPipe{ Src: m.DataType, Logs: logBatch, diff --git a/agent/agent/modules/syslog.go b/agent/modules/syslog.go similarity index 76% rename from agent/agent/modules/syslog.go rename to agent/modules/syslog.go index 4dff2e904..3bfc6582b 100644 --- a/agent/agent/modules/syslog.go +++ b/agent/modules/syslog.go @@ -10,11 +10,11 @@ import ( "strings" "time" - "github.com/threatwinds/logger" "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" "github.com/utmstack/UTMStack/agent/agent/logservice" "github.com/utmstack/UTMStack/agent/agent/parser" + "github.com/utmstack/UTMStack/agent/agent/utils" ) type SyslogModule struct { @@ -22,7 +22,6 @@ type SyslogModule struct { TCPListener listenerTCP UDPListener listenerUDP Parser parser.Parser - h *logger.Logger } type listenerTCP struct { @@ -41,7 +40,7 @@ type listenerUDP struct { Port string } -func GetSyslogModule(dataType string, protoPorts configuration.ProtoPort, h *logger.Logger) *SyslogModule { +func GetSyslogModule(dataType string, protoPorts config.ProtoPort) *SyslogModule { return &SyslogModule{ DataType: dataType, TCPListener: listenerTCP{ @@ -53,7 +52,6 @@ func GetSyslogModule(dataType string, protoPorts configuration.ProtoPort, h *log Port: protoPorts.UDP, }, Parser: parser.GetParser(dataType), - h: h, } } @@ -113,18 +111,18 @@ func (m *SyslogModule) DisablePort(proto string) { func (m *SyslogModule) enableTCP() { if !m.TCPListener.IsEnabled && m.TCPListener.Port != "" { - m.h.Info("Server %s listening in port: %s protocol: TCP", m.DataType, m.TCPListener.Port) + utils.Logger.Info("Server %s listening in port: %s protocol: TCP", m.DataType, m.TCPListener.Port) m.TCPListener.IsEnabled = true listener, err := net.Listen("tcp", "0.0.0.0"+":"+m.TCPListener.Port) if err != nil { - m.h.ErrorF("error listening TCp in port %s: %v", m.TCPListener.Port, err) + utils.Logger.ErrorF("error listening TCp in port %s: %v", m.TCPListener.Port, err) return } tcpListener, ok := listener.(*net.TCPListener) if !ok { - m.h.ErrorF("Could not assert to *net.TCPListener") + utils.Logger.ErrorF("Could not assert to *net.TCPListener") return } @@ -135,7 +133,7 @@ func (m *SyslogModule) enableTCP() { defer func() { err = m.TCPListener.Listener.Close() if err != nil { - m.h.ErrorF("error closing tcp listener: %v", err) + utils.Logger.ErrorF("error closing tcp listener: %v", err) } }() for { @@ -155,7 +153,7 @@ func (m *SyslogModule) enableTCP() { continue } - m.h.ErrorF("error connecting with tcp listener: %v", err) + utils.Logger.ErrorF("error connecting with tcp listener: %v", err) continue } go m.handleConnectionTCP(conn) @@ -168,18 +166,18 @@ func (m *SyslogModule) enableTCP() { func (m *SyslogModule) enableUDP() { if !m.UDPListener.IsEnabled && m.UDPListener.Port != "" { - m.h.Info("Server %s listening in port: %s protocol: UDP\n", m.DataType, m.UDPListener.Port) + utils.Logger.Info("Server %s listening in port: %s protocol: UDP\n", m.DataType, m.UDPListener.Port) m.UDPListener.IsEnabled = true listener, err := net.ListenPacket("udp", "0.0.0.0"+":"+m.UDPListener.Port) if err != nil { - m.h.ErrorF("error listening UDP in port %s: %v", m.UDPListener.Port, err) + utils.Logger.ErrorF("error listening UDP in port %s: %v", m.UDPListener.Port, err) return } udpListener, ok := listener.(*net.UDPConn) if !ok { - m.h.ErrorF("Could not assert to *net.UDPConn") + utils.Logger.ErrorF("Could not assert to *net.UDPConn") return } @@ -195,7 +193,7 @@ func (m *SyslogModule) enableUDP() { defer func() { err = m.UDPListener.Listener.Close() if err != nil { - m.h.ErrorF("error closing udp listener: %v", err) + utils.Logger.ErrorF("error closing udp listener: %v", err) } }() for { @@ -211,28 +209,29 @@ func (m *SyslogModule) enableUDP() { return } - netOpErr, ok := err.(*net.OpError) + var netOpErr *net.OpError + ok := errors.As(err, &netOpErr) if ok && netOpErr.Timeout() { continue } - m.h.ErrorF("error connecting with udp listener: %v", err) + utils.Logger.ErrorF("error connecting with udp listener: %v", err) continue } remoteAddr := add.String() remoteAddr, _, err = net.SplitHostPort(remoteAddr) if err != nil { - m.h.ErrorF("error getting remote addr: %v", err) + utils.Logger.ErrorF("error getting remote addr: %v", err) continue } if remoteAddr == "127.0.0.1" { remoteAddr, err = os.Hostname() if err != nil { - m.h.ErrorF("error getting hostname: %v\n", err) + utils.Logger.ErrorF("error getting hostname: %v\n", err) continue } } - messageWithIP := configuration.GetMessageFormated(remoteAddr, string(buffer[:n])) + messageWithIP := config.GetMessageFormated(remoteAddr, string(buffer[:n])) msgChannel <- messageWithIP } } @@ -242,7 +241,7 @@ func (m *SyslogModule) enableUDP() { func (m *SyslogModule) disableTCP() { if m.TCPListener.IsEnabled && m.TCPListener.Port != "" { - m.h.Info("Server %s closed in port: %s protocol: TCP", m.DataType, m.TCPListener.Port) + utils.Logger.Info("Server %s closed in port: %s protocol: TCP", m.DataType, m.TCPListener.Port) m.TCPListener.Cancel() m.TCPListener.Listener.Close() m.TCPListener.IsEnabled = false @@ -251,7 +250,7 @@ func (m *SyslogModule) disableTCP() { func (m *SyslogModule) disableUDP() { if m.UDPListener.IsEnabled && m.UDPListener.Port != "" { - m.h.Info("Server %s closed in port: %s protocol: UDP", m.DataType, m.UDPListener.Port) + utils.Logger.Info("Server %s closed in port: %s protocol: UDP", m.DataType, m.UDPListener.Port) m.UDPListener.Cancel() m.UDPListener.Listener.Close() m.UDPListener.IsEnabled = false @@ -266,13 +265,13 @@ func (m *SyslogModule) handleConnectionTCP(c net.Conn) { var err error remoteAddr, _, err = net.SplitHostPort(remoteAddr) if err != nil { - m.h.ErrorF("error spliting host and port: %v", err) + utils.Logger.ErrorF("error spliting host and port: %v", err) } if remoteAddr == "127.0.0.1" { remoteAddr, err = os.Hostname() if err != nil { - m.h.ErrorF("error getting hostname: %v\n", err) + utils.Logger.ErrorF("error getting hostname: %v\n", err) } } @@ -289,10 +288,10 @@ func (m *SyslogModule) handleConnectionTCP(c net.Conn) { if err == io.EOF || err.(net.Error).Timeout() { return } - m.h.ErrorF("error reading tcp data: %v", err) + utils.Logger.ErrorF("error reading tcp data: %v", err) return } - message = configuration.GetMessageFormated(remoteAddr, message) + message = config.GetMessageFormated(remoteAddr, message) msgChannel <- message } } @@ -307,9 +306,9 @@ func (m *SyslogModule) handleMessageTCP(logsChannel chan string) { case <-ticker.C: if len(logBatch) > 0 { if m.Parser != nil { - logs, err := m.Parser.ProcessData(logBatch, m.h) + logs, err := m.Parser.ProcessData(logBatch) if err != nil { - m.h.ErrorF("error parsing data: %v", err) + utils.Logger.ErrorF("error parsing data: %v", err) continue } for typ, bulk := range logs { @@ -331,15 +330,15 @@ func (m *SyslogModule) handleMessageTCP(logsChannel chan string) { message = strings.TrimSuffix(message, "\n") message, _, err := validations.ValidateString(message, false) if err != nil { - m.h.ErrorF("error validating string: %v: message: %s", err, message) + utils.Logger.ErrorF("error validating string: %v: message: %s", err, message) } logBatch = append(logBatch, message) - if len(logBatch) == configuration.BatchCapacity { + if len(logBatch) == config.BatchCapacity { if m.Parser != nil { - logs, err := m.Parser.ProcessData(logBatch, m.h) + logs, err := m.Parser.ProcessData(logBatch) if err != nil { - m.h.ErrorF("error parsing data: %v", err) + utils.Logger.ErrorF("error parsing data: %v", err) continue } for typ, bulk := range logs { @@ -369,9 +368,9 @@ func (m *SyslogModule) handleConnectionUDP(logsChannel chan string) { case <-ticker.C: if len(logBatch) > 0 { if m.Parser != nil { - logs, err := m.Parser.ProcessData(logBatch, m.h) + logs, err := m.Parser.ProcessData(logBatch) if err != nil { - m.h.ErrorF("error parsing data: %v", err) + utils.Logger.ErrorF("error parsing data: %v", err) continue } for typ, bulk := range logs { @@ -396,15 +395,15 @@ func (m *SyslogModule) handleConnectionUDP(logsChannel chan string) { message = strings.TrimSuffix(message, "\n") message, _, err := validations.ValidateString(message, false) if err != nil { - m.h.ErrorF("error validating string: %v: message: %s", err, message) + utils.Logger.ErrorF("error validating string: %v: message: %s", err, message) } logBatch = append(logBatch, message) - if len(logBatch) == configuration.BatchCapacity { + if len(logBatch) == config.BatchCapacity { if m.Parser != nil { - logs, err := m.Parser.ProcessData(logBatch, m.h) + logs, err := m.Parser.ProcessData(logBatch) if err != nil { - m.h.ErrorF("error parsing data: %v", err) + utils.Logger.ErrorF("error parsing data: %v", err) continue } for typ, bulk := range logs { diff --git a/agent/parser/beats.go b/agent/parser/beats.go new file mode 100644 index 000000000..4a416965b --- /dev/null +++ b/agent/parser/beats.go @@ -0,0 +1,80 @@ +package parser + +import ( + "fmt" + "regexp" + "sync" + + "github.com/threatwinds/validations" + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +var ( + beatsParser = BeatsParser{} + beatsParserOnce sync.Once + RegexspBeats = map[config.DataType]string{ + config.DataTypeApacheModule: `"type":"apache"|"module":"apache"`, + config.DataTypeLinuxAuditdModule: `"type":"auditd"|"module":"auditd"`, + config.DataTypeElasticsearchModule: `"type":"elasticsearch"|"module":"elasticsearch"`, + config.DataTypeKafkaModule: `"type":"kafka"|"module":"kafka"`, + config.DataTypeKibanaModule: `"type":"kibana"|"module":"kibana"`, + config.DataTypeLogstashModule: `"type":"logstash"|"module":"logstash"`, + config.DataTypeMongodbModule: `"type":"mongodb"|"module":"mongodb"`, + config.DataTypeMysqlModule: `"type":"mysql"|"module":"mysql"`, + config.DataTypeNginxModule: `"type":"nginx"|"module":"nginx"`, + config.DataTypeOsqueryModule: `"type":"osquery"|"module":"osquery"`, + config.DataTypePostgresqlModule: `"type":"postgresql"|"module":"postgresql"`, + config.DataTypeRedisModule: `"type":"redis"|"module":"redis"`, + config.DataTypeLinuxAgent: `"type":"system"|"module":"system"`, + config.DataTypeIisModule: `"type":"iis"|"module":"iis"`, + config.DataTypeTraefikModule: `"type":"traefik"|"module":"traefik"`, + config.DataTypeNatsModule: `"type":"nats"|"module":"nats"`, + config.DataTypeHaproxyModule: `"type":"haproxy"|"module":"haproxy"`, + } +) + +type BeatsParser struct{} + +func GetBeatsParser() *BeatsParser { + beatsParserOnce.Do(func() { + beatsParser = BeatsParser{} + }) + return &beatsParser +} + +func (p *BeatsParser) IdentifySource(log string) (config.DataType, error) { + for logType, regp := range RegexspBeats { + regExpCompiled, err := regexp.Compile(string(regp)) + if err != nil { + return "", err + } + if regExpCompiled.MatchString(log) { + return logType, nil + } + } + return config.DataTypeGeneric, nil +} + +func (p *BeatsParser) ProcessData(logBatch interface{}) (map[string][]string, error) { + classifiedLogs := make(map[string][]string) + batch, ok := logBatch.([]string) + if !ok { + return nil, fmt.Errorf("invalid log batch type") + } + for _, log := range batch { + if logType, err := p.IdentifySource(log); err != nil { + return nil, err + } else { + if logType != "" { + validatedLog, _, err := validations.ValidateString(log, false) + if err != nil { + utils.Logger.ErrorF("error validating log: %s: %v", log, err) + continue + } + classifiedLogs[string(logType)] = append(classifiedLogs[string(logType)], validatedLog) + } + } + } + return classifiedLogs, nil +} diff --git a/agent/agent/parser/cisco.go b/agent/parser/cisco.go similarity index 60% rename from agent/agent/parser/cisco.go rename to agent/parser/cisco.go index 8343c7421..62fbd4785 100644 --- a/agent/agent/parser/cisco.go +++ b/agent/parser/cisco.go @@ -5,17 +5,16 @@ import ( "regexp" "sync" - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" ) var ( ciscoParser = CiscoParser{} ciscoParserOnce sync.Once - RegexspCisco = map[configuration.LogType]string{ - configuration.LogTypeCiscoAsa: `%ASA-`, - configuration.LogTypeCiscoFirepower: `%FTD-`, - configuration.LogTypeCiscoSwitch: `%(\w|_)+-((\b\w+\b-\b\w+\b-)?)(\d)-([A-Z]|_)+`, + RegexspCisco = map[config.DataType]string{ + config.DataTypeCiscoAsa: `%ASA-`, + config.DataTypeCiscoFirepower: `%FTD-`, + config.DataTypeCiscoSwitch: `%(\w|_)+-((\b\w+\b-\b\w+\b-)?)(\d)-([A-Z]|_)+`, } ) @@ -28,7 +27,7 @@ func GetCiscoParser() *CiscoParser { return &ciscoParser } -func (p *CiscoParser) IdentifySource(log string) (configuration.LogType, error) { +func (p *CiscoParser) IdentifySource(log string) (config.DataType, error) { for logType, regp := range RegexspCisco { regExpCompiled, err := regexp.Compile(string(regp)) if err != nil { @@ -38,10 +37,10 @@ func (p *CiscoParser) IdentifySource(log string) (configuration.LogType, error) return logType, nil } } - return configuration.LogTypeCiscoMeraki, nil + return config.DataTypeCiscoMeraki, nil } -func (p *CiscoParser) ProcessData(logBatch interface{}, h *logger.Logger) (map[string][]string, error) { +func (p *CiscoParser) ProcessData(logBatch interface{}) (map[string][]string, error) { classifiedLogs := make(map[string][]string) batch, ok := logBatch.([]string) if !ok { diff --git a/agent/agent/parser/netflow.go b/agent/parser/netflow.go similarity index 90% rename from agent/agent/parser/netflow.go rename to agent/parser/netflow.go index b7d0d06d1..50a1ea34b 100644 --- a/agent/agent/parser/netflow.go +++ b/agent/parser/netflow.go @@ -11,7 +11,6 @@ import ( "github.com/tehmaze/netflow/netflow6" "github.com/tehmaze/netflow/netflow7" "github.com/tehmaze/netflow/netflow9" - "github.com/threatwinds/logger" pnf "github.com/utmstack/UTMStack/agent/agent/parser/netflow" ) @@ -35,7 +34,7 @@ type NetflowObject struct { Message netflow.Message } -func (p *NetflowParser) ProcessData(logBatch interface{}, h *logger.Logger) (map[string][]string, error) { +func (p *NetflowParser) ProcessData(logBatch interface{}) (map[string][]string, error) { var metrics []pnf.Metric var remote string diff --git a/agent/agent/parser/netflow/dump.go b/agent/parser/netflow/dump.go similarity index 76% rename from agent/agent/parser/netflow/dump.go rename to agent/parser/netflow/dump.go index d3fb982cd..ae510a314 100644 --- a/agent/agent/parser/netflow/dump.go +++ b/agent/parser/netflow/dump.go @@ -5,7 +5,7 @@ import ( "reflect" "strings" - "github.com/utmstack/UTMStack/agent/agent/configuration" + "github.com/utmstack/UTMStack/agent/agent/config" ) func Dump(metrics []Metric, remote string) []string { @@ -23,7 +23,7 @@ func Dump(metrics []Metric, remote string) []string { header := field.Tag.Get("header") kvPairs = append(kvPairs, fmt.Sprintf("%s=\"%v\"", header, value)) } - allKVPairs = append(allKVPairs, configuration.GetMessageFormated(remote, strings.Join(kvPairs, " "))) + allKVPairs = append(allKVPairs, config.GetMessageFormated(remote, strings.Join(kvPairs, " "))) } return allKVPairs } diff --git a/agent/agent/parser/netflow/ipfix.go b/agent/parser/netflow/ipfix.go similarity index 100% rename from agent/agent/parser/netflow/ipfix.go rename to agent/parser/netflow/ipfix.go diff --git a/agent/agent/parser/netflow/metrics.go b/agent/parser/netflow/metrics.go similarity index 100% rename from agent/agent/parser/netflow/metrics.go rename to agent/parser/netflow/metrics.go diff --git a/agent/agent/parser/netflow/proto.go b/agent/parser/netflow/proto.go similarity index 100% rename from agent/agent/parser/netflow/proto.go rename to agent/parser/netflow/proto.go diff --git a/agent/agent/parser/netflow/v1.go b/agent/parser/netflow/v1.go similarity index 100% rename from agent/agent/parser/netflow/v1.go rename to agent/parser/netflow/v1.go diff --git a/agent/agent/parser/netflow/v5.go b/agent/parser/netflow/v5.go similarity index 100% rename from agent/agent/parser/netflow/v5.go rename to agent/parser/netflow/v5.go diff --git a/agent/agent/parser/netflow/v6.go b/agent/parser/netflow/v6.go similarity index 100% rename from agent/agent/parser/netflow/v6.go rename to agent/parser/netflow/v6.go diff --git a/agent/agent/parser/netflow/v7.go b/agent/parser/netflow/v7.go similarity index 100% rename from agent/agent/parser/netflow/v7.go rename to agent/parser/netflow/v7.go diff --git a/agent/agent/parser/netflow/v9.go b/agent/parser/netflow/v9.go similarity index 100% rename from agent/agent/parser/netflow/v9.go rename to agent/parser/netflow/v9.go diff --git a/agent/agent/parser/parser.go b/agent/parser/parser.go similarity index 67% rename from agent/agent/parser/parser.go rename to agent/parser/parser.go index 11b992fef..b139d8573 100644 --- a/agent/agent/parser/parser.go +++ b/agent/parser/parser.go @@ -1,9 +1,7 @@ package parser -import "github.com/threatwinds/logger" - type Parser interface { - ProcessData(logBatch interface{}, h *logger.Logger) (map[string][]string, error) + ProcessData(logMessage interface{}) (map[string][]string, error) } func GetParser(typ string) Parser { diff --git a/agent/agent/protos/agent.proto b/agent/protos/agent.proto similarity index 100% rename from agent/agent/protos/agent.proto rename to agent/protos/agent.proto diff --git a/agent/agent/protos/common.proto b/agent/protos/common.proto similarity index 100% rename from agent/agent/protos/common.proto rename to agent/protos/common.proto diff --git a/agent/agent/protos/log.proto b/agent/protos/log.proto similarity index 100% rename from agent/agent/protos/log.proto rename to agent/protos/log.proto diff --git a/agent/agent/protos/ping.proto b/agent/protos/ping.proto similarity index 100% rename from agent/agent/protos/ping.proto rename to agent/protos/ping.proto diff --git a/agent/redline/README.md b/agent/redline/README.md deleted file mode 100644 index f48a76a4d..000000000 --- a/agent/redline/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# UTMStack Redline Service -The UTMStack Redline service is a critical component of the UTMStack. Its primary function is to monitor the other services within the UTMStack ecosystem, ensuring they are not unexpectedly terminated. In the event that a service is stopped unexpectedly, the Redline service will trigger an alert. - -### Logging -The UTMStack Redline service logs its activities to a file located in the logs directory. The name of the log file is path/logs/utmstack_redline.log. diff --git a/agent/redline/configuration/const.go b/agent/redline/configuration/const.go deleted file mode 100644 index 4dc8b45b0..000000000 --- a/agent/redline/configuration/const.go +++ /dev/null @@ -1,32 +0,0 @@ -package configuration - -import "runtime" - -const ( - SERV_NAME = "UTMStackRedline" - SERV_LOG = "utmstack_redline.log" - SERV_LOCK_NAME = "utmstack_redline.lock" -) - -func GetServicesLock() map[string]string { - var services = map[string]string{ - "UTMStackAgent": "utmstack_agent.lock", - "UTMStackModulesLogsCollector": "utmstack_modules_collector.lock", - "UTMStackUpdater": "utmstack_updater.lock", - } - if runtime.GOOS == "windows" { - services["UTMStackWindowsLogsCollector"] = "utmstack_windows_collector.lock" - } - return services -} - -func GetAgentBin() string { - var bin string - switch runtime.GOOS { - case "windows": - bin = "utmstack_agent_service.exe" - case "linux": - bin = "utmstack_agent_service" - } - return bin -} diff --git a/agent/redline/constants/const.go b/agent/redline/constants/const.go deleted file mode 100644 index b8adb36b2..000000000 --- a/agent/redline/constants/const.go +++ /dev/null @@ -1,32 +0,0 @@ -package constants - -import "runtime" - -const ( - SERV_NAME = "UTMStackRedline" - SERV_LOG = "utmstack_redline.log" - SERV_LOCK_NAME = "utmstack_redline.lock" -) - -func GetServicesLock() map[string]string { - var services = map[string]string{ - "UTMStackAgent": "utmstack_agent.lock", - "UTMStackModulesLogsCollector": "utmstack_modules_collector.lock", - "UTMStackUpdater": "utmstack_updater.lock", - } - if runtime.GOOS == "windows" { - services["UTMStackWindowsLogsCollector"] = "utmstack_windows_collector.lock" - } - return services -} - -func GetAgentBin() string { - var bin string - switch runtime.GOOS { - case "windows": - bin = "utmstack_agent_service.exe" - case "linux": - bin = "utmstack_agent_service" - } - return bin -} diff --git a/agent/redline/go.mod b/agent/redline/go.mod deleted file mode 100644 index d26f5681d..000000000 --- a/agent/redline/go.mod +++ /dev/null @@ -1,42 +0,0 @@ -module github.com/utmstack/UTMStack/agent/redline - -go 1.22.4 - -toolchain go1.23.4 - -require ( - github.com/kardianos/service v1.2.2 - github.com/threatwinds/logger v1.1.12 -) - -require ( - github.com/bytedance/sonic v1.12.1 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.0 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/agent/redline/go.sum b/agent/redline/go.sum deleted file mode 100644 index 4f9770c5c..000000000 --- a/agent/redline/go.sum +++ /dev/null @@ -1,97 +0,0 @@ -github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= -github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= -github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= -github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= -github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= -github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= -github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= -github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -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= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= -golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/agent/redline/main.go b/agent/redline/main.go deleted file mode 100644 index d5ac6cb30..000000000 --- a/agent/redline/main.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - "path/filepath" - - "github.com/utmstack/UTMStack/agent/redline/configuration" - "github.com/utmstack/UTMStack/agent/redline/serv" - "github.com/utmstack/UTMStack/agent/redline/utils" -) - -func main() { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - log.Fatalf("Failed to get current path: %v", err) - } - - // Configuring log saving - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) - - if len(os.Args) > 1 { - arg := os.Args[1] - switch arg { - case "run": - serv.RunService(h) - case "install": - h.Info("Installing UTMStack Redline service...") - serv.InstallService(h) - h.Info("UTMStack Redline service installed correctly") - - case "uninstall": - h.Info("Uninstalling UTMStack Redline service...") - - serv.UninstallService(h) - h.Info("UTMStack Redline service uninstalled correctly") - os.Exit(0) - default: - fmt.Println("unknown option") - } - } else { - serv.RunService(h) - } -} diff --git a/agent/redline/protector/protector.go b/agent/redline/protector/protector.go deleted file mode 100644 index b07ac9ba3..000000000 --- a/agent/redline/protector/protector.go +++ /dev/null @@ -1,66 +0,0 @@ -package protector - -import ( - "fmt" - "path/filepath" - "runtime" - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/redline/configuration" - "github.com/utmstack/UTMStack/agent/redline/utils" -) - -func ProtectService(servName, lockName string, h *logger.Logger) { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - fmt.Printf("Failed to get current path: %v", err) - h.Fatal("Failed to get current path: %v", err) - } - - bin := configuration.GetAgentBin() - - attempts := 0 - for { - if attempts >= 3 { - h.Info("%s service has been stopped", servName) - if err := utils.Execute(filepath.Join(path, bin), path, "send-log", fmt.Sprintf("%s service has been stopped", servName)); err != nil { - h.ErrorF("error checking %s: error sending log : %v", servName, err) - time.Sleep(time.Second * 5) - continue - } - if err := utils.RestartService(servName); err != nil { - h.ErrorF("error checking %s: error restarting %s service: %v", servName, servName, err) - time.Sleep(time.Second * 5) - continue - } - - h.Info("%s restarted correctly", servName) - time.Sleep(time.Second * 5) - attempts = 0 - continue - } - - if isRunning, err := utils.CheckIfServiceIsActive(servName); err != nil { - h.ErrorF("error checking if %s is running: %v", servName, err) - time.Sleep(time.Second * 5) - } else if isRunning { - time.Sleep(time.Second * 5) - continue - } - if !utils.CheckIfPathExist(filepath.Join(path, "locks", lockName)) { - attempts++ - time.Sleep(time.Second * 30) - continue - } - if lockName == "utmstack_updater.lock" && runtime.GOOS == "linux" { - err = utils.Execute(filepath.Join(path, "utmstack_updater_self"), path) - if err != nil { - h.ErrorF("error executing utmstack_updater_self: %v", err) - } - time.Sleep(time.Second * 5) - continue - } - } -} diff --git a/agent/redline/serv/config.go b/agent/redline/serv/config.go deleted file mode 100644 index 88f45a9b2..000000000 --- a/agent/redline/serv/config.go +++ /dev/null @@ -1,17 +0,0 @@ -package serv - -import ( - "github.com/kardianos/service" - "github.com/utmstack/UTMStack/agent/redline/configuration" -) - -// GetConfigServ creates and returns a pointer to a service configuration structure. -func GetConfigServ() *service.Config { - svcConfig := &service.Config{ - Name: configuration.SERV_NAME, - DisplayName: "UTMStack Redline", - Description: "UTMStack Redline Service", - } - - return svcConfig -} diff --git a/agent/redline/serv/install.go b/agent/redline/serv/install.go deleted file mode 100644 index 8f0d2d032..000000000 --- a/agent/redline/serv/install.go +++ /dev/null @@ -1,30 +0,0 @@ -package serv - -import ( - "fmt" - - "github.com/kardianos/service" - "github.com/threatwinds/logger" -) - -func InstallService(h *logger.Logger) { - svcConfig := GetConfigServ() - prg := new(program) - newService, err := service.New(prg, svcConfig) - if err != nil { - fmt.Printf("error creating new service: %v", err) - h.Fatal("error creating new service: %v", err) - } - err = newService.Install() - if err != nil { - fmt.Printf("error installing new service: %v", err) - h.Fatal("error installing new service: %v", err) - } - - // Start the service after installing it - err = newService.Start() - if err != nil { - fmt.Printf("error starting new service: %v", err) - h.Fatal("error starting new service: %v", err) - } -} diff --git a/agent/redline/serv/run.go b/agent/redline/serv/run.go deleted file mode 100644 index 1706b223a..000000000 --- a/agent/redline/serv/run.go +++ /dev/null @@ -1,19 +0,0 @@ -package serv - -import ( - "github.com/kardianos/service" - "github.com/threatwinds/logger" -) - -func RunService(h *logger.Logger) { - svcConfig := GetConfigServ() - prg := new(program) - newService, err := service.New(prg, svcConfig) - if err != nil { - h.Fatal("error creating new service: %v", err) - } - err = newService.Run() - if err != nil { - h.Fatal("error running new service: %v", err) - } -} diff --git a/agent/redline/serv/service.go b/agent/redline/serv/service.go deleted file mode 100644 index 286fc9d0d..000000000 --- a/agent/redline/serv/service.go +++ /dev/null @@ -1,54 +0,0 @@ -package serv - -import ( - "log" - "os" - "os/signal" - "path/filepath" - "syscall" - "time" - - "github.com/kardianos/service" - "github.com/utmstack/UTMStack/agent/redline/configuration" - "github.com/utmstack/UTMStack/agent/redline/protector" - "github.com/utmstack/UTMStack/agent/redline/utils" -) - -type program struct{} - -func (p *program) Start(s service.Service) error { - go p.run() - return nil -} - -func (p *program) Stop(s service.Service) error { - return nil -} - -func (p *program) run() { - path, err := utils.GetMyPath() - if err != nil { - log.Fatalf("Failed to get current path: %v\n", err) - } - - // Configuring log saving - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) - - for { - if utils.CheckIfPathExist(filepath.Join(path, "locks", "setup.lock")) { - time.Sleep(time.Second * 5) - continue - } - break - } - - h.Info("UTMStackRedline started correctly") - for servName, lockName := range configuration.GetServicesLock() { - go protector.ProtectService(servName, lockName, h) - } - - signals := make(chan os.Signal, 1) - signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) - <-signals - -} diff --git a/agent/redline/serv/uninstall.go b/agent/redline/serv/uninstall.go deleted file mode 100644 index 689851559..000000000 --- a/agent/redline/serv/uninstall.go +++ /dev/null @@ -1,19 +0,0 @@ -package serv - -import ( - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/redline/configuration" - "github.com/utmstack/UTMStack/agent/redline/utils" -) - -func UninstallService(h *logger.Logger) { - // Uninstall service - err := utils.StopService(configuration.SERV_NAME) - if err != nil { - h.Fatal("error stopping %s: %v", configuration.SERV_NAME, err) - } - err = utils.UninstallService("%s") - if err != nil { - h.Fatal("error uninstalling %s: %v", configuration.SERV_NAME, err) - } -} diff --git a/agent/redline/utils/cmd.go b/agent/redline/utils/cmd.go deleted file mode 100644 index b1881855f..000000000 --- a/agent/redline/utils/cmd.go +++ /dev/null @@ -1,47 +0,0 @@ -package utils - -import ( - "errors" - "os/exec" - "unicode/utf8" -) - -func CleanString(s string) string { - v := make([]rune, 0, len(s)) - for i, r := range s { - if r == utf8.RuneError { - _, size := utf8.DecodeRuneInString(s[i:]) - if size == 1 { - v = append(v, '?') - continue - } - } - v = append(v, r) - } - return string(v) -} - -func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { - cmd := exec.Command(c, arg...) - - cmd.Dir = dir - if errors.Is(cmd.Err, exec.ErrDot) { - cmd.Err = nil - } - - out, err := cmd.Output() - if err != nil { - return string(out[:]) + err.Error(), true - } - - validUtf8Out := CleanString(string(out[:])) - - return validUtf8Out, false -} - -func Execute(c string, dir string, arg ...string) error { - cmd := exec.Command(c, arg...) - cmd.Dir = dir - - return cmd.Run() -} diff --git a/agent/redline/utils/files.go b/agent/redline/utils/files.go deleted file mode 100644 index 990ba483c..000000000 --- a/agent/redline/utils/files.go +++ /dev/null @@ -1,24 +0,0 @@ -package utils - -import ( - "os" - "path/filepath" -) - -// GetMyPath returns the directory path where the currently running executable is located. -// Returns a string representing the directory path, and an error if any error occurs during the process. -func GetMyPath() (string, error) { - ex, err := os.Executable() - if err != nil { - return "", err - } - exPath := filepath.Dir(ex) - return exPath, nil -} - -func CheckIfPathExist(path string) bool { - if _, err := os.Stat(path); os.IsNotExist(err) { - return false - } - return true -} diff --git a/agent/redline/utils/logger.go b/agent/redline/utils/logger.go deleted file mode 100644 index 173644bf7..000000000 --- a/agent/redline/utils/logger.go +++ /dev/null @@ -1,22 +0,0 @@ -package utils - -import ( - "sync" - - "github.com/threatwinds/logger" -) - -var ( - redlineLogger *logger.Logger - loggerOnceInstance sync.Once -) - -// CreateLogger returns a single instance of a Logger configured to save logs to a rotating file. -func CreateLogger(filename string) *logger.Logger { - loggerOnceInstance.Do(func() { - redlineLogger = logger.NewLogger( - &logger.Config{Format: "text", Level: 100, Output: filename, Retries: 3, Wait: 5}, - ) - }) - return redlineLogger -} diff --git a/agent/redline/utils/services.go b/agent/redline/utils/services.go deleted file mode 100644 index 79fd9c5a4..000000000 --- a/agent/redline/utils/services.go +++ /dev/null @@ -1,125 +0,0 @@ -package utils - -import ( - "fmt" - "runtime" - "strings" -) - -// CheckIfServiceIsActive checks if a service is active or running -func CheckIfServiceIsActive(serv string) (bool, error) { - var errB bool - var output string - - path, err := GetMyPath() - if err != nil { - return false, fmt.Errorf("error getting current path: %v", err) - } - - switch runtime.GOOS { - case "windows": - output, errB = ExecuteWithResult("sc", path, "query", serv) - case "linux": - output, errB = ExecuteWithResult("systemctl", path, "is-active", serv) - default: - return false, fmt.Errorf("unknown operating system") - } - - if errB { - return false, nil - } - - serviceStatus := strings.ToLower(strings.TrimSpace(string(output))) - if runtime.GOOS == "linux" { - return serviceStatus == "active", nil - } else if runtime.GOOS == "windows" { - return strings.Contains(serviceStatus, "running"), nil - } - - return false, fmt.Errorf("unsupported operating system") -} - -// RestartService restarts a service -func RestartService(serv string) error { - path, err := GetMyPath() - if err != nil { - return fmt.Errorf("error getting current path: %v", err) - } - - isRunning, err := CheckIfServiceIsActive(serv) - if err != nil { - return fmt.Errorf("error checking if %s service is active: %v", serv, err) - } - - switch runtime.GOOS { - case "windows": - if isRunning { - err := Execute("sc", path, "stop", serv) - if err != nil { - return fmt.Errorf("error stopping service: %v", err) - } - } - err := Execute("sc", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - - case "linux": - if isRunning { - err := Execute("systemctl", path, "restart", serv) - if err != nil { - return fmt.Errorf("error restarting service: %v", err) - } - } else { - err := Execute("systemctl", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - } - } - return nil -} - -func StopService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } - switch runtime.GOOS { - case "windows": - err := Execute("sc", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - case "linux": - err := Execute("systemctl", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - } - return nil -} - -func UninstallService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } - switch runtime.GOOS { - case "windows": - err := Execute("sc", path, "delete", name) - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - case "linux": - err := Execute("systemctl", path, "disable", name) - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - err = Execute("rm", "/etc/systemd/system/", "/etc/systemd/system/"+name+".service") - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - } - return nil -} diff --git a/agent/rsrc_windows_386.syso b/agent/rsrc_windows_386.syso new file mode 100644 index 0000000000000000000000000000000000000000..2aaa16e001adb2fdf5e602bb8287edcae60fa5d8 GIT binary patch literal 29120 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

2RE?qPlPEHP^SQ!%vv^rOxkWj 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 literal 0 HcmV?d00001 diff --git a/agent/self/README.md b/agent/self/README.md deleted file mode 100644 index 4298e1517..000000000 --- a/agent/self/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# UTMStack Agent Service Dependency: Self-Updater -This project is a crucial dependency for the UTMStack Agent Service. It is specifically designed to handle updates for the UTMStack Updater Service. When the UTMStack Updater Service finds an update for itself, this tool allows it to uninstall and update itself seamlessly. - -### Features -Self-Updating: The primary feature of this tool is to enable the UTMStack Updater Service to update itself when an update is found. -Logging: The tool logs all its activities, which can be useful for debugging and tracking its operations. -Error Handling: The tool is designed to handle errors gracefully and log them for further analysis. - -### How it Works -The tool first gets the current path of the UTMStack Updater Service. It then configures log saving and reads data from versions.json. It selects the environment and checks if the UTMStack Updater Service is active. If it is, the service is stopped. The tool then updates the UTMStack Updater Service and restarts it. diff --git a/agent/self/config/const.go b/agent/self/config/const.go new file mode 100644 index 000000000..2d89a1ee5 --- /dev/null +++ b/agent/self/config/const.go @@ -0,0 +1,6 @@ +package config + +const ( + SERV_NAME = "UTMStackAgent" + SERV_LOG = "utmstack_updater_self.log" +) diff --git a/agent/self/config/linux_amd64.go b/agent/self/config/linux_amd64.go new file mode 100644 index 000000000..2bd4ccf23 --- /dev/null +++ b/agent/self/config/linux_amd64.go @@ -0,0 +1,8 @@ +//go:build linux && amd64 +// +build linux,amd64 + +package config + +var ( + ServiceFile = "utmstack_agent_service%s" +) diff --git a/agent/self/config/linux_arm64.go b/agent/self/config/linux_arm64.go new file mode 100644 index 000000000..35fbef145 --- /dev/null +++ b/agent/self/config/linux_arm64.go @@ -0,0 +1,8 @@ +//go:build linux && arm64 +// +build linux,arm64 + +package config + +var ( + ServiceFile = "utmstack_agent_service_arm64%s" +) diff --git a/agent/self/config/win_amd64.go b/agent/self/config/win_amd64.go new file mode 100644 index 000000000..87bcb5eea --- /dev/null +++ b/agent/self/config/win_amd64.go @@ -0,0 +1,8 @@ +//go:build windows && amd64 +// +build windows,amd64 + +package config + +var ( + ServiceFile = "utmstack_agent_service%s.exe" +) diff --git a/agent/self/config/win_arm64.go b/agent/self/config/win_arm64.go new file mode 100644 index 000000000..ccedb2f95 --- /dev/null +++ b/agent/self/config/win_arm64.go @@ -0,0 +1,8 @@ +//go:build windows && arm64 +// +build windows,arm64 + +package config + +var ( + ServiceFile = "utmstack_agent_service_arm64%s.exe" +) diff --git a/agent/self/configuration/config.go b/agent/self/configuration/config.go deleted file mode 100644 index bb2b4ceeb..000000000 --- a/agent/self/configuration/config.go +++ /dev/null @@ -1,32 +0,0 @@ -package configuration - -import ( - "os" - "path/filepath" - - "github.com/utmstack/UTMStack/agent/self/utils" -) - -type Environment struct { - Branch string `yaml:"branch"` -} - -func ReadEnv() (*Environment, error) { - var env Environment - path, err := utils.GetMyPath() - if err != nil { - return nil, err - } - - path = filepath.Join(path, "env.yml") - - if _, err = os.Stat(path); os.IsNotExist(err) { - return &Environment{Branch: "release"}, nil - } else { - err = utils.ReadYAML(path, &env) - if err != nil { - return nil, err - } - } - return &env, nil -} diff --git a/agent/self/configuration/const.go b/agent/self/configuration/const.go deleted file mode 100644 index 854fa2846..000000000 --- a/agent/self/configuration/const.go +++ /dev/null @@ -1,23 +0,0 @@ -package configuration - -import "runtime" - -const ( - SERV_NAME = "UTMStackUpdaterSelf" - SERV_LOG = "utmstack_updater_self.log" - UPDATER_SERV_NAME = "UTMStackUpdater" - UPDATER_SERV_LOCK = "utmstack_updater.lock" - Bucket = "https://cdn.utmstack.com/agent_updates/" - SERV_LOCK = "utmstack_updater.lock" -) - -func GetUpdaterBin() string { - var bin string - switch runtime.GOOS { - case "windows": - bin = "utmstack_updater_service.exe" - case "linux": - bin = "utmstack_updater_service" - } - return bin -} diff --git a/agent/self/constants/const.go b/agent/self/constants/const.go deleted file mode 100644 index cbe5cfa99..000000000 --- a/agent/self/constants/const.go +++ /dev/null @@ -1,23 +0,0 @@ -package constants - -import "runtime" - -const ( - SERV_NAME = "UTMStackUpdaterSelf" - SERV_LOG = "utmstack_updater_self.log" - UPDATER_SERV_NAME = "UTMStackUpdater" - UPDATER_SERV_LOCK = "utmstack_updater.lock" - Bucket = "https://cdn.utmstack.com/agent_updates/" - SERV_LOCK = "utmstack_updater.lock" -) - -func GetUpdaterBin() string { - var bin string - switch runtime.GOOS { - case "windows": - bin = "utmstack_updater_service.exe" - case "linux": - bin = "utmstack_updater_service" - } - return bin -} diff --git a/agent/self/go.mod b/agent/self/go.mod index d74d8737c..738410b61 100644 --- a/agent/self/go.mod +++ b/agent/self/go.mod @@ -4,10 +4,7 @@ go 1.22.4 toolchain go1.23.4 -require ( - github.com/threatwinds/logger v1.1.12 - gopkg.in/yaml.v2 v2.4.0 -) +require github.com/threatwinds/logger v1.1.12 require ( github.com/bytedance/sonic v1.12.1 // indirect diff --git a/agent/self/go.sum b/agent/self/go.sum index ec4ffc893..791835d83 100644 --- a/agent/self/go.sum +++ b/agent/self/go.sum @@ -88,8 +88,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/agent/self/main.go b/agent/self/main.go index 9f217ef07..51f057b6a 100644 --- a/agent/self/main.go +++ b/agent/self/main.go @@ -1,64 +1,41 @@ package main import ( - "log" "path/filepath" + "time" - "github.com/utmstack/UTMStack/agent/self/configuration" + "github.com/utmstack/UTMStack/agent/self/config" "github.com/utmstack/UTMStack/agent/self/update" "github.com/utmstack/UTMStack/agent/self/utils" ) func main() { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - log.Fatalf("Failed to get current path: %v", err) - } - - // Configuring log saving - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) + path := utils.GetMyPath() + utils.InitLogger(filepath.Join(path, "logs", config.SERV_LOG)) - // Save data from versions.json - allVersions := update.Version{} - err = utils.ReadJson(filepath.Join(path, "versions.json"), &allVersions) - if err != nil { - h.Fatal("error reading current versions.json: %v", err) - } + utils.SelfLogger.Info("Updating %s...", config.SERV_NAME) - // Select environment - env, err := configuration.ReadEnv() - if err != nil { - h.Fatal("Failed to get current path: %v", err) - } - - h.Info("Updating UTMStackUpdater...") - - if isRunning, err := utils.CheckIfServiceIsActive(configuration.UPDATER_SERV_NAME); err != nil { - h.Fatal("error checking %s service: %v", configuration.UPDATER_SERV_NAME, err) + if isRunning, err := utils.CheckIfServiceIsActive(config.SERV_NAME); err != nil { + utils.SelfLogger.Fatal("error checking %s service: %v", config.SERV_NAME, err) } else if isRunning { - err = utils.StopService(configuration.UPDATER_SERV_NAME) + err = utils.StopService(config.SERV_NAME) if err != nil { - h.Fatal("error stopping %s service: %v", configuration.UPDATER_SERV_NAME, err) + utils.SelfLogger.Fatal("error stopping %s service: %v", config.SERV_NAME, err) } - h.Info("UTMStackUpdater stopped correctly") + utils.SelfLogger.Info("%s stopped correctly", config.SERV_NAME) } - err = update.UpdateUpdaterService(allVersions.UpdaterVersion, env.Branch) - if err != nil { - h.Fatal("error downloading new %s service: %v", configuration.UPDATER_SERV_NAME, err) - } - h.Info("New UTMStackUpdater downloaded correctly") + time.Sleep(10 * time.Second) - err = utils.RestartService(configuration.UPDATER_SERV_NAME) + err := update.RunUpdate() if err != nil { - h.Fatal("error restarting %s service: %v", configuration.UPDATER_SERV_NAME, err) + utils.SelfLogger.Fatal("error updating new %s service: %v", config.SERV_NAME, err) } - h.Info("UTMStackUpdater restarted correctly") + utils.SelfLogger.Info("New %s downloaded correctly", config.SERV_NAME) - err = utils.RemoveLock(filepath.Join(path, "locks", configuration.SERV_LOCK)) + err = utils.RestartService(config.SERV_NAME) if err != nil { - h.Fatal("error removing %s: %v", configuration.SERV_LOCK, err) + utils.SelfLogger.Fatal("error restarting %s service: %v", config.SERV_NAME, err) } - h.Info("UTMStackUpdater updated correctly") + utils.SelfLogger.Info("%s updated correctly", config.SERV_NAME) } diff --git a/agent/self/rsrc_windows_386.syso b/agent/self/rsrc_windows_386.syso new file mode 100644 index 0000000000000000000000000000000000000000..2aaa16e001adb2fdf5e602bb8287edcae60fa5d8 GIT binary patch literal 29120 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

2RE?qPlPEHP^SQ!%vv^rOxkWj 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 literal 0 HcmV?d00001 diff --git a/agent/self/update/schema.go b/agent/self/update/schema.go deleted file mode 100644 index 7a58ae79f..000000000 --- a/agent/self/update/schema.go +++ /dev/null @@ -1,8 +0,0 @@ -package update - -type Version struct { - MasterVersion string `json:"master_version"` - AgentVersion string `json:"agent_version"` - UpdaterVersion string `json:"updater_version"` - RedlineVersion string `json:"redline_version"` -} diff --git a/agent/self/update/update.go b/agent/self/update/update.go index c45559d3c..22011d831 100644 --- a/agent/self/update/update.go +++ b/agent/self/update/update.go @@ -2,31 +2,26 @@ package update import ( "fmt" + "os" "path/filepath" - "runtime" - "github.com/utmstack/UTMStack/agent/self/configuration" + "github.com/utmstack/UTMStack/agent/self/config" "github.com/utmstack/UTMStack/agent/self/utils" ) -func UpdateUpdaterService(version, env string) error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } +func RunUpdate() error { + path := utils.GetMyPath() - // Download new bin - bin := configuration.GetUpdaterBin() - url := configuration.Bucket + env + "/updater_service/v" + version + "/" + bin + "?time=" + utils.GetCurrentTime() - err = utils.DownloadFile(url, filepath.Join(path, bin)) + newbin := fmt.Sprintf(config.ServiceFile, "_new") + oldbin := fmt.Sprintf(config.ServiceFile, "") + err := os.Remove(filepath.Join(path, oldbin)) if err != nil { - return fmt.Errorf("error downloading new %s: %v", bin, err) + return fmt.Errorf("error removing old %s: %v", oldbin, err) } - if runtime.GOOS == "linux" { - if err = utils.Execute("chmod", path, "-R", "777", bin); err != nil { - return fmt.Errorf("error executing chmod: %v", err) - } + err = os.Rename(filepath.Join(path, newbin), filepath.Join(path, oldbin)) + if err != nil { + return fmt.Errorf("error renaming new %s: %v", newbin, err) } return nil diff --git a/agent/self/utils/delay.go b/agent/self/utils/delay.go deleted file mode 100644 index e3000ea71..000000000 --- a/agent/self/utils/delay.go +++ /dev/null @@ -1,11 +0,0 @@ -package utils - -import "time" - -func IncrementReconnectDelay(delay time.Duration, maxReconnectDelay time.Duration) time.Duration { - delay *= 2 - if delay > maxReconnectDelay { - delay = maxReconnectDelay - } - return delay -} diff --git a/agent/self/utils/download.go b/agent/self/utils/download.go deleted file mode 100644 index a0d578eb0..000000000 --- a/agent/self/utils/download.go +++ /dev/null @@ -1,51 +0,0 @@ -package utils - -import ( - "fmt" - "io" - "net/http" - "os" - "time" -) - -const ( - maxConnectionAttempts = 3 - initialReconnectDelay = 10 * time.Second - maxReconnectDelay = 60 * time.Second -) - -// DownloadFile downloads a file from a URL and saves it to disk. Returns an error on failure. -func DownloadFile(url string, fileName string) error { - connectionAttemps := 0 - reconnectDelay := initialReconnectDelay - - var resp *http.Response - var err error - - for { - if connectionAttemps >= maxConnectionAttempts { - return fmt.Errorf("error downloading file after %d attemps: %v", maxConnectionAttempts, err) - } - resp, err = http.Get(url) - if err != nil || resp.StatusCode != http.StatusOK { - if resp != nil { - resp.Body.Close() - } - connectionAttemps++ - time.Sleep(reconnectDelay) - reconnectDelay = IncrementReconnectDelay(reconnectDelay, maxReconnectDelay) - continue - } - break - } - defer resp.Body.Close() - - out, err := os.Create(fileName) - if err != nil { - return err - } - defer out.Close() - - _, err = io.Copy(out, resp.Body) - return err -} diff --git a/agent/self/utils/files.go b/agent/self/utils/files.go index 805cc34e8..24baf7dae 100644 --- a/agent/self/utils/files.go +++ b/agent/self/utils/files.go @@ -1,56 +1,15 @@ package utils import ( - "encoding/json" "os" "path/filepath" - - "gopkg.in/yaml.v2" ) -// GetMyPath returns the directory path where the currently running executable is located. -// Returns a string representing the directory path, and an error if any error occurs during the process. -func GetMyPath() (string, error) { +func GetMyPath() string { ex, err := os.Executable() if err != nil { - return "", err + return "" } exPath := filepath.Dir(ex) - return exPath, nil -} - -// ReadJson reads the json data from the specified file URL and unmarshal it into the provided result interface{}. -// Returns an error if any error occurs during the process. -func ReadJson(fileName string, data interface{}) error { - content, err := os.ReadFile(fileName) - if err != nil { - return err - } - err = json.Unmarshal(content, data) - if err != nil { - return err - } - return nil -} - -// ReadYAML reads the YAML data from the specified file URL and deserializes it into the provided result interface{}. -// Returns an error if any error occurs during the process. -func ReadYAML(path string, result interface{}) error { - file, err := os.Open(path) - if err != nil { - return err - } - defer file.Close() - d := yaml.NewDecoder(file) - if err := d.Decode(result); err != nil { - return err - } - return nil -} - -func CheckIfPathExist(path string) bool { - if _, err := os.Stat(path); os.IsNotExist(err) { - return false - } - return true + return exPath } diff --git a/agent/self/utils/lock.go b/agent/self/utils/lock.go deleted file mode 100644 index 965dba81c..000000000 --- a/agent/self/utils/lock.go +++ /dev/null @@ -1,18 +0,0 @@ -package utils - -import ( - "fmt" - "os" -) - -func RemoveLock(lockdir string) error { - if CheckIfPathExist(lockdir) { - err := os.Remove(lockdir) - if err != nil { - return err - } - } else { - return fmt.Errorf("lock file %s not exists", lockdir) - } - return nil -} diff --git a/agent/self/utils/logger.go b/agent/self/utils/logger.go index 050144d20..e2e8c7fdf 100644 --- a/agent/self/utils/logger.go +++ b/agent/self/utils/logger.go @@ -7,16 +7,14 @@ import ( ) var ( - selfLogger *logger.Logger + SelfLogger *logger.Logger loggerOnceInstance sync.Once ) -// CreateLogger returns a single instance of a Logger configured to save logs to a rotating file. -func CreateLogger(filename string) *logger.Logger { +func InitLogger(filename string) { loggerOnceInstance.Do(func() { - selfLogger = logger.NewLogger( + SelfLogger = logger.NewLogger( &logger.Config{Format: "text", Level: 100, Output: filename, Retries: 3, Wait: 5}, ) }) - return selfLogger } diff --git a/agent/self/utils/services.go b/agent/self/utils/services.go index 38f7b37cd..b8f273306 100644 --- a/agent/self/utils/services.go +++ b/agent/self/utils/services.go @@ -6,15 +6,10 @@ import ( "strings" ) -// CheckIfServiceIsActive checks if a service is active or running func CheckIfServiceIsActive(serv string) (bool, error) { var errB bool var output string - - path, err := GetMyPath() - if err != nil { - return false, fmt.Errorf("error getting current path: %v", err) - } + path := GetMyPath() switch runtime.GOOS { case "windows": @@ -29,7 +24,7 @@ func CheckIfServiceIsActive(serv string) (bool, error) { return false, nil } - serviceStatus := strings.ToLower(strings.TrimSpace(string(output))) + serviceStatus := strings.ToLower(strings.TrimSpace(output)) if runtime.GOOS == "linux" { return serviceStatus == "active", nil } else if runtime.GOOS == "windows" { @@ -39,13 +34,8 @@ func CheckIfServiceIsActive(serv string) (bool, error) { return false, fmt.Errorf("unsupported operating system") } -// RestartService restarts a service func RestartService(serv string) error { - path, err := GetMyPath() - if err != nil { - return fmt.Errorf("error getting current path: %v", err) - } - + path := GetMyPath() isRunning, err := CheckIfServiceIsActive(serv) if err != nil { return fmt.Errorf("error checking if %s service is active: %v", serv, err) @@ -81,10 +71,7 @@ func RestartService(serv string) error { } func StopService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } + path := GetMyPath() switch runtime.GOOS { case "windows": err := Execute("sc", path, "stop", name) diff --git a/agent/self/utils/timestamp.go b/agent/self/utils/timestamp.go deleted file mode 100644 index e33aa0f2a..000000000 --- a/agent/self/utils/timestamp.go +++ /dev/null @@ -1,8 +0,0 @@ -package utils - -import "time" - -func GetCurrentTime() string { - t := time.Now() - return t.Format("20060102150405") -} diff --git a/agent/serv/clean-old.go b/agent/serv/clean-old.go new file mode 100644 index 000000000..1db7626dc --- /dev/null +++ b/agent/serv/clean-old.go @@ -0,0 +1,65 @@ +package serv + +import ( + "fmt" + "os" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +func CleanOldServices(cnf *config.Config) { + oldVersion := false + + isUpdaterINstalled, err := utils.CheckIfServiceIsInstalled("UTMStackUpdater") + if err != nil { + utils.Logger.ErrorF("Error checking if service is installed: %v", err) + } + + if isUpdaterINstalled { + oldVersion = true + err = utils.StopService("UTMStackUpdater") + if err != nil { + utils.Logger.ErrorF("Error stopping service: %v", err) + } + + err = utils.UninstallService("UTMStackUpdater") + if err != nil { + utils.Logger.ErrorF("Error uninstalling service: %v", err) + } + } + + isRedlineInstalled, err := utils.CheckIfServiceIsInstalled("UTMStackRedline") + if err != nil { + utils.Logger.ErrorF("Error checking if service is installed: %v", err) + } + + if isRedlineInstalled { + oldVersion = true + err = utils.StopService("UTMStackRedline") + if err != nil { + utils.Logger.ErrorF("Error stopping service: %v", err) + } + + err = utils.UninstallService("UTMStackRedline") + if err != nil { + utils.Logger.ErrorF("Error uninstalling service: %v", err) + } + } + + if oldVersion { + headers := map[string]string{ + "key": cnf.AgentKey, + "id": fmt.Sprintf("%v", cnf.AgentID), + "type": "agent", + } + + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, fmt.Sprintf(config.UpdaterSelf, "")), headers, fmt.Sprintf(config.UpdaterSelf, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + utils.Logger.ErrorF("error downloading updater: %v", err) + return + } + + os.Remove(fmt.Sprintf(config.UpdaterSelf, "")) + os.Rename(fmt.Sprintf(config.UpdaterSelf, "_new"), fmt.Sprintf(config.UpdaterSelf, "")) + } +} diff --git a/agent/agent/serv/config.go b/agent/serv/config.go similarity index 91% rename from agent/agent/serv/config.go rename to agent/serv/config.go index f4e55ef55..90f9c683c 100644 --- a/agent/agent/serv/config.go +++ b/agent/serv/config.go @@ -10,6 +10,7 @@ func GetConfigServ() *service.Config { Name: "UTMStackAgent", DisplayName: "UTMStack Agent", Description: "UTMStack Agent Service", + Arguments: []string{"run"}, } return svcConfig diff --git a/agent/agent/serv/install.go b/agent/serv/install.go similarity index 50% rename from agent/agent/serv/install.go rename to agent/serv/install.go index 79bba16eb..06ab38a06 100644 --- a/agent/agent/serv/install.go +++ b/agent/serv/install.go @@ -1,25 +1,29 @@ package serv import ( + "fmt" + "os" + "github.com/kardianos/service" - "github.com/threatwinds/logger" ) -func InstallService(h *logger.Logger) { +func InstallService() { svcConfig := GetConfigServ() prg := new(program) newService, err := service.New(prg, svcConfig) if err != nil { - h.Fatal("error creating new service: %v", err) + fmt.Println("\nError creating new service: ", err) + os.Exit(1) } err = newService.Install() if err != nil { - h.Fatal("error installing new service: %v", err) + fmt.Println("\nError installing new service: ", err) + os.Exit(1) } - // Start the service after installing it err = newService.Start() if err != nil { - h.Fatal("error starting new service: %v", err) + fmt.Println("\nError starting new service: ", err) + os.Exit(1) } } diff --git a/agent/serv/run.go b/agent/serv/run.go new file mode 100644 index 000000000..138259931 --- /dev/null +++ b/agent/serv/run.go @@ -0,0 +1,19 @@ +package serv + +import ( + "github.com/kardianos/service" + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +func RunService() { + svcConfig := GetConfigServ() + p := new(program) + newService, err := service.New(p, svcConfig) + if err != nil { + utils.Logger.Fatal("error creating new service: %v", err) + } + err = newService.Run() + if err != nil { + utils.Logger.Fatal("error running new service: %v", err) + } +} diff --git a/agent/serv/service.go b/agent/serv/service.go new file mode 100644 index 000000000..a6c4c4226 --- /dev/null +++ b/agent/serv/service.go @@ -0,0 +1,62 @@ +package serv + +import ( + "context" + "os" + "os/signal" + "strconv" + "syscall" + + "github.com/kardianos/service" + pb "github.com/utmstack/UTMStack/agent/agent/agent" + "github.com/utmstack/UTMStack/agent/agent/collectors" + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/logservice" + "github.com/utmstack/UTMStack/agent/agent/modules" + "github.com/utmstack/UTMStack/agent/agent/updates" + "github.com/utmstack/UTMStack/agent/agent/utils" + "google.golang.org/grpc/metadata" +) + +type program struct{} + +func (p *program) Start(s service.Service) error { + go p.run() + return nil +} + +func (p *program) Stop(s service.Service) error { + return nil +} + +func (p *program) run() { + utils.InitLogger(config.ServiceLogFile) + cnf, err := config.GetCurrentConfig() + if err != nil { + utils.Logger.Fatal("error getting config: %v", err) + } + + CleanOldServices(cnf) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx = metadata.AppendToOutgoingContext(ctx, "key", cnf.AgentKey) + ctx = metadata.AppendToOutgoingContext(ctx, "id", strconv.Itoa(int(cnf.AgentID))) + ctx = metadata.AppendToOutgoingContext(ctx, "type", "agent") + + go pb.IncidentResponseStream(cnf, ctx) + go pb.StartPing(cnf, ctx) + + logProcessor := logservice.GetLogProcessor() + go logProcessor.ProcessLogs(cnf, ctx) + + go pb.UpdateAgent(cnf, ctx) + go modules.StartModules() + collectors.LogsReader() + + go updates.UpdateDependencies(cnf) + + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) + <-signals +} diff --git a/agent/agent/serv/uninstall.go b/agent/serv/uninstall.go similarity index 50% rename from agent/agent/serv/uninstall.go rename to agent/serv/uninstall.go index fe9d6edcd..18354d246 100644 --- a/agent/agent/serv/uninstall.go +++ b/agent/serv/uninstall.go @@ -1,18 +1,16 @@ package serv import ( - "github.com/threatwinds/logger" "github.com/utmstack/UTMStack/agent/agent/utils" ) -func UninstallService(h *logger.Logger) { - // Uninstall service +func UninstallService() { err := utils.StopService("UTMStackAgent") if err != nil { - h.Fatal("error stopping UTMStackAgent: %v", err) + utils.Logger.Fatal("error stopping UTMStackAgent: %v", err) } err = utils.UninstallService("UTMStackAgent") if err != nil { - h.Fatal("error uninstalling UTMStackAgent: %v", err) + utils.Logger.Fatal("error uninstalling UTMStackAgent: %v", err) } } diff --git a/agent/agent/templates/filebeat.yml b/agent/templates/filebeat.yml similarity index 100% rename from agent/agent/templates/filebeat.yml rename to agent/templates/filebeat.yml diff --git a/agent/agent/templates/winlogbeat.yml b/agent/templates/winlogbeat.yml similarity index 100% rename from agent/agent/templates/winlogbeat.yml rename to agent/templates/winlogbeat.yml diff --git a/agent/updater/README.md b/agent/updater/README.md deleted file mode 100644 index 253341f5b..000000000 --- a/agent/updater/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# UTMStack Updater Service -UTMStack Updater Service is a crucial component of the UTMStack Agent. This service is responsible for monitoring updates for all UTMStack Agent services. If a new update is available, the UTMStack Updater Service will automatically download and install it. - -### Features -- Automatic Updates: The service regularly checks for updates to all UTMStack Agent services. If an update is available, it is downloaded and installed automatically, ensuring that your UTMStack Agent is always up-to-date with the latest features and security patches. - -- Logging: The service logs all its activities, making it easy to track its operations and troubleshoot any issues that may arise. - -- Service Management: The UTMStack Updater Service can be installed or uninstalled as needed. This provides flexibility in managing the services on your system. \ No newline at end of file diff --git a/agent/updater/configuration/config.go b/agent/updater/configuration/config.go deleted file mode 100644 index c3e47b1a1..000000000 --- a/agent/updater/configuration/config.go +++ /dev/null @@ -1,42 +0,0 @@ -package configuration - -import ( - "os" - "path/filepath" - - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -type Config struct { - Server string `yaml:"server"` - AgentID uint `yaml:"agent-id"` - AgentKey string `yaml:"agent-key"` - SkipCertValidation bool `yaml:"insecure"` -} - -type Environment struct { - Branch string `yaml:"branch"` -} - -// ReadEnv reads the environment file -// If the file does not exist, it returns a default environment with release branch -// If the file exists, it returns the environment -func ReadEnv() (string, error) { - var env Environment - path, err := utils.GetMyPath() - if err != nil { - return "", err - } - - path = filepath.Join(path, "env.yml") - - if _, err = os.Stat(path); os.IsNotExist(err) { - return "release", nil - } else { - err = utils.ReadYAML(path, &env) - if err != nil { - return "", err - } - } - return env.Branch, nil -} diff --git a/agent/updater/configuration/const.go b/agent/updater/configuration/const.go deleted file mode 100644 index 2e89a5c31..000000000 --- a/agent/updater/configuration/const.go +++ /dev/null @@ -1,70 +0,0 @@ -package configuration - -import ( - "path/filepath" - "runtime" - "time" - - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -const ( - SERV_NAME = "UTMStackUpdater" - SERV_LOG = "utmstack_updater.log" - SERV_LOCK = "utmstack_updater.lock" - MASTERVERSIONENDPOINT = "/management/info" - Bucket = "https://cdn.utmstack.com/agent_updates/" - CHECK_EVERY = 5 * time.Minute -) - -type ServiceAttribt struct { - ServName string - ServBin string - ServLock string -} - -// GetServAttr returns a map of ServiceAttribt -func GetServAttr() map[string]ServiceAttribt { - serAttr := map[string]ServiceAttribt{ - "agent": {ServName: "UTMStackAgent", ServBin: "utmstack_agent_service", ServLock: "utmstack_agent.lock"}, - "updater": {ServName: "UTMStackUpdater", ServBin: "utmstack_updater_self", ServLock: "utmstack_updater.lock"}, - "redline": {ServName: "UTMStackRedline", ServBin: "utmstack_redline_service", ServLock: "utmstack_redline.lock"}, - } - - switch runtime.GOOS { - case "windows": - for code, att := range serAttr { - att.ServBin += ".exe" - serAttr[code] = att - } - } - - return serAttr -} - -// GetAgentBin returns the agent binary name -func GetAgentBin() string { - bin := "utmstack_agent_service" - if runtime.GOOS == "windows" { - bin = bin + ".exe" - } - return bin -} - -// GetCertPath returns the path to the certificate -func GetCertPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "utm.crt") -} - -// GetKeyPath returns the path to the key -func GetKeyPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "utm.key") -} - -// GetCaPath returns the path to the CA -func GetCaPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "ca.crt") -} diff --git a/agent/updater/go.mod b/agent/updater/go.mod deleted file mode 100644 index 71f2464b2..000000000 --- a/agent/updater/go.mod +++ /dev/null @@ -1,43 +0,0 @@ -module github.com/utmstack/UTMStack/agent/updater - -go 1.22.4 - -toolchain go1.23.4 - -require ( - github.com/kardianos/service v1.2.2 - github.com/threatwinds/logger v1.1.12 - gopkg.in/yaml.v2 v2.4.0 -) - -require ( - github.com/bytedance/sonic v1.12.1 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.0 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/agent/updater/go.sum b/agent/updater/go.sum deleted file mode 100644 index c0e35a1ff..000000000 --- a/agent/updater/go.sum +++ /dev/null @@ -1,99 +0,0 @@ -github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= -github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= -github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= -github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= -github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= -github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= -github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= -github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -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= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= -golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/agent/updater/main.go b/agent/updater/main.go deleted file mode 100644 index 0a7ce9ea5..000000000 --- a/agent/updater/main.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - "path/filepath" - "time" - - "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/serv" - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -func main() { - path, err := utils.GetMyPath() - if err != nil { - log.Fatalf("failed to get current path: %v", err) - } - - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) - - if len(os.Args) > 1 { - mode := os.Args[1] - switch mode { - case "run": - serv.RunService(h) - case "install": - h.Info("Installing UTMStack Updater service...") - - if isInstalled, err := utils.CheckIfServiceIsInstalled(configuration.SERV_NAME); err != nil { - h.Fatal("error checking %s service: %v", configuration.SERV_NAME, err) - } else if isInstalled { - h.Fatal("%s is already installed", configuration.SERV_NAME) - } - - serv.InstallService(h) - h.Info("UTMStack Updater service installed correctly.") - time.Sleep(5 * time.Second) - os.Exit(0) - - case "uninstall": - h.Info("Uninstalling UTMStack Updater service...") - serv.UninstallService(h) - h.Info("UTMStack Updater service uninstalled correctly.") - time.Sleep(5 * time.Second) - os.Exit(0) - - default: - fmt.Println("unknown option") - } - } else { - serv.RunService(h) - } -} diff --git a/agent/updater/serv/config.go b/agent/updater/serv/config.go deleted file mode 100644 index 05c68ddf9..000000000 --- a/agent/updater/serv/config.go +++ /dev/null @@ -1,17 +0,0 @@ -package serv - -import ( - "github.com/kardianos/service" - "github.com/utmstack/UTMStack/agent/updater/configuration" -) - -// GetConfigServ creates and returns a pointer to a service configuration structure. -func GetConfigServ() *service.Config { - svcConfig := &service.Config{ - Name: configuration.SERV_NAME, - DisplayName: "UTMStack Updater", - Description: "UTMStack Updater Service", - } - - return svcConfig -} diff --git a/agent/updater/serv/install.go b/agent/updater/serv/install.go deleted file mode 100644 index 297aecdae..000000000 --- a/agent/updater/serv/install.go +++ /dev/null @@ -1,31 +0,0 @@ -package serv - -import ( - "fmt" - - "github.com/kardianos/service" - "github.com/threatwinds/logger" -) - -// InstallService installs the service in the system and starts it -func InstallService(utmLogger *logger.Logger) { - svcConfig := GetConfigServ() - prg := new(program) - newService, err := service.New(prg, svcConfig) - if err != nil { - fmt.Printf("error creating new service: %v", err) - utmLogger.Fatal("error creating new service: %v", err) - } - err = newService.Install() - if err != nil { - fmt.Printf("error installing new service: %v", err) - utmLogger.Fatal("error installing new service: %v", err) - } - - // Start the service after installing it - err = newService.Start() - if err != nil { - fmt.Printf("error starting new service: %v", err) - utmLogger.Fatal("error starting new service: %v", err) - } -} diff --git a/agent/updater/serv/run.go b/agent/updater/serv/run.go deleted file mode 100644 index 5581325d2..000000000 --- a/agent/updater/serv/run.go +++ /dev/null @@ -1,20 +0,0 @@ -package serv - -import ( - "github.com/kardianos/service" - "github.com/threatwinds/logger" -) - -// RunService runs the service in the system -func RunService(utmLogger *logger.Logger) { - svcConfig := GetConfigServ() - prg := new(program) - newService, err := service.New(prg, svcConfig) - if err != nil { - utmLogger.Fatal("error creating new service: %v", err) - } - err = newService.Run() - if err != nil { - utmLogger.Fatal("error running new service: %v", err) - } -} diff --git a/agent/updater/serv/service.go b/agent/updater/serv/service.go deleted file mode 100644 index 6f74b2e7a..000000000 --- a/agent/updater/serv/service.go +++ /dev/null @@ -1,63 +0,0 @@ -package serv - -import ( - "log" - "os" - "os/signal" - "path/filepath" - "syscall" - "time" - - "github.com/kardianos/service" - "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/updates" - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -type program struct{} - -func (p *program) Start(s service.Service) error { - go p.run() - return nil -} - -func (p *program) Stop(s service.Service) error { - return nil -} - -func (p *program) run() { - // Get current path - path, err := utils.GetMyPath() - if err != nil { - log.Fatalf("Failed to get current path: %v", err) - } - - // Configuring log saving - var h = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) - - for { - isActive, err := utils.CheckIfServiceIsActive(configuration.GetServAttr()["agent"].ServName) - if err != nil { - time.Sleep(time.Second * 5) - h.ErrorF("error checking if %s service is active: %v", configuration.GetServAttr()["agent"].ServName, err) - continue - } else if !isActive { - time.Sleep(time.Second * 5) - continue - } - break - } - - var cnf configuration.Config - err = utils.ReadYAML(filepath.Join(path, "config.yml"), &cnf) - if err != nil { - h.Fatal("error reading config.yml: %v", err) - } - - go updates.UpdateServices(cnf, h) - - signals := make(chan os.Signal, 1) - signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) - <-signals - -} diff --git a/agent/updater/serv/uninstall.go b/agent/updater/serv/uninstall.go deleted file mode 100644 index c66b742a5..000000000 --- a/agent/updater/serv/uninstall.go +++ /dev/null @@ -1,20 +0,0 @@ -package serv - -import ( - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -// UninstallService uninstalls the service in the system -func UninstallService(utmLogger *logger.Logger) { - // Uninstall service - err := utils.StopService(configuration.SERV_NAME) - if err != nil { - utmLogger.Fatal("error stopping %s: %v", configuration.SERV_NAME, err) - } - err = utils.UninstallService(configuration.SERV_NAME) - if err != nil { - utmLogger.Fatal("error uninstalling %s: %v", configuration.SERV_NAME, err) - } -} diff --git a/agent/updater/updates/schema.go b/agent/updater/updates/schema.go deleted file mode 100644 index a36f0d280..000000000 --- a/agent/updater/updates/schema.go +++ /dev/null @@ -1,29 +0,0 @@ -package updates - -import "encoding/json" - -type InfoResponse struct { - Display string `json:"display-ribbon-on-profiles"` - Git json.RawMessage `json:"git"` - Build Build `json:"build"` - Profiles []string `json:"activeProfiles"` -} - -type Build struct { - Artifact string `json:"artifact"` - Name string `json:"name"` - Time string `json:"time"` - Version string `json:"version"` - Group string `json:"group"` -} - -type DataVersions struct { - Versions []Version `json:"versions"` -} - -type Version struct { - MasterVersion string `json:"master_version"` - AgentVersion string `json:"agent_version"` - UpdaterVersion string `json:"updater_version"` - RedlineVersion string `json:"redline_version"` -} diff --git a/agent/updater/updates/service.go b/agent/updater/updates/service.go deleted file mode 100644 index 5c4953934..000000000 --- a/agent/updater/updates/service.go +++ /dev/null @@ -1,164 +0,0 @@ -package updates - -import ( - "fmt" - "path/filepath" - "runtime" - "sync" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -type UTMServices struct { - MasterVersion string - CurrentVersions Version - LatestVersions Version - ServAttr map[string]configuration.ServiceAttribt -} - -func (u *UTMServices) UpdateCurrentMasterVersion(cnf configuration.Config) error { - masterVersion, err := getMasterVersion(cnf.Server, cnf.SkipCertValidation) - if err != nil { - return fmt.Errorf("error getting master version: %v", err) - } - u.MasterVersion = masterVersion - return nil -} - -func (u *UTMServices) UpdateCurrentVersions() error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - err = utils.ReadJson(filepath.Join(path, "versions.json"), &u.CurrentVersions) - if err != nil { - return fmt.Errorf("error reading current versions.json: %v", err) - } - - return nil -} - -func (u *UTMServices) UpdateLatestVersions(env string, utmLogger *logger.Logger) error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - err = utils.DownloadFile(configuration.Bucket+env+"/versions.json", filepath.Join(path, "versions.json"), utmLogger) - if err != nil { - return fmt.Errorf("error downloading latest versions.json: %v", err) - } - - newData := DataVersions{} - err = utils.ReadJson(filepath.Join(path, "versions.json"), &newData) - if err != nil { - return fmt.Errorf("error reading latest versions.json: %v", err) - } - - u.LatestVersions = getLatestVersion(newData, u.MasterVersion) - err = utils.WriteJSON(filepath.Join(path, "versions.json"), &u.LatestVersions) - if err != nil { - return fmt.Errorf("error writing versions.json: %v", err) - } - - return nil -} - -func (u *UTMServices) CheckUpdates(env string, utmLogger *logger.Logger) error { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - - if isVersionGreater(u.CurrentVersions.RedlineVersion, u.LatestVersions.RedlineVersion) { - err := u.UpdateService(path, env, "redline", u.LatestVersions.RedlineVersion, utmLogger) - if err != nil { - return fmt.Errorf("error updating UTMStackRedline service: %v", err) - } - utmLogger.Info("UTMStackRedline service updated correctly") - } - - if isVersionGreater(u.CurrentVersions.AgentVersion, u.LatestVersions.AgentVersion) { - err := u.UpdateService(path, env, "agent", u.LatestVersions.AgentVersion, utmLogger) - if err != nil { - return fmt.Errorf("error updating UTMStackAgent service: %v", err) - } - utmLogger.Info("UTMStackAgent service updated correctly") - } - - if isVersionGreater(u.CurrentVersions.UpdaterVersion, u.LatestVersions.UpdaterVersion) { - err := u.UpdateService(path, env, "updater", u.LatestVersions.UpdaterVersion, utmLogger) - if err != nil { - return fmt.Errorf("error updating UTMStackUpdater service: %v", err) - } - utmLogger.Info("UTMStackUpdater service updated correctly") - } - - return nil -} - -func (u *UTMServices) UpdateService(path string, env string, servCode string, newVers string, utmLogger *logger.Logger) error { - attr := u.ServAttr[servCode] - err := utils.CreatePathIfNotExist(filepath.Join(path, "locks")) - if err != nil { - return fmt.Errorf("error creating locks path: %v", err) - } - - err = utils.SetLock(filepath.Join(path, "locks", attr.ServLock)) - if err != nil { - return fmt.Errorf("error setting lock %s: %v", attr.ServLock, err) - } - - if servCode == "updater" { - utils.Execute(filepath.Join(path, attr.ServBin), path) - } else { - err = utils.StopService(attr.ServName) - if err != nil { - return fmt.Errorf("error stoping %s service: %v", attr.ServName, err) - } - - url := configuration.Bucket + env + "/" + servCode + "_service/v" + newVers + "/" + attr.ServBin + "?time=" + utils.GetCurrentTime() - err = utils.DownloadFile(url, filepath.Join(path, attr.ServBin), utmLogger) - if err != nil { - return fmt.Errorf("error downloading new %s: %v", attr.ServBin, err) - } - - if runtime.GOOS == "linux" { - if err = utils.Execute("chmod", path, "-R", "777", attr.ServBin); err != nil { - return fmt.Errorf("error executing chmod: %v", err) - } - } - - err = utils.RestartService(attr.ServName) - if err != nil { - return fmt.Errorf("error restarting %s service: %v", attr.ServName, err) - } - } - - err = utils.RemoveLock(filepath.Join(path, "locks", attr.ServLock)) - if err != nil { - return fmt.Errorf("error removing lock %s: %v", attr.ServLock, err) - } - - return nil -} - -var ( - utmServ UTMServices - utmServOnce sync.Once -) - -func GetUTMServicesInstance() UTMServices { - utmServOnce.Do(func() { - utmServ = UTMServices{ - MasterVersion: "", - CurrentVersions: Version{}, - LatestVersions: Version{}, - ServAttr: configuration.GetServAttr(), - } - }) - return utmServ -} diff --git a/agent/updater/updates/update.go b/agent/updater/updates/update.go deleted file mode 100644 index cfed20ba1..000000000 --- a/agent/updater/updates/update.go +++ /dev/null @@ -1,48 +0,0 @@ -package updates - -import ( - "time" - - "github.com/threatwinds/logger" - "github.com/utmstack/UTMStack/agent/updater/configuration" -) - -func UpdateServices(cnf configuration.Config, utmLogger *logger.Logger) { - utmServices := GetUTMServicesInstance() - - env, err := configuration.ReadEnv() - if err != nil { - utmLogger.Fatal("error reading environment configuration: %v", err) - } - - utmLogger.Info("enviroment: %v", env) - - for { - time.Sleep(configuration.CHECK_EVERY) - - err = utmServices.UpdateCurrentMasterVersion(cnf) - if err != nil { - utmLogger.ErrorF("error updating current master version: %v", err) - continue - } - - err = utmServices.UpdateCurrentVersions() - if err != nil { - utmLogger.ErrorF("error updating current versions: %v", err) - continue - } - - err = utmServices.UpdateLatestVersions(env, utmLogger) - if err != nil { - utmLogger.ErrorF("error updating latest versions: %v", err) - continue - } - - err = utmServices.CheckUpdates(env, utmLogger) - if err != nil { - utmLogger.ErrorF("error updating services: %v", err) - continue - } - - } -} diff --git a/agent/updater/updates/version.go b/agent/updater/updates/version.go deleted file mode 100644 index 5f1f6c078..000000000 --- a/agent/updater/updates/version.go +++ /dev/null @@ -1,85 +0,0 @@ -package updates - -import ( - "crypto/tls" - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -// getLatestVersion returns the latest version of the service -func getLatestVersion(versions DataVersions, masterVersions string) Version { - for _, vers := range versions.Versions { - if vers.MasterVersion == masterVersions { - return vers - } - } - return Version{} -} - -// getMasterVersion returns the master version of the service -func getMasterVersion(ip string, skip bool) (string, error) { - config := &tls.Config{InsecureSkipVerify: skip} - if !skip { - var err error - config, err = utils.LoadTLSCredentials(configuration.GetCertPath()) - if err != nil { - return "", fmt.Errorf("error loading tls credentials: %v", err) - } - } - resp, status, err := utils.DoReq[InfoResponse]("https://"+ip+configuration.MASTERVERSIONENDPOINT, nil, http.MethodGet, map[string]string{}, config) - if err != nil { - return "", err - } else if status != http.StatusOK { - return "", fmt.Errorf("status code %d: %v", status, resp) - } - return resp.Build.Version, nil -} - -// isVersionGreater returns true if newVersion is greater than oldVersion -func isVersionGreater(oldVersion, newVersion string) bool { - oldParts := strings.Split(oldVersion, ".") - newParts := strings.Split(newVersion, ".") - - for i, oldPart := range oldParts { - nOld, _ := strconv.Atoi(oldPart) - if i < len(newParts) { - nNew, _ := strconv.Atoi(newParts[i]) - if nNew > nOld { - return true - } else if nNew < nOld { - return false - } - } - } - return false -} - -/* -func isNewOrEqualVersion(oldVersion, newVersion string) bool { - oldParts := strings.Split(oldVersion, ".") - newParts := strings.Split(newVersion, ".") - - minLength := len(oldParts) - if len(newParts) < minLength { - minLength = len(newParts) - } - - for i := 0; i < minLength; i++ { - nOld, _ := strconv.Atoi(oldParts[i]) - nNew, _ := strconv.Atoi(newParts[i]) - - if nNew > nOld { - return true - } else if nNew < nOld { - return false - } - } - - return len(newParts) >= len(oldParts) -} -*/ diff --git a/agent/updater/utils/cmd.go b/agent/updater/utils/cmd.go deleted file mode 100644 index 686c93f95..000000000 --- a/agent/updater/utils/cmd.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import ( - "errors" - "os/exec" - "unicode/utf8" -) - -// ExecuteWithResult executes a command and returns the output -func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { - cmd := exec.Command(c, arg...) - - cmd.Dir = dir - if errors.Is(cmd.Err, exec.ErrDot) { - cmd.Err = nil - } - - out, err := cmd.Output() - if err != nil { - return string(out[:]) + err.Error(), true - } - - validUtf8Out := cleanString(string(out[:])) - - return validUtf8Out, false -} - -// Execute executes a command without returning the output -func Execute(c string, dir string, arg ...string) error { - cmd := exec.Command(c, arg...) - cmd.Dir = dir - - return cmd.Run() -} - -// cleanString cleans a string from invalid utf8 characters -func cleanString(s string) string { - v := make([]rune, 0, len(s)) - for i, r := range s { - if r == utf8.RuneError { - _, size := utf8.DecodeRuneInString(s[i:]) - if size == 1 { - v = append(v, '?') - continue - } - } - v = append(v, r) - } - return string(v) -} diff --git a/agent/updater/utils/delay.go b/agent/updater/utils/delay.go deleted file mode 100644 index 61193d39b..000000000 --- a/agent/updater/utils/delay.go +++ /dev/null @@ -1,12 +0,0 @@ -package utils - -import "time" - -// IncrementReconnectDelay increments the delay for reconnecting to the server -func IncrementReconnectDelay(delay time.Duration, maxReconnectDelay time.Duration) time.Duration { - delay *= 2 - if delay > maxReconnectDelay { - delay = maxReconnectDelay - } - return delay -} diff --git a/agent/updater/utils/download.go b/agent/updater/utils/download.go deleted file mode 100644 index d313e8054..000000000 --- a/agent/updater/utils/download.go +++ /dev/null @@ -1,43 +0,0 @@ -package utils - -import ( - "io" - "net/http" - "os" - "time" - - "github.com/threatwinds/logger" -) - -const ( - reconnectDelay = 5 * time.Minute -) - -// DownloadFile downloads a file from a URL and saves it to disk. Returns an error on failure. -func DownloadFile(url string, fileName string, utmLogger *logger.Logger) error { - var resp *http.Response - var err error - - for { - resp, err = http.Get(url) - if err != nil || resp.StatusCode != http.StatusOK { - if resp != nil { - resp.Body.Close() - } - utmLogger.ErrorF("error downloading file from %s: %v", url, err) - time.Sleep(reconnectDelay) - continue - } - break - } - defer resp.Body.Close() - - out, err := os.Create(fileName) - if err != nil { - return err - } - defer out.Close() - - _, err = io.Copy(out, resp.Body) - return err -} diff --git a/agent/updater/utils/files.go b/agent/updater/utils/files.go deleted file mode 100644 index 1006b2c0f..000000000 --- a/agent/updater/utils/files.go +++ /dev/null @@ -1,99 +0,0 @@ -package utils - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "gopkg.in/yaml.v2" -) - -// GetMyPath returns the directory path where the currently running executable is located. -// Returns a string representing the directory path, and an error if any error occurs during the process. -func GetMyPath() (string, error) { - ex, err := os.Executable() - if err != nil { - return "", err - } - exPath := filepath.Dir(ex) - return exPath, nil -} - -// ReadYAML reads the YAML data from the specified file URL and deserializes it into the provided result interface{}. -// Returns an error if any error occurs during the process. -func ReadYAML(path string, result interface{}) error { - file, err := os.Open(path) - if err != nil { - return err - } - defer file.Close() - d := yaml.NewDecoder(file) - if err := d.Decode(result); err != nil { - return err - } - return nil -} - -// ReadJson reads the json data from the specified file URL and unmarshal it into the provided result interface{}. -// Returns an error if any error occurs during the process. -func ReadJson(fileName string, data interface{}) error { - content, err := os.ReadFile(fileName) - if err != nil { - return err - } - err = json.Unmarshal(content, data) - if err != nil { - return err - } - return nil -} - -// WriteJSON writes the provided data interface{} to the specified file URL in JSON format. -func WriteJSON(path string, data interface{}) error { - jsonData, err := json.MarshalIndent(data, "", " ") - if err != nil { - return err - } - - err = writeToFile(path, string(jsonData[:])) - if err != nil { - return err - } - - return nil -} - -// CreatePathIfNotExist creates a specific path if not exist -func CreatePathIfNotExist(path string) error { - if _, err := os.Stat(path); os.IsNotExist(err) { - if err := os.Mkdir(path, 0755); err != nil { - return fmt.Errorf("error creating path: %v", err) - } - } else if err != nil { - return fmt.Errorf("error checking path: %v", err) - } - return nil -} - -// CheckIfPathExist checks if a specific path exists -func CheckIfPathExist(path string) bool { - if _, err := os.Stat(path); os.IsNotExist(err) { - return false - } - return true -} - -// writeToFile writes the provided body string to the specified file URL. -func writeToFile(fileName string, body string) error { - file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) - - if err != nil { - return err - } - - defer file.Close() - - _, err = file.WriteString(body) - return err -} diff --git a/agent/updater/utils/lock.go b/agent/updater/utils/lock.go deleted file mode 100644 index 261ee0415..000000000 --- a/agent/updater/utils/lock.go +++ /dev/null @@ -1,31 +0,0 @@ -package utils - -import ( - "fmt" - "os" -) - -// SetLock creates a lock file -func SetLock(lockdir string) error { - if !CheckIfPathExist(lockdir) { - file, err := os.OpenFile(lockdir, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) - if err != nil { - return err - } - defer file.Close() - } - return nil -} - -// RemoveLock removes a lock file -func RemoveLock(lockdir string) error { - if CheckIfPathExist(lockdir) { - err := os.Remove(lockdir) - if err != nil { - return err - } - } else { - return fmt.Errorf("lock file %s not exists", lockdir) - } - return nil -} diff --git a/agent/updater/utils/logger.go b/agent/updater/utils/logger.go deleted file mode 100644 index 213f64a69..000000000 --- a/agent/updater/utils/logger.go +++ /dev/null @@ -1,22 +0,0 @@ -package utils - -import ( - "sync" - - "github.com/threatwinds/logger" -) - -var ( - agentLogger *logger.Logger - loggerOnceInstance sync.Once -) - -// CreateLogger returns a single instance of a Logger configured to save logs to a rotating file. -func CreateLogger(filename string) *logger.Logger { - loggerOnceInstance.Do(func() { - agentLogger = logger.NewLogger( - &logger.Config{Format: "text", Level: 100, Output: filename, Retries: 3, Wait: 5}, - ) - }) - return agentLogger -} diff --git a/agent/updater/utils/req.go b/agent/updater/utils/req.go deleted file mode 100644 index 5e8a639af..000000000 --- a/agent/updater/utils/req.go +++ /dev/null @@ -1,51 +0,0 @@ -package utils - -import ( - "bytes" - "crypto/tls" - "encoding/json" - "io" - "net/http" -) - -// DoReq makes a request to the specified URL with the specified data, method and headers. -func DoReq[response any](url string, data []byte, method string, headers map[string]string, config *tls.Config) (response, int, error) { - req, err := http.NewRequest(method, url, bytes.NewBuffer(data)) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - - for k, v := range headers { - req.Header.Add(k, v) - } - - transp := &http.Transport{ - TLSClientConfig: config, - } - - client := &http.Client{Transport: transp} - - resp, err := client.Do(req) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - - var result response - - err = json.Unmarshal(body, &result) - if err != nil { - return *new(response), http.StatusInternalServerError, err - } - - if resp.StatusCode != http.StatusAccepted && resp.StatusCode != http.StatusOK { - return *new(response), http.StatusInternalServerError, err - } - - return result, resp.StatusCode, nil -} diff --git a/agent/updater/utils/services.go b/agent/updater/utils/services.go deleted file mode 100644 index 96d9b18f4..000000000 --- a/agent/updater/utils/services.go +++ /dev/null @@ -1,146 +0,0 @@ -package utils - -import ( - "fmt" - "os/exec" - "runtime" - "strings" -) - -// CheckIfServiceIsActive checks if a service is active or running -func CheckIfServiceIsActive(serv string) (bool, error) { - var errB bool - var output string - - path, err := GetMyPath() - if err != nil { - return false, fmt.Errorf("error getting current path: %v", err) - } - - switch runtime.GOOS { - case "windows": - output, errB = ExecuteWithResult("sc", path, "query", serv) - case "linux": - output, errB = ExecuteWithResult("systemctl", path, "is-active", serv) - default: - return false, fmt.Errorf("unknown operating system") - } - - if errB { - return false, nil - } - - serviceStatus := strings.ToLower(strings.TrimSpace(string(output))) - if runtime.GOOS == "linux" { - return serviceStatus == "active", nil - } else if runtime.GOOS == "windows" { - return strings.Contains(serviceStatus, "running"), nil - } - - return false, fmt.Errorf("unsupported operating system") -} - -// RestartService restarts a service -func RestartService(serv string) error { - path, err := GetMyPath() - if err != nil { - return fmt.Errorf("error getting current path: %v", err) - } - - isRunning, err := CheckIfServiceIsActive(serv) - if err != nil { - return fmt.Errorf("error checking if %s service is active: %v", serv, err) - } - - switch runtime.GOOS { - case "windows": - if isRunning { - err := Execute("sc", path, "stop", serv) - if err != nil { - return fmt.Errorf("error stopping service: %v", err) - } - } - err := Execute("sc", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - - case "linux": - if isRunning { - err := Execute("systemctl", path, "restart", serv) - if err != nil { - return fmt.Errorf("error restarting service: %v", err) - } - } else { - err := Execute("systemctl", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - } - } - return nil -} - -// StopService stops a service -func StopService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } - switch runtime.GOOS { - case "windows": - err := Execute("sc", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - case "linux": - err := Execute("systemctl", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - } - return nil -} - -// UninstallService uninstalls a service -func UninstallService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } - switch runtime.GOOS { - case "windows": - err := Execute("sc", path, "delete", name) - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - case "linux": - err := Execute("systemctl", path, "disable", name) - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - err = Execute("rm", "/etc/systemd/system/", "/etc/systemd/system/"+name+".service") - if err != nil { - return fmt.Errorf("error uninstalling service: %v", err) - } - } - return nil -} - -// CheckIfServiceIsInstalled checks if a service is installed -func CheckIfServiceIsInstalled(serv string) (bool, error) { - var cmd *exec.Cmd - switch runtime.GOOS { - case "windows": - cmd = exec.Command("sc", "query", serv) - case "linux": - cmd = exec.Command("systemctl", "status", serv) - default: - return false, fmt.Errorf("operative system unknown") - } - - if err := cmd.Run(); err != nil { - return false, nil - } - return true, nil -} diff --git a/agent/updater/utils/timestamp.go b/agent/updater/utils/timestamp.go deleted file mode 100644 index 7fbb24f2e..000000000 --- a/agent/updater/utils/timestamp.go +++ /dev/null @@ -1,9 +0,0 @@ -package utils - -import "time" - -// GetCurrentTime returns the current time in the format YYYYMMDDHHMMSS -func GetCurrentTime() string { - t := time.Now() - return t.Format("20060102150405") -} diff --git a/agent/updates/dependencies.go b/agent/updates/dependencies.go new file mode 100644 index 000000000..948f721bb --- /dev/null +++ b/agent/updates/dependencies.go @@ -0,0 +1,60 @@ +package updates + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +func DownloadFirstDependencies(address string, authKey string, insecure bool) error { + headers := map[string]string{"connection-key": authKey} + + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, address, config.DependenciesPort, "version.json"), headers, "version.json", utils.GetMyPath(), insecure); err != nil { + return fmt.Errorf("error downloading version.json : %v", err) + } + + dependFiles := config.DependFiles + for _, file := range dependFiles { + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, address, config.DependenciesPort, file), headers, file, utils.GetMyPath(), insecure); err != nil { + return fmt.Errorf("error downloading file %s: %v", file, err) + } + } + + if err := handleDependenciesPostDownload(dependFiles); err != nil { + return err + } + + return nil + +} + +func handleDependenciesPostDownload(dependencies []string) error { + for _, file := range dependencies { + if strings.HasSuffix(file, ".zip") { + if err := utils.Unzip(filepath.Join(utils.GetMyPath(), file), utils.GetMyPath()); err != nil { + return fmt.Errorf("error unzipping dependencies: %v", err) + } + + if runtime.GOOS == "linux" { + if err := utils.Execute("chmod", utils.GetMyPath(), "-R", "777", fmt.Sprintf(config.UpdaterSelf, "")); err != nil { + return fmt.Errorf("error executing chmod on %s: %v", fmt.Sprintf(config.UpdaterSelf, ""), err) + } + } + + if err := os.Remove(filepath.Join(utils.GetMyPath(), file)); err != nil { + return fmt.Errorf("error removing file %s: %v", file, err) + } + } else if runtime.GOOS == "linux" { + if err := utils.Execute("chmod", utils.GetMyPath(), "-R", "777", file); err != nil { + return fmt.Errorf("error executing chmod on %s: %v", file, err) + } + } + } + + return nil +} diff --git a/agent/updates/update.go b/agent/updates/update.go new file mode 100644 index 000000000..d784d9817 --- /dev/null +++ b/agent/updates/update.go @@ -0,0 +1,73 @@ +package updates + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "time" + + "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/agent/models" + "github.com/utmstack/UTMStack/agent/agent/utils" +) + +const ( + checkEvery = 5 * time.Minute +) + +var currentVersion = models.Version{} + +func UpdateDependencies(cnf *config.Config) { + if utils.CheckIfPathExist(config.VersionPath) { + err := utils.ReadJson(config.VersionPath, ¤tVersion) + if err != nil { + utils.Logger.Fatal("error reading version file: %v", err) + } + } + + for { + time.Sleep(checkEvery) + + headers := map[string]string{ + "key": cnf.AgentKey, + "id": fmt.Sprintf("%v", cnf.AgentID), + "type": "agent", + } + + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, "version.json"), headers, "version_new.json", utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + utils.Logger.ErrorF("error downloading version.json: %v", err) + continue + } + newVersion := models.Version{} + err := utils.ReadJson(filepath.Join(utils.GetMyPath(), "version_new.json"), &newVersion) + if err != nil { + utils.Logger.ErrorF("error reading version file: %v", err) + continue + } + + if newVersion.Version != currentVersion.Version { + utils.Logger.Info("New version of agent found: %s", newVersion.Version) + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, fmt.Sprintf(config.ServiceFile, "")), headers, fmt.Sprintf(config.ServiceFile, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + utils.Logger.ErrorF("error downloading agent: %v", err) + continue + } + + currentVersion = newVersion + err = utils.WriteJSON(config.VersionPath, ¤tVersion) + if err != nil { + utils.Logger.ErrorF("error writing version file: %v", err) + continue + } + os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) + + if runtime.GOOS == "linux" { + if err = utils.Execute("chmod", utils.GetMyPath(), "-R", "777", filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.ServiceFile, "_new"))); err != nil { + utils.Logger.ErrorF("error executing chmod: %v", err) + } + } + + utils.Execute(fmt.Sprintf(config.UpdaterSelf, ""), utils.GetMyPath()) + } + } +} diff --git a/agent/agent/utils/address.go b/agent/utils/address.go similarity index 100% rename from agent/agent/utils/address.go rename to agent/utils/address.go diff --git a/agent/utils/banner.go b/agent/utils/banner.go new file mode 100644 index 000000000..cb7c45f59 --- /dev/null +++ b/agent/utils/banner.go @@ -0,0 +1,17 @@ +package utils + +import "fmt" + +func PrintBanner() { + banner := "\n" + + "..........................................................................\n" + + " _ _ _ _____ _ _ \n" + + " | | | | | | / ____| | | | | \n" + + " | | | | | |_ _ __ ___ | (___ | |_ __ _ ___ | | __ \n" + + " | | | | | __| | '_ ` _ \\ \\___ \\ | __| / _` | / __| | |/ / \n" + + " | |__| | | |_ | | | | | | ____) | | |_ | (_| | | (__ | < \n" + + " \\____/ \\__| |_| |_| |_| |_____/ \\__| \\__,_| \\___| |_|\\_\\ \n" + + ".........................................................................." + + fmt.Println(banner) +} diff --git a/agent/agent/utils/certs.go b/agent/utils/certs.go similarity index 100% rename from agent/agent/utils/certs.go rename to agent/utils/certs.go diff --git a/agent/agent/utils/cmd.go b/agent/utils/cmd.go similarity index 100% rename from agent/agent/utils/cmd.go rename to agent/utils/cmd.go diff --git a/agent/agent/utils/crypt.go b/agent/utils/crypt.go similarity index 100% rename from agent/agent/utils/crypt.go rename to agent/utils/crypt.go diff --git a/agent/agent/utils/delay.go b/agent/utils/delay.go similarity index 100% rename from agent/agent/utils/delay.go rename to agent/utils/delay.go diff --git a/agent/utils/download.go b/agent/utils/download.go new file mode 100644 index 000000000..ec350c51e --- /dev/null +++ b/agent/utils/download.go @@ -0,0 +1,53 @@ +package utils + +import ( + "fmt" + "io" + "net/http" + "os" + "path/filepath" +) + +func DownloadFile(url string, headers map[string]string, fileName string, path string, skipTls bool) error { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return fmt.Errorf("error creating new request: %v", err) + } + for key, value := range headers { + req.Header.Add(key, value) + } + + client := &http.Client{} + if !skipTls { + tlsConfig, err := LoadHTTPTLSCredentials(filepath.Join(GetMyPath(), "certs", "utm.crt")) + if err != nil { + return fmt.Errorf("failed to load TLS credentials: %v", err) + } + client.Transport = &http.Transport{ + TLSClientConfig: tlsConfig, + } + } + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("error sending request: %v", err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("expected status %d; got %d", http.StatusOK, resp.StatusCode) + } + + out, err := os.Create(filepath.Join(path, fileName)) + if err != nil { + return fmt.Errorf("error creating file: %v", err) + } + defer func() { _ = out.Close() }() + + _, err = io.Copy(out, resp.Body) + if err != nil { + return fmt.Errorf("error copying file: %v", err) + } + + return nil +} diff --git a/agent/agent/utils/files.go b/agent/utils/files.go similarity index 68% rename from agent/agent/utils/files.go rename to agent/utils/files.go index 56b9936f7..977b5689c 100644 --- a/agent/agent/utils/files.go +++ b/agent/utils/files.go @@ -12,40 +12,36 @@ import ( "gopkg.in/yaml.v2" ) -// GetMyPath returns the directory path where the currently running executable is located. -// Returns a string representing the directory path, and an error if any error occurs during the process. -func GetMyPath() (string, error) { +func GetMyPath() string { ex, err := os.Executable() if err != nil { - return "", err + return "" } exPath := filepath.Dir(ex) - return exPath, nil + return exPath } -// ReadYAML reads the YAML data from the specified file URL and deserializes it into the provided result interface{}. -// Returns an error if any error occurs during the process. func ReadYAML(path string, result interface{}) error { file, err := os.Open(path) if err != nil { return err } - defer file.Close() + defer func() { _ = file.Close() }() + d := yaml.NewDecoder(file) if err := d.Decode(result); err != nil { return err } + return nil } -func writeToFile(fileName string, body string) error { +func WriteStringToFile(fileName string, body string) error { file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) - if err != nil { return err } - - defer file.Close() + defer func() { _ = file.Close() }() _, err = file.WriteString(body) return err @@ -57,7 +53,7 @@ func WriteYAML(url string, data interface{}) error { return err } - err = writeToFile(url, string(config[:])) + err = WriteStringToFile(url, string(config)) if err != nil { return err } @@ -71,7 +67,7 @@ func WriteJSON(path string, data interface{}) error { return err } - err = writeToFile(path, string(jsonData[:])) + err = WriteStringToFile(path, string(jsonData)) if err != nil { return err } @@ -84,29 +80,28 @@ func ReadJson(fileName string, data interface{}) error { if err != nil { return err } + err = json.Unmarshal(content, data) if err != nil { return err } + return nil } -func GenerateFromTemplate(data interface{}, tfile string, cfile string) error { - _, fileName := filepath.Split(tfile) - ut, err := template.New(fileName).ParseFiles(tfile) - +func GenerateFromTemplate(data interface{}, templateFile string, configFile string) error { + _, fileName := filepath.Split(templateFile) + ut, err := template.New(fileName).ParseFiles(templateFile) if err != nil { return err } - writer, err := os.OpenFile(cfile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) - + writer, err := os.OpenFile(configFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) if err != nil { return err } err = ut.Execute(writer, data) - if err != nil { return err } @@ -114,10 +109,9 @@ func GenerateFromTemplate(data interface{}, tfile string, cfile string) error { return nil } -// CreatePathIfNotExist creates a specific path if not exist func CreatePathIfNotExist(path string) error { if _, err := os.Stat(path); os.IsNotExist(err) { - if err := os.Mkdir(path, 0755); err != nil { + if err := os.MkdirAll(path, 0755); err != nil { return fmt.Errorf("error creating path: %v", err) } } else if err != nil { diff --git a/agent/agent/utils/host.go b/agent/utils/host.go similarity index 100% rename from agent/agent/utils/host.go rename to agent/utils/host.go diff --git a/agent/agent/utils/log.go b/agent/utils/log.go similarity index 61% rename from agent/agent/utils/log.go rename to agent/utils/log.go index 14acda6e6..123518653 100644 --- a/agent/agent/utils/log.go +++ b/agent/utils/log.go @@ -1,36 +1,13 @@ package utils import ( - "fmt" "os" "path/filepath" "regexp" - "runtime" "strconv" "time" ) -func SentLog(msg string) error { - // Get current path - path, err := GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } - switch runtime.GOOS { - case "windows": - err := Execute("eventcreate", path, "/T", "INFORMATION", "/ID", "1000", "/SO", "UTMStackAgent", "/D", msg) - if err != nil { - return fmt.Errorf("%v", err) - } - case "linux": - err := Execute("logger", path, "-p", "syslog.info", msg) - if err != nil { - return fmt.Errorf("%v", err) - } - } - return nil -} - func FindLatestLog(path string, pattern *regexp.Regexp) (string, error) { files, err := os.ReadDir(path) if err != nil { diff --git a/agent/utils/logger.go b/agent/utils/logger.go new file mode 100644 index 000000000..1ae428c49 --- /dev/null +++ b/agent/utils/logger.go @@ -0,0 +1,20 @@ +package utils + +import ( + "sync" + + "github.com/threatwinds/logger" +) + +var ( + Logger *logger.Logger + loggerOnceInstance sync.Once +) + +func InitLogger(filename string) { + loggerOnceInstance.Do(func() { + Logger = logger.NewLogger( + &logger.Config{Format: "text", Level: 200, Output: filename, Retries: 3, Wait: 5}, + ) + }) +} diff --git a/agent/agent/utils/os.go b/agent/utils/os.go similarity index 100% rename from agent/agent/utils/os.go rename to agent/utils/os.go diff --git a/agent/utils/port.go b/agent/utils/port.go new file mode 100644 index 000000000..c194e12d5 --- /dev/null +++ b/agent/utils/port.go @@ -0,0 +1,29 @@ +package utils + +import ( + "fmt" + "net" + "time" +) + +func ArePortsReachable(ip string, ports ...string) error { + var conn net.Conn + var err error + +external: + for _, port := range ports { + for i := 0; i < 3; i++ { + conn, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%s", ip, port), 5*time.Second) + if err == nil { + conn.Close() + continue external + } + time.Sleep(5 * time.Second) + } + if err != nil { + return fmt.Errorf("cannot connect to %s on port %s: %v", ip, port, err) + } + } + + return nil +} diff --git a/agent/utils/req.go b/agent/utils/req.go new file mode 100644 index 000000000..9fe861f46 --- /dev/null +++ b/agent/utils/req.go @@ -0,0 +1,58 @@ +package utils + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "path/filepath" +) + +func DoReq[response any](url string, data []byte, method string, headers map[string]string, skipTlsVerification bool) (response, int, error) { + var result response + + req, err := http.NewRequest(method, url, bytes.NewBuffer(data)) + if err != nil { + return result, http.StatusInternalServerError, err + } + + for k, v := range headers { + req.Header.Add(k, v) + } + + client := &http.Client{} + if !skipTlsVerification { + tlsConfig, err := LoadHTTPTLSCredentials(filepath.Join(GetMyPath(), "certs", "utm.crt")) + if err != nil { + return result, http.StatusInternalServerError, fmt.Errorf("failed to load TLS credentials: %v", err) + } + client.Transport = &http.Transport{ + TLSClientConfig: tlsConfig, + } + } + + resp, err := client.Do(req) + if err != nil { + return result, http.StatusInternalServerError, err + } + defer func() { + _ = resp.Body.Close() + }() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return result, http.StatusInternalServerError, err + } + + if resp.StatusCode != http.StatusAccepted && resp.StatusCode != http.StatusOK { + return result, resp.StatusCode, fmt.Errorf("while sending request to %s received status code: %d and response body: %s", url, resp.StatusCode, body) + } + + err = json.Unmarshal(body, &result) + if err != nil { + return result, http.StatusInternalServerError, err + } + + return result, resp.StatusCode, nil +} diff --git a/agent/installer/utils/service.go b/agent/utils/services.go similarity index 53% rename from agent/installer/utils/service.go rename to agent/utils/services.go index fa7327825..f3faf1191 100644 --- a/agent/installer/utils/service.go +++ b/agent/utils/services.go @@ -2,18 +2,15 @@ package utils import ( "fmt" - "os/exec" + "os" "runtime" ) func StopService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } + path := GetMyPath() switch runtime.GOOS { case "windows": - err := Execute("cmd", path, "/c", "sc", "stop", name) + err := Execute("sc", path, "stop", name) if err != nil { return fmt.Errorf("error stoping service: %v", err) } @@ -27,13 +24,10 @@ func StopService(name string) error { } func UninstallService(name string) error { - path, err := GetMyPath() - if err != nil { - return err - } + path := GetMyPath() switch runtime.GOOS { case "windows": - err := Execute("cmd", path, "/c", "sc", "delete", name) + err := Execute("sc", path, "delete", name) if err != nil { return fmt.Errorf("error uninstalling service: %v", err) } @@ -52,18 +46,56 @@ func UninstallService(name string) error { // CheckIfServiceIsInstalled checks if a service is installed func CheckIfServiceIsInstalled(serv string) (bool, error) { - var cmd *exec.Cmd + path := GetMyPath() + var err error switch runtime.GOOS { case "windows": - cmd = exec.Command("sc", "query", serv) + err = Execute("sc", path, "query", serv) case "linux": - cmd = exec.Command("systemctl", "status", serv) + err = Execute("systemctl", path, "status", serv) default: return false, fmt.Errorf("operative system unknown") } - if err := cmd.Run(); err != nil { + if err != nil { return false, nil } return true, nil } + +func CreateLinuxService(serviceName string, execStart string) error { + servicePath := "/etc/systemd/system/" + serviceName + ".service" + if !CheckIfPathExist(servicePath) { + file, err := os.Create(servicePath) + if err != nil { + return fmt.Errorf("error creating %s file: %v", servicePath, err) + } + defer func() { _ = file.Close() }() + + serviceContent := fmt.Sprintf(`[Unit] +Description=%s +After=network.target + +[Service] +ExecStart=%s +Restart=always + +[Install] +WantedBy=multi-user.target +`, serviceName, execStart) + + _, err = file.WriteString(serviceContent) + if err != nil { + return err + } + + err = file.Sync() + if err != nil { + return err + } + } else { + return fmt.Errorf("service %s already exists", serviceName) + } + + return nil +} diff --git a/agent/updater/utils/tls.go b/agent/utils/tls.go similarity index 54% rename from agent/updater/utils/tls.go rename to agent/utils/tls.go index d0a1bb693..b60be2ca5 100644 --- a/agent/updater/utils/tls.go +++ b/agent/utils/tls.go @@ -5,11 +5,11 @@ import ( "crypto/x509" "fmt" "os" + + "google.golang.org/grpc/credentials" ) -// LoadTLSCredentials loads the TLS credentials from the specified certificate file. -func LoadTLSCredentials(crtName string) (*tls.Config, error) { - // Load the server's certificate +func LoadHTTPTLSCredentials(crtName string) (*tls.Config, error) { serverCert, err := os.ReadFile(crtName) if err != nil { return nil, err @@ -26,3 +26,12 @@ func LoadTLSCredentials(crtName string) (*tls.Config, error) { return config, nil } + +func LoadGRPCTLSCredentials(crtName string) (credentials.TransportCredentials, error) { + config, err := LoadHTTPTLSCredentials(crtName) + if err != nil { + return nil, err + } + + return credentials.NewTLS(config), nil +} diff --git a/agent/agent/utils/watcher.go b/agent/utils/watcher.go similarity index 85% rename from agent/agent/utils/watcher.go rename to agent/utils/watcher.go index 1b0ae662c..01bb45efe 100644 --- a/agent/agent/utils/watcher.go +++ b/agent/utils/watcher.go @@ -4,13 +4,11 @@ import ( "fmt" "regexp" "time" - - "github.com/threatwinds/logger" ) const maxBatchWait = 5 * time.Second -func TailLogFile(filePath string, logLinesChan chan []string, stopChan chan bool, batchCapacity int, h *logger.Logger) { +func TailLogFile(filePath string, logLinesChan chan []string, stopChan chan bool, batchCapacity int) { latestline := "null" batch := make([]string, 0, batchCapacity) ticker := time.NewTicker(maxBatchWait) @@ -32,7 +30,7 @@ loop: default: lines, err := ReadFileLines(filePath) if err != nil { - h.Info("error reading file %s: %v\n", filePath, err) + Logger.Info("error reading file %s: %v\n", filePath, err) continue } if len(lines) <= 1 { @@ -64,7 +62,7 @@ loop: } } -func WatchFolder(logType string, logsPath string, logLinesChan chan []string, batchCapacity int, h *logger.Logger) { +func WatchFolder(logType string, logsPath string, logLinesChan chan []string, batchCapacity int) { stopChan := make(chan bool) latestLog := "" pattern := regexp.MustCompile(fmt.Sprintf(`%s-(\d+)(?:-(\d+))?\.ndjson`, logType)) @@ -74,13 +72,13 @@ func WatchFolder(logType string, logsPath string, logLinesChan chan []string, ba for range ticker.C { isEmpty, err := IsDirEmpty(logsPath) if err != nil { - h.Info("error checking if %s is empty: %v\n", logsPath, err) + Logger.Info("error checking if %s is empty: %v\n", logsPath, err) continue } if !isEmpty { newLatestLog, err := FindLatestLog(logsPath, pattern) if err != nil { - h.Info("error getting latest log name: %v", err) + Logger.Info("error getting latest log name: %v", err) continue } if newLatestLog != latestLog && newLatestLog != "" { @@ -88,7 +86,7 @@ func WatchFolder(logType string, logsPath string, logLinesChan chan []string, ba stopChan <- true } latestLog = newLatestLog - go TailLogFile(latestLog, logLinesChan, stopChan, batchCapacity, h) + go TailLogFile(latestLog, logLinesChan, stopChan, batchCapacity) } } } diff --git a/agent/installer/utils/unzip.go b/agent/utils/zip.go similarity index 92% rename from agent/installer/utils/unzip.go rename to agent/utils/zip.go index ccd121334..e8c8381b8 100644 --- a/agent/installer/utils/unzip.go +++ b/agent/utils/zip.go @@ -8,7 +8,6 @@ import ( "path/filepath" ) -// Unzip function unzip a zip file to a specified destination path func Unzip(zipFile, destPath string) error { archive, err := zip.OpenReader(zipFile) if err != nil { diff --git a/agent/version.json b/agent/version.json new file mode 100644 index 000000000..641e8961a --- /dev/null +++ b/agent/version.json @@ -0,0 +1,3 @@ +{ + "version": "10.6.0" +} diff --git a/agent/versions.json b/agent/versions.json deleted file mode 100644 index 44e2fcfbf..000000000 --- a/agent/versions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "agent_version": "10.5.1", - "updater_version": "10.1.4", - "redline_version": "10.1.2" -} From 79d1deeb9b5cf492b94df3d7616830ef931c5990 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Wed, 12 Mar 2025 20:49:35 -0400 Subject: [PATCH 10/19] update dependencies --- agent/agent/delete.go | 6 ++-- agent/agent/incident_response.go | 6 ++-- agent/agent/ping_imp.go | 6 ++-- agent/agent/register.go | 8 ++--- agent/agent/uninstall.go | 4 +-- agent/agent/update.go | 8 ++--- agent/collectors/collectors.go | 2 +- agent/collectors/filebeat.go | 8 ++--- agent/collectors/winlogbeat.go | 6 ++-- agent/config/config.go | 2 +- agent/config/const.go | 2 +- agent/conn/conn.go | 4 +-- agent/go.mod | 19 ++++++------ agent/go.sum | 52 +++++++++----------------------- agent/logservice/log.pb.go | 2 +- agent/logservice/processor.go | 8 ++--- agent/main.go | 14 ++++----- agent/modules/configuration.go | 4 +-- agent/modules/modules.go | 4 +-- agent/modules/netflow.go | 8 ++--- agent/modules/syslog.go | 8 ++--- agent/parser/beats.go | 4 +-- agent/parser/cisco.go | 2 +- agent/parser/netflow.go | 2 +- agent/parser/netflow/dump.go | 2 +- agent/serv/clean-old.go | 4 +-- agent/serv/run.go | 2 +- agent/serv/service.go | 14 ++++----- agent/serv/uninstall.go | 2 +- agent/updates/dependencies.go | 4 +-- agent/updates/update.go | 6 ++-- log-auth-proxy/go.mod | 10 +++--- log-auth-proxy/go.sum | 16 +++++----- 33 files changed, 112 insertions(+), 137 deletions(-) diff --git a/agent/agent/delete.go b/agent/agent/delete.go index 1e1255185..af51fca85 100644 --- a/agent/agent/delete.go +++ b/agent/agent/delete.go @@ -6,9 +6,9 @@ import ( "os/user" "strconv" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/conn" + "github.com/utmstack/UTMStack/agent/utils" "google.golang.org/grpc/metadata" ) diff --git a/agent/agent/incident_response.go b/agent/agent/incident_response.go index cb1fea151..77cec794e 100644 --- a/agent/agent/incident_response.go +++ b/agent/agent/incident_response.go @@ -6,9 +6,9 @@ import ( "strings" "time" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/conn" + "github.com/utmstack/UTMStack/agent/utils" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/timestamppb" diff --git a/agent/agent/ping_imp.go b/agent/agent/ping_imp.go index 45463440f..4dea548ef 100644 --- a/agent/agent/ping_imp.go +++ b/agent/agent/ping_imp.go @@ -5,9 +5,9 @@ import ( "strings" "time" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/conn" + "github.com/utmstack/UTMStack/agent/utils" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) diff --git a/agent/agent/register.go b/agent/agent/register.go index 993f4a115..b69de591e 100644 --- a/agent/agent/register.go +++ b/agent/agent/register.go @@ -4,10 +4,10 @@ import ( context "context" "fmt" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/models" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/conn" + "github.com/utmstack/UTMStack/agent/models" + "github.com/utmstack/UTMStack/agent/utils" "google.golang.org/grpc/metadata" ) diff --git a/agent/agent/uninstall.go b/agent/agent/uninstall.go index f1d28f2cc..3d0bbf291 100644 --- a/agent/agent/uninstall.go +++ b/agent/agent/uninstall.go @@ -4,8 +4,8 @@ import ( "fmt" "path/filepath" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" ) func UninstallAll() error { diff --git a/agent/agent/update.go b/agent/agent/update.go index 3301b468b..7fca7450e 100644 --- a/agent/agent/update.go +++ b/agent/agent/update.go @@ -4,10 +4,10 @@ import ( context "context" "fmt" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/models" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/conn" + "github.com/utmstack/UTMStack/agent/models" + "github.com/utmstack/UTMStack/agent/utils" ) func UpdateAgent(cnf *config.Config, ctx context.Context) error { diff --git a/agent/collectors/collectors.go b/agent/collectors/collectors.go index ab1e39b40..865a5df6a 100644 --- a/agent/collectors/collectors.go +++ b/agent/collectors/collectors.go @@ -4,7 +4,7 @@ import ( "fmt" "runtime" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/utils" ) type CollectorConfig struct { diff --git a/agent/collectors/filebeat.go b/agent/collectors/filebeat.go index d6aeec440..6bca22e12 100644 --- a/agent/collectors/filebeat.go +++ b/agent/collectors/filebeat.go @@ -5,10 +5,10 @@ import ( "path/filepath" "runtime" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/logservice" - "github.com/utmstack/UTMStack/agent/agent/parser" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/logservice" + "github.com/utmstack/UTMStack/agent/parser" + "github.com/utmstack/UTMStack/agent/utils" ) type Filebeat struct{} diff --git a/agent/collectors/winlogbeat.go b/agent/collectors/winlogbeat.go index ef65a48c0..d39fbf1e6 100644 --- a/agent/collectors/winlogbeat.go +++ b/agent/collectors/winlogbeat.go @@ -5,9 +5,9 @@ import ( "path/filepath" "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/logservice" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/logservice" + "github.com/utmstack/UTMStack/agent/utils" ) type Winlogbeat struct{} diff --git a/agent/config/config.go b/agent/config/config.go index 4e1061c87..8e41ef88f 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -7,7 +7,7 @@ import ( aesCrypt "github.com/AtlasInsideCorp/AtlasInsideAES" "github.com/google/uuid" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/utils" ) type InstallationUUID struct { diff --git a/agent/config/const.go b/agent/config/const.go index c4b6ce04b..51ce80aae 100644 --- a/agent/config/const.go +++ b/agent/config/const.go @@ -3,7 +3,7 @@ package config import ( "path/filepath" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/utils" ) const REPLACE_KEY string = "" diff --git a/agent/conn/conn.go b/agent/conn/conn.go index 87396fd23..e045ca020 100644 --- a/agent/conn/conn.go +++ b/agent/conn/conn.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" grpc "google.golang.org/grpc" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials" diff --git a/agent/go.mod b/agent/go.mod index f0e2355d0..4f19d6525 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -1,17 +1,17 @@ -module github.com/utmstack/UTMStack/agent/agent +module github.com/utmstack/UTMStack/agent -go 1.22.4 +go 1.23.0 toolchain go1.23.4 require ( github.com/AtlasInsideCorp/AtlasInsideAES v1.0.0 - github.com/elastic/go-sysinfo v1.11.1 + github.com/elastic/go-sysinfo v1.15.1 github.com/google/uuid v1.6.0 github.com/kardianos/service v1.2.2 github.com/tehmaze/netflow v0.0.0-20240303214733-8c13bb004068 github.com/threatwinds/logger v1.1.12 - github.com/threatwinds/validations v1.0.5 + github.com/threatwinds/validations v1.0.9 google.golang.org/grpc v1.70.0 google.golang.org/protobuf v1.36.5 gopkg.in/yaml.v2 v2.4.0 @@ -30,7 +30,6 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.22.0 // indirect github.com/goccy/go-json v0.10.3 // indirect - github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -39,14 +38,14 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.32.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/agent/go.sum b/agent/go.sum index 5862389e1..048b78c61 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -1,7 +1,5 @@ github.com/AtlasInsideCorp/AtlasInsideAES v1.0.0 h1:TBiBl9KCa4i4epY0/q9WSC4ugavL6+6JUkOXWDnMM6I= github.com/AtlasInsideCorp/AtlasInsideAES v1.0.0/go.mod h1:cRhQ3TS/VEfu/z+qaciyuDZdtxgaXgaX8+G6Wa5NzBk= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -14,16 +12,8 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho= -github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elastic/go-sysinfo v1.11.1 h1:g9mwl05njS4r69TisC+vwHWTSKywZFYYUu3so3T/Lao= -github.com/elastic/go-sysinfo v1.11.1/go.mod h1:6KQb31j0QeWBDF88jIdWSxE8cwoOB9tO4Y4osN7Q70E= +github.com/elastic/go-sysinfo v1.15.1 h1:zBmTnFEXxIQ3iwcQuk7MzaUotmKRp3OabbbWM8TdzIQ= +github.com/elastic/go-sysinfo v1.15.1/go.mod h1:jPSuTgXG+dhhh0GKIyI2Cso+w5lPJ5PvVqKlL8LV/Hk= github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= @@ -46,8 +36,6 @@ github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4 github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -56,8 +44,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= @@ -80,10 +66,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -91,8 +73,8 @@ 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= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -109,8 +91,8 @@ github.com/tehmaze/netflow v0.0.0-20240303214733-8c13bb004068 h1:1B+EAUqxEyPByCf github.com/tehmaze/netflow v0.0.0-20240303214733-8c13bb004068/go.mod h1:QRP5wJOf7gGMGL2fCAfmh/5CMZQspRxT5DqghaPRrjM= github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= -github.com/threatwinds/validations v1.0.5 h1:kY/Y1g3urTqTNAL/80wWkxPrCHhcbISGduBuVz99d00= -github.com/threatwinds/validations v1.0.5/go.mod h1:vedgpo8crNfHtCMoTlimBlbsFMalXpoTSuSfQh4gU48= +github.com/threatwinds/validations v1.0.9 h1:p+DkqNpZ7g+uCmgv2FPDnkOM4ITrNxgauiTmNbVjo/E= +github.com/threatwinds/validations v1.0.9/go.mod h1:POXU59KPuFTXcKl7qNWoQRNc9LiQnjbYBujjqWgW86A= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -127,23 +109,17 @@ go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQD go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= diff --git a/agent/logservice/log.pb.go b/agent/logservice/log.pb.go index c05bbb1fc..b1657f80e 100644 --- a/agent/logservice/log.pb.go +++ b/agent/logservice/log.pb.go @@ -7,7 +7,7 @@ package logservice import ( - agent "github.com/utmstack/UTMStack/agent/agent/agent" + agent "github.com/utmstack/UTMStack/agent/agent" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" diff --git a/agent/logservice/processor.go b/agent/logservice/processor.go index 50475168b..009081132 100644 --- a/agent/logservice/processor.go +++ b/agent/logservice/processor.go @@ -10,10 +10,10 @@ import ( "sync" "time" - "github.com/utmstack/UTMStack/agent/agent/agent" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/conn" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/agent" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/conn" + "github.com/utmstack/UTMStack/agent/utils" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) diff --git a/agent/main.go b/agent/main.go index 0e707c939..cdd84a7c7 100644 --- a/agent/main.go +++ b/agent/main.go @@ -6,13 +6,13 @@ import ( "path/filepath" "time" - pb "github.com/utmstack/UTMStack/agent/agent/agent" - "github.com/utmstack/UTMStack/agent/agent/collectors" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/modules" - "github.com/utmstack/UTMStack/agent/agent/serv" - "github.com/utmstack/UTMStack/agent/agent/updates" - "github.com/utmstack/UTMStack/agent/agent/utils" + pb "github.com/utmstack/UTMStack/agent/agent" + "github.com/utmstack/UTMStack/agent/collectors" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/modules" + "github.com/utmstack/UTMStack/agent/serv" + "github.com/utmstack/UTMStack/agent/updates" + "github.com/utmstack/UTMStack/agent/utils" ) func main() { diff --git a/agent/modules/configuration.go b/agent/modules/configuration.go index f926df588..bbf527d32 100644 --- a/agent/modules/configuration.go +++ b/agent/modules/configuration.go @@ -6,8 +6,8 @@ import ( "os" "strings" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" ) type Port struct { diff --git a/agent/modules/modules.go b/agent/modules/modules.go index 33eb0be04..0ce4eb491 100644 --- a/agent/modules/modules.go +++ b/agent/modules/modules.go @@ -3,8 +3,8 @@ package modules import ( "time" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" ) const ( diff --git a/agent/modules/netflow.go b/agent/modules/netflow.go index 94ca5f0e1..a2b5f5560 100644 --- a/agent/modules/netflow.go +++ b/agent/modules/netflow.go @@ -12,10 +12,10 @@ import ( "github.com/tehmaze/netflow" "github.com/tehmaze/netflow/session" "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/logservice" - "github.com/utmstack/UTMStack/agent/agent/parser" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/logservice" + "github.com/utmstack/UTMStack/agent/parser" + "github.com/utmstack/UTMStack/agent/utils" ) var ( diff --git a/agent/modules/syslog.go b/agent/modules/syslog.go index 3bfc6582b..dd559c205 100644 --- a/agent/modules/syslog.go +++ b/agent/modules/syslog.go @@ -11,10 +11,10 @@ import ( "time" "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/logservice" - "github.com/utmstack/UTMStack/agent/agent/parser" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/logservice" + "github.com/utmstack/UTMStack/agent/parser" + "github.com/utmstack/UTMStack/agent/utils" ) type SyslogModule struct { diff --git a/agent/parser/beats.go b/agent/parser/beats.go index 4a416965b..ed52650ba 100644 --- a/agent/parser/beats.go +++ b/agent/parser/beats.go @@ -6,8 +6,8 @@ import ( "sync" "github.com/threatwinds/validations" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" ) var ( diff --git a/agent/parser/cisco.go b/agent/parser/cisco.go index 62fbd4785..6becc42e6 100644 --- a/agent/parser/cisco.go +++ b/agent/parser/cisco.go @@ -5,7 +5,7 @@ import ( "regexp" "sync" - "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/config" ) var ( diff --git a/agent/parser/netflow.go b/agent/parser/netflow.go index 50a1ea34b..b979c232f 100644 --- a/agent/parser/netflow.go +++ b/agent/parser/netflow.go @@ -11,7 +11,7 @@ import ( "github.com/tehmaze/netflow/netflow6" "github.com/tehmaze/netflow/netflow7" "github.com/tehmaze/netflow/netflow9" - pnf "github.com/utmstack/UTMStack/agent/agent/parser/netflow" + pnf "github.com/utmstack/UTMStack/agent/parser/netflow" ) var ( diff --git a/agent/parser/netflow/dump.go b/agent/parser/netflow/dump.go index ae510a314..5184d0112 100644 --- a/agent/parser/netflow/dump.go +++ b/agent/parser/netflow/dump.go @@ -5,7 +5,7 @@ import ( "reflect" "strings" - "github.com/utmstack/UTMStack/agent/agent/config" + "github.com/utmstack/UTMStack/agent/config" ) func Dump(metrics []Metric, remote string) []string { diff --git a/agent/serv/clean-old.go b/agent/serv/clean-old.go index 1db7626dc..489edd9b1 100644 --- a/agent/serv/clean-old.go +++ b/agent/serv/clean-old.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" ) func CleanOldServices(cnf *config.Config) { diff --git a/agent/serv/run.go b/agent/serv/run.go index 138259931..d7d864905 100644 --- a/agent/serv/run.go +++ b/agent/serv/run.go @@ -2,7 +2,7 @@ package serv import ( "github.com/kardianos/service" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/utils" ) func RunService() { diff --git a/agent/serv/service.go b/agent/serv/service.go index a6c4c4226..8206cb220 100644 --- a/agent/serv/service.go +++ b/agent/serv/service.go @@ -8,13 +8,13 @@ import ( "syscall" "github.com/kardianos/service" - pb "github.com/utmstack/UTMStack/agent/agent/agent" - "github.com/utmstack/UTMStack/agent/agent/collectors" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/logservice" - "github.com/utmstack/UTMStack/agent/agent/modules" - "github.com/utmstack/UTMStack/agent/agent/updates" - "github.com/utmstack/UTMStack/agent/agent/utils" + pb "github.com/utmstack/UTMStack/agent/agent" + "github.com/utmstack/UTMStack/agent/collectors" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/logservice" + "github.com/utmstack/UTMStack/agent/modules" + "github.com/utmstack/UTMStack/agent/updates" + "github.com/utmstack/UTMStack/agent/utils" "google.golang.org/grpc/metadata" ) diff --git a/agent/serv/uninstall.go b/agent/serv/uninstall.go index 18354d246..644bc713a 100644 --- a/agent/serv/uninstall.go +++ b/agent/serv/uninstall.go @@ -1,7 +1,7 @@ package serv import ( - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/utils" ) func UninstallService() { diff --git a/agent/updates/dependencies.go b/agent/updates/dependencies.go index 948f721bb..a740f3551 100644 --- a/agent/updates/dependencies.go +++ b/agent/updates/dependencies.go @@ -7,8 +7,8 @@ import ( "runtime" "strings" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" ) func DownloadFirstDependencies(address string, authKey string, insecure bool) error { diff --git a/agent/updates/update.go b/agent/updates/update.go index d784d9817..4b4312c8c 100644 --- a/agent/updates/update.go +++ b/agent/updates/update.go @@ -7,9 +7,9 @@ import ( "runtime" "time" - "github.com/utmstack/UTMStack/agent/agent/config" - "github.com/utmstack/UTMStack/agent/agent/models" - "github.com/utmstack/UTMStack/agent/agent/utils" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/models" + "github.com/utmstack/UTMStack/agent/utils" ) const ( diff --git a/log-auth-proxy/go.mod b/log-auth-proxy/go.mod index d06b549c1..f72cb2fd1 100644 --- a/log-auth-proxy/go.mod +++ b/log-auth-proxy/go.mod @@ -1,6 +1,6 @@ module github.com/utmstack/UTMStack/log-auth-proxy -go 1.22.4 +go 1.23.0 toolchain go1.23.4 @@ -33,10 +33,10 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.30.0 // indirect - golang.org/x/net v0.32.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/log-auth-proxy/go.sum b/log-auth-proxy/go.sum index fb16a837c..e6d84d872 100644 --- a/log-auth-proxy/go.sum +++ b/log-auth-proxy/go.sum @@ -86,16 +86,16 @@ go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQD go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= From 5b13f1ba6a9792dce793340bff3b968cfb529483 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Wed, 12 Mar 2025 23:23:02 -0400 Subject: [PATCH 11/19] update CI/CD pipelines --- .github/scripts/agent-deploy.py | 80 ------------- .github/workflows/alpha-deployment.yml | 32 ++++-- .github/workflows/beta-deployment.yml | 21 ++-- .github/workflows/build.yml | 73 ++++++------ .../workflows/images-without-dependencies.yml | 4 +- .github/workflows/principal-agent.yml | 94 ---------------- .github/workflows/principal-installer-dev.yml | 41 ------- .github/workflows/principal-multi-env.yml | 106 ++++++++++-------- .github/workflows/production-deployment.yml | 20 ++-- .github/workflows/rc-deployment.yml | 21 ++-- .github/workflows/used-runner.yml | 2 +- agent-manager/Dockerfile | 6 +- 12 files changed, 155 insertions(+), 345 deletions(-) delete mode 100644 .github/scripts/agent-deploy.py delete mode 100644 .github/workflows/principal-agent.yml delete mode 100644 .github/workflows/principal-installer-dev.yml diff --git a/.github/scripts/agent-deploy.py b/.github/scripts/agent-deploy.py deleted file mode 100644 index eb3be137f..000000000 --- a/.github/scripts/agent-deploy.py +++ /dev/null @@ -1,80 +0,0 @@ -import argparse -import json -import os -import requests -from google.cloud import storage -import yaml - -def main(environment): - if environment.startswith("v10-"): - environment = environment.replace("v10-", "") - - gcp_key = json.loads(os.environ.get("GCP_KEY")) - storage_client = storage.Client.from_service_account_info(gcp_key) - - bucket_name = "utmstack-updates" - bucket = storage_client.bucket(bucket_name) - - # Read utmstack version from version.yml - with open(os.path.join(os.environ["GITHUB_WORKSPACE"], "version.yml"), "r") as f: - local_master_version = yaml.safe_load(f)['version'] - - # Read agent services version from versions.json - with open(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "versions.json"), "r") as f: - local_agent_versions = json.load(f) - - # Download versions.json from URL - endp = "agent_updates/{}".format(environment) - response = requests.get("https://storage.googleapis.com/" + bucket_name + "/" + endp + "/versions.json") - remote_versions = response.json()['versions'] - - # Find the object with matching master_version - version_found = False - for obj in remote_versions: - if obj['master_version'] == local_master_version: - obj['agent_version'] = local_agent_versions["agent_version"] - obj['updater_version'] = local_agent_versions["updater_version"] - obj['redline_version'] = local_agent_versions["redline_version"] - version_found = True - break - - # If no matching object found, create a new one - if version_found == False: - version_obj = { - 'master_version': local_master_version, - 'agent_version': local_agent_versions["agent_version"], - 'updater_version': local_agent_versions["updater_version"], - 'redline_version': local_agent_versions["redline_version"], - } - remote_versions.append(version_obj) - - # Update version.json - version_blob = bucket.blob(endp + "/versions.json") - version_blob.upload_from_string(json.dumps({'versions': remote_versions}, indent=4)) - - # Create agent blobs - agent_windows_blob = bucket.blob(endp + "/agent_service/v" + local_agent_versions["agent_version"] + "/utmstack_agent_service.exe") - agent_linux_blob = bucket.blob(endp + "/agent_service/v" + local_agent_versions["agent_version"] + "/utmstack_agent_service") - updater_windows_blob = bucket.blob(endp + "/updater_service/v" + local_agent_versions["updater_version"] + "/utmstack_updater_service.exe") - updater_linux_blob = bucket.blob(endp + "/updater_service/v" + local_agent_versions["updater_version"] + "/utmstack_updater_service") - redline_windows_blob = bucket.blob(endp + "/redline_service/v" + local_agent_versions["redline_version"] + "/utmstack_redline_service.exe") - redline_linux_blob = bucket.blob(endp + "/redline_service/v" + local_agent_versions["redline_version"] + "/utmstack_redline_service") - installer_windows_blob = bucket.blob(endp + "/installer/v" + local_master_version + "/utmstack_agent_installer.exe") - installer_linux_blob = bucket.blob(endp + "/installer/v" + local_master_version + "/utmstack_agent_installer") - - # Upload agent services - agent_windows_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "agent", "utmstack_agent_service.exe")) - agent_linux_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "agent", "utmstack_agent_service")) - updater_windows_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "updater", "utmstack_updater_service.exe")) - updater_linux_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "updater", "utmstack_updater_service")) - redline_windows_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "redline", "utmstack_redline_service.exe")) - redline_linux_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "redline", "utmstack_redline_service")) - installer_windows_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "installer", "utmstack_agent_installer.exe")) - installer_linux_blob.upload_from_filename(os.path.join(os.environ["GITHUB_WORKSPACE"], "agent", "installer", "utmstack_agent_installer")) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Update UTMStack agents in Google Cloud Storage") - parser.add_argument("environment", type=str, help="Environment(dev, rc, release)") - - args = parser.parse_args() - main(args.environment) \ No newline at end of file diff --git a/.github/workflows/alpha-deployment.yml b/.github/workflows/alpha-deployment.yml index 06fa407da..0f6f11ab6 100644 --- a/.github/workflows/alpha-deployment.yml +++ b/.github/workflows/alpha-deployment.yml @@ -22,23 +22,32 @@ jobs: if [[ "${{ github.event.inputs.version_tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-alpha\.[0-9]+$ ]]; then echo "✅ Version tag format is correct." - if [[ "${ github.ref }" =~ ^refs/heads/(release/|feature/) ]]; then - echo "✅ Base branch ${ github.ref } is valid." + if [[ "${{ github.ref }}" =~ ^refs/heads/(release/|feature/) ]]; then + echo "✅ Base branch ${{ github.ref }} is valid." else - echo "â›” ERROR: Base branch ${ github.ref } is not valid. It should be release/ or feature/." + echo "â›” ERROR: Base branch ${{ github.ref }} is not valid. It should be release/ or feature/." exit 1 fi echo "Validating user permissions..." - RESPONSE=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + RESPONSE=$(curl -s -H "Authorization: Bearer ${{ secrets.API_SECRET }}" \ -H "Accept: application/vnd.github.json" \ "https://api.github.com/orgs/utmstack/teams/integration-developers/memberships/${{ github.actor }}") if echo "$RESPONSE" | grep -q '"state": "active"'; then echo "✅ User ${{ github.actor }} is a member of the integration-developers team." else - echo "â›” ERROR: User ${{ github.actor }} is not a member of the integration-developers team." - exit 1 + RESPONSE=$(curl -s -H "Authorization: Bearer ${{ secrets.API_SECRET }}" \ + -H "Accept: application/vnd.github.json" \ + "https://api.github.com/orgs/utmstack/teams/core-developers/memberships/${{ github.actor }}") + + if echo "$RESPONSE" | grep -q '"state": "active"'; then + echo "✅ User ${{ github.actor }} is a member of the core-developers team." + else + echo "â›” ERROR: User ${{ github.actor }} is not a member of the core-developers or integration-developers team." + echo $RESPONSE + exit 1 + fi fi else @@ -47,17 +56,16 @@ jobs: fi deploy: - name: Deploy + name: Deploy to Alpha needs: validations uses: ./.github/workflows/build.yml with: version_tag: ${{ github.event.inputs.version_tag }} event_processor_tag: ${{ github.event.inputs.event_processor_tag }} environment: alpha - ghcr_token: ${{ secrets.GITHUB_TOKEN }} - sign_cert: ${{ vars.SIGN_CERT }} - sign_key: ${{ secrets.SIGN_KEY }} - sign_container: ${{ secrets.SIGN_CONTAINER }} - env: + secrets: + AGENT_SECRET_PREFIX: ${{ secrets.AGENT_SECRET_PREFIX }} + SIGN_KEY: ${{ secrets.SIGN_KEY }} + SIGN_CONTAINER: ${{ secrets.SIGN_CONTAINER }} CM_AUTH: ${{ secrets.CM_AUTH_ALPHA }} \ No newline at end of file diff --git a/.github/workflows/beta-deployment.yml b/.github/workflows/beta-deployment.yml index dc7b7eeb1..8042aff8e 100644 --- a/.github/workflows/beta-deployment.yml +++ b/.github/workflows/beta-deployment.yml @@ -22,10 +22,10 @@ jobs: if [[ "${{ github.event.inputs.version_tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+$ ]]; then echo "✅ Version tag format is correct." - if [[ "${ github.ref }" =~ ^refs/heads/(release/|feature/) ]]; then - echo "✅ Base branch ${ github.ref } is valid." + if [[ "${{ github.ref }}" =~ ^refs/heads/(release/|feature/) ]]; then + echo "✅ Base branch ${{ github.ref }} is valid." else - echo "â›” ERROR: Base branch ${ github.ref } is not valid. It should be release/ or feature/." + echo "â›” ERROR: Base branch ${{ github.ref }} is not valid. It should be release/ or feature/." exit 1 fi @@ -38,7 +38,7 @@ jobs: echo "✅ User ${{ github.actor }} is a member of the core-developers team." else echo "â›” ERROR: User ${{ github.actor }} is not a member of the core-developers team." - exit 1 + exit 1 fi else @@ -47,17 +47,16 @@ jobs: fi deploy: - name: Deploy + name: Deploy to Beta needs: validations uses: ./.github/workflows/build.yml with: version_tag: ${{ github.event.inputs.version_tag }} event_processor_tag: ${{ github.event.inputs.event_processor_tag }} environment: beta - ghcr_token: ${{ secrets.GITHUB_TOKEN }} - sign_cert: ${{ vars.SIGN_CERT }} - sign_key: ${{ secrets.SIGN_KEY }} - sign_container: ${{ secrets.SIGN_CONTAINER }} - env: - CM_AUTH: ${{ secrets.CM_AUTH_BETA }} + secrets: + AGENT_SECRET_PREFIX: ${{ secrets.AGENT_SECRET_PREFIX }} + SIGN_KEY: ${{ secrets.SIGN_KEY }} + SIGN_CONTAINER: ${{ secrets.SIGN_CONTAINER }} + CM_AUTH: ${{ secrets.CM_AUTH_ALPHA }} \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 71c0eb9d6..7274af7d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,18 +12,16 @@ on: environment: required: true type: string - ghcr_token: + secrets: + AGENT_SECRET_PREFIX: required: true - type: string - sign_cert: + SIGN_KEY: required: true - type: string - sign_key: + SIGN_CONTAINER: required: true - type: string - sign_container: + CM_AUTH: required: true - type: string + jobs: build_images: @@ -49,7 +47,7 @@ jobs: - name: Login to GitHub Container Registry run: | - docker login ghcr.io -u utmstack -p ${{ inputs.ghcr_token }} + docker login ghcr.io -u utmstack -p ${{ secrets.GITHUB_TOKEN }} echo "Logged in to GitHub Container Registry" - name: Download base images @@ -59,47 +57,53 @@ jobs: - name: Build Agent run: | - cd ${{ github.workspace }}/agent/service/config; (Get-Content const.go) | Foreach-Object { $_ -replace 'const REPLACE_KEY string = ""', 'const REPLACE_KEY string = "${{ secrets.AGENT_SECRET_PREFIX }}"' } | Set-Content const.go + cd ${{ github.workspace }}/agent/config; (Get-Content const.go) | Foreach-Object { $_ -replace 'const REPLACE_KEY string = ""', 'const REPLACE_KEY string = "${{ secrets.AGENT_SECRET_PREFIX }}"' } | Set-Content const.go - $env:GOOS = "linux" $env:GOARCH = "amd64" - cd ${{ github.workspace }}/agent/service; go build -o utmstack_agent_service -v . - cd ${{ github.workspace }}/agent/installer; go build -o utmstack_agent_installer -v . - + $env:GOOS = "linux" + cd ${{ github.workspace }}/agent + go build -o utmstack_agent -v . + $env:GOOS = "windows" - cd ${{ github.workspace }}/agent/service; go build -o utmstack_agent_service.exe -v . - signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ inputs.sign_cert }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ inputs.sign_key }}}}]=${{ inputs.sign_container }}" "utmstack_agent_service.exe" - cd ${{ github.workspace }}/agent/installer; go build -o utmstack_agent_installer.exe -v . - signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ inputs.sign_cert }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ inputs.sign_key }}}}]=${{ inputs.sign_container }}" "utmstack_agent_installer.exe" + go build -o utmstack_agent.exe -v . + signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent.exe" + New-Item -ItemType Directory -Force -Path "./dependencies/" Copy-Item -Path "C:/dependencies/${{ inputs.environment }}/agent/*" -Destination "./dependencies/" echo "Agent build completed" - name: Build Plugins run: | - export GOOS=linux - export GOARCH=amd64 - cd ${{ github.workspace }}/plugins - make build + $env:GOOS = "linux" + $env:GOARCH = "amd64" + cd ${{ github.workspace }}/plugins/alerts; go build -o com.utmstack.alerts.plugin -v . + cd ${{ github.workspace }}/plugins/aws; go build -o com.utmstack.aws.plugin -v . + cd ${{ github.workspace }}/plugins/azure; go build -o com.utmstack.azure.plugin -v . + cd ${{ github.workspace }}/plugins/bitdefender; go build -o com.utmstack.bitdefender.plugin -v . + cd ${{ github.workspace }}/plugins/config; go build -o com.utmstack.config.plugin -v . + cd ${{ github.workspace }}/plugins/events; go build -o com.utmstack.events.plugin -v . + cd ${{ github.workspace }}/plugins/gcp; go build -o com.utmstack.gcp.plugin -v . + cd ${{ github.workspace }}/plugins/geolocation; go build -o com.utmstack.geolocation.plugin -v . + cd ${{ github.workspace }}/plugins/inputs; go build -o com.utmstack.inputs.plugin -v . + cd ${{ github.workspace }}/plugins/o365; go build -o com.utmstack.o365.plugin -v . + cd ${{ github.workspace }}/plugins/sophos; go build -o com.utmstack.sophos.plugin -v . + cd ${{ github.workspace }}/plugins/stats; go build -o com.utmstack.stats.plugin -v . - name: Build Event Processor Image run: | New-Item -ItemType Directory -Force -Path "./geolocation/" Copy-Item -Path "C:/dependencies/${{ inputs.environment }}/geolocation/*" -Destination "./geolocation/" - - docker build -t ghcr.io/utmstack/utmstack/eventprocessor:${{ inputs.version_tag }}-community \ - --build-arg BASE_IMAGE=ghcr.io/threatwinds/eventprocessor/base:${{ inputs.event_processor_tag }} \ - -f ./event_processor.Dockerfile \ - . + docker build -t ghcr.io/utmstack/utmstack/eventprocessor:${{ inputs.version_tag }}-community --build-arg BASE_IMAGE=ghcr.io/threatwinds/eventprocessor/base:${{ inputs.event_processor_tag }} -f ./event_processor.Dockerfile . echo "Event Processor image built" - name: Build Agent Manager Image run: | - go build -o ./agent-manager/agent-manager -v ./agent-manager - docker build -t ghcr.io/utmstack/utmstack/agent-manager:${{ inputs.version_tag }}-community \ - -f ./agent-manager/Dockerfile \ - . + $env:GOOS = "linux" + $env:GOARCH = "amd64" + cd ${{ github.workspace }}/agent-manager; go build -o agent-manager -v . + cd ${{ github.workspace }} + docker build -t ghcr.io/utmstack/utmstack/agent-manager:${{ inputs.version_tag }}-community -f ./agent-manager/Dockerfile . echo "Agent Manager image built" - name: Push images with dependencies @@ -112,11 +116,12 @@ jobs: run: | echo "Pushing new release..." $changelog = Get-Content -Path "CHANGELOG.md" -Raw + $changelog = [string]$changelog - $cmAuth = $env:CM_AUTH | ConvertFrom-Json + $cmAuth = '${{ secrets.CM_AUTH }}' | ConvertFrom-Json $body = @{ - version = ${{ inputs.version_tag }} + version = '${{ inputs.version_tag }}' changelog = $changelog images = "ghcr.io/utmstack/utmstack/backend,ghcr.io/utmstack/utmstack/frontend,ghcr.io/utmstack/utmstack/user-auditor,ghcr.io/utmstack/utmstack/web-pdf,ghcr.io/utmstack/utmstack/eventprocessor,ghcr.io/utmstack/utmstack/agent-manager" edition = "community" @@ -131,4 +136,4 @@ jobs: -Body $body ` -ContentType "application/json" - $response + $response \ No newline at end of file diff --git a/.github/workflows/images-without-dependencies.yml b/.github/workflows/images-without-dependencies.yml index e8cf5a51c..1e30ff742 100644 --- a/.github/workflows/images-without-dependencies.yml +++ b/.github/workflows/images-without-dependencies.yml @@ -57,7 +57,7 @@ jobs: name: Java 11 deployment needs: prepare_deployment if: ${{ needs.prepare_deployment.outputs.tech == 'java-11' }} - uses: ./.github/workflows/used-docker-java-11.yml + uses: ./.github/workflows/used-docker-java-11-new.yml with: image_name: ${{ inputs.microservice }} tag: ${{inputs.tag}}-community @@ -70,4 +70,4 @@ jobs: uses: ./.github/workflows/used-docker-java.yml with: image_name: ${{ inputs.microservice }} - environment: ${{inputs.tag}}-community + environment: ${{inputs.tag}}-community \ No newline at end of file diff --git a/.github/workflows/principal-agent.yml b/.github/workflows/principal-agent.yml deleted file mode 100644 index 83bee2a0d..000000000 --- a/.github/workflows/principal-agent.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Agent Build - -on: - release: - types: [ 'released' ] - push: - branches: [ 'main', 'feature/**' ] - paths: - - 'agent/**' - - 'version.yml' - pull_request_review: - types: [submitted] - paths: - - 'agent/**' - - 'version.yml' - -jobs: - check: - name: Checking - runs-on: ubuntu-latest - outputs: - env_version: ${{ steps.set-env.outputs.env_version }} - steps: - - name: Determine Build Environment - id: set-env - run: | - if ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/heads/feature/') }}; then - echo "DEV environment" - echo "env_version=v10-dev" >> $GITHUB_OUTPUT - elif ${{ github.event_name == 'pull_request_review' && github.event.review.state == 'approved' && github.event.pull_request.base.ref == 'main' && startsWith(github.event.pull_request.head.ref, 'feature/') }}; then - echo "QA environment" - echo "env_version=v10-qa" >> $GITHUB_OUTPUT - elif ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}; then - echo "RC environment" - echo "env_version=v10-rc" >> $GITHUB_OUTPUT - elif ${{ github.event_name == 'release' }}; then - echo "RELEASE environment" - echo "env_version=release" >> $GITHUB_OUTPUT - fi - - build: - name: Build - needs: check - if: needs.check.outputs.env_version != '' - runs-on: signing - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: 1.21 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - - name: Build and sign agent services - id: set-env - run: | - $env:DEPLOY_ENV = '${{ needs.check.outputs.env_version }}' - - cd ${{ github.workspace }}/agent/agent/configuration; (Get-Content const.go) | Foreach-Object { $_ -replace 'const REPLACE_KEY string = ""', 'const REPLACE_KEY string = "${{ secrets.AGENT_SECRET_PREFIX }}"' } | Set-Content const.go - - $env:GOOS = "linux" - $env:GOARCH = "amd64" - cd ${{ github.workspace }}/agent/agent; go build -o utmstack_agent_service -v . - cd ${{ github.workspace }}/agent/installer; go build -o utmstack_agent_installer -v . - cd ${{ github.workspace }}/agent/redline; go build -o utmstack_redline_service -v . - cd ${{ github.workspace }}/agent/updater; go build -o utmstack_updater_service -v . - - $env:GOOS = "windows" - cd ${{ github.workspace }}/agent/agent; go build -o utmstack_agent_service.exe -v . - signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service.exe" - cd ${{ github.workspace }}/agent/installer; go build -o utmstack_agent_installer.exe -v . - signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_installer.exe" - cd ${{ github.workspace }}/agent/redline; go build -o utmstack_redline_service.exe -v . - signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_redline_service.exe" - cd ${{ github.workspace }}/agent/updater; go build -o utmstack_updater_service.exe -v . - signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_updater_service.exe" - - Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.12.1/python-3.12.1-amd64.exe" -OutFile "python-installer.exe" - Start-Process -FilePath "python-installer.exe" -ArgumentList "/quiet InstallAllUsers=1 PrependPath=1" -Wait - Remove-Item -Path "python-installer.exe" - python -m pip install --upgrade pip - pip install requests google-cloud-storage pyyaml - - $env:GCP_KEY = '${{ secrets.GCP_KEY }}' - cd ${{ github.workspace }}/.github/scripts; & 'C:\Program Files\Python312\python.exe' 'agent-deploy.py' $env:DEPLOY_ENV - - cd ${{ github.workspace }}; Remove-Item -Path "./*" -Recurse -Force - \ No newline at end of file diff --git a/.github/workflows/principal-installer-dev.yml b/.github/workflows/principal-installer-dev.yml deleted file mode 100644 index 82e8fe705..000000000 --- a/.github/workflows/principal-installer-dev.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Installer Dev - -on: - workflow_run: - workflows: ["Multi Environment Build"] - types: - - completed - -jobs: - check_feature: - name: Check if feature - runs-on: ubuntu-latest - outputs: - is_feature: ${{ steps.check.outputs.is_feature }} - steps: - - id: check - run: | - echo "Doing ${{ github.event.workflow_run.event }} on ${{ github.event.workflow_run.head_branch }}" - if ${{ github.event.workflow_run.event == 'push' && startsWith(github.event.workflow_run.head_branch, 'feature/') }}; then - echo "It's a feature" - echo "is_feature=true" >> $GITHUB_OUTPUT - else - echo "It's not a feature" - echo "is_feature=false" >> $GITHUB_OUTPUT - fi - deploy: - name: Deploy to dev - needs: check_feature - if: needs.check_feature.outputs.is_feature == 'true' - runs-on: dev - steps: - - name: Run - working-directory: /home/utmstack - run: | - sudo ./installer - - - name: Open ports - id: open_ports - working-directory: /home/utmstack - run: | - sudo docker service update --publish-add 9200:9200 utmstack_node1 & docker service update --publish-add 5432:5432 utmstack_postgres diff --git a/.github/workflows/principal-multi-env.yml b/.github/workflows/principal-multi-env.yml index 1fabb67a4..6097706f4 100644 --- a/.github/workflows/principal-multi-env.yml +++ b/.github/workflows/principal-multi-env.yml @@ -4,9 +4,7 @@ on: release: types: [ 'released' ] push: - branches: [ 'main', 'feature/**' ] - pull_request_review: - types: [submitted] + branches: [ 'main' ] jobs: setup_deployment: @@ -19,13 +17,7 @@ jobs: - name: Determine Build Environment id: set-env run: | - if ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/heads/feature/') }}; then - echo "DEV environment" - echo "env_version=v10-dev" >> $GITHUB_OUTPUT - elif ${{ github.event_name == 'pull_request_review' && github.event.review.state == 'approved' && github.event.pull_request.base.ref == 'main' && startsWith(github.event.pull_request.head.ref, 'feature/') }}; then - echo "QA environment" - echo "env_version=v10-qa" >> $GITHUB_OUTPUT - elif ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}; then + if ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}; then echo "RC environment" echo "env_version=v10-rc" >> $GITHUB_OUTPUT elif ${{ github.event_name == 'release' }}; then @@ -33,48 +25,70 @@ jobs: echo "env_version=v10" >> $GITHUB_OUTPUT fi - - uses: actions/checkout@v4 - - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - agent-manager: agent-manager/** - aws: aws/** - backend: - - 'backend/**' - - 'version.yml' - correlation: correlation/** - frontend: frontend/** - bitdefender: bitdefender/** - mutate: mutate/** - office365: office365/** - log-auth-proxy: log-auth-proxy/** - sophos: sophos/** - user-auditor: user-auditor/** - web-pdf: web-pdf/** - - runner: - name: Deployment + build_agent: + name: Build Agent-Manager Image & Agent & Dependencies needs: setup_deployment - if: ${{ needs.setup_deployment.outputs.microservices != '[]' && needs.setup_deployment.outputs.env_version != ''}} - strategy: - fail-fast: false - matrix: - service: ${{ fromJson(needs.setup_deployment.outputs.microservices) }} - uses: ./.github/workflows/used-runner.yml - with: - microservice: ${{ matrix.service }} - environment: ${{ needs.setup_deployment.outputs.env_version }} - secrets: inherit - + if: ${{ needs.setup_deployment.outputs.env_version != '' }} + runs-on: signing + steps: + - name: Check out code into the right branch + uses: actions/checkout@v4 + + - name: Login to GitHub Container Registry + run: | + docker login ghcr.io -u utmstack -p ${{ secrets.GITHUB_TOKEN }} + echo "Logged in to GitHub Container Registry" + + - name: Build Agent + run: | + cd ${{ github.workspace }}/agent/config; (Get-Content const.go) | Foreach-Object { $_ -replace 'const REPLACE_KEY string = ""', 'const REPLACE_KEY string = "${{ secrets.AGENT_SECRET_PREFIX }}"' } | Set-Content const.go + cd ${{ github.workspace }}/agent + + $env:GOOS = "linux" + $env:GOARCH = "amd64" + go build -o utmstack_agent_service -v . + $env:GOARCH = "arm64" + go build -o utmstack_agent_service_arm64 -v . + + $env:GOOS = "windows" + $env:GOARCH = "amd64" + go build -o utmstack_agent_service.exe -v . + signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service.exe" + $env:GOARCH = "arm64" + go build -o utmstack_agent_service_arm64.exe -v . + signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service_arm64.exe" + + echo "Agent build completed" + + - name: Build & Push Agent Manager Image + run: | + $env:GOOS = "linux" + $env:GOARCH = "amd64" + cd ${{ github.workspace }}/agent-manager; go build -o agent-manager -v . + + New-Item -ItemType Directory -Force -Path "./dependencies/collector/" + Copy-Item -Path "C:/dependencies/${{ needs.setup_deployment.outputs.env_version }}/collector/*" -Destination "./dependencies/collector/" + + New-Item -ItemType Directory -Force -Path "./dependencies/agent/" + Copy-Item -Path "C:/dependencies/${{ needs.setup_deployment.outputs.env_version }}/agent/*" -Destination "./dependencies/agent/" + Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service" -Destination "./dependencies/agent/" + Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64" -Destination "./dependencies/agent/" + Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service.exe" -Destination "./dependencies/agent/" + Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64.exe" -Destination "./dependencies/agent/" + Copy-Item -Path "${{ github.workspace }}/agent/version.json" -Destination "./dependencies/agent/" + + docker build -t ghcr.io/utmstack/utmstack/agent-manager:${{ needs.setup_deployment.outputs.env_version }} . + docker push ghcr.io/utmstack/utmstack/agent-manager:${{ needs.setup_deployment.outputs.env_version }} + echo "Agent Manager image built and pushed" + runner_release: - name: Deployment for Release + name: Images deployment needs: setup_deployment - if: ${{ needs.setup_deployment.outputs.env_version == 'v10' }} + if: ${{ needs.setup_deployment.outputs.env_version != '' }} strategy: fail-fast: false matrix: - service: ['agent-manager', 'aws', 'backend', 'correlation', 'frontend', 'bitdefender', 'mutate', 'office365', 'log-auth-proxy', 'sophos', 'user-auditor', 'web-pdf'] + service: ['aws', 'backend', 'correlation', 'frontend', 'bitdefender', 'mutate', 'office365', 'log-auth-proxy', 'sophos', 'user-auditor', 'web-pdf'] uses: ./.github/workflows/used-runner.yml with: microservice: ${{ matrix.service }} diff --git a/.github/workflows/production-deployment.yml b/.github/workflows/production-deployment.yml index a37ef257b..653bdca86 100644 --- a/.github/workflows/production-deployment.yml +++ b/.github/workflows/production-deployment.yml @@ -22,10 +22,10 @@ jobs: if [[ "${{ github.event.inputs.version_tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "✅ Version tag format is correct." - if [[ "${ github.ref }" =~ ^refs/heads/main) ]]; then - echo "✅ Base branch ${ github.ref } is valid." + if [[ "${{ github.ref }}" =~ ^refs/heads/main) ]]; then + echo "✅ Base branch ${{ github.ref }} is valid." else - echo "â›” ERROR: Base branch ${ github.ref } is not valid. It should be main." + echo "â›” ERROR: Base branch ${{ github.ref }} is not valid. It should be main." exit 1 fi @@ -38,7 +38,7 @@ jobs: echo "✅ User ${{ github.actor }} is a member of the core-developers team." else echo "â›” ERROR: User ${{ github.actor }} is not a member of the core-developers team." - exit 1 + exit 1 fi else @@ -47,7 +47,7 @@ jobs: fi deploy: - name: Deploy + name: Deploy to Production needs: validations uses: ./.github/workflows/build.yml with: @@ -55,9 +55,9 @@ jobs: event_processor_tag: ${{ github.event.inputs.event_processor_tag }} environment: prod ghcr_token: ${{ secrets.GITHUB_TOKEN }} - sign_cert: ${{ vars.SIGN_CERT }} - sign_key: ${{ secrets.SIGN_KEY }} - sign_container: ${{ secrets.SIGN_CONTAINER }} - env: - CM_AUTH: ${{ secrets.CM_AUTH_PROD }} + secrets: + AGENT_SECRET_PREFIX: ${{ secrets.AGENT_SECRET_PREFIX }} + SIGN_KEY: ${{ secrets.SIGN_KEY }} + SIGN_CONTAINER: ${{ secrets.SIGN_CONTAINER }} + CM_AUTH: ${{ secrets.CM_AUTH_ALPHA }} \ No newline at end of file diff --git a/.github/workflows/rc-deployment.yml b/.github/workflows/rc-deployment.yml index 908385706..8e2417fd0 100644 --- a/.github/workflows/rc-deployment.yml +++ b/.github/workflows/rc-deployment.yml @@ -22,10 +22,10 @@ jobs: if [[ "${{ github.event.inputs.version_tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then echo "✅ Version tag format is correct." - if [[ "${ github.ref }" =~ ^refs/heads/main) ]]; then - echo "✅ Base branch ${ github.ref } is valid." + if [[ "${{ github.ref }}" =~ ^refs/heads/main) ]]; then + echo "✅ Base branch ${{ github.ref }} is valid." else - echo "â›” ERROR: Base branch ${ github.ref } is not valid. It should be main." + echo "â›” ERROR: Base branch ${{ github.ref }} is not valid. It should be main." exit 1 fi @@ -38,7 +38,7 @@ jobs: echo "✅ User ${{ github.actor }} is a member of the core-developers team." else echo "â›” ERROR: User ${{ github.actor }} is not a member of the core-developers team." - exit 1 + exit 1 fi else @@ -47,17 +47,16 @@ jobs: fi deploy: - name: Deploy + name: Deploy to RC needs: validations uses: ./.github/workflows/build.yml with: version_tag: ${{ github.event.inputs.version_tag }} event_processor_tag: ${{ github.event.inputs.event_processor_tag }} environment: rc - ghcr_token: ${{ secrets.GITHUB_TOKEN }} - sign_cert: ${{ vars.SIGN_CERT }} - sign_key: ${{ secrets.SIGN_KEY }} - sign_container: ${{ secrets.SIGN_CONTAINER }} - env: - CM_AUTH: ${{ secrets.CM_AUTH_RC }} + secrets: + AGENT_SECRET_PREFIX: ${{ secrets.AGENT_SECRET_PREFIX }} + SIGN_KEY: ${{ secrets.SIGN_KEY }} + SIGN_CONTAINER: ${{ secrets.SIGN_CONTAINER }} + CM_AUTH: ${{ secrets.CM_AUTH_ALPHA }} \ No newline at end of file diff --git a/.github/workflows/used-runner.yml b/.github/workflows/used-runner.yml index c79c2907c..0ad6744e9 100644 --- a/.github/workflows/used-runner.yml +++ b/.github/workflows/used-runner.yml @@ -22,7 +22,7 @@ jobs: id: get_tech run: | folder_changed="${{inputs.microservice}}" - if [[ "$folder_changed" == "agent-manager" || "$folder_changed" == "aws" || "$folder_changed" == "correlation" || "$folder_changed" == "bitdefender" || "$folder_changed" == "office365" || "$folder_changed" == "sophos" || "$folder_changed" == "log-auth-proxy" ]]; then + if [[ "$folder_changed" == "aws" || "$folder_changed" == "correlation" || "$folder_changed" == "bitdefender" || "$folder_changed" == "office365" || "$folder_changed" == "sophos" || "$folder_changed" == "log-auth-proxy" ]]; then tech="golang" elif [[ "$folder_changed" == "backend" ]]; then tech="java-11" diff --git a/agent-manager/Dockerfile b/agent-manager/Dockerfile index ab3514eff..8435564ac 100644 --- a/agent-manager/Dockerfile +++ b/agent-manager/Dockerfile @@ -1,8 +1,8 @@ FROM ubuntu:22.04 -COPY ./agent-manager/agent-manager /app/ -COPY ./agent/dependencies/ /dependencies/agent/ -COPY ./collector/dependencies/ /dependencies/collector/ +COPY agent-manager /app/ +COPY ./dependencies/agent/ /dependencies/agent/ +COPY ./dependencies/collector/ /dependencies/collector/ # Install jq RUN apt-get update && \ From 25468787a85e740ec1e72e915c0915d1626802da Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Mon, 17 Mar 2025 11:48:46 -0400 Subject: [PATCH 12/19] remove arm builds --- .github/workflows/principal-multi-env.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/principal-multi-env.yml b/.github/workflows/principal-multi-env.yml index 6097706f4..5cbeedfdc 100644 --- a/.github/workflows/principal-multi-env.yml +++ b/.github/workflows/principal-multi-env.yml @@ -47,16 +47,16 @@ jobs: $env:GOOS = "linux" $env:GOARCH = "amd64" go build -o utmstack_agent_service -v . - $env:GOARCH = "arm64" - go build -o utmstack_agent_service_arm64 -v . + # $env:GOARCH = "arm64" + # go build -o utmstack_agent_service_arm64 -v . $env:GOOS = "windows" $env:GOARCH = "amd64" go build -o utmstack_agent_service.exe -v . signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service.exe" - $env:GOARCH = "arm64" - go build -o utmstack_agent_service_arm64.exe -v . - signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service_arm64.exe" + # $env:GOARCH = "arm64" + # go build -o utmstack_agent_service_arm64.exe -v . + # signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service_arm64.exe" echo "Agent build completed" @@ -72,9 +72,9 @@ jobs: New-Item -ItemType Directory -Force -Path "./dependencies/agent/" Copy-Item -Path "C:/dependencies/${{ needs.setup_deployment.outputs.env_version }}/agent/*" -Destination "./dependencies/agent/" Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service" -Destination "./dependencies/agent/" - Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64" -Destination "./dependencies/agent/" + # Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64" -Destination "./dependencies/agent/" Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service.exe" -Destination "./dependencies/agent/" - Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64.exe" -Destination "./dependencies/agent/" + # Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64.exe" -Destination "./dependencies/agent/" Copy-Item -Path "${{ github.workspace }}/agent/version.json" -Destination "./dependencies/agent/" docker build -t ghcr.io/utmstack/utmstack/agent-manager:${{ needs.setup_deployment.outputs.env_version }} . From 616de08a4ab00533a9cd419922a57a6fd7068c62 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Mon, 17 Mar 2025 12:56:41 -0400 Subject: [PATCH 13/19] fix message when there is no command output --- agent/utils/cmd.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/agent/utils/cmd.go b/agent/utils/cmd.go index 2c1543286..e573973ae 100644 --- a/agent/utils/cmd.go +++ b/agent/utils/cmd.go @@ -20,6 +20,9 @@ func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { return string(out[:]) + err.Error(), true } + if string(out[:]) == "" { + return "Command executed successfully but no output", false + } validUtf8Out, _, err := validations.ValidateString(string(out[:]), false) if err != nil { return string(out[:]) + err.Error(), true From da0a342ddd024bafb204d557c59e4f69ad432f14 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Mon, 17 Mar 2025 14:09:06 -0400 Subject: [PATCH 14/19] update version and changelog --- CHANGELOG.md | 12 +++++++----- version.yml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5725c7c1..1992b0f16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ -# UTMStack 10.6.2 Release Notes -## Bug Fixes -- Enhanced the Log Explorer UI to improve usability by refining the display of Refresh, Save Query, Load Query, and Add Filter actions for a more intuitive user experience.. +# UTMStack 10.6.3 Release Notes +## New Features and Improvements +- **Agent & Collector Dependencies**: agents and collectors now fetch their dependencies from the **agent-manager**, improving consistency and centralizing dependency management. -- Updating installer to address missing GeoIP index +- **Agent Installation**: improved the installation messages for the agent to provide clearer instructions during the setup process. -- Retag docker images to github registry +- **Agent Service Cleanup**: removed unnecessary services to streamline the system and reduce overhead. + +- **Error Recovery**: enhanced the agent's ability to recover from certain data streaming errors when interacting with the agent-manager, improving stability and fault tolerance. diff --git a/version.yml b/version.yml index 23251a8ee..aa72feb11 100644 --- a/version.yml +++ b/version.yml @@ -1 +1 @@ -version: 10.6.2 \ No newline at end of file +version: 10.6.3 \ No newline at end of file From b628807a78ed8f3e4a0f7d26a081ae31adc5f7da Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Mon, 17 Mar 2025 14:45:28 -0400 Subject: [PATCH 15/19] Update dependencies --- agent-manager/go.mod | 4 ++-- agent-manager/go.sum | 30 ++++++++++++++++-------------- agent/go.mod | 6 +++--- agent/go.sum | 34 ++++++++++++++++++---------------- agent/self/go.mod | 12 ++++++------ agent/self/go.sum | 20 ++++++++++---------- log-auth-proxy/go.mod | 6 +++--- log-auth-proxy/go.sum | 34 ++++++++++++++++++---------------- 8 files changed, 76 insertions(+), 70 deletions(-) diff --git a/agent-manager/go.mod b/agent-manager/go.mod index d56a55c96..a0822d381 100644 --- a/agent-manager/go.mod +++ b/agent-manager/go.mod @@ -9,8 +9,8 @@ require ( github.com/gin-contrib/gzip v1.2.2 github.com/gin-gonic/gin v1.10.0 github.com/google/uuid v1.6.0 - github.com/threatwinds/logger v1.1.13 - google.golang.org/grpc v1.70.0 + github.com/threatwinds/logger v1.2.1 + google.golang.org/grpc v1.71.0 google.golang.org/protobuf v1.36.5 gorm.io/driver/postgres v1.5.11 gorm.io/gorm v1.25.12 diff --git a/agent-manager/go.sum b/agent-manager/go.sum index 6919e0286..852fb92da 100644 --- a/agent-manager/go.sum +++ b/agent-manager/go.sum @@ -90,22 +90,24 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.13 h1:hhN3cqWX98td1XX6hGfh5CWq4r274rLfMrtE+bgxn+w= -github.com/threatwinds/logger v1.1.13/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA= golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= @@ -121,8 +123,8 @@ golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/agent/go.mod b/agent/go.mod index 4f19d6525..e25ed3f7a 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -10,9 +10,9 @@ require ( github.com/google/uuid v1.6.0 github.com/kardianos/service v1.2.2 github.com/tehmaze/netflow v0.0.0-20240303214733-8c13bb004068 - github.com/threatwinds/logger v1.1.12 + github.com/threatwinds/logger v1.2.1 github.com/threatwinds/validations v1.0.9 - google.golang.org/grpc v1.70.0 + google.golang.org/grpc v1.71.0 google.golang.org/protobuf v1.36.5 gopkg.in/yaml.v2 v2.4.0 ) @@ -46,7 +46,7 @@ require ( golang.org/x/net v0.37.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect diff --git a/agent/go.sum b/agent/go.sum index 048b78c61..192c8f5ac 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -89,24 +89,26 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tehmaze/netflow v0.0.0-20240303214733-8c13bb004068 h1:1B+EAUqxEyPByCfk55tB21DtR7WF7Q2w71g7+uVkvIg= github.com/tehmaze/netflow v0.0.0-20240303214733-8c13bb004068/go.mod h1:QRP5wJOf7gGMGL2fCAfmh/5CMZQspRxT5DqghaPRrjM= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/threatwinds/validations v1.0.9 h1:p+DkqNpZ7g+uCmgv2FPDnkOM4ITrNxgauiTmNbVjo/E= github.com/threatwinds/validations v1.0.9/go.mod h1:POXU59KPuFTXcKl7qNWoQRNc9LiQnjbYBujjqWgW86A= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= @@ -120,10 +122,10 @@ golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/agent/self/go.mod b/agent/self/go.mod index 738410b61..f9ba38c2e 100644 --- a/agent/self/go.mod +++ b/agent/self/go.mod @@ -1,10 +1,10 @@ module github.com/utmstack/UTMStack/agent/self -go 1.22.4 +go 1.23.0 toolchain go1.23.4 -require github.com/threatwinds/logger v1.1.12 +require github.com/threatwinds/logger v1.2.1 require ( github.com/bytedance/sonic v1.12.1 // indirect @@ -29,10 +29,10 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/crypto v0.35.0 // indirect + golang.org/x/net v0.36.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/agent/self/go.sum b/agent/self/go.sum index 791835d83..7e6037bf1 100644 --- a/agent/self/go.sum +++ b/agent/self/go.sum @@ -62,24 +62,24 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= +golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= diff --git a/log-auth-proxy/go.mod b/log-auth-proxy/go.mod index f72cb2fd1..338ff0aa3 100644 --- a/log-auth-proxy/go.mod +++ b/log-auth-proxy/go.mod @@ -6,8 +6,8 @@ toolchain go1.23.4 require ( github.com/gin-gonic/gin v1.10.0 - github.com/threatwinds/logger v1.1.12 - google.golang.org/grpc v1.70.0 + github.com/threatwinds/logger v1.2.1 + google.golang.org/grpc v1.71.0 google.golang.org/protobuf v1.36.5 ) @@ -37,7 +37,7 @@ require ( golang.org/x/net v0.37.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/log-auth-proxy/go.sum b/log-auth-proxy/go.sum index e6d84d872..833a01eca 100644 --- a/log-auth-proxy/go.sum +++ b/log-auth-proxy/go.sum @@ -68,22 +68,24 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.1.12 h1:3TzwO2+m5XwSHDc3QOYvg0nUnsj/U2yJppULndRzL/4= -github.com/threatwinds/logger v1.1.12/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= +github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= +github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= @@ -96,10 +98,10 @@ golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 264b117c0ceef9e3ccb7220b175a47192d3c481c Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Mon, 17 Mar 2025 14:56:32 -0400 Subject: [PATCH 16/19] add connection mode --- installer/types/compose.go | 1 + 1 file changed, 1 insertion(+) diff --git a/installer/types/compose.go b/installer/types/compose.go index ce7b44769..2be5383f2 100644 --- a/installer/types/compose.go +++ b/installer/types/compose.go @@ -442,6 +442,7 @@ func (c *Compose) Populate(conf *Config, stack *StackConfig) *Compose { "ELASTICSEARCH_HOST=node1", "ELASTICSEARCH_PORT=9200", "ERROR_LEVEL=info", + "CONNECTION_MODE=ONLINE", }, Logging: &dLogging, Deploy: &Deploy{ From 09a53d16ed25662e70744b0c23f1ac5d54d10dd8 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Thu, 20 Mar 2025 12:11:51 -0400 Subject: [PATCH 17/19] include agent debugger, remove mTLS and fix module names --- .github/workflows/principal-multi-env.yml | 8 +- agent/agent/incident_response.go | 18 ++- agent/agent/ping_imp.go | 11 ++ agent/agent/register.go | 2 + agent/agent/update.go | 10 +- agent/collectors/collectors.go | 4 +- agent/config/const.go | 73 ++++++------ agent/conn/conn.go | 17 +-- agent/logservice/processor.go | 6 +- agent/main.go | 15 --- agent/serv/clean-old.go | 32 +++-- agent/updates/update.go | 5 +- agent/utils/certs.go | 136 ---------------------- agent/utils/download.go | 13 +-- agent/utils/logger.go | 26 ++++- agent/utils/req.go | 12 +- installer/types/compose.go | 1 + version.yml | 2 +- 18 files changed, 143 insertions(+), 248 deletions(-) delete mode 100644 agent/utils/certs.go diff --git a/.github/workflows/principal-multi-env.yml b/.github/workflows/principal-multi-env.yml index 5cbeedfdc..73beeacf9 100644 --- a/.github/workflows/principal-multi-env.yml +++ b/.github/workflows/principal-multi-env.yml @@ -54,9 +54,9 @@ jobs: $env:GOARCH = "amd64" go build -o utmstack_agent_service.exe -v . signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service.exe" - # $env:GOARCH = "arm64" - # go build -o utmstack_agent_service_arm64.exe -v . - # signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service_arm64.exe" + $env:GOARCH = "arm64" + go build -o utmstack_agent_service_arm64.exe -v . + signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service_arm64.exe" echo "Agent build completed" @@ -74,7 +74,7 @@ jobs: Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service" -Destination "./dependencies/agent/" # Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64" -Destination "./dependencies/agent/" Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service.exe" -Destination "./dependencies/agent/" - # Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64.exe" -Destination "./dependencies/agent/" + Copy-Item -Path "${{ github.workspace }}/agent/utmstack_agent_service_arm64.exe" -Destination "./dependencies/agent/" Copy-Item -Path "${{ github.workspace }}/agent/version.json" -Destination "./dependencies/agent/" docker build -t ghcr.io/utmstack/utmstack/agent-manager:${{ needs.setup_deployment.outputs.env_version }} . diff --git a/agent/agent/incident_response.go b/agent/agent/incident_response.go index 77cec794e..2ad06f481 100644 --- a/agent/agent/incident_response.go +++ b/agent/agent/incident_response.go @@ -35,6 +35,8 @@ func IncidentResponseStream(cnf *config.Config, ctx context.Context) { if !connErrMsgWritten { utils.Logger.ErrorF("failed to start AgentStream: %v", err) connErrMsgWritten = true + } else { + utils.Logger.LogF(100, "failed to start AgentStream: %v", err) } time.Sleep(timeToSleep) continue @@ -46,6 +48,7 @@ func IncidentResponseStream(cnf *config.Config, ctx context.Context) { in, err := stream.Recv() if err != nil { if strings.Contains(err.Error(), "EOF") { + utils.Logger.LogF(100, "error receiving command from server: %v", err) time.Sleep(timeToSleep) break } @@ -54,6 +57,8 @@ func IncidentResponseStream(cnf *config.Config, ctx context.Context) { if !errorLogged { utils.Logger.ErrorF("error receiving command from server: %v", err) errorLogged = true + } else { + utils.Logger.LogF(100, "error receiving command from server: %v", err) } time.Sleep(timeToSleep) break @@ -61,6 +66,8 @@ func IncidentResponseStream(cnf *config.Config, ctx context.Context) { if !errorLogged { utils.Logger.ErrorF("error receiving command from server: %v", err) errorLogged = true + } else { + utils.Logger.LogF(100, "error receiving command from server: %v", err) } time.Sleep(timeToSleep) continue @@ -72,6 +79,7 @@ func IncidentResponseStream(cnf *config.Config, ctx context.Context) { err = commandProcessor(path, stream, cnf, []string{msg.Command.Command, in.GetCommand().CmdId}) if err != nil { if strings.Contains(err.Error(), "EOF") { + utils.Logger.LogF(100, "error sending result to server: %v", err) time.Sleep(timeToSleep) break } @@ -80,6 +88,8 @@ func IncidentResponseStream(cnf *config.Config, ctx context.Context) { if !errorLogged { utils.Logger.ErrorF("error sending result to server: %v", err) errorLogged = true + } else { + utils.Logger.LogF(100, "error sending result to server: %v", err) } time.Sleep(timeToSleep) break @@ -87,6 +97,8 @@ func IncidentResponseStream(cnf *config.Config, ctx context.Context) { if !errorLogged { utils.Logger.ErrorF("error sending result to server: %v", err) errorLogged = true + } else { + utils.Logger.LogF(100, "error sending result to server: %v", err) } time.Sleep(timeToSleep) continue @@ -102,7 +114,7 @@ func commandProcessor(path string, stream AgentService_AgentStreamClient, cnf *c var result string var errB bool - utils.Logger.Info("Received command: %s", commandPair[0]) + utils.Logger.LogF(100, "Received command: %s", commandPair[0]) switch runtime.GOOS { case "windows": @@ -116,7 +128,7 @@ func commandProcessor(path string, stream AgentService_AgentStreamClient, cnf *c if errB { utils.Logger.ErrorF("error executing command %s: %s", commandPair[0], result) } else { - utils.Logger.Info("Result when executing the command %s: %s", commandPair[0], result) + utils.Logger.LogF(100, "Result when executing the command %s: %s", commandPair[0], result) } if err := stream.Send(&BidirectionalStream{ @@ -126,7 +138,7 @@ func commandProcessor(path string, stream AgentService_AgentStreamClient, cnf *c }); err != nil { return err } else { - utils.Logger.Info("Result sent to server successfully!!!") + utils.Logger.LogF(100, "Result sent to server successfully!!!") } return nil } diff --git a/agent/agent/ping_imp.go b/agent/agent/ping_imp.go index 4dea548ef..40b5081cc 100644 --- a/agent/agent/ping_imp.go +++ b/agent/agent/ping_imp.go @@ -26,6 +26,8 @@ func StartPing(cnf *config.Config, ctx context.Context) { if !connErrMsgWritten { utils.Logger.ErrorF("error connecting to Agent Manager: %v", err) connErrMsgWritten = true + } else { + utils.Logger.LogF(100, "error connecting to Agent Manager: %v", err) } time.Sleep(timeToSleep) continue @@ -37,11 +39,14 @@ func StartPing(cnf *config.Config, ctx context.Context) { if !connErrMsgWritten { utils.Logger.ErrorF("failed to start Ping Stream: %v", err) connErrMsgWritten = true + } else { + utils.Logger.LogF(100, "failed to start Ping Stream: %v", err) } time.Sleep(timeToSleep) continue } + utils.Logger.LogF(100, "Ping Stream started") connErrMsgWritten = false ticker := time.NewTicker(pingInterval) @@ -50,6 +55,7 @@ func StartPing(cnf *config.Config, ctx context.Context) { err := stream.Send(&PingRequest{Type: ConnectorType_AGENT}) if err != nil { if strings.Contains(err.Error(), "EOF") { + utils.Logger.LogF(100, "error sending Ping request: %v", err) time.Sleep(timeToSleep) break } @@ -58,6 +64,8 @@ func StartPing(cnf *config.Config, ctx context.Context) { if !errorLogged { utils.Logger.ErrorF("error sending Ping request: %v", err) errorLogged = true + } else { + utils.Logger.LogF(100, "error sending Ping request: %v", err) } time.Sleep(timeToSleep) break @@ -65,6 +73,8 @@ func StartPing(cnf *config.Config, ctx context.Context) { if !errorLogged { utils.Logger.ErrorF("error sending Ping request: %v", err) errorLogged = true + } else { + utils.Logger.LogF(100, "error sending Ping request: %v", err) } time.Sleep(timeToSleep) continue @@ -72,6 +82,7 @@ func StartPing(cnf *config.Config, ctx context.Context) { } errorLogged = false + utils.Logger.LogF(100, "Ping request sent") } ticker.Stop() diff --git a/agent/agent/register.go b/agent/agent/register.go index b69de591e..8e434f137 100644 --- a/agent/agent/register.go +++ b/agent/agent/register.go @@ -60,5 +60,7 @@ func RegisterAgent(cnf *config.Config, UTMKey string) error { cnf.AgentID = uint(response.Id) cnf.AgentKey = response.Key + utils.Logger.LogF(100, "Agent registered with ID: %v", cnf.AgentID) + return nil } diff --git a/agent/agent/update.go b/agent/agent/update.go index 7fca7450e..4ea6aa2fb 100644 --- a/agent/agent/update.go +++ b/agent/agent/update.go @@ -24,9 +24,13 @@ func UpdateAgent(cnf *config.Config, ctx context.Context) error { } version := models.Version{} - err = utils.ReadJson(config.VersionPath, &version) - if err != nil { - utils.Logger.Fatal("error reading version file: %v", err) + if utils.CheckIfPathExist(config.VersionPath) { + err = utils.ReadJson(config.VersionPath, &version) + if err != nil { + utils.Logger.Fatal("error reading version file: %v", err) + } + } else { + version.Version = "10.6.0" } request := &AgentRequest{ diff --git a/agent/collectors/collectors.go b/agent/collectors/collectors.go index 865a5df6a..dc22ec4b3 100644 --- a/agent/collectors/collectors.go +++ b/agent/collectors/collectors.go @@ -41,7 +41,7 @@ func InstallCollectors() error { } } - utils.Logger.Info("collector installed correctly") + utils.Logger.LogF(100, "collectors installed correctly") return nil } @@ -63,6 +63,6 @@ func UninstallCollectors() error { } } - utils.Logger.Info("collectors uninstalled correctly") + utils.Logger.LogF(100, "collectors uninstalled correctly") return nil } diff --git a/agent/config/const.go b/agent/config/const.go index 51ce80aae..287b4842e 100644 --- a/agent/config/const.go +++ b/agent/config/const.go @@ -32,7 +32,6 @@ var ( PortRangeMax = "9000" RetentionConfigFile = filepath.Join(utils.GetMyPath(), "retention.json") LogsDBFile = filepath.Join(utils.GetMyPath(), "logs_process", "logs.db") - CertPath = filepath.Join(utils.GetMyPath(), "certs", "utm.crt") VersionPath = filepath.Join(utils.GetMyPath(), "version.json") MESSAGE_HEADER = "utm_stack_agent_ds" BatchCapacity = 100 @@ -46,46 +45,46 @@ var ( // RedlineServName = "UTMStackRedline" // BatchToSend = 5 - DataTypeWindowsAgent DataType = "wineventlog" + DataTypeWindowsAgent DataType = "beats_windows_agent" DataTypeSyslog DataType = "syslog" - DataTypeVmware DataType = "vmware-esxi" - DataTypeLinuxAgent DataType = "linux" - DataTypeEset DataType = "antivirus-esmc-eset" - DataTypeKaspersky DataType = "antivirus-kaspersky" - DataTypeTraefikModule DataType = "traefik" - DataTypeMongodbModule DataType = "mongodb" - DataTypeMysqlModule DataType = "mysql" - DataTypePostgresqlModule DataType = "postgresql" - DataTypeRedisModule DataType = "redis" - DataTypeElasticsearchModule DataType = "elasticsearch" - DataTypeKafkaModule DataType = "kafka" - DataTypeKibanaModule DataType = "kibana" - DataTypeLogstashModule DataType = "logstash" - DataTypeCiscoAsa DataType = "firewall-cisco-asa" - DataTypeCiscoMeraki DataType = "firewall-meraki" - DataTypeFortinet DataType = "firewall-fortigate-traffic" - DataTypePaloalto DataType = "firewall-paloalto" - DataTypeMikrotik DataType = "firewall-mikrotik" - DataTypeCiscoFirepower DataType = "firewall-cisco-firepower" - DataTypeSophosXG DataType = "firewall-sophos-xg" - DataTypeCiscoSwitch DataType = "cisco-switch" - DataTypeSonicwall DataType = "firewall-sonicwall" - DataTypeNatsModule DataType = "nats" - DataTypeDeceptivebytes DataType = "deceptive-bytes" - DataTypeOsqueryModule DataType = "osquery" - DataTypeLinuxAuditdModule DataType = "auditd" - DataTypeHaproxyModule DataType = "haproxy" - DataTypeNginxModule DataType = "nginx" - DataTypeIisModule DataType = "iis" - DataTypeApacheModule DataType = "apache" - DataTypeSentinelOne DataType = "antivirus-sentinel-one" + DataTypeVmware DataType = "vmware" + DataTypeLinuxAgent DataType = "beats_linux_agent" + DataTypeEset DataType = "antivirus_eset" + DataTypeKaspersky DataType = "antivirus_kaspersky" + DataTypeTraefikModule DataType = "beats_traefik_module" + DataTypeMongodbModule DataType = "beats_mongodb_module" + DataTypeMysqlModule DataType = "beats_mysql_module" + DataTypePostgresqlModule DataType = "beats_postgresql_module" + DataTypeRedisModule DataType = "beats_redis_module" + DataTypeElasticsearchModule DataType = "beats_elasticsearch_module" + DataTypeKafkaModule DataType = "beats_kafka_module" + DataTypeKibanaModule DataType = "beats_kibana_module" + DataTypeLogstashModule DataType = "beats_logstash_module" + DataTypeCiscoAsa DataType = "cisco_asa" + DataTypeCiscoMeraki DataType = "cisco_meraki" + DataTypeFortinet DataType = "firewall_fortinet" + DataTypePaloalto DataType = "firewall_paloalto" + DataTypeMikrotik DataType = "firewall_mikrotik" + DataTypeCiscoFirepower DataType = "cisco_firepower" + DataTypeSophosXG DataType = "firewall_sophos" + DataTypeCiscoSwitch DataType = "cisco_switch" + DataTypeSonicwall DataType = "firewall_sonicwall" + DataTypeNatsModule DataType = "beats_nats_module" + DataTypeDeceptivebytes DataType = "antivirus_deceptivebytes" + DataTypeOsqueryModule DataType = "beats_osquery_module" + DataTypeLinuxAuditdModule DataType = "beats_auditd_module" + DataTypeHaproxyModule DataType = "beats_haproxy_module" + DataTypeNginxModule DataType = "beats_nginx_module" + DataTypeIisModule DataType = "beats_iis_module" + DataTypeApacheModule DataType = "beats_apache_module" + DataTypeSentinelOne DataType = "antivirus_sentinel_one" DataTypeCiscoGeneric DataType = "cisco" - DataTypeMacOs DataType = "macos" + DataTypeMacOs DataType = "macos_logs" DataTypeGeneric DataType = "generic" DataTypeNetflow DataType = "netflow" - DataTypeAix DataType = "ibm-aix" - DataTypePfsense DataType = "firewall-pfsense" - DataTypeFortiweb DataType = "firewall-fortiweb" + DataTypeAix DataType = "ibm_aix" + DataTypePfsense DataType = "firewall_pfsense" + DataTypeFortiweb DataType = "firewall_fortiweb" ProtoPorts = map[DataType]ProtoPort{ DataTypeSyslog: {UDP: "7014", TCP: "7014"}, diff --git a/agent/conn/conn.go b/agent/conn/conn.go index e045ca020..35e6a2c26 100644 --- a/agent/conn/conn.go +++ b/agent/conn/conn.go @@ -88,21 +88,10 @@ func connectToServer(addrs, port string, skip bool) (*grpc.ClientConn, error) { return nil, fmt.Errorf("failed to connect to Server: %v", err) } - dialOptions := []grpc.DialOption{ + conn, err = grpc.NewClient( + serverAddress, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMessageSize)), - } - - if !skip { - tlsCredentials, err := utils.LoadGRPCTLSCredentials(config.CertPath) - if err != nil { - return nil, fmt.Errorf("failed to load TLS credentials: %v", err) - } - dialOptions = append(dialOptions, grpc.WithTransportCredentials(tlsCredentials)) - } else { - dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))) - } - - conn, err = grpc.NewClient(serverAddress, dialOptions...) + grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: skip}))) if err != nil { connectionAttemps++ utils.Logger.ErrorF("error connecting to Server, trying again in %.0f seconds", reconnectDelay.Seconds()) diff --git a/agent/logservice/processor.go b/agent/logservice/processor.go index 009081132..fa76adda8 100644 --- a/agent/logservice/processor.go +++ b/agent/logservice/processor.go @@ -71,16 +71,16 @@ func (l *LogProcessor) ProcessLogs(cnf *config.Config, ctx context.Context) { client := NewLogServiceClient(connection) l.connErrWritten = false - l.processLogs(client, ctxEof, cancelEof) + l.processLogs(client, ctx, ctxEof, cancelEof) } } -func (l *LogProcessor) processLogs(client LogServiceClient, ctx context.Context, cancel context.CancelFunc) { +func (l *LogProcessor) processLogs(client LogServiceClient, ctx context.Context, ctxEof context.Context, cancel context.CancelFunc) { invalidKeyCounter := 0 for { select { - case <-ctx.Done(): + case <-ctxEof.Done(): utils.Logger.Info("LogProcessor: Context done, exiting...") return case newLog := <-LogQueue: diff --git a/agent/main.go b/agent/main.go index cdd84a7c7..6a4ab80ed 100644 --- a/agent/main.go +++ b/agent/main.go @@ -3,7 +3,6 @@ package main import ( "fmt" "os" - "path/filepath" "time" pb "github.com/utmstack/UTMStack/agent/agent" @@ -50,20 +49,6 @@ func main() { } fmt.Println("[OK]") - fmt.Print("Creating certificates ... ") - certsPath := filepath.Join(utils.GetMyPath(), "certs") - err = utils.CreatePathIfNotExist(certsPath) - if err != nil { - fmt.Println("\nError creating certs path: ", err) - os.Exit(1) - } - err = utils.GenerateCerts(certsPath) - if err != nil { - fmt.Println("\nError generating certs: ", err) - os.Exit(1) - } - fmt.Println("[OK]") - fmt.Print("Downloading dependencies ... ") if err := updates.DownloadFirstDependencies(cnf.Server, utmKey, cnf.SkipCertValidation); err != nil { fmt.Println("\nError downloading dependencies: ", err) diff --git a/agent/serv/clean-old.go b/agent/serv/clean-old.go index 489edd9b1..bbe3a53a3 100644 --- a/agent/serv/clean-old.go +++ b/agent/serv/clean-old.go @@ -3,6 +3,7 @@ package serv import ( "fmt" "os" + "path/filepath" "github.com/utmstack/UTMStack/agent/config" "github.com/utmstack/UTMStack/agent/utils" @@ -13,41 +14,42 @@ func CleanOldServices(cnf *config.Config) { isUpdaterINstalled, err := utils.CheckIfServiceIsInstalled("UTMStackUpdater") if err != nil { - utils.Logger.ErrorF("Error checking if service is installed: %v", err) + utils.Logger.LogF(100, "Error checking if service is installed: %v", err) } if isUpdaterINstalled { oldVersion = true err = utils.StopService("UTMStackUpdater") if err != nil { - utils.Logger.ErrorF("Error stopping service: %v", err) + utils.Logger.LogF(100, "Error stopping service: %v", err) } err = utils.UninstallService("UTMStackUpdater") if err != nil { - utils.Logger.ErrorF("Error uninstalling service: %v", err) + utils.Logger.LogF(100, "Error uninstalling service: %v", err) } } isRedlineInstalled, err := utils.CheckIfServiceIsInstalled("UTMStackRedline") if err != nil { - utils.Logger.ErrorF("Error checking if service is installed: %v", err) + utils.Logger.LogF(100, "Error checking if service is installed: %v", err) } if isRedlineInstalled { oldVersion = true err = utils.StopService("UTMStackRedline") if err != nil { - utils.Logger.ErrorF("Error stopping service: %v", err) + utils.Logger.LogF(100, "Error stopping service: %v", err) } err = utils.UninstallService("UTMStackRedline") if err != nil { - utils.Logger.ErrorF("Error uninstalling service: %v", err) + utils.Logger.LogF(100, "Error uninstalling service: %v", err) } } if oldVersion { + utils.Logger.Info("Old version of agent found, downloading new version") headers := map[string]string{ "key": cnf.AgentKey, "id": fmt.Sprintf("%v", cnf.AgentID), @@ -55,11 +57,23 @@ func CleanOldServices(cnf *config.Config) { } if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, fmt.Sprintf(config.UpdaterSelf, "")), headers, fmt.Sprintf(config.UpdaterSelf, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { - utils.Logger.ErrorF("error downloading updater: %v", err) + utils.Logger.LogF(100, "error downloading updater: %v", err) return } - os.Remove(fmt.Sprintf(config.UpdaterSelf, "")) - os.Rename(fmt.Sprintf(config.UpdaterSelf, "_new"), fmt.Sprintf(config.UpdaterSelf, "")) + oldFilePath := filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.UpdaterSelf, "")) + newFilePath := filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.UpdaterSelf, "_new")) + + utils.Logger.LogF(100, "Renaming %s to %s", newFilePath, oldFilePath) + err := os.Remove(oldFilePath) + if err != nil { + utils.Logger.LogF(100, "error removing old updater: %v", err) + } + err = os.Rename(newFilePath, oldFilePath) + if err != nil { + utils.Logger.LogF(100, "error renaming updater: %v", err) + } + } else { + utils.Logger.LogF(100, "No old version of agent found") } } diff --git a/agent/updates/update.go b/agent/updates/update.go index 4b4312c8c..f6ada2f47 100644 --- a/agent/updates/update.go +++ b/agent/updates/update.go @@ -48,7 +48,7 @@ func UpdateDependencies(cnf *config.Config) { if newVersion.Version != currentVersion.Version { utils.Logger.Info("New version of agent found: %s", newVersion.Version) - if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, fmt.Sprintf(config.ServiceFile, "")), headers, fmt.Sprintf(config.ServiceFile, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, fmt.Sprintf(config.ServiceFile, "")), headers, fmt.Sprintf(config.ServiceFile, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { utils.Logger.ErrorF("error downloading agent: %v", err) continue } @@ -59,7 +59,6 @@ func UpdateDependencies(cnf *config.Config) { utils.Logger.ErrorF("error writing version file: %v", err) continue } - os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) if runtime.GOOS == "linux" { if err = utils.Execute("chmod", utils.GetMyPath(), "-R", "777", filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.ServiceFile, "_new"))); err != nil { @@ -69,5 +68,7 @@ func UpdateDependencies(cnf *config.Config) { utils.Execute(fmt.Sprintf(config.UpdaterSelf, ""), utils.GetMyPath()) } + + os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) } } diff --git a/agent/utils/certs.go b/agent/utils/certs.go deleted file mode 100644 index 85d078654..000000000 --- a/agent/utils/certs.go +++ /dev/null @@ -1,136 +0,0 @@ -package utils - -import ( - "bytes" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "math/big" - "net" - "os" - "path/filepath" - "time" -) - -func GenerateCerts(folder string) error { - ca := &x509.Certificate{ - SerialNumber: big.NewInt(2019), - Subject: pkix.Name{ - Organization: []string{"UTMStack LLC"}, - Country: []string{"US"}, - Province: []string{"FL"}, - Locality: []string{"Coral Springs"}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(10, 0, 0), - IsCA: true, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - } - - caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) - if err != nil { - return err - } - - caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) - if err != nil { - return err - } - - caPEM := new(bytes.Buffer) - pem.Encode(caPEM, &pem.Block{ - Type: "CERTIFICATE", - Bytes: caBytes, - }) - - caPrivKeyPEM := new(bytes.Buffer) - pem.Encode(caPrivKeyPEM, &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey), - }) - - caCertFile, err := os.Create(filepath.Join(folder, "ca.crt")) - if err != nil { - return err - } - defer caCertFile.Close() - _, err = caCertFile.WriteString(caPEM.String()) - if err != nil { - return err - } - - caKeyFile, err := os.Create(filepath.Join(folder, "ca.key")) - if err != nil { - return err - } - defer caKeyFile.Close() - _, err = caKeyFile.WriteString(caPrivKeyPEM.String()) - if err != nil { - return err - } - - cert := &x509.Certificate{ - SerialNumber: big.NewInt(1658), - Subject: pkix.Name{ - Organization: []string{"UTMStack LLC"}, - Country: []string{"US"}, - Province: []string{"FL"}, - Locality: []string{"Coral Springs"}, - }, - IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, - DNSNames: []string{"localhost"}, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(10, 0, 0), - SubjectKeyId: []byte{1, 2, 3, 4, 6}, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature, - } - - certPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) - if err != nil { - return err - } - - certBytes, err := x509.CreateCertificate(rand.Reader, cert, ca, &certPrivKey.PublicKey, caPrivKey) - if err != nil { - return err - } - - certPEM := new(bytes.Buffer) - pem.Encode(certPEM, &pem.Block{ - Type: "CERTIFICATE", - Bytes: certBytes, - }) - - certPrivKeyPEM := new(bytes.Buffer) - pem.Encode(certPrivKeyPEM, &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey), - }) - - crtFile, err := os.Create(filepath.Join(folder, "utm.crt")) - if err != nil { - return err - } - defer crtFile.Close() - _, err = crtFile.WriteString(certPEM.String()) - if err != nil { - return err - } - - keyFile, err := os.Create(filepath.Join(folder, "utm.key")) - if err != nil { - return err - } - defer keyFile.Close() - _, err = keyFile.WriteString(certPrivKeyPEM.String()) - if err != nil { - return err - } - - return nil -} diff --git a/agent/utils/download.go b/agent/utils/download.go index ec350c51e..055c44881 100644 --- a/agent/utils/download.go +++ b/agent/utils/download.go @@ -1,6 +1,7 @@ package utils import ( + "crypto/tls" "fmt" "io" "net/http" @@ -8,7 +9,7 @@ import ( "path/filepath" ) -func DownloadFile(url string, headers map[string]string, fileName string, path string, skipTls bool) error { +func DownloadFile(url string, headers map[string]string, fileName string, path string, skipTlsVerification bool) error { req, err := http.NewRequest("GET", url, nil) if err != nil { return fmt.Errorf("error creating new request: %v", err) @@ -18,14 +19,8 @@ func DownloadFile(url string, headers map[string]string, fileName string, path s } client := &http.Client{} - if !skipTls { - tlsConfig, err := LoadHTTPTLSCredentials(filepath.Join(GetMyPath(), "certs", "utm.crt")) - if err != nil { - return fmt.Errorf("failed to load TLS credentials: %v", err) - } - client.Transport = &http.Transport{ - TLSClientConfig: tlsConfig, - } + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: skipTlsVerification}, } resp, err := client.Do(req) diff --git a/agent/utils/logger.go b/agent/utils/logger.go index 1ae428c49..a93ac7455 100644 --- a/agent/utils/logger.go +++ b/agent/utils/logger.go @@ -1,6 +1,7 @@ package utils import ( + "path/filepath" "sync" "github.com/threatwinds/logger" @@ -9,12 +10,35 @@ import ( var ( Logger *logger.Logger loggerOnceInstance sync.Once + logLevelConfigFile = filepath.Join(GetMyPath(), "log_level.yml") + LogLevelMap = map[string]int{ + "debug": 100, + "info": 200, + "notice": 300, + "warning": 400, + "error": 500, + "critical": 502, + "alert": 509, + } ) +type LogLevels struct { + Level string `yaml:"level"` +} + func InitLogger(filename string) { + logLevel := LogLevels{} + err := ReadYAML(logLevelConfigFile, &logLevel) + if err != nil { + logLevel.Level = "info" + } + logLevelInt := 200 + if val, ok := LogLevelMap[logLevel.Level]; ok { + logLevelInt = val + } loggerOnceInstance.Do(func() { Logger = logger.NewLogger( - &logger.Config{Format: "text", Level: 200, Output: filename, Retries: 3, Wait: 5}, + &logger.Config{Format: "text", Level: logLevelInt, Output: filename, Retries: 3, Wait: 5}, ) }) } diff --git a/agent/utils/req.go b/agent/utils/req.go index 9fe861f46..d0ed278dd 100644 --- a/agent/utils/req.go +++ b/agent/utils/req.go @@ -2,11 +2,11 @@ package utils import ( "bytes" + "crypto/tls" "encoding/json" "fmt" "io" "net/http" - "path/filepath" ) func DoReq[response any](url string, data []byte, method string, headers map[string]string, skipTlsVerification bool) (response, int, error) { @@ -22,14 +22,8 @@ func DoReq[response any](url string, data []byte, method string, headers map[str } client := &http.Client{} - if !skipTlsVerification { - tlsConfig, err := LoadHTTPTLSCredentials(filepath.Join(GetMyPath(), "certs", "utm.crt")) - if err != nil { - return result, http.StatusInternalServerError, fmt.Errorf("failed to load TLS credentials: %v", err) - } - client.Transport = &http.Transport{ - TLSClientConfig: tlsConfig, - } + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: skipTlsVerification}, } resp, err := client.Do(req) diff --git a/installer/types/compose.go b/installer/types/compose.go index 2be5383f2..5dbd6a0a3 100644 --- a/installer/types/compose.go +++ b/installer/types/compose.go @@ -153,6 +153,7 @@ func (c *Compose) Populate(conf *Config, stack *StackConfig) *Compose { }, Ports: []string{ "9000:50051", + "9001:8080", }, Environment: []string{ "DB_PATH=/data/utmstack.db", diff --git a/version.yml b/version.yml index aa72feb11..0c72b9627 100644 --- a/version.yml +++ b/version.yml @@ -1 +1 @@ -version: 10.6.3 \ No newline at end of file +version: 10.7.0 From 2323f1232e551f0ccb40a0024711a97d217380d6 Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Thu, 20 Mar 2025 13:37:19 -0400 Subject: [PATCH 18/19] add arm64 icons --- agent/rsrc_windows_arm64.syso | Bin 0 -> 205126 bytes agent/self/rsrc_windows_arm64.syso | Bin 0 -> 205126 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 agent/rsrc_windows_arm64.syso create mode 100644 agent/self/rsrc_windows_arm64.syso diff --git a/agent/rsrc_windows_arm64.syso b/agent/rsrc_windows_arm64.syso new file mode 100644 index 0000000000000000000000000000000000000000..edf10285e23291a65d9d5ee5acb6be54899da616 GIT binary patch literal 205126 zcmeHQ2V4}#{>PW(`|i-qtv5bZ%BH1$xHGQV}qOjZ)VHw(GKO{cJF3C{MhoFot^p3_q)H@z1jICr8aWI zOK{W2+?cJ$8wJjuGkY94%KR(!c+9O6Y`zX@@bVXs2=a&bxaBWySnJ{DmhvpD2f-Rv zf~65TuU!?#pL)E~K{&4wDbK`8szz=&{WeH(2*el4#w}T}{UW!6bs(SNeJF4vTr#`} z(lZC>|N6Foa<~8g>5ut`X^#br)1|gpr%i3~o-Q@uiZ(Ssu00W;)t+df$7{`r0J-MF zfGe60TfC?F(0`rwq~AEzhyG#TUwZkO`Yt2QpIX447PxiL<8Q{}ExKwy2-v7Q9*_-k zS9iQ6B9aR0)Br|Kz#0VbkF*~OVvS{>cB1_M;Zr+EXnyXiqoqiu1Q;d1+qM z0`{-~lDYjwd%Q(Q-3Nj1=#B^ep!)!@j)lWMw|*oJU>>k?${*=Y`TwB%*zaxNLq~jF zdz7E%K`rp87Qpvp-TQ$_x??R1LCm^ifq;E1^~V7%@PNq2erD}y|3d94zi}CW>9Y)E{g41#kcn>|^{lCwT#le7pT#{A801{7Xb$}r~Q!Tw69rv#!s#O*eB{?>O<2~3)I#EhNJ%e`u76Q zgP8U21tIqgU23)Ex*W>EAA=tsn!U^p7|o&G4`9t($m32*@O zKy#MJcbap)$+$k%)s-Hn7N}?e?Ylu;0snb`doz!J$#TFKY0fn_0}teyv%V1(>q_^j z1%wv3buidNcQ`oJa3r`)evT^fbhT!T+pdL@gC?*IB>2UN)c!ULrKq?sAya`Ac3mad2&Dc4!IH{?bA{#H8x_xB73TO&p&2P(c7s@@N9 z9Pj}ifL!vquesE0hwhAz@KZ%8L&Ryzu1xj+t6_iZDTV{Bel#2a>|>!EfH4#7y`TGi zfPFVwYYs3xz<%LJ^(Wp_u$`S2L=vu;{+-~Sfd4`s`;-Ihcp<>Qy*O}*_ynZ7)T~f( z**j9gaB-@l8~3&LHtuizkzrr!a^L`S@8|GO{Q!f1J99vNsTuT-yvspODL?V@b}B$g zs5099&HrwACuE&rf5@L8h!M&GGF}vq8Rf@~+TRZl4qOHvV7cP`r|OFLI_-_-f0qz^ zBwbYeyS{N>$XNZp*54TR0rs&_4lv)(kZ)*M{5KQ_2oEq9nth|Z+$^4syQp7!8Q%`> zpnp3g3-136_9+L*H^t1ilz@H5ascxHsjqrxDKC3aA8TW>oL3sRAKLB&harnn;er_QV`vH~% zmKNZ`|7k5&TmQSms&8^DRo71DFR$ zmF9I{mFD@D;?t%tJ13GKzE*h7Hq+kFnZ`HU`~>(%L?{QCd3U*aM!B^!aDd?f@WJzE zaoN;%X&Bi@#@9@~C9Iz38z!f+^c!0nk+)<@B-D0}p`JA&60m1kN!|t}@ zjJw-@5BNt!IP7z4>IWDuaPc?rntKl5*3R@iVC4rG4uC&Es?Uggue{!Ld|H|tL|u~p zQnIT}7r?$8guy=Lz(dBN5pcnEIDnME1;usGJk52FaH+CD^G2|TX;;`W)9$uqAc%4R z$6>kzP&)Ei;mjV8NH|=VRF#ahA*tkrT1Ke)} z_;&(E$TM-Jz7X*Pm;;P7Mas{c{;s_4u|k<9-nsD*a%*JV6*jVDXIKf~A2C8XU=@>$ za-c38z&t?88%;}|^{>4m40qKFgRPv5%Q!#|zc) z`@q9;fcOLO2_9vto9_G7*WF)fXfBXB+qQ?zHSK8kUl0cO9R4W>CVX58 z3m!;$)8iL)hWos)GU`7*CxVdoaNqB5+TKnBf(ZU82OJ)k(slg+&jHK>q|ETp7T;_< z5I>vNhhH#kZPUWIz1_u9f}+K>E?z?caWtjqcFa`^XRry4W&sL#YTaljoZGu@FQ!@U&x zM_nG)Cm7#o+wImH?F&lYz}V*md;sM@jU3Q_5csF|Sj!9g4_Z#p9J6oCFC0TmbJBkT z@Zf^>W4}9;1Dr1)&%}bh5a$P24qzT+x!+S}HA$`w55C+O;$_;}{zSeWJ?&?v&%`VbxPA~`1NMm@z#PEa z*-gq7S&ipZ#{Y>zHI! z`+*$YvB2*5U2#QwI$|Hc3sisP*Hd%GH@Cs(TC~hFCjkzCPsna^yEv;!h_IbXwzM~c z4*>jA4%muIsXH3@o%U!@qNDEn!gi}_8-J$(ejyQf@Lhw=H!3v_WDy=Hgt4Xw{wW8T zxUAL357g8b zBG1Rz7l1Tg%(WZk0K_M&HZEmQx&CP2Y0bMqKAgRzw1ybOKEQ#~nzPNztzytTY77oG z{(#lI)6(<ZM( zU|#^w#|yB{ClocQCS`@Vlw3?cC+iF0{!npFlZ7tM0fYW<(2&~V#u?LT z&NmyXzTjiTJYeF~yA}r&xs6Y`A_pK&_pcDMe$iK3>;IbzDewk=djkGovF4)BuZ$0H zDL{;`J2gygEQU?hKdUKu#0n^c*MO&+R&in- z-yl|wV0!@v#(+QgnsC8c{eTm5z<8kbpCGGo9AmNKObX?K@kf8xT=rR`x!mkeHO~Vl z>I*p|2llrr*B@woQn$aQrxY+Il`<+WczeP4pp(!?g81~51N=9|cuon?%q!8_46(ZN zP5WAPmkO?=SWe(T58y(9`m(oK+GFPMxH%A~@dK@YfSARTa9k%T;!0{|R;IfBRei~O zGRTjF2i%xZyq3(kQD@;m>%01QLbiYXuJ1pkh9hSvujbR&{;9gsYzK^+zAL@4(-P;v zz7VtFoz|bI-wd?d95T*;Nk`Q|eaR~T`bL+)2bifJXps3vb%uSd`#Y+=>2<5Ofbz2U z0QIL{x{5Kn>u7$M)#NY4+L-VXV%@tx3lh8?aQ%d>g}ibI3P zXaf)CtFC(e;+T2nYWp3Tq&RTj^mgbz?ao%OildcjDQaT@?d8U=s;+tO2Oiv~e&CVg z&_K-Mkn6fPL)+HI<}{5sEug&Gv@Q6A>kxOq%*P<$V$k4qz0I{~J--m&4`RNlXTK>1 zUm)6dqoJjyw?aoDk;NJjC(6WMD*UY$#H5c=UG@CJJ~24BIp&=4c_8$*;jNGrIHsBS zTb7paVJ(1Ti7Br&U8%a}dHWIKkv-&`yVCLlrnlOZ8Q*I2LCLOG?hk8MnqGPqP+x88 zu1@zlu1@nTqkW+^$oOWc+_0yOWMj}u4}sz-vF4gbIB+13;eoy9UKhU~FumF4TjQH; z#v@sTQ^X<{53;0H5(Kg6mFZr|5PRTT`^Fy-H3#mP_JnT1u|1^KTC}wFX#wRYufL$W z-gJxVGtWC9c8I|tQV#5HdrrT*wO@VOlIAUK3n)Hw_fvl6c@Bh)&yCmc{s+fo<>ZFc z-V3!c8+W%=n|6gpNxOAu=^N4l>d)Mx0Q+hXv!pq&Gwf&6?$B9uOmjn`$9b-W$7mO) zd(KvV?(sA41DII#I9@#~Fg60mq-5e!3gVGDyf1VgV${D?vMsDZ;<7kTtJ9iPWdTK2 z)0cqH`!i@t`GOwLY#T3o!pKnhgqY8BCyX`&4-nx% zavaJTABS>h3`d2B+ad*iE~p_crG3YZhM7yYx63lV(XONI($f^21x!2Jw=CJ-{!+=d zc4j{IC*=TVo+{V!Fiau_M6x{nE9FLXz zhK!F(S@-YAjN96M4gH>Y9Q&=xLeqnlEMVBt>Lsw*PSduqdnCp=j(N+){-hkJWG{T+ zR($;5@+OU%mp3`)zkq)vpBRH|aUeTs49W&Brfo1E6Xif9TL}&{%AY!NK;D#58u{c=NInV6LvSEz zEXp1SGBFnAzu5&T;I{-EpPLBxE%8HsLvst_)tk1pKV{m|R+2I41h#F^&5~VVJxx2q z3Qar7yJAE+VB7q;6GsH(O&NJHf6B=6JdFRka3C=rWr1YR9Dxc?1lNTF3iyqyr|r_y z6r2UV+!5ks+THdP{61I?96&^NzC-Lf*FSs2HA?`TmfNc_mC++x-Xnt5ehHm}b76Y;C~1v1d)Y+pIJ0ZgUs#k4(E* z{9_(a4peDAjIaD@(UbD04gXL6)Db8TOMP%40eAqCyLRr0c zAtYvNl?A5ylyLG(r&9+|~_q0VYHW2VnIbda^Dt3yd59?kqeRv_@9}#H) z4rIkAqMW4zQSnXSK_x%X-fY_3;d05QFqeu+S4Go2)FIvOkWTRZXC{0Hgp7NzP!8BK zVBX|t@4^|;9~R7rF3+DH&EOyNpn*7$IW`gHu8Bg$LSF#$O5EDqeh_^3-^f<^sh+Wb zad$vt`2P7Q;Qs*#d<#lBU<(^r)A~GHFn!qCf*C_^7t9!jfCI=;9Kbxt-`~OF3xET* z%1`x-1>}1}o;JQ6ved9Q^nb>^p@`t0a-c?d;IU&xGX{?-oH_KXf|(fmoH&vL<4`8N zLoK?}oS%EW#!6778{8xs8QuvU22x^t8?cY@PdQ){8AY>)v@4uFB(rel5HoN9iHZYb z$D!O+eNizRf52vCTsVPYUr;N%fGLpxT-_9yj$z^v<2ZN&^hN}|rkBCqX*u;WzLBF7)xdW~i&mCwk znv3x-F%Ez)C^#AH^6!Oo2V45;4+Wny911Q64lww~JfIw?mIL|I`n;r=H(*ckyn**Y zP%*~8L^&Ye(amK!Pz-Z?>D~?6qJKB|uKo~U9}DF`wYbL$d2+}Tih2EJDCYP7xp+Q| zJ;3;vI0v$q4stmT;PDN*!$HaVBSGKm4+kUtyR8uAK#kDH%0|kCQN0xl`>PZS`XdF# zzmsqvb6Si`almjSAi{7oNUlEu*vI&%9Iy%g;zj*@l?(fxhQ7a<;NQtOkdYMc5*#ob z3h>e$4LYtr8dL`Ne?&Q86Z&q-S-oCREb6;Sv8dml%7y(9_yFXT9DuQOwyh!E6x#jG z|E_&MV72bOpg;8Q0rrn#{8J9p)S@Ul`Z49=-pQ&(eZNyK>Wh?%`XQ(0KwOejasZD3 zGQ_3R#PrbC)O2Gdgs-=Ap_y7>s;y`9x(g!sfNdn4@)YqTV9&fQg zm)i1Iz&|2FIZ$KE;W5q1WxZn5%X*iBAT`Fni*g_%cKnPQjU{3w?(^$D^c$p2ZK2bp z1|TAo12$VsxujcL_3~cVHOnH+1pltgfw*yI@B@;J38P8%ZK?gR#U&84_5_Q6%md1S zYB``@-1!x?EONhQdE|Y~@?HpdfLxseH{-??!b>4ZeM6~C^?yNg(toG+WQ%)%f292| z08tK93wxrtFwOf(?TQ}rbSXW5(a0hZ5y}CC$4+O&B~7W>dg9T__qsiy``B-?_LTpB zv>yTXPh$L24%E~_`2MDqbsYfs*J)FFA`KSG0ffJuAu?v%cQ+Cf|6Y>~#i9f3_t2j9 zF9iG}?MGNB2W+*CW?7e(x|KaHYFBnQ0|yZ00L(E2zX#**=~?{4b3o!mTXuA`UU}Nf zTXWj)Bkjk2nzgICP13FE_5sK z?pEYLMttJk8?o`CoI_WA#=D*RoNt!qTyryU08tLu#=cJ0$y2|k>q(Guz(3Nh#`vck zAak!*!GTP`KRgc%ux;6fO;L2g`*qC)pLYTK<(hMVeT;v~ff^gZAPaleur_=R$e)0J zM1*nxkr*6Y{DF!bh)?(-YfNI-8V%dPO8J>ro>pD(S**R_^Q-23b42h@IZ$IOplG+p z0QYf*b>Uwc)|>!EklAVi!`cq*jqAJIG_3Dp1`Z&~0UVQziOI*sBdf@P?8LF(X2r)Rro#6Sw(Q$b zdhNxgf$B>>SJa<0GpjH9Aj$!VOJ*Y;nQnFa*NhuF9|HV80Q@6@f64)?xRh0J;7(TJ z*v$p;@&9NjY}>jH^m|@ZU-8}z_`j$A1h9{Va)61;R}BYl$s+z{+SqZSabu_7fCC6P zfG7uQj!T&{Zj2dx!P$)XcwbwXY$&~4?)HS{iq|ytm1aMwFE>NL0S5n+1J%Z*#N!)` zn>r0PZtQ3@ZR}(w_@^AGIWA>VoEdz9DmQUVpN7JAEw0l@{b|#l>Z{%gz&|4RryQ^u zj||5^F>UI2#k8pt0{kQ6M!5fD{8J88%Yp3iaX)8|i<_m4j{a*caM>V9G@p9Wx&NV*FDM*oaG62G7JtZ*6J+UdiST$g~;bpK`!PTuL*YCR#AP6`BLOEbFF6A5TvrU`BI^jlwIEb4l2W-csluwAc zm7N?D4KI@a(jefj#YL3YnsijAd*%QK%&IiNKIK3y;!=ivYuXx?kP5$daVDl5uoaVU z)bH|%G0Wu1{hsD*=IFKZbI&HK&ph8#eb%%b@Q(=oDF6>a9I{h~`RKcl?vv0V9?=kFj0cz`GeY{jK)TW;JQ_OWSuShMQd zjdGw04on%9l{;~G$Leg>(8pykrdf5P>2T%e9wo}_O_B1tC!!pvMO?}qVMQf7!Xj<8 z7v+GE10%l9n=~Q;&-ZA{ZVjbZrg{8ZdBfv0h*=47?kNXq6_@fyn;u^R{*m$q;Gc59R$R*ard@4z8FsXKsW$fI z(zrGUqRn~JhMy{!KD64tB4?+DUMp|7cU5M1{01BV{8J9p9G5cGY~0i4ifLy^%SUM^ zm*l|oVdjGA(Taj8(W3mOi`@S+0sk3*eaZn_aVd4iJt2c01^e7NuE&As9}8zhPfe4F z^PBdZw3q&^$ZYbZGQ%BF4%8T%^;gqdAq&3R`ubBGmLGNPDjX=BIqY8kjG;SmJikY^ zRehg_-~SY6H94)w#Q3Kis46a{VQ=UIMy z4(t#45`4mF;rIr7^1vB6P&j+=Z^g3*FUXkHzRrC`d)m6Dyc9W2VhR2!2ZS-YZyOJU ztSZ_R_)JZx-HLi~HVDF6_Hi zIjfh$`ieqZ)z>z`zjHqm-!r@)__p$(|G(?YhIPqTj2uue>01tQ>dz?`^>KJ#u`af) z?YYj(0sXO-X`1(1ie?^;s@g<^98jwl_w6f%@eNhk^HGjDDF<$8-wzm$#{oWyO&anX zv2Xxl)&EzyBx<%{S|3sM6&s>0oQneizw3{;TqfW9ifHEHu+@f+=74Hh?+1YYw-t-K zi)PL?TQ;+|-YGb6BA`s4+VVZ)u>jG`!%^FIauf$N%OcGXr#@Z1xL51imepC)Nt**L z%(@dTvUREcWX?7zwvmH4P@-NQIl`6t{54@ix*Q1jT6@AjAx-A?cun;ayRLyb@IQ^L z=ko98M%L?CSh3r@V)>-T0o_Obe`-&**idlFLo{(lD%$j6_8Wo&x)nXk0Q>K&mvnP~ zn6kM_TIq1W&#e8(|Fr2tKhe#@Q5US#KL>isb+R6k?JL&BwzWN1^c*-1*#FqCSaZtP z=A3P{t+SZY)guSK)voA14oTqsu%p{U*Q!V)z|gy&ViNP?&w!_-&i1v zaEiWSec4@@uP8Zi*6*(7wC^t68J`!0Wp&1FdvQR&x?8z+Ww$fhRb87qqn+xjP9+<| zB1Of4bIr{Vulus@tWQvV)md!$+JggzHC+|PRS~_RZla&RK`iz+ZE5RsYfFbyV1H)J zs0hZ)sn7Zv)MtGLOJRJ2J=?KP99Y}+C;gg;8HQ=%8VhSr``9}#)B2F-Oq)AwxV5Rn zZ5;mx$B1^cAJATC{+s5!&%#@29)GiUeWj4!BXZz@VQu&x!`jZGowH4Bw#WBYhI}w2Xo+J^9Py>K8LiYo7-*9HnG{gHsyIJ4y^BDHmvJ%RkyyA%k&j%V?$eM zAkJ+^hL1&Nf@N5Tm}f9DrE$2DtAJqvIQD--@R7 z9h(5|-z(YFsf>yF32{Fi&4EkJzEEBCj!jLq#H6czjhr*3O%AN@{F`BY=f&U1LL@U5 z*3m8XJ-m2q-ZPGSPU7A=lmmaLFEv}Oz0q9q^KjU^eQV%AnPFq+BgWNT zBsUh;-ZrXjez?zXSl@AY$;Qqm(?*PYp|J6v8`uwMu6UQLE_-+%&IHi1l3PRaZSH(msFf+LYzMpSL!5 zT&La8k@gj9XErxHKZs#{r`g60U48)$AR-Rtfbxf7Y@ZG#OZ+WK+BT zUu|vgO^s1I3*h%+`n8?&zpl%9)B4Wk1pgx7K=FxSlrw(_%1VewS&0d(!~+-N?_?&7-THY< z%=7lDKh4K=EufUOf5EUWe5+x7_#Fery-*zF2NV~5k$iO&U>>la0NBT3%>m2ceq$zqB-?z%{lUd<8wj-+4PWde)~`5ricfCC_o<$xm13+3;OKw0C*pse^r3;wI& zK=wH76ULge$BoI)Op1+=UMtWNJIVrvRS^;Twc!PTeHb4C*mp1o6cD4n;7D7PJ#7?& zeT@Iwa$ww8lucv|=0a+AQe1FV_PKQ(IFJL+6gf$8=G^gP zKF=9Hx{b)1h8Cv*ETCK6xvg$Z*BgL+vwlriBpME6xTD-PQI>mueR2TvfJoefoaER8 z^5j^_#q?|ds5spv)N4Aw0^dI$1l&Jhu#fRC4h|G&x+D449w>7R+xHRTzdrncg#*Ba zI0QWSRX#p;L0Wu-OMX-4bYQPgprL=4A`YP339(r2 z=1v&BL!La!>E{}9Cer9+5ie?1b=?K`|GOYaw~D#{b3726A1J!yi!$I{55~U;IlypX zV(gE($)l&FMMOw?o@r;oc~x~mvWUlZE4xhv`H{gs#=rPEkPGiYIsA*30~1CA7h=rd z6N>XEjP72Q{pm5sT0kx9-b1^xN3m{Y52RbkVV_%z*AEnDc%aPjW2M1?iNFI8IdDNf zar8%dlVj<)d&k0_TwT4iXEW`}?x#S^zyZL&v^Y@kVKB;wWBNdxFA&KyG50*ct{MCj z4qzT&K1_=FQ$BIjI(c&Rb0UC(%N4=2pvQACxAl7MiXMN0AdG)0azMVVyJR^apA>_L zOpN(TK55igI!3!;Xqblk{42VT1>AqFUC|Q}{7aYv*^38Dp96#oqs+jE%!0`y>3j_J zNCoY(o*i{5Ju?CKW(NP#=RoGH|#FC6z(NDP?VC`7p zuV%G>O1&&{Da14TU6T@tus9tD;>J5E2Y?GxFds&mawm@*=4x}g*Odl%Of%f`hiR5a zmS|*veJqp%_8&W4Y0MlmUWgqlVe`FE&3=I8z?6}|gAwMuDI>4uP8->(uGnye^VN&H zwFb;z1^k?meN@YOtAGP$_43}xB{>kAw9GX* z06dt+a3ODM^ts$g(JmFwv3OCWuX&`a1R8cwa2+`@CvtpUvtez3-}*^uD=7y!4h%;H)1y(rjA6Op8^WD|2a1KgBh*Wxa^e1uuuu+I$E7437&GQI_>TAw zjt5d1H(Eb_faL(@!Sv{|!WqMk!P`l�F4U7=hY^#{Q|#y{l% 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 BRp0;s literal 0 HcmV?d00001 diff --git a/agent/self/rsrc_windows_arm64.syso b/agent/self/rsrc_windows_arm64.syso new file mode 100644 index 0000000000000000000000000000000000000000..edf10285e23291a65d9d5ee5acb6be54899da616 GIT binary patch literal 205126 zcmeHQ2V4}#{>PW(`|i-qtv5bZ%BH1$xHGQV}qOjZ)VHw(GKO{cJF3C{MhoFot^p3_q)H@z1jICr8aWI zOK{W2+?cJ$8wJjuGkY94%KR(!c+9O6Y`zX@@bVXs2=a&bxaBWySnJ{DmhvpD2f-Rv zf~65TuU!?#pL)E~K{&4wDbK`8szz=&{WeH(2*el4#w}T}{UW!6bs(SNeJF4vTr#`} z(lZC>|N6Foa<~8g>5ut`X^#br)1|gpr%i3~o-Q@uiZ(Ssu00W;)t+df$7{`r0J-MF zfGe60TfC?F(0`rwq~AEzhyG#TUwZkO`Yt2QpIX447PxiL<8Q{}ExKwy2-v7Q9*_-k zS9iQ6B9aR0)Br|Kz#0VbkF*~OVvS{>cB1_M;Zr+EXnyXiqoqiu1Q;d1+qM z0`{-~lDYjwd%Q(Q-3Nj1=#B^ep!)!@j)lWMw|*oJU>>k?${*=Y`TwB%*zaxNLq~jF zdz7E%K`rp87Qpvp-TQ$_x??R1LCm^ifq;E1^~V7%@PNq2erD}y|3d94zi}CW>9Y)E{g41#kcn>|^{lCwT#le7pT#{A801{7Xb$}r~Q!Tw69rv#!s#O*eB{?>O<2~3)I#EhNJ%e`u76Q zgP8U21tIqgU23)Ex*W>EAA=tsn!U^p7|o&G4`9t($m32*@O zKy#MJcbap)$+$k%)s-Hn7N}?e?Ylu;0snb`doz!J$#TFKY0fn_0}teyv%V1(>q_^j z1%wv3buidNcQ`oJa3r`)evT^fbhT!T+pdL@gC?*IB>2UN)c!ULrKq?sAya`Ac3mad2&Dc4!IH{?bA{#H8x_xB73TO&p&2P(c7s@@N9 z9Pj}ifL!vquesE0hwhAz@KZ%8L&Ryzu1xj+t6_iZDTV{Bel#2a>|>!EfH4#7y`TGi zfPFVwYYs3xz<%LJ^(Wp_u$`S2L=vu;{+-~Sfd4`s`;-Ihcp<>Qy*O}*_ynZ7)T~f( z**j9gaB-@l8~3&LHtuizkzrr!a^L`S@8|GO{Q!f1J99vNsTuT-yvspODL?V@b}B$g zs5099&HrwACuE&rf5@L8h!M&GGF}vq8Rf@~+TRZl4qOHvV7cP`r|OFLI_-_-f0qz^ zBwbYeyS{N>$XNZp*54TR0rs&_4lv)(kZ)*M{5KQ_2oEq9nth|Z+$^4syQp7!8Q%`> zpnp3g3-136_9+L*H^t1ilz@H5ascxHsjqrxDKC3aA8TW>oL3sRAKLB&harnn;er_QV`vH~% zmKNZ`|7k5&TmQSms&8^DRo71DFR$ zmF9I{mFD@D;?t%tJ13GKzE*h7Hq+kFnZ`HU`~>(%L?{QCd3U*aM!B^!aDd?f@WJzE zaoN;%X&Bi@#@9@~C9Iz38z!f+^c!0nk+)<@B-D0}p`JA&60m1kN!|t}@ zjJw-@5BNt!IP7z4>IWDuaPc?rntKl5*3R@iVC4rG4uC&Es?Uggue{!Ld|H|tL|u~p zQnIT}7r?$8guy=Lz(dBN5pcnEIDnME1;usGJk52FaH+CD^G2|TX;;`W)9$uqAc%4R z$6>kzP&)Ei;mjV8NH|=VRF#ahA*tkrT1Ke)} z_;&(E$TM-Jz7X*Pm;;P7Mas{c{;s_4u|k<9-nsD*a%*JV6*jVDXIKf~A2C8XU=@>$ za-c38z&t?88%;}|^{>4m40qKFgRPv5%Q!#|zc) z`@q9;fcOLO2_9vto9_G7*WF)fXfBXB+qQ?zHSK8kUl0cO9R4W>CVX58 z3m!;$)8iL)hWos)GU`7*CxVdoaNqB5+TKnBf(ZU82OJ)k(slg+&jHK>q|ETp7T;_< z5I>vNhhH#kZPUWIz1_u9f}+K>E?z?caWtjqcFa`^XRry4W&sL#YTaljoZGu@FQ!@U&x zM_nG)Cm7#o+wImH?F&lYz}V*md;sM@jU3Q_5csF|Sj!9g4_Z#p9J6oCFC0TmbJBkT z@Zf^>W4}9;1Dr1)&%}bh5a$P24qzT+x!+S}HA$`w55C+O;$_;}{zSeWJ?&?v&%`VbxPA~`1NMm@z#PEa z*-gq7S&ipZ#{Y>zHI! z`+*$YvB2*5U2#QwI$|Hc3sisP*Hd%GH@Cs(TC~hFCjkzCPsna^yEv;!h_IbXwzM~c z4*>jA4%muIsXH3@o%U!@qNDEn!gi}_8-J$(ejyQf@Lhw=H!3v_WDy=Hgt4Xw{wW8T zxUAL357g8b zBG1Rz7l1Tg%(WZk0K_M&HZEmQx&CP2Y0bMqKAgRzw1ybOKEQ#~nzPNztzytTY77oG z{(#lI)6(<ZM( zU|#^w#|yB{ClocQCS`@Vlw3?cC+iF0{!npFlZ7tM0fYW<(2&~V#u?LT z&NmyXzTjiTJYeF~yA}r&xs6Y`A_pK&_pcDMe$iK3>;IbzDewk=djkGovF4)BuZ$0H zDL{;`J2gygEQU?hKdUKu#0n^c*MO&+R&in- z-yl|wV0!@v#(+QgnsC8c{eTm5z<8kbpCGGo9AmNKObX?K@kf8xT=rR`x!mkeHO~Vl z>I*p|2llrr*B@woQn$aQrxY+Il`<+WczeP4pp(!?g81~51N=9|cuon?%q!8_46(ZN zP5WAPmkO?=SWe(T58y(9`m(oK+GFPMxH%A~@dK@YfSARTa9k%T;!0{|R;IfBRei~O zGRTjF2i%xZyq3(kQD@;m>%01QLbiYXuJ1pkh9hSvujbR&{;9gsYzK^+zAL@4(-P;v zz7VtFoz|bI-wd?d95T*;Nk`Q|eaR~T`bL+)2bifJXps3vb%uSd`#Y+=>2<5Ofbz2U z0QIL{x{5Kn>u7$M)#NY4+L-VXV%@tx3lh8?aQ%d>g}ibI3P zXaf)CtFC(e;+T2nYWp3Tq&RTj^mgbz?ao%OildcjDQaT@?d8U=s;+tO2Oiv~e&CVg z&_K-Mkn6fPL)+HI<}{5sEug&Gv@Q6A>kxOq%*P<$V$k4qz0I{~J--m&4`RNlXTK>1 zUm)6dqoJjyw?aoDk;NJjC(6WMD*UY$#H5c=UG@CJJ~24BIp&=4c_8$*;jNGrIHsBS zTb7paVJ(1Ti7Br&U8%a}dHWIKkv-&`yVCLlrnlOZ8Q*I2LCLOG?hk8MnqGPqP+x88 zu1@zlu1@nTqkW+^$oOWc+_0yOWMj}u4}sz-vF4gbIB+13;eoy9UKhU~FumF4TjQH; z#v@sTQ^X<{53;0H5(Kg6mFZr|5PRTT`^Fy-H3#mP_JnT1u|1^KTC}wFX#wRYufL$W z-gJxVGtWC9c8I|tQV#5HdrrT*wO@VOlIAUK3n)Hw_fvl6c@Bh)&yCmc{s+fo<>ZFc z-V3!c8+W%=n|6gpNxOAu=^N4l>d)Mx0Q+hXv!pq&Gwf&6?$B9uOmjn`$9b-W$7mO) zd(KvV?(sA41DII#I9@#~Fg60mq-5e!3gVGDyf1VgV${D?vMsDZ;<7kTtJ9iPWdTK2 z)0cqH`!i@t`GOwLY#T3o!pKnhgqY8BCyX`&4-nx% zavaJTABS>h3`d2B+ad*iE~p_crG3YZhM7yYx63lV(XONI($f^21x!2Jw=CJ-{!+=d zc4j{IC*=TVo+{V!Fiau_M6x{nE9FLXz zhK!F(S@-YAjN96M4gH>Y9Q&=xLeqnlEMVBt>Lsw*PSduqdnCp=j(N+){-hkJWG{T+ zR($;5@+OU%mp3`)zkq)vpBRH|aUeTs49W&Brfo1E6Xif9TL}&{%AY!NK;D#58u{c=NInV6LvSEz zEXp1SGBFnAzu5&T;I{-EpPLBxE%8HsLvst_)tk1pKV{m|R+2I41h#F^&5~VVJxx2q z3Qar7yJAE+VB7q;6GsH(O&NJHf6B=6JdFRka3C=rWr1YR9Dxc?1lNTF3iyqyr|r_y z6r2UV+!5ks+THdP{61I?96&^NzC-Lf*FSs2HA?`TmfNc_mC++x-Xnt5ehHm}b76Y;C~1v1d)Y+pIJ0ZgUs#k4(E* z{9_(a4peDAjIaD@(UbD04gXL6)Db8TOMP%40eAqCyLRr0c zAtYvNl?A5ylyLG(r&9+|~_q0VYHW2VnIbda^Dt3yd59?kqeRv_@9}#H) z4rIkAqMW4zQSnXSK_x%X-fY_3;d05QFqeu+S4Go2)FIvOkWTRZXC{0Hgp7NzP!8BK zVBX|t@4^|;9~R7rF3+DH&EOyNpn*7$IW`gHu8Bg$LSF#$O5EDqeh_^3-^f<^sh+Wb zad$vt`2P7Q;Qs*#d<#lBU<(^r)A~GHFn!qCf*C_^7t9!jfCI=;9Kbxt-`~OF3xET* z%1`x-1>}1}o;JQ6ved9Q^nb>^p@`t0a-c?d;IU&xGX{?-oH_KXf|(fmoH&vL<4`8N zLoK?}oS%EW#!6778{8xs8QuvU22x^t8?cY@PdQ){8AY>)v@4uFB(rel5HoN9iHZYb z$D!O+eNizRf52vCTsVPYUr;N%fGLpxT-_9yj$z^v<2ZN&^hN}|rkBCqX*u;WzLBF7)xdW~i&mCwk znv3x-F%Ez)C^#AH^6!Oo2V45;4+Wny911Q64lww~JfIw?mIL|I`n;r=H(*ckyn**Y zP%*~8L^&Ye(amK!Pz-Z?>D~?6qJKB|uKo~U9}DF`wYbL$d2+}Tih2EJDCYP7xp+Q| zJ;3;vI0v$q4stmT;PDN*!$HaVBSGKm4+kUtyR8uAK#kDH%0|kCQN0xl`>PZS`XdF# zzmsqvb6Si`almjSAi{7oNUlEu*vI&%9Iy%g;zj*@l?(fxhQ7a<;NQtOkdYMc5*#ob z3h>e$4LYtr8dL`Ne?&Q86Z&q-S-oCREb6;Sv8dml%7y(9_yFXT9DuQOwyh!E6x#jG z|E_&MV72bOpg;8Q0rrn#{8J9p)S@Ul`Z49=-pQ&(eZNyK>Wh?%`XQ(0KwOejasZD3 zGQ_3R#PrbC)O2Gdgs-=Ap_y7>s;y`9x(g!sfNdn4@)YqTV9&fQg zm)i1Iz&|2FIZ$KE;W5q1WxZn5%X*iBAT`Fni*g_%cKnPQjU{3w?(^$D^c$p2ZK2bp z1|TAo12$VsxujcL_3~cVHOnH+1pltgfw*yI@B@;J38P8%ZK?gR#U&84_5_Q6%md1S zYB``@-1!x?EONhQdE|Y~@?HpdfLxseH{-??!b>4ZeM6~C^?yNg(toG+WQ%)%f292| z08tK93wxrtFwOf(?TQ}rbSXW5(a0hZ5y}CC$4+O&B~7W>dg9T__qsiy``B-?_LTpB zv>yTXPh$L24%E~_`2MDqbsYfs*J)FFA`KSG0ffJuAu?v%cQ+Cf|6Y>~#i9f3_t2j9 zF9iG}?MGNB2W+*CW?7e(x|KaHYFBnQ0|yZ00L(E2zX#**=~?{4b3o!mTXuA`UU}Nf zTXWj)Bkjk2nzgICP13FE_5sK z?pEYLMttJk8?o`CoI_WA#=D*RoNt!qTyryU08tLu#=cJ0$y2|k>q(Guz(3Nh#`vck zAak!*!GTP`KRgc%ux;6fO;L2g`*qC)pLYTK<(hMVeT;v~ff^gZAPaleur_=R$e)0J zM1*nxkr*6Y{DF!bh)?(-YfNI-8V%dPO8J>ro>pD(S**R_^Q-23b42h@IZ$IOplG+p z0QYf*b>Uwc)|>!EklAVi!`cq*jqAJIG_3Dp1`Z&~0UVQziOI*sBdf@P?8LF(X2r)Rro#6Sw(Q$b zdhNxgf$B>>SJa<0GpjH9Aj$!VOJ*Y;nQnFa*NhuF9|HV80Q@6@f64)?xRh0J;7(TJ z*v$p;@&9NjY}>jH^m|@ZU-8}z_`j$A1h9{Va)61;R}BYl$s+z{+SqZSabu_7fCC6P zfG7uQj!T&{Zj2dx!P$)XcwbwXY$&~4?)HS{iq|ytm1aMwFE>NL0S5n+1J%Z*#N!)` zn>r0PZtQ3@ZR}(w_@^AGIWA>VoEdz9DmQUVpN7JAEw0l@{b|#l>Z{%gz&|4RryQ^u zj||5^F>UI2#k8pt0{kQ6M!5fD{8J88%Yp3iaX)8|i<_m4j{a*caM>V9G@p9Wx&NV*FDM*oaG62G7JtZ*6J+UdiST$g~;bpK`!PTuL*YCR#AP6`BLOEbFF6A5TvrU`BI^jlwIEb4l2W-csluwAc zm7N?D4KI@a(jefj#YL3YnsijAd*%QK%&IiNKIK3y;!=ivYuXx?kP5$daVDl5uoaVU z)bH|%G0Wu1{hsD*=IFKZbI&HK&ph8#eb%%b@Q(=oDF6>a9I{h~`RKcl?vv0V9?=kFj0cz`GeY{jK)TW;JQ_OWSuShMQd zjdGw04on%9l{;~G$Leg>(8pykrdf5P>2T%e9wo}_O_B1tC!!pvMO?}qVMQf7!Xj<8 z7v+GE10%l9n=~Q;&-ZA{ZVjbZrg{8ZdBfv0h*=47?kNXq6_@fyn;u^R{*m$q;Gc59R$R*ard@4z8FsXKsW$fI z(zrGUqRn~JhMy{!KD64tB4?+DUMp|7cU5M1{01BV{8J9p9G5cGY~0i4ifLy^%SUM^ zm*l|oVdjGA(Taj8(W3mOi`@S+0sk3*eaZn_aVd4iJt2c01^e7NuE&As9}8zhPfe4F z^PBdZw3q&^$ZYbZGQ%BF4%8T%^;gqdAq&3R`ubBGmLGNPDjX=BIqY8kjG;SmJikY^ zRehg_-~SY6H94)w#Q3Kis46a{VQ=UIMy z4(t#45`4mF;rIr7^1vB6P&j+=Z^g3*FUXkHzRrC`d)m6Dyc9W2VhR2!2ZS-YZyOJU ztSZ_R_)JZx-HLi~HVDF6_Hi zIjfh$`ieqZ)z>z`zjHqm-!r@)__p$(|G(?YhIPqTj2uue>01tQ>dz?`^>KJ#u`af) z?YYj(0sXO-X`1(1ie?^;s@g<^98jwl_w6f%@eNhk^HGjDDF<$8-wzm$#{oWyO&anX zv2Xxl)&EzyBx<%{S|3sM6&s>0oQneizw3{;TqfW9ifHEHu+@f+=74Hh?+1YYw-t-K zi)PL?TQ;+|-YGb6BA`s4+VVZ)u>jG`!%^FIauf$N%OcGXr#@Z1xL51imepC)Nt**L z%(@dTvUREcWX?7zwvmH4P@-NQIl`6t{54@ix*Q1jT6@AjAx-A?cun;ayRLyb@IQ^L z=ko98M%L?CSh3r@V)>-T0o_Obe`-&**idlFLo{(lD%$j6_8Wo&x)nXk0Q>K&mvnP~ zn6kM_TIq1W&#e8(|Fr2tKhe#@Q5US#KL>isb+R6k?JL&BwzWN1^c*-1*#FqCSaZtP z=A3P{t+SZY)guSK)voA14oTqsu%p{U*Q!V)z|gy&ViNP?&w!_-&i1v zaEiWSec4@@uP8Zi*6*(7wC^t68J`!0Wp&1FdvQR&x?8z+Ww$fhRb87qqn+xjP9+<| zB1Of4bIr{Vulus@tWQvV)md!$+JggzHC+|PRS~_RZla&RK`iz+ZE5RsYfFbyV1H)J zs0hZ)sn7Zv)MtGLOJRJ2J=?KP99Y}+C;gg;8HQ=%8VhSr``9}#)B2F-Oq)AwxV5Rn zZ5;mx$B1^cAJATC{+s5!&%#@29)GiUeWj4!BXZz@VQu&x!`jZGowH4Bw#WBYhI}w2Xo+J^9Py>K8LiYo7-*9HnG{gHsyIJ4y^BDHmvJ%RkyyA%k&j%V?$eM zAkJ+^hL1&Nf@N5Tm}f9DrE$2DtAJqvIQD--@R7 z9h(5|-z(YFsf>yF32{Fi&4EkJzEEBCj!jLq#H6czjhr*3O%AN@{F`BY=f&U1LL@U5 z*3m8XJ-m2q-ZPGSPU7A=lmmaLFEv}Oz0q9q^KjU^eQV%AnPFq+BgWNT zBsUh;-ZrXjez?zXSl@AY$;Qqm(?*PYp|J6v8`uwMu6UQLE_-+%&IHi1l3PRaZSH(msFf+LYzMpSL!5 zT&La8k@gj9XErxHKZs#{r`g60U48)$AR-Rtfbxf7Y@ZG#OZ+WK+BT zUu|vgO^s1I3*h%+`n8?&zpl%9)B4Wk1pgx7K=FxSlrw(_%1VewS&0d(!~+-N?_?&7-THY< z%=7lDKh4K=EufUOf5EUWe5+x7_#Fery-*zF2NV~5k$iO&U>>la0NBT3%>m2ceq$zqB-?z%{lUd<8wj-+4PWde)~`5ricfCC_o<$xm13+3;OKw0C*pse^r3;wI& zK=wH76ULge$BoI)Op1+=UMtWNJIVrvRS^;Twc!PTeHb4C*mp1o6cD4n;7D7PJ#7?& zeT@Iwa$ww8lucv|=0a+AQe1FV_PKQ(IFJL+6gf$8=G^gP zKF=9Hx{b)1h8Cv*ETCK6xvg$Z*BgL+vwlriBpME6xTD-PQI>mueR2TvfJoefoaER8 z^5j^_#q?|ds5spv)N4Aw0^dI$1l&Jhu#fRC4h|G&x+D449w>7R+xHRTzdrncg#*Ba zI0QWSRX#p;L0Wu-OMX-4bYQPgprL=4A`YP339(r2 z=1v&BL!La!>E{}9Cer9+5ie?1b=?K`|GOYaw~D#{b3726A1J!yi!$I{55~U;IlypX zV(gE($)l&FMMOw?o@r;oc~x~mvWUlZE4xhv`H{gs#=rPEkPGiYIsA*30~1CA7h=rd z6N>XEjP72Q{pm5sT0kx9-b1^xN3m{Y52RbkVV_%z*AEnDc%aPjW2M1?iNFI8IdDNf zar8%dlVj<)d&k0_TwT4iXEW`}?x#S^zyZL&v^Y@kVKB;wWBNdxFA&KyG50*ct{MCj z4qzT&K1_=FQ$BIjI(c&Rb0UC(%N4=2pvQACxAl7MiXMN0AdG)0azMVVyJR^apA>_L zOpN(TK55igI!3!;Xqblk{42VT1>AqFUC|Q}{7aYv*^38Dp96#oqs+jE%!0`y>3j_J zNCoY(o*i{5Ju?CKW(NP#=RoGH|#FC6z(NDP?VC`7p zuV%G>O1&&{Da14TU6T@tus9tD;>J5E2Y?GxFds&mawm@*=4x}g*Odl%Of%f`hiR5a zmS|*veJqp%_8&W4Y0MlmUWgqlVe`FE&3=I8z?6}|gAwMuDI>4uP8->(uGnye^VN&H zwFb;z1^k?meN@YOtAGP$_43}xB{>kAw9GX* z06dt+a3ODM^ts$g(JmFwv3OCWuX&`a1R8cwa2+`@CvtpUvtez3-}*^uD=7y!4h%;H)1y(rjA6Op8^WD|2a1KgBh*Wxa^e1uuuu+I$E7437&GQI_>TAw zjt5d1H(Eb_faL(@!Sv{|!WqMk!P`l�F4U7=hY^#{Q|#y{l% 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 BRp0;s literal 0 HcmV?d00001 From 98e05e2aa38c56fc0ca76a40938125898710272f Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara Date: Thu, 20 Mar 2025 13:42:12 -0400 Subject: [PATCH 19/19] Update changelog --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1992b0f16..e4b1ddbdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# UTMStack 10.6.3 Release Notes +# UTMStack 10.7.0 Release Notes ## New Features and Improvements - **Agent & Collector Dependencies**: agents and collectors now fetch their dependencies from the **agent-manager**, improving consistency and centralizing dependency management. @@ -7,3 +7,9 @@ - **Agent Service Cleanup**: removed unnecessary services to streamline the system and reduce overhead. - **Error Recovery**: enhanced the agent's ability to recover from certain data streaming errors when interacting with the agent-manager, improving stability and fault tolerance. + +- **Debug Mode for Agents**: Added a debug mode for agents, allowing better troubleshooting and logging for debugging purposes. + +- **Certificate Verification Improvements**: Improved certificate verification in agents to enhance security and prevent connection issues. + +- **Windows ARM64 Agent Support**: Added support for a Windows ARM64 agent, expanding compatibility to more architectures. \ No newline at end of file