backend.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package cwplugin
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "plugin"
  8. "time"
  9. "github.com/crowdsecurity/crowdsec/pkg/types"
  10. log "github.com/sirupsen/logrus"
  11. "gopkg.in/yaml.v2"
  12. )
  13. // the structure returned by the function New() of the plugin must match this interface
  14. type Backend interface {
  15. Insert(types.SignalOccurence) error
  16. ReadAT(time.Time) ([]map[string]string, error)
  17. Delete(string) (int, error)
  18. Init(map[string]string) error
  19. Flush() error
  20. Shutdown() error
  21. DeleteAll() error
  22. }
  23. type BackendPlugin struct {
  24. Name string `yaml:"name"`
  25. Path string `yaml:"path"`
  26. ConfigFilePath string
  27. Config map[string]string `yaml:"config"`
  28. ID string
  29. funcs Backend
  30. }
  31. type BackendManager struct {
  32. backendPlugins map[string]BackendPlugin
  33. }
  34. func NewBackendPlugin(path string, isDaemon bool) (*BackendManager, error) {
  35. var files []string
  36. var backendManager = &BackendManager{}
  37. err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
  38. if filepath.Ext(path) == ".yaml" {
  39. files = append(files, path)
  40. }
  41. return nil
  42. })
  43. if err != nil {
  44. panic(err)
  45. }
  46. backendManager.backendPlugins = make(map[string]BackendPlugin, len(files))
  47. for _, file := range files {
  48. var newPlugin BackendPlugin
  49. log.Debugf("opening plugin '%s'", file)
  50. bConfig, err := ioutil.ReadFile(file)
  51. if err != nil {
  52. log.Errorf("unable to open file '%s' : %s, skipping", file, err)
  53. continue
  54. }
  55. if err := yaml.UnmarshalStrict(bConfig, &newPlugin); err != nil {
  56. log.Errorf("parsing '%s' yaml error : %s, skipping", file, err)
  57. continue
  58. }
  59. plug, err := plugin.Open(newPlugin.Path)
  60. if err != nil {
  61. return nil, err
  62. }
  63. //Lookup a function called 'New' to get the plugin interface
  64. symbol, err := plug.Lookup("New")
  65. if err != nil {
  66. return nil, fmt.Errorf("no 'New' function in plugin : %s", err)
  67. }
  68. symNew, ok := symbol.(func() interface{})
  69. if !ok {
  70. log.Errorf("plugin '%s' do not implement a GetFunctions() that return a list of string, skipping", file)
  71. continue
  72. }
  73. // cast the return interface to Backend interface
  74. plugNew := symNew()
  75. bInterface, ok := plugNew.(Backend)
  76. if !ok {
  77. return nil, fmt.Errorf("unexpected '%s' type (%T), skipping", newPlugin.Name, plugNew)
  78. }
  79. // Add the interface and Init()
  80. newPlugin.funcs = bInterface
  81. if isDaemon {
  82. newPlugin.Config["flush"] = "true"
  83. } else {
  84. newPlugin.Config["flush"] = "false"
  85. }
  86. err = newPlugin.funcs.Init(newPlugin.Config)
  87. if err != nil {
  88. return nil, fmt.Errorf("plugin '%s' init error : %s", newPlugin.Name, err)
  89. }
  90. log.Infof("backend plugin '%s' loaded", newPlugin.Name)
  91. backendManager.backendPlugins[newPlugin.Name] = newPlugin
  92. }
  93. log.Debugf("loaded %d backend plugins", len(backendManager.backendPlugins))
  94. if len(backendManager.backendPlugins) == 0 {
  95. return nil, fmt.Errorf("no plugins loaded from %s", path)
  96. }
  97. return backendManager, nil
  98. }
  99. func (b *BackendManager) Delete(target string) (int, error) {
  100. var err error
  101. var nbDel int
  102. for _, plugin := range b.backendPlugins {
  103. nbDel, err = plugin.funcs.Delete(target)
  104. if err != nil {
  105. return 0, fmt.Errorf("failed to delete : %s", err)
  106. }
  107. }
  108. return nbDel, nil
  109. }
  110. func (b *BackendManager) Shutdown() error {
  111. var err error
  112. for _, plugin := range b.backendPlugins {
  113. err = plugin.funcs.Shutdown()
  114. if err != nil {
  115. return fmt.Errorf("failed to shutdown : %s", err)
  116. }
  117. }
  118. return nil
  119. }
  120. func (b *BackendManager) DeleteAll() error {
  121. var err error
  122. for _, plugin := range b.backendPlugins {
  123. err = plugin.funcs.DeleteAll()
  124. if err != nil {
  125. return fmt.Errorf("failed to delete : %s", err)
  126. }
  127. }
  128. return nil
  129. }
  130. // Insert the signal for the plugin specified in the config["plugin"] parameter
  131. func (b *BackendManager) InsertOnePlugin(sig types.SignalOccurence, pluginName string) error {
  132. if val, ok := b.backendPlugins[pluginName]; ok {
  133. if err := val.funcs.Insert(sig); err != nil {
  134. return fmt.Errorf("failed to load %s : %s", pluginName, err)
  135. }
  136. } else {
  137. return fmt.Errorf("plugin '%s' not loaded", pluginName)
  138. }
  139. return nil
  140. }
  141. // Insert the signal for all the plugins
  142. func (b *BackendManager) Insert(sig types.SignalOccurence) error {
  143. var err error
  144. for _, plugin := range b.backendPlugins {
  145. err = plugin.funcs.Insert(sig)
  146. if err != nil {
  147. return fmt.Errorf("flushing backend plugin '%s' failed: %s", plugin.Name, err)
  148. }
  149. }
  150. return nil
  151. }
  152. func (b *BackendManager) IsBackendPlugin(plugin string) bool {
  153. if _, ok := b.backendPlugins[plugin]; ok {
  154. return true
  155. }
  156. return false
  157. }
  158. func (b *BackendManager) ReadAT(timeAT time.Time) ([]map[string]string, error) {
  159. var ret []map[string]string
  160. var err error
  161. for _, plugin := range b.backendPlugins {
  162. ret, err = plugin.funcs.ReadAT(timeAT)
  163. if err != nil {
  164. return nil, err
  165. }
  166. }
  167. return ret, nil
  168. }
  169. func (b *BackendManager) Flush() error {
  170. var err error
  171. for _, plugin := range b.backendPlugins {
  172. err = plugin.funcs.Flush()
  173. if err != nil {
  174. return fmt.Errorf("flushing backend plugin '%s' failed: %s", plugin.Name, err)
  175. }
  176. }
  177. return nil
  178. }