Categories
DSSP2

Per-process firewalling with DSSP2-standard and NFTables using Secmark filtering

NFTables 0.9.3 was recently released with Secmark filtering support (Thanks!). Secmark with DSSP2-standard allows for per-process network filtering.

DSSP2-standard by default allows processes to send and receive “invalid” packets with the sys.recv_and_send_invalid_packets boolean. This means that processes can send and receive packets that are not associated with a valid label.

This makes it easier to configure your firewall because you will not lose connectivity in enforcing mode while you label your packets and associate your packets with nodes and ports. Access to valid packet labels is ofcourse denied by default. Associate your packet types with allow rules.

Here is a simple example that creates four packet types: two client packet types and two server packet types. One server and client packet type for IRC and one server and client packet type for ICMP. The IRC client and server packet types are associated with port 4567 but in this example they are not associated with any specific nodes (IP addresses).

In the example there are no rules associated with the packet types yet and so access to these packets is blocked by default.

!/usr/sbin/nft -f

# nft -f <file>

# echo "(block icmp (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > icmp_packet.ci>
# echo "(in irc (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > irc_packet.cil && >

table inet mysecmark {

    secmark icmp_client {
        "sys.id:sys.role:icmp.client.packet:s0"
    }

    secmark icmp_server {
        "sys.id:sys.role:icmp.server.packet:s0"
    }

    secmark irc_client {
        "sys.id:sys.role:irc.client.packet:s0"
    }

    secmark irc_server {
        "sys.id:sys.role:irc.server.packet:s0"
    }

    map secmapping_in {
        type inet_service : secmark
        elements = { 4567 : "irc_server" }

    }

    map secmapping_out {
        type inet_service : secmark
        elements = { 4567 : "irc_client" }
    }

    chain input {
        type filter hook input priority -225;

        # label new incoming packets and add to connection
        ct state new meta secmark set tcp dport map @secmapping_in
        ct state new meta secmark set udp dport map @secmapping_in
        ct state new ip protocol icmp meta secmark set "icmp_server"
        ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_server"
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }

    chain output {
        type filter hook output priority 225;

        # label new outgoing packets and add to connection
        ct state new meta secmark set tcp dport map @secmapping_out
        ct state new meta secmark set udp dport map @secmapping_out
        ct state new ip protocol icmp meta secmark set "icmp_client"
        ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_client"
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }
}

You can simply load the above table with sudo nft -f <file>. This should not interfere with existing tables. So you can for example use this alongside Firewalld as that maintains its own “Firewalld” table. Make sure you declare the packet types referenced in the table:

echo "(block icmp (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > icmp_packet.cil && sudo semodule -i icmp_packet.cil

echo "(in irc (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > irc_packet.cil && sudo semodule -i irc_packet.cil

Once you have created packet types for all your network requirements and you have associated these packet types with the appropriate rules, You can disable the sys.recv_and_send_invalid_packets boolean so that all traffic that is not explicitly allowed will be denied.

If you want to undo your Secmark configuration then simply delete the mysecmark table:

nft delete table inet mysecmark

And remove the custom modules:

sudo semodule -r icmp_packet irc_packet

Leave a Reply

Your email address will not be published. Required fields are marked *