module (..., package.seeall) require ("posix") require ("format") require ("fs") require ("procps") local baseurl = "/etc/openvpn/" -- no initializer in model - use controller.init for that -- ################################################################################ -- LOCAL FUNCTIONS local function file_info ( path ) require("posix") local filedetails = posix.stat(path) filedetails["owner"]=rawget((posix.getpasswd(filedetails["uid"])),"name") filedetails["group"]=rawget((posix.getgroup(filedetails["gid"])),"name") filedetails["atimelong"]=os.date("%c", filedetails["atime"]) filedetails["mtimelong"]=os.date("%c", filedetails["mtime"]) filedetails["longname"]=path filedetails["name"]=basename(path) filedetails["size"]=filedetails["size"] .. " bytes" return filedetails end local function config_content( f ) local config = {} config.name = baseurl .. 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*).*$" ) if (a) then config[string.lower(a)]=b end if (a == "remote") then config["remoteport"]=string.match ( l, "^%s*%S+%s+%S+%s+(%S*)" ) 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 config["linkname"]=basename(f) 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 i,v for i,v in ipairs(procps.pidof(process) or {}) 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 ( baseurl ) 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(clientlist) 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_config ( self, f ) local path = basename(f) local configresult = {} config = nil config = config_content ( path ) local clientlist, client_count, client_lastupdate, client_lastdatechangediff = clientlist () local status_isrunning = is_running ("openvpn", path) if (client_lastupdate == nil) then config["client_lastupdate"] = "?" else config["client_lastupdate"]=client_lastupdate end if (client_lastupdate == nil) then config["client_lastdatechangediff"] = "? min" else config["client_lastdatechangediff"]=client_lastdatechangediff end config["client_count"]=client_count config["status_isrunning"]=status_isrunning configresult = config return configresult end function update_filecontent (self, f, modifications) name = basename(f) path = baseurl .. name local available_files = list_conffiles() for k,v in pairs(available_files) do if ( available_files[k].name == name ) then local file = io.open( path, "w+" ) local file_result,err = file:write(format.dostounix(modifications)) file:close() if (err ~= nil) then local filedetails = get_config(name) file_content = {name=name, value=file_result, filedetails=filedetails, err=err} end end end return file_content end function get_logfile( self, path) 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_filecontent( self, f) local path = basename(f) local configresult = {} config = config_content ( path ) local file = io.open( config.name ) local file_result = file:read("*a") or "unknown" file:close() local conf_type, err = check_valid_config ( path ) local filedetails = file_info( config.name ) file_content = cfe{name=config.name, value=file_result, type=conf_type, filedetails=filedetails} return file_content end function get_conflist () local configlist = {} for k,v in pairs(list_conffiles() or {}) 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, err = err, status = isrunning, clients = connclients } ) end local countconfigs = table.maxn(configlist) return configlist, countconfigs end get = function (self) return list_conffiles() end