How to configure firewalld to act as a router for specific interfaces?

Hi,

I am looking for a way to use (internal, LAN) interface eth0 to provide Internet comming from (external) interface eth1.

Based on this info I have set:


# cat /etc/firewalld/direct.xml
<?xml version="1.0" encoding="utf-8"?>
<direct>
  <rule ipv="ipv4" table="nat" chain="POSTROUTING" priority="0">-o eth1 -j MASQUERADE</rule>
  <rule ipv="ipv4" table="filter" chain="FORWARD" priority="0">-i eth0 -o eth1 -j ACCEPT</rule>
  <rule ipv="ipv4" table="filter" chain="FORWARD" priority="0">-i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT</rule>
</direct>

and also in /etc/sysctl.conf (applied using ‘sysctl -p’):


net.ipv4.ip_forward = 0
net.ipv4.conf.eth0.forwarding = 1

but it doesn’t work unless I also set:


net.ipv4.ip_forward = 1

which as far as I understand enables forwarding for all interfaces (which I don’t want) and not only for eth0 (which I want). According to kernel documentation of sysctl:

conf/interface/* changes special settings per interface (where
“interface” is the name of your network interface)

forwarding - BOOLEAN
Enable IP forwarding on this interface. This controls whether packets
received on this interface can be forwarded.

Am I misunderstanding the docs and how should this be set correctly?

You cannot forward from eth0 to eth1 without forwarding replies from eth1 to eth0

Am I misunderstanding the docs
Yes
and how should this be set correctly?

You set net.ipv4.ip_forward = 1.

P.S. Your literal question in subject has no answer because firewalld has absolutely nothing to do with routing.

According to tha kernel docs you need to set

net.ipv4.ip_forward = 1

to enable forwarding.

Try to use this

# cat /etc/firewalld/direct.xml
 <?xml version="1.0" encoding="utf-8"?> 

<direct> 
      <rule ipv="ipv4" table="filter" chain="FORWARD_direct" priority="0"> -i eth0 -o eth1 -j ACCEPT </rule> ]
 </direct>

and see if it solves your problem.

OK, with this I have Internet connection on the LAN machines:


net.ipv4.ip_forward = 0
net.ipv4.conf.eth0.forwarding = 1
net.ipv4.conf.eth1.forwarding = 1

Is the above a correct set up?

You set net.ipv4.ip_forward = 1.

Won’t that enable forwarding for all interfaces?

P.S. Your literal question in subject has no answer because firewalld has absolutely nothing to do with routing.

I am not a network expert, so I may have been mislead to put it this way because it was asked similarly in the first link.

Mmmmm…
I’m sorry to “post and run” in this case because I’m in the middle of something that demands my attention, and on top of that I haven’t looked at this that closely recently, but my understanding is that netfilter and current ip tools support a kind of “session state” so you likely <should not> be configuring ip forwarding in both directions (because you’re implementing NAT).

If you want to manually configure your NAT iptables rules, a quick Internet search returns the following two articles which I consider reliable and authoritative, and neither configure a forwarding rule for “replies,” instead rely on the kernel netfilter module and the conntrack module. Note that these two references do <not> meld together perfectly, in one case the instructions use the sysctl command to temporarily apply a rule and/etc/sysctl to apply rules persistently and in another case makes a call directly to /proc/sys, you will want to know that both methods are ways to accomplish the same thing, but using /etc/sysctl is safer because if you make a mistake, the rule just isn’t applied whereas a bad call to /proc/sys/ can lock up your machine. And, I haven’t looked at configuring using firewalld’s xml files in which case perhaps sysctl and /proc/sys/ wouldn’t even be used.

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Security_Guide/s1-firewall-ipt-fwd.html
https://www.karlrupp.net/en/computer/nat_tutorial

Maybe in the “old days” before ip a forwarding rule might have been required for replies but not so today.

Sorry to post and run…
TSU

No

Won’t that enable forwarding for all interfaces?

This will enable forwarding. Without further qualification. Without this setting no forwarding happens at all.

You should be able to configure NAT without handcrafting your config files…

  1. Launch firewall-config (eg YaST Firewall module)
  2. Your network interfaces should be listed in the “Active Bindings” pane to the far left.
  3. Select your LAN interface (facing your LAN). Set to the “internal” zone
  4. Select your WAN interface (facing the Internet). It should already be assigned to the “public” zone or you need to set accordingly. Scroll the tabs until you reach the “Masquerading” tab. Check the “Masquerade Zone” checkbox.
  5. Reload the firewall daemon.

Remember that you should be configuring “Runtime” for now until you are sure you have configured what you want.
Once you are sure of your configuration, then switch to “Permanent” and re-apply your settings.

Test.

Post your results, your LAN clients should be able to connect to resources on the Internet while nothing from the Internet should be able to initiate a connection to your LAN clients.

If not working, then we’ll need to take a closer look at your firewall modules(typically you should see an error in your journal).

TSU

Along with enabling IP forwarding in the kernel IP stack, it is the firewall rules which then decide how such packets are filtered/forwarded etc.

May I ask why please?

This will enable forwarding. Without further qualification. Without this setting no forwarding happens at all.

How do you restrict it to specific interface?

@tsu2 - thanks for the links. I will have a deeper look at that (seems I have a lot to learn).

I answered this in the next sentence in the post you are replying to.

How do you restrict it to specific interface?

Forwarding by definition cannot be restricted “to specific interface” because it requires at least two interfaces. You probably need to step back and explain what you are trying to achieve instead of showing how you are trying to do it. I have a feeling that we mean something different when speaking about “forwarding”.

Sharing of Internet connection with the LAN machines following the principle “drop all, allow explicitly only what is needed”.
On the particular machine I am trying to do it: External interface: eth1. Internal interface: eth0.

Many years ago on an old RedHat version a friend showed me how to do it this way but I couldn’t find a way to use this method with SuSEfirewall2 and now when it is replaced with firewalld I suppose it would be more relevant to learn how to all this using the modern tools like firewalld and nftables (and whatever else applies).

So that is what I am trying to learn.

And where are all those other interfaces you implied previously? Your system has just two interfaces and you need to forward between those two interfaces so what are you going to restrict?

Many years ago on an old RedHat version a friend showed me how to do it this way but I couldn’t find a way to use this method with SuSEfirewall2 and now when it is replaced with firewalld I suppose it would be more relevant to learn how to all this using the modern tools like firewalld and nftables (and whatever else applies).

Now that is entirely different from what you have asked in your original post.
This script can be taken almost literally using firewalld direct rules with added bonus that firewalld will automatically support both iptables and nftables backends. Unfortunately, firewalld has very limited support for high level definition of forwarding rules. This has been requested, but nothing happened so far:
Accept/Reject/Drop Forwarding packets
Zone to zone chains for forward rules

On the openSUSE machine which is going to act as a router and firewall.

Your system has just two interfaces and you need to forward between those two interfaces so what are you going to restrict?

According to ‘ip link show’ there are 5 interfaces:

1: lo
2: eth0
3: eth1
4: virbr1
5: virbr1-nic

Now that is entirely different from what you have asked in your original post.

I agree this widens the discussion a little but as far as I understood you wanted to know the high-level objective, that’s why I explained. I can open a separate thread if you consider this more appropriate.

This script can be taken almost literally using firewalld direct rules with added bonus that firewalld will automatically support both iptables and nftables backends.

May I ask how to do this please?

Unfortunately, firewalld has very limited support for high level definition of forwarding rules. This has been requested, but nothing happened so far:
Accept/Reject/Drop Forwarding packets
Zone to zone chains for forward rules

Could you suggest a better way then?

Oh well. You can stop forwarding packets coming into specific interface by setting interface’s forwarding flag to 0. Or you can define netfilter rules to pass only explicitly matched packets and reject/block everything else as fallback. It is really up to you.

May I ask how to do this please?

But you already know what direct rules are, you have shown them in your very first post. So I’m not sure what you want me to explain?

May I make a few suggestions…

  • Regarding the original question that was posted in the first post…
    I’d recommend disregarding almost the entirety of this thread and focus on my post that describes how to use firewall-config to configure a typical NAT routing device…

https://forums.opensuse.org/showthread.php/533578-How-to-configure-firewalld-to-act-as-a-router-for-specific-interfaces?p=2884307#post2884307

  • If the result of the steps I described to set up your machine delivers what you want, then you can look at the individual config files if you want to learn what rules were created. Unfortunately, the official firewalld documentation is very minimal… It mostly just refers you to the MAN pages, but if you still need help at this point deciphering the syntax, post your questions then.

The above should be easy for anyone to do on their own.

HTH,
TSU

OK I understand now. So initially I was hoping to approach this again by using the “blacklist forwarding for all interfaces by default, white list only what is going to be used”. You seem to suggest the opposite approach: enable ipv4 forwarding globally, blacklist what won’t be used. Is that the only way to set up these particular kernel parameters?

Or you can define netfilter rules to pass only explicitly matched packets and reject/block everything else as fallback.

Do the rules which I posted in the OP do this or are you suggesting something else?

It is really up to you.

AFAIU from your words there are more than one ways. I am willing to learn how to do this correctly in the sense: using the right (most appropriate and technically efficient) tool for the job.

But you already know what direct rules are, you have shown them in your very first post. So I’m not sure what you want me to explain?

Since we reached this point I am hoping to learn the right approach to the high-level objective. As I am still learning I don’t know if those direct rules are the most appropriate ones or if firewalld is the right tool as a whole (considering what you explained about limitations).

That won’t work because I don’t like the default zones of “internal” and “public”. I want a more controlled approach, similar to the shared script.

Unfortunately, the official firewalld documentation is very minimal… It mostly just refers you to the MAN pages,

Quite right.

but if you still need help at this point deciphering the syntax, post your questions then.

Ideally I am looking to “translate” the script/approach I shared for the purpose explained in the “language” of firewalld (or of whatever tool better may serve the purpose).

There’s no diff in “preciseness”
The assignment of zones is just an additional management layer to better understand the collection of rules applied to a specified interface., and can also help avoid mistakes like pointing your firewall in a wrong direction.

TSU

I question that. For example “public” may have different meanings depending on purpose. I read its description:

“For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.”

Yet ssh is enabled on it by default as a trusted service and its target is set to “Default Target” which is (greyed out) ACCEPT. To me this is the opposite of “not trust other computers”. For public I won’t allow even ping. This is not a public server.

The assignment of zones is just an additional management layer to better understand the collection of rules applied to a specified interface., and can also help avoid mistakes like pointing your firewall in a wrong direction.

Considering the above it seems it may also point one it in the wrong direction. So I right now I have the external interface set to drop zone and the interna to a custom zone (with default target ‘DROP’) which has only specifics enabled for my LAN clients. Unfortunately that is only part of the goal.

You can check each of the default services allowed for a given zone, they’re just broad (predefined) usage categories, but you can actually configure each of them as you like.

The names of each zone are just labels. In coding parlance, that means that it’s just a sticker you slap on something just to put a name on it, the name has nothing to do with what it’s attached to… Although smarter people will attach a meaning to the name to more easily remember or know what that something is that the label is attached to.

In other words…
If “public” makes you uncomfortable, then create something new on your own and customize the zone however you wish.
The provided zones are only common configurations most people will want but there is nothing that forces you to use any of them.

I also think you intentionally strain to misunderstand what “public” is… Compared to other less paranoid zones, what sets the Public zone apart is that <by default> all ports are closed. A service like SSH has to be defined and configured to be let through which might not be the case in another zone. Just because the SSH rule may be partially configured, unless it’s completed I doubt that the rule will allow traffic through and if it bothers you that much, then just remove the rule.

TSU