diff --git a/cmd/root.go b/cmd/root.go index 168834dc..076928d6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,8 +1,8 @@ package cmd import ( - "bytes" "context" + "errors" "flag" "fmt" "net" @@ -20,6 +20,7 @@ import ( csbouncer "github.com/crowdsecurity/go-cs-bouncer" "github.com/crowdsecurity/go-cs-lib/csdaemon" + "github.com/crowdsecurity/go-cs-lib/csstring" "github.com/crowdsecurity/go-cs-lib/version" "github.com/crowdsecurity/crowdsec/pkg/models" @@ -47,9 +48,9 @@ func HandleSignals(ctx context.Context) error { case s := <-signalChan: switch s { case syscall.SIGTERM: - return fmt.Errorf("received SIGTERM") + return errors.New("received SIGTERM") case os.Interrupt: // cross-platform SIGINT - return fmt.Errorf("received interrupt") + return errors.New("received interrupt") } case <-ctx.Done(): return ctx.Err() @@ -76,6 +77,7 @@ func deleteDecisions(backend *backend.BackendCTX, decisions []*models.Decision, } log.Debugf("deleted %s", *d.Value) + nbDeletedDecisions++ } @@ -112,6 +114,7 @@ func addDecisions(backend *backend.BackendCTX, decisions []*models.Decision, con } log.Debugf("Adding '%s' for '%s'", *d.Value, *d.Duration) + nbNewDecisions++ } @@ -149,20 +152,22 @@ func Execute() error { } if configPath == nil || *configPath == "" { - return fmt.Errorf("configuration file is required") + return errors.New("configuration file is required") } - configBytes, err := cfg.MergedConfig(*configPath) + configMerged, err := cfg.MergedConfig(*configPath) if err != nil { return fmt.Errorf("unable to read config file: %w", err) } if *showConfig { - fmt.Println(string(configBytes)) + fmt.Println(string(configMerged)) return nil } - config, err := cfg.NewConfig(bytes.NewReader(configBytes)) + configExpanded := csstring.StrictExpand(string(configMerged), os.LookupEnv) + + config, err := cfg.NewConfig(strings.NewReader(configExpanded)) if err != nil { return fmt.Errorf("unable to load configuration: %w", err) } @@ -186,7 +191,7 @@ func Execute() error { bouncer := &csbouncer.StreamBouncer{} - err = bouncer.ConfigReader(bytes.NewReader(configBytes)) + err = bouncer.ConfigReader(strings.NewReader(configExpanded)) if err != nil { return err } @@ -209,7 +214,7 @@ func Execute() error { g.Go(func() error { bouncer.Run(ctx) - return fmt.Errorf("bouncer stream halted") + return errors.New("bouncer stream halted") }) if config.PrometheusConfig.Enabled { @@ -234,6 +239,7 @@ func Execute() error { g.Go(func() error { log.Infof("Processing new and deleted decisions . . .") + for { select { case <-ctx.Done(): @@ -242,6 +248,7 @@ func Execute() error { if decisions == nil { continue } + deleteDecisions(backend, decisions.Deleted, config) addDecisions(backend, decisions.New, config) } diff --git a/pkg/backend/backend.go b/pkg/backend/backend.go index b7f10310..b66fb908 100644 --- a/pkg/backend/backend.go +++ b/pkg/backend/backend.go @@ -1,6 +1,7 @@ package backend import ( + "errors" "fmt" "runtime" @@ -72,7 +73,7 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) { switch config.Mode { case cfg.IptablesMode, cfg.IpsetMode: if runtime.GOOS != "linux" { - return nil, fmt.Errorf("iptables and ipset is linux only") + return nil, errors.New("iptables and ipset is linux only") } b.firewall, err = iptables.NewIPTables(config) @@ -81,7 +82,7 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) { } case cfg.NftablesMode: if runtime.GOOS != "linux" { - return nil, fmt.Errorf("nftables is linux only") + return nil, errors.New("nftables is linux only") } b.firewall, err = nftables.NewNFTables(config) diff --git a/pkg/cfg/config.go b/pkg/cfg/config.go index 0251d913..71d6014b 100644 --- a/pkg/cfg/config.go +++ b/pkg/cfg/config.go @@ -1,14 +1,13 @@ package cfg import ( + "errors" "fmt" "io" - "os" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" - "github.com/crowdsecurity/go-cs-lib/csstring" "github.com/crowdsecurity/go-cs-lib/ptr" "github.com/crowdsecurity/go-cs-lib/yamlpatch" ) @@ -86,9 +85,7 @@ func NewConfig(reader io.Reader) (*BouncerConfig, error) { return nil, err } - configBuff := csstring.StrictExpand(string(fcontent), os.LookupEnv) - - err = yaml.Unmarshal([]byte(configBuff), &config) + err = yaml.Unmarshal(fcontent, &config) if err != nil { return nil, fmt.Errorf("failed to unmarshal: %w", err) } @@ -98,7 +95,7 @@ func NewConfig(reader io.Reader) (*BouncerConfig, error) { } if config.Mode == "" { - return nil, fmt.Errorf("config does not contain 'mode'") + return nil, errors.New("config does not contain 'mode'") } if len(config.SupportedDecisionsTypes) == 0 { @@ -152,7 +149,7 @@ func NewConfig(reader io.Reader) (*BouncerConfig, error) { return config, nil } -func pfConfig(config *BouncerConfig) error { +func pfConfig(_ *BouncerConfig) error { return nil } @@ -191,7 +188,7 @@ func nftablesConfig(config *BouncerConfig) error { } if !*config.Nftables.Ipv4.Enabled && !*config.Nftables.Ipv6.Enabled { - return fmt.Errorf("both IPv4 and IPv6 disabled, doing nothing") + return errors.New("both IPv4 and IPv6 disabled, doing nothing") } if config.NftablesHooks == nil || len(config.NftablesHooks) == 0 { diff --git a/pkg/cfg/logging.go b/pkg/cfg/logging.go index 1f6bc977..01afcc39 100644 --- a/pkg/cfg/logging.go +++ b/pkg/cfg/logging.go @@ -1,7 +1,7 @@ package cfg import ( - "fmt" + "errors" "io" "os" "path/filepath" @@ -75,7 +75,7 @@ func (c *LoggingConfig) setDefaults() { func (c *LoggingConfig) validate() error { if c.LogMode != "stdout" && c.LogMode != "file" { - return fmt.Errorf("log_mode should be either 'stdout' or 'file'") + return errors.New("log_mode should be either 'stdout' or 'file'") } return nil diff --git a/pkg/iptables/iptables.go b/pkg/iptables/iptables.go index fcc31145..8541333d 100644 --- a/pkg/iptables/iptables.go +++ b/pkg/iptables/iptables.go @@ -4,6 +4,7 @@ package iptables import ( + "errors" "fmt" "os/exec" "strings" @@ -68,7 +69,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) { ipsetBin, err := exec.LookPath("ipset") if err != nil { - return nil, fmt.Errorf("unable to find ipset") + return nil, errors.New("unable to find ipset") } ipv4Ctx.ipsetBin = ipsetBin @@ -77,7 +78,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) { } else { ipv4Ctx.iptablesBin, err = exec.LookPath("iptables") if err != nil { - return nil, fmt.Errorf("unable to find iptables") + return nil, errors.New("unable to find iptables") } ipv4Ctx.Chains = config.IptablesChains for _, v := range config.IptablesChains { @@ -109,7 +110,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) { } else { ipv6Ctx.iptablesBin, err = exec.LookPath("ip6tables") if err != nil { - return nil, fmt.Errorf("unable to find ip6tables") + return nil, errors.New("unable to find ip6tables") } ipv6Ctx.Chains = config.IptablesChains for _, v := range config.IptablesChains { @@ -237,7 +238,7 @@ func (ipt *iptables) Delete(decision *models.Decision) error { } if err := ipt.v6.delete(decision); err != nil { - return fmt.Errorf("failed deleting ban") + return errors.New("failed deleting ban") } done = true @@ -245,7 +246,7 @@ func (ipt *iptables) Delete(decision *models.Decision) error { if strings.Contains(*decision.Value, ".") { if err := ipt.v4.delete(decision); err != nil { - return fmt.Errorf("failed deleting ban") + return errors.New("failed deleting ban") } done = true diff --git a/test/bouncer/test_yaml_local.py b/test/bouncer/test_yaml_local.py index 3cab695b..3c28b667 100644 --- a/test/bouncer/test_yaml_local.py +++ b/test/bouncer/test_yaml_local.py @@ -1,3 +1,5 @@ +import os + def test_yaml_local(bouncer, fw_cfg_factory): cfg = fw_cfg_factory() @@ -21,3 +23,18 @@ def test_yaml_local(bouncer, fw_cfg_factory): ]) fw.proc.wait(timeout=0.2) assert not fw.proc.is_running() + + # variable expansion + + config_local = { + 'mode': '$BOUNCER_MODE' + } + + os.environ['BOUNCER_MODE'] = 'fromenv' + + with bouncer(cfg, config_local=config_local) as fw: + fw.wait_for_lines_fnmatch([ + "*firewall 'fromenv' is not supported*", + ]) + fw.proc.wait(timeout=0.2) + assert not fw.proc.is_running()