runtime.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. package parser
  2. /*
  3. This file contains
  4. - the runtime parsing routines
  5. */
  6. import (
  7. "errors"
  8. "fmt"
  9. "reflect"
  10. "strings"
  11. "time"
  12. "github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
  13. "github.com/crowdsecurity/crowdsec/pkg/types"
  14. "strconv"
  15. "github.com/davecgh/go-spew/spew"
  16. "github.com/mohae/deepcopy"
  17. "github.com/prometheus/client_golang/prometheus"
  18. log "github.com/sirupsen/logrus"
  19. "github.com/antonmedv/expr"
  20. )
  21. /* ok, this is kinda experimental, I don't know how bad of an idea it is .. */
  22. func SetTargetByName(target string, value string, evt *types.Event) bool {
  23. if evt == nil {
  24. return false
  25. }
  26. //it's a hack, we do it for the user
  27. target = strings.TrimPrefix(target, "evt.")
  28. log.Debugf("setting target %s to %s", target, value)
  29. defer func() {
  30. if r := recover(); r != nil {
  31. log.Errorf("Runtime error while trying to set '%s' in %s : %+v", target, spew.Sdump(evt), r)
  32. return
  33. }
  34. }()
  35. iter := reflect.ValueOf(evt).Elem()
  36. if (iter == reflect.Value{}) || iter.IsZero() {
  37. log.Tracef("event is nill")
  38. //event is nill
  39. return false
  40. }
  41. for _, f := range strings.Split(target, ".") {
  42. /*
  43. ** According to current Event layout we only have to handle struct and map
  44. */
  45. switch iter.Kind() {
  46. case reflect.Map:
  47. tmp := iter.MapIndex(reflect.ValueOf(f))
  48. /*if we're in a map and the field doesn't exist, the user wants to add it :) */
  49. if (tmp == reflect.Value{}) || tmp.IsZero() {
  50. log.Debugf("map entry is zero in '%s'", target)
  51. }
  52. iter.SetMapIndex(reflect.ValueOf(f), reflect.ValueOf(value))
  53. return true
  54. case reflect.Struct:
  55. tmp := iter.FieldByName(f)
  56. if !tmp.IsValid() {
  57. log.Debugf("%s IsValid false", f)
  58. return false
  59. }
  60. iter = tmp
  61. break
  62. default:
  63. log.Errorf("unexpected type %s in '%s'", iter.Kind(), target)
  64. return false
  65. }
  66. }
  67. //now we should have the final member :)
  68. if !iter.CanSet() {
  69. log.Errorf("'%s' can't be set", target)
  70. return false
  71. }
  72. if iter.Kind() != reflect.String {
  73. log.Errorf("Expected string, got %v when handling '%s'", iter.Kind(), target)
  74. return false
  75. }
  76. iter.Set(reflect.ValueOf(value))
  77. return true
  78. }
  79. func printStaticTarget(static types.ExtraField) string {
  80. if static.Method != "" {
  81. return static.Method
  82. } else if static.Parsed != "" {
  83. return fmt.Sprintf(".Parsed[%s]", static.Parsed)
  84. } else if static.Meta != "" {
  85. return fmt.Sprintf(".Meta[%s]", static.Meta)
  86. } else if static.Enriched != "" {
  87. return fmt.Sprintf(".Enriched[%s]", static.Enriched)
  88. } else if static.TargetByName != "" {
  89. return static.TargetByName
  90. } else {
  91. return "?"
  92. }
  93. }
  94. func (n *Node) ProcessStatics(statics []types.ExtraField, event *types.Event) error {
  95. //we have a few cases :
  96. //(meta||key) + (static||reference||expr)
  97. var value string
  98. clog := n.Logger
  99. for _, static := range statics {
  100. value = ""
  101. if static.Value != "" {
  102. value = static.Value
  103. } else if static.RunTimeValue != nil {
  104. output, err := expr.Run(static.RunTimeValue, exprhelpers.GetExprEnv(map[string]interface{}{"evt": event}))
  105. if err != nil {
  106. clog.Warningf("failed to run RunTimeValue : %v", err)
  107. continue
  108. }
  109. switch out := output.(type) {
  110. case string:
  111. value = out
  112. case int:
  113. value = strconv.Itoa(out)
  114. default:
  115. clog.Fatalf("unexpected return type for RunTimeValue : %T", output)
  116. return errors.New("unexpected return type for RunTimeValue")
  117. }
  118. }
  119. if value == "" {
  120. //allow ParseDate to have empty input
  121. if static.Method != "ParseDate" {
  122. clog.Debugf("Empty value for %s, skip.", printStaticTarget(static))
  123. continue
  124. }
  125. }
  126. if static.Method != "" {
  127. processed := false
  128. /*still way too hackish, but : inject all the results in enriched, and */
  129. if enricherPlugin, ok := n.EnrichFunctions.Registered[static.Method]; ok {
  130. clog.Tracef("Found method '%s'", static.Method)
  131. ret, err := enricherPlugin.EnrichFunc(value, event, enricherPlugin.Ctx)
  132. if err != nil {
  133. clog.Errorf("method '%s' returned an error : %v", static.Method, err)
  134. }
  135. processed = true
  136. clog.Debugf("+ Method %s('%s') returned %d entries to merge in .Enriched\n", static.Method, value, len(ret))
  137. if len(ret) == 0 {
  138. clog.Debugf("+ Method '%s' empty response on '%s'", static.Method, value)
  139. }
  140. for k, v := range ret {
  141. clog.Debugf("\t.Enriched[%s] = '%s'\n", k, v)
  142. event.Enriched[k] = v
  143. }
  144. } else {
  145. clog.Debugf("method '%s' doesn't exist or plugin not initialized", static.Method)
  146. }
  147. if !processed {
  148. clog.Debugf("method '%s' doesn't exist", static.Method)
  149. }
  150. } else if static.Parsed != "" {
  151. clog.Debugf(".Parsed[%s] = '%s'", static.Parsed, value)
  152. event.Parsed[static.Parsed] = value
  153. } else if static.Meta != "" {
  154. clog.Debugf(".Meta[%s] = '%s'", static.Meta, value)
  155. event.Meta[static.Meta] = value
  156. } else if static.Enriched != "" {
  157. clog.Debugf(".Enriched[%s] = '%s'", static.Enriched, value)
  158. event.Enriched[static.Enriched] = value
  159. } else if static.TargetByName != "" {
  160. if !SetTargetByName(static.TargetByName, value, event) {
  161. clog.Errorf("Unable to set value of '%s'", static.TargetByName)
  162. } else {
  163. clog.Debugf("%s = '%s'", static.TargetByName, value)
  164. }
  165. } else {
  166. clog.Fatalf("unable to process static : unknown tartget")
  167. }
  168. }
  169. return nil
  170. }
  171. var NodesHits = prometheus.NewCounterVec(
  172. prometheus.CounterOpts{
  173. Name: "cs_node_hits_total",
  174. Help: "Total events entered node.",
  175. },
  176. []string{"source", "type", "name"},
  177. )
  178. var NodesHitsOk = prometheus.NewCounterVec(
  179. prometheus.CounterOpts{
  180. Name: "cs_node_hits_ok_total",
  181. Help: "Total events successfully exited node.",
  182. },
  183. []string{"source", "type", "name"},
  184. )
  185. var NodesHitsKo = prometheus.NewCounterVec(
  186. prometheus.CounterOpts{
  187. Name: "cs_node_hits_ko_total",
  188. Help: "Total events unsuccessfully exited node.",
  189. },
  190. []string{"source", "type", "name"},
  191. )
  192. func stageidx(stage string, stages []string) int {
  193. for i, v := range stages {
  194. if stage == v {
  195. return i
  196. }
  197. }
  198. return -1
  199. }
  200. type ParserResult struct {
  201. Evt types.Event
  202. Success bool
  203. }
  204. var ParseDump bool
  205. var DumpFolder string
  206. var StageParseCache map[string]map[string][]ParserResult
  207. func Parse(ctx UnixParserCtx, xp types.Event, nodes []Node) (types.Event, error) {
  208. var event types.Event = xp
  209. /* the stage is undefined, probably line is freshly acquired, set to first stage !*/
  210. if event.Stage == "" && len(ctx.Stages) > 0 {
  211. event.Stage = ctx.Stages[0]
  212. log.Tracef("no stage, set to : %s", event.Stage)
  213. }
  214. event.Process = false
  215. if event.Time.IsZero() {
  216. event.Time = time.Now().UTC()
  217. }
  218. if event.Parsed == nil {
  219. event.Parsed = make(map[string]string)
  220. }
  221. if event.Enriched == nil {
  222. event.Enriched = make(map[string]string)
  223. }
  224. if event.Meta == nil {
  225. event.Meta = make(map[string]string)
  226. }
  227. if event.Type == types.LOG {
  228. log.Tracef("INPUT '%s'", event.Line.Raw)
  229. }
  230. if ParseDump {
  231. if StageParseCache == nil {
  232. StageParseCache = make(map[string]map[string][]ParserResult)
  233. StageParseCache["success"] = make(map[string][]ParserResult)
  234. StageParseCache["success"][""] = make([]ParserResult, 0)
  235. }
  236. }
  237. for _, stage := range ctx.Stages {
  238. if ParseDump {
  239. if _, ok := StageParseCache[stage]; !ok {
  240. StageParseCache[stage] = make(map[string][]ParserResult)
  241. }
  242. }
  243. /* if the node is forward in stages, seek to its stage */
  244. /* this is for example used by testing system to inject logs in post-syslog-parsing phase*/
  245. if stageidx(event.Stage, ctx.Stages) > stageidx(stage, ctx.Stages) {
  246. log.Tracef("skipping stage, we are already at [%s] expecting [%s]", event.Stage, stage)
  247. continue
  248. }
  249. log.Tracef("node stage : %s, current stage : %s", event.Stage, stage)
  250. /* if the stage is wrong, it means that the log didn't manage "pass" a stage with a onsuccess: next_stage tag */
  251. if event.Stage != stage {
  252. log.Debugf("Event not parsed, expected stage '%s' got '%s', abort", stage, event.Stage)
  253. return types.Event{Process: false}, nil
  254. }
  255. isStageOK := false
  256. for idx, node := range nodes {
  257. //Only process current stage's nodes
  258. if event.Stage != node.Stage {
  259. continue
  260. }
  261. clog := log.WithFields(log.Fields{
  262. "node-name": node.rn,
  263. "stage": event.Stage,
  264. })
  265. clog.Tracef("Processing node %d/%d -> %s", idx, len(nodes), node.rn)
  266. if ctx.Profiling {
  267. node.Profiling = true
  268. }
  269. ret, err := node.process(&event, ctx)
  270. if err != nil {
  271. clog.Fatalf("Error while processing node : %v", err)
  272. }
  273. clog.Tracef("node (%s) ret : %v", node.rn, ret)
  274. if ParseDump {
  275. if len(StageParseCache[stage][node.Name]) == 0 {
  276. StageParseCache[stage][node.Name] = make([]ParserResult, 0)
  277. }
  278. evtcopy := deepcopy.Copy(event)
  279. parserInfo := ParserResult{Evt: evtcopy.(types.Event), Success: ret}
  280. StageParseCache[stage][node.Name] = append(StageParseCache[stage][node.Name], parserInfo)
  281. }
  282. if ret {
  283. isStageOK = true
  284. }
  285. if ret && node.OnSuccess == "next_stage" {
  286. clog.Debugf("node successful, stop end stage %s", stage)
  287. break
  288. }
  289. //the parsed object moved onto the next phase
  290. if event.Stage != stage {
  291. clog.Tracef("node moved stage, break and redo")
  292. break
  293. }
  294. }
  295. if !isStageOK {
  296. log.Debugf("Log didn't finish stage %s", event.Stage)
  297. event.Process = false
  298. return event, nil
  299. }
  300. }
  301. event.Process = true
  302. return event, nil
  303. }