Implementing BCP38 in firewall

I have public IP addresses on the inside of the router, i.e. no NAT, and have interest in doing source address validation, i.e. BCP38.

Before shooting myself in both feet, I ask whether anyone else have configured the Turris Omnia for this.

If I have the network 1.1.1.0/24 on the inside of the Turris, can the following two rules being the last ones in /etc/config/firewall do the trick? Because it is “first match” I hope?

config rule
	option enabled '1'
	option target 'ACCEPT'
	option src 'lan'
	option dest 'wan'
	option name 'BCP38 Allow'
	option family 'ipv4'
	option src_ip '1.1.1.0/24'

config rule
	option enabled '1'
	option target 'REJECT'
	option src 'lan'
	option dest 'wan'
	option name 'BCP38 Deny'
	option family 'ipv4'
	option src_ip '0.0.0.0/0'

those rules will probably not do what you want.
there is a bcp38 package in openwrt.

dont think it’s “wise” to use 1.1.1.0/24

What I have seen of the bcp38 package is that it only filter RFC1918 addresses, at least when I look in the package itself. Not good enough. But on the other hand, if I knew I would not have asked here :smiley:

Regarding the 1.1.1.0/24, it was just an example. I do have my own PI space, a /24, and AS, and use bird for the routing/peering with my upstream ISP. :slight_smile:

Why do you not think the rules do what I want? Because they are added to the wrong chain? Maybe I should add my own IP-tables rules then, but they might also be in the wrong chain?

yes, your rules will probably not be “early enough” to catch everything.
have you tested them?
also agree that the bcp-package is not sufficient.

afaik this functionality is implemented in the form of “reverse path filtering” (sysctl knob) for bogon-src.

and for not forwarding bogon-dst upstream you would most likely have null/reject-routes, either via bird or “local” (i.e. ip route add reject 0.0.0.0/8 metric 999 )
might see http://www.team-cymru.org/bogon-reference-http.html

hope this helps

Aha, “early enough”…good point!

Thanks for the Cymru Bogons. I forgot about those.

I have not, but will now, test my proposal. Have just studied the schnaps snap feature :slight_smile:

I have now tested, and it did work to implement BCP38 by adding rules in the firewall table so that egress filtering happened as it should.

/etc/config/firewall now looks like this (where N and M is the IPv4 and IPv6 range I have at home respectively):

config rule
	option target 'ACCEPT'
	option src 'lan'
	option dest 'wan'
	option family 'ipv4'
	option src_ip 'N.N.N.N.0/24'
	option name 'BCP38 Allow IPv4'

config rule
	option target 'ACCEPT'
	option src 'lan'
	option dest 'wan'
	option name 'BCP38 Allow IPv6'
	option family 'ipv6'
	option src_ip 'M:M:M:M::/64'

config rule
	option src 'lan'
	option dest 'wan'
	option name 'BCP38 Deny'
	option target 'DROP'
1 Like

As one of the authors of the BCP38 packet in lede/openwrt, I am puzzled as to its inapplicability to your case. You can add as many matches or nomatches to the bcp38 file as you like.

Also, instead of doing “bcp38 for ipv6”, what is implemented in openwrt instead is “source specific routing”, where the only routes out that are allowed are from your networks. There is no global default route, just routes with a “default from” clause. Anything not “from” your network will be rejected - no need for firewall rules at all.

root@gw:~# ip -6 route | grep default
default from 2001:558:6045:105:f039:c605:3f8b:8605 via fe80::46d9:e7ff:fe93:822f dev eth0 proto babel metric 1024 pref medium
default from 2601:646:8500:7100::/60 via fe80::46d9:e7ff:fe93:822f dev eth0 proto babel metric 1024 pref medium
default from 2601:646:8501:d00:46d9:e7ff:fe93:822e via fe80::46d9:e7ff:fe93:822f dev eth0 proto babel metric 1024 pref medium
default from 2601:646:8501:df0::/60 via fe80::46d9:e7ff:fe93:822f dev eth0 proto babel metric 1024 pref medium
default from 2603:3024:1536:8600:16cc:20ff:fee5:6803 via fe80::46d9:e7ff:fe93:822f dev eth0 proto babel metric 1024 pref medium
default from 2603:3024:1536:86f0::/60 via fe80::46d9:e7ff:fe93:822f dev eth0 proto babel metric 1024 pref medium
default from fde5:dfb9:df90:fff0::/60 via fe80::46d9:e7ff:fe93:822f dev eth0 proto babel metric 1024 pref medium

I agree with your statement that one can add however many match or nomatch one wants! And possibly I was expressing myself badly. But if one have to do that one can as well add them directly to the firewall rule set.

What I thought at first was that the package would work similarly to source address validation in for example Cisco boxes where it automatically filters out based on the content of the routing tables.

I now solved the issue by simply adding rules to the firewall (as you saw).

Regarding automatically solving the problem with IPv6 I can just tell you that the main reason why I started look into this was after testing the BCP38 issues by participating in the Caida Spoofer project which gave an alarm for precisely IPv6 spoofing being possible.

https://spoofer.caida.org/report.php?sessionid=185076

With the firewall rules explained here, that solved the problem for me.

“spoofer” is a very cool tool. I just ran it against my (lede) network, results here:

https://spoofer.caida.org/report.php?sessionkey=3rhe08ej5x3zcw

The ipv6 “spoofed” addresses it reports are on my local network, which for something running as root on my local network, is as expected. :whew: - you worried me there. The intent of the ipv6 source specific routing stuff was indeed to act more like (better than, IMHO) - the cisco router map does.

so - so long as you are installing a “default from” route for your ipv6 allocation rather than a default route, no further egress firewalling rules seem needed. (send me your route table?) for bcp38 on llede/openwrt for ipv6.

Unfortunately there is no source specific support for ipv4 linux, and worse, much of the world is behind double, or worse nat, therefore the bcp38 package grew to automatically handle the basic double-nat case, and be more configurable for complicated networks than we would have wanted. One example of where the bcp38 package does more or less work “right” is within the nation of Nicaragua, where it seems like the whole country shares one ip address.

http://blog.cerowrt.org/post/nicaragua/

Another is comcast modems - even in bridge mode - tend to have their config interface only on 192.168.1.100 (100.1? can’t remember) - so you can’t get to them unless you punch a small hole.

Having not done this test before, I’m not sure what my “rewritten” result means for ipv4, I’ll poke into it.

My IPv6 routing table today looks like this:

# ip -6 route
2a02:80:3ffc::/64 dev br-lan  proto static  metric 1024 
unreachable 2a02:80:3ffc::/64 dev lo  proto static  metric 2147483647  error -113
2a02:80:3ffd::/64 dev eth1  proto kernel  metric 256 
fd63:7af2:e043::/64 dev br-lan  proto static  metric 1024 
unreachable fd63:7af2:e043::/48 dev lo  proto static  metric 2147483647  error -113
fe80::/64 dev br-lan  proto kernel  metric 256 
fe80::/64 dev eth1  proto kernel  metric 256 
default via 2a02:80:3ffd::1 dev eth1  proto static  metric 1024 

And in the config/network file I have:

config interface 'wan6'
	option ifname '@wan'
	option proto 'static'
	option ip6addr '2A02:80:3FFD::2/64'
	option ip6gw '2A02:80:3FFD::1'
	option ip6prefix '2a02:80:3ffc::/64'

config globals 'globals'
	option ula_prefix 'fd63:7af2:e043::/48'