module (..., package.seeall) require ("posix") require ("fs") -- no initializer in model - use controller.init for that -- ################################################################################ -- LOCAL FUNCTIONS local function config_content( f ) local config = {} config.name = "/etc/openvpn/" .. f local conf_file = fs.read_file_as_array ( config.name ) for i=1,table.maxn(conf_file) do local l = conf_file[i] -- Filter out commented lines if not string.find ( l, "^[;#].*" ) then local a,b = string.match ( l, "^%s*(%S*)%s+(%S*).*$" ) -- Working exept on 'remote xxxxx xxxx' -- FIXME: Problem with clients 'remote' values (the port num to the remote) -- local a,b = string.match ( l, "^%s*(%S*)%s+(.*)%s+$" ) -- This brakes client/server check if (a) then config[a]=b end end end if not ( config.log ) then config.log = config["log-append"] end if not ( config["max-clients"] ) then config["max-clients"] = "Unlimited" end if not ( config["local"] ) then config["local"] = "0.0.0.0" end return config end local is_running = function( process, parameters ) local strsplit = require("split") local retval = "" local tst = "" local pidofsx, error = io.popen("pidof " .. process ,r) local pidofs = string.gsub(pidofsx:read("*a"), "\n", "") pidofsx:close() for v in string.gmatch(pidofs, "%S+") do local path = string.gsub("/proc/".. v .. "/cmdline", "%s", "") local f,err = io.open(path,r) local file_resultx = f:read("*a") local file_result = string.match(file_resultx, parameters) f:close() if ( file_result ) then retval = "Running" end end return retval end local function check_valid_config ( f ) config.err = "" if not (config.client) or not (config.ca) or not (config.cert) or not (config.key) or not (config.dev) or not (config.proto) or not (config.remote) then config.type = nil config.err = "" if not (config.ca) then config.err = config.err .. "Check CA; " end if not (config.cert) then config.err = config.err .. "Check CERT; " end if not (config.key) then config.err = config.err .. "Check KEY; " end if not (config.dev) then config.err = config.err .. "Check DEV; " end if not (config.proto) then config.err = config.err .. "Check PROTO; " end if (config.client) or not (config.ca) or not (config.cert) or not (config.key) or not (config.dev) or not (config.proto) or not (config.port) then config.type = nil else config.type = "server" config.err = "" end else config.type = "client" config.err = "" end if not (config.type) then config.type = "unknown" end return config.type, config.err end local function list_conffiles() local configfiles = {} local config = {} local files , errstr, errno = posix.dir ( "/etc/openvpn/" ) if files then for k,v in ipairs(files) do if string.match (v, "^.*conf$") then table.insert ( configfiles, cfe{ name = v } ) end end return configfiles end end -- ################################################################################ -- PUBLIC FUNCTIONS function clientlist( self, path ) local libdate = require("date") local clientlist = {} local routinglist = {} local datechange = {} local list = {} local f = "" local clientlst = nil local routinglst = nil local strsplit = require("split") if ( path ) then config = config_content ( path ) end if (config.status) then local f = fs.read_file_as_array( config.status ) if ( f ) then for k,v in ipairs(f) do local col = strsplit(",", v) if ( col[1] == "ROUTING TABLE" ) or ( col[1] == "GLOBAL STATS" ) then clientlst = nil routinglst = nil end if ( clientlst ) then table.insert(clientlist, { CN=col[1], REALADDR=col[2], BYTESRCV=col[3], BYTESSND=col[4], CONN=col[5] } ) end if ( routinglst ) then table.insert(routinglist, { VIRTADDR=col[1], CN=col[2], REALADDR=col[3], LAST=col[4] } ) if (col[4]) then local month,day,hour,min,sec,year = string.match(col[4],"^%S+%s+(%S+)%s+(%S+)%s+(%d%d):(%d%d):(%d%d)%s+(%S+)") table.insert(datechange, { year=year, month=libdate.abr_month_num(month), day=day, hour=hour, min=min, sec=sec } ) end end if ( col[1] == "Virtual Address" ) then routinglst = "YES" end if ( col[1] == "Common Name" ) then clientlst = "YES" end end end end -- JOIN 'CLIENT_LIST' and 'ROUTING_LIST' TABLES INTO ONE TABLE AND LATER ON PRESENT THIS TABLE for k,v in ipairs(clientlist) do for kk,vv in ipairs(routinglist) do if ( v.CN == vv.CN ) then table.insert(list, { CN=v.CN, REALADDR=v.REALADDR, BYTESRCV=v.BYTESRCV, BYTESSND=v.BYTESSND, VIRTADDR=vv.VIRTADDR, CONN=v.CONN, LAST = LAST } ) end end end connclients = table.maxn(list) if ( connclients > 0 ) then -- FIXME: If possible, use lib/date.lua instead of the following code. local lastdatechange = libdate.date_to_seconds(datechange) lastdatechangetxt = os.date("%c", lastdatechange[#lastdatechange]) lastdatechangediff = os.time() - os.date(lastdatechange[table.maxn(lastdatechange)]) if (lastdatechangediff > 60) then lastdatechangediff = math.modf(lastdatechangediff / 60) .. " min" else lastdatechangediff = lastdatechangediff .. " sec" end end return list, connclients, lastdatechangetxt, lastdatechangediff end function openvpn_version() local f,error = io.popen("/usr/sbin/openvpn --version") openvpnversion = f:read("*l") f:close() if not (openvpnversion) then openvpnversion = "Not installed!" end return openvpnversion end function get_serverconfig ( self, f ) local serverconfig = {} config = config_content ( f ) local clientlist, connclients, lastupdate, lastdatechangediff = clientlist () local isrunning = is_running ("openvpn", f) serverconfig = cfe{ name = f, device = config.dev, log = config.log, verb = config.verb, maxclients = config["max-clients"], clients = connclients, status = isrunning, dh = config.dh, ca = config.ca, cert = config.cert, key = config.key, tls = config["tls-auth"] , crl = config["crl-verify"], port = config.port, proto = config.proto, loca = config["local"], longname = config.name, lastdatechangetxt = lastdatechangetxt, lastdatechangediff = lastdatechangediff, remote = config.remote } return serverconfig end function get_logfile( self, path) local logcontent = {} config = config_content ( path ) local logfilecontent = fs.read_file ( config.log ) if not (logfilecontent) then logfilecontent = "File is empty or missing!" end return ( { name = config.log, value = logfilecontent } ) end function get_config( self, path) local logcontent = {} config = config_content ( path ) local logfilecontent = fs.read_file ( config.name ) if not (logfilecontent) then logfilecontent = "File is empty or missing!" end return ( { name = config.name, shortname = path, value = logfilecontent } ) end function get_conflist () local configlist = {} for k,v in pairs(list_conffiles()) do config = config_content ( v.name ) local conf_type, err = check_valid_config ( v.name ) local isrunning = is_running ("openvpn", v.name) local clientlist, connclients = clientlist () table.insert ( configlist, cfe{ name = v.name, type = conf_type, test = config.ca, err = err, status = isrunning, clients = connclients } ) end local countconfigs = table.maxn(configlist) return configlist, countconfigs end get = function (self) return list_conffiles() end