Project

General

Profile

Actions

Feature #12945

closed

Implement missing ipfw equivalents in libpfctl necessary for captiveportal

Added by Reid Linnemann over 2 years ago. Updated over 2 years ago.

Status:
Resolved
Priority:
Normal
Category:
Captive Portal
Target version:
Start date:
Due date:
% Done:

0%

Estimated time:
Plus Target Version:
22.05
Release Notes:
Force Exclusion

Description

As indicated by Viktor Gurov:

pfSense_ipfw_*() functions have been rewritten to use shell scripts, which is slow, and can be a serious issue for the large (>1k clients) captive
portal installations. These shell scripts should be rewritten as C functions (maybe not all):
pfSense_pf_flush_anchor(): https://gitlab.netgate.com/pfSense/pfSense/-/blob/viktor-captive/src/etc/inc/captiveportal.inc#L1064
pfSense_pf_get_cp_anchor_pipes(): https://gitlab.netgate.com/pfSense/pfSense/-/blob/viktor-captive/src/etc/inc/captiveportal.inc#L1116
pfSense_pf_mod_table(): https://gitlab.netgate.com/pfSense/pfSense/-/blob/viktor-captive/src/etc/inc/captiveportal.inc#L1129
pfSense_pf_get_table_counters(): https://gitlab.netgate.com/pfSense/pfSense/-/blob/viktor-captive/src/etc/inc/captiveportal.inc#L1764
pfSense_pf_anchor_rules(): https://gitlab.netgate.com/pfSense/pfSense/-/blob/viktor-captive/src/etc/inc/captiveportal.inc#L3054

Some of these may have been introduced into libpfctl already.

Some of this code has changed in the interim.
For reference, here is what looks to be needed:

/* XXX OPTIMIZE: pfSense_pf_flush_anchor($anchor, $type = 'rules/nat/ether') */
mwexec("/sbin/pfctl -a {$cpzoneprefix}_passthrumac/{$host} -F ethernet");

/* XXX OPTIMIZE: pfSense_pf_flush_anchor($anchor, $type = 'rules/nat/ether') */
mwexec("/sbin/pfctl -a {$cpzoneprefix}_{$anchor}/{$host} -F ether");

/* XXX OPTIMIZE: list($pipeup, $pipedown) = pfSense_pf_get_cp_anchor_pipes($anchor); */
$pipeup = mwexec("/sbin/pfctl -a {$cpzoneprefix}_{$anchor}/{$host} -se | cut -d' ' -f 17 | head -n1");

/* XXX OPTIMIZE: list($pipeup, $pipedown) = pfSense_pf_get_cp_anchor_pipes($anchor) */
exec("/sbin/pfctl -a {$cpzoneprefix}_{$anchor}mac/{$host} -se | awk -F'[()]' '{print $2; exit}'", $result, $retval);

/* XXX OPTIMIZE: array('output_pkts', 'output_bytes', 'input_pkts', 'input_bytes') = pfSense_pf_get_table_counters($table) */
exec("/sbin/pfctl -a {$anchor}/{$ip} -se -v 2>/dev/null | grep Bytes", $result);

/* Load rules for a host directly into pf = pfSense_pf_anchor_rules($anchor, $host, $rules) */
function captiveportal_load_pfctl($anchor, $host, $rules) {
    global $g, $cpzone;

    if (!empty($rules)) {
        mwexec("/usr/bin/printf \"{$rules}\" | /sbin/pfctl -a {$anchor}/{$host} -f-");
    } else {
        log_error("CP zone ${cpzone}: {$anchor} rules are empty for {$host}");
    }
}

/* Zero anchor counters = pfSense_pf_zero_anchor_counters($anchor) */
function captiveportal_anchor_zerocnt($ip, $anchor = 'auth') {
    global $config, $cpzone;
    $cpzoneprefix = CPPREFIX . $config['captiveportal'][$cpzone]['zoneid'];

    mwexec("/sbin/pfctl -z -a {$cpzoneprefix}_{$anchor}/{$ip}");
}

Rule loading will be omitted for now as it is not straightforward to expose the parser through libpfctl.

Actions

Also available in: Atom PDF