Merge pull request #701 from bunkerity/dev

Merge branch "dev" into "staging"
This commit is contained in:
Théophile Diot 2023-10-16 14:14:27 +02:00 committed by GitHub
commit 4a10ec8c30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
113 changed files with 3319 additions and 2967 deletions

View file

@ -21,11 +21,11 @@ jobs:
- name: Checkout repository
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Initialize CodeQL
uses: github/codeql-action/init@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1
uses: github/codeql-action/init@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1
uses: github/codeql-action/analyze@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3
with:
category: "/language:${{matrix.language}}"

View file

@ -92,7 +92,7 @@ jobs:
- id: set-matrix
run: |
tests=$(find ./tests/core/ -maxdepth 1 -mindepth 1 -type d -printf "%f\n" | jq -c --raw-input --slurp 'split("\n")| .[0:-1]')
echo "::set-output name=tests::$tests"
echo "tests=$tests" >> $GITHUB_OUTPUT
outputs:
tests: ${{ steps.set-matrix.outputs.tests }}
tests-core:

View file

@ -23,7 +23,7 @@ jobs:
with:
name: BunkerWeb_documentation_v${{ inputs.VERSION }}.pdf
# Create tag
- uses: rickstaa/action-create-tag@88dbf7ff6fe2405f8e8f6c6fdfd78829bc631f83 # v1.6.3
- uses: rickstaa/action-create-tag@55450aa830ede05bcbb37fbdad678e36c73e9d15 # v1.6.4
name: Create tag
if: inputs.VERSION != 'testing'
with:
@ -31,7 +31,7 @@ jobs:
message: "v${{ inputs.VERSION }}"
force_push_tag: true
# Create tag
- uses: rickstaa/action-create-tag@88dbf7ff6fe2405f8e8f6c6fdfd78829bc631f83 # v1.6.3
- uses: rickstaa/action-create-tag@55450aa830ede05bcbb37fbdad678e36c73e9d15 # v1.6.4
name: Create tag
if: inputs.VERSION == 'testing'
with:
@ -47,7 +47,7 @@ jobs:
content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"
echo "::set-output name=content::$content"
echo "content=$content" >> $GITHUB_OUTPUT
# Create release
- name: Create release
if: inputs.VERSION != 'testing'

View file

@ -42,7 +42,7 @@ jobs:
- name: Check out repository code
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Install ruby
uses: ruby/setup-ruby@d37167af451eb51448db3354e1057b75c4b268f7 # v1.155.0
uses: ruby/setup-ruby@5cfe23c062c0aac352e765b1b7cc12ea5255ccc4 # v1.156.0
with:
ruby-version: "3.0"
- name: Install packagecloud

View file

@ -25,6 +25,6 @@ jobs:
results_format: sarif
publish_results: true
- name: "Upload SARIF results to code scanning"
uses: github/codeql-action/upload-sarif@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1
uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3
with:
sarif_file: results.sarif

View file

@ -93,7 +93,7 @@ jobs:
- id: set-matrix
run: |
tests=$(find ./tests/core/ -maxdepth 1 -mindepth 1 -type d -printf "%f\n" | jq -c --raw-input --slurp 'split("\n")| .[0:-1]')
echo "::set-output name=tests::$tests"
echo "tests=$tests" >> $GITHUB_OUTPUT
outputs:
tests: ${{ steps.set-matrix.outputs.tests }}

View file

@ -67,8 +67,6 @@ jobs:
- name: Fix version without a starting number
if: inputs.RELEASE == 'testing' || inputs.RELEASE == 'dev'
run: echo "force-bad-version" | sudo tee -a /etc/dpkg/dpkg.cfg
- name: Install BunkerWeb
run: sudo apt install -fy /tmp/bunkerweb.deb
- name: Edit configuration files
run: |
# Misc
@ -79,6 +77,7 @@ jobs:
sudo systemctl stop php8.1-fpm
sudo systemctl start php8.1-fpm
# BunkerWeb
sudo mkdir -p /etc/bunkerweb
echo "SERVER_NAME=www.example.com" | sudo tee /etc/bunkerweb/variables.env
echo "HTTP_PORT=80" | sudo tee -a /etc/bunkerweb/variables.env
echo "HTTPS_PORT=443" | sudo tee -a /etc/bunkerweb/variables.env
@ -88,8 +87,11 @@ jobs:
echo "LOG_LEVEL=info" | sudo tee -a /etc/bunkerweb/variables.env
sudo chown nginx:nginx /etc/bunkerweb/variables.env
sudo chmod 777 /etc/bunkerweb/variables.env
- name: Install BunkerWeb
run: sudo apt install -fy /tmp/bunkerweb.deb
- name: Run tests
run: |
cd ./tests/core/${{ inputs.TEST }}
MAKEFLAGS="-j $(nproc)" find . -name "requirements.txt" -exec pip install --no-cache-dir --require-hashes -r {} \;
sudo truncate -s 0 /var/log/bunkerweb/error.log
./test.sh "linux"

2
.luacheckrc Normal file
View file

@ -0,0 +1,2 @@
globals = {"ngx", "delay", "unpack"}
ignore = {"411"}

View file

@ -3,7 +3,7 @@
exclude: (^LICENSE.md$|^src/VERSION$|^src/(bw/misc/root-ca.pem$|deps/src/|common/core/modsecurity/files|ui/static/js/(editor/|utils/purify/|tsparticles\.bundle\.min\.js))|\.(svg|drawio|patch\d?|ascii|tf|tftpl)$)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: f71fa2c1f9cf5cb705f73dffe4b21f7c61470ba9 # frozen: v4.4.0
rev: c4a0b883114b00d8d76b479c820ce7950211c99b # frozen: v4.5.0
hooks:
- id: requirements-txt-fixer
- id: trailing-whitespace
@ -26,6 +26,19 @@ repos:
- id: prettier
name: Prettier Code Formatter
- repo: https://github.com/JohnnyMorganz/StyLua
rev: 27e6b388796604181e810ef05c9fb15a9f7a7769 # frozen: v0.18.2
hooks:
- id: stylua-github
exclude: ^src/(bw/lua/middleclass.lua|common/core/antibot/captcha.lua)$
- repo: https://github.com/lunarmodules/luacheck
rev: ababb6d403d634eb74d2c541035e9ede966e710d # frozen: v1.1.1
hooks:
- id: luacheck
exclude: ^src/(bw/lua/middleclass.lua|common/core/antibot/captcha.lua)$
args: ["--std", "min", "--codes", "--ranges", "--no-cache"]
- repo: https://github.com/pycqa/flake8
rev: 10f4af6dbcf93456ba7df762278ae61ba3120dc6 # frozen: 6.1.0
hooks:

View file

@ -1,5 +1,5 @@
mkdocs==1.5.3
mkdocs-material==9.4.5
mkdocs-material==9.4.6
pytablewriter==1.2.0
mike==1.1.2
mkdocs-print-site-plugin==2.3.6

View file

@ -236,9 +236,9 @@ mkdocs==1.5.3 \
# -r requirements.in
# mike
# mkdocs-material
mkdocs-material==9.4.5 \
--hash=sha256:0922e3e34d95dbf3f0c84fc817a233e1cbd5874830c6fd821d525ba90e0ce077 \
--hash=sha256:efaa52843a8c64b99bcf5a97cf4ba57d410424828e3087b13c9b3954e8adb5ff
mkdocs-material==9.4.6 \
--hash=sha256:09665e60df7ee9e5ff3a54af173f6d45be718b1ee7dd962bcff3102b81fb0c14 \
--hash=sha256:78802035d5768a78139c84ad7dce0c6493e8f7dc4861727d36ed91d1520a54da
# via
# -r requirements.in
# mkdocs-print-site-plugin
@ -472,6 +472,7 @@ typepy==1.3.2 \
# dataproperty
# pytablewriter
# tabledata
# typepy
urllib3==2.0.6 \
--hash=sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2 \
--hash=sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564

View file

@ -1,20 +1,46 @@
local dummy = {}
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local logger = require "logger"
local dummy = class("dummy", plugin)
dummy.init = function(self)
logger.log(ngx.NOTICE, "DUMMY", "init() called")
return true, "success"
function dummy:initialize()
plugin.initialize(self, "dummy")
self.dummy = "dummy"
end
dummy.access = function(self)
logger.log(ngx.NOTICE, "DUMMY", "access() called")
return true, "success", false, nil
function dummy:init()
self.logger:log(ngx.NOTICE, "init called")
return self:ret(true, "success")
end
dummy.log = function(self)
logger.log(ngx.NOTICE, "DUMMY", "log() called")
return true, "success"
function dummy:set()
self.logger:log(ngx.NOTICE, "set called")
return self:ret(true, "success")
end
function dummy:access()
self.logger:log(ngx.NOTICE, "access called")
return self:ret(true, "success")
end
function dummy:log()
self.logger:log(ngx.NOTICE, "log called")
return self:ret(true, "success")
end
function dummy:log_default()
self.logger:log(ngx.NOTICE, "log_default called")
return self:ret(true, "success")
end
function dummy:preread()
self.logger:log(ngx.NOTICE, "preread called")
return self:ret(true, "success")
end
function dummy:log_stream()
self.logger:log(ngx.NOTICE, "log_stream called")
return self:ret(true, "success")
end
return dummy

View file

