Block outbound traffic except for one destination

Was trying to block all outbound traffic from one machine, except for allowing one destination. As a test was trying to just block outbound traffic to one particular IP address, but even that fails.
Blocking inbound traffic to this machine works - it seems blocking outbound traffic entailment is different, but searching here and the web generally has not solved this.

While one solution arised, it used --direct which appears deprecated. Was looking to used rich rules, or something else that’s hopefully sustainable and simple.

Here’s an attempted example, which intends to block access to google.com

sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" destination not address="142.250.191.174" reject'

…and another with the same intention…

sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" destination address="142.250.191.174" accept'
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" destination address="0.0.0.0" reject'

How should this be done? To thoroughly block all outbound traffic, is it necessary to apply separate ipv6 rule(s) too?
It’s clear that the examples above are only temporary, and that --permanent should be added once the rules are confirmed correct.
Also, is there any way to refer to the destination with a url instead of an ip address?

All help is appreciated. Thanks.

Well, it still works, and it is exactly suitable for blocking something in addition to standard rules.

sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" destination not address="142.250.191.174" reject'

Zones are by definition for incoming traffic only. To block outgoing traffic you need to create policy with ingress zone HOST and egress zone ANY. You can further use mostly the same tools as in zone - you can set default to REJECT and allow single service/port or use rich rules to filter per destination address.

Right, but since it’s planned for removal, it makes more sense to implement a more lasting solution now, rather than something expected to regress.

Ok. This is unfamiliar - would you kindly assimilate the example from the original post, into what you’re describing?

Thanks for your help

Got it…


firewall-cmd --new-policy block-outbound --permanent
firewall-cmd --policy block-outbound --add-ingress-zone HOST --permanent
firewall-cmd --policy block-outbound --add-egress-zone ANY --permanent
firewall-cmd --policy block-outbound --set-priority -100 --permanent
firewall-cmd --policy block-outbound --set-target REJECT --permanent # block all outbound traffic
firewall-cmd --policy=block-outbound --add-rich-rule 'rule family="ipv4" destination address="142.250.191.174" accept' --permanent # allow exception
firewall-cmd --info-policy block-outbound --permanent # look things over
firewall-cmd --reload

…Thanks for your direction.

Obviously, there’s no need here to separately deal with ipv6.
Still wondering though, is there any way to refer to the destination with a url instead of an ip address? Though if you could, it would seem you must add a rule that allows reaching your dns server as another exception to the outbound blockage.

Not using firewalld which is more or less just a wrapper around kernel netfilter. This would require deep packet inspection which is obviously possible (including intercepting SSL traffic), but out of scope for firewalld. Various open source DPI implementations exist if you are interested.

Poor man solution is to resolve host name and pass IP addresses. This needs expiration management though so is not entirely trivial. Also it will give false positives for hosting sites with multiple separate domains on the same physical host/IP address.

Ok.

Poor man solution is to resolve host name and pass IP addresses.

It seems this additional code should do it (but ignoring removal of stale rule for now)…

firewall-cmd --policy=block-outbound --add-rich-rule 'rule family="ipv4" destination address="192.168.1.1" accept' --permanent # allow exception to default gateway for dns
firewall-cmd --reload
exception_ip="$(host google.com | head -1 | cut --delimiter ' ' --fields 4)"
firewall-cmd --policy=block-outbound --add-rich-rule "rule family='ipv4' destination address='${exception_ip}' accept" --permanent # allow exception
firewall-cmd --reload

This needs expiration management though so is not entirely trivial.

Timing here is not critical, so if the url is resolved and the policy is updated/recreated at each boot, that seems frequent enough - does that address what you mean?

Also it will give false positives for hosting sites with multiple separate domains on the same physical host/IP address.

If we’re only dealing with significant sites from large enterprises, e.g. google.com, should this be of little/no concern?

Thanks

No. Each DNS record has associated lifetime and compliant consumers are expected to verify that record is still valid when lifetime expires. The most obvious practical example is DynDNS.

If we’re only dealing with significant sites from large enterprises, e.g. google.com, should this be of little/no concern?

I really do not know. Nothing prevents one large enterprise from using services provided by another large enterprise. It is up to you to test and make decision.

It’s been over a year, but finally got back around to finishing this project.
This suffices for our use case…
dig @1.1.1.1 -4 +short domain.com
This is solved.

Thank you very much