99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
package traefik_safeline
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"sync"
|
|
|
|
t1k "github.com/chaitin/t1k-go"
|
|
)
|
|
|
|
// Package example a example plugin.
|
|
|
|
// Config the plugin configuration.
|
|
type Config struct {
|
|
// Addr is the address for the detector
|
|
Addr string `yaml:"addr"`
|
|
PoolSize int `yaml:"pool_size"`
|
|
}
|
|
|
|
// CreateConfig creates the default plugin configuration.
|
|
func CreateConfig() *Config {
|
|
return &Config{
|
|
Addr: "",
|
|
PoolSize: 100,
|
|
}
|
|
}
|
|
|
|
// Safeline a plugin.
|
|
type Safeline struct {
|
|
next http.Handler
|
|
server *t1k.Server
|
|
name string
|
|
config *Config
|
|
logger *log.Logger
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// New created a new plugin.
|
|
func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
|
|
logger := log.New(os.Stdout, "safeline", log.LstdFlags)
|
|
logger.Printf("config: %+v", config)
|
|
return &Safeline{
|
|
next: next,
|
|
name: name,
|
|
config: config,
|
|
logger: logger,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Safeline) initServer() error {
|
|
if s.server != nil {
|
|
return nil
|
|
}
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.server == nil {
|
|
server, err := t1k.NewWithPoolSize(s.config.Addr, s.config.PoolSize)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.server = server
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Safeline) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
s.logger.Printf("panic: %s", r)
|
|
}
|
|
}()
|
|
if err := s.initServer(); err != nil {
|
|
s.logger.Printf("error in initServer: %s", err)
|
|
s.next.ServeHTTP(rw, req)
|
|
return
|
|
}
|
|
rw.Header().Set("X-Chaitin-waf", "safeline")
|
|
result, err := s.server.DetectHttpRequest(req)
|
|
if err != nil {
|
|
s.logger.Printf("error in detection: \n%+v\n", err)
|
|
s.next.ServeHTTP(rw, req)
|
|
return
|
|
}
|
|
if result.Blocked() {
|
|
rw.WriteHeader(result.StatusCode())
|
|
msg := fmt.Sprintf(`{"code": %d, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "%s"}`,
|
|
result.StatusCode(),
|
|
result.EventID(),
|
|
)
|
|
_, _ = rw.Write([]byte(msg))
|
|
return
|
|
}
|
|
s.next.ServeHTTP(rw, req)
|
|
//rw.WriteHeader(http.StatusForbidden)
|
|
//_, _ = rw.Write([]byte("Inject by safeline\n"))
|
|
}
|