@ -4,6 +4,7 @@
"name": "Dummy example plugin",
"description": "Just an example plugin.",
"version": "0.1",
"stream": "no",
"settings": {
"DUMMY_SETTING": {
"context": "multisite",

View file

@ -1 +1 @@
ansible==8.4.0
ansible==8.5.0

View file

@ -4,9 +4,9 @@
#
# pip-compile --allow-unsafe --generate-hashes --strip-extras requirements-ansible.in
#
ansible==8.4.0 \
--hash=sha256:d601d89a4306934e7c0aae05195fd72c0719287fde165982d0ebac282b4280f1 \
--hash=sha256:f33c492690592fad12684e9897f6de2da15c9f6e1ecb79137703a06470af2ce6
ansible==8.5.0 \
--hash=sha256:2749032e26b0dbc9a694528b85fd89e7f950b8c7b53606f17dd997f23ac7cc88 \
--hash=sha256:327c509bdaf5cdb2489d85c09d2c107e9432f9874c8bb5c0702a731160915f2d
# via -r requirements-ansible.in
ansible-core==2.15.5 \
--hash=sha256:3efa234de5fce79ec98853f3369535b27cacd7ce498495b996030cd15c373735 \

View file

@ -1,15 +1,15 @@
local class = require "middleclass"
local cjson = require "cjson"
local class = require "middleclass"
local datastore = require "bunkerweb.datastore"
local utils = require "bunkerweb.utils"
local logger = require "bunkerweb.logger"
local cjson = require "cjson"
local upload = require "resty.upload"
local rsignal = require "resty.signal"
local process = require "ngx.process"
local logger = require "bunkerweb.logger"
local process = require "ngx.process"
local rsignal = require "resty.signal"
local upload = require "resty.upload"
local utils = require "bunkerweb.utils"
local api = class("api")
local api = class("api")
api.global = { GET = {}, POST = {}, PUT = {}, DELETE = {} }
api.global = { GET = {}, POST = {}, PUT = {}, DELETE = {} }
function api:initialize()
self.datastore = datastore:new()
@ -26,6 +26,7 @@ function api:initialize()
end
end
-- luacheck: ignore 212
function api:log_cmd(cmd, status, stdout, stderr)
local level = ngx.NOTICE
local prefix = "success"
@ -33,7 +34,7 @@ function api:log_cmd(cmd, status, stdout, stderr)
level = ngx.ERR
prefix = "error"
end
self.logger:log(level, prefix .. " while running command " .. command)
self.logger:log(level, prefix .. " while running command " .. cmd)
self.logger:log(level, "stdout = " .. stdout)
self.logger:log(level, "stdout = " .. stderr)
end
@ -41,6 +42,7 @@ end
-- TODO : use this if we switch to OpenResty
function api:cmd(cmd)
-- Non-blocking command
-- luacheck: ignore 113
local ok, stdout, stderr, reason, status = shell.run(cmd, nil, 10000)
self.logger:log_cmd(cmd, status, stdout, stderr)
-- Timeout
@ -51,6 +53,7 @@ function api:cmd(cmd)
return status == 0, reason, status
end
-- luacheck: ignore 212
function api:response(http_status, api_status, msg)
local resp = {}
resp["status"] = api_status
@ -101,6 +104,7 @@ api.global.POST["^/confs$"] = function(self)
form:set_timeout(1000)
local file = io.open(tmp, "w+")
while true do
-- luacheck: ignore 421
local typ, res, err = form:read()
if not typ then
file:close()
@ -117,9 +121,9 @@ api.global.POST["^/confs$"] = function(self)
file:close()
local cmds = {
"rm -rf " .. destination .. "/*",
"tar xzf " .. tmp .. " -C " .. destination
"tar xzf " .. tmp .. " -C " .. destination,
}
for i, cmd in ipairs(cmds) do
for _, cmd in ipairs(cmds) do
local status = os.execute(cmd)
if status ~= 0 then
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
@ -176,17 +180,23 @@ end
api.global.GET["^/bans$"] = function(self)
local data = {}
for i, k in ipairs(self.datastore:keys()) do
for _, k in ipairs(self.datastore:keys()) do
if k:find("^bans_ip_") then
local reason, err = self.datastore:get(k)
if err then
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error",
"can't access " .. k .. " from datastore : " .. reason)
return self:response(
ngx.HTTP_INTERNAL_SERVER_ERROR,
"error",
"can't access " .. k .. " from datastore : " .. reason
)
end
local ok, ttl = self.datastore:ttl(k)
if not ok then
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error",
"can't access ttl " .. k .. " from datastore : " .. ttl)
return self:response(
ngx.HTTP_INTERNAL_SERVER_ERROR,
"error",
"can't access ttl " .. k .. " from datastore : " .. ttl
)
end
local ban = { ip = k:sub(9, #k), reason = reason, exp = math.floor(ttl) }
table.insert(data, ban)
@ -196,7 +206,7 @@ api.global.GET["^/bans$"] = function(self)
end
api.global.GET["^/variables$"] = function(self)
local variables, err = datastore:get('variables', true)
local variables, err = datastore:get("variables", true)
if not variables then
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't access variables from datastore : " .. err)
end
@ -219,9 +229,9 @@ function api:do_api_call()
if status ~= ngx.HTTP_OK then
ret = false
end
if (#resp["msg"] == 0) then
if #resp["msg"] == 0 then
resp["msg"] = ""
elseif (type(resp["msg"]) == "table") then
elseif type(resp["msg"]) == "table" then
resp["data"] = resp["msg"]
resp["msg"] = resp["status"]
end
@ -231,10 +241,10 @@ function api:do_api_call()
end
local list, err = self.datastore:get("plugins", true)
if not list then
local status, resp = self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't list loaded plugins : " .. err)
local _, resp = self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't list loaded plugins : " .. err)
return false, resp["msg"], ngx.HTTP_INTERNAL_SERVER_ERROR, cjson.encode(resp)
end
for i, plugin in ipairs(list) do
for _, plugin in ipairs(list) do
if pcall(require, plugin.id .. "/" .. plugin.id) then
local plugin_lua = require(plugin.id .. "/" .. plugin.id)
if plugin_lua.api ~= nil then

View file

@ -1,42 +1,38 @@
local mlcache = require "resty.mlcache"
local class = require "middleclass"
local clusterstore = require "bunkerweb.clusterstore"
local logger = require "bunkerweb.logger"
local utils = require "bunkerweb.utils"
local class = require "middleclass"
local cachestore = class("cachestore")
local logger = require "bunkerweb.logger"
local mlcache = require "resty.mlcache"
local utils = require "bunkerweb.utils"
local cachestore = class("cachestore")
-- Instantiate mlcache object at module level (which will be cached when running init phase)
-- TODO : custom settings
local shm = "cachestore"
local ipc_shm = "cachestore_ipc"
local shm_miss = "cachestore_miss"
local shm_locks = "cachestore_locks"
local shm = "cachestore"
local ipc_shm = "cachestore_ipc"
local shm_miss = "cachestore_miss"
local shm_locks = "cachestore_locks"
if not ngx.shared.cachestore then
shm = "cachestore_stream"
ipc_shm = "cachestore_ipc_stream"
shm_miss = "cachestore_miss_stream"
shm = "cachestore_stream"
ipc_shm = "cachestore_ipc_stream"
shm_miss = "cachestore_miss_stream"
shm_locks = "cachestore_locks_stream"
end
local cache, err = mlcache.new(
"cachestore",
shm,
{
lru_size = 100,
ttl = 30,
neg_ttl = 0.1,
shm_set_tries = 3,
shm_miss = shm_miss,
shm_locks = shm_locks,
resty_lock_opts = {
exptime = 30,
timeout = 5,
step = 0.001,
ratio = 2,
max_step = 0.5
},
ipc_shm = ipc_shm
}
)
local cache, err = mlcache.new("cachestore", shm, {
lru_size = 100,
ttl = 30,
neg_ttl = 0.1,
shm_set_tries = 3,
shm_miss = shm_miss,
shm_locks = shm_locks,
resty_lock_opts = {
exptime = 30,
timeout = 5,
step = 0.001,
ratio = 2,
max_step = 0.5,
},
ipc_shm = ipc_shm,
})
local module_logger = logger:new("CACHESTORE")
if not cache then
module_logger:log(ngx.ERR, "can't instantiate mlcache : " .. err)
@ -57,10 +53,12 @@ function cachestore:initialize(use_redis, new_cs, ctx)
end
function cachestore:get(key)
-- luacheck: ignore 432
local callback = function(key, cs)
-- Connect to redis
-- luacheck: ignore 431
local clusterstore = cs or require "bunkerweb.clusterstore":new(false)
local ok, err, reused = clusterstore:connect()
local ok, err, _ = clusterstore:connect()
if not ok then
return nil, "can't connect to redis : " .. err, nil
end
@ -96,6 +94,7 @@ function cachestore:get(key)
local callback_no_miss = function()
return nil, nil, -1
end
-- luacheck: ignore 431
local value, err, hit_level
if self.use_redis and utils.is_cosocket_available() then
local cs = nil
@ -114,13 +113,14 @@ function cachestore:get(key)
end
function cachestore:set(key, value, ex)
-- luacheck: ignore 431
local ok, err
if self.use_redis and utils.is_cosocket_available() then
local ok, err = self:set_redis(key, value, ex)
ok, err = self:set_redis(key, value, ex)
if not ok then
self.logger:log(ngx.ERR, err)
end
end
local ok, err
if ex then
ok, err = self.cache:set(key, { ttl = ex }, value)
else
@ -134,13 +134,14 @@ end
function cachestore:set_redis(key, value, ex)
-- Connect to redis
local ok, err, reused = self.clusterstore:connect()
-- luacheck: ignore 431
local ok, err, _ = self.clusterstore:connect()
if not ok then
return false, "can't connect to redis : " .. err
end
-- Set value with ttl
local default_ex = ex or 30
local ok, err = self.clusterstore:call("set", key, value, "EX", default_ex)
local _, err = self.clusterstore:call("set", key, value, "EX", default_ex)
if err then
self.clusterstore:close()
return false, "SET failed : " .. err
@ -149,14 +150,16 @@ function cachestore:set_redis(key, value, ex)
return true
end
function cachestore:delete(key, value, ex)
function cachestore:delete(key)
-- luacheck: ignore 431
local ok, err
if self.use_redis and utils.is_cosocket_available() then
local ok, err = self.del_redis(key)
ok, err = self:del_redis(key)
if not ok then
self.logger:log(ngx.ERR, err)
end
end
local ok, err = self.cache:delete(key)
ok, err = self.cache:delete(key)
if not ok then
return false, err
end
@ -165,12 +168,13 @@ end
function cachestore:del_redis(key)
-- Connect to redis
-- luacheck: ignore 431
local ok, err = self.clusterstore:connect()
if not ok then
return false, "can't connect to redis : " .. err
end
-- Set value with ttl
local ok, err = self.clusterstore:del(key)
local _, err = self.clusterstore:del(key)
if err then
self.clusterstore:close()
return false, "DEL failed : " .. err

View file

@ -1,135 +1,138 @@
local class = require "middleclass"
local utils = require "bunkerweb.utils"
local logger = require "bunkerweb.logger"
local redis = require "resty.redis"
local class = require "middleclass"
local logger = require "bunkerweb.logger"
local redis = require "resty.redis"
local utils = require "bunkerweb.utils"
local clusterstore = class("clusterstore")
function clusterstore:initialize(pool)
-- Instantiate logger
self.logger = logger:new("CLUSTERSTORE")
-- Get variables
local variables = {
["REDIS_HOST"] = "",
["REDIS_PORT"] = "",
["REDIS_DATABASE"] = "",
["REDIS_SSL"] = "",
["REDIS_TIMEOUT"] = "",
["REDIS_KEEPALIVE_IDLE"] = "",
["REDIS_KEEPALIVE_POOL"] = ""
}
-- Set them for later user
self.variables = {}
for k, v in pairs(variables) do
local value, err = utils.get_variable(k, false)
if value == nil then
self.logger:log(ngx.ERR, err)
end
self.variables[k] = value
end
-- Don't instantiate a redis object for now
self.redis_client = nil
self.pool = pool == nil or pool
-- Instantiate logger
self.logger = logger:new("CLUSTERSTORE")
-- Get variables
local variables = {
["REDIS_HOST"] = "",
["REDIS_PORT"] = "",
["REDIS_DATABASE"] = "",
["REDIS_SSL"] = "",
["REDIS_TIMEOUT"] = "",
["REDIS_KEEPALIVE_IDLE"] = "",
["REDIS_KEEPALIVE_POOL"] = "",
}
-- Set them for later user
self.variables = {}
for k, _ in pairs(variables) do
local value, err = utils.get_variable(k, false)
if value == nil then
self.logger:log(ngx.ERR, err)
end
self.variables[k] = value
end
-- Don't instantiate a redis object for now
self.redis_client = nil
self.pool = pool == nil or pool
end
function clusterstore:connect()
-- Check if we are already connected
if self.redis_client then
return true, "already connected", self.redis_client:get_reused_times()
end
-- Instantiate object
local redis_client, err = redis:new()
if redis_client == nil then
return false, err
end
-- Set timeouts
redis_client:set_timeout(tonumber(self.variables["REDIS_TIMEOUT"]))
-- Connect
local options = {
ssl = self.variables["REDIS_SSL"] == "yes",
}
if self.pool then
options.pool = "bw-redis"
options.pool_size = tonumber(self.variables["REDIS_KEEPALIVE_POOL"])
end
local ok, err = redis_client:connect(self.variables["REDIS_HOST"], tonumber(self.variables["REDIS_PORT"]), options)
if not ok then
return false, err
end
self.redis_client = redis_client
-- Select database if needed
local times, err = self.redis_client:get_reused_times()
if err then
self:close()
return false, err
end
if times == 0 then
local select, err = self.redis_client:select(tonumber(self.variables["REDIS_DATABASE"]))
if err then
self:close()
return false, err
end
end
return true, "success", times
-- Check if we are already connected
if self.redis_client then
return true, "already connected", self.redis_client:get_reused_times()
end
-- Instantiate object
local redis_client, err = redis:new()
if redis_client == nil then
return false, err
end
-- Set timeouts
redis_client:set_timeout(tonumber(self.variables["REDIS_TIMEOUT"]))
-- Connect
local options = {
ssl = self.variables["REDIS_SSL"] == "yes",
}
if self.pool then
options.pool = "bw-redis"
options.pool_size = tonumber(self.variables["REDIS_KEEPALIVE_POOL"])
end
local ok, err = redis_client:connect(self.variables["REDIS_HOST"], tonumber(self.variables["REDIS_PORT"]), options)
if not ok then
return false, err
end
self.redis_client = redis_client
-- Select database if needed
local times, err = self.redis_client:get_reused_times()
if err then
self:close()
return false, err
end
if times == 0 then
-- luacheck: ignore 421
local _, err = self.redis_client:select(tonumber(self.variables["REDIS_DATABASE"]))
if err then
self:close()
return false, err
end
end
return true, "success", times
end
function clusterstore:close()
if self.redis_client then
-- Equivalent to close but keep a pool of connections
if self.pool then
local ok, err = self.redis_client:set_keepalive(tonumber(self.variables["REDIS_KEEPALIVE_IDLE"]),
tonumber(self.variables["REDIS_KEEPALIVE_POOL"]))
self.redis_client = nil
if not ok then
require "bunkerweb.logger":new("clusterstore-close"):log(ngx.ERR, err)
end
return ok, err
end
-- Close
local ok, err = self.redis_client:close()
self.redis_client.redis_client = nil
return ok, err
end
return false, "not connected"
if self.redis_client then
-- Equivalent to close but keep a pool of connections
if self.pool then
local ok, err = self.redis_client:set_keepalive(
tonumber(self.variables["REDIS_KEEPALIVE_IDLE"]),
tonumber(self.variables["REDIS_KEEPALIVE_POOL"])
)
self.redis_client = nil
if not ok then
require("bunkerweb.logger"):new("clusterstore-close"):log(ngx.ERR, err)
end
return ok, err
end
-- Close
local ok, err = self.redis_client:close()
self.redis_client.redis_client = nil
return ok, err
end
return false, "not connected"
end
function clusterstore:call(method, ...)
-- Check if we are connected
if not self.redis_client then
return false, "not connected"
end
-- Call method
return self.redis_client[method](self.redis_client, ...)
-- Check if we are connected
if not self.redis_client then
return false, "not connected"
end
-- Call method
return self.redis_client[method](self.redis_client, ...)
end
function clusterstore:multi(calls)
-- Check if we are connected
if not self.redis_client then
return false, "not connected"
end
-- Start transaction
local ok, err = self.redis_client:multi()
if not ok then
return false, "multi() failed : " .. err
end
-- Loop on calls
for i, call in ipairs(calls) do
local method = call[1]
local args = unpack(call[2])
local ok, err = self.redis_client[method](self.redis_client, args)
if not ok then
return false, method + "() failed : " .. err
end
end
-- Exec transaction
local exec, err = self.redis_client:exec()
if not exec then
return false, "exec() failed : " .. err
end
if type(exec) ~= "table" then
return false, "exec() result is not a table"
end
return true, "success", exec
-- Check if we are connected
if not self.redis_client then
return false, "not connected"
end
-- Start transaction
local ok, err = self.redis_client:multi()
if not ok then
return false, "multi() failed : " .. err
end
-- Loop on calls
for _, call in ipairs(calls) do
local method = call[1]
local args = unpack(call[2])
ok, err = self.redis_client[method](self.redis_client, args)
if not ok then
return false, method + "() failed : " .. err
end
end
-- Exec transaction
local exec, err = self.redis_client:exec()
if not exec then
return false, "exec() failed : " .. err
end
if type(exec) ~= "table" then
return false, "exec() result is not a table"
end
return true, "success", exec
end
return clusterstore

View file

@ -1,11 +1,12 @@
local class = require "middleclass"
local lrucache = require "resty.lrucache"
local class = require "middleclass"
local lrucache = require "resty.lrucache"
local datastore = class("datastore")
local lru, err = lrucache.new(100000)
local lru, err = lrucache.new(100000)
if not lru then
require "bunkerweb.logger":new("DATASTORE"):log(ngx.ERR,
"failed to instantiate LRU cache : " .. (err or "unknown error"))
require "bunkerweb.logger"
:new("DATASTORE")
:log(ngx.ERR, "failed to instantiate LRU cache : " .. (err or "unknown error"))
end
function datastore:initialize()
@ -16,11 +17,13 @@ function datastore:initialize()
end
function datastore:get(key, worker)
-- luacheck: ignore 431
local value, err
if worker then
local value, err = lru:get(key)
value, err = lru:get(key)
return value, err or "not found"
end
local value, err = self.dict:get(key)
value, err = self.dict:get(key)
if not value and not err then
err = "not found"
end
@ -52,10 +55,11 @@ function datastore:keys(worker)
return self.dict:get_keys(0)
end
function datastore:ttl(key)
function datastore:ttl(key, worker)
if worker then
return false, "not supported by LRU"
end
-- luacheck: ignore 431
local ttl, err = self.dict:ttl(key)
if not ttl then
return false, err
@ -64,13 +68,13 @@ function datastore:ttl(key)
end
function datastore:delete_all(pattern, worker)
local keys = {}
local keys
if worker then
keys = lru:keys(0)
else
keys = self.dict:get_keys(0)
end
for i, key in ipairs(keys) do
for _, key in ipairs(keys) do
if key:match(pattern) then
self.dict:delete(key)
end
@ -78,6 +82,7 @@ function datastore:delete_all(pattern, worker)
return true, "success"
end
-- luacheck: ignore 212
function datastore:flush_lru()
lru:flush_all()
end

View file

@ -1,263 +1,263 @@
local utils = require "bunkerweb.utils"
local cjson = require "cjson"
local cjson = require "cjson"
local utils = require "bunkerweb.utils"
local helpers = {}
local helpers = {}
helpers.load_plugin = function(json)
-- Open file
local file, err, nb = io.open(json, "r")
if not file then
return false, "can't load JSON at " .. json .. " : " .. err .. " (nb = " .. tostring(nb) .. ")"
end
-- Decode JSON
local ok, plugin = pcall(cjson.decode, file:read("*a"))
file:close()
if not ok then
return false, "invalid JSON at " .. json .. " : " .. err
end
-- Check fields
local missing_fields = {}
local required_fields = { "id", "name", "description", "version", "settings", "stream" }
for i, field in ipairs(required_fields) do
if plugin[field] == nil then
table.insert(missing_fields, field)
end
end
if #missing_fields > 0 then
return false, "missing field(s) " .. cjson.encode(missing_fields) .. " for JSON at " .. json
end
-- Try require
local plugin_lua, err = helpers.require_plugin(plugin.id)
if plugin_lua == false then
return false, err
end
-- Fill phases
local phases = utils.get_phases()
plugin.phases = {}
if plugin_lua then
for i, phase in ipairs(phases) do
if plugin_lua[phase] ~= nil then
table.insert(plugin.phases, phase)
end
end
end
-- Return plugin
return true, plugin
helpers.load_plugin = function(json)
-- Open file
local file, err, nb = io.open(json, "r")
if not file then
return false, "can't load JSON at " .. json .. " : " .. err .. " (nb = " .. tostring(nb) .. ")"
end
-- Decode JSON
local ok, plugin = pcall(cjson.decode, file:read("*a"))
file:close()
if not ok then
return false, "invalid JSON at " .. json .. " : " .. err
end
-- Check fields
local missing_fields = {}
local required_fields = { "id", "name", "description", "version", "settings", "stream" }
for _, field in ipairs(required_fields) do
if plugin[field] == nil then
table.insert(missing_fields, field)
end
end
if #missing_fields > 0 then
return false, "missing field(s) " .. cjson.encode(missing_fields) .. " for JSON at " .. json
end
-- Try require
local plugin_lua, err = helpers.require_plugin(plugin.id)
if plugin_lua == false then
return false, err
end
-- Fill phases
local phases = utils.get_phases()
plugin.phases = {}
if plugin_lua then
for _, phase in ipairs(phases) do
if plugin_lua[phase] ~= nil then
table.insert(plugin.phases, phase)
end
end
end
-- Return plugin
return true, plugin
end
helpers.order_plugins = function(plugins)
-- Extract orders
local file, err, nb = io.open("/usr/share/bunkerweb/core/order.json", "r")
if not file then
return false, err .. " (nb = " .. tostring(nb) .. ")"
end
local ok, orders = pcall(cjson.decode, file:read("*a"))
file:close()
if not ok then
return false, "invalid order.json : " .. err
end
-- Compute plugins/id/phases table
local plugins_phases = {}
for i, plugin in ipairs(plugins) do
plugins_phases[plugin.id] = {}
for j, phase in ipairs(plugin.phases) do
plugins_phases[plugin.id][phase] = true
end
end
-- Order result
local result_orders = {}
for i, phase in ipairs(utils.get_phases()) do
result_orders[phase] = {}
end
-- Fill order first
for phase, order in pairs(orders) do
for i, id in ipairs(order) do
local plugin = plugins_phases[id]
if plugin and plugin[phase] then
table.insert(result_orders[phase], id)
plugin[phase] = nil
end
end
end
-- Then append missing plugins to the end
for i, phase in ipairs(utils.get_phases()) do
for id, plugin in pairs(plugins_phases) do
if plugin[phase] then
table.insert(result_orders[phase], id)
plugin[phase] = nil
end
end
end
return true, result_orders
helpers.order_plugins = function(plugins)
-- Extract orders
local file, err, nb = io.open("/usr/share/bunkerweb/core/order.json", "r")
if not file then
return false, err .. " (nb = " .. tostring(nb) .. ")"
end
local ok, orders = pcall(cjson.decode, file:read("*a"))
file:close()
if not ok then
return false, "invalid order.json : " .. err
end
-- Compute plugins/id/phases table
local plugins_phases = {}
for _, plugin in ipairs(plugins) do
plugins_phases[plugin.id] = {}
for _, phase in ipairs(plugin.phases) do
plugins_phases[plugin.id][phase] = true
end
end
-- Order result
local result_orders = {}
for _, phase in ipairs(utils.get_phases()) do
result_orders[phase] = {}
end
-- Fill order first
for phase, order in pairs(orders) do
for _, id in ipairs(order) do
local plugin = plugins_phases[id]
if plugin and plugin[phase] then
table.insert(result_orders[phase], id)
plugin[phase] = nil
end
end
end
-- Then append missing plugins to the end
for _, phase in ipairs(utils.get_phases()) do
for id, plugin in pairs(plugins_phases) do
if plugin[phase] then
table.insert(result_orders[phase], id)
plugin[phase] = nil
end
end
end
return true, result_orders
end
helpers.require_plugin = function(id)
-- Require call
local ok, plugin_lua = pcall(require, id .. "/" .. id)
if not ok then
if plugin_lua:match("not found") then
return nil, "plugin " .. id .. " doesn't have LUA code"
end
return false, "require error for plugin " .. id .. " : " .. plugin_lua
end
-- New call
if plugin_lua.new == nil then
return false, "missing new() method for plugin " .. id
end
-- Return plugin
return plugin_lua, "require() call successful for plugin " .. id
-- Require call
local ok, plugin_lua = pcall(require, id .. "/" .. id)
if not ok then
if plugin_lua:match("not found") then
return nil, "plugin " .. id .. " doesn't have LUA code"
end
return false, "require error for plugin " .. id .. " : " .. plugin_lua
end
-- New call
if plugin_lua.new == nil then
return false, "missing new() method for plugin " .. id
end
-- Return plugin
return plugin_lua, "require() call successful for plugin " .. id
end
helpers.new_plugin = function(plugin_lua, ctx)
-- Require call
local ok, plugin_obj = pcall(plugin_lua.new, plugin_lua, ctx)
if not ok then
return false, "new error for plugin " .. plugin_lua.name .. " : " .. plugin_obj
end
return true, plugin_obj
helpers.new_plugin = function(plugin_lua, ctx)
-- Require call
local ok, plugin_obj = pcall(plugin_lua.new, plugin_lua, ctx)
if not ok then
return false, "new error for plugin " .. plugin_lua.name .. " : " .. plugin_obj
end
return true, plugin_obj
end
helpers.call_plugin = function(plugin, method)
-- Check if method is present
if plugin[method] == nil then
return nil, "missing " .. method .. "() method for plugin " .. plugin:get_id()
end
-- Call method
local ok, ret = pcall(plugin[method], plugin)
if not ok then
return false, plugin:get_id() .. ":" .. method .. "() failed : " .. ret
end
if ret == nil then
return false, plugin:get_id() .. ":" .. method .. "() returned nil value"
end
-- Check values
local missing_values = {}
local required_values = { "ret", "msg" }
for i, value in ipairs(required_values) do
if ret[value] == nil then
table.insert(missing_values, value)
end
end
if #missing_values > 0 then
return false, "missing required return value(s) : " .. cjson.encode(missing_values)
end
-- Return
return true, ret
helpers.call_plugin = function(plugin, method)
-- Check if method is present
if plugin[method] == nil then
return nil, "missing " .. method .. "() method for plugin " .. plugin:get_id()
end
-- Call method
local ok, ret = pcall(plugin[method], plugin)
if not ok then
return false, plugin:get_id() .. ":" .. method .. "() failed : " .. ret
end
if ret == nil then
return false, plugin:get_id() .. ":" .. method .. "() returned nil value"
end
-- Check values
local missing_values = {}
local required_values = { "ret", "msg" }
for _, value in ipairs(required_values) do
if ret[value] == nil then
table.insert(missing_values, value)
end
end
if #missing_values > 0 then
return false, "missing required return value(s) : " .. cjson.encode(missing_values)
end
-- Return
return true, ret
end
helpers.fill_ctx = function()
-- Return errors as table
local errors = {}
local ctx = ngx.ctx
-- Check if ctx is already filled
if not ctx.bw then
-- Instantiate bw table
local data = {}
-- Common vars
data.kind = "http"
if ngx.shared.datastore_stream then
data.kind = "stream"
end
data.remote_addr = ngx.var.remote_addr
data.server_name = ngx.var.server_name
if data.kind == "http" then
data.uri = ngx.var.uri
data.request_uri = ngx.var.request_uri
data.request_method = ngx.var.request_method
data.http_user_agent = ngx.var.http_user_agent
data.http_host = ngx.var.http_host
data.server_name = ngx.var.server_name
data.http_content_type = ngx.var.http_content_type
data.http_content_length = ngx.var.http_content_length
data.http_origin = ngx.var.http_origin
data.http_version = ngx.req.http_version()
data.scheme = ngx.var.scheme
end
-- IP data : global
local ip_is_global, err = utils.ip_is_global(data.remote_addr)
if ip_is_global == nil then
table.insert(errors, "can't check if IP is global : " .. err)
else
data.ip_is_global = ip_is_global
end
-- IP data : v4 / v6
data.ip_is_ipv4 = utils.is_ipv4(data.ip)
data.ip_is_ipv6 = utils.is_ipv6(data.ip)
-- Misc info
data.integration = utils.get_integration()
data.version = utils.get_version()
-- Fill ctx
ctx.bw = data
end
-- Always create new objects for current phases in case of cosockets
local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then
table.insert(errors, "can't get variable from datastore : " .. err)
end
ctx.bw.datastore = require "bunkerweb.datastore":new()
ctx.bw.clusterstore = require "bunkerweb.clusterstore":new()
ctx.bw.cachestore = require "bunkerweb.cachestore":new(use_redis == "yes")
return true, "ctx filled", errors, ctx
helpers.fill_ctx = function()
-- Return errors as table
local errors = {}
local ctx = ngx.ctx
-- Check if ctx is already filled
if not ctx.bw then
-- Instantiate bw table
local data = {}
-- Common vars
data.kind = "http"
if ngx.shared.datastore_stream then
data.kind = "stream"
end
data.remote_addr = ngx.var.remote_addr
data.server_name = ngx.var.server_name
if data.kind == "http" then
data.uri = ngx.var.uri
data.request_uri = ngx.var.request_uri
data.request_method = ngx.var.request_method
data.http_user_agent = ngx.var.http_user_agent
data.http_host = ngx.var.http_host
data.server_name = ngx.var.server_name
data.http_content_type = ngx.var.http_content_type
data.http_content_length = ngx.var.http_content_length
data.http_origin = ngx.var.http_origin
data.http_version = ngx.req.http_version()
data.scheme = ngx.var.scheme
end
-- IP data : global
local ip_is_global, err = utils.ip_is_global(data.remote_addr)
if ip_is_global == nil then
table.insert(errors, "can't check if IP is global : " .. err)
else
data.ip_is_global = ip_is_global
end
-- IP data : v4 / v6
data.ip_is_ipv4 = utils.is_ipv4(data.ip)
data.ip_is_ipv6 = utils.is_ipv6(data.ip)
-- Misc info
data.integration = utils.get_integration()
data.version = utils.get_version()
-- Fill ctx
ctx.bw = data
end
-- Always create new objects for current phases in case of cosockets
local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then
table.insert(errors, "can't get variable from datastore : " .. err)
end
ctx.bw.datastore = require "bunkerweb.datastore":new()
ctx.bw.clusterstore = require "bunkerweb.clusterstore":new()
ctx.bw.cachestore = require "bunkerweb.cachestore":new(use_redis == "yes")
return true, "ctx filled", errors, ctx
end
function helpers.load_variables(all_variables, plugins)
-- Extract settings from plugins and global ones
local all_settings = {}
for i, plugin in ipairs(plugins) do
if plugin.settings then
for setting, data in pairs(plugin.settings) do
all_settings[setting] = data
end
end
end
local file = io.open("/usr/share/bunkerweb/settings.json")
if not file then
return false, "can't open settings.json"
end
local ok, settings = pcall(cjson.decode, file:read("*a"))
file:close()
if not ok then
return false, "invalid settings.json : " .. err
end
for setting, data in pairs(settings) do
all_settings[setting] = data
end
-- Extract vars
local variables = { ["global"] = {} }
local multisite = all_variables["MULTISITE"] == "yes"
local server_names = {}
if multisite then
for server_name in all_variables["SERVER_NAME"]:gmatch("%S+") do
variables[server_name] = {}
table.insert(server_names, server_name)
end
end
for setting, data in pairs(all_settings) do
if all_variables[setting] then
variables["global"][setting] = all_variables[setting]
end
if data.multiple then
for variable, value in pairs(all_variables) do
local _, server_name, multiple_setting = variable:match("((%S*_?)(" .. setting .. "_%d+))")
if multiple_setting then
if multisite and server_name and server_name:match("%S+_$") then
variables[server_name:sub(1, -2)][multiple_setting] = value
else
variables["global"][multiple_setting] = value
end
end
end
end
if multisite then
for i, server_name in ipairs(server_names) do
local key = server_name .. "_" .. setting
if all_variables[key] then
variables[server_name][setting] = all_variables[key]
end
end
end
end
return true, variables
-- Extract settings from plugins and global ones
local all_settings = {}
for _, plugin in ipairs(plugins) do
if plugin.settings then
for setting, data in pairs(plugin.settings) do
all_settings[setting] = data
end
end
end
local file = io.open("/usr/share/bunkerweb/settings.json")
if not file then
return false, "can't open settings.json"
end
local ok, settings = pcall(cjson.decode, file:read("*a"))
file:close()
if not ok then
return false, "invalid settings.json : " .. settings
end
for setting, data in pairs(settings) do
all_settings[setting] = data
end
-- Extract vars
local variables = { ["global"] = {} }
local multisite = all_variables["MULTISITE"] == "yes"
local server_names = {}
if multisite then
for server_name in all_variables["SERVER_NAME"]:gmatch("%S+") do
variables[server_name] = {}
table.insert(server_names, server_name)
end
end
for setting, data in pairs(all_settings) do
if all_variables[setting] then
variables["global"][setting] = all_variables[setting]
end
if data.multiple then
for variable, value in pairs(all_variables) do
local _, server_name, multiple_setting = variable:match("((%S*_?)(" .. setting .. "_%d+))")
if multiple_setting then
if multisite and server_name and server_name:match("%S+_$") then
variables[server_name:sub(1, -2)][multiple_setting] = value
else
variables["global"][multiple_setting] = value
end
end
end
end
if multisite then
for _, server_name in ipairs(server_names) do
local key = server_name .. "_" .. setting
if all_variables[key] then
variables[server_name][setting] = all_variables[key]
end
end
end
end
return true, variables
end
return helpers

View file

@ -1,5 +1,5 @@
local class = require "middleclass"
local errlog = require "ngx.errlog"
local class = require "middleclass"
local logger = class("logger")
function logger:initialize(prefix)

View file

@ -1,6 +1,6 @@
local geoip = require "geoip.mmdb"
return {
country_db = geoip.load_database("/var/cache/bunkerweb/country.mmdb"),
asn_db = geoip.load_database("/var/cache/bunkerweb/asn.mmdb")
country_db = geoip.load_database "/var/cache/bunkerweb/country.mmdb",
asn_db = geoip.load_database "/var/cache/bunkerweb/asn.mmdb",
}

View file

@ -1,87 +1,88 @@
local class = require "middleclass"
local logger = require "bunkerweb.logger"
local datastore = require "bunkerweb.datastore"
local cachestore = require "bunkerweb.cachestore"
local cachestore = require "bunkerweb.cachestore"
local class = require "middleclass"
local clusterstore = require "bunkerweb.clusterstore"
local utils = require "bunkerweb.utils"
local cjson = require "cjson"
local plugin = class("plugin")
local datastore = require "bunkerweb.datastore"
local logger = require "bunkerweb.logger"
local utils = require "bunkerweb.utils"
local plugin = class("plugin")
function plugin:initialize(id, ctx)
-- Store common, values
self.id = id
local multisite = false
local current_phase = ngx.get_phase()
for i, check_phase in ipairs({ "set", "access", "content", "header_filter", "log", "preread", "log_stream",
"log_default" }) do
if current_phase == check_phase then
multisite = true
break
end
end
self.is_request = multisite
-- Store common objects
self.logger = logger:new(self.id)
local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then
self.logger:log(ngx.ERR, err)
end
self.use_redis = use_redis == "yes"
if self.is_request then
-- Store ctx
self.ctx = ctx or ngx.ctx
self.datastore = utils.get_ctx_obj("datastore", self.ctx) or datastore:new()
self.cachestore = utils.get_ctx_obj("cachestore", self.ctx) or cachestore:new(use_redis == "yes", true, self.ctx)
self.clusterstore = utils.get_ctx_obj("clusterstore", self.ctx) or clusterstore:new(false)
else
self.datastore = datastore:new()
self.cachestore = cachestore:new(use_redis == "yes", true)
self.clusterstore = clusterstore:new(false)
end
-- Get metadata
local metadata, err = self.datastore:get("plugin_" .. id, true)
if not metadata then
self.logger:log(ngx.ERR, err)
return
end
-- Store variables
self.variables = {}
self.multiples = {}
for k, v in pairs(metadata.settings) do
local value, err = utils.get_variable(k, v.context == "multisite" and multisite)
if value == nil then
self.logger:log(ngx.ERR, "can't get " .. k .. " variable : " .. err)
end
self.variables[k] = value
-- if v.multiple then
-- local multiples, err = utils.get_multiple_variables(k)
-- if not multiples then
-- self.logger:log(ngx.ERR, "can't get " .. k .. " multiple variable : " .. err)
-- self.multiples[k] = {}
-- else
-- self.multiples[k] = multiples
-- end
-- end
end
-- Is loading
local is_loading, err = utils.get_variable("IS_LOADING", false)
if is_loading == nil then
self.logger:log(ngx.ERR, "can't get IS_LOADING variable : " .. err)
end
self.is_loading = is_loading == "yes"
-- Kind of server
self.kind = "http"
if ngx.shared.datastore_stream then
self.kind = "stream"
end
-- Store common, values
self.id = id
local multisite = false
local current_phase = ngx.get_phase()
for _, check_phase in ipairs {
"set",
"access",
"content",
"header_filter",
"log",
"preread",
"log_stream",
"log_default",
} do
if current_phase == check_phase then
multisite = true
break
end
end
self.is_request = multisite
-- Store common objects
self.logger = logger:new(self.id)
local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then
self.logger:log(ngx.ERR, err)
end
self.use_redis = use_redis == "yes"
if self.is_request then
-- Store ctx
self.ctx = ctx or ngx.ctx
self.datastore = utils.get_ctx_obj("datastore", self.ctx) or datastore:new()
self.cachestore = utils.get_ctx_obj("cachestore", self.ctx)
or cachestore:new(use_redis == "yes", true, self.ctx)
self.clusterstore = utils.get_ctx_obj("clusterstore", self.ctx) or clusterstore:new(false)
else
self.datastore = datastore:new()
self.cachestore = cachestore:new(use_redis == "yes", true)
self.clusterstore = clusterstore:new(false)
end
-- Get metadata
local metadata, err = self.datastore:get("plugin_" .. id, true)
if not metadata then
self.logger:log(ngx.ERR, err)
return
end
-- Store variables
self.variables = {}
self.multiples = {}
local value
for k, v in pairs(metadata.settings) do
value, err = utils.get_variable(k, v.context == "multisite" and multisite)
if value == nil then
self.logger:log(ngx.ERR, "can't get " .. k .. " variable : " .. err)
end
self.variables[k] = value
end
-- Is loading
local is_loading, err = utils.get_variable("IS_LOADING", false)
if is_loading == nil then
self.logger:log(ngx.ERR, "can't get IS_LOADING variable : " .. err)
end
self.is_loading = is_loading == "yes"
-- Kind of server
self.kind = "http"
if ngx.shared.datastore_stream then
self.kind = "stream"
end
end
function plugin:get_id()
return self.id
return self.id
end
-- luacheck: ignore 212
function plugin:ret(ret, msg, status, redirect)
return { ret = ret, msg = msg, status = status, redirect = redirect }
return { ret = ret, msg = msg, status = status, redirect = redirect }
end
return plugin

View file

@ -1,26 +1,26 @@
local cdatastore = require "bunkerweb.datastore"
local mmdb = require "bunkerweb.mmdb"
local clogger = require "bunkerweb.logger"
local clogger = require "bunkerweb.logger"
local mmdb = require "bunkerweb.mmdb"
local ipmatcher = require "resty.ipmatcher"
local resolver = require "resty.dns.resolver"
local session = require "resty.session"
local cjson = require "cjson"
local cjson = require "cjson"
local ipmatcher = require "resty.ipmatcher"
local resolver = require "resty.dns.resolver"
local session = require "resty.session"
local logger = clogger:new("UTILS")
local datastore = cdatastore:new()
local logger = clogger:new("UTILS")
local datastore = cdatastore:new()
local utils = {}
local utils = {}
math.randomseed(os.time())
utils.get_variable = function(var, site_search)
utils.get_variable = function(var, site_search)
-- Default site search to true
if site_search == nil then
site_search = true
end
-- Get global value
local variables, err = datastore:get('variables', true)
local variables, err = datastore:get("variables", true)
if not variables then
return nil, "can't access variables from datastore : " .. err
end
@ -33,9 +33,9 @@ utils.get_variable = function(var, site_search)
return value, "success"
end
utils.has_variable = function(var, value)
utils.has_variable = function(var, value)
-- Get global variable
local variables, err = datastore:get('variables', true)
local variables, err = datastore:get("variables", true)
if not variables then
return nil, "can't access variables " .. var .. " from datastore : " .. err
end
@ -56,9 +56,9 @@ utils.has_variable = function(var, value)
return variables["global"][var] == value, "success"
end
utils.has_not_variable = function(var, value)
utils.has_not_variable = function(var, value)
-- Get global variable
local variables, err = datastore:get('variables', true)
local variables, err = datastore:get("variables", true)
if not variables then
return nil, "can't access variables " .. var .. " from datastore : " .. err
end
@ -80,9 +80,9 @@ utils.has_not_variable = function(var, value)
end
utils.get_multiple_variables = function(vars)
local variables, err = datastore:get('variables', true)
local variables, err = datastore:get("variables", true)
if not variables then
return nil, "can't access variables " .. var .. " from datastore : " .. err
return nil, "can't access variables " .. vars .. " from datastore : " .. err
end
local result = {}
-- Loop on scoped vars
@ -90,7 +90,7 @@ utils.get_multiple_variables = function(vars)
result[scope] = {}
-- Loop on vars
for variable, value in pairs(scoped_vars) do
for i, var in ipairs(vars) do
for _, var in ipairs(vars) do
if variable:find("^" .. var .. "_?[0-9]*$") then
result[scope][variable] = value
end
@ -100,7 +100,7 @@ utils.get_multiple_variables = function(vars)
return result
end
utils.is_ip_in_networks = function(ip, networks)
utils.is_ip_in_networks = function(ip, networks)
-- Instantiate ipmatcher
local ipm, err = ipmatcher.new(networks)
if not ipm then
@ -114,15 +114,15 @@ utils.is_ip_in_networks = function(ip, networks)
return matched
end
utils.is_ipv4 = function(ip)
utils.is_ipv4 = function(ip)
return ipmatcher.parse_ipv4(ip)
end
utils.is_ipv6 = function(ip)
utils.is_ipv6 = function(ip)
return ipmatcher.parse_ipv6(ip)
end
utils.ip_is_global = function(ip)
utils.ip_is_global = function(ip)
-- Reserved, non public IPs
local reserved_ips = {
"0.0.0.0/8",
@ -154,7 +154,7 @@ utils.ip_is_global = function(ip)
"2002::/16",
"fc00::/7",
"fe80::/10",
"ff00::/8"
"ff00::/8",
}
-- Instantiate ipmatcher
local ipm, err = ipmatcher.new(reserved_ips)
@ -169,9 +169,9 @@ utils.ip_is_global = function(ip)
return not matched, "success"
end
utils.get_integration = function()
utils.get_integration = function()
-- Check if already in datastore
local integration, err = datastore:get("misc_integration", true)
local integration, _ = datastore:get("misc_integration", true)
if integration then
return integration
end
@ -193,12 +193,12 @@ utils.get_integration = function()
integration = "autoconf"
else
-- Already present (e.g. : linux)
local f, err = io.open("/usr/share/bunkerweb/INTEGRATION", "r")
local f, _ = io.open("/usr/share/bunkerweb/INTEGRATION", "r")
if f then
integration = f:read("*a"):gsub("[\n\r]", "")
f:close()
else
local f, err = io.open("/etc/os-release", "r")
f, _ = io.open("/etc/os-release", "r")
if f then
local data = f:read("*a")
f:close()
@ -222,9 +222,9 @@ utils.get_integration = function()
return integration
end
utils.get_version = function()
utils.get_version = function()
-- Check if already in datastore
local version, err = datastore:get("misc_version", true)
local version, _ = datastore:get("misc_version", true)
if version then
return version
end
@ -244,7 +244,7 @@ utils.get_version = function()
return version
end
utils.get_reason = function(ctx)
utils.get_reason = function(ctx)
-- ngx.ctx
if ctx.bw.reason then
return ctx.bw.reason
@ -258,7 +258,7 @@ utils.get_reason = function(ctx)
return "modsecurity"
end
-- datastore ban
local banned, err = datastore:get("bans_ip_" .. ngx.var.remote_addr)
local banned, _ = datastore:get("bans_ip_" .. ngx.var.remote_addr)
if banned then
return banned
end
@ -269,9 +269,9 @@ utils.get_reason = function(ctx)
return nil
end
utils.get_resolvers = function()
utils.get_resolvers = function()
-- Get resolvers from datastore if existing
local resolvers, err = datastore:get("misc_resolvers", true)
local resolvers, _ = datastore:get("misc_resolvers", true)
if resolvers then
return resolvers
end
@ -282,7 +282,7 @@ utils.get_resolvers = function()
return "unknown"
end
-- Make table for resolver1 resolver2 ... string
local resolvers = {}
resolvers = {}
for str_resolver in variables["global"]["DNS_RESOLVERS"]:gmatch("%S+") do
table.insert(resolvers, str_resolver)
end
@ -294,7 +294,7 @@ utils.get_resolvers = function()
return resolvers
end
utils.get_rdns = function(ip)
utils.get_rdns = function(ip)
-- Check cache
local cachestore = utils.new_cachestore()
local ok, value = cachestore:get("rdns_" .. ip)
@ -312,7 +312,7 @@ utils.get_rdns = function(ip)
local rdns, err = resolver:new {
nameservers = resolvers,
retrans = 1,
timeout = 1000
timeout = 1000,
}
if not rdns then
return false, err
@ -330,21 +330,21 @@ utils.get_rdns = function(ip)
ret_err = answers.errstr
end
-- Extract all PTR
for i, answer in ipairs(answers) do
for _, answer in ipairs(answers) do
if answer.ptrdname then
table.insert(ptrs, answer.ptrdname)
end
end
end
-- Save to cache
local ok, err = cachestore:set("rdns_" .. ip, cjson.encode(ptrs), 3600)
ok, err = cachestore:set("rdns_" .. ip, cjson.encode(ptrs), 3600)
if not ok then
logger:log(ngx.ERR, "can't set rdns into cachestore : " .. err)
end
return ptrs, ret_err
end
utils.get_ips = function(fqdn, ipv6)
utils.get_ips = function(fqdn, ipv6)
-- Check cache
local cachestore = utils.new_cachestore()
local ok, value = cachestore:get("dns_" .. fqdn)
@ -366,7 +366,7 @@ utils.get_ips = function(fqdn, ipv6)
local res, err = resolver:new {
nameservers = resolvers,
retrans = 1,
timeout = 1000
timeout = 1000,
}
if not res then
return false, err
@ -374,6 +374,7 @@ utils.get_ips = function(fqdn, ipv6)
-- Get query types : AAAA and A if using IPv6 / only A if not using IPv6
local qtypes = {}
if ipv6 then
-- luacheck: ignore 421
local use_ipv6, err = utils.get_variable("USE_IPV6", false)
if not use_ipv6 then
logger:log(ngx.ERR, "can't get USE_IPV6 variable " .. err)
@ -386,9 +387,10 @@ utils.get_ips = function(fqdn, ipv6)
local res_answers = {}
local res_errors = {}
local ans_errors = {}
for i, qtype in ipairs(qtypes) do
local answers
for _, qtype in ipairs(qtypes) do
-- Query FQDN
local answers, err = res:query(fqdn, { qtype = qtype }, {})
answers, err = res:query(fqdn, { qtype = qtype }, {})
local qtype_str = qtype == res.TYPE_AAAA and "AAAA" or "A"
if not answers then
res_errors[qtype_str] = err
@ -403,22 +405,23 @@ utils.get_ips = function(fqdn, ipv6)
end
-- Extract all IPs
local ips = {}
for i, answers in ipairs(res_answers) do
for j, answer in ipairs(answers) do
-- luacheck: ignore 421
for _, answers in ipairs(res_answers) do
for _, answer in ipairs(answers) do
if answer.address then
table.insert(ips, answer.address)
end
end
end
-- Save to cache
local ok, err = cachestore:set("dns_" .. fqdn, cjson.encode(ips), 3600)
ok, err = cachestore:set("dns_" .. fqdn, cjson.encode(ips), 3600)
if not ok then
logger:log(ngx.ERR, "can't set dns into cachestore : " .. err)
end
return ips, cjson.encode(res_errors) .. " " .. cjson.encode(ans_errors)
end
utils.get_country = function(ip)
utils.get_country = function(ip)
-- Check if mmdb is loaded
if not mmdb.country_db then
return false, "mmdb country not loaded"
@ -434,7 +437,7 @@ utils.get_country = function(ip)
return result.country.iso_code, "success"
end
utils.get_asn = function(ip)
utils.get_asn = function(ip)
-- Check if mmdp is loaded
if not mmdb.asn_db then
return false, "mmdb asn not loaded"
@ -450,22 +453,28 @@ utils.get_asn = function(ip)
return result.autonomous_system_number, "success"
end
utils.rand = function(nb, no_numbers)
utils.rand = function(nb, no_numbers)
local charset = {}
-- lowers, uppers and numbers
if not no_numbers then
for i = 48, 57 do table.insert(charset, string.char(i)) end
for i = 48, 57 do
table.insert(charset, string.char(i))
end
end
for i = 65, 90 do
table.insert(charset, string.char(i))
end
for i = 97, 122 do
table.insert(charset, string.char(i))
end
for i = 65, 90 do table.insert(charset, string.char(i)) end
for i = 97, 122 do table.insert(charset, string.char(i)) end
local result = ""
for i = 1, nb do
for _ = 1, nb do
result = result .. charset[math.random(1, #charset)]
end
return result
end
utils.get_deny_status = function(ctx)
utils.get_deny_status = function(ctx)
-- Stream case
if ctx.bw and ctx.bw.kind == "stream" then
return 444
@ -479,10 +488,10 @@ utils.get_deny_status = function(ctx)
return tonumber(variables["global"]["DENY_HTTP_STATUS"])
end
utils.check_session = function(ctx)
local _session, err, exists, refreshed = session.start({ audience = "metadata" })
utils.check_session = function(ctx)
local _session, _, exists, _ = session.start({ audience = "metadata" })
if exists then
for i, check in ipairs(ctx.bw.sessions_checks) do
for _, check in ipairs(ctx.bw.sessions_checks) do
local key = check[1]
local value = check[2]
if _session:get(key) ~= value then
@ -496,7 +505,7 @@ utils.check_session = function(ctx)
end
end
else
for i, check in ipairs(ctx.bw.sessions_checks) do
for _, check in ipairs(ctx.bw.sessions_checks) do
_session:set(check[1], check[2])
end
local ok, err = _session:save()
@ -509,7 +518,7 @@ utils.check_session = function(ctx)
return true, exists
end
utils.get_session = function(audience, ctx)
utils.get_session = function(audience, ctx)
-- Check session
if not ctx.bw.sessions_is_checked then
local ok, err = utils.check_session(ctx)
@ -518,14 +527,15 @@ utils.get_session = function(audience, ctx)
end
end
-- Open session with specific audience
local _session, err, exists = session.open({ audience = audience })
local _session, err, _ = session.open({ audience = audience })
if err then
logger:log(ngx.INFO, "session:open() error : " .. err)
end
return _session
end
utils.get_session_data = function(_session, site, ctx)
-- luacheck: ignore 214
utils.get_session_data = function(_session, site, ctx)
local site_only = site == nil or site
local data = _session:get_data()
if site_only then
@ -534,7 +544,8 @@ utils.get_session_data = function(_session, site, ctx)
return data
end
utils.set_session_data = function(_session, data, site, ctx)
-- luacheck: ignore 214
utils.set_session_data = function(_session, data, site, ctx)
local site_only = site == nil or site
if site_only then
local all_data = _session:get_data()
@ -546,7 +557,7 @@ utils.set_session_data = function(_session, data, site, ctx)
return _session:save()
end
utils.is_banned = function(ip)
utils.is_banned = function(ip)
-- Check on local datastore
local reason, err = datastore:get("bans_ip_" .. ip)
if not reason and err ~= "not found" then
@ -599,7 +610,7 @@ utils.is_banned = function(ip)
elseif data[1] ~= ngx.null then
clusterstore:close()
-- Update local cache
local ok, err = datastore:set("bans_ip_" .. ip, data[1], data[2])
ok, err = datastore:set("bans_ip_" .. ip, data[1], data[2])
if not ok then
return nil, "datastore:set() error : " .. err
end
@ -609,7 +620,7 @@ utils.is_banned = function(ip)
return false, "not banned"
end
utils.add_ban = function(ip, reason, ttl)
utils.add_ban = function(ip, reason, ttl)
-- Set on local datastore
local ok, err = datastore:set("bans_ip_" .. ip, reason, ttl)
if not ok then
@ -624,12 +635,12 @@ utils.add_ban = function(ip, reason, ttl)
end
-- Connect
local clusterstore = require "bunkerweb.clusterstore":new()
local ok, err = clusterstore:connect()
ok, err = clusterstore:connect()
if not ok then
return false, "can't connect to redis server : " .. err
end
-- SET call
local ok, err = clusterstore:call("set", "bans_ip_" .. ip, reason, "EX", ttl)
ok, err = clusterstore:call("set", "bans_ip_" .. ip, reason, "EX", ttl)
if not ok then
clusterstore:close()
return false, "redis SET failed : " .. err
@ -638,7 +649,7 @@ utils.add_ban = function(ip, reason, ttl)
return true, "success"
end
utils.new_cachestore = function()
utils.new_cachestore = function()
-- Check if redis is used
local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then
@ -650,7 +661,7 @@ utils.new_cachestore = function()
return require "bunkerweb.cachestore":new(use_redis, true)
end
utils.regex_match = function(str, regex, options)
utils.regex_match = function(str, regex, options)
local all_options = "o"
if options then
all_options = all_options .. options
@ -663,7 +674,7 @@ utils.regex_match = function(str, regex, options)
return match
end
utils.get_phases = function()
utils.get_phases = function()
return {
"init",
"init_worker",
@ -673,18 +684,18 @@ utils.get_phases = function()
"log",
"preread",
"log_stream",
"log_default"
"log_default",
}
end
utils.is_cosocket_available = function()
utils.is_cosocket_available = function()
local phases = {
"timer",
"access",
"preread"
"preread",
}
local current_phase = ngx.get_phase()
for i, phase in ipairs(phases) do
for _, phase in ipairs(phases) do
if current_phase == phase then
return true
end
@ -692,8 +703,8 @@ utils.is_cosocket_available = function()
return false
end
utils.kill_all_threads = function(threads)
for i, thread in ipairs(threads) do
utils.kill_all_threads = function(threads)
for _, thread in ipairs(threads) do
local ok, err = ngx.thread.kill(thread)
if not ok then
logger:log(ngx.ERR, "error while killing thread : " .. err)
@ -701,7 +712,7 @@ utils.kill_all_threads = function(threads)
end
end
utils.get_ctx_obj = function(obj)
utils.get_ctx_obj = function(obj)
if ngx.ctx and ngx.ctx.bw then
return ngx.ctx.bw[obj]
end

View file

@ -1,12 +1,12 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local cjson = require "cjson"
local captcha = require "antibot.captcha"
local base64 = require "base64"
local sha256 = require "resty.sha256"
local str = require "resty.string"
local http = require "resty.http"
local base64 = require "base64"
local captcha = require "antibot.captcha"
local cjson = require "cjson"
local class = require "middleclass"
local http = require "resty.http"
local plugin = require "bunkerweb.plugin"
local sha256 = require "resty.sha256"
local str = require "resty.string"
local utils = require "bunkerweb.utils"
local template = nil
if ngx.shared.datastore then
template = require "resty.template"
@ -51,40 +51,41 @@ function antibot:header()
return self:ret(true, "Not antibot uri")
end
local header = "Content-Security-Policy"
if self.variables["CONTENT_SECURITY_POLICY_REPORT_ONLY"] == "yes" then
header = header .. "-Report-Only"
end
if self.session_data.type == "recaptcha" then
ngx.header[header] =
"default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" ..
self.session_data.nonce_script ..
"' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 'unsafe-inline' http: https:; img-src https://www.gstatic.com/recaptcha/ 'self' data:; frame-src https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/; style-src 'self' 'nonce-" ..
self.session_data.nonce_style ..
"'; font-src 'self' https://fonts.gstatic.com data:; base-uri 'self';"
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
.. self.session_data.nonce_script
.. "' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 'unsafe-inline' http: https:;"
.. " img-src https://www.gstatic.com/recaptcha/ 'self' data:; "
.. " frame-src https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/;"
.. " style-src 'self' 'nonce-"
.. self.session_data.nonce_style
.. "'; font-src 'self' https://fonts.gstatic.com data:; base-uri 'self';"
elseif self.session_data.type == "hcaptcha" then
ngx.header[header] =
"default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" ..
self.session_data.nonce_script ..
"' https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' http: https:; img-src 'self' data:; frame-src https://hcaptcha.com https://*.hcaptcha.com; style-src 'self' 'nonce-" ..
self.session_data.nonce_style ..
"' https://hcaptcha.com https://*.hcaptcha.com; connect-src https://hcaptcha.com https://*.hcaptcha.com; font-src 'self' data:; base-uri 'self';"
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
.. self.session_data.nonce_script
.. "' https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' http: https:; img-src 'self' data:;"
.. " frame-src https://hcaptcha.com https://*.hcaptcha.com; style-src 'self' 'nonce-"
.. self.session_data.nonce_style
.. "' https://hcaptcha.com https://*.hcaptcha.com; connect-src https://hcaptcha.com https://*.hcaptcha.com; "
.. " font-src 'self' data:; base-uri 'self';"
elseif self.session_data.type == "turnstile" then
ngx.header[header] =
"default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" ..
self.session_data.nonce_script ..
"' https://challenges.cloudflare.com 'unsafe-inline' http: https:; img-src 'self' data:; frame-src https://challenges.cloudflare.com; style-src 'self' 'nonce-" ..
self.session_data.nonce_style ..
"'; font-src 'self' data:; base-uri 'self';"
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
.. self.session_data.nonce_script
.. "' https://challenges.cloudflare.com 'unsafe-inline' http: https:; img-src 'self' data:;"
.. " frame-src https://challenges.cloudflare.com; style-src 'self' 'nonce-"
.. self.session_data.nonce_style
.. "'; font-src 'self' data:; base-uri 'self';"
else
ngx.header[header] =
"default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-" ..
self.session_data.nonce_script ..
"' 'unsafe-inline' http: https:; img-src 'self' data:; style-src 'self' 'nonce-" ..
self.session_data.nonce_style ..
"'; font-src 'self' data:; base-uri 'self';"
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
.. self.session_data.nonce_script
.. "' 'unsafe-inline' http: https:; img-src 'self' data:; style-src 'self' 'nonce-"
.. self.session_data.nonce_style
.. "'; font-src 'self' data:; base-uri 'self';"
end
return self:ret(true, "Successfully overridden CSP header")
end
@ -138,6 +139,7 @@ function antibot:access()
-- Check challenge
if self.ctx.bw.request_method == "POST" then
-- luacheck: ignore 421
local ok, err, redirect = self:check_challenge()
local set_ok, set_err = self:set_session_data()
if not set_ok then
@ -152,7 +154,7 @@ function antibot:access()
return self:ret(true, "check challenge redirect : " .. redirect, nil, redirect)
end
self:prepare_challenge()
local ok, err = self:set_session_data()
ok, err = self:set_session_data()
if not ok then
return self:ret(false, "can't save session : " .. err, ngx.HTTP_INTERNAL_SERVER_ERROR)
end
@ -215,7 +217,9 @@ function antibot:check_session()
return
end
-- Check if new prepare is needed
if not resolved and (time_resolve > time or time - time_resolve > tonumber(self.variables["ANTIBOT_TIME_RESOLVE"])) then
if
not resolved and (time_resolve > time or time - time_resolve > tonumber(self.variables["ANTIBOT_TIME_RESOLVE"]))
then
self.session_data = {}
self.session_updated = true
return
@ -312,7 +316,7 @@ function antibot:check_challenge()
return nil, "challenge not prepared"
end
local resolved = false
local resolved
self.session_data.prepared = false
self.session_updated = true
@ -364,12 +368,15 @@ function antibot:check_challenge()
end
local res, err = httpc:request_uri("https://www.google.com/recaptcha/api/siteverify", {
method = "POST",
body = "secret=" ..
self.variables["ANTIBOT_RECAPTCHA_SECRET"] ..
"&response=" .. args["token"] .. "&remoteip=" .. self.ctx.bw.remote_addr,
body = "secret="
.. self.variables["ANTIBOT_RECAPTCHA_SECRET"]
.. "&response="
.. args["token"]
.. "&remoteip="
.. self.ctx.bw.remote_addr,
headers = {
["Content-Type"] = "application/x-www-form-urlencoded"
}
["Content-Type"] = "application/x-www-form-urlencoded",
},
})
httpc:close()
if not res then
@ -400,12 +407,15 @@ function antibot:check_challenge()
end
local res, err = httpc:request_uri("https://hcaptcha.com/siteverify", {
method = "POST",
body = "secret=" ..
self.variables["ANTIBOT_HCAPTCHA_SECRET"] ..
"&response=" .. args["token"] .. "&remoteip=" .. self.ctx.bw.remote_addr,
body = "secret="
.. self.variables["ANTIBOT_HCAPTCHA_SECRET"]
.. "&response="
.. args["token"]
.. "&remoteip="
.. self.ctx.bw.remote_addr,
headers = {
["Content-Type"] = "application/x-www-form-urlencoded"
}
["Content-Type"] = "application/x-www-form-urlencoded",
},
})
httpc:close()
if not res then
@ -413,7 +423,7 @@ function antibot:check_challenge()
end
local ok, hdata = pcall(cjson.decode, res.body)
if not ok then
return nil, "error while decoding JSON from hCaptcha API : " .. data, nil
return nil, "error while decoding JSON from hCaptcha API : " .. hdata, nil
end
if not hdata.success then
return false, "client failed challenge", nil
@ -436,12 +446,15 @@ function antibot:check_challenge()
end
local res, err = httpc:request_uri("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
method = "POST",
body = "secret=" ..
self.variables["ANTIBOT_TURNSTILE_SECRET"] ..
"&response=" .. args["token"] .. "&remoteip=" .. self.ctx.bw.remote_addr,
body = "secret="
.. self.variables["ANTIBOT_TURNSTILE_SECRET"]
.. "&response="
.. args["token"]
.. "&remoteip="
.. self.ctx.bw.remote_addr,
headers = {
["Content-Type"] = "application/x-www-form-urlencoded"
}
["Content-Type"] = "application/x-www-form-urlencoded",
},
})
httpc:close()
if not res then
@ -449,7 +462,7 @@ function antibot:check_challenge()
end
local ok, tdata = pcall(cjson.decode, res.body)
if not ok then
return nil, "error while decoding JSON from Turnstile API : " .. data, nil
return nil, "error while decoding JSON from Turnstile API : " .. tdata, nil
end
if not tdata.success then
return false, "client failed challenge", nil

View file

@ -1,6 +1,6 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local badbehavior = class("badbehavior", plugin)
@ -23,14 +23,20 @@ function badbehavior:log()
return self:ret(true, "not increasing counter")
end
-- Check if we are already banned
local banned, err = self.datastore:get("bans_ip_" .. self.ctx.bw.remote_addr)
local banned, _ = self.datastore:get("bans_ip_" .. self.ctx.bw.remote_addr)
if banned then
return self:ret(true, "already banned")
end
-- Call increase function later and with cosocket enabled
local ok, err = ngx.timer.at(0, badbehavior.increase, self.ctx.bw.remote_addr,
tonumber(self.variables["BAD_BEHAVIOR_COUNT_TIME"]), tonumber(self.variables["BAD_BEHAVIOR_BAN_TIME"]),
tonumber(self.variables["BAD_BEHAVIOR_THRESHOLD"]), self.use_redis)
local ok, err = ngx.timer.at(
0,
badbehavior.increase,
self.ctx.bw.remote_addr,
tonumber(self.variables["BAD_BEHAVIOR_COUNT_TIME"]),
tonumber(self.variables["BAD_BEHAVIOR_BAN_TIME"]),
tonumber(self.variables["BAD_BEHAVIOR_THRESHOLD"]),
self.use_redis
)
if not ok then
return self:ret(false, "can't create increase timer : " .. err)
end
@ -45,6 +51,7 @@ function badbehavior:log_stream()
return self:log()
end
-- luacheck: ignore 212
function badbehavior.increase(premature, ip, count_time, ban_time, threshold, use_redis)
-- Instantiate objects
local logger = require "bunkerweb.logger":new("badbehavior")
@ -84,16 +91,28 @@ function badbehavior.increase(premature, ip, count_time, ban_time, threshold, us
end
-- Store local ban
if counter > threshold then
local ok, err = utils.add_ban(ip, "bad behavior", ban_time)
ok, err = utils.add_ban(ip, "bad behavior", ban_time)
if not ok then
logger:log(ngx.ERR, "(increase) can't save ban : " .. err)
return
end
logger:log(ngx.WARN,
"IP " .. ip .. " is banned for " .. ban_time .. "s (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")")
logger:log(
ngx.WARN,
"IP "
.. ip
.. " is banned for "
.. ban_time
.. "s ("
.. tostring(counter)
.. "/"
.. tostring(threshold)
.. ")"
)
end
logger:log(ngx.NOTICE,
"increased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")")
logger:log(
ngx.NOTICE,
"increased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")"
)
end
function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
@ -126,7 +145,7 @@ function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
-- Store local counter
if counter <= 0 then
counter = 0
local ok, err = datastore:delete("plugin_badbehavior_count_" .. ip)
datastore:delete("plugin_badbehavior_count_" .. ip)
else
local ok, err = datastore:set("plugin_badbehavior_count_" .. ip, counter, count_time)
if not ok then
@ -134,8 +153,10 @@ function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
return
end
end
logger:log(ngx.NOTICE,
"decreased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")")
logger:log(
ngx.NOTICE,
"decreased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")"
)
end
function badbehavior.redis_increase(ip, count_time, ban_time)
@ -168,9 +189,8 @@ function badbehavior.redis_increase(ip, count_time, ban_time)
return false, err
end
-- Execute LUA script
local counter, err = clusterstore:call("eval", redis_script, 2, "plugin_bad_behavior_" .. ip, "bans_ip" .. ip,
count_time,
ban_time)
local counter, err =
clusterstore:call("eval", redis_script, 2, "plugin_bad_behavior_" .. ip, "bans_ip" .. ip, count_time, ban_time)
if not counter then
clusterstore:close()
return false, err

