How to replace openSUSE firewall with a custom script of rules?

I would like to create my own iptables rules from scratch instead of using the YaST > Firewall custom rules.

If I create my own firewall script with those rules and disable the built-in firewall service of openSUSE - where should I put this script in order the system to run it at proper time during boot? I would like to do it in a clean way so that if I change my mind later I can still go back to the built-in firewall.

P.S. My main idea is to drop all packets and to allow only what I really need. Does that imply any worse security than the default firewall scheme?

Just from looking at my firewall on Leap, the default seems to do this out of the box and looks pretty secure for most users to me. If you do iptables -L -v -n you should see rules like so (pay attention to bolded):


Chain INPUT (**policy DROP** 0 packets, 0 bytes)
...
    22  27K **input_ext**  all  --  *      *       0.0.0.0/0            0.0.0.0/0   
    **0     0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            limit: avg 3/min burst 5 LOG flags 6 level 4 prefix "SFW2-IN-ILL-TARGET "**
    **0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0**     


Chain OUTPUT (**policy ACCEPT** 1064K packets, 75M bytes)
26657   48M ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0


Chain **input_ext** (1 references)
 pkts bytes target     prot opt in     out     source               destination         
  0  238K DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = broadcast
    0     0 **ACCEPT**     **icmp** --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 4
    0    0 **ACCEPT**     **icmp** --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 8
   0    0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = multicast
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            PKTTYPE = broadcast
   **0  0 LOG        tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            limit: avg 3/min burst 5 tcp flags:0x17/0x02 LOG flags 6 level 4 prefix "SFW2-INext-DROP-DEFLT "**
    **0     0 LOG        icmp --  *      *       0.0.0.0/0            0.0.0.0/0            limit: avg 3/min burst 5 LOG flags 6 level 4 prefix "SFW2-INext-DROP-DEFLT "**
   **0  0 LOG        udp  --  *      *       0.0.0.0/0            0.0.0.0/0            limit: avg 3/min burst 5 ctstate NEW LOG flags 6 level 4 prefix "SFW2-INext-DROP-DEFLT "**
**  0  0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0**

Explanation (No spoiler tags?):
Note how iptables has a default policy for INPUT set to drop, this means that any packet that does not match one of the rules will be dropped. In addition, there is a DROP for all packets at the end of the INPUT chain. Note that the LOG above the DROP in the INPUT chain ensures that all these packets get logged so we can always check if there is some communication made that we did not approve of.

Then the OUTPUT chain is set to ACCEPT all traffic. This is done because the computer will likely need to act as a client various services like HTTP, SSH and so on. The reason its set to accept is to allow use of the high non reserved ports since they are assigned randomly and its not really possible to predict what service will use what port.

Lastly there is input_ext chain which is actually referenced in the INPUT chain. Since its referenced before the LOG and DROP, iptables will check this chain to see if the packet matches any of the rules here. Notice in this chain there are 3 LOG rules which are used to track what type of traffic is being sent to us if it didnt match the rules above (TCP, ICMP or UDP). After the packets are logged they are dropped.

IMO these rules are pretty good, it could be hardened further if you are dedicated but I think you should be able to do that with the SuSE firewall, unless you really really want to write all the rules yourself :slight_smile:

Hope that wasnt too much to read…

Thanks a lot for taking the time to write that.

Actually the policy seems to be:

  1. Accept all on lo
  2. Accept related and established on all interfaces
  3. Accept ICMP
  4. Accept all input on internal interace
  5. Log all (with some limit burst etc)
  6. And just after all that - drop

And what I want is something like:


#!/bin/bash
ipt=`which iptables`

$ipt -F
$ipt -t nat -F

$ipt -P INPUT DROP
$ipt -P FORWARD DROP

$ipt -A INPUT -i lo -j ACCEPT
$ipt -A INPUT -s 127.0.0.1/8 -i ! lo -j LOG
$ipt -A INPUT -s 127.0.0.1/8 -i ! lo -j DROP

# and then allow only what I really need

I am not sure I want all the logging which SuSEfirewall2 does by default. Why would I fill my journal with that info? I suppose cleaner approach would be: if some program doesn’t work, use tcpdump to see what it needs and add it to the custom script as a rule.

Then the OUTPUT chain is set to ACCEPT all traffic. This is done because the computer will likely need to act as a client various services like HTTP, SSH and so on. The reason its set to accept is to allow use of the high non reserved ports since they are assigned randomly and its not really possible to predict what service will use what port.

I certainly don’t want anything happening randomly. No program should communicate without being explicitly allowed. Imagine this machine used as as a router and there are Windows machines in the LAN. Some of the machines might get infected by something at any time and start sending and receiving info randomly (not that Windows is not a spyware by itself but that’s another story). You get the point.

I also don’t want to forward all ports for all protocols to all the world.

Also - why would I want all the icmp related accepts which SuSEfirewall2 offers by default? I don’t want even to be pinged (except from a few known hosts).

I hope that makes clear why I am looking for a solution with full control over all this.

Ah you didn’t mention you wanted to use this as a router :slight_smile:

