diff --git a/example/plugins/lua-api/connect_geoip.lua b/example/plugins/lua-api/connect_geoip.lua index 1277e205763..cdb5c74fe03 100644 --- a/example/plugins/lua-api/connect_geoip.lua +++ b/example/plugins/lua-api/connect_geoip.lua @@ -14,17 +14,23 @@ -- See the License for the specific language governing permissions and -- limitations under the License. - -- This example depends on "luajit-geoip". --- It illustrates how to connect to GeoIP and use it to look up country of an IP address. +-- It illustrates how to connect to GeoIP and uses it to look up country of an IP address. -- It can be used in plugin.config with the lua plugin. -- Setup Instructions --- 1) install GeoIP - 1.6.12 --- 2) install GeoIP legacy country database - https://dev.maxmind.com/geoip/legacy/install/country/ --- 3) install luajit-geoip (https://github.com/leafo/luajit-geoip) --- or just copy geoip/init.lua from the repo to /usr/local/share/lua/5.1/geoip/init.lua --- 4) You may need to make change so luajit-geoip does ffi.load() on /usr/local/lib/libGeoIP.so +-- 1. install legacy GeoIP library 1.6.12 (https://github.com/maxmind/geoip-api-c) +-- a. wget https://github.com/maxmind/geoip-api-c/releases/download/v1.6.12/GeoIP-1.6.12.tar.gz +-- b. tar zxvf GeoIP-1.6.12.tar.gz +-- c. cd GeoIP-1.6.12 +-- d. ./configure; make; make install +-- 2. Find and install GeoIP legacy country database to /usr/local/share/GeoIP/GeoIP.dat +-- 3. install luajit-geoip v2.1.0 (https://github.com/leafo/luajit-geoip) +-- a. wget https://github.com/leafo/luajit-geoip/archive/refs/tags/v2.1.0.tar.gz +-- b. tar zxvf v2.1.0.tar.gz +-- c. mkdir -p /usr/local/share/lua/5.1/geoip +-- d. cp luajit-geoip-2.1.0/geoip.lua /usr/local/share/lua/5.1/geoip.lua +-- e. cp luajit-geoip-2.1.0/geoip/*.lua /usr/local/share/lua/5.1/geoip/ ts.add_package_path('/usr/local/share/lua/5.1/?.lua') diff --git a/example/plugins/lua-api/connect_maxmind.lua b/example/plugins/lua-api/connect_maxmind.lua new file mode 100644 index 00000000000..28d8a8fb1ee --- /dev/null +++ b/example/plugins/lua-api/connect_maxmind.lua @@ -0,0 +1,45 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +-- This example depends on "libmaxminddb". +-- It illustrates how to connect to MaxMind DB and uses it to look up country of an IP address. +-- It can be used in plugin.config with the lua plugin. + +-- Setup Instructions +-- 1. install libmaxminddb 1.6.0 (https://github.com/maxmind/libmaxminddb) +-- a. wget https://github.com/maxmind/libmaxminddb/releases/download/1.6.0/libmaxminddb-1.6.0.tar.gz +-- b. tar zxvf libmaxminddb-1.6.0.tar.gz +-- c. cd libmaxminddb-1.6.0 +-- d. ./configure; make; make install +-- 2) Get GeoLite2 country database from https://dev.maxmind.com/geoip/geolite2-free-geolocation-data and put it in /usr/share/GeoIP/GeoLite2-Country.mmdb +-- 3. install luajit-geoip v2.1.0 (https://github.com/leafo/luajit-geoip) +-- a. wget https://github.com/leafo/luajit-geoip/archive/refs/tags/v2.1.0.tar.gz +-- b. tar zxvf v2.1.0.tar.gz +-- c. mkdir -p /usr/local/share/lua/5.1/geoip +-- d. cp luajit-geoip-2.1.0/geoip.lua /usr/local/share/lua/5.1/geoip.lua +-- e. cp luajit-geoip-2.1.0/geoip/*.lua /usr/local/share/lua/5.1/geoip/ + +ts.add_package_path('/usr/local/share/lua/5.1/?.lua') + +local geoip = require 'geoip.mmdb' + +function do_global_send_response() + local mmdb = geoip.load_database("/usr/share/GeoIP/GeoLite2-Country.mmdb") + + local result = mmdb:lookup("8.8.8.8") + + ts.client_response.header['X-Maxmind-Info'] = result.country.iso_code +end diff --git a/example/plugins/lua-api/connect_redis.lua b/example/plugins/lua-api/connect_redis.lua index dddb2af3dce..4e004d913fb 100644 --- a/example/plugins/lua-api/connect_redis.lua +++ b/example/plugins/lua-api/connect_redis.lua @@ -19,10 +19,31 @@ -- It illustrates how to connect to redis and retrieve a key value. -- It can be used in plugin.config with the lua plugin. --- unix domain socket has better performance and so we should set up local redis to use that --- Note the sock must be readable/writable by nobody since ATS runs as that user --- Sample instructions for setting up redis 2.8.4 and putting a key in --- 1. edit /etc/redis/redis.conf to set "port 0", "unixsocket /var/run/redis/redis.sock" and "unixsocketperm 755" +-- Compile luasocket with luajit library and installation: +-- 1. wget https://github.com/diegonehab/luasocket/archive/v3.0-rc1.tar.gz +-- 2. tar zxf v3.0-rc1.tar.gz +-- 3. cd luasocket-3.0-rc1 +-- 4. sed -i "s/LDFLAGS_linux=-O -shared -fpic -o/LDFLAGS_linux=-O -shared -fpic -L\/usr\/lib -lluajit-5.1 -o/" src/makefile +-- 5. ln -sf /usr/lib/libluajit-5.1.so.2.1.0 /usr/lib/libluajit-5.1.so +-- 6. mkdir -p /usr/include/lua +-- 7. ln -sf /usr/include/luajit-2.1 /usr/include/lua/5.1 +-- 8. make +-- 9. make install-unix + +-- redis-lua installation: +-- 1. wget https://github.com/nrk/redis-lua/archive/v2.0.4.tar.gz +-- 2. tar zxf v2.0.4.tar.gz +-- 3. mkdir -p /usr/local/share/lua/5.1 +-- 4. cp redis-lua-2.0.4/src/redis.lua /usr/local/share/lua/5.1/redis.lua + +-- Redis setup instructions: +-- Unix domain socket has better performance and so we should set up local redis to use that. +-- Note the sock must be readable/writable by nobody since ATS runs as that user. +-- Sample instructions for setting up redis and putting a key in +-- 1. edit /etc/redis/redis.conf (or copy from redis configuration file). Make the following changes +-- a. "port 0" +-- b. "unixsocket /var/run/redis/redis.sock" +-- c. "unixsocketperm 755" -- 2. sudo chown nobody /var/run/redis -- 3. sudo chgrp nogroup /var/run/redis -- 4. sudo chown nobody /var/log/redis @@ -30,7 +51,7 @@ -- 6. sudo -u nobody redis-server /etc/redis/redis.conf -- 7. sudo -u nobody redis-cli -s /var/run/redis/redis.sock set mykey helloworld -ts.add_package_cpath("/usr/local/lib/lua/5.1/socket/?.so;/usr/local/lib/lua/5.1/mime/?.so") +ts.add_package_cpath("/usr/local/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/socket/?.so;/usr/local/lib/lua/5.1/mime/?.so") ts.add_package_path("/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/socket/?.lua") local redis = require "redis" diff --git a/example/plugins/lua-api/modsecurity/README.md b/example/plugins/lua-api/modsecurity/README.md index 2d8eb3ee473..1b17a4258a3 100644 --- a/example/plugins/lua-api/modsecurity/README.md +++ b/example/plugins/lua-api/modsecurity/README.md @@ -3,10 +3,10 @@ Integrating ATS with ModSecurity V3 using LuaJIT and FFI Opensource WAF for [Apache Traffic Server](http://trafficserver.apache.org/). -Requirement +Tested with the following ==== - - ModSecurity v3.0.4 - - ATS 8.0.8 + - ModSecurity v3.0.6 + - ATS 9.1.1 How to Use ==== @@ -63,7 +63,7 @@ SecDebugLogLevel 9 TODOs/Limitations ==== - No support for `REQUEST_BODY` examination (We need to buffer the request body for examination first before we send to origin.) - - No support for `RESPONSE BODY` examination (We need to uncompress the contents first if they are gzipped. And that will be expensive operation for proxy) + - No support for `RESPONSE_BODY` examination (We need to uncompress the contents first if they are gzipped. And that will be expensive operation for proxy). See https://github.com/SpiderLabs/ModSecurity/issues/2494 for reference - How does this work with the lua engine inside ModSecurity V3? - Unit Test using busted framework - More functional testing needed diff --git a/example/plugins/lua-api/modsecurity/example.conf b/example/plugins/lua-api/modsecurity/example.conf index c7df943adf6..36eb7818c2f 100644 --- a/example/plugins/lua-api/modsecurity/example.conf +++ b/example/plugins/lua-api/modsecurity/example.conf @@ -23,6 +23,6 @@ SecDebugLog /tmp/debug.log SecDebugLogLevel 9 SecRule ARGS:testparam "@contains test2" "id:1234,deny,status:403" -SecRule ARGS:testparam "@contains test1" "id:1235,redirect:https://www.yahoo.com/" +SecRule ARGS:testparam "@contains test1" "id:1235,status:301,redirect:https://www.yahoo.com/" SecRule RESPONSE_HEADERS:test "@contains 1" "id:1236,phase:3,deny,status:403" -SecRule RESPONSE_HEADERS:test "@contains 2" "id:1237,phase:3,redirect:https://www.yahoo.com/" +SecRule RESPONSE_HEADERS:test "@contains 2" "id:1237,phase:3,status:301,redirect:https://www.yahoo.com/" diff --git a/plugins/lua/business/mediaslice.lua b/plugins/lua/business/mediaslice.lua deleted file mode 100644 index c118445a67e..00000000000 --- a/plugins/lua/business/mediaslice.lua +++ /dev/null @@ -1,155 +0,0 @@ --- Licensed to the Apache Software Foundation (ASF) under one --- or more contributor license agreements. See the NOTICE file --- distributed with this work for additional information --- regarding copyright ownership. The ASF licenses this file --- to you under the Apache License, Version 2.0 (the --- "License"); you may not use this file except in compliance --- with the License. You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. - - -function media_transform(data, eos) - done = 0 - slen = string.len(data) - - if ts.ctx['fit'] > 0 then - if ts.ctx['fit'] + slen >= ts.ctx['len'] then - need = ts.ctx['len'] - ts.ctx['fit'] - done = 1 - else - need = slen - end - - ts.ctx['fit'] = ts.ctx['fit'] + need - ts.ctx['passed'] = ts.ctx['passed'] + slen - return data:sub(1, need), done - - elseif ts.ctx['passed'] + slen >= ts.ctx['offset'] then - spos = ts.ctx['offset'] - ts.ctx['passed'] + 1 - need = ts.ctx['passed'] + slen - ts.ctx['offset'] - if need >= ts.ctx['len'] then - need = ts.ctx['len'] - done = 1 - end - - epos = spos + need - 1 - - ts.ctx['fit'] = ts.ctx['fit'] + need - ts.ctx['passed'] = ts.ctx['passed'] + slen - - return data:sub(spos, epos), done - else - ts.ctx['passed'] = ts.ctx['passed'] + slen - return nil, eos - end - -end - - -function read_response() - http_status = ts.server_response.header.get_status() - ts.debug(string.format('server_response status = %d', http_status)) - if http_status ~= 200 then - return - end - - ts.http.resp_cache_transformed(0) - ts.http.resp_cache_untransformed(1) - - if ts.ctx['transform_add'] == 1 then - return - end - - ts.hook(TS_LUA_RESPONSE_TRANSFORM, media_transform) - ts.ctx['fit'] = 0 - ts.ctx['passed'] = 0 -end - - -function cache_lookup() - status = ts.http.get_cache_lookup_status() - ts.debug(string.format('cache lookup status: %d', status)) - if status ~= TS_LUA_CACHE_LOOKUP_HIT_FRESH and status ~= TS_LUA_CACHE_LOOKUP_HIT_STALE then - return - end - - http_status = ts.cached_response.header.get_status() - ts.debug(string.format('cached_response http status: %d', http_status)) - if http_status ~= 200 then - return - end - - ts.http.resp_cache_transformed(0) - ts.hook(TS_LUA_RESPONSE_TRANSFORM, media_transform) - - ts.ctx['transform_add'] = 1 - ts.ctx['fit'] = 0 - ts.ctx['passed'] = 0 -end - - -function do_remap() - - url = ts.client_request.get_url() - ts.debug(string.format('src_url = %s', url)) - - param_s = string.find(url, '?') - start_s, start_e, start_val = string.find(url, 'start=(%d+)', param_s) - - if start_s ~= nil then - end_s, end_e, end_val = string.find(url, 'end=(%d+)', start_e) - offset_s, offset_e, offset_val = string.find(url, 'offset=(%d+)', end_e) - len_s, len_e, len_val = string.find(url, 'len=(%d+)', offset_e) - in_query = true - else - start_s, start_e, start_val = string.find(url, "/start_(%d+)") - end_s, end_e, end_val = string.find(url, "/end_(%d+)", start_e) - offset_s, offset_e, offset_val = string.find(url, "/offset_(%d+)", end_e) - len_s, len_e, len_val = string.find(url, "/len_(%d+)", offset_e) - end - - start_val = tonumber(start_val) - end_val = tonumber(end_val) - offset_val = tonumber(offset_val) - len_val = tonumber(len_val) - - if start_val == nil or end_val == nil or offset_val == nil or len_val == nil then - ts.http.set_resp(400, "params invalid\n") - return 0 - end - - if start_val < 0 or end_val < start_val or offset_val < 0 or len_val <= 0 then - ts.http.set_resp(400, "params invalid\n") - return 0 - end - - if in_query then - slash = url:len() - url:reverse():find("/") + 1 - cache_url = string.format('%sstart_%d/end_%d/%s', string.sub(url, 1, slash), start_val, end_val, string.sub(url, slash+1, param_s-1)) - else - cache_url = string.format('%s%s', string.sub(url, 1, end_e), string.sub(url, len_e)) - end - - ts.debug(string.format('cache_url = %s', cache_url)) - - ts.http.set_cache_url(cache_url) - ts.client_request.header['Range'] = nil - - ts.ctx['start'] = start_val - ts.ctx['end'] = end_val - ts.ctx['offset'] = offset_val - ts.ctx['len'] = len_val - - ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) - ts.hook(TS_LUA_HOOK_READ_RESPONSE_HDR, read_response) - - return 0 -end - diff --git a/plugins/lua/business/sethost.lua b/plugins/lua/example/sethost.lua similarity index 100% rename from plugins/lua/business/sethost.lua rename to plugins/lua/example/sethost.lua