RouterOS – Controlar / Filtrar contenido por DNS 2023

En muchas ocasiones he tenido que controlar mediante QoS algunas cuestiones como las actualizaciones de windows, o las redes sociales, y en otros casos filtra Whatsapp.
OpenDNS de Cisco permite mediante un dashboard poder ir tildando y destildando contenidos a filtrar.
Anda bien pero no te deja discriminar. Por ejemplo filtra «Redes Sociales» pero el termino es muy grande y termina cometiendo errores. Si tildas por ejemplo «File Sharing» los audios de Whatsapp no se envian.
Entonces para evitar este tipo de problemas lo que hacemos es armar nuestro script que marque por nombre de dominio.

Te deja utilizar los filtros de manera gratuita para 1 direccion IP por cuenta. Es decir que para 1 red nateada andaria bien. Tiene para tildar por defecto redes bogon, sitios que propagan malware, pornografia, etc.

OpenDNS

El script

Para que funcione correctamente tenemos que habilitar el cache de DNS de nuestro router y hacer resolver a nuestos clientes con los DNS del router. Luego siempre dropear el DNS input en el firewall para que no nos ataquen los DNS desde afuera.

Lo que hace el script es buscar una palabra que coincida en el nombre del dominio.

# Use DNS Entrys and add Address to the Firewall Address-list #
:foreach i in=[/ip dns cache all find where ( (name~"instagram") || (name~"facebook") || (name~"twitter") || (name~"twitch") ) && (type="A") && (data!=0.0.0.0) ] do={
:local tmpAddress [/ip dns cache get $i data];
delay delay-time=10ms;
# prevent script from using all cpu time #
:if ( [/ip firewall address-list find where address=$tmpAddress] = "") do={ 
:local cacheName [/ip dns cache get $i name] ;
#:log info ("added entry: $cacheName $tmpAddress");
/ip firewall address-list add address=$tmpAddress list=RedesSociales comment=$cacheName timeout=6d;
}
}

Si se fijan donde dice:

(name~»instagram«) || (name~»facebook«) || (name~»twitter«) || (name~»twitch«)

Modificamos a nuestro antojo.

Y mas abajo le damos el nombre al Address-List:

/ip firewall address-list add address=$tmpAddress list=RedesSociales comment=$cacheName timeout=6d;

Tambien pueden modificar el timeout: Todas las direcciones nuevas que resuelva las va agregando al AddressList (en este caso las mantiene por 6 dias), esto hace que tengamos un segundo cache que se vaya limpiando cada 6 dias y las direcciones IP viejas se vayan eliminando automaticamente.

Luego solo nos queda hacer algo con ese address list. Podemso dropearlo en el firewall.
O bien crear un mangle que marque la conexion con destino a esas IP y luego usarlo en Queues.

Por ejemplo:

/ip firewall filter
add action=drop chain=forward dst-address-list=RedesSociales in-interface=bridge_alumnos
add action=drop chain=output dst-address-list=RedesSociales out-interface=bridge_alumnos

Ojo que en mi caso ademas le digo en que interfaz eliminar las redes sociales. Elijan la interfaz para su caso.

origen: tech-nico.com

Mikrotik Script para bloquear intentos de login

Leyendo en el foro de mikrotik me encontre con este script que monitorea el log en busca errores , Y bloquea en base a la cantidad de intentos de acceso. Lo interesante es que podemos configurarlo para detectar distintos tipos de acceso. Por ejemplo los famosos intentos de acceso por VPN Ipsec que dicen «phase1 negotiation failed…». O los accesos erroneos por winbox nos dirian «login failure for user», etc.

Paso 1, importar script pegando esto en la terminal.

/sys script 
add dont-require-permissions=no name=LoginAttempBlocker owner=usuario policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="# Check if exist drop \
    firewall rule and add\r\
    \n/ip firewall raw\r\
    \n:if ([:len [find where src-address-list=\"blockedUsers\"]] = 0) do={\r\
    \n    add action=drop chain=prerouting src-address-list=blockedUsers\r\
    \n}\r\
    \n\r\
    \n:global lastLogLogin\r\
    \n:if ([:typeof \$lastLogLogin] != \"num\") do={:set lastLogLogin 0}\r\
    \n\r\
    \n/log\r\
    \n:global maxattampt 3\r\
    \n:global errorArray [:toarray \"\"]\r\
    \n:global failmsg    \"login failure for user \"\r\
    \n:global frommsg    \" from \"\r\
    \n:global viamsg     \" via \"\r\
    \n:global listfail   \"blockedUsers\"\r\
    \n:local  id2num     do={:return [:tonum \"0x\$[:pick \$1 1 [:len \$1]]\"]}\r\
    \n\r\
    \n:foreach rlog in=[find where (([\$id2num \$\".id\"] > \$lastLogLogin) \\\r\
    \n                             and \\\r\
    \n                             (message~\"((25[0-5]|(2[0-4]|[01]\\\?[0-9]\\\?)[0-9])\\\\.){3}(25[0-5]|(2[0-4]|[01]\\\?[0-9]\\\?)[0-9])\"))] do={\r\
    \n    \r\
    \n    :set lastLogLogin [\$id2num \$rlog]\r\
    \n    :local rmess [get \$rlog message]\r\
    \n    :if ((\$rmess~\$failmsg) and (\$rmess~\$frommsg) and (\$rmess~\$viamsg)) do={\r\
    \n         :local userinside [:pick \$rmess ([:find \$rmess \$failmsg -1] + [:len \$failmsg]) [:find \$rmess \$frommsg -1]]\r\
    \n         :local ipinside   [:pick \$rmess ([:find \$rmess \$frommsg -1] + [:len \$frommsg]) [:find \$rmess \$viamsg -1]]\r\
    \n         :local intinside  [:pick \$rmess ([:find \$rmess \$viamsg -1] + [:len \$viamsg]) [:len \$rmess]]\r\
    \n         :if ([:typeof ((\$errorArray)->\$ipinside)] = \"nothing\") do={\r\
    \n             :set ((\$errorArray)->\$ipinside) 1\r\
    \n         } else={\r\
    \n             :set ((\$errorArray)->\$ipinside) (((\$errorArray)->\$ipinside) + 1) \r\
    \n         }\r\
    \n         :if (((\$errorArray)->\$ipinside) > (\$maxattampt - 1)) do={\r\
    \n             /ip firewall address-list\r\
    \n             :if ([:len [find where list=\$listfail and address=\$ipinside]] = 0) do={\r\
    \n                 add list=\$listfail address=\$ipinside comment=\"\$rmess\" timeout=24h\r\
    \n             }\r\
    \n         }\r\
    \n         \r\
    \n    }\r\
    \n}"

Paso 2, configurar el script editando las variables globales:

:global maxattampt 3
:global failmsg    "login failure for user "
:global frommsg    " from "
:global viamsg     " via "
:global listfail  "blockedUsers"

3 serian la cantidad de intentos que toleramos. (para bloquear en un cuarto intento).

login from user, from y via van a depender del mensaje en el log que querramos capturar. Si quieren filtrar intentos de acceso por winbox entonces dejarlo como esta.

blockedUsers es la lista del firewall que se crea dinamicamente con la/s IP del usuario que intenta acceder.

Paso 3, agregar tu script al calendario para que se ejecute cada 5 minutos o menos.

Esto hara que nuestro script lea el log cada 5 minutos. Mas ajustemos el tiempo, mas eficiente sera el chequeo de acceso. Si dentro de estos 5 minutos, hubo 3 o mas intentos, automaticamente se creara una regla en el Firewall Raw, y borrara todo el input desde la direccion IP dinamica detectada en la lista blockedUsers. Se entiende que en las proximas 24 hs caducara la direccion y volvera a tener acceso.

______________

origen: tech-nico.com

RouterOS DHCP Server Automático con Queues Dinámicas

Esto esta pensado para lugares de mucha «mucha» concurrencia, para no derrochar recursos. Direcciones IP y Ancho de Banda. Por supuesto que esto tiene que estar acompañado de un buen CPU (para mi caso con un equipo 2011, me fue suficiente), y también debería estar acompañado de un caudal de ancho de banda suficiente dependiendo de cada caso y el factor simultaneidad.

Funcionamiento

Se crea un DHCP server como siempre, pero en la solapa Script se le dice que a cada Lease dinamico lo convierta en estatico, y que ademas le otorgue un RATE-LIMIT de Upload y Download. (En nuestro caso configure 1 mega de subida y 3 de bajada). Esto es lo que hace toda la magia.

#tech-nico.com  CONTACTO: administracion@tech-nico.com  01-01-2022
/ip dhcp-server lease make-static [/ip dhcp-server lease find dynamic && active-server="dhcp-invitados"];
/ip dhcp-server lease set [find where active-mac-address=$leaseActMAC] rate-limit="2M/3M" insert-queue-before="bottom";

Luego deben agregar un script que limpie los Leases que queden en estado «waiting». (son clientes que no pudieron obtener direccion IP por mala señal, o bien al renovar el Lease ya no estaba ese dispositivo en el sitio).

/ip dhcp-server lease remove [/ip dhcp-server lease find status="waiting" && server="dhcp-invitados"];

Nicolas Daitsch
Tech-nico.com

Automatizacion de Backups con Mikrotik y Google Drive Parte 2

En la primera parte, te enseñe como automatizar mediante un script el envio de tus backups. Ahora viene la parte divertida, «donde el google drive cobra vida». Esta segunda parte no tiene nada de Mikrotik, para ello leer la primera parte.

Esta «segunda» parte consiste en recibir el correo con un archivo adjunto (El backup), y dependiendo del asunto del email organizarlo en distintas carpetas y documentar todo en una planilla de calculo.

Como logramos esto?

Con Scripts de Google App Scripts que son muy muy poderosos y te permitirian mejorar funcionalidades en todo esto:

Nosotros lo que haremos es darle funcionalidades especiales dentro de una planilla de calculo «Sheet» que tendra funciones para:

  1. Leer el Gmail,
  2. Manipular el G.Drive
  3. y finalmente escribir el resultado en una planilla de calculo.

Pasos a seguir para implementarlo:

  1. Nos logueamos en la misma cuenta de gmail que utilizamos en la primera parte (donde estarian llegando los backups). Yo les recomiendo que lo hagan en una ventana de incognito.
  2. Luego como se muestra en la imagen, click en aplicaciones, y finalmente en Hojas de calculo. O bien, luego de loguearnos vamos a esta direccion: https://docs.google.com/spreadsheets/

3. Creamos una hoja de calculo nueva. Le damos el nombre que mas nos guste:

4. Usar la primer fila para crear los encabezados para cada columna

IDFECHA SUBIDACARPETAARCHIVOURLTIPOHORA ESCRITURA

5. Ahora iremos al menu «Herramientas» > Editor de secuencias de comandos tal como muestro en la siguiente imagen:

Es lo mismo que acceder a script.google.com, con la diferencia de que aqui queda el codigo ligado a esta planilla

6. Aqui pegaremos el siguiente codigo:


/*
 * Script por Nicolas Daitsch www.tech-nico.com/blog
   30 de septiembre de 2020
 */

// GLOBALS
//Filtro de extenciones de los archivos adjuntos
var fileTypesToExtract = ['backup', 'rsc', 'gz'];
//Carpeta de google drive donde los archivos seran movidos
var folderName = 'MIS-BACKUPS';
//Etiqueta que le pondremos a los correos ya procesados
var labelName = 'read_label';
// ID de la carpeta definida en la variable "folderName"
var DocsfolderID='1kLOIsv1Co_4SA6oE838kskfPXvZUuXcZg4fH';

function GmailToDrive(){
    var query = '';
    for(var i in fileTypesToExtract){
      query += (query === '' ?('filename:'+fileTypesToExtract[i]) : (' OR filename:'+fileTypesToExtract[i]));
    }
    query = 'in:inbox has:nouserlabels ' + query;
    var threads = GmailApp.search(query);
    var label = getGmailLabel_(labelName); // Get Label ID
    var parentFolder,parentMyFolder,parentMySubFolder; 
    if(threads.length > 0){
      parentFolder = createFolder(folderName,DocsfolderID); // Si la carpeta existe, traer el ID
    }
    var root = DriveApp.getRootFolder();
    for(var i in threads){
        var mesgs = threads[i].getMessages();
        for(var j in mesgs){
              var subject = mesgs[j].getSubject();
              var subject_array = subject.split("//");
              if(subject_array.length<2) { 
                 threads[i].addLabel(label); 
              }else{ 
                  var subject_folder = subject_array[0];
                  var subject_subfolder = subject_array[1];
                
                  var attachments = mesgs[j].getAttachments();
                  for(var k in attachments){
                      var attachment = attachments[k];
                      var isDefinedType = checkIfDefinedType_(attachment);
                      if(!isDefinedType) continue;
                      var attachmentBlob = attachment.copyBlob();
                      var file = DriveApp.createFile(attachmentBlob);
                      var nom_archivo="";
                      nom_archivo = attachment.getName();

                      parentMyFolder = createFolder(subject_folder,parentFolder.getId());
                      parentMySubFolder = createFolder(subject_subfolder,parentMyFolder.getId());

                      parentMySubFolder.addFile(file);
                      var files = [];
                      files.push({ id:file.getId(), fecha:file.getDateCreated(), carpeta: subject, archivo: file.getName(), url:file.getUrl(), tipo:file.getMimeType()});
                      printInSheet2(files[0])

                      root.removeFile(file);
                  }
              }
            
        }
        threads[i].addLabel(label); // set as just read
    }
}

function getGmailLabel_(name){
  var label = GmailApp.getUserLabelByName(name);
  if(!label){
	label = GmailApp.createLabel(name);
  }
  return label;
}

function checkIfDefinedType_(attachment){
  var fileName = attachment.getName();
  var temp = fileName.split('.');
  var fileExtension = temp[temp.length-1].toLowerCase();
  if(fileTypesToExtract.indexOf(fileExtension) !== -1) return true;
  else return false;
}


function createFolder(Name,folderID){
  
  var PF = DriveApp.getFolderById(folderID);
  if(Name==folderName){ return PF; }
  
  var subFolders = PF.getFolders();
  var doesntExists = true;
  var newFolder = '';
  
  while(subFolders.hasNext()){
    var folder = subFolders.next();
    if(folder.getName() === Name){
      doesntExists = false;
      newFolder = folder;
      return newFolder;
    };
  };
  
  if(doesntExists = true){
    newFolder = PF.createFolder(Name);
    return newFolder;
  };
};



function printInSheet2(objeto) {
  var today = (Utilities.formatDate(new Date(), "GMT-3", "dd-MM-yyyy")).toString();
  var today_hora = (Utilities.formatDate(new Date(), "GMT-3", "HH:mm")).toString();
  var ss = SpreadsheetApp.getActiveSpreadsheet();  
  var sheet = ss.getSheetByName(today);
  if (!sheet){
    SpreadsheetApp.setActiveSheet(ss.getSheets()[0]); 
  
    ss.duplicateActiveSheet(); 
    ss.renameActiveSheet(today); 
    ss.moveActiveSheet(1); 
    // Prepares tab (clears old content)
    var sheet = ss.getSheetByName(today); 
    sheet.getRange('A2:G200').clearContent(); // clean
    sheet.getRange('A2:G200').setBackground(null);
  }

  var found = sheet.getRange(1,1,sheet.getLastRow()).createTextFinder(objeto["id"]).matchCase(false).findNext(); 
  if ( found==null ){ // only write if any cell content not match with de file ID
      var data, sheet = SpreadsheetApp.getActiveSheet();
      data = [
        objeto["id"],
        objeto["fecha"],
        objeto["carpeta"],
        objeto["archivo"],
        objeto["url"],
        objeto["tipo"],
        today_hora
      ];
      sheet.appendRow(data);
   }
};

La Magia:

Nos quedaria algo asi:

7. Solo tendremos que editar primeras 4 variables, y son obligatorias la creacion de la carpeta MIS-BACKUPS o como quieras llamarla. Al crearla, obtenemos el ID de la carpeta que necesitamos definir en la ultima variable (tambien obligatoria), como muestro a continuacion:

En una nueva solapa vamos a https://drive.google.com/

Presionamos NUEVO:

Elegimos Carpeta:

Finalmente le damos click derecho «Obtener Enlace»

Copiamos el ID, Asegurense de que este completo porque es mas largo de lo que se ve en la captura:

8. Ahora ya podemos ejecutar el codigo y probar si funciona: Volver a la ventana de script.google.com y ejecuta el codigo eliguendo la funcion GmailToDrive y seguidamente presionar el boton Play

Finalmente les va a pedir que le den permisos de lectura para acceder al gmail, drive, etc.

Por supuesto que si no hay correos en tu casilla no va a procesar nada. Y ademas que si el asunto no respeta la doble barra para separar el nombre de la carpeta con la fecha, el mail no va a ser procesado. Si el correo es procesado lo marca con la etiqueta de leido «read_label»:

Finalemente revisamos en nuestro drive la creacion de las carpetas y en la planilla que deberia aparecer el resumen del archivo en solapas por fecha, para que si buscamos entre muchos backusp de una fecha especifica, lo podamos encontrar super rapido!.

9. Para agregar el script a un calendario de ejecucion y que corra el proceso de manera automatica, lo que tenemos que hacer es crear un nuevo Trigger o Activador:

Añadir Activador:

Yo lo configure asi: (Ustedes pueden setearlo a su gusto)

No hace falta que les diga que pueden utilizar este mismo script para recibir backups de Linux, Mikrotik, Windows, o cualquier dispositivo que sea capaz de enviar un mail con un archivo adjunto.

Espero que les haya gustado tanto como a mi, y cualquier cosa que no se entienda puedo armar un video-tutorial.

Saludos
_______________
Por Nicolas en tech-nico.com/blog

Mikrotik: Como direccionar trafico PPPoE por interfaz (sin balancear): 3 WAN / 3 LAN

No quiero extenderme explicando por que tuve que elegir esta configuracion, pero si quiero decir que fue una solucion muy buena en su momento. Por supuesto que tienen que darse condiciones muy similiares para que te sirva hacer lo mismo. Pero somos tantos en el mundo que seguro mi aporte puede ayudar a otros. 🙂

Escenario

3 LAN (OLT), cada una en una VLAN distinta, los usuarios conectan por PPPoE a cada VLAN y se routean a un WAN especificio.
Son 3 WAN de 100 Mb c/u. Los clientes hacen NAT en cada interfaz LAN. La clave de todo es generar dinamicamente listas de direcciones IP de los abonados en el momento que conectan y se desconectan.

