Captive portal MAC address blocking with mask not working
-
I am trying to block a MAC address in pfSense using a mask, but it is not working. However, if I use the pass option and specify the same mask, it works fine.
So when I add the mac with a mask for example 12:34:56:00:00:00/24 and select block I can still access the captive portal, authenticate and then browse the internet.
When I add the mac with a mask for example 12:34:56:00:00:00/24 and select pass I can browse the internet immediatly without ahving to authenticate against the captive portal.
When I add the single MAC address without a mask and select block I get redirected to the Blocked MAC address redirect URL. So I nwo blockign does work but just not when using masks.
I am not sure what is causing this problem. Masking MAC addresses might only work when using the pass option by design or it might be a bug in pfSense. I have tried searching for a solution, but I have not been able to find anything.
If anyone knows how to fix this problem, please let me know.
Thanks!
-
@Gordon-Bennett said in Captive portal MAC address blocking with mask not working:
I am trying to block a MAC address in pfSense using a mask
If masks, or parts of a MAC addresses was an option, then that would have been mentioned here : MAC Address Control
I've looked at the new "Ethernet (Layer 2) Rules" but could only use, pass or block, entire MAC addresses, not 'masks'.
This isn't correct :
The blue info or help text is applicable for a Pass action.
The Pass action with "12:34:56:00:00:00/24" becomes a pf MAC based firewall rule ::[23.05.1-RELEASE][root@pfSense.bhf.net]/etc/inc: pfSsh.php playback pfanchordrill ..... cpzoneid_2_passthrumac/123456000000_24 rules/nat contents: ether pass in quick from 12:34:56:00:00:00/24 l3 all tag cpzoneid_2_auth dnpipe 2038 ether pass out quick to 12:34:56:00:00:00/24 l3 all tag cpzoneid_2_auth dnpipe 2039
A Block action can not be a firewall rule, because if it was, the user with a blocked MAC would never see in his browser that his device was blocked ....as the device would never be able to even reach the captive portal web server to chow that info.
Even DNS or DHCP ( ? ) wouldn't probably work. Let's call that 'bad'.So, blocked MAC's are verbatim checked one by one : see here.
and the loop that compare the user's MAC with a list of MACs to be blocked is not 'mask' aware.
But looking at it ..... and now some of my neurons are lighting up : this question was already asked ones in the past, so it's time again to use the forum search button?!
After all : it's possible to make the captiveportal_blocked_mac() function 'mask' aware.For example, if a block masked MAC range "12:34:56:00:00:00/24" is found, the /24 is used, divided by 4, that gives us 6.
The separators have to removed, and the ending /24, leaving us with an 12 character string "123456000000".
Do the same thing with the device MAC address to test, let's say "12:34:56cd:ef" becomes "123456abcdef".
Now, the left part of our block MAC (total length - 6) have to be compared the device MAC, identical left part, so we compare "121346" (blocked MAC's) to "123456" (device MAC).
That's a match -> we return "true"I hoped to find a regex to do the work, but I didn't found one.
-
If you are able to edit a file :
Open /etc/inc/captiveportal.inc, and locate the function captiveportal_blocked_mac($mac)Replace it with this :
function captiveportal_blocked_mac($mac) { global $config, $g, $cpzone; if (empty($mac) || !is_macaddr($mac)) { return false; } if (!is_array($config['captiveportal'][$cpzone]['passthrumac'])) { return false; } foreach ($config['captiveportal'][$cpzone]['passthrumac'] as $passthrumac) { if (($passthrumac['action'] == 'block')) { if (!str_contains($passthrumac['mac'],'/')) { /* Compare the entire MAC */ if ($passthrumac['mac'] == strtolower($mac)) { return true; } } else { $mask = array(); /* We know there is a '/', lets get the 'mask' */ $mask = explode('/',$passthrumac['mac']); $length = intval($mask[1])/4; if ( ($length > 0) && ($length < 48) ) { $mac1 = substr(str_replace(':','',strtolower($mac)),0,$length); $mac2 = substr(str_replace(':','',strtolower($mask[0])),0,$length); if ($mac1 == $mac2) { return true; } else { return false; } } else { return false; } } } } return false; }
And from now on you can :
which means that a device that has a MAC start starts with e0:92:5c:xx:yy:cc will be blocked.
-
Your solution involving the modification of the captiveportal_blocked_mac function in the /etc/inc/captiveportal.inc file has been tested successfully.
Following your guidance, I implemented the updated function you provided. The modifications have brought about the desired outcome, enabling us to effectively block MAC addresses using mask values.
Your willingness to share your knowledge and solution has not only resolved the technical challenge but has also showcased the strength and support of the community. I appreciate your dedication and time spent on investigating and addressing this issue.
Thanks again.