main.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. _ "net/http/pprof"
  6. "os"
  7. "runtime"
  8. "strings"
  9. "time"
  10. "github.com/pkg/errors"
  11. log "github.com/sirupsen/logrus"
  12. "gopkg.in/tomb.v2"
  13. "github.com/crowdsecurity/crowdsec/pkg/acquisition"
  14. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  15. "github.com/crowdsecurity/crowdsec/pkg/csplugin"
  16. "github.com/crowdsecurity/crowdsec/pkg/cwhub"
  17. "github.com/crowdsecurity/crowdsec/pkg/cwversion"
  18. "github.com/crowdsecurity/crowdsec/pkg/fflag"
  19. "github.com/crowdsecurity/crowdsec/pkg/leakybucket"
  20. "github.com/crowdsecurity/crowdsec/pkg/parser"
  21. "github.com/crowdsecurity/crowdsec/pkg/types"
  22. )
  23. var (
  24. /*tombs for the parser, buckets and outputs.*/
  25. acquisTomb tomb.Tomb
  26. parsersTomb tomb.Tomb
  27. bucketsTomb tomb.Tomb
  28. outputsTomb tomb.Tomb
  29. apiTomb tomb.Tomb
  30. crowdsecTomb tomb.Tomb
  31. pluginTomb tomb.Tomb
  32. flags *Flags
  33. /*the state of acquisition*/
  34. dataSources []acquisition.DataSource
  35. /*the state of the buckets*/
  36. holders []leakybucket.BucketFactory
  37. buckets *leakybucket.Buckets
  38. inputLineChan chan types.Event
  39. inputEventChan chan types.Event
  40. outputEventChan chan types.Event // the buckets init returns its own chan that is used for multiplexing
  41. /*settings*/
  42. lastProcessedItem time.Time /*keep track of last item timestamp in time-machine. it is used to GC buckets when we dump them.*/
  43. pluginBroker csplugin.PluginBroker
  44. )
  45. type Flags struct {
  46. ConfigFile string
  47. LogLevelTrace bool
  48. LogLevelDebug bool
  49. LogLevelInfo bool
  50. LogLevelWarn bool
  51. LogLevelError bool
  52. LogLevelFatal bool
  53. PrintVersion bool
  54. SingleFileType string
  55. Labels map[string]string
  56. OneShotDSN string
  57. TestMode bool
  58. DisableAgent bool
  59. DisableAPI bool
  60. WinSvc string
  61. DisableCAPI bool
  62. Transform string
  63. }
  64. type labelsMap map[string]string
  65. func LoadBuckets(cConfig *csconfig.Config) error {
  66. var (
  67. err error
  68. files []string
  69. )
  70. for _, hubScenarioItem := range cwhub.GetItemMap(cwhub.SCENARIOS) {
  71. if hubScenarioItem.Installed {
  72. files = append(files, hubScenarioItem.LocalPath)
  73. }
  74. }
  75. buckets = leakybucket.NewBuckets()
  76. log.Infof("Loading %d scenario files", len(files))
  77. holders, outputEventChan, err = leakybucket.LoadBuckets(cConfig.Crowdsec, files, &bucketsTomb, buckets)
  78. if err != nil {
  79. return fmt.Errorf("scenario loading failed: %v", err)
  80. }
  81. if cConfig.Prometheus != nil && cConfig.Prometheus.Enabled {
  82. for holderIndex := range holders {
  83. holders[holderIndex].Profiling = true
  84. }
  85. }
  86. return nil
  87. }
  88. func LoadAcquisition(cConfig *csconfig.Config) error {
  89. var err error
  90. if flags.SingleFileType != "" && flags.OneShotDSN != "" {
  91. flags.Labels = labels
  92. flags.Labels["type"] = flags.SingleFileType
  93. dataSources, err = acquisition.LoadAcquisitionFromDSN(flags.OneShotDSN, flags.Labels, flags.Transform)
  94. if err != nil {
  95. return fmt.Errorf("failed to configure datasource for %s: %w", flags.OneShotDSN, err)
  96. }
  97. } else {
  98. dataSources, err = acquisition.LoadAcquisitionFromFile(cConfig.Crowdsec)
  99. if err != nil {
  100. return err
  101. }
  102. }
  103. if len(dataSources) == 0 {
  104. return fmt.Errorf("no datasource enabled")
  105. }
  106. return nil
  107. }
  108. var (
  109. dumpFolder string
  110. dumpStates bool
  111. labels = make(labelsMap)
  112. )
  113. func (l *labelsMap) String() string {
  114. return "labels"
  115. }
  116. func (l labelsMap) Set(label string) error {
  117. split := strings.Split(label, ":")
  118. if len(split) != 2 {
  119. return errors.Wrapf(errors.New("Bad Format"), "for Label '%s'", label)
  120. }
  121. l[split[0]] = split[1]
  122. return nil
  123. }
  124. func (f *Flags) Parse() {
  125. flag.StringVar(&f.ConfigFile, "c", csconfig.DefaultConfigPath("config.yaml"), "configuration file")
  126. flag.BoolVar(&f.LogLevelTrace, "trace", false, "set log level to 'trace' (VERY verbose)")
  127. flag.BoolVar(&f.LogLevelDebug, "debug", false, "set log level to 'debug'")
  128. flag.BoolVar(&f.LogLevelInfo, "info", false, "set log level to 'info'")
  129. flag.BoolVar(&f.LogLevelWarn, "warning", false, "set log level to 'warning'")
  130. flag.BoolVar(&f.LogLevelError, "error", false, "set log level to 'error'")
  131. flag.BoolVar(&f.LogLevelFatal, "fatal", false, "set log level to 'fatal'")
  132. flag.BoolVar(&f.PrintVersion, "version", false, "display version")
  133. flag.StringVar(&f.OneShotDSN, "dsn", "", "Process a single data source in time-machine")
  134. flag.StringVar(&f.Transform, "transform", "", "expr to apply on the event after acquisition")
  135. flag.StringVar(&f.SingleFileType, "type", "", "Labels.type for file in time-machine")
  136. flag.Var(&labels, "label", "Additional Labels for file in time-machine")
  137. flag.BoolVar(&f.TestMode, "t", false, "only test configs")
  138. flag.BoolVar(&f.DisableAgent, "no-cs", false, "disable crowdsec agent")
  139. flag.BoolVar(&f.DisableAPI, "no-api", false, "disable local API")
  140. flag.BoolVar(&f.DisableCAPI, "no-capi", false, "disable communication with Central API")
  141. if runtime.GOOS == "windows" {
  142. flag.StringVar(&f.WinSvc, "winsvc", "", "Windows service Action: Install, Remove etc..")
  143. }
  144. flag.StringVar(&dumpFolder, "dump-data", "", "dump parsers/buckets raw outputs")
  145. flag.Parse()
  146. }
  147. func newLogLevel(curLevelPtr *log.Level, f *Flags) *log.Level {
  148. // mother of all defaults
  149. ret := log.InfoLevel
  150. // keep if already set
  151. if curLevelPtr != nil {
  152. ret = *curLevelPtr
  153. }
  154. // override from flags
  155. switch {
  156. case f.LogLevelTrace:
  157. ret = log.TraceLevel
  158. case f.LogLevelDebug:
  159. ret = log.DebugLevel
  160. case f.LogLevelInfo:
  161. ret = log.InfoLevel
  162. case f.LogLevelWarn:
  163. ret = log.WarnLevel
  164. case f.LogLevelError:
  165. ret = log.ErrorLevel
  166. case f.LogLevelFatal:
  167. ret = log.FatalLevel
  168. default:
  169. }
  170. if curLevelPtr != nil && ret == *curLevelPtr {
  171. // avoid returning a new ptr to the same value
  172. return curLevelPtr
  173. }
  174. return &ret
  175. }
  176. // LoadConfig returns a configuration parsed from configuration file
  177. func LoadConfig(configFile string, disableAgent bool, disableAPI bool, quiet bool) (*csconfig.Config, error) {
  178. cConfig, _, err := csconfig.NewConfig(configFile, disableAgent, disableAPI, quiet)
  179. if err != nil {
  180. return nil, err
  181. }
  182. if (cConfig.Common == nil || *cConfig.Common == csconfig.CommonCfg{}) {
  183. return nil, fmt.Errorf("unable to load configuration: common section is empty")
  184. }
  185. cConfig.Common.LogLevel = newLogLevel(cConfig.Common.LogLevel, flags)
  186. if dumpFolder != "" {
  187. parser.ParseDump = true
  188. parser.DumpFolder = dumpFolder
  189. leakybucket.BucketPourTrack = true
  190. dumpStates = true
  191. }
  192. // Configuration paths are dependency to load crowdsec configuration
  193. if err := cConfig.LoadConfigurationPaths(); err != nil {
  194. return nil, err
  195. }
  196. if flags.SingleFileType != "" && flags.OneShotDSN != "" {
  197. // if we're in time-machine mode, we don't want to log to file
  198. cConfig.Common.LogMedia = "stdout"
  199. }
  200. // Configure logging
  201. if err := types.SetDefaultLoggerConfig(cConfig.Common.LogMedia,
  202. cConfig.Common.LogDir, *cConfig.Common.LogLevel,
  203. cConfig.Common.LogMaxSize, cConfig.Common.LogMaxFiles,
  204. cConfig.Common.LogMaxAge, cConfig.Common.CompressLogs,
  205. cConfig.Common.ForceColorLogs); err != nil {
  206. return nil, err
  207. }
  208. if err := csconfig.LoadFeatureFlagsFile(configFile, log.StandardLogger()); err != nil {
  209. return nil, err
  210. }
  211. if !flags.DisableAgent {
  212. if err := cConfig.LoadCrowdsec(); err != nil {
  213. return nil, err
  214. }
  215. }
  216. if !flags.DisableAPI {
  217. if err := cConfig.LoadAPIServer(); err != nil {
  218. return nil, err
  219. }
  220. }
  221. if !cConfig.DisableAgent && (cConfig.API == nil || cConfig.API.Client == nil || cConfig.API.Client.Credentials == nil) {
  222. return nil, errors.New("missing local API credentials for crowdsec agent, abort")
  223. }
  224. if cConfig.DisableAPI && cConfig.DisableAgent {
  225. return nil, errors.New("You must run at least the API Server or crowdsec")
  226. }
  227. if flags.TestMode && !cConfig.DisableAgent {
  228. cConfig.Crowdsec.LintOnly = true
  229. }
  230. if flags.OneShotDSN != "" && flags.SingleFileType == "" {
  231. return nil, errors.New("-dsn requires a -type argument")
  232. }
  233. if flags.Transform != "" && flags.OneShotDSN == "" {
  234. return nil, errors.New("-transform requires a -dsn argument")
  235. }
  236. if flags.SingleFileType != "" && flags.OneShotDSN == "" {
  237. return nil, errors.New("-type requires a -dsn argument")
  238. }
  239. if flags.SingleFileType != "" && flags.OneShotDSN != "" {
  240. if cConfig.API != nil && cConfig.API.Server != nil {
  241. cConfig.API.Server.OnlineClient = nil
  242. }
  243. /*if the api is disabled as well, just read file and exit, don't daemonize*/
  244. if flags.DisableAPI {
  245. cConfig.Common.Daemonize = false
  246. }
  247. log.Infof("single file mode : log_media=%s daemonize=%t", cConfig.Common.LogMedia, cConfig.Common.Daemonize)
  248. }
  249. if cConfig.Common.PidDir != "" {
  250. log.Warn("Deprecation warning: the pid_dir config can be safely removed and is not required")
  251. }
  252. if cConfig.Common.Daemonize && runtime.GOOS == "windows" {
  253. log.Debug("Daemonization is not supported on Windows, disabling")
  254. cConfig.Common.Daemonize = false
  255. }
  256. // recap of the enabled feature flags, because logging
  257. // was not enabled when we set them from envvars
  258. if fflist := csconfig.ListFeatureFlags(); fflist != "" {
  259. log.Infof("Enabled feature flags: %s", fflist)
  260. }
  261. return cConfig, nil
  262. }
  263. // crowdsecT0 can be used to measure start time of services,
  264. // or uptime of the application
  265. var crowdsecT0 time.Time
  266. func main() {
  267. if err := fflag.RegisterAllFeatures(); err != nil {
  268. log.Fatalf("failed to register features: %s", err)
  269. }
  270. // some features can require configuration or command-line options,
  271. // so wwe need to parse them asap. we'll load from feature.yaml later.
  272. if err := csconfig.LoadFeatureFlagsEnv(log.StandardLogger()); err != nil {
  273. log.Fatalf("failed to set feature flags from environment: %s", err)
  274. }
  275. crowdsecT0 = time.Now()
  276. log.Debugf("os.Args: %v", os.Args)
  277. // Handle command line arguments
  278. flags = &Flags{}
  279. flags.Parse()
  280. if len(flag.Args()) > 0 {
  281. fmt.Fprintf(os.Stderr, "argument provided but not defined: %s\n", flag.Args()[0])
  282. flag.Usage()
  283. // the flag package exits with 2 in case of unknown flag
  284. os.Exit(2)
  285. }
  286. if flags.PrintVersion {
  287. cwversion.Show()
  288. os.Exit(0)
  289. }
  290. err := StartRunSvc()
  291. if err != nil {
  292. log.Fatal(err)
  293. }
  294. os.Exit(0)
  295. }