From: Roman Bazalevsky Date: Thu, 26 Sep 2019 18:45:36 +0000 (+0300) Subject: Первый вариант. Внешний ACL-helper для идентификации пользователей прозрачного squid... X-Git-Url: https://git.rvb.name/lua-squid-acl-helper.git/commitdiff_plain/2e41ad1dc4bac0a74a64a14fabec46bd0aeb7fae?ds=sidebyside Первый вариант. Внешний ACL-helper для идентификации пользователей прозрачного squid с использованием ident и учетом маппинга портов. --- 2e41ad1dc4bac0a74a64a14fabec46bd0aeb7fae diff --git a/src/arpcache.lua b/src/arpcache.lua new file mode 100644 index 0000000..1ae8136 --- /dev/null +++ b/src/arpcache.lua @@ -0,0 +1,51 @@ +-- module to access linux ARP cache + +config = require "config" + +_arpcache = {} +_ARPCACHE4 = '/sbin/ip -4 n' +_ARPCACHE6 = '/sbin/ip -6 n' + +function _match_v4(ip) + return string.match(ip,"%d*%.%d*%.%d*%.%d*") +end + +function _arpcache.get_mac(ip) + + local cmd + if _match_v4(ip) then + cmd = _ARPCACHE4 + else + cmd = _ARPCACHE6 + end + + local f = io.popen(cmd) + local res = nil + local line, w + + while true do + + line = f:read() + if not line then + break + end + + w = {} + + for k in string.gmatch(line, "(%S+)") do + table.insert(w, k) + end + + if w[1]==ip then + res = w[5] + break + end + + end + + f:close() + return res + +end + +return _arpcache diff --git a/src/config.json b/src/config.json new file mode 100644 index 0000000..72f54e8 --- /dev/null +++ b/src/config.json @@ -0,0 +1,39 @@ +{ + +"ident": { + "timeout": 2, + "default": "" +}, + +"portmap" : { + + "3128" : "80", + "3130" : "80", + "3131" : "443", + "3132" : "443" + +}, + +"hosts" : { + "ip": { + + "192.168.1.100": "*ident", + "2001:470:6f:9d5::100": "*ident", + + "192.168.1.4": "net" + + }, + + "mac": { + + "00:1f:c6:86:f7:9c": "*ident", + + "90:a2:da:f8:0b:73": "media", + + "ea:cf:b0:f9:24:43": "camera" + + } + + } + +} diff --git a/src/config.lua b/src/config.lua new file mode 100644 index 0000000..6c427cb --- /dev/null +++ b/src/config.lua @@ -0,0 +1,64 @@ +json = require "json" + +_config = {} + +function _config.read(file) + + local file = file or "/opt/squid-auth-helper/config.json" + local f = assert(io.open(file)) + local cfg = json.decode(f:read("*all")) + + _config.pmap = cfg["portmap"] or {} + + _config.ident_timeout = 2 + _config.ident_default = nil + + if cfg["ident"] then + _config.ident_timeout = cfg["ident"]["timeout"] or _config.ident_timeout + _config.ident_default = cfg["ident"]["default"] or _config.ident_default + end + + _config.ipmap = {} + _config.macmap = {} + + if cfg["hosts"] then + if cfg["hosts"]["ip"] then + for k, v in pairs(cfg["hosts"]["ip"]) do + local k, n = string.gsub(k, "%.", "%%.") + local k, n = string.gsub(k,"%*",".*") + _config.ipmap["^"..k.."$"] = v + end + end + if cfg["hosts"]["mac"] then + for k, v in pairs(cfg["hosts"]["mac"]) do + local k, n = string.gsub(k,"%*",".*") + _config.macmap["^"..k.."$"] = v + end + end + end + +end + +function _config.map_port(port) + return _config.pmap[tostring(port)] or port +end + +function _config.map_ip(ip) + for k,v in pairs(_config.ipmap) do + if string.match(ip,k) then + return v + end + end + return nil +end + +function _config.map_mac(mac) + for k,v in pairs(_config.macmap) do + if string.match(mac,k) then + return v + end + end + return nil +end + +return _config diff --git a/src/connection.lua b/src/connection.lua new file mode 100644 index 0000000..e1eff46 --- /dev/null +++ b/src/connection.lua @@ -0,0 +1,26 @@ +_connection = {} + +config = require "config" +ident = require "ident" +arpcache = require "arpcache" + +function _connection.auth(serv, localport, remoteport) + + local user = config.map_ip(serv) + + if not user then + local mac = arpcache.get_mac(serv) + if mac then + user = config.map_mac(mac) + end + end + + if user == "*ident" then + user = ident.resolve(serv,localport,config.map_port(remoteport)) + end + + return user + +end + +return _connection diff --git a/src/helper.lua b/src/helper.lua new file mode 100755 index 0000000..79711e2 --- /dev/null +++ b/src/helper.lua @@ -0,0 +1,42 @@ +#!/usr/bin/lua + +config = require "config" +connection = require "connection" + +io.stdout:setvbuf 'no' +io.stdin:setvbuf 'no' + +if arg then + cf = arg[1] +else + cf = nil +end + +config.read(cf) + +function string:split(sep) + local sep, fields = sep or ":", {} + local pattern = string.format("([^%s]+)", sep) + self:gsub(pattern, function(c) fields[#fields+1] = c end) + return fields +end + +function main() + while true do + str=io.read() + vals = str:split(" ") + status, res = pcall(connection.auth,vals[1],vals[2],vals[3]) + if status then + if res and res ~= "" then + io.write("OK user="..res.."\n") + else + io.write("OK\n") + end + else + io.write("BH\n") + end + end +end + +main() + diff --git a/src/ident.lua b/src/ident.lua new file mode 100644 index 0000000..1567fc0 --- /dev/null +++ b/src/ident.lua @@ -0,0 +1,35 @@ +config = require("config") + +local socket = require("socket") + +_ident = {} + +_IDENTD_PORT = 113 + +function _ident.resolve(serv, port, remote) + + local tcp = assert(socket.tcp()) + tcp:settimeout(config.ident_timeout, 't') + tcp:connect(serv,_IDENTD_PORT) + tcp:send(tostring(port) .. ", "..tostring(remote).."\n") + + res = "" + while true do + local s, status, partial = tcp:receive() + res = res..(s or partial) + if status == "closed" then break end + end + + tcp:close() + + local uname = config.ident_default + + for user in string.gmatch(res,"%d*,%d*:USERID:UNIX:(.*)") do + uname = user + end + + return uname + +end + +return _ident