Hi,
I am experimenting with FreeBSD 11.2 as a firewall and I'd like to write firewall rules for IPv6. Since most ISPs only assign dynamic IPv6 prefixes to their customers I need to ignore the IPv6 prefix and only match the host part of an IPv6 address (which is static in my case). This is what I am trying to do:
Code:
pass in quick on pppoe0 inet6 proto tcp to {::1:1:1:1/::ffff:ffff:ffff:ffff} port {22} keep state label "SSH" # Allow SSH to raspberry pi only, ignore /64 prefix
Unfortunately
pfctl gives me a syntax error with this notation. I have also tried the
/!64 syntax which ip6tables uses for this, but this also does not work.
So the big question is: how can I apply a (hexadecimal?) mask to an IPv6 address, so
pf ignores the prefix and only matches the host part? Or is there another way of accomplishing this?
BTW: I am getting a new IPv6 prefix every 24 hours, so I cannot hard-code it into the firewall rules.
Thanks in advance,
suzaku
The network mask is incorrect, you can't do that
For example in IPv4, such masks are invalids
0:255:255:255
0.0.224.255
Or we can call that inverted masks that are not useful here
Masks always start from the left to the right, so :
255.0.0.0
255.224.0.0
255.255.255.0
255.255.255.255
This is the same thing in ipv6, masks are working in the same way
::1:1:1:1 = 0:0:0:0:1:1:1:1
::ffff:ffff:ffff:fff = 0:0:0:0:ffff:ffff:ffff:fff => forbidden mask
To understand why, refer to the CIDR notation
255.255.0.0 => CIDR mask 16
255.255.0.0 => Binary 11111111 11111111 0000000 0000000
CIDR mask 16 means : counting 16 bits flagged to 1
But you will note that CIDR notation can't take into account the position of the bit
so the following mask : 11101111 11111111 10000000 00000000 = 239 255 128.0
Would have exactly the same CIDR =>16, creating a lot of conflicts
So a network mask means : "block of contiguous bits flagged to '1', ranked from the left to the right"
So CIDR mask 16 will resolve only in : 11111111 11111111 00000000 00000000 = 255.255.0.0, and so 239.255.128.0 is a forbidden mask
This is the same thing in ipv6, the difference is : "ffffffff" => in binary "1111111111111111" (so for 8 blocks, max CIDR value is 128)
Some firewalls don't report network mask error. So depending on the firewall, a forbidden mask will be either interpreted as 0.0.0.0 / :: (authorize all) or 255.255.255.255 / IPv6 mask CIDR 128 (one address)
In packet filter dig a little, you should use dynamic tables
Code:
table <example1> const {192.168.1.0/24} # static table, can't be modified. But after compilation, if this table is not used, the table will be destroyed
table <example2> const {192.168.1.0/24} persist # same thing except that table stays in memory even if it is not in use
table <example3> {} persist # THIS IS the dynamic table you should use
pass in to <example3>
PF initializes with an empty table example3 but keeps it in memory
Further you can add, remove addresses with external command
pfctl
pfctl add -t example -T command ipv6prefix:1:1:1:1
Command can be : add, delete, flush ... see
man pfctl
You should write a shell script that will be start at boot, or that will be launched later via a cron task.
This script should grab the IPv6 address assigned to the computer, and then you can use
pfctl
to add this address
If you are not aware of Bourn Shell scripting, this is probably the time to start learning.
if your interface is em0
Code:
A=${ifconfig em0 | grep "inet6 2" | tail -n 1 | cut -w -f3}
pfctl -t example3 -T add -$A
Should grab the IPv6 global permanent address and assign it to variable A
Address is added to the table. Just note that ipv6 global routable addresses always start with "2"
The more easy way to learn is to start by analysing and modifying existing scripts.
And little by little, you will understand
Also, if your station is a simple workstation, the common user should not complicate things using it's own fixed IP.
Use the default stateless addresses (or ipv6 autoconfig).
In stateless mode your computer will get :
Address a : A permanent IPv6 link local address fe80:w:j:y:z, that will be the same after reboot. The last "w:j:y:z" is calculated according to the MAC address, so this block is permanent (in a given operating system, Windows works in a same way but generate a different address compared to FreeBSD)
Address b : permanent IPv6 global address : ipv6prefix:w:j:y:z, the last block w:j:y:z will be exactly the same as the block w:j:y:z of the Link Local Address, in your case only prefix changes. So you shouldn't worry using your own fixed IP
Address c : An auto-generated temporary address : ipv6prefix:r:r:r:r where r:r:r:r are defined on a random basis, and will change regularly
Address a : is only local, nobody can get access from global internet
Address b : is not used by default. The user can bind this address to a local server and use it to authorize incoming trafic
Address c : is used as the default outbound trafic address and subsequent incoming trafic linked to firewall stateful packet inspection. So this is the only address to be exposed publicly to the internet. For that reason, in the common stateless configuration, this address will regularly change to reduce the risk of attack. As address changes in a block of 64 bit, running an intrusive scan is difficult.