Feature #2861

Shorewall: enable green-only mode

Added by Giacomo Sanchietti about 5 years ago. Updated about 5 years ago.

Status:CLOSEDStart date:
Priority:NormalDue date:
Assignee:-% Done:

100%

Category:nethserver-firewall-base
Target version:v6.5
Resolution: NEEDINFO:No

Description

After install nethserver-firewall-base package the system will work only if a red interface is configured.

Update Shorewall configuration to enable a green-only mode: the behavior must be the same one implemented with lokkit .


Related issues

Related to NethServer 6 - Enhancement #2873: Handle nethserver-firewall-base uninstallation CLOSED

Associated revisions

Revision dd84c7d6
Added by Giacomo Sanchietti about 5 years ago

Templates: implement green+red behavior even with only one interface. Refs #2861

Revision 1deb6268
Added by Davide Principi about 5 years ago

Merged into master. Refs #2873 #2861

History

#1 Updated by Filippo Carletti about 5 years ago

  • Target version set to v6.5

#2 Updated by Giacomo Sanchietti about 5 years ago

  • Category set to nethserver-firewall-base
  • Status changed from NEW to TRIAGED
  • % Done changed from 0 to 20

Even with only one green interface configured, shorewall works well and all network service are accessible.

Extract from iptables:

...
Chain loc2fw (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    7  1170 dynamic    all  --  *      *       0.0.0.0/0            0.0.0.0/0           ctstate INVALID,NEW,UNTRACKED 
    7  1170 smurfs     all  --  *      *       0.0.0.0/0            0.0.0.0/0           ctstate INVALID,NEW,UNTRACKED 
  138 10208 tcpflags   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           
  141 10447 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           ctstate RELATED,ESTABLISHED 
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           icmp type 8 /* Ping */ 
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80 /* httpd */ 
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:443 /* httpd */ 
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:980 /* httpd-admin */ 
    1    60 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:3306 /* mysqld */ 
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0           udp dpt:123 /* ntpd */ 
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:389 /* slapd */ 
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22 /* sshd */ 
    6  1110 Reject     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           LOG flags 0 level 6 prefix `Shorewall:loc2fw:REJECT:' 
    0     0 reject     all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto] 
...

Is there any other scenario to test?

#3 Updated by Giacomo Sanchietti about 5 years ago

With this configuration rules for blocking access to local network service don't work.

Example:
  • Service: SSH
  • Port: 22
  • Access: public
  • DenyHosts: 8.8.8.8 (on net zone)

The rule should be generated in net2fw chain, but net2fw is not defined since no red interface is configured.

#4 Updated by Giacomo Sanchietti about 5 years ago

  • Status changed from TRIAGED to ON_DEV
  • Assignee set to Giacomo Sanchietti
  • % Done changed from 20 to 30

#5 Updated by Giacomo Sanchietti about 5 years ago

The proposed solution is to configure Shorewall as follow:
  • the green zone is all traffic coming to the network interface from all local networks
  • the red zone is all other traffic

Below there is an implementation with templates custom.
If any modification is done on "Trusted network" page, the firewall must be restart with following command:

signal-event firewall-adjust

Please test this configuration on a running system and on a VPS.
If the implementation is good, remember to add firewall-adjust action to following events:
  • network-create
  • network-delete
  • network-modify

/etc/e-smith/templates-custom/etc/shorewall/interfaces/20nics:

#
# 20nics
#
{
    use esmith::NetworksDB;
    my $ndb = esmith::NetworksDB->open_ro();

    if (!defined($ndb->red)) {
        foreach my $i ($ndb->green) {
            my $role = $i->prop('role') || next;
            my $type = $i->prop('type') || '';
            next if ($i->prop('role') eq 'slave' || $i->prop('role') eq 'bridged');
            next if ($type eq 'alias');
            if ($role eq 'green') {
                $OUT .= "# Force GREEN + RED mode with only one interface\n";
                $OUT .= "net\t".$i->key."\ttcpflags,dhcp,nosmurfs,logmartians,optional";
            }
            $OUT .= ",bridge" if ($type eq 'bridge');
            $OUT .= "\n";
        }
    } else {
        foreach my $i ($ndb->interfaces) {
            my $role = $i->prop('role') || next;
            my $type = $i->prop('type') || '';
            next if ($i->prop('role') eq 'slave' || $i->prop('role') eq 'bridged');
            next if ($type eq 'alias');
            if ($role eq 'green') {
                $OUT .= "loc\t".$i->key."\ttcpflags,nosmurfs";
            } elsif ($role eq 'red') {
                $OUT.="net\t".$i->key."\ttcpflags,dhcp,nosmurfs,logmartians,optional";
            } else {
                $role = substr($role,0,5); #truncate zone name to 5 chars
                $OUT.="$role\t".$i->key."\ttcpflags,nosmurfs,logmartians";
            }
            $OUT .= ",bridge" if ($type eq 'bridge');
            $OUT .= "\n";
        } 
    }
}

/etc/e-smith/templates-custom/etc/shorewall/hosts/20green:

{
    use esmith::NetworksDB;
    my $ndb = esmith::NetworksDB->open_ro();

    if (!defined($ndb->red)) {
        foreach my $i ($ndb->green) {
            $OUT .= "# Force GREEN + RED mode with only one interface\n";
            foreach my $n ($ndb->local_access_spec()) {
                my ($addr, $mask) = split('/', $n);
                my $net = esmith::util::computeLocalNetworkShortSpec($addr, $mask || '255.255.255.255');
                $OUT .= "loc\t".$i->key.":".$net."\n";
            }
        }
    }
}

/etc/e-smith/templates-custom/etc/shorewall/rules/40services (cosmetic fix):

{
    use NethServer::Service;
    use NethServer::Firewall;
    use esmith::ConfigDB;
    my $fw = NethServer::Firewall->new();
    my $confDb = esmith::ConfigDB->open();
    my $accept = 'ACCEPT';
    my $nfqueue = $firewall{'nfqueue'} || 'disabled';
    if ($nfqueue eq 'enabled') {
        $accept = 'NFQUEUE';
        # SSH and HTTPD-ADMIN exeception: do not filter ssh from local network
        $OUT.="#\n#\tAllow administration from local network\n#\n";
        $OUT .= "?COMMENT always accept sshd from loc\n";
        $OUT.="ACCEPT\tloc\t\$FW\ttcp\t".$sshd{'TCPPort'}."\n";
        $OUT .= "?COMMENT always accept httpd-admin from loc\n";
        $OUT.="ACCEPT\tloc\t\$FW\ttcp\t".${'httpd-admin'}{'TCPPort'}."\n";
    }

    foreach my $serviceRecord ($confDb->get_all_by_prop('type' => 'service')) {
        my $access = $serviceRecord->prop('access') || 'private';
    my $tcpPorts = $serviceRecord->prop('TCPPorts') || $serviceRecord->prop('TCPPort') || '';
    my $udpPorts = $serviceRecord->prop('UDPPorts') || $serviceRecord->prop('UDPPort') || '';
        if ($access eq 'none') {
            $OUT.="#\n#\tService: ".$serviceRecord->key." Access: NONE\n#\n";
            next;
        }
        if($tcpPorts || $udpPorts) {
            if( ! NethServer::Service::is_enabled($serviceRecord->key) ) {
            next;
            }
            $OUT.="#\n#\tService: ".$serviceRecord->key." Access: $access\n#\n"; 
            foreach my $port (split(',', $tcpPorts)) {
                my $allow = $serviceRecord->prop('AllowHosts') || '';
                my $deny = $serviceRecord->prop('DenyHosts') || '';
                $port =~ s/\-/:/g;
                # Always deny from hosts listed in DenyHosts
                foreach my $host (split(/,/,$deny)) {
                    my $addr = $fw->getAddress($host);
                    $OUT.="?COMMENT deny ".$serviceRecord->key." access from $host\n"; 
                    $OUT.="REJECT\t".$fw->getZone($host)."\t\$FW\ttcp\t$port\n";
                }
                # Always accept from hosts listed in AllowHosts
                foreach my $host (split(/,/,$allow)) {
                    my $addr = $fw->getAddress($host);
                    $OUT.="?COMMENT allow ".$serviceRecord->key." access from $host\n"; 
                    $OUT.="$accept\t".$fw->getZone($host)."\t\$FW\ttcp\t$port\n";
                }
                $OUT.="?COMMENT ".$serviceRecord->key."\n"; 
                $OUT.="ACCEPT\tloc\t\$FW\ttcp\t$port\n";
                if ($access eq 'public') {
                    $OUT.="$accept\tnet\t\$FW\ttcp\t$port\n";
                }
            }
            foreach my $port (split(',', $udpPorts)) {
                my $allow = $serviceRecord->prop('AllowHosts') || '';
                my $deny = $serviceRecord->prop('DenyHosts') || '';
                $port =~ s/\-/:/g;
                # Always deny from hosts listed in DenyHosts
                foreach my $host (split(/,/,$deny)) {
                    my $addr = $fw->getAddress($host);
                    $OUT.="?COMMENT deny ".$serviceRecord->key." access from $host\n"; 
                    $OUT.="REJECT\t".$fw->getZone($host)."\t\$FW\tudp\t$port\n";
                }
                # Always accept from hosts listed in AllowHosts
                foreach my $host (split(/,/,$allow)) {
                    my $addr = $fw->getAddress($host);
                    $OUT.="?COMMENT allow ".$serviceRecord->key." access from $host\n"; 
                    $OUT.="$accept\t".$fw->getZone($host)."\t\$FW\tudp\t$port\n";
                }
                $OUT.="ACCEPT\tloc\t\$FW\tudp\t$port\n";
                if ($access eq 'public') {
                    $OUT.="$accept\tnet\t\$FW\tudp\t$port\n";
                }
            }
        }
    }
}

#6 Updated by Giacomo Sanchietti about 5 years ago

  • Assignee deleted (Giacomo Sanchietti)

#7 Updated by Giacomo Sanchietti about 5 years ago

  • Assignee set to Giacomo Sanchietti

#8 Updated by Giacomo Sanchietti about 5 years ago

  • Status changed from ON_DEV to MODIFIED
  • % Done changed from 30 to 60

Implemented in branch b2861.

#9 Updated by Giacomo Sanchietti about 5 years ago

  • Status changed from MODIFIED to ON_QA
  • Assignee deleted (Giacomo Sanchietti)
  • % Done changed from 60 to 70
Package in nethserver-testing:
  • nethserver-firewall-base-2.0.0-2.4git30ca6de.ns6.noarch.rpm
    nethserver-firewall-base-2.0.0-2.10gitc9af047.ns6.noarch.rpm
Test case
  • Install nethserver-firewall-base on a system with one interface
  • Configure AllowHosts and DenyHosts for a service using local and public addresses
  • Check all rules are correctly created
  • Check the firewall is reconfigured each time a local network is modified

#10 Updated by Davide Principi about 5 years ago

  • Assignee set to Davide Principi

#11 Updated by Davide Principi about 5 years ago

  • Status changed from ON_QA to VERIFIED
  • Assignee deleted (Davide Principi)
  • % Done changed from 70 to 90

#12 Updated by Davide Principi about 5 years ago

#13 Updated by Davide Principi about 5 years ago

  • Status changed from VERIFIED to CLOSED
  • % Done changed from 90 to 100

In nethserver-updates:
nethserver-firewall-base-2.1.0-1.ns6.noarch.rpm

Also available in: Atom PDF