Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint #339

Merged
merged 2 commits into from
Nov 7, 2023
Merged

Lint #339

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ import (
"github.com/crowdsecurity/cs-firewall-bouncer/pkg/metrics"
)

const (
name = "crowdsec-firewall-bouncer"
)
const name = "crowdsec-firewall-bouncer"

func backendCleanup(backend *backend.BackendCTX) {
log.Info("Shutting down backend")

if err := backend.ShutDown(); err != nil {
log.Errorf("while shutting down backend: %s", err)
}
Expand All @@ -54,22 +53,27 @@ func HandleSignals(ctx context.Context) error {
case <-ctx.Done():
return ctx.Err()
}

return nil
}

func deleteDecisions(backend *backend.BackendCTX, decisions []*models.Decision, config *cfg.BouncerConfig) {
nbDeletedDecisions := 0

for _, d := range decisions {
if !slices.Contains(config.SupportedDecisionsTypes, strings.ToLower(*d.Type)) {
log.Debugf("decisions for ip '%s' will not be deleted because its type is '%s'", *d.Value, *d.Type)
continue
}

if err := backend.Delete(d); err != nil {
if !strings.Contains(err.Error(), "netlink receive: no such file or directory") {
log.Errorf("unable to delete decision for '%s': %s", *d.Value, err)
}

continue
}

log.Debugf("deleted %s", *d.Value)
nbDeletedDecisions++
}
Expand All @@ -78,24 +82,29 @@ func deleteDecisions(backend *backend.BackendCTX, decisions []*models.Decision,
if nbDeletedDecisions == 1 {
noun = "decision"
}

if nbDeletedDecisions > 0 {
log.Debug("committing expired decisions")

if err := backend.Commit(); err != nil {
log.Errorf("unable to commit expired decisions %v", err)
return
}

log.Debug("committed expired decisions")
log.Infof("%d %s deleted", nbDeletedDecisions, noun)
}
}

func addDecisions(backend *backend.BackendCTX, decisions []*models.Decision, config *cfg.BouncerConfig) {
nbNewDecisions := 0

for _, d := range decisions {
if !slices.Contains(config.SupportedDecisionsTypes, strings.ToLower(*d.Type)) {
log.Debugf("decisions for ip '%s' will not be added because its type is '%s'", *d.Value, *d.Type)
continue
}

if err := backend.Add(d); err != nil {
log.Errorf("unable to insert decision for '%s': %s", *d.Value, err)
continue
Expand All @@ -109,19 +118,21 @@ func addDecisions(backend *backend.BackendCTX, decisions []*models.Decision, con
if nbNewDecisions == 1 {
noun = "decision"
}

if nbNewDecisions > 0 {
log.Debug("committing added decisions")

if err := backend.Commit(); err != nil {
log.Errorf("unable to commit add decisions %v", err)
return
}

log.Debug("committed added decisions")
log.Infof("%d %s added", nbNewDecisions, noun)
}
}

func Execute() error {
var err error
configPath := flag.String("c", "", "path to crowdsec-firewall-bouncer.yaml")
verbose := flag.Bool("v", false, "set verbose mode")
bouncerVersion := flag.Bool("V", false, "display version and exit (deprecated)")
Expand Down Expand Up @@ -173,6 +184,7 @@ func Execute() error {
defer backendCleanup(backend)

bouncer := &csbouncer.StreamBouncer{}

err = bouncer.ConfigReader(bytes.NewReader(configBytes))
if err != nil {
return err
Expand Down Expand Up @@ -204,9 +216,12 @@ func Execute() error {
go backend.CollectMetrics()
prometheus.MustRegister(metrics.TotalDroppedBytes, metrics.TotalDroppedPackets, metrics.TotalActiveBannedIPs)
}

prometheus.MustRegister(csbouncer.TotalLAPICalls, csbouncer.TotalLAPIError)

go func() {
http.Handle("/metrics", promhttp.Handler())

listenOn := net.JoinHostPort(
config.PrometheusConfig.ListenAddress,
config.PrometheusConfig.ListenPort,
Expand All @@ -215,6 +230,7 @@ func Execute() error {
log.Error(http.ListenAndServe(listenOn, nil))
}()
}

g.Go(func() error {
log.Infof("Processing new and deleted decisions . . .")
for {
Expand Down
7 changes: 7 additions & 0 deletions pkg/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,19 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) {
var err error

b := &BackendCTX{}

log.Printf("backend type : %s", config.Mode)

if config.DisableIPV6 {
log.Println("IPV6 is disabled")
}

switch config.Mode {
case cfg.IptablesMode, cfg.IpsetMode:
if runtime.GOOS != "linux" {
return nil, fmt.Errorf("iptables and ipset is linux only")
}

b.firewall, err = iptables.NewIPTables(config)
if err != nil {
return nil, err
Expand All @@ -78,6 +82,7 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) {
if runtime.GOOS != "linux" {
return nil, fmt.Errorf("nftables is linux only")
}

b.firewall, err = nftables.NewNFTables(config)
if err != nil {
return nil, err
Expand All @@ -86,6 +91,7 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) {
if !isPFSupported(runtime.GOOS) {
log.Warning("pf mode can only work with openbsd and freebsd. It is available on other platforms only for testing purposes")
}

b.firewall, err = pf.NewPF(config)
if err != nil {
return nil, err
Expand All @@ -98,5 +104,6 @@ func NewBackend(config *cfg.BouncerConfig) (*BackendCTX, error) {
default:
return b, fmt.Errorf("firewall '%s' is not supported", config.Mode)
}

return b, nil
}
3 changes: 3 additions & 0 deletions pkg/cfg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@ type BouncerConfig struct {
// MergedConfig() returns the byte content of the patched configuration file (with .yaml.local).
func MergedConfig(configPath string) ([]byte, error) {
patcher := yamlpatch.NewPatcher(configPath, ".local")

data, err := patcher.MergedPatchContent()
if err != nil {
return nil, err
}

return data, nil
}

Expand Down Expand Up @@ -119,6 +121,7 @@ func NewConfig(reader io.Reader) (*BouncerConfig, error) {
if config.BlacklistsIpv6 == "" {
config.BlacklistsIpv6 = "crowdsec6-blacklists"
}

if config.SetType == "" {
config.SetType = "nethash"
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/cfg/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,17 @@ func (c *LoggingConfig) validate() error {
if c.LogMode != "stdout" && c.LogMode != "file" {
return fmt.Errorf("log_mode should be either 'stdout' or 'file'")
}

return nil
}

func (c *LoggingConfig) setup(fileName string) error {
c.setDefaults()

if err := c.validate(); err != nil {
return err
}

log.SetLevel(*c.LogLevel)

if c.LogMode == "stdout" {
Expand Down
26 changes: 24 additions & 2 deletions pkg/iptables/iptables.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ type iptables struct {

func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) {
var err error

ret := &iptables{}

ipv4Ctx := &ipTablesContext{
Name: "ipset",
version: "v4",
Expand Down Expand Up @@ -70,6 +72,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) {
if err != nil {
return nil, fmt.Errorf("unable to find ipset")
}

ipv4Ctx.ipsetBin = ipsetBin
if config.Mode == cfg.IpsetMode {
ipv4Ctx.ipsetContentOnly = true
Expand All @@ -96,10 +99,12 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) {
}
}
}

ret.v4 = ipv4Ctx
if config.DisableIPV6 {
return ret, nil
}

ipv6Ctx.ipsetBin = ipsetBin
if config.Mode == cfg.IpsetMode {
ipv6Ctx.ipsetContentOnly = true
Expand All @@ -126,6 +131,7 @@ func NewIPTables(config *cfg.BouncerConfig) (types.Backend, error) {
}
}
}

ret.v6 = ipv6Ctx

return ret, nil
Expand All @@ -135,18 +141,20 @@ func (ipt *iptables) Init() error {
var err error

log.Printf("iptables for ipv4 initiated")

// flush before init
if err := ipt.v4.shutDown(); err != nil {
if err = ipt.v4.shutDown(); err != nil {
return fmt.Errorf("iptables shutdown failed: %w", err)
}

// Create iptable to rule to attach the set
if err := ipt.v4.CheckAndCreate(); err != nil {
if err = ipt.v4.CheckAndCreate(); err != nil {
return fmt.Errorf("iptables init failed: %w", err)
}

if ipt.v6 != nil {
log.Printf("iptables for ipv6 initiated")

err = ipt.v6.shutDown() // flush before init
if err != nil {
return fmt.Errorf("iptables shutdown failed: %w", err)
Expand All @@ -157,6 +165,7 @@ func (ipt *iptables) Init() error {
return fmt.Errorf("iptables init failed: %w", err)
}
}

return nil
}

Expand All @@ -181,15 +190,19 @@ func (ipt *iptables) Add(decision *models.Decision) error {
log.Debugf("not adding '%s' because ipv6 is disabled", *decision.Value)
return nil
}

if err := ipt.v6.add(decision); err != nil {
return fmt.Errorf("failed inserting ban ip '%s' for iptables ipv4 rule", *decision.Value)
}

done = true
}

if strings.Contains(*decision.Value, ".") {
if err := ipt.v4.add(decision); err != nil {
return fmt.Errorf("failed inserting ban ip '%s' for iptables ipv6 rule", *decision.Value)
}

done = true
}

Expand All @@ -205,35 +218,44 @@ func (ipt *iptables) ShutDown() error {
if err != nil {
return fmt.Errorf("iptables for ipv4 shutdown failed: %w", err)
}

if ipt.v6 != nil {
err = ipt.v6.shutDown()
if err != nil {
return fmt.Errorf("iptables for ipv6 shutdown failed: %w", err)
}
}

return nil
}

func (ipt *iptables) Delete(decision *models.Decision) error {
done := false

if strings.Contains(*decision.Value, ":") {
if ipt.v6 == nil {
log.Debugf("not deleting '%s' because ipv6 is disabled", *decision.Value)
return nil
}

if err := ipt.v6.delete(decision); err != nil {
return fmt.Errorf("failed deleting ban")
}

done = true
}

if strings.Contains(*decision.Value, ".") {
if err := ipt.v4.delete(decision); err != nil {
return fmt.Errorf("failed deleting ban")
}

done = true
}

if !done {
return fmt.Errorf("failed deleting ban: ip %s was not recognized", *decision.Value)
}

return nil
}
Loading