Captive Portal for single subnet only



  • So I've been able to get the Captive Portal working with local auth + vouchers on my test box. Easy - Love it.

    But I really want to do something a bit weird. Ive got a dumb switch to work with so I can't do any fancy VLAN'ing or Port based authentication

    Setup
    WAN PPPOE
    LAN 172.17.0.0/16
    OPT1 192.168.1.0/24
    IPSEC 192.168.0.0/24

    What I want is for everyone on the LAN to be able to connect to the internet through the WAN and all LAN but not the IPSEC or OPT1 network connections unless they authenticate through the portal first. (I have hardware devices on a separate switch than need direct connection through IPSEC and regularly need access over it myself)

    from what i gather I need to modify some setting in the /etc/inc/captiveportal.inc file -> but this is huge and i really don't know what I'm looking for.

    another additional but off topic
    I currently use OPENVPN with Duo Authentication to do the dual factor authentication - I haven't tested it on my test box yet because I dont have everything in place to be able to test it - however, is it possible to use this authentication server? (This is shown on a dropdown along with local database in System -> Usermanager -> Settings -> Authentication Server) That way my captive portal can have two factor authentication on it!!



  • hi all - still looking for this

    specifically having a captive portal to a single subnet

    so access to the internet as a whole but firewalled off from a subnet on the lan (different vlan so its routed through pfsense)

    almost the opposite of what currently happens

    Cheers!


  • Netgate

    I think the easiest way to do this is going to be another pfSense between your main router and the protected subnet.



  • as that would probably work - I'd rather avoid placing additional boxes in my network for what really is a small task - I feel there is going to be some configuration setting where it by default finds its local subnet allows that and blocks everything else. But without spending weeks looking through and actually understanding the code in it I have no clue.

    I want to just comment that out and swap the order so it blocks 192.168.1.0/24 and allows everything else, until you sign in then allow everything while the captive portal session is open.


  • Netgate

    This could probably be done by modifying the ipfw rules for the captive portal.  They're in /etc/inc/captiveportal.inc in function captiveportal_init_rules.

    It would survive a reboot but you'd have to merge changes from upgrades, etc.  Something like:

    pass traffic not destined for protected subnet

    add 65531 pass ip from any to not 192.168.1.1/24 in

    redirect non-authenticated clients to captive portal when accessing protected subnet

    add 65532 fwd 127.0.0.1,{$listenporthttp} tcp from any to any dst-port 80 in

    Something like that.

    Seems like it would be pretty trivial to add a 'Not' checkbox to the allowed IP rules and submit it as a feature.



  • This function I've placed in what I think you are recommending - however are these rule numbers the order they are performed in or basically arbitrary?

    …....

    $cprules = "add 65291 allow pfsync from any to any\n";
    $cprules .= "add 65292 allow carp from any to any\n";

    $cprules .= <<<eod<br># layer 2: pass ARP
    add 65301 pass layer2 mac-type arp,rarp

    pfsense requires for WPA

    add 65302 pass layer2 mac-type 0x888e,0x88c7

    PPP Over Ethernet Session Stage/Discovery Stage

    add 65303 pass layer2 mac-type 0x8863,0x8864

    layer 2: block anything else non-IP(v4/v6)

    add 65307 deny layer2 not mac-type ip,ipv6

    EOD;

    $rulenum = 65310;
    $ipcount = 0;
    $ips = "";
    foreach ($cpips as $cpip) {
    if($ipcount == 0) {
    $ips = "{$cpip} ";
    } else {
    $ips .= "or {$cpip} ";
    }
    $ipcount++;
    }
    $ips = "{ 255.255.255.255 or {$ips} }";
    $cprules .= "add {$rulenum} pass ip from any to {$ips} in\n";
    $rulenum++;
    $cprules .= "add {$rulenum} pass ip from {$ips} to any out\n";
    $rulenum++;
    $cprules .= "add {$rulenum} pass icmp from {$ips} to any out icmptype 0\n";
    $rulenum++;
    $cprules .= "add {$rulenum} pass icmp from any to {$ips} in icmptype 8 \n";
    $rulenum++;
    /* Allowed ips */
    $cprules .= "add {$rulenum} pipe tablearg ip from table(3) to any in\n";
    $rulenum++;
    $cprules .= "add {$rulenum} pipe tablearg ip from any to table(4) in\n";
    $rulenum++;
    $cprules .= "add {$rulenum} pipe tablearg ip from table(3) to any out\n";
    $rulenum++;
    $cprules .= "add {$rulenum} pipe tablearg ip from any to table(4) out\n";
    $rulenum++;

    /* Authenticated users rules. */
    $cprules .= "add {$rulenum} pipe tablearg ip from table(1) to any in\n";
    $rulenum++;
    $cprules .= "add {$rulenum} pipe tablearg ip from any to table(2) out\n";
    $rulenum++;

    $listenporthttp =
    $config['captiveportal'][$cpzone]['listenporthttp'] ?
    $config['captiveportal'][$cpzone]['listenporthttp'] :
    $config['captiveportal'][$cpzone]['zoneid'];

    if (isset($config['captiveportal'][$cpzone]['httpslogin'])) {
    $listenporthttps = $listenporthttp + 1;
    $cprules .= "add 65531 fwd 127.0.0.1,{$listenporthttps} tcp from any to any dst-port 443 in\n";
    }

    $cprules .= << <eod<br>**# pass traffic not destined for protected subnet 1
    add 65532 pass all from any to not 192.168.1.0/24 in

    redirect non-authenticated clients to captive portal

    add 65533 fwd 127.0.0.1,{$listenporthttp} tcp from any to any dst-port 80 in

    let the responses from the captive portal web server back out

    add 65534 pass tcp from any to any out

    block everything else

    add 65535 deny all from any to any

    EOD;

    /* generate passthru mac database */
    $cprules .= captiveportal_passthrumac_configure(true);
    $cprules .= "\n";

    /* allowed ipfw rules to make allowed ip work */
    $cprules .= captiveportal_allowedip_configure();

    /* allowed ipfw rules to make allowed hostnames work */
    $cprules .= captiveportal_allowedhostname_configure();

    /* load rules */
    $cprules = "flush\n{$cprules}";
    file_put_contents("{$g['tmp_path']}/ipfw_{$cpzone}.cp.rules", $cprules);
    mwexec("/sbin/ipfw -x {$cpzone} -q {$g['tmp_path']}/ipfw_{$cpzone}.cp.rules", true);
    //@unlink("{$g['tmp_path']}/ipfw_{$cpzone}.cp.rules");
    unset($cprules, $tmprules);

    if ($reinit == false)
    unlock($captiveportallck);
    }

    I'm thinking that this isn't going to pick up if i have multiple protected subnets - not a huge problem but would be nice to know / get the syntax for this correct to start with.

    **# pass traffic not destined for protected subnet 1
    add 65532 pass all from any to not 192.168.1.0/24 in
    **# pass traffic not destined for protected subnet 2
    add 65533 pass all from any to not 10.0.0.0/24 in

    Sorry only saw this today - must have missed the notification! Will try it tomorrow (Australia time)******</eod<br></eod<br>