#!/usr/local/cpanel/3rdparty/bin/perl

package scripts::cpanel_dovecot_solr_firewall;

# cpanel - scripts/cpanel_dovecot_solr_firewall          Copyright 2017 cPanel, Inc.
#                                                           All Rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

=encoding utf-8

=head1 NAME

cpanel_dovecot_solr_firewall

=head1 SYNOPSIS

    cpanel_dovecot_solr_firewall start
    cpanel_dovecot_solr_firewall stop

=head1 DESCRIPTION

This script sets up solr firewalls

=cut

use strict;
use warnings;

use Cpanel::PwCache ();

use constant SOLR_USER           => 'cpanelsolr';
use constant SOLR_PORT           => 8984;
use constant ZOOKEEPER_PORT      => ( SOLR_PORT - 1000 );
use constant IPTABLES_CHAIN_NAME => 'cpanel-dovecot-solr';
our $VERSION = '1.0';

__PACKAGE__->run(@ARGV) unless caller();

sub run {
    my ( $class, @args ) = @_;

    my $self = bless {}, $class;

    if ( grep { index( $_, 'stop' ) > -1 } @args ) {
        $self->stop_firewall();
    }
    elsif ( grep { index( $_, 'start' ) > -1 } @args ) {
        $self->start_firewall();
    }
    else {
        die "\n" . $class->help( @args ? "Unknown command: @args" : () );
    }

    return 0;
}

sub stop_firewall {
    my ($self) = @_;
    return $self->iptables()->purge_chain();
}

sub start_firewall {
    my ($self) = @_;

    {
        local $@;
        eval { $self->stop_firewall(); };    # purge so we can make new one
    }

    my $iptables = $self->iptables();
    $iptables->init_chain();

    # Workaround blanked nftables -- HB-6086
    if( ref $iptables eq 'Cpanel::NFTables' ) {
        $iptables->exec_checked_calls([
            [qw'add table inet filter'],
            [qw'add chain inet filter INPUT { type filter hook input priority 0; policy accept; }'],
            [qw'add chain inet filter FORWARD { type filter hook forward priority 0; policy accept; }'],
            [qw'add chain inet filter OUTPUT { type filter hook output priority 0; policy accept; }'],
        ]);
    }
    else {
        $iptables->attach_chain('OUTPUT');
    }

    my $cpanelsolr_uid = ( Cpanel::PwCache::getpwnam(SOLR_USER) )[2];
    my $ports_to_match = join( ',', SOLR_PORT, ZOOKEEPER_PORT );
    if( ref $iptables eq 'Cpanel::IpTables' ) {
        my @add_chain = ( '-A', $iptables->{'chain'} );
        my @port_match = ( '--protocol', 'tcp', '-m', 'multiport', '--sports' );
        my @uid_match = ( '-m', 'owner', '--uid-owner' );
        my @accept    = qw(-j ACCEPT);
        my @reject    = qw(-j REJECT);


        return $iptables->exec_checked_calls(
            [
                [ @add_chain, @port_match, $ports_to_match, @uid_match, $cpanelsolr_uid, @accept ],
                [ @add_chain, @port_match, $ports_to_match, @uid_match, 0,               @accept ],
                [ @add_chain, @port_match, $ports_to_match, @reject ],

            ]
        );
    }
    elsif( ref $iptables eq 'Cpanel::NFTables' ) { # NFTables
        return $iptables->exec_checked_calls(
            [
                [
                    qw{add rule inet filter},
                    $iptables->{'chain'},
                    qw{ip protocol tcp tcp sport},
                    "{$ports_to_match}",
                    qw{skuid}, $cpanelsolr_uid, qw{counter accept},
                ],
                [
                    qw{add rule inet filter},
                    $iptables->{'chain'},
                    qw{ip protocol tcp tcp sport},
                    "{$ports_to_match}",
                    qw{skuid 0 counter accept},
                ],
                [
                    qw{add rule inet filter},
                    $iptables->{'chain'},
                    qw{ip protocol tcp tcp sport},
                    "{$ports_to_match}",
                    qw{counter reject},
                ],
            ]
        );
    }
    return;
}

sub iptables {
    my ($self) = @_;

    # Older versions of cPanel/WHM do not have the XTables module
    if ( eval { require Cpanel::XTables; } ) {
        return ( $self->{'_iptables'} ||= Cpanel::XTables->new( 'chain' => IPTABLES_CHAIN_NAME, 'ipversion' => 4 ) );
    }

    require Cpanel::IpTables;
    return ( $self->{'_iptables'} ||= Cpanel::IpTables->new( 'chain' => IPTABLES_CHAIN_NAME, 'ipversion' => 4 ) );
}

sub help {
    my ( $class, $msg ) = @_;

    my $val;
    open my $wfh, '>', \$val or die "Failed to open to a scalar: $!";

    $msg .= "\n" if $msg;

    require 'Pod/Usage.pm';    ##no critic qw(RequireBarewordIncludes)

    'Pod::Usage'->can('pod2usage')->(
        -exitval   => 'NOEXIT',
        -message   => $msg,
        -noperldoc => 1,
        -output    => $wfh,
        -input     => $0,
    );

    return $val;
}

1;