View file

@ -1,7 +1,7 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local class = require "middleclass"
local ipmatcher = require "resty.ipmatcher"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local blacklist = class("blacklist", plugin)
@ -78,7 +78,7 @@ function blacklist:init()
}
local i = 0
for kind, _ in pairs(blacklists) do
local f, err = io.open("/var/cache/bunkerweb/blacklist/" .. kind .. ".list", "r")
local f, _ = io.open("/var/cache/bunkerweb/blacklist/" .. kind .. ".list", "r")
if f then
for line in f:lines() do
table.insert(blacklists[kind], line)
@ -102,7 +102,7 @@ function blacklist:access()
end
-- Check the caches
local checks = {
["IP"] = "ip" .. self.ctx.bw.remote_addr
["IP"] = "ip" .. self.ctx.bw.remote_addr,
}
if self.ctx.bw.http_user_agent then
checks["UA"] = "ua" .. self.ctx.bw.http_user_agent
@ -113,14 +113,18 @@ function blacklist:access()
local already_cached = {
["IP"] = false,
["URI"] = false,
["UA"] = false
["UA"] = false,
}
for k, v in pairs(checks) do
local ok, cached = self:is_in_cache(v)
if not ok then
self.logger:log(ngx.ERR, "error while checking cache : " .. cached)
elseif cached and cached ~= "ok" then
return self:ret(true, k .. " is in cached blacklist (info : " .. cached .. ")", utils.get_deny_status(self.ctx))
return self:ret(
true,
k .. " is in cached blacklist (info : " .. cached .. ")",
utils.get_deny_status(self.ctx)
)
end
if ok and cached then
already_cached[k] = true
@ -131,18 +135,23 @@ function blacklist:access()
return self:ret(false, "lists is nil")
end
-- Perform checks
for k, v in pairs(checks) do
for k, _ in pairs(checks) do
if not already_cached[k] then
local ok, blacklisted = self:is_blacklisted(k)
if ok == nil then
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is blacklisted : " .. blacklisted)
else
-- luacheck: ignore 421
local ok, err = self:add_to_cache(self:kind_to_ele(k), blacklisted)
if not ok then
self.logger:log(ngx.ERR, "error while adding element to cache : " .. err)
end
if blacklisted ~= "ok" then
return self:ret(true, k .. " is blacklisted (info : " .. blacklisted .. ")", utils.get_deny_status(self.ctx))
return self:ret(
true,
k .. " is blacklisted (info : " .. blacklisted .. ")",
utils.get_deny_status(self.ctx)
)
end
end
end
@ -205,11 +214,11 @@ function blacklist:is_blacklisted_ip()
end
if not match then
-- Check if IP is in blacklist
local ipm, err = ipmatcher.new(self.lists["IP"])
ipm, err = ipmatcher.new(self.lists["IP"])
if not ipm then
return nil, err
end
local match, err = ipm:match(self.ctx.bw.remote_addr)
match, err = ipm:match(self.ctx.bw.remote_addr)
if err then
return nil, err
end
@ -225,13 +234,14 @@ function blacklist:is_blacklisted_ip()
end
if check_rdns then
-- Get rDNS
-- luacheck: ignore 421
local rdns_list, err = utils.get_rdns(self.ctx.bw.remote_addr)
if rdns_list then
-- Check if rDNS is in ignore list
local ignore = false
for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["IGNORE_RDNS"]) do
if rdns:sub(- #suffix) == suffix then
for _, rdns in ipairs(rdns_list) do
for _, suffix in ipairs(self.lists["IGNORE_RDNS"]) do
if rdns:sub(-#suffix) == suffix then
ignore = true
break
end
@ -239,9 +249,9 @@ function blacklist:is_blacklisted_ip()
end
-- Check if rDNS is in blacklist
if not ignore then
for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(- #suffix) == suffix then
for _, rdns in ipairs(rdns_list) do
for _, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(-#suffix) == suffix then
return true, "rDNS " .. suffix
end
end
@ -259,7 +269,7 @@ function blacklist:is_blacklisted_ip()
self.logger:log(ngx.ERR, "can't get ASN of IP " .. self.ctx.bw.remote_addr .. " : " .. err)
else
local ignore = false
for i, ignore_asn in ipairs(self.lists["IGNORE_ASN"]) do
for _, ignore_asn in ipairs(self.lists["IGNORE_ASN"]) do
if ignore_asn == tostring(asn) then
ignore = true
break
@ -267,7 +277,7 @@ function blacklist:is_blacklisted_ip()
end
-- Check if ASN is in blacklist
if not ignore then
for i, bl_asn in ipairs(self.lists["ASN"]) do
for _, bl_asn in ipairs(self.lists["ASN"]) do
if bl_asn == tostring(asn) then
return true, "ASN " .. bl_asn
end
@ -283,7 +293,7 @@ end
function blacklist:is_blacklisted_uri()
-- Check if URI is in ignore list
local ignore = false
for i, ignore_uri in ipairs(self.lists["IGNORE_URI"]) do
for _, ignore_uri in ipairs(self.lists["IGNORE_URI"]) do
if utils.regex_match(self.ctx.bw.uri, ignore_uri) then
ignore = true
break
@ -291,7 +301,7 @@ function blacklist:is_blacklisted_uri()
end
-- Check if URI is in blacklist
if not ignore then
for i, uri in ipairs(self.lists["URI"]) do
for _, uri in ipairs(self.lists["URI"]) do
if utils.regex_match(self.ctx.bw.uri, uri) then
return true, "URI " .. uri
end
@ -304,7 +314,7 @@ end
function blacklist:is_blacklisted_ua()
-- Check if UA is in ignore list
local ignore = false
for i, ignore_ua in ipairs(self.lists["IGNORE_USER_AGENT"]) do
for _, ignore_ua in ipairs(self.lists["IGNORE_USER_AGENT"]) do
if utils.regex_match(self.ctx.bw.http_user_agent, ignore_ua) then
ignore = true
break
@ -312,7 +322,7 @@ function blacklist:is_blacklisted_ua()
end
-- Check if UA is in blacklist
if not ignore then
for i, ua in ipairs(self.lists["USER_AGENT"]) do
for _, ua in ipairs(self.lists["USER_AGENT"]) do
if utils.regex_match(self.ctx.bw.http_user_agent, ua) then
return true, "UA " .. ua
end

View file

@ -122,8 +122,10 @@ try:
logger.info(
f"Blacklist for {kind} is already in cache, skipping downloads...",
)
if not urls[kind]:
logger.warning(
f"Blacklist for {kind} is cached but no URL is configured, removing from cache...",
)
blacklist_path.joinpath(f"{kind}.list").unlink(missing_ok=True)
deleted, err = del_file_in_db(f"{kind}.list", db)
if not deleted:

View file

@ -1,8 +1,8 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local cjson = require "cjson"
local http = require "resty.http"
local cjson = require "cjson"
local class = require "middleclass"
local http = require "resty.http"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local bunkernet = class("bunkernet", plugin)
@ -49,12 +49,15 @@ function bunkernet:init_worker()
return self:ret(false, "missing instance ID")
end
-- Send ping request
local ok, err, status, data = self:ping()
local ok, err, status, _ = self:ping()
if not ok then
return self:ret(false, "error while sending request to API : " .. err)
end
if status ~= 200 then
return self:ret(false, "received status " .. tostring(status) .. " from API using instance ID " .. self.bunkernet_id)
return self:ret(
false,
"received status " .. tostring(status) .. " from API using instance ID " .. self.bunkernet_id
)
end
self.logger:log(ngx.NOTICE, "connectivity with API using instance ID " .. self.bunkernet_id .. " is successful")
return self:ret(true, "connectivity with API using instance ID " .. self.bunkernet_id .. " is successful")
@ -82,7 +85,7 @@ function bunkernet:init()
local ret = true
local i = 0
local db = {
ip = {}
ip = {},
}
local f, err = io.open("/var/cache/bunkerweb/bunkernet/ip.list", "r")
if not f then
@ -128,6 +131,7 @@ function bunkernet:access()
if db then
-- Check if is IP is present
if #db.ip > 0 then
-- luacheck: ignore 421
local present, err = utils.is_ip_in_networks(self.ctx.bw.remote_addr, db.ip)
if present == nil then
return self:ret(false, "can't check if ip is in db : " .. err)
@ -166,8 +170,9 @@ function bunkernet:log(bypass_checks)
return self:ret(true, "IP is not global")
end
-- TODO : check if IP has been reported recently
-- luacheck: ignore 212 431
local function report_callback(premature, obj, ip, reason, method, url, headers)
local ok, err, status, data = obj:report(ip, reason, method, url, headers)
local ok, err, status, _ = obj:report(ip, reason, method, url, headers)
if status == 429 then
obj.logger:log(ngx.WARN, "bunkernet API is rate limiting us")
elseif not ok then
@ -177,8 +182,16 @@ function bunkernet:log(bypass_checks)
end
end
local hdr, err = ngx.timer.at(0, report_callback, self, self.ctx.bw.remote_addr, reason, self.ctx.bw.request_method,
self.ctx.bw.request_uri, ngx.req.get_headers())
local hdr, err = ngx.timer.at(
0,
report_callback,
self,
self.ctx.bw.remote_addr,
reason,
self.ctx.bw.request_method,
self.ctx.bw.request_uri,
ngx.req.get_headers()
)
if not hdr then
return self:ret(false, "can't create report timer : " .. err)
end
@ -218,7 +231,7 @@ function bunkernet:request(method, url, data)
local all_data = {
id = self.bunkernet_id,
version = self.version,
integration = self.integration
integration = self.integration,
}
if data then
for k, v in pairs(data) do
@ -230,8 +243,8 @@ function bunkernet:request(method, url, data)
body = cjson.encode(all_data),
headers = {
["Content-Type"] = "application/json",
["User-Agent"] = "BunkerWeb/" .. self.version
}
["User-Agent"] = "BunkerWeb/" .. self.version,
},
})
httpc:close()
if not res then
@ -257,7 +270,7 @@ function bunkernet:report(ip, reason, method, url, headers)
reason = reason,
method = method,
url = url,
headers = headers
headers = headers,
}
return self:request("POST", "/report", data)
end

View file

@ -1,8 +1,8 @@
local class = require "middleclass"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local utils = require "bunkerweb.utils"
local cors = class("cors", plugin)
local cors = class("cors", plugin)
function cors:initialize(ctx)
-- Call parent initialize
@ -17,7 +17,7 @@ function cors:initialize(ctx)
["CORS_MAX_AGE"] = "Access-Control-Max-Age",
["CORS_ALLOW_CREDENTIALS"] = "Access-Control-Allow-Credentials",
["CORS_ALLOW_METHODS"] = "Access-Control-Allow-Methods",
["CORS_ALLOW_HEADERS"] = "Access-Control-Allow-Headers"
["CORS_ALLOW_HEADERS"] = "Access-Control-Allow-Headers",
}
end
@ -43,7 +43,12 @@ function cors:header()
ngx.header.Vary = "Origin"
end
-- Check if Origin is allowed
if self.ctx.bw.http_origin and self.variables["CORS_DENY_REQUEST"] == "yes" and self.variables["CORS_ALLOW_ORIGIN"] ~= "*" and not utils.regex_match(self.ctx.bw.http_origin, self.variables["CORS_ALLOW_ORIGIN"]) then
if
self.ctx.bw.http_origin
and self.variables["CORS_DENY_REQUEST"] == "yes"
and self.variables["CORS_ALLOW_ORIGIN"] ~= "*"
and not utils.regex_match(self.ctx.bw.http_origin, self.variables["CORS_ALLOW_ORIGIN"])
then
self.logger:log(ngx.WARN, "origin " .. self.ctx.bw.http_origin .. " is not allowed")
return self:ret(true, "origin " .. self.ctx.bw.http_origin .. " is not allowed")
end
@ -81,9 +86,17 @@ function cors:access()
return self:ret(true, "service doesn't use CORS")
end
-- Deny as soon as possible if needed
if self.ctx.bw.http_origin and self.variables["CORS_DENY_REQUEST"] == "yes" and self.variables["CORS_ALLOW_ORIGIN"] ~= "*" and not utils.regex_match(self.ctx.bw.http_origin, self.variables["CORS_ALLOW_ORIGIN"]) then
return self:ret(true, "origin " .. self.ctx.bw.http_origin .. " is not allowed, denying access",
utils.get_deny_status(self.ctx))
if
self.ctx.bw.http_origin
and self.variables["CORS_DENY_REQUEST"] == "yes"
and self.variables["CORS_ALLOW_ORIGIN"] ~= "*"
and not utils.regex_match(self.ctx.bw.http_origin, self.variables["CORS_ALLOW_ORIGIN"])
then
return self:ret(
true,
"origin " .. self.ctx.bw.http_origin .. " is not allowed, denying access",
utils.get_deny_status(self.ctx)
)
end
-- Send CORS policy with a 204 (no content) status
if self.ctx.bw.request_method == "OPTIONS" and self.ctx.bw.http_origin then

View file

@ -1,7 +1,7 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local cjson = require "cjson"
local cjson = require "cjson"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local country = class("country", plugin)
@ -16,17 +16,28 @@ function country:access()
return self:ret(true, "country not activated")
end
-- Check if IP is in cache
local ok, data = self:is_in_cache(self.ctx.bw.remote_addr)
local _, data = self:is_in_cache(self.ctx.bw.remote_addr)
if data then
data = cjson.decode(data)
if data.result == "ok" then
return self:ret(true,
"client IP " ..
self.ctx.bw.remote_addr .. " is in country cache (not blacklisted, country = " .. data.country .. ")")
return self:ret(
true,
"client IP "
.. self.ctx.bw.remote_addr
.. " is in country cache (not blacklisted, country = "
.. data.country
.. ")"
)
end
return self:ret(true,
"client IP " .. self.ctx.bw.remote_addr .. " is in country cache (blacklisted, country = " .. data.country .. ")",
utils.get_deny_status(self.ctx))
return self:ret(
true,
"client IP "
.. self.ctx.bw.remote_addr
.. " is in country cache (blacklisted, country = "
.. data.country
.. ")",
utils.get_deny_status(self.ctx)
)
end
-- Don't go further if IP is not global
@ -39,50 +50,64 @@ function country:access()
end
-- Get the country of client
local country, err = utils.get_country(self.ctx.bw.remote_addr)
if not country then
local country_data, err = utils.get_country(self.ctx.bw.remote_addr)
if not country_data then
return self:ret(false, "can't get country of client IP " .. self.ctx.bw.remote_addr .. " : " .. err)
end
-- Process whitelist first
if self.variables["WHITELIST_COUNTRY"] ~= "" then
for wh_country in self.variables["WHITELIST_COUNTRY"]:gmatch("%S+") do
if wh_country == country then
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country, "ok")
for wh_country in self.variables["WHITELIST_COUNTRY"]:gmatch "%S+" do
if wh_country == country_data then
-- luacheck: ignore 421
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country_data, "ok")
if not ok then
return self:ret(false, "error while adding item to cache : " .. err)
end
return self:ret(true, "client IP " .. self.ctx.bw.remote_addr .. " is whitelisted (country = " .. country .. ")")
return self:ret(
true,
"client IP " .. self.ctx.bw.remote_addr .. " is whitelisted (country = " .. country_data .. ")"
)
end
end
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country, "ko")
-- luacheck: ignore 421
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country_data, "ko")
if not ok then
return self:ret(false, "error while adding item to cache : " .. err)
end
return self:ret(true, "client IP " .. self.ctx.bw.remote_addr .. " is not whitelisted (country = " .. country .. ")",
utils.get_deny_status(self.ctx))
return self:ret(
true,
"client IP " .. self.ctx.bw.remote_addr .. " is not whitelisted (country = " .. country_data .. ")",
utils.get_deny_status(self.ctx)
)
end
-- And then blacklist
if self.variables["BLACKLIST_COUNTRY"] ~= "" then
for bl_country in self.variables["BLACKLIST_COUNTRY"]:gmatch("%S+") do
if bl_country == country then
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country, "ko")
for bl_country in self.variables["BLACKLIST_COUNTRY"]:gmatch "%S+" do
if bl_country == country_data then
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country_data, "ko")
if not ok then
return self:ret(false, "error while adding item to cache : " .. err)
end
return self:ret(true, "client IP " .. self.ctx.bw.remote_addr .. " is blacklisted (country = " .. country .. ")",
utils.get_deny_status(self.ctx))
return self:ret(
true,
"client IP " .. self.ctx.bw.remote_addr .. " is blacklisted (country = " .. country_data .. ")",
utils.get_deny_status(self.ctx)
)
end
end
end
-- Country IP is not in blacklist
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country, "ok")
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr, country_data, "ok")
if not ok then
return self:ret(false, "error while caching IP " .. self.ctx.bw.remote_addr .. " : " .. err)
end
return self:ret(true, "client IP " .. self.ctx.bw.remote_addr .. " is not blacklisted (country = " .. country .. ")")
return self:ret(
true,
"client IP " .. self.ctx.bw.remote_addr .. " is not blacklisted (country = " .. country_data .. ")"
)
end
function country:preread()
@ -97,9 +122,12 @@ function country:is_in_cache(ip)
return true, data
end
function country:add_to_cache(ip, country, result)
local ok, err = self.cachestore:set("plugin_country_" .. self.ctx.bw.server_name .. ip,
cjson.encode({ country = country, result = result }), 86400)
function country:add_to_cache(ip, country_data, result)
local ok, err = self.cachestore:set(
"plugin_country_" .. self.ctx.bw.server_name .. ip,
cjson.encode { country = country_data, result = result },
86400
)
if not ok then
return false, err
end

View file

@ -1,9 +1,23 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local resolver = require "resty.dns.resolver"
local utils = require "bunkerweb.utils"
local dnsbl = class("dnsbl", plugin)
local dnsbl = class("dnsbl", plugin)
local is_in_dnsbl = function(addr, server)
local request = resolver.arpa_str(addr):gsub("%.in%-addr%.arpa", ""):gsub("%.ip6%.arpa", "") .. "." .. server
local ips, err = utils.get_ips(request, false)
if not ips then
return nil, server, err
end
for _, ip in ipairs(ips) do
if ip:find "^127%.0%.0%." then
return true, server
end
end
return false, server
end
function dnsbl:initialize(ctx)
-- Call parent initialize
@ -26,14 +40,15 @@ function dnsbl:init_worker()
local threads = {}
for server in self.variables["DNSBL_LIST"]:gmatch("%S+") do
-- Create thread
local thread = ngx.thread.spawn(self.is_in_dnsbl, self, "127.0.0.2", server)
local thread = ngx.thread.spawn(is_in_dnsbl, "127.0.0.2", server)
threads[server] = thread
end
-- Wait for threads
for dnsbl, thread in pairs(threads) do
for data, thread in pairs(threads) do
-- luacheck: ignore 421
local ok, result, server, err = ngx.thread.wait(thread)
if not ok then
self.logger:log(ngx.ERR, "error while waiting thread of " .. dnsbl .. " check : " .. result)
self.logger:log(ngx.ERR, "error while waiting thread of " .. data .. " check : " .. result)
elseif result == nil then
self.logger:log(ngx.ERR, "error while sending DNS request to " .. server .. " : " .. err)
elseif not result then
@ -65,14 +80,17 @@ function dnsbl:access()
if cached == "ok" then
return self:ret(true, "client IP " .. self.ctx.bw.remote_addr .. " is in DNSBL cache (not blacklisted)")
end
return self:ret(true, "client IP " .. self.ctx.bw.remote_addr .. " is in DNSBL cache (server = " .. cached .. ")",
utils.get_deny_status(self.ctx))
return self:ret(
true,
"client IP " .. self.ctx.bw.remote_addr .. " is in DNSBL cache (server = " .. cached .. ")",
utils.get_deny_status(self.ctx)
)
end
-- Loop on DNSBL list
local threads = {}
for server in self.variables["DNSBL_LIST"]:gmatch("%S+") do
-- Create thread
local thread = ngx.thread.spawn(self.is_in_dnsbl, self, self.ctx.bw.remote_addr, server)
local thread = ngx.thread.spawn(is_in_dnsbl, self.ctx.bw.remote_addr, server)
threads[server] = thread
end
-- Wait for threads
@ -82,7 +100,7 @@ function dnsbl:access()
while true do
-- Compute threads to wait
local wait_threads = {}
for dnsbl, thread in pairs(threads) do
for _, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
-- No server reported IP
@ -90,6 +108,7 @@ function dnsbl:access()
break
end
-- Wait for first thread
-- luacheck: ignore 421
local ok, result, server, err = ngx.thread.wait(unpack(wait_threads))
-- Error case
if not ok then
@ -115,7 +134,7 @@ function dnsbl:access()
-- Kill other threads
if #threads > 0 then
local wait_threads = {}
for dnsbl, thread in pairs(threads) do
for _, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
utils.kill_all_threads(wait_threads)
@ -159,18 +178,4 @@ function dnsbl:add_to_cache(ip, value)
return true
end
function dnsbl:is_in_dnsbl(ip, server)
local request = resolver.arpa_str(ip):gsub("%.in%-addr%.arpa", ""):gsub("%.ip6%.arpa", "") .. "." .. server
local ips, err = utils.get_ips(request, false)
if not ips then
return nil, server, err
end
for i, ip in ipairs(ips) do
if ip:find("^127%.0%.0%.") then
return true, server
end
end
return false, server
end
return dnsbl

View file

@ -1,5 +1,5 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local template = nil
if ngx.shared.datastore then
template = require "resty.template"
@ -14,52 +14,52 @@ function errors:initialize(ctx)
self.default_errors = {
["400"] = {
title = "Bad Request",
text = "The server did not understand the request."
text = "The server did not understand the request.",
},
["401"] = {
title = "Not Authorized",
text = "Valid authentication credentials needed for the target resource."
text = "Valid authentication credentials needed for the target resource.",
},
["403"] = {
title = "Forbidden",
text = "Access is forbidden to the requested page."
text = "Access is forbidden to the requested page.",
},
["404"] = {
title = "Not Found",
text = "The server cannot find the requested page."
text = "The server cannot find the requested page.",
},
["405"] = {
title = "Method Not Allowed",
text = "The method specified in the request is not allowed."
text = "The method specified in the request is not allowed.",
},
["413"] = {
title = "Request Entity Too Large",
text = "The server will not accept the request, because the request entity is too large."
text = "The server will not accept the request, because the request entity is too large.",
},
["429"] = {
title = "Too Many Requests",
text = "Too many requests sent in a given amount of time, try again later."
text = "Too many requests sent in a given amount of time, try again later.",
},
["500"] = {
title = "Internal Server Error",
text = "The request was not completed. The server met an unexpected condition."
text = "The request was not completed. The server met an unexpected condition.",
},
["501"] = {
title = "Not Implemented",
text = "The request was not completed. The server did not support the functionality required."
text = "The request was not completed. The server did not support the functionality required.",
},
["502"] = {
title = "Bad Gateway",
text = "The request was not completed. The server received an invalid response from the upstream server."
text = "The request was not completed. The server received an invalid response from the upstream server.",
},
["503"] = {
title = "Service Unavailable",
text = "The request was not completed. The server is temporarily overloading or down."
text = "The request was not completed. The server is temporarily overloading or down.",
},
["504"] = {
title = "Gateway Timeout",
text = "The gateway has timed out."
}
text = "The gateway has timed out.",
},
}
end
@ -69,7 +69,7 @@ function errors:render_template(code)
title = code .. " - " .. self.default_errors[code].title,
error_title = self.default_errors[code].title,
error_code = code,
error_text = self.default_errors[code].text
error_text = self.default_errors[code].text,
})
end

View file

