Comcast Business SMCD3G Port Forward Autoconfig

Easily/Automatically create port forwards, without having to sit and wait for each change to apply. Created to while diagnosing an issue with SMCD3G that caused it to forgets all configured port forwards, which seems to be a common problem for some xfinity customers as well.

Versión del día 27/3/2017. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Comcast Business SMCD3G Port Forward Autoconfig
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  Easily/Automatically create port forwards, without having to sit and wait for each change to apply. Created to while diagnosing an issue with SMCD3G that caused it to forgets all configured port forwards, which seems to be a common problem for some xfinity customers as well. 
// @author       [email protected]
// @include      /https?:\/\/10\.\d{1,3}\.\d{1,3}\.\d{1,3}\/user/\index\.asp/
// @grant        none
// ==/UserScript==

// [ "Application Name", Public port start, Public port end, Internal port Start, "Protocall", "Forward IP"]
var Ports = [
    ["HTTP",        80,80,80,'TCP','10.0.0.12'],
    ["HTTPS",        443,443,443,'TCP','10.0.0.12'],
    ["IKEv2-NAT-T", 4500,4500,4500,'UDP','10.0.0.12'],
    ["IPSEC-IKE",        500,500,500,'UDP','10.0.0.12'],
    ["IPSEC-ESP",        50,50,50,'ESP','10.0.0.12'],
    ["SSH",        2222,2222,22,'TCP','10.0.0.12'],
];


function dbg(txt) {
    console.log(txt);
}

