diff --git a/README.md b/README.md index 77f76af5..11e21f91 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,10 @@ log_dir: /var/log/ log_level: info api_url: # when install, default is "localhost:8080" api_key: # Add your API key generated with `cscli bouncers add --name ` +disable_ipv6: false +deny_mode: DROP +deny_log: false +#deny_log_prefix: "crowdsec: " #if present, insert rule in those chains iptables_chains: - INPUT @@ -87,6 +91,10 @@ iptables_chains: - `update_frequency` controls how often the bouncer is going to query the local API - `api_url` and `api_key` control local API parameters. - `iptables_chains` allows (in _iptables_ mode) to control in which chain rules are going to be inserted. (if empty, bouncer will only maintain ipset lists) + - `disable_ipv6` - set to true to disable ipv6 + - `deny_mode` - what action to use to deny, one of DROP or REJECT + - `deny_log` - set this to true to add a log statement to the firewall rule + - `deny_log_prefix` - if logging is true, this sets the log prefix, defaults to "crowdsec: " You can then start the service: @@ -103,9 +111,3 @@ logs can be found in `/var/log/cs-firewall-bouncer.log` - mode `nftables` relies on github.com/google/nftables to create table, chain and set. - mode `iptables` relies on `iptables` and `ipset` commands to insert `match-set` directives and maintain associated ipsets - mode `ipset` relies on `ipset` and only manage contents of the sets (they need to exist at startup and will be flushed rather than created) - - - - - - diff --git a/config.go b/config.go index cbabc053..d26d340b 100644 --- a/config.go +++ b/config.go @@ -22,6 +22,9 @@ type bouncerConfig struct { APIUrl string `yaml:"api_url"` APIKey string `yaml:"api_key"` DisableIPV6 bool `yaml:"disable_ipv6"` + DenyAction string `yaml:"deny_action"` + DenyLog bool `yaml:"deny_log"` + DenyLogPrefix string `yaml:"deny_log_prefix"` //specific to iptables, following https://github.com/crowdsecurity/cs-firewall-bouncer/issues/19 IptablesChains []string `yaml:"iptables_chains"` } @@ -44,6 +47,9 @@ func NewConfig(configPath string) (*bouncerConfig, error) { if config.Mode == "" || config.PidDir == "" || config.LogMode == "" { return &bouncerConfig{}, fmt.Errorf("invalid configuration in %s", configPath) } + if config.DenyLog && config.DenyLogPrefix == "" { + config.DenyLogPrefix = "crowdsec drop: " + } /*Configure logging*/ if err = types.SetDefaultLoggerConfig(config.LogMode, config.LogDir, config.LogLevel); err != nil { log.Fatal(err.Error()) diff --git a/config/cs-firewall-bouncer.yaml b/config/cs-firewall-bouncer.yaml index 8b3ec6dc..1f0016d5 100644 --- a/config/cs-firewall-bouncer.yaml +++ b/config/cs-firewall-bouncer.yaml @@ -8,11 +8,12 @@ log_level: info api_url: http://localhost:8080/ api_key: ${API_KEY} disable_ipv6: false +deny_mode: DROP +deny_log: false +#to change log prefix +#deny_log_prefix: "crowdsec: " #if present, insert rule in those chains iptables_chains: - INPUT # - FORWARD # - DOCKER-USER - - - diff --git a/go.mod b/go.mod index 0b9d24e9..c81b4e8a 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/sevlyar/go-daemon v0.1.5 github.com/sirupsen/logrus v1.7.0 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect - golang.org/x/sys v0.0.0-20210113131315-ba0562f347e0 // indirect + golang.org/x/sys v0.0.0-20210113131315-ba0562f347e0 golang.org/x/text v0.3.5 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 diff --git a/go.sum b/go.sum index acb4165c..d2a6b4d7 100644 --- a/go.sum +++ b/go.sum @@ -109,6 +109,8 @@ github.com/crowdsecurity/crowdsec v0.3.7 h1:JOC73mpPL75ZZ5GMQjZubkWoV/0XCgEzwwb+ github.com/crowdsecurity/crowdsec v0.3.7/go.mod h1:4MMkcfc5vWvAgA27GN9tFuZ6rEZJHZyjMsKt5UdGJ18= github.com/crowdsecurity/crowdsec v0.3.8-0.20201130100924-000fec27df14 h1:m7dfmY1kk7ScEHOtUSRUniD8xOq1M1C2dR81dsAQ1Ys= github.com/crowdsecurity/crowdsec v0.3.8-0.20201130100924-000fec27df14/go.mod h1:dPkoQ+hsiGToZMxsft5QW7zK2MsX6sNvmfOOQH2I/68= +github.com/crowdsecurity/crowdsec v1.0.2 h1:DxUKaXx/cCZ9yvsl0zUFjbL4PPt+YZaXeT6bkqOhWvQ= +github.com/crowdsecurity/crowdsec v1.0.2/go.mod h1:dPkoQ+hsiGToZMxsft5QW7zK2MsX6sNvmfOOQH2I/68= github.com/crowdsecurity/go-cs-bouncer v0.0.0-20201004231041-82fed0c01d72 h1:WawQ+5C4sLNrXTHkARfv6oMFTS9+H+OTc6bd+mJIXWY= github.com/crowdsecurity/go-cs-bouncer v0.0.0-20201004231041-82fed0c01d72/go.mod h1:fHOSYGhe4BnJ1eUh53ooMyOffppYHJaguU+EfL5EqPA= github.com/crowdsecurity/go-cs-bouncer v0.0.0-20201020154335-83f26d9e943b h1:8ziuAE5FjwjhP1dG99zmJSsZAkqa6eLQjGDBqK+O/Go= @@ -121,6 +123,8 @@ github.com/crowdsecurity/go-cs-bouncer v0.0.0-20201022143713-ab83f6aa48fd h1:ISI github.com/crowdsecurity/go-cs-bouncer v0.0.0-20201022143713-ab83f6aa48fd/go.mod h1:fHOSYGhe4BnJ1eUh53ooMyOffppYHJaguU+EfL5EqPA= github.com/crowdsecurity/go-cs-bouncer v0.0.0-20201130114000-e5b8016e5bf3 h1:Dp9uxZWJ0izvq8PeKI/dCn1hbXtHh3d4B4CsQXAhamA= github.com/crowdsecurity/go-cs-bouncer v0.0.0-20201130114000-e5b8016e5bf3/go.mod h1:fHOSYGhe4BnJ1eUh53ooMyOffppYHJaguU+EfL5EqPA= +github.com/crowdsecurity/go-cs-bouncer v0.0.0-20210113162030-7eec88c1afa8 h1:wHgmUMNfXGcHHE9rptRp+iR4J4tjcIXatM2Y44VcnF4= +github.com/crowdsecurity/go-cs-bouncer v0.0.0-20210113162030-7eec88c1afa8/go.mod h1:fHOSYGhe4BnJ1eUh53ooMyOffppYHJaguU+EfL5EqPA= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -218,6 +222,8 @@ github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2e github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= github.com/go-openapi/loads v0.19.7 h1:6cALLpCAq4tYhaic7TMbEzjv8vq/wg+0AFivNy/Bma8= github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= +github.com/go-openapi/loads v0.20.0 h1:Pymw1O8zDmWeNv4kVsHd0W3cvgdp8juRa4U/U/8D/Pk= +github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= @@ -240,6 +246,8 @@ github.com/go-openapi/spec v0.19.10/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2R github.com/go-openapi/spec v0.19.13/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA= github.com/go-openapi/spec v0.19.15 h1:uxh8miNJEfMm8l8ekpY7i39LcORm1xSRtoipEGl1JPk= github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I= +github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= @@ -274,6 +282,8 @@ github.com/go-openapi/validate v0.19.11/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0 github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= github.com/go-openapi/validate v0.19.15 h1:oUHZO8jD7p5oRLANlXF0U8ic9ePBUkDQyRZdN0EhL6M= github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= +github.com/go-openapi/validate v0.20.0 h1:pzutNCCBZGZlE+u8HD3JZyWdc/TVbtVwlWUp8/vgUKk= +github.com/go-openapi/validate v0.20.0/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= @@ -525,6 +535,8 @@ github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8 github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -710,6 +722,8 @@ go.mongodb.org/mongo-driver v1.4.2 h1:WlnEglfTg/PfPq4WXs2Vkl/5ICC6hoG8+r+LraPmGk go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.mongodb.org/mongo-driver v1.4.3 h1:moga+uhicpVshTyaqY9L23E6QqwcHRUv1sqyOsoyOO8= go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.4.4 h1:bsPHfODES+/yx2PCWzUYMH8xj6PVniPI8DQrsJuSXSs= +go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -809,6 +823,9 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjN golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -876,9 +893,13 @@ golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a h1:e3IU37lwO4aq3uoRKINC7JikojFmE5gO7xhfxs8VC34= golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201116161645-c061ba923fbb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201130072748-111129e158e2 h1:zXpk15uCEAaaJcTxBqQacweHUQ0HDhDOzupNGFs4imE= golang.org/x/sys v0.0.0-20201130072748-111129e158e2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210113131315-ba0562f347e0 h1:rTJ72jiMIolMfCaiZLkdlJLN2Og7LKF6xE1cgwQnwzQ= +golang.org/x/sys v0.0.0-20210113131315-ba0562f347e0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201113234701-d7a72108b828/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -887,6 +908,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/iptables.go b/iptables.go index bd53197f..4cfa8b01 100644 --- a/iptables.go +++ b/iptables.go @@ -36,6 +36,13 @@ func newIPTables(config *bouncerConfig) (interface{}, error) { CheckIptableCmds: [][]string{}, } + var target string + if strings.EqualFold(config.DenyAction, "REJECT") { + target = "REJECT" + } else { + target = "DROP" + } + ipsetBin, err := exec.LookPath("ipset") if err != nil { return nil, fmt.Errorf("unable to find ipset") @@ -49,12 +56,20 @@ func newIPTables(config *bouncerConfig) (interface{}, error) { return nil, fmt.Errorf("unable to find iptables") } for _, v := range config.IptablesChains { + if config.DenyLog { + ipv4Ctx.StartupCmds = append(ipv4Ctx.StartupCmds, + []string{"-I", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "--log-prefix", config.DenyLogPrefix, "-j", "LOG"}) + ipv4Ctx.ShutdownCmds = append(ipv4Ctx.ShutdownCmds, + []string{"-D", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "--log-prefix", config.DenyLogPrefix, "-j", "LOG"}) + ipv4Ctx.CheckIptableCmds = append(ipv4Ctx.CheckIptableCmds, + []string{"-C", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "--log-prefix", config.DenyLogPrefix, "-j", "LOG"}) + } ipv4Ctx.StartupCmds = append(ipv4Ctx.StartupCmds, - []string{"-I", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "-j", "DROP"}) + []string{"-I", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "-j", target}) ipv4Ctx.ShutdownCmds = append(ipv4Ctx.ShutdownCmds, - []string{"-D", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "-j", "DROP"}) + []string{"-D", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "-j", target}) ipv4Ctx.CheckIptableCmds = append(ipv4Ctx.CheckIptableCmds, - []string{"-C", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "-j", "DROP"}) + []string{"-C", v, "-m", "set", "--match-set", "crowdsec-blacklists", "src", "-j", target}) } } ret.v4 = ipv4Ctx @@ -70,12 +85,20 @@ func newIPTables(config *bouncerConfig) (interface{}, error) { return nil, fmt.Errorf("unable to find ip6tables") } for _, v := range config.IptablesChains { + if config.DenyLog { + ipv6Ctx.StartupCmds = append(ipv4Ctx.StartupCmds, + []string{"-I", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "--log-prefix", config.DenyLogPrefix, "-j", "LOG"}) + ipv6Ctx.ShutdownCmds = append(ipv4Ctx.ShutdownCmds, + []string{"-D", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "--log-prefix", config.DenyLogPrefix, "-j", "LOG"}) + ipv6Ctx.CheckIptableCmds = append(ipv4Ctx.CheckIptableCmds, + []string{"-C", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "--log-prefix", config.DenyLogPrefix, "-j", "LOG"}) + } ipv6Ctx.StartupCmds = append(ipv6Ctx.StartupCmds, - []string{"-I", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "-j", "DROP"}) + []string{"-I", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "-j", target}) ipv6Ctx.ShutdownCmds = append(ipv6Ctx.ShutdownCmds, - []string{"-D", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "-j", "DROP"}) + []string{"-D", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "-j", target}) ipv6Ctx.CheckIptableCmds = append(ipv6Ctx.CheckIptableCmds, - []string{"-C", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "-j", "DROP"}) + []string{"-C", v, "-m", "set", "--match-set", "crowdsec6-blacklists", "src", "-j", target}) } } ret.v6 = ipv6Ctx diff --git a/nftables.go b/nftables.go index f74db322..e8f952fc 100644 --- a/nftables.go +++ b/nftables.go @@ -8,6 +8,7 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/models" "github.com/google/nftables" "github.com/google/nftables/expr" + "golang.org/x/sys/unix" log "github.com/sirupsen/logrus" ) @@ -20,6 +21,9 @@ type nft struct { set6 *nftables.Set table *nftables.Table table6 *nftables.Table + DenyAction string + DenyLog bool + DenyLogPrefix string } func newNFTables(config *bouncerConfig) (interface{}, error) { @@ -29,6 +33,9 @@ func newNFTables(config *bouncerConfig) (interface{}, error) { if !config.DisableIPV6 { ret.conn6 = &nftables.Conn{} } + ret.DenyAction = config.DenyAction + ret.DenyLog = config.DenyLog + ret.DenyLogPrefix = config.DenyLogPrefix return ret, nil } @@ -58,29 +65,42 @@ func (n *nft) Init() error { } n.set = set - n.conn.AddRule(&nftables.Rule{ + r := &nftables.Rule{ Table: n.table, Chain: chain, - Exprs: []expr.Any{ - // [ payload load 4b @ network header + 16 => reg 1 ] - &expr.Payload{ - DestRegister: 1, - Base: expr.PayloadBaseNetworkHeader, - Offset: 12, - Len: 4, - }, - // [ lookup reg 1 set whitelist ] - &expr.Lookup{ - SourceRegister: 1, - SetName: n.set.Name, - SetID: n.set.ID, - }, - //[ immediate reg 0 drop ] - &expr.Verdict{ - Kind: expr.VerdictDrop, - }, - }, + Exprs: []expr.Any{}, + } + // [ payload load 4b @ network header + 16 => reg 1 ] + r.Exprs = append(r.Exprs, &expr.Payload{ + DestRegister: 1, + Base: expr.PayloadBaseNetworkHeader, + Offset: 12, + Len: 4, }) + // [ lookup reg 1 set whitelist ] + r.Exprs = append(r.Exprs, &expr.Lookup{ + SourceRegister: 1, + SetName: n.set.Name, + SetID: n.set.ID, + }) + if n.DenyLog { + r.Exprs = append(r.Exprs, &expr.Log{ + Key: unix.NFTA_LOG_PREFIX, + Data: []byte(n.DenyLogPrefix), + }) + } + if strings.EqualFold(n.DenyAction, "REJECT") { + r.Exprs = append(r.Exprs, &expr.Reject{ + Type: unix.NFT_REJECT_ICMP_UNREACH, + Code: unix.NFT_REJECT_ICMPX_ADMIN_PROHIBITED, + }) + } else { + r.Exprs = append(r.Exprs, &expr.Verdict{ + Kind: expr.VerdictDrop, + }) + } + + n.conn.AddRule(r) if err := n.conn.Flush(); err != nil { return err @@ -113,29 +133,42 @@ func (n *nft) Init() error { } n.set6 = set - n.conn6.AddRule(&nftables.Rule{ + r := &nftables.Rule{ Table: n.table6, Chain: chain, - Exprs: []expr.Any{ - // [ payload load 4b @ network header + 16 => reg 1 ] - &expr.Payload{ - DestRegister: 1, - Base: expr.PayloadBaseNetworkHeader, - Offset: 8, - Len: 16, - }, - // [ lookup reg 1 set whitelist ] - &expr.Lookup{ - SourceRegister: 1, - SetName: n.set6.Name, - SetID: n.set6.ID, - }, - //[ immediate reg 0 drop ] - &expr.Verdict{ - Kind: expr.VerdictDrop, - }, - }, + Exprs: []expr.Any{}, + } + // [ payload load 4b @ network header + 16 => reg 1 ] + r.Exprs = append(r.Exprs, &expr.Payload{ + DestRegister: 1, + Base: expr.PayloadBaseNetworkHeader, + Offset: 8, + Len: 16, }) + // [ lookup reg 1 set whitelist ] + r.Exprs = append(r.Exprs, &expr.Lookup{ + SourceRegister: 1, + SetName: n.set6.Name, + SetID: n.set6.ID, + }) + if n.DenyLog { + r.Exprs = append(r.Exprs, &expr.Log{ + Key: unix.NFTA_LOG_PREFIX, + Data: []byte(n.DenyLogPrefix), + }) + } + if strings.EqualFold(n.DenyAction, "REJECT") { + r.Exprs = append(r.Exprs, &expr.Reject{ + Type: unix.NFT_REJECT_ICMP_UNREACH, + Code: unix.NFT_REJECT_ICMPX_ADMIN_PROHIBITED, + }) + } else { + r.Exprs = append(r.Exprs, &expr.Verdict{ + Kind: expr.VerdictDrop, + }) + } + + n.conn6.AddRule(r) if err := n.conn6.Flush(); err != nil { return err