標籤:
在為mysql-proxy編寫lua腳步的時候,需要知道一下幾個入口函數,通過這幾個入口函數我們可以控制mysql-proxy的一些行為。
- connect_server() 當Proxy 伺服器接受到用戶端串連請求時(tcp中的握手)會調用該函數
- read_handshake() 當mysql伺服器返回握手相應時會被調用
- read_auth() 當用戶端發送認證資訊(username,password,port,database)時會被調用
- read_auth_result(aut) 當mysql返回認證結果時會被調用
- read_query(packet) 當用戶端提交一個sql語句時會被調用
- read_query_result(inj) 當mysql返回查詢結果時會被調用
1.connect_server使用
function read_handshake( ) local con = proxy.connection print("<-- let‘s send him some information about us") print(" server-addr : " .. con.server.dst.name) print(" client-addr : " .. con.client.src.name)
-- lets deny clients from !127.0.0.1
if con.client.src.address ~= "127.0.0.1" then
proxy.response.type = proxy.MYSQLD_PACKET_ERR
proxy.response.errmsg = "only local connects are allowed"
print("we don‘t like this client");
return proxy.PROXY_SEND_RESULT
end
end
擷取代理的連結化物件,這個對象是全域的,可以在函數中直接拿來使用。從連線物件中我們可以拿到用戶端名稱和伺服器名稱,通過也能獲得用戶端的ip地址,上面的代碼就是禁止非本機ip登入mysql。
2、read_auth使用
讀取使用者的認證資訊包括使用者名稱、密碼、所要串連的資料庫。其中的proxy.MYSQLD_PACKET_ERR是mysql-proxy中內建的常量。
function read_auth( ) local con = proxy.connection print("--> there, look, the client is responding to the server auth packet") print(" username : " .. con.client.username) print(" password : " .. string.format("%q", con.client.scrambled_password)) print(" default_db : " .. con.client.default_db) if con.client.username == "evil" then proxy.response.type = proxy.MYSQLD_PACKET_ERR proxy.response.errmsg = "evil logins are not allowed" return proxy.PROXY_SEND_RESULT endend3.read_auth_result使用
通過該方法我們可以獲得mysql資料庫的認證結果,認證結果由auth對象持有,我們可以訪問其packet屬性(字串類型),可以查看返回結果。字串的第一個字元是對結果的標識。
function read_auth_result( auth ) local state = auth.packet:byte() //擷取第一個字元並將其轉為整型 if state == proxy.MYSQLD_PACKET_OK then print("<-- auth ok"); elseif state == proxy.MYSQLD_PACKET_ERR then print("<-- auth failed"); else print("<-- auth ... don‘t know: " .. string.format("%q", auth.packet)); endend4.read_query的使用
packet中就存放著客戶請求的SQL語句,類型為字串類型。起始第一個字元同上,為標識符。這裡判斷是不是一個查詢語句,是的話就從第二個字元開始輸出查詢語句。
function read_query( packet ) print("--> someone sent us a query") if packet:byte() == proxy.COM_QUERY then print(" query: " .. packet:sub(2)) if packet:sub(2) == "SELECT 1" then proxy.queries:append(1, packet) end endend5、read_query_result使用
其實我們該函數和read_query函數時是希望對SQL語句進行處理,但是由於時間有限,不能對mysql-proxy提供的sql處理繼續研究,這裡先就先貼出來。
function read_query_result( inj ) print("<-- ... ok, this only gets called when read_query() told us") proxy.response = { type = proxy.MYSQLD_PACKET_RAW, packets = { "\255" .. "\255\004" .. -- errno "#" .. "12S23" .. "raw, raw, raw" } } return proxy.PROXY_SEND_RESULTend
--[[ $%BEGINLICENSE%$ Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $%ENDLICENSE%$ --]]local proto = require("mysql.proto")local prep_stmts = { }function read_query( packet ) local cmd_type = packet:byte() if cmd_type == proxy.COM_STMT_PREPARE then proxy.queries:append(1, packet, { resultset_is_needed = true } ) return proxy.PROXY_SEND_QUERY elseif cmd_type == proxy.COM_STMT_EXECUTE then proxy.queries:append(2, packet, { resultset_is_needed = true } ) return proxy.PROXY_SEND_QUERY elseif cmd_type == proxy.COM_STMT_CLOSE then proxy.queries:append(3, packet, { resultset_is_needed = true } ) return proxy.PROXY_SEND_QUERY endendfunction read_query_result(inj) if inj.id == 1 then -- print the query we sent local stmt_prepare = assert(proto.from_stmt_prepare_packet(inj.query)) print(("> PREPARE: %s"):format(stmt_prepare.stmt_text)) -- and the stmt-id we got for it if inj.resultset.raw:byte() == 0 then local stmt_prepare_ok = assert(proto.from_stmt_prepare_ok_packet(inj.resultset.raw)) print(("< PREPARE: stmt-id = %d (resultset-cols = %d, params = %d)"):format( stmt_prepare_ok.stmt_id, stmt_prepare_ok.num_columns, stmt_prepare_ok.num_params)) prep_stmts[stmt_prepare_ok.stmt_id] = { num_columns = stmt_prepare_ok.num_columns, num_params = stmt_prepare_ok.num_params, } end elseif inj.id == 2 then local stmt_id = assert(proto.stmt_id_from_stmt_execute_packet(inj.query)) local stmt_execute = assert(proto.from_stmt_execute_packet(inj.query, prep_stmts[stmt_id].num_params)) print(("> EXECUTE: stmt-id = %d"):format(stmt_execute.stmt_id)) if stmt_execute.new_params_bound then for ndx, v in ipairs(stmt_execute.params) do print((" [%d] %s (type = %d)"):format(ndx, tostring(v.value), v.type)) end end elseif inj.id == 3 then local stmt_close = assert(proto.from_stmt_close_packet(inj.query)) print(("> CLOSE: stmt-id = %d"):format(stmt_close.stmt_id)) prep_stmts[stmt_close.stmt_id] = nil -- cleanup endendView Code
這裡使用了MySQL新的介面stmt,對其不瞭解可以查看下面的串連。
戳我
Mysql-proxy中的lua指令碼編程(一)