diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f23997..315be68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Changelog +## v1.4.2 - + +- Fix static config (SERVER_NAME not empty) support when using autoconf/swarm/k8s +- Fix config files overwrite when using Docker autoconf +- Add log_default() plugin hook +- Force NGINX version dependencies in Linux packages DEB/RPM +- Add Discord to supported plugins + ## v1.4.1 - 2022/16/06 + - Fix sending local IPs to BunkerNet when DISABLE_DEFAULT_SERVER=yes - Fix certbot bug when AUTOCONF_MODE=yes - Fix certbot bug when MULTISITE=no diff --git a/README.md b/README.md index 29f6d85..a0711d5 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,7 @@ Here is the list of "official" plugins that we maintain (see the [bunkerweb-plug | :------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------: | | **ClamAV** | 0.1 | Automatically scans uploaded files with the ClamAV antivirus engine and denies the request when a file is detected as malicious. | [bunkerweb-plugins/clamav](https://github.com/bunkerity/bunkerweb-plugins/tree/main/clamav) | | **CrowdSec** | 0.1 | CrowdSec bouncer for BunkerWeb. | [bunkerweb-plugins/crowdsec](https://github.com/bunkerity/bunkerweb-plugins/tree/main/crowdsec) | +| **Discord** | 0.1 | Send security notifications to a Discord channel using a Webhook. | [bunkerweb-plugins/discord](https://github.com/bunkerity/bunkerweb-plugins/tree/main/discord) | | **VirusTotal** | 0.1 | Automatically scans uploaded files with the VirusTotal API and denies the request when a file is detected as malicious. | [bunkerweb-plugins/virustotal](https://github.com/bunkerity/bunkerweb-plugins/tree/main/virustotal) | You will find more information in the [plugins section](https://docs.bunkerweb.io/latest/plugins) of the documentation. @@ -280,7 +281,7 @@ This project is licensed under the terms of the [GNU Affero General Public Licen # Contribute -If you would like to contribute to the plugins you can read the [contributing guidelines](https://github.com/bunkerity/bunkerweb/tree/master/LICENSE.md) to get started. +If you would like to contribute to the plugins you can read the [contributing guidelines](https://github.com/bunkerity/bunkerweb/tree/master/CONTRIBUTING.md) to get started. # Security policy diff --git a/confs/default-server-http.conf b/confs/default-server-http.conf index 7b31686..5cef586 100644 --- a/confs/default-server-http.conf +++ b/confs/default-server-http.conf @@ -12,4 +12,50 @@ server { # include custom default-server configurations include /opt/bunkerweb/configs/default-server-http/*.conf; + + log_by_lua_block { + + local utils = require "utils" + local logger = require "logger" + local datastore = require "datastore" + local plugins = require "plugins" + + logger.log(ngx.INFO, "LOG", "Log phase started") + + -- List all plugins + local list, err = plugins:list() + if not list then + logger.log(ngx.ERR, "LOG", "Can't list loaded plugins : " .. err) + list = {} + end + + -- Call log_default method of plugins + for i, plugin in ipairs(list) do + local ret, plugin_lua = pcall(require, plugin.id .. "/" .. plugin.id) + if ret then + local plugin_obj = plugin_lua.new() + if plugin_obj.log_default ~= nil then + logger.log(ngx.INFO, "LOG", "Executing log_default() of " .. plugin.id) + local ok, err = plugin_obj:log_default() + if not ok then + logger.log(ngx.ERR, "LOG", "Error while calling log_default() on plugin " .. plugin.id .. " : " .. err) + else + logger.log(ngx.INFO, "LOG", "Return value from " .. plugin.id .. ".log_default() is : " .. err) + end + else + logger.log(ngx.INFO, "LOG", "log_default() method not found in " .. plugin.id .. ", skipped execution") + end + end + end + + -- Display reason at info level + local reason = utils.get_reason() + if reason then + logger.log(ngx.INFO, "LOG", "Client was denied with reason : " .. reason) + end + + logger.log(ngx.INFO, "LOG", "Log phase ended") + + } + } diff --git a/core/bunkernet/bunkernet.lua b/core/bunkernet/bunkernet.lua index 8ee08b2..36467d2 100644 --- a/core/bunkernet/bunkernet.lua +++ b/core/bunkernet/bunkernet.lua @@ -141,11 +141,13 @@ function _M:report(ip, reason, method, url, headers) return self:request("POST", "/report", data) end -function _M:log() - -- Check if BunkerNet is activated - local use_bunkernet = utils.get_variable("USE_BUNKERNET") - if use_bunkernet ~= "yes" then - return true, "bunkernet not activated" +function _M:log(bypass_use_bunkernet) + if bypass_use_bunkernet then + -- Check if BunkerNet is activated + local use_bunkernet = utils.get_variable("USE_BUNKERNET") + if use_bunkernet ~= "yes" then + return true, "bunkernet not activated" + end end -- Check if BunkerNet ID is generated if not self.id then @@ -193,6 +195,27 @@ function _M:log() return true, "created report timer" end +function _M:log_default() + -- Check if bunkernet is activated + local check, err = utils.has_variable("USE_BUNKERNET", "yes") + if check == nil then + return false, "error while checking variable USE_BUNKERNET (" .. err .. ")" + end + if not check then + return true, "bunkernet not enabled" + end + -- Check if default server is disabled + local check, err = utils.get_variable("DISABLE_DEFAULT_SERVER", false) + if check == nil then + return false, "error while getting variable DISABLE_DEFAULT_SERVER (" .. err .. ")" + end + if check ~= "yes" then + return true, "default server not disabled" + end + -- Call log method + return self:log(true) +end + function _M:access() local use_bunkernet = utils.get_variable("USE_BUNKERNET") if use_bunkernet ~= "yes" then diff --git a/core/bunkernet/confs/default-server-http/bunkernet.conf b/core/bunkernet/confs/default-server-http/bunkernet.conf deleted file mode 100644 index 419090b..0000000 --- a/core/bunkernet/confs/default-server-http/bunkernet.conf +++ /dev/null @@ -1,59 +0,0 @@ -log_by_lua_block { - local bunkernet = require "bunkernet.bunkernet" - local utils = require "utils" - local datastore = require "datastore" - local logger = require "logger" - local disable_default_server = utils.get_variable("DISABLE_DEFAULT_SERVER", false) - local use_bunkernet = utils.has_variable("USE_BUNKERNET", "yes") - - if disable_default_server == "yes" and use_bunkernet then - -- Instantiate bunkernet - local bnet, err = bunkernet.new() - if not bnet then - ngx.log(ngx.ERR, "BUNKERNET", "can't instantiate bunkernet " .. err) - return - end - -- Check if BunkerNet ID is generated - if not bnet.id then - return - end - -- Check if IP has been blocked - if ngx.status ~= ngx.HTTP_CLOSE then - return - end - -- Check if IP is global - local is_global, err = utils.ip_is_global(ngx.var.remote_addr) - if is_global == nil then - return - end - if not is_global then - return - end - -- Only report if it hasn't been reported for the same reason recently - local reported = datastore:get("plugin_bunkernet_cache_" .. ngx.var.remote_addr .. "default") - if reported then - return - end - -- report callback called in a light thread - local function report_callback(premature, obj, ip, reason, method, url, headers) - local ok, err, status, data = obj:report(ip, reason, method, url, headers) - if not ok then - logger.log(ngx.ERR, "BUNKERNET", "Can't report IP : " .. err) - elseif status ~= 200 then - logger.log(ngx.ERR, "BUNKERNET", "Error from remote server : " .. tostring(status)) - else - logger.log(ngx.NOTICE, "BUNKERNET", "Successfully reported IP " .. ip .. " (reason : " .. reason .. ")") - local ok, err = datastore:set("plugin_bunkernet_cache_" .. ip .. reason, true, 3600) - if not ok then - logger.log(ngx.ERR, "BUNKERNET", "Can't store cached report : " .. err) - end - end - end - -- Set a timer at the end of log() - local hdr, err = ngx.timer.at(0, report_callback, bnet, ngx.var.remote_addr, "default", ngx.var.request_method, ngx.var.request_uri, ngx.req.get_headers()) - if not hdr then - logger.log(ngx.ERR, "BUNKERNET", "can't create report timer : " .. err) - end - return - end -} \ No newline at end of file diff --git a/core/misc/confs/default-server-http/disable.conf b/core/misc/confs/default-server-http/disable.conf index dc7b907..6868be9 100644 --- a/core/misc/confs/default-server-http/disable.conf +++ b/core/misc/confs/default-server-http/disable.conf @@ -1,5 +1,6 @@ {% if DISABLE_DEFAULT_SERVER == "yes" +%} location / { + set $reason "default"; return 444; } {% endif %} \ No newline at end of file diff --git a/docs/plugins.md b/docs/plugins.md index b9d59ad..bd99bb3 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -10,6 +10,7 @@ Here is the list of "official" plugins that we maintain (see the [bunkerweb-plug | :------------: | :-----: | :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------: | | **ClamAV** | 0.1 | Automatically scans uploaded files with the ClamAV antivirus engine and denies the request when a file is detected as malicious. | [bunkerweb-plugins/clamav](https://github.com/bunkerity/bunkerweb-plugins/tree/main/clamav) | | **CrowdSec** | 0.1 | CrowdSec bouncer for BunkerWeb. | [bunkerweb-plugins/crowdsec](https://github.com/bunkerity/bunkerweb-plugins/tree/main/crowdsec) | +| **Discord** | 0.1 | Send security notifications to a Discord channel using a Webhook. | [bunkerweb-plugins/discord](https://github.com/bunkerity/bunkerweb-plugins/tree/main/discord) | | **VirusTotal** | 0.1 | Automatically scans uploaded files with the VirusTotal API and denies the request when a file is detected as malicious. | [bunkerweb-plugins/virustotal](https://github.com/bunkerity/bunkerweb-plugins/tree/main/virustotal) | ## How to use a plugin @@ -242,16 +243,22 @@ function _M:log() return true, "success" end +function _M:log_default() + logger.log(ngx.NOTICE, "MYPLUGIN", "log_default called") + return true, "success" +end + return _M ``` -The 3 functions `init`, `access`, and `log` are automatically called during specific contexts. Here are the details of each function : +The declared functions are automatically called during specific contexts. Here are the details of each function : | Function | Context | Description | Return value | | :------: | :--------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `init` | [init_by_lua](https://github.com/openresty/lua-nginx-module#init_by_lua) | Called when NGINX just started or received a reload order. the typical use case is to prepare any data that will be used by your plugin. | `ret`, `err` | | `access` | [access_by_lua](https://github.com/openresty/lua-nginx-module#access_by_lua) | Called on each request received by the server. The typical use case is to do the security checks here and deny the request if needed. | `ret`, `err`, `return`, `status` | | `log` | [log_by_lua](https://github.com/openresty/lua-nginx-module#log_by_lua) | Called when a request has finished (and before it gets logged to the access logs). The typical use case is to make stats or compute counters for example. | `ret`, `err` | +| `log_default` | [log_by_lua](https://github.com/openresty/lua-nginx-module#log_by_lua) | Same as `log` but only called on the default server. | `ret`, `err` | #### Libraries