A continuación paso a detallar cada bloque de comandos

A cada una de mis salidas las voy a nombrar Fortinet 1,2 y 3. (Asi se llaman los firewall que suele instalar telefonica en uno de sus servicios)

/ip firewall mangle
add action=mark-connection chain=input comment=UPLOAD in-interface=vlan_fortinet1 new-connection-mark=input1_connection passthrough=yes
add action=mark-routing chain=output connection-mark=input1_connection new-routing-mark=route_fortinet1 passthrough=no
add action=mark-connection chain=input in-interface=vlan_fortinet2 new-connection-mark=input2_connection passthrough=yes
add action=mark-routing chain=output connection-mark=input2_connection new-routing-mark=route_fortinet2 passthrough=no
add action=mark-connection chain=input in-interface=vlan_fortinet3 new-connection-mark=input3_connection passthrough=yes
add action=mark-routing chain=output connection-mark=input3_connection new-routing-mark=route_fortinet3 passthrough=no
add action=mark-routing chain=prerouting comment="ROUTING OLT 3 por FOTINET 3" new-routing-mark=route_fortinet3 passthrough=no src-address-list=\
OLT_service3
add action=mark-routing chain=prerouting comment="ROUTING OLT 2 por FOTINET 2" new-routing-mark=route_fortinet2 passthrough=no src-address-list=\
OLT_service2
add action=mark-routing chain=prerouting comment="ROUTING OLT 1 por FOTINET 1" new-routing-mark=route_fortinet1 passthrough=no src-address-list=\
OLT_service1

Estas son las rutas de cada salida. Deberas reeemplazar el gateway por los tuyos. Cada salida tiene su propia tabla de routeo.
Esto hace que puedas hacer traceroute desde afuera o desde adentro y no se confunda de ruta.

Hay una ruta que no tiene marca. Es la que yo elijo por defecto. (Es decir que nuestro router va a preferir esa ruta).

/ip route
add comment="gw fortinet 2" distance=3 gateway=200.2.2.105 routing-mark=route_fortinet2
add comment="gw fortinet 1" distance=2 gateway=200.1.1.137 routing-mark=route_fortinet1
add comment="gw fortinet 3" distance=4 gateway=200.3.3.97 routing-mark=route_fortinet3
add comment="default gw fortinet 2" distance=10 gateway=200.2.2.105
/ip route rule
add action=lookup-only-in-table routing-mark=route_fortinet1 table=route_fortinet1
add action=lookup-only-in-table routing-mark=route_fortinet3 table=route_fortinet3
add action=lookup-only-in-table routing-mark=route_fortinet2 table=route_fortinet2

Esta es la parte de de NAT, no hay mucho para ver. Cada interfaz LAN hace mascarade con las direcciones que se almacenan con el Script -PPP-On_up On_down. Veras mas abajo como se crean.

/ip firewall nat
add action=masquerade chain=srcnat comment="mascarading RED LOCAL" out-interface=vlan_fortinet1 src-address-list=OLT_service1 src-address-type=""
add action=masquerade chain=srcnat comment="mascarading RED LOCAL" out-interface=vlan_fortinet2 src-address-list=OLT_service2 src-address-type=""
add action=masquerade chain=srcnat comment="mascarading RED LOCAL" out-interface=vlan_fortinet3 src-address-list=OLT_service3 src-address-type=""

Cada PPPoE server tiene un nombre de servicio especifico: mas abajo se van a dar cuenta por que. En este caso son: «service1», «service2», y «service3». (Recordar esos nombres)

/interface pppoe-server server
add authentication=pap disabled=no interface=sfp-sfpplus1_olt1 keepalive-timeout=5 one-session-per-host=yes service-name=service1
add authentication=pap disabled=no interface=sfp-sfpplus2_olt2 keepalive-timeout=5 one-session-per-host=yes service-name=service2
add authentication=pap disabled=no interface=sfp-sfpplus3_olt3 keepalive-timeout=5 one-session-per-host=yes service-name=service3

Para poder routear los clientes correctamente necesitamos separar las direcciones IP de los tuneles PPP que se conecten, en 3 listas (address-lists) distintas. (una por cada LAN o en este caso OLT).
En PPP Profile (solapa) Scripts On-UP / On-DOWN. Esto hace que cuando conecta el PPPoE ponga su direccion remota en una lista con el nombre de la interfaz por donde esta conectando. En este caso OLT1, 2 o 3.
A continuacion, estos 2 pequeños comandos, se fijan de que pppoe server esta pidiendo este usuario conectar o desconectar. Entonces con la variable «caller-id» traemos el nombre del servicio desde donde se conecta. Como mencionamos anteriormente, «service1», «service2», y «service3».

La parte donde ocurre la magia

En cada perfil de ancho de banda tienes que ingresar a editar en las solapas donde dice On_up y On_Down y pegar los siguientes 2 scripts: (Tiene partes con comillas dobles, dejarlas tal cual).

ON UP
/ip firewall address-list add list="OLT_$"called-id"" address=$"remote-address"

ON DOWN
/ip firewall address-list remove [find list="OLT_$"called-id"" address=$"remote-address"]

No se por que algunas veces el On-UP Script faya, entonces la direccion IP de ese cliente no queda dentro de la lista OLT_serviceX y eso hace que ese cliente no tenga navegacion, ya que en Firewall NAT hacemos masqarading por listas. Realmente no tuve tiempo de descubir por que lo hacia. Entonces decidi hacer un script al que denomine PPP-SYNC-FIXER compara las direcciones IP de los tuneles PPP conectados con las listas de IP. Si no encuentra alguna de las direcciones, pateo el usuario para obligarlo a reconectar. El script se ejecuta cada 2 minutos en el calendario de ejecucion. (Bajarle el tiempo en equipos con poco procesador).

Para importar el script pegar esto en la consola y presionar enter.

/system script add dont-require-permissions=no name=PPP_SYNC_FIXER owner=soporte1 policy=\
read,write,policy,test,password,sniff,sensitive source=":log info message=\"*** comienza\
_a buscar usuarios PPP sin routeo \";\r\ \n:local arrnoestan [:toarray \"\"];\r\ \n:local pppactivos value=[/ppp active find];\r\ \n:local indice 1;\r\ \n:foreach usuario in=\$pppactivos do={\r\ \n :local direccionip value=[/ppp active get \$usuario value-name=address];\r\ \n :local busqolt1 value=[/ip firewall address-list print count-only where list=\"O\ LT_service1\" address=\$direccionip];\r\ \n :local busqolt2 value=[/ip firewall address-list print count-only where list=\"O\ LT_service2\" address=\$direccionip];\r\ \n :local busqolt3 value=[/ip firewall address-list print count-only where list=\"O\ LT_service3\" address=\$direccionip];\r\ \n :if ((\$busqolt1=0) && (\$busqolt2=0) && (\$busqolt3=0)) do={\r\ \n# :set arrnoestan ( \$arrnoestan, \$direccionip );\r\ \n :log info message=\"I \$indice IP \$direccionip - no encontrada --- PATEAN\ DO\";\r\ \n /ppp active remove \$usuario;\r\ \n }\r\ \n :set indice (\$indice + 1);\r\ \n}\r\ \n#:log info message=\" fin de script ***\";\r\
\n#:log info message=\"\$arrnoestan\";\r\
\n"

Para importar el scheduler pegar esto en la consola:

/system scheduler
add interval=2m name=Corro_fixer_PPP on-event="/sys script run PPP_SYNC_FIXER" policy=read,write,policy,test,password,sniff,sensitive \
start-date=dec/30/2019 start-time=21:38:15

Automatizacion de Backups con Mikrotik y Google Drive Parte 1

1) CONFIGURAR sNTP Client

Para que nuestro backup se ejecute correctamente lo primero es que nuestro RouterOS se mantenga siempre con la hora correcta por mas que se reinicie. Entonces pegamos esto en la consola:

/system ntp client
set enabled=yes primary-ntp=216.239.35.12

Solo aceptaremos en nuestro firewall el servidor NTP de google, ya que estos puertos suelen estar dentro de los mas atacados. Para ellos pegamos nuevamente lo siguiente en la consola:

/ip firewal filter
add action=accept chain=input comment="NTP Admitir solo a time.google.com" dst-port=123 protocol=tcp src-address=\
216.239.35.12
add action=accept chain=input dst-port=123 protocol=udp src-address=216.239.35.12
add action=drop chain=input dst-port=123 protocol=udp

2) CONFIGURAR E-MAIL

Las siguientes lineas corresponden al seteo del servicio de correo. La direccion IP es de smtp.google.com: Lo editas en tu notepad reemplazando tu contraseña y la direccion de correo y lo pegamos en la consola:

/tool e-mail
set address=172.217.192.109 from= password="TU_CONTRASEÑA_FUERTE" port=587 start-tls=yes user=\
TUMAIL@GMAIL.com

NOTA IMPORTANTE: recorda que Gmail bloquea el envio de mails de cualquier aplicacion externa (que se considera poco segura) como por ejemplo Outlook, (y cualquier otros), y por supuesto el envio de mails a traves de RouterOS. Para resolverlo loggearse con la cuenta que usaran para backups y luego hacen click en el siguiente este enlace: https://myaccount.google.com/lesssecureapps

Cambiar de NO a SI

3) PROBAR EL ENVIO DE EMAIL

Para saber si el envio es correcto probamos el envio desde consola con la siguiente linea:

/tool e-mail send to="TUMAIL@GMAIL.com" subject="soy tech-nico backups"

4) IMPORTAR SCRIPTS DE BACKUPS

A continuacion tenemos 2 scripts que debemos pegar en la consola (previo a editar la direccion de e-mail). El primer script envia el binario completo. «.backup» y el segundo script envia un export completo «.rsc». Por ahora no editen el asunto porque es importante mantener el doble slash «//». (en la parte 2 te daras cuenta del por que). Recueden que al pegar en la consola hay que presionar enter.

/system script add name=backup_binary source={/system backup save name=([/system identity get name] . "-" . \
[:pick [/system clock get date] 7 11] . [:pick [/system clock get date] 0 3] . [:pick [/system clock get date] 4 6]); \
/tool e-mail send to="TUMAIL@GMAIL.com" subject=([/system identity get name] . "_BACKUP//" . \
[/system clock get date]) file=([/system identity get name] . "-" . [:pick [/system clock get date] 7 11] . \
[:pick [/system clock get date] 0 3] . [:pick [/system clock get date] 4 6] . ".backup"); :delay 10; \
/file rem [/file find name=([/system identity get name] . "-" . [:pick [/system clock get date] 7 11] . \
[:pick [/system clock get date] 0 3] . [:pick [/system clock get date] 4 6] . ".backup")]; \
:log info ("System Backup emailed at " . [/sys cl get time] . " " . [/sys cl get date])}

Y este otro:

/system script add name=backup_export source={/export file=([/system identity get name] . "-" . \
[:pick [/system clock get date] 7 11] . [:pick [/system clock get date] 0 3] . [:pick [/system clock get date] 4 6]); :delay 2; \
/tool e-mail send to="TUMAIL@GMAIL.com" subject=([/system identity get name] . "_BACKUP//" . \
[/system clock get date]) file=([/system identity get name] . "-" . [:pick [/system clock get date] 7 11] . \
[:pick [/system clock get date] 0 3] . [:pick [/system clock get date] 4 6] . ".rsc"); :delay 10; \
/file rem [/file find name=([/system identity get name] . "-" . [:pick [/system clock get date] 7 11] . \
[:pick [/system clock get date] 0 3] . [:pick [/system clock get date] 4 6] . ".rsc")]; \
:log info ("System Backup emailed at " . [/sys cl get time] . " " . [/sys cl get date])}

5) AGREGARLO AL CALENDARIO DE EJECUCION

Y finalmente lo ejecutamos cada 5 dias. O como ustedes prefieran. Esto hara que se envien 2 mails. 1 con el .backup y el otro con el export .rsc.

/system scheduler
add interval=5d name=backup_binary on-event="/sys script run backup_binary" policy=\
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-date=aug/03/2020 start-time=16:35:00
add interval=5d name=backup_export on-event="/sys script run backup_export" policy=\
ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-date=aug/03/2020 start-time=16:35:00


En la segunda parte de este post te enseñare como volcar estos mails a un Google Drive.

Cambios en RouterOS 6.43: API Class con passwords en texto plano

Para todos los que estan usando las librerías de PHP de Denis Basta (como yo), luego de actualizar tu RouterOS a la version 6.43 «en adelante» van a tener el inconveniente de que la libreria deja de funcionar (de conectar mas bien). Esto se debe a que el Team de Mikrotik Modifico la manera en que RouterOS internamente almacena las contraseñas, ya que según explican en su foro ellos comparan al viejo Telnet inseguro que usa contraseñas en texto plano con el API inseguro, y el SHH con el API HTTPs. Esto genera un poco de controversia entre los que usan el API sin HTTPs ya que lo bueno era que al menos las contraseñas viajaban encriptadas.

A raíz de las ultimas vulnerabilidades y tantos ataques dirigidos a dispositivos con Mikrotik, han tenido que hacer muchos cambios que nos obliga a tener que ponernos las pilas e instalar un certificado en cada router para no ser víctimas de los ataques de diccionario (con MKBrutus u otros) que atacan el puerto 8728 (API inseguro). Seria muy importante tener también HTTPs en el dominio donde tengamos corriendo la libreria.

Si se fijan en el manual explican la diferencia entre lo que seria el antes y el después de la version 6.43. Incluso aclaran que en la version 6.45.1 ya se toma como obsoleto.

Por suerte hay un colega que edito la libreria de Denis Basta para que intente conectar primero de forma segura, si no tiene exito lo hace de manera plana. A editar nuestro codigo.!. Si se fijan en la linea 109 y 116 estan las 2 formas de loggeo.

Saludos!!!

____________________
Primero en tech-nico.com/blog

Scripts Mikrotik | 2 esenciales para un sys admin: Ether state and Speedtest

2 Scripts que yo denomino «Criminales»

Hola amigos,  disculpen la ausencia, estamos con muchas implementaciones, pero no queria dejar pasar esta oportunidad de dejarles 2 script que trabajan de la mano y para mi gusto son increibles.

Script 1: Chequear el estado de un puerto ethernet

Este script esta pendiente del estado de un puerto de red que le configuremos. Es decir que esta atento a si el estado del puerto esa con link o sin link. Cuando el puerto hace link chequea que tenga salida a internet haciendo un ping a www.tech-nico.com.
Si tiene salida a internet, entonces ahi entra en juego el script nro 2.

[PHP]
# Nicolas: Tech-nico.com/blog
# CHEQUEAMOS ESTADO DE ETHERNET
:global etherNET;
:set $etherNET value=»ether1″;
:global «ether-state»;
:global «ether-laststate»;
/interface ethernet monitor $etherNET once do={:set «ether-state» $status};
:if ($»ether-state» != $»ether-laststate») do={
:log info («Interface $etherNET – link status cambio a: » . $»ether-state»);
:set «ether-laststate» $»ether-state»;
:do {
:put [:resolve www.tech-nico.com];
:if ($»ether-state»=»link-ok») do { :log warning («HACER TEST!!»); /system script run speedtest; }
} on-error={ :put «resolver failed»};
}
[/PHP]

Script 2: Hacer un test de velocidad descargando un archivo

En principio enciende la pantalla LCD del equipo (tenemos que usar algún equipo como un RB-2011) para mostrar la velocidad de download reflejada en la pantalla. Fíjense que tienen que editar la url donde dice archivo_pesado.tif y setear el servidor y nombre de archivo que ustedes tengan, y usen como prueba. Se recomienda algún video AVI pesado, (algo que pueda almacenar nuestro RB).

[PHP]
{
# Nicolas: Tech-nico.com/blog
# HACEMOS UN SPEEDTEST
/lcd backlight state=on;
local startTime [/system clock get time];
:global myurl «http://www.tech-nico.com/archivo_pesado.tif»;
/tool fetch url=$myurl mode=http;
local endTime [/system clock get time];
# subtract startTime from endTime to get time elapsed
local finalTime ( $endTime – $startTime );
# convert hours to seconds, add to sum
:local sum ( $sum + ( [ :pick $finalTime 0 2 ] * 60 * 60 ));
# convert minutes to seconds, add to sum
:set sum ( $sum + ( [ :pick $finalTime 3 5 ] * 60 ));
# add seconds to sum
:set sum ( $sum + [ :pick $finalTime 6 8 ] );
:local sise [[/file get [/file find name=archivo_pesado.tif] size] /1024];
:local sdonspped ((($sise / $sum ) * 8 ) /1024);
:local ddow ((($sdonspped *1000) /8) / 1024);
:global speedtest $sdonspped;
:log warning («My connection Speed «.[:pick $sdonspped 0 1] .».». [:pick $sdonspped 1 3] . » Mbps» );
:log error («My Speed Download = «. $ddow .» Kbps»);
}
[/PHP]

Casos de uso

La idea de estos 2 script es la siguiente:  Crear una herramienta para mostrarle al cliente «sin encender ninguna computadora», cual es el rendimiento de su conexion a internet. Por eso es un requisito fundamental usarlo con modelos de hardward que tengan pantalla LCD. Tambien porque en el mercado no existe ningun tester o appliance que haga algo tan basico como un testspeed y lo entregue de manera elegante en una pantallita LCD, Sin paracticamente configurar nada. Loco no?

Funcionamiento

En mi caso tengo configurado un usuario PPPoE en el ether1. El mismo puerto esta seteado en el Script 1 para chequear el estado de red. Una vez que es detectado el estado del ethernet como UP, hacemos un ping, y si el PPPoE client alcanzo a conectar, el ping a tech-nico.com nos va a dar OK, con lo cual finalmente se va a ejecutar el download.

Pd: Aclaro que la foto fue «gestionada» con google. Aclaro por si aparece el dueñ0.  😀

____________________
Primero en tech-nico.com/blog

API MIKROTIK [Updated] Graficar Interfaces o Queues en tiempo real con Highcharts y PHP

Nueva Versión Actualizada

Todos lo que leyeron la primera versión de «Graficar trafico de interfaces en tiempo real con Highcharts y PHP«, aquí les traigo la nueva versión con bastantes fixes que detallo a continuación:

  • Actualización de la librería de que conecta con el API de Denis Basta desde la versión 1.4  a la versión 1.6.
  • Actualizacion de la libreria Highcharts, pasando de v3.0.5 a v6.1.1. (ultima hasta el dia de hoy 30/05/18).
  • Se agrego un parámetro para graficar Interfaces o Queues a elección.
  • Se agrego función para formatear correctamente los bytes y mostrar bien los bytes, megas, etc.
  • Cambio de estilos y colores por unos mas amigables.