@ -1,9 +1,9 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local class = require "middleclass"
local ipmatcher = require "resty.ipmatcher"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local greylist = class("greylist", plugin)
local greylist = class("greylist", plugin)
function greylist:initialize(ctx)
-- Call parent initialize
@ -22,7 +22,7 @@ function greylist:initialize(ctx)
["RDNS"] = {},
["ASN"] = {},
["USER_AGENT"] = {},
["URI"] = {}
["URI"] = {},
}
for kind, _ in pairs(kinds) do
for data in self.variables["GREYLIST_" .. kind]:gmatch("%S+") do
@ -67,7 +67,7 @@ function greylist:init()
}
local i = 0
for kind, _ in pairs(greylists) do
local f, err = io.open("/var/cache/bunkerweb/greylist/" .. kind .. ".list", "r")
local f, _ = io.open("/var/cache/bunkerweb/greylist/" .. kind .. ".list", "r")
if f then
for line in f:lines() do
table.insert(greylists[kind], line)
@ -91,7 +91,7 @@ function greylist:access()
end
-- Check the caches
local checks = {
["IP"] = "ip" .. self.ctx.bw.remote_addr
["IP"] = "ip" .. self.ctx.bw.remote_addr,
}
if self.ctx.bw.http_user_agent then
checks["UA"] = "ua" .. self.ctx.bw.http_user_agent
@ -102,7 +102,7 @@ function greylist:access()
local already_cached = {
["IP"] = false,
["URI"] = false,
["UA"] = false
["UA"] = false,
}
for k, v in pairs(checks) do
local ok, cached = self:is_in_cache(v)
@ -120,12 +120,13 @@ function greylist:access()
return self:ret(false, "lists is nil")
end
-- Perform checks
for k, v in pairs(checks) do
for k, _ in pairs(checks) do
if not already_cached[k] then
local ok, greylisted = self:is_greylisted(k)
if ok == nil then
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is greylisted : " .. greylisted)
else
-- luacheck: ignore 421
local ok, err = self:add_to_cache(self:kind_to_ele(k), greylisted)
if not ok then
self.logger:log(ngx.ERR, "error while adding element to cache : " .. err)
@ -187,12 +188,13 @@ function greylist:is_greylisted_ip()
end
if check_rdns then
-- Get rDNS
-- luacheck: ignore 421
local rdns_list, err = utils.get_rdns(self.ctx.bw.remote_addr)
-- Check if rDNS is in greylist
if rdns_list then
for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(- #suffix) == suffix then
for _, rdns in ipairs(rdns_list) do
for _, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(-#suffix) == suffix then
return true, "rDNS " .. suffix
end
end
@ -208,7 +210,7 @@ function greylist:is_greylisted_ip()
if not asn then
self.logger:log(ngx.ERR, "can't get ASN of IP " .. self.ctx.bw.remote_addr .. " : " .. err)
else
for i, bl_asn in ipairs(self.lists["ASN"]) do
for _, bl_asn in ipairs(self.lists["ASN"]) do
if bl_asn == tostring(asn) then
return true, "ASN " .. bl_asn
end
@ -222,7 +224,7 @@ end
function greylist:is_greylisted_uri()
-- Check if URI is in greylist
for i, uri in ipairs(self.lists["URI"]) do
for _, uri in ipairs(self.lists["URI"]) do
if utils.regex_match(self.ctx.bw.uri, uri) then
return true, "URI " .. uri
end
@ -233,7 +235,7 @@ end
function greylist:is_greylisted_ua()
-- Check if UA is in greylist
for i, ua in ipairs(self.lists["USER_AGENT"]) do
for _, ua in ipairs(self.lists["USER_AGENT"]) do
if utils.regex_match(self.ctx.bw.http_user_agent, ua) then
return true, "UA " .. ua
end

View file

@ -106,12 +106,15 @@ try:
logger.info(
f"Greylist for {kind} is already in cache, skipping downloads...",
)
if not urls[kind]:
logger.warning(
f"Greylist for {kind} is cached but no URL is configured, removing from cache...",
)
greylist_path.joinpath(f"{kind}.list").unlink(missing_ok=True)
deleted, err = del_file_in_db(f"{kind}.list", db)
if not deleted:
logger.warning(f"Couldn't delete {kind}.list from cache : {err}")
if all_fresh:
_exit(0)

View file

@ -1,99 +1,110 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local headers = class("headers", plugin)
function headers:initialize(ctx)
-- Call parent initialize
plugin.initialize(self, "headers", ctx)
self.all_headers = {
["STRICT_TRANSPORT_SECURITY"] = "Strict-Transport-Security",
["CONTENT_SECURITY_POLICY"] = "Content-Security-Policy",
["REFERRER_POLICY"] = "Referrer-Policy",
["PERMISSIONS_POLICY"] = "Permissions-Policy",
["FEATURE_POLICY"] = "Feature-Policy",
["X_FRAME_OPTIONS"] = "X-Frame-Options",
["X_CONTENT_TYPE_OPTIONS"] = "X-Content-Type-Options",
["X_XSS_PROTECTION"] = "X-XSS-Protection"
}
-- Load data from datastore if needed
if ngx.get_phase() ~= "init" then
-- Get custom headers from datastore
local custom_headers, err = self.datastore:get("plugin_headers_custom_headers", true)
if not custom_headers then
self.logger:log(ngx.ERR, err)
return
end
self.custom_headers = {}
-- Extract global headers
if custom_headers.global then
for k, v in pairs(custom_headers.global) do
self.custom_headers[k] = v
end
end
-- Extract and overwrite if needed server headers
if custom_headers[self.ctx.bw.server_name] then
for k, v in pairs(custom_headers[self.ctx.bw.server_name]) do
self.custom_headers[k] = v
end
end
end
-- Call parent initialize
plugin.initialize(self, "headers", ctx)
self.all_headers = {
["STRICT_TRANSPORT_SECURITY"] = "Strict-Transport-Security",
["CONTENT_SECURITY_POLICY"] = "Content-Security-Policy",
["REFERRER_POLICY"] = "Referrer-Policy",
["PERMISSIONS_POLICY"] = "Permissions-Policy",
["FEATURE_POLICY"] = "Feature-Policy",
["X_FRAME_OPTIONS"] = "X-Frame-Options",
["X_CONTENT_TYPE_OPTIONS"] = "X-Content-Type-Options",
["X_XSS_PROTECTION"] = "X-XSS-Protection",
}
-- Load data from datastore if needed
if ngx.get_phase() ~= "init" then
-- Get custom headers from datastore
local custom_headers, err = self.datastore:get("plugin_headers_custom_headers", true)
if not custom_headers then
self.logger:log(ngx.ERR, err)
return
end
self.custom_headers = {}
-- Extract global headers
if custom_headers.global then
for k, v in pairs(custom_headers.global) do
self.custom_headers[k] = v
end
end
-- Extract and overwrite if needed server headers
if custom_headers[self.ctx.bw.server_name] then
for k, v in pairs(custom_headers[self.ctx.bw.server_name]) do
self.custom_headers[k] = v
end
end
end
end
function headers:init()
-- Get variables
local variables, err = utils.get_multiple_variables({ "CUSTOM_HEADER" })
if variables == nil then
return self:ret(false, err)
end
-- Store custom headers name and value
local data = {}
local i = 0
for srv, vars in pairs(variables) do
for var, value in pairs(vars) do
if data[srv] == nil then
data[srv] = {}
end
local m = utils.regex_match(value, "([\\w-]+): ([^,]+)")
if m then
data[srv][m[1]] = m[2]
end
i = i + 1
end
end
local ok, err = self.datastore:set("plugin_headers_custom_headers", data, nil, true)
if not ok then
return self:ret(false, err)
end
return self:ret(true, "successfully loaded " .. tostring(i) .. " custom headers")
-- Get variables
local variables, err = utils.get_multiple_variables({ "CUSTOM_HEADER" })
if variables == nil then
return self:ret(false, err)
end
-- Store custom headers name and value
local data = {}
local i = 0
for srv, vars in pairs(variables) do
for _, value in pairs(vars) do
if data[srv] == nil then
data[srv] = {}
end
local m = utils.regex_match(value, "([\\w-]+): ([^,]+)")
if m then
data[srv][m[1]] = m[2]
end
i = i + 1
end
end
local ok
ok, err = self.datastore:set("plugin_headers_custom_headers", data, nil, true)
if not ok then
return self:ret(false, err)
end
return self:ret(true, "successfully loaded " .. tostring(i) .. " custom headers")
end
function headers:header()
-- Override upstream headers if needed
local ssl = self.ctx.bw.scheme == "https"
for variable, header in pairs(self.all_headers) do
if ngx.header[header] == nil or (self.variables[variable] ~= "" and self.variables["KEEP_UPSTREAM_HEADERS"] ~= "*" and utils.regex_match(self.variables["KEEP_UPSTREAM_HEADERS"], "(^| )" .. header .. "($| )") == nil) then
if (header ~= "Strict-Transport-Security" or ssl) then
if header == "Content-Security-Policy" and self.variables["CONTENT_SECURITY_POLICY_REPORT_ONLY"] == "yes" then
ngx.header["Content-Security-Policy-Report-Only"] = self.variables[variable]
else
ngx.header[header] = self.variables[variable]
end
end
end
end
-- Add custom headers
for header, value in pairs(self.custom_headers) do
ngx.header[header] = value
end
-- Remove headers
if self.variables["REMOVE_HEADERS"] ~= "" then
for header in self.variables["REMOVE_HEADERS"]:gmatch("%S+") do
ngx.header[header] = nil
end
end
return self:ret(true, "edited headers for request")
-- Override upstream headers if needed
local ssl = self.ctx.bw.scheme == "https"
for variable, header in pairs(self.all_headers) do
if
ngx.header[header] == nil
or (
self.variables[variable] ~= ""
and self.variables["KEEP_UPSTREAM_HEADERS"] ~= "*"
and utils.regex_match(self.variables["KEEP_UPSTREAM_HEADERS"], "(^| )" .. header .. "($| )") == nil
)
then
if header ~= "Strict-Transport-Security" or ssl then
if
header == "Content-Security-Policy"
and self.variables["CONTENT_SECURITY_POLICY_REPORT_ONLY"] == "yes"
then
ngx.header["Content-Security-Policy-Report-Only"] = self.variables[variable]
else
ngx.header[header] = self.variables[variable]
end
end
end
end
-- Add custom headers
for header, value in pairs(self.custom_headers) do
ngx.header[header] = value
end
-- Remove headers
if self.variables["REMOVE_HEADERS"] ~= "" then
for header in self.variables["REMOVE_HEADERS"]:gmatch("%S+") do
ngx.header[header] = nil
end
end
return self:ret(true, "edited headers for request")
end
return headers

View file

@ -1,6 +1,6 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local cjson = require "cjson"
local cjson = require "cjson"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local letsencrypt = class("letsencrypt", plugin)
@ -17,9 +17,12 @@ function letsencrypt:access()
return self:ret(true, "success")
end
-- luacheck: ignore 212
function letsencrypt:api(ctx)
if not string.match(ctx.bw.uri, "^/lets%-encrypt/challenge$") or
(ctx.bw.request_method ~= "POST" and ctx.bw.request_method ~= "DELETE") then
if
not string.match(ctx.bw.uri, "^/lets%-encrypt/challenge$")
or (ctx.bw.request_method ~= "POST" and ctx.bw.request_method ~= "DELETE")
then
return false, nil, nil
end
local acme_folder = "/var/tmp/bunkerweb/lets-encrypt/.well-known/acme-challenge/"
@ -32,7 +35,9 @@ function letsencrypt:api(ctx)
if ctx.bw.request_method == "POST" then
local file, err = io.open(acme_folder .. data.token, "w+")
if not file then
return true, ngx.HTTP_INTERNAL_SERVER_ERROR, { status = "error", msg = "can't write validation token : " .. err }
return true,
ngx.HTTP_INTERNAL_SERVER_ERROR,
{ status = "error", msg = "can't write validation token : " .. err }
end
file:write(data.validation)
file:close()
@ -40,7 +45,9 @@ function letsencrypt:api(ctx)
elseif ctx.bw.request_method == "DELETE" then
local ok, err = os.remove(acme_folder .. data.token)
if not ok then
return true, ngx.HTTP_INTERNAL_SERVER_ERROR, { status = "error", msg = "can't remove validation token : " .. err }
return true,
ngx.HTTP_INTERNAL_SERVER_ERROR,
{ status = "error", msg = "can't remove validation token : " .. err }
end
return true, ngx.HTTP_OK, { status = "success", msg = "validation token removed" }
end

View file

@ -1,9 +1,40 @@
local class = require "middleclass"
local cjson = require "cjson"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local cjson = require "cjson"
local utils = require "bunkerweb.utils"
local limit = class("limit", plugin)
local limit = class("limit", plugin)
local limit_req_timestamps = function(rate_max, rate_time, timestamps)
-- Compute new timestamps
local updated = false
local new_timestamps = {}
local current_timestamp = os.time(os.date "!*t")
local delay = 0
if rate_time == "s" then
delay = 1
elseif rate_time == "m" then
delay = 60
elseif rate_time == "h" then
delay = 3600
elseif rate_time == "d" then
delay = 86400
end
-- Keep only timestamp within the delay
for _, timestamp in ipairs(timestamps) do
if current_timestamp - timestamp <= delay then
table.insert(new_timestamps, timestamp)
else
updated = true
end
end
-- Only insert the new timestamp if client is not limited already to avoid infinite insert
if #new_timestamps <= rate_max then
table.insert(new_timestamps, current_timestamp)
updated = true
end
return updated, new_timestamps, delay
end
function limit:initialize(ctx)
-- Call parent initialize
@ -11,7 +42,6 @@ function limit:initialize(ctx)
-- Load rules if needed
if ngx.get_phase() ~= "init" and self:is_needed() then
-- Get all rules from datastore
local limited = false
local all_rules, err = self.datastore:get("plugin_limit_rules", true)
if not all_rules then
self.logger:log(ngx.ERR, err)
@ -93,19 +123,16 @@ function limit:access()
return self:ret(true, "limit request not enabled")
end
-- Check if URI is limited
local rate = nil
local uri = nil
local rate
for k, v in pairs(self.rules) do
if k ~= "/" and utils.regex_match(self.ctx.bw.uri, k) then
rate = v
uri = k
break
end
end
if not rate then
if self.rules["/"] then
rate = self.rules["/"]
uri = "/"
else
return self:ret(true, "no rule for " .. self.ctx.bw.uri)
end
@ -118,19 +145,37 @@ function limit:access()
end
-- Limit reached
if limited then
return self:ret(true,
"client IP " ..
self.ctx.bw.remote_addr ..
" is limited for URL " ..
self.ctx.bw.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")",
ngx.HTTP_TOO_MANY_REQUESTS)
return self:ret(
true,
"client IP "
.. self.ctx.bw.remote_addr
.. " is limited for URL "
.. self.ctx.bw.uri
.. " (current rate = "
.. current_rate
.. "r/"
.. rate_time
.. " and max rate = "
.. rate
.. ")",
ngx.HTTP_TOO_MANY_REQUESTS
)
end
-- Limit not reached
return self:ret(true,
"client IP " ..
self.ctx.bw.remote_addr ..
" is not limited for URL " ..
self.ctx.bw.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")")
return self:ret(
true,
"client IP "
.. self.ctx.bw.remote_addr
.. " is not limited for URL "
.. self.ctx.bw.uri
.. " (current rate = "
.. current_rate
.. "r/"
.. rate_time
.. " and max rate = "
.. rate
.. ")"
)
end
function limit:limit_req(rate_max, rate_time)
@ -143,9 +188,12 @@ function limit:limit_req(rate_max, rate_time)
else
timestamps = redis_timestamps
-- Save the new timestamps
-- luacheck: ignore 421
local ok, err = self.datastore:set(
"plugin_limit_" .. self.ctx.bw.server_name .. self.ctx.bw.remote_addr .. self.ctx.bw.uri,
cjson.encode(timestamps), delay)
cjson.encode(timestamps),
delay
)
if not ok then
return nil, "can't update timestamps : " .. err
end
@ -167,8 +215,8 @@ end
function limit:limit_req_local(rate_max, rate_time)
-- Get timestamps
local timestamps, err = self.datastore:get("plugin_limit_" ..
self.ctx.bw.server_name .. self.ctx.bw.remote_addr .. self.ctx.bw.uri)
local timestamps, err =
self.datastore:get("plugin_limit_" .. self.ctx.bw.server_name .. self.ctx.bw.remote_addr .. self.ctx.bw.uri)
if not timestamps and err ~= "not found" then
return nil, err
elseif err == "not found" then
@ -176,12 +224,15 @@ function limit:limit_req_local(rate_max, rate_time)
end
timestamps = cjson.decode(timestamps)
-- Compute new timestamps
local updated, new_timestamps, delay = self:limit_req_timestamps(rate_max, rate_time, timestamps)
local updated, new_timestamps, delay = limit_req_timestamps(rate_max, rate_time, timestamps)
-- Save new timestamps if needed
if updated then
-- luacheck: ignore 421
local ok, err = self.datastore:set(
"plugin_limit_" .. self.ctx.bw.server_name .. self.ctx.bw.remote_addr .. self.ctx.bw.uri,
cjson.encode(new_timestamps), delay)
cjson.encode(new_timestamps),
delay
)
if not ok then
return nil, err
end
@ -245,9 +296,15 @@ function limit:limit_req_redis(rate_max, rate_time)
return nil, err
end
-- Execute script
local timestamps, err = self.clusterstore:call("eval", redis_script, 1,
"plugin_limit_" .. self.ctx.bw.server_name .. self.ctx.bw.remote_addr .. self.ctx.bw.uri, rate_max, rate_time,
os.time(os.date("!*t")))
local timestamps, err = self.clusterstore:call(
"eval",
redis_script,
1,
"plugin_limit_" .. self.ctx.bw.server_name .. self.ctx.bw.remote_addr .. self.ctx.bw.uri,
rate_max,
rate_time,
os.time(os.date("!*t"))
)
if not timestamps then
self.clusterstore:close()
return nil, err
@ -257,35 +314,4 @@ function limit:limit_req_redis(rate_max, rate_time)
return timestamps, "success"
end
function limit:limit_req_timestamps(rate_max, rate_time, timestamps)
-- Compute new timestamps
local updated = false
local new_timestamps = {}
local current_timestamp = os.time(os.date("!*t"))
local delay = 0
if rate_time == "s" then
delay = 1
elseif rate_time == "m" then
delay = 60
elseif rate_time == "h" then
delay = 3600
elseif rate_time == "d" then
delay = 86400
end
-- Keep only timestamp within the delay
for i, timestamp in ipairs(timestamps) do
if current_timestamp - timestamp <= delay then
table.insert(new_timestamps, timestamp)
else
updated = true
end
end
-- Only insert the new timestamp if client is not limited already to avoid infinite insert
if #new_timestamps <= rate_max then
table.insert(new_timestamps, current_timestamp)
updated = true
end
return updated, new_timestamps, delay
end
return limit

View file

@ -1,27 +1,27 @@
local class = require "middleclass"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local utils = require "bunkerweb.utils"
local misc = class("misc", plugin)
local misc = class("misc", plugin)
function misc:initialize(ctx)
-- Call parent initialize
plugin.initialize(self, "misc", ctx)
-- Call parent initialize
plugin.initialize(self, "misc", ctx)
end
function misc:access()
-- Check if method is valid
local method = self.ctx.bw.request_method
if not method or not utils.regex_match(method, "^[A-Z]+$") then
return self:ret(true, "method is not valid", ngx.HTTP_BAD_REQUEST)
end
-- Check if method is allowed
for allowed_method in self.variables["ALLOWED_METHODS"]:gmatch("[^|]+") do
if method == allowed_method then
return self:ret(true, "method " .. method .. " is allowed")
end
end
return self:ret(true, "method " .. method .. " is not allowed", ngx.HTTP_NOT_ALLOWED)
-- Check if method is valid
local method = self.ctx.bw.request_method
if not method or not utils.regex_match(method, "^[A-Z]+$") then
return self:ret(true, "method is not valid", ngx.HTTP_BAD_REQUEST)
end
-- Check if method is allowed
for allowed_method in self.variables["ALLOWED_METHODS"]:gmatch("[^|]+") do
if method == allowed_method then
return self:ret(true, "method " .. method .. " is allowed")
end
end
return self:ret(true, "method " .. method .. " is not allowed", ngx.HTTP_NOT_ALLOWED)
end
return misc

View file

@ -77,12 +77,13 @@ try:
# Don't go further if the cache is fresh
if is_cached_file(realip_path.joinpath("combined.list"), "hour", db):
logger.info("RealIP list is already in cache, skipping download...")
if not urls:
logger.warning("No URL found, deleting combined.list from cache...")
tmp_realip_path.joinpath("combined.list").unlink(missing_ok=True)
deleted, err = del_file_in_db("combined.list", db)
if not deleted:
logger.warning(f"Couldn't delete combined.list from cache : {err}")
logger.info("RealIP list is already in cache, skipping download...")
_exit(0)
# Download and write data to temp file

View file

@ -1,9 +1,9 @@
local class = require "middleclass"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local redis = class("redis", plugin)
local redis = class("redis", plugin)
function redis:initialize()
function redis:initialize(ctx)
-- Call parent initialize
plugin.initialize(self, "redis", ctx)
end

View file

@ -1,153 +1,155 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local cachestore = require "bunkerweb.cachestore"
local cjson = require "cjson"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local reversescan = class("reversescan", plugin)
function reversescan:initialize(ctx)
-- Call parent initialize
plugin.initialize(self, "reversescan", ctx)
-- Call parent initialize
plugin.initialize(self, "reversescan", ctx)
end
function reversescan:access()
-- Check if access is needed
if self.variables["USE_REVERSE_SCAN"] ~= "yes" then
return self:ret(true, "reverse scan not activated")
end
-- Loop on ports
local threads = {}
local ret_threads = nil
local ret_err = nil
for port in self.variables["REVERSE_SCAN_PORTS"]:gmatch("%S+") do
-- Check if the scan is already cached
local ok, cached = self:is_in_cache(self.ctx.bw.remote_addr .. ":" .. port)
if not ok then
ret_threads = false
ret_err = "error getting info from cachestore : " .. cached
break
-- Deny access if port opened
elseif cached == "open" then
ret_threads = true
ret_err = "port " .. port .. " is opened for IP " .. self.ctx.bw.remote_addr
break
-- Perform scan in a thread
elseif not cached then
local thread = ngx.thread.spawn(self.scan, self.ctx.bw.remote_addr, tonumber(port),
tonumber(self.variables["REVERSE_SCAN_TIMEOUT"]))
threads[port] = thread
end
end
if ret_threads ~= nil then
if #threads > 0 then
local wait_threads = {}
for port, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
utils.kill_all_threads(wait_threads)
end
-- Open port case
if ret_threads then
return self:ret(true, ret_err, utils.get_deny_status(self.ctx))
end
-- Error case
return self:ret(false, ret_err)
end
-- Check results of threads
ret_threads = nil
ret_err = nil
local results = {}
while true do
-- Compute threads to wait
local wait_threads = {}
for port, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
-- No port opened
if #wait_threads == 0 then
break
end
-- Wait for first thread
local ok, open, port = ngx.thread.wait(unpack(wait_threads))
-- Error case
if not ok then
ret_threads = false
ret_err = "error while waiting thread : " .. open
break
end
port = tostring(port)
-- Remove thread from list
threads[port] = nil
-- Add result to cache
local result = "close"
if open then
result = "open"
end
results[port] = result
-- Port is opened
if open then
ret_threads = true
ret_err = "port " .. port .. " is opened for IP " .. self.ctx.bw.remote_addr
break
end
end
-- Kill running threads
if #threads > 0 then
local wait_threads = {}
for port, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
utils.kill_all_threads(wait_threads)
end
-- Cache results
for port, result in pairs(results) do
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr .. ":" .. port, result)
if not ok then
return self:ret(false, "error while adding element to cache : " .. err)
end
end
if ret_threads ~= nil then
-- Open port case
if ret_threads then
return self:ret(true, ret_err, utils.get_deny_status(self.ctx))
end
-- Error case
return self:ret(false, ret_err)
end
-- No port opened
return self:ret(true, "no port open for IP " .. self.ctx.bw.remote_addr)
-- Check if access is needed
if self.variables["USE_REVERSE_SCAN"] ~= "yes" then
return self:ret(true, "reverse scan not activated")
end
-- Loop on ports
local threads = {}
local ret_threads = nil
local ret_err = nil
for port in self.variables["REVERSE_SCAN_PORTS"]:gmatch("%S+") do
-- Check if the scan is already cached
local ok, cached = self:is_in_cache(self.ctx.bw.remote_addr .. ":" .. port)
if not ok then
ret_threads = false
ret_err = "error getting info from cachestore : " .. cached
break
-- Deny access if port opened
elseif cached == "open" then
ret_threads = true
ret_err = "port " .. port .. " is opened for IP " .. self.ctx.bw.remote_addr
break
-- Perform scan in a thread
elseif not cached then
local thread = ngx.thread.spawn(
self.scan,
self.ctx.bw.remote_addr,
tonumber(port),
tonumber(self.variables["REVERSE_SCAN_TIMEOUT"])
)
threads[port] = thread
end
end
if ret_threads ~= nil then
if #threads > 0 then
local wait_threads = {}
for _, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
utils.kill_all_threads(wait_threads)
end
-- Open port case
if ret_threads then
return self:ret(true, ret_err, utils.get_deny_status(self.ctx))
end
-- Error case
return self:ret(false, ret_err)
end
-- Check results of threads
ret_threads = nil
ret_err = nil
local results = {}
while true do
-- Compute threads to wait
local wait_threads = {}
for _, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
-- No port opened
if #wait_threads == 0 then
break
end
-- Wait for first thread
local ok, open, port = ngx.thread.wait(unpack(wait_threads))
-- Error case
if not ok then
ret_threads = false
ret_err = "error while waiting thread : " .. open
break
end
port = tostring(port)
-- Remove thread from list
threads[port] = nil
-- Add result to cache
local result = "close"
if open then
result = "open"
end
results[port] = result
-- Port is opened
if open then
ret_threads = true
ret_err = "port " .. port .. " is opened for IP " .. self.ctx.bw.remote_addr
break
end
end
-- Kill running threads
if #threads > 0 then
local wait_threads = {}
for _, thread in pairs(threads) do
table.insert(wait_threads, thread)
end
utils.kill_all_threads(wait_threads)
end
-- Cache results
for port, result in pairs(results) do
local ok, err = self:add_to_cache(self.ctx.bw.remote_addr .. ":" .. port, result)
if not ok then
return self:ret(false, "error while adding element to cache : " .. err)
end
end
if ret_threads ~= nil then
-- Open port case
if ret_threads then
return self:ret(true, ret_err, utils.get_deny_status(self.ctx))
end
-- Error case
return self:ret(false, ret_err)
end
-- No port opened
return self:ret(true, "no port open for IP " .. self.ctx.bw.remote_addr)
end
function reversescan:preread()
return self:access()
return self:access()
end
function reversescan.scan(ip, port, timeout)
local tcpsock = ngx.socket.tcp()
tcpsock:settimeout(timeout)
local ok, err = tcpsock:connect(ip, port)
tcpsock:close()
if not ok then
return false, port
end
return true, port
local tcpsock = ngx.socket.tcp()
tcpsock:settimeout(timeout)
local ok, _ = tcpsock:connect(ip, port)
tcpsock:close()
if not ok then
return false, port
end
return true, port
end
function reversescan:is_in_cache(ip_port)
local ok, data = self.cachestore:get("plugin_reverse_scan_" .. ip_port)
if not ok then
return false, data
end
return true, data
local ok, data = self.cachestore:get("plugin_reverse_scan_" .. ip_port)
if not ok then
return false, data
end
return true, data
end
function reversescan:add_to_cache(ip_port, value)
local ok, err = self.cachestore:set("plugin_reverse_scan_" .. ip_port, value, 86400)
if not ok then
return false, err
end
return true
local ok, err = self.cachestore:set("plugin_reverse_scan_" .. ip_port, value, 86400)
if not ok then
return false, err
end
return true
end
return reversescan

View file

@ -1,118 +1,118 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local session = require "resty.session"
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local session = require "resty.session"
local utils = require "bunkerweb.utils"
local sessions = class("sessions", plugin)
function sessions:initialize(ctx)
-- Call parent initialize
plugin.initialize(self, "sessions", ctx)
-- Check if random cookie name and secrets are already generated
local is_random = {
"SESSIONS_SECRET",
"SESSIONS_NAME"
}
self.randoms = {}
for i, var in ipairs(is_random) do
if self.variables[var] == "random" then
local data, err = self.datastore:get("storage_sessions_" .. var)
if data then
self.randoms[var] = data
end
end
end
-- Call parent initialize
plugin.initialize(self, "sessions", ctx)
-- Check if random cookie name and secrets are already generated
local is_random = {
"SESSIONS_SECRET",
"SESSIONS_NAME",
}
self.randoms = {}
for _, var in ipairs(is_random) do
if self.variables[var] == "random" then
local data, _ = self.datastore:get("storage_sessions_" .. var)
if data then
self.randoms[var] = data
end
end
end
end
function sessions:set()
if self.is_loading or self.kind ~= "http" then
return self:ret(true, "set not needed")
end
local checks = {
["IP"] = self.ctx.bw.remote_addr,
["USER_AGENT"] = self.ctx.bw.http_user_agent or ""
}
self.ctx.bw.sessions_checks = {}
for check, value in pairs(checks) do
if self.variables["SESSIONS_CHECK_" .. check] == "yes" then
table.insert(self.ctx.bw.sessions_checks, { check, value })
end
end
return self:ret(true, "success")
if self.is_loading or self.kind ~= "http" then
return self:ret(true, "set not needed")
end
local checks = {
["IP"] = self.ctx.bw.remote_addr,
["USER_AGENT"] = self.ctx.bw.http_user_agent or "",
}
self.ctx.bw.sessions_checks = {}
for check, value in pairs(checks) do
if self.variables["SESSIONS_CHECK_" .. check] == "yes" then
table.insert(self.ctx.bw.sessions_checks, { check, value })
end
end
return self:ret(true, "success")
end
function sessions:init()
if self.is_loading or self.kind ~= "http" then
return self:ret(true, "init not needed")
end
-- Get redis vars
local redis_vars = {
["USE_REDIS"] = "",
["REDIS_HOST"] = "",
["REDIS_PORT"] = "",
["REDIS_DATABASE"] = "",
["REDIS_SSL"] = "",
["REDIS_TIMEOUT"] = "",
["REDIS_KEEPALIVE_IDLE"] = "",
["REDIS_KEEPALIVE_POOL"] = ""
}
for k, v in pairs(redis_vars) do
local value, err = utils.get_variable(k, false)
if value == nil then
return self:ret(false, "can't get " .. k .. " variable : " .. err)
end
redis_vars[k] = value
end
-- Init configuration
local config = {
secret = self.variables["SESSIONS_SECRET"],
cookie_name = self.variables["SESSIONS_NAME"],
idling_timeout = tonumber(self.variables["SESSIONS_IDLING_TIMEOUT"]),
rolling_timeout = tonumber(self.variables["SESSIONS_ROLLING_TIMEOUT"]),
absolute_timeout = tonumber(self.variables["SESSIONS_ABSOLUTE_TIMEOUT"])
}
if self.variables["SESSIONS_SECRET"] == "random" then
if self.randoms["SESSIONS_SECRET"] then
config.secret = self.randoms["SESSIONS_SECRET"]
else
config.secret = utils.rand(16)
local ok, err = self.datastore:set("storage_sessions_SESSIONS_SECRET", config.secret)
if not ok then
self.logger:log(ngx.ERR, "error from datastore:set : " .. err)
end
end
end
if self.variables["SESSIONS_NAME"] == "random" then
if self.randoms["SESSIONS_NAME"] then
config.cookie_name = self.randoms["SESSIONS_NAME"]
else
config.cookie_name = utils.rand(16)
local ok, err = self.datastore:set("storage_sessions_SESSIONS_NAME", config.cookie_name)
if not ok then
self.logger:log(ngx.ERR, "error from datastore:set : " .. err)
end
end
end
if redis_vars["USE_REDIS"] ~= "yes" then
config.storage = "cookie"
else
config.storage = "redis"
config.redis = {
prefix = "sessions_",
connect_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
send_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
read_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
keepalive_timeout = tonumber(redis_vars["REDIS_KEEPALIVE_IDLE"]),
pool = "bw-redis",
pool_size = tonumber(redis_vars["REDIS_KEEPALIVE_POOL"]),
ssl = redis_vars["REDIS_SSL"] == "yes",
host = redis_vars["REDIS_HOST"],
port = tonumber(redis_vars["REDIS_PORT"]),
database = tonumber(redis_vars["REDIS_DATABASE"])
}
end
session.init(config)
return self:ret(true, "sessions init successful")
if self.is_loading or self.kind ~= "http" then
return self:ret(true, "init not needed")
end
-- Get redis vars
local redis_vars = {
["USE_REDIS"] = "",
["REDIS_HOST"] = "",
["REDIS_PORT"] = "",
["REDIS_DATABASE"] = "",
["REDIS_SSL"] = "",
["REDIS_TIMEOUT"] = "",
["REDIS_KEEPALIVE_IDLE"] = "",
["REDIS_KEEPALIVE_POOL"] = "",
}
for k, _ in pairs(redis_vars) do
local value, err = utils.get_variable(k, false)
if value == nil then
return self:ret(false, "can't get " .. k .. " variable : " .. err)
end
redis_vars[k] = value
end
-- Init configuration
local config = {
secret = self.variables["SESSIONS_SECRET"],
cookie_name = self.variables["SESSIONS_NAME"],
idling_timeout = tonumber(self.variables["SESSIONS_IDLING_TIMEOUT"]),
rolling_timeout = tonumber(self.variables["SESSIONS_ROLLING_TIMEOUT"]),
absolute_timeout = tonumber(self.variables["SESSIONS_ABSOLUTE_TIMEOUT"]),
}
if self.variables["SESSIONS_SECRET"] == "random" then
if self.randoms["SESSIONS_SECRET"] then
config.secret = self.randoms["SESSIONS_SECRET"]
else
config.secret = utils.rand(16)
local ok, err = self.datastore:set("storage_sessions_SESSIONS_SECRET", config.secret)
if not ok then
self.logger:log(ngx.ERR, "error from datastore:set : " .. err)
end
end
end
if self.variables["SESSIONS_NAME"] == "random" then
if self.randoms["SESSIONS_NAME"] then
config.cookie_name = self.randoms["SESSIONS_NAME"]
else
config.cookie_name = utils.rand(16)
local ok, err = self.datastore:set("storage_sessions_SESSIONS_NAME", config.cookie_name)
if not ok then
self.logger:log(ngx.ERR, "error from datastore:set : " .. err)
end
end
end
if redis_vars["USE_REDIS"] ~= "yes" then
config.storage = "cookie"
else
config.storage = "redis"
config.redis = {
prefix = "sessions_",
connect_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
send_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
read_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
keepalive_timeout = tonumber(redis_vars["REDIS_KEEPALIVE_IDLE"]),
pool = "bw-redis",
pool_size = tonumber(redis_vars["REDIS_KEEPALIVE_POOL"]),
ssl = redis_vars["REDIS_SSL"] == "yes",
host = redis_vars["REDIS_HOST"],
port = tonumber(redis_vars["REDIS_PORT"]),
database = tonumber(redis_vars["REDIS_DATABASE"]),
}
end
session.init(config)
return self:ret(true, "sessions init successful")
end
return sessions

View file

@ -106,8 +106,10 @@ try:
logger.info(
f"Whitelist for {kind} is already in cache, skipping downloads...",
)
if not urls[kind]:
logger.info(
f"Whitelist for {kind} is already in cache, skipping downloads...",
)
whitelist_path.joinpath(f"{kind}.list").unlink(missing_ok=True)
deleted, err = del_file_in_db(f"{kind}.list", db)
if not deleted:

View file

