stage.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package parser
  2. /*
  3. This file contains
  4. - the runtime definition of parser
  5. - the compilation/parsing routines of parser configuration
  6. */
  7. import (
  8. //"fmt"
  9. "fmt"
  10. "io"
  11. _ "net/http/pprof"
  12. "os"
  13. "path/filepath"
  14. "sort"
  15. "strings"
  16. "time"
  17. "github.com/crowdsecurity/crowdsec/pkg/cwversion"
  18. log "github.com/sirupsen/logrus"
  19. "github.com/goombaio/namegenerator"
  20. yaml "gopkg.in/yaml.v2"
  21. )
  22. var seed namegenerator.Generator = namegenerator.NewNameGenerator(time.Now().UTC().UnixNano())
  23. /*
  24. identify generic component to alter maps, smartfilters ? (static, conditional static etc.)
  25. */
  26. type Stagefile struct {
  27. Filename string `yaml:"filename"`
  28. Stage string `yaml:"stage"`
  29. }
  30. func LoadStages(stageFiles []Stagefile, pctx *UnixParserCtx) ([]Node, error) {
  31. var nodes []Node
  32. tmpstages := make(map[string]bool)
  33. for _, stageFile := range stageFiles {
  34. if !strings.HasSuffix(stageFile.Filename, ".yaml") {
  35. log.Warningf("skip non yaml : %s", stageFile.Filename)
  36. continue
  37. }
  38. st, err := os.Stat(stageFile.Filename)
  39. if err != nil {
  40. return nil, fmt.Errorf("failed to stat %s : %v", stageFile, err)
  41. }
  42. if st.IsDir() {
  43. continue
  44. }
  45. yamlFile, err := os.Open(stageFile.Filename)
  46. if err != nil {
  47. return nil, fmt.Errorf("can't access parsing configuration file %s : %s", stageFile.Filename, err)
  48. }
  49. //process the yaml
  50. dec := yaml.NewDecoder(yamlFile)
  51. dec.SetStrict(true)
  52. nodesCount := 0
  53. for {
  54. node := Node{}
  55. node.OnSuccess = "continue" //default behaviour is to continue
  56. err = dec.Decode(&node)
  57. if err != nil {
  58. if err == io.EOF {
  59. log.Tracef("End of yaml file")
  60. break
  61. }
  62. log.Fatalf("Error decoding parsing configuration file '%s': %v", stageFile.Filename, err)
  63. }
  64. //check for empty bucket
  65. if node.Name == "" && node.Description == "" && node.Author == "" {
  66. log.Infof("Node has no name,author or description. Skipping.")
  67. continue
  68. }
  69. //check compat
  70. if node.FormatVersion == "" {
  71. log.Debugf("no version in %s, assuming '1.0'", stageFile.Filename)
  72. node.FormatVersion = "1.0"
  73. }
  74. ok, err := cwversion.Statisfies(node.FormatVersion, cwversion.Constraint_parser)
  75. if err != nil {
  76. log.Fatalf("Failed to check version : %s", err)
  77. }
  78. if !ok {
  79. log.Errorf("%s doesn't satisfy parser format %s, skip", node.FormatVersion, cwversion.Constraint_parser)
  80. continue
  81. }
  82. node.Stage = stageFile.Stage
  83. if _, ok := tmpstages[stageFile.Stage]; !ok {
  84. tmpstages[stageFile.Stage] = true
  85. }
  86. //compile the node : grok pattern and expression
  87. err = node.compile(pctx)
  88. if err != nil {
  89. if node.Name != "" {
  90. return nil, fmt.Errorf("failed to compile node '%s' in '%s' : %s", node.Name, stageFile.Filename, err.Error())
  91. }
  92. return nil, fmt.Errorf("failed to compile node in '%s' : %s", stageFile.Filename, err.Error())
  93. }
  94. /* if the stage is empty, the node is empty, it's a trailing entry in users yaml file */
  95. if node.Stage == "" {
  96. continue
  97. }
  98. nodes = append(nodes, node)
  99. nodesCount++
  100. }
  101. log.WithFields(log.Fields{"file": stageFile.Filename}).Infof("Loaded %d parser nodes", nodesCount)
  102. }
  103. for k := range tmpstages {
  104. pctx.Stages = append(pctx.Stages, k)
  105. }
  106. sort.Strings(pctx.Stages)
  107. log.Debugf("Stages loaded: %+v", pctx.Stages)
  108. return nodes, nil
  109. }
  110. func LoadStageDir(dir string, pctx *UnixParserCtx) ([]Node, error) {
  111. var files []Stagefile
  112. m, err := filepath.Glob(dir + "/*/*")
  113. if err != nil {
  114. return nil, fmt.Errorf("unable to find configs in '%s' : %v", dir, err)
  115. }
  116. for _, f := range m {
  117. tmp := Stagefile{}
  118. tmp.Filename = f
  119. //guess stage : (prefix - file).split('/')[0]
  120. stages := strings.Split(f, "/")
  121. stage := stages[len(stages)-2]
  122. tmp.Stage = stage
  123. files = append(files, tmp)
  124. }
  125. return LoadStages(files, pctx)
  126. }