There is a configuration file for susefirewall located at /etc/sysconfig/SuSEfirewall2 (https://en.opensuse.org/SuSEfirewall2) which may help you out with some of what you want. Perhaps the best way to set it would be with a systemd service for your custom rules? You could just tell it when to start and it should work… but I havent tried this before so maybe someone else can help with that :slight_smile:

Best of luck.

That’s what I am here for :slight_smile:

There is some documentation here:
http://www.freedesktop.org/software/systemd/man/systemd.unit.html
https://wiki.archlinux.org/index.php/Systemd#Writing_unit_files

In /usr/lib/systemd/system I see:

-rw-r--r--  1 root root   423 Jun 27 12:44 SuSEfirewall2.service
-rw-r--r--  1 root root   240 Jun 27 12:44 SuSEfirewall2_init.service

Is it appropriate to use one of them (which one if yes?) as a template and put my own firewall script in the ExecStart? Then I will simply enable my service and disable the SuSEfirewall2 one. Would that be a clean solution?

I still hope someone can answer as I couldn’t find info how to properly activate the custom script. I don’t want to break anything.

Without digging into why your script may not work (if you want help with this, start with providing a link to whatever you’re using to guide your efforts),

You should know that SUSE FW is only one iptables management app.
It’s pretty well known that SUSE FW is a fairly simple tool which only supports most common User scenarios.

Searching the OSS,

zypper se firewall

Returns a couple tools “Firewall Builder” and “Firewall Configuration” which might be of interest (I haven’t used either).

Searching the OSS, it looks like there is an alternative to to SUSE FW called xfw.
You may want to try uninstalling SUSE FW and installing ufw

zypper rm SuSEfirewall2 yast2-firewall && zypper in xfw

You can also download iptables firewall config and managers from non-openSUSE sources, just be sure to uninstall SuSEfirewall2 first.

TSU

I don’t want to install other firewalls. I can write my own iptables lines. My script will work - it has worked for years on an older router and on a different distro, so the script itself is ok. It is similar to this one but not identical.

I understand that the SuSEfirewall2 service needs to be disabled. I know how to do that in YaST. The only question is how to make my script run on boot, i.e. register it as a service with proper parameters.

Recommend you copy the SUSE FW systemd Unit file as follows. Note that the original location is the standard location for system Unit files which you should <never> alter and the new location is where any custom User Unit files files reside. If a Unit file in the User location is the same name as the original default in /usr/lib/* then the custom Unit file will over-ride.

cp /usr/lib/systemd/system/SuSE* /etc/systemd/system/

Now, I recommend you rename your copied files to whatever you wish to avoid confusion.

The result is Unit files which are used to start and run SUSE FW but now can be pointed to your custom script or configuration files.

TSU

Thanks TSU. So basically as I thought. I will try to set up a systemd unit.

Trying to combine /usr/lib/systemd/system/SuSEfirewall2.service and /usr/lib/systemd/system/SuSEfirewall2_init.service I wrote this:


[Unit]
Description=My custom firewall
Before=network.service
Before=basic.service
After=network.target ypbind.service nfs.service nfsserver.service rpcbind.service

[Service]
ExecStart=/usr/local/sbin/my-firewall-start
ExecStop=/usr/local/sbin/my-firewall-stop
RemainAfterExit=true
Type=oneshot

[Install]
WantedBy=multi-user.target

Is it correct? (I am just not 100% sure about the Before and After options)

Can’t say without specific, detailed info.

So, for instance you should look at what the default SuSEfirewall2 scripts currently say. It’s almost certain that they will contain code to both instantiate (or stop) iptables as well as contain configurations.

Since it appears that you’re replacing the existing SuSEfirewall2 scripts completely, you need to make sure you replace all the necessary functionality, which means that if your existing script only modifies you’d need to insert all the other functionality.

I’d recommend you use the existing SuSEfirewall2 scripts as templates for whatever you wish to do, modifying with your existing script.

Of course, this all supposes that your existing script can’t just modify iptables the way SUSE FW sets up which would be a lot less work.

TSU

What info would that be? The script is just lines of iptables rules (as shown in a previous post).

The SuSEfirewall2 scripts are too complicated because they need to read info from what one puts in YaST etc. So I am not going to adopt such complexity, it is not necessary. Actually that is exactly what I am trying to avoid - some complicated script aimed at better desktop usability doing the thinking for me (and logging and so on).

Uhm, maybe something like this:


[Unit]
Description=My custom firewall
Requires=network.service
Before=network.target
After=network.service ypbind.service nfs.service nfsserver.service rpcbind.service

[Service]
ExecStart=/usr/local/sbin/my-firewall-start
ExecStop=/usr/local/sbin/my-firewall-stop
RemainAfterExit=true
Type=oneshot

[Install]
WantedBy=multi-user.target

Can you explain the changes you made and the reasons for them?

Network.service brings network interfaces up. I assume your script needs that. My changes also ensure your firewall script is executed after network.service exits and only if the latter doesn’t fail.

Besides that, “Before=basic.service” should not be necessary.

Hm. But I have adopted those from the original SuSEfirewall2 service files. Are you saying the order in them is wrong too?

Here (OSuse 13.2) the SuSEfirewall2 service is split in 2 units: SuSEfirewall2_init.service and SuSEfirewall2.service.

As far as I can tell you have used the former as template. Can you confirm that?