@ -1,8 +1,8 @@
local class = require "middleclass"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local class = require "middleclass"
local env = require "resty.env"
local ipmatcher = require "resty.ipmatcher"
local env = require "resty.env"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local whitelist = class("whitelist", plugin)
@ -23,7 +23,7 @@ function whitelist:initialize(ctx)
["RDNS"] = {},
["ASN"] = {},
["USER_AGENT"] = {},
["URI"] = {}
["URI"] = {},
}
for kind, _ in pairs(kinds) do
for data in self.variables["WHITELIST_" .. kind]:gmatch("%S+") do
@ -64,11 +64,11 @@ function whitelist:init()
["RDNS"] = {},
["ASN"] = {},
["USER_AGENT"] = {},
["URI"] = {}
["URI"] = {},
}
local i = 0
for kind, _ in pairs(whitelists) do
local f, err = io.open("/var/cache/bunkerweb/whitelist/" .. kind .. ".list", "r")
local f, _ = io.open("/var/cache/bunkerweb/whitelist/" .. kind .. ".list", "r")
if f then
for line in f:lines() do
table.insert(whitelists[kind], line)
@ -123,13 +123,14 @@ function whitelist:access()
return self:ret(true, err, ngx.OK)
end
-- Perform checks
for k, v in pairs(already_cached) do
local ok
for k, _ in pairs(already_cached) do
if not already_cached[k] then
local ok, whitelisted = self:is_whitelisted(k)
ok, whitelisted = self:is_whitelisted(k)
if ok == nil then
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is whitelisted : " .. whitelisted)
else
local ok, err = self:add_to_cache(self:kind_to_ele(k), whitelisted)
ok, err = self:add_to_cache(self:kind_to_ele(k), whitelisted)
if not ok then
self.logger:log(ngx.ERR, "error while adding element to cache : " .. err)
end
@ -163,7 +164,7 @@ end
function whitelist:check_cache()
-- Check the caches
local checks = {
["IP"] = "ip" .. self.ctx.bw.remote_addr
["IP"] = "ip" .. self.ctx.bw.remote_addr,
}
if self.ctx.bw.http_user_agent then
checks["UA"] = "ua" .. self.ctx.bw.http_user_agent
@ -172,7 +173,7 @@ function whitelist:check_cache()
checks["URI"] = "uri" .. self.ctx.bw.uri
end
local already_cached = {}
for k, v in pairs(checks) do
for k, _ in pairs(checks) do
already_cached[k] = false
end
for k, v in pairs(checks) do
@ -242,14 +243,15 @@ function whitelist:is_whitelisted_ip()
end
if check_rdns then
-- Get rDNS
-- luacheck: ignore 421
local rdns_list, err = utils.get_rdns(self.ctx.bw.remote_addr)
-- Check if rDNS is in whitelist
if rdns_list then
local forward_check = nil
local rdns_suffix = nil
for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(- #suffix) == suffix then
for _, rdns in ipairs(rdns_list) do
for _, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(-#suffix) == suffix then
forward_check = rdns
rdns_suffix = suffix
break
@ -262,12 +264,15 @@ function whitelist:is_whitelisted_ip()
if forward_check then
local ip_list, err = utils.get_ips(forward_check)
if ip_list then
for i, ip in ipairs(ip_list) do
for _, ip in ipairs(ip_list) do
if ip == self.ctx.bw.remote_addr then
return true, "rDNS " .. rdns_suffix
end
end
self.logger:log(ngx.WARN, "IP " .. self.ctx.bw.remote_addr .. " may spoof reverse DNS " .. forward_check)
self.logger:log(
ngx.WARN,
"IP " .. self.ctx.bw.remote_addr .. " may spoof reverse DNS " .. forward_check
)
else
self.logger:log(ngx.ERR, "error while getting rdns (forward check) : " .. err)
end
@ -283,7 +288,7 @@ function whitelist:is_whitelisted_ip()
if not asn then
self.logger:log(ngx.ERR, "can't get ASN of IP " .. self.ctx.bw.remote_addr .. " : " .. err)
else
for i, bl_asn in ipairs(self.lists["ASN"]) do
for _, bl_asn in ipairs(self.lists["ASN"]) do
if bl_asn == tostring(asn) then
return true, "ASN " .. bl_asn
end
@ -297,7 +302,7 @@ end
function whitelist:is_whitelisted_uri()
-- Check if URI is in whitelist
for i, uri in ipairs(self.lists["URI"]) do
for _, uri in ipairs(self.lists["URI"]) do
if utils.regex_match(self.ctx.bw.uri, uri) then
return true, "URI " .. uri
end
@ -308,7 +313,7 @@ end
function whitelist:is_whitelisted_ua()
-- Check if UA is in whitelist
for i, ua in ipairs(self.lists["USER_AGENT"]) do
for _, ua in ipairs(self.lists["USER_AGENT"]) do
if utils.regex_match(self.ctx.bw.http_user_agent, ua) then
return true, "UA " .. ua
end

View file

@ -1,4 +1,4 @@
cryptography==41.0.4
psycopg2-binary==2.9.9
PyMySQL==1.1.0
sqlalchemy==2.0.21
sqlalchemy==2.0.22

View file

@ -226,56 +226,56 @@ pymysql==1.1.0 \
--hash=sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96 \
--hash=sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7
# via -r requirements.in
sqlalchemy==2.0.21 \
--hash=sha256:014794b60d2021cc8ae0f91d4d0331fe92691ae5467a00841f7130fe877b678e \
--hash=sha256:0268256a34806e5d1c8f7ee93277d7ea8cc8ae391f487213139018b6805aeaf6 \
--hash=sha256:05b971ab1ac2994a14c56b35eaaa91f86ba080e9ad481b20d99d77f381bb6258 \
--hash=sha256:141675dae56522126986fa4ca713739d00ed3a6f08f3c2eb92c39c6dfec463ce \
--hash=sha256:1e7dc99b23e33c71d720c4ae37ebb095bebebbd31a24b7d99dfc4753d2803ede \
--hash=sha256:2a1f7ffac934bc0ea717fa1596f938483fb8c402233f9b26679b4f7b38d6ab6e \
--hash=sha256:2e617727fe4091cedb3e4409b39368f424934c7faa78171749f704b49b4bb4ce \
--hash=sha256:3cf229704074bce31f7f47d12883afee3b0a02bb233a0ba45ddbfe542939cca4 \
--hash=sha256:3eb7c03fe1cd3255811cd4e74db1ab8dca22074d50cd8937edf4ef62d758cdf4 \
--hash=sha256:3f7d57a7e140efe69ce2d7b057c3f9a595f98d0bbdfc23fd055efdfbaa46e3a5 \
--hash=sha256:419b1276b55925b5ac9b4c7044e999f1787c69761a3c9756dec6e5c225ceca01 \
--hash=sha256:44ac5c89b6896f4740e7091f4a0ff2e62881da80c239dd9408f84f75a293dae9 \
--hash=sha256:4615623a490e46be85fbaa6335f35cf80e61df0783240afe7d4f544778c315a9 \
--hash=sha256:50a69067af86ec7f11a8e50ba85544657b1477aabf64fa447fd3736b5a0a4f67 \
--hash=sha256:513fd5b6513d37e985eb5b7ed89da5fd9e72354e3523980ef00d439bc549c9e9 \
--hash=sha256:526b869a0f4f000d8d8ee3409d0becca30ae73f494cbb48801da0129601f72c6 \
--hash=sha256:56628ca27aa17b5890391ded4e385bf0480209726f198799b7e980c6bd473bd7 \
--hash=sha256:632784f7a6f12cfa0e84bf2a5003b07660addccf5563c132cd23b7cc1d7371a9 \
--hash=sha256:6ff3dc2f60dbf82c9e599c2915db1526d65415be323464f84de8db3e361ba5b9 \
--hash=sha256:73c079e21d10ff2be54a4699f55865d4b275fd6c8bd5d90c5b1ef78ae0197301 \
--hash=sha256:7614f1eab4336df7dd6bee05bc974f2b02c38d3d0c78060c5faa4cd1ca2af3b8 \
--hash=sha256:785e2f2c1cb50d0a44e2cdeea5fd36b5bf2d79c481c10f3a88a8be4cfa2c4615 \
--hash=sha256:7ca38746eac23dd7c20bec9278d2058c7ad662b2f1576e4c3dbfcd7c00cc48fa \
--hash=sha256:7f0c4ee579acfe6c994637527c386d1c22eb60bc1c1d36d940d8477e482095d4 \
--hash=sha256:87bf91ebf15258c4701d71dcdd9c4ba39521fb6a37379ea68088ce8cd869b446 \
--hash=sha256:89e274604abb1a7fd5c14867a412c9d49c08ccf6ce3e1e04fffc068b5b6499d4 \
--hash=sha256:8c323813963b2503e54d0944813cd479c10c636e3ee223bcbd7bd478bf53c178 \
--hash=sha256:a95aa0672e3065d43c8aa80080cdd5cc40fe92dc873749e6c1cf23914c4b83af \
--hash=sha256:af520a730d523eab77d754f5cf44cc7dd7ad2d54907adeb3233177eeb22f271b \
--hash=sha256:b19ae41ef26c01a987e49e37c77b9ad060c59f94d3b3efdfdbf4f3daaca7b5fe \
--hash=sha256:b4eae01faee9f2b17f08885e3f047153ae0416648f8e8c8bd9bc677c5ce64be9 \
--hash=sha256:b69f1f754d92eb1cc6b50938359dead36b96a1dcf11a8670bff65fd9b21a4b09 \
--hash=sha256:b977bfce15afa53d9cf6a632482d7968477625f030d86a109f7bdfe8ce3c064a \
--hash=sha256:bf8eebccc66829010f06fbd2b80095d7872991bfe8415098b9fe47deaaa58063 \
--hash=sha256:bfece2f7cec502ec5f759bbc09ce711445372deeac3628f6fa1c16b7fb45b682 \
--hash=sha256:c111cd40910ffcb615b33605fc8f8e22146aeb7933d06569ac90f219818345ef \
--hash=sha256:c2d494b6a2a2d05fb99f01b84cc9af9f5f93bf3e1e5dbdafe4bed0c2823584c1 \
--hash=sha256:c9cba4e7369de663611ce7460a34be48e999e0bbb1feb9130070f0685e9a6b66 \
--hash=sha256:cca720d05389ab1a5877ff05af96551e58ba65e8dc65582d849ac83ddde3e231 \
--hash=sha256:ccb99c3138c9bde118b51a289d90096a3791658da9aea1754667302ed6564f6e \
--hash=sha256:d59cb9e20d79686aa473e0302e4a82882d7118744d30bb1dfb62d3c47141b3ec \
--hash=sha256:db726be58837fe5ac39859e0fa40baafe54c6d54c02aba1d47d25536170b690f \
--hash=sha256:e36339a68126ffb708dc6d1948161cea2a9e85d7d7b0c54f6999853d70d44430 \
--hash=sha256:e7421c1bfdbb7214313919472307be650bd45c4dc2fcb317d64d078993de045b \
--hash=sha256:ea7da25ee458d8f404b93eb073116156fd7d8c2a776d8311534851f28277b4ce \
--hash=sha256:f6f7276cf26145a888f2182a98f204541b519d9ea358a65d82095d9c9e22f917 \
--hash=sha256:f9fefd6298433b6e9188252f3bff53b9ff0443c8fde27298b8a2b19f6617eeb9 \
--hash=sha256:fb87f763b5d04a82ae84ccff25554ffd903baafba6698e18ebaf32561f2fe4aa \
--hash=sha256:fc6b15465fabccc94bf7e38777d665b6a4f95efd1725049d6184b3a39fd54880
sqlalchemy==2.0.22 \
--hash=sha256:0b0b3f2686c3f162123adba3cb8b626ed7e9b8433ab528e36ed270b4f70d1cdb \
--hash=sha256:0c1fea8c0abcb070ffe15311853abfda4e55bf7dc1d4889497b3403629f3bf00 \
--hash=sha256:0e1ce8ebd2e040357dde01a3fb7d30d9b5736b3e54a94002641dfd0aa12ae6ce \
--hash=sha256:129415f89744b05741c6f0b04a84525f37fbabe5dc3774f7edf100e7458c48cd \
--hash=sha256:13790cb42f917c45c9c850b39b9941539ca8ee7917dacf099cc0b569f3d40da7 \
--hash=sha256:14cd3bcbb853379fef2cd01e7c64a5d6f1d005406d877ed9509afb7a05ff40a5 \
--hash=sha256:154a32f3c7b00de3d090bc60ec8006a78149e221f1182e3edcf0376016be9396 \
--hash=sha256:19c6986cf2fb4bc8e0e846f97f4135a8e753b57d2aaaa87c50f9acbe606bd1db \
--hash=sha256:2096d6b018d242a2bcc9e451618166f860bb0304f590d205173d317b69986c95 \
--hash=sha256:2c9bac865ee06d27a1533471405ad240a6f5d83195eca481f9fc4a71d8b87df8 \
--hash=sha256:3076740335e4aaadd7deb3fe6dcb96b3015f1613bd190a4e1634e1b99b02ec86 \
--hash=sha256:3940677d341f2b685a999bffe7078697b5848a40b5f6952794ffcf3af150c301 \
--hash=sha256:3aa1472bf44f61dd27987cd051f1c893b7d3b17238bff8c23fceaef4f1133868 \
--hash=sha256:40b1206a0d923e73aa54f0a6bd61419a96b914f1cd19900b6c8226899d9742ad \
--hash=sha256:4bb062784f37b2d75fd9b074c8ec360ad5df71f933f927e9e95c50eb8e05323c \
--hash=sha256:4e869a8ff7ee7a833b74868a0887e8462445ec462432d8cbeff5e85f475186da \
--hash=sha256:4f6ff392b27a743c1ad346d215655503cec64405d3b694228b3454878bf21590 \
--hash=sha256:505f503763a767556fa4deae5194b2be056b64ecca72ac65224381a0acab7ebe \
--hash=sha256:53a766cb0b468223cafdf63e2d37f14a4757476157927b09300c8c5832d88560 \
--hash=sha256:5434cc601aa17570d79e5377f5fd45ff92f9379e2abed0be5e8c2fba8d353d2b \
--hash=sha256:54bcceaf4eebef07dadfde424f5c26b491e4a64e61761dea9459103ecd6ccc95 \
--hash=sha256:55914d45a631b81a8a2cb1a54f03eea265cf1783241ac55396ec6d735be14883 \
--hash=sha256:564e9f9e4e6466273dbfab0e0a2e5fe819eec480c57b53a2cdee8e4fdae3ad5f \
--hash=sha256:56a7e2bb639df9263bf6418231bc2a92a773f57886d371ddb7a869a24919face \
--hash=sha256:58a3aba1bfb32ae7af68da3f277ed91d9f57620cf7ce651db96636790a78b736 \
--hash=sha256:625b72d77ac8ac23da3b1622e2da88c4aedaee14df47c8432bf8f6495e655de2 \
--hash=sha256:69fd9e41cf9368afa034e1c81f3570afb96f30fcd2eb1ef29cb4d9371c6eece2 \
--hash=sha256:6ac28bd6888fe3c81fbe97584eb0b96804bd7032d6100b9701255d9441373ec1 \
--hash=sha256:7c6c3e9350f9fb16de5b5e5fbf17b578811a52d71bb784cc5ff71acb7de2a7f9 \
--hash=sha256:7ee7ccf47aa503033b6afd57efbac6b9e05180f492aeed9fcf70752556f95624 \
--hash=sha256:875de9414393e778b655a3d97d60465eb3fae7c919e88b70cc10b40b9f56042d \
--hash=sha256:8db5ba8b7da759b727faebc4289a9e6a51edadc7fc32207a30f7c6203a181592 \
--hash=sha256:92e512a6af769e4725fa5b25981ba790335d42c5977e94ded07db7d641490a85 \
--hash=sha256:9886a72c8e6371280cb247c5d32c9c8fa141dc560124348762db8a8b236f8692 \
--hash=sha256:9e55dff5ec115316dd7a083cdc1a52de63693695aecf72bc53a8e1468ce429e5 \
--hash=sha256:a42c9fa3abcda0dcfad053e49c4f752eef71ecd8c155221e18b99d4224621176 \
--hash=sha256:a571bc8ac092a3175a1d994794a8e7a1f2f651e7c744de24a19b4f740fe95034 \
--hash=sha256:af66001d7b76a3fab0d5e4c1ec9339ac45748bc4a399cbc2baa48c1980d3c1f4 \
--hash=sha256:b39a6e21110204a8c08d40ff56a73ba542ec60bab701c36ce721e7990df49fb9 \
--hash=sha256:b560f075c151900587ade06706b0c51d04b3277c111151997ea0813455378ae0 \
--hash=sha256:c8f1792d20d2f4e875ce7a113f43c3561ad12b34ff796b84002a256f37ce9437 \
--hash=sha256:cb9a758ad973e795267da334a92dd82bb7555cb36a0960dcabcf724d26299db8 \
--hash=sha256:ccca778c0737a773a1ad86b68bda52a71ad5950b25e120b6eb1330f0df54c3d0 \
--hash=sha256:ccd87c25e4c8559e1b918d46b4fa90b37f459c9b4566f1dfbce0eb8122571547 \
--hash=sha256:d143c5a9dada696bcfdb96ba2de4a47d5a89168e71d05a076e88a01386872f97 \
--hash=sha256:d80eeb5189d7d4b1af519fc3f148fe7521b9dfce8f4d6a0820e8f5769b005051 \
--hash=sha256:e04ab55cf49daf1aeb8c622c54d23fa4bec91cb051a43cc24351ba97e1dd09f5 \
--hash=sha256:f146c61ae128ab43ea3a0955de1af7e1633942c2b2b4985ac51cc292daf33222 \
--hash=sha256:f776c2c30f0e5f4db45c3ee11a5f2a8d9de68e81eb73ec4237de1e32e04ae81c
# via -r requirements.in
typing-extensions==4.8.0 \
--hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \

View file

@ -9,23 +9,23 @@
"git_repository": [
{
"id": "luajit",
"name": "LuaJIT v2.1-20230911",
"name": "LuaJIT v2.1-20231006",
"url": "https://github.com/openresty/luajit2.git",
"commit": "e598aeb7426dbc069f90ba70db9bce43cd573b0e"
"commit": "492cfdd0d829e21abbf8ef8761aa48a3daf5a73f"
},
{
"id": "modsecurity",
"name": "ModSecurity v3.0.10",
"url": "https://github.com/SpiderLabs/ModSecurity.git",
"commit": "ccc2d9b53632fb5088673bbaafedf0d8d4b5f1d8",
"post_install": "patch src/deps/src/modsecurity/configure.ac src/deps/misc/modsecurity.patch && rm -rf src/deps/src/modsecurity/others/libinjection"
"post_install": "patch --forward src/deps/src/modsecurity/configure.ac src/deps/misc/modsecurity.patch && rm -rf src/deps/src/modsecurity/others/libinjection"
},
{
"id": "modsecurity-nginx",
"name": "ModSecurity-nginx v1.0.3",
"url": "https://github.com/SpiderLabs/ModSecurity-nginx.git",
"commit": "d59e4ad121df702751940fd66bcc0b3ecb51a079",
"post_install": "patch src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_log.c src/deps/misc/modsecurity-nginx.patch && patch src/deps/src/modsecurity-nginx/config src/deps/misc/config.patch && patch src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_common.h src/deps/misc/ngx_http_modsecurity_common.h.patch && patch src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_module.c src/deps/misc/ngx_http_modsecurity_module.c.patch"
"post_install": "patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_log.c src/deps/misc/modsecurity-nginx.patch && patch --forward src/deps/src/modsecurity-nginx/config src/deps/misc/config.patch && patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_common.h src/deps/misc/ngx_http_modsecurity_common.h.patch && patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_module.c src/deps/misc/ngx_http_modsecurity_module.c.patch"
},
{
"id": "nginx",
@ -86,7 +86,7 @@
"name": "lua-ffi-zlib v0.6",
"url": "https://github.com/hamishforbes/lua-ffi-zlib.git",
"commit": "61e95cb434e4047c8bc65a180c293a05bf754416",
"post_install": "patch src/deps/src/lua-ffi-zlib/lib/ffi-zlib.lua src/deps/misc/lua-ffi-zlib.patch"
"post_install": "patch --forward src/deps/src/lua-ffi-zlib/lib/ffi-zlib.lua src/deps/misc/lua-ffi-zlib.patch"
},
{
"id": "lua-gd",
@ -129,7 +129,7 @@
"name": "lua-resty-ipmatcher v0.6.1 (3 commits after just in case)",
"url": "https://github.com/api7/lua-resty-ipmatcher.git",
"commit": "7fbb618f7221b1af1451027d3c64e51f3182761c",
"post_install": "patch src/deps/src/lua-resty-ipmatcher/resty/ipmatcher.lua src/deps/misc/ipmatcher.patch"
"post_install": "patch --forward src/deps/src/lua-resty-ipmatcher/resty/ipmatcher.lua src/deps/misc/ipmatcher.patch"
},
{
"id": "lua-resty-lock",
@ -203,7 +203,7 @@
"name": "luajit-geoip v2.1.0",
"url": "https://github.com/leafo/luajit-geoip.git",
"commit": "fde33e045083522d73665a6894d78dbf995b9e12",
"post_install": "patch src/deps/src/luajit-geoip/geoip/mmdb.lua src/deps/misc/mmdb.patch"
"post_install": "patch --forward src/deps/src/luajit-geoip/geoip/mmdb.lua src/deps/misc/mmdb.patch"
},
{
"id": "lualogging",

View file

@ -1,4 +1,4 @@
pip==23.2.1
pip==23.3
pip-tools==7.3.0
wheel==0.41.2
setuptools==68.2.2

View file

@ -131,9 +131,9 @@ packaging==23.2 \
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
pip==23.2.1 \
--hash=sha256:7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be \
--hash=sha256:fb0bd5435b3200c602b5bf61d2d43c2f13c02e29c1707567ae7fbc514eb9faf2
pip==23.3 \
--hash=sha256:bb7d4f69f488432e4e96394612f43ab43dd478d073ef7422604a570f7157561e \
--hash=sha256:bc38bb52bc286514f8f7cb3a1ba5ed100b76aaef29b521d48574329331c5ae7b
# via
# build
# pip-upgrader

View file

@ -1,4 +1,4 @@
pip==23.2.1
pip==23.3
pip-tools==7.3.0
wheel==0.41.2
setuptools==68.2.2

View file

@ -22,9 +22,9 @@ packaging==23.2 \
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
pip==23.2.1 \
--hash=sha256:7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be \
--hash=sha256:fb0bd5435b3200c602b5bf61d2d43c2f13c02e29c1707567ae7fbc514eb9faf2
pip==23.3 \
--hash=sha256:bb7d4f69f488432e4e96394612f43ab43dd478d073ef7422604a570f7157561e \
--hash=sha256:bc38bb52bc286514f8f7cb3a1ba5ed100b76aaef29b521d48574329331c5ae7b
# via build
pip-tools==7.3.0 \
--hash=sha256:8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e \

View file

@ -426,9 +426,7 @@ the toolchain used to compile LuaJIT:
on the C&nbsp;stack. The contents of the C++&nbsp;exception object
pass through unmodified.</li>
<li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>.
The corresponding Lua error message can be retrieved from the Lua stack.<br>
For MSVC for Windows 64 bit this requires compilation of your C++ code
with <tt>/EHa</tt>.</li>
The corresponding Lua error message can be retrieved from the Lua stack.</li>
<li>Throwing Lua errors across C++ frames is safe. C++ destructors
will be called.</li>
</ul>

View file

@ -203,7 +203,7 @@ Or install Microsoft's Visual Studio (MSVC).
</p>
<h3>Building with MSVC</h3>
<p>
Open a "Visual Studio Command Prompt" (either x86 or x64), <tt>cd</tt> to the
Open a "Visual Studio Command Prompt" (x86, x64 or ARM64), <tt>cd</tt> to the
directory with the source code and run these commands:
</p>
<pre class="code">
@ -214,6 +214,9 @@ msvcbuild
Check the <tt>msvcbuild.bat</tt> file for more options.
Then follow the installation instructions below.
</p>
<p>
For an x64 to ARM64 cross-build run this first: <tt>vcvarsall.bat x64_arm64</tt>
</p>
<h3>Building with MinGW or Cygwin</h3>
<p>
Open a command prompt window and make sure the MinGW or Cygwin programs

View file

@ -233,7 +233,7 @@ TARGET_ALDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS) $(TARGET_FLAGS) $(TARGET_LDFLAG
TARGET_ASHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS) $(TARGET_FLAGS) $(TARGET_SHLDFLAGS)
TARGET_ALIBS= $(TARGET_XLIBS) $(LIBS) $(TARGET_LIBS)
TARGET_TESTARCH=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E lj_arch.h -dM)
TARGET_TESTARCH:=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E lj_arch.h -dM)
ifneq (,$(findstring LJ_TARGET_X64 ,$(TARGET_TESTARCH)))
TARGET_LJARCH= x64
else
@ -488,7 +488,11 @@ DASM_FLAGS= $(DASM_XFLAGS) $(DASM_AFLAGS)
DASM_DASC= vm_$(DASM_ARCH).dasc
GIT= git
GIT_RELVER= [ -e ../.git ] && $(GIT) show -s --format=%ct >luajit_relver.txt 2>/dev/null || cat ../.relver >luajit_relver.txt 2>/dev/null || :
ifeq (Windows,$(HOST_SYS)$(HOST_MSYS))
GIT_RELVER= if exist ..\.git ( $(GIT) show -s --format=%%ct >luajit_relver.txt ) else ( type ..\.relver >luajit_relver.txt )
else
GIT_RELVER= [ -e ../.git ] && $(GIT) show -s --format=%ct >luajit_relver.txt 2>/dev/null || cat ../.relver >luajit_relver.txt 2>/dev/null || :
endif
GIT_DEP= $(wildcard ../.git/HEAD ../.git/refs/heads/*)
BUILDVM_O= host/buildvm.o host/buildvm_asm.o host/buildvm_peobj.o \

View file

@ -9,7 +9,7 @@
#include "buildvm.h"
#include "lj_bc.h"
#if LJ_TARGET_X86ORX64
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
/* Context for PE object emitter. */
static char *strtab;
@ -93,6 +93,17 @@ typedef struct PEsymaux {
#define PEOBJ_RELOC_ADDR32NB 0x03
#define PEOBJ_RELOC_OFS 0
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
#define PEOBJ_PDATA_NRELOC 6
#define PEOBJ_XDATA_SIZE (8*2+4+6*2)
#elif LJ_TARGET_ARM64
#define PEOBJ_ARCH_TARGET 0xaa64
#define PEOBJ_RELOC_REL32 0x03 /* MS: BRANCH26. */
#define PEOBJ_RELOC_DIR32 0x01
#define PEOBJ_RELOC_ADDR32NB 0x02
#define PEOBJ_RELOC_OFS (-4)
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
#define PEOBJ_PDATA_NRELOC 4
#define PEOBJ_XDATA_SIZE (4+24+4 +4+8)
#endif
/* Section numbers (0-based). */
@ -100,7 +111,7 @@ enum {
PEOBJ_SECT_ABS = -2,
PEOBJ_SECT_UNDEF = -1,
PEOBJ_SECT_TEXT,
#if LJ_TARGET_X64
#ifdef PEOBJ_PDATA_NRELOC
PEOBJ_SECT_PDATA,
PEOBJ_SECT_XDATA,
#elif LJ_TARGET_X86
@ -175,6 +186,9 @@ void emit_peobj(BuildCtx *ctx)
uint32_t sofs;
int i, nrsym;
union { uint8_t b; uint32_t u; } host_endian;
#ifdef PEOBJ_PDATA_NRELOC
uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
#endif
sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
@ -188,18 +202,18 @@ void emit_peobj(BuildCtx *ctx)
/* Flags: 60 = read+execute, 50 = align16, 20 = code. */
pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
#if LJ_TARGET_X64
#ifdef PEOBJ_PDATA_NRELOC
memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
pesect[PEOBJ_SECT_PDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4);
sofs += (pesect[PEOBJ_SECT_PDATA].size = PEOBJ_PDATA_NRELOC*4);
pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE;
sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = PEOBJ_PDATA_NRELOC) * PEOBJ_RELOC_SIZE;
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
pesect[PEOBJ_SECT_XDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2); /* See below. */
sofs += (pesect[PEOBJ_SECT_XDATA].size = PEOBJ_XDATA_SIZE); /* See below. */
pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
@ -234,7 +248,7 @@ void emit_peobj(BuildCtx *ctx)
*/
nrsym = ctx->nrelocsym;
pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
#if LJ_TARGET_X64
#ifdef PEOBJ_PDATA_NRELOC
pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */
#endif
@ -259,7 +273,6 @@ void emit_peobj(BuildCtx *ctx)
#if LJ_TARGET_X64
{ /* Write .pdata section. */
uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
PEreloc reloc;
pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
@ -308,6 +321,86 @@ void emit_peobj(BuildCtx *ctx)
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
#elif LJ_TARGET_ARM64
/* https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling */
{ /* Write .pdata section. */
uint32_t pdata[4];
PEreloc reloc;
pdata[0] = 0;
pdata[1] = 0;
pdata[2] = fcofs;
pdata[3] = 4+24+4;
owrite(ctx, &pdata, sizeof(pdata));
/* Start of .text and start of .xdata. */
reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
/* Start of vm_ffi_call and start of second part of .xdata. */
reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
{ /* Write .xdata section. */
uint32_t u32;
uint8_t *p, uwc[24];
PEreloc reloc;
#define CBE16(x) (*p = ((x) >> 8) & 0xff, p[1] = (x) & 0xff, p += 2)
#define CALLOC_S(s) (*p++ = ((s) >> 4)) /* s < 512 */
#define CSAVE_FPLR(o) (*p++ = 0x40 | ((o) >> 3)) /* o <= 504 */
#define CSAVE_REGP(r,o) CBE16(0xc800 | (((r) - 19) << 6) | ((o) >> 3))
#define CSAVE_REGS(r1,r2,o1) do { \
int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_REGP(r, o); \
} while (0)
#define CSAVE_REGPX(r,o) CBE16(0xcc00 | (((r) - 19) << 6) | (~(o) >> 3))
#define CSAVE_FREGP(r,o) CBE16(0xd800 | (((r) - 8) << 6) | ((o) >> 3))
#define CSAVE_FREGS(r1,r2,o1) do { \
int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_FREGP(r, o); \
} while (0)
#define CADD_FP(s) CBE16(0xe200 | ((s) >> 3)) /* s < 8*256 */
#define CODE_NOP 0xe3
#define CODE_END 0xe4
#define CEND_ALIGN do { \
*p++ = CODE_END; \
while ((p - uwc) & 3) *p++ = CODE_NOP; \
} while (0)
/* Unwind codes for .text section with handler. */
p = uwc;
CSAVE_REGS(19, 28, 176); /* +5*2 */
CSAVE_FREGS(8, 15, 96); /* +4*2 */
CSAVE_FPLR(192); /* +1 */
CALLOC_S(208); /* +1 */
CEND_ALIGN; /* +1 +3 -> 24 */
u32 = ((24u >> 2) << 27) | (1u << 20) | (fcofs >> 2);
owrite(ctx, &u32, 4);
owrite(ctx, &uwc, 24);
u32 = 0; /* Handler RVA to be relocated at 4 + 24. */
owrite(ctx, &u32, 4);
/* Unwind codes for vm_ffi_call without handler. */
p = uwc;
CADD_FP(16); /* +2 */
CSAVE_FPLR(16); /* +1 */
CSAVE_REGPX(19, -32); /* +2 */
CEND_ALIGN; /* +1 +2 -> 8 */
u32 = ((8u >> 2) << 27) | (((uint32_t)ctx->codesz - fcofs) >> 2);
owrite(ctx, &u32, 4);
owrite(ctx, &uwc, 8);
reloc.vaddr = 4 + 24; reloc.symidx = 1+2+nrsym+2+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
#elif LJ_TARGET_X86
/* Write .sxdata section. */
for (i = 0; i < nrsym; i++) {
@ -339,7 +432,7 @@ void emit_peobj(BuildCtx *ctx)
emit_peobj_sym(ctx, ctx->relocsym[i], 0,
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
#if LJ_TARGET_X64
#ifdef PEOBJ_PDATA_NRELOC
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
emit_peobj_sym(ctx, "lj_err_unwind_win", 0,

View file

@ -5,9 +5,10 @@
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
local FILE_ROLLING_H = "luajit_rolling.h"
local FILE_RELVER_TXT = "luajit_relver.txt"
local FILE_LUAJIT_H = "luajit.h"
local arg = {...}
local FILE_ROLLING_H = arg[1] or "luajit_rolling.h"
local FILE_RELVER_TXT = arg[2] or "luajit_relver.txt"
local FILE_LUAJIT_H = arg[3] or "luajit.h"
local function file_read(file)
local fp = assert(io.open(file, "rb"), "run from the wrong directory")

View file

@ -107,24 +107,20 @@ local map_logsr = { -- Logical, shifted register.
[0] = {
shift = 29, mask = 3,
[0] = {
shift = 21, mask = 7,
[0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
"andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
shift = 21, mask = 1,
[0] = "andDNMSg", "bicDNMSg"
},
{
shift = 21, mask = 7,
[0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
"orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
shift = 21, mask = 1,
[0] = "orr|movDN0MSg", "orn|mvnDN0MSg"
},
{
shift = 21, mask = 7,
[0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
"eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
shift = 21, mask = 1,
[0] = "eorDNMSg", "eonDNMSg"
},
{
shift = 21, mask = 7,
[0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
"ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
shift = 21, mask = 1,
[0] = "ands|tstD0NMSg", "bicsDNMSg"
}
},
false -- unallocated
@ -132,24 +128,20 @@ local map_logsr = { -- Logical, shifted register.
{
shift = 29, mask = 3,
[0] = {
shift = 21, mask = 7,
[0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
"andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
shift = 21, mask = 1,
[0] = "andDNMSg", "bicDNMSg"
},
{
shift = 21, mask = 7,
[0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
"orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
shift = 21, mask = 1,
[0] = "orr|movDN0MSg", "orn|mvnDN0MSg"
},
{
shift = 21, mask = 7,
[0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
"eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
shift = 21, mask = 1,
[0] = "eorDNMSg", "eonDNMSg"
},
{
shift = 21, mask = 7,
[0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
"ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
shift = 21, mask = 1,
[0] = "ands|tstD0NMSg", "bicsDNMSg"
}
}
}
@ -735,7 +727,7 @@ local map_cond = {
"hi", "ls", "ge", "lt", "gt", "le", "al",
}
local map_shift = { [0] = "lsl", "lsr", "asr", }
local map_shift = { [0] = "lsl", "lsr", "asr", "ror"}
local map_extend = {
[0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx",

View file

@ -617,7 +617,10 @@ static int ffh_resume(lua_State *L, lua_State *co, int wrap)
setstrV(L, L->base-LJ_FR2, lj_err_str(L, em));
return FFH_RES(2);
}
lj_state_growstack(co, (MSize)(L->top - L->base));
if (lj_state_cpgrowstack(co, (MSize)(L->top - L->base)) != LUA_OK) {
cTValue *msg = --co->top;
lj_err_callermsg(L, strVdata(msg));
}
return FFH_RETRY;
}

View file

@ -746,7 +746,7 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.)
"\003win"
#endif
#if LJ_ABI_PAUTH
"\007pauth"
"\005pauth"
#endif
#if LJ_TARGET_UWP
"\003uwp"

View file

@ -104,7 +104,12 @@ LUA_API int lua_checkstack(lua_State *L, int size)
if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) {
return 0; /* Stack overflow. */
} else if (size > 0) {
lj_state_checkstack(L, (MSize)size);
int avail = (int)(mref(L->maxstack, TValue) - L->top);
if (size > avail &&
lj_state_cpgrowstack(L, (MSize)(size - avail)) != LUA_OK) {
L->top--;
return 0; /* Out of memory. */
}
}
return 1;
}

View file

@ -59,7 +59,7 @@
#define LUAJIT_TARGET LUAJIT_ARCH_X64
#elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM)
#define LUAJIT_TARGET LUAJIT_ARCH_ARM
#elif defined(__aarch64__)
#elif defined(__aarch64__) || defined(_M_ARM64)
#define LUAJIT_TARGET LUAJIT_ARCH_ARM64
#elif defined(__s390x__) || defined(__s390x)
#define LUAJIT_TARGET LUAJIT_ARCH_S390X
@ -70,7 +70,7 @@
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS)
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS32
#else
#error "No support for this architecture (yet)"
#error "Architecture not supported (in this version), see: https://luajit.org/status.html#architectures"
#endif
#endif
@ -245,7 +245,7 @@
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
#if __ARM_ARCH == 8 || __ARM_ARCH_8__ || __ARM_ARCH_8A__
#if __ARM_ARCH >= 8 || __ARM_ARCH_8__ || __ARM_ARCH_8A__
#define LJ_ARCH_VERSION 80
#elif __ARM_ARCH == 7 || __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH_7S__ || __ARM_ARCH_7VE__
#define LJ_ARCH_VERSION 70
@ -523,30 +523,45 @@
#elif LJ_TARGET_ARM
#if defined(__ARMEB__)
#error "No support for big-endian ARM"
#undef LJ_TARGET_ARM
#endif
#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__
#error "No support for Cortex-M CPUs"
#undef LJ_TARGET_ARM
#endif
#if !(__ARM_EABI__ || LJ_TARGET_IOS)
#error "Only ARM EABI or iOS 3.0+ ABI is supported"
#undef LJ_TARGET_ARM
#endif
#elif LJ_TARGET_ARM64
#if defined(_ILP32)
#error "No support for ILP32 model on ARM64"
#undef LJ_TARGET_ARM64
#endif
#elif LJ_TARGET_PPC
#if defined(_LITTLE_ENDIAN) && (!defined(_BYTE_ORDER) || (_BYTE_ORDER == _LITTLE_ENDIAN))
#error "No support for little-endian PPC32"
#undef LJ_TARGET_PPC
#endif
#if defined(__NO_FPRS__) && !defined(_SOFT_FLOAT)
#error "No support for PPC/e500, use LuaJIT 2.0"
#undef LJ_TARGET_PPC
#endif
#elif LJ_TARGET_MIPS32
#if !((defined(_MIPS_SIM_ABI32) && _MIPS_SIM == _MIPS_SIM_ABI32) || (defined(_ABIO32) && _MIPS_SIM == _ABIO32))
#error "Only o32 ABI supported for MIPS32"
#undef LJ_TARGET_MIPS
#endif
#if LJ_TARGET_MIPSR6
/* Not that useful, since most available r6 CPUs are 64 bit. */
#error "No support for MIPS32R6"
#undef LJ_TARGET_MIPS
#endif
#elif LJ_TARGET_MIPS64
#if !((defined(_MIPS_SIM_ABI64) && _MIPS_SIM == _MIPS_SIM_ABI64) || (defined(_ABI64) && _MIPS_SIM == _ABI64))
/* MIPS32ON64 aka n32 ABI support might be desirable, but difficult. */
#error "Only n64 ABI supported for MIPS64"
#undef LJ_TARGET_MIPS
#endif
#endif
#endif

View file

@ -606,7 +606,11 @@ static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow)
IRIns *ir = IR(ref);
if ((ir->o == IR_KINT64 && k == (int64_t)ir_kint64(ir)->u64) ||
#if LJ_GC64
#if LJ_TARGET_ARM64
(ir->o == IR_KINT && (uint64_t)k == (uint32_t)ir->i) ||
#else
(ir->o == IR_KINT && k == ir->i) ||
#endif
(ir->o == IR_KGC && k == (intptr_t)ir_kgc(ir)) ||
((ir->o == IR_KPTR || ir->o == IR_KKPTR) &&
k == (intptr_t)ir_kptr(ir))

View file

@ -1990,6 +1990,7 @@ static void asm_prof(ASMState *as, IRIns *ir)
static void asm_stack_check(ASMState *as, BCReg topslot,
IRIns *irp, RegSet allow, ExitNo exitno)
{
int savereg = 0;
Reg pbase;
uint32_t k;
if (irp) {
@ -2000,12 +2001,14 @@ static void asm_stack_check(ASMState *as, BCReg topslot,
pbase = rset_pickbot(allow);
} else {
pbase = RID_RET;
emit_lso(as, ARMI_LDR, RID_RET, RID_SP, 0); /* Restore temp. register. */
savereg = 1;
}
} else {
pbase = RID_BASE;
}
emit_branch(as, ARMF_CC(ARMI_BL, CC_LS), exitstub_addr(as->J, exitno));
if (savereg)
emit_lso(as, ARMI_LDR, RID_RET, RID_SP, 0); /* Restore temp. register. */
k = emit_isk12(0, (int32_t)(8*topslot));
lj_assertA(k, "slot offset %d does not fit in K12", 8*topslot);
emit_n(as, ARMI_CMP^k, RID_TMP);
@ -2017,7 +2020,7 @@ static void asm_stack_check(ASMState *as, BCReg topslot,
if (ra_hasspill(irp->s))
emit_lso(as, ARMI_LDR, pbase, RID_SP, sps_scale(irp->s));
emit_lso(as, ARMI_LDR, RID_TMP, RID_TMP, (i & 4095));
if (ra_hasspill(irp->s) && !allow)
if (savereg)
emit_lso(as, ARMI_STR, RID_RET, RID_SP, 0); /* Save temp. register. */
emit_loadi(as, RID_TMP, (i & ~4095));
} else {

View file

@ -84,18 +84,23 @@ static void asm_guardcc(ASMState *as, A64CC cc)
emit_cond_branch(as, cc, target);
}
/* Emit test and branch instruction to exit for guard. */
static void asm_guardtnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit)
/* Emit test and branch instruction to exit for guard, if in range. */
static int asm_guardtnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit)
{
MCode *target = asm_exitstub_addr(as, as->snapno);
MCode *p = as->mcp;
ptrdiff_t delta = target - p;
if (LJ_UNLIKELY(p == as->invmcp)) {
if (as->orignins > 1023) return 0; /* Delta might end up too large. */
as->loopinv = 1;
*p = A64I_B | A64F_S26(target-p);
emit_tnb(as, ai^0x01000000u, r, bit, p-1);
return;
*p = A64I_B | A64F_S26(delta);
ai ^= 0x01000000u;
target = p-1;
} else if (LJ_UNLIKELY(delta >= 0x1fff)) {
return 0;
}
emit_tnb(as, ai, r, bit, target);
return 1;
}
/* Emit compare and branch instruction to exit for guard. */
@ -211,16 +216,14 @@ static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow,
static uint32_t asm_fuseopm(ASMState *as, A64Ins ai, IRRef ref, RegSet allow)
{
IRIns *ir = IR(ref);
int logical = (ai & 0x1f000000) == 0x0a000000;
if (ra_hasreg(ir->r)) {
ra_noweak(as, ir->r);
return A64F_M(ir->r);
} else if (irref_isk(ref)) {
uint32_t m;
int64_t k = get_k64val(as, ref);
if ((ai & 0x1f000000) == 0x0a000000)
m = emit_isk13(k, irt_is64(ir->t));
else
m = emit_isk12(k);
uint32_t m = logical ? emit_isk13(k, irt_is64(ir->t)) :
emit_isk12(irt_is64(ir->t) ? k : (int32_t)k);
if (m)
return m;
} else if (mayfuse(as, ref)) {
@ -232,7 +235,7 @@ static uint32_t asm_fuseopm(ASMState *as, A64Ins ai, IRRef ref, RegSet allow)
(IR(ir->op2)->i & (irt_is64(ir->t) ? 63 : 31));
IRIns *irl = IR(ir->op1);
if (sh == A64SH_LSL &&
irl->o == IR_CONV &&
irl->o == IR_CONV && !logical &&
irl->op2 == ((IRT_I64<<IRCONV_DSH)|IRT_INT|IRCONV_SEXT) &&
shift <= 4 &&
canfuse(as, irl)) {
@ -242,7 +245,11 @@ static uint32_t asm_fuseopm(ASMState *as, A64Ins ai, IRRef ref, RegSet allow)
Reg m = ra_alloc1(as, ir->op1, allow);
return A64F_M(m) | A64F_SH(sh, shift);
}
} else if (ir->o == IR_CONV &&
} else if (ir->o == IR_BROR && logical && irref_isk(ir->op2)) {
Reg m = ra_alloc1(as, ir->op1, allow);
int shift = (IR(ir->op2)->i & (irt_is64(ir->t) ? 63 : 31));
return A64F_M(m) | A64F_SH(A64SH_ROR, shift);
} else if (ir->o == IR_CONV && !logical &&
ir->op2 == ((IRT_I64<<IRCONV_DSH)|IRT_INT|IRCONV_SEXT)) {
Reg m = ra_alloc1(as, ir->op1, allow);
return A64F_M(m) | A64F_EX(A64EX_SXTW);
@ -455,6 +462,11 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
for (gpr = REGARG_FIRSTGPR; gpr <= REGARG_LASTGPR; gpr++)
as->cost[gpr] = REGCOST(~0u, ASMREF_L);
gpr = REGARG_FIRSTGPR;
#if LJ_HASFFI && LJ_ABI_WIN
if ((ci->flags & CCI_VARARG)) {
fpr = REGARG_LASTFPR+1;
}
#endif
for (n = 0; n < nargs; n++) { /* Setup args. */
IRRef ref = args[n];
IRIns *ir = IR(ref);
@ -465,6 +477,11 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
"reg %d not free", fpr); /* Must have been evicted. */
ra_leftov(as, fpr, ref);
fpr++;
#if LJ_HASFFI && LJ_ABI_WIN
} else if ((ci->flags & CCI_VARARG) && (gpr <= REGARG_LASTGPR)) {
Reg rf = ra_alloc1(as, ref, RSET_FPR);
emit_dn(as, A64I_FMOV_R_D, gpr++, rf & 31);
#endif
} else {
Reg r = ra_alloc1(as, ref, RSET_FPR);
int32_t al = spalign;
@ -570,8 +587,6 @@ static void asm_retf(ASMState *as, IRIns *ir)
as->topslot -= (BCReg)delta;
if ((int32_t)as->topslot < 0) as->topslot = 0;
irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */
/* Need to force a spill on REF_BASE now to update the stack slot. */
emit_lso(as, A64I_STRx, base, RID_SP, ra_spill(as, IR(REF_BASE)));
emit_setgl(as, base, jit_base);
emit_addptr(as, base, -8*delta);
asm_guardcc(as, CC_NE);
@ -695,25 +710,22 @@ static void asm_strto(ASMState *as, IRIns *ir)
{
const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num];
IRRef args[2];
Reg dest = 0, tmp;
int destused = ra_used(ir);
Reg tmp;
int32_t ofs = 0;
ra_evictset(as, RSET_SCRATCH);
if (destused) {
if (ra_used(ir)) {
if (ra_hasspill(ir->s)) {
ofs = sps_scale(ir->s);
destused = 0;
if (ra_hasreg(ir->r)) {
ra_free(as, ir->r);
ra_modified(as, ir->r);
emit_spload(as, ir, ir->r, ofs);
}
} else {
dest = ra_dest(as, ir, RSET_FPR);
Reg dest = ra_dest(as, ir, RSET_FPR);
emit_lso(as, A64I_LDRd, (dest & 31), RID_SP, 0);
}
}
if (destused)
emit_lso(as, A64I_LDRd, (dest & 31), RID_SP, 0);
asm_guardcnb(as, A64I_CBZ, RID_RET);
args[0] = ir->op1; /* GCstr *str */
args[1] = ASMREF_TMP1; /* TValue *n */
@ -804,113 +816,75 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
int destused = ra_used(ir);
Reg dest = ra_dest(as, ir, allow);
Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest));
Reg key = 0, tmp = RID_TMP;
Reg ftmp = RID_NONE, type = RID_NONE, scr = RID_NONE, tisnum = RID_NONE;
Reg tmp = RID_TMP, type = RID_NONE, key, tkey;
IRRef refkey = ir->op2;
IRIns *irkey = IR(refkey);
int isk = irref_isk(ir->op2);
int isk = irref_isk(refkey);
IRType1 kt = irkey->t;
uint32_t k = 0;
uint32_t khash;
MCLabel l_end, l_loop, l_next;
MCLabel l_end, l_loop;
rset_clear(allow, tab);
if (!isk) {
key = ra_alloc1(as, ir->op2, irt_isnum(kt) ? RSET_FPR : allow);
rset_clear(allow, key);
if (!irt_isstr(kt)) {
tmp = ra_scratch(as, allow);
rset_clear(allow, tmp);
}
} else if (irt_isnum(kt)) {
int64_t val = (int64_t)ir_knum(irkey)->u64;
if (!(k = emit_isk12(val))) {
key = ra_allock(as, val, allow);
rset_clear(allow, key);
}
} else if (!irt_ispri(kt)) {
if (!(k = emit_isk12(irkey->i))) {
key = ra_alloc1(as, refkey, allow);
rset_clear(allow, key);
}
}
/* Allocate constants early. */
if (irt_isnum(kt)) {
if (!isk) {
tisnum = ra_allock(as, LJ_TISNUM << 15, allow);
ftmp = ra_scratch(as, rset_exclude(RSET_FPR, key));
rset_clear(allow, tisnum);
}
} else if (irt_isaddr(kt)) {
if (isk) {
int64_t kk = ((int64_t)irt_toitype(kt) << 47) | irkey[1].tv.u64;
scr = ra_allock(as, kk, allow);
/* Allocate register for tkey outside of the loop. */
if (isk) {
int64_t kk;
if (irt_isaddr(kt)) {
kk = ((int64_t)irt_toitype(kt) << 47) | irkey[1].tv.u64;
} else if (irt_isnum(kt)) {
kk = (int64_t)ir_knum(irkey)->u64;
/* Assumes -0.0 is already canonicalized to +0.0. */
} else {
scr = ra_scratch(as, allow);
lj_assertA(irt_ispri(kt) && !irt_isnil(kt), "bad HREF key type");
kk = ~((int64_t)~irt_toitype(kt) << 47);
}
rset_clear(allow, scr);
k = emit_isk12(kk);
tkey = k ? 0 : ra_allock(as, kk, allow);
} else {
lj_assertA(irt_ispri(kt) && !irt_isnil(kt), "bad HREF key type");
type = ra_allock(as, ~((int64_t)~irt_toitype(kt) << 47), allow);
scr = ra_scratch(as, rset_clear(allow, type));
rset_clear(allow, scr);
tkey = ra_scratch(as, allow);
}
/* Key not found in chain: jump to exit (if merged) or load niltv. */
l_end = emit_label(as);
as->invmcp = NULL;
if (merge == IR_NE)
if (merge == IR_NE) {
asm_guardcc(as, CC_AL);
else if (destused)
emit_loada(as, dest, niltvg(J2G(as->J)));
} else if (destused) {
uint32_t k12 = emit_isk12(offsetof(global_State, nilnode.val));
lj_assertA(k12 != 0, "Cannot k12 encode niltv(L)");
emit_dn(as, A64I_ADDx^k12, dest, RID_GL);
}
/* Follow hash chain until the end. */
l_loop = --as->mcp;
emit_n(as, A64I_CMPx^A64I_K12^0, dest);
emit_lso(as, A64I_LDRx, dest, dest, offsetof(Node, next));
l_next = emit_label(as);
if (destused)
emit_lso(as, A64I_LDRx, dest, dest, offsetof(Node, next));
/* Type and value comparison. */
if (merge == IR_EQ)
asm_guardcc(as, CC_EQ);
else
emit_cond_branch(as, CC_EQ, l_end);
emit_nm(as, A64I_CMPx^k, tmp, tkey);
if (!destused)
emit_lso(as, A64I_LDRx, dest, dest, offsetof(Node, next));
emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key));
*l_loop = A64I_X | A64I_CBNZ | A64F_S19(as->mcp - l_loop) | dest;
if (irt_isnum(kt)) {
if (isk) {
/* Assumes -0.0 is already canonicalized to +0.0. */
if (k)
emit_n(as, A64I_CMPx^k, tmp);
else
emit_nm(as, A64I_CMPx, key, tmp);
emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64));
/* Construct tkey as canonicalized or tagged key. */
if (!isk) {
if (irt_isnum(kt)) {
key = ra_alloc1(as, refkey, RSET_FPR);
emit_dnm(as, A64I_CSELx | A64F_CC(CC_EQ), tkey, RID_ZERO, tkey);
/* A64I_FMOV_R_D from key to tkey done below. */
} else {
emit_nm(as, A64I_FCMPd, key, ftmp);
emit_dn(as, A64I_FMOV_D_R, (ftmp & 31), (tmp & 31));
emit_cond_branch(as, CC_LO, l_next);
emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32), tisnum, tmp);
emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.n));
lj_assertA(irt_isaddr(kt), "bad HREF key type");
key = ra_alloc1(as, refkey, allow);
type = ra_allock(as, irt_toitype(kt) << 15, rset_clear(allow, key));
emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 32), tkey, key, type);
}
} else if (irt_isaddr(kt)) {
if (isk) {
emit_nm(as, A64I_CMPx, scr, tmp);
emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64));
} else {
emit_nm(as, A64I_CMPx, tmp, scr);
emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key.u64));
}
} else {
emit_nm(as, A64I_CMPx, scr, type);
emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key));
}
*l_loop = A64I_BCC | A64F_S19(as->mcp - l_loop) | CC_NE;
if (!isk && irt_isaddr(kt)) {
type = ra_allock(as, (int32_t)irt_toitype(kt), allow);
emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 47), tmp, key, type);
rset_clear(allow, type);
}
/* Load main position relative to tab->node into dest. */
khash = isk ? ir_khash(as, irkey) : 1;
if (khash == 0) {
@ -924,7 +898,6 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
emit_dnm(as, A64I_ANDw, dest, dest, tmphash);
emit_lso(as, A64I_LDRw, dest, tab, offsetof(GCtab, hmask));
} else if (irt_isstr(kt)) {
/* Fetch of str->sid is cheaper than ra_allock. */
emit_dnm(as, A64I_ANDw, dest, dest, tmp);
emit_lso(as, A64I_LDRw, tmp, key, offsetof(GCstr, sid));
emit_lso(as, A64I_LDRw, dest, tab, offsetof(GCtab, hmask));
@ -933,23 +906,18 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
emit_lso(as, A64I_LDRw, tmp, tab, offsetof(GCtab, hmask));
emit_dnm(as, A64I_SUBw, dest, dest, tmp);
emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT3)), tmp, tmp, tmp);
emit_dnm(as, A64I_EORw, dest, dest, tmp);
emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT2)), dest, dest, dest);
emit_dnm(as, A64I_EORw | A64F_SH(A64SH_ROR, 32-HASH_ROT2), dest, tmp, dest);
emit_dnm(as, A64I_SUBw, tmp, tmp, dest);
emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT1)), dest, dest, dest);
emit_dnm(as, A64I_EORw, tmp, tmp, dest);
if (irt_isnum(kt)) {
emit_dnm(as, A64I_EORw, tmp, tkey, dest);
emit_dnm(as, A64I_ADDw, dest, dest, dest);
emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, dest);
emit_dm(as, A64I_MOVw, tmp, dest);
emit_dn(as, A64I_FMOV_R_D, dest, (key & 31));
emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, tkey);
emit_nm(as, A64I_FCMPZd, (key & 31), 0);
emit_dn(as, A64I_FMOV_R_D, tkey, (key & 31));
} else {
checkmclim(as);
emit_dm(as, A64I_MOVw, tmp, key);
emit_dnm(as, A64I_EORw, dest, dest,
ra_allock(as, irt_toitype(kt) << 15, allow));
emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, dest);
emit_dm(as, A64I_MOVx, dest, key);
emit_dnm(as, A64I_EORw, tmp, key, dest);
emit_dnm(as, A64I_EORx | A64F_SH(A64SH_LSR, 32), dest, type, key);
}
}
}
@ -964,7 +932,7 @@ static void asm_hrefk(ASMState *as, IRIns *ir)
int bigofs = !emit_checkofs(A64I_LDRx, kofs);
Reg dest = (ra_used(ir) || bigofs) ? ra_dest(as, ir, RSET_GPR) : RID_NONE;
Reg node = ra_alloc1(as, ir->op1, RSET_GPR);
Reg key, idx = node;
Reg idx = node;
RegSet allow = rset_exclude(RSET_GPR, node);
uint64_t k;
lj_assertA(ofs % sizeof(Node) == 0, "unaligned HREFK slot");
@ -983,9 +951,8 @@ static void asm_hrefk(ASMState *as, IRIns *ir)
} else {
k = ((uint64_t)irt_toitype(irkey->t) << 47) | (uint64_t)ir_kgc(irkey);
}
key = ra_scratch(as, allow);
emit_nm(as, A64I_CMPx, key, ra_allock(as, k, rset_exclude(allow, key)));
emit_lso(as, A64I_LDRx, key, idx, kofs);
emit_nm(as, A64I_CMPx, RID_TMP, ra_allock(as, k, allow));
emit_lso(as, A64I_LDRx, RID_TMP, idx, kofs);
if (bigofs)
emit_opk(as, A64I_ADDx, dest, node, ofs, rset_exclude(RSET_GPR, node));
}
@ -998,18 +965,16 @@ static void asm_uref(ASMState *as, IRIns *ir)
MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
emit_lsptr(as, A64I_LDRx, dest, v);
} else {
Reg uv = ra_scratch(as, RSET_GPR);
Reg func = ra_alloc1(as, ir->op1, RSET_GPR);
if (ir->o == IR_UREFC) {
asm_guardcc(as, CC_NE);
emit_n(as, (A64I_CMPx^A64I_K12) | A64F_U12(1), RID_TMP);
emit_opk(as, A64I_ADDx, dest, uv,
asm_guardcnb(as, A64I_CBZ, RID_TMP);
emit_opk(as, A64I_ADDx, dest, dest,
(int32_t)offsetof(GCupval, tv), RSET_GPR);
emit_lso(as, A64I_LDRB, RID_TMP, uv, (int32_t)offsetof(GCupval, closed));
emit_lso(as, A64I_LDRB, RID_TMP, dest,
(int32_t)offsetof(GCupval, closed));
} else {
emit_lso(as, A64I_LDRx, dest, uv, (int32_t)offsetof(GCupval, v));
emit_lso(as, A64I_LDRx, dest, dest, (int32_t)offsetof(GCupval, v));
}
emit_lso(as, A64I_LDRx, uv, func,
emit_lso(as, A64I_LDRx, dest, ra_alloc1(as, ir->op1, RSET_GPR),
(int32_t)offsetof(GCfuncL, uvptr) + 8*(int32_t)(ir->op2 >> 8));
}
}
@ -1135,7 +1100,7 @@ static void asm_xstore(ASMState *as, IRIns *ir)
static void asm_ahuvload(ASMState *as, IRIns *ir)
{
Reg idx, tmp, type;
Reg idx, tmp;
int32_t ofs = 0;
RegSet gpr = RSET_GPR, allow = irt_isnum(ir->t) ? RSET_FPR : RSET_GPR;
lj_assertA(irt_isnum(ir->t) || irt_ispri(ir->t) || irt_isaddr(ir->t) ||
@ -1154,8 +1119,7 @@ static void asm_ahuvload(ASMState *as, IRIns *ir)
} else {
tmp = ra_scratch(as, gpr);
}
type = ra_scratch(as, rset_clear(gpr, tmp));
idx = asm_fuseahuref(as, ir->op1, &ofs, rset_clear(gpr, type), A64I_LDRx);
idx = asm_fuseahuref(as, ir->op1, &ofs, rset_clear(gpr, tmp), A64I_LDRx);
rset_clear(gpr, idx);
if (ofs & FUSE_REG) rset_clear(gpr, ofs & 31);
if (ir->o == IR_VLOAD) ofs += 8 * ir->op2;
@ -1167,8 +1131,8 @@ static void asm_ahuvload(ASMState *as, IRIns *ir)
emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32),
ra_allock(as, LJ_TISNUM << 15, gpr), tmp);
} else if (irt_isaddr(ir->t)) {
emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(ir->t)), type);
emit_dn(as, A64I_ASRx | A64F_IMMR(47), type, tmp);
emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(ir->t)), RID_TMP);
emit_dn(as, A64I_ASRx | A64F_IMMR(47), RID_TMP, tmp);
} else if (irt_isnil(ir->t)) {
emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(1), tmp);
} else {
@ -1291,9 +1255,8 @@ dotypecheck:
emit_nm(as, A64I_CMPx,
ra_allock(as, ~((int64_t)~irt_toitype(t) << 47) , allow), tmp);
} else {
Reg type = ra_scratch(as, allow);
emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(t)), type);
emit_dn(as, A64I_ASRx | A64F_IMMR(47), type, tmp);
emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(t)), RID_TMP);
emit_dn(as, A64I_ASRx | A64F_IMMR(47), RID_TMP, tmp);
}
emit_lso(as, A64I_LDRx, tmp, base, ofs);
return;
@ -1384,7 +1347,6 @@ static void asm_obar(ASMState *as, IRIns *ir)
const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv];
IRRef args[2];
MCLabel l_end;
RegSet allow = RSET_GPR;
Reg obj, val, tmp;
/* No need for other object barriers (yet). */
lj_assertA(IR(ir->op1)->o == IR_UREFC, "bad OBAR type");
@ -1395,14 +1357,13 @@ static void asm_obar(ASMState *as, IRIns *ir)
asm_gencall(as, ci, args);
emit_dm(as, A64I_MOVx, ra_releasetmp(as, ASMREF_TMP1), RID_GL);
obj = IR(ir->op1)->r;
tmp = ra_scratch(as, rset_exclude(allow, obj));
emit_cond_branch(as, CC_EQ, l_end);
emit_n(as, A64I_TSTw^emit_isk13(LJ_GC_BLACK, 0), tmp);
tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj));
emit_tnb(as, A64I_TBZ, tmp, lj_ffs(LJ_GC_BLACK), l_end);
emit_cond_branch(as, CC_EQ, l_end);
emit_n(as, A64I_TSTw^emit_isk13(LJ_GC_WHITES, 0), RID_TMP);
val = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, obj));
emit_lso(as, A64I_LDRB, tmp, obj,
(int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv));
(int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv));
emit_lso(as, A64I_LDRB, RID_TMP, val, (int32_t)offsetof(GChead, marked));
}
@ -1444,12 +1405,12 @@ static int asm_swapops(ASMState *as, IRRef lref, IRRef rref)
if (irref_isk(lref))
return 1; /* But swap constants to the right. */
ir = IR(rref);
if ((ir->o >= IR_BSHL && ir->o <= IR_BSAR) ||
if ((ir->o >= IR_BSHL && ir->o <= IR_BROR) ||
(ir->o == IR_ADD && ir->op1 == ir->op2) ||
(ir->o == IR_CONV && ir->op2 == ((IRT_I64<<IRCONV_DSH)|IRT_INT|IRCONV_SEXT)))
return 0; /* Don't swap fusable operands to the left. */
ir = IR(lref);
if ((ir->o >= IR_BSHL && ir->o <= IR_BSAR) ||
if ((ir->o >= IR_BSHL && ir->o <= IR_BROR) ||
(ir->o == IR_ADD && ir->op1 == ir->op2) ||
(ir->o == IR_CONV && ir->op2 == ((IRT_I64<<IRCONV_DSH)|IRT_INT|IRCONV_SEXT)))
return 1; /* But swap fusable operands to the right. */
@ -1500,8 +1461,7 @@ static void asm_intmul(ASMState *as, IRIns *ir)
if (irt_isguard(ir->t)) { /* IR_MULOV */
asm_guardcc(as, CC_NE);
emit_dm(as, A64I_MOVw, dest, dest); /* Zero-extend. */
emit_nm(as, A64I_CMPw | A64F_SH(A64SH_ASR, 31), RID_TMP, dest);
emit_dn(as, A64I_ASRx | A64F_IMMR(32), RID_TMP, dest);
emit_nm(as, A64I_CMPx | A64F_EX(A64EX_SXTW), dest, dest);
emit_dnm(as, A64I_SMULL, dest, right, left);
} else {
emit_dnm(as, irt_is64(ir->t) ? A64I_MULx : A64I_MULw, dest, left, right);
@ -1762,16 +1722,15 @@ static void asm_intcomp(ASMState *as, IRIns *ir)
if (asm_swapops(as, blref, brref)) {
Reg tmp = blref; blref = brref; brref = tmp;
}
bleft = ra_alloc1(as, blref, RSET_GPR);
if (irref_isk(brref)) {
uint64_t k = get_k64val(as, brref);
if (k && !(k & (k-1)) && (cc == CC_EQ || cc == CC_NE)) {
asm_guardtnb(as, cc == CC_EQ ? A64I_TBZ : A64I_TBNZ,
ra_alloc1(as, blref, RSET_GPR), emit_ctz64(k));
if (k && !(k & (k-1)) && (cc == CC_EQ || cc == CC_NE) &&
asm_guardtnb(as, cc == CC_EQ ? A64I_TBZ : A64I_TBNZ, bleft,
emit_ctz64(k)))
return;
}
m2 = emit_isk13(k, irt_is64(irl->t));
}
bleft = ra_alloc1(as, blref, RSET_GPR);
ai = (irt_is64(irl->t) ? A64I_TSTx : A64I_TSTw);
if (!m2)
m2 = asm_fuseopm(as, ai, brref, rset_exclude(RSET_GPR, bleft));
@ -1846,37 +1805,28 @@ static void asm_prof(ASMState *as, IRIns *ir)
static void asm_stack_check(ASMState *as, BCReg topslot,
IRIns *irp, RegSet allow, ExitNo exitno)
{
Reg pbase;
uint32_t k;
Reg pbase = RID_BASE;
if (irp) {
if (!ra_hasspill(irp->s)) {
pbase = irp->r;
lj_assertA(ra_hasreg(pbase), "base reg lost");
} else if (allow) {
pbase = rset_pickbot(allow);
} else {
pbase = RID_RET;
emit_lso(as, A64I_LDRx, RID_RET, RID_SP, 0); /* Restore temp register. */
}
} else {
pbase = RID_BASE;
pbase = irp->r;
if (!ra_hasreg(pbase))
pbase = allow ? (0x40 | rset_pickbot(allow)) : (0xC0 | RID_RET);
}
emit_cond_branch(as, CC_LS, asm_exitstub_addr(as, exitno));
if (pbase & 0x80) /* Restore temp. register. */
emit_lso(as, A64I_LDRx, (pbase & 31), RID_SP, 0);
k = emit_isk12((8*topslot));
lj_assertA(k, "slot offset %d does not fit in K12", 8*topslot);
emit_n(as, A64I_CMPx^k, RID_TMP);
emit_dnm(as, A64I_SUBx, RID_TMP, RID_TMP, pbase);
emit_dnm(as, A64I_SUBx, RID_TMP, RID_TMP, (pbase & 31));
emit_lso(as, A64I_LDRx, RID_TMP, RID_TMP,
(int32_t)offsetof(lua_State, maxstack));
if (irp) { /* Must not spill arbitrary registers in head of side trace. */
if (ra_hasspill(irp->s))
emit_lso(as, A64I_LDRx, pbase, RID_SP, sps_scale(irp->s));
emit_lso(as, A64I_LDRx, RID_TMP, RID_GL, glofs(as, &J2G(as->J)->cur_L));
if (ra_hasspill(irp->s) && !allow)
emit_lso(as, A64I_STRx, RID_RET, RID_SP, 0); /* Save temp register. */
} else {
emit_getgl(as, RID_TMP, cur_L);
if (pbase & 0x40) {
emit_getgl(as, (pbase & 31), jit_base);
if (pbase & 0x80) /* Save temp register. */
emit_lso(as, A64I_STRx, (pbase & 31), RID_SP, 0);
}
emit_getgl(as, RID_TMP, cur_L);
}
/* Restore Lua stack from on-trace state. */
@ -1918,7 +1868,7 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap)
/* Marker to prevent patching the GC check exit. */
#define ARM64_NOPATCH_GC_CHECK \
(A64I_ORRx|A64F_D(RID_TMP)|A64F_M(RID_TMP)|A64F_N(RID_TMP))
(A64I_ORRx|A64F_D(RID_ZERO)|A64F_M(RID_ZERO)|A64F_N(RID_ZERO))
/* Check GC threshold and do one or more GC steps. */
static void asm_gc_check(ASMState *as)
@ -1973,57 +1923,40 @@ static void asm_loop_tail_fixup(ASMState *as)
/* -- Head of trace ------------------------------------------------------- */
/* Reload L register from g->cur_L. */
static void asm_head_lreg(ASMState *as)
{
IRIns *ir = IR(ASMREF_L);
if (ra_used(ir)) {
Reg r = ra_dest(as, ir, RSET_GPR);
emit_getgl(as, r, cur_L);
ra_evictk(as);
}
}
/* Coalesce BASE register for a root trace. */
static void asm_head_root_base(ASMState *as)
{
IRIns *ir;
asm_head_lreg(as);
ir = IR(REF_BASE);
if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t)))
ra_spill(as, ir);
ra_destreg(as, ir, RID_BASE);
IRIns *ir = IR(REF_BASE);
Reg r = ir->r;
if (ra_hasreg(r)) {
ra_free(as, r);
if (rset_test(as->modset, r) || irt_ismarked(ir->t))
ir->r = RID_INIT; /* No inheritance for modified BASE register. */
if (r != RID_BASE)
emit_movrr(as, ir, r, RID_BASE);
}
}
/* Coalesce BASE register for a side trace. */
static Reg asm_head_side_base(ASMState *as, IRIns *irp)
{
IRIns *ir;
asm_head_lreg(as);
ir = IR(REF_BASE);
/* IRRefs that get into the side trace from the parent trace may restore
* REF_BASE under severe register pressure and thus reach here holding on to
* the register. Restore such references so that REF_BASE gets RID_BASE back
* when it tries to allocate below. */
if (!ra_hasreg(ir->r)) {
Reg r = ra_gethint(ir->r);
if (!rset_test(as->freeset, r))
ra_restore(as, regcost_ref(as->cost[r]));
}
if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t)))
ra_spill(as, ir);
if (ra_hasspill(irp->s)) {
return ra_dest(as, ir, RSET_GPR);
} else {
Reg r = irp->r;
lj_assertA(ra_hasreg(r), "base reg lost");
if (r != ir->r && !rset_test(as->freeset, r))
ra_restore(as, regcost_ref(as->cost[r]));
ra_destreg(as, ir, r);
return r;
IRIns *ir = IR(REF_BASE);
Reg r = ir->r;
if (ra_hasreg(r)) {
ra_free(as, r);
if (rset_test(as->modset, r) || irt_ismarked(ir->t))
ir->r = RID_INIT; /* No inheritance for modified BASE register. */
if (irp->r == r) {
return r; /* Same BASE register already coalesced. */
} else if (ra_hasreg(irp->r) && rset_test(as->freeset, irp->r)) {
/* Move from coalesced parent reg. */
emit_movrr(as, ir, r, irp->r);
return irp->r;
} else {
emit_getgl(as, r, jit_base); /* Otherwise reload BASE. */
}
}
return RID_NONE;
}
/* -- Tail of trace ------------------------------------------------------- */
@ -2075,6 +2008,9 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci)
int ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR;
int spofs = 0, spalign = LJ_TARGET_OSX ? 0 : 7, nslots;
asm_collectargs(as, ir, ci, args);
#if LJ_ABI_WIN
if ((ci->flags & CCI_VARARG)) nfpr = 0;
#endif
for (i = 0; i < nargs; i++) {
int al = spalign;
if (!args[i]) {
@ -2086,7 +2022,9 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci)
#endif
} else if (irt_isfp(IR(args[i])->t)) {
if (nfpr > 0) { nfpr--; continue; }
#if LJ_TARGET_OSX
#if LJ_ABI_WIN
if ((ci->flags & CCI_VARARG) && ngpr > 0) { ngpr--; continue; }
#elif LJ_TARGET_OSX
al |= irt_isnum(IR(args[i])->t) ? 7 : 3;
#endif
} else {

View file

@ -140,7 +140,8 @@ static IRRef asm_fuseabase(ASMState *as, IRRef ref)
}
} else if (irb->o == IR_ADD && irref_isk(irb->op2)) {
/* Fuse base offset (vararg load). */
as->mrm.ofs = IR(irb->op2)->i;
IRIns *irk = IR(irb->op2);
as->mrm.ofs = irk->o == IR_KINT ? irk->i : (int32_t)ir_kint64(irk)->u64;
return irb->op1;
}
return ref; /* Otherwise use the given array base. */

