stage.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. "errors"
  9. "fmt"
  10. "io"
  11. _ "net/http/pprof"
  12. "os"
  13. "sort"
  14. "strings"
  15. "time"
  16. "github.com/goombaio/namegenerator"
  17. log "github.com/sirupsen/logrus"
  18. yaml "gopkg.in/yaml.v2"
  19. "github.com/crowdsecurity/crowdsec/pkg/cwversion"
  20. "github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
  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, ectx EnricherCtx) ([]Node, error) {
  31. var nodes []Node
  32. tmpstages := make(map[string]bool)
  33. pctx.Stages = []string{}
  34. for _, stageFile := range stageFiles {
  35. if !strings.HasSuffix(stageFile.Filename, ".yaml") && !strings.HasSuffix(stageFile.Filename, ".yml") {
  36. log.Warningf("skip non yaml : %s", stageFile.Filename)
  37. continue
  38. }
  39. log.Debugf("loading parser file '%s'", stageFile)
  40. st, err := os.Stat(stageFile.Filename)
  41. if err != nil {
  42. return nil, fmt.Errorf("failed to stat %s : %v", stageFile, err)
  43. }
  44. if st.IsDir() {
  45. continue
  46. }
  47. yamlFile, err := os.Open(stageFile.Filename)
  48. if err != nil {
  49. return nil, fmt.Errorf("can't access parsing configuration file %s : %s", stageFile.Filename, err)
  50. }
  51. //process the yaml
  52. dec := yaml.NewDecoder(yamlFile)
  53. dec.SetStrict(true)
  54. nodesCount := 0
  55. for {
  56. node := Node{}
  57. node.OnSuccess = "continue" //default behavior is to continue
  58. err = dec.Decode(&node)
  59. if err != nil {
  60. if errors.Is(err, io.EOF) {
  61. log.Tracef("End of yaml file")
  62. break
  63. }
  64. log.Fatalf("Error decoding parsing configuration file '%s': %v", stageFile.Filename, err)
  65. }
  66. //check for empty bucket
  67. if node.Name == "" && node.Description == "" && node.Author == "" {
  68. log.Infof("Node in %s has no name, author or description. Skipping.", stageFile.Filename)
  69. continue
  70. }
  71. //check compat
  72. if node.FormatVersion == "" {
  73. log.Tracef("no version in %s, assuming '1.0'", node.Name)
  74. node.FormatVersion = "1.0"
  75. }
  76. ok, err := cwversion.Satisfies(node.FormatVersion, cwversion.Constraint_parser)
  77. if err != nil {
  78. log.Fatalf("Failed to check version : %s", err)
  79. }
  80. if !ok {
  81. log.Errorf("%s : %s doesn't satisfy parser format %s, skip", node.Name, node.FormatVersion, cwversion.Constraint_parser)
  82. continue
  83. }
  84. node.Stage = stageFile.Stage
  85. if _, ok := tmpstages[stageFile.Stage]; !ok {
  86. tmpstages[stageFile.Stage] = true
  87. }
  88. //compile the node : grok pattern and expression
  89. err = node.compile(pctx, ectx)
  90. if err != nil {
  91. if node.Name != "" {
  92. return nil, fmt.Errorf("failed to compile node '%s' in '%s' : %s", node.Name, stageFile.Filename, err)
  93. }
  94. return nil, fmt.Errorf("failed to compile node in '%s' : %s", stageFile.Filename, err)
  95. }
  96. /* if the stage is empty, the node is empty, it's a trailing entry in users yaml file */
  97. if node.Stage == "" {
  98. continue
  99. }
  100. for _, data := range node.Data {
  101. err = exprhelpers.FileInit(pctx.DataFolder, data.DestPath, data.Type)
  102. if err != nil {
  103. log.Error(err)
  104. }
  105. if data.Type == "regexp" { //cache only makes sense for regexp
  106. exprhelpers.RegexpCacheInit(data.DestPath, *data)
  107. }
  108. }
  109. nodes = append(nodes, node)
  110. nodesCount++
  111. }
  112. log.WithFields(log.Fields{"file": stageFile.Filename, "stage": stageFile.Stage}).Infof("Loaded %d parser nodes", nodesCount)
  113. }
  114. for k := range tmpstages {
  115. pctx.Stages = append(pctx.Stages, k)
  116. }
  117. sort.Strings(pctx.Stages)
  118. log.Infof("Loaded %d nodes from %d stages", len(nodes), len(pctx.Stages))
  119. return nodes, nil
  120. }