# Enable firewall and install defined rules
#
# Rules are readed from variable $firewall_rules which needs to be an
# array containing list of opened services in format:
#
#     <proto>/<port> [source]
#
# for example:
#
#     $firewall_rules = [ "tcp/22 192.168.1.0/24",
#                         "tcp/80", ]
#
# If source is left out the service will be opened to all connecting
# hosts.
#
# Custom rules can be defined into variable $firewall_custom:
#
#     $firewall_custom = [ "pass in quick carp", ]
#
# Loading of extra modules is supported on centos. For example FTP
# support for iptables:
#
#     $firewall_modules = [ "nf_conntrack_ftp", ]

class firewall {

    if ! $firewall_custom {
        $firewall_custom = []
    }
    if ! $firewall_rules {
        $firewall_rules = []
    }

    case $::operatingsystem {
        "centos","redhat","debian","fedora","ubuntu": {
            include firewall::iptables
        }
        "openbsd": {
            include firewall::pf
        }
        default: {
            fail("Firewall module not supported in ${::operatingsystem}")
        }
    }

}


# Enable firewall and install custom config file
#
# Config file is searched in following order:
#
#     puppet:///files/firewall/${config}.${fqdn}
#     puppet:///files/firewall/${config}
#
# where config is firewall configuration file name
# (iptables or pf.conf).
#
class firewall::custom {

    case $::operatingsystem {
        "centos","redhat","debian","fedora","ubuntu": {
            include firewall::custom::iptables
        }
        openbsd: {
            include firewall::custom::pf
        }
        default: {
            fail("Firewall module not supported in ${::operatingsystem}")
        }
    }

}


# Linux iptables handler.
#
class firewall::common::iptables {

    case $::operatingsystem {
        "centos","fedora","redhat": {
            $iptables = "/etc/sysconfig/iptables"
            $ip6tables = "/etc/sysconfig/ip6tables"
        }
        "ubuntu": {
            if versioncmp($::operatingsystemrelease, "11.10") < 0 {
                $iptables = "/etc/iptables/rules"
            } else {
                $iptables = "/etc/iptables/rules.v4"
            }
            if versioncmp($::operatingsystemrelease, "11.04") < 0 {
                $ip6tables = undef
            } else {
                $ip6tables = "/etc/iptables/rules.v6"
            }
            # kludge for missing directory in Ubuntu 11.04 Natty
            if $::operatingsystemrelease == "11.04" {
                file { "/etc/iptables":
                    ensure => directory,
                    mode   => "0755",
                    owner  => "root",
                    group  => "root",
                    before => File[$iptables],
                }
            }
        }
        "debian": {
            $iptables = "/etc/iptables/rules"
            $ip6tables = undef
        }
    }
    $ip6states = versioncmp($::kernelversion, "2.6.20")

    if $::operatingsystem == "Fedora" and $::operatingsystemrelease > 17 {
        package { "firewall-config":
            ensure => absent,
            before => Package["firewalld"],
        }
        package { "firewalld":
            ensure => absent,
            before => Package["iptables"],
        }
    }

    package { "iptables":
        ensure => installed,
        name   => $::operatingsystem ? {
            "centos" => [ "iptables", "iptables-ipv6" ],
            "redhat" => [ "iptables", "iptables-ipv6" ],
            "debian" => [ "iptables", "iptables-persistent" ],
            "fedora" => $::operatingsystemrelease ? {
                /^1[0-5]/ => [ "iptables", "iptables-ipv6" ],
                /^1[6-7]/ => "iptables",
                default   => [ "iptables", "iptables-services" ],
            },
            "ubuntu" => [ "iptables", "iptables-persistent" ],
        },
    }

    file { $iptables:
        ensure  => present,
        mode    => "0600",
        owner   => "root",
        group   => "root",
        require => Package["iptables"],
        notify  => Service["iptables"],
    }
    service { "iptables":
        ensure  => running,
        name    => $::operatingsystem ? {
            "debian" => "iptables-persistent",
            "ubuntu" => "iptables-persistent",
            default  => "iptables",
        },
        alias   => $::operatingsystem ? {
            "ubuntu" => "ip6tables",
            default  => undef,
        },
        enable  => true,
        status  => "iptables -t filter --list --line-numbers | egrep '^1'",
        require => Package["iptables"],
    }

    if $ip6tables {
        file { $ip6tables:
            ensure  => present,
            mode    => "0600",
            owner   => "root",
            group   => "root",
            require => Package["iptables"],
            notify  => Service["ip6tables"],
        }
        case $::operatingsystem {
            "centos","fedora","redhat": {
                service { "ip6tables":
                    ensure     => running,
                    enable     => true,
                    hasstatus  => true,
                    hasrestart => true,
                    require    => Package["iptables"],
                }
            }
        }
    }

    if $firewall_modules {
        case $::operatingsystem {
            "centos","fedora","redhat": {
                $firewall_modules_str = inline_template('<%= @firewall_modules.join(" ") -%>')
                augeas { "iptables-config":
                    context => "/files/etc/sysconfig/iptables-config",
                    changes => [ "set IPTABLES_MODULES '${firewall_modules_str}'" ],
                    notify  => Service["iptables"],
                }
            }
        }
    }

}


# Linux iptables handler to install default firewall config.
#
class firewall::iptables inherits firewall::common::iptables {

    File[$firewall::common::iptables::iptables] {
        content => template("firewall/iptables.erb"),
    }

    if $firewall::common::iptables::ip6tables {
        File[$firewall::common::iptables::ip6tables] {
            content => template("firewall/ip6tables.erb"),
        }
    }

}


# Linux iptables handler to install custom firewall config.
#
class firewall::custom::iptables inherits firewall::common::iptables {

    File["/etc/sysconfig/iptables"] {
        source  => [ "puppet:///files/firewall/iptables.${::homename}",
                     "puppet:///files/firewall/iptables", ],
    }

}


# OpenBSD Packet Filter handler
#
class firewall::common::pf {

    file { "/etc/pf.conf":
        ensure  => present,
        mode    => "0600",
        owner   => "root",
        group   => "wheel",
        notify  => Exec["pfctl -f /etc/pf.conf"],
    }

    exec { "pfctl -f /etc/pf.conf":
        path        => "/bin:/usr/bin:/sbin:/usr/sbin",
        refreshonly => true,
    }

}


# OpenBSD Packet Filter handler for default config.
#
class firewall::pf inherits firewall::common::pf {

    File["/etc/pf.conf"] {
        content => template("firewall/pf.conf.erb"),
    }

}


# OpenBSD Packet Filter handler for custom config.
#
class firewall::custom::pf inherits firewall::common::pf {

    File["/etc/pf.conf"] {
        source  => [ "puppet:///files/firewall/pf.conf.${::homename}",
                     "puppet:///files/firewall/pf.conf", ],
    }

}


# OpenBSD NAT handler for FTP protocol.
#
class firewall::ftpproxy {

    service { "ftpproxy":
        ensure => running,
        enable => true,
        binary => "/usr/sbin/ftp-proxy",
        start  => "/usr/sbin/ftp-proxy",
    }

}
