diff options
author | Ted Trask <ttrask01@yahoo.com> | 2008-08-20 19:02:16 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2008-08-20 19:02:16 +0000 |
commit | 8730ef0997957b46d392b981913d8934373e980a (patch) | |
tree | b9cd2e28088756e1441e76790242a5890c14b945 | |
parent | 4f7c42c67f5e22295d178b924861f150c35132c0 (diff) | |
download | acf-tcpproxy-8730ef0997957b46d392b981913d8934373e980a.tar.bz2 acf-tcpproxy-8730ef0997957b46d392b981913d8934373e980a.tar.xz |
Modified tcpproxy to add in SMTP proxy support. Entries are directly edited, this still has to be improved.
git-svn-id: svn://svn.alpinelinux.org/acf/tcpproxy/trunk@1388 ab2d0c66-481e-0410-8bed-d214d4d58bed
-rw-r--r-- | tcpproxy-controller.lua | 32 | ||||
l--------- | tcpproxy-createsmtpfile-html.lsp | 1 | ||||
-rw-r--r-- | tcpproxy-editsmtpentry-html.lsp | 11 | ||||
l--------- | tcpproxy-editsmtpfile-html.lsp | 1 | ||||
-rw-r--r-- | tcpproxy-listsmtpentries-html.lsp | 29 | ||||
-rw-r--r-- | tcpproxy-listsmtpfiles-html.lsp | 32 | ||||
-rw-r--r-- | tcpproxy-model.lua | 240 | ||||
-rw-r--r-- | tcpproxy-smtpstatus-html.lsp | 15 | ||||
-rw-r--r-- | tcpproxy.menu | 1 | ||||
-rw-r--r-- | tcpproxy.roles | 6 |
10 files changed, 366 insertions, 2 deletions
diff --git a/tcpproxy-controller.lua b/tcpproxy-controller.lua index 45044e0..802f1de 100644 --- a/tcpproxy-controller.lua +++ b/tcpproxy-controller.lua @@ -16,3 +16,35 @@ end function expert(self) return controllerfunctions.handle_form(self, self.model.getconfigfile, self.model.setconfigfile, self.clientdata, "Save", "Edit Config", "Configuration Saved") end + +function smtpstatus(self) + return self.model.getsmtpstatus() +end + +function listsmtpentries(self) + return self.model.listsmtpentries(self) +end + +function editsmtpentry(self) + return controllerfunctions.handle_form(self, function() return self.model.readsmtpentry(self.clientdata.ipaddr) end, self.model.updatesmtpentry, self.clientdata, "Save", "Edit SMTP Proxy Entry", "SMTP Proxy Entry Saved" ) +end + +function delsmtpentry(self) + return self:redirect_to_referrer(self.model.delsmtpentry(self.clientdata.ipaddr)) +end + +function listsmtpfiles(self) + return self.model.listsmtpfiles(self) +end + +function createsmtpfile(self) + return controllerfunctions.handle_form(self, self.model.getnewsmtpfile, self.model.createsmtpfile, self.clientdata, "Create", "Create New SMTP Proxy File", "SMTP Proxy File Created") +end + +function editsmtpfile(self) + return controllerfunctions.handle_form(self, function() return self.model.readsmtpfile(self.clientdata.filename) end, self.model.updatesmtpfile, self.clientdata, "Save", "Edit SMTP Proxy File", "SMTP Proxy File Saved" ) +end + +function delsmtpfile(self) + return self:redirect_to_referrer(self.model.delsmtpfile(self.clientdata.filename)) +end diff --git a/tcpproxy-createsmtpfile-html.lsp b/tcpproxy-createsmtpfile-html.lsp new file mode 120000 index 0000000..4b6b762 --- /dev/null +++ b/tcpproxy-createsmtpfile-html.lsp @@ -0,0 +1 @@ +../form-html.lsp
\ No newline at end of file diff --git a/tcpproxy-editsmtpentry-html.lsp b/tcpproxy-editsmtpentry-html.lsp new file mode 100644 index 0000000..61579d4 --- /dev/null +++ b/tcpproxy-editsmtpentry-html.lsp @@ -0,0 +1,11 @@ +<% local form, viewlibrary, page_info = ... +require("viewfunctions") +%> + +<H1><%= form.label %></H1> +<% + form.action = page_info.script .. page_info.prefix .. page_info.controller .. "/" .. page_info.action + form.value.ipaddr.contenteditable = false + local order = {"ipaddr"} + displayform(form, order) +%> diff --git a/tcpproxy-editsmtpfile-html.lsp b/tcpproxy-editsmtpfile-html.lsp new file mode 120000 index 0000000..15b1930 --- /dev/null +++ b/tcpproxy-editsmtpfile-html.lsp @@ -0,0 +1 @@ +../filedetails-html.lsp
\ No newline at end of file diff --git a/tcpproxy-listsmtpentries-html.lsp b/tcpproxy-listsmtpentries-html.lsp new file mode 100644 index 0000000..7cfa651 --- /dev/null +++ b/tcpproxy-listsmtpentries-html.lsp @@ -0,0 +1,29 @@ +<% local view, viewlibrary, page_info, session = ... +require("viewfunctions") +%> + +<% displaycommandresults({"delsmtpentry"}, session) %> + +<H1>Interface Entries</H1> +<DL> +<TABLE> + <TR style="background:#eee;font-weight:bold;"> + <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Action</TD> + <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Interface</TD> + <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">IP Address</TD> + <TD style="white-space:nowrap;text-align:left;" class="header">Command Entry</TD> + </TR> +<% for i,interface in ipairs(view.value) do %> + <TR> + <TD style="padding-right:20px;white-space:nowrap;"> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/editsmtpentry?ipaddr="..(interface.ipaddr or interface.interface), label="Edit "} %> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/delsmtpentry?ipaddr="..(interface.ipaddr or interface.interface), label="Delete "} %> + </TD> + <TD style="padding-right:20px;white-space:nowrap;"><%= interface.interface or "" %></TD> + <TD style="padding-right:20px;white-space:nowrap;"><%= interface.ipaddr or "" %></TD> + <TD style="white-space:nowrap;"><%= interface.cmd or "" %></TD> + </TR> +<% end %> +</TABLE> + +</DL> diff --git a/tcpproxy-listsmtpfiles-html.lsp b/tcpproxy-listsmtpfiles-html.lsp new file mode 100644 index 0000000..753857b --- /dev/null +++ b/tcpproxy-listsmtpfiles-html.lsp @@ -0,0 +1,32 @@ +<% local view, viewlibrary, page_info, session = ... +require("viewfunctions") +%> + +<% displaycommandresults({"delsmtpfile"}, session) %> + +<H1>Files</H1> +<DL> +<TABLE> + <TR style="background:#eee;font-weight:bold;"> + <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Action</TD> + <TD style="white-space:nowrap;text-align:left;" class="header">File</TD> + </TR> +<% for i,file in ipairs(view.value) do %> + <TR> + <TD style="padding-right:20px;white-space:nowrap;"> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/editsmtpfile?filename="..file, label="Edit "} %> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/delsmtpfile?filename="..file, label="Delete "} %> + </TD> + <TD style="white-space:nowrap;"><%= file %></TD> + </TR> +<% end %> +</TABLE> +</DL> + +<% if viewlibrary and viewlibrary.dispatch_component then + local createform = viewlibrary.dispatch_component("createsmtpfile", nil, true) %> +<H2><%= createform.label %></H2> +<% + createform.action = page_info.script .. page_info.prefix .. page_info.controller .. "/createsmtpfile" + displayform(createform) +end %> diff --git a/tcpproxy-model.lua b/tcpproxy-model.lua index 57bb845..b1caf83 100644 --- a/tcpproxy-model.lua +++ b/tcpproxy-model.lua @@ -2,15 +2,39 @@ module(..., package.seeall) -- Load libraries require("modelfunctions") +require("validator") +require("fs") +require("posix") -- Set variables local configfile = "/etc/tcpproxy.conf" local processname = "tcpproxy" local packagename = "tcpproxy" +local smtppackagename = "rxmtp" +local smtpdirectory = "/etc/rxmtp/" + +local keywords = { "standalone", "port", "interface", "rotate", "server", "uid", "gid", "user", "exec", "acp", "logname", "setenv", "timeout", "writefile" } +local config -- ################################################################################ -- LOCAL FUNCTIONS +local function parseconfigfile(file) + file = file or "" + local retval = {} + for line in string.gmatch(file, "([^\n]+)\n?") do + line = string.gsub(line, "#.*$", "") + if line and line ~= "" then + table.insert(retval, {}) + for word in string.gmatch(line, "%S+") do + table.insert(retval[#retval], word) + end + end + end + + return retval +end + -- ################################################################################ -- PUBLIC FUNCTIONS @@ -30,3 +54,219 @@ function setconfigfile(filedetails) filedetails.value.filename.value = configfile return modelfunctions.setfiledetails(filedetails) end + +local function getsmtpconfig(config) + -- parse the TCP proxy config file for smtp entries + local retval = {} + local port25 = false + local currentint + for i,entry in ipairs(config) do + if entry[1] == "port" then + if entry[2] == "25" then + port25 = true + currentint = nil + else + port25 = false + currentint = nil + end + elseif port25 then + if entry[1] == "interface" then + currentint = entry[2] + elseif entry[1] == "exec" and string.find(entry[2], "rxmtp$") then + if currentint then + table.insert(retval, {ipaddr=currentint, cmd=table.concat(entry, " ", 2)}) + else + -- bad config - exec command without interface + end + end + end + end + + return retval +end + +local function setsmtpcmd(ipaddr, cmd) + if cmd then cmd = "exec "..cmd end + local file = fs.read_file(configfile) + local inport25 = false + local ininterface = false + local done = false + local lines = {} + for line in string.gmatch(file, "([^\n]*)\n?") do + if not done then + if ininterface and string.find(line, "^%s*exec%s") then + -- We found the line, replace it + line = cmd + done = true + elseif ininterface and string.find(line, "^%s*interface%s") then + -- We're leaving the interface and we haven't written line yet + if cmd then + if string.find(lines[#lines], "^%s*$") then lines[#lines] = nil end + lines[#lines + 1] = "exec "..cmd + lines[#lines + 1] = "" + end + done = true + elseif inport25 and string.find(line, "^%s*interface%s+"..ipaddr) then + ininterface = true + elseif inport25 and string.find(line, "^%s*port%s") then + -- we're leaving port 25 and we haven't written line yet + if cmd then + lines[#lines + 1] = "interface "..ipaddr + lines[#lines + 1] = "exec "..cmd + lines[#lines + 1] = "" + end + done = true + elseif string.find(line, "^%s*port%s+25") then + inport25 = true + end + end + lines[#lines + 1] = line + end + if not done and cmd then + if not inport25 then lines[#lines + 1] = "port 25" end + if not ininterface then lines[#lines + 1] = "interface "..ipaddr end + lines[#lines + 1] = "exec "..cmd + end + + fs.write_file(configfile, table.concat(lines, "\n")) +end + +function getsmtpstatus() + local value, errtxt = processinfo.package_version(smtppackagename) + local version = cfe({ value=value, label="Program version" }) + return cfe({ type="group", value={version=version, entries=entries}, label="SMTP Proxy Status" }) +end + +function listsmtpentries(self) + local entries = cfe({ type="structure", value={}, label="SMTP Command Entries" }) + if self then + local interfacescontroller = self:new("alpine-baselayout/interfaces") + local interfaces = interfacescontroller.model:get_addresses() + interfacescontroller:destroy() + -- add in entries for interfaces (w/o ipaddr) + local interface + for i,entry in ipairs(interfaces.value) do + if interface ~= entry.interface then + interface = entry.interface + table.insert(entries.value, {interface=interface}) + end + table.insert(entries.value, entry) + end + end + + local reverseaddress = {} + for i,int in ipairs(entries.value) do reverseaddress[int.ipaddr or int.interface] = i end + + config = config or parseconfigfile(fs.read_file(configfile)) + local smtpconfig = getsmtpconfig(config) + for i,int in ipairs(smtpconfig) do + local pos = reverseaddress[int.ipaddr] + if pos then + entries.value[pos].cmd = int.cmd + else + if not validator.is_ipv4(int.ipaddr) then + int.interface = int.ipaddr + int.ipaddr = nil + end + table.insert(entries.value, int) + end + end + + return entries +end + +function readsmtpentry(ipaddr) + config = config or parseconfigfile(fs.read_file(configfile)) + local smtpconfig = getsmtpconfig(config) + local exec = "" + for i,entry in ipairs(smtpconfig) do + if entry.ipaddr == ipaddr then + exec = entry.cmd + break + end + end + + local ipaddrcfe = cfe({ value=ipaddr, label="Interface / IP Address" }) + local execcfe = cfe({ value=exec, label="Command" }) + return cfe({ type="group", value={exec=execcfe, ipaddr=ipaddrcfe}, label="SMTP Proxy Entry" }) +end + +function updatesmtpentry(entry) + -- validate? + setsmtpcmd(entry.value.ipaddr.value, entry.value.exec.value) + return entry +end + +function delsmtpentry(ipaddr) + setsmtpcmd(ipaddr, nil) + return cfe({ value="Deleted SMTP Proxy Entry", label="Delete SMTP Entry result" }) +end + +function listsmtpfiles() + local retval = cfe({ type="list", value={}, label="SMTP Proxy Files" }) + if not fs.is_dir(smtpdirectory) then posix.mkdir(smtpdirectory) end + for file in posix.files(smtpdirectory) do + if fs.is_file(smtpdirectory .. file) then + table.insert(retval.value, smtpdirectory .. file) + end + end + return retval +end + +function getnewsmtpfile() + local filename = cfe({ label="File Name", descr="Must be in "..smtpdirectory }) + return cfe({ type="group", value={filename=filename}, label="SMTP Proxy File" }) +end + +function createsmtpfile(filedetails) + local success = true + + if not validator.is_valid_filename(filedetails.value.filename.value, smtpdirectory) then + success = false + filedetails.value.filename.errtxt = "Invalid filename" + else + if not fs.is_dir(smtpdirectory) then posix.mkdir(smtpdirectory) end + if posix.stat(filedetails.value.filename.value) then + success = false + filedetails.value.filename.errtxt = "Filename already exists" + end + end + + if success then + fs.create_file(filedetails.value.filename.value) + else + filedetails.errtxt = "Failed to Create File" + end + + return filedetails +end + +function readsmtpfile(filename) + if validator.is_valid_filename(filename, smtpdirectory) and fs.is_file(filename) then + return modelfunctions.getfiledetails(filename) + end + local retval = modelfunctions.getfiledetails("") + retval.value.filename.value = filename + return retval +end + +function updatesmtpfile(filedetails) + if validator.is_valid_filename(filedetails.value.filename.value, smtpdirectory) and fs.is_file(filedetails.value.filename.value) then + return modelfunctions.setfiledetails(filedetails) + end + filedetails.value.filename.errtxt = "Invalid Filename" + filedetails.errtxt = "Failed to set file" + return filedetails +end + +function delsmtpfile(filename) + local retval = cfe({ value="Deleted SMTP Proxy File", label="Delete SMTP File result" }) + if validator.is_valid_filename(filename, smtpdirectory) and fs.is_file(filename) then + os.remove(filename) + else + retval.value = "Failed to delete SMTP Proxy File - invalid filename" + end + + return retval +end + diff --git a/tcpproxy-smtpstatus-html.lsp b/tcpproxy-smtpstatus-html.lsp new file mode 100644 index 0000000..c639424 --- /dev/null +++ b/tcpproxy-smtpstatus-html.lsp @@ -0,0 +1,15 @@ +<% local view, viewlibrary, page_info, session = ... +require("viewfunctions") +%> + +<% displaycommandresults({"delsmtpentry", "delsmtpfile"}, session) %> + +<H1>SMTP Proxy Status</H1> +<DL> +<% displayitem(view.value.version) %> +</DL> + +<% if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("listsmtpentries") + viewlibrary.dispatch_component("listsmtpfiles") +end %> diff --git a/tcpproxy.menu b/tcpproxy.menu index 0f68d61..da4fdc1 100644 --- a/tcpproxy.menu +++ b/tcpproxy.menu @@ -1,3 +1,4 @@ #CAT GROUP/DESC TAB ACTION Networking 35TCP_Proxy Status status +Networking 35TCP_Proxy SMTP_Proxy smtpstatus Networking 35TCP_Proxy Expert expert diff --git a/tcpproxy.roles b/tcpproxy.roles index 9b40383..803e033 100644 --- a/tcpproxy.roles +++ b/tcpproxy.roles @@ -1,2 +1,4 @@ -READ=tcpproxy:status -UPDATE=tcpproxy:startstop,tcpproxy:expert +READ=tcpproxy:status,tcpproxy:smtpstatus,tcpproxy:listsmtpentries,tcpproxy:listsmtpfiles +UPDATE=tcpproxy:startstop,tcpproxy:expert,tcpproxy:editsmtpentry,tcpproxy:editsmtpfile +DELETE=tcpproxy:delsmtpentry,tcpproxy:delsmtpfile +CREATE=tcpproxy:createsmtpfile |