File: stage.go

package info (click to toggle)
crowdsec 1.4.6-10.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 18,500 kB
  • sloc: sh: 2,870; makefile: 386; python: 74
file content (134 lines) | stat: -rw-r--r-- 3,772 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package parser

/*
 This file contains
 - the runtime definition of parser
 - the compilation/parsing routines of parser configuration
*/

import (
	"errors"
	"fmt"
	"io"
	_ "net/http/pprof"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/crowdsecurity/crowdsec/pkg/cwversion"
	"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"

	log "github.com/sirupsen/logrus"

	"github.com/goombaio/namegenerator"
	yaml "gopkg.in/yaml.v2"
)

var seed namegenerator.Generator = namegenerator.NewNameGenerator(time.Now().UTC().UnixNano())

/*
 identify generic component to alter maps, smartfilters ? (static, conditional static etc.)
*/

type Stagefile struct {
	Filename string `yaml:"filename"`
	Stage    string `yaml:"stage"`
}

func LoadStages(stageFiles []Stagefile, pctx *UnixParserCtx, ectx EnricherCtx) ([]Node, error) {
	var nodes []Node
	tmpstages := make(map[string]bool)
	pctx.Stages = []string{}

	for _, stageFile := range stageFiles {
		if !strings.HasSuffix(stageFile.Filename, ".yaml") && !strings.HasSuffix(stageFile.Filename, ".yml") {
			log.Warningf("skip non yaml : %s", stageFile.Filename)
			continue
		}
		log.Debugf("loading parser file '%s'", stageFile)
		st, err := os.Stat(stageFile.Filename)
		if err != nil {
			return nil, fmt.Errorf("failed to stat %s : %v", stageFile, err)
		}
		if st.IsDir() {
			continue
		}
		yamlFile, err := os.Open(stageFile.Filename)
		if err != nil {
			return nil, fmt.Errorf("can't access parsing configuration file %s : %s", stageFile.Filename, err)
		}
		//process the yaml
		dec := yaml.NewDecoder(yamlFile)
		dec.SetStrict(true)
		nodesCount := 0
		for {
			node := Node{}
			node.OnSuccess = "continue" //default behavior is to continue
			err = dec.Decode(&node)
			if err != nil {
				if errors.Is(err, io.EOF) {
					log.Tracef("End of yaml file")
					break
				}
				log.Fatalf("Error decoding parsing configuration file '%s': %v", stageFile.Filename, err)
			}

			//check for empty bucket
			if node.Name == "" && node.Description == "" && node.Author == "" {
				log.Infof("Node in %s has no name,author or description. Skipping.", stageFile.Filename)
				continue
			}
			//check compat
			if node.FormatVersion == "" {
				log.Tracef("no version in %s, assuming '1.0'", node.Name)
				node.FormatVersion = "1.0"
			}
			ok, err := cwversion.Statisfies(node.FormatVersion, cwversion.Constraint_parser)
			if err != nil {
				log.Fatalf("Failed to check version : %s", err)
			}
			if !ok {
				log.Errorf("%s : %s doesn't satisfy parser format %s, skip", node.Name, node.FormatVersion, cwversion.Constraint_parser)
				continue
			}

			node.Stage = stageFile.Stage
			if _, ok := tmpstages[stageFile.Stage]; !ok {
				tmpstages[stageFile.Stage] = true
			}
			//compile the node : grok pattern and expression
			err = node.compile(pctx, ectx)
			if err != nil {
				if node.Name != "" {
					return nil, fmt.Errorf("failed to compile node '%s' in '%s' : %s", node.Name, stageFile.Filename, err)
				}
				return nil, fmt.Errorf("failed to compile node in '%s' : %s", stageFile.Filename, err)
			}
			/* if the stage is empty, the node is empty, it's a trailing entry in users yaml file */
			if node.Stage == "" {
				continue
			}

			if len(node.Data) > 0 {
				for _, data := range node.Data {
					err = exprhelpers.FileInit(pctx.DataFolder, data.DestPath, data.Type)
					if err != nil {
						log.Error(err)
					}
				}
			}
			nodes = append(nodes, node)
			nodesCount++
		}
		log.WithFields(log.Fields{"file": stageFile.Filename, "stage": stageFile.Stage}).Infof("Loaded %d parser nodes", nodesCount)
	}

	for k := range tmpstages {
		pctx.Stages = append(pctx.Stages, k)
	}
	sort.Strings(pctx.Stages)
	log.Infof("Loaded %d nodes from %d stages", len(nodes), len(pctx.Stages))

	return nodes, nil
}