From 0b1d5e7d461b6b7535ef4aff33d4813e46a0062b Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Tue, 7 Jul 2026 08:47:53 +1200 Subject: [PATCH] port_forwarding: add source-zone selector for extra WAN VLANs basic.js's WAN VLAN table (PR #33) lets a router have more than one WAN zone (the default 'wan' plus 'wan_vlan' zones for each additive VLAN row), but every port forward and open-port rule was still hardcoded to src='wan' -- there was no way to route a forward at a specific WAN VLAN (e.g. an ISP's IPTV/VoIP VLAN) rather than the primary connection. Each of the 4 rule tables (single/range forward, single/range open) now has a Source Zone column and a matching dropdown in its add/edit modal, populated from the firewall zones currently present (uciOriginal already has both firewall and network injected on this page, so no backend change was needed) -- 'wan' plus any 'wan_vlan' zone, shown with its VLAN's own description when set. Zone is now part of a rule's identity for the multi-tab-safe save/reuse logic added in PR #27 -- buildRuleIndex()'s key gained the source zone, and every duplicate/overlap check (proofreadForward*/ proofreadOpen*) and TCP+UDP merge check became zone-aware, so the same external port can now legitimately be forwarded on two different WAN zones without being treated as a collision. Changing an existing rule's zone is treated as an identity change (old section retired, new one allocated), the same way toggling a rule's enabled/disabled state already was. --- .../gargoyle/files/www/js/port_forwarding.js | 146 ++++++++++++------ .../www/templates/multi_forward_template | 4 + .../files/www/templates/multi_open_template | 4 + .../www/templates/single_forward_template | 4 + .../files/www/templates/single_open_template | 4 + .../files/www/i18n/English-EN/port.js | 1 + 6 files changed, 114 insertions(+), 49 deletions(-) diff --git a/package/gargoyle/files/www/js/port_forwarding.js b/package/gargoyle/files/www/js/port_forwarding.js index 434613f996..84e86b313f 100644 --- a/package/gargoyle/files/www/js/port_forwarding.js +++ b/package/gargoyle/files/www/js/port_forwarding.js @@ -8,6 +8,37 @@ var prtS=new Object(); //part of i18n var TSort_Data = new Array ('portf_table', 's', 's', 'i', 'p', 'i', ''); +// Available WAN source zones a forward/open rule can target: the default +// 'wan' zone plus any additive WAN VLAN zone basic.js's WAN VLAN table +// creates (firewall.zone sections named 'wan_vlan'). Both firewall and +// network are already injected into this page (see port_forwarding.sh's +// gargoyle_header_footer package list), so this reads straight out of +// uciOriginal -- no backend change needed. Returns an ordered +// {zoneName: displayLabel} map, 'wan' first. Used both by saveChanges() +// (to key/identify rules by zone) and by the add/edit modals (to populate +// the source-zone dropdown). +function getWanZoneOptionsMap() +{ + var zones = uciOriginal.getAllSectionsOfType("firewall", "zone"); + var found = {}; + for(var i = 0; i < zones.length; i++) + { + var zname = uciOriginal.get("firewall", zones[i], "name"); + if(zname == "wan" || zname.match(/^wan_vlan[0-9]+$/) != null) + { + var zdesc = uciOriginal.get("network", zname, "gargoyle_desc"); + found[zname] = zdesc ? (zdesc + " (" + zname + ")") : zname; + } + } + if(found["wan"] == null) { found["wan"] = "wan"; } + var ordered = {}; + ordered["wan"] = found["wan"]; + Object.keys(found).filter(function(n){ return n != "wan"; }) + .sort(function(a,b){ return parseInt(a.replace("wan_vlan",""),10) - parseInt(b.replace("wan_vlan",""),10); }) + .forEach(function(n){ ordered[n] = found[n]; }); + return ordered; +} + function saveChanges() { errorList = proofreadAll(); @@ -23,9 +54,10 @@ function saveChanges() var firewallSectionCommands = []; // Match existing firewall redirect/rule sections to current-table - // rows by their actual identity (protocol + port(s) + destination -- - // the same fields this page's own duplicate-rule checks already - // treat as what makes a rule unique) instead of deleting every + // rows by their actual identity (source zone + protocol + port(s) + + // destination -- the same fields this page's own duplicate-rule + // checks already treat as what makes a rule unique, now that a rule + // can target any WAN zone, not just 'wan') instead of deleting every // section this tab's uciOriginal knows about and rebuilding all of // them fresh by row position. The old approach meant any save from // this page rewrote every rule wholesale from whatever this tab's @@ -59,7 +91,8 @@ function saveChanges() if(namePrefix != null && secName.indexOf(namePrefix) != 0) { continue; } var proto = uciOriginal.get("firewall", secName, "proto"); var srcdport = uciOriginal.get("firewall", secName, "src_dport"); - var key = (proto||"") + "|" + (srcdport||""); + var srczone = uciOriginal.get("firewall", secName, "src") || "wan"; + var key = srczone + "|" + (proto||"") + "|" + (srcdport||""); if(includeDestInKey) { var destip = uciOriginal.get("firewall", secName, "dest_ip"); @@ -121,16 +154,16 @@ function saveChanges() { var rowData = singlePortData[rowIndex]; - var enabled = rowData[5].checked; + var enabled = rowData[6].checked; var protos = rowData[1].toLowerCase() == UI.both.toLowerCase() ? ["tcp", "udp"] : [ rowData[1].toLowerCase() ]; var protoIndex=0; for(protoIndex=0;protoIndex < protos.length; protoIndex++) { - var key = protos[protoIndex] + "|" + rowData[2]; + var key = rowData[5] + "|" + protos[protoIndex] + "|" + rowData[2]; var id = resolveRuleSection(redirectIndex, key, enabled, "redirect", "redirect_disabled", "redirect_", uci); uci.set("firewall", id, "name", rowData[0]); - uci.set("firewall", id, "src", "wan"); + uci.set("firewall", id, "src", rowData[5]); uci.set("firewall", id, "dest", "lan"); uci.set("firewall", id, "family", "ipv4"); uci.set("firewall", id, "proto", protos[protoIndex]); @@ -146,17 +179,17 @@ function saveChanges() for(rowIndex = 0; rowIndex < portRangeData.length; rowIndex++) { var rowData = portRangeData[rowIndex]; - var enabled = rowData[5].checked; + var enabled = rowData[6].checked; var protos = rowData[1].toLowerCase() == UI.both.toLowerCase() ? ["tcp", "udp"] : [ rowData[1].toLowerCase() ]; var protoIndex=0; for(protoIndex=0;protoIndex < protos.length; protoIndex++) { var srcdport = rowData[2] + "-" + rowData[3]; - var key = protos[protoIndex] + "|" + srcdport; + var key = rowData[5] + "|" + protos[protoIndex] + "|" + srcdport; var id = resolveRuleSection(redirectIndex, key, enabled, "redirect", "redirect_disabled", "redirect_", uci); uci.set("firewall", id, "name", rowData[0]); - uci.set("firewall", id, "src", "wan"); + uci.set("firewall", id, "src", rowData[5]); uci.set("firewall", id, "dest", "lan"); uci.set("firewall", id, "family", "ipv4"); uci.set("firewall", id, "proto", protos[protoIndex]); @@ -224,16 +257,16 @@ function saveChanges() for(rowIndex = 0; rowIndex < singlePortData.length; rowIndex++) { var rowData = singlePortData[rowIndex]; - var enabled = rowData[4].checked; + var enabled = rowData[5].checked; var protos = rowData[1].toLowerCase() == UI.both.toLowerCase() ? ["tcp", "udp"] : [ rowData[1].toLowerCase() ]; var protoIndex=0; for(protoIndex=0;protoIndex < protos.length; protoIndex++) { - var key = protos[protoIndex] + "||" + rowData[2] + "|" + rowData[3]; + var key = rowData[4] + "|" + protos[protoIndex] + "||" + rowData[2] + "|" + rowData[3]; var id = resolveRuleSection(openIndex, key, enabled, "rule", "rule_disabled", "portopen_rule_", uci); uci.set("firewall", id, "name", rowData[0]); - uci.set("firewall", id, "src", "wan"); + uci.set("firewall", id, "src", rowData[4]); uci.set("firewall", id, "dest", "lan"); uci.set("firewall", id, "family", "ipv6"); uci.set("firewall", id, "target", "ACCEPT"); @@ -248,17 +281,17 @@ function saveChanges() for(rowIndex = 0; rowIndex < portRangeData.length; rowIndex++) { var rowData = portRangeData[rowIndex]; - var enabled = rowData[5].checked; + var enabled = rowData[6].checked; var protos = rowData[1].toLowerCase() == UI.both.toLowerCase() ? ["tcp", "udp"] : [ rowData[1].toLowerCase() ]; var protoIndex=0; for(protoIndex=0;protoIndex < protos.length; protoIndex++) { var destport = rowData[2] + "-" + rowData[3]; - var key = protos[protoIndex] + "||" + rowData[4] + "|" + destport; + var key = rowData[5] + "|" + protos[protoIndex] + "||" + rowData[4] + "|" + destport; var id = resolveRuleSection(openIndex, key, enabled, "rule", "rule_disabled", "portopen_rule_", uci); uci.set("firewall", id, "name", rowData[0]); - uci.set("firewall", id, "src", "wan"); + uci.set("firewall", id, "src", rowData[5]); uci.set("firewall", id, "dest", "lan"); uci.set("firewall", id, "family", "ipv6"); uci.set("firewall", id, "target", "ACCEPT"); @@ -322,7 +355,7 @@ function addPortfRule() else { values = new Array(); - ids = ['add_desc', 'add_prot', 'add_fp', 'add_ip', 'add_dp']; + ids = ['add_desc', 'add_prot', 'add_fp', 'add_ip', 'add_dp', 'add_src_zone']; for (idIndex in ids) { element = document.getElementById(ids[idIndex]); @@ -348,7 +381,7 @@ function addPortfRule() { rowData = currentPortfData[rowDataIndex]; - if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3] && values[4] == rowData[4]) + if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3] && values[4] == rowData[4] && values[5] == rowData[5]) { portfTable.rows[(rowDataIndex*1)+1].childNodes[1].firstChild.data = UI.both; @@ -392,7 +425,7 @@ function addPortfRangeRule() else { values = new Array(); - ids = ['addr_desc', 'addr_prot', 'addr_sp', 'addr_ep', 'addr_ip']; + ids = ['addr_desc', 'addr_prot', 'addr_sp', 'addr_ep', 'addr_ip', 'addr_src_zone']; for (idIndex in ids) { element = document.getElementById(ids[idIndex]); @@ -412,7 +445,7 @@ function addPortfRangeRule() for (rowDataIndex in currentRangeData) { rowData = currentRangeData[rowDataIndex]; - if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3] && values[4] == rowData[4]) + if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3] && values[4] == rowData[4] && values[5] == rowData[5]) { portfRangeTable.rows[(rowDataIndex*1)+1].childNodes[1].firstChild.data = UI.both; if(values[0] != '-' && rowData[0] == '-') @@ -468,11 +501,12 @@ function proofreadForwardRange(excludeRow) var addStartPort = document.getElementById('addr_sp').value; var addEndPort = document.getElementById('addr_ep').value; var addProtocol = document.getElementById('addr_prot').value; + var addZone = document.getElementById('addr_src_zone').value; var rowDataIndex=0; for (rowDataIndex=0; rowDataIndex < currentPortfData.length ; rowDataIndex++) { var rowData = currentPortfData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addStartPort*1 <= rowData[2]*1 && addEndPort*1 >= rowData[2]*1 ) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addStartPort*1 <= rowData[2]*1 && addEndPort*1 >= rowData[2]*1 && addZone == rowData[5]) { errors.push(prtS.DupErr); } @@ -485,7 +519,7 @@ function proofreadForwardRange(excludeRow) if(portfRangeTable.rows[rowDataIndex+1] != excludeRow) { var rowData = currentRangeData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addEndPort*1 && rowData[3]*1 >= addStartPort*1) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addEndPort*1 && rowData[3]*1 >= addStartPort*1 && addZone == rowData[5]) { errors.push(prtS.DupErr); } @@ -519,13 +553,14 @@ function proofreadForwardSingle(excludeRow) var currentPortfData = getTableDataArray(portfTable, true, false); var addPort = document.getElementById('add_fp').value; var addProtocol = document.getElementById('add_prot').value; + var addZone = document.getElementById('add_src_zone').value; var rowDataIndex=0; for (rowDataIndex=0; rowDataIndex < currentPortfData.length; rowDataIndex++) { if(portfTable.rows[rowDataIndex+1] != excludeRow) { var rowData = currentPortfData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addPort == rowData[2]) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addPort == rowData[2] && addZone == rowData[5]) { errors.push(prtS.CopErr); } @@ -537,7 +572,7 @@ function proofreadForwardSingle(excludeRow) for (rowDataIndex=0; rowDataIndex < currentRangeData.length; rowDataIndex++) { var rowData = currentRangeData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addPort*1 && rowData[3]*1 >= addPort*1) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addPort*1 && rowData[3]*1 >= addPort*1 && addZone == rowData[5]) { errors.push(prtS.CopErr); } @@ -581,6 +616,8 @@ function resetData() var srcdport = uciOriginal.get("firewall", rId, "src_dport"); var destip = uciOriginal.get("firewall", rId, "dest_ip"); var destport = uciOriginal.get("firewall", rId, "dest_port"); + var srczone = uciOriginal.get("firewall", rId, "src"); + srczone = srczone == "" ? "wan" : srczone; if(srcdport == "" && destport == "" && sectionType == "redirect") @@ -594,7 +631,7 @@ function resetData() destport = destport == "" ? srcdport : destport; otherProto = proto == "tcp" ? "udp" : "tcp"; - hashStr = name + "-" + srcdport + "-" + destip + "-" + destport; + hashStr = name + "-" + srcdport + "-" + destip + "-" + destport + "-" + srczone; if(srcdport.match(/-/)) { var splitPorts = srcdport.split(/-/); @@ -606,7 +643,7 @@ function resetData() } else { - var nextTableRowData = [name, proto.toUpperCase(), splitPorts[0], splitPorts[1], destip, checkbox, createEditButton(false,"forward")]; + var nextTableRowData = [name, proto.toUpperCase(), splitPorts[0], splitPorts[1], destip, srczone, checkbox, createEditButton(false,"forward")]; portRangeTableData.push(nextTableRowData); portRangeProtoHash[proto][hashStr] = nextTableRowData; portRangeEnabledStatus.push(checkbox.checked); @@ -622,7 +659,7 @@ function resetData() } else { - var nextTableRowData = [name, proto.toUpperCase(), srcdport, destip, destport, checkbox, createEditButton(true,"forward")]; + var nextTableRowData = [name, proto.toUpperCase(), srcdport, destip, destport, srczone, checkbox, createEditButton(true,"forward")]; singlePortTableData.push(nextTableRowData); singlePortProtoHash[proto][hashStr] = nextTableRowData; singlePortEnabledStatus.push(checkbox.checked); @@ -633,7 +670,7 @@ function resetData() } - columnNames = [prtS.Desc, prtS.Proto, prtS.FPrt, prtS.TIP, prtS.TPrt, UI.Enabled, ''] + columnNames = [prtS.Desc, prtS.Proto, prtS.FPrt, prtS.TIP, prtS.TPrt, prtS.SrcZone, UI.Enabled, ''] portfTable=createTable(columnNames, singlePortTableData, "portf_table", true, false); table1Container = document.getElementById('portf_table_container'); @@ -647,7 +684,7 @@ function resetData() - columnNames = [prtS.Desc, prtS.Proto, prtS.SPrt, prtS.EPrt, prtS.TIP, UI.Enabled, ''] + columnNames = [prtS.Desc, prtS.Proto, prtS.SPrt, prtS.EPrt, prtS.TIP, prtS.SrcZone, UI.Enabled, ''] portfrangeTable=createTable(columnNames, portRangeTableData, "portf_range_table", true, false); table2Container = document.getElementById('portfrange_table_container'); if(document.getElementById('portfrange_table_container').firstChild != null) @@ -662,11 +699,11 @@ function resetData() // checkboxes become unchecked when added to table. We need to reset checked status here. for(spIndex = 0; spIndex < singlePortEnabledStatus.length; spIndex++) { - singlePortTableData[spIndex][5].checked = singlePortEnabledStatus[spIndex]; + singlePortTableData[spIndex][6].checked = singlePortEnabledStatus[spIndex]; } for(prIndex = 0; prIndex < portRangeEnabledStatus.length; prIndex++) { - portRangeTableData[prIndex][5].checked = portRangeEnabledStatus[prIndex]; + portRangeTableData[prIndex][6].checked = portRangeEnabledStatus[prIndex]; } @@ -775,6 +812,8 @@ function resetData() var proto = uciOriginal.get("firewall", poId, "proto").toLowerCase(); var destip = uciOriginal.get("firewall", poId, "dest_ip"); var destport = uciOriginal.get("firewall", poId, "dest_port"); + var srczone = uciOriginal.get("firewall", poId, "src"); + srczone = srczone == "" ? "wan" : srczone; if(proto.toLowerCase() == "tcp" || proto.toLowerCase() == "udp") @@ -783,7 +822,7 @@ function resetData() checkbox.checked = sectionType == "rule" ? true : false; otherProto = proto == "tcp" ? "udp" : "tcp"; - hashStr = name + "-" + destip + "-" + destport; + hashStr = name + "-" + destip + "-" + destport + "-" + srczone; if(destport.match(/-/)) { var splitPorts = destport.split(/-/); @@ -795,7 +834,7 @@ function resetData() } else { - var nextTableRowData = [name, proto.toUpperCase(), splitPorts[0], splitPorts[1], destip, checkbox, createEditButton(false,"open")]; + var nextTableRowData = [name, proto.toUpperCase(), splitPorts[0], splitPorts[1], destip, srczone, checkbox, createEditButton(false,"open")]; portRangeTableData.push(nextTableRowData); portRangeProtoHash[proto][hashStr] = nextTableRowData; portRangeEnabledStatus.push(checkbox.checked); @@ -811,7 +850,7 @@ function resetData() } else { - var nextTableRowData = [name, proto.toUpperCase(), destip, destport, checkbox, createEditButton(true,"open")]; + var nextTableRowData = [name, proto.toUpperCase(), destip, destport, srczone, checkbox, createEditButton(true,"open")]; singlePortTableData.push(nextTableRowData); singlePortProtoHash[proto][hashStr] = nextTableRowData; singlePortEnabledStatus.push(checkbox.checked); @@ -822,7 +861,7 @@ function resetData() } - columnNames = [prtS.Desc, prtS.Proto, "IP", prtS.Port, UI.Enabled, ''] + columnNames = [prtS.Desc, prtS.Proto, "IP", prtS.Port, prtS.SrcZone, UI.Enabled, ''] portoTable=createTable(columnNames, singlePortTableData, "porto_table", true, false); table1Container = document.getElementById('porto_table_container'); @@ -832,7 +871,7 @@ function resetData() } table1Container.appendChild(portoTable); - columnNames = [prtS.Desc, prtS.Proto, prtS.SPrt, prtS.EPrt, prtS.TIP, UI.Enabled, ''] + columnNames = [prtS.Desc, prtS.Proto, prtS.SPrt, prtS.EPrt, prtS.TIP, prtS.SrcZone, UI.Enabled, ''] portorangeTable=createTable(columnNames, portRangeTableData, "porto_range_table", true, false); table2Container = document.getElementById('portorange_table_container'); if(document.getElementById('portorange_table_container').firstChild != null) @@ -905,6 +944,7 @@ function editForward(isSingle, editRow) editRow.childNodes[3].firstChild.data = document.getElementById("addr_ep").value; editRow.childNodes[4].firstChild.data = document.getElementById("addr_ip").value; } + editRow.childNodes[5].firstChild.data = getSelectedValue( "add" + r + "_src_zone", document ); closeModalWindow(isSingle ? "single_forward_modal" : "multi_forward_modal"); } } @@ -1014,7 +1054,8 @@ function addPortFModal(isSingle) modalElements = [ {"id" : "add" + r + "_desc", "value" : desc}, {"id" : "add" + r + "_prot", "value" : prot}, - {"id" : "add" + r + "_ip", "value" : ip} + {"id" : "add" + r + "_ip", "value" : ip}, + {"id" : "add" + r + "_src_zone", "options" : getWanZoneOptionsMap(), "value" : "wan"} ]; if(isSingle) { @@ -1057,13 +1098,14 @@ function editPortFModal(isSingle, triggerEl) var ep = editRow.childNodes[3].firstChild.data; var ip = editRow.childNodes[4].firstChild.data; } - + var zone = editRow.childNodes[5].firstChild.data; var r = isSingle ? "" : "r"; modalElements = [ {"id" : "add" + r + "_desc", "value" : desc}, {"id" : "add" + r + "_prot", "value" : prot}, - {"id" : "add" + r + "_ip", "value" : ip} + {"id" : "add" + r + "_ip", "value" : ip}, + {"id" : "add" + r + "_src_zone", "options" : getWanZoneOptionsMap(), "value" : zone} ]; if(isSingle) { @@ -1102,13 +1144,14 @@ function proofreadOpenSingle(excludeRow) var addProtocol = document.getElementById('addo_prot').value; var addIP = document.getElementById('addo_ip').value; addIP = ip6_canonical(addIP); + var addZone = document.getElementById('addo_src_zone').value; var rowDataIndex=0; for (rowDataIndex=0; rowDataIndex < currentPortoData.length; rowDataIndex++) { if(portoTable.rows[rowDataIndex+1] != excludeRow) { var rowData = currentPortoData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addPort == rowData[3] && addIP == rowData[2]) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addPort == rowData[3] && addIP == rowData[2] && addZone == rowData[4]) { errors.push(prtS.CopOErr); } @@ -1120,7 +1163,7 @@ function proofreadOpenSingle(excludeRow) for (rowDataIndex=0; rowDataIndex < currentRangeData.length; rowDataIndex++) { var rowData = currentRangeData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addPort*1 && rowData[3]*1 >= addPort*1 && addIP == rowData[4]) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addPort*1 && rowData[3]*1 >= addPort*1 && addIP == rowData[4] && addZone == rowData[5]) { errors.push(prtS.CopOErr); } @@ -1153,11 +1196,12 @@ function proofreadOpenRange(excludeRow) var addProtocol = document.getElementById('addor_prot').value; var addIP = document.getElementById('addor_ip').value; addIP = ip6_canonical(addIP); + var addZone = document.getElementById('addor_src_zone').value; var rowDataIndex=0; for (rowDataIndex=0; rowDataIndex < currentPortoData.length ; rowDataIndex++) { var rowData = currentPortoData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addStartPort*1 <= rowData[3]*1 && addEndPort*1 >= rowData[3]*1 && addIP == rowData[2]) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && addStartPort*1 <= rowData[3]*1 && addEndPort*1 >= rowData[3]*1 && addIP == rowData[2] && addZone == rowData[4]) { errors.push(prtS.DupOErr); } @@ -1170,7 +1214,7 @@ function proofreadOpenRange(excludeRow) if(portoRangeTable.rows[rowDataIndex+1] != excludeRow) { var rowData = currentRangeData[rowDataIndex]; - if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addEndPort*1 && rowData[3]*1 >= addStartPort*1 && addIP == rowData[4]) + if( (addProtocol == rowData[1] || addProtocol == UI.both || rowData[1] == UI.both) && rowData[2]*1 <= addEndPort*1 && rowData[3]*1 >= addStartPort*1 && addIP == rowData[4] && addZone == rowData[5]) { errors.push(prtS.DupOErr); } @@ -1193,7 +1237,7 @@ function addPortoRule() else { values = new Array(); - ids = ['addo_desc', 'addo_prot', 'addo_ip', 'addo_dp']; + ids = ['addo_desc', 'addo_prot', 'addo_ip', 'addo_dp', 'addo_src_zone']; for (idIndex in ids) { element = document.getElementById(ids[idIndex]); @@ -1217,7 +1261,7 @@ function addPortoRule() { rowData = currentPortoData[rowDataIndex]; - if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3]) + if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3] && values[4] == rowData[4]) { portoTable.rows[(rowDataIndex*1)+1].childNodes[1].firstChild.data = UI.both; if(values[0] != '-' && rowData[0] == '-') @@ -1258,7 +1302,7 @@ function addPortoRangeRule() else { values = new Array(); - ids = ['addor_desc', 'addor_prot', 'addor_sp', 'addor_ep', 'addor_ip']; + ids = ['addor_desc', 'addor_prot', 'addor_sp', 'addor_ep', 'addor_ip', 'addor_src_zone']; for (idIndex in ids) { element = document.getElementById(ids[idIndex]); @@ -1279,7 +1323,7 @@ function addPortoRangeRule() for (rowDataIndex in currentRangeData) { rowData = currentRangeData[rowDataIndex]; - if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3] && values[4] == rowData[4]) + if( otherProto == rowData[1] && values[2] == rowData[2] && values[3] == rowData[3] && values[4] == rowData[4] && values[5] == rowData[5]) { portfRangeTable.rows[(rowDataIndex*1)+1].childNodes[1].firstChild.data = UI.both; if(values[0] != '-' && rowData[0] == '-') @@ -1332,7 +1376,8 @@ function addPortOModal(isSingle) modalElements = [ {"id" : "addo" + r + "_desc", "value" : desc}, {"id" : "addo" + r + "_prot", "value" : prot}, - {"id" : "addo" + r + "_ip", "value" : ip} + {"id" : "addo" + r + "_ip", "value" : ip}, + {"id" : "addo" + r + "_src_zone", "options" : getWanZoneOptionsMap(), "value" : "wan"} ]; if(isSingle) @@ -1372,12 +1417,14 @@ function editOpen(isSingle, editRow) { editRow.childNodes[2].firstChild.data = document.getElementById("addo_ip").value; editRow.childNodes[3].firstChild.data = document.getElementById("addo_dp").value; + editRow.childNodes[4].firstChild.data = getSelectedValue( "addo_src_zone", document ); } else { editRow.childNodes[2].firstChild.data = document.getElementById("addor_sp").value; editRow.childNodes[3].firstChild.data = document.getElementById("addor_ep").value; editRow.childNodes[4].firstChild.data = document.getElementById("addor_ip").value; + editRow.childNodes[5].firstChild.data = getSelectedValue( "addor_src_zone", document ); } closeModalWindow(isSingle ? "single_open_modal" : "multi_open_modal"); } @@ -1396,10 +1443,11 @@ function editPortOModal(isSingle, triggerEl) var prot = editRow.childNodes[1].firstChild.data; var r = isSingle ? "" : "r"; + var zone = editRow.childNodes[isSingle ? 4 : 5].firstChild.data; modalElements = [ {"id" : "addo" + r + "_desc", "value" : desc}, {"id" : "addo" + r + "_prot", "value" : prot}, - + {"id" : "addo" + r + "_src_zone", "options" : getWanZoneOptionsMap(), "value" : zone} ]; if(isSingle) diff --git a/package/gargoyle/files/www/templates/multi_forward_template b/package/gargoyle/files/www/templates/multi_forward_template index 7f7a7a0415..d52164c5f7 100644 --- a/package/gargoyle/files/www/templates/multi_forward_template +++ b/package/gargoyle/files/www/templates/multi_forward_template @@ -24,3 +24,7 @@ +
+ + +
diff --git a/package/gargoyle/files/www/templates/multi_open_template b/package/gargoyle/files/www/templates/multi_open_template index 03b8b61995..229bfe83d5 100644 --- a/package/gargoyle/files/www/templates/multi_open_template +++ b/package/gargoyle/files/www/templates/multi_open_template @@ -24,3 +24,7 @@ +
+ + +
diff --git a/package/gargoyle/files/www/templates/single_forward_template b/package/gargoyle/files/www/templates/single_forward_template index ae183c4896..eed28e2a85 100644 --- a/package/gargoyle/files/www/templates/single_forward_template +++ b/package/gargoyle/files/www/templates/single_forward_template @@ -24,3 +24,7 @@ +
+ + +
diff --git a/package/gargoyle/files/www/templates/single_open_template b/package/gargoyle/files/www/templates/single_open_template index f043da659e..392260d052 100644 --- a/package/gargoyle/files/www/templates/single_open_template +++ b/package/gargoyle/files/www/templates/single_open_template @@ -20,3 +20,7 @@ +
+ + +
diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/port.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/port.js index 8e0d5a2749..9a58fa3c48 100644 --- a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/port.js +++ b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/port.js @@ -31,6 +31,7 @@ prtS.TIP="To IP"; prtS.TPrt="To Port"; prtS.SPrt="Start Port"; prtS.EPrt="End Port"; +prtS.SrcZone="Source Zone"; //javascript prtS.AFRErr="Could not add forwarding rule.";