Filtrado de capa 2 con ipfw sin activar portal cautivo



  • Hola.

    He implementado un php cli script para:

    Como activar ipfw en pfSense, sin tener activo el Portal Cautivo, y efectuar filtrado de capa 2. El script permite o deniega una mac de origen a una mac de destino en una interfaz de un pfSense (Testeado en pfSense 2.3.2 amd64)

    Uso:
    Alojar el script ipfw_enable_and_block_or_allow_mac.php en un directorio, por ejemplo /scripts

    Para denegar el tráfico de la mac origen  08:00:27🇩🇪18:c3 a la mac destino 00:0c:29:5d:96:f1 en lainterfaz em0

    Ejecutar desde shell:

    php /scripts/ipfw_enable_and_block_or_allow_mac.php 'em0' '08:00:27:de:18:c3' '00:0c:29:5d:96:f1' 'deny'
    

    Para permitir (allow), ejecutar desde shell:

    php /scripts/ipfw_enable_and_block_or_allow_mac.php 'em0' '08:00:27:de:18:c3' '00:0c:29:5d:96:f1' 'allow'
    

    El código:

    
    /*
    By Javier Castañón - @javcasta - 2016
    https://javcasta.com/ - PIyMenta
    
    How to enable ipfw without start captive portal
    in pfSense 2.3.X for filter layer 2 - block or allow mac
    ---------------------------------------
    You see more code about ipfw in "/etc/inc/captiveportal.inc"
    ---------------------------------------
    mac origin 00:0c:29:5d:96:f1 - ip 10.168.0.254
    mac dst 08:00:27:de:18:c3 -ip 10.168.0.14 if=em0
    
    ipfw -q add deny MAC 00:0c:29:5d:96:f1 08:00:27:de:18:c3 mac-type ip,ipv6
    --------------------------------------
    */
    require_once("functions.inc");
    require_once("filter.inc");
    
    //cli
      $interfaz = $argv[1];
      $macorigen = $argv[2];
      $macdestino = $argv[3];
      $action = $argv[4];
    
    if (count($argv) == 0) {echo "No arguments.\n"; exit;}
    if (count($argv) < 5) {echo "This script need 4 arguments, see the code.\n"; exit;}
    
    //data example
    /*
    $interfaz = "em0";
    $macorigen = "08:00:27:de:18:c3";
    $macdestino = "00:0c:29:5d:96:f1";
    $action = "allow"; //deny
    */
    
    //call to function
    $doit = ipfw_enable_and_block_or_allow_mac($interfaz, $macorigen, $macdestino, $action);
    
    function ipfw_enable_and_block_or_allow_mac($lainterfaz, $lamacorigen, $lamacdestino, $laaction) {
    	//mute_kernel_msgs();
      //load module ipfw if is not loaded
    	if (!is_module_loaded("ipfw.ko")) {
    		mwexec("/sbin/kldload ipfw");
    		/* make sure ipfw is not on pfil hooks */
    		set_sysctl(array(
    			"net.inet.ip.pfil.inbound" => "pf", "net.inet6.ip6.pfil.inbound" => "pf",
    			"net.inet.ip.pfil.outbound" => "pf", "net.inet6.ip6.pfil.outbound" => "pf")
    		);
    	}
    	/* Activate layer2 filtering */
    	set_sysctl(array("net.link.ether.ipfw" => "1", "net.inet.ip.fw.one_pass" => "1"));
    
    	/* Always load dummynet now that even allowed ip and mac passthrough use it. */
    	if (!is_module_loaded("dummynet.ko")) {
    		mwexec("/sbin/kldload dummynet");
    		set_sysctl(array("net.inet.ip.dummynet.io_fast" => "1", "net.inet.ip.dummynet.hash_size" => "256"));
    	}
      //create zone 111 -creamos la zona 111 - attention if already exist zone 111 this destroy before defined zone 111
      mwexec("/sbin/ipfw zone 111 create");
      //associate interface to zone - asociamos interfaz a la zona
      mwexec("/sbin/ipfw zone 111 madd $lainterfaz");
      //flush - COMENTAR LINEA A CONTINUACION SINO SE BORRAN REGLAS ANTERIORES PARA ZONA 111
      //mwexec("/sbin/ipfw -x 111 -q flush"); 
      //add block o allow a la mac
      mwexec("/sbin/ipfw -x 111 -q add $laaction MAC $lamacdestino $lamacorigen mac-type ip,ipv6");
      //unmute_kernel_msgs();
      echo "Its $laaction the origin mac $lamacorigen to the dst mac $lamacdestino in interface $lainterfaz.\n";
    }
    ?>
    
    

    Salu2

    Referencias:

    https://www.javcasta.com/pfsense-ipfw-layer-2-filter-sin-activar-portal-cautivo/

    https://forum.pfsense.org/index.php?topic=116291.msg644789#msg644789



  • En la versión en inglés dejas la línea de flush?



  • Hola.

    Sí, en ese post dejo sin comentar la linea:

    mwexec("/sbin/ipfw -x 111 -q flush");

    lo que hace es borrar todas las reglas de esa zona y (si ipfw esta con política permisiva por defecto. como suele ser en pfSense y otros sistemas) deja solo la regla por defecto.:

    65535 allow ip from any to any

    Pero si cada vez que deniegues o permitas una mac con el script, y dejas esa linea sin comentar, estarás borrando las reglas anterirores, quitando la restricción a las macs que hayas aplicado un deny.

    Otra versión del script seria leer un fichero o tabla de macs a denegar (por defecto ipfw viene en modo permitir todo, así que deberiamos en realidad solo preocuparnos por los deny.)

    Salu2



  • Probado  y funciona ok. Si no se dispone de Switch gestionable con filtrado de macs  (capa 2), es una solución hacer el filtrado de macs desde el propio pfSense