View file

@ -1141,6 +1141,14 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
fid = ctf->sib;
}
#if LJ_TARGET_ARM64 && LJ_ABI_WIN
if ((ct->info & CTF_VARARG)) {
nsp -= maxgpr * CTSIZE_PTR; /* May end up with negative nsp. */
ngpr = maxgpr;
nfpr = CCALL_NARG_FPR;
}
#endif
/* Walk through all passed arguments. */
for (o = L->base+1, narg = 1; o < top; o++, narg++) {
CTypeID did;
@ -1201,9 +1209,14 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
align = CTSIZE_PTR-1;
nsp = (nsp + align) & ~align;
}
#if LJ_TARGET_ARM64 && LJ_ABI_WIN
/* A negative nsp points into cc->gpr. Blame MS for their messy ABI. */
dp = ((uint8_t *)cc->stack) + (int32_t)nsp;
#else
dp = ((uint8_t *)cc->stack) + nsp;
#endif
nsp += CCALL_PACK_STACKARG ? sz : n * CTSIZE_PTR;
if (nsp > CCALL_SIZE_STACK) { /* Too many arguments. */
if ((int32_t)nsp > CCALL_SIZE_STACK) { /* Too many arguments. */
err_nyi:
lj_err_caller(L, LJ_ERR_FFI_NYICALL);
}
@ -1314,6 +1327,9 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
#endif
}
if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */
#if LJ_TARGET_ARM64 && LJ_ABI_WIN
if ((int32_t)nsp < 0) nsp = 0;
#endif
#if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP)
cc->nfpr = nfpr; /* Required for vararg functions. */

View file

@ -1118,12 +1118,8 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd,
ngpr = 1;
else if (ctype_cconv(ct->info) == CTCC_FASTCALL)
ngpr = 2;
#elif LJ_TARGET_ARM64
#if LJ_ABI_WIN
#error "NYI: ARM64 Windows ABI calling conventions"
#elif LJ_TARGET_OSX
#elif LJ_TARGET_ARM64 && LJ_TARGET_OSX
int ngpr = CCALL_NARG_GPR;
#endif
#endif
/* Skip initial attributes. */

View file

