From fe38cc7a520ab5ab8be3f0f8b997a3ec7e9c3b70 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 27 Nov 2015 18:32:38 +1100 Subject: [PATCH 01/48] Remove UCIContainer.listOptions The code has been simplified by replacing the use of UCIContain.listOptions with checks to see if (UCIContainer.value instanceof Array). Also bugs identified and fixed. Background. While implementing new functionality to store uci list values, problems were encountered. While UCIContainer.set() accomodated for uci list values using UCIContainer.listOptions, UCIContainer.getScriptCommands() did not refer to UCIContainer.listOptions and did not return the correct commands to set uci list values. While investigating and correcting this problem, various other corrections and simplifications were undertaken. UCIContainer.set() is recoded UCIContainer.listOptions is replaced with instanceof Array checks UCIContainer.values is declared as an Object rather than an Array UCIContainer.clone() corrected clone of Array values --- package/gargoyle/files/www/js/common.js | 291 +++++++++++------------- 1 file changed, 131 insertions(+), 160 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 98dab793ec..0d57deb505 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -1,8 +1,8 @@ /* - * This program is copyright © 2008-2011 Eric Bishop and is distributed under the terms of the GNU GPL - * version 2.0 with a special clarification/exception that permits adapting the program to + * This program is copyright © 2008-2011 Eric Bishop and is distributed under the terms of the GNU GPL + * version 2.0 with a special clarification/exception that permits adapting the program to * configure proprietary "back end" software provided that all modifications to the web interface - * itself remain covered by the GPL. + * itself remain covered by the GPL. * See http://gargoyle-router.com/faq.html#qfoss for more information */ @@ -42,7 +42,7 @@ function setControlsEnabled(enabled, showWaitMessage, waitText) { var totalHeight="100%"; var totalWidth="100%"; - + var heightFromDoc=0; var widthFromDoc=0; if(document.body.parentNode.scrollHeight) @@ -72,11 +72,11 @@ function setControlsEnabled(enabled, showWaitMessage, waitText) widthFromDoc = widthFromDoc >= document.width ? widthFromDoc : document.width } totalWidth = widthFromDoc > 0 ? widthFromDoc + "px" : totalWidth - - + + var viewportHeight; var vewportWidth; @@ -97,7 +97,7 @@ function setControlsEnabled(enabled, showWaitMessage, waitText) } var leftOffset = Math.floor((viewportWidth-300)/2); - var topOffset = Math.floor((viewportHeight-150)/2); + var topOffset = Math.floor((viewportHeight-150)/2); var is_ie = false; if(document.all) { @@ -128,7 +128,7 @@ function setControlsEnabled(enabled, showWaitMessage, waitText) msg.style.left = leftOffset >= 0 ? leftOffset+"px" : "0px"; msg.style.top = topOffset >=0 ? topOffset+"px" : "0px"; - + dark.style.display="block"; if(showWaitMessage) @@ -174,12 +174,12 @@ function getRequestObj() { req = new ActiveXObject("Msxml2.XMLHTTP"); } - catch (ex) + catch (ex) { try { req = new ActiveXObject("Microsoft.XMLHTTP"); - } + } catch (ex) { // Browser is not Ajax compliant @@ -209,7 +209,7 @@ function runAjax(method, url, params, stateChangeFunction) { //for some reason we need at least one character of data, so use a space if params == null params = (params == null) ? " " : params; - + req.open("POST", url, true); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //req.setRequestHeader("Content-length", params.length); @@ -231,7 +231,7 @@ function execute(cmd) var commands = cmd.join("\n"); var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); setControlsEnabled(false, true, UI.WaitSettings); - + var stateChangeFunction = function(req) { if(req.readyState == 4) @@ -256,97 +256,73 @@ function execute(cmd) function UCIContainer() { this.keys = new Array(); - this.values = new Array(); - this.listOptions = new Array(); + this.values = new Object(); - - this.createListOption = function(pkg,section,option,destroy_existing_nonlist) - { - destroy_existing_nonlist = destroy_existing_nonlist == null ? true : false; - var list_key = pkg + "\." + section + "\." + option; - if( this.listOptions[ list_key ] != null ) - { - return; - } - - this.listOptions[ list_key ] = 1; - if( this.values[list_key] != null ) - { - var old = this.values[list_key]; - this.values[list_key] = (!destroy_existing_nonlist) && old != null ? [old] : [] ; - } - else - { - this.keys.push(list_key); - this.values[list_key] = []; - } - } - this.set = function(pkg, section, option, value, preserveExistingListValues) - { - preserveExistingListValues = preserveExistingListValues == null ? false : preserveExistingListValues; - var next_key = pkg + "\." + section; - if(option != null && option != "" ) - { - next_key = next_key + "\." + option; - } - if(this.values[next_key] != null) + this.createListOption = function(pkg,section,option,destroy_existing_nonlist) { - if (this.listOptions[ next_key ] != null) + destroy_existing_nonlist = destroy_existing_nonlist == null ? true : false; + var list_key = pkg + "\." + section + "\." + option; + var existing_value = this.values[ list_key ]; + if( existing_value instanceof Array ) { - var set = this.values[next_key]; - while(set.length > 0 && (!preserveExistingListValues)) - { - set.pop(); - } - if( value instanceof Array ) - { - var vi; - for(vi=0; vi 1024) || units == "MBytes/s") { parsed = (kbytes/(1024)).toFixed(3) + " "+UI.MBs; @@ -942,15 +914,15 @@ function parseKbytesPerSecond(kbytes, units) function truncateDecimal(dec) { result = "" + ((Math.floor(dec*1000))/1000); - - //make sure we have exactly three decimal places so + + //make sure we have exactly three decimal places so //results line up properly in table presentation decMatch=result.match(/.*\.(.*)$/); if(decMatch == null) { result = result + ".000" } - else + else { if(decMatch[1].length==1) { @@ -974,7 +946,7 @@ function enableAssociatedField(checkbox, associatedId, defaultValue, controlDocu function setElementEnabled(element, enabled, defaultValue) { - + if(enabled) { element.readonly=false; @@ -1025,7 +997,7 @@ function setElementEnabled(element, enabled, defaultValue) function getSelectedValue(selectId, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; - + if(controlDocument.getElementById(selectId) == null) { alert(UI.Err+": " + selectId + " "+UI.nex); @@ -1045,7 +1017,7 @@ function getSelectedValue(selectId, controlDocument) function getSelectedText(selectId, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; - + selectedIndex = controlDocument.getElementById(selectId).selectedIndex; selectedText = ""; if(selectedIndex >= 0) @@ -1058,7 +1030,7 @@ function getSelectedText(selectId, controlDocument) function setSelectedValue(selectId, selection, controlDocument) { var controlDocument = controlDocument == null ? document : controlDocument; - + var selectElement = controlDocument.getElementById(selectId); if(selectElement == null){ alert(UI.Err+": " + selectId + " "+UI.nex); } @@ -1082,7 +1054,7 @@ function setSelectedValue(selectId, selection, controlDocument) function setSelectedText(selectId, selection, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; - + selectElement = controlDocument.getElementById(selectId); selectionFound = false; for(optionIndex = 0; optionIndex < selectElement.options.length && (!selectionFound); optionIndex++) @@ -1106,7 +1078,7 @@ function addOptionToSelectElement(selectId, optionText, optionValue, before, con option = controlDocument.createElement("option"); option.text=optionText; option.value=optionValue; - + //FUCK M$ IE, FUCK IT UP THE ASS WITH A BASEBALL BAT. A BIG WOODEN ONE. WITH SPLINTERS. try { @@ -1120,14 +1092,14 @@ function addOptionToSelectElement(selectId, optionText, optionValue, before, con } else { - controlDocument.getElementById(selectId).add(option, before.index); + controlDocument.getElementById(selectId).add(option, before.index); } } } function removeOptionFromSelectElement(selectId, optionText, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; - + selectElement = controlDocument.getElementById(selectId); selectionFound = false; for(optionIndex = 0; optionIndex < selectElement.options.length && (!selectionFound); optionIndex++) @@ -1236,7 +1208,7 @@ function setVariableFromModifiedValue(params) { uci.set(pkg, section, option, modFunction(value)); } - } + } } function setVariableFromCombined(params) { @@ -1248,7 +1220,7 @@ function setVariableFromCombined(params) option = params[5]; setIfBlank = params[6]; combineFunction = params[7]; - + isVisible = true; if(visibilityId != null) { @@ -1307,7 +1279,7 @@ function setVariableFromConcatenation(params) } function setVariableConditionally(params) { - elementId = params[0]; + elementId = params[0]; visibilityId = params[1]; uci = params[2]; pkg = params[3]; @@ -1316,7 +1288,7 @@ function setVariableConditionally(params) testFunction = params[6]; useValueFromElement = params[7]; alternateValue = params[8]; - + isVisible = true; if(visibilityId != null) { @@ -1325,7 +1297,7 @@ function setVariableConditionally(params) if(isVisible==true) { value = useValueFromElement == true ? document.getElementById(elementId).value : alternateValue; - + if(testFunction(value)) { uci.set(pkg, section, option, value); @@ -1371,7 +1343,7 @@ function loadSelectedValueFromVariable(params) var section = params[3]; var option = params[4]; var defaultValue = params[5]; - + var v=uci.get(pkg, section, option); if(v != null && v != '') { @@ -1393,7 +1365,7 @@ function loadValueFromVariable(params) var section = params[3]; var option = params[4]; var defaultValue = params[5]; - + var v=uci.get(pkg, section, option); var e=document.getElementById(elementId); if(v != null && v != '') @@ -1421,7 +1393,7 @@ function loadValueFromModifiedVariable(params) var option = params[4]; var defaultValue = params[5]; var modificationFunction = params[6]; - + var v=modificationFunction(uci.get(pkg, section, option)); var e=document.getElementById(elementId); if(v != null && v != '') @@ -1431,7 +1403,7 @@ function loadValueFromModifiedVariable(params) else if(defaultValue != null) { e.value = defaultValue; - } + } } function loadValueFromVariableAtIndex(params) @@ -1443,10 +1415,10 @@ function loadValueFromVariableAtIndex(params) var option = params[4]; var defaultValue = params[5]; var index = params[6]; - + var vStr=uci.get(pkg, section, option); var vSplit = vStr.split(/[,\t ]+/); - + var v; if(index < vSplit.length) @@ -1457,7 +1429,7 @@ function loadValueFromVariableAtIndex(params) { v = ''; } - + var e=document.getElementById(elementId); if(v != null && v != '') { @@ -1487,7 +1459,7 @@ function isArray(obj) } function loadVariables(uci, varIds, varPkgs, varSections, varOptions, varParams, varFunctions) -{ +{ for (idIndex in varIds) { nextId = varIds[idIndex]; @@ -1511,7 +1483,7 @@ function loadVariables(uci, varIds, varPkgs, varSections, varOptions, varParams, nextFunc([nextId, uci, nextPkg, nextSection, nextOption, nextParams]); } } -} +} function loadValueFromMultipleVariables(params) { var elementId = params[0]; @@ -1655,7 +1627,7 @@ function validateMultipleIps(ips) else { valid = 1; - } + } } else { @@ -1685,7 +1657,7 @@ function validateMultipleIpsOrMacs(addresses) else { valid = 1; - } + } } else if(nextAddr.match(/:/)) { @@ -1766,7 +1738,7 @@ function validateNetMask(mask) //return codes: //0 = valid mask //1 = invalid digit - //2 = invalid field order + //2 = invalid field order //3 = fields > 255 //4 = invalid format @@ -1789,12 +1761,12 @@ function validateNetMask(mask) { errorCode = 2; } - if( ipFields[field] != 255 && - ipFields[field] != 254 && - ipFields[field] != 252 && + if( ipFields[field] != 255 && + ipFields[field] != 254 && + ipFields[field] != 252 && ipFields[field] != 248 && - ipFields[field] != 240 && - ipFields[field] != 224 && + ipFields[field] != 240 && + ipFields[field] != 224 && ipFields[field] != 192 && ipFields[field] != 128 && ipFields[field] != 0 && @@ -1823,9 +1795,9 @@ function validateIpRange(range) var ipValid = validateIP(split[0]); var maskValid = validateNetMask(split[1]) == 0 || validateNumericRange(split[1],1,31) == 0 ? 0 : 1; valid = ipValid == 0 && maskValid == 0 ? 0 : 1; - } + } } - else + else { valid = validateIP(range); } @@ -2000,15 +1972,15 @@ function getBridgeSection(testUci) var wanDef = uciOriginal.get("network", "wan", ""); var bridgeSection = ""; var sectionIndex; - - + + for(sectionIndex=0; sectionIndex < allWirelessSections.length && bridgeSection == ""; sectionIndex++) { - var getWirelessVar = function(varName) + var getWirelessVar = function(varName) { - return testUci.get("wireless", allWirelessSections[sectionIndex], varName).toLowerCase() + return testUci.get("wireless", allWirelessSections[sectionIndex], varName).toLowerCase() } - + if( getWirelessVar("mode") == "wds" && wanDef == "") { bridgeSection = allWirelessSections[sectionIndex]; @@ -2040,7 +2012,7 @@ function cnv24hToLocal(timestamp) { style=uciOriginal.get("gargoyle", "global", "hour_style"); if (style == 24) return timestamp; locale_time="" - + h_m_stamp=timestamp.split(":"); curr_hour=eval(h_m_stamp[0]); if (UI.pAM.length > 0 && UI.pPM.length > 0) { @@ -2056,7 +2028,7 @@ function cnv24hToLocal(timestamp) { //cnv_LocaleTime takes a full "09/16/13 21:09 EDT" date/time stamp // returns (based on hour prefs & pre/post AM/PM notations): "09/16/13 21:09 EDT", "09/16/13 午前 9:09 UTC" or "09/16/13 9:09 PM EDT" //NOTE: requires uciOriginal to have the 'gargoyle' section; use 'gargoyle_header_footer [options] gargoyle' -function cnv_LocaleTime(full_date) { // +function cnv_LocaleTime(full_date) { // style=uciOriginal.get("gargoyle", "global", "hour_style"); if (style == 24) return full_date; tcomponents=full_date.split(" "); @@ -2115,7 +2087,7 @@ function textListToSpanElement(textList, addCommas, controlDocument) { spanEl.appendChild( controlDocument.createElement("br") ); } - + spanEl.appendChild(controlDocument.createTextNode( textList[tlIndex] + (tlIndex < textList.length-1 && addCommas ? "," : "") )); } return spanEl; @@ -2186,7 +2158,7 @@ function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, ta currAddrs.push(addr); //if we're adding multiple addrs and there's overlap, this will allow us to detect it } } - else + else { valid = 1; } @@ -2199,12 +2171,12 @@ function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, ta newAddrs = newAddrs.replace(/^[\t ]*/, ""); newAddrs = newAddrs.replace(/[\t ]*$/, ""); var addrs = newAddrs.split(/[\t ]*,[\t ]*/); - + while(addrs.length > 0) { addTableRow(table, [ addrs.shift() ], true, false, null, null, controlDocument); } - + if(tableContainer.childNodes.length == 0) { tableContainer.appendChild(table); @@ -2226,7 +2198,7 @@ function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, ta function addAddressesToTable(controlDocument, textId, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) { - + var newAddrs = controlDocument.getElementById(textId).value; var valid = addAddressStringToTable(controlDocument, newAddrs, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) if(valid) @@ -2294,14 +2266,14 @@ function getIpRangeIntegers(ipStr) function testSingleAddrOverlap(addrStr1, addrStr2) { - /* + /* * this adjustment is useful in multiple places, particularly quotas * if you don't want these conversions, just validate quota BEFORE you * try calling this function */ var adj = function(addrStr) { - addrStr = addrStr == "" ? "ALL" : addrStr.toUpperCase(); + addrStr = addrStr == "" ? "ALL" : addrStr.toUpperCase(); if(addrStr == "ALL_OTHERS_COMBINED" || addrStr == "ALL_OTHERS_INDIVIDUAL") { addrStr = "ALL_OTHERS_COMBINED"; @@ -2420,17 +2392,17 @@ function confirmPassword(confirmText, validatedFunc, invalidFunc) } var wlocation = "password_confirm.sh"; confirmWindow = window.open(wlocation, "password", "width=560,height=260,left=" + xCoor + ",top=" + yCoor ); - + var okButton = createInput("button", confirmWindow.document); var cancelButton = createInput("button", confirmWindow.document); - + okButton.value = UI.OK; okButton.className = "default_button"; cancelButton.value = UI.Cancel; cancelButton.className = "default_button"; - runOnEditorLoaded = function () + runOnEditorLoaded = function () { updateDone=false; if(confirmWindow.document != null) @@ -2440,7 +2412,7 @@ function confirmPassword(confirmText, validatedFunc, invalidFunc) confirmWindow.document.getElementById("bottom_button_container").appendChild(okButton); confirmWindow.document.getElementById("bottom_button_container").appendChild(cancelButton); setChildText("confirm_text", confirmText, null, null, null, confirmWindow.document); - + cancelButton.onclick = function() { confirmWindow.close(); @@ -2448,7 +2420,7 @@ function confirmPassword(confirmText, validatedFunc, invalidFunc) okButton.onclick = function() { setControlsEnabled(false, true, UI.VPass); - + var commands = "gargoyle_session_validator -p \"" + confirmWindow.document.getElementById("password").value + "\" -a \"dummy.browser\" -i \"127.0.0.1\"" var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); var stateChangeFunction = function(req) @@ -2512,7 +2484,7 @@ function getHttpPort(uciData) function getUsedPorts() { - var dropbearSections = uciOriginal.getAllSections("dropbear"); + var dropbearSections = uciOriginal.getAllSections("dropbear"); var sshPort = uciOriginal.get("dropbear", dropbearSections[0], "Port") var httpPort = getHttpPort() var httpsPort = getHttpsPort() @@ -2561,7 +2533,7 @@ function getUsedPorts() if(localport != remotePort && localport != "") { if(proto == "" || proto == "tcpudp") - { + { portDefs.push([remotePort, "tcp", defIndex[2] ]) portDefs.push([remotePort, "udp", defIndex[2] ]) foundPorts["tcp"][remotePort] = 1; @@ -2746,9 +2718,9 @@ function query(queryHeader, queryText, buttonNameList, continueFunction ) queryFieldset = document.createElement("fieldset"); queryFieldset.innerHTML='' + queryHeader + '
' + queryText + '
 
' - + document.getElementById("wait_msg").appendChild(queryFieldset) - + var buttonList = []; var bIndex; for(bIndex=0; bIndex < buttonNameList.length ; bIndex++) @@ -2781,4 +2753,3 @@ function ObjLen(an_obj) { } return len } - From a129734b9d2475a542b5d09b90d9a03c7f73b4e4 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 29 Nov 2015 06:03:53 +1100 Subject: [PATCH 02/48] resolve conflict --- package/gargoyle/files/www/js/common.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 0d57deb505..811c062457 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -303,9 +303,6 @@ function UCIContainer() for(vi=0; vi Date: Sun, 29 Nov 2015 05:18:02 +1100 Subject: [PATCH 03/48] bugfix add new key --- package/gargoyle/files/www/js/common.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 811c062457..cc57bbd6a5 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -275,6 +275,7 @@ function UCIContainer() { this.values[ list_key ] = [existing_value]; } + this.keys.push(list_key); } @@ -319,7 +320,6 @@ function UCIContainer() this.get = function(pkg, section, option) { - var next_key = pkg + "\." + section; if(option != null && option != '') { @@ -328,6 +328,7 @@ function UCIContainer() var value = this.values[next_key]; return value != null ? value : ''; } + this.removeAllSectionsOfType = function(pkg, type) { var removeSections = this.getAllSectionsOfType(pkg, type); @@ -337,6 +338,7 @@ function UCIContainer() this.removeSection(pkg, removeSections[rmIndex]); } } + this.getAllOptionsInSection = function(pkg, section, includeLists) { includeLists = includeLists == null ? false : includeLists; @@ -353,6 +355,7 @@ function UCIContainer() } return matches; } + this.getAllSectionsOfType = function(pkg, type) { var matches = new Array(); @@ -370,6 +373,7 @@ function UCIContainer() } return matches; } + this.getAllSections = function(pkg) { var matches = new Array(); @@ -411,6 +415,7 @@ function UCIContainer() } return value; } + this.removeSection = function(pkg, section) { removeKeys = new Array(); From 92a0def9ced669f5110994c7eca5c5e8b16f6ad7 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Mon, 30 Nov 2015 16:02:44 +1100 Subject: [PATCH 04/48] Remove UCIContainer.keys The code has been made more simple and robust by removing the need to maintain keys separately. The use of keys[] has been replaced by tests on values.hasOwnProperty(key) as recommended at: http://stackoverflow.com/questions/11040472/check-if-object-property- exists-using-a-variable#11040508 --- package/gargoyle/files/www/js/common.js | 193 ++++++++++++------------ 1 file changed, 93 insertions(+), 100 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index cc57bbd6a5..d47a88fe9f 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -255,7 +255,6 @@ function execute(cmd) // they are defined with set method function UCIContainer() { - this.keys = new Array(); this.values = new Object(); this.createListOption = function(pkg,section,option,destroy_existing_nonlist) @@ -275,11 +274,9 @@ function UCIContainer() { this.values[ list_key ] = [existing_value]; } - this.keys.push(list_key); } - this.set = function(pkg, section, option, value, preserveExistingListValues) { preserveExistingListValues = preserveExistingListValues == null ? false : preserveExistingListValues; @@ -288,12 +285,7 @@ function UCIContainer() { key = key + "\." + option; } - if(this.keys.indexOf(key) == -1) - { // add a new key and value - this.keys.push(key); - this.values[ key ] = value; - } - else + if(this.values.hasOwnProperty(key)) { // an existing key if (preserveExistingListValues) { @@ -315,6 +307,11 @@ function UCIContainer() this.values[ key ] = value; } } + else + { // add a new key and value + this.values[ key ] = value; + } + } } @@ -343,14 +340,15 @@ function UCIContainer() { includeLists = includeLists == null ? false : includeLists; var matches = new Array(); - for (keyIndex in this.keys) - { - var key = this.keys[keyIndex]; - var test = pkg + "." + section; - if(key.match(test) && key.match(/^[^\.]+\.[^\.]+\.[^\.]+/) && (includeLists || !(this.values[key] instanceof Array))) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - var option = key.match(/^[^\.]+\.[^\.]+\.([^\.]+)$/)[1]; - matches.push(option); + var test = pkg + "." + section; + if(key.match(test) && key.match(/^[^\.]+\.[^\.]+\.[^\.]+/) && (includeLists || !(this.values[key] instanceof Array))) + { + var option = key.match(/^[^\.]+\.[^\.]+\.([^\.]+)$/)[1]; + matches.push(option); + } } } return matches; @@ -359,15 +357,16 @@ function UCIContainer() this.getAllSectionsOfType = function(pkg, type) { var matches = new Array(); - for (keyIndex in this.keys) - { - key = this.keys[keyIndex]; - if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - if(this.values[key] == type) + if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) { - var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; - matches.push(section); + if(this.values[key] == type) + { + var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; + matches.push(section); + } } } } @@ -377,13 +376,14 @@ function UCIContainer() this.getAllSections = function(pkg) { var matches = new Array(); - for (keyIndex in this.keys) - { - key = this.keys[keyIndex]; - if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; - matches.push(section); + if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) + { + var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; + matches.push(section); + } } } return matches; @@ -398,21 +398,8 @@ function UCIContainer() } var value = this.values[removeKey]; - if(value != null) - { - this.values[removeKey] = null; - var newKeys = []; - while(this.keys.length > 0) - { - var nextKey = this.keys.shift(); - if(nextKey != removeKey){ newKeys.push(nextKey); } - } - this.keys = newKeys; - } - else - { - value = '' - } + value = (value == null) ? '' : value; + this.values[removeKey] = null; return value; } @@ -420,20 +407,21 @@ function UCIContainer() { removeKeys = new Array(); sectionDefined = false; - for (keyIndex in this.keys) + for (var key in this.values) { - key = this.keys[keyIndex]; - testExp = new RegExp(pkg + "\\." + section + "\\."); - if(key.match(testExp)) + if (this.values.hasOwnProperty(key)) { - var splitKey = key.split("\."); - removeKeys.push(splitKey[2]); - } - if(key == pkg + "." + section) - { - sectionDefined = true; + testExp = new RegExp(pkg + "\\." + section + "\\."); + if(key.match(testExp)) + { + var splitKey = key.split("\."); + removeKeys.push(splitKey[2]); + } + if(key == pkg + "." + section) + { + sectionDefined = true; + } } - } for (rkIndex in removeKeys) { @@ -449,30 +437,31 @@ function UCIContainer() { var copy = new UCIContainer(); var keyIndex = 0; - for(keyIndex = 0; keyIndex < this.keys.length; keyIndex++) - { - var key = this.keys[keyIndex]; - var val = this.values[key] - if (val instanceof Array) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - val = val.slice(0); - } - - var splitKey = key.match(/^([^\.]+)\.([^\.]+)\.([^\.]+)$/); - if(splitKey == null) - { - splitKey = key.match(/^([^\.]+)\.([^\.]+)$/); - if(splitKey != null) + var val = this.values[key] + if (val instanceof Array) { - splitKey.push(""); + val = val.slice(0); } - else + + var splitKey = key.match(/^([^\.]+)\.([^\.]+)\.([^\.]+)$/); + if(splitKey == null) { + splitKey = key.match(/^([^\.]+)\.([^\.]+)$/); + if(splitKey != null) + { + splitKey.push(""); + } + else + { //should never get here -- if problems put debugging code here //val = val; // good enough for a breakpoint to be set. + } } + copy.set(splitKey[1], splitKey[2], splitKey[3], val); } - copy.set(splitKey[1], splitKey[2], splitKey[3], val); } return copy; } @@ -481,16 +470,18 @@ function UCIContainer() { var str=""; var keyIndex=0; - for(keyIndex=0; keyIndex < this.keys.length; keyIndex++) + for (var key in this.values) { - var key = this.keys[keyIndex] - if(this.values[key] instanceof Array ) - { - str=str+ "\n" + key + " = \"" + this.values[key].join(",") + "\""; - } - else + if (this.values.hasOwnProperty(key)) { - str=str+ "\n" + key + " = \"" + this.values[key] + "\""; + if(this.values[key] instanceof Array ) + { + str=str+ "\n" + key + " = \"" + this.values[key].join(",") + "\""; + } + else + { + str=str+ "\n" + key + " = \"" + this.values[key] + "\""; + } } } return str; @@ -543,44 +534,46 @@ function UCIContainer() } } - for(keyIndex=0; keyIndex < this.keys.length; keyIndex++) + for (var key in this.values) { - var key = this.keys[keyIndex]; - var oldValue = oldSettings.values[key]; - var newValue = this.values[key]; - try + if (this.values.hasOwnProperty(key)) { - - if( (oldValue instanceof Array) || (newValue instanceof Array) ) + var oldValue = oldSettings.values[key]; + var newValue = this.values[key]; + try { - if(newValue instanceof Array) + + if( (oldValue instanceof Array) || (newValue instanceof Array) ) { - if(listsWithoutUpdates[key] == null) + if(newValue instanceof Array) { - var vi; - for(vi=0; vi< newValue.length ; vi++) + if(listsWithoutUpdates[key] == null) { - var nv = "" + newValue[vi] + ""; - commandArray.push( "uci add_list " + key + "=\'" + nv.replace(/'/, "'\\''") + "\'" ); + var vi; + for(vi=0; vi< newValue.length ; vi++) + { + var nv = "" + newValue[vi] + ""; + commandArray.push( "uci add_list " + key + "=\'" + nv.replace(/'/, "'\\''") + "\'" ); + } } } + else + { + newValue = "" + newValue + "" + commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/, "'\\''") + "\'" ); + } } - else + else if(oldValue != newValue && (newValue != null && newValue !='')) { newValue = "" + newValue + "" commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/, "'\\''") + "\'" ); } } - else if(oldValue != newValue && (newValue != null && newValue !='')) + catch(e) { - newValue = "" + newValue + "" - commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/, "'\\''") + "\'" ); + alert("bad key = " + key + "\n"); } } - catch(e) - { - alert("bad key = " + key + "\n"); - } } commandArray.push("uci commit"); From c41a1865d5e9e3ea10280557bffd7326f8dafc2f Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Mon, 30 Nov 2015 16:02:44 +1100 Subject: [PATCH 05/48] Remove UCIContainer.keys The code has been made more simple and robust by removing the need to maintain keys separately. The use of keys[] has been replaced by tests on values.hasOwnProperty(key) as recommended at: http://stackoverflow.com/questions/11040472/check-if-object-property- exists-using-a-variable#11040508 --- package/gargoyle/files/www/js/common.js | 193 ++++++++++++------------ 1 file changed, 93 insertions(+), 100 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index cc57bbd6a5..d47a88fe9f 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -255,7 +255,6 @@ function execute(cmd) // they are defined with set method function UCIContainer() { - this.keys = new Array(); this.values = new Object(); this.createListOption = function(pkg,section,option,destroy_existing_nonlist) @@ -275,11 +274,9 @@ function UCIContainer() { this.values[ list_key ] = [existing_value]; } - this.keys.push(list_key); } - this.set = function(pkg, section, option, value, preserveExistingListValues) { preserveExistingListValues = preserveExistingListValues == null ? false : preserveExistingListValues; @@ -288,12 +285,7 @@ function UCIContainer() { key = key + "\." + option; } - if(this.keys.indexOf(key) == -1) - { // add a new key and value - this.keys.push(key); - this.values[ key ] = value; - } - else + if(this.values.hasOwnProperty(key)) { // an existing key if (preserveExistingListValues) { @@ -315,6 +307,11 @@ function UCIContainer() this.values[ key ] = value; } } + else + { // add a new key and value + this.values[ key ] = value; + } + } } @@ -343,14 +340,15 @@ function UCIContainer() { includeLists = includeLists == null ? false : includeLists; var matches = new Array(); - for (keyIndex in this.keys) - { - var key = this.keys[keyIndex]; - var test = pkg + "." + section; - if(key.match(test) && key.match(/^[^\.]+\.[^\.]+\.[^\.]+/) && (includeLists || !(this.values[key] instanceof Array))) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - var option = key.match(/^[^\.]+\.[^\.]+\.([^\.]+)$/)[1]; - matches.push(option); + var test = pkg + "." + section; + if(key.match(test) && key.match(/^[^\.]+\.[^\.]+\.[^\.]+/) && (includeLists || !(this.values[key] instanceof Array))) + { + var option = key.match(/^[^\.]+\.[^\.]+\.([^\.]+)$/)[1]; + matches.push(option); + } } } return matches; @@ -359,15 +357,16 @@ function UCIContainer() this.getAllSectionsOfType = function(pkg, type) { var matches = new Array(); - for (keyIndex in this.keys) - { - key = this.keys[keyIndex]; - if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - if(this.values[key] == type) + if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) { - var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; - matches.push(section); + if(this.values[key] == type) + { + var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; + matches.push(section); + } } } } @@ -377,13 +376,14 @@ function UCIContainer() this.getAllSections = function(pkg) { var matches = new Array(); - for (keyIndex in this.keys) - { - key = this.keys[keyIndex]; - if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; - matches.push(section); + if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) + { + var section = key.match(/^[^\.]+\.([^\.]+)$/)[1]; + matches.push(section); + } } } return matches; @@ -398,21 +398,8 @@ function UCIContainer() } var value = this.values[removeKey]; - if(value != null) - { - this.values[removeKey] = null; - var newKeys = []; - while(this.keys.length > 0) - { - var nextKey = this.keys.shift(); - if(nextKey != removeKey){ newKeys.push(nextKey); } - } - this.keys = newKeys; - } - else - { - value = '' - } + value = (value == null) ? '' : value; + this.values[removeKey] = null; return value; } @@ -420,20 +407,21 @@ function UCIContainer() { removeKeys = new Array(); sectionDefined = false; - for (keyIndex in this.keys) + for (var key in this.values) { - key = this.keys[keyIndex]; - testExp = new RegExp(pkg + "\\." + section + "\\."); - if(key.match(testExp)) + if (this.values.hasOwnProperty(key)) { - var splitKey = key.split("\."); - removeKeys.push(splitKey[2]); - } - if(key == pkg + "." + section) - { - sectionDefined = true; + testExp = new RegExp(pkg + "\\." + section + "\\."); + if(key.match(testExp)) + { + var splitKey = key.split("\."); + removeKeys.push(splitKey[2]); + } + if(key == pkg + "." + section) + { + sectionDefined = true; + } } - } for (rkIndex in removeKeys) { @@ -449,30 +437,31 @@ function UCIContainer() { var copy = new UCIContainer(); var keyIndex = 0; - for(keyIndex = 0; keyIndex < this.keys.length; keyIndex++) - { - var key = this.keys[keyIndex]; - var val = this.values[key] - if (val instanceof Array) + for (var key in this.values) { + if (this.values.hasOwnProperty(key)) { - val = val.slice(0); - } - - var splitKey = key.match(/^([^\.]+)\.([^\.]+)\.([^\.]+)$/); - if(splitKey == null) - { - splitKey = key.match(/^([^\.]+)\.([^\.]+)$/); - if(splitKey != null) + var val = this.values[key] + if (val instanceof Array) { - splitKey.push(""); + val = val.slice(0); } - else + + var splitKey = key.match(/^([^\.]+)\.([^\.]+)\.([^\.]+)$/); + if(splitKey == null) { + splitKey = key.match(/^([^\.]+)\.([^\.]+)$/); + if(splitKey != null) + { + splitKey.push(""); + } + else + { //should never get here -- if problems put debugging code here //val = val; // good enough for a breakpoint to be set. + } } + copy.set(splitKey[1], splitKey[2], splitKey[3], val); } - copy.set(splitKey[1], splitKey[2], splitKey[3], val); } return copy; } @@ -481,16 +470,18 @@ function UCIContainer() { var str=""; var keyIndex=0; - for(keyIndex=0; keyIndex < this.keys.length; keyIndex++) + for (var key in this.values) { - var key = this.keys[keyIndex] - if(this.values[key] instanceof Array ) - { - str=str+ "\n" + key + " = \"" + this.values[key].join(",") + "\""; - } - else + if (this.values.hasOwnProperty(key)) { - str=str+ "\n" + key + " = \"" + this.values[key] + "\""; + if(this.values[key] instanceof Array ) + { + str=str+ "\n" + key + " = \"" + this.values[key].join(",") + "\""; + } + else + { + str=str+ "\n" + key + " = \"" + this.values[key] + "\""; + } } } return str; @@ -543,44 +534,46 @@ function UCIContainer() } } - for(keyIndex=0; keyIndex < this.keys.length; keyIndex++) + for (var key in this.values) { - var key = this.keys[keyIndex]; - var oldValue = oldSettings.values[key]; - var newValue = this.values[key]; - try + if (this.values.hasOwnProperty(key)) { - - if( (oldValue instanceof Array) || (newValue instanceof Array) ) + var oldValue = oldSettings.values[key]; + var newValue = this.values[key]; + try { - if(newValue instanceof Array) + + if( (oldValue instanceof Array) || (newValue instanceof Array) ) { - if(listsWithoutUpdates[key] == null) + if(newValue instanceof Array) { - var vi; - for(vi=0; vi< newValue.length ; vi++) + if(listsWithoutUpdates[key] == null) { - var nv = "" + newValue[vi] + ""; - commandArray.push( "uci add_list " + key + "=\'" + nv.replace(/'/, "'\\''") + "\'" ); + var vi; + for(vi=0; vi< newValue.length ; vi++) + { + var nv = "" + newValue[vi] + ""; + commandArray.push( "uci add_list " + key + "=\'" + nv.replace(/'/, "'\\''") + "\'" ); + } } } + else + { + newValue = "" + newValue + "" + commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/, "'\\''") + "\'" ); + } } - else + else if(oldValue != newValue && (newValue != null && newValue !='')) { newValue = "" + newValue + "" commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/, "'\\''") + "\'" ); } } - else if(oldValue != newValue && (newValue != null && newValue !='')) + catch(e) { - newValue = "" + newValue + "" - commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/, "'\\''") + "\'" ); + alert("bad key = " + key + "\n"); } } - catch(e) - { - alert("bad key = " + key + "\n"); - } } commandArray.push("uci commit"); From 30aaad86f7f4035536bc0b3f98527cb57bdf4abc Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Wed, 2 Dec 2015 22:54:30 +1100 Subject: [PATCH 06/48] Rough-cut Device Group implementation device.sh is implemented to enable DeviceNames to be associated with one or more MACs, and to enable DeviceNames to be assigned to Device Groups. --- package/gargoyle/files/www/device.sh | 113 +++++ package/gargoyle/files/www/js/device.js | 427 ++++++++++++++++++ .../files/www/templates/device_template | 12 + .../files/www/templates/group_template | 12 + .../files/www/i18n/English-EN/device.js | 16 + 5 files changed, 580 insertions(+) create mode 100644 package/gargoyle/files/www/device.sh create mode 100644 package/gargoyle/files/www/js/device.js create mode 100644 package/gargoyle/files/www/templates/device_template create mode 100644 package/gargoyle/files/www/templates/group_template create mode 100644 package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js diff --git a/package/gargoyle/files/www/device.sh b/package/gargoyle/files/www/device.sh new file mode 100644 index 0000000000..31349da05e --- /dev/null +++ b/package/gargoyle/files/www/device.sh @@ -0,0 +1,113 @@ +#!/usr/bin/haserl +<% + # This program is copyright © 2008-2015 John Brown and is distributed under the terms of the GNU GPL + # version 2.0 with a special clarification/exception that permits adapting the program to + # configure proprietary "back end" software provided that all modifications to the web interface + # itself remain covered by the GPL. + # See http://gargoyle-router.com/faq.html#qfoss for more information + eval $( gargoyle_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.sh" -t $(uci get gargoyle.global.session_timeout) -b "$COOKIE_browser_time" ) + gargoyle_header_footer -h -s "connection" -p "devices" -c "internal.css" -j "table.js device.js" -z "device.js" network dhcp known + subnet=$(ifconfig br-lan | awk 'BEGIN {FS=":"}; $0 ~ /inet.addr/ {print $2}' | awk 'BEGIN {FS="."}; {print $1"\."$2"\."$3"\."}') +%> + + + +
+ +
+ <%~ KnDev %> + +
+ +
+
+
+ <%in templates/device_template %> +
+
+ +
+
+ +
+ <%~ KnDev %>: +
+
+
+
+
+ + +
+ <%~ DevGp %> + +
+ +
+
+
+ <%in templates/group_template %> +
+
+ + +
+
+ +
+ <%~ DevGp %>: +
+
+
+
+
+ + + +
+ + +
+
+ + + + + +<% + gargoyle_header_footer -f -s "connection" -p "devices" +%> diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js new file mode 100644 index 0000000000..ea86e914b4 --- /dev/null +++ b/package/gargoyle/files/www/js/device.js @@ -0,0 +1,427 @@ +/* + * This program is copyright © 2015 John Brown and is distributed under the terms of the GNU GPL + * version 2.0 with a special clarification/exception that permits adapting the program to + * configure proprietary "back end" software provided that all modifications to the web interface + * itself remain covered by the GPL. + * See http://gargoyle-router.com/faq.html#qfoss for more information + */ + +var deviceS=new Object(); //part of i18n + +function saveChanges() +{ + //errorList = proofreadAll(); + errorList = ""; + if(errorList.length > 0) + { + errorString = errorList.join("\n") + "\n\n"+UI.ErrChanges; + alert(errorString); + } + else + { + setControlsEnabled(false, true); + + uci = uciOriginal.clone(); + + saveDeviceChanges(uci); + saveGroupChanges(uci); + + commands = uci.getScriptCommands(uciOriginal) ; + + var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); + + var stateChangeFunction = function(req) + { + if(req.readyState == 4) + { + uciOriginal = uci.clone(); + //resetData(); + //alert(req.responseText); + } + } + runAjax("POST", "utility/run_commands.sh", param, stateChangeFunction); + } +} + + +function saveDeviceChanges(uci){ + deviceTable = document.getElementById('device_table_container').firstChild; + tableData = getTableDataArray(deviceTable, true, false); + + uci.removeAllSectionsOfType('known','device'); + for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) + { + rowData = tableData[rowIndex]; + var device = rowData[0]; + var macs = rowData[1]; + uci.set("known", device, "mac", macs.split("\n"), true); + } +} + + +function saveGroupChanges(uci){ +} + + +function createEditButton(onclick) +{ + var editButton = createInput("button"); + editButton.value = UI.Edit; + editButton.className="default_button"; + editButton.onclick = onclick; + return editButton; +} + +function resetData() +{ + resetDeviceTable(); + resetGroupTable(); + + //setup hostname/mac list + resetHostList(); + resetGroupList(); + resetDeviceList(); +} + + + +function resetDeviceTable() +{ + var deviceTableData = new Array(); + + var devices = uciOriginal.getAllSectionsOfType("known", "device"); + for (dIx=0; dIx < devices.length; dIx++) + { // process the MAC's assigned to each device + var device = devices[dIx]; + var devMacs = uciOriginal.get("known", device, "mac"); + var macs = (devMacs instanceof Array) ? devMacs.join("\n") : "" ; + macs = macs.slice(1); // truely horrible brittle removal of the first extraneous /n + deviceTableData.push([device, macs, createEditButton("editDevice")]); + } + + // create the device Table and place it into the document + var columnNames=[deviceS.DevNm, "MACs", '']; + var deviceTable=createTable(columnNames, deviceTableData, "device_table", true, false, removeDevice ); + var tableContainer = document.getElementById('device_table_container'); + if(tableContainer.firstChild != null) + { + tableContainer.removeChild(tableContainer.firstChild); + } + tableContainer.appendChild(deviceTable); +} + + +/** +* Populates a Select id=host_list with know MACs which have not yet been assigned +* to a Known Device. +*/ +function resetHostList() +{ + var kmMacIndex = 0; + var kmHostIndex = 2; + var knownMac = knownMacLookup(); + + var deviceTable = document.getElementById("device_table_container").firstChild; + var dtdMacIx = 1; + var deviceTableData = (deviceTable == null) ? [] : getTableDataArray(deviceTable, true, false); + var deviceMacs = ''; + for (dtdIx=0; dtdIx < deviceTableData.length; dtdIx++){ + deviceMacs = deviceMacs.concat(deviceTableData[dtdIx][dtdMacIx], ","); + } + + var hlVals = [ "none" ]; + var hlText = [ deviceS.SelH ]; + for (var mac in knownMac) + { + if (knownMac.hasOwnProperty(mac)) + { + if( deviceMacs.indexOf(mac) == -1 ) + { // exclude MAC's that are already assigned to a device + var host = knownMac[mac][kmHostIndex]; + hlVals.push( host + "," + mac ); + hlText.push((host == "" || host == "*" ? mac : host ) + " " + mac); + } + } + } + + setAllowableSelections("host_list", hlVals, hlText, document); +} + + + +function removeDevice(table, row) +{ + resetHostList(); +} + + + +function hostSelected() +{ + var selectedVal = getSelectedValue("host_list"); + var host = document.getElementById("add_host"); + var macs = document.getElementById("add_mac"); + if(selectedVal == "") + { + host.value = ""; + macs.value = ""; + } + else + { + if (host.value == "") + { + host.value = (selectedVal.split(/,/))[0]; + } + var selMac = (selectedVal.split(/,/))[1]; + macs.value = (macs.value == null) ? selMac : macs.value.concat(" ", selMac); + setSelectedValue("host_list", ""); + } +} + + +function addMac() +{ + //errors = proofreadDevice(document); + errors = ""; + if(errors.length > 0) + { + alert(errors.join("\n") + "\n\n" + deviceS.AErr); + } + else + { + var host = document.getElementById("add_host"); + var macs = document.getElementById("add_mac"); + if (host.value != null && macs.value != null) + { + var deviceTable = document.getElementById('device_table_container').firstChild; + var values = [host.value, macs.value.replace(/ /g, "\n"), createEditButton("editDevice")]; + addTableRow(deviceTable, values, true, false, resetHostList); + host.value = ""; + macs.value = ""; + } + } +} + + +function proofReadMac(input) +{ + window.alert("please implement proofReadMAC"); +} + + + +function resetGroupTable() +{ + var groupTableData = new Array(); + + var groups = new Object(); + var devices = uciOriginal.getAllSectionsOfType("known", "device"); + + for (dIx=0; dIx < devices.length; dIx++) + { // survey all of the devices and groups + var device = devices[dIx]; + var group = uciOriginal.get("known", device, "group"); + if (group != null && group.length > 0) + { + if (groups.hasOwnProperty(group)) + { + groups[group].push(device); + } + else + { + groups[group] = [device]; + } + } + } + + for (var group in groups) + { // place each group in an array + if (groups.hasOwnProperty(group)) + { // with a list of member devices + groupTableData.push([group, groups[group].join("\n"), createEditButton("editGroup")]); + } + } + + // create the group Table and place it into the document + var columnNames=[deviceS.GpNm, deviceS.DevNms, '']; + var groupTable=createTable(columnNames, groupTableData, "group_table", true, false, removeGroup ); + var tableContainer = document.getElementById('group_table_container'); + if(tableContainer.firstChild != null) + { + tableContainer.removeChild(tableContainer.firstChild); + } + tableContainer.appendChild(groupTable); +} + + +/** +* Populates a Select id=group_list with know MACs which have not yet been assigned +* to a Known Device. +*/ +function resetGroupList() +{ + var groups = []; + var devices = uciOriginal.getAllSectionsOfType("known", "device"); + for (dIx=0; dIx < devices.length; dIx++) + { // survey all of the devices and groups + var device = devices[dIx]; + var group = uciOriginal.get("known", device, "group"); + if (groups.indexOf(group) == -1) + { + groups.push(group); + } + } + + var gpVals = [ "" ]; + var gpText = [ deviceS.SelG ]; + for (gIx = 0; gIx < groups.length; gIx++) + { + var group = groups[gIx]; + gpVals.push( group ); + gpText.push( group); + } + setAllowableSelections("group_list", gpVals, gpText, document); +} + + +function removeGroup(table, row) +{ + resetGroupList(); +} + + +function groupSelected() +{ + document.getElementById("add_group").value = getSelectedValue("group_list"); +} + + +/** +* Populates a Select id=device_list with know MACs which have not yet been assigned +* to a Known Device. +*/ +function resetDeviceList() +{ + var gpVals = [ "" ]; + var gpText = [ deviceS.SelD ]; + + var devices = uciOriginal.getAllSectionsOfType("known", "device"); + for (dIx=0; dIx < devices.length; dIx++) + { // survey all of the devices and groups + var device = devices[dIx]; + var group = uciOriginal.get("known", device, "group"); + if (group == null || group.length == 0) + { + gpVals.push( device ); + gpText.push( device ); + } + } + + setAllowableSelections("device_list", gpVals, gpText, document); +} + + +function deviceSelected() +{ + document.getElementById("add_device").value = getSelectedValue("device_list"); +} + + +function addDevice() +{ + //errors = proofreadDevice(document); + errors = ""; + if(errors.length > 0) + { + alert(errors.join("\n") + "\n\n" + deviceS.AErr); + } + else + { + var group = document.getElementById("add_group"); + var devices = document.getElementById("add_device"); + if (group.value != null && devices.value != null) + { + var groupTable = document.getElementById('group_table_container').firstChild; + var values = [group.value, devices.value, createEditButton("editGroup")]; + addTableRow(groupTable,values, true, false, resetDeviceList); + group.value=""; + devices.value=""; + } + } +} + +/** +* Returns an Object able to be used as a lookup table indexed by the MAC and +* containing an [MAC, IP, hostname] for hosts listed in /etc/ethers and +* /tmp/dhcp.leases +*/ +function knownMacLookup() +{ // gather known MACs from /etc/ethers + var knownMac = mergeEtherHost(); + var kmMacIndex = 0; + var macLookup = lookupList(knownMac, kmMacIndex); + + var ldMacIndex = 0; + var ldIpIndex = 1; + var ldHostIndex = 2; + for(ldIndex=0; ldIndex < leaseData.length; ldIndex++) + { // gather known MACs from dhcp leases + var leaseRow = leaseData[ldIndex]; + var mac = leaseRow[ldMacIndex].toUpperCase(); + if(macLookup[mac] == null) + { + macLookup[mac] = [mac, leaseRow[ldIpIndex], leaseRow[ldHostIndex]]; + } + } + return macLookup; +} + + +/** +* Returns an Array of Arrays containing [mac, ip, host] generated by +* combining /etc/hosts with /etc/ethers +*/ +function mergeEtherHost() +{ + var hdIpIndex = 0; + var hdHostIndex = 1; + var hostLookup = lookupList(hostData, hdIpIndex); + + var mhdMacIndex = 0; + var mhdIpIndex = 1; + var mhdHostIndex = 2; + var macHostData = etherData.slice(); + for(var mhdIndex=0; mhdIndex < macHostData.length; mhdIndex++) + { + macHostData[mhdIndex][mhdMacIndex] = macHostData[mhdIndex][mhdMacIndex].toUpperCase(); + var host = null; + var mhdRow = macHostData[mhdIndex]; + var ip = mhdRow[mhdIpIndex]; + var hdRow = hostLookup[ ip ]; + if (hdRow instanceof Array) + { + host = hdRow[hdHostIndex] ; + } + macHostData[mhdIndex][mhdHostIndex] = (host == null) ? "?" : host ; + } + + return macHostData; +} + + +/** +* Returns an Object able to be used as a Lookup table on the elements of the +* supplied data[][], indexed by the data[][field]. +* data: an Array of Arrays +* field: the index of a field in the inner array to be used as the lookup index. +*/ +function lookupList(data, field){ + var lookup = new Object(); + var index=0; + for(index=0; index < data.length; index++) + { + var key = (data[index][field]); + lookup[key] = data[index]; + } + return lookup; +} diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template new file mode 100644 index 0000000000..de0974fb9d --- /dev/null +++ b/package/gargoyle/files/www/templates/device_template @@ -0,0 +1,12 @@ + + + + + + + + + + + +
diff --git a/package/gargoyle/files/www/templates/group_template b/package/gargoyle/files/www/templates/group_template new file mode 100644 index 0000000000..d5a637b59c --- /dev/null +++ b/package/gargoyle/files/www/templates/group_template @@ -0,0 +1,12 @@ + + + + + + + + + + + +
diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js new file mode 100644 index 0000000000..8eb88ca482 --- /dev/null +++ b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js @@ -0,0 +1,16 @@ +/* + * UTF-8 (with BOM) English-EN text strings for device.sh html elements + */ + +deviceS.KnDev="Known Devices"; +deviceS.AdKnDev="Add Known Device"; +deviceS.AdGp="Add Group"; +deviceS.DevNm="Device name"; +deviceS.DevNms="Device names"; +deviceS.GpNm="Group name"; +deviceS.EdKnDev="Edit Device"; +deviceS.DevGp="Device Groups"; +deviceS.SelH="Select known Host"; +deviceS.SelG="Select Group"; +deviceS.SelD="Select known Device"; +deviceS.GpNm="Group name"; From 66952b839ec8e30b72ef95494d3ea2969bd7db7c Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 3 Dec 2015 00:02:45 +1100 Subject: [PATCH 07/48] fix i18n implementation completed the initial i18n implementation in devices.sh --- package/gargoyle/files/www/device.sh | 4 ++-- package/gargoyle/files/www/templates/device_template | 2 +- package/gargoyle/files/www/templates/group_template | 2 +- .../files/www/i18n/English-EN/device.js | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package/gargoyle/files/www/device.sh b/package/gargoyle/files/www/device.sh index 31349da05e..a4666482d9 100644 --- a/package/gargoyle/files/www/device.sh +++ b/package/gargoyle/files/www/device.sh @@ -37,7 +37,7 @@
- <%~ KnDev %> + <%~ device.KnDev %>
@@ -48,7 +48,7 @@
diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index de0974fb9d..6ca3776710 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -1,6 +1,6 @@ - + diff --git a/package/gargoyle/files/www/templates/group_template b/package/gargoyle/files/www/templates/group_template index d5a637b59c..1283700ea0 100644 --- a/package/gargoyle/files/www/templates/group_template +++ b/package/gargoyle/files/www/templates/group_template @@ -1,7 +1,7 @@
- + diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js index 8eb88ca482..4d9be8e1e8 100644 --- a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js +++ b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js @@ -5,12 +5,12 @@ deviceS.KnDev="Known Devices"; deviceS.AdKnDev="Add Known Device"; deviceS.AdGp="Add Group"; +deviceS.GpNm="Group name"; deviceS.DevNm="Device name"; deviceS.DevNms="Device names"; deviceS.GpNm="Group name"; deviceS.EdKnDev="Edit Device"; deviceS.DevGp="Device Groups"; -deviceS.SelH="Select known Host"; +deviceS.SelH="Select Known Host"; deviceS.SelG="Select Group"; -deviceS.SelD="Select known Device"; -deviceS.GpNm="Group name"; +deviceS.SelD="Select Known Device"; From 00e00fb1f631e4bbe27428370cb491f3dd878ee4 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 3 Dec 2015 06:40:59 +1100 Subject: [PATCH 08/48] Add device.sh to Gargoyle Menu Gargoyle - Connections - Devices --- package/gargoyle/files/etc/config/gargoyle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package/gargoyle/files/etc/config/gargoyle b/package/gargoyle/files/etc/config/gargoyle index 2be0104cfc..869e16a0b9 100644 --- a/package/gargoyle/files/etc/config/gargoyle +++ b/package/gargoyle/files/etc/config/gargoyle @@ -30,6 +30,7 @@ config display display option connection 'Connection' option connection_dyndns 'Dynamic DNS' option connection_dhcp 'DHCP' + option connection_devices 'Devices' option connection_basic 'Basic' option connection_routing 'Routing' option connection_wol 'Wake on LAN' @@ -62,6 +63,7 @@ config scripts scripts option connection_dyndns 'ddns.sh' option connection_basic 'basic.sh' option connection_dhcp 'dhcp.sh' + option connection_devices 'device.sh' option connection_routing 'routing.sh' option connection_wol 'wol.sh' option system_access 'access.sh' @@ -93,6 +95,7 @@ config 100 status config 200 connection option basic '100' option dhcp '200' + option devices '250' option dyndns '300' option routing '400' option wol '500' @@ -117,4 +120,3 @@ config bandwidth_display bandwidth_display config help help option ddns_1 1 - From 23330523bc9c85faf3f4b9eec0759706ea21fa51 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 3 Dec 2015 09:27:22 +1100 Subject: [PATCH 09/48] Implement SaveChanges & validate GroupName rename SelectMAC validate GroupName implement Save Changes to uci --- package/gargoyle/files/www/device.sh | 4 +- package/gargoyle/files/www/js/device.js | 63 +++++++++++++------ .../files/www/templates/device_template | 2 +- .../files/www/i18n/English-EN/device.js | 2 +- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/package/gargoyle/files/www/device.sh b/package/gargoyle/files/www/device.sh index a4666482d9..19cb654307 100644 --- a/package/gargoyle/files/www/device.sh +++ b/package/gargoyle/files/www/device.sh @@ -47,8 +47,8 @@ <%in templates/device_template %>
- +
diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js index ea86e914b4..7c1196709d 100644 --- a/package/gargoyle/files/www/js/device.js +++ b/package/gargoyle/files/www/js/device.js @@ -36,6 +36,7 @@ function saveChanges() { uciOriginal = uci.clone(); //resetData(); + setControlsEnabled(true); //alert(req.responseText); } } @@ -48,18 +49,37 @@ function saveDeviceChanges(uci){ deviceTable = document.getElementById('device_table_container').firstChild; tableData = getTableDataArray(deviceTable, true, false); - uci.removeAllSectionsOfType('known','device'); for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) { rowData = tableData[rowIndex]; var device = rowData[0]; var macs = rowData[1]; + if (uci.get("known", device).length == 0){ + uci.set("known", device, null, "device"); + } uci.set("known", device, "mac", macs.split("\n"), true); } } function saveGroupChanges(uci){ + groupTable = document.getElementById('group_table_container').firstChild; + tableData = getTableDataArray(groupTable, true, false); + + for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) + { + rowData = tableData[rowIndex]; + var group = rowData[0]; + var devices = rowData[1].split("\n"); + for(dIx=0; dIx < devices.length; dIx++) + { + var device = devices[dIx]; + if (uci.get("known", device).length == 0){ + uci.set("known", device, null, "device"); + } + uci.set("known", device, "group", group, true); + } + } } @@ -78,7 +98,7 @@ function resetData() resetGroupTable(); //setup hostname/mac list - resetHostList(); + resetMacList(); resetGroupList(); resetDeviceList(); } @@ -112,10 +132,10 @@ function resetDeviceTable() /** -* Populates a Select id=host_list with know MACs which have not yet been assigned +* Populates a Select id=mac_list with know MACs which have not yet been assigned * to a Known Device. */ -function resetHostList() +function resetMacList() { var kmMacIndex = 0; var kmHostIndex = 2; @@ -129,8 +149,8 @@ function resetHostList() deviceMacs = deviceMacs.concat(deviceTableData[dtdIx][dtdMacIx], ","); } - var hlVals = [ "none" ]; - var hlText = [ deviceS.SelH ]; + var hlVals = [ "" ]; + var hlText = [ deviceS.SelM ]; for (var mac in knownMac) { if (knownMac.hasOwnProperty(mac)) @@ -144,22 +164,22 @@ function resetHostList() } } - setAllowableSelections("host_list", hlVals, hlText, document); + setAllowableSelections("mac_list", hlVals, hlText, document); } function removeDevice(table, row) { - resetHostList(); + resetMacList(); } -function hostSelected() +function macSelected() { - var selectedVal = getSelectedValue("host_list"); - var host = document.getElementById("add_host"); + var selectedVal = getSelectedValue("mac_list"); + var host = document.getElementById("add_host"); var macs = document.getElementById("add_mac"); if(selectedVal == "") { @@ -171,10 +191,11 @@ function hostSelected() if (host.value == "") { host.value = (selectedVal.split(/,/))[0]; + fixGroupName(host); } var selMac = (selectedVal.split(/,/))[1]; - macs.value = (macs.value == null) ? selMac : macs.value.concat(" ", selMac); - setSelectedValue("host_list", ""); + macs.value = (macs.value == "") ? selMac : macs.value.concat(" ", selMac); + setSelectedValue("mac_list", ""); } } @@ -195,17 +216,24 @@ function addMac() { var deviceTable = document.getElementById('device_table_container').firstChild; var values = [host.value, macs.value.replace(/ /g, "\n"), createEditButton("editDevice")]; - addTableRow(deviceTable, values, true, false, resetHostList); + addTableRow(deviceTable, values, true, false, resetMacList); host.value = ""; macs.value = ""; } } } +function fixGroupName(element) +{ + var name = element.value; + name = name.replace(/-|\s/g,"_"); + element.value = name; +} + function proofReadMac(input) { - window.alert("please implement proofReadMAC"); + // please implement proofReadMAC } @@ -393,18 +421,17 @@ function mergeEtherHost() var macHostData = etherData.slice(); for(var mhdIndex=0; mhdIndex < macHostData.length; mhdIndex++) { - macHostData[mhdIndex][mhdMacIndex] = macHostData[mhdIndex][mhdMacIndex].toUpperCase(); var host = null; var mhdRow = macHostData[mhdIndex]; + mhdRow[mhdMacIndex] = mhdRow[mhdMacIndex].toUpperCase(); var ip = mhdRow[mhdIpIndex]; var hdRow = hostLookup[ ip ]; if (hdRow instanceof Array) { host = hdRow[hdHostIndex] ; } - macHostData[mhdIndex][mhdHostIndex] = (host == null) ? "?" : host ; + mhdRow[mhdHostIndex] = (host == null) ? "?" : host ; } - return macHostData; } diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index 6ca3776710..73cbbecb90 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -5,7 +5,7 @@
- + diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js index 4d9be8e1e8..43710f030c 100644 --- a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js +++ b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js @@ -11,6 +11,6 @@ deviceS.DevNms="Device names"; deviceS.GpNm="Group name"; deviceS.EdKnDev="Edit Device"; deviceS.DevGp="Device Groups"; -deviceS.SelH="Select Known Host"; +deviceS.SelM="Select MAC"; deviceS.SelG="Select Group"; deviceS.SelD="Select Known Device"; From b67a12527d0f373aab3532ed0a9b3f6d7e7cfe44 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 3 Dec 2015 09:29:16 +1100 Subject: [PATCH 10/48] Bugfix extra } would have been nice if a extra } at the end of .js would generate a warning! --- package/gargoyle/files/www/js/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index d47a88fe9f..c739594558 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -311,10 +311,10 @@ function UCIContainer() { // add a new key and value this.values[ key ] = value; } - } } + this.get = function(pkg, section, option) { var next_key = pkg + "\." + section; From efae785c42f382d9be997889534985ac8c68843b Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 3 Dec 2015 09:47:03 +1100 Subject: [PATCH 11/48] Bump dosfstools 3.0.28 dosfstools 3.0.27 not found in repositories --- package/dosfstools/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/dosfstools/Makefile b/package/dosfstools/Makefile index 41483f2ef7..5bcabd6582 100644 --- a/package/dosfstools/Makefile +++ b/package/dosfstools/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dosfstools -PKG_VERSION:=3.0.27 +PKG_VERSION:=3.0.28 PKG_RELEASE:=1 PKG_LICENSE:=GPL-3.0+ @@ -19,7 +19,7 @@ PKG_MAINTAINER:=David Bonnes PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://daniel-baumann.ch/files/software/dosfstools \ http://fossies.org/linux/misc -PKG_MD5SUM:=2e31e7bdf92998e41ed17de505a4a552 +PKG_MD5SUM:=64e3b3a59b51d2a97d7ac38b23a124bb include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/nls.mk From f1829c41e9b8539612a267671a8d601b02669f96 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 3 Dec 2015 12:00:00 +1100 Subject: [PATCH 12/48] Create README.md --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..b8084679b7 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# gargoyle +Known Devices + +The idea is to be able to set policy (Quota, QoS, Restrictions etc) over a +Group of Known Devices (owned by an individual for example). To achieve this +the Known Devices need to be identified by their MAC address' and then arranged +into Groups. Both Devices and Groups can be named by the Gargoyle Administrator. + +Currently, the user has to work with an IP range for the devices of each user throughout +the Gargoyle GUI. MAC Groups will releive the Gargoyle administrator of needing to asign +a static IP address to each device requiring management. + +Status +- Gargoyle-Connection-Devices has a Section for Known Devices and another for Device Groups. +- Known Device and Group data is stored in uci /etc/config/known From ad9eda6d09be07f96b6a8fda7e70dacfc02d9e6b Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 4 Dec 2015 07:33:09 +1100 Subject: [PATCH 13/48] Bug Fix Remove missed reference to keys --- package/gargoyle/files/www/js/common.js | 145 ++++++++++++------------ 1 file changed, 72 insertions(+), 73 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index d47a88fe9f..0322a2a06e 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -257,63 +257,60 @@ function UCIContainer() { this.values = new Object(); - this.createListOption = function(pkg,section,option,destroy_existing_nonlist) + this.createListOption = function(pkg,section,option,destroy_existing_nonlist) + { + destroy_existing_nonlist = destroy_existing_nonlist == null ? true : false; + var list_key = pkg + "\." + section + "\." + option; + var existing_value = this.values[ list_key ]; + if( existing_value instanceof Array ) { - destroy_existing_nonlist = destroy_existing_nonlist == null ? true : false; - var list_key = pkg + "\." + section + "\." + option; - var existing_value = this.values[ list_key ]; - if( existing_value instanceof Array ) - { - return; - } - else if(destroy_existing_nonlist) - { - this.values[ list_key ] = []; - } - else - { - this.values[ list_key ] = [existing_value]; - } + return; } + else if(destroy_existing_nonlist) + { + this.values[ list_key ] = []; + } + else + { + this.values[ list_key ] = [existing_value]; + } + } - - this.set = function(pkg, section, option, value, preserveExistingListValues) + this.set = function(pkg, section, option, value, preserveExistingListValues) + { + preserveExistingListValues = preserveExistingListValues == null ? false : preserveExistingListValues; + var key = pkg + "\." + section; + if(option != null && option != "" ) { - preserveExistingListValues = preserveExistingListValues == null ? false : preserveExistingListValues; - var key = pkg + "\." + section; - if(option != null && option != "" ) + key = key + "\." + option; + } + if(this.values.hasOwnProperty(key)) + { // an existing key + if (preserveExistingListValues) { - key = key + "\." + option; - } - if(this.values.hasOwnProperty(key)) - { // an existing key - if (preserveExistingListValues) + var existingValue = this.values[ key ]; + var existingValues = (existingValue instanceof Array) ? existingValue : [existingValue]; + var newValues = ( value instanceof Array ) ? value : [value]; + var vi; + for(vi=0; vi Date: Fri, 4 Dec 2015 11:35:07 +1100 Subject: [PATCH 14/48] Bug fix To resolve a mess --- package/gargoyle/files/www/js/common.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index f8b8229ecf..5f3106824c 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -305,10 +305,6 @@ function UCIContainer() { // simply replace the existing values this.values[ key ] = value; } - else - { // add a new key and value - this.values[ key ] = value; - } } else { // add a new key and value From 403d64198e7e29b07dd8374679abc8881ae81877 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 4 Dec 2015 11:44:14 +1100 Subject: [PATCH 15/48] Add blank uci file: known --- package/gargoyle/files/etc/config/known | 1 + 1 file changed, 1 insertion(+) create mode 100644 package/gargoyle/files/etc/config/known diff --git a/package/gargoyle/files/etc/config/known b/package/gargoyle/files/etc/config/known new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/package/gargoyle/files/etc/config/known @@ -0,0 +1 @@ + From 5ef607be7e9348b40e24e6e4b851ff794a1bc5e7 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sat, 5 Dec 2015 08:30:44 +1100 Subject: [PATCH 16/48] Various tidyup & bug fix - various js tidy-up and bug fix - correct device lable - css layout for device & group table columns --- README.md | 17 +- package/gargoyle/files/www/js/common.js | 43 ++- package/gargoyle/files/www/js/device.js | 280 +++++++++--------- .../files/www/templates/device_template | 2 +- .../files/www/themes/Gargoyle/internal.css | 23 +- 5 files changed, 208 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index b8084679b7..dc4c80718b 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,22 @@ # gargoyle Known Devices -The idea is to be able to set policy (Quota, QoS, Restrictions etc) over a -Group of Known Devices (owned by an individual for example). To achieve this +The idea is to be able to set policy (Quota, QoS, Restrictions etc) over a +Group of Known Devices (owned by an individual for example). To achieve this the Known Devices need to be identified by their MAC address' and then arranged into Groups. Both Devices and Groups can be named by the Gargoyle Administrator. -Currently, the user has to work with an IP range for the devices of each user throughout -the Gargoyle GUI. MAC Groups will releive the Gargoyle administrator of needing to asign -a static IP address to each device requiring management. +Currently, the user has to work with an IP range for the devices of each user +throughout the Gargoyle GUI. MAC Groups will relieve the Gargoyle administrator +of needing to assign a static IP address to each device requiring management. Status - Gargoyle-Connection-Devices has a Section for Known Devices and another for Device Groups. - Known Device and Group data is stored in uci /etc/config/known + +TODO device.sh +- Update selects after address +- layout input and select elements +- implement edit button +- implement remove button +- diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 5f3106824c..4e82b00d88 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -256,11 +256,12 @@ function execute(cmd) function UCIContainer() { this.values = new Object(); + const DOT = "."; this.createListOption = function(pkg,section,option,destroy_existing_nonlist) { destroy_existing_nonlist = destroy_existing_nonlist == null ? true : false; - var list_key = pkg + "\." + section + "\." + option; + var list_key = pkg + DOT + section + DOT + option; var existing_value = this.values[ list_key ]; if( existing_value instanceof Array ) { @@ -279,25 +280,37 @@ function UCIContainer() this.set = function(pkg, section, option, value, preserveExistingListValues) { preserveExistingListValues = preserveExistingListValues == null ? false : preserveExistingListValues; - var key = pkg + "\." + section; + var key = pkg + DOT + section; if(option != null && option != "" ) { - key = key + "\." + option; + key = key + DOT + option; } + if(this.values.hasOwnProperty(key)) { // an existing key if (preserveExistingListValues) - { - var existingValue = this.values[ key ]; - var existingValues = (existingValue instanceof Array) ? existingValue : [existingValue]; + { // guarantee that the existing values are an Array + var existing = this.values[ key ]; + if (!(existing instanceof Array)) + { + this.values[ key ] = (existing == null) ? [] : [existing]; + } + + var existingValues = this.values[ key ]; var newValues = ( value instanceof Array ) ? value : [value]; - var vi; - for(vi=0; vi 0) - { - alert(errors.join("\n") + "\n\n" + deviceS.AErr); - } - else - { - var host = document.getElementById("add_host"); - var macs = document.getElementById("add_mac"); - if (host.value != null && macs.value != null) - { - var deviceTable = document.getElementById('device_table_container').firstChild; - var values = [host.value, macs.value.replace(/ /g, "\n"), createEditButton("editDevice")]; - addTableRow(deviceTable, values, true, false, resetMacList); - host.value = ""; - macs.value = ""; - } - } -} - -function fixGroupName(element) -{ - var name = element.value; - name = name.replace(/-|\s/g,"_"); - element.value = name; -} - - -function proofReadMac(input) -{ - // please implement proofReadMAC -} - - - function resetGroupTable() { var groupTableData = new Array(); @@ -245,9 +137,9 @@ function resetGroupTable() var groups = new Object(); var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIx=0; dIx < devices.length; dIx++) + for (dIndex=0; dIndex < devices.length; dIndex++) { // survey all of the devices and groups - var device = devices[dIx]; + var device = devices[dIndex]; var group = uciOriginal.get("known", device, "group"); if (group != null && group.length > 0) { @@ -282,6 +174,43 @@ function resetGroupTable() } + +/** +* Populates a Select id=mac_list with know MACs which have not yet been assigned +* to a Known Device. +*/ +function resetMacList() +{ + var kmMacIndex = 0; + var kmHostIndex = 2; + var knownMac = knownMacLookup(); + + var deviceTable = document.getElementById("device_table_container").firstChild; + var dtdMacIx = 1; + var deviceTableData = (deviceTable == null) ? [] : getTableDataArray(deviceTable, true, false); + var deviceMacs = ''; + for (dtdIndex=0; dtdIndex < deviceTableData.length; dtdIndex++){ + deviceMacs = deviceMacs.concat(deviceTableData[dtdIndex][dtdMacIx], ","); + } + + var hlVals = [ "" ]; + var hlText = [ deviceS.SelM ]; + for (var mac in knownMac) + { + if (knownMac.hasOwnProperty(mac)) + { + if( deviceMacs.indexOf(mac) == -1 ) + { // exclude MAC's that are already assigned to a device + var host = knownMac[mac][kmHostIndex]; + hlVals.push( host + "," + mac ); + hlText.push((host == "" || host == "*" ? mac : host ) + " " + mac); + } + } + } + + setAllowableSelections("mac_list", hlVals, hlText, document); +} + /** * Populates a Select id=group_list with know MACs which have not yet been assigned * to a Known Device. @@ -290,11 +219,11 @@ function resetGroupList() { var groups = []; var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIx=0; dIx < devices.length; dIx++) + for (dIndex=0; dIndex < devices.length; dIndex++) { // survey all of the devices and groups - var device = devices[dIx]; + var device = devices[dIndex]; var group = uciOriginal.get("known", device, "group"); - if (groups.indexOf(group) == -1) + if (group.length > 0 && groups.indexOf(group) == -1) { groups.push(group); } @@ -311,19 +240,6 @@ function resetGroupList() setAllowableSelections("group_list", gpVals, gpText, document); } - -function removeGroup(table, row) -{ - resetGroupList(); -} - - -function groupSelected() -{ - document.getElementById("add_group").value = getSelectedValue("group_list"); -} - - /** * Populates a Select id=device_list with know MACs which have not yet been assigned * to a Known Device. @@ -334,9 +250,9 @@ function resetDeviceList() var gpText = [ deviceS.SelD ]; var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIx=0; dIx < devices.length; dIx++) + for (dIndex=0; dIndex < devices.length; dIndex++) { // survey all of the devices and groups - var device = devices[dIx]; + var device = devices[dIndex]; var group = uciOriginal.get("known", device, "group"); if (group == null || group.length == 0) { @@ -344,17 +260,77 @@ function resetDeviceList() gpText.push( device ); } } - setAllowableSelections("device_list", gpVals, gpText, document); } +/******************************************************************************* +* Event functions +*******************************************************************************/ + + +function macSelected() +{ + var selectedVal = getSelectedValue("mac_list"); + var host = document.getElementById("add_host"); + var macs = document.getElementById("add_mac"); + if(selectedVal == "") + { + host.value = ""; + macs.value = ""; + } + else + { + if (host.value == "") + { + host.value = (selectedVal.split(/,/))[0]; + fixGroupName(host); + } + var selMac = (selectedVal.split(/,/))[1]; + macs.value = (macs.value == "") ? selMac : macs.value.concat(" ", selMac); + setSelectedValue("mac_list", ""); + } +} + + +function groupSelected() +{ + document.getElementById("add_group").value = getSelectedValue("group_list"); +} + + function deviceSelected() { document.getElementById("add_device").value = getSelectedValue("device_list"); } + +function addMac() +{ + //errors = proofreadDevice(document); + errors = ""; + if(errors.length > 0) + { + alert(errors.join("\n") + "\n\n" + deviceS.AErr); + } + else + { + var host = document.getElementById("add_host"); + var macs = document.getElementById("add_mac"); + if (host.value != null && macs.value != null) + { + var deviceTable = document.getElementById('device_table_container').firstChild; + var values = [host.value, macs.value, createEditButton("editDevice")]; + addTableRow(deviceTable, values, true, false, resetMacList); + host.value = ""; + macs.value = ""; + } + } +} + + + function addDevice() { //errors = proofreadDevice(document); @@ -378,6 +354,40 @@ function addDevice() } } + + +function removeDevice(table, row) +{ + resetMacList(); +} + + +function removeGroup(table, row) +{ + resetGroupList(); +} + + + +function fixGroupName(element) +{ + var name = element.value; + name = name.replace(/-|\s/g,"_"); + element.value = name; +} + + +function proofReadMac(input) +{ + // please implement proofReadMAC +} + + + +/******************************************************************************* +* Utility functions +*******************************************************************************/ + /** * Returns an Object able to be used as a lookup table indexed by the MAC and * containing an [MAC, IP, hostname] for hosts listed in /etc/ethers and diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index 73cbbecb90..c0928286e0 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -1,6 +1,6 @@
- + diff --git a/package/gargoyle/files/www/themes/Gargoyle/internal.css b/package/gargoyle/files/www/themes/Gargoyle/internal.css index 532fa3f31a..d2bfe0f3c7 100644 --- a/package/gargoyle/files/www/themes/Gargoyle/internal.css +++ b/package/gargoyle/files/www/themes/Gargoyle/internal.css @@ -1,5 +1,5 @@ /* - * This program is copyright 2008-2011 Eric Bishop and is distributed under the terms of the GNU GPL + * This program is copyright � 2008-2011 Eric Bishop and is distributed under the terms of the GNU GPL * version 2.0 with a special clarification/exception that permits adapting the program to * configure proprietary "back end" software provided that all modifications to the web interface * itself remain covered by the GPL. @@ -1554,3 +1554,24 @@ td.bandwidth_table_column_4 text-align:right; border:1px solid #000; } + +td.device_table_column_1 +{ + text-align:left; +} + +td.device_table_column_2 +{ + text-align:center; + width:10em; +} + +td.group_table_column_1 +{ + text-align:left; +} + +td.group_table_column_2 +{ + text-align:left; +} From 7469eb65e8c5a5e29ea632c58745cfd2a3ec3dbf Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 6 Dec 2015 07:31:25 +1100 Subject: [PATCH 17/48] Implement Edit & Remove Buttons The Edit Button is done a little differently than std Gargoyle. In std Gargoyle the Edit Button pops up and populates a form for editing. Here, the Edited Row is Removed and the fields in the ADD form are populated with the existing info so that the user can adjust and re-add. This approach seems intuitive for the User and makes the JS code simpler and smaller. If editing a really large table then the User may be confused when the row dissapears while not being able to see the Add Row at the top? --- README.md | 4 +- package/gargoyle/files/www/js/common.js | 2 +- package/gargoyle/files/www/js/device.js | 96 ++++++++++++++----------- 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index dc4c80718b..8c049b7be2 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,4 @@ Status TODO device.sh - Update selects after address - layout input and select elements -- implement edit button -- implement remove button -- +- validate inputs diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 4e82b00d88..1b0457123d 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -403,7 +403,7 @@ function UCIContainer() this.remove = function(pkg, section, option) { var removeKey = pkg + DOT + section; - if(option != "") + if(option != "") { removeKey = removeKey + DOT + option; } diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js index 79b894fd1a..c620afdab0 100644 --- a/package/gargoyle/files/www/js/device.js +++ b/package/gargoyle/files/www/js/device.js @@ -22,9 +22,39 @@ function saveChanges() setControlsEnabled(false, true); uci = uciOriginal.clone(); + uci.removeAllSectionsOfType("known", "device"); - saveDeviceChanges(uci); - saveGroupChanges(uci); + // save Device changes + deviceTable = document.getElementById('device_table_container').firstChild; + tableData = getTableDataArray(deviceTable, true, false); + for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) + { + rowData = tableData[rowIndex]; + var device = rowData[0]; + var macs = rowData[1]; + if (uci.get("known", device).length == 0){ + uci.set("known", device, null, "device"); + } + uci.set("known", device, "mac", macs.split(" "), true); + } + + // save Group changes + groupTable = document.getElementById('group_table_container').firstChild; + tableData = getTableDataArray(groupTable, true, false); + for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) + { + rowData = tableData[rowIndex]; + var group = rowData[0]; + var devices = rowData[1].split(" "); + for(dIndex=0; dIndex < devices.length; dIndex++) + { + var device = devices[dIndex]; + if (uci.get("known", device).length == 0){ + uci.set("known", device, null, "device"); + } + uci.set("known", device, "group", group); + } + } commands = uci.getScriptCommands(uciOriginal) ; @@ -45,44 +75,6 @@ function saveChanges() } -function saveDeviceChanges(uci){ - deviceTable = document.getElementById('device_table_container').firstChild; - tableData = getTableDataArray(deviceTable, true, false); - - for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) - { - rowData = tableData[rowIndex]; - var device = rowData[0]; - var macs = rowData[1]; - if (uci.get("known", device).length == 0){ - uci.set("known", device, null, "device"); - } - uci.set("known", device, "mac", macs.split(" "), true); - } -} - - -function saveGroupChanges(uci){ - groupTable = document.getElementById('group_table_container').firstChild; - tableData = getTableDataArray(groupTable, true, false); - - for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) - { - rowData = tableData[rowIndex]; - var group = rowData[0]; - var devices = rowData[1].split("\n"); - for(dIndex=0; dIndex < devices.length; dIndex++) - { - var device = devices[dIndex]; - if (uci.get("known", device).length == 0){ - uci.set("known", device, null, "device"); - } - uci.set("known", device, "group", group, true); - } - } -} - - function createEditButton(onclick) { var editButton = createInput("button"); @@ -114,8 +106,8 @@ function resetDeviceTable() { // process the MAC's assigned to each device var device = devices[dIndex]; var devMacs = uciOriginal.get("known", device, "mac"); - var macs = (devMacs instanceof Array) ? devMacs.join("\n") : "" ; - deviceTableData.push([device, macs, createEditButton("editDevice")]); + var macs = (devMacs instanceof Array) ? devMacs.join(" ") : "" ; + deviceTableData.push([device, macs, createEditButton(editDevice)]); } // create the device Table and place it into the document @@ -158,7 +150,7 @@ function resetGroupTable() { // place each group in an array if (groups.hasOwnProperty(group)) { // with a list of member devices - groupTableData.push([group, groups[group].join("\n"), createEditButton("editGroup")]); + groupTableData.push([group, groups[group].join(" "), createEditButton(editGroup)]); } } @@ -355,6 +347,24 @@ function addDevice() } +function editDevice() +{ + editRow=this.parentNode.parentNode; + editRow.parentNode.removeChild(editRow); + document.getElementById('add_host').value = editRow.childNodes[0].firstChild.data; + document.getElementById('add_mac').value = editRow.childNodes[1].firstChild.data; +} + + +function editGroup() +{ + editRow=this.parentNode.parentNode; + editRow.parentNode.removeChild(editRow); + document.getElementById('add_group').value = editRow.childNodes[0].firstChild.data; + document.getElementById('add_device').value = editRow.childNodes[1].firstChild.data; +} + + function removeDevice(table, row) { From 434387ad9ec148bc935c65e19dc2c70b29f34329 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 6 Dec 2015 17:45:41 +1100 Subject: [PATCH 18/48] Integrate Device Groups into Quotas page The Gagoyle admin can use a Device Group to define a Quota by selecting "Only the following Host(s) and providing an IP, or IP range, or a Device Group. The Group can be selected or entered manually and it is validated an saved thru the existing processes. The Device Group MACs are included in the validation to avoid quota overlaps involving MACs. To integrate the MACs validation, the groupsValid parameter was added to the function addAddressStringToTable() and this cascaded small adjustments to other JavaScript files which called this function. --- package/gargoyle/files/www/js/common.js | 94 ++++++++- package/gargoyle/files/www/js/quotas.js | 181 +++++++++++------- package/gargoyle/files/www/quotas.sh | 2 +- .../files/www/templates/quotas_template | 15 +- package/gargoyle/files/www/webmon.sh | 2 +- .../files/www/i18n/English-EN/quotas.js | 3 +- .../files/www/js/usb_storage.js | 168 ++++++++-------- .../files/www/templates/usb_storage_template | 2 +- 8 files changed, 295 insertions(+), 172 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 1b0457123d..0eb6f81ae2 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -1557,6 +1557,7 @@ function validateIP(address) //3 = ends with 255 (actually, broadcast address can end with other value if subnet smaller than 255... but let's not worry about that) //4 = value >255 in at least one field //5 = improper format + //6 = Undefined Group var errorCode = 0; if(address == "0.0.0.0") @@ -1614,6 +1615,24 @@ function validateMac(mac) return errorCode; } + +function validateGroup(name) +{ + var errorCode = (deviceGroups().indexOf(name) == -1) ? 6 : 0 ; + return errorCode; +} + + +function validateMultipleIpsOrGroup(ips) +{ + var errorCode = validateGroup(ips); + if (errorCode != 0) + { + errorCode = validateMultipleIps(ips); + } + return errorCode; +} + function validateMultipleIps(ips) { ips = ips.replace(/^[\t ]+/g, ""); @@ -1915,6 +1934,10 @@ function proofreadMultipleIpsOrMacs(input) { proofreadText(input, validateMultipleIpsOrMacs, 0); } +function proofreadMultipleIpsOrGroup(input) +{ + proofreadText(input, validateMultipleIpsOrGroup, 0); +} function proofreadDecimal(input) { @@ -2101,10 +2124,11 @@ function textListToSpanElement(textList, addCommas, controlDocument) return spanEl; } -function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) +function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, tableId, macsValid, ipValidType, groupsValid, alertOnError, tableWidth) { //ipValidType: 0=none, 1=ip only, 2=ip or ip subnet, 3>=ip, ip subnet or ip range macsValid = macsValid == null ? true : macsValid; + groupsValid = groupsValid == null ? true : groupsValid; ipValidType = ipValidType == null ? 3 : ipValidType; var ipValidFunction; if(ipValidType == 0) @@ -2135,7 +2159,11 @@ function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, ta for(rowIndex=0; rowIndex < data.length; rowIndex++) { var addr = data[rowIndex][0]; - if(validateMac(addr) == 0) + if (validateGroup(addr) == 0) + { + allCurrentMacs.push(groupMacs(addr)); + } + else if(validateMac(addr) == 0) { allCurrentMacs.push(addr); } @@ -2157,9 +2185,9 @@ function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, ta var addr = splitAddrs[splitIndex]; var macValid = (macsValid && validateMac(addr) == 0); var ipValid = (ipValidFunction(addr) == 0); - if(macValid || ipValid) + if(macValid || ipValid || groupsValid) { - var currAddrs = macValid ? allCurrentMacs : allCurrentIps; + var currAddrs = (macValid || groupsValid) ? allCurrentMacs : allCurrentIps; valid = currAddrs.length == 0 || (!testAddrOverlap(addr, currAddrs.join(","))) ? 0 : 1; if(valid == 0) { @@ -2204,11 +2232,11 @@ function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, ta } -function addAddressesToTable(controlDocument, textId, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) +function addAddressesToTable(controlDocument, textId, tableContainerId, tableId, macsValid, ipValidType, groupsValid, alertOnError, tableWidth) { var newAddrs = controlDocument.getElementById(textId).value; - var valid = addAddressStringToTable(controlDocument, newAddrs, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) + var valid = addAddressStringToTable(controlDocument, newAddrs, tableContainerId, tableId, macsValid, ipValidType, groupsValid, alertOnError, tableWidth) if(valid) { controlDocument.getElementById(textId).value = ""; @@ -2754,10 +2782,62 @@ function query(queryHeader, queryText, buttonNameList, continueFunction ) } //apparently these var fbS=new Object(); //part of i18n -> objects do not have a length (it is undefined) -function ObjLen(an_obj) { +function ObjLen(an_obj) +{ var len=0; for (item in an_obj) { len++; } return len } + + +function deviceGroups() +{ + // get a list of Device Groups from uci + var groups = []; + var devices = uciOriginal.getAllSectionsOfType("known", "device"); + for (dIndex=0; dIndex < devices.length; dIndex++) + { // survey all of the devices and groups + var device = devices[dIndex]; + var group = uciOriginal.get("known", device, "group"); + if (group.length > 0 && groups.indexOf(group) == -1) + { + groups.push(group); + } + } + return groups; +} + +function groupDevices(group) +{ + var groupDevices = []; + var devices = uciOriginal.getAllSectionsOfType("known", "device"); + for (dIndex=0; dIndex < devices.length; dIndex++) + { // survey all of the devices + var device = devices[dIndex]; + var deviceGroup = uciOriginal.get("known", device, "group"); + if (deviceGroup.localeCompare(group) == 0) + { + groupDevices.push(device); + } + } + return groupDevices; +} + + +function groupMacs(group) +{ + groupMacs = []; + var devices = groupDevices(group); + for (dIndex = 0 ; dIndex < devices.length; dIndex++) + { + var device = devices[dIndex]; + var mac = uciOriginal.get("known", device, "mac"); + if (mac.length > 0) + { + groupMacs = groupMacs.concat(mac); + } + } + return groupMacs; +} diff --git a/package/gargoyle/files/www/js/quotas.js b/package/gargoyle/files/www/js/quotas.js index 900c5c5d51..18ae3900d7 100644 --- a/package/gargoyle/files/www/js/quotas.js +++ b/package/gargoyle/files/www/js/quotas.js @@ -1,12 +1,12 @@ /* - * This program is copyright © 2008,2009-2013 Eric Bishop and is distributed under the terms of the GNU GPL - * version 2.0 with a special clarification/exception that permits adapting the program to + * This program is copyright © 2008,2009-2013 Eric Bishop and is distributed under the terms of the GNU GPL + * version 2.0 with a special clarification/exception that permits adapting the program to * configure proprietary "back end" software provided that all modifications to the web interface - * itself remain covered by the GPL. + * itself remain covered by the GPL. * See http://gargoyle-router.com/faq.html#qfoss for more information */ -var quotasStr=new Object(); //part of i18n +var quotasStr=new Object(); //part of i18n var pkg = "firewall"; var changedIds = []; @@ -20,7 +20,7 @@ var upQosMarks = []; function saveChanges() { setControlsEnabled(false, true); - + //remove old quotas var preCommands = []; var allOriginalQuotas = uciOriginal.getAllSectionsOfType(pkg, "quota"); @@ -28,7 +28,7 @@ function saveChanges() { var section = allOriginalQuotas.shift(); uciOriginal.removeSection(pkg, section); - preCommands.push("uci del " + pkg + "." + section); + preCommands.push("uci del " + pkg + "." + section); } preCommands.push("uci commit"); @@ -47,7 +47,7 @@ function saveChanges() } } - //set enabled / disabled + //set enabled / disabled var quotaTable = document.getElementById('quota_table_container').firstChild; var quotaTableData = getTableDataArray(quotaTable, true, false); var qtIndex=0; @@ -78,7 +78,7 @@ function saveChanges() { //just reload page -- it's easier than any other mechanism to load proper quota data from uci setControlsEnabled(true); - window.location.href = window.location.href; + window.location.href = window.location.href; } } @@ -119,7 +119,7 @@ function resetData() changedIds = []; for(sectionIndex = 0; sectionIndex < quotaSections.length; sectionIndex++) { - var ip = uciOriginal.get(pkg, quotaSections[sectionIndex], "ip").toUpperCase(); + var ip = uciOriginal.get(pkg, quotaSections[sectionIndex], "ip"); var id = uciOriginal.get(pkg, quotaSections[sectionIndex], "id"); if(id == "") { @@ -128,24 +128,24 @@ function resetData() } - + var timeParameters = getTimeParametersFromUci(uci, quotaSections[sectionIndex], 1); var limitStr = getLimitStrFromUci(uci, quotaSections[sectionIndex]); var enabled = uciOriginal.get(pkg, quotaSections[sectionIndex], "enabled"); enabled = enabled != "0" ? true : false; - - + + var enabledCheck = createEnabledCheckbox(enabled); enabledCheck.id= id; checkElements.push(enabledCheck); areChecked.push(enabled); - quotaTableData.push( [ ipToTableSpan(ip), timeParamsToTableSpan(timeParameters), limitStr, enabledCheck, createEditButton(enabled) ] ); + quotaTableData.push( [ hostsToTableSpan(ip), timeParamsToTableSpan(timeParameters), limitStr, enabledCheck, createEditButton(enabled) ] ); } - + columnNames=[quotasStr.IPs, quotasStr.Active, textListToSpanElement([quotasStr.Limits,quotasStr.Totals], false), UI.Enabled, "" ]; - + quotaTable = createTable(columnNames, quotaTableData, "quota_table", true, false, removeQuotaCallback); tableContainer = document.getElementById('quota_table_container'); if(tableContainer.firstChild != null) @@ -160,28 +160,62 @@ function resetData() var b = areChecked.shift(); c.checked = b; } - + setDocumentFromUci(document, new UCIContainer(), ""); - + + resetMacGroupData(); + setVisibility(document); } -function ipToTableSpan(ip) +function resetMacGroupData() +{ + var select = document.getElementById("group"); + var groups = deviceGroups(); + if (groups.length == 0) + { + select.disabled = true; + } + else + { + var mgVals = [ "" ]; + var mgText = [ quotasStr.QSelGrp ]; + + for(gIndex = 0; gIndex < groups.length; gIndex++) + { + var group = groups[gIndex]; + mgVals.push(group); + mgText.push(group); + } + setAllowableSelections('group', mgVals, mgText, document) + select.disabled=false; + } +} + + +function groupSelected() { - var ipStr = ip; - if(ipStr == "ALL_OTHERS_INDIVIDUAL") + document.getElementById("add_ip").value = getSelectedValue("group"); + setSelectedValue("group", ""); +} + + +function hostsToTableSpan(hosts) +{ + var hostsStr = hosts; + if(hostsStr == "ALL_OTHERS_INDIVIDUAL") { - ipStr=quotasStr.OthersOne; + hostsStr=quotasStr.OthersOne; } - else if(ipStr == "ALL_OTHERS_COMBINED") + else if(hostsStr == "ALL_OTHERS_COMBINED") { - ipStr=quotasStr.OthersAll; + hostsStr=quotasStr.OthersAll; } - else if(ipStr == "ALL" || ipStr == "") + else if(hostsStr == "ALL" || hostsStr == "") { - ipStr=quotasStr.All; + hostsStr=quotasStr.All; } - return textListToSpanElement(ipStr.split(/[\t ]*,[\t ]*/), true, document); + return textListToSpanElement(hostsStr.split(/[\t ]*,[\t ]*/), true, document); } function timeParamsToTableSpan(timeParameters) @@ -190,8 +224,8 @@ function timeParamsToTableSpan(timeParameters) var days = timeParameters[1]; var weekly = timeParameters[2]; var active = timeParameters[3]; - - + + var textList = []; if(active == "always") { @@ -226,7 +260,8 @@ function getIdFromIp(ip) { id = ip == "" ? "ALL" : ip.replace(/[\t, ]+.*$/, ""); id = id.replace(/\//, "_"); - + id = id.toUpperCase(); + var idPrefix = id; var found = true; var suffixCount = 0; @@ -272,7 +307,7 @@ function getIpFromDocument(controlDocument) } else if(getSelectedValue("applies_to_type", controlDocument) == "only") { - + var table = controlDocument.getElementById("quota_ip_table_container").firstChild; var ipData = table != null ? getTableDataArray(table, true, false) : []; var ipList = []; @@ -316,7 +351,7 @@ function setDocumentIp(ip, controlDocument) { setSelectedValue("applies_to_type", "only", controlDocument); controlDocument.getElementById("add_ip").value = ip; - var valid = addAddressesToTable(controlDocument,"add_ip","quota_ip_table_container","quota_ip_table",false, 3, false,250); + var valid = addAddressesToTable(controlDocument,"add_ip","quota_ip_table_container","quota_ip_table",false, 3, false, false,250); if(!valid) { controlDocument.getElementById("add_ip").value = ""; @@ -339,18 +374,18 @@ function addNewQuota() setUciFromDocument(document, ""); - + var enabledCheck = createEnabledCheckbox(true); enabledCheck.id = uci.get(pkg, "quota_" + quotaNum, "id"); var tableContainer = document.getElementById("quota_table_container"); var table = tableContainer.firstChild; - - + + var ip = getIpFromDocument(document); var timeParameters = getTimeParametersFromUci(uci, "quota_" + quotaNum); var limitStr = getLimitStrFromUci(pkg, "quota_" + quotaNum); - addTableRow(table, [ ipToTableSpan(ip), timeParamsToTableSpan(timeParameters), limitStr, enabledCheck, createEditButton(true)], true, false, removeQuotaCallback); + addTableRow(table, [ hostsToTableSpan(ip), timeParamsToTableSpan(timeParameters), limitStr, enabledCheck, createEditButton(true)], true, false, removeQuotaCallback); setDocumentFromUci(document, new UCIContainer(), ""); @@ -367,7 +402,7 @@ function setVisibility(controlDocument) setInvisibleIfIdMatches("max_up_type", ["unlimited"], "max_up_container", "inline", controlDocument); setInvisibleIfIdMatches("max_down_type", ["unlimited"], "max_down_container", "inline", controlDocument); setInvisibleIfIdMatches("max_combined_type", ["unlimited"], "max_combined_container", "inline", controlDocument); - + setInvisibleIfIdMatches("quota_active", ["always"], "quota_active_type", "inline", controlDocument); setInvisibleIfIdMatches("quota_active", ["always"], "quota_active_controls_container", "block", controlDocument); if(getSelectedValue("quota_active", controlDocument) != "always") @@ -383,7 +418,7 @@ function setVisibility(controlDocument) setInvisibleIfIdMatches("quota_active", ["always"], "active_days_container", "block", controlDocument); setInvisibleIfIdMatches("quota_active", ["always"], "active_weekly_container", "block", controlDocument); } - + setInvisibleIfIdMatches("quota_exceeded", ["hard_cutoff"], "quota_only_qos_container", "block", controlDocument); setInvisibleIfIdMatches("quota_exceeded", ["hard_cutoff"], "quota_full_qos_container", "block", controlDocument); if(fullQosEnabled) @@ -399,8 +434,8 @@ function setVisibility(controlDocument) var qri=getSelectedValue("quota_reset", controlDocument); if(qri == "month") { - var vals = []; - var names = []; + var vals = []; + var names = []; var day=1; for(day=1; day <= 28; day++) { @@ -452,7 +487,7 @@ function timeVariablesToWeeklyRanges(hours, days, weekly, invert) var hours = hours == null ? "" : hours; var days = days == null ? "" : days; var weekly = weekly == null ? "" : weekly; - + var dayToIndex = []; dayToIndex[UI.Sun.toUpperCase()] = 0; dayToIndex[UI.Mon.toUpperCase()] = 1; @@ -480,7 +515,7 @@ function timeVariablesToWeeklyRanges(hours, days, weekly, invert) var e = rangeList[rangeIndex+1]; startEndPairs.push( [s,e] ); } - + //sort based on starts var sortPairs = function(a,b){ return a[0] - b[0]; } var sortedPairs = startEndPairs.sort(sortPairs); @@ -551,7 +586,7 @@ function timeVariablesToWeeklyRanges(hours, days, weekly, invert) splitPiece[2] = splitPiece[2] != null ? ( parsePaddedInt(splitPiece[2]) + "" != "NaN" ? parsePaddedInt(splitPiece[2]) : 0) : 0; - return splitPiece[0] + splitPiece[1] + splitPiece[2]; + return splitPiece[0] + splitPiece[1] + splitPiece[2]; } var pairs = hours.split(/[\t ]*,[\t ]*/); var pairIndex; @@ -661,7 +696,7 @@ function validateQuota(controlDocument, originalQuotaId, originalQuotaIp) //add any ips in add_ip box, if it is visible and isn't empty if(errors.length == 0 && getSelectedValue("applies_to_type", controlDocument) == "only" && controlDocument.getElementById("add_ip").value != "") { - var valid = addAddressesToTable(controlDocument,"add_ip","quota_ip_table_container","quota_ip_table",false, 3, false,250); + var valid = addAddressesToTable(controlDocument,"add_ip","quota_ip_table_container","quota_ip_table",false, 3, true, false,250); if(!valid) { errors.push("\"" + controlDocument.getElementById("add_ip").value + "\" is not a valid IP or IP range"); @@ -669,7 +704,7 @@ function validateQuota(controlDocument, originalQuotaId, originalQuotaIp) } // check that ip is not empty (e.g. that we are matching based on IP(s) and no ips are defined) - // thw getIpFromDocument function will always return ALL in the case where uci had no ip originallly, + // thw getIpFromDocument function will always return ALL in the case where uci had no ip originallly, // so we don't have to worry about empty ip meaning ALL vs null here var ip = ""; if(errors.length == 0) @@ -681,11 +716,11 @@ function validateQuota(controlDocument, originalQuotaId, originalQuotaIp) } } - //check that up,down,total aren't all unlimited + //check that up,down,total aren't all unlimited if(errors.length == 0) { - if( getSelectedValue("max_up_type", controlDocument) == "unlimited" && - getSelectedValue("max_down_type", controlDocument) == "unlimited" && + if( getSelectedValue("max_up_type", controlDocument) == "unlimited" && + getSelectedValue("max_down_type", controlDocument) == "unlimited" && getSelectedValue("max_combined_type", controlDocument) == "unlimited" ) { @@ -719,9 +754,9 @@ function validateQuota(controlDocument, originalQuotaId, originalQuotaIp) } } } - + if(overlapFound) - { + { if(!ip.match(/ALL/)) { errors.push(quotasStr.DuplicateRange); @@ -743,7 +778,7 @@ function validateQuota(controlDocument, originalQuotaId, originalQuotaIp) function setDocumentFromUci(controlDocument, srcUci, id) { controlDocument = controlDocument == null ? document : controlDocument; - + var quotaSection = ""; var sections = srcUci.getAllSectionsOfType(pkg, "quota"); @@ -822,13 +857,13 @@ function setDocumentFromUci(controlDocument, srcUci, id) var activeType = activeTypes[activeTypeId] != null ? activeTypes[activeTypeId] : "weekly_range"; setSelectedValue("quota_active_type", activeType, controlDocument); } - + setSelectedValue("max_up_type", uploadLimit == "" ? "unlimited" : "limited", controlDocument ); setSelectedValue("max_down_type", downloadLimit == "" ? "unlimited" : "limited", controlDocument ); setSelectedValue("max_combined_type", combinedLimit == "" ? "unlimited" : "limited", controlDocument ); - + setDocumentLimit(uploadLimit, "max_up", "max_up_unit", controlDocument); setDocumentLimit(downloadLimit, "max_down", "max_down_unit", controlDocument); setDocumentLimit(combinedLimit, "max_combined", "max_combined_unit", controlDocument); @@ -839,7 +874,7 @@ function setDocumentFromUci(controlDocument, srcUci, id) setDocumentSpeed(exceededUpSpeed, "quota_qos_up", "quota_qos_up_unit", controlDocument); setDocumentSpeed(exceededDownSpeed, "quota_qos_down", "quota_qos_down_unit", controlDocument); - + setVisibility(controlDocument); setSelectedValue("quota_day", resetDay + "", controlDocument); @@ -885,7 +920,7 @@ function setDocumentSpeed(kbytes, textId, unitSelectId, controlDocument) var defaultUnit = UI.KBs; var textEl = controlDocument.getElementById(textId); setSelectedValue(unitSelectId, defaultUnit, controlDocument); - + kbytes = kbytes == "" ? 0 : parseInt(kbytes); if(kbytes <= 0) { @@ -911,7 +946,7 @@ function setDocumentSpeed(kbytes, textId, unitSelectId, controlDocument) function setUciFromDocument(controlDocument, id) { controlDocument = controlDocument == null ? document : controlDocument; - + var ip = getIpFromDocument(controlDocument); id = id == null ? "" : id; id = id == "" ? getIdFromIp(ip) : id; @@ -942,7 +977,7 @@ function setUciFromDocument(controlDocument, id) } } - + uci.set(pkg, quotaSection, "ingress_limit", getDocumentLimit("max_down", "max_down_type", "max_down_unit", controlDocument) ); uci.set(pkg, quotaSection, "egress_limit", getDocumentLimit("max_up", "max_up_type", "max_up_unit", controlDocument) ); uci.set(pkg, quotaSection, "combined_limit", getDocumentLimit("max_combined", "max_combined_type", "max_combined_unit", controlDocument) ); @@ -982,10 +1017,10 @@ function setUciFromDocument(controlDocument, id) { var prefix = onoff[onoffIndex]; var updateFun = function(prefixActive,option,val) - { + { if(prefixActive) { - uci.set(pkg,quotaSection,option,val); + uci.set(pkg,quotaSection,option,val); } else { @@ -1003,7 +1038,7 @@ function getTimeParametersFromDocument(controlDocument) { var hours = controlDocument.getElementById("active_hours_container").style.display != "none" ? controlDocument.getElementById("active_hours").value : ""; var weekly = controlDocument.getElementById("active_weekly_container").style.display != "none" ? controlDocument.getElementById("active_weekly").value : ""; - + var dayList = []; if(controlDocument.getElementById("active_days_container").style.display != "none") { @@ -1020,7 +1055,7 @@ function getTimeParametersFromDocument(controlDocument) var days = "" + dayList.join(","); var active = getSelectedValue("quota_active", controlDocument); - + return [hours,days,weekly_i18n(weekly, "page"),active]; } @@ -1098,7 +1133,7 @@ function createEditButton(enabled) editButton.value = UI.Edit; editButton.className="default_button"; editButton.onclick = editQuota; - + editButton.className = enabled ? "default_button" : "default_button_disabled" ; editButton.disabled = enabled ? false : true; @@ -1126,9 +1161,9 @@ function setRowEnabled() function removeQuotaCallback(table, row) { var id = row.childNodes[rowCheckIndex].firstChild.id; - var sections = uci.getAllSectionsOfType(pkg, "quota"); - for(sectionIndex=0; sectionIndex < sections.length; sectionIndex++) - { + var sections = uci.getAllSectionsOfType(pkg, "quota"); + for(sectionIndex=0; sectionIndex < sections.length; sectionIndex++) + { if(uci.get(pkg, sections[sectionIndex], "id") == id) { uci.removeSection(pkg, sections[sectionIndex]); @@ -1151,7 +1186,7 @@ function editQuota() catch(e){} } - + try { xCoor = window.screenX + 225; @@ -1165,7 +1200,7 @@ function editQuota() editQuotaWindow = window.open("quotas_edit.sh", "edit", "width=560,height=600,left=" + xCoor + ",top=" + yCoor ); - + var saveButton = createInput("button", editQuotaWindow.document); var closeButton = createInput("button", editQuotaWindow.document); saveButton.value = UI.CApplyChanges; @@ -1175,7 +1210,7 @@ function editQuota() var editRow=this.parentNode.parentNode; var editId = editRow.childNodes[rowCheckIndex].firstChild.id; - + var editIp; var editSection = ""; @@ -1193,7 +1228,7 @@ function editQuota() var editDownMax = uci.get(pkg, editSection, "ingress_limit"); var editCombinedMax = uci.get(pkg, editSection, "combined_limit"); - var runOnEditorLoaded = function () + var runOnEditorLoaded = function () { var updateDone=false; if(editQuotaWindow.document != null) @@ -1236,21 +1271,21 @@ function editQuota() { changedIds[newId] = 1; } - - - setElementAtColumn(ipToTableSpan(newIp), 0); + + + setElementAtColumn(hostsToTableSpan(newIp), 0); editRow.childNodes[rowCheckIndex].firstChild.id = newId; } setElementAtColumn(timeParamsToTableSpan(getTimeParametersFromUci(uci, editSection, 1)), 1); editRow.childNodes[2].firstChild.data =getLimitStrFromUci(uci, editSection); - + editQuotaWindow.close(); } } editQuotaWindow.moveTo(xCoor,yCoor); editQuotaWindow.focus(); updateDone = true; - + } } if(!updateDone) diff --git a/package/gargoyle/files/www/quotas.sh b/package/gargoyle/files/www/quotas.sh index 6da3c21ed8..18c55a2cf5 100755 --- a/package/gargoyle/files/www/quotas.sh +++ b/package/gargoyle/files/www/quotas.sh @@ -6,7 +6,7 @@ # itself remain covered by the GPL. # See http://gargoyle-router.com/faq.html#qfoss for more information eval $( gargoyle_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.sh" -t $(uci get gargoyle.global.session_timeout) -b "$COOKIE_browser_time" ) - gargoyle_header_footer -h -s "firewall" -p "quotas" -c "internal.css" -j "table.js quotas.js" -z "quotas.js" gargoyle firewall qos_gargoyle + gargoyle_header_footer -h -s "firewall" -p "quotas" -c "internal.css" -j "table.js quotas.js" -z "quotas.js" gargoyle firewall qos_gargoyle known %> diff --git a/package/gargoyle/files/www/templates/quotas_template b/package/gargoyle/files/www/templates/quotas_template index 37ff0c7fe1..0cc41e110d 100644 --- a/package/gargoyle/files/www/templates/quotas_template +++ b/package/gargoyle/files/www/templates/quotas_template @@ -41,11 +41,18 @@
- +   - + +
+
+ <%~ IPorRange %> + + +
-
<%~ IPorRange %>
@@ -170,7 +177,7 @@ - + <%~ SSample %> 02:00-04:00,11:35-13:25 diff --git a/package/gargoyle/files/www/webmon.sh b/package/gargoyle/files/www/webmon.sh index d6772cebfa..2c5ada6597 100755 --- a/package/gargoyle/files/www/webmon.sh +++ b/package/gargoyle/files/www/webmon.sh @@ -49,7 +49,7 @@
- +
<%~ SpcIP %>
diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/quotas.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/quotas.js index 70da8cc9b8..0229ba49a8 100644 --- a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/quotas.js +++ b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/quotas.js @@ -32,7 +32,8 @@ quotasStr.QLocalNet="Entire Local Network"; quotasStr.QOnlyHosts="Only the following Host(s)"; quotasStr.HostsWithoutQuotas="All Individual Hosts Without Explicit Quotas"; quotasStr.ComboHostsWithoutQuotas="All Hosts Without Explicit Quotas (Combined)"; -quotasStr.IPorRange="Specify an IP or IP range"; +quotasStr.IPorRange="Specify an IP or IP range, or"; +quotasStr.QSelGrp="Select a Group"; quotasStr.MaxUp="Max Upload"; quotasStr.MaxDown="Max Download"; quotasStr.MaxUpDown="Max Total Up+Down"; diff --git a/package/plugin-gargoyle-usb-storage/files/www/js/usb_storage.js b/package/plugin-gargoyle-usb-storage/files/www/js/usb_storage.js index e2a2eb6b43..abeef4ffda 100644 --- a/package/plugin-gargoyle-usb-storage/files/www/js/usb_storage.js +++ b/package/plugin-gargoyle-usb-storage/files/www/js/usb_storage.js @@ -1,17 +1,17 @@ -/* - * This program is copyright © 2008-2012 Eric Bishop and is distributed under the terms of the GNU GPL - * version 2.0 with a special clarification/exception that permits adapting the program to +/* + * This program is copyright © 2008-2012 Eric Bishop and is distributed under the terms of the GNU GPL + * version 2.0 with a special clarification/exception that permits adapting the program to * configure proprietary "back end" software provided that all modifications to the web interface - * itself remain covered by the GPL. + * itself remain covered by the GPL. * See http://gargoyle-router.com/faq.html#qfoss for more information */ - + var usbSStr=new Object(); //part of i18n -/* - * mountPoint refers to the blkid mount point +/* + * mountPoint refers to the blkid mount point * mountPath may refer to either blkid mount point - * or symlink to dev_[devid], wherever share is + * or symlink to dev_[devid], wherever share is * actually mounted */ var driveToMountPoints = []; @@ -19,7 +19,7 @@ var mountPointToDrive = []; var mountPointToFs = []; var mountPointToDriveSize = []; -/* +/* * These global data structure are special -- they contain * the data that will be saved once the user hits the save changes button * @@ -28,9 +28,9 @@ var mountPointToDriveSize = []; * variable in a simpler format, and then update uci when we do the final save */ var userNames = []; -var nameToSharePath = []; +var nameToSharePath = []; var sharePathList = []; -var sharePathToShareData = []; +var sharePathToShareData = []; var badUserNames = [ "ftp", "anonymous", "root", "daemon", "network", "nobody" ]; @@ -167,8 +167,8 @@ function saveChanges() uci.removeSection("firewall", ftpFirewallRule); uci.removeSection("firewall", pasvFirewallRule); } - - + + //update shares uci.removeAllSectionsOfType("samba", "samba") @@ -176,7 +176,7 @@ function saveChanges() uci.removeAllSectionsOfType("vsftpd", "vsftpd") uci.removeAllSectionsOfType("vsftpd", "share") uci.removeAllSectionsOfType("nfsd", "nfsshare") - + uci.set("samba", "global", "", "samba") uci.set("samba", "global", "workgroup", sambaGroup); @@ -194,11 +194,11 @@ function saveChanges() var shareName = shareData[0] var shareId = shareName.replace(/[^0-9A-Za-z]+/, "_").toLowerCase() - + var isCifs = shareData[5]; var isFtp = shareData[6]; var isNfs = shareData[7]; - + var anonymousAccess = shareData[8] var rwUsers = shareData[9] var roUsers = shareData[10] @@ -215,7 +215,7 @@ function saveChanges() uci.set(pkg, shareId, "create_mask", "0777"); uci.set(pkg, shareId, "dir_mask", "0777"); uci.set(pkg, shareId, "browseable", "yes"); - + uci.set(pkg, shareId, "read_only", (anonymousAccess == "ro" ? "yes" : "no")); uci.set(pkg, shareId, "guest_ok", (anonymousAccess == "none" ? "no" : "yes")); if(rwUsers.length > 0) @@ -246,7 +246,7 @@ function saveChanges() haveAnonymousFtp = true; uci.set(pkg, shareId, "users_" + anonymousAccess, [ "anonymous" ], true); } - + } if(isNfs) { @@ -257,7 +257,7 @@ function saveChanges() uci.set(pkg, shareId, "sync", "1"); uci.set(pkg, shareId, "insecure", "1"); uci.set(pkg, shareId, "subtree_check", "0"); - + uci.set(pkg, shareId, "read_only", (nfsAccess == "ro" ? "1" : "0")); if(nfsAccessIps instanceof Array) { @@ -268,7 +268,7 @@ function saveChanges() uci.set(pkg, shareId, "allowed_hosts", [ "*" ], false) } - } + } } uci.set("vsftpd", "global", "", "vsftpd") uci.set("vsftpd", "global", "anonymous", (haveAnonymousFtp ? "yes" : "no")) @@ -282,9 +282,9 @@ function saveChanges() var postCommands = []; if( - uciOriginal.get("firewall", ftpFirewallRule, "local_port") != uci.get("firewall", ftpFirewallRule, "local_port") || - uciOriginal.get("firewall", pasvFirewallRule, "start_port") != uci.get("firewall", pasvFirewallRule, "start_port") || - uciOriginal.get("firewall", pasvFirewallRule, "end_port") != uci.get("firewall", pasvFirewallRule, "end_port") + uciOriginal.get("firewall", ftpFirewallRule, "local_port") != uci.get("firewall", ftpFirewallRule, "local_port") || + uciOriginal.get("firewall", pasvFirewallRule, "start_port") != uci.get("firewall", pasvFirewallRule, "start_port") || + uciOriginal.get("firewall", pasvFirewallRule, "end_port") != uci.get("firewall", pasvFirewallRule, "end_port") ) { postCommands.push("/etc/init.d/firewall restart"); @@ -321,7 +321,7 @@ function addUser() //validate - var errors = []; + var errors = []; var testUser = user.replace(/[0-9a-zA-Z]+/g, ""); if(user == "") { @@ -378,7 +378,7 @@ function addUser() if(userTable == null) { var tableContainer = document.getElementById("user_table_container"); - userTable = createTable(["", ""], [], "share_user_table", true, false, removeUserCallback); + userTable = createTable(["", ""], [], "share_user_table", true, false, removeUserCallback); setSingleChild(tableContainer, userTable); } var userPass = createInput("hidden") @@ -420,7 +420,7 @@ function removeUserCallback(table, row) var shareData = sharePathToShareData[sharePath] var rwUsers = shareData[9] var roUsers = shareData[10] - shareData[9] = removeStringFromArray(rwUsers, removeUser) + shareData[9] = removeStringFromArray(rwUsers, removeUser) shareData[10] = removeStringFromArray(roUsers, removeUser) sharePathToShareData[sharePath] = shareData; } @@ -443,8 +443,8 @@ function removeUserCallback(table, row) var newAccessTable = createTable(["", ""], newTableData, "user_access_table", true, false, removeUserAccessCallback); setSingleChild(document.getElementById("user_access_table_container"), newAccessTable); - } - + } + } function editUser() @@ -461,7 +461,7 @@ function editUser() catch(e){} } - + try { xCoor = window.screenX + 225; @@ -477,7 +477,7 @@ function editUser() editUserWindow = window.open("share_user_edit.sh", "edit", "width=560,height=300,left=" + xCoor + ",top=" + yCoor ); var okButton = createInput("button", editUserWindow.document); var cancelButton = createInput("button", editUserWindow.document); - + okButton.value = usbSStr.ChPass; okButton.className = "default_button"; cancelButton.value = UI.Cancel; @@ -488,7 +488,7 @@ function editUser() editShareUser=editShareUserRow.childNodes[0].firstChild.data; - runOnEditorLoaded = function () + runOnEditorLoaded = function () { updateDone=false; if(editUserWindow.document != null) @@ -496,11 +496,11 @@ function editUser() if(editUserWindow.document.getElementById("bottom_button_container") != null) { editUserWindow.document.getElementById("share_user_text").appendChild( document.createTextNode(editShareUser) ) - - + + editUserWindow.document.getElementById("bottom_button_container").appendChild(okButton); editUserWindow.document.getElementById("bottom_button_container").appendChild(cancelButton); - + cancelButton.onclick = function() { editUserWindow.close(); @@ -556,8 +556,8 @@ function resetData() document.getElementById("shared_disks").style.display = storageDrives.length > 0 ? "block" : "none"; document.getElementById("disk_unmount").style.display = storageDrives.length > 0 ? "block" : "none"; document.getElementById("disk_format").style.display = storageDrives.length > 0 || drivesWithNoMounts.length > 0 ? "block" : "none" - - + + if(storageDrives.length > 0) { @@ -576,7 +576,7 @@ function resetData() pmaxText.value = pmin == "" || pmax == "" ? 50999 : pmax; document.getElementById("ftp_wan_pasv").checked = (wanFtp && pmin != "" && pmax != "") || (!wanFtp); //enable pasv by default when WAN FTP access is selected updateWanFtpVisibility() - + //share users userNames = uciOriginal.getAllSectionsOfType("share_users", "user"); //global @@ -608,10 +608,10 @@ function resetData() setAllowableSelections("user_access", userNames, userNames); - + //globals driveToMountPoints = []; - mountPointToDrive = []; + mountPointToDrive = []; mountPointToFs = []; mountPointToDriveSize = []; mountPointList = [] @@ -632,11 +632,11 @@ function resetData() } } - + sharePathList = []; //global sharePathToShareData = []; //global nameToSharePath = []; //global - + var mountedDrives = []; var sambaShares = uciOriginal.getAllSectionsOfType("samba", "sambashare"); var nfsShares = uciOriginal.getAllSectionsOfType("nfsd", "nfsshare"); @@ -664,14 +664,14 @@ function resetData() } } - + if( shareDrive != null ) { mountedDrives[ shareDrive ] = 1; - + //shareMountPoint->[shareName, shareDrive, shareDiskMount, shareSubdir, fullSharePath, isCifs, isFtp, isNfs, anonymousAccess, rwUsers, roUsers, nfsAccess, nfsAccessIps] var shareData = sharePathToShareData[fullSharePath] == null ? ["", "", "", "", "", false, false, false, "none", [], [], "ro", "*" ] : sharePathToShareData[fullSharePath] ; - + //name if( shareData[0] == "" || config == "samba") { @@ -711,7 +711,7 @@ function resetData() { //handle anonymous for vsftpd shareData[ 8 ] = readType - + } else { @@ -766,11 +766,11 @@ function resetData() } } } - + getMounted(sambaShares, "samba"); getMounted(ftpShares, "vsftpd"); getMounted(nfsShares, "nfsd"); - + if(setDriveList(document)) { document.getElementById("sharing_add_heading_container").style.display = "block"; @@ -784,7 +784,7 @@ function resetData() } - + //create current share table //name, disk, subdirectory, type, [edit], [remove] var shareTableData = []; @@ -810,7 +810,7 @@ function resetData() // not lack of network shared/mounts which is what the other variables // refer to. This can be confusing, so I'm putting this comment here - + if(drivesWithNoMounts.length > 0) { var dindex; @@ -846,7 +846,7 @@ function resetData() //returns (boolean) whether drive list is empty function setDriveList(controlDocument) { - + var driveList = []; var driveDisplayList = []; for(driveIndex=0; driveIndex < storageDrives.length; driveIndex++) @@ -895,13 +895,13 @@ function addUserAccess(controlDocument) var addUser = getSelectedValue("user_access", controlDocument) if(addUser == null || addUser == "") { - alert(usbSStr.NShUsrErr) + alert(usbSStr.NShUsrErr) } else { var access = getSelectedValue("user_access_type", controlDocument) removeOptionFromSelectElement("user_access", addUser, controlDocument); - + createUserAccessTable(false) var userAccessTable = controlDocument.getElementById("user_access_table"); addTableRow(userAccessTable, [ addUser, access ], true, false, removeUserAccessCallback, null, controlDocument) @@ -928,8 +928,8 @@ function updateFormatPercentages(ctrlId) var otherCtrlId = ctrlId == "swap_percent" ? "storage_percent" : "swap_percent" var sizeId = ctrlId == "swap_percent" ? "swap_size" : "storage_size" var otherSizeId = ctrlId == "swap_percent" ? "storage_size" : "swap_size" - - + + var driveId = getSelectedValue("format_disk_select") if(driveId != null) { @@ -941,10 +941,10 @@ function updateFormatPercentages(ctrlId) document.getElementById(ctrlId).style.color = "black" var percent2 = 100 - percent1; var size = parseInt(drivesWithNoMounts[parseInt(driveId)][1]); - + var size1 = (percent1 * size)/100; var size2 = size - size1; - + document.getElementById(otherCtrlId).value = "" + percent2 setChildText(sizeId, "(" + parseBytes(size1) + ")"); setChildText(otherSizeId, "(" + parseBytes(size2) + ")"); @@ -986,9 +986,9 @@ function getVisStr(vis) function getShareDataFromDocument(controlDocument, originalName) { controlDocument = controlDocument == null ? document : controlDocument - + var shareDrive = getSelectedValue("share_disk", controlDocument); - + var shareSubdir = controlDocument.getElementById("share_dir").value shareSubdir = shareSubdir.replace(/^\//, "").replace(/\/$/, "") @@ -1000,7 +1000,7 @@ function getShareDataFromDocument(controlDocument, originalName) var altSharePath = (altDiskMount + "/" + shareSubdir).replace(/\/\//g, "/").replace(/\/$/, ""); var enabledTypes = getVis(controlDocument); - + @@ -1074,17 +1074,17 @@ function getShareDataFromDocument(controlDocument, originalName) function setDocumentFromShareData(controlDocument, shareData) { controlDocument = controlDocument == null ? document : controlDocument - + var shareDrive = shareData[1] setDriveList(controlDocument); setSelectedValue("share_disk", shareDrive, controlDocument) controlDocument.getElementById("share_dir").value = "/" + shareData[3] controlDocument.getElementById("share_name").value = shareData[0] - + var shareSpecificity = (shareData[2] == driveToMountPoints[shareDrive][0]) ? "blkid" : "dev"; setSelectedValue("share_specificity", shareSpecificity, controlDocument) - - + + controlDocument.getElementById("share_type_cifs").checked = shareData[5] controlDocument.getElementById("share_type_ftp").checked = shareData[6] controlDocument.getElementById("share_type_nfs").checked = shareData[7] @@ -1108,13 +1108,13 @@ function setDocumentFromShareData(controlDocument, shareData) usersWithEntries[ userList[ulIndex] ] = 1 } } - + setSelectedValue("nfs_access", shareData[11], controlDocument); var nfsAccessIps = shareData[12]; setSelectedValue("nfs_policy", typeof(nfsAccessIps) == "string" ? "share" : "ip", controlDocument); if(nfsAccessIps instanceof Array) { - addAddressStringToTable(controlDocument,nfsAccessIps.join(","),"nfs_ip_table_container","nfs_ip_table",false, 2, true, 250) + addAddressStringToTable(controlDocument,nfsAccessIps.join(","),"nfs_ip_table_container","nfs_ip_table",false, 2, false, true, 250) } //update user select element @@ -1147,7 +1147,7 @@ function addNewShare() else { var shareData = rawShareData["share"] - + var shareName = shareData[0] var fullSharePath = shareData[4]; var shareType = getVisStr( getVis() ); @@ -1158,7 +1158,7 @@ function addNewShare() var shareTable = document.getElementById("share_table") addTableRow(shareTable, [shareName, shareData[1], "/" + shareData[3], shareType, createEditButton(editShare) ], true, false, removeShareCallback) - + shareSettingsToDefault(); } @@ -1167,7 +1167,7 @@ function addNewShare() function setShareTypeVisibility(controlDocument) { controlDocument = controlDocument == null ? document : controlDocument - + var vis = getVis(controlDocument); vis["ftp_or_cifs"] = vis["ftp"] || vis["cifs"] @@ -1240,7 +1240,7 @@ function removeShareCallback(table, row) delete nameToSharePath[removeName] delete sharePathToShareData[removePath] - + var newSharePathList = [] while(sharePathList.length > 0) { @@ -1269,7 +1269,7 @@ function editShare() catch(e){} } - + try { xCoor = window.screenX + 225; @@ -1283,7 +1283,7 @@ function editShare() editShareWindow = window.open("usb_storage_edit.sh", "edit", "width=560,height=600,left=" + xCoor + ",top=" + yCoor ); - + var saveButton = createInput("button", editShareWindow.document); var closeButton = createInput("button", editShareWindow.document); saveButton.value = UI.CApplyChanges; @@ -1297,7 +1297,7 @@ function editShare() editShareData=sharePathToShareData[ editPath ]; - var runOnEditorLoaded = function () + var runOnEditorLoaded = function () { var updateDone=false; if(editShareWindow.document != null) @@ -1305,12 +1305,12 @@ function editShare() if(editShareWindow.document.getElementById("bottom_button_container") != null) { updateDone = true; - + editShareWindow.document.getElementById("bottom_button_container").appendChild(saveButton); editShareWindow.document.getElementById("bottom_button_container").appendChild(closeButton); - - setDocumentFromShareData(editShareWindow.document, editShareData) - + + setDocumentFromShareData(editShareWindow.document, editShareData) + closeButton.onclick = function() { editShareWindow.close(); @@ -1332,7 +1332,7 @@ function editShare() if(editName != shareName) { - delete nameToSharePath[ editName ] + delete nameToSharePath[ editName ] } if(editPath != fullSharePath) { @@ -1347,7 +1347,7 @@ function editShare() } newSharePathList.push(fullSharePath) sharePathList = newSharePathList - delete sharePathToShareData[ editPath ] + delete sharePathToShareData[ editPath ] } sharePathToShareData[ fullSharePath ] = shareData nameToSharePath [ shareName ] = fullSharePath @@ -1387,7 +1387,7 @@ function unmountAllUsb() { setControlsEnabled(false, true, usbSStr.UDisk); - + var commands = "/etc/init.d/samba stop ; /etc/init.d/vsftpd stop ; /etc/init.d/nfsd stop ; /etc/init.d/usb_storage stop ; " var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); @@ -1426,7 +1426,7 @@ function doDiskFormat() var driveId = drivesWithNoMounts[ parseInt(getSelectedValue("format_disk_select")) ][0] var swapPercent = parseFloat(document.getElementById("swap_percent").value) var extroot = document.getElementById("extroot").checked ? "1":"0"; - + //format shell script requires percent as an integer, round as necessary if(swapPercent >0 && swapPercent <1) { @@ -1440,10 +1440,10 @@ function doDiskFormat() if(confirm(usbSStr.CfmPass1+"\n\n"+usbSStr.CfmPass2+" " + driveId)) { - + setControlsEnabled(false, true, usbSStr.FmtMsg); - - + + var commands = "/usr/sbin/gargoyle_format_usb \"" + driveId + "\" \"" + swapPercent + "\" \"4\" \""+ extroot + "\"; sleep 1 ; /etc/init.d/usb_storage restart ; sleep 1 " var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); var stateChangeFunction = function(req) @@ -1527,7 +1527,7 @@ function reloadPage() //IE calls onload even when page isn't loaded -- it just times out and calls it anyway //We can test if it's loaded for real by looking at the (IE only) readyState property //For Browsers NOT designed by dysfunctional cretins whose mothers were a pack of sewer-dwelling, shit-eating rodents, - //well, for THOSE browsers, readyState (and therefore reloadState) should be null + //well, for THOSE browsers, readyState (and therefore reloadState) should be null var reloadState = document.getElementById("reboot_test").readyState; if( typeof(reloadState) == "undefined" || reloadState == null || reloadState == "complete") { diff --git a/package/plugin-gargoyle-usb-storage/files/www/templates/usb_storage_template b/package/plugin-gargoyle-usb-storage/files/www/templates/usb_storage_template index 04f4a5eae0..6b2a670990 100644 --- a/package/plugin-gargoyle-usb-storage/files/www/templates/usb_storage_template +++ b/package/plugin-gargoyle-usb-storage/files/www/templates/usb_storage_template @@ -74,7 +74,7 @@
- +
<%~ IPSub %> From b523cbaa30a3b70ce9f6f6597737816c27d8f847 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 10 Dec 2015 22:02:30 +1100 Subject: [PATCH 19/48] uci dhcp Move uci configuration from known to dhcp --- package/gargoyle/files/www/js/common.js | 34 +++++------ package/gargoyle/files/www/js/device.js | 75 ++++++++++++++----------- 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 0eb6f81ae2..182b7feae0 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -2796,11 +2796,11 @@ function deviceGroups() { // get a list of Device Groups from uci var groups = []; - var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIndex=0; dIndex < devices.length; dIndex++) + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) { // survey all of the devices and groups - var device = devices[dIndex]; - var group = uciOriginal.get("known", device, "group"); + var host = hosts[hIndex]; + var group = uciOriginal.get("dhcp", host, "group"); if (group.length > 0 && groups.indexOf(group) == -1) { groups.push(group); @@ -2809,31 +2809,31 @@ function deviceGroups() return groups; } -function groupDevices(group) +function groupHosts(group) { - var groupDevices = []; - var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIndex=0; dIndex < devices.length; dIndex++) + var groupHosts = []; + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) { // survey all of the devices - var device = devices[dIndex]; - var deviceGroup = uciOriginal.get("known", device, "group"); - if (deviceGroup.localeCompare(group) == 0) + var host = hosts[hIndex]; + var hostGroup = uciOriginal.get("dhcp", host, "group"); + if (hostGroup.localeCompare(group) == 0) { - groupDevices.push(device); + groupHosts.push(host); } } - return groupDevices; + return groupHosts; } function groupMacs(group) { groupMacs = []; - var devices = groupDevices(group); - for (dIndex = 0 ; dIndex < devices.length; dIndex++) + var hosts = groupHosts(group); + for (hIndex = 0 ; hIndex < hosts.length; hIndex++) { - var device = devices[dIndex]; - var mac = uciOriginal.get("known", device, "mac"); + var host = hosts[hIndex]; + var mac = uciOriginal.get("dhcp", host, "mac"); if (mac.length > 0) { groupMacs = groupMacs.concat(mac); diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js index c620afdab0..b482254054 100644 --- a/package/gargoyle/files/www/js/device.js +++ b/package/gargoyle/files/www/js/device.js @@ -22,7 +22,7 @@ function saveChanges() setControlsEnabled(false, true); uci = uciOriginal.clone(); - uci.removeAllSectionsOfType("known", "device"); + uci.removeAllSectionsOfType("dhcp", "host"); // save Device changes deviceTable = document.getElementById('device_table_container').firstChild; @@ -30,17 +30,20 @@ function saveChanges() for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) { rowData = tableData[rowIndex]; - var device = rowData[0]; + var host = rowData[0]; var macs = rowData[1]; - if (uci.get("known", device).length == 0){ - uci.set("known", device, null, "device"); + if (uci.get("dhcp", host).length == 0){ + uci.set("dhcp", host, null, "host"); + uci.set("dhcp", host, "name", host); + uci.set("dhcp", host, "ip", 'ignore'); } - uci.set("known", device, "mac", macs.split(" "), true); + uci.set("dhcp", host, "mac", macs); } // save Group changes groupTable = document.getElementById('group_table_container').firstChild; tableData = getTableDataArray(groupTable, true, false); + var groups = []; for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) { rowData = tableData[rowIndex]; @@ -48,15 +51,21 @@ function saveChanges() var devices = rowData[1].split(" "); for(dIndex=0; dIndex < devices.length; dIndex++) { - var device = devices[dIndex]; - if (uci.get("known", device).length == 0){ - uci.set("known", device, null, "device"); + var host = devices[dIndex]; + if (uci.get("dhcp", host).length == 0){ + uci.set("dhcp", host, null, "host"); + uci.set("dhcp", host, "name", host); + uci.set("dhcp", host, "ip", 'ignore'); + } + uci.set("dhcp", host, "group", group); + if(groups.indexOf(group) == -1) + { + groups.push(group); } - uci.set("known", device, "group", group); } } - commands = uci.getScriptCommands(uciOriginal) ; + var commands = uci.getScriptCommands(uciOriginal) + "\n" + ipsetCommands.join("\n"); var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); @@ -101,17 +110,17 @@ function resetDeviceTable() { var deviceTableData = new Array(); - var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIndex=0; dIndex < devices.length; dIndex++) + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) { // process the MAC's assigned to each device - var device = devices[dIndex]; - var devMacs = uciOriginal.get("known", device, "mac"); - var macs = (devMacs instanceof Array) ? devMacs.join(" ") : "" ; - deviceTableData.push([device, macs, createEditButton(editDevice)]); + var host = hosts[hIndex]; + var hostMacs = uciOriginal.get("dhcp", host, "mac"); + var macs = (hostMacs instanceof Array) ? devMacs.join(" ") : hostMacs ; + deviceTableData.push([host, macs, createEditButton(editDevice)]); } // create the device Table and place it into the document - var columnNames=[deviceS.DevNm, "MACs", '']; + var columnNames=[hosts.DevNm, "MACs", '']; var deviceTable=createTable(columnNames, deviceTableData, "device_table", true, false, removeDevice ); var tableContainer = document.getElementById('device_table_container'); if(tableContainer.firstChild != null) @@ -127,21 +136,21 @@ function resetGroupTable() var groupTableData = new Array(); var groups = new Object(); - var devices = uciOriginal.getAllSectionsOfType("known", "device"); + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); - for (dIndex=0; dIndex < devices.length; dIndex++) + for (hIndex=0; hIndex < hosts.length; hIndex++) { // survey all of the devices and groups - var device = devices[dIndex]; - var group = uciOriginal.get("known", device, "group"); + var host = hosts[hIndex]; + var group = uciOriginal.get("dhcp", host, "group"); if (group != null && group.length > 0) { if (groups.hasOwnProperty(group)) { - groups[group].push(device); + groups[group].push(host); } else { - groups[group] = [device]; + groups[group] = [host]; } } } @@ -210,11 +219,11 @@ function resetMacList() function resetGroupList() { var groups = []; - var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIndex=0; dIndex < devices.length; dIndex++) + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) { // survey all of the devices and groups - var device = devices[dIndex]; - var group = uciOriginal.get("known", device, "group"); + var host = hosts[hIndex]; + var group = uciOriginal.get("dhcp", host, "group"); if (group.length > 0 && groups.indexOf(group) == -1) { groups.push(group); @@ -241,15 +250,15 @@ function resetDeviceList() var gpVals = [ "" ]; var gpText = [ deviceS.SelD ]; - var devices = uciOriginal.getAllSectionsOfType("known", "device"); - for (dIndex=0; dIndex < devices.length; dIndex++) + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) { // survey all of the devices and groups - var device = devices[dIndex]; - var group = uciOriginal.get("known", device, "group"); + var host = hosts[hIndex]; + var group = uciOriginal.get("dhcp", host, "group"); if (group == null || group.length == 0) { - gpVals.push( device ); - gpText.push( device ); + gpVals.push( host ); + gpText.push( host ); } } setAllowableSelections("device_list", gpVals, gpText, document); From 5bf6f4a0910d3b4442eabb8f7777b69361d79372 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 10 Dec 2015 22:13:19 +1100 Subject: [PATCH 20/48] Implement ipsets for Device Groups Each Device Group is reflected by an ipset of the same name. The ipset is utilised in iptables to implement quota policy for a Device Group. IP addresses are added and deleted from ipsets when a new dhcp lease is assigned by setting dhcp.dnsmasq.dhcp_script --- README.md | 5 +- .../src/restore_quotas.c | 253 ++++++++++++++---- .../files/usr/lib/gargoyle/post_lease.sh | 47 ++++ package/gargoyle/files/www/js/device.js | 6 + 4 files changed, 255 insertions(+), 56 deletions(-) create mode 100755 package/gargoyle/files/usr/lib/gargoyle/post_lease.sh diff --git a/README.md b/README.md index 8c049b7be2..c9ccb78168 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,12 @@ of needing to assign a static IP address to each device requiring management. Status - Gargoyle-Connection-Devices has a Section for Known Devices and another for Device Groups. -- Known Device and Group data is stored in uci /etc/config/known +- Known Device and Group data is stored in uci /etc/config/dhcp TODO device.sh - Update selects after address - layout input and select elements - validate inputs + +TODO quotas.sh +- diff --git a/package/gargoyle-firewall-util/src/restore_quotas.c b/package/gargoyle-firewall-util/src/restore_quotas.c index 3030b16707..4abdf52bba 100644 --- a/package/gargoyle-firewall-util/src/restore_quotas.c +++ b/package/gargoyle-firewall-util/src/restore_quotas.c @@ -1,4 +1,4 @@ -/* restore_quotas -- Used to initialize and restore bandwidth quotas based on UCI config files +/* restore_quotas -- Used to initialize and restore bandwidth quotas based on UCI config files * and any previously saved quota data in /usr/data/quotas * Originally designed for use with Gargoyle router firmware (gargoyle-router.com) * @@ -54,6 +54,12 @@ void free_split_pieces(char** split_pieces); list* get_all_sections_of_type(struct uci_context *ctx, char* package, char* section_type); char* get_uci_option(struct uci_context* ctx,char* package_name, char* section_name, char* option_name); char* get_option_value_string(struct uci_option* uopt); +char* get_ip_from_group(struct uci_context* ctx, char* mac_group); +char* get_groups(struct uci_context* ctx); + + +string_map* get_leases(void); + int main(int argc, char** argv) { @@ -64,7 +70,7 @@ int main(int argc, char** argv) char* death_mask = NULL; char* crontab_line = NULL; int ret; - + unsigned char full_qos_active = 0; char c; @@ -153,7 +159,7 @@ int main(int argc, char** argv) char* base_id = get_uci_option(ctx, "firewall", next_quota, "id"); char* exceeded_up_speed_str = get_uci_option(ctx, "firewall", next_quota, "exceeded_up_speed"); char* exceeded_down_speed_str = get_uci_option(ctx, "firewall", next_quota, "exceeded_down_speed"); - + if(base_id != NULL) { @@ -175,7 +181,7 @@ int main(int argc, char** argv) if(oldval != NULL) { free(oldval); } oldval = set_long_map_element(down_speeds, down, strdup(exceeded_down_speed_str) ); if(oldval != NULL) { free(oldval); } - + } } } @@ -219,13 +225,13 @@ int main(int argc, char** argv) - + /* initialize chains */ run_shell_command(dynamic_strcat(3, "iptables -t ", quota_table, " -N forward_quotas 2>/dev/null"), 1); run_shell_command(dynamic_strcat(3, "iptables -t ", quota_table, " -N egress_quotas 2>/dev/null"), 1); run_shell_command(dynamic_strcat(3, "iptables -t ", quota_table, " -N ingress_quotas 2>/dev/null"), 1); run_shell_command(dynamic_strcat(3, "iptables -t ", quota_table, " -N combined_quotas 2>/dev/null"), 1); - + run_shell_command("iptables -t nat -N quota_redirects 2>/dev/null", 0); run_shell_command("iptables -t nat -A quota_redirects -j CONNMARK --set-mark 0x0/0xFF000000 2>/dev/null", 0); run_shell_command("iptables -t nat -I zone_lan_prerouting -j quota_redirects 2>/dev/null", 0); @@ -235,7 +241,7 @@ int main(int argc, char** argv) run_shell_command(dynamic_strcat(6, "iptables -t ", quota_table, " -I INPUT 2 -i ", wan_if, no_death_mark_test, " -j combined_quotas 2>/dev/null"), 1); run_shell_command(dynamic_strcat(6, "iptables -t ", quota_table, " -I OUTPUT 1 -o ", wan_if, no_death_mark_test, " -j egress_quotas 2>/dev/null"), 1); run_shell_command(dynamic_strcat(6, "iptables -t ", quota_table, " -I OUTPUT 2 -o ", wan_if, no_death_mark_test, " -j combined_quotas 2>/dev/null"), 1); - + run_shell_command(dynamic_strcat(3, "iptables -t ", quota_table, " -I FORWARD -j forward_quotas 2>/dev/null"), 1); run_shell_command(dynamic_strcat(6, "iptables -t ", quota_table, " -A forward_quotas -o ", wan_if, no_death_mark_test, " -j egress_quotas 2>/dev/null"), 1); @@ -283,10 +289,9 @@ int main(int argc, char** argv) } } free(quota_enabled_var); - + if(enabled) { - char* ip = get_uci_option(ctx, "firewall", next_quota, "ip"); char* exceeded_up_speed_str = NULL; char* exceeded_down_speed_str = NULL; if(!full_qos_active) /* without defined up/down speeds we always set hard cutoff, which is what we want when full qos is active */ @@ -297,6 +302,14 @@ int main(int argc, char** argv) if(exceeded_up_speed_str == NULL) { exceeded_up_speed_str = strdup(" "); } if(exceeded_down_speed_str == NULL) { exceeded_down_speed_str = strdup(" "); } + char* mac = get_uci_option(ctx, "firewall", next_quota, "mac"); + char* ip = (mac != NULL) ? get_ip_from_group(ctx, mac) : get_uci_option(ctx, "firewall", next_quota, "ip"); + + if (strlen(ip) == 0) + { + ip = get_uci_option(ctx, "firewall", next_quota, "ip"); + free(mac); + } if(ip == NULL) { ip = strdup("ALL"); } if(strlen(ip) == 0) { ip = strdup("ALL"); } @@ -314,8 +327,8 @@ int main(int argc, char** argv) ip = dynamic_replace(ip, "- ", "-"); free(tmp_ip); } - - + + if( (strcmp(ip, "ALL_OTHERS_COMBINED") == 0 || strcmp(ip, "ALL_OTHERS_INDIVIDUAL") == 0) && (!process_other_quota) ) { push_list(other_quota_section_names, strdup(next_quota)); @@ -328,7 +341,7 @@ int main(int argc, char** argv) /* this is an explicitly defined ip or ip range, so save it for later, to deal with individual other overlap problem */ push_list(defined_ip_groups, strdup(ip)); } - + /* compute proper base id for rule, adding variable to uci if necessary */ char* quota_base_id = get_uci_option(ctx, "firewall", next_quota, "id"); if(quota_base_id == NULL) @@ -338,7 +351,7 @@ int main(int argc, char** argv) char** split_ip = split_on_separators(ip, id_breaks, 3, -1, 0, &num_pieces); char* first_ip = dynamic_replace(split_ip[0], "/", "_"); free_null_terminated_string_array(split_ip); - + quota_base_id = strdup(first_ip); unsigned long next_postfix_count = 0; while( get_string_map_element(defined_base_ids, quota_base_id) != NULL) @@ -359,7 +372,7 @@ int main(int argc, char** argv) /* D for dummy place holder */ set_string_map_element(defined_base_ids, quota_base_id, strdup("D")); - + /* add id we've decided on to UCI */ char* var_set = dynamic_strcat(4, "firewall.", next_quota, ".id=", quota_base_id); if (uci_lookup_ptr(ctx, &ptr, var_set, true) == UCI_OK) @@ -375,7 +388,7 @@ int main(int argc, char** argv) do_restore = strcmp(ignore_backup, "1") == 0 ? 0 : 1; if(!do_restore) { - //remove variable from uci + //remove variable from uci char* var_name = dynamic_strcat(3, "firewall.", next_quota, ".ignore_backup_at_next_restore"); if (uci_lookup_ptr(ctx, &ptr, var_name, true) == UCI_OK) { @@ -385,7 +398,7 @@ int main(int argc, char** argv) } } free(ignore_backup); - + char* reset_interval = get_uci_option(ctx, "firewall", next_quota, "reset_interval"); @@ -393,7 +406,7 @@ int main(int argc, char** argv) if(reset_interval != NULL) { char* reset_time = get_uci_option(ctx, "firewall", next_quota, "reset_time"); - + char* interval_option = strdup(" --reset_interval "); reset = dcat_and_free(&reset, &interval_option, 1, 1); reset = dcat_and_free(&reset, &reset_interval, 1, 1); @@ -404,9 +417,9 @@ int main(int argc, char** argv) reset = dcat_and_free(&reset, &reset_time, 1, 1); } } - - char* time_match_str = strdup(""); - + + char* time_match_str = strdup(""); + char* offpeak_hours = get_uci_option(ctx, "firewall", next_quota, "offpeak_hours"); char* offpeak_weekdays = get_uci_option(ctx, "firewall", next_quota, "offpeak_weekdays"); char* offpeak_weekly_ranges = get_uci_option(ctx, "firewall", next_quota, "offpeak_weekly_ranges"); @@ -432,15 +445,15 @@ int main(int argc, char** argv) time_match_str = dcat_and_free(&time_match_str, &timerange_match, 1,1); if(hours_var != NULL && weekly_ranges_var == NULL) { - time_match_str = dcat_and_free(&time_match_str, &hour_match, 1, 1); - time_match_str = dcat_and_free(&time_match_str, &hours_var, 1, 1); - time_match_str = dcat_and_free(&time_match_str, "e_end, 1, 0); + time_match_str = dcat_and_free(&time_match_str, &hour_match, 1, 1); + time_match_str = dcat_and_free(&time_match_str, &hours_var, 1, 1); + time_match_str = dcat_and_free(&time_match_str, "e_end, 1, 0); } if(weekdays_var != NULL && weekly_ranges_var == NULL) { - time_match_str = dcat_and_free(&time_match_str, &weekday_match, 1, 1); + time_match_str = dcat_and_free(&time_match_str, &weekday_match, 1, 1); time_match_str = dcat_and_free(&time_match_str, &weekdays_var, 1, 1); - time_match_str = dcat_and_free(&time_match_str, "e_end, 1, 0); + time_match_str = dcat_and_free(&time_match_str, "e_end, 1, 0); } if(weekly_ranges_var != NULL) { @@ -450,11 +463,11 @@ int main(int argc, char** argv) } free(quote_end); } - + char* types[] = { "ingress_limit", "egress_limit", "combined_limit" }; char* postfixes[] = { "_ingress", "_egress", "_combined" }; char* chains[] = { "ingress_quotas", "egress_quotas", "combined_quotas" }; - + int type_index; for(type_index=0; type_index < 3; type_index++) { @@ -463,28 +476,43 @@ int main(int argc, char** argv) char* subnet_definition = strdup(""); char* limit = get_uci_option(ctx, "firewall", next_quota, types[type_index]); - + char* type_id = dynamic_strcat(2, quota_base_id, postfixes[type_index] ); - + char* up_qos_mark = get_string_map_element(upload_qos_marks, exceeded_up_speed_str); char* down_qos_mark = get_string_map_element(download_qos_marks, exceeded_down_speed_str); if(full_qos_active) { up_qos_mark = get_uci_option(ctx, "firewall", next_quota, "exceeded_up_class_mark"); down_qos_mark = get_uci_option(ctx, "firewall", next_quota, "exceeded_down_class_mark"); - } + } - /* + /* * need to do ip test even if limit is null, because ALL_OTHERS quotas should not apply when any of the three types of explicit limit is defined * and we therefore need to use this test to set mark indicating an explicit quota has been checked */ - char* ip_test = strdup(""); + char* ip_test = strdup(""); if( strcmp(ip, "ALL_OTHERS_COMBINED") != 0 && strcmp(ip, "ALL_OTHERS_INDIVIDUAL") != 0 && strcmp(ip, "ALL") != 0 ) { + char* groups = dynamic_strcat(3, ",", get_groups(ctx), ","); + char* src_test; + char* dst_test; + if (strstr(groups, ip) != NULL) + { + src_test = dynamic_strcat(3, " -m set --set ", ip, " src "); + dst_test = dynamic_strcat(3, " -m set --set ", ip, " dst "); + } + else if (strstr(ip, "-") == NULL) + { + src_test = dynamic_strcat(3, " --src ", ip, " "); + dst_test = dynamic_strcat(3, " --dst ", ip, " "); + } + else + { + src_test = dynamic_strcat(3, " -m iprange --src-range ", ip, " "); + dst_test = dynamic_strcat(3, " -m iprange --dst-range ", ip, " "); + } - char* src_test = strstr(ip, "-") == NULL ? dynamic_strcat(3, " --src ", ip, " ") : dynamic_strcat(3, " -m iprange --src-range ", ip, " "); - char* dst_test = strstr(ip, "-") == NULL ? dynamic_strcat(3, " --dst ", ip, " ") : dynamic_strcat(3, " -m iprange --dst-range ", ip, " "); - if(strstr(ip, ",") != NULL || strstr(ip, " ") != NULL || strstr(ip, "\t") != NULL ) { char ip_breaks[] = { ',', ' ', '\t' }; @@ -494,8 +522,23 @@ int main(int argc, char** argv) for(ip_index=0; ip_index < num_ips; ip_index++) { char *next_ip = ip_list[ip_index]; - char* egress_test = strstr(next_ip, "-") == NULL ? dynamic_strcat(3, " --src ", next_ip, " ") : dynamic_strcat(3, " -m iprange --src-range ", next_ip, " "); - char* ingress_test = strstr(next_ip, "-") == NULL ? dynamic_strcat(3, " --dst ", next_ip, " ") : dynamic_strcat(3, " -m iprange --dst-range ", next_ip, " "); + char* egress_test; + char* ingress_test; + if (strstr(groups, next_ip) != NULL) + { + egress_test = dynamic_strcat(3, " -m set --set ", next_ip, " src "); + ingress_test = dynamic_strcat(3, " -m set --set ", next_ip, " dst "); + } + else if (strstr(ip, "-") == NULL) + { + egress_test = dynamic_strcat(3, " --src ", next_ip, " "); + ingress_test = dynamic_strcat(3, " --dst ", next_ip, " "); + } + else + { + egress_test = dynamic_strcat(3, " -m iprange --src-range ", next_ip, " "); + ingress_test = dynamic_strcat(3, " -m iprange --dst-range ", next_ip, " "); + } if(strcmp(types[type_index], "egress_limit") == 0) { @@ -560,13 +603,13 @@ int main(int argc, char** argv) { applies_to = strdup("individual_local"); } - + char *subnet_option = strdup(" --subnet "); subnet_definition = dcat_and_free(&subnet_definition, &subnet_option, 1, 1); subnet_definition = dcat_and_free(&subnet_definition, &local_subnet, 1, 0); } } - + if(up_qos_mark != NULL && down_qos_mark != NULL) @@ -582,11 +625,11 @@ int main(int argc, char** argv) char* other_type_id = dynamic_strcat(2, quota_base_id, postfixes[other_type_index] ); if(type_index == EGRESS_INDEX) { - run_shell_command(dynamic_strcat(10, "iptables -t ", quota_table, " -A ", chains[type_index], ip_test, time_match_str, " -m bandwidth --id \"", other_type_id, "\" --bcheck_with_src_dst_swap ", set_egress_mark), 1); + run_shell_command(dynamic_strcat(10, "iptables -t ", quota_table, " -A ", chains[type_index], ip_test, time_match_str, " -m bandwidth --id \"", other_type_id, "\" --bcheck_with_src_dst_swap ", set_egress_mark), 1); } else { - run_shell_command(dynamic_strcat(10, "iptables -t ", quota_table, " -A ", chains[type_index], ip_test, time_match_str, " -m bandwidth --id \"", other_type_id, "\" --bcheck_with_src_dst_swap ", set_ingress_mark), 1); + run_shell_command(dynamic_strcat(10, "iptables -t ", quota_table, " -A ", chains[type_index], ip_test, time_match_str, " -m bandwidth --id \"", other_type_id, "\" --bcheck_with_src_dst_swap ", set_ingress_mark), 1); } free(other_type_id); } @@ -595,13 +638,13 @@ int main(int argc, char** argv) free(set_egress_mark); free(set_ingress_mark); } - + if(limit != NULL) { if(up_qos_mark != NULL && down_qos_mark != NULL) { char* set_egress_mark = dynamic_strcat(2, " -j MARK --set-mark ", up_qos_mark); - char* set_ingress_mark = dynamic_strcat(2, " -j MARK --set-mark ", down_qos_mark); + char* set_ingress_mark = dynamic_strcat(2, " -j MARK --set-mark ", down_qos_mark); if(strcmp(types[type_index], "egress_limit") == 0) { run_shell_command(dynamic_strcat(15, "iptables -t ", quota_table, " -A ", chains[type_index], ip_test, time_match_str, " -m bandwidth --id \"", type_id, "\" --type ", applies_to, subnet_definition, " --greater_than ", limit, reset, set_egress_mark), 1); @@ -624,7 +667,7 @@ int main(int argc, char** argv) //insert quota block rule run_shell_command(dynamic_strcat(15, "iptables -t ", quota_table, " -A ", chains[type_index], ip_test, time_match_str, " -m bandwidth --id \"", type_id, "\" --type ", applies_to, subnet_definition, " --greater_than ", limit, reset, set_death_mark), 1); - + //insert redirect rule if(strcmp(ip, "ALL") == 0 || strcmp(ip, "ALL_OTHERS_INDIVIDUAL") == 0) { @@ -804,17 +847,17 @@ void restore_backup_for_id(char* id, char* quota_backup_dir, unsigned char is_in ip_bw* ptr = loaded_backup_data + ip_index; push_list(ip_bw_list, ptr); } - + unsigned long num_groups = 0; char** group_strs = (char**)get_list_values(defined_ip_groups, &num_groups); unsigned long group_index; - + for(group_index = 0; group_index < num_groups; group_index++) { filter_group_from_list(&ip_bw_list, group_strs[group_index]); } - - + + //rebuild the backup data array from the filtered list if(num_ips != ip_bw_list->length) { @@ -828,7 +871,7 @@ void restore_backup_for_id(char* id, char* quota_backup_dir, unsigned char is_in free(loaded_backup_data); loaded_backup_data = adj_backup; } - + destroy_list(ip_bw_list, DESTROY_MODE_IGNORE_VALUES, &num_groups); free(group_strs); //don't want to destroy values, they're still contained in list, so just destroy container array } @@ -871,7 +914,7 @@ list* filter_group_from_list(list** orig_ip_bw_list, char* ip_group_str) unsigned long num_groups = 0; char** split_group = split_on_separators(dyn_group_str, group_breaks, 3, -1, 0, &num_groups); unsigned long group_index; - + for(group_index = 0; group_index < num_groups; group_index++) { uint32_t* range = ip_range_to_host_ints( split_group[group_index] ); @@ -906,8 +949,8 @@ uint32_t* ip_range_to_host_ints(char* ip_str) uint32_t* ret_val = (uint32_t*)malloc(2*sizeof(uint32_t)); uint32_t start = 0; uint32_t end = 0; - - + + unsigned long num_pieces = 0; char ip_breaks[] = "/-"; char** split_ip = split_on_separators(ip_str, ip_breaks, 2, -1, 0, &num_pieces); @@ -957,7 +1000,7 @@ void delete_chain_from_table(char* table, char* delete_chain) char *command = dynamic_strcat(3, "iptables -t ", table, " -L -n --line-numbers 2>/dev/null"); unsigned long num_lines = 0; char** table_dump = get_shell_command_output_lines(command, &num_lines ); - free(command); + free(command); unsigned long line_index; char* current_chain = NULL; @@ -975,7 +1018,7 @@ void delete_chain_from_table(char* table, char* delete_chain) if(current_chain != NULL) { free(current_chain); } current_chain = strdup(line_pieces[1]); } - else + else { unsigned long line_num; int read = sscanf(line_pieces[0], "%ld", &line_num); @@ -994,7 +1037,7 @@ void delete_chain_from_table(char* table, char* delete_chain) free_null_terminated_string_array(line_pieces); } free_null_terminated_string_array(table_dump); - + /* final two commands to flush chain being deleted and whack it */ unshift_list(delete_commands, dynamic_strcat(5, "iptables -t ", table, " -F ", delete_chain, " 2>/dev/null")); unshift_list(delete_commands, dynamic_strcat(5, "iptables -t ", table, " -X ", delete_chain, " 2>/dev/null")); @@ -1102,4 +1145,104 @@ char* get_option_value_string(struct uci_option* uopt) return opt_str; } +/** +* returns a comma delimited string of group names +*/ +char* get_groups(struct uci_context* ctx) +{ + char* groups = ""; + list* hosts = get_all_sections_of_type(ctx, "dhcp", "host"); + + while(hosts->length > 0) + { + char* next_host = shift_list(hosts); + char* group = get_uci_option(ctx, "dhcp", next_host, "group"); + if (strstr(groups, group) == NULL) + { + char* tmp; + tmp = dynamic_strcat(3, groups, ",", strdup(group)); + free(groups); + groups = tmp; + } + free(next_host); + } + return groups; +} + + +/** +* Takes the name of a MAC Group, retrieves the MAC addresses in the Group, and +* returns a comma delimited list of IP addresses that are currently dhcp.leased +* to those MACs in the Group. +*/ +char* get_ip_from_group(struct uci_context* ctx, char* group) +{ + char* ip = ""; + + char* macs = get_uci_option(ctx, "known", group, "mac"); + if (macs != NULL || sizeof(macs) > 0) + { // get dhcp.leases relating to MACs in the Group + string_map* mac_to_ip = get_leases(); + unsigned long num_keys; + get_string_map_keys(mac_to_ip, &num_keys); + + if (num_keys > 0) + { // check each MAC in the Group against dhcp.leases + char mac_breaks[] = { ',', ' ', '\t' }; + unsigned long num_macs = 0; + char** mac_list = split_on_separators(macs, mac_breaks, 3, -1, 0, &num_macs); + unsigned long mac_index; + for(mac_index=0; mac_index < num_macs; mac_index++) + { // + char* next_ip = get_string_map_element(mac_to_ip, mac_list[mac_index]); + char* tmp; + tmp = dynamic_strcat(3, ip, ",", strdup(next_ip)); + free(ip); + ip = tmp; + } + + unsigned long num_destroyed; + destroy_string_map(mac_to_ip, DESTROY_MODE_FREE_VALUES, &num_destroyed); + } + } + return ip; +} + + + +string_map* get_leases(void) +{ + string_map* mac_to_ip = initialize_string_map(1); + + char* dhcp_leases = "/tmp/dhcp.leases"; + int ip_index = 2; + int mac_index = 1; + int min_line_pieces = ip_index > mac_index ? ip_index+1 : mac_index+1; + + FILE* lease_file = fopen(dhcp_leases, "r"); + if(lease_file != NULL) + { + char *line = NULL; + unsigned long read_len; + int sep = '\n'; + do + { + sep = dyn_read_line(lease_file, &line, &read_len); + unsigned long num_line_pieces; + char* whitespace_seps = "\t "; + char** line_pieces = split_on_separators(line, whitespace_seps, 2, -1, 0, &num_line_pieces); + free(line); + if(num_line_pieces >= min_line_pieces) + { + char* mac = line_pieces[ mac_index ]; + char* ip = line_pieces[ ip_index ]; + set_string_map_element(mac_to_ip, mac, ip); + } + free_null_terminated_string_array(line_pieces); + }while(sep != EOF); + fclose(lease_file); + } + + return mac_to_ip; +} diff --git a/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh b/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh new file mode 100755 index 0000000000..0d9b3606a6 --- /dev/null +++ b/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh @@ -0,0 +1,47 @@ +# This program is copyright © 2015 John Brown and is distributed under the terms of the GNU GPL +# version 2.0 with a special clarification/exception that permits adapting the program to +# configure proprietary "back end" software provided that all modifications to the web interface +# itself remain covered by the GPL. +# See http://gargoyle-router.com/faq.html#qfoss for more information + +# This script was written as part of the Device Groups implementation (see: /www/device.sh) +# Know Devices may be assigned to a Group (see: uci show known.device) +# An ipset is created for each Group (see: ipset list -n) +# Each new dhcp lease must update the ipset (see: uci show dnsmasq.dhcp-script) +# This script searches Know Devices for a matching MAC and will add/del the IP to/from the Group's ipset + + +event = $1 +mac = $2 +ip = $3 +host = $4 + +OIFS=$IFS; + +deviceStr=$(uci get known.device | grep 'known.device=' | awk ' -F= { print $2 ; } '); +IFS="\n"; +devices = ($deviceStr); + +for ((d=0; d<${#devices[@]}; ++d)); do + device = devices[$d]; + group = $(uci get known.$device.group); + macStr = $(uci get known.$device.mac); + IFS=" "; + macs = $(macStr); + + for ((m=0; m<${#macs[@]}; ++m)); do + if [macs[$m] = mac]; then + if [event = "add"]; then + ipset add $group $ip + fi + if [event = "old"]; then + fi + if [event = "del"]; then + ipset del $group $ip -exist + fi + fi + done +done + + +IFS=$OIFS; diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js index b482254054..9a5378dee0 100644 --- a/package/gargoyle/files/www/js/device.js +++ b/package/gargoyle/files/www/js/device.js @@ -65,6 +65,12 @@ function saveChanges() } } + // create ipsets + var ipsetCommands = ["ipset destroy"]; // fails on ipsets with existing references + for (gIndex=0; gIndex < groups.length; gIndex++){ + ipsetCommands.push("ipset create " + groups[gIndex] + " iphash"); + } + var commands = uci.getScriptCommands(uciOriginal) + "\n" + ipsetCommands.join("\n"); var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); From 4b6fb90423c6f98a3630af68354fca2ac84e8c7d Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 11 Dec 2015 05:55:38 +1100 Subject: [PATCH 21/48] Add dnsmasq.conf The dnsmasq dhcp-script is not available thru OpenWRT uci but it is possible to suppliment the uci settings with /etc/dnsmasq.conf https://wiki.openwrt.org/doc/uci/dhcp?&#using_plain_dnsmasqconf --- package/gargoyle/files/etc/dnsmasq.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 package/gargoyle/files/etc/dnsmasq.conf diff --git a/package/gargoyle/files/etc/dnsmasq.conf b/package/gargoyle/files/etc/dnsmasq.conf new file mode 100644 index 0000000000..4cc45f5afe --- /dev/null +++ b/package/gargoyle/files/etc/dnsmasq.conf @@ -0,0 +1 @@ +dhcp-script=/usr/lib/gargoyle/post_lease.sh From 03a93d962be0539b2a57250f927565bcf87521e7 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 11 Dec 2015 05:56:26 +1100 Subject: [PATCH 22/48] Remove /etc/config/known --- package/gargoyle/files/etc/config/known | 1 - 1 file changed, 1 deletion(-) delete mode 100644 package/gargoyle/files/etc/config/known diff --git a/package/gargoyle/files/etc/config/known b/package/gargoyle/files/etc/config/known deleted file mode 100644 index 8b13789179..0000000000 --- a/package/gargoyle/files/etc/config/known +++ /dev/null @@ -1 +0,0 @@ - From 3ed0a79869710047282dd9c4a157f52289d559e2 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 11 Dec 2015 07:50:06 +1100 Subject: [PATCH 23/48] Improve layout of Select Elements --- package/gargoyle/files/www/device.sh | 13 ------------- .../gargoyle/files/www/templates/device_template | 9 +++++++++ package/gargoyle/files/www/templates/group_template | 13 +++++++++++++ 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/package/gargoyle/files/www/device.sh b/package/gargoyle/files/www/device.sh index 19cb654307..e7e06719bc 100644 --- a/package/gargoyle/files/www/device.sh +++ b/package/gargoyle/files/www/device.sh @@ -46,11 +46,6 @@
<%in templates/device_template %>
-
- -
@@ -72,14 +67,6 @@
<%in templates/group_template %>
-
- - -
diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index c0928286e0..52a67da14e 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -9,4 +9,13 @@
+ + + + +
+ +
diff --git a/package/gargoyle/files/www/templates/group_template b/package/gargoyle/files/www/templates/group_template index 1283700ea0..41a10df095 100644 --- a/package/gargoyle/files/www/templates/group_template +++ b/package/gargoyle/files/www/templates/group_template @@ -9,4 +9,17 @@ + + + + + + + + + From 67ac871a3ffa10bb105daf6355bead0e994aec05 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 11 Dec 2015 07:53:24 +1100 Subject: [PATCH 24/48] Improve refresh of Tables & Selects - Reset all tables & selects after Save - Add new Devices & Groups to Select Options while editing --- package/gargoyle/files/www/js/device.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js index 9a5378dee0..caa1389120 100644 --- a/package/gargoyle/files/www/js/device.js +++ b/package/gargoyle/files/www/js/device.js @@ -80,7 +80,7 @@ function saveChanges() if(req.readyState == 4) { uciOriginal = uci.clone(); - //resetData(); + resetData(); setControlsEnabled(true); //alert(req.responseText); } @@ -204,7 +204,7 @@ function resetMacList() var hlText = [ deviceS.SelM ]; for (var mac in knownMac) { - if (knownMac.hasOwnProperty(mac)) + if (knownMac.hasOwnProperty(mac)) { if( deviceMacs.indexOf(mac) == -1 ) { // exclude MAC's that are already assigned to a device @@ -330,6 +330,7 @@ function addMac() var deviceTable = document.getElementById('device_table_container').firstChild; var values = [host.value, macs.value, createEditButton("editDevice")]; addTableRow(deviceTable, values, true, false, resetMacList); + addNewOption('device_list', host.value, host.value); host.value = ""; macs.value = ""; } @@ -355,6 +356,8 @@ function addDevice() var groupTable = document.getElementById('group_table_container').firstChild; var values = [group.value, devices.value, createEditButton("editGroup")]; addTableRow(groupTable,values, true, false, resetDeviceList); + addNewOption('group_list', group.value, group.value); + addOptionToSelectElement('group_list', group.value, group.value, null, document) group.value=""; devices.value=""; } @@ -487,3 +490,18 @@ function lookupList(data, field){ } return lookup; } + + +function addNewOption(selectId, optionText, optionValue) +{ + var options = document.getElementById(selectId).options; + var exists = false; + for(oIndex=0; oIndex < options.length; oIndex++) + { + exists = exists | (options[oIndex].text == optionText); + } + if (!exists) + { + addOptionToSelectElement(selectId, optionText, optionValue, null, document) + } +} From e97058a46239c31a51f8d757165a1fb473bdab7b Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sat, 12 Dec 2015 07:50:48 +1100 Subject: [PATCH 25/48] Validation of Hosts MACs & Groups --- README.md | 9 +-- package/gargoyle/files/www/js/common.js | 70 +++++++++++++++- package/gargoyle/files/www/js/device.js | 81 +++++++++++++------ .../files/www/templates/device_template | 6 +- .../files/www/templates/group_template | 6 +- 5 files changed, 132 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index c9ccb78168..9f6cc079b8 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,4 @@ of needing to assign a static IP address to each device requiring management. Status - Gargoyle-Connection-Devices has a Section for Known Devices and another for Device Groups. - Known Device and Group data is stored in uci /etc/config/dhcp - -TODO device.sh -- Update selects after address -- layout input and select elements -- validate inputs - -TODO quotas.sh -- +- Device Groups can be used to apply a Quota. diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 182b7feae0..4c4baf99f2 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -1557,7 +1557,7 @@ function validateIP(address) //3 = ends with 255 (actually, broadcast address can end with other value if subnet smaller than 255... but let's not worry about that) //4 = value >255 in at least one field //5 = improper format - //6 = Undefined Group + //6 = invalid characters var errorCode = 0; if(address == "0.0.0.0") @@ -1615,10 +1615,29 @@ function validateMac(mac) return errorCode; } - +/* +* Each Group is reflected by an ipset of the same name so the Group Name must + be a valid ipset name. +*/ function validateGroup(name) { - var errorCode = (deviceGroups().indexOf(name) == -1) ? 6 : 0 ; + if(name.match(/^[a-zA-Z0-9-_.:]{2,63}$/) == null) + { + errorCode = 6; + } + return errorCode; +} + + +/* +* Host names may include a-z, A-Z, 0-9 and - +*/ +function validateHost(name) +{ + if(name.match(/^[a-zA-Z0-9-]{2,63}$/) == null) + { + errorCode = 6; + } return errorCode; } @@ -1699,6 +1718,35 @@ function validateMultipleIpsOrMacs(addresses) } +function validateMultipleMacs(macs) +{ + macs = macs.replace(/^[\t ]+/g, ""); + macs = macs.replace(/[\t ]+$/g, ""); + var splitMacs = macs.split(/[\t ]*,[\t ]*/); + var valid = splitMacs.length > 0 ? 0 : 1; //1= error, 0=true + while(valid == 0 && splitMacs.length > 0) + { + var nextMac = splitMacs.pop(); + valid = validateMac(nextMac); + } + return valid; +} + +function validateMultipleHosts(hosts) +{ + hosts = hosts.replace(/^[\t ]+/g, ""); + hosts = hosts.replace(/[\t ]+$/g, ""); + var splitHosts = hosts.split(/[\t ]*,[\t ]*/); + var valid = splitHosts.length > 0 ? 0 : 1; //1= error, 0=true + while(valid == 0 && splitHosts.length > 0) + { + var nextHost = splitHosts.pop(); + valid = validateHost(nextHost); + } + return valid; +} + + function validateDecimal(num) { var errorCode = num.match(/^[\d]*\.?[\d]+$/) != null || num.match(/^[\d]+\.?[\d]*$/) != null ? 0 : 1; @@ -1926,6 +1974,10 @@ function proofreadMac(input) { proofreadText(input, validateMac, 0); } +function proofreadMultipleMacs(input) +{ + proofreadText(input, validateMultipleMacs, 0); +} function proofreadMultipleIps(input) { proofreadText(input, validateMultipleIps, 0); @@ -1938,6 +1990,18 @@ function proofreadMultipleIpsOrGroup(input) { proofreadText(input, validateMultipleIpsOrGroup, 0); } +function proofreadHost(input) +{ + proofreadText(input, validateHost, 0); +} +function proofreadMultipleHosts(input) +{ + proofreadText(input, validateMultipleHosts, 0); +} +function proofreadGroup(input) +{ + proofreadText(input, validateGroup, 0); +} function proofreadDecimal(input) { diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js index caa1389120..c966a8da4a 100644 --- a/package/gargoyle/files/www/js/device.js +++ b/package/gargoyle/files/www/js/device.js @@ -291,7 +291,6 @@ function macSelected() if (host.value == "") { host.value = (selectedVal.split(/,/))[0]; - fixGroupName(host); } var selMac = (selectedVal.split(/,/))[1]; macs.value = (macs.value == "") ? selMac : macs.value.concat(" ", selMac); @@ -313,10 +312,9 @@ function deviceSelected() -function addMac() +function addDevice() { - //errors = proofreadDevice(document); - errors = ""; + errors = proofReadDeviceForm(); if(errors.length > 0) { alert(errors.join("\n") + "\n\n" + deviceS.AErr); @@ -339,10 +337,9 @@ function addMac() -function addDevice() +function addDeviceToGroup() { - //errors = proofreadDevice(document); - errors = ""; + errors = proofReadGroupForm(); if(errors.length > 0) { alert(errors.join("\n") + "\n\n" + deviceS.AErr); @@ -396,22 +393,6 @@ function removeGroup(table, row) } - -function fixGroupName(element) -{ - var name = element.value; - name = name.replace(/-|\s/g,"_"); - element.value = name; -} - - -function proofReadMac(input) -{ - // please implement proofReadMAC -} - - - /******************************************************************************* * Utility functions *******************************************************************************/ @@ -505,3 +486,57 @@ function addNewOption(selectId, optionText, optionValue) addOptionToSelectElement(selectId, optionText, optionValue, null, document) } } + +/****************************************************************************** +* Validation functions +******************************************************************************/ + +/** +* Checks for invalid or duplicate host names and MACs +*/ +function proofReadDeviceForm() +{ + addIds=['add_host', 'add_mac']; + labelIds= ['add_host_label', 'add_mac_label']; + functions = [validateHost, validateMac]; + returnCodes = [0,0]; + visibilityIds=addIds; + errors = proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, controlDocument); + + if(errors.length == 0) + { // check that the host and mac are not duplicates of existing values + var newHost = document.getElementById('add_host').value; + var newMac = document.getElementById('add_mac').value; + var deviceTable = tableDocument.getElementById('device_table_container').firstChild; + var currentData = getTableDataArray(deviceTable, true, false); + for (cdIndex=0; cdIndex < currentData.length ; cdIndex++) + { + var rowData = currentData[cdIndex]; + var oldHost = rowData[0]; + var oldMac = rowData[1]; + if(oldHost != '' && oldHost != '-' && oldHost == newHost) + { + errors.push(dhcpS.dHErr); + } + if(oldMac == newMac) + { + errors.push(dhcpS.dMErr); + } + } + } + return errors; +} + + +/** +* Checks for invalid host or group names +*/ +function proofReadGroupForm() +{ + addIds=['add_group', 'add_device']; + labelIds= ['add_group_label', 'add_device_label']; + functions = [validateGroup, validateDevice]; + returnCodes = [0,0]; + visibilityIds=addIds; + return proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, controlDocument); +} diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index 52a67da14e..ddb2f77416 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -5,9 +5,9 @@ - - - + + + diff --git a/package/gargoyle/files/www/templates/group_template b/package/gargoyle/files/www/templates/group_template index 41a10df095..2c90d09050 100644 --- a/package/gargoyle/files/www/templates/group_template +++ b/package/gargoyle/files/www/templates/group_template @@ -5,9 +5,9 @@ - - - + + + From c53e308e5c856dc4e9dce6f3a5f5a2374a6595a1 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Tue, 15 Dec 2015 12:25:55 +1100 Subject: [PATCH 26/48] Bug fixes --- .../src/restore_quotas.c | 115 +++--------------- package/gargoyle/files/etc/config/gargoyle | 2 +- .../files/usr/lib/gargoyle/post_lease.sh | 62 +++++----- package/gargoyle/files/www/device.sh | 2 + package/gargoyle/files/www/js/common.js | 48 +++++++- package/gargoyle/files/www/js/device.js | 40 +++--- package/gargoyle/files/www/js/quotas.js | 8 +- package/gargoyle/files/www/quotas.sh | 2 +- .../files/www/templates/device_template | 2 +- .../files/www/templates/group_template | 10 +- .../files/www/i18n/English-EN/device.js | 6 +- 11 files changed, 127 insertions(+), 170 deletions(-) diff --git a/package/gargoyle-firewall-util/src/restore_quotas.c b/package/gargoyle-firewall-util/src/restore_quotas.c index 4abdf52bba..118f4e6d21 100644 --- a/package/gargoyle-firewall-util/src/restore_quotas.c +++ b/package/gargoyle-firewall-util/src/restore_quotas.c @@ -54,13 +54,9 @@ void free_split_pieces(char** split_pieces); list* get_all_sections_of_type(struct uci_context *ctx, char* package, char* section_type); char* get_uci_option(struct uci_context* ctx,char* package_name, char* section_name, char* option_name); char* get_option_value_string(struct uci_option* uopt); -char* get_ip_from_group(struct uci_context* ctx, char* mac_group); char* get_groups(struct uci_context* ctx); -string_map* get_leases(void); - - int main(int argc, char** argv) { @@ -292,6 +288,7 @@ int main(int argc, char** argv) if(enabled) { + char* ip = get_uci_option(ctx, "firewall", next_quota, "ip"); char* exceeded_up_speed_str = NULL; char* exceeded_down_speed_str = NULL; if(!full_qos_active) /* without defined up/down speeds we always set hard cutoff, which is what we want when full qos is active */ @@ -302,15 +299,6 @@ int main(int argc, char** argv) if(exceeded_up_speed_str == NULL) { exceeded_up_speed_str = strdup(" "); } if(exceeded_down_speed_str == NULL) { exceeded_down_speed_str = strdup(" "); } - char* mac = get_uci_option(ctx, "firewall", next_quota, "mac"); - char* ip = (mac != NULL) ? get_ip_from_group(ctx, mac) : get_uci_option(ctx, "firewall", next_quota, "ip"); - - if (strlen(ip) == 0) - { - ip = get_uci_option(ctx, "firewall", next_quota, "ip"); - free(mac); - } - if(ip == NULL) { ip = strdup("ALL"); } if(strlen(ip) == 0) { ip = strdup("ALL"); } @@ -328,6 +316,12 @@ int main(int argc, char** argv) free(tmp_ip); } + char* groups = get_groups(ctx); + if (strstr(groups, ip) != NULL) + { // ensure that an ipset corresponding to the group exists + run_shell_command(dynamic_strcat(3, "ipset create ", ip, " hash:ip hashsize 64 2>/dev/null"), 1); + } + if( (strcmp(ip, "ALL_OTHERS_COMBINED") == 0 || strcmp(ip, "ALL_OTHERS_INDIVIDUAL") == 0) && (!process_other_quota) ) { @@ -494,13 +488,12 @@ int main(int argc, char** argv) char* ip_test = strdup(""); if( strcmp(ip, "ALL_OTHERS_COMBINED") != 0 && strcmp(ip, "ALL_OTHERS_INDIVIDUAL") != 0 && strcmp(ip, "ALL") != 0 ) { - char* groups = dynamic_strcat(3, ",", get_groups(ctx), ","); char* src_test; char* dst_test; if (strstr(groups, ip) != NULL) { - src_test = dynamic_strcat(3, " -m set --set ", ip, " src "); - dst_test = dynamic_strcat(3, " -m set --set ", ip, " dst "); + src_test = dynamic_strcat(3, " -m set --match-set ", ip, " src "); + dst_test = dynamic_strcat(3, " -m set --match-set ", ip, " dst "); } else if (strstr(ip, "-") == NULL) { @@ -526,8 +519,8 @@ int main(int argc, char** argv) char* ingress_test; if (strstr(groups, next_ip) != NULL) { - egress_test = dynamic_strcat(3, " -m set --set ", next_ip, " src "); - ingress_test = dynamic_strcat(3, " -m set --set ", next_ip, " dst "); + egress_test = dynamic_strcat(3, " -m set --match-set ", next_ip, " src "); + ingress_test = dynamic_strcat(3, " -m set --match-set ", next_ip, " dst "); } else if (strstr(ip, "-") == NULL) { @@ -1146,7 +1139,7 @@ char* get_option_value_string(struct uci_option* uopt) } /** -* returns a comma delimited string of group names +* returns a space delimited string of group names */ char* get_groups(struct uci_context* ctx) { @@ -1157,92 +1150,16 @@ char* get_groups(struct uci_context* ctx) { char* next_host = shift_list(hosts); char* group = get_uci_option(ctx, "dhcp", next_host, "group"); - if (strstr(groups, group) == NULL) + + if (group != NULL && strlen(group) > 0 && strstr(groups, group) == NULL) { char* tmp; - tmp = dynamic_strcat(3, groups, ",", strdup(group)); + tmp = dynamic_strcat(3, groups, " ", strdup(group)); free(groups); groups = tmp; } free(next_host); - } - return groups; -} - - - -/** -* Takes the name of a MAC Group, retrieves the MAC addresses in the Group, and -* returns a comma delimited list of IP addresses that are currently dhcp.leased -* to those MACs in the Group. -*/ -char* get_ip_from_group(struct uci_context* ctx, char* group) -{ - char* ip = ""; - - char* macs = get_uci_option(ctx, "known", group, "mac"); - if (macs != NULL || sizeof(macs) > 0) - { // get dhcp.leases relating to MACs in the Group - string_map* mac_to_ip = get_leases(); - unsigned long num_keys; - get_string_map_keys(mac_to_ip, &num_keys); - - if (num_keys > 0) - { // check each MAC in the Group against dhcp.leases - char mac_breaks[] = { ',', ' ', '\t' }; - unsigned long num_macs = 0; - char** mac_list = split_on_separators(macs, mac_breaks, 3, -1, 0, &num_macs); - unsigned long mac_index; - for(mac_index=0; mac_index < num_macs; mac_index++) - { // - char* next_ip = get_string_map_element(mac_to_ip, mac_list[mac_index]); - char* tmp; - tmp = dynamic_strcat(3, ip, ",", strdup(next_ip)); - free(ip); - ip = tmp; - } - - unsigned long num_destroyed; - destroy_string_map(mac_to_ip, DESTROY_MODE_FREE_VALUES, &num_destroyed); - } - } - return ip; -} - - -string_map* get_leases(void) -{ - string_map* mac_to_ip = initialize_string_map(1); - - char* dhcp_leases = "/tmp/dhcp.leases"; - int ip_index = 2; - int mac_index = 1; - int min_line_pieces = ip_index > mac_index ? ip_index+1 : mac_index+1; - - FILE* lease_file = fopen(dhcp_leases, "r"); - if(lease_file != NULL) - { - char *line = NULL; - unsigned long read_len; - int sep = '\n'; - do - { - sep = dyn_read_line(lease_file, &line, &read_len); - unsigned long num_line_pieces; - char* whitespace_seps = "\t "; - char** line_pieces = split_on_separators(line, whitespace_seps, 2, -1, 0, &num_line_pieces); - free(line); - if(num_line_pieces >= min_line_pieces) - { - char* mac = line_pieces[ mac_index ]; - char* ip = line_pieces[ ip_index ]; - set_string_map_element(mac_to_ip, mac, ip); - } - free_null_terminated_string_array(line_pieces); - }while(sep != EOF); - fclose(lease_file); } - - return mac_to_ip; + return groups; } diff --git a/package/gargoyle/files/etc/config/gargoyle b/package/gargoyle/files/etc/config/gargoyle index 869e16a0b9..86d0993a22 100644 --- a/package/gargoyle/files/etc/config/gargoyle +++ b/package/gargoyle/files/etc/config/gargoyle @@ -95,7 +95,7 @@ config 100 status config 200 connection option basic '100' option dhcp '200' - option devices '250' + option devices '220' option dyndns '300' option routing '400' option wol '500' diff --git a/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh b/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh index 0d9b3606a6..f5c45e92f4 100755 --- a/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh +++ b/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh @@ -1,5 +1,7 @@ -# This program is copyright © 2015 John Brown and is distributed under the terms of the GNU GPL -# version 2.0 with a special clarification/exception that permits adapting the program to +#!/bin/sh +# +# This program is copyright © 2015 John Brown and is distributed under the terms of the GNU GPL +# version 2.0 with a special clarification/exception that permits adapting the program to # configure proprietary "back end" software provided that all modifications to the web interface # itself remain covered by the GPL. # See http://gargoyle-router.com/faq.html#qfoss for more information @@ -11,37 +13,39 @@ # This script searches Know Devices for a matching MAC and will add/del the IP to/from the Group's ipset -event = $1 -mac = $2 -ip = $3 -host = $4 +event=$1 +mac="$(echo $2 | awk '{print toupper($0)}')" +ip=$3 +host=$4 OIFS=$IFS; -deviceStr=$(uci get known.device | grep 'known.device=' | awk ' -F= { print $2 ; } '); -IFS="\n"; -devices = ($deviceStr); - -for ((d=0; d<${#devices[@]}; ++d)); do - device = devices[$d]; - group = $(uci get known.$device.group); - macStr = $(uci get known.$device.mac); - IFS=" "; - macs = $(macStr); - - for ((m=0; m<${#macs[@]}; ++m)); do - if [macs[$m] = mac]; then - if [event = "add"]; then - ipset add $group $ip - fi - if [event = "old"]; then - fi - if [event = "del"]; then - ipset del $group $ip -exist +#echo "" >>//tmp/post_lease +#echo $event $mac $ip $host >>/tmp/post_lease + +uciHosts=$(uci show dhcp 2>>//dev/null | grep '=host' | sed s/dhcp.// | sed s/=host// | awk '{ print $1 ; } ') + +for uciHost in $uciHosts; do + + IFS=" " + uciMacs=$(uci get dhcp.$uciHost.mac 2>>//dev/null) + for uciMac in $uciMacs ; do + if [ "$uciMac" = "$mac" ]; then + + uciGroup=$(uci get dhcp.$uciHost.group 2>>//dev/null) + if [ "${#uciGroup}" -gt 0 ]; then + + if [ "$event" = "add" ] || [ "$event" = "old" ]; then + ipset create $uciGroup hash:ip hashsize 64 2>>//dev/null # create ipset if not exist + ipset add $uciGroup $ip 2>>//dev/null + fi + if [ "$event" = "del" ]; then + ipset del $uciGroup $ip -exist 2>>//dev/null + fi + #ipset list $uciGroup >>//tmp/post_lease + IFS=$OIFS; + return 0 # remove to continue searching for Macs in other Hosts fi fi done done - - -IFS=$OIFS; diff --git a/package/gargoyle/files/www/device.sh b/package/gargoyle/files/www/device.sh index e7e06719bc..d192e35e70 100644 --- a/package/gargoyle/files/www/device.sh +++ b/package/gargoyle/files/www/device.sh @@ -40,6 +40,7 @@ <%~ device.KnDev %>
+
@@ -61,6 +62,7 @@ <%~ DevGp %>
+
diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 4c4baf99f2..9fbd4ebaf0 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -351,7 +351,8 @@ function UCIContainer() { includeLists = includeLists == null ? false : includeLists; var matches = new Array(); - for (var key in this.values) { + for (var key in this.values) + { if (this.values.hasOwnProperty(key)) { var test = pkg + "." + section; @@ -368,7 +369,8 @@ function UCIContainer() this.getAllSectionsOfType = function(pkg, type) { var matches = new Array(); - for (var key in this.values) { + for (var key in this.values) + { if (this.values.hasOwnProperty(key)) { if(key.match(pkg) && key.match(/^[^\.]+\.[^\.]+$/)) @@ -505,7 +507,6 @@ function UCIContainer() var listsWithoutUpdates = []; - for (var key in oldSettings.values) { if (oldSettings.values.hasOwnProperty(key)) @@ -555,7 +556,6 @@ function UCIContainer() var newValue = this.values[key]; try { - if( (oldValue instanceof Array) || (newValue instanceof Array) ) { if(newValue instanceof Array) @@ -1621,6 +1621,7 @@ function validateMac(mac) */ function validateGroup(name) { + var errorCode = 0; if(name.match(/^[a-zA-Z0-9-_.:]{2,63}$/) == null) { errorCode = 6; @@ -1634,6 +1635,7 @@ function validateGroup(name) */ function validateHost(name) { + var errorCode = 0; if(name.match(/^[a-zA-Z0-9-]{2,63}$/) == null) { errorCode = 6; @@ -1642,6 +1644,20 @@ function validateHost(name) } +/* +* UCI names may include a-z, A-Z, 0-9 and _ +*/ +function validateUCI(name) +{ + var errorCode = 0; + if(name.match(/^[a-zA-Z0-9_]{2,63}$/) == null) + { + errorCode = 6; + } + return errorCode; +} + + function validateMultipleIpsOrGroup(ips) { var errorCode = validateGroup(ips); @@ -1722,7 +1738,7 @@ function validateMultipleMacs(macs) { macs = macs.replace(/^[\t ]+/g, ""); macs = macs.replace(/[\t ]+$/g, ""); - var splitMacs = macs.split(/[\t ]*,[\t ]*/); + var splitMacs = macs.split(/[\t ]+/); var valid = splitMacs.length > 0 ? 0 : 1; //1= error, 0=true while(valid == 0 && splitMacs.length > 0) { @@ -1746,6 +1762,20 @@ function validateMultipleHosts(hosts) return valid; } +function validateMultipleUCIs(ucis) +{ + ucis = ucis.replace(/^[\t ]+/g, ""); + ucis = ucis.replace(/[\t ]+$/g, ""); + var splitUCIs = ucis.split(/[\t ]* [\t ]*/); + var valid = splitUCIs.length > 0 ? 0 : 1; //1= error, 0=true + while(valid == 0 && splitUCIs.length > 0) + { + var nextUCI = splitUCIs.pop(); + valid = validateUCI(nextUCI); + } + return valid; +} + function validateDecimal(num) { @@ -1998,6 +2028,14 @@ function proofreadMultipleHosts(input) { proofreadText(input, validateMultipleHosts, 0); } +function proofreadUCI(input) +{ + proofreadText(input, validateUCI, 0); +} +function proofreadMultipleUCIs(input) +{ + proofreadText(input, validateMultipleUCIs, 0); +} function proofreadGroup(input) { proofreadText(input, validateGroup, 0); diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js index c966a8da4a..9693cb68f0 100644 --- a/package/gargoyle/files/www/js/device.js +++ b/package/gargoyle/files/www/js/device.js @@ -35,7 +35,7 @@ function saveChanges() if (uci.get("dhcp", host).length == 0){ uci.set("dhcp", host, null, "host"); uci.set("dhcp", host, "name", host); - uci.set("dhcp", host, "ip", 'ignore'); + //uci.set("dhcp", host, "ip", 'ignore'); } uci.set("dhcp", host, "mac", macs); } @@ -55,7 +55,7 @@ function saveChanges() if (uci.get("dhcp", host).length == 0){ uci.set("dhcp", host, null, "host"); uci.set("dhcp", host, "name", host); - uci.set("dhcp", host, "ip", 'ignore'); + //uci.set("dhcp", host, "ip", 'ignore'); } uci.set("dhcp", host, "group", group); if(groups.indexOf(group) == -1) @@ -108,6 +108,11 @@ function resetData() resetMacList(); resetGroupList(); resetDeviceList(); + + var host = document.getElementById("add_host").value = ""; + var macs = document.getElementById("add_mac").value = ""; + var group = document.getElementById("add_group").value = ""; + var devices = document.getElementById("add_device").value = ""; } @@ -126,7 +131,7 @@ function resetDeviceTable() } // create the device Table and place it into the document - var columnNames=[hosts.DevNm, "MACs", '']; + var columnNames=[deviceS.DevNm, "MACs", '']; var deviceTable=createTable(columnNames, deviceTableData, "device_table", true, false, removeDevice ); var tableContainer = document.getElementById('device_table_container'); if(tableContainer.firstChild != null) @@ -290,7 +295,8 @@ function macSelected() { if (host.value == "") { - host.value = (selectedVal.split(/,/))[0]; + var selectedHost = (selectedVal.split(/,/))[0]; + host.value = selectedHost.replace(/-| /g,"_"); } var selMac = (selectedVal.split(/,/))[1]; macs.value = (macs.value == "") ? selMac : macs.value.concat(" ", selMac); @@ -299,15 +305,11 @@ function macSelected() } -function groupSelected() -{ - document.getElementById("add_group").value = getSelectedValue("group_list"); -} - - function deviceSelected() { - document.getElementById("add_device").value = getSelectedValue("device_list"); + var selectedVal = getSelectedValue("device_list"); + var devices = document.getElementById("add_device"); + devices.value = selectedValue + " " + devices.value; } @@ -353,8 +355,6 @@ function addDeviceToGroup() var groupTable = document.getElementById('group_table_container').firstChild; var values = [group.value, devices.value, createEditButton("editGroup")]; addTableRow(groupTable,values, true, false, resetDeviceList); - addNewOption('group_list', group.value, group.value); - addOptionToSelectElement('group_list', group.value, group.value, null, document) group.value=""; devices.value=""; } @@ -364,6 +364,7 @@ function addDeviceToGroup() function editDevice() { + location.hash="#device_form"; editRow=this.parentNode.parentNode; editRow.parentNode.removeChild(editRow); document.getElementById('add_host').value = editRow.childNodes[0].firstChild.data; @@ -373,6 +374,7 @@ function editDevice() function editGroup() { + location.hash="#group_form"; editRow=this.parentNode.parentNode; editRow.parentNode.removeChild(editRow); document.getElementById('add_group').value = editRow.childNodes[0].firstChild.data; @@ -498,16 +500,16 @@ function proofReadDeviceForm() { addIds=['add_host', 'add_mac']; labelIds= ['add_host_label', 'add_mac_label']; - functions = [validateHost, validateMac]; + functions = [validateUCI, validateMultipleMacs]; returnCodes = [0,0]; visibilityIds=addIds; - errors = proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, controlDocument); + errors = proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, document); if(errors.length == 0) { // check that the host and mac are not duplicates of existing values var newHost = document.getElementById('add_host').value; var newMac = document.getElementById('add_mac').value; - var deviceTable = tableDocument.getElementById('device_table_container').firstChild; + var deviceTable = document.getElementById('device_table_container').firstChild; var currentData = getTableDataArray(deviceTable, true, false); for (cdIndex=0; cdIndex < currentData.length ; cdIndex++) { @@ -534,9 +536,9 @@ function proofReadDeviceForm() function proofReadGroupForm() { addIds=['add_group', 'add_device']; - labelIds= ['add_group_label', 'add_device_label']; - functions = [validateGroup, validateDevice]; + labelIds= ['add_group_label', 'add_known_device_label']; + functions = [validateGroup, validateMultipleUCIs]; returnCodes = [0,0]; visibilityIds=addIds; - return proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, controlDocument); + return proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, document); } diff --git a/package/gargoyle/files/www/js/quotas.js b/package/gargoyle/files/www/js/quotas.js index 18ae3900d7..56755f748c 100644 --- a/package/gargoyle/files/www/js/quotas.js +++ b/package/gargoyle/files/www/js/quotas.js @@ -163,12 +163,12 @@ function resetData() setDocumentFromUci(document, new UCIContainer(), ""); - resetMacGroupData(); + resetGroupData(); setVisibility(document); } -function resetMacGroupData() +function resetGroupData() { var select = document.getElementById("group"); var groups = deviceGroups(); @@ -186,9 +186,9 @@ function resetMacGroupData() var group = groups[gIndex]; mgVals.push(group); mgText.push(group); - } + } setAllowableSelections('group', mgVals, mgText, document) - select.disabled=false; + select.disabled = false; } } diff --git a/package/gargoyle/files/www/quotas.sh b/package/gargoyle/files/www/quotas.sh index 18c55a2cf5..7a3cbc35ee 100755 --- a/package/gargoyle/files/www/quotas.sh +++ b/package/gargoyle/files/www/quotas.sh @@ -6,7 +6,7 @@ # itself remain covered by the GPL. # See http://gargoyle-router.com/faq.html#qfoss for more information eval $( gargoyle_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.sh" -t $(uci get gargoyle.global.session_timeout) -b "$COOKIE_browser_time" ) - gargoyle_header_footer -h -s "firewall" -p "quotas" -c "internal.css" -j "table.js quotas.js" -z "quotas.js" gargoyle firewall qos_gargoyle known + gargoyle_header_footer -h -s "firewall" -p "quotas" -c "internal.css" -j "table.js quotas.js" -z "quotas.js" gargoyle firewall qos_gargoyle dhcp %> diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index ddb2f77416..30c3f1e896 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -5,7 +5,7 @@ - + diff --git a/package/gargoyle/files/www/templates/group_template b/package/gargoyle/files/www/templates/group_template index 2c90d09050..50cf0344dc 100644 --- a/package/gargoyle/files/www/templates/group_template +++ b/package/gargoyle/files/www/templates/group_template @@ -1,20 +1,16 @@ - + - + - + + - + + diff --git a/package/gargoyle/files/www/templates/static_ip_template b/package/gargoyle/files/www/templates/static_ip_template deleted file mode 100644 index d6b2ed6483..0000000000 --- a/package/gargoyle/files/www/templates/static_ip_template +++ /dev/null @@ -1,14 +0,0 @@ -
- - +   diff --git a/package/gargoyle/files/www/templates/restriction_template b/package/gargoyle/files/www/templates/restriction_template index 2859c7700f..87472bbab1 100644 --- a/package/gargoyle/files/www/templates/restriction_template +++ b/package/gargoyle/files/www/templates/restriction_template @@ -13,11 +13,16 @@
- +
<%~ HstAddr %> + + +
@@ -113,7 +118,7 @@
- + +
<%~ HstAddr %> + + +
@@ -112,7 +117,7 @@
- + - +
diff --git a/package/gargoyle/files/www/templates/restriction_template b/package/gargoyle/files/www/templates/restriction_template index 87472bbab1..917e3fc499 100644 --- a/package/gargoyle/files/www/templates/restriction_template +++ b/package/gargoyle/files/www/templates/restriction_template @@ -18,7 +18,7 @@
<%~ HstAddr %> - + diff --git a/package/gargoyle/files/www/templates/whitelist_template b/package/gargoyle/files/www/templates/whitelist_template index d379b955a2..382bedd54a 100644 --- a/package/gargoyle/files/www/templates/whitelist_template +++ b/package/gargoyle/files/www/templates/whitelist_template @@ -18,7 +18,7 @@
<%~ HstAddr %> - + diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/strings.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/strings.js index 0f7a6ddc68..5e07d8f37a 100644 --- a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/strings.js +++ b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/strings.js @@ -56,7 +56,7 @@ UI.HsNm="Hostname"; UI.HDsp="Host Display"; UI.DspHn="Display Hostnames"; UI.DspHIP="Display Host IPs"; -UI.SelGrp="Select a Group"; +UI.SelGrp="Group"; UI.never="never"; UI.disabled="disabled"; From fb0b5c927a2b9229d6e67266191f178cb9ea87f4 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sat, 19 Dec 2015 17:15:10 +1100 Subject: [PATCH 32/48] Implement Device Groups for QoS Gargoyle QoS Classification rules can now accept Device Groups --- README.md | 2 + package/gargoyle/files/www/js/common.js | 25 ++++- package/gargoyle/files/www/js/qos.js | 92 +++++++++++++------ package/gargoyle/files/www/qos_download.sh | 19 ++-- package/gargoyle/files/www/qos_upload.sh | 13 ++- .../files/www/i18n/English-EN/qos.js | 2 + package/qos-gargoyle/files/qos_gargoyle.init | 56 ++++++----- 7 files changed, 145 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index e4b0ee65be..2b2f551ab5 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ Status - Gargoyle-Firewall-Quotas-BandwidthQuotas-AppliesTo - Gargoyle-Firewall-Restrictions-AccessRestrictions-RuleAppliesTo - Gargoyle-Firewall-Restrictions-Exceptions(Whitelist)-RuleAppliesTo + - Gargoyle-Forewall-QoS(Upload)-ClassificationRules + - Gargoyle-Forewall-QoS(Download)-ClassificationRules Technical - Approx 17k in size diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 74ded91cdd..578276923c 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -952,9 +952,20 @@ function enableAssociatedField(checkbox, associatedId, defaultValue, controlDocu setElementEnabled(element, checkbox.checked, defaultValue); } -function setElementEnabled(element, enabled, defaultValue) +function enableAssociatedFields(checkbox, associatedId, defaultValue, controlDocument) { + associatedId = Array.isArray(associatedId) ? associatedId : [associatedArray]; + defaultValue = Array.isArray(defaultValue) ? defaultValue : [defaultValue]; + if (associatedId.length == defaultValue.length){ + for (index=0; index < associatedId.length; index++) + { + enableAssociatedField(checkbox, associatedId[index], defaultValue[index], controlDocument); + } + } +} +function setElementEnabled(element, enabled, defaultValue) +{ if(enabled) { element.readonly=false; @@ -1913,6 +1924,14 @@ function validateIpRange(range) return valid; } +function validateIpRangeOrGroup(range) +{ + if (range.indexOf(".") != -1) + { + return validateIpRange(range); + } + return validateGroup(range); +} function validateLengthRange(text,min,max) { @@ -2004,6 +2023,10 @@ function proofreadIpRange(input) { proofreadText(input, validateIpRange, 0); } +function proofreadIpRangeOrGroup(input) +{ + proofreadText(input, validateIpRangeOrGroup, 0); +} function proofreadMac(input) { proofreadText(input, validateMac, 0); diff --git a/package/gargoyle/files/www/js/qos.js b/package/gargoyle/files/www/js/qos.js index 8ce64cc425..b22c37cc42 100644 --- a/package/gargoyle/files/www/js/qos.js +++ b/package/gargoyle/files/www/js/qos.js @@ -5,7 +5,7 @@ * itself remain covered by the GPL. * See http://gargoyle-router.com/faq.html#qfoss for more information */ - + var qosStr=new Object; // part of i18n function saveChanges() @@ -152,7 +152,7 @@ function saveChanges() uci.set("qos_gargoyle", classId, "max_bandwidth", maxBandwidth); } - if (classData[classIndex][4] == qosStr.YES) + if (classData[classIndex][4] == qosStr.YES) { uci.set("qos_gargoyle",classId,"minRTT","Yes"); } @@ -171,7 +171,7 @@ function saveChanges() { classId = classIds[getSelectedText("default_class")]; } - else + else { classId = classIds[ ruleData[ruleIndex][1] ]; } @@ -283,7 +283,7 @@ function init_classtable() totalPercent = totalPercent + parseInt(uciOriginal.get("qos_gargoyle", classSections[classIndex], "percent_bandwidth")); } - //This array setup such that classIndex+1 = the classno (ie dclass_x, where x=classno) + //This array setup such that classIndex+1 = the classno (ie dclass_x, where x=classno) for (classIndex=0; classIndex < classSections.length; classIndex++) { var classSection = classSections[classIndex]; @@ -338,7 +338,7 @@ function bpsToKbpsString(bps) else if (bpsn < 1) { kbps = bpsn.toFixed(1) + ''; - } + } else { kbps = bpsn.toFixed(0) + ''; @@ -363,7 +363,7 @@ function update_classtable() dynamic_update = false; } } - + var tableRows=table.firstChild; var rowIndex; for (rowIndex=1; rowIndex <= classTable.length; rowIndex++) { @@ -401,7 +401,7 @@ function resetData() initializeDescriptionVisibility(uciOriginal, "qos_down_3"); initializeDescriptionVisibility(uciOriginal, "qos_down_4"); } - + uciOriginal.removeSection("gargoyle", "help"); //necessary, or we over-write the help settings when we save @@ -464,7 +464,7 @@ function resetData() } classification = uciOriginal.get("qos_gargoyle", ruleSection, "class"); - idx = parseInt(classification.match(/class_([0-9]+)/)[1])-1; + idx = parseInt(classification.match(/class_([0-9]+)/)[1])-1; ruleTableData.push( [ruleText, classTable[idx].Name, createRuleTableEditButton()] ); } @@ -535,15 +535,38 @@ function resetData() { //Run updateqosmon once to clear away any old data. setTimeout("updateqosmon()", 100); - } + } } //The default screen updater. if (timerid == null) { timerid=setInterval("updatetc()", 2500); } + + if (direction == "download") + { + resetGroupOptions("group_dest"); + document.getElementById("dest_ip").value=""; + } + else + { + resetGroupOptions("group_source"); + document.getElementById("source_ip").value=""; + } } +function groupSource() +{ + document.getElementById("source_ip").value = getSelectedValue("group_source"); + setSelectedValue("group_source", ""); +} + +function groupDest() +{ + document.getElementById("dest_ip").value = getSelectedValue("group_dest"); + setSelectedValue("group_dest", ""); +} + function qosQuotasExist() { var quotaSections = uciOriginal.getAllSectionsOfType("firewall", "quota"); @@ -648,7 +671,9 @@ function proofreadClassificationRule(controlDocument) validatePktSize = function(text){ return validateNumericRange(text, 1, 1500); }; validateCBSize = function(text){ return validateNumericRange(text, 0, 4194393); }; alwaysValid = function(text){return 0;}; - ruleValidationFunctions = [ validateIpRange, validatePortOrPortRange, validateIpRange, validatePortOrPortRange, validatePktSize, validatePktSize, alwaysValid, validateCBSize, alwaysValid ]; + var validateSource = (controlDocument.getElementById("group_source") != null) ? validateIpRangeOrGroup : validateIpRange; + var validateDest = (controlDocument.getElementById("group_dest") != null) ? validateIpRangeOrGroup : validateIpRange; + ruleValidationFunctions = [ validateSource, validatePortOrPortRange, validateDest, validatePortOrPortRange, validatePktSize, validatePktSize, alwaysValid, validateCBSize, alwaysValid ]; labelIds = new Array(); returnCodes = new Array(); toggledMatchCriteria = 0; @@ -681,6 +706,16 @@ function resetRuleControls() checkbox.checked =false; enableAssociatedField( checkbox, ruleControlIds[ruleControlIndex], ""); } + + var groupIds = ["group_source","group_dest"]; + for (index=0; index < groupIds.length; index++) + { + var element = document.getElementById(groupIds[index]); + if (element != null){ + // only half does the job for some reason ???? + setElementEnabled(element, false, ""); + } + } } function addServiceClass() @@ -1063,15 +1098,15 @@ function editClassTableRow() if (direction == "upload") {editClassWindow.document.getElementById('rttdiv').style.display = 'none';} - /* Watch the window in case the user just closes without using one of the buttons. + /* Watch the window in case the user just closes without using one of the buttons. in which case we must re-enable the class bandwidth updater */ - var timer = setInterval(function() { - if(editClassWindow.closed) { - clearInterval(timer); - updateInProgress = false; - dynamic_update=true; - } - }, 700); + var timer = setInterval(function() { + if(editClassWindow.closed) { + clearInterval(timer); + updateInProgress = false; + dynamic_update=true; + } + }, 700); editClassWindow.document.getElementById("bottom_button_container").appendChild(saveButton); @@ -1113,7 +1148,7 @@ function editClassTableRow() closeButton.onclick = function() { - clearInterval(timer); + clearInterval(timer); editClassWindow.close(); } @@ -1169,7 +1204,7 @@ function editClassTableRow() } } } - + var rowData = classTable[ editClassWindowRow.childNodes[6].firstChild.id ]; rowData.Name = editClassWindow.document.getElementById("class_name").value ; rowData.Percent = editClassWindow.document.getElementById("percent_bandwidth").value ; @@ -1184,7 +1219,7 @@ function editClassTableRow() editClassWindowRow.childNodes[4].firstChild.data = rowData.MinRTT; updateInProgress = false; - clearInterval(timer); + clearInterval(timer); editClassWindow.close(); } } @@ -1251,8 +1286,8 @@ function updatetc() } else { - /* - * NOTE: This NEEDS to be "currentWanName" variable NOT "currentWanIf" Variable!!! + /* + * NOTE: This NEEDS to be "currentWanName" variable NOT "currentWanIf" Variable!!! * If this doesn't work the problem is in gargoyle_header_footer utility, not here */ commands = commands + currentWanName; @@ -1274,7 +1309,7 @@ function updatetc() { for(i = 0; i < lines.length; i++) { - //Here the minor number of the qdisc ID is equal to class number+1 or index+2 + //Here the minor number of the qdisc ID is equal to class number+1 or index+2 var idx=parseInt(lines[i].match(/hfsc\s1:([0-9]+)/)[1])-2; var lastbytes; @@ -1319,7 +1354,7 @@ function updateqosmon() if(req.readyState == 4) { var lines = req.responseText.split("\n"); - + if (lines[0].substr(0,6) == "State:") { document.getElementById("qstate").innerHTML = lines[0]; @@ -1334,7 +1369,7 @@ function updateqosmon() for (i=0; i @@ -36,7 +36,7 @@
-

<%~ QoSAbout %> +

<%~ QoSAbout %>

@@ -80,10 +80,15 @@
- - + +
- + + + +
@@ -279,7 +284,7 @@    - +
@@ -287,7 +292,7 @@    - +
diff --git a/package/gargoyle/files/www/qos_upload.sh b/package/gargoyle/files/www/qos_upload.sh index 8f5b417e12..9861226597 100755 --- a/package/gargoyle/files/www/qos_upload.sh +++ b/package/gargoyle/files/www/qos_upload.sh @@ -6,7 +6,7 @@ # itself remain covered by the GPL. # See http://gargoyle-router.com/faq.html#qfoss for more information eval $( gargoyle_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.sh" -t $(uci get gargoyle.global.session_timeout) -b "$COOKIE_browser_time" ) - gargoyle_header_footer -h -s "firewall" -p "qosupload" -c "internal.css" -j "qos.js table.js" -z "qos.js" qos_gargoyle firewall gargoyle -i qos_gargoyle + gargoyle_header_footer -h -s "firewall" -p "qosupload" -c "internal.css" -j "qos.js table.js" -z "qos.js" qos_gargoyle firewall gargoyle dhcp -i qos_gargoyle %> From 5b866dacf1a29b8f783c19fc02a104e4e61e97ca Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 20 Dec 2015 08:36:39 +1100 Subject: [PATCH 34/48] Bugfix testAddrOverlap --- package/gargoyle/files/www/js/common.js | 44 ++++++++++++++++++------- package/gargoyle/files/www/quotas.sh | 6 ++++ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index c362a595ff..30bb438e36 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -2471,11 +2471,12 @@ function testSingleAddrOverlap(addrStr1, addrStr2) function testAddrOverlap(addrStr1, addrStr2) { - if (isGroup(addrStr1)) + var groups = deviceGroups(); + if (groups.indexOf(addrStr1) > -1) { addrStr1 = groupIPs(addrStr1).join(); } - if (isGroup(addrStr2)) + if (groups.indexOf(addrStr2) > -1) { addrStr2 = groupIPs(addrStr2).join(); } @@ -2966,15 +2967,19 @@ function groupHosts(group) function groupMacs(group) { - groupMacs = []; + var groupMacs = []; var hosts = groupHosts(group); for (hIndex = 0 ; hIndex < hosts.length; hIndex++) { var host = hosts[hIndex]; - var mac = uciOriginal.get("dhcp", host, "mac"); - if (mac.length > 0) + var uciMac = uciOriginal.get("dhcp", host, "mac"); + if (typeof uciMac === 'string') { - groupMacs = groupMacs.concat(mac); + var macs = uciMac.split(" "); + for (mIndex = 0; mIndex < macs.length; mIndex++) + { + groupMacs.push(macs[mIndex]); + } } } return groupMacs; @@ -2983,21 +2988,36 @@ function groupMacs(group) function groupIPs(group) { - var ipStr = []; + var groupIPs = []; + var macs = groupMacs(group); + var ldMacIndex = 0; var ldIpIndex = 1; for (ldIndex=0; ldIndex < leaseData.length; ldIndex++) { - var ip = leaseData[ldIndex][ldIpIndex]; - if (ip != null && ip.length > 0){ - ipStr.push(ip); + var mac = leaseData[ldIndex][ldMacIndex]; + if (typeof mac === 'string' && macs.indexOf(mac.toUpperCase()) > -1) + { + var ip = leaseData[ldIndex][ldIpIndex]; + if (ip != null && ip.length > 0){ + groupIPs.push(ip); + } } } - return ipStr; + return groupIPs; } function isGroup(group) { - return (uciOriginal.get("dhcp", group).length > 0); + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) + { // survey all of the device groups until found + var host = hosts[hIndex]; + if (uciOriginal.get("dhcp", host, "group").localeCompare(group) == 0) + { + return true; + } + } + return false; } diff --git a/package/gargoyle/files/www/quotas.sh b/package/gargoyle/files/www/quotas.sh index 7a3cbc35ee..b933177409 100755 --- a/package/gargoyle/files/www/quotas.sh +++ b/package/gargoyle/files/www/quotas.sh @@ -22,6 +22,12 @@ echo "var fullQosEnabled = false;" fi + echo ""; + echo "var leaseData = new Array();"; + if [ -e /tmp/dhcp.leases ] ; then + awk ' $0 ~ /[a-z,A-Z,0-9]+/ {print "leaseData.push([\""$2"\",\""$3"\",\""$4"\"]);"};' /tmp/dhcp.leases + fi + print_quotas %> var uci = uciOriginal.clone(); From 1c21f95c615b28969387966911ce5996c20fca36 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 10 Jan 2016 22:35:11 +1100 Subject: [PATCH 35/48] Implement Groups into Quota Edit popup --- package/gargoyle/files/www/js/common.js | 38 ++++++++++--------- package/gargoyle/files/www/js/quotas.js | 8 +++- .../files/www/templates/quotas_template | 2 +- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 30bb438e36..274a055344 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -3021,26 +3021,30 @@ function isGroup(group) } -function resetGroupOptions(selectId) +function resetGroupOptions(selectId, controlDocument) { - selectElement = document.getElementById(selectId); - var groups = deviceGroups(); - if (groups.length == 0) - { - selectElement.disabled = true; - } - else + controlDocument = controlDocument == null ? document : controlDocument; + selectElement = controlDocument.getElementById(selectId); + if (selectElement != null) { - var mgVals = [ "" ]; - var mgText = [ UI.SelGrp ]; - - for(gIndex = 0; gIndex < groups.length; gIndex++) + var groups = deviceGroups(); + if (groups.length == 0) { - var group = groups[gIndex]; - mgVals.push(group); - mgText.push(group); + selectElement.disabled = true; + } + else + { + var mgVals = [ "" ]; + var mgText = [ UI.SelGrp ]; + + for(gIndex = 0; gIndex < groups.length; gIndex++) + { + var group = groups[gIndex]; + mgVals.push(group); + mgText.push(group); + } + setAllowableSelections(selectId, mgVals, mgText, controlDocument) + selectElement.disabled = false; } - setAllowableSelections(selectId, mgVals, mgText, document) - selectElement.disabled = false; } } diff --git a/package/gargoyle/files/www/js/quotas.js b/package/gargoyle/files/www/js/quotas.js index dda6ad6222..8c65742d87 100644 --- a/package/gargoyle/files/www/js/quotas.js +++ b/package/gargoyle/files/www/js/quotas.js @@ -323,6 +323,11 @@ function setDocumentIp(ip, controlDocument) { setSelectedValue("applies_to_type", "others_individual", controlDocument); } + else if (isGroup(ip)) + { + setSelectedValue("applies_to_type", "only", controlDocument); + controlDocument.getElementById("add_ip").value = ip; + } else { setSelectedValue("applies_to_type", "only", controlDocument); @@ -1185,7 +1190,7 @@ function editQuota() closeButton.className = "default_button"; var editRow=this.parentNode.parentNode; - var editId = editRow.childNodes[rowCheckIndex].firstChild.id; + var editId = editRow.childNodes[rowCheckIndex].firstChild.id; var editIp; @@ -1263,6 +1268,7 @@ function editQuota() updateDone = true; } + resetGroupOptions("group", editQuotaWindow.document); } if(!updateDone) { diff --git a/package/gargoyle/files/www/templates/quotas_template b/package/gargoyle/files/www/templates/quotas_template index fce1984250..771f0a3963 100644 --- a/package/gargoyle/files/www/templates/quotas_template +++ b/package/gargoyle/files/www/templates/quotas_template @@ -49,7 +49,7 @@ <%~ IPorRange %> From 9540eaada63c15e08c1a1acce93ae9f0e2ef058a Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 10 Jan 2016 22:35:52 +1100 Subject: [PATCH 36/48] Implement Groups into Restrictions Edit popup --- package/gargoyle/files/www/js/restrictions.js | 8 ++++---- package/gargoyle/files/www/templates/restriction_template | 4 ++-- package/gargoyle/files/www/templates/whitelist_template | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package/gargoyle/files/www/js/restrictions.js b/package/gargoyle/files/www/js/restrictions.js index 739807ed18..3831b718c4 100644 --- a/package/gargoyle/files/www/js/restrictions.js +++ b/package/gargoyle/files/www/js/restrictions.js @@ -126,7 +126,7 @@ function resetData() setDocumentFromUci(document, new UCIContainer(), "", ruleType, rulePrefix); setVisibility(document, rulePrefix); } - resetGroupOptions("group_restriction"); + resetGroupOptions("group"); resetGroupOptions("group_exception"); document.getElementById("rule_applies_to_addr").value=""; document.getElementById("exception_applies_to_addr").value=""; @@ -135,8 +135,8 @@ function resetData() function groupRestriction() { - document.getElementById("rule_applies_to_addr").value = getSelectedValue("group_restriction"); - setSelectedValue("group_restriction", ""); + document.getElementById("rule_applies_to_addr").value = getSelectedValue("group"); + setSelectedValue("group", ""); } function groupException() @@ -386,6 +386,7 @@ function editRule() updateDone = true; } + resetGroupOptions("group", editRuleWindow.document); } if(!updateDone) { @@ -708,7 +709,6 @@ function setIpTableAndSelectFromUci(controlDocument, sourceUci, pkg, sectionId, optionValue = optionValue.replace(/[\t ]*$/, ""); var ips = optionValue.split(/[\t ]*,[\t ]*/); - var table = createTable([""], [], tableId, true, false, null, null, controlDocument); while(ips.length > 0) { diff --git a/package/gargoyle/files/www/templates/restriction_template b/package/gargoyle/files/www/templates/restriction_template index 917e3fc499..771e05f49e 100644 --- a/package/gargoyle/files/www/templates/restriction_template +++ b/package/gargoyle/files/www/templates/restriction_template @@ -19,8 +19,8 @@
<%~ HstAddr %> - +
diff --git a/package/gargoyle/files/www/templates/whitelist_template b/package/gargoyle/files/www/templates/whitelist_template index 382bedd54a..d650caa55a 100644 --- a/package/gargoyle/files/www/templates/whitelist_template +++ b/package/gargoyle/files/www/templates/whitelist_template @@ -20,7 +20,7 @@ <%~ HstAddr %> From 35718cd981f3d7580d43080a9238b05d7c151f02 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Mon, 11 Jan 2016 08:08:39 +1100 Subject: [PATCH 37/48] Implement Groups into Qos Edit popup --- package/gargoyle/files/www/js/qos.js | 60 +++++++++------------ package/gargoyle/files/www/qos_download.sh | 6 +-- package/gargoyle/files/www/qos_edit_rule.sh | 2 + package/gargoyle/files/www/qos_upload.sh | 6 +-- 4 files changed, 32 insertions(+), 42 deletions(-) diff --git a/package/gargoyle/files/www/js/qos.js b/package/gargoyle/files/www/js/qos.js index 162efc5808..7d2a020238 100644 --- a/package/gargoyle/files/www/js/qos.js +++ b/package/gargoyle/files/www/js/qos.js @@ -541,30 +541,14 @@ function resetData() //The default screen updater. if (timerid == null) { timerid=setInterval("updatetc()", 2500); } - - if (direction == "download") - { - resetGroupOptions("group_dest"); - document.getElementById("dest_ip").value=""; - } - else - { - resetGroupOptions("group_source"); - document.getElementById("source_ip").value=""; - } + resetGroupOptions("group"); + document.getElementById((direction == "download") ? "dest_ip" : "source_ip" ).value=""; } - -function groupSource() +function groupSelected(id) { - document.getElementById("source_ip").value = getSelectedValue("group_source"); - setSelectedValue("group_source", ""); -} - -function groupDest() -{ - document.getElementById("dest_ip").value = getSelectedValue("group_dest"); - setSelectedValue("group_dest", ""); + document.getElementById(id).value = getSelectedValue("group"); + setSelectedValue("group", ""); } function qosQuotasExist() @@ -671,8 +655,7 @@ function proofreadClassificationRule(controlDocument) validatePktSize = function(text){ return validateNumericRange(text, 1, 1500); }; validateCBSize = function(text){ return validateNumericRange(text, 0, 4194393); }; alwaysValid = function(text){return 0;}; - var validateSource = (controlDocument.getElementById("group_source") != null) ? validateIpRangeOrGroup : validateIpRange; - var validateDest = (controlDocument.getElementById("group_dest") != null) ? validateIpRangeOrGroup : validateIpRange; + var validateDest = (controlDocument.getElementById("group") != null) ? validateIpRangeOrGroup : validateIpRange; ruleValidationFunctions = [ validateSource, validatePortOrPortRange, validateDest, validatePortOrPortRange, validatePktSize, validatePktSize, alwaysValid, validateCBSize, alwaysValid ]; labelIds = new Array(); returnCodes = new Array(); @@ -707,15 +690,11 @@ function resetRuleControls() enableAssociatedField( checkbox, ruleControlIds[ruleControlIndex], ""); } - var groupIds = ["group_source","group_dest"]; - for (index=0; index < groupIds.length; index++) - { - var element = document.getElementById(groupIds[index]); - if (element != null){ - // only half does the job for some reason ???? - setElementEnabled(element, false, ""); - } - } + var element = document.getElementById("group"); + if (element != null) + { + setElementEnabled(element, false, ""); + } } function addServiceClass() @@ -960,10 +939,6 @@ function editRuleTableRow() } setSelectedText("classification", editRuleWindowRow.childNodes[1].firstChild.data, editRuleWindow.document); - - - - //exit & save functions closeButton.onclick = function() { @@ -1015,6 +990,19 @@ function editRuleTableRow() editRuleWindow.focus(); update_done = true; } + + container = (direction == "download") ? "dest_group_container" : "source_group_container"; + groupSpan = editRuleWindow.document.getElementById(container); + if (groupSpan != null) + { + groupSelect = editRuleWindow.document.createElement('select'); + groupSelect.id = "group"; + groupSelected = (direction == "download") ? "groupSelected('dest_ip')" : "groupSelected('source_ip')"; + groupSelect.setAttribute("onchange", groupSelected); + groupSpan.appendChild(groupSelect); + } + + resetGroupOptions("group", editRuleWindow.document); } if(update_done == false) { diff --git a/package/gargoyle/files/www/qos_download.sh b/package/gargoyle/files/www/qos_download.sh index c0dadca75e..3205c5f36e 100755 --- a/package/gargoyle/files/www/qos_download.sh +++ b/package/gargoyle/files/www/qos_download.sh @@ -80,13 +80,13 @@
- +
- +
diff --git a/package/gargoyle/files/www/qos_edit_rule.sh b/package/gargoyle/files/www/qos_edit_rule.sh index 762a8e8801..bae840810a 100755 --- a/package/gargoyle/files/www/qos_edit_rule.sh +++ b/package/gargoyle/files/www/qos_edit_rule.sh @@ -16,6 +16,7 @@ +
@@ -30,6 +31,7 @@
+
diff --git a/package/gargoyle/files/www/qos_upload.sh b/package/gargoyle/files/www/qos_upload.sh index 9861226597..f542590ee3 100755 --- a/package/gargoyle/files/www/qos_upload.sh +++ b/package/gargoyle/files/www/qos_upload.sh @@ -65,13 +65,13 @@
- +
- +
From 710d575b5d6dcb53ebe628c84d3ccdf370094fa0 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 14 Jan 2016 21:29:06 +1100 Subject: [PATCH 38/48] Replace StaticIP fieldset with Known Devices Fieldset The Known Devices fieldset can associate a host name with a MAC address and optionally assign a static IP address --- package/gargoyle/files/etc/config/gargoyle | 3 - .../files/usr/lib/gargoyle/post_lease.sh | 2 +- package/gargoyle/files/www/device.sh | 102 --- package/gargoyle/files/www/dhcp.sh | 47 +- package/gargoyle/files/www/js/device.js | 544 ------------ package/gargoyle/files/www/js/dhcp.js | 809 ++++++++++++------ .../files/www/templates/device_template | 4 +- .../files/www/templates/static_ip_template | 14 - .../files/www/i18n/English-EN/device.js | 14 - .../files/www/i18n/English-EN/dhcp.js | 12 + 10 files changed, 588 insertions(+), 963 deletions(-) delete mode 100644 package/gargoyle/files/www/device.sh delete mode 100644 package/gargoyle/files/www/js/device.js delete mode 100644 package/gargoyle/files/www/templates/static_ip_template delete mode 100644 package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js diff --git a/package/gargoyle/files/etc/config/gargoyle b/package/gargoyle/files/etc/config/gargoyle index 86d0993a22..734bd6d51a 100644 --- a/package/gargoyle/files/etc/config/gargoyle +++ b/package/gargoyle/files/etc/config/gargoyle @@ -30,7 +30,6 @@ config display display option connection 'Connection' option connection_dyndns 'Dynamic DNS' option connection_dhcp 'DHCP' - option connection_devices 'Devices' option connection_basic 'Basic' option connection_routing 'Routing' option connection_wol 'Wake on LAN' @@ -63,7 +62,6 @@ config scripts scripts option connection_dyndns 'ddns.sh' option connection_basic 'basic.sh' option connection_dhcp 'dhcp.sh' - option connection_devices 'device.sh' option connection_routing 'routing.sh' option connection_wol 'wol.sh' option system_access 'access.sh' @@ -95,7 +93,6 @@ config 100 status config 200 connection option basic '100' option dhcp '200' - option devices '220' option dyndns '300' option routing '400' option wol '500' diff --git a/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh b/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh index f5c45e92f4..2d3966e520 100755 --- a/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh +++ b/package/gargoyle/files/usr/lib/gargoyle/post_lease.sh @@ -6,7 +6,7 @@ # itself remain covered by the GPL. # See http://gargoyle-router.com/faq.html#qfoss for more information -# This script was written as part of the Device Groups implementation (see: /www/device.sh) +# This script was written as part of the Device Groups implementation (see: /www/dhcp.sh) # Know Devices may be assigned to a Group (see: uci show known.device) # An ipset is created for each Group (see: ipset list -n) # Each new dhcp lease must update the ipset (see: uci show dnsmasq.dhcp-script) diff --git a/package/gargoyle/files/www/device.sh b/package/gargoyle/files/www/device.sh deleted file mode 100644 index d192e35e70..0000000000 --- a/package/gargoyle/files/www/device.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/haserl -<% - # This program is copyright © 2008-2015 John Brown and is distributed under the terms of the GNU GPL - # version 2.0 with a special clarification/exception that permits adapting the program to - # configure proprietary "back end" software provided that all modifications to the web interface - # itself remain covered by the GPL. - # See http://gargoyle-router.com/faq.html#qfoss for more information - eval $( gargoyle_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.sh" -t $(uci get gargoyle.global.session_timeout) -b "$COOKIE_browser_time" ) - gargoyle_header_footer -h -s "connection" -p "devices" -c "internal.css" -j "table.js device.js" -z "device.js" network dhcp known - subnet=$(ifconfig br-lan | awk 'BEGIN {FS=":"}; $0 ~ /inet.addr/ {print $2}' | awk 'BEGIN {FS="."}; {print $1"\."$2"\."$3"\."}') -%> - - - - - -
- <%~ device.KnDev %> - -
- - -
-
-
- <%in templates/device_template %> -
-
- -
- <%~ KnDev %>: -
-
-
-
-
- - -
- <%~ DevGp %> - -
- - -
-
-
- <%in templates/group_template %> -
-
- -
- <%~ DevGp %>: -
-
-
-
-
- - - -
- - -
- - - - - - -<% - gargoyle_header_footer -f -s "connection" -p "devices" -%> diff --git a/package/gargoyle/files/www/dhcp.sh b/package/gargoyle/files/www/dhcp.sh index 3ee9d4cf9f..6c2bf9ffa2 100755 --- a/package/gargoyle/files/www/dhcp.sh +++ b/package/gargoyle/files/www/dhcp.sh @@ -6,7 +6,7 @@ # itself remain covered by the GPL. # See http://gargoyle-router.com/faq.html#qfoss for more information eval $( gargoyle_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.sh" -t $(uci get gargoyle.global.session_timeout) -b "$COOKIE_browser_time" ) - gargoyle_header_footer -h -s "connection" -p "dhcp" -c "internal.css" -j "table.js dhcp.js" -z "dhcp.js" network wireless dhcp firewall + gargoyle_header_footer -h -s "connection" -p "dhcp" -c "internal.css" -j "table.js dhcp.js" -z "dhcp.js" network wireless dhcp firewall known subnet=$(ifconfig br-lan | awk 'BEGIN {FS=":"}; $0 ~ /inet.addr/ {print $2}' | awk 'BEGIN {FS="."}; {print $1"\."$2"\."$3"\."}') %> @@ -89,7 +89,7 @@ for (etherIndex in etherData)
- <%~ SIPs %> + <%~ device.KnDev %>
@@ -98,28 +98,47 @@ for (etherIndex in etherData)
-
- +
+ +
-
- <%in templates/static_ip_template %> -
-
- +
+ <%in templates/device_template %>
-
- <%~ AsSIP %>: +
+ <%~ KnDev %>:
-
+
+ +
+ <%~ DevGp %> + +
+ + +
+
+
+ <%in templates/group_template %> +
+
+ +
+ <%~ DevGp %>: +
+
+
+
+
+ + diff --git a/package/gargoyle/files/www/js/device.js b/package/gargoyle/files/www/js/device.js deleted file mode 100644 index 9693cb68f0..0000000000 --- a/package/gargoyle/files/www/js/device.js +++ /dev/null @@ -1,544 +0,0 @@ -/* - * This program is copyright © 2015 John Brown and is distributed under the terms of the GNU GPL - * version 2.0 with a special clarification/exception that permits adapting the program to - * configure proprietary "back end" software provided that all modifications to the web interface - * itself remain covered by the GPL. - * See http://gargoyle-router.com/faq.html#qfoss for more information - */ - -var deviceS=new Object(); //part of i18n - -function saveChanges() -{ - //errorList = proofreadAll(); - errorList = ""; - if(errorList.length > 0) - { - errorString = errorList.join("\n") + "\n\n"+UI.ErrChanges; - alert(errorString); - } - else - { - setControlsEnabled(false, true); - - uci = uciOriginal.clone(); - uci.removeAllSectionsOfType("dhcp", "host"); - - // save Device changes - deviceTable = document.getElementById('device_table_container').firstChild; - tableData = getTableDataArray(deviceTable, true, false); - for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) - { - rowData = tableData[rowIndex]; - var host = rowData[0]; - var macs = rowData[1]; - if (uci.get("dhcp", host).length == 0){ - uci.set("dhcp", host, null, "host"); - uci.set("dhcp", host, "name", host); - //uci.set("dhcp", host, "ip", 'ignore'); - } - uci.set("dhcp", host, "mac", macs); - } - - // save Group changes - groupTable = document.getElementById('group_table_container').firstChild; - tableData = getTableDataArray(groupTable, true, false); - var groups = []; - for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) - { - rowData = tableData[rowIndex]; - var group = rowData[0]; - var devices = rowData[1].split(" "); - for(dIndex=0; dIndex < devices.length; dIndex++) - { - var host = devices[dIndex]; - if (uci.get("dhcp", host).length == 0){ - uci.set("dhcp", host, null, "host"); - uci.set("dhcp", host, "name", host); - //uci.set("dhcp", host, "ip", 'ignore'); - } - uci.set("dhcp", host, "group", group); - if(groups.indexOf(group) == -1) - { - groups.push(group); - } - } - } - - // create ipsets - var ipsetCommands = ["ipset destroy"]; // fails on ipsets with existing references - for (gIndex=0; gIndex < groups.length; gIndex++){ - ipsetCommands.push("ipset create " + groups[gIndex] + " iphash"); - } - - var commands = uci.getScriptCommands(uciOriginal) + "\n" + ipsetCommands.join("\n"); - - var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); - - var stateChangeFunction = function(req) - { - if(req.readyState == 4) - { - uciOriginal = uci.clone(); - resetData(); - setControlsEnabled(true); - //alert(req.responseText); - } - } - runAjax("POST", "utility/run_commands.sh", param, stateChangeFunction); - } -} - - -function createEditButton(onclick) -{ - var editButton = createInput("button"); - editButton.value = UI.Edit; - editButton.className="default_button"; - editButton.onclick = onclick; - return editButton; -} - - -function resetData() -{ - resetDeviceTable(); - resetGroupTable(); - - resetMacList(); - resetGroupList(); - resetDeviceList(); - - var host = document.getElementById("add_host").value = ""; - var macs = document.getElementById("add_mac").value = ""; - var group = document.getElementById("add_group").value = ""; - var devices = document.getElementById("add_device").value = ""; -} - - - -function resetDeviceTable() -{ - var deviceTableData = new Array(); - - var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); - for (hIndex=0; hIndex < hosts.length; hIndex++) - { // process the MAC's assigned to each device - var host = hosts[hIndex]; - var hostMacs = uciOriginal.get("dhcp", host, "mac"); - var macs = (hostMacs instanceof Array) ? devMacs.join(" ") : hostMacs ; - deviceTableData.push([host, macs, createEditButton(editDevice)]); - } - - // create the device Table and place it into the document - var columnNames=[deviceS.DevNm, "MACs", '']; - var deviceTable=createTable(columnNames, deviceTableData, "device_table", true, false, removeDevice ); - var tableContainer = document.getElementById('device_table_container'); - if(tableContainer.firstChild != null) - { - tableContainer.removeChild(tableContainer.firstChild); - } - tableContainer.appendChild(deviceTable); -} - - -function resetGroupTable() -{ - var groupTableData = new Array(); - - var groups = new Object(); - var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); - - for (hIndex=0; hIndex < hosts.length; hIndex++) - { // survey all of the devices and groups - var host = hosts[hIndex]; - var group = uciOriginal.get("dhcp", host, "group"); - if (group != null && group.length > 0) - { - if (groups.hasOwnProperty(group)) - { - groups[group].push(host); - } - else - { - groups[group] = [host]; - } - } - } - - for (var group in groups) - { // place each group in an array - if (groups.hasOwnProperty(group)) - { // with a list of member devices - groupTableData.push([group, groups[group].join(" "), createEditButton(editGroup)]); - } - } - - // create the group Table and place it into the document - var columnNames=[deviceS.GpNm, deviceS.DevNms, '']; - var groupTable=createTable(columnNames, groupTableData, "group_table", true, false, removeGroup ); - var tableContainer = document.getElementById('group_table_container'); - if(tableContainer.firstChild != null) - { - tableContainer.removeChild(tableContainer.firstChild); - } - tableContainer.appendChild(groupTable); -} - - - -/** -* Populates a Select id=mac_list with know MACs which have not yet been assigned -* to a Known Device. -*/ -function resetMacList() -{ - var kmMacIndex = 0; - var kmHostIndex = 2; - var knownMac = knownMacLookup(); - - var deviceTable = document.getElementById("device_table_container").firstChild; - var dtdMacIx = 1; - var deviceTableData = (deviceTable == null) ? [] : getTableDataArray(deviceTable, true, false); - var deviceMacs = ''; - for (dtdIndex=0; dtdIndex < deviceTableData.length; dtdIndex++){ - deviceMacs = deviceMacs.concat(deviceTableData[dtdIndex][dtdMacIx], ","); - } - - var hlVals = [ "" ]; - var hlText = [ deviceS.SelM ]; - for (var mac in knownMac) - { - if (knownMac.hasOwnProperty(mac)) - { - if( deviceMacs.indexOf(mac) == -1 ) - { // exclude MAC's that are already assigned to a device - var host = knownMac[mac][kmHostIndex]; - hlVals.push( host + "," + mac ); - hlText.push((host == "" || host == "*" ? mac : host ) + " " + mac); - } - } - } - - setAllowableSelections("mac_list", hlVals, hlText, document); -} - -/** -* Populates a Select id=group_list with know MACs which have not yet been assigned -* to a Known Device. -*/ -function resetGroupList() -{ - var groups = []; - var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); - for (hIndex=0; hIndex < hosts.length; hIndex++) - { // survey all of the devices and groups - var host = hosts[hIndex]; - var group = uciOriginal.get("dhcp", host, "group"); - if (group.length > 0 && groups.indexOf(group) == -1) - { - groups.push(group); - } - } - - var gpVals = [ "" ]; - var gpText = [ deviceS.SelG ]; - for (gIx = 0; gIx < groups.length; gIx++) - { - var group = groups[gIx]; - gpVals.push( group ); - gpText.push( group); - } - setAllowableSelections("group_list", gpVals, gpText, document); -} - -/** -* Populates a Select id=device_list with know MACs which have not yet been assigned -* to a Known Device. -*/ -function resetDeviceList() -{ - var gpVals = [ "" ]; - var gpText = [ deviceS.SelD ]; - - var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); - for (hIndex=0; hIndex < hosts.length; hIndex++) - { // survey all of the devices and groups - var host = hosts[hIndex]; - var group = uciOriginal.get("dhcp", host, "group"); - if (group == null || group.length == 0) - { - gpVals.push( host ); - gpText.push( host ); - } - } - setAllowableSelections("device_list", gpVals, gpText, document); -} - - -/******************************************************************************* -* Event functions -*******************************************************************************/ - - -function macSelected() -{ - var selectedVal = getSelectedValue("mac_list"); - var host = document.getElementById("add_host"); - var macs = document.getElementById("add_mac"); - if(selectedVal == "") - { - host.value = ""; - macs.value = ""; - } - else - { - if (host.value == "") - { - var selectedHost = (selectedVal.split(/,/))[0]; - host.value = selectedHost.replace(/-| /g,"_"); - } - var selMac = (selectedVal.split(/,/))[1]; - macs.value = (macs.value == "") ? selMac : macs.value.concat(" ", selMac); - setSelectedValue("mac_list", ""); - } -} - - -function deviceSelected() -{ - var selectedVal = getSelectedValue("device_list"); - var devices = document.getElementById("add_device"); - devices.value = selectedValue + " " + devices.value; -} - - - -function addDevice() -{ - errors = proofReadDeviceForm(); - if(errors.length > 0) - { - alert(errors.join("\n") + "\n\n" + deviceS.AErr); - } - else - { - var host = document.getElementById("add_host"); - var macs = document.getElementById("add_mac"); - if (host.value != null && macs.value != null) - { - var deviceTable = document.getElementById('device_table_container').firstChild; - var values = [host.value, macs.value, createEditButton("editDevice")]; - addTableRow(deviceTable, values, true, false, resetMacList); - addNewOption('device_list', host.value, host.value); - host.value = ""; - macs.value = ""; - } - } -} - - - -function addDeviceToGroup() -{ - errors = proofReadGroupForm(); - if(errors.length > 0) - { - alert(errors.join("\n") + "\n\n" + deviceS.AErr); - } - else - { - var group = document.getElementById("add_group"); - var devices = document.getElementById("add_device"); - if (group.value != null && devices.value != null) - { - var groupTable = document.getElementById('group_table_container').firstChild; - var values = [group.value, devices.value, createEditButton("editGroup")]; - addTableRow(groupTable,values, true, false, resetDeviceList); - group.value=""; - devices.value=""; - } - } -} - - -function editDevice() -{ - location.hash="#device_form"; - editRow=this.parentNode.parentNode; - editRow.parentNode.removeChild(editRow); - document.getElementById('add_host').value = editRow.childNodes[0].firstChild.data; - document.getElementById('add_mac').value = editRow.childNodes[1].firstChild.data; -} - - -function editGroup() -{ - location.hash="#group_form"; - editRow=this.parentNode.parentNode; - editRow.parentNode.removeChild(editRow); - document.getElementById('add_group').value = editRow.childNodes[0].firstChild.data; - document.getElementById('add_device').value = editRow.childNodes[1].firstChild.data; -} - - - -function removeDevice(table, row) -{ - resetMacList(); -} - - -function removeGroup(table, row) -{ - resetGroupList(); -} - - -/******************************************************************************* -* Utility functions -*******************************************************************************/ - -/** -* Returns an Object able to be used as a lookup table indexed by the MAC and -* containing an [MAC, IP, hostname] for hosts listed in /etc/ethers and -* /tmp/dhcp.leases -*/ -function knownMacLookup() -{ // gather known MACs from /etc/ethers - var knownMac = mergeEtherHost(); - var kmMacIndex = 0; - var macLookup = lookupList(knownMac, kmMacIndex); - - var ldMacIndex = 0; - var ldIpIndex = 1; - var ldHostIndex = 2; - for(ldIndex=0; ldIndex < leaseData.length; ldIndex++) - { // gather known MACs from dhcp leases - var leaseRow = leaseData[ldIndex]; - var mac = leaseRow[ldMacIndex].toUpperCase(); - if(macLookup[mac] == null) - { - macLookup[mac] = [mac, leaseRow[ldIpIndex], leaseRow[ldHostIndex]]; - } - } - return macLookup; -} - - -/** -* Returns an Array of Arrays containing [mac, ip, host] generated by -* combining /etc/hosts with /etc/ethers -*/ -function mergeEtherHost() -{ - var hdIpIndex = 0; - var hdHostIndex = 1; - var hostLookup = lookupList(hostData, hdIpIndex); - - var mhdMacIndex = 0; - var mhdIpIndex = 1; - var mhdHostIndex = 2; - var macHostData = etherData.slice(); - for(var mhdIndex=0; mhdIndex < macHostData.length; mhdIndex++) - { - var host = null; - var mhdRow = macHostData[mhdIndex]; - mhdRow[mhdMacIndex] = mhdRow[mhdMacIndex].toUpperCase(); - var ip = mhdRow[mhdIpIndex]; - var hdRow = hostLookup[ ip ]; - if (hdRow instanceof Array) - { - host = hdRow[hdHostIndex] ; - } - mhdRow[mhdHostIndex] = (host == null) ? "?" : host ; - } - return macHostData; -} - - -/** -* Returns an Object able to be used as a Lookup table on the elements of the -* supplied data[][], indexed by the data[][field]. -* data: an Array of Arrays -* field: the index of a field in the inner array to be used as the lookup index. -*/ -function lookupList(data, field){ - var lookup = new Object(); - var index=0; - for(index=0; index < data.length; index++) - { - var key = (data[index][field]); - lookup[key] = data[index]; - } - return lookup; -} - - -function addNewOption(selectId, optionText, optionValue) -{ - var options = document.getElementById(selectId).options; - var exists = false; - for(oIndex=0; oIndex < options.length; oIndex++) - { - exists = exists | (options[oIndex].text == optionText); - } - if (!exists) - { - addOptionToSelectElement(selectId, optionText, optionValue, null, document) - } -} - -/****************************************************************************** -* Validation functions -******************************************************************************/ - -/** -* Checks for invalid or duplicate host names and MACs -*/ -function proofReadDeviceForm() -{ - addIds=['add_host', 'add_mac']; - labelIds= ['add_host_label', 'add_mac_label']; - functions = [validateUCI, validateMultipleMacs]; - returnCodes = [0,0]; - visibilityIds=addIds; - errors = proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, document); - - if(errors.length == 0) - { // check that the host and mac are not duplicates of existing values - var newHost = document.getElementById('add_host').value; - var newMac = document.getElementById('add_mac').value; - var deviceTable = document.getElementById('device_table_container').firstChild; - var currentData = getTableDataArray(deviceTable, true, false); - for (cdIndex=0; cdIndex < currentData.length ; cdIndex++) - { - var rowData = currentData[cdIndex]; - var oldHost = rowData[0]; - var oldMac = rowData[1]; - if(oldHost != '' && oldHost != '-' && oldHost == newHost) - { - errors.push(dhcpS.dHErr); - } - if(oldMac == newMac) - { - errors.push(dhcpS.dMErr); - } - } - } - return errors; -} - - -/** -* Checks for invalid host or group names -*/ -function proofReadGroupForm() -{ - addIds=['add_group', 'add_device']; - labelIds= ['add_group_label', 'add_known_device_label']; - functions = [validateGroup, validateMultipleUCIs]; - returnCodes = [0,0]; - visibilityIds=addIds; - return proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, document); -} diff --git a/package/gargoyle/files/www/js/dhcp.js b/package/gargoyle/files/www/js/dhcp.js index 35bad6d661..ee72d7353e 100644 --- a/package/gargoyle/files/www/js/dhcp.js +++ b/package/gargoyle/files/www/js/dhcp.js @@ -1,8 +1,8 @@ /* - * This program is copyright © 2008-2013 Eric Bishop and is distributed under the terms of the GNU GPL - * version 2.0 with a special clarification/exception that permits adapting the program to + * This program is copyright © 2015 John Brown and is distributed under the terms of the GNU GPL + * version 2.0 with a special clarification/exception that permits adapting the program to * configure proprietary "back end" software provided that all modifications to the web interface - * itself remain covered by the GPL. + * itself remain covered by the GPL. * See http://gargoyle-router.com/faq.html#qfoss for more information */ @@ -10,7 +10,7 @@ var dhcpS=new Object(); //part of i18n function saveChanges() { - errorList = proofreadAll(); + errorList = proofreadDhcpForm(); if(errorList.length > 0) { errorString = errorList.join("\n") + "\n\n"+UI.ErrChanges; @@ -19,8 +19,9 @@ function saveChanges() else { setControlsEnabled(false, true); - uci = uciOriginal.clone(); + + // save dhcp changes uci.remove('dhcp', dhcpSection, 'ignore'); uci.set('dhcp', dhcpSection, 'interface', 'lan'); dhcpIds = ['dhcp_start', ['dhcp_start','dhcp_end'], 'dhcp_lease']; @@ -28,12 +29,12 @@ function saveChanges() dhcpPkgs = ['dhcp','dhcp','dhcp']; dhcpSections = [dhcpSection,dhcpSection,dhcpSection]; dhcpOptions = ['start', 'limit', 'leasetime']; - + dhcpFunctions = [setVariableFromValue, setVariableFromCombined, setVariableFromModifiedValue]; limitParams = [false, function(values){ return (parseInt(values[1]) - parseInt(values[0]) + 1); }]; leaseParams = [false, function(value){ return value + "h"; }]; - dhcpParams = [false, limitParams,leaseParams]; - + dhcpParams = [false, limitParams,leaseParams]; + setVariables(dhcpIds, dhcpVisIds, uci, dhcpPkgs, dhcpSections, dhcpOptions, dhcpFunctions, dhcpParams); dhcpWillBeEnabled = true; @@ -46,32 +47,57 @@ function saveChanges() uci.set("dhcp", "lan", "ignore", "1"); dhcpWillBeEnabled = false; } - - - staticIpTable = document.getElementById('staticip_table_container').firstChild; - tableData = getTableDataArray(staticIpTable, true, false); - - createEtherCommands = [ "touch /etc/ethers", "rm /etc/ethers" ]; - staticIpTableData = new Array(); - for (rowIndex in tableData) + + // save Device changes + uci.removeAllSectionsOfType("dhcp", "host"); + deviceTable = document.getElementById('device_table_container').firstChild; + tableData = getTableDataArray(deviceTable, true, false); + for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) { rowData = tableData[rowIndex]; - createEtherCommands.push("echo \"" + rowData[1].toLowerCase() + "\t" + rowData[2] + "\" >> /etc/ethers"); - staticIpTableData.push( [ rowData[0], rowData[1], rowData[2] ] ); - if(rowData[0] != '-') - { - ipHostHash[ rowData[2] ] = rowData[0]; + var host = rowData[0]; + var macs = rowData[1]; + var ip = rowData[2]; + if (uci.get("dhcp", host).length == 0){ + uci.set("dhcp", host, null, "host"); + uci.set("dhcp", host, "name", host); } + uci.set("dhcp", host, "mac", macs); + uci.set("dhcp", host, "ip", ip); } - - createHostCommands = [ "touch /etc/hosts", "rm /etc/hosts" ]; - for (ip in ipHostHash) + // save Group changes + groupTable = document.getElementById('group_table_container').firstChild; + tableData = getTableDataArray(groupTable, true, false); + var groups = []; + for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) { - host= ipHostHash[ip]; - createHostCommands.push("echo \"" + ip + "\t" + host + "\" >> /etc/hosts"); + rowData = tableData[rowIndex]; + var group = rowData[0]; + var devices = rowData[1].split(" "); + for(dIndex=0; dIndex < devices.length; dIndex++) + { + var host = devices[dIndex]; + if (uci.get("dhcp", host).length == 0){ + uci.set("dhcp", host, null, "host"); + uci.set("dhcp", host, "name", host); + //uci.set("dhcp", host, "ip", 'ignore'); + } + uci.set("dhcp", host, "group", group); + if(groups.indexOf(group) == -1) + { + groups.push(group); + } + } } + // create ipsets + var ipsetCommands = ["ipset destroy"]; // fails on ipsets with existing references + for (gIndex=0; gIndex < groups.length; gIndex++){ + ipsetCommands.push("ipset create " + groups[gIndex] + " iphash"); + } + + // save blockMismatches changes var firewallCommands = []; var firewallDefaultSections = uci.getAllSectionsOfType("firewall", "defaults"); var oldBlockMismatches = uciOriginal.get("firewall", firewallDefaultSections[0], "block_static_ip_mismatches") == "1" ? true : false; @@ -79,7 +105,7 @@ function saveChanges() if(newBlockMismatches != oldBlockMismatches) { if(newBlockMismatches) - { + { uci.set("firewall", firewallDefaultSections[0], "block_static_ip_mismatches", "1"); firewallCommands.push("uci set firewall.@defaults[0].block_static_ip_mismatches=1"); } @@ -91,14 +117,10 @@ function saveChanges() firewallCommands.push("uci commit"); } - //need to restart firewall here because for add/remove of static ips, we need to restart bandwidth monitor, as well as for firewall commands above if we have any - var restartDhcpCommand = "\n/etc/init.d/dnsmasq restart ; \nsh /usr/lib/gargoyle/restart_firewall.sh\n" ; - - commands = uci.getScriptCommands(uciOriginal) + "\n" + createEtherCommands.join("\n") + "\n" + createHostCommands.join("\n") + "\n" + firewallCommands.join("\n") + "\n" + restartDhcpCommand ; - - //document.getElementById("output").value = commands; + var restartDhcpCommand = "\n/etc/init.d/dnsmasq restart ; \nsh /usr/lib/gargoyle/restart_firewall.sh\n" ; + commands = uci.getScriptCommands(uciOriginal) + "\n" + ipsetCommands.join("\n") + "\n" + firewallCommands.join("\n") + "\n" + restartDhcpCommand ; var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); @@ -118,137 +140,276 @@ function saveChanges() } } -function createEditButton() + +function createEditButton(onclick) { var editButton = createInput("button"); editButton.value = UI.Edit; editButton.className="default_button"; - editButton.onclick = editStatic; + editButton.onclick = onclick; return editButton; } + function resetData() { - dhcpEnabled = uciOriginal.get("dhcp", "lan", "ignore") == "1" ? false : true; - var rowIndex=0; - for(rowIndex=0; rowIndex < staticIpTableData.length ; rowIndex++) + resetDhcp(); + + var firewallDefaultSections = uciOriginal.getAllSectionsOfType("firewall", "defaults"); + var blockMismatches = uciOriginal.get("firewall", firewallDefaultSections[0], "block_static_ip_mismatches") == "1" ? true : false; + document.getElementById("block_mismatches").checked = blockMismatches; + + resetDeviceTable(); + resetGroupTable(); + + resetMacList(); + resetGroupList(); + resetDeviceList(); + + setEnabled(document.getElementById('dhcp_enabled').checked); + + var host = document.getElementById("add_host").value = ""; + var macs = document.getElementById("add_mac").value = ""; + var group = document.getElementById("add_group").value = ""; + var devices = document.getElementById("add_device").value = ""; +} + +function resetDhcp() +{ + dhcpEnabled = uciOriginal.get("dhcp", "lan", "ignore") == "1" ? false : true; + dhcpIds = ['dhcp_start', 'dhcp_end', 'dhcp_lease']; + dhcpPkgs = ['dhcp',['dhcp','dhcp'],'dhcp']; + dhcpSections = [dhcpSection,[dhcpSection,dhcpSection],dhcpSection]; + dhcpOptions = ['start', ['start','limit'], 'leasetime']; + + enabledTest = function(value){return value != 1;}; + endCombineFunc= function(values) { return (parseInt(values[0])+parseInt(values[1])-1); }; + leaseModFunc = function(value) + { + var leaseHourValue; + if(value.match(/.*h/)) + { + leaseHourValue=value.substr(0,value.length-1); + } + else if(value.match(/.*m/)) + { + leaseHourValue=value.substr(0,value.length-1)/(60); + } + else if(value.match(/.*s/)) + { + leaseHourValue=value.substr(0,value.length-1)/(60*60); + } + return leaseHourValue; + }; + + dhcpParams = [100, [endCombineFunc,150],[12,leaseModFunc]]; + dhcpFunctions = [loadValueFromVariable, loadValueFromMultipleVariables, loadValueFromModifiedVariable]; + + loadVariables(uciOriginal, dhcpIds, dhcpPkgs, dhcpSections, dhcpOptions, dhcpParams, dhcpFunctions); + + document.getElementById("dhcp_enabled").checked = dhcpEnabled; +} + +function resetDeviceTable() +{ + var deviceTableData = new Array(); + + // process uci dhcp hosts + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + var uciMacs = []; + for (hIndex=0; hIndex < hosts.length; hIndex++) + { // process the MAC's assigned to each device + var host = hosts[hIndex]; + var macs = uciOriginal.get("dhcp", host, "mac"); + var ip = uciOriginal.get("dhcp", host, "ip"); + ip = ip == null ? "" : ip; + deviceTableData.push([host, macs, ip, createEditButton(editDevice)]); + uciMacs = uciMacs.concat(macs.split(" ")); + } + + // process /etc/hosts & /etc/ethers + var etherMap = map(etherData); + var hostMap = map(hostData); + for (mac in etherMap) { - var rowData = staticIpTableData[rowIndex]; - rowData.push(createEditButton()); - staticIpTableData[rowIndex] = rowData; + ucMAC = mac.toUpperCase(); + if (etherMap.hasOwnProperty(mac) && uciMacs.indexOf(ucMAC) == -1) + { + ip = etherMap[mac][0]; + host = (hostMap.hasOwnProperty(ip)) ? hostMap[ip][0] : ""; + deviceTableData.push([host, ucMAC, ip, createEditButton(editDevice)]); + } } - columnNames=[UI.HsNm, 'MAC', 'IP', '']; - staticIpTable=createTable(columnNames, staticIpTableData, "static_ip_table", true, false, removeStaticIp ); - tableContainer = document.getElementById('staticip_table_container'); + + // create the device Table and place it into the document + var columnNames=[dhcpS.DevNm, "MACs", dhcpS.StcIP, '']; + var deviceTable=createTable(columnNames, deviceTableData, "device_table", true, false, removeDevice ); + var tableContainer = document.getElementById('device_table_container'); if(tableContainer.firstChild != null) { tableContainer.removeChild(tableContainer.firstChild); } - tableContainer.appendChild(staticIpTable); + tableContainer.appendChild(deviceTable); +} - dhcpIds = ['dhcp_start', 'dhcp_end', 'dhcp_lease']; - dhcpPkgs = ['dhcp',['dhcp','dhcp'],'dhcp']; - dhcpSections = [dhcpSection,[dhcpSection,dhcpSection],dhcpSection]; - dhcpOptions = ['start', ['start','limit'], 'leasetime']; - - enabledTest = function(value){return value != 1;}; - endCombineFunc= function(values) { return (parseInt(values[0])+parseInt(values[1])-1); }; - leaseModFunc = function(value) +function map(data) +{ + var map = new Object(); + if (data instanceof Array) { - var leaseHourValue; - if(value.match(/.*h/)) - { - leaseHourValue=value.substr(0,value.length-1); - } - else if(value.match(/.*m/)) + for (i=0; i 0) + { + if (groups.hasOwnProperty(group)) + { + groups[group].push(host); + } + else + { + groups[group] = [host]; + } + } + } + for (var group in groups) + { // place each group in an array + if (groups.hasOwnProperty(group)) + { // with a list of member devices + groupTableData.push([group, groups[group].join(" "), createEditButton(editGroup)]); + } + } - //setup hostname/mac list - resetHostnameMacList(); + // create the group Table and place it into the document + var columnNames=[dhcpS.GpNm, dhcpS.DevNms, '']; + var groupTable=createTable(columnNames, groupTableData, "group_table", true, false, removeGroup ); + var tableContainer = document.getElementById('group_table_container'); + if(tableContainer.firstChild != null) + { + tableContainer.removeChild(tableContainer.firstChild); + } + tableContainer.appendChild(groupTable); } -function removeStaticIp(table, row) -{ - var removedIp = row.childNodes[2].firstChild.data - delete ipHostHash[removedIp] - resetHostnameMacList() -} -function resetHostnameMacList() +/** +* Populates a Select id=mac_list with know MACs which have not yet been assigned +* to a Known Device. +*/ +function resetMacList() { - var staticTable = document.getElementById("staticip_table_container").firstChild; - var staticTableData = staticTable == null ? [] : getTableDataArray(staticTable, true, false); - var staticMacs = []; - var staticIndex=0; - for(staticIndex=0; staticIndex < staticTableData.length; staticIndex++) - { - var mac = (staticTableData[staticIndex][1]).toUpperCase(); - staticMacs[ mac ] = 1; + var kmMacIndex = 0; + var kmHostIndex = 2; + var knownMac = knownMacLookup(); + + var deviceTable = document.getElementById("device_table_container").firstChild; + var dtdMacIx = 1; + var deviceTableData = (deviceTable == null) ? [] : getTableDataArray(deviceTable, true, false); + var deviceMacs = ''; + for (dtdIndex=0; dtdIndex < deviceTableData.length; dtdIndex++){ + deviceMacs = deviceMacs.concat(deviceTableData[dtdIndex][dtdMacIx], ","); } - var hmVals = [ "none" ]; - var hmText = [ dhcpS.SelH ]; - var leaseIndex = 0; - for(leaseIndex=0; leaseIndex < leaseData.length; leaseIndex++) + var hlVals = [ "" ]; + var hlText = [ dhcpS.SelM ]; + for (var mac in knownMac) { - var lease = leaseData[leaseIndex]; - var mac = (lease[0]).toUpperCase(); - if( staticMacs[ mac ] == null ) + if (knownMac.hasOwnProperty(mac)) { - hmVals.push( lease[2] + "," + mac ); - hmText.push( (lease[2] == "" || lease[2] == "*" ? lease[1] : lease[2] ) + " (" + mac + ")" ); + if( deviceMacs.indexOf(mac) == -1 ) + { // exclude MAC's that are already assigned to a device + var host = knownMac[mac][kmHostIndex]; + hlVals.push( host + "," + mac ); + hlText.push((host == "" || host == "*" ? mac : host ) + " " + mac); + } } } - setAllowableSelections("static_from_connected", hmVals, hmText); - - var hmEnabled = hmText.length > 1 && document.getElementById('dhcp_enabled').checked ? true : false; - setElementEnabled(document.getElementById("static_from_connected"), hmEnabled, "none"); + setAllowableSelections("mac_list", hlVals, hlText, document); } +/** +* Populates a Select id=group_list with know MACs which have not yet been assigned +* to a Known Device. +*/ +function resetGroupList() +{ + var groups = []; + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) + { // survey all of the devices and groups + var host = hosts[hIndex]; + var group = uciOriginal.get("dhcp", host, "group"); + if (group.length > 0 && groups.indexOf(group) == -1) + { + groups.push(group); + } + } + var gpVals = [ "" ]; + var gpText = [ dhcpS.SelG ]; + for (gIx = 0; gIx < groups.length; gIx++) + { + var group = groups[gIx]; + gpVals.push( group ); + gpText.push( group); + } + setAllowableSelections("group_list", gpVals, gpText, document); +} -function staticFromConnected() +/** +* Populates a Select id=device_list with know MACs which have not yet been assigned +* to a Known Device. +*/ +function resetDeviceList() { - var selectedVal = getSelectedValue("static_from_connected"); - if(selectedVal != "none") - { - var host = (selectedVal.split(/,/))[0]; - var mac = (selectedVal.split(/,/))[1]; - document.getElementById("add_host").value = host; - document.getElementById("add_mac").value = mac; - setSelectedValue("static_from_connected", "none"); + var gpVals = [ "" ]; + var gpText = [ dhcpS.SelD ]; + + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); + for (hIndex=0; hIndex < hosts.length; hIndex++) + { // survey all of the devices and groups + var host = hosts[hIndex]; + var group = uciOriginal.get("dhcp", host, "group"); + if (group == null || group.length == 0) + { + gpVals.push( host ); + gpText.push( host ); + } } + setAllowableSelections("device_list", gpVals, gpText, document); } function setEnabled(enabled) { - var ids=['dhcp_start', 'dhcp_end', 'dhcp_lease', 'block_mismatches', 'add_host', 'add_mac', 'add_ip', 'add_button']; + var ids=['dhcp_start', 'dhcp_end', 'dhcp_lease', 'block_mismatches', 'add_host', 'add_mac', 'add_ip', 'add_device_button', 'mac_list', 'add_group', 'add_device', 'add_device_to_group_button', 'device_list']; var idIndex; for (idIndex in ids) { @@ -256,96 +417,296 @@ function setEnabled(enabled) setElementEnabled(element, enabled, ""); } - var staticIpTable = document.getElementById('staticip_table_container').firstChild; - setRowClasses(staticIpTable, enabled); - - resetHostnameMacList(); + var deviceTable = document.getElementById('device_table_container').firstChild; + setRowClasses(deviceTable, enabled); + resetDeviceList(); - + var groupTable = document.getElementById('group_table_container').firstChild; + setRowClasses(groupTable, enabled); + resetGroupList(); } -function addStatic() + + +/******************************************************************************* +* Event functions +*******************************************************************************/ + + +function macSelected() { - errors = proofreadStatic(document); + var selectedVal = getSelectedValue("mac_list"); + var host = document.getElementById("add_host"); + var macs = document.getElementById("add_mac"); + if(selectedVal == "") + { + host.value = ""; + macs.value = ""; + } + else + { + if (host.value == "") + { + var selectedHost = (selectedVal.split(/,/))[0]; + host.value = selectedHost.replace(/-| /g,"_"); + } + var selMac = (selectedVal.split(/,/))[1]; + macs.value = (macs.value == "") ? selMac : macs.value.concat(" ", selMac); + setSelectedValue("mac_list", ""); + } +} + + +function deviceSelected() +{ + var selectedVal = getSelectedValue("device_list"); + var devices = document.getElementById("add_device"); + devices.value = selectedValue + " " + devices.value; +} + + + +function addDevice() +{ + errors = proofReadDeviceForm(); if(errors.length > 0) { alert(errors.join("\n") + "\n\n" + dhcpS.AErr); } else { - values = new Array(); - ids = ['add_host', 'add_mac', 'add_ip']; - for (idIndex in ids) + var host = document.getElementById("add_host"); + var macs = document.getElementById("add_mac"); + var ip = document.getElementById("add_ip"); + if (host.value != null && macs.value != null) { - v = document.getElementById(ids[idIndex]).value; - v = v== '' ? '-' : v; - values.push(v); - document.getElementById(ids[idIndex]).value = ""; + var deviceTable = document.getElementById('device_table_container').firstChild; + var values = [host.value, macs.value, ip.value, createEditButton("editDevice")]; + addTableRow(deviceTable, values, true, false, resetMacList); + addNewOption('device_list', host.value, host.value); + host.value = ""; + macs.value = ""; + ip.value = ""; } - values.push(createEditButton()); - staticIpTable = document.getElementById('staticip_table_container').firstChild; - addTableRow(staticIpTable,values, true, false, resetHostnameMacList); - resetHostnameMacList(); } } -function proofreadStatic(controlDocument, tableDocument, excludeRow) + + +function addDeviceToGroup() { - controlDocument = controlDocument == null ? document : controlDocument; - tableDocument = tableDocument == null ? document : tableDocument; - - addIds=['add_mac', 'add_ip']; - labelIds= ['add_mac_label', 'add_ip_label']; - functions = [validateMac, validateIP]; - returnCodes = [0,0]; - visibilityIds=addIds; - errors = proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, controlDocument); - if(errors.length == 0) + errors = proofReadGroupForm(); + if(errors.length > 0) + { + alert(errors.join("\n") + "\n\n" + dhcpS.AErr); + } + else { - var staticIpTable = tableDocument.getElementById('staticip_table_container').firstChild; - var currentData = getTableDataArray(staticIpTable, true, false); - var rowDataIndex = 0; - for (rowDataIndex=0; rowDataIndex < currentData.length ; rowDataIndex++) + var group = document.getElementById("add_group"); + var devices = document.getElementById("add_device"); + if (group.value != null && devices.value != null) { - if(staticIpTable.rows[rowDataIndex+1] != excludeRow) - { - rowData = currentData[rowDataIndex]; - if(rowData[0] != '' && rowData[0] != '-' && rowData[0] == controlDocument.getElementById('add_host').value) - { - errors.push(dhcpS.dHErr); - } - if(rowData[1] == controlDocument.getElementById('add_mac').value) - { - errors.push(dhcpS.dMErr); - } - if(rowData[2] == controlDocument.getElementById('add_ip').value) - { - errors.push(dhcpS.dIPErr); - } - } + var groupTable = document.getElementById('group_table_container').firstChild; + var values = [group.value, devices.value, createEditButton("editGroup")]; + addTableRow(groupTable,values, true, false, resetDeviceList); + group.value=""; + devices.value=""; } } - if(errors.length == 0) - { - var dhcpSection = getDhcpSection(uciOriginal); - var mask = uciOriginal.get("network", "lan", "netmask"); - var ip = uciOriginal.get("network", "lan", "ipaddr"); - var testIp = controlDocument.getElementById('add_ip').value; - var testEnd = parseInt( (testIp.split("."))[3] ); +} + + +function editDevice() +{ + location.hash="#device_form"; + editRow=this.parentNode.parentNode; + editRow.parentNode.removeChild(editRow); + document.getElementById('add_host').value = editRow.childNodes[0].firstChild.data; + document.getElementById('add_mac').value = editRow.childNodes[1].firstChild.data; + document.getElementById('add_ip').value = editRow.childNodes[2].firstChild.data; +} + + +function editGroup() +{ + location.hash="#group_form"; + editRow=this.parentNode.parentNode; + editRow.parentNode.removeChild(editRow); + document.getElementById('add_group').value = editRow.childNodes[0].firstChild.data; + document.getElementById('add_device').value = editRow.childNodes[1].firstChild.data; +} + + + +function removeDevice(table, row) +{ + resetMacList(); +} + - if(!rangeInSubnet(mask, ip, testEnd, testEnd)) +function removeGroup(table, row) +{ + resetGroupList(); +} + + +/******************************************************************************* +* Utility functions +*******************************************************************************/ + +/** +* Returns an Object able to be used as a lookup table indexed by the MAC and +* containing an [MAC, IP, hostname] for hosts listed in /etc/ethers and +* /tmp/dhcp.leases +*/ +function knownMacLookup() +{ // gather known MACs from /etc/ethers + var knownMac = mergeEtherHost(); + var kmMacIndex = 0; + var macLookup = lookupList(knownMac, kmMacIndex); + + var ldMacIndex = 0; + var ldIpIndex = 1; + var ldHostIndex = 2; + for(ldIndex=0; ldIndex < leaseData.length; ldIndex++) + { // gather known MACs from dhcp leases + var leaseRow = leaseData[ldIndex]; + var mac = leaseRow[ldMacIndex].toUpperCase(); + if(macLookup[mac] == null) { - errors.push(dhcpS.subErr); + macLookup[mac] = [mac, leaseRow[ldIpIndex], leaseRow[ldHostIndex]]; } - if(ip == testIp) + } + return macLookup; +} + + +/** +* Returns an Array of Arrays containing [mac, ip, host] generated by +* combining /etc/hosts with /etc/ethers +*/ +function mergeEtherHost() +{ + var hdIpIndex = 0; + var hdHostIndex = 1; + var hostLookup = lookupList(hostData, hdIpIndex); + + var mhdMacIndex = 0; + var mhdIpIndex = 1; + var mhdHostIndex = 2; + var macHostData = etherData.slice(); + for(var mhdIndex=0; mhdIndex < macHostData.length; mhdIndex++) + { + var host = null; + var mhdRow = macHostData[mhdIndex]; + mhdRow[mhdMacIndex] = mhdRow[mhdMacIndex].toUpperCase(); + var ip = mhdRow[mhdIpIndex]; + var hdRow = hostLookup[ ip ]; + if (hdRow instanceof Array) { - errors.push(dhcpS.ipErr); - } + host = hdRow[hdHostIndex] ; + } + mhdRow[mhdHostIndex] = (host == null) ? "?" : host ; + } + return macHostData; +} + + +/** +* Returns an Object able to be used as a Lookup table on the elements of the +* supplied data[][], indexed by the data[][field]. +* data: an Array of Arrays +* field: the index of a field in the inner array to be used as the lookup index. +*/ +function lookupList(data, field){ + var lookup = new Object(); + var index=0; + for(index=0; index < data.length; index++) + { + var key = (data[index][field]); + lookup[key] = data[index]; + } + return lookup; +} + + +function addNewOption(selectId, optionText, optionValue) +{ + var options = document.getElementById(selectId).options; + var exists = false; + for(oIndex=0; oIndex < options.length; oIndex++) + { + exists = exists | (options[oIndex].text == optionText); + } + if (!exists) + { + addOptionToSelectElement(selectId, optionText, optionValue, null, document) + } +} + +/****************************************************************************** +* Validation functions +******************************************************************************/ + +/** +* Checks for invalid or duplicate host names and MACs +*/ +function proofReadDeviceForm() +{ + addIds=['add_host', 'add_mac']; + labelIds= ['add_host_label', 'add_mac_label']; + functions = [validateUCI, validateMultipleMacs]; + returnCodes = [0,0]; + ip = document.getElementById('add_host').value.length; + if (ip != null && ip.length > 0) + { + addIds.push('add_ip'); + labelIds.push('add_ip_label'); + functions.push(validateIP); + returnCodes.push(0); + } + visibilityIds=addIds; + errors = proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, document); + + if(errors.length == 0) + { // check that the host and mac are not duplicates of existing values + var newHost = document.getElementById('add_host').value; + var newMac = document.getElementById('add_mac').value; + var deviceTable = document.getElementById('device_table_container').firstChild; + var currentData = getTableDataArray(deviceTable, true, false); + for (cdIndex=0; cdIndex < currentData.length ; cdIndex++) + { + var rowData = currentData[cdIndex]; + var oldHost = rowData[0]; + var oldMac = rowData[1]; + if(oldHost != '' && oldHost != '-' && oldHost == newHost) + { + errors.push(dhcpS.dHErr); + } + if(oldMac == newMac) + { + errors.push(dhcpS.dMErr); + } + } } return errors; } -function proofreadAll() + +/** +* Checks for invalid host or group names +*/ +function proofReadGroupForm() +{ + addIds=['add_group', 'add_device']; + labelIds= ['add_group_label', 'add_known_device_label']; + functions = [validateGroup, validateMultipleUCIs]; + returnCodes = [0,0]; + visibilityIds=addIds; + return proofreadFields(addIds, labelIds, functions, returnCodes, visibilityIds, document); +} + +function proofreadDhcpForm() { dhcpIds = ['dhcp_start', 'dhcp_end', 'dhcp_lease']; labelIds= ['dhcp_start_label', 'dhcp_end_label', 'dhcp_lease_label']; @@ -366,7 +727,7 @@ function proofreadAll() { errors.push(dhcpS.dsubErr); } - + var ipEnd = parseInt( (ip.split("."))[3] ); if(ipEnd >= start && ipEnd <= end) { @@ -376,95 +737,3 @@ function proofreadAll() return errors; } - -function editStatic() -{ - if( typeof(editStaticWindow) != "undefined" ) - { - //opera keeps object around after - //window is closed, so we need to deal - //with error condition - try - { - editStaticWindow.close(); - } - catch(e){} - } - - - try - { - xCoor = window.screenX + 225; - yCoor = window.screenY+ 225; - } - catch(e) - { - xCoor = window.left + 225; - yCoor = window.top + 225; - } - - - editStaticWindow = window.open("static_ip_edit.sh", "edit", "width=560,height=180,left=" + xCoor + ",top=" + yCoor ); - - saveButton = createInput("button", editStaticWindow.document); - closeButton = createInput("button", editStaticWindow.document); - saveButton.value = UI.CApplyChanges; - saveButton.className = "default_button"; - closeButton.value = UI.CDiscardChanges; - closeButton.className = "default_button"; - - editRow=this.parentNode.parentNode; - - runOnEditorLoaded = function () - { - updateDone=false; - if(editStaticWindow.document != null) - { - if(editStaticWindow.document.getElementById("bottom_button_container") != null) - { - editStaticWindow.document.getElementById("bottom_button_container").appendChild(saveButton); - editStaticWindow.document.getElementById("bottom_button_container").appendChild(closeButton); - - //set edit values - editStaticWindow.document.getElementById("add_host").value = editRow.childNodes[0].firstChild.data; - editStaticWindow.document.getElementById("add_mac").value = editRow.childNodes[1].firstChild.data; - editStaticWindow.document.getElementById("add_ip").value = editRow.childNodes[2].firstChild.data; - editStaticWindow.document.getElementById("add_button").style.display="none"; - closeButton.onclick = function() - { - editStaticWindow.close(); - } - saveButton.onclick = function() - { - // error checking goes here - var errors = proofreadStatic(editStaticWindow.document, document, editRow); - if(errors.length > 0) - { - alert(errors.join("\n") + "\n"+dhcpS.upErr); - } - else - { - //update document with new data - editRow.childNodes[0].firstChild.data = editStaticWindow.document.getElementById("add_host").value; - editRow.childNodes[1].firstChild.data = editStaticWindow.document.getElementById("add_mac").value; - editRow.childNodes[2].firstChild.data = editStaticWindow.document.getElementById("add_ip").value; - - editStaticWindow.close(); - - resetHostnameMacList(); - - } - } - editStaticWindow.moveTo(xCoor,yCoor); - editStaticWindow.focus(); - updateDone = true; - } - } - if(!updateDone) - { - setTimeout( "runOnEditorLoaded()", 250); - } - } - runOnEditorLoaded(); -} - diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index 30c3f1e896..5140b6d483 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -2,11 +2,13 @@
- - - - - - - - - - - - -

(<%~ dhcp.opt %>)
diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js deleted file mode 100644 index 6255cb90ff..0000000000 --- a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/device.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * UTF-8 (with BOM) English-EN text strings for device.sh html elements - */ - -deviceS.KnDev="Known Devices"; -deviceS.AdKnDev="Add Known Device"; -deviceS.AdGp="Add Group"; -deviceS.GpNm="Group name"; -deviceS.DevNm="Device name"; -deviceS.DevNms="Device names"; -deviceS.EdKnDev="Edit Device"; -deviceS.DevGp="Device Groups"; -deviceS.SelM="Include MAC"; -deviceS.SelD="Include Device"; diff --git a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/dhcp.js b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/dhcp.js index 07b150454a..c31eb060a0 100644 --- a/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/dhcp.js +++ b/package/plugin-gargoyle-i18n-English-EN/files/www/i18n/English-EN/dhcp.js @@ -23,3 +23,15 @@ dhcpS.dsubErr="Specified DHCP range falls outside LAN subnet."; dhcpS.dipErr="Specified DHCP range contains current LAN IP."; dhcpS.upErr="Could not update static IP."; dhcpS.AErr="Could not add row."; + +dhcpS.KnDev="Known Devices"; +dhcpS.AdKnDev="Add Known Device"; +dhcpS.AdGp="Add Group"; +dhcpS.GpNm="Group name"; +dhcpS.DevNm="Device name"; +dhcpS.DevNms="Device names"; +dhcpS.EdKnDev="Edit Device"; +dhcpS.DevGp="Device Groups"; +dhcpS.SelM="Include MAC"; +dhcpS.SelD="Include Device"; +dhcpS.StcIP="Static IP"; From 44d6498218b960eea224a3cb72fa70f72447d07d Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 14 Jan 2016 22:47:08 +1100 Subject: [PATCH 39/48] Bugfix typo --- package/gargoyle/files/www/dhcp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/gargoyle/files/www/dhcp.sh b/package/gargoyle/files/www/dhcp.sh index 6c2bf9ffa2..cafc22a959 100755 --- a/package/gargoyle/files/www/dhcp.sh +++ b/package/gargoyle/files/www/dhcp.sh @@ -89,7 +89,7 @@ for (etherIndex in etherData)
- <%~ device.KnDev %> + <%~ KnDev %>
From 6747567a08567611da2628f35ce81e83e11027da Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 15 Jan 2016 11:47:05 +1100 Subject: [PATCH 40/48] Remove redundant entries from hosts and ethers The Known Devices table is populated with entries from uci and from /etc/ethers & /etc/hosts. When the user Saves Changes then all devices are saved into uci and /etc/ethers & /etc/hosts are recreated without redundant entries. --- package/gargoyle/files/www/js/dhcp.js | 109 +++++++++++++++++--------- 1 file changed, 70 insertions(+), 39 deletions(-) diff --git a/package/gargoyle/files/www/js/dhcp.js b/package/gargoyle/files/www/js/dhcp.js index ee72d7353e..b4233c9c3a 100644 --- a/package/gargoyle/files/www/js/dhcp.js +++ b/package/gargoyle/files/www/js/dhcp.js @@ -48,8 +48,10 @@ function saveChanges() dhcpWillBeEnabled = false; } - // save Device changes + // save Device changes to uci uci.removeAllSectionsOfType("dhcp", "host"); + var etherMap = map(etherData, 0); + var hostMap = map(hostData, 0); deviceTable = document.getElementById('device_table_container').firstChild; tableData = getTableDataArray(deviceTable, true, false); for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) @@ -64,6 +66,42 @@ function saveChanges() } uci.set("dhcp", host, "mac", macs); uci.set("dhcp", host, "ip", ip); + + // remove devices moved to uci from /etc/ethers & /etc/hosts + var macList = macs.split("\t"); + for (mIndex = 0; mIndex < macList.length; mIndex++) + { + uciMac = macList[mIndex]; + if (etherMap.hasOwnProperty(uciMac)) + { + etherIP = etherMap[uciMac][1]; + delete etherMap[uciMac]; + if (hostMap.hasOwnProperty(etherIP)) + { + delete hostMap[etherIP]; + } + } + } + } + + // recreate /etc/ethers without redundant entries + createEtherCommands = [ "touch /etc/ethers", "rm /etc/ethers" ]; + for (mac in etherMap) + { + if (etherMap.hasOwnProperty(mac)) + { + createEtherCommands.push("echo \"" + mac.toLowerCase() + "\t" + etherMap[mac][1] + "\" >> /etc/ethers"); + } + } + + // recreate /etc/hosts without redundant entries + createHostCommands = [ "touch /etc/hosts", "rm /etc/hosts" ]; + for (ip in hostMap) + { + if (hostMap.hasOwnProperty(ip)) + { + createHostCommands.push("echo \"" + ip + "\t" + hostMap[ip][1] + "\" >> /etc/hosts"); + } } // save Group changes @@ -117,10 +155,14 @@ function saveChanges() firewallCommands.push("uci commit"); } - //need to restart firewall here because for add/remove of static ips, we need to restart bandwidth monitor, as well as for firewall commands above if we have any - var restartDhcpCommand = "\n/etc/init.d/dnsmasq restart ; \nsh /usr/lib/gargoyle/restart_firewall.sh\n" ; + commands = uci.getScriptCommands(uciOriginal) + "\n"; + commands += ipsetCommands.join("\n") + "\n"; + commands += createEtherCommands.join("\n") + "\n"; + commands += createHostCommands.join("\n") + "\n"; + commands += firewallCommands.join("\n") + "\n"; - commands = uci.getScriptCommands(uciOriginal) + "\n" + ipsetCommands.join("\n") + "\n" + firewallCommands.join("\n") + "\n" + restartDhcpCommand ; + //need to restart firewall here because for add/remove of static ips, we need to restart bandwidth monitor, as well as for firewall commands above if we have any + commands += "\n/etc/init.d/dnsmasq restart ; \nsh /usr/lib/gargoyle/restart_firewall.sh\n" ; var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); @@ -228,15 +270,15 @@ function resetDeviceTable() } // process /etc/hosts & /etc/ethers - var etherMap = map(etherData); - var hostMap = map(hostData); + var etherMap = map(etherData, 0); + var hostMap = map(hostData, 0); for (mac in etherMap) { ucMAC = mac.toUpperCase(); if (etherMap.hasOwnProperty(mac) && uciMacs.indexOf(ucMAC) == -1) { - ip = etherMap[mac][0]; - host = (hostMap.hasOwnProperty(ip)) ? hostMap[ip][0] : ""; + ip = etherMap[mac][1]; + host = (hostMap.hasOwnProperty(ip)) ? hostMap[ip][1] : ""; deviceTableData.push([host, ucMAC, ip, createEditButton(editDevice)]); } } @@ -253,25 +295,6 @@ function resetDeviceTable() } -function map(data) -{ - var map = new Object(); - if (data instanceof Array) - { - for (i=0; i Date: Wed, 20 Jan 2016 13:19:07 +1100 Subject: [PATCH 41/48] Add a UCI dnsmasq networkid for each Device Group An OpenWRT patch is backported to "Allow UCI dhcp classifier to accept a list of MAC" https://patchwork.ozlabs.org/patch/569678/ Recording each Device Group additionally as a uci dhcp mac classifier enables the utilization of the dnsmasq --dhcp-option and makes 3 functions in common.js redundant. https://wiki.openwrt.org/doc/uci/dhcp#classifying_clients_and_assigning_individual_options http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html --- package/gargoyle/files/www/js/common.js | 62 ++------------------- package/gargoyle/files/www/js/dhcp.js | 31 ++++++----- package/gargoyle/files/www/js/quotas.js | 2 +- patches-generic/120_uci_dhcp_mac_list.patch | 16 ++++++ 4 files changed, 39 insertions(+), 72 deletions(-) create mode 100644 patches-generic/120_uci_dhcp_mac_list.patch diff --git a/package/gargoyle/files/www/js/common.js b/package/gargoyle/files/www/js/common.js index 274a055344..6ecd59a73a 100644 --- a/package/gargoyle/files/www/js/common.js +++ b/package/gargoyle/files/www/js/common.js @@ -2290,7 +2290,8 @@ function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, ta var addr = data[rowIndex][0]; if (validateGroup(addr) == 0) { - allCurrentMacs.push(groupMacs(addr)); + var groupMacs = uciOriginal("dhcp", addr, "mac"); + allCurrentMacs.push(groupMacs); } else if(validateMac(addr) == 0) { @@ -2471,7 +2472,7 @@ function testSingleAddrOverlap(addrStr1, addrStr2) function testAddrOverlap(addrStr1, addrStr2) { - var groups = deviceGroups(); + var groups = uciOriginal.getAllSectionsOfType("dhcp", "mac"); if (groups.indexOf(addrStr1) > -1) { addrStr1 = groupIPs(addrStr1).join(); @@ -2930,24 +2931,6 @@ function ObjLen(an_obj) return len } - -function deviceGroups() -{ - // get a list of Device Groups from uci - var groups = []; - var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); - for (hIndex=0; hIndex < hosts.length; hIndex++) - { // survey all of the devices and groups - var host = hosts[hIndex]; - var group = uciOriginal.get("dhcp", host, "group"); - if (group.length > 0 && groups.indexOf(group) == -1) - { - groups.push(group); - } - } - return groups; -} - function groupHosts(group) { var groupHosts = []; @@ -2965,31 +2948,10 @@ function groupHosts(group) } -function groupMacs(group) -{ - var groupMacs = []; - var hosts = groupHosts(group); - for (hIndex = 0 ; hIndex < hosts.length; hIndex++) - { - var host = hosts[hIndex]; - var uciMac = uciOriginal.get("dhcp", host, "mac"); - if (typeof uciMac === 'string') - { - var macs = uciMac.split(" "); - for (mIndex = 0; mIndex < macs.length; mIndex++) - { - groupMacs.push(macs[mIndex]); - } - } - } - return groupMacs; -} - - function groupIPs(group) { var groupIPs = []; - var macs = groupMacs(group); + var macs = uciOriginal("dhcp", group, "mac"); var ldMacIndex = 0; var ldIpIndex = 1; for (ldIndex=0; ldIndex < leaseData.length; ldIndex++) @@ -3006,20 +2968,6 @@ function groupIPs(group) return groupIPs; } -function isGroup(group) -{ - var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); - for (hIndex=0; hIndex < hosts.length; hIndex++) - { // survey all of the device groups until found - var host = hosts[hIndex]; - if (uciOriginal.get("dhcp", host, "group").localeCompare(group) == 0) - { - return true; - } - } - return false; -} - function resetGroupOptions(selectId, controlDocument) { @@ -3027,7 +2975,7 @@ function resetGroupOptions(selectId, controlDocument) selectElement = controlDocument.getElementById(selectId); if (selectElement != null) { - var groups = deviceGroups(); + var groups = uciOriginal.getAllSectionsOfType("dhcp", "mac"); if (groups.length == 0) { selectElement.disabled = true; diff --git a/package/gargoyle/files/www/js/dhcp.js b/package/gargoyle/files/www/js/dhcp.js index b4233c9c3a..ee3dd2233c 100644 --- a/package/gargoyle/files/www/js/dhcp.js +++ b/package/gargoyle/files/www/js/dhcp.js @@ -52,6 +52,7 @@ function saveChanges() uci.removeAllSectionsOfType("dhcp", "host"); var etherMap = map(etherData, 0); var hostMap = map(hostData, 0); + var macMap = new Object(); deviceTable = document.getElementById('device_table_container').firstChild; tableData = getTableDataArray(deviceTable, true, false); for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) @@ -66,6 +67,7 @@ function saveChanges() } uci.set("dhcp", host, "mac", macs); uci.set("dhcp", host, "ip", ip); + macMap[host]=macs; // remove devices moved to uci from /etc/ethers & /etc/hosts var macList = macs.split("\t"); @@ -105,34 +107,35 @@ function saveChanges() } // save Group changes + uci.removeAllSectionsOfType("dhcp", "mac"); + var ipsetCommands = ["ipset destroy"]; // fails on ipsets with existing references + groupTable = document.getElementById('group_table_container').firstChild; tableData = getTableDataArray(groupTable, true, false); - var groups = []; for (rowIndex = 0; rowIndex < tableData.length; rowIndex++) { rowData = tableData[rowIndex]; var group = rowData[0]; var devices = rowData[1].split(" "); + + if (uci.get("dhcp", group).length == 0){ + uci.set("dhcp", group, null, "mac"); + uci.set("dhcp", group, "networkid", group); + } + for(dIndex=0; dIndex < devices.length; dIndex++) { var host = devices[dIndex]; - if (uci.get("dhcp", host).length == 0){ - uci.set("dhcp", host, null, "host"); - uci.set("dhcp", host, "name", host); - //uci.set("dhcp", host, "ip", 'ignore'); - } - uci.set("dhcp", host, "group", group); - if(groups.indexOf(group) == -1) + var macs = macMap[host].split(" "); + for (mIndex=0; mIndex < macs.length; mIndex++) { - groups.push(group); + uci.set("dhcp", group, "mac", macs[mIndex[]); } +- uci.set("dhcp", host, "group", group); } - } - // create ipsets - var ipsetCommands = ["ipset destroy"]; // fails on ipsets with existing references - for (gIndex=0; gIndex < groups.length; gIndex++){ - ipsetCommands.push("ipset create " + groups[gIndex] + " iphash"); + // create ipset + ipsetCommands.push("ipset create " + group + " iphash"); } // save blockMismatches changes diff --git a/package/gargoyle/files/www/js/quotas.js b/package/gargoyle/files/www/js/quotas.js index 8c65742d87..d42eef4a51 100644 --- a/package/gargoyle/files/www/js/quotas.js +++ b/package/gargoyle/files/www/js/quotas.js @@ -323,7 +323,7 @@ function setDocumentIp(ip, controlDocument) { setSelectedValue("applies_to_type", "others_individual", controlDocument); } - else if (isGroup(ip)) + else if (uci.get("dhcp", ip).length > 0) { setSelectedValue("applies_to_type", "only", controlDocument); controlDocument.getElementById("add_ip").value = ip; diff --git a/patches-generic/120_uci_dhcp_mac_list.patch b/patches-generic/120_uci_dhcp_mac_list.patch new file mode 100644 index 0000000000..3db187654a --- /dev/null +++ b/patches-generic/120_uci_dhcp_mac_list.patch @@ -0,0 +1,16 @@ +--- a/package/network/services/dnsmasq/files/dnsmasq.init ++++ b/package/network/services/dnsmasq/files/dnsmasq.init +@@ -363,7 +363,9 @@ dhcp_mac_add() { + config_get mac "$cfg" mac + [ -n "$mac" ] || return 0 + +- xappend "--dhcp-mac=$networkid,$mac" ++ for o in $mac; do ++ xappend "--dhcp-mac=$networkid,$mac" ++ done + + dhcp_option_add "$cfg" "$networkid" + } +-- +2.5.0 + From 432750301a56a8ae745156f29cfb388774d5571e Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Fri, 22 Jan 2016 20:28:24 +1100 Subject: [PATCH 42/48] Retrieve WOL candidates from uci Potential Wake On Lan hosts are now drawn from the uci system first before drawing from arp, dhcp.leases and ethers --- package/gargoyle/files/www/js/wol.js | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/package/gargoyle/files/www/js/wol.js b/package/gargoyle/files/www/js/wol.js index 86ce4891a0..0b541a079c 100644 --- a/package/gargoyle/files/www/js/wol.js +++ b/package/gargoyle/files/www/js/wol.js @@ -5,7 +5,7 @@ * itself remain covered by the GPL. * See http://gargoyle-router.com/faq.html#qfoss for more information */ - + var wolS=new Object(); //part of i18n function initWolTable() @@ -16,26 +16,39 @@ function initWolTable() initializeDescriptionVisibility(uciOriginal, "wol_help"); // set description visibility uciOriginal.removeSection("gargoyle", "help"); // necessary, or we overwrite the help settings when we save - arpLines.shift(); // skip header + var hosts = uciOriginal.getAllSectionsOfType("dhcp", "host"); var lineIndex = 0; + for(lineIndex=0; lineIndex < hosts.length; lineIndex++) + { + var host = hosts[lineIndex]; + var ip = uciOriginal.get("dhcp", host, "ip"); + var mac = uciOriginal.get("dhcp", host, "mac"); + dataList.push( [ host, ip, mac, createWakeUpButton() ] ); + ipToHostAndMac[ip] = 1; + } + + arpLines.shift(); // skip header for(lineIndex=0; lineIndex < arpLines.length; lineIndex++) { var nextLine = arpLines[lineIndex]; var splitLine = nextLine.split(/[\t ]+/); - var mac = splitLine[3].toUpperCase(); var ip = splitLine[0]; - dataList.push( [ getHostname(ip), ip, mac, createWakeUpButton() ] ); - ipToHostAndMac[ip] = 1; + if(ipToHostAndMac[ip] == null) + { + var mac = splitLine[3].toUpperCase(); + dataList.push( [ getHostname(ip), ip, mac, createWakeUpButton() ] ); + ipToHostAndMac[ip] = 1; + } } for(lineIndex=0; lineIndex < dhcpLeaseLines.length; lineIndex++) { var leaseLine = dhcpLeaseLines[lineIndex]; var splitLease = leaseLine.split(/[\t ]+/); - var mac = splitLease[1].toUpperCase(); var ip = splitLease[2]; if(ipToHostAndMac[ip] == null) { + var mac = splitLease[1].toUpperCase(); dataList.push( [ getHostname(ip), ip, mac, createWakeUpButton() ] ); ipToHostAndMac[ip] = 1; } @@ -44,10 +57,10 @@ function initWolTable() for(lineIndex=0; lineIndex < etherData.length; lineIndex++) { var ether = etherData[lineIndex]; - var mac = ether[0].toUpperCase(); var ip = ether[1]; if(ipToHostAndMac[ip] == null) { + var mac = ether[0].toUpperCase(); dataList.push( [ getHostname(ip), ip, mac, createWakeUpButton() ] ); ipToHostAndMac[ip] = 1; } From 8cfc235a0d31fef7a3f6d59b9cfa642f2499d755 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 24 Jan 2016 08:36:32 +1100 Subject: [PATCH 43/48] Bugfix typo --- package/gargoyle/files/www/js/dhcp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/gargoyle/files/www/js/dhcp.js b/package/gargoyle/files/www/js/dhcp.js index b14e4f6062..4248c7bea4 100644 --- a/package/gargoyle/files/www/js/dhcp.js +++ b/package/gargoyle/files/www/js/dhcp.js @@ -129,7 +129,7 @@ function saveChanges() var macs = macMap[host].split(" "); for (mIndex=0; mIndex < macs.length; mIndex++) { - uci.set("dhcp", group, "mac", macs[mIndex[]); + uci.set("dhcp", group, "mac", macs[mIndex]); } - uci.set("dhcp", host, "group", group); } From 2e8c85b3854bcef0c4f20e98f39738aa39132322 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 24 Jan 2016 13:44:58 +1100 Subject: [PATCH 44/48] Bugfix typo --- package/gargoyle/files/www/js/dhcp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/gargoyle/files/www/js/dhcp.js b/package/gargoyle/files/www/js/dhcp.js index 4248c7bea4..baa51d8d00 100644 --- a/package/gargoyle/files/www/js/dhcp.js +++ b/package/gargoyle/files/www/js/dhcp.js @@ -131,7 +131,7 @@ function saveChanges() { uci.set("dhcp", group, "mac", macs[mIndex]); } -- uci.set("dhcp", host, "group", group); + uci.set("dhcp", host, "group", group); } // create ipset From 96a139986a8f821397441acf6e6e751ed5a45a9e Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Wed, 27 Jan 2016 06:51:48 +1100 Subject: [PATCH 45/48] French Translations for Known Devices & Groups Thank you lyrz --- .../files/www/i18n/French-FR/dhcp.js | 12 ++++++++++++ .../files/www/i18n/French-FR/qos.js | 2 ++ .../files/www/i18n/French-FR/quotas.js | 2 +- .../files/www/i18n/French-FR/restrictions.js | 2 +- .../files/www/i18n/French-FR/strings.js | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/dhcp.js b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/dhcp.js index 4140e6b84a..e05a87d5f2 100644 --- a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/dhcp.js +++ b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/dhcp.js @@ -23,3 +23,15 @@ dhcpS.dsubErr="La plage DHCP spécifiée est en dehors du sous-réseau LAN."; dhcpS.dipErr="La plage DHCP spécifiée content l'IP du LAN."; dhcpS.upErr="Impossible de mettre à jour l'IP statique."; dhcpS.AErr="Impossible d'ajouter une colonne."; + +dhcpS.KnDev="Equipements connus"; +dhcpS.AdKnDev="Ajouter un équipement connu"; +dhcpS.AdGp="Ajouter un groupe"; +dhcpS.GpNm="Nom du groupe"; +dhcpS.DevNm="Nom de l'équipement"; +dhcpS.DevNms="Noms des équipements"; +dhcpS.EdKnDev="Editer l'équipement"; +dhcpS.DevGp="Groupes d'équipement"; +dhcpS.SelM="Inclure l'adresse MAC"; +dhcpS.SelD="Inclure l'équipement"; +dhcpS.StcIP="IP statique"; diff --git a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/qos.js b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/qos.js index a575b80319..ef74daf479 100644 --- a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/qos.js +++ b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/qos.js @@ -32,8 +32,10 @@ qosStr.ServClass="Classe de service par défaut"; qosStr.AddNewClassRule="Ajouter nouvelle règle de classement"; qosStr.AddNewServiceRule="Ajouter nouvelle classe de service"; qosStr.SrcIP="IP source"; +qosStr.SrcIPor="IP source ou groupe"; qosStr.SrcPort="Port(s) source"; qosStr.DstIP="IP de destination"; +qosStr.DstIPor="IP destination ou groupe"; qosStr.DstPort="Port(s) de destination"; qosStr.MaxPktLen="longueur de paquet maximum"; qosStr.MinPktLen="longueur de paquet minimum"; diff --git a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/quotas.js b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/quotas.js index e630e66a7a..79d5e27b4c 100644 --- a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/quotas.js +++ b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/quotas.js @@ -32,7 +32,7 @@ quotasStr.QLocalNet="Tout le réseau local"; quotasStr.QOnlyHosts="Seulement les hôte(s) suivant(s)"; quotasStr.HostsWithoutQuotas="Tous les hôtes individuels sans quota explicite"; quotasStr.ComboHostsWithoutQuotas="Tous les hôtes individuels sans quota explicite (Combiné)"; -quotasStr.IPorRange="Spécifier une IP ou plage IP"; +quotasStr.IPorRange="Spécifier une IP ou plage IP, ou"; quotasStr.MaxUp="Max Upload"; quotasStr.MaxDown="Max Download"; quotasStr.MaxUpDown="Max Total Up+Down"; diff --git a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/restrictions.js b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/restrictions.js index 7c4b414825..db5e22bf1d 100644 --- a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/restrictions.js +++ b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/restrictions.js @@ -19,7 +19,7 @@ restStr.RAppl="La règle s'applique à"; restStr.AHsts="Tous les hôtes"; restStr.EHsts="Tous les hôtes excepté"; restStr.OHsts="Seulement aux hôtes suivants"; -restStr.HstAddr="Spécifier une IP, plage IP ou adresse MAC"; +restStr.HstAddr="Spécifier une IP, plage IP, adresse MAC ou"; restStr.Schd="Planifier"; restStr.ADay="Par jour"; restStr.EDay="Tous les jours de la semaine"; diff --git a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/strings.js b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/strings.js index ab9977815e..6e86f758b5 100644 --- a/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/strings.js +++ b/package/plugin-gargoyle-i18n-French-FR/files/www/i18n/French-FR/strings.js @@ -56,6 +56,7 @@ UI.HsNm="Nom hôte"; UI.HDsp="Affichage hôte"; UI.DspHn="Afficher les noms d'hôte"; UI.DspHIP="Afficher les IP des hôtes"; +UI.SelGrp="Groupe"; UI.never="jamais"; UI.disabled="désactivé"; From eb8d43770afa718dcbf6bef447642a1082887326 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Tue, 9 Feb 2016 07:44:53 +1100 Subject: [PATCH 46/48] Show valid characters for Device and Group names The restiction on the Device and Group names are different (based on uci and ipset respectively) and a little confusing so it is important to guide the user. --- package/gargoyle/files/www/templates/device_template | 2 +- package/gargoyle/files/www/templates/group_template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/gargoyle/files/www/templates/device_template b/package/gargoyle/files/www/templates/device_template index 5140b6d483..e8a9bd83c2 100644 --- a/package/gargoyle/files/www/templates/device_template +++ b/package/gargoyle/files/www/templates/device_template @@ -6,7 +6,7 @@ - + diff --git a/package/gargoyle/files/www/templates/group_template b/package/gargoyle/files/www/templates/group_template index 50cf0344dc..4ce44fff12 100644 --- a/package/gargoyle/files/www/templates/group_template +++ b/package/gargoyle/files/www/templates/group_template @@ -5,7 +5,7 @@ - + From 256923fa62677ce8b33fc73e1b9c5e5a28811420 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Thu, 11 Feb 2016 12:23:06 +1100 Subject: [PATCH 47/48] Simplified Chinese Translations for Known Devices & Groups thank you ericwong --- .../files/www/i18n/SimplifiedChinese-ZH-CN/dhcp.js | 12 ++++++++++++ .../files/www/i18n/SimplifiedChinese-ZH-CN/qos.js | 2 ++ .../files/www/i18n/SimplifiedChinese-ZH-CN/quotas.js | 2 +- .../www/i18n/SimplifiedChinese-ZH-CN/restrictions.js | 2 +- .../www/i18n/SimplifiedChinese-ZH-CN/strings.js | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/dhcp.js b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/dhcp.js index c7d32a6c1d..5eaec60ffb 100644 --- a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/dhcp.js +++ b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/dhcp.js @@ -23,3 +23,15 @@ dhcpS.dsubErr="指定的DHCP范围超出LAN子网。"; dhcpS.dipErr="指定DHCP范围包含当前的LAN IP。"; dhcpS.upErr="无法更新静态IP。"; dhcpS.AErr="无法添加行。"; + +dhcpS.KnDev=“已知设备”; +dhcpS.AdKnDev=“添加已知设备”; +dhcpS.AdGp=“添加组”; +dhcpS.GpNm=“组名”; +dhcpS.DevNm=“设备名称”; +dhcpS.DevNms=“设备名称”; +dhcpS.EdInDex=“编辑设备”; +dhcpS.DevGp=“设备组”; +dhcpS.SelM=“包括MAC”; +dhcpS.SelD=“包括设备”; +dhcpS.StcIP=“静态IP”; diff --git a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/qos.js b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/qos.js index 4715cb27f1..eda24206c8 100644 --- a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/qos.js +++ b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/qos.js @@ -32,8 +32,10 @@ qosStr.ServClass="默认服务类型"; qosStr.AddNewClassRule="添加新的分类规则"; qosStr.AddNewServiceRule="添加新的服务类型"; qosStr.SrcIP="来源IP"; +qosStr.SrcIPor=“源IP或组”; qosStr.SrcPort="来源端口(或范围)"; qosStr.DstIP="目标IP"; +qosStr.DstIPor=“目标IP或组”; qosStr.DstPort="目标端口(或范围)"; qosStr.MaxPktLen="最大包长"; qosStr.MinPktLen="最小包长"; diff --git a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/quotas.js b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/quotas.js index c938050f1d..610cccb0bd 100644 --- a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/quotas.js +++ b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/quotas.js @@ -32,7 +32,7 @@ quotasStr.QLocalNet="整个本地网络"; quotasStr.QOnlyHosts="只有下列主机"; quotasStr.HostsWithoutQuotas="所有没有明确配额的独立主机"; quotasStr.ComboHostsWithoutQuotas="所有没有明确配额的主机(合并)"; -quotasStr.IPorRange="指定IP或IP范围"; +quotasStr.IPorRange=“指定IP或IP范围,或”; quotasStr.MaxUp="最大上传"; quotasStr.MaxDown="最大下载"; quotasStr.MaxUpDown="最大总量"; diff --git a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/restrictions.js b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/restrictions.js index 539e9154d6..e22b4cdd7d 100644 --- a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/restrictions.js +++ b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/restrictions.js @@ -19,7 +19,7 @@ restStr.RAppl="规则应用到"; restStr.AHsts="所有主机"; restStr.EHsts="除以下外的所有主机"; restStr.OHsts="仅以下主机"; -restStr.HstAddr="指定IP,IP范围或MAC地址"; +restStr.HstAddr="指定IP,IP范围,MAC或"; restStr.Schd="计划表"; restStr.ADay="全日"; restStr.EDay="每天"; diff --git a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/strings.js b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/strings.js index e79c56cde4..f862d7a90f 100644 --- a/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/strings.js +++ b/package/plugin-gargoyle-i18n-SimplifiedChinese-ZH-CN/files/www/i18n/SimplifiedChinese-ZH-CN/strings.js @@ -56,6 +56,7 @@ UI.HsNm="主机名"; UI.HDsp="主机显示"; UI.DspHn="显示主机名"; UI.DspHIP="显示主机IP"; +UI.SelGrp=“组”; UI.never="从不"; UI.disabled="禁用"; From 6e1bb82b6a2597848ccd795890a22d0c79c9e812 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sun, 6 Mar 2016 08:58:21 +1100 Subject: [PATCH 48/48] Bugfix save known device group Corrected and strengthened saveChanges() to handle whitespace properly and reject unknown host names --- package/gargoyle/files/www/js/dhcp.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/package/gargoyle/files/www/js/dhcp.js b/package/gargoyle/files/www/js/dhcp.js index bf6dbbb154..4a4de3b0b6 100644 --- a/package/gargoyle/files/www/js/dhcp.js +++ b/package/gargoyle/files/www/js/dhcp.js @@ -127,12 +127,15 @@ function saveChanges() for(dIndex=0; dIndex < devices.length; dIndex++) { var host = devices[dIndex]; - var macs = macMap[host].split(" "); - for (mIndex=0; mIndex < macs.length; mIndex++) + if(macMap.hasOwnProperty(host)) { - uci.set("dhcp", group, "mac", macs[mIndex]); + var macs = macMap[host].split(" "); + for (mIndex=0; mIndex < macs.length; mIndex++) + { + uci.set("dhcp", group, "mac", macs[mIndex]); + } + uci.set("dhcp", host, "group", group); } - uci.set("dhcp", host, "group", group); } // create ipset