La configuración es la misma que en el post anterior.

Espero que les guste!.

Descargar Ejemplo de Graficar interfaces o queues en tiempo real version 2.0

______________

Primero en tech-nico.com

Script Mikrotik – Enviar mail cuando ping es mayor a 200ms

Minientrada

Algo para agregar a la navaja suiza de tus script (sysadmin only): 

Hola Amigos, hace mucho que no escribo, y en este caso, me pareció que vale la pena repostear. Este script de mikrotik hecho por un chino te envia un mail cuando el ping a cierta dirección supera los 200 ms; por ejemplo, si tenemos algun enlace o cliente que queremos monitorear cuando estamos durmiendo. Si sos nerd (como yo), No dejes escapar este script, es justo para vos.

#Mikrotik Ping more than 200ms to send mail
#https://ros.ac
#By:Ali
#From:China
:local Asunto "Alarma! Monitor de ping a IP"
#Configurar la IP a monitorear
:local addre 192.168.88.1;
#Configurar el Delay maximo tolerado
:local ms 200;
:local avgRtt;
/tool flood-ping $addre count=10 do={
  :if ($sent = 10) do={
    :set avgRtt $"avg-rtt"
}}
:if ($avgRtt &gt;= $ms) do={
#Send mail
/tool e-mail send server=&lt;Server IP&gt; port=25 user=&lt;user&gt; password=&lt;pass&gt; to=to@mail.com from=from@mail.com subject=$Asunto body=("Monitoreando IP:$addre\ndelay:$avgRtt ms")
:log err "La alarma ha sido enviada.";
}

Atencion, configurar las siguientes variables para que funcione correctamente el script:

:local addre 192.168.88.1; —- Aqui setear la direccion IP a la que queremos monitorear.

:local ms 200; ———- Aqui los ms. Solo cambiar el nro 200 por el valor deseado.

Email Settings: ———– No Olvides configurar server, port, user, password, to y from.
________
Primero en tech-nico.com

API MIKROTIK – Eliminar una dirección del firewall address-list

Te interesa saber como agregar una direccion IP a una lista?.

Exactamente hace 1 año atrás, el armamos un ejemplo para agregar una direccion IP una lista determinada del firewall; pero nunca dijimos como eliminarla y por eso aquí esta la solución.

Aquí va el código de como hacerlo:

Requisito: Descargar la librería api_mt_include2.php (podes hacerlo en uno de nuestros primeros ejemplos)

<?php require_once('api_mt_include2.php'); ?>
<?php
/*
/// AUTOR: Tech-Nico.com ///
/// admin@tech-nico.com /////
/// API: Firewall Address-list: Elimino una direccion IP a un address-list
/// Fecha: 10/08/2016 
  
//////// configura tus datos
$ServerList ="192.168.100.1"; //ip_de_tu_API
$Username ="api"; //usuario_API
$Pass ="#pass"; //contraseña_API
$Port ="8727"; //puerto_API
*/
/// VARIABLES DE FORMULARIO
$address= "5.4.3.1";  // direccion que borraremos en el address-list
$list=    "FACEBOOK";  // nombre de la lista  que borraremos 
if( $address !="" && $list!=""  ){
    $API = new routeros_api();
    $API->debug = false;
    if ($API->connect($ServerList, $Username, $Pass, $Port)) {
       $API->write("/ip/firewall/address-list/getall",false);
       $API->write('?address='.$address,false);
       $API->write('?list='.$list,true);       
       $READ = $API->read(false);
       $ARRAY = $API->parse_response($READ); // busco si ya existe
        if(count($ARRAY)>0){ 
            $ID = $ARRAY[0]['.id'];
            $API->write('/ip/firewall/address-list/remove', false);
            $API->write('=.id='.$ID, true);
       		$READ = $API->read(false);
        }else{ // si no existe lo creo
            echo 'La IP "'.$address.'" No existe en el address-list "' . $list .'" del firewall L3, no se hará nada!';
        }
        $API->disconnect();
    }
}
?>              

Primero en tech-nico.com: Por favor, pongan la fuente si van a copiar y pegar en otro sitio.!!.

Script Mikrotik para LIMITAR dispositivos móviles con DHCP con QUEUEs Dinamicas

Bloquear / Limitar

En las 3 versiones anteriores de este script podiamos «bloquear» un dispositivo movil tanto por DHCP como en el firewall del Bridge (capa 2) y en firewall capa 3.

Tal vez te interesen los scripts anteriores:
Version 1: Filtrar en Bridge Filter
Version 2: Filtrar en Firewall Filter
Version 3: Filtrar con DHCP Block

Ahora con una mínima modificación podemos controlarles el ancho de banda a cada uno de ellos. En este caso el script permite setear el RATE-LIMIT en una variable para todos los dispositivos.

########## INICIO DEL SCRIPT
:local DHCPSERVER "dhcp1";
:local LIMITE "256k";
# # www.tech-nico.com 
 
:foreach i in=[/ip dhcp-server lease find active-server=$DHCPSERVER] do={
log warning "Hola";
    :local DhcpDynMAC [/ip dhcp-server lease get $i mac-address];
                :local DhcpDynCLIENTID [/ip dhcp-server lease get $i active-client-id];
    :local DhcpDynHOST [/ip dhcp-server lease get $i host-name];
    :local phoneNAME [:pick $DhcpDynHOST 0 4];
 
    :if ( ($phoneNAME="BLUS") || ($phoneNAME="iPad") || ($phoneNAME="andr") || ($phoneNAME="Andr") || ($phoneNAME="Wind") || ($phoneNAME="iPho") || ($phoneNAME="BLAC") ) do={
        /ip dhcp-server lease set $i block-access=no  rate-limit="$LIMITE" insert-queue-before=first  mac-address="$DhcpDynMAC" use-src-mac=yes comment="$DhcpDynHOST" server="$DHCPSERVER" client-id="$DhcpDynCLIENTID";
    }
}
############## FIN DEL SCRIPT

La forma de limitar del script (sincronizando con queues) es como lo hacen algunos servidores radius.

El script recorre la lista de Leases DHCP y busca los dispositivos que comienzan con Host_name «iPad», «andr», etc. Luego lo edita, agregandole el limite de velocidad. Esto instantaneamente agrega un Queue dinamico en la lista de queues, controlando asi en el acto a cada Lease. Si el lease caduca, el queue se elimina solo, y si el lease por alguna razon renueva con otra direccion IP, tambien lo hace el queue de manera sincronizada. Es tal y como lo manejan los Servidores Radius.

Espero que lo disfruten de estas utilidades tan sencillas pero al mismo tiempo tan brillantes.

A pedido de Leonardo Jung. (excelente idea).

Saludos.

[Actualizado] Script Mikrotik para bloquear dispositivos móviles en bridge – Muy Efectivo!

Bloqueando Celulares desde Mikrotik con Bridge filter (Efectividad 80%)

NOTA: Esta es la version para filtrar por bridge, tambien podes filtrar en firewall o bloquear directamente en dhcp-server.

Me toco en un colegio tener que dejar sin navegación a los celulares. En este caso opte por armar un script que recorra la lista de Leases del DHCP Server y filtre a los hosts llamados «Android» o «Windows Phone», «Blackberry». Con lo cual podríamos estar filtrando la mayoría de los dispositivos. Creo que se van a escapar los teléfonos chinos que suelen venir con sistemas operativos bastante raros. Tambien se estan escapando los celulares con SO  de Apple (no lo pude setear porque no se cual es su Host Name). Pero bueno, no queremos llegar a la perfección.. al menos con esto he quitado de circulación unos 50 dispositivos en el primer dia. No solo me ha bajado el consumo del CPU del RB 2011 si no que ademas ha mejorado mucho el rendimiento del ancho de banda ya que los celulares están todo el tiempo bajando actualizaciones, hasta incluso estando en el bolsillo del pantalón.

¿Como los bloqueamos?

Cuando abrimos la lista de Leases en «IP — DHCP-Server» veremos un listado de todas las IP dinamicas entregadas en la red. Uno de los campos es «HOST-NAME». Ese es el que nos interesa. Vean la imagen:

leases cossettini

Lista de nombres de mobiles a filtrar:  (que yo detecte y filtre) (AMPLIAREMOS)

  • android-8d0a00d6eddf7787
  • Android_356434048181508
  • Windows-Phone
  • BLACKBERRY-8A8D
  •  (nombre en blanco)

Entonces esto es lo que vamos a usar para detectarlos.
El primero y segundo, «android, Android» estan porque con mikrotik scripting no encontré un comando para hacer Upper o Lower Case de los caracteres. BLACKBERRY me aparece 2 veces en mayusculas (en otro router) asi que por ahora lo mantendremos asi. Y buscando en los mac-address vendors pude descubrir que muchos de los dispositivos celulares que vienen con el Host-Name en blanco son Samsung, Nokia, etc. Por lo que opte por dropearlos y cuando mucho, si es una laptop… «que le ponga el nombre de equipo». jeje.

Vamos a lo nuestro:
Para que el script funcione, debemos configurarle el nombre de nuestro DHCP-Server y ademas el nombre del Bridge en el cual vamos a filtrar (Son las primeras 2 variables). Esta parte es interesante porque si tambien es tu caso, puede ser que en el mismo equipo tengas mas de un DHCP Server o mas de 1 bridge, (uno para directivos y otro para alumnos). Por lo tanto, si esto no seria seteable, estaríamos quitándote navegación a TODOS, y no queremos que los directivos se enojen porque no pueden revisar el facebook en su android. :D.

# # SCRIPT: FILTRAR CELULARES EN BRIDGE

:local DHCPSERVER "dhcp_alumnos";
:local BRIDGEFILTER "bridge-alumnos";

# # AUTOR: NICOLAS DAITSCH
# # www.tech-nico.com

:foreach i in=[/ip dhcp-server lease find dynamic=yes active-server=$DHCPSERVER]  do={
   :local DhcpDynIP [/ip dhcp-server lease get $i address];
   :local DhcpDynMAC [/ip dhcp-server lease get $i mac-address];
   :local DhcpDynHOST [/ip dhcp-server lease get $i host-name];
   :local IfMacExist [/interface bridge filter find src-mac-address="$DhcpDynMAC/FF:FF:FF:FF:FF:FF"];
   :local phoneNAME [:pick $DhcpDynHOST 0 4];

:if ( ($phoneNAME="iPad") || ($phoneNAME="S410") || ($phoneNAME="Andr") || ($phoneNAME="LANI") || ($phoneNAME="Ipho") || ($phoneNAME="S220") || ($phoneNAME="S120") || ($phoneNAME="BLUS") || ($phoneNAME="iPod") || ($phoneNAME="andr") || ($phoneNAME="Wind") || ($phoneNAME="iPho") || ($phoneNAME="BLAC") || ([:len $DhcpDynHOST]=0) ) do={
          :if ($IfMacExist != "") do={
#               :log error ("Filtrando telefono... ".$DhcpDynMAC. " Ya existe")
          } else= {
               /interface bridge filter add action=drop chain=input in-bridge=$BRIDGEFILTER src-mac-address="$DhcpDynMAC/FF:FF:FF:FF:FF:FF" comment=$DhcpDynHOST;
                 :log warning ("Se filtro un nuevo dispositivo " . $phoneNAME . " MAC: " .  $DhcpDynMAC);
          }
     }
}

Muy bien el script recoje los mac-adddress de este listado (leases), y si coinciden con alguno de los nombres que dijimos, se filtra automáticamente sin retorno.
Y digo sin retorno porque si ya lo filtro, por mas que cambie el hostname YA ESTA!!!.
Lo bueno de este script es que estamos filtrando por MAC-Address en el Bridge, cosa que resulta MUY Efectiva.

La linea que dice:

($phoneNAME="androi") || ($phoneNAME="Window")

Esta tomando los primeros 6 caracteres del hostname. Entonces podríamos seguir agregando nombres de dispositivos seteados de fabrica con un nombre por default. Ejemplo: «Iphone»   —  justo 6.  Que yo estimo, «rara vez se modifica».

ATENTOS: Si alguien sabe como aparece el hostname del IPhone u algun otro dispositivo que no este contemplado, por favor deje un comentario y vamos actualizando el script.

Frecuencia de ejecucion del script y leases dhcp:
Lo tengo seteado en el Scheduler cada 10 minutos, Cosa que por mas que el «Lease dhcp» quede activo, ese dispositivo ya no navega. Lo que pueden hacer es setear los Leases del DHCP en 10 minutos (menos tiempo), o bien agregarle al script que tambien patee el lease. Pero ya no es necesario… cuando caduca su tiempo, ya no vuelve a aparecer mas.

Saludos! ! ! .

________________________
Este post se escribio primero en Tech-nico.com

Script Mikrotik para hacer parpadear un led del router.

Vos dirás.. y para que lo quiero?. Tal como dice el creador del script (foro Mikrotik) podría servir para señalar remotamente (al tecnico in-situ) cual es el equipo que tiene que supervisar. Lo acabo de probar y me anduvo bien. Es una pabada, pero a mi me encantó. 🙂

Importar por consola

add name=ParpadearLed policy=read,write,policy,test,sensitive source="# CONFIGURAR CANTIDAD DE PARPADEOS\r\
\n:local count 10\r\
\n# SETEAR EL LED QUE QUREMOS MANEJAR a) wlan-led b) led1 c) user-led\r\
\n:local led led1\r\
\n# NO EDITAR DE ACA PARA ABAJO\r\
\n:local numb 0\r\
\n:local test [ /system leds find leds~\"\$led\" ]\r\
\n:if (\$test = \"\") do={ /system leds add leds=\$led type=on }\r\
\n:local test2 [ /system leds find leds~\"\$led\" ]\r\
\n:local state [ /system leds get value-name=type number=\$test2 ]\r\
\n:while (\$numb &lt; \$count) do={\r\
\n :set \$numb (\$numb + 1)\r\
\n /system leds set numbers=\$test2 type=on\r\
\n :delay 0.5\r\
\n /system leds set numbers=\$test2 type=off\r\
\n :delay 0.5\r\
\n}\r\
\n/system leds set type=\$state numbers=\$test2"

Script Mikrotik para bloquear dispositivos moviles en Firewall

Bloqueando Celulares desde Mikrotik con Firewall (Efectividad 80%)

NOTA: Esta es la version para filtrar por firewall, tambien podes filtrar en bridge filter o bloquear directamente en dhcp-server.

Me toco en un colegio tener que dejar sin navegación a los celulares. En este caso opte por armar un script que recorra la lista de Leases del DHCP Server y filtre a los hosts llamados «Android» o «Windows Phone», «Blackberry». Con lo cual podríamos estar filtrando la mayoría de los dispositivos. Creo que se van a escapar los teléfonos chinos que suelen venir con sistemas operativos bastante raros. Con esto he quitado de circulación unos 50 dispositivos en el primer dia. No solo me ha bajado el consumo del CPU del RB 2011 si no que ademas ha mejorado mucho el rendimiento del ancho de banda ya que los celulares están todo el tiempo bajando actualizaciones, hasta incluso estando en el bolsillo del pantalón. Quizas te interese saber como bloquear las actualizaciones de android.

¿Como los bloqueamos?

Cuando abrimos la lista de Leases en «IP — DHCP-Server» veremos un listado de todas las IP dinamicas entregadas en la red. Uno de los campos es «HOST-NAME». Ese es el que nos interesa. Vean la imagen:

leases cossettini

Lista de nombres de mobiles a filtrar:  (que yo detecte y filtre) (AMPLIAREMOS)

  • android-8d0a00d6eddf7787
  • Android_356434048181508
  • Windows-Phone
  • BLACKBERRY-8A8D
  •  (nombre en blanco)

Entonces esto es lo que vamos a usar para detectarlos.
El primero y segundo, «android, Android» estan porque con mikrotik scripting no encontré un comando para hacer Upper o Lower Case de los caracteres. BLACKBERRY me aparece 2 veces en mayusculas (en otro router) asi que por ahora lo mantendremos asi. Y buscando en los mac-address vendors pude descubrir que muchos de los dispositivos celulares que vienen con el Host-Name en blanco son Samsung, Nokia, etc. Por lo que opte por dropearlos y cuando mucho, si es una laptop… «que le ponga el nombre de equipo». jeje.

Vamos a lo nuestro:
Para que el script funcione, debemos configurarle el nombre de nuestro DHCP-Server y ademas el nombre de la interfaz de tu LAN en el cual vamos a filtrar (Son las primeras 2 variables). Esta parte es interesante porque si tambien es tu caso, puede ser que en el mismo equipo tengas mas de un DHCP Server o mas de 1 LAN, (una red para directivos y otro para alumnos). Por lo tanto, si esto no seria seteable, estaríamos quitándote navegación a TODOS, y no queremos que los directivos se enojen porque no pueden revisar el facebook en su android. :D.

Muy bien el script recoje los mac-adddress de este listado (leases), y si coinciden con alguno de los nombres que dijimos, se filtra automáticamente sin retorno.
Y digo sin retorno porque si ya lo filtro, por mas que cambie el hostname YA ESTA!!!.
Lo bueno de este script es que estamos filtrando por MAC-Address en el Bridge, cosa que resulta MUY Efectiva.

La linea que dice:

($phoneNAME="androi") || ($phoneNAME="Window")

Esta tomando los primeros 6 caracteres del hostname. Entonces podríamos seguir agregando nombres de dispositivos seteados de fabrica con un nombre por default. Ejemplo: «Iphone»   —  justo 6.  Que yo estimo, «rara vez se modifica»..

Frecuencia de ejecucion del script y leases dhcp:
Lo tengo seteado en el Scheduler cada 10 minutos, Cosa que por mas que el «Lease dhcp» quede activo, ese dispositivo ya no navega. Lo que pueden hacer es setear los Leases del DHCP en 10 minutos (menos tiempo), o bien agregarle al script que tambien patee el lease. Pero ya no es necesario… cuando caduca su tiempo, ya no vuelve a aparecer mas.

# # SCRIPT: FILTRAR CELULARES EN FIREWALL (SIN BRIDGE)

:local DHCPSERVER "dhcp_alumnos";
:local INTERFACEFILTER "bridge-alumnos";

# # AUTOR: NICOLAS DAITSCH
# # www.tech-nico.com