@ -69,7 +69,7 @@ typedef unsigned int uintptr_t;
#define LJ_MAX_UPVAL 120 /* Max. # of upvalues. */
#define LJ_MAX_IDXCHAIN 100 /* __index/__newindex chain limit. */
#define LJ_STACK_EXTRA (5+2*LJ_FR2) /* Extra stack space (metamethods). */
#define LJ_STACK_EXTRA (5+3*LJ_FR2) /* Extra stack space (metamethods). */
#if defined(__powerpc64__) && _CALL_ELF != 2
#define LJ_NUM_CBPAGE 4 /* Number of FFI callback pages. */
@ -154,15 +154,9 @@ typedef uintptr_t BloomFilter;
#define LJ_UNLIKELY(x) __builtin_expect(!!(x), 0)
#define lj_ffs(x) ((uint32_t)__builtin_ctz(x))
/* Don't ask ... */
#if defined(__INTEL_COMPILER) && (defined(__i386__) || defined(__x86_64__))
static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
uint32_t r; __asm__("bsrl %1, %0" : "=r" (r) : "rm" (x) : "cc"); return r;
}
#else
#define lj_fls(x) ((uint32_t)(__builtin_clz(x)^31))
#endif
#define lj_ffs64(x) ((uint32_t)__builtin_ctzll(x))
#define lj_fls64(x) ((uint32_t)(__builtin_clzll(x)^63))
#if defined(__arm__)
static LJ_AINLINE uint32_t lj_bswap(uint32_t x)
@ -273,8 +267,12 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x)
#else
unsigned char _BitScanForward(unsigned long *, unsigned long);
unsigned char _BitScanReverse(unsigned long *, unsigned long);
unsigned char _BitScanForward64(unsigned long *, uint64_t);
unsigned char _BitScanReverse64(unsigned long *, uint64_t);
#pragma intrinsic(_BitScanForward)
#pragma intrinsic(_BitScanReverse)
#pragma intrinsic(_BitScanForward64)
#pragma intrinsic(_BitScanReverse64)
static LJ_AINLINE uint32_t lj_ffs(uint32_t x)
{
@ -285,6 +283,16 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x)
{
unsigned long r; _BitScanReverse(&r, x); return (uint32_t)r;
}
static LJ_AINLINE uint32_t lj_ffs64(uint64_t x)
{
unsigned long r; _BitScanForward64(&r, x); return (uint32_t)r;
}
static LJ_AINLINE uint32_t lj_fls64(uint64_t x)
{
unsigned long r; _BitScanReverse64(&r, x); return (uint32_t)r;
}
#endif
unsigned long _byteswap_ulong(unsigned long);

View file

@ -453,7 +453,7 @@ static int call_init(lua_State *L, GCfunc *fn)
int numparams = pt->numparams;
int gotparams = (int)(L->top - L->base);
int need = pt->framesize;
if ((pt->flags & PROTO_VARARG)) need += 1+gotparams;
if ((pt->flags & PROTO_VARARG)) need += 1+LJ_FR2+gotparams;
lj_state_checkstack(L, (MSize)need);
numparams -= gotparams;
return numparams >= 0 ? numparams : 0;

View file

@ -20,7 +20,7 @@ static uint64_t get_k64val(ASMState *as, IRRef ref)
} else {
lj_assertA(ir->o == IR_KINT || ir->o == IR_KNULL,
"bad 64 bit const IR op %d", ir->o);
return ir->i; /* Sign-extended. */
return (uint32_t)ir->i; /* Zero-extended. */
}
}
@ -30,39 +30,31 @@ static uint32_t emit_isk12(int64_t n)
uint64_t k = n < 0 ? ~(uint64_t)n+1u : (uint64_t)n;
uint32_t m = n < 0 ? 0x40000000 : 0;
if (k < 0x1000) {
return A64I_K12|m|A64F_U12(k);
return (uint32_t)(A64I_K12|m|A64F_U12(k));
} else if ((k & 0xfff000) == k) {
return A64I_K12|m|0x400000|A64F_U12(k>>12);
return (uint32_t)(A64I_K12|m|0x400000|A64F_U12(k>>12));
}
return 0;
}
#define emit_clz64(n) __builtin_clzll(n)
#define emit_ctz64(n) __builtin_ctzll(n)
#define emit_clz64(n) (lj_fls64(n)^63)
#define emit_ctz64(n) lj_ffs64(n)
/* Encode constant in K13 format for logical data processing instructions. */
static uint32_t emit_isk13(uint64_t n, int is64)
{
int inv = 0, w = 128, lz, tz;
if (n & 1) { n = ~n; w = 64; inv = 1; } /* Avoid wrap-around of ones. */
if (!n) return 0; /* Neither all-zero nor all-ones are allowed. */
do { /* Find the repeat width. */
if (is64 && (uint32_t)(n^(n>>32))) break;
n = (uint32_t)n;
if (!n) return 0; /* Ditto when passing n=0xffffffff and is64=0. */
w = 32; if ((n^(n>>16)) & 0xffff) break;
n = n & 0xffff; w = 16; if ((n^(n>>8)) & 0xff) break;
n = n & 0xff; w = 8; if ((n^(n>>4)) & 0xf) break;
n = n & 0xf; w = 4; if ((n^(n>>2)) & 0x3) break;
n = n & 0x3; w = 2;
} while (0);
lz = emit_clz64(n);
tz = emit_ctz64(n);
if ((int64_t)(n << lz) >> (lz+tz) != -1ll) return 0; /* Non-contiguous? */
if (inv)
return A64I_K13 | (((lz-w) & 127) << 16) | (((lz+tz-w-1) & 63) << 10);
else
return A64I_K13 | ((w-tz) << 16) | (((63-lz-tz-w-w) & 63) << 10);
/* Thanks to: https://dougallj.wordpress.com/2021/10/30/ */
int rot, ones, size, immr, imms;
if (!is64) n = ((uint64_t)n << 32) | (uint32_t)n;
if ((n+1u) <= 1u) return 0; /* Neither all-zero nor all-ones are allowed. */
rot = (n & (n+1u)) ? emit_ctz64(n & (n+1u)) : 64;
n = lj_ror(n, rot & 63);
ones = emit_ctz64(~n);
size = emit_clz64(n) + ones;
if (lj_ror(n, size & 63) != n) return 0; /* Non-repeating? */
immr = -rot & (size - 1);
imms = (-(size << 1) | (ones - 1)) & 63;
return A64I_K13 | A64F_IMMR(immr | (size & 64)) | A64F_IMMS(imms);
}
static uint32_t emit_isfpk64(uint64_t n)
@ -121,9 +113,20 @@ static int emit_checkofs(A64Ins ai, int64_t ofs)
}
}
static void emit_lso(ASMState *as, A64Ins ai, Reg rd, Reg rn, int64_t ofs)
static LJ_AINLINE uint32_t emit_lso_pair_candidate(A64Ins ai, int ofs, int sc)
{
int ot = emit_checkofs(ai, ofs), sc = (ai >> 30) & 3;
if (ofs >= 0) {
return ai | A64F_U12(ofs>>sc); /* Subsequent lj_ror checks ofs. */
} else if (ofs >= -256) {
return (ai^A64I_LS_U) | A64F_S9(ofs & 0x1ff);
} else {
return A64F_D(31); /* Will mismatch prev. */
}
}
static void emit_lso(ASMState *as, A64Ins ai, Reg rd, Reg rn, int64_t ofs64)
{
int ot = emit_checkofs(ai, ofs64), sc = (ai >> 30) & 3, ofs = (int)ofs64;
lj_assertA(ot, "load/store offset %d out of range", ofs);
/* Combine LDR/STR pairs to LDP/STP. */
if ((sc == 2 || sc == 3) &&
@ -132,11 +135,9 @@ static void emit_lso(ASMState *as, A64Ins ai, Reg rd, Reg rn, int64_t ofs)
uint32_t prev = *as->mcp & ~A64F_D(31);
int ofsm = ofs - (1<<sc), ofsp = ofs + (1<<sc);
A64Ins aip;
if (prev == (ai | A64F_N(rn) | A64F_U12(ofsm>>sc)) ||
prev == ((ai^A64I_LS_U) | A64F_N(rn) | A64F_S9(ofsm&0x1ff))) {
if (prev == emit_lso_pair_candidate(ai | A64F_N(rn), ofsm, sc)) {
aip = (A64F_A(rd) | A64F_D(*as->mcp & 31));
} else if (prev == (ai | A64F_N(rn) | A64F_U12(ofsp>>sc)) ||
prev == ((ai^A64I_LS_U) | A64F_N(rn) | A64F_S9(ofsp&0x1ff))) {
} else if (prev == emit_lso_pair_candidate(ai | A64F_N(rn), ofsp, sc)) {
aip = (A64F_D(rd) | A64F_A(*as->mcp & 31));
ofsm = ofs;
} else {
@ -158,13 +159,12 @@ nopair:
/* -- Emit loads/stores --------------------------------------------------- */
/* Prefer rematerialization of BASE/L from global_State over spills. */
#define emit_canremat(ref) ((ref) <= ASMREF_L)
#define emit_canremat(ref) ((ref) <= REF_BASE)
/* Try to find an N-step delta relative to other consts with N < lim. */
static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim)
/* Try to find a one-step delta relative to other consts. */
static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int is64)
{
RegSet work = (~as->freeset & RSET_GPR) | RID2RSET(RID_GL);
if (lim <= 1) return 0; /* Can't beat that. */
while (work) {
Reg r = rset_picktop(work);
IRRef ref = regcost_ref(as->cost[r]);
@ -173,13 +173,14 @@ static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim)
uint64_t kx = ra_iskref(ref) ? (uint64_t)ra_krefk(as, ref) :
get_k64val(as, ref);
int64_t delta = (int64_t)(k - kx);
if (!is64) delta = (int64_t)(int32_t)delta; /* Sign-extend. */
if (delta == 0) {
emit_dm(as, A64I_MOVx, rd, r);
emit_dm(as, is64|A64I_MOVw, rd, r);
return 1;
} else {
uint32_t k12 = emit_isk12(delta < 0 ? (int64_t)(~(uint64_t)delta+1u) : delta);
if (k12) {
emit_dn(as, (delta < 0 ? A64I_SUBx : A64I_ADDx)^k12, rd, r);
emit_dn(as, (delta < 0 ? A64I_SUBw : A64I_ADDw)^is64^k12, rd, r);
return 1;
}
/* Do other ops or multi-step deltas pay off? Probably not.
@ -192,53 +193,52 @@ static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim)
return 0; /* Failed. */
}
static void emit_loadk(ASMState *as, Reg rd, uint64_t u64, int is64)
static void emit_loadk(ASMState *as, Reg rd, uint64_t u64)
{
int i, zeros = 0, ones = 0, neg;
if (!is64) u64 = (int64_t)(int32_t)u64; /* Sign-extend. */
/* Count homogeneous 16 bit fragments. */
for (i = 0; i < 4; i++) {
uint64_t frag = (u64 >> i*16) & 0xffff;
zeros += (frag == 0);
ones += (frag == 0xffff);
int zeros = 0, ones = 0, neg, lshift = 0;
int is64 = (u64 >> 32) ? A64I_X : 0, i = is64 ? 4 : 2;
/* Count non-homogeneous 16 bit fragments. */
while (--i >= 0) {
uint32_t frag = (u64 >> i*16) & 0xffff;
zeros += (frag != 0);
ones += (frag != 0xffff);
}
neg = ones > zeros; /* Use MOVN if it pays off. */
if ((neg ? ones : zeros) < 3) { /* Need 2+ ins. Try shorter K13 encoding. */
neg = ones < zeros; /* Use MOVN if it pays off. */
if ((neg ? ones : zeros) > 1) { /* Need 2+ ins. Try 1 ins encodings. */
uint32_t k13 = emit_isk13(u64, is64);
if (k13) {
emit_dn(as, (is64|A64I_ORRw)^k13, rd, RID_ZERO);
return;
}
}
if (!emit_kdelta(as, rd, u64, 4 - (neg ? ones : zeros))) {
int shift = 0, lshift = 0;
uint64_t n64 = neg ? ~u64 : u64;
if (n64 != 0) {
/* Find first/last fragment to be filled. */
shift = (63-emit_clz64(n64)) & ~15;
lshift = emit_ctz64(n64) & ~15;
if (emit_kdelta(as, rd, u64, is64)) {
return;
}
/* MOVK requires the original value (u64). */
while (shift > lshift) {
uint32_t u16 = (u64 >> shift) & 0xffff;
/* Skip fragments that are correctly filled by MOVN/MOVZ. */
if (u16 != (neg ? 0xffff : 0))
emit_d(as, is64 | A64I_MOVKw | A64F_U16(u16) | A64F_LSL16(shift), rd);
shift -= 16;
}
/* But MOVN needs an inverted value (n64). */
emit_d(as, (neg ? A64I_MOVNx : A64I_MOVZx) |
A64F_U16((n64 >> lshift) & 0xffff) | A64F_LSL16(lshift), rd);
}
if (neg) {
u64 = ~u64;
if (!is64) u64 = (uint32_t)u64;
}
if (u64) {
/* Find first/last fragment to be filled. */
int shift = (63-emit_clz64(u64)) & ~15;
lshift = emit_ctz64(u64) & ~15;
for (; shift > lshift; shift -= 16) {
uint32_t frag = (u64 >> shift) & 0xffff;
if (frag == 0) continue; /* Will be correctly filled by MOVN/MOVZ. */
if (neg) frag ^= 0xffff; /* MOVK requires the original value. */
emit_d(as, is64 | A64I_MOVKw | A64F_U16(frag) | A64F_LSL16(shift), rd);
}
}
/* But MOVN needs an inverted value. */
emit_d(as, is64 | (neg ? A64I_MOVNw : A64I_MOVZw) |
A64F_U16((u64 >> lshift) & 0xffff) | A64F_LSL16(lshift), rd);
}
/* Load a 32 bit constant into a GPR. */
#define emit_loadi(as, rd, i) emit_loadk(as, rd, i, 0)
#define emit_loadi(as, rd, i) emit_loadk(as, rd, (uint32_t)i)
/* Load a 64 bit constant into a GPR. */
#define emit_loadu64(as, rd, i) emit_loadk(as, rd, i, A64I_X)
#define emit_loada(as, r, addr) emit_loadu64(as, (r), (uintptr_t)(addr))
#define emit_loadu64(as, rd, i) emit_loadk(as, rd, i)
#define glofs(as, k) \
((intptr_t)((uintptr_t)(k) - (uintptr_t)&J2GG(as->J)->g))
@ -252,19 +252,20 @@ static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow);
/* Get/set from constant pointer. */
static void emit_lsptr(ASMState *as, A64Ins ai, Reg r, void *p)
{
/* First, check if ip + offset is in range. */
if ((ai & 0x00400000) && checkmcpofs(as, p)) {
Reg base = RID_GL;
int64_t ofs = glofs(as, p);
if (emit_checkofs(ai, ofs)) {
/* GL + offset, might subsequently fuse to LDP/STP. */
} else if (ai == A64I_LDRx && checkmcpofs(as, p)) {
/* IP + offset is cheaper than allock, but address must be in range. */
emit_d(as, A64I_LDRLx | A64F_S19(mcpofs(as, p)>>2), r);
} else {
Reg base = RID_GL; /* Next, try GL + offset. */
int64_t ofs = glofs(as, p);
if (!emit_checkofs(ai, ofs)) { /* Else split up into base reg + offset. */
int64_t i64 = i64ptr(p);
base = ra_allock(as, (i64 & ~0x7fffull), rset_exclude(RSET_GPR, r));
ofs = i64 & 0x7fffull;
}
emit_lso(as, ai, r, base, ofs);
return;
} else { /* Split up into base reg + offset. */
int64_t i64 = i64ptr(p);
base = ra_allock(as, (i64 & ~0x7fffull), rset_exclude(RSET_GPR, r));
ofs = i64 & 0x7fffull;
}
emit_lso(as, ai, r, base, ofs);
}
/* Load 64 bit IR constant into register. */

View file

@ -174,12 +174,15 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
case FRAME_PCALL: /* FF pcall() frame. */
case FRAME_PCALLH: /* FF pcall() frame inside hook. */
if (errcode) {
global_State *g;
if (errcode == LUA_YIELD) {
frame = frame_prevd(frame);
break;
}
g = G(L);
setgcref(g->cur_L, obj2gco(L));
if (frame_typep(frame) == FRAME_PCALL)
hook_leave(G(L));
hook_leave(g);
L->base = frame_prevd(frame) + 1;
L->cframe = cf;
unwindstack(L, L->base);
@ -209,11 +212,6 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
** from 3rd party docs or must be found by trial-and-error. They really
** don't want you to write your own language-specific exception handler
** or to interact gracefully with MSVC. :-(
**
** Apparently MSVC doesn't call C++ destructors for foreign exceptions
** unless you compile your C++ code with /EHa. Unfortunately this means
** catch (...) also catches things like access violations. The use of
** _set_se_translator doesn't really help, because it requires /EHa, too.
*/
#define WIN32_LEAN_AND_MEAN
@ -261,6 +259,8 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
{
#if LJ_TARGET_X86
void *cf = (char *)f - CFRAME_OFS_SEH;
#elif LJ_TARGET_ARM64
void *cf = (char *)f - CFRAME_SIZE;
#else
void *cf = f;
#endif
@ -268,11 +268,25 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
if (rec->ExceptionCode == STATUS_LONGJUMP &&
rec->ExceptionRecord &&
LJ_EXCODE_CHECK(rec->ExceptionRecord->ExceptionCode)) {
errcode = LJ_EXCODE_ERRCODE(rec->ExceptionRecord->ExceptionCode);
if ((rec->ExceptionFlags & 0x20)) { /* EH_TARGET_UNWIND */
/* Unwinding is about to finish; revert the ExceptionCode so that
** RtlRestoreContext does not try to restore from a _JUMP_BUFFER.
*/
rec->ExceptionCode = 0;
}
}
/* Unwind internal frames. */
err_unwind(L, cf, errcode);
} else {
void *cf2 = err_unwind(L, cf, 0);
if (cf2) { /* We catch it, so start unwinding the upper frames. */
#if !LJ_TARGET_X86
EXCEPTION_RECORD rec2;
#endif
if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
rec->ExceptionCode == LJ_GCC_EXCODE) {
#if !LJ_TARGET_CYGWIN
@ -295,14 +309,29 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
(void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
/* lj_vm_rtlunwind does not return. */
#else
if (LJ_EXCODE_CHECK(rec->ExceptionCode)) {
/* For unwind purposes, wrap the EXCEPTION_RECORD in something that
** looks like a longjmp, so that MSVC will execute C++ destructors in
** the frames we unwind over. ExceptionInformation[0] should really
** contain a _JUMP_BUFFER*, but hopefully nobody is looking too closely
** at this point.
*/
rec2.ExceptionCode = STATUS_LONGJUMP;
rec2.ExceptionRecord = rec;
rec2.ExceptionAddress = 0;
rec2.NumberParameters = 1;
rec2.ExceptionInformation[0] = (ULONG_PTR)ctx;
rec = &rec2;
}
/* Unwind the stack and call all handlers for all lower C frames
** (including ourselves) again with EH_UNWINDING set. Then set
** stack pointer = cf, result = errcode and jump to the specified target.
** stack pointer = f, result = errcode and jump to the specified target.
*/
RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
lj_vm_unwind_ff_eh :
lj_vm_unwind_c_eh),
rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable);
RtlUnwindEx(f, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
lj_vm_unwind_ff_eh :
lj_vm_unwind_c_eh),
rec, (void *)(uintptr_t)errcode, dispatch->ContextRecord,
dispatch->HistoryTable);
/* RtlUnwindEx should never return. */
#endif
}

View file

@ -1131,7 +1131,7 @@ static TRef recff_sbufx_check(jit_State *J, RecordFFData *rd, ptrdiff_t arg)
/* Emit BUFHDR for write to extended string buffer. */
static TRef recff_sbufx_write(jit_State *J, TRef ud)
{
TRef trbuf = emitir(IRT(IR_ADD, IRT_PGC), ud, lj_ir_kint(J, sizeof(GCudata)));
TRef trbuf = emitir(IRT(IR_ADD, IRT_PGC), ud, lj_ir_kintpgc(J, sizeof(GCudata)));
return emitir(IRT(IR_BUFHDR, IRT_PGC), trbuf, IRBUFHDR_WRITE);
}
@ -1165,20 +1165,19 @@ static void LJ_FASTCALL recff_buffer_method_reset(jit_State *J, RecordFFData *rd
SBufExt *sbx = bufV(&rd->argv[0]);
int iscow = (int)sbufiscow(sbx);
TRef trl = recff_sbufx_get_L(J, ud);
TRef trcow = emitir(IRT(IR_BAND, IRT_IGC), trl, lj_ir_kint(J, SBUF_FLAG_COW));
TRef zero = lj_ir_kint(J, 0);
emitir(IRTG(iscow ? IR_NE : IR_EQ, IRT_IGC), trcow, zero);
TRef trcow = emitir(IRT(IR_BAND, IRT_IGC), trl, lj_ir_kintpgc(J, SBUF_FLAG_COW));
TRef zeropgc = lj_ir_kintpgc(J, 0);
emitir(IRTG(iscow ? IR_NE : IR_EQ, IRT_IGC), trcow, zeropgc);
if (iscow) {
trl = emitir(IRT(IR_BXOR, IRT_IGC), trl,
LJ_GC64 ? lj_ir_kint64(J, SBUF_FLAG_COW) :
lj_ir_kint(J, SBUF_FLAG_COW));
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, zero);
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_E, zero);
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_B, zero);
TRef zerop = lj_ir_kintp(J, 0);
trl = emitir(IRT(IR_BXOR, IRT_IGC), trl, lj_ir_kintpgc(J, SBUF_FLAG_COW));
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, zerop);
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_E, zerop);
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_B, zerop);
recff_sbufx_set_L(J, ud, trl);
emitir(IRT(IR_FSTORE, IRT_PGC),
emitir(IRT(IR_FREF, IRT_PGC), ud, IRFL_SBUF_REF), zero);
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, zero);
emitir(IRT(IR_FREF, IRT_PGC), ud, IRFL_SBUF_REF), zeropgc);
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, zerop);
} else {
TRef trb = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_B);
recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, trb);

View file

@ -76,8 +76,8 @@
\
_(ABS, N , ref, ref) \
_(LDEXP, N , ref, ref) \
_(MIN, C , ref, ref) \
_(MAX, C , ref, ref) \
_(MIN, N , ref, ref) \
_(MAX, N , ref, ref) \
_(FPMATH, N , ref, lit) \
\
/* Overflow-checking arithmetic ops. */ \

View file

@ -63,7 +63,7 @@ typedef struct CCallInfo {
/* Helpers for conditional function definitions. */
#define IRCALLCOND_ANY(x) x
#if LJ_TARGET_X86ORX64
#if LJ_TARGET_X86ORX64 || LJ_TARGET_ARM64
#define IRCALLCOND_FPMATH(x) NULL
#else
#define IRCALLCOND_FPMATH(x) x

View file

@ -56,6 +56,12 @@ LJ_FUNC TRef lj_ir_ktrace(jit_State *J);
#define lj_ir_kintp(J, k) lj_ir_kint(J, (int32_t)(k))
#endif
#if LJ_GC64
#define lj_ir_kintpgc lj_ir_kintp
#else
#define lj_ir_kintpgc lj_ir_kint
#endif
static LJ_AINLINE TRef lj_ir_knum(jit_State *J, lua_Number n)
{
TValue tv;

View file

@ -29,6 +29,11 @@
#include <valgrind/valgrind.h>
#endif
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#if LJ_TARGET_IOS
void sys_icache_invalidate(void *start, size_t len);
#endif
@ -41,6 +46,8 @@ void lj_mcode_sync(void *start, void *end)
#endif
#if LJ_TARGET_X86ORX64
UNUSED(start); UNUSED(end);
#elif LJ_TARGET_WINDOWS
FlushInstructionCache(GetCurrentProcess(), start, (char *)end-(char *)start);
#elif LJ_TARGET_IOS
sys_icache_invalidate(start, (char *)end-(char *)start);
#elif LJ_TARGET_PPC
@ -58,9 +65,6 @@ void lj_mcode_sync(void *start, void *end)
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define MCPROT_RW PAGE_READWRITE
#define MCPROT_RX PAGE_EXECUTE_READ
#define MCPROT_RWX PAGE_EXECUTE_READWRITE
@ -363,7 +367,7 @@ void lj_mcode_limiterr(jit_State *J, size_t need)
sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10;
sizemcode = (sizemcode + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1);
maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10;
if ((size_t)need > sizemcode)
if (need * sizeof(MCode) > sizemcode)
lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */
if (J->szallmcarea + sizemcode > maxmcode)
lj_trace_err(J, LJ_TRERR_MCODEAL);

View file

@ -44,12 +44,12 @@ static void dce_propagate(jit_State *J)
IRIns *ir = IR(ins);
if (irt_ismarked(ir->t)) {
irt_clearmark(ir->t);
pchain[ir->o] = &ir->prev;
} else if (!ir_sideeff(ir)) {
*pchain[ir->o] = ir->prev; /* Reroute original instruction chain. */
lj_ir_nop(ir);
continue;
}
pchain[ir->o] = &ir->prev;
if (ir->op1 >= REF_FIRST) irt_setmark(IR(ir->op1)->t);
if (ir->op2 >= REF_FIRST) irt_setmark(IR(ir->op2)->t);
}

View file

@ -377,10 +377,10 @@ static uint64_t kfold_int64arith(jit_State *J, uint64_t k1, uint64_t k2,
case IR_BOR: k1 |= k2; break;
case IR_BXOR: k1 ^= k2; break;
case IR_BSHL: k1 <<= (k2 & 63); break;
case IR_BSHR: k1 = (int32_t)((uint32_t)k1 >> (k2 & 63)); break;
case IR_BSAR: k1 >>= (k2 & 63); break;
case IR_BROL: k1 = (int32_t)lj_rol((uint32_t)k1, (k2 & 63)); break;
case IR_BROR: k1 = (int32_t)lj_ror((uint32_t)k1, (k2 & 63)); break;
case IR_BSHR: k1 >>= (k2 & 63); break;
case IR_BSAR: k1 = (uint64_t)((int64_t)k1 >> (k2 & 63)); break;
case IR_BROL: k1 = lj_rol(k1, (k2 & 63)); break;
case IR_BROR: k1 = lj_ror(k1, (k2 & 63)); break;
default: lj_assertJ(0, "bad IR op %d", op); break;
}
#else
@ -1972,7 +1972,10 @@ LJFOLD(NE any any)
LJFOLDF(comm_equal)
{
/* For non-numbers only: x == x ==> drop; x ~= x ==> fail */
if (fins->op1 == fins->op2 && !irt_isnum(fins->t))
if (fins->op1 == fins->op2 &&
(!irt_isnum(fins->t) ||
(fleft->o == IR_CONV && /* Converted integers cannot be NaN. */
(uint32_t)(fleft->op2 & IRCONV_SRCMASK) - (uint32_t)IRT_I8 <= (uint32_t)(IRT_U64 - IRT_U8))))
return CONDFOLD(fins->o == IR_EQ);
return fold_comm_swap(J);
}

View file

@ -1599,10 +1599,16 @@ TRef lj_record_idx(jit_State *J, RecordIndex *ix)
lj_assertJ(!hasmm, "inconsistent metamethod handling");
if (oldv == niltvg(J2G(J))) { /* Need to insert a new key. */
TRef key = ix->key;
if (tref_isinteger(key)) /* NEWREF needs a TValue as a key. */
if (tref_isinteger(key)) { /* NEWREF needs a TValue as a key. */
key = emitir(IRTN(IR_CONV), key, IRCONV_NUM_INT);
else if (tref_isnumber(key) && tref_isk(key) && tvismzero(&ix->keyv))
key = lj_ir_knum_zero(J); /* Canonicalize -0.0 to +0.0. */
} else if (tref_isnum(key)) {
if (tref_isk(key)) {
if (tvismzero(&ix->keyv))
key = lj_ir_knum_zero(J); /* Canonicalize -0.0 to +0.0. */
} else {
emitir(IRTG(IR_EQ, IRT_NUM), key, key); /* Check for !NaN. */
}
}
xref = emitir(IRT(IR_NEWREF, IRT_PGC), ix->tab, key);
keybarrier = 0; /* NEWREF already takes care of the key barrier. */
#ifdef LUAJIT_ENABLE_TABLE_BUMP
@ -1775,7 +1781,7 @@ noconstify:
emitir(IRTG(IR_EQ, IRT_PGC),
REF_BASE,
emitir(IRT(IR_ADD, IRT_PGC), uref,
lj_ir_kint(J, (slot - 1 - LJ_FR2) * -8)));
lj_ir_kintpgc(J, (slot - 1 - LJ_FR2) * -8)));
slot -= (int32_t)J->baseslot; /* Note: slot number may be negative! */
if (val == 0) {
return getslot(J, slot);
@ -1788,7 +1794,7 @@ noconstify:
}
emitir(IRTG(IR_UGT, IRT_PGC),
emitir(IRT(IR_SUB, IRT_PGC), uref, REF_BASE),
lj_ir_kint(J, (J->baseslot + J->maxslot) * 8));
lj_ir_kintpgc(J, (J->baseslot + J->maxslot) * 8));
} else {
needbarrier = 1;
uref = tref_ref(emitir(IRTG(IR_UREFC, IRT_PGC), fn, uv));
@ -1966,7 +1972,8 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults)
emitir(IRTGI(IR_EQ), fr,
lj_ir_kint(J, (int32_t)frame_ftsz(J->L->base-1)));
vbase = emitir(IRT(IR_SUB, IRT_IGC), REF_BASE, fr);
vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase, lj_ir_kint(J, frofs-8*(1+LJ_FR2)));
vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase,
lj_ir_kintpgc(J, frofs-8*(1+LJ_FR2)));
for (i = 0; i < nload; i++) {
IRType t = itype2irt(&J->L->base[i-1-LJ_FR2-nvararg]);
J->base[dst+i] = lj_record_vload(J, vbase, (MSize)i, t);
@ -1985,8 +1992,11 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults)
TRef tr = TREF_NIL;
ptrdiff_t idx = lj_ffrecord_select_mode(J, tridx, &J->L->base[dst-1]);
if (idx < 0) goto nyivarg;
if (idx != 0 && !tref_isinteger(tridx))
if (idx != 0 && !tref_isinteger(tridx)) {
if (tref_isstr(tridx))
tridx = emitir(IRTG(IR_STRTO, IRT_NUM), tridx, 0);
tridx = emitir(IRTGI(IR_CONV), tridx, IRCONV_INT_NUM|IRCONV_INDEX);
}
if (idx != 0 && tref_isk(tridx)) {
emitir(IRTGI(idx <= nvararg ? IR_GE : IR_LT),
fr, lj_ir_kint(J, frofs+8*(int32_t)idx));
@ -2014,7 +2024,7 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults)
IRType t;
TRef aref, vbase = emitir(IRT(IR_SUB, IRT_IGC), REF_BASE, fr);
vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase,
lj_ir_kint(J, frofs-(8<<LJ_FR2)));
lj_ir_kintpgc(J, frofs-(8<<LJ_FR2)));
t = itype2irt(&J->L->base[idx-2-LJ_FR2-nvararg]);
aref = emitir(IRT(IR_AREF, IRT_PGC), vbase, tridx);
tr = lj_record_vload(J, aref, 0, t);

View file

