safeline.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package traefik_safeline
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "os"
  8. "sync"
  9. t1k "github.com/chaitin/t1k-go"
  10. )
  11. // Package example a example plugin.
  12. // Config the plugin configuration.
  13. type Config struct {
  14. // Addr is the address for the detector
  15. Addr string `yaml:"addr"`
  16. PoolSize int `yaml:"pool_size"`
  17. }
  18. // CreateConfig creates the default plugin configuration.
  19. func CreateConfig() *Config {
  20. return &Config{
  21. Addr: "",
  22. PoolSize: 100,
  23. }
  24. }
  25. // Safeline a plugin.
  26. type Safeline struct {
  27. next http.Handler
  28. server *t1k.Server
  29. name string
  30. config *Config
  31. logger *log.Logger
  32. mu sync.Mutex
  33. }
  34. // New created a new plugin.
  35. func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
  36. logger := log.New(os.Stdout, "safeline", log.LstdFlags)
  37. logger.Printf("config: %+v", config)
  38. return &Safeline{
  39. next: next,
  40. name: name,
  41. config: config,
  42. logger: logger,
  43. }, nil
  44. }
  45. func (s *Safeline) initServer() error {
  46. if s.server != nil {
  47. return nil
  48. }
  49. s.mu.Lock()
  50. defer s.mu.Unlock()
  51. if s.server == nil {
  52. server, err := t1k.NewWithPoolSize(s.config.Addr, s.config.PoolSize)
  53. if err != nil {
  54. return err
  55. }
  56. s.server = server
  57. }
  58. return nil
  59. }
  60. func (s *Safeline) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
  61. defer func() {
  62. if r := recover(); r != nil {
  63. s.logger.Printf("panic: %s", r)
  64. }
  65. }()
  66. if err := s.initServer(); err != nil {
  67. s.logger.Printf("error in initServer: %s", err)
  68. s.next.ServeHTTP(rw, req)
  69. return
  70. }
  71. rw.Header().Set("X-Chaitin-waf", "safeline")
  72. result, err := s.server.DetectHttpRequest(req)
  73. if err != nil {
  74. s.logger.Printf("error in detection: \n%+v\n", err)
  75. s.next.ServeHTTP(rw, req)
  76. return
  77. }
  78. if result.Blocked() {
  79. rw.WriteHeader(result.StatusCode())
  80. msg := fmt.Sprintf(`{"code": %d, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "%s"}`,
  81. result.StatusCode(),
  82. result.EventID(),
  83. )
  84. _, _ = rw.Write([]byte(msg))
  85. return
  86. }
  87. s.next.ServeHTTP(rw, req)
  88. //rw.WriteHeader(http.StatusForbidden)
  89. //_, _ = rw.Write([]byte("Inject by safeline\n"))
  90. }