:foreach i in=[/ip dhcp-server lease find dynamic=yes active-server=$DHCPSERVER]  do={
   :local DhcpDynIP [/ip dhcp-server lease get $i address];
   :local DhcpDynMAC [/ip dhcp-server lease get $i mac-address];
   :local DhcpDynHOST [/ip dhcp-server lease get $i host-name];
   :local IfMacExist [/ip firewall filter find src-mac-address="$DhcpDynMAC"];
   :local phoneNAME [:pick $DhcpDynHOST 0 6];

    :if ( ($phoneNAME="androi") || ($phoneNAME="Window") || ($phoneNAME="Androi")  || ($phoneNAME="BLACKB") || ([:len $DhcpDynHOST]=0) ) do={
          :if ($IfMacExist != "") do={
#               :log error ("Filtrando telefono... ".$DhcpDynMAC. " Ya existe")
          } else= {
               /ip firewall filter add action=drop chain=input in-interface=$INTERFACEFILTER src-mac-address="$DhcpDynMAC" comment=$DhcpDynHOST;
                 :log warning ("Se filtro un nuevo dispositivo " . $phoneNAME . " MAC: " .  $DhcpDynMAC);
          }
     }
}

Saludos! ! ! .

________________________
Este post se escribio primero en Tech-nico.com

Script Mikrotik para bloquear dispositivos móviles con DHCP

El script nacio por un comentario de nuestro colaborador «Felix Serrato» que NO vio la necesidad de bloquear los dispositivos celulares usando firewall o bridge filter. Es decir, bloquearlos directamente en los «leases» del dhcp-server y ademas que el board Mikrotik utilice menos recursos (si es que hay muchos dispositivos para bloquear en tu red).

Efectividad: 

Si bien el script es muy efectivo, probando me encontré con la particularidad de que no bloquea al instante. Te bloquea el lease (para que, A tu mac-address ya no le pueda entregar nunca mas una direccion IP), pero al filtrar por DHCP, no te quita la navegacion hasta que tu dispositivo vuelva a pedir una nueva solicitud DHCP. Una vez que apago y enciendo el Wifi de mi celular queda en «Obteniendo una direccion IP». Sin embargo los 2 scripts mencionados al principio (por bridge y por firewall), filtran en el acto.

Funcionamiento:

El script busca en la lista de dhcp-server leases todos los clientes conectados con el flag «dynamic=yes» y donde el dhcp server sea el que definimos en la variable DHCPSERVER. Esto es por si tenemos mas de 1 servidor dhcp para no filtrar en todos. Busca el host-name coincida con «Android», «iPad», etc, entonces agrega un nuevo lease con el flag «block-access=yes» para ese mac. Finalmente libera a todos los leases con ese nombre para no ocupar una direccion IP.

Solo hay que definirle el nombre del DHCP-server.

########## INICIO DEL SCRIPT
:local DHCPSERVER "dhcp1";
# # www.tech-nico.com 

:foreach i in=[/ip dhcp-server lease find dynamic=yes active-server=$DHCPSERVER] do={
	:local DhcpDynMAC [/ip dhcp-server lease get $i mac-address];
                :local DhcpDynCLIENTID [/ip dhcp-server lease get $i active-client-id];
	:local DhcpDynHOST [/ip dhcp-server lease get $i host-name];
	:local phoneNAME [:pick $DhcpDynHOST 0 4];

	:if ( ($phoneNAME="BLUS") || ($phoneNAME="iPad") || ($phoneNAME="andr") || ($phoneNAME="Andr") || ($phoneNAME="Wind") || ($phoneNAME="iPho") || ($phoneNAME="BLAC") ) do={
		/ip dhcp-server lease add block-access=yes mac-address="$DhcpDynMAC" use-src-mac=yes comment="$DhcpDynHOST" server="$DHCPSERVER" client-id="$DhcpDynCLIENTID";
	}
}
/ip dhcp-server lease remove [find host-name~"BLUS*"]
/ip dhcp-server lease remove [find host-name~"android*"]
/ip dhcp-server lease remove [find host-name~"Android*"]
/ip dhcp-server lease remove [find host-name~"Windows*"]
/ip dhcp-server lease remove [find host-name~"iPad*"]
/ip dhcp-server lease remove [find host-name~"iPhone*"]
/ip dhcp-server lease remove [find host-name~"BLACKBERRY*"]
############## FIN DEL SCRIPT

API MIKROTIK – Graficar trafico de interfaces en tiempo real con Highcharts y PHP

Te voy a enseñar como graficar en vivo una interfaz en particular de tu RouterOS. El ejemplo que arme en esta ocasión con las fabulosas, increíbles gráficas highcharts.com. (tal como lo pidio Cesar Maffini).

Si te interesa podes continuar leyendo una actualizacion de este post con bastantes mejoras: Graficar Interfaces y Queues con Highcharts version mejorada

Actualización: un fiel lector de nombre Alejandro Mogollon nos armo un video tutorial para demostrar que es muy muy facil la puesta en marcha.

El codigo tiene 3 archivos:

1) api_mt_include2.php: API RouterOS.
2) data.php: Conecta a RouterOS, trae TX, RX y los imprime en formato JSON.
3) index.html: Utiliza Ajax para llamar data.php cada 1 segundo y graficar puntos en tiempo real usando highcharts.
highchart_tech-nico.com_API_MIKROTIK

El codigo esta muy muy facil. Vamos a resumirlo:

index.html

           chart = new Highcharts.Chart({
			   chart: {
				renderTo: 'container',
				animation: Highcharts.svg,
				type: 'spline',
				events: {
					load: function () {
						setInterval(function () {
							requestDatta(document.getElementById("interface").value);
						}, 1000);
					}
			}
		 },

Sin duda esta es la parte mas importante del codigo En la linea donde comienza el setInterval lo que hace es llamar a la funcion requestDatta() y pasarle como parametro el nombre de la interfaz de red de nuestro Mikrotik que queremos graficar en tiempo real, cada 1 segundo. Esto funciona con cualquier interfaz. Bridge, Vlan, pppoe, Wlan, etc. En este caso, el parametro con el nombre de la interfaz que le vamos a pasar a la funcion requestDatta lo asigne a un campo de texto editable para hacerlo un poco mas interesante.

	function requestDatta(interface) {
		$.ajax({
			url: 'data.php?interface='+interface,
			datatype: "json",
			success: function(data) {
				var midata = JSON.parse(data);
				if( midata.length > 0 ) {
					var TX=parseInt(midata[0].data);
					var RX=parseInt(midata[1].data);
					var x = (new Date()).getTime();
					shift=chart.series[0].data.length > 19;
					chart.series[0].addPoint([x, TX], true, shift);
					chart.series[1].addPoint([x, RX], true, shift);
					document.getElementById("trafico").innerHTML=TX + " / " + RX;
				}else{
					document.getElementById("trafico").innerHTML="- / -";
				}
			}

Aqui, como explicábamos mas arriba, tenemos la función que se conecta al RouterOS y nos trae el dato de TX / RX de la interfaz que nosotros le pidamos.
Los datos que traemos de data.php estan en formato JSON, por lo tanto los tenemos que parsear para poner cada dato en una variable y luego graficar el punto en el Highchart. Si se fijan, es muy importante convertir el valor que viene en JSON a numero «parseINT».

La linea, shift=chart.series[0].data.length > 19; la usamos para que, cada vez que agregamos un punto nuevo, guardemos un indice con la cantidad de puntos, que le va a decir al chart cuando comenzar a pisar los valores antiguos de la serie.

Aqui pego las lineas con comentario:

	var TX=parseInt(midata[0].data);   // UPLOAD
	var RX=parseInt(midata[1].data);   // DOWNLOAD
	var x = (new Date()).getTime();    // tooltip cuando hacemos hover en el punto
	shift=chart.series[0].data.length > 19;  // indice de cantidad de puntos
	chart.series[0].addPoint([x, TX], true, shift);  // agrego TX en SERIE 0
	chart.series[1].addPoint([x, RX], true, shift);  // agrego RX en SERIE 1

Podemos agregar la cantidad de series que queramos; solo que mas abajo tenemos que definirlas asi:

            series: [{
                name: 'TX',
                data: []
            }, {
                name: 'RX',
                data: []
            }]

Con esto de arriba, tendriamos serie0 y serie1 (siempre contamos de arriba hacia abajo).
Presten atencion que «data» esta vacio, ya que nosotros le agregamos los puntos en tiempo de ejecución.
Si se nos ocurre graficar un tercer valor a la par de TX y RX lo haríamos definiendo otra serie, de esta manera:

series: [{
name: ‘TX’,
data: []
}, {
name: ‘RX’,
data: []
}, {
name: ‘RX’,
data: []
}]

Aca tendriamos, serie0, serie1 y serie2.
Espero que se entienda.

data.php
Este archivo como dijimos mas arriba es el que se conecta al routerOS y hace su trabajito. Editen las primeras lineas con los datos de su servidor Mikrotik.

Usaremos el comando /interfaces/monitor-traffic
Este nos pide el nombre de la interfaz, que ya la traemos desde el otro archivo.

		   $API->write("/interface/monitor-traffic",false);
		   $API->write("=interface=".$interface,false);
		   $API->write("=once=",true);

Esto ya lo hemos explicado en los posts anteriores, así que solo quiero detallar que la ultima linea dice =once= para que el trafic monitor, ejecute el comando 1 vez y pare. Si no ponemos este comando, se queda trabado, trayendo y trayendo el trafico en tiempo real, pero de manera infinita, con esto nos aseguramos que lo haga 1 vez.

Espero que les guste tanto como a mi. Investiguen un poco las graficas lindas que tiene higcharts porque son fantasticas y por supuesto si tienen modificaciones, mejoras, etc no duden en pasar un mail que las posteamos!!

Estoy pensando en usar github para control de versiones 😀

Descargar el codigo fuente completo

Se escribió primero en Tech-nico.com por Nicolas Daistch

Mikrotik Script: Marcar y controlar trafico de whatsapp por DNS

whatsappSi queremos controlar el ancho de banda de whatsapp por QoS o dropear o simplemente dejar pasar este trafico, podemos ejecutar este maravilloso script desde nuestro RouterOS, que recolecta las IP que usa esta aplicación de mensajería.

Las IP que recolecta realmente son MUCHAS!.

whatsapp_ips

 
Entonces, pegamos este codigo en la consola de comandos de routerOS y luego lo configuramos en el scheduler para que se ejecute cada 2 minutos. (o menos, dependiendo del procesador de tu equipo).
 

/system script add name=whatsapp policy=read,write,policy source="# chequear las entradas al \
    DNS\r\
    \n:foreach i in=[/ip dns cache find] do={\r\
    \n:local bNew \"true\";\r\
    \n:local cacheName [/ip dns cache all get \$i name] ;\r\
    \n# Revisar el DNS si contiene cadenas whatsapp\r\
    \n:if ([:find [/ip dns cache get \$i name] \"whatsapp\"] > 0) do={\r\
    \n:local tmpAddress [/ip dns cache get \$i address] ;\r\
    \n#---- Si address list esta vacio, no lo chequeo ( add address directly )\
    \r\
    \n:if ( [/ip firewall address-list find ] = \"\") do={\r\
    \n/ip firewall address-list add address=\$tmpAddress list=whatsapp_dns_ips\
    \_disabled=no comment=\$cacheName; \r\
    \n} else={\r\
    \n#------- chequeo cada entrada del address-list para no repetir las ips\r\
    \n:foreach j in=[/ip firewall address-list find ] do={\r\
    \n#---------- set bNew variable to false if address exists in address list\
    \r\
    \n:if ( [/ip firewall address-list get \$j address] = \$tmpAddress ) do={\
    \r\
    \n:set bNew \"false\";\r\
    \n}\r\
    \n}\r\
    \n#------- Si la direccion (IP) es nueva, la agrego al ADDRESS-LIST\r\
    \n:if ( \$bNew = \"true\" ) do={\r\
    \n/ip firewall address-list add address=\$tmpAddress list=whatsapp_dns_ips\
    \_disabled=no comment=\$cacheName; \r\
    \n}\r\
    \n}\r\
    \n}\r\
    \n}"

Script Mikrotik, mandar backup por FTP

Un usuario del foro oficial de mikrotik publico un pequeño script para enviar un backup de nuestro RouterOS por FTP. Muy bueno para automatizar nuestros routers y enviar todos los backups a una caja NAS.

/system backup save name="filename"

/tool fetch address="ftpaddress" src-path="filename.backup" \
user="ftpuser" mode=ftp password="ftppassword" \
dst-path="Path of your ftp(/Mt-Backup/filename.backup)<--example" upload=yes

delay 10;
/file remove filename.backup

_________
publicado en tech-nico.com

API MIKROTIK – Crear queues simples con PHP (con validacion)

Hola señores, el codigo para agregar un Queue Simple validando que no se duplique ningún cliente seria asi:

ACTUALIZADO: agrega un queue si no existe el nombre, y si existe, lo edita.

<?php require_once('api_mt_include2.php'); ?>
<?php

/// AUTOR: Tech-Nico.com ///
/// admin@tech-nico.com /////
///  API: agrega un queue simple y si este existe lo edita.
/// Editado: 03/05/2015 

//////// configura tus datos
$ServerList ="192.168.100.1"; //ip_de_tu_API
$Username ="api"; //usuario_API
$Pass ="#pass"; //contraseña_API
$Port ="8727"; //puerto_API
/// VARIABLES DE FORMULARIO
$target= "192.168.0.5";  // IP Cliente
$name=    "nicolas222";
$maxlimit=    "5M/5M";
$comment= "Este es un ejemplo.";
if( $target !="" ){
    $API = new routeros_api();
    $API->debug = false;
    if ($API->connect($ServerList, $Username, $Pass, $Port)) {
       $API->write("/queue/simple/getall",false);
       $API->write('?name='.$name,true);
       $READ = $API->read(false);
       $ARRAY = $API->parse_response($READ);
        if(count($ARRAY)>0){ // si el nombre de usuario "ya existe" lo edito
			$API->write("/queue/simple/set",false);
			$API->write("=.id=".$ARRAY[0]['.id'],false);
            $API->write('=max-limit='.$maxlimit,true);   //   2M/2M   [TX/RX]
			$READ = $API->read(false);
			$ARRAY = $API->parse_response($READ);
            echo "Error: El nombre no puede estar duplicado, el queue fue editado.";
            echo '<img src="../images/icon_error.png" />';
        }else{
            $API->write("/queue/simple/add",false);
            $API->write('=target='.$target,false);   // IP
            $API->write('=name='.$name,false);       // nombre
            $API->write('=max-limit='.$maxlimit,false);   //   2M/2M   [TX/RX]
            $API->write('=comment='.$comment,true);         // comentario
            $READ = $API->read(false);
            $ARRAY = $API->parse_response($READ);
            echo "El Usuario $name, ha sido creado con exito!.";
            echo '<img src="../images/okicon.png" />';
        }
        $API->disconnect();
    }
}
?>

Descargar el Descargar_ejemplo_actualizado_03-05-2015

No hay mucho que explicar porque esta comentado el codigo y explicado en los post anteriores.

API MIKROTIK – Como optimizar tu administracion con un poco de PHP (introduccion)

API MIKROTIK Segunda parte – Usando el API con PHP

API MIKROTIK Tercera parte – Nuestro primer ejemplo (codigo abierto)

_________________
Nicolas
Primero en Tech-nico.com

Mikrotik bloquear actualizaciones de Android en firewall

Estoy implementando algunas reglas para mejorar el ancho de banda de un colegio. Esta me parece una muy buena practica. Aquí la dejamos anotada por si acaso.

Ir a la consola y ejecutar esto.

/ip firewall filter add action=drop chain=forward port=5228 protocol=tcp
/ip firewall filter add action=drop chain=forward port=5228 protocol=udp

Luego, si sos tan amable, arrastra las reglas para arriba de tu firewall y tener la seguridad de que se ejecuten.
_______________________
Este post se publico primero en Tech-nico.com

Script Mikrotik para patear un cliente registrado con mala señal

Hola amigos, bueno, este script no es muy nuevo que digamos. Pero lo voy a postear porque le hice un agregado para mi gusto bastante importante.
En este caso, se trata de un routerboard 2011 con Wifi, y va a instalarse en un colegio. Como hay muchos celulares y netbooks, la clave del funcionamiento esta en patear cada 1 minuto los clientes que tienen muy mala señal. Y ademas, dentro del mismo script, tambien eliminaremos el «lease» del DHCP-Server.

Esto sirve para darle mucho mas rendimiento al AP, ya que si hay muchos dispositivos (celulares, tablets, netebooks de «conectar igualdad») con baja señal, el radio tiene que manejar demasiadas peticiones con re-transmicion de paquetes y llegado a un punto hasta se puede plantar.

Veran que donde dice «-86» es el tope de señal que yo configure para cuando el cliente este conectado con -87 o mas… lo saque de circulación. Ustedes pueden setear el que mas les guste.

/system script
add name=station-check-signal policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive source="/interfac\
    e wireless registration-table;\r\
    \n:foreach i in=[ /interface wireless registration-table find ap=no] do={\r\
    \n   :local SIGNAL ([:pick ([get \$i signal-strength]) 0 3]);\r\
    \n   :if (\$SIGNAL < \"-86\") do={\r\
    \n           :local MAC [get \$i mac-address];\r\
    \n           :log warning (\$MAC . \" fue desconectado por baja se\F1al:  \"\
    \_.\$SIGNAL );\r\
    \n           /interface wireless registration-table remove \$i;\r\
    \n# PATEO EL DHCP DEL CLIENTE CON MALA SE\D1AL\r\
    \n          /ip dhcp-server lease;\r\
    \n           :foreach s in=[find] do={\r\
    \n                  /ip dhcp-server lease;\r\
    \n                   :if ([get \$s active-mac-address] = \$MAC) do={\r\
    \n                           :log warning (\"DHCP pateado por script de mala\
    \_se\F1al:  \" .\$MAC );\r\
    \n                           /ip dhcp-server lease remove \$s;\r\
    \n                   }\r\
    \n           }\r\
    \n           :delay 5s;\r\
    \n     }\r\
    \n}"

Solución al script de DuckDNS en Mikrotik RouterOS

Cuando quisiste usar DuckDNS.org en tu RouterOS tuviste problemas con la instalación?. Bueno a mi me paso que el script «corría»  pero no me devolvía nunca el resultado deseado (mas claro: NO ANDABA). Depurando linea por linea me di cuenta que el problema no era el script si no la vesion de mi RouterOS.

¿para que uso DuckDNS?
Para el que no lo conoce, se usa para cuando tenes un sitio remoto con IP publica Dinamica y queres accederlo desde afuera. Tambien podes usarlo para una camara IP.
En este caso, el script del routerOS se encarga de que cuando la IP cambie… el sistema de duckDNS guarde la nueva IP. Entonces cada vez que accedas a tudominio.duckdns.org vas a entrar a tu routerOS sin problemas.

Para el que no lo usa, la instalación es super sencilla:
La instalacion del script es muy sencilla solo basta con copiar y pegar y tan solo modificar «domains» por tu dominio y el «token» por el que te de al hacer login y «agregar un dominio».

domains=exampledomain&token=a7c4d0ad-114e-40ef-ba1d-d217904a50f2

Aqui abajo el script completo:

:global currentIP;
:local newIP [/ip cloud get public-address];
:if ($newIP != $currentIP) do={
    :log info "IP address $currentIP changed to $newIP";
    :set currentIP $newIP;
    /tool fetch mode=https url="https://www.duckdns.org/update?domains=exampledomain&token=a7c4d0ad-114e-40ef-ba1d-d217904a50f2&ip=$newIP" dst-path=duckdns.txt;
    :local result [/file get duckdns.txt contents];
    :log info "Duck DNS update result: $result";
}

Conclusión y forma de resolverlo:
RouterOS agrego el «https»del comando fetch en la version 6.0, es por eso que el script no corre. Lo unico que hay que hacer es actualizar el RouterOS a la version 6.X.

Escribir Scripts para Mikrotik con el editor Sublime Text

Ahora es mucho mas fácil poder escribir código usando el famoso editor gratuito «Sublime Text» que permite entre otras cosas el highlight de los comandos, funciones, variables, comentarios, etc., para que todo sea mas legible y eficaz.
Un ayudante del foro de Mikrotik nos hizo este gran aporte que realmente es de gran ayuda para nosotros los fanáticos.

El paquete esta disponible para instalarlo desde el administrador de paquetes de Sublime o bien descargarlo desde Github.

mikrotik sublime text

API MIKROTIK – Manipular Wireless-Registration y Access-List con PHP y MYSQL

En esta ocasión, te traigo un pequeño sistema desarrollado en php y mysql para que puedas controlar cada cliente de un nodos AP de distintas o una misma localidad. Esto te permitirá habilitar/deshabilitar un MacAddress del access-list de muchísimos AP desde un solo lugar, tambien ver el nivel de señal y patearlo para que re-conecte cuando sea necesario.

Editamos el archivo config.php con los datos del mysql y con el usuario y contraseña del API. Este es el usuario y contraseña que va a utilizar el sistema para acceder a todos los equipos routerboard que cargues.

//////// Base de datos //////////////
$hostname_myCnx = "localhost";
$database_myCnx = "manage_isp";
$username_myCnx = "root";
$password_myCnx = "";

/// API ///  Se usa el mismo para todos los routerboards.
$Username ="tusuario";
$Pass ="tucontraseña";

Base de datos MYSQL
Las tablas son 4, por supuesto que aqui faltan muchas cosas, como la tabla de Login, de Logs, de bajas. etc, pero para mostrar un ejemplo totalmente funcional nos alcanza con estas 4.
Tabla Categorías: Contiene si el cliente es 2,4 ghz o 5,8 por ejemplo.
Tabla Localidades: Como su nombre lo dice aquí cargaremos las localidades.
Tabla Internet: Aquí cargaremos nuestros clientes a los que les brindamos internet. Esta tabla tiene 2 campos importantes. «ip_equipo_inalambrico» es el campo que nos identifica el equipo por el comentario que le demos en el «access-list» del RouterOS. Podemos escribirle su direccion IP o bien un string que lo identifique. Luego el campo «activo» es para identificar que hemos cortado el servicio por falta de pago. Simplemente lo identifica con 0 o 1 si esta activo y por supuesto lo activa/desactiva del access-list, identificándolo con el campo anterior «ip_equipo_inalambrico».
Tabla Puntos_de_acceso: Aquí cargaremos en cada localidad (ejemplo: Liniers) y categoría (ejemplo: 2,4 Ghz), el o los puntos de acceso que necesitemos. Entonces si en Liniers tenemos 2 o 3 puntos de acceso, el cliente lo va a buscar en los 3 puntos de acceso hasta que lo encuentre. Por supuesto que si tenemos muchos puntos de acceso para 1 localidad quizás se pueda hacer mas lenta la busqueda. De todos modos podemos crear «Barrios o Zonas» (en vez de localidades) para que el sistema haga mas rapida la busqueda. Se entiende?. Aqui hay 2 cosas a recalcar, Cuando busca un cliente, lo busca «conectado» en el wireless-registration-table, esto es asi, para poder usar el sistema no solo para desactivar un cliente sino que ademas para poder tomar un reclamo. Y claro que cuando activa o desactiva lo hace en el access-list 🙂 .

CREATE DATABASE IF NOT EXISTS `manage_isp` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `manage_isp`;

CREATE TABLE `categorias` (
  `id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
  `descripcion` char(100) DEFAULT '0',
  `default` int(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;

CREATE TABLE `internet` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `numloca` int(2) NOT NULL DEFAULT '1',
  `apellido` char(100) DEFAULT NULL,
  `descripcion` char(100) DEFAULT NULL,
  `categoria` int(1) DEFAULT '0',
  `ip_equipo_inalambrico` char(40) DEFAULT NULL,
  `activo` int(1) DEFAULT NULL,
  `fecha_alta` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;

CREATE TABLE `localidades` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `nombre` char(80) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;

CREATE TABLE `puntos_de_acceso` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `nombre` char(50) DEFAULT NULL,
  `localidad` int(6) DEFAULT NULL,
  `categoria` int(6) DEFAULT NULL,
  `modo_neighbords` int(1) DEFAULT NULL,
  `ip` char(15) DEFAULT NULL,
  `puerto` int(5) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;

Estructura de la base de datos: Pueden importar el achivo «.sql» que esta junto a los archivos a descargar, y luego lo borran por seguridad.

Pantalla principal:
main

1) Primer paso, recomiendo cargar las localidades, para ello vamos a {Nueva Localidad}.
nueva_localida

2) Luego volvemos a la pantalla principal cargamos los Nodos AP o puntos de acceso en el link {Nuevo Punto de Acceso}
nuevo_nodo
Aqui necesitaremos elegir la localidad ( o zona), por eso es importante que primero carguemos las localidades del paso 1.
Para que el API pueda ver la señal de los equipos en el Wireless registration table de cada RB, tenemos que elegir la categoría «INALAMB 2,4» y el modo «Mikrotik Wireless»
Y finalmente, lo mas importante, tenemos que cargar la IP y puerto de nuestro Routerboard para esa localidad o zona que estemos generando. Si el RB tiene una IP privada, hacemos un port-forwarding en el router donde este la IP publica.
El modo «Mikrotik Neighbords» No esta probado pero debería estar funcionando, se usa para la categoría «INALAMB 5,8» y poder ver si el equipo cliente esta conectado. Como se trata de un AP «Ubiquiti Rocket» del cual no tenemos acceso mediante el API, lo que hacemos es acceder al API del router principal donde se encuentra conectado el Rocket y acceder al IP-Neighbords. Este nos va a mostrar todos los clientes (si el equipo esta encendido) para poder atender un reclamo y ademas ver cual es su firmware.

3) Volvemos a la pantalla principal y hacemos click sobre algun cliente.
Como ejemplo hay 2 para clickear. Editamos la localidad y categoría, presionamos en el boton [Guardar] y volvemos a entrar. Finalmente, donde dice «Ip Equipo», le ingresamos la IP o algun identificador que hayamos puesto en el comentario del access-list. Si presionan [Enter] hara una busqueda para, si el cliente esta conectado en este momento, trae sus datos.
modificar_cliente

En IP Equipo podemos poner lo que haya en el comentario, me ha pasado que no toma la primer palabra, siempre las ultimas. Tiene que ser un identificador «Unico» ya que con esto controlaremos si se activa o desactiva.
Al darle [enter], deberiamos ver datos de señal, CCQ, TimeUp. Etc. Como ejemplo les pongo una imagen de otro sistema que había hecho para uso propio.
Vean que, usando su imaginacion pueden integrar todo lo que deseen.
ejemplo_sistema

4) Volvemos a la pantalla principal y veremos que en el link {Nuevo Cliente} aparece la pantalla:
nuevo_cliente

Revisen como esta hecho y veran que es muy facil editarlo. Cualquier duda, sugerencia o error, seran contestados aqui en los comentarios.

Les dejo el link para descargar los archivos.

Saludos amigos!!
___________________________
Publicado primero en tech-nico.com

API MIKROTIK – Patear un cliente PPPoE activo

En esta ocasión voy a publicar un código sencillo pero que varios lectores me han consultado como se hace. El codigo se utiliza con el include para manejar el API, que pueden encontrar en cualquiera de las publicaciones anteriores.

<?php require_once('api_mt_include2.php'); ?>
<?php
////////////////////////////////////////////////////////////////////
// ESTE EJEMPLO SE DESCARGO DE www.tech-nico.com ///////////////////
// Creado por: Nicolas Daitsch. Guatrache. La Pampa ////////////////
// Contacto: administracion {@} tech-nico.com //////////////////////
// RouterOS API: Busco cliente pppoe activo y lo pateo  ////////////
////////////////////////////////////////////////////////////////////

$ipRouteros="200.20.30.40";  // tu RouterOS. 
$Username="blog.tech-nico.com"; 
$Pass="tupassword"; 
$api_puerto=8728; 
$name = "dolores";  // ---- nombre del usuario pppoe

    $API = new routeros_api();
    $API->debug = false;
    if ($API->connect($ServerList , $Username , $Pass, $Port)) {
       $API->write("/ppp/active/getall",false);
       $API->write('?name='.$name,true);      
       $READ = $API->read(false);
       $ARRAY = $API->parse_response($READ);
        if(count($ARRAY)>0){ // si el usuario esta activo lo pateo.
             $API->write("/ppp/active/remove",false);	
             $API->write("=.id=".$ARRAY[0]['.id'],true);
             $READ = $API->read(false);
             $ARRAY = $API->parse_response($READ);
        }
       $API->disconnect();
    }
?>

__________________
primero en www.tech-nico.com

Mikrotik Script: ejecutar un script si aparece cierta palabra o frase en el Log.

En el foro de Mikrotik un participante ha posteado algo interesante!!

Creo que el titulo esta bastante claro, es un script que detecta cierto contenido en el log, y luego ejecuta «otro script».

Script:

:global lastTime;

:local currentBuf [ :toarray [ /log find message~"wrong peer state" || message~"master flag=false" ] ] ;
:local currentLineCount [ :len $currentBuf ] ;

if ($currentLineCount > 0) do={
   :local currentTime "$[ /log get [ :pick $currentBuf ($currentLineCount -1) ] time ]";

   :if ([:len $currentTime] = 15 ) do={
      :set currentTime [ :pick $currentTime 7 15 ];
   }

   :local output "$currentTime $[/log get [ :pick $currentBuf ($currentLineCount-1) ] message ]";

   :if (([:len $lastTime] < 1) || (([:len $lastTime] > 0) && ($lastTime != $currentTime))) do={
      :set lastTime $currentTime ;
      /system script run myScript
   }
}

ver el post completo en el foro de Mikrotik

Primero en tech-nico.com

API MIKROTIK – Activar o desactivar un puerto ethernet

A pedido del lector Vitor Monteiro, vamos a presentar un pequeño y facil ejemplo para habilitar o deshabilitar un puerto ethernet con cierto nombre.

¿Como funciona?
Lo que vamos a hacer es definir una variable llamada $name que va a contener el nombre de la interfaz que queremos activar o desactivar. El script verifica primero si ese nombre existe, luego, (si existe), almacenamos «el ID» y si «esta activa o no» en distintas variables. Si esta activa, entonces tomamos el ID y la desactivamos, de lo contrario, la habilitamos.

El codigo es el siguiente:

<?php require_once('api_mt_include2.php'); ?>
<?php 

////////////////////////////////////////////////////////////////////
// ESTE EJEMPLO SE DESCARGO DE www.tech-nico.com ///////////////////
// Creado por: Nicolas Daitsch. Guatrache. La Pampa ////////////////
// Contacto: administracion@tech-nico.com //////////////////////////
// RouterOS API: Busco interfaz ethernet y la activo o desactivo  //
////////////////////////////////////////////////////////////////////

$ipRouteros="200.20.30.40";  // tu RouterOS. 
$Username="blog.tech-nico.com"; 
$Pass="tupassword"; 
$api_puerto=8728; 
$name="ether1";    // -------> aqui el nombre de tu interfaz!!

$API = new routeros_api();
$API->debug = false;
if ($API->connect($ipRouteros , $Username , $Pass, $api_puerto)) {
	   $API->write("/int/ether/getall",false);
	   $API->write('?name='.$name,true);
	   $READ = $API->read(false);
	   $ARRAY = $API->parse_response($READ);
	   if(count($ARRAY)>0){ // SI LA INTERFAZ EXISTE!!
	   		$id_interfaz = $ARRAY[0][".id"];
	   		$disabled = $ARRAY[0]["disabled"];
			if ($disabled=="true"){ // SI ESTA DESACTIVADA!!
				$API->write("/int/ether/enable",false);
				$API->write("=.id=".$id_interfaz,true);
           		echo '<strong>'.$name.'</strong> esta ahora activada <img alt="" src="icon_led_green.png" /> ';
			}else{ // SI ESTA ACTIVADA!!
				$API->write("/int/ether/disable",false);
				$API->write("=.id=".$id_interfaz,true);
				echo '<strong>'.$name.'</strong> esta ahora desactivada <img alt="" src="icon_led_grey.png" /> ';
			}
			$READ = $API->read(false);
    }else{  //el servidor API esta of line
           echo 'Ocurrio un error: '.$ARRAY['!trap'][0]['message'];
    }

}else{
    echo "<span style="color: #ff0000;">La conexion ha fallado. Verifique si el Api esta activo.</span>";
}
$API->disconnect();
?>

El resultado es este:

API-Activar_Ethernet

Para descargar el codigo fuente haz click aqui!

Saludos!.
____________________
Publicado Primero en www.tech-nico.com

API MIKROTIK – Graficar el trafico de nuestros clientes y mostrar el log

Hola viejos amigos!. Algo que me han preguntado bastante es como hacer que el cliente o nosotros mismos veamos las graficas de consumo con el API de Mikrotik. Y para su sorpresa les cuento que esta parte se hace sin el API.

Estudiemos la ruta que nos da mikortik para ver el graph de un cliente:

Nota: Comprobar que en /tools/graphing  este graficando todos los queues.

http://200.20.30.40:8080/graphs/queue/%3Cpppoe-fduckardt52104%3E/

OK como veran.. aqui pueden haber 3 datos variables:

  1. La direccion IP del RouterOS.
  2. El puerto de www (/ip/services).
  3. El nombre del pppoe: fduckardt52104

Si Inspeccionamos el código de esta imagen con en el navegador veremos que solo se agrega /daily.gif al final de la URL quedando así:

http://200.20.30.40:8080/graphs/queue/%3Cpppoe-fduckardt52104%3E/daily.gif

consumo_cliente

Hagamoslo mas interesante:
Ahora que ya sabemos la ruta exacta de cada gráfica (no tuvimos que usar el api), es cuestión de armar esto con PHP, pero para que sea un poco mas interesante vamos dale uso del API para hacer que si el usuario pppoe esta activo, mostramos el Graph usando la ruta anterior, pero si no esta conectado, mostramos el log del usuario. Para ello vamos a armar un buscador de usuarios activos.

Si el usuario esta desconectado.

Si el usuario esta desconectado.

Si el usuario esta activo

Si el usuario esta activo

Archivos importantes:

  • log.php: Este es el archivo raiz principal, aquí esta el formulario y los contenedores desde donde se carga el JS, estilos, etc. Ademas, en este archivo debemos modificar las variables de Session.
<!--
////////////////////////////////////////////////////////////////////
// ESTE EJEMPLO SE DESCARGO DE www.tech-nico.com ///////////////////
// Creado por: Nicolas Daitsch. Guatrache. La Pampa ////////////////
// Contacto: administracion@tech-nico.com //////////////////////////
// RouterOS API: Busco Usuario PPPoE activo y muestro Graph o Log //
////////////////////////////////////////////////////////////////////
-->
<?php
session_start();
$_SESSION['api_ip'] ="192.168.0.1"; // Tu RouterOS
$_SESSION['api_user'] ="tu_usuario";
$_SESSION['api_pass'] ="tu_password";
$_SESSION['api_port'] =8728;
$_SESSION['www_port'] =80;
?>

Desde este archivo se configura todo!!. Solo tienes que modificar las variables que están justo aquí arriba en el archivo log.php.
Si sigues mirando un poco mas abajo de los seteos veras que en esta ocasión estoy usando el framework de Mootools, aunque por el poquito código que estamos usando tranquilamente podríamos hacerlo todo con javascript (ajax).  Lo dejo a tu criterio.

  •  api/isonline_soporte.php: Este archivo se ocupa de conectarse mediante el API, a tu servidor Mikrotik. Chequea si el usuario esta activo y muestra la grafica en una etiqueta IMG. Miren el código porque esta muy fácil de entender.
  • api/log.php: Este codigo trae todo el log y filtra por nombre de secret para mostrarte solo por usuario.

Importante: para buscar tienes que escribir el nombre exacto del secret. Y luego presionar la tecla Enter.

Buscar Secret con el API de Mikrotik.

Buscar Secret con el API de Mikrotik.

Espero que te haya gustado, puedes probar, investigar mi código y ademas modificarlo, pero asegúrate de no quitar las lineas del autor.

Descarga aqui el codigo de este ejemplo

Este post fue escrito por Nicolas. Primero en tech-nico.com/blog

Mikrotik Script: Buscar en PPP las IP libres no asignadas en una Clase C

Bueno, este es un script muy rebuscado que arme para listar las IP Libres de un /24. Es muy util ya que hay escasos bloques IPv4. En mi caso doy pppoe con IP fija, entonces es muy facil a veces (por error) saltearnos alguna IP y quede en desuso.

Antes de ejecutarlo hay que editar una variable que contiene nuestro rango de IP a buscar.

:global BUSCA "210.100.200";
/ip firewall address-list remove [/ip firewall address-list find list="pool_ip_libres"];
:for i from= 1 to= 254 do={
:local DIREC ($BUSCA . "." . $i);
:local VAR [:put [/ppp secret find where remote-address=$DIREC]];
:if ($VAR!="") do={
:log info (" Existe " . $DIREC );
} else={
/ip firewall address-list add list=pool_ip_libres address=$DIREC;
}
}

Luego de ejecutarlo vamos a ver que se crea una nueva lista llamada «pool_ip_libres».
Cada vez que ejecutamos el script, se limpia primero esa lista para que no queden ips duplicadas.

Se puede mejorar, se aceptan modificaciones. El que modifique también comparta su versión asi ampliamos el post.

___________
Primero en Tech-nico.com
Nicolas

Theme HTML y PSD usado en proyecto API Mikrotik

Hola colegas, a pedido del publico, comparto mi Theme usado en el proyecto.
No tiene nada de otro mundo, solo es HTML y CSS. Pero por si a alguno le sirve, programe sobre el usando Dreamweaver. Ahora estoy probando Sublime Text 2 con el package Emmet; y realmente es «magia» se programa mucho mas rapido y facil.

Ahora ponganse a codificar sus API’s.

Descargar theme
___________________________________
Este post estuvo primero en tech-nico.com

 

API MIKROTIK Tercera parte – Nuestro primer ejemplo (codigo abierto)

Hola amigos.

Tal como lo habíamos anunciado en la Segunda parte, vamos a dar un caso de uso real,
en esta ocasión dedicado para el señor Nemox de Micromax Computación R.L. (Barinas – Venezuela) El nos pidio hacer algo especifico: Poder controlar la lista de «Hotspot > IP-Bindings» desde su celular; y  para comprobar que con el API se puede hacer prácticamente todo, tome su caso como un desafió.

Y aqui el resultado:
API-hotspot_ipbindingsapi_desde_iphone

A la izquierda esta visto desde el Iphone de Nemox. Y a la derecha desde el google chrome.

Muestra la lista de Hotspot – Ip Bindings y permite eliminar, habilitar y deshabilitar un cliente. El boton «agregar» no esta programado, pero dejo el código abierto para que cualquiera pueda editarlo y agregar o quitar funcionaliedades.

Esta armado el esqueleto del sitio en HTML5 y CSS3, los eventos y funcionalidades estan hechos con JQuery y el manejo del API con PHP5.

Vamos por partes:

El codigo de los 4 botones, Agregar, Eliminar, Habilitar, Deshabilitar, esta en el archivo index.html; si lo abrimos y vamos hacia el final, mas precisamente en la linea 110 veremos el codigo de cada boton. Pueden notar que cada boton tiene un codigo muy parecido. Lo que hace es, si esta seleccionado algun cliente (binding), toma su ID de un campo oculto (hidden field) para luego enviarlo como parametro al PHP que ejecuta la accion dentro del routerOS.
En la linea 119 vemos como ejemplo la ruta api/hotspot_general.php?ac=enable&id=numero  que tiene 2 parametros: «ac» (accion) que en nuestro caso son  las de los botones e «id» que es el codigo que identifica al IP Binding seleccionado con 1 click.

index.html
APIcodigobotones

APIcodigoPHP

 

api/hotspot_general.php
Este es el archivo que se comunica con tu RouterOS por medio del API, tienes que editar las primeras lineas con los datos de tu servidor: Revisen los otros archivos de la carpeta «api».

$ipRouteros=»192.168.33.200″;
$Username=»usuario»;
$Pass=»contraseña»;
$api_puerto=8727;

A partir de la linea 30 comenzamos a ver los casos para el parametro «ac» y depende el parametro que le pasemos es lo que ira a ejecutar. Creo que esta muy facil de entender. Para el boton «Agregar» debemos añadir un nuevo «case» con el parametro correspondiente.

El codigo que ejecuta la accion en el Mikrotik es este:

case «enable»:
$API->write(«/ip/hotspot/ip-binding/enable«,false);
$API->write(«=.id=».$id,true);
$READ = $API->read(false);
$API->parse_response($READ);
break;

Es muy facil de entender:

Hay comandos que nos solicitan datos. Antes de ejecutar el codigo con PHP lo probamos en la consola. Escribimos /ip hotspot ip-binding print  y vamos a saber quien esta desabilitado y su codigo ID.
Tomemos cualquier nro para testear y probemos:  /ip hotspot ip-binding enable.(enter) y nos va a pedir el ID, en nuestro ejemplo de prueba ponemos el 7 que esta deshabilitado.

API-consola

Bien, aqui tenemos estas 2 lineas:

$API->write(«/ip/hotspot/ip-binding/enable»,false);
$API->write(«=.id=».$id,true);

El flag false o true se refiere a que si este comando requiere de un dato, id, etc todavia no ejecuta el comando hasta no tener todo lo que necesita. Como vemos en la segunda linea el flag es true ya que el comando esta completo y lo manda a ejecutar.

Las siguientes 2 lineas…

$READ = $API->read(false);
$API->parse_response($READ);

son la respuesta de lo que ejecutamos, que en nuestro codigo no la estamos mostrando. Si el numero de ID no existiera, nos devolvería un error de «no such item». O si el comando ejecutado nos traeria una lista deberiamos recorrer el array $READ con un for para mostrar lo que se nos antoje.

Hay cosas que no las estoy explicando porque estan muy bien comentadas. Si no se entiende algo por favor pregunten.

Acá va el código abierto del ejemplo: mikrotik-test

Enjoy the saturday!

API MIKROTIK – Como optimizar tu administracion con un poco de PHP (introduccion)

API MIKROTIK Tercera parte – Nuestro primer ejemplo (codigo abierto)

API MIKROTIK – Crear queues simples con PHP (con validacion)

_______________________________________
Primero en tech-nico.com Autor Nicolas Daitsch

API MIKROTIK Segunda parte – Usando el API con PHP

En la primera parte, explicamos cual podría ser su uso y para que sirve.
Ahora vamos a explicar como se configura el API en pocos pasos, con un poco de PHP y usando las clases creadas por Denis Basta. (version 1.3 o 1.4), con apenas un minimo cambio hecho para que la clase «connect» permita pasar ademas el numero de puerto del RouterOS como parametro.

Yo estoy familiarizado con programar en PHP pero para el que no, pueden hacerlo con el lenguaje que desee. En la Wiki de Mikrotik podran encontrar ejemplos para:

Paso 1: Configura tu RouterOS

a) Habilitar el servicio API.
desde IP > Services. Seleccionas la fila que dice «api» y la habilitas, luego doble click sobre ella para editar. Puedes asignarle el puerto que quieras, pero por defecto usa el 8728 tcp. Si te gusta tener todo ecualizado podrías agregarlo en los mangles para darle QoS. Finalmente donde dice «Avaliable From» es la direccion IP desde donde estara el API corriendo. En nuestro caso, como usaremos PHP puede ser el servidor Apache.  (sigue los pasos de la imagen).
ip-services-api

 

b) Crear un grupo
Para darle seguridad necesitamos crear un usuario y un grupo nuevo dentro del RouterOS donde queremos ordenar nuestras tareas diarias. Para ello vamos a «System > Users > Groups» y presionamos en el icono «+». En esta ventana simplemente escribimos el nombre del grupo, (para este ejemplo yo le puse «tugrupoapi») y elegi las politicas «read, write, api». Damos click en OK
user_api_group

c) Crear un usuario
Luego de crear el Grupo, nos movemos a la pestaña Users como esta en la imagen a continuacion. Presionamos el icono «+» para crear un usuario nuevo.
Name: aqui escribiremos nuestro nuevo nombre de usuario: Ejemplo blog.tech-nico.com, (puedes crear el tuyo).
Group: elegimos el grupo «tugrupoapi» (ver el punto «b»),
Address allowed:  Es la IP que tiene permitido acceder a nuestro RouterOS a través del API. «El apache server en nuestro caso»,
Password: tipeamos nuestro password, asegurate que sea fuerte.
Finalmente click en el boton «OK».

user_api_user_add

Paso 2: Crear un script para testear el acceso: conectar_test_api.php

<?php require_once(‘api_mt_include2.php’); ?>
<?php
$ipRouteros=»200.20.30.40″; // tu RouterOS.
$Username=»blog.tech-nico.com»;
$Pass=»tupassword»;
$api_puerto=8728;

$API = new routeros_api();
$API->debug = false;
if ($API->connect($ipRouteros , $Username , $Pass, $api_puerto)) {
$API->write(«/system/ident/getall»,true);
$READ = $API->read(false);
$ARRAY = $API->parse_response($READ);
$name = $ARRAY[0][«name»];
if(count($ARRAY)>0){ // si esta conectado
$API->write(«/system/licen/getall»,true);
$READ = $API->read(false);
$ARRAY = $API->parse_response($READ);
$nlevel = $ARRAY[0][«nlevel»];
$API->write(«/system/reso/getall»,true);
$READ = $API->read(false);
$ARRAY = $API->parse_response($READ);
$cpu = $ARRAY[0][«cpu»];
$cpu_frequency = $ARRAY[0][«cpu-frequency»];
$arquitectura = $ARRAY[0][«board-name»];
$API->write(«/system/pack/getall»,true);
$READ = $API->read(false);
$ARRAY = $API->parse_response($READ);
$version = $ARRAY[0][«version»];

echo ‘<img src=»icon_led_green.png» />&nbsp;’;
echo «<strong>».$name.»(» .$arquitectura. «)</strong>&nbsp;&nbsp;»;
echo «v:» . $version. «&nbsp;&nbsp;»;
echo «level:» . $nlevel . «&nbsp;&nbsp;»;
echo $cpu.»(«.$cpu_frequency.» Mhz.)»;
}else{ //el usuario esta of line
echo ‘<img src=»icon_led_grey.png» />&nbsp;’.$ARRAY[‘!trap’][0][‘message’];
}

}else{
echo «<font color=’#ff0000′>La conexion ha fallado. Verifique si el Api esta activo.</font>»;
}
$API->disconnect();
?>

Paso 3: Editamos las lineas que dicen:

$ipRouteros=»200.20.30.40″; // tu RouterOS.
$Username=»blog.tech-nico.com»;
$Pass=»tupassword»
$api_puerto=8728;

Paso 4: Finalmente subimos por FTP los archivos a nuestro servidor Web y ejecutamos en el navegador el archivo conectar_test_api.php;
test_php_navegador
Si todo salio bien, vamos a ver una pantalla parecida a la de arriba. Lo que hicimos fue loguearnos mediante el API a nuestro servidor, y luego traer el nombre «Identity», la plataforma, la version del ROS, que licencia tiene instalada, etc.

Descarga aqui todos los archivos de este ejemplo.

Como veran, este seria el primer paso para comenzar a programar tus scripts. Ya teniendo esto funcionando vamos a poder realizar varios ejemplos que voy ir posteando en mi tiempo libre.

Cualquier cosa comenten que les respondo enseguida.

API MIKROTIK – Como optimizar tu administracion con un poco de PHP (introduccion)

API MIKROTIK Tercera parte – Nuestro primer ejemplo (codigo abierto)

API MIKROTIK – Crear queues simples con PHP (con validacion)

_______________
Nicolas tech-nico.com/blog

Template Cacti AirOS 5.5 para cacti version: 0.8.7g (hash version)

Para los que no lo saben, en el firmware 5.5 de ubiquiti dejaron de funcionar los graficos del Cacti. Por suerte un colaborador del foro oficial forum.ubnt.com publico un template que funciona de maravillas.

El unico inconveniente que se presenta al importar el archivo cacti_host_template_airos-ubnt_5_5.xml en el panel de control de cacti es que arroja el error:

Error: XML: Hash version does not exist

Este error es porque dentro del archivo xml tiene un tag llamado hash, que se forma con la version de cacti y unos numeros aleatorios. Por lo tanto si tu version no coincide con la del hash, arroja el error de arriba.

ejemplo: hash_0200248f0dcc6cc49fee26220bfeb7ae781802

0024 es la version de Cacti, que si miramos en la siguiente tabla de versiones corresponde a la 0.8.8 o 0.8.8a

"0.8.4"  => "0000",
"0.8.5"  => "0001",
"0.8.5a" => "0002",
"0.8.6"  => "0003",
"0.8.6a" => "0004",
"0.8.6b" => "0005",
"0.8.6c" => "0006",
"0.8.6d" => "0007",
"0.8.6e" => "0008",
"0.8.6f" => "0009",
"0.8.6g" => "0010",
"0.8.6h" => "0011",
"0.8.6i" => "0012",
"0.8.6j" => "0013",
"0.8.7"  => "0014",
"0.8.7a" => "0015",
"0.8.7b" => "0016",
"0.8.7c" => "0017",
"0.8.7d" => "0018",
"0.8.7e" => "0019",
"0.8.7f" => "0020",
"0.8.7g" => "0021",
"0.8.7h" => "0022",
"0.8.7i" => "0023",
"0.8.8"  => "0024",
"0.8.8a" => "0024"

En mi caso tengo la version 0.8.7g. Por lo tanto tendria que modificar el 24 por 21. :).
Lo que hice fue usar Adobe Dreamweaver para buscar y reemplazar mediante una expresion regular:  (lo vamos a hacer en 2 pasos).

Paso 1:

Buscar:

(hash_)([0-9]{2})(00)(24)

y reemplazarlo con:

$1$2$3{loquequieras}21

Paso 2:

Buscar:

{loquequieras}

y reemplazarlo por NADA. (dejar vacio).

Este paso ultimo paso es necesario porque si no, dreamweaver se confunde y piensa que $3 es $321, entonces separamos $3__algo__21 con algo que quieras y finalmente quitamos ese «algo» con el paso 2.

El archivo finalmente queda asi: descargar aqui

Recuerda situar el archivo AirOS5_5.xml en la ruta:
<path_cacti>/resource/snmp_queries/AirOs5_5.xml

__________________
Nicolas
tech-nico.com

Mikrotik script para recorrer lista de secrets pppoe y reemplazar IP’s

PPPoE Secrets: Migrar de IP privada «fija» a IP publica «fija»
Algo muy puntual que tuve que hacer cuando migre de IP Privadas a IP Publicas fue mantener la terminación de las IP de los clientes PPPoE de mi Red. Se preguntarán.. para que?. Bueno en mi caso tengo un sistema de gestión que maneja el servidor usando el API mediante PHP y Mysql. Entonces me tiene que quedar sincronizadas las IP del Mysql con las del Mikrotik. Por otro lado, siempre fui de la idea de que todos los secrets tengan una IP fija asignada, ya que cuando me reportan un problema, de virus, ataque o violación de derechos de autor, puedo identificar con velocidad de quien se trata.

Ejemplo 192.168.100.8     por 201.250.45.8

Para ello, elabore un script que me recorra la lista y reemplace lo que quiero.

El Script es el siguiente:

       :local BUSCA "192.168.100";
       :local REMPL "201.250.45";
       # recorro todos los secrets
       :foreach i in=[/ppp secret find] do={
       # guardo remote IP
          :local tmpIP [/ppp secret get $i remote-address];
       # guardo la primera parte
          :local ipfirst [pick $tmpIP 0 11];
       #guardo la ultima parte
          :local iplast [pick $tmpIP 12 15];
       #busco los secrets que tienen el rango de Ip a reemplazar
            :if ($ipfirst=$BUSCA) do={
                  :log info ($REMPL .".".  $iplast);
                 /ppp secret set $i remote-address="$REMPL.$iplast"
            }
       }

Solo tienes que editar las primeras 2 variables «BUSCA» por la IP actual que vas a buscar, y «REMPL» por la IP nueva que quieres asignar a cada secret. Si tienes 4 clases C tendras que ejecutar el script 4 veces.

Para importarlo hay que copiar y pegar lo siguiente en la consola:

sys scr add name=recorro_ppp_remoteAddress policy=\
    ftp,reboot,read,write,policy,test,winbox,password,sniff,sensitive,api source=":local\
    \_BUSCA \"192.168.100\";\r\
    \n:local REMPL \"201.250.45\";\r\
    \n# recorro todos los secrets\r\
    \n:foreach i in=[/ppp secret find] do={\r\
    \n# guardo remote IP\r\
    \n   :local tmpIP [/ppp secret get \$i remote-address]; \r\
    \n# guardo la primera parte\r\
    \n   :local ipfirst [pick \$tmpIP 0 11];\r\
    \n#guardo la ultima parte\r\
    \n   :local iplast [pick \$tmpIP 12 15];\r\
    \n#busco los secrets que tienen el rango de Ip a reemplazar\r\
    \n     :if (\$ipfirst=\$BUSCA) do={ \r\
    \n           :log info (\$REMPL .\".\".  \$iplast);\r\
    \n          /ppp secret set \$i remote-address=\"\$REMPL.\$iplast\"\r\
    \n     }\r\
    \n}"

Salutes

_________
Nicolas Daitsch
tech-nico.com

Publicar Imagen de Ubiquiti Aircam en un sitio web (sin login) de manera automática

Esta webcam, mas precisamente la Aircam de Ubiquiti no tiene muchos parámetros para configurarla. Solo se acceden via login. Otras camaras tienen la opcion de desactivar el login o bien configurar un servidor FTP y publicar la imagen de la cámara cada x tiempo.
Nosotros lo que haremos es ingresarle por SSH y copiar la imagen /tmp/snap.jpeg (que es la ruta donde publica ubiquiti la imagen en vivo) dentro de nuestro sitio web de apache.

Para ello deberemos primero crear las Keys que requiere el acceso SSH.

Crear el par de claves públicas y privadas:

$ sudo ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):

Damos enter, para que las llaves se guarden en ~/.ssh

Enter passphrase (empty for no passphrase):
Enter same passphrase again:

Le ponen el password que quieran. Luego vamos a la carpeta home del usuario root o bien al home del usuario logeado y veremos 2 archivos: id_rsa e id_rsa.pub.

Publicamos la llave publica id_rsa.pub en nuestra cámara desde el navegador. Como esta en la imagen.

Para testear que ingresas bien a la cámara puedes correr la siguiente linea desde la consola de linux donde se hospeda tu sitio web:

$ sudo /usr/bin/scp -qv «ubnt@IPdeAircam:/tmp/snap.jpeg» /var/www/tusitio/webcam.jpg.
Si todo va bien te tiene que solicitar la contraseña de la cámara. Luego revisa que se haya generado el archivo webcam.jpg en tu sitio.  :). Perfecto!, Ahora si queremos que la foto se publique sola, tenemos que lograr que esta linea de comandos no nos pida la contraseña. Para ello necesitamos instalar «expect», un programa para automatizar tareas que va a encargarse del login.

sudo apt-get install expect

Luego vamos a armar 2 script; uno que hara el trabajo de ingresar a la camarita, con lo siguiente:   webcam_image_get.sh

#! /usr/bin/expect
set hostName [lindex $argv 0]
 ### Modificar ubnt por el usuario, y /var/... por la ruta de tu sitio.
spawn /usr/bin/scp -q "ubnt@$hostName:/tmp/snap.jpeg" /var/www/tusitio/webcam.jpg

set timeout 10
expect {
  ### Modificar ubnt por la contraseña de tu camara
 -re ".*passphrase.*" { send "ubnt\n"; expect eof exit }
  eof { exit }
  timeout { puts "\n--TIMEOUT!--\n";exit}
}
exit

Modificar «ubnt ubnt» por el usuario y contraseña de tu camara y la ruta que tiene que apuntar a la de tu sitio web.

Y el otro script ejecutara el anterior cada cierto tiempo en segundos, y ademas usaremos «convert» para reescribir la imagen con un texto personalizado.

Para poder usar «convert» instalamos:  $ sudo apt-get install imagemagick

Y aqui el script: webcam_cron.sh

#! /bin/sh

while [ true ]; do
        sleep 2   # espearmos 2 segundos
 /home/tu_usario/webcam_image_get.sh 190.100.100.5 # ip de tu camara
        sleep 1  # esperamos 1 segundo mas
        convert -family Arial -pointsize 16 -fill "#ffffff"  -draw "text 20,20 'Tech-Nico.com Live'" /var/www/tusitio/webcam.jpg/var/www/tusitio/webcam.jpg
done

En rojo las cosas que tenes que modificar para tu caso.
Le damos permisos de ejecución a los 2 scripts con: $ sudo chmod +x

Finalmente para ejecutar «webcam_cron.sh» como trabajo en background y re-direccionamos la salida estándar a un archivo de texto llamado output para esconder los mensajes.

$  sudo ./webcam_cron.sh >>output 2>&1 &

Ahora si! ya tenemos nuestra imagen publicandose automaticamente. Solo tenemos que armar un archivito HTML y ponerle la etiqueta Refresh para que refresque cada cierto tiempo.

La única desventaja de esto es que «no vamos a ver la imagen como un video» Es mas lento porque hasta que se logea por ssh, intercambia las llaves.. ingresa la contraseña… copia el archivo..  todo eso le demora unos 2 segundos. Asi que lo mas rapido que puede publicar va a ser en 3 o 4 segundos como maximo.

Resultado

Espero que les guste y.. lo mas importante.. «les sirva».

________________
Nicolas Daitsch
tech-nico.com/blog

Crontab y PHP: Enviar logs, procesos, o backups via mail

Algo que surgió anoche en la clase de Linux (Crontab), fue casualmente «poder hacer un backup automático y que lo envie a nuestro mail». Todavía no aprendimos Bash Scripting / Pyton / Perl o bien para el que esta mi situación, tenemos la alternativa de ejecutar un script PHP.

Inicialmente este script hacia un dump de la base de datos mysql y enviaba el archivo .sql via mail. Aca lo posteo con algunas modificaciones para que cada uno lo adapte a sus necesidades.
En este ejemplo vamos a imprimir el syslog (tail syslog) y enviarlo via mail como archivo adjunto.
La funcion en PHP para ejecutar un comando Linux es:

system(«tu comando»);            // Ej:  system(«ps -fea»);
*En este ejemplo listamos los procesos.

Sabiendo esto, el código del script PHP podría ser algo asi:

<?php
//// Script: Nicolas Daitsch 24 de noviembre de 2011
//// http://tech-nico.com/blog

////////////// CONFIGURACION //////////////////////////
$sendto = "Webmaster <tuemail@gmail.com>"; // DESTINO
$sendfrom = "Log Diario Servidor <logs@tuempresa.com>"; // ORIGEN
$sendsubject = "Log Diario mi servidor"; // ASUNTO
$bodyofemail = "Aca esta el log que genero el Crontab."; // MENSAJE
$COMANDO_LINUX = "tail /var/log/syslog"; // COMANDO
////////////////////////////////////////////////////////

    $backupfile = "syslog_". date("Y-m-d") . '.txt';
    system($COMANDO_LINUX > $backupfile);
    include('Mail.php');
    include('Mail/mime.php');

    $message = new Mail_mime();
    $text = "$bodyofemail";
    $message->setTXTBody($text);
    $message->AddAttachment($backupfile);
    $body = $message->get();
    $extraheaders = array("From"=>"$sendfrom", "Subject"=>"$sendsubject");
    $headers = $message->headers($extraheaders);
    $mail = Mail::factory("mail");
    $mail->send("$sendto", $headers, $body);

    //unlink($backupfile);
?>

Editamos la sección que dice //// CONFIGURACION y escribimos nuestros valores.
Luego instalamos el modulo PEAR para envio de mails con PHP:

#  apt-get  install  php-mail   php-mail-mime   php-mail-mimedecode

Editamos el Crontab:

# crontab -e

Agregamos esta linea al final, guardamos y salimos:

08 12 * * * /usr/bin/php -f /var/www/backup.php > /root/cronerrors.txt 2>&1

Explicamos lo que hace esta linea:

  1. (08 12 * * *) Todos los dias a las 12:08 PM
  2. (/usr/bin/php -f) Ruta del interprete PHP en Debian/Ubuntu. Flag «-f» Ejecutar un archivo PHP.
  3. (/var/www/log_script/log_send.php) Ruta del Script
  4. (> /root/cronerrors.txt 2>&1) Redirecciono la salida de error hacia un archivo de texto en /root. Esto también puede ser /home/usuario/errores.log
Descargamos los archivos necesarios para el funcionamiento. Y los ubicamos en la ruta /var/www/.
___________________

Flash CS3: Arma tu propio Datagrid con Tooltips

Después de tanto tiempo sin postear, me decidí por traerles un Datagrid (Flash) que tuve que armar en un apuro cuando necesitaba terminar uno de mis trabajos. La aplicación era muy sencilla: Imprimir datos de un Stored Procedure de SQL Server, por medio de un archivito en ASP, que parseado por Flash mostrara datos en pantalla.

Y aquí fue donde se presentaron los contratiempos: Mostrar los datos en un Datagrid puede parecer algo sumamente sencillo. Pero, en mi caso, al ser tanta la cantidad de columnas que debía mostrar, si quería lograr algunos detalles como por ejemplo 1 tooltip, (o seleccionar el ultimo registro con otro color), se tornaba algo bastante inflexible.

El Datagrid nativo de Flash sinceramente me hizo perder bastante tiempo y no logre hacer nada de lo que quería. «Llenar el datagrid fue fácil, el resto imposible :p». Supuse que alguien tenia que haber armado algo en la red. Pero no encontre nada.

Aqui va el datagrid creado.

Es bastante mas liviano pero a la hora de configurarlo, (al no ser un componente), hay que modificar mucho codigo.

A Futuro: Le falta pulir muchas cosas: Scroll vertical y horizontal y/o paginacion. Y armarlo como componente.

Creo que el uso es bastante puntual. Pero seguramente mas de uno ha perdido tiempo. Enjoy!.

Descarga de archivos

___________________

nicolas Tech-nico.com/blog

Bug de Google Ads causa problemas con Internet Explorer

A muchos de nosotros los desarrolladores nos esta pasando, que en algunos de los sitios que tienen Ads de Google aparecen errores en IE6, IE7 e IE8 sin que hayamos hecho ningún cambio.

Luego de que carga nuestro sitio aparece una ventana que dice «Internet explorer no puede abir el sitio: http://tech-nico.com
Operacion anulada
«.

Con IE8 da el siguiente error:
Detalles de error de página web

Agente de usuario: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; AskTB5.6)
Fecha: Wed, 22 Sep 2010 14:33:30 UTC

Mensaje: No se pudo completar la operación debido un error 800a03e8.
Línea: 1
Carácter: 244
Código: 0
URI: http://pagead2.googlesyndication.com/pagead/render_ads.js

La linea del error es:

(function(){var a=»window.google_render_ad();»;if(typeof google_protectAndRun==»function»&&typeof google_handleError==»function»)a=’google_protectAndRun(«render_ads.js::google_render_ad», google_handleError, google_render_ad);’;var b=»script»;document.write(«<«+b+»>»+a+»</»+b+»>»);})()

Al parecer se trata de un error en el Javascript de uno de los servidores de Adsense , que ocurre con conexiones lentas, o cuando algun script carga antes de que termine de cargar el html.

Si intentamos acceder desde el mismo u otro PC, (a través de la misma conexión), arroja el mismo error con cualquier sitio que tenga Adsense de Google.

Por lo que se ve; el problema ya fue resuelto para IE8. Por lo tanto la mayoria de nuestros sitios aun no funcionan en IE6 e IE7.

Oremos! 😀

fuente: foro google

____________________
Nicolas Daitsch
www.tech-nico.com/blog

Graficando la cantidad de túneles PPPoE (conectados simultáneamente) con DUDE 4

Lo que queremos obtener es el numero de tuneles PPP simultanes en nuestro concentrador PPPoE Server Mikrotik. Que quedaria como la imagen que se muestra a continuacion:

En primer lugar necesitamos crear una función:

Para ello vamos al menu Tree, y hacemos doble click en «Functions».

Presionamos entonces el Boton «+» como muestra la siguiente imagen.

En nombre de funcion ponemos: cant_pppoe_clients
En descripción: cantidad simultanea de clientes PPPoE .
Y en codigo:

array_size(oid_column(«iso.org.dod.internet.private.enterprises.mikrotik.mikrotikExperimentalModule.mtXRouterOs.mtxrQueues.mtxrQueueSimpleTable.mtxrQueueSimpleEntry.mtxrQueueSimpleName»))-8

Nota: Este Codigo cuenta la cantidad  de queues simples. En mi caso tengo justo 8 queues simples que agregue manualmente. Entonces como solo me interesa contar los Queues dinamicos, simplemente al final le resto 8. Es por eso el «-8» al final del codigo. Si no tienes queues manuales reemplaza por cero.

Ahora que tenemos la Función creada, vamos de nuevo al menu Tree, y hacemos doble click en «Probes», como muestra a continuacion.

Luego presionar el boton «+» que se marca en rojo.

Completamos con estos datos:
Nombre: pppoe_probe
Tips: Function
Agente: por defecto
Disponible: cant_pppoe_clients()
Error: if(cant_pppoe_clients(),»»,»»)
Valor: cant_pppoe_clients()
Unidad: Clientes

En el menu Tree, doble click en «Local» para ir al diagrama de Red.

Click derecho en el dispositivo PPPoE, y en el menu contextual click en «Configuraciones».

Click en la pestaña «Servicios» y luego en el boton «+» remarcado en rojo.

Donde dice Prueba: elegir «pppoe_probe». Y presionar OK

Deberia quedar asi. Presionamos de nuevo en OK.

Click con boton derecho sobre el Dispositivo PPPoE, y click en apariencia.

Finalmente editamos la «Etiqueta», y agregamos

[cant_pppoe_clients()] clientes conectados

Finalizamos presionando OK.
Eso es todo!!. 🙂 despues de 2 segundos aparece el contador.
Recuerda que tienes que tener el SNMP habilitado en tu Mikrotik para poder leer el OID. Saludos
_____________________
Nicolas Tech-nico.com

Galeria de Fotos Flash II con Comentarios

Por suerte la Galeria de Fotos en Flash y PHP (con thumbs GD) y lectura de folders tubo mucha aceptación; así que aquí va la «Versión del Galery en flash con comentarios» tipo fotolog 😀

Como varios me lo han pedido, aqui esta la version del galery en flash con comentarios.
El sistema de comentarios se basa en 1 solo archivo PHP llamado guestBook.php que se conecta a la base de datos e interactua con flash como gateway para postar comentarios o leerlos.
Tiene filtro de malas palabras, y para el que quiere tambien puede habilitar las lineas para que te avise por mail que alguien posteo un comment.
Con respecto a la base de datos: Esta hecho para mysql, y consiste de tan solo una sola tablita.
CREATE TABLE `fotolog` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` CHAR( 200 ) NOT NULL ,
`nombrefoto` CHAR( 200 ) NOT NULL ,
`email` VARCHAR( 200 ) NULL ,
`comments` LONGTEXT NULL ,
`time` TIME NULL
) ENGINE = innodb COMMENT = ‘comentarios galery comment’;
El funcionamiento es sencillo pero poco robusto 😛
Como las fotos no estan en la base de datos; tome en cuenta el nombre de la foto como ID, por lo tanto hay que tener mucho cuidado con los nombres de fotos duplicados.
Ademas; como no hay ningun Admin para administrar la galeria o comentarios, si eliminamos una foto por FTP el comentario «no se elimina», entonces van quedan registros perdidos en la tabla de la base de datos.
Con una galeria que no tenga demaciado movimiento no va a haber problema (como fue en mi caso), pero si hay mucho trafico de fotos que se suben y se eliminan podria aparecer comentarios huerfanos.
Configuracion:
Abrir archivo guestBook.php y modificar las lineas siguientes por las de tu base de datos.
$DBhost = «localhost»;   // servidor
$DBuser = «root»;            // usuario
$DBpass = «»;            // clave
$DBName = «fotolog»;            // nombre base de datos
$table = «fotolog»;             // nombre tabla base de datos
$numComments = 5;       // cantidad de comentarios por pagina.
To DO // Para hacer
Lo ideal seria armar un mini admin que muestre las fotos y te permita eliminar la foto con el comentario relacionado.
Agregando un campito mas de «activate» podriamos mostrar los comentarios que solo esten aprobados.
Modificar BadWords desde el admin.
Agregar filtros de metacaracteres para evitar el sql injection.
Descargar Fla Modificado y guestBook.php

El sistema de comentarios se basa en 1 solo archivo PHP llamado guestBook.php que se conecta a la base de datos e interactua con flash como gateway para postear comentarios o leerlos.

galery_commentTiene filtro de malas palabras, y para el que quiere también puede habilitar las lineas para envié por mail un aviso en caso de que haya comentarios nuevos.

Con respecto a la base de datos:  Esta hecho para mysql, y consiste de tan solo una sola tablita.

CREATE TABLE `fotolog` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` CHAR( 200 ) NOT NULL ,
`nombrefoto` CHAR( 200 ) NOT NULL ,
`email` VARCHAR( 200 ) NULL ,
`comments` LONGTEXT NULL ,
`time` TIME NULL
) ENGINE = innodb COMMENT = ‘comentarios galery comment’;

El funcionamiento es sencillo pero poco robusto 😛

Como las fotos no están en la base de datos; tome en cuenta el nombre de la foto como ID, por lo tanto hay que tener mucho cuidado con los nombres de fotos duplicadas.
Ademas, como no hay ningún Admin para administrar la galería o comentarios, si eliminamos una foto por FTP, el comentario «no se elimina», entonces van quedan registros perdidos en la tabla de la base de datos.
Con una galeria que no tenga demaciado movimiento no va a haber problema (como fue en mi caso), pero si hay mucho trafico de fotos que se suben y se eliminan podria aparecer comentarios huerfanos.

Configuracion:

Abrir archivo guestBook.php y modificar las lineas siguientes por las de tu base de datos.

$DBhost = «localhost»;   // servidor
$DBuser = «root»;            // usuario
$DBpass = «»;            // clave
$DBName = «fotolog»;            // nombre base de datos
$table = «fotolog»;             // nombre tabla base de datos
$numComments = 5;       // cantidad de comentarios por pagina.

To DO // Para hacer

  • Lo ideal seria armar un mini admin que muestre las fotos y te permita eliminar la foto con el comentario relacionado.
  • Agregando un campito mas de «activate» podriamos mostrar los comentarios que solo esten aprobados.
  • Modificar BadWords desde el admin.
  • Agregar filtros de metacaracteres para evitar el sql injection.

Descargar Fla Modificado y guestBook.php

________________
tech-nico.com/blog

Micro Sitio dinamico en Ajax + XML (sin base de datos)

Quiero compartir con todos ustedes, un mini sitio que diagrame hace un tiempo en el que necesitaba algo «dinámico» y tenia la restricción de no poder usar base de datos mysql.

El micro sitio esta desarrollado en PHP, y el Maquetado XHTML/CSS estan diagramados de forma limpia y accesible para todos los navegadores.
Los contenidos están en archivos XML. Esta pensado para mostrar listados de Links en columnas. Pero con algunos conocimientos de programación podes modificarlo a tu gusto y antojo.

Como ventajas:

  • es bonito y liviano
  • muy facil de modificar.
  • no usa base de datos

Desventajas:

  • Muy estructurado en el diseño.
  • No tiene CMS ni editor WYSIWYG.
  • No es practica la forma de presentar los contenidos.

El Home del sitio se ve asi:
sitio_inicio

Configuración:
1) abrir js/core.js
editar_core
2) modificar las lineas 4 y 5

Atención: Por defecto esta configurado para levantar inicialmente la sección id «inicio». Esto lo pueden modificar mas abajo en la linea 130 donde dice «section?=inicio».

Para agregar solapas o modificarlas:
1) Abrir archivo index.php
2) Duplicar las zonas seleccionadas en A y B (ver imagen Click para agrandar).
add_layers

3) Estan marcados con círculos Rojos las zonas que deben modificar con el ID «3» en el caso de los círculos. Solo basta con incrementarle el numero. Ejemplo reemplazar 3 por 4 o cualquier otro Nº que no se repita. Abajo dentro de «div_content» también va el mismo Nº.
«Servicios» también esta seleccionado, para que vean que este es el nombre de la sección a levantar. Si la sección se llama «About Us» iría: ?section=about. Tienen que usarse solo palabras resumidas, ya que esta palabra también se usa para armar la URL permanente de la sección cargada con ajax.  Ejemplo: www.tech-nico.com/#about. Algo realmente útil y que por lo general es un problema en Ajax.  :p

4) Abrir callbacks.php y agregar en el Select Case la llamada para la nueva solapa. Duplicar cualquiera de los casos del select o switch, que van desde «case ‘xx’: …. hasta break; » y lo modificamos para que quede asi:

case ‘about’: ?>
<script type=»text/javascript»>
actualizarPestanas(4);__exec_command(‘content/about.htm’,’pest4′,’Acerca de’);
</script>
<?php break;
Funciones de callbacks.php
actualizarPestanas(id): Esta funcion oculta todos los divs contents y muestra solo el que tiene el ID que pasamos como parametro. Param id{es el id que le dimos en el paso 3}
__exec_command(url, div_pestaña, titulo): Ejecuta por medio de Ajax la «url» y la muestra en «div_pestaña» y finalmente
modifica el titulo de la pagina por el que le proporcionemos. Aqui pueden levantar URL’s estaticas o dinamicas. Miren el codigo que esta facil de entender.
Contenido:
Todo el contenido del sitio esta dentro de la carpeta «content». Y sea estatico o dinamico.
Estoy seguro de que se puede mejorar muchisimo. De hecho se podrian validar varias cosas con expressiones regulares pero eso que lo haga cada uno por su cuenta. Pense en armar un mini admin para poder cargar XML’s pero por cuestiones de tiempo se complica. De todos modos esta bueno para esos proyectos que necesitan arrancar con algo sencillo. Quizas este sea el esqueleto base.
Espero que les guste y sirva. Cualquier duda sera respondida por aqui.
Nicolas
blog tech-nico.com

case ‘about’: ?>
<script type=»text/javascript»>
actualizarPestanas(4); __exec_command(‘content/about.htm’,’pest4′,’Acerca de’);</script> <?php break;

Funciones de callbacks.php

actualizarPestanas(id): Esta funcion oculta todos los divs contents y muestra solo el que tiene el ID que pasamos como parametro. Param id{es el id que le dimos en el paso 3}

__exec_command(url, div_pestaña, titulo): Ejecuta por medio de Ajax la «url» y la muestra en «div_pestaña» y finalmente modifica el titulo de la pagina por el que le proporcionemos. Aquí pueden levantar URL’s estáticas o dinámicas. Miren el código que esta fácil de entender.

Contenido:
Todo el contenido del sitio esta dentro de la carpeta «content». Y sea estático o dinámico.

Estoy seguro que se puede mejorar muchísimo. De hecho se podrían validar varias cosas con expresiones regulares pero eso que lo haga cada uno. Pensé en armar un mini admin para poder cargar XML’s pero por cuestiones de tiempo se complica. De todos modos esta bueno para esos proyectos que necesitan arrancar con algo sencillo. Quizás este sea el esqueleto base.

Espero que les guste y sirva. Cualquier duda sera respondida por aquí.

descargar el codigo

Nicolas

blog tech-nico.com

Galeria de Fotos en Flash y PHP (con thumbs GD) y lectura de folders.

Hace mucho tiempo tuve que crear una galería de fotos en flash y PHP ( que me saco de muchos apuros ).

Lo particularmente bueno de esta galería es que levanta las fotos on the fly desde carpetas del servidor que creemos o ya estén creadas. Entonces el cliente mismo puede generar galerías de fotos simplemente creando carpetas por FTP y haciendo copy paste de las imágenes que desea subir. Algo muy practico y sencillo para los clientes no entendidos.
Mi propósito principal fue evitar que alguien tenga que editar un FLA… o un XML o mas engorroso aun tener que armar un admin con upload para el manejo de la galería.

Características de la galería:

  • Usa Flash para precarga de fotos.
  • Lee varias carpetas de fotos.
  • Paginación de fotos (20 x página).
  • Librería GD de php para generar los thumbs con cacheo para agilizar la carga.
  • No usa base de datos ni XML.
  • Fácil configuración y mantenimiento.

Dentro de la carpeta «galery» debe haber 5 archivos y 1 carpeta llamada «images». Se recomienda no cambiar el nombre de la carpeta. (De lo contrario la galería no funciona).

galery_tech_nico.fla
Archivo editable de Flash contenedor de la galería de fotos.

galery_tech_nico.swf
Este archivo es la galería de fotos compilada y lista para embeber en tu web.

folderImages.php
Recibe como parámetro un string («nombre de carpeta») y recorre en el servidor las imágenes que esta contenga. Finalmente devuelve sus rutas a flash.

folders.php
Recorre todo el directorio «images» y devuelve a flash los nombres, rutas, tamaño de cada una de las fotos y además la cantidad de fotos por directorio.

thumb.php
Recibe varios parámetros como alto, ancho, etc. y devuelve la imagen resampleada para generar los thumbnail de la galería.

INSTALACION:
1) Editar archivo galery_tech_nico.fla.
Escribe el nombre de tu dominio

2) Editar folderImages.php y folders.php.

Esta versión también tenia para postear comentarios en las fotos. Pero esa parte usa una base de datos MySQL así que verán que en el archivo de flash esta comentado. (Si alguien los necesita subo los archivos.).
Se que tiene muchas cosas por mejorar, pero ya cumplió su ciclo :P.

GALERIA CON COMENTARIOS:
http://www.tech-nico.com/blog/galeria-de-fotos-flash-con-comentarios-php/

descargar galery

Nicolas
______________________
www.tech-nico.com/blog

Embeber Objetos Audio y Video con Ajax usando swfobject

Algo realmente curioso e interesante es ver que el wp-standalone-player utiliza la
funcion Javascript para embeber Objetos Flash usando DOM creado por «Geoff Stearns, Michael Williams, y Bobby van der Sluis»
Casualmente es muy util para los que quieran embeber Objetos Flash mediante AJAX.
Es un problema muy tipico el querer embeber video de youtube y que el innerHTML no funcione. (Sinceramente da muchos dolores de cabeza).
Pero con este pequeño include llamado player.js de tan solo 11kb solucionamos todos nuestros problemas y podemos embeber indistintamente Objetos Flash (SWF) Locales, como URL de Objetos, como es el caso de los videos de Youtube.

Vamos a aclarar que salio una version de «WordPress Audio Player» version standalone. Por lo tanto podemos customizarla y usarla en cualquiera de nuestros sitios webs (aunque no tengan WP instalado).

Entonces hasta aca tenemos:
– Funcion JS para embeber objetos flash con DOM de 11 Kb.
– Reproductor de audio WordPress Audio Player (Standalone)
– Y una funcion para incluir Objetos Flash (mas especificamente Videos Youtube)

Aqui abajo les muestro como implementarlo:

<!– HEADER –>
<script src=»player/player.js» type=»text/javascript»></script>

<script type=»text/javascript»>  
 // VIDEO DE YOUTUBE
 function show_video(element_descripcion, video_objeto, video_descripcion){
     var div_element_descrip = document.getElementById(element_descripcion); 
     audioplayer_swfobject.embedSWF(video_objeto, «main_video», «295», «237», «9.0.0»);
     div_element_descrip.innerHTML = video_descripcion;
 }

 // WP_STANDALONE_PLAYER ( la siguiente linea, invoca el audioPlayer )
       
AudioPlayer.setup(«
http://<?php echo $tudominio; ?>/player/player.swf», {  
                width: 290  
        });   
</script>

 Son 2 funciones totalmente distintas; la primera, show_video( ), es la que usaremos para embeber video.  Y AudioPlayer.setup( ), es la que invoca al reproductor de audio. Lo que tienen en comun, es que ambas funciones utilizan el mismo Include player.js con el que embeben los tags usando DOM.

En el Body:

<!– BODY –>
 <!– audio player –>
<p id=»audioplayer_1″>Alternative content</p>  
<script type=»text/javascript»> 
                 AudioPlayer.embed(«audioplayer_1», {soundFile: «
http://<?php echo $tudominio;?>/<?php echo $ruta_de_tu_audio .’/’. $nombre_archivo; ?>»,transparentpagebg: «yes»,titles: «descripcion del audio»});   
</script>
                                   

 <!– video player –>
<script type=»text/javascript»> 
          show_video(‘video_descripcion’, ‘http://www.youtube.com/v/codigovideo’,  ‘la descripcion del video desde la base de datos’);
</script>
 <div id=»main_video»></div>
 <div id=»video_descripcion»></div>
 

Multiples Instancias:

Los contenedores para cada reproductor son los que estab en negrita.
Para agregar multiples reproductores de audio, solo basta con cambiar el ID del contenedor y duplicar el codigo. Para el caso del reproductor de video habria que hacer unas minimas modificaciones en la funcion show_video( ), y pasandole como parametro el identificador del DIV podriamos tener multiples reproductores de video.

Bien!. veran que es muy facil!!!

UN TIP > USAR YOUTUBE COMO SERVIDOR DE VIDEO STREAM:
Esto es para los que ahorramos ancho de banda. (Hoy en dia los que tienen reproductores de video propios insertados en su sitio web, estimo que es porque el sitio les da mucha ganancia)  🙂
Lo que yo hice fue guardar toda las rutas de los videos de youtube en mi base de datos. Para ello, se me presento un inconveniente; las URL’s de los videos son diferentes a la URL de publicacion que estan en los tags.. se entiende?.

Ejemplo: esta es la URL del video que esta en la barra de direcciones del navegador, http://www.youtube.com/watch?v=Mxo9D_aTrx4. (Esta URL NO FUNCIONA!).
pero si miramos la URL del objeto a insertar:

<object width="425" height="344"><param name="movie" value="
http://www.youtube.com/v/G8whC4Me8d4&hl=en&fs=1«></param> <param name=»allowFullScreen» value=»true»></param><param name=»allowscriptaccess» value=»always»></param> <embed src=»http://www.youtube.com/v/G8whC4Me8d4&hl=en&fs=1» type=»application/x-shockwave-flash» allowscriptaccess=»always» allowfullscreen=»true» width=»425″ height=»344″></embed></object>

Ja, si!  es totalmente distinta; en mi caso, necesitaba guardar solo la URL en el campo de la Base de datos, entonces lo que hice fue armar una expresion regular que me devuelva la URL del video de forma limpia.

function validate_youtube(text_element) {
if (text_element.value != ""){
var matches = "";
var expression = /((http:\/\/)|(www\.[^ \[\]\(\)\n\r\t]+)|(([012]?[0-9]{1,2}\.){3}[012]?[0-9]{1,2})\/)([^ \[\]\(\),;\"'<>\n\r\t]+)([^\. \[\]\(\),;\"'<>\n\r\t])|(([012]?[0-9]{1,2}\.){3}[012]?[0-9]{1,2})/gi;
var rx = new RegExp(expression);
var str = text_element.value;
matches = str.match(rx);
text_element.value=matches[0];
}
}

La podes agregar en el textfield con el evento onChange, entonces cuando hagas «Copy/Paste» del codigo <object…/object> en el textbox de tu CMS, obtendras la URL on the fly.

Esto ultimo tambien podria hacerce mucho mejor con el API de google para Youtube, y se podrian obtener hasta los comentarios de los videos (estuve viendo el codigo y no es para nada dificil). Pero yo necesitaba una solucion sencilla y rapida, asi que dejamos el API para el Upgrade del sitio.

descargar archivos

Nicolas. tech-nico.com/blog

Duplicar ancho de banda en horario nocturno con Mikrotik

Todos los que estamos trabajando como WISP sabemos que si hay algo que es sumamente valioso «es nuestro ancho de banda». El Mb para empresas pequeñas termina siendo muy caro y se pone dificil remar contra las telco.

La idea de este post: crear un script para aprovechar al maximo todo nuestro ancho de banda; ya que durante la noche queda casi sin uso, y nosotros lo estamos pagando!!!.

Escenario: PPPoE con Queues Dinamicas asignando a los clientes 128k y 256k respectivamente (de acuerdo al plan que tenga contratado) los cuales pasan a ser 256k y 512k entre las 00:45 y las 7:00 am.

El Script recorre las queue simples y cambia el max-limit. Se acpetan sugerencias y comentarios.


#subo128a256
:foreach i in=[/queue simple find] do={
:if ([:find [/queue simple get $i max-limit] "128000/128000"] = 0) do={
/queue simple set $i max-limit= "257000/257000";
}
}


#bajo256a128
:foreach i in=[/queue simple find] do={
:if ([:find [/queue simple get $i max-limit] "257000/257000"] = 0) do={
/queue simple set $i max-limit= "128000/128000";
}
}

Finalmente se cargan en el Scheduler y lo pueden configurar para que corra luego de la medianoche cada 1 hora hasta las 7 de la mañana. Digo cada 1 hora porque el script recorre los queues simple de los usuarios que estan conectados en ese momento (en que corrio el script), entonces si algun cliente conecta despues de que paso nuestro script, ese queda sin «doble velocidad», por eso es recomendable ejecutarlo cada 1 hora.

Este es nuestro resultado. (En este caso el Script duplica en un plan de 256k).

Algo muy facil de hacer; y los clientes no solo quedan conformes, si no que aumentan las ventas. 😉

Pinger Tool v2.0 // Reportar estado del Servicio

«Tool para reportar en tiempo real el estado de tu Red o Servicio, reduciendo reclamos telefónicos innecesarios, mediante la creacion de un componente que embeberas en la pagina web inicial de tu empresa.»

Hace algunos años tuve la necesidad de implementar en uno de mis sitios, algun sistema o especie de SNMP que sea capás de mostrar en tiempo real el estado de la red troncal de internet a los clientes.

Mas bien, la idea era reducir llamadas telefónicas innecesarias, ya que si el problema esta en el Carrier, o Telefónica aprovechamos para decir que esta andando pésimo, o que tengamos un problema nosotros mismos, en fin, estamos mostrandole al cliente «en tiempo real», que hay un corte en tal tramo de la red o en nuestro carrier de internet.

Googleando… no pude encontrar ninguna solución sencilla que represente dicha utilidad. >Todos los SNMP que publican estados de servicios en WEB, son mas bien para usos de Admins, y no para clientes finales, entonces vienen demaciado completos y/o complejos.

Aqui debajo el ejemplo: En este caso ( al estar corriendo sobre un hosting pago y compartido ) tienen desactivado el shell_exec() por razones de seguridad y politicas propias del hosting. Por eso, solo muestra color amarillo el primer tramo y arroja el error: Warning: shell_exec() has been disabled for security reasons. (solo visible en el modo debug de Flash).
Pero don’t worry; nosotros lo queremos para nuestra pagina hosteada en nuestro servidor, situado en el mismo segmento de red que queremos monitorear. Ya que, no tiene ningun sentido que queramos ver el estado de la red estando fuera de ella, precisamente porque si hay un corte en cualquier punto de la red, y la Web y Tool estan hosteados fuera, el cliente no tiene forma accederlos y menos aun ver el estado.
Entonces, para que funcione correctamente el tool, debe estar corriendo en un servidor Linux Apache que este situado dentro de la red troncal / LAN / Intranet, etc. la cual estamos monitoreando.

Desarrollar el tool: Soluciones:

  • 1) Applet Java.
  • 2) Ajax.
  • 3) Macromedia Flash.

Opte por la Tercer opcion: «Macromedia Flash» (solo poque me resulta amigable para programar).

Explicación: Se crea un archivo SWF (extención nativa de un archivo flash compilado) que viene a ser el Front End. Este interactua con 1 archivo PHP ( que no es ni mas ni menos que un ping ) que hace de MiddleWare entre el servidor Apache donde hosteamos nuestro Site y Flash, entonces cada x tiempo ejecutamos una función de flash que llama al PHP pasandole como parámetro la IP que queremos chequear si esta caido. El PHP ejecuta el comando «PING x.x.x.x», e imprime el resultado en una variable que parseamos desde Flash para interpretar que hacer con las graficas. Si el resultado da que perdio 1 paquete, cambia el estado del grafico (objeto que tiene como nombre de instancia la misma IP que chequeamos) a color Amarillo, inmediatamente vuelve a tirarle un ping para ver si realmente esta caido, y de ser asi cambia el estado a color Rojo. Como chequea (loopea) cada X segundos, la proxima vez evaluará en que estado debera estar el objeto. (Verde, Amarillo o Rojo).
Un poco de Codigo ActionScript:

function PING(ip){
pinger = new LoadVars();
pinger.host = ip;
pinger.sendAndLoad(pat + "ping.php?host=" + ip, pinger, "POST");
pinger.onLoad = function (success) {
if (success){
tramasDato = String(pinger.ping).split(" ");
trace(tramasDato[20] + " " + tramasDato[21] + " " + tramasDato[1]);
if (String(tramasDato[20] + " " + tramasDato[21]) != "1 received,"){
trace("PIERDE PAQUETE !!!!");
bad = bad + 1;
i = i - 1;
if (i < 0){
i = 1;
} // end if
gotoAndPlay(25);
}else{
bad = 0;
} // end if
trace("BAD:::: " + bad);
if (bad == 0){
colores(ip.replace(".", "_"), "on");
}else if (bad == 1){
colores(ip.replace(".", "_"), "lose");
}else if (bad > 1){
colores(ip.replace(".", "_"), "off");
i = i + 1;
if (i > 3){
i = 1;
} // end if
bad = 0;
} // end if
}else{
colores(tramo3.replace(".", "_"), "off");
colores(tramo2.replace(".", "_"), "off");
colores(tramo1.replace(".", "_"), "off");
}
};
}
function colores(tram, goto){
trace(eval(tram) + "  ///  " + goto);
eval(tram).gotoAndStop(goto);
}
pat = "http://www.tusitio.com.ar/";
tramo3 = "64.233.167.147" // ping a google.
tramo2 = "201.X.X.X"; // equipo de radio troncal.
tramo1 = "201.X.X.X"; // equipo de radio troncal.
actual = tramo1;
i = 1;
bad = 0;
tramasDato = new Array();

Para pulir un poco mas se podria haber creado un XML con la lista de IPs, y de esta manera no tener que editar el FLA cada ves que cambie el nro. de IP de algun tramo.

PHP del archivo ping.php:

// Declare some globals
global $ip, $host_name, $host_ip;
$host = $_GET['host'];

function get_ip()
{
if (isset($_SERVER[‘HTTP_X_FORWARDED_FOR’])) {
$ip = $_SERVER[‘HTTP_X_FORWARDED_FOR’]; }
elseif (isset($_SERVER[‘HTTP_CLIENT_IP’])) {
$ip = $_SERVER[‘HTTP_CLIENT_IP’]; }
else {
$ip = $_SERVER[‘REMOTE_ADDR’]; }

return $ip;
}

function ping($host, $ping_count)
{
if (get_ip()==»127.0.0.1″){
$command = «ping -c $ping_count $host»;
$fp = shell_exec(«$command 2>&1»);
$output = (htmlentities(trim($fp)));
echo ‘&ping=’.$output;
}else{
echo ‘&ping=error’;
}
}

ping($host, 1);

NOTA: sin duda «algo muy util para WISPs». Espero les sirva.

Descargar Codigo Fuente y Archivos FLA, SWF y PHP.
Recuerda que tienes que tener shell_exec habilitado en tu apache.

__________________________
Tech-Nico.com

Nicolas.