@ -103,8 +103,17 @@ void lj_state_shrinkstack(lua_State *L, MSize used)
void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need)
{
MSize n;
if (L->stacksize > LJ_STACK_MAXEX) /* Overflow while handling overflow? */
lj_err_throw(L, LUA_ERRERR);
if (L->stacksize >= LJ_STACK_MAXEX) {
/* 4. Throw 'error in error handling' when we are _over_ the limit. */
if (L->stacksize > LJ_STACK_MAXEX)
lj_err_throw(L, LUA_ERRERR); /* Does not invoke an error handler. */
/* 1. We are _at_ the limit after the last growth. */
if (L->status < LUA_ERRRUN) { /* 2. Throw 'stack overflow'. */
L->status = LUA_ERRRUN; /* Prevent ending here again for pushed msg. */
lj_err_msg(L, LJ_ERR_STKOV); /* May invoke an error handler. */
}
/* 3. Add space (over the limit) for pushed message and error handler. */
}
n = L->stacksize + need;
if (n > LJ_STACK_MAX) {
n += 2*LUA_MINSTACK;
@ -114,8 +123,6 @@ void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need)
n = LJ_STACK_MAX;
}
resizestack(L, n);
if (L->stacksize >= LJ_STACK_MAXEX)
lj_err_msg(L, LJ_ERR_STKOV);
}
void LJ_FASTCALL lj_state_growstack1(lua_State *L)
@ -123,6 +130,18 @@ void LJ_FASTCALL lj_state_growstack1(lua_State *L)
lj_state_growstack(L, 1);
}
static TValue *cpgrowstack(lua_State *co, lua_CFunction dummy, void *ud)
{
UNUSED(dummy);
lj_state_growstack(co, *(MSize *)ud);
return NULL;
}
int LJ_FASTCALL lj_state_cpgrowstack(lua_State *L, MSize need)
{
return lj_vm_cpcall(L, NULL, &need, cpgrowstack);
}
/* Allocate basic stack for new state. */
static void stack_init(lua_State *L1, lua_State *L)
{

View file

@ -18,6 +18,7 @@ LJ_FUNC void lj_state_relimitstack(lua_State *L);
LJ_FUNC void lj_state_shrinkstack(lua_State *L, MSize used);
LJ_FUNCA void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need);
LJ_FUNC void LJ_FASTCALL lj_state_growstack1(lua_State *L);
LJ_FUNC int LJ_FASTCALL lj_state_cpgrowstack(lua_State *L, MSize need);
static LJ_AINLINE void lj_state_checkstack(lua_State *L, MSize need)
{

View file

@ -58,9 +58,13 @@ typedef uint32_t RegSP;
#if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64
typedef uint64_t RegSet;
#define RSET_BITS 6
#define rset_picktop_(rs) ((Reg)lj_fls64(rs))
#define rset_pickbot_(rs) ((Reg)lj_ffs64(rs))
#else
typedef uint32_t RegSet;
#define RSET_BITS 5
#define rset_picktop_(rs) ((Reg)lj_fls(rs))
#define rset_pickbot_(rs) ((Reg)lj_ffs(rs))
#endif
#define RID2RSET(r) (((RegSet)1) << (r))
@ -71,13 +75,6 @@ typedef uint32_t RegSet;
#define rset_set(rs, r) (rs |= RID2RSET(r))
#define rset_clear(rs, r) (rs &= ~RID2RSET(r))
#define rset_exclude(rs, r) (rs & ~RID2RSET(r))
#if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64
#define rset_picktop_(rs) ((Reg)(__builtin_clzll(rs)^63))
#define rset_pickbot_(rs) ((Reg)__builtin_ctzll(rs))
#else
#define rset_picktop_(rs) ((Reg)lj_fls(rs))
#define rset_pickbot_(rs) ((Reg)lj_ffs(rs))
#endif
/* -- Register allocation cost -------------------------------------------- */

View file

@ -621,22 +621,27 @@ static int trace_abort(jit_State *J)
J->cur.link = 0;
J->cur.linktype = LJ_TRLINK_NONE;
lj_vmevent_send(L, TRACE,
cTValue *bot = tvref(L->stack)+LJ_FR2;
cTValue *frame;
int size;
BCIns pc;
GCfunc *fn;
const BCIns *pc;
BCPos pos = 0;
setstrV(L, L->top++, lj_str_newlit(L, "abort"));
setintV(L->top++, traceno);
/* Find original function call to generate a better error message. */
frame = lj_debug_frame(L, 0, &size);
lj_assertL(frame != NULL, "missing debug frame");
fn = frame_func(frame);
if (frame == L->base-1 && isluafunc(fn))
pc = proto_bcpos(funcproto(fn), J->pc);
else
pc = lj_debug_framepc(L, fn, frame);
setfuncV(L, L->top++, fn);
setintV(L->top++, pc);
/* Find original Lua function call to generate a better error message. */
for (frame = J->L->base-1, pc = J->pc; ; frame = frame_prev(frame)) {
if (isluafunc(frame_func(frame))) {
pos = proto_bcpos(funcproto(frame_func(frame)), pc);
break;
} else if (frame_prev(frame) <= bot) {
break;
} else if (frame_iscont(frame)) {
pc = frame_contpc(frame) - 1;
} else {
pc = frame_pc(frame) - 1;
}
}
setfuncV(L, L->top++, frame_func(frame));
setintV(L->top++, pos);
copyTV(L, L->top++, restorestack(L, errobj));
copyTV(L, L->top++, &J->errinfo);
);

View file

@ -27,39 +27,52 @@
@set BUILDTYPE=release
@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c
@setlocal
@call :SETHOSTVARS
%LJCOMPILE% host\minilua.c
@if errorlevel 1 goto :BAD
%LJLINK% /out:minilua.exe minilua.obj
@if errorlevel 1 goto :BAD
if exist minilua.exe.manifest^
%LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe
@endlocal
@set DASMFLAGS=-D WIN -D JIT -D FFI -D P64
@set DASMFLAGS=-D WIN -D JIT -D FFI -D ENDIAN_LE -D FPU -D P64
@set LJARCH=x64
@minilua
@if errorlevel 8 goto :X64
@if errorlevel 8 goto :NO32
@set DASC=vm_x86.dasc
@set DASMFLAGS=-D WIN -D JIT -D FFI
@set DASMFLAGS=-D WIN -D JIT -D FFI -D ENDIAN_LE -D FPU
@set LJARCH=x86
@set LJCOMPILE=%LJCOMPILE% /arch:SSE2
@goto :DA
:NO32
@if "%VSCMD_ARG_TGT_ARCH%" neq "arm64" goto :X64
@set DASC=vm_arm64.dasc
@set DASMTARGET=-D LUAJIT_TARGET=LUAJIT_ARCH_ARM64
@set LJARCH=arm64
@goto :DA
:X64
@if "%1" neq "nogc64" goto :GC64
@if "%1" neq "nogc64" goto :DA
@shift
@set DASC=vm_x86.dasc
@set LJCOMPILE=%LJCOMPILE% /DLUAJIT_DISABLE_GC64
:GC64
:DA
minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h %DASC%
@if errorlevel 1 goto :BAD
if exist ..\.git ( git show -s --format=%%ct >luajit_relver.txt ) else ( type ..\.relver >luajit_relver.txt )
minilua host\genversion.lua
%LJCOMPILE% /I "." /I %DASMDIR% host\buildvm*.c
@setlocal
@call :SETHOSTVARS
%LJCOMPILE% /I "." /I %DASMDIR% %DASMTARGET% host\buildvm*.c
@if errorlevel 1 goto :BAD
%LJLINK% /out:buildvm.exe buildvm*.obj
@if errorlevel 1 goto :BAD
if exist buildvm.exe.manifest^
%LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe
@endlocal
buildvm -m peobj -o lj_vm.obj
@if errorlevel 1 goto :BAD
@ -118,6 +131,12 @@ if exist luajit.exe.manifest^
@echo.
@echo === Successfully built LuaJIT for Windows/%LJARCH% ===
@goto :END
:SETHOSTVARS
@if "%VSCMD_ARG_HOST_ARCH%_%VSCMD_ARG_TGT_ARCH%" equ "x64_arm64" (
call "%VSINSTALLDIR%Common7\Tools\VsDevCmd.bat" -arch=%VSCMD_ARG_HOST_ARCH% -no_logo
echo on
)
@goto :END
:BAD
@echo.

View file

@ -113,13 +113,37 @@
|
|.define TMPDofs, #24
|
|.if WIN
|// Windows unwind data is suited to r1 stored first.
|.macro stp_unwind, r1, r2, where
| stp r1, r2, where
|.endmacro
|.macro ldp_unwind, r1, r2, where
| ldp r1, r2, where
|.endmacro
|.macro ldp_unwind, r1, r2, where, post_index
| ldp r1, r2, where, post_index
|.endmacro
|.else
|// Otherwise store r2 first for compact unwind info (OSX).
|.macro stp_unwind, r1, r2, where
| stp r2, r1, where
|.endmacro
|.macro ldp_unwind, r1, r2, where
| ldp r2, r1, where
|.endmacro
|.macro ldp_unwind, r1, r2, where, post_index
| ldp r2, r1, where, post_index
|.endmacro
|.endif
|
|.macro save_, gpr1, gpr2, fpr1, fpr2
| stp d..fpr2, d..fpr1, [sp, # SAVE_FPR_+(14-fpr1)*8]
| stp x..gpr2, x..gpr1, [sp, # SAVE_GPR_+(27-gpr1)*8]
| stp_unwind d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(14-fpr1)*8]
| stp_unwind x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(27-gpr1)*8]
|.endmacro
|.macro rest_, gpr1, gpr2, fpr1, fpr2
| ldp d..fpr2, d..fpr1, [sp, # SAVE_FPR_+(14-fpr1)*8]
| ldp x..gpr2, x..gpr1, [sp, # SAVE_GPR_+(27-gpr1)*8]
| ldp_unwind d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(14-fpr1)*8]
| ldp_unwind x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(27-gpr1)*8]
|.endmacro
|
|.macro saveregs
@ -127,14 +151,14 @@
| sub sp, sp, # CFRAME_SPACE
| stp fp, lr, [sp, # SAVE_FP_LR_]
| add fp, sp, # SAVE_FP_LR_
| stp x20, x19, [sp, # SAVE_GPR_+(27-19)*8]
| stp_unwind x19, x20, [sp, # SAVE_GPR_+(27-19)*8]
| save_ 21, 22, 8, 9
| save_ 23, 24, 10, 11
| save_ 25, 26, 12, 13
| save_ 27, 28, 14, 15
|.endmacro
|.macro restoreregs
| ldp x20, x19, [sp, # SAVE_GPR_+(27-19)*8]
| ldp_unwind x19, x20, [sp, # SAVE_GPR_+(27-19)*8]
| rest_ 21, 22, 8, 9
| rest_ 23, 24, 10, 11
| rest_ 25, 26, 12, 13
@ -408,24 +432,24 @@ static void build_subroutines(BuildCtx *ctx)
| // (void *cframe, int errcode)
| mov sp, CARG1
| mov CRET1, CARG2
|->vm_unwind_c_eh: // Landing pad for external unwinder.
| ldr L, SAVE_L
| mv_vmstate TMP0w, C
| ldr GL, L->glref
|->vm_unwind_c_eh: // Landing pad for external unwinder.
| mv_vmstate TMP0w, C
| st_vmstate TMP0w
| b ->vm_leave_unw
|
|->vm_unwind_ff: // Unwind C stack, return from ff pcall.
| // (void *cframe)
| and sp, CARG1, #CFRAME_RAWMASK
|->vm_unwind_ff_eh: // Landing pad for external unwinder.
| ldr L, SAVE_L
| movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
| movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
| movn TISNIL, #0
| ldr GL, L->glref // Setup pointer to global state.
|->vm_unwind_ff_eh: // Landing pad for external unwinder.
| mov RC, #16 // 2 results: false + error message.
| ldr BASE, L->base
| ldr GL, L->glref // Setup pointer to global state.
| mov_false TMP0
| sub RA, BASE, #8 // Results start at BASE-8.
| ldr PC, [BASE, FRAME_PC] // Fetch PC of previous frame.
@ -2005,13 +2029,13 @@ static void build_subroutines(BuildCtx *ctx)
|.if JIT
| ldr L, SAVE_L
|1:
| movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
| movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
| movn TISNIL, #0
| cmn CARG1w, #LUA_ERRERR
| bhs >9 // Check for error from exit.
| lsl RC, CARG1, #3
| ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
| movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
| movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
| movn TISNIL, #0
| lsl RC, CARG1, #3
| and LFUNC:CARG2, CARG2, #LJ_GCVMASK
| str RCw, SAVE_MULTRES
| str BASE, L->base
@ -2162,7 +2186,7 @@ static void build_subroutines(BuildCtx *ctx)
|//-----------------------------------------------------------------------
|
|// Handler for callback functions.
|// Saveregs already performed. Callback slot number in [sp], g in r12.
|// Saveregs already performed. Callback slot number in w9, g in x10.
|->vm_ffi_callback:
|.if FFI
|.type CTSTATE, CTState, PC
@ -2215,7 +2239,7 @@ static void build_subroutines(BuildCtx *ctx)
|.if FFI
| .type CCSTATE, CCallState, x19
| sp_auth
| stp x20, CCSTATE, [sp, #-32]!
| stp_unwind CCSTATE, x20, [sp, #-32]!
| stp fp, lr, [sp, #16]
| add fp, sp, #16
| mov CCSTATE, x0
@ -2247,7 +2271,7 @@ static void build_subroutines(BuildCtx *ctx)
| stp d0, d1, CCSTATE->fpr[0]
| stp d2, d3, CCSTATE->fpr[2]
| ldp fp, lr, [sp, #16]
| ldp x20, CCSTATE, [sp], #32
| ldp_unwind CCSTATE, x20, [sp], #32
| ret_auth
|.endif
|// Note: vm_ffi_call must be the last function in this object file!
@ -3816,9 +3840,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|.if JIT
| // RA = base (ignored), RC = traceno
| ldr CARG1, [GL, #GL_J(trace)]
| mov CARG2w, #0 // Traces on ARM64 don't store the trace #, so use 0.
| st_vmstate wzr // Traces on ARM64 don't store the trace #, so use 0.
| ldr TRACE:RC, [CARG1, RC, lsl #3]
| st_vmstate CARG2w
|.if PAUTH
| ldr RA, TRACE:RC->mcauth
|.else
@ -3893,6 +3916,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| add TMP2, BASE, RC
| add LFUNC:CARG3, CARG3, TMP0, lsl #47
| add RA, RA, RC
| sub CARG1, CARG1, #8
| add TMP0, RC, #16+FRAME_VARG
| str LFUNC:CARG3, [TMP2], #8 // Store (tagged) copy of LFUNC.
| ldr KBASE, [PC, #-4+PC2PROTO(k)]

View file

@ -5396,6 +5396,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| settp LFUNC:RB, TMP0
| daddu TMP0, RA, RC
| sd LFUNC:RB, 0(TMP1) // Store (tagged) copy of LFUNC.
| daddiu TMP2, TMP2, -8
| daddiu TMP3, RC, 16+FRAME_VARG
| sltu AT, TMP0, TMP2
| ld KBASE, -4+PC2PROTO(k)(PC)

View file

@ -136,7 +136,7 @@ print(tostring(saved_q))
cdata<void *>: 0xefdeaddeadbeef
cdata<void *>: 0xefdeaddeadbeef
--- err
[TRACE --- test.lua:8 -- trace too short at thread.exdata]
[TRACE --- test.lua:8 -- trace too short at test.lua:9]
@ -195,7 +195,7 @@ print("get: " .. total)
set: 0
get: 10
--- err
[TRACE --- test.lua:14 -- trace too short at thread.exdata]
[TRACE --- test.lua:14 -- trace too short at test.lua:15]
[TRACE 1 test.lua:21 loop]

View file

@ -160,7 +160,7 @@ print(tostring(saved_q))
cdata<void *>: 0xefdeaddeadbeef
cdata<void *>: 0xefdeaddeadbeef
--- err
[TRACE --- test.lua:8 -- trace too short at thread.exdata2]
[TRACE --- test.lua:8 -- trace too short at test.lua:9]
@ -224,7 +224,7 @@ get: 10
cdata<void *>: NULL
cdata<void *>: 0xefdeaddeadbeef
--- err
[TRACE --- test.lua:15 -- trace too short at thread.exdata2]
[TRACE --- test.lua:15 -- trace too short at test.lua:16]
[TRACE 1 test.lua:22 loop]

View file

@ -49,7 +49,7 @@ print('ok')
ok
--- jv
--- err eval
qr/trace too short at jit\.prngstate/
qr/trace too short at test.lua:4/

View file

@ -4,6 +4,7 @@
"requires": true,
"packages": {
"": {
"name": "ui",
"dependencies": {
"ace-builds": "^1.12.5",
"air-datepicker": "^3.3.1",
@ -627,9 +628,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{
@ -1453,9 +1454,9 @@
"dev": true
},
"postcss": {
"version": "8.4.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"requires": {
"nanoid": "^3.3.6",

View file

@ -56,7 +56,9 @@ flask-wtf==1.2.1 \
gunicorn==21.2.0 \
--hash=sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0 \
--hash=sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033
# via -r requirements.in
# via
# -r requirements.in
# gunicorn
importlib-metadata==6.8.0 \
--hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \
--hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743

File diff suppressed because it is too large Load diff

View file

@ -222,7 +222,8 @@ class DisabledPop {
init() {
window.addEventListener("pointerover", (e) => {
//for checkbox and regular inputs
if (e.target.tagName === "INPUT") {
if (e.target.tagName === "INPUT" &&
e.target.hasAttribute('data-default-method')) {
const el = e.target;
this.showPopup(el, "input");
}
@ -252,7 +253,7 @@ class DisabledPop {
const popupHTML = `
<div data-disabled-info class="${
type === "select" ? "translate-y-2" : ""
} bg-blue-500 absolute right-2 rounded-lg px-2 py-1 z-20 dark:brightness-90">
} right-8 pointer-events-none bg-blue-500 absolute rounded-lg px-2 py-1 z-20 dark:brightness-90">
<p class="m-0 text-xs text-white dark:text-gray-100">disabled by ${method}</p>
</div>`;
let cleanHTML = DOMPurify.sanitize(popupHTML);

View file

@ -81,7 +81,7 @@
}
.popover-settings-container {
@apply dark:brightness-90 transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500;
@apply transition-all duration-500 dark:brightness-90 transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500;
}
.popover-settings-text {

4
stylua.toml Normal file
View file

@ -0,0 +1,4 @@
call_parentheses = "Input"
[sort_requires]
enabled = true

View file

@ -166,6 +166,7 @@ urllib3==2.0.6 \
# -r requirements.in
# requests
# selenium
# urllib3
wsproto==1.2.0 \
--hash=sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065 \
--hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736

View file

@ -166,6 +166,7 @@ urllib3==2.0.6 \
# -r requirements.in
# requests
# selenium
# urllib3
wsproto==1.2.0 \
--hash=sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065 \
--hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736

View file

@ -260,62 +260,123 @@ typing-extensions==4.8.0 \
uvicorn==0.23.2 \
--hash=sha256:1f9be6558f01239d4fdf22ef8126c39cb1ad0addf76c40e760549d2c2f43ab53 \
--hash=sha256:4d3cc12d7727ba72b64d12d3cc7743124074c0a69f7b201512fc50c3e3f1569a
# via -r requirements.in
uvloop==0.17.0 \
--hash=sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d \
--hash=sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1 \
--hash=sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595 \
--hash=sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b \
--hash=sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05 \
--hash=sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8 \
--hash=sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20 \
--hash=sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded \
--hash=sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c \
--hash=sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8 \
--hash=sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474 \
--hash=sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f \
--hash=sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62 \
--hash=sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376 \
--hash=sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c \
--hash=sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e \
--hash=sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b \
--hash=sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4 \
--hash=sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578 \
--hash=sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811 \
--hash=sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d \
--hash=sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738 \
--hash=sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa \
--hash=sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9 \
--hash=sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539 \
--hash=sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c \
--hash=sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718 \
--hash=sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667 \
--hash=sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c \
--hash=sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024
# via
# -r requirements.in
# uvicorn
uvloop==0.18.0 \
--hash=sha256:1121087dfeb46e9e65920b20d1f46322ba299b8d93f7cb61d76c94b5a1adc20c \
--hash=sha256:12af0d2e1b16780051d27c12de7e419b9daeb3516c503ab3e98d364cc55303bb \
--hash=sha256:1f354d669586fca96a9a688c585b6257706d216177ac457c92e15709acaece10 \
--hash=sha256:1f4a549cd747e6f4f8446f4b4c8cb79504a8372d5d3a9b4fc20e25daf8e76c05 \
--hash=sha256:211ce38d84118ae282a91408f61b85cf28e2e65a0a8966b9a97e0e9d67c48722 \
--hash=sha256:25b714f07c68dcdaad6994414f6ec0f2a3b9565524fba181dcbfd7d9598a3e73 \
--hash=sha256:280904236a5b333a273292b3bcdcbfe173690f69901365b973fa35be302d7781 \
--hash=sha256:2b8b7cf7806bdc745917f84d833f2144fabcc38e9cd854e6bc49755e3af2b53e \
--hash=sha256:4d90858f32a852988d33987d608bcfba92a1874eb9f183995def59a34229f30d \
--hash=sha256:53aca21735eee3859e8c11265445925911ffe410974f13304edb0447f9f58420 \
--hash=sha256:54b211c46facb466726b227f350792770fc96593c4ecdfaafe20dc00f3209aef \
--hash=sha256:56c1026a6b0d12b378425e16250acb7d453abaefe7a2f5977143898db6cfe5bd \
--hash=sha256:585b7281f9ea25c4a5fa993b1acca4ad3d8bc3f3fe2e393f0ef51b6c1bcd2fe6 \
--hash=sha256:58e44650cbc8607a218caeece5a689f0a2d10be084a69fc32f7db2e8f364927c \
--hash=sha256:61151cc207cf5fc88863e50de3d04f64ee0fdbb979d0b97caf21cae29130ed78 \
--hash=sha256:6132318e1ab84a626639b252137aa8d031a6c0550250460644c32ed997604088 \
--hash=sha256:680da98f12a7587f76f6f639a8aa7708936a5d17c5e7db0bf9c9d9cbcb616593 \
--hash=sha256:6e20bb765fcac07879cd6767b6dca58127ba5a456149717e0e3b1f00d8eab51c \
--hash=sha256:74020ef8061678e01a40c49f1716b4f4d1cc71190d40633f08a5ef8a7448a5c6 \
--hash=sha256:75baba0bfdd385c886804970ae03f0172e0d51e51ebd191e4df09b929771b71e \
--hash=sha256:847f2ed0887047c63da9ad788d54755579fa23f0784db7e752c7cf14cf2e7506 \
--hash=sha256:8849b8ef861431543c07112ad8436903e243cdfa783290cbee3df4ce86d8dd48 \
--hash=sha256:895a1e3aca2504638a802d0bec2759acc2f43a0291a1dff886d69f8b7baff399 \
--hash=sha256:99deae0504547d04990cc5acf631d9f490108c3709479d90c1dcd14d6e7af24d \
--hash=sha256:ad79cd30c7e7484bdf6e315f3296f564b3ee2f453134a23ffc80d00e63b3b59e \
--hash=sha256:b028776faf9b7a6d0a325664f899e4c670b2ae430265189eb8d76bd4a57d8a6e \
--hash=sha256:b0a8f706b943c198dcedf1f2fb84899002c195c24745e47eeb8f2fb340f7dfc3 \
--hash=sha256:c65585ae03571b73907b8089473419d8c0aff1e3826b3bce153776de56cbc687 \
--hash=sha256:c6d341bc109fb8ea69025b3ec281fcb155d6824a8ebf5486c989ff7748351a37 \
--hash=sha256:d5d1135beffe9cd95d0350f19e2716bc38be47d5df296d7cc46e3b7557c0d1ff \
--hash=sha256:db1fcbad5deb9551e011ca589c5e7258b5afa78598174ac37a5f15ddcfb4ac7b \
--hash=sha256:e14de8800765b9916d051707f62e18a304cde661fa2b98a58816ca38d2b94029 \
--hash=sha256:e3d301e23984dcbc92d0e42253e0e0571915f0763f1eeaf68631348745f2dccc \
--hash=sha256:ed3c28337d2fefc0bac5705b9c66b2702dc392f2e9a69badb1d606e7e7f773bb \
--hash=sha256:edbb4de38535f42f020da1e3ae7c60f2f65402d027a08a8c60dc8569464873a6 \
--hash=sha256:f3b18663efe0012bc4c315f1b64020e44596f5fabc281f5b0d9bc9465288559c
# via uvicorn
watchfiles==0.20.0 \
--hash=sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38 \
--hash=sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db \
--hash=sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0 \
--hash=sha256:13f995d5152a8ba4ed7c2bbbaeee4e11a5944defc7cacd0ccb4dcbdcfd78029a \
--hash=sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9 \
--hash=sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf \
--hash=sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490 \
--hash=sha256:608cd94a8767f49521901aff9ae0c92cc8f5a24d528db7d6b0295290f9d41193 \
--hash=sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019 \
--hash=sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164 \
--hash=sha256:835df2da7a5df5464c4a23b2d963e1a9d35afa422c83bf4ff4380b3114603644 \
--hash=sha256:87d9e1f75c4f86c93d73b5bd1ebe667558357548f11b4f8af4e0e272f79413ce \
--hash=sha256:89d1de8218874925bce7bb2ae9657efc504411528930d7a83f98b1749864f2ef \
--hash=sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95 \
--hash=sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa \
--hash=sha256:9b5c8d3be7b502f8c43a33c63166ada8828dbb0c6d49c8f9ce990a96de2f5a49 \
--hash=sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5 \
--hash=sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c \
--hash=sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458 \
--hash=sha256:d97db179f7566dcf145c5179ddb2ae2a4450e3a634eb864b09ea04e68c252e8e \
--hash=sha256:e43af4464daa08723c04b43cf978ab86cc55c684c16172622bdac64b34e36af0 \
--hash=sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3
watchfiles==0.21.0 \
--hash=sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc \
--hash=sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365 \
--hash=sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0 \
--hash=sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e \
--hash=sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124 \
--hash=sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c \
--hash=sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317 \
--hash=sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094 \
--hash=sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7 \
--hash=sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235 \
--hash=sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c \
--hash=sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c \
--hash=sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c \
--hash=sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235 \
--hash=sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293 \
--hash=sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa \
--hash=sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef \
--hash=sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19 \
--hash=sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8 \
--hash=sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d \
--hash=sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915 \
--hash=sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429 \
--hash=sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097 \
--hash=sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe \
--hash=sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0 \
--hash=sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d \
--hash=sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99 \
--hash=sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1 \
--hash=sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a \
--hash=sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895 \
--hash=sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94 \
--hash=sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562 \
--hash=sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab \
--hash=sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360 \
--hash=sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1 \
--hash=sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7 \
--hash=sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f \
--hash=sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03 \
--hash=sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01 \
--hash=sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58 \
--hash=sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052 \
--hash=sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e \
--hash=sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765 \
--hash=sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6 \
--hash=sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137 \
--hash=sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85 \
--hash=sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca \
--hash=sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f \
--hash=sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214 \
--hash=sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7 \
--hash=sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7 \
--hash=sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3 \
--hash=sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b \
--hash=sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7 \
--hash=sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6 \
--hash=sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994 \
--hash=sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9 \
--hash=sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec \
--hash=sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128 \
--hash=sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c \
--hash=sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2 \
--hash=sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078 \
--hash=sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3 \
--hash=sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e \
--hash=sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a \
--hash=sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6 \
--hash=sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49 \
--hash=sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b \
--hash=sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28 \
--hash=sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9 \
--hash=sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586 \
--hash=sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400 \
--hash=sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165 \
--hash=sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303 \
--hash=sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d
# via uvicorn
websockets==11.0.3 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \

View file

@ -260,62 +260,123 @@ typing-extensions==4.8.0 \
uvicorn==0.23.2 \
--hash=sha256:1f9be6558f01239d4fdf22ef8126c39cb1ad0addf76c40e760549d2c2f43ab53 \
--hash=sha256:4d3cc12d7727ba72b64d12d3cc7743124074c0a69f7b201512fc50c3e3f1569a
# via -r requirements.in
uvloop==0.17.0 \
--hash=sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d \
--hash=sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1 \
--hash=sha256:1436c8673c1563422213ac6907789ecb2b070f5939b9cbff9ef7113f2b531595 \
--hash=sha256:23609ca361a7fc587031429fa25ad2ed7242941adec948f9d10c045bfecab06b \
--hash=sha256:2a6149e1defac0faf505406259561bc14b034cdf1d4711a3ddcdfbaa8d825a05 \
--hash=sha256:2deae0b0fb00a6af41fe60a675cec079615b01d68beb4cc7b722424406b126a8 \
--hash=sha256:307958f9fc5c8bb01fad752d1345168c0abc5d62c1b72a4a8c6c06f042b45b20 \
--hash=sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded \
--hash=sha256:3378eb62c63bf336ae2070599e49089005771cc651c8769aaad72d1bd9385a7c \
--hash=sha256:3d97672dc709fa4447ab83276f344a165075fd9f366a97b712bdd3fee05efae8 \
--hash=sha256:3db8de10ed684995a7f34a001f15b374c230f7655ae840964d51496e2f8a8474 \
--hash=sha256:3ebeeec6a6641d0adb2ea71dcfb76017602ee2bfd8213e3fcc18d8f699c5104f \
--hash=sha256:45cea33b208971e87a31c17622e4b440cac231766ec11e5d22c76fab3bf9df62 \
--hash=sha256:6708f30db9117f115eadc4f125c2a10c1a50d711461699a0cbfaa45b9a78e376 \
--hash=sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c \
--hash=sha256:6aafa5a78b9e62493539456f8b646f85abc7093dd997f4976bb105537cf2635e \
--hash=sha256:7d37dccc7ae63e61f7b96ee2e19c40f153ba6ce730d8ba4d3b4e9738c1dccc1b \
--hash=sha256:864e1197139d651a76c81757db5eb199db8866e13acb0dfe96e6fc5d1cf45fc4 \
--hash=sha256:8887d675a64cfc59f4ecd34382e5b4f0ef4ae1da37ed665adba0c2badf0d6578 \
--hash=sha256:8efcadc5a0003d3a6e887ccc1fb44dec25594f117a94e3127954c05cf144d811 \
--hash=sha256:9b09e0f0ac29eee0451d71798878eae5a4e6a91aa275e114037b27f7db72702d \
--hash=sha256:a4aee22ece20958888eedbad20e4dbb03c37533e010fb824161b4f05e641f738 \
--hash=sha256:a5abddb3558d3f0a78949c750644a67be31e47936042d4f6c888dd6f3c95f4aa \
--hash=sha256:c092a2c1e736086d59ac8e41f9c98f26bbf9b9222a76f21af9dfe949b99b2eb9 \
--hash=sha256:c686a47d57ca910a2572fddfe9912819880b8765e2f01dc0dd12a9bf8573e539 \
--hash=sha256:cbbe908fda687e39afd6ea2a2f14c2c3e43f2ca88e3a11964b297822358d0e6c \
--hash=sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718 \
--hash=sha256:dbbaf9da2ee98ee2531e0c780455f2841e4675ff580ecf93fe5c48fe733b5667 \
--hash=sha256:f1e507c9ee39c61bfddd79714e4f85900656db1aec4d40c6de55648e85c2799c \
--hash=sha256:ff3d00b70ce95adce264462c930fbaecb29718ba6563db354608f37e49e09024
# via
# -r requirements.in
# uvicorn
uvloop==0.18.0 \
--hash=sha256:1121087dfeb46e9e65920b20d1f46322ba299b8d93f7cb61d76c94b5a1adc20c \
--hash=sha256:12af0d2e1b16780051d27c12de7e419b9daeb3516c503ab3e98d364cc55303bb \
--hash=sha256:1f354d669586fca96a9a688c585b6257706d216177ac457c92e15709acaece10 \
--hash=sha256:1f4a549cd747e6f4f8446f4b4c8cb79504a8372d5d3a9b4fc20e25daf8e76c05 \
--hash=sha256:211ce38d84118ae282a91408f61b85cf28e2e65a0a8966b9a97e0e9d67c48722 \
--hash=sha256:25b714f07c68dcdaad6994414f6ec0f2a3b9565524fba181dcbfd7d9598a3e73 \
--hash=sha256:280904236a5b333a273292b3bcdcbfe173690f69901365b973fa35be302d7781 \
--hash=sha256:2b8b7cf7806bdc745917f84d833f2144fabcc38e9cd854e6bc49755e3af2b53e \
--hash=sha256:4d90858f32a852988d33987d608bcfba92a1874eb9f183995def59a34229f30d \
--hash=sha256:53aca21735eee3859e8c11265445925911ffe410974f13304edb0447f9f58420 \
--hash=sha256:54b211c46facb466726b227f350792770fc96593c4ecdfaafe20dc00f3209aef \
--hash=sha256:56c1026a6b0d12b378425e16250acb7d453abaefe7a2f5977143898db6cfe5bd \
--hash=sha256:585b7281f9ea25c4a5fa993b1acca4ad3d8bc3f3fe2e393f0ef51b6c1bcd2fe6 \
--hash=sha256:58e44650cbc8607a218caeece5a689f0a2d10be084a69fc32f7db2e8f364927c \
--hash=sha256:61151cc207cf5fc88863e50de3d04f64ee0fdbb979d0b97caf21cae29130ed78 \
--hash=sha256:6132318e1ab84a626639b252137aa8d031a6c0550250460644c32ed997604088 \
--hash=sha256:680da98f12a7587f76f6f639a8aa7708936a5d17c5e7db0bf9c9d9cbcb616593 \
--hash=sha256:6e20bb765fcac07879cd6767b6dca58127ba5a456149717e0e3b1f00d8eab51c \
--hash=sha256:74020ef8061678e01a40c49f1716b4f4d1cc71190d40633f08a5ef8a7448a5c6 \
--hash=sha256:75baba0bfdd385c886804970ae03f0172e0d51e51ebd191e4df09b929771b71e \
--hash=sha256:847f2ed0887047c63da9ad788d54755579fa23f0784db7e752c7cf14cf2e7506 \
--hash=sha256:8849b8ef861431543c07112ad8436903e243cdfa783290cbee3df4ce86d8dd48 \
--hash=sha256:895a1e3aca2504638a802d0bec2759acc2f43a0291a1dff886d69f8b7baff399 \
--hash=sha256:99deae0504547d04990cc5acf631d9f490108c3709479d90c1dcd14d6e7af24d \
--hash=sha256:ad79cd30c7e7484bdf6e315f3296f564b3ee2f453134a23ffc80d00e63b3b59e \
--hash=sha256:b028776faf9b7a6d0a325664f899e4c670b2ae430265189eb8d76bd4a57d8a6e \
--hash=sha256:b0a8f706b943c198dcedf1f2fb84899002c195c24745e47eeb8f2fb340f7dfc3 \
--hash=sha256:c65585ae03571b73907b8089473419d8c0aff1e3826b3bce153776de56cbc687 \
--hash=sha256:c6d341bc109fb8ea69025b3ec281fcb155d6824a8ebf5486c989ff7748351a37 \
--hash=sha256:d5d1135beffe9cd95d0350f19e2716bc38be47d5df296d7cc46e3b7557c0d1ff \
--hash=sha256:db1fcbad5deb9551e011ca589c5e7258b5afa78598174ac37a5f15ddcfb4ac7b \
--hash=sha256:e14de8800765b9916d051707f62e18a304cde661fa2b98a58816ca38d2b94029 \
--hash=sha256:e3d301e23984dcbc92d0e42253e0e0571915f0763f1eeaf68631348745f2dccc \
--hash=sha256:ed3c28337d2fefc0bac5705b9c66b2702dc392f2e9a69badb1d606e7e7f773bb \
--hash=sha256:edbb4de38535f42f020da1e3ae7c60f2f65402d027a08a8c60dc8569464873a6 \
--hash=sha256:f3b18663efe0012bc4c315f1b64020e44596f5fabc281f5b0d9bc9465288559c
# via uvicorn
watchfiles==0.20.0 \
--hash=sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38 \
--hash=sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db \
--hash=sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0 \
--hash=sha256:13f995d5152a8ba4ed7c2bbbaeee4e11a5944defc7cacd0ccb4dcbdcfd78029a \
--hash=sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9 \
--hash=sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf \
--hash=sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490 \
--hash=sha256:608cd94a8767f49521901aff9ae0c92cc8f5a24d528db7d6b0295290f9d41193 \
--hash=sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019 \
--hash=sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164 \
--hash=sha256:835df2da7a5df5464c4a23b2d963e1a9d35afa422c83bf4ff4380b3114603644 \
--hash=sha256:87d9e1f75c4f86c93d73b5bd1ebe667558357548f11b4f8af4e0e272f79413ce \
--hash=sha256:89d1de8218874925bce7bb2ae9657efc504411528930d7a83f98b1749864f2ef \
--hash=sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95 \
--hash=sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa \
--hash=sha256:9b5c8d3be7b502f8c43a33c63166ada8828dbb0c6d49c8f9ce990a96de2f5a49 \
--hash=sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5 \
--hash=sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c \
--hash=sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458 \
--hash=sha256:d97db179f7566dcf145c5179ddb2ae2a4450e3a634eb864b09ea04e68c252e8e \
--hash=sha256:e43af4464daa08723c04b43cf978ab86cc55c684c16172622bdac64b34e36af0 \
--hash=sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3
watchfiles==0.21.0 \
--hash=sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc \
--hash=sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365 \
--hash=sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0 \
--hash=sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e \
--hash=sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124 \
--hash=sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c \
--hash=sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317 \
--hash=sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094 \
--hash=sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7 \
--hash=sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235 \
--hash=sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c \
--hash=sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c \
--hash=sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c \
--hash=sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235 \
--hash=sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293 \
--hash=sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa \
--hash=sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef \
--hash=sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19 \
--hash=sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8 \
--hash=sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d \
--hash=sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915 \
--hash=sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429 \
--hash=sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097 \
--hash=sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe \
--hash=sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0 \
--hash=sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d \
--hash=sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99 \
--hash=sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1 \
--hash=sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a \
--hash=sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895 \
--hash=sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94 \
--hash=sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562 \
--hash=sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab \
--hash=sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360 \
--hash=sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1 \
--hash=sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7 \
--hash=sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f \
--hash=sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03 \
--hash=sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01 \
--hash=sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58 \
--hash=sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052 \
--hash=sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e \
--hash=sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765 \
--hash=sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6 \
--hash=sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137 \
--hash=sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85 \
--hash=sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca \
--hash=sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f \
--hash=sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214 \
--hash=sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7 \
--hash=sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7 \
--hash=sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3 \
--hash=sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b \
--hash=sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7 \
--hash=sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6 \
--hash=sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994 \
--hash=sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9 \
--hash=sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec \
--hash=sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128 \
--hash=sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c \
--hash=sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2 \
--hash=sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078 \
--hash=sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3 \
--hash=sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e \
--hash=sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a \
--hash=sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6 \
--hash=sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49 \
--hash=sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b \
--hash=sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28 \
--hash=sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9 \
--hash=sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586 \
--hash=sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400 \
--hash=sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165 \
--hash=sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303 \
--hash=sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d
# via uvicorn
websockets==11.0.3 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \

Some files were not shown because too many files have changed in this diff Show more