function getElementByXpath(path,element=document) {
  return document.evaluate(path, element, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
function getElementsByXpath(xpath, parent=document)
{
  let results = [];
  let query = document.evaluate(xpath,
      parent,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  for (let i=0, length=query.snapshotLength; i<length; ++i) {
    results.push(query.snapshotItem(i));
  }
  return results;
}
function SelectOptionByText(selectList,val) {// class = ffSelectWrapper
    dbg("Got Select List");
    dbg(selectList);
    for (var i=0;i<selectList.options.length;i++) {
        dbg("Scanning option " + selectList.options[i].value.trim() + " with id " + i + " for option " + val);
        if (selectList.options[i].textContent.trim() == val) {
            dbg("Selected option " + val + " with id " + i);
            selectList.selectedIndex=i;
            break;
        }
    }
}
function SelectOption(selectList,val) {// class = ffSelectWrapper
    dbg("Got Select List");
    dbg(selectList);
    for (var i=0;i<selectList.options.length;i++) {
        dbg("Scanning option " + selectList.options[i].value.trim() + " with id " + i + " for option " + val);
        if (selectList.options[i].value.trim() == val) {
            dbg("Selected option " + val + " with id " + i);
            selectList.selectedIndex=i;
            break;
        }
    }
}

function SetPortForwarding(name,start,stop,local_start,type,ip) {
    dbg("Setting up a port forward");
    var doc = getElementByXpath('//frame[@src="main.asp"]').contentDocument;
    var form  = getElementByXpath('//form[@name="PortForwardForm"]',doc);
    var f_name = getElementByXpath('.//input[@id="app_X_name"]',form);
    var f_start = getElementByXpath('.//input[@id="app_X_public_start"]',form);
    var f_stop = getElementByXpath('.//input[@id="app_X_public_end"]',form);
    var f_local_start = getElementByXpath('.//input[@id="app_X_private_start"]',form);
    var f_type = getElementByXpath('.//select[@id="app_X_protocol"]',form);
    var f_ip = getElementByXpath('.//input[@id="app_X_ip"]',form);
    var f_submit = getElementByXpath('.//div[@id="submit"]/input',form);
    f_name.value=name;
    f_start.value=start;
    f_stop.value=stop;
    f_local_start.value=local_start;
    // Update local stop via keyup event
    f_local_start.onkeyup();
    SelectOptionByText(f_type,type);
    f_ip.value=ip;
    setTimeout(function() { f_submit.onmouseup(); f_submit.click(); },500);
}

function AddNewForward() {
    var doc = getElementByXpath('//frame[@src="main.asp"]').contentDocument;
    var form  = getElementByXpath('//form[@name="ServiceA"]',doc);
    var add_new = getElementByXpath('.//input[@name="add_new"]',form);
    add_new.click();
}

function CheckLoop(xpath,callback,thenCall=function(){return null;},timeout=500,tries=1000,errcallback=function(e_xpath) { dbg("Failed to find form '" + e_xpath + "' within tries limit."); }) {
    var doc = getElementByXpath('//frame[@src="main.asp"]').contentDocument;
    var elm = getElementByXpath(xpath,doc);
    if ( elm ) {
        callback();
        thenCall();
    }
    else if (tries !== 0) {
        dbg("Didn't see element");
        dbg(tries);
        setTimeout(function() { CheckLoop(xpath,callback,thenCall,timeout,tries - 1); }, timeout);
    }
    else {
        errcallback(xpath);
    }
}




var rollTimeout=null;
function rollmsg(elm,msg) {
    var NowMsg=elm.textContent;
    NowMsg=NowMsg.substring(1,NowMsg.length)+NowMsg.substring(0,1);
    elm.textContent = NowMsg;
    if (elm.offsetParent !== null) {
        clearTimeout(rollTimeout);
        rollTimeout=setTimeout(function(){ rollmsg(elm,msg); },200);
    }
}
var origTitle="";
function SavingBanner() {
    dbg("Activating Saving Banner");
    var doc = getElementByXpath('//frame[@src="main.asp"]').contentDocument;
    var title  = getElementByXpath('//div[@id="body-container"]/h2',doc);
    origTitle=title.textContent;
    title.textContent="SAVING ! ! !";
    // I am not sure why this makes the title 3 lines long, but I like it!
    title.style.width*=2;
    clearTimeout(rollTimeout);
    rollmsg(title,"");
}
function SetApplyBanner() {
    dbg("Apply Btn now calls Saving Banner");
    var doc = getElementByXpath('//frame[@src="main.asp"]').contentDocument;
    var form  = getElementByXpath('//form',doc);
    var apply = getElementByXpath('.//div[@id="submit"]/input',form);
    var origOnClick = apply.onclick;
    //apply.onclick=function() {rollTimeout=setTimeout(function(){ SavingBanner(); },200); origOnClick.apply(null,arguments);};
    apply.onmouseup=function() { rollTimeout=setTimeout(function(){ SavingBanner(); },200);};
    // Intercept Alerts
    var awin = getElementByXpath('//frame[@src="main.asp"]').contentWindow;
    var oldAlert=window.alert;
    awin.alert = function() {
        dbg("got Alert!");
        clearTimeout(rollTimeout);
        oldAlert.apply(awin,arguments);
    };
}
function SetApplyBannerLoop() {
    CheckLoop('//form//div[@id="submit"]/input',SetApplyBanner,function() { setTimeout(SetApplyBannerLoop,5000); },5000);
}
SetApplyBannerLoop();

var port_i = 0;
function itteratePorts() {
    if (port_i < Ports.length) {
        var port = Ports[port_i];
        port_i++;
        var forwardPort = function() {
            SetApplyBanner();
            SetPortForwarding.apply(null,port);
            /*
            var doc = getElementByXpath('//frame[@src="main.asp"]').contentDocument;
            var title  = getElementByXpath('//div[@id="body-container"]/h2',doc);
            title.textContent="SAVING ! ! !";
            // I am not sure why this makes the title 3 lines long, but I like it!
            title.style.width*=2;
            rollmsg(title,"");
            */
        };
        var addNewForward = function() {
            var doc = getElementByXpath('//frame[@src="main.asp"]').contentDocument;
            var form  = getElementByXpath('//form[@name="ServiceA"]',doc);
            var add_new_btn = getElementByXpath('.//input[@name="add_new"]',form);
            var edit_btn = getElementByXpath('.//input[@name="edit"]',form);
            var rows = getElementsByXpath('.//tr[td/@class="content"]',form);
            var edit = false;
            dbg("Configuring Forward Named " + port[0]);
            for (var r=0; r<rows.length; r++) {
                var row=rows[r];
                if (row.children[2].textContent === port[0] ) {
                    dbg("Found Existing Forward! Editing #" + (r + 1));
                    edit = true;
                    row.children[0].children[0].click();
                }
            }
            if (edit) {
                edit_btn.click();
            }
            else {
                dbg("Creating new Forward!");
                add_new_btn.click();
            }
        };
        //CheckLoop('//form[@name="ServiceA"]',addNewForward);
        //if (true) return null;
        CheckLoop('//form[@name="ServiceA"]',addNewForward,function() {
            CheckLoop('//form[@name="PortForwardForm"]',forwardPort,itteratePorts);
        });
    }
}
itteratePorts();