runtime.go 8.3 KB

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