    -- | Maintainer: Arnaud Bailly <arnaud.oqube@gmail.com>
    --
    -- Properties for configuring firewall (iptables) rules

    module Propellor.Property.Firewall (
    	rule,
    	installed,
    	Chain(..),
    	Table(..),
    	Target(..),
    	Proto(..),
    	Rules(..),
    	ConnectionState(..),
    	ICMPTypeMatch(..),
    	TCPFlag(..),
    	Frequency(..),
    	IPWithMask(..),
    ) where

    import qualified Data.Semigroup as Sem
    import Data.Char
    import Data.List

    import Propellor.Base
    import qualified Propellor.Property.Apt as Apt
    import qualified Propellor.Property.Network as Network

    installed :: Property DebianLike
    installed :: Property DebianLike
    installed = [Package] -> Property DebianLike
    Apt.installed ["iptables"]

    rule :: Chain -> Table -> Target -> Rules -> Property Linux
    rule :: Chain -> Table -> Target -> Rules -> Property Linux
    rule c :: Chain
    c tb :: Table
    tb tg :: Target
    tg rs :: Rules
    rs = Package -> Propellor Result -> Property Linux
    forall k (metatypes :: k).
    SingI metatypes =>
    Package -> Propellor Result -> Property (MetaTypes metatypes)
    property ("firewall rule: " Package -> Package -> Package
    forall a. Semigroup a => a -> a -> a
    <> Rule -> Package
    forall a. Show a => a -> Package
    show Rule
    r) Propellor Result
    addIpTable
      where
    	r :: Rule
    r = Chain -> Table -> Target -> Rules -> Rule
    Rule Chain
    c Table
    tb Target
    tg Rules
    rs
    	addIpTable :: Propellor Result
    addIpTable = IO Result -> Propellor Result
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Result -> Propellor Result) -> IO Result -> Propellor Result
    forall a b. (a -> b) -> a -> b
    $ do
    		let args :: [CommandParam]
    args = Rule -> [CommandParam]
    toIpTable Rule
    r
    		Bool
    exist <- Package -> [CommandParam] -> IO Bool
    boolSystem "iptables" ([CommandParam] -> [CommandParam]
    chk [CommandParam]
    args)
    		if Bool
    exist
    			then Result -> IO Result
    forall (m :: * -> *) a. Monad m => a -> m a
    return Result
    NoChange
    			else Bool -> Result
    forall t. ToResult t => t -> Result
    toResult (Bool -> Result) -> IO Bool -> IO Result
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Package -> [CommandParam] -> IO Bool
    boolSystem "iptables" ([CommandParam] -> [CommandParam]
    add [CommandParam]
    args)
    	add :: [CommandParam] -> [CommandParam]
    add params :: [CommandParam]
    params = Package -> CommandParam
    Param "-A" CommandParam -> [CommandParam] -> [CommandParam]
    forall a. a -> [a] -> [a]
    : [CommandParam]
    params
    	chk :: [CommandParam] -> [CommandParam]
    chk params :: [CommandParam]
    params = Package -> CommandParam
    Param "-C" CommandParam -> [CommandParam] -> [CommandParam]
    forall a. a -> [a] -> [a]
    : [CommandParam]
    params

    toIpTable :: Rule -> [CommandParam]
    toIpTable :: Rule -> [CommandParam]
    toIpTable r :: Rule
    r =  (Package -> CommandParam) -> [Package] -> [CommandParam]
    forall a b. (a -> b) -> [a] -> [b]
    map Package -> CommandParam
    Param ([Package] -> [CommandParam]) -> [Package] -> [CommandParam]
    forall a b. (a -> b) -> a -> b
    $
    	Chain -> Package
    forall t. ConfigurableValue t => t -> Package
    val (Rule -> Chain
    ruleChain Rule
    r) Package -> [Package] -> [Package]
    forall a. a -> [a] -> [a]
    :
    	["-t", Table -> Package
    forall t. ConfigurableValue t => t -> Package
    val (Rule -> Table
    ruleTable Rule
    r), "-j", Target -> Package
    forall t. ConfigurableValue t => t -> Package
    val (Rule -> Target
    ruleTarget Rule
    r)] [Package] -> [Package] -> [Package]
    forall a. [a] -> [a] -> [a]
    ++
    	Rules -> [Package]
    toIpTableArg (Rule -> Rules
    ruleRules Rule
    r)

    toIpTableArg :: Rules -> [String]
    toIpTableArg :: Rules -> [Package]
    toIpTableArg Everything = []
    toIpTableArg (Proto proto :: Proto
    proto) = ["-p", (Char -> Char) -> Package -> Package
    forall a b. (a -> b) -> [a] -> [b]
    map Char -> Char
    toLower (Package -> Package) -> Package -> Package
    forall a b. (a -> b) -> a -> b
    $ Proto -> Package
    forall a. Show a => a -> Package
    show Proto
    proto]
    toIpTableArg (DPort port :: Port
    port) = ["--dport", Port -> Package
    forall t. ConfigurableValue t => t -> Package
    val Port
    port]
    toIpTableArg (DPortRange (portf :: Port
    portf, portt :: Port
    portt)) =
    	["--dport", Port -> Package
    forall t. ConfigurableValue t => t -> Package
    val Port
    portf Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ ":" Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ Port -> Package
    forall t. ConfigurableValue t => t -> Package
    val Port
    portt]
    toIpTableArg (InIFace iface :: Package
    iface) = ["-i", Package
    iface]
    toIpTableArg (OutIFace iface :: Package
    iface) = ["-o", Package
    iface]
    toIpTableArg (Ctstate states :: [ConnectionState]
    states) =
    	[ "-m"
    	, "conntrack"
    	, "--ctstate", Package -> [Package] -> Package
    forall a. [a] -> [[a]] -> [a]
    intercalate "," ((ConnectionState -> Package) -> [ConnectionState] -> [Package]
    forall a b. (a -> b) -> [a] -> [b]
    map ConnectionState -> Package
    forall a. Show a => a -> Package
    show [ConnectionState]
    states)
    	]
    toIpTableArg (ICMPType i :: ICMPTypeMatch
    i) =
    	[ "-m"
    	, "icmp"
    	, "--icmp-type", ICMPTypeMatch -> Package
    forall t. ConfigurableValue t => t -> Package
    val ICMPTypeMatch
    i
    	]
    toIpTableArg (RateLimit f :: Frequency
    f) =
    	[ "-m"
    	, "limit"
    	, "--limit", Frequency -> Package
    forall t. ConfigurableValue t => t -> Package
    val Frequency
    f
    	]
    toIpTableArg (TCPFlags m :: TCPFlagMask
    m c :: TCPFlagMask
    c) =
    	[ "-m"
    	, "tcp"
    	, "--tcp-flags"
    	, Package -> [Package] -> Package
    forall a. [a] -> [[a]] -> [a]
    intercalate "," ((TCPFlag -> Package) -> TCPFlagMask -> [Package]
    forall a b. (a -> b) -> [a] -> [b]
    map TCPFlag -> Package
    forall a. Show a => a -> Package
    show TCPFlagMask
    m)
    	, Package -> [Package] -> Package
    forall a. [a] -> [[a]] -> [a]
    intercalate "," ((TCPFlag -> Package) -> TCPFlagMask -> [Package]
    forall a b. (a -> b) -> [a] -> [b]
    map TCPFlag -> Package
    forall a. Show a => a -> Package
    show TCPFlagMask
    c)
    	]
    toIpTableArg TCPSyn = ["--syn"]
    toIpTableArg (GroupOwner (Group g :: Package
    g)) =
    	[ "-m"
    	, "owner"
    	, "--gid-owner"
    	, Package
    g
    	]
    toIpTableArg (Source ipwm :: [IPWithMask]
    ipwm) =
    	[ "-s"
    	, Package -> [Package] -> Package
    forall a. [a] -> [[a]] -> [a]
    intercalate "," ((IPWithMask -> Package) -> [IPWithMask] -> [Package]
    forall a b. (a -> b) -> [a] -> [b]
    map IPWithMask -> Package
    forall t. ConfigurableValue t => t -> Package
    val [IPWithMask]
    ipwm)
    	]
    toIpTableArg (Destination ipwm :: [IPWithMask]
    ipwm) =
    	[ "-d"
    	, Package -> [Package] -> Package
    forall a. [a] -> [[a]] -> [a]
    intercalate "," ((IPWithMask -> Package) -> [IPWithMask] -> [Package]
    forall a b. (a -> b) -> [a] -> [b]
    map IPWithMask -> Package
    forall t. ConfigurableValue t => t -> Package
    val [IPWithMask]
    ipwm)
    	]
    toIpTableArg (NotDestination ipwm :: [IPWithMask]
    ipwm) =
    	[ "!"
    	, "-d"
    	, Package -> [Package] -> Package
    forall a. [a] -> [[a]] -> [a]
    intercalate "," ((IPWithMask -> Package) -> [IPWithMask] -> [Package]
    forall a b. (a -> b) -> [a] -> [b]
    map IPWithMask -> Package
    forall t. ConfigurableValue t => t -> Package
    val [IPWithMask]
    ipwm)
    	]
    toIpTableArg (NatDestination ip :: IPAddr
    ip mport :: Maybe Port
    mport) =
    	[ "--to-destination"
    	, IPAddr -> Package
    forall t. ConfigurableValue t => t -> Package
    val IPAddr
    ip Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ Package -> (Port -> Package) -> Maybe Port -> Package
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe "" (\p :: Port
    p -> ":" Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ Port -> Package
    forall t. ConfigurableValue t => t -> Package
    val Port
    p) Maybe Port
    mport
    	]
    toIpTableArg (r :: Rules
    r :- r' :: Rules
    r') = Rules -> [Package]
    toIpTableArg Rules
    r [Package] -> [Package] -> [Package]
    forall a. Semigroup a => a -> a -> a
    <> Rules -> [Package]
    toIpTableArg Rules
    r'

    data IPWithMask = IPWithNoMask IPAddr | IPWithIPMask IPAddr IPAddr | IPWithNumMask IPAddr Int
    	deriving (IPWithMask -> IPWithMask -> Bool
    (IPWithMask -> IPWithMask -> Bool)
    -> (IPWithMask -> IPWithMask -> Bool) -> Eq IPWithMask
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: IPWithMask -> IPWithMask -> Bool
    $c/= :: IPWithMask -> IPWithMask -> Bool
    == :: IPWithMask -> IPWithMask -> Bool
    $c== :: IPWithMask -> IPWithMask -> Bool
    Eq, Int -> IPWithMask -> Package -> Package
    [IPWithMask] -> Package -> Package
    IPWithMask -> Package
    (Int -> IPWithMask -> Package -> Package)
    -> (IPWithMask -> Package)
    -> ([IPWithMask] -> Package -> Package)
    -> Show IPWithMask
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [IPWithMask] -> Package -> Package
    $cshowList :: [IPWithMask] -> Package -> Package
    show :: IPWithMask -> Package
    $cshow :: IPWithMask -> Package
    showsPrec :: Int -> IPWithMask -> Package -> Package
    $cshowsPrec :: Int -> IPWithMask -> Package -> Package
    Show)

    instance ConfigurableValue IPWithMask where
    	val :: IPWithMask -> Package
    val (IPWithNoMask ip :: IPAddr
    ip) = IPAddr -> Package
    forall t. ConfigurableValue t => t -> Package
    val IPAddr
    ip
    	val (IPWithIPMask ip :: IPAddr
    ip ipm :: IPAddr
    ipm) = IPAddr -> Package
    forall t. ConfigurableValue t => t -> Package
    val IPAddr
    ip Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ "/" Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ IPAddr -> Package
    forall t. ConfigurableValue t => t -> Package
    val IPAddr
    ipm
    	val (IPWithNumMask ip :: IPAddr
    ip m :: Int
    m) = IPAddr -> Package
    forall t. ConfigurableValue t => t -> Package
    val IPAddr
    ip Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ "/" Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ Int -> Package
    forall t. ConfigurableValue t => t -> Package
    val Int
    m

    data Rule = Rule
    	{ Rule -> Chain
    ruleChain  :: Chain
    	, Rule -> Table
    ruleTable  :: Table
    	, Rule -> Target
    ruleTarget :: Target
    	, Rule -> Rules
    ruleRules  :: Rules
    	} deriving (Rule -> Rule -> Bool
    (Rule -> Rule -> Bool) -> (Rule -> Rule -> Bool) -> Eq Rule
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Rule -> Rule -> Bool
    $c/= :: Rule -> Rule -> Bool
    == :: Rule -> Rule -> Bool
    $c== :: Rule -> Rule -> Bool
    Eq, Int -> Rule -> Package -> Package
    [Rule] -> Package -> Package
    Rule -> Package
    (Int -> Rule -> Package -> Package)
    -> (Rule -> Package) -> ([Rule] -> Package -> Package) -> Show Rule
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [Rule] -> Package -> Package
    $cshowList :: [Rule] -> Package -> Package
    show :: Rule -> Package
    $cshow :: Rule -> Package
    showsPrec :: Int -> Rule -> Package -> Package
    $cshowsPrec :: Int -> Rule -> Package -> Package
    Show)

    data Table = Filter | Nat | Mangle | Raw | Security
    	deriving (Table -> Table -> Bool
    (Table -> Table -> Bool) -> (Table -> Table -> Bool) -> Eq Table
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Table -> Table -> Bool
    $c/= :: Table -> Table -> Bool
    == :: Table -> Table -> Bool
    $c== :: Table -> Table -> Bool
    Eq, Int -> Table -> Package -> Package
    [Table] -> Package -> Package
    Table -> Package
    (Int -> Table -> Package -> Package)
    -> (Table -> Package)
    -> ([Table] -> Package -> Package)
    -> Show Table
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [Table] -> Package -> Package
    $cshowList :: [Table] -> Package -> Package
    show :: Table -> Package
    $cshow :: Table -> Package
    showsPrec :: Int -> Table -> Package -> Package
    $cshowsPrec :: Int -> Table -> Package -> Package
    Show)

    instance ConfigurableValue Table where
    	val :: Table -> Package
    val Filter = "filter"
    	val Nat = "nat"
    	val Mangle = "mangle"
    	val Raw = "raw"
    	val Security = "security"

    data Target = ACCEPT | REJECT | DROP | LOG | TargetCustom String
    	deriving (Target -> Target -> Bool
    (Target -> Target -> Bool)
    -> (Target -> Target -> Bool) -> Eq Target
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Target -> Target -> Bool
    $c/= :: Target -> Target -> Bool
    == :: Target -> Target -> Bool
    $c== :: Target -> Target -> Bool
    Eq, Int -> Target -> Package -> Package
    [Target] -> Package -> Package
    Target -> Package
    (Int -> Target -> Package -> Package)
    -> (Target -> Package)
    -> ([Target] -> Package -> Package)
    -> Show Target
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [Target] -> Package -> Package
    $cshowList :: [Target] -> Package -> Package
    show :: Target -> Package
    $cshow :: Target -> Package
    showsPrec :: Int -> Target -> Package -> Package
    $cshowsPrec :: Int -> Target -> Package -> Package
    Show)

    instance ConfigurableValue Target where
    	val :: Target -> Package
    val ACCEPT = "ACCEPT"
    	val REJECT = "REJECT"
    	val DROP = "DROP"
    	val LOG = "LOG"
    	val (TargetCustom t :: Package
    t) = Package
    t

    data Chain = INPUT | OUTPUT | FORWARD | PREROUTING | POSTROUTING | ChainCustom String
    	deriving (Chain -> Chain -> Bool
    (Chain -> Chain -> Bool) -> (Chain -> Chain -> Bool) -> Eq Chain
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Chain -> Chain -> Bool
    $c/= :: Chain -> Chain -> Bool
    == :: Chain -> Chain -> Bool
    $c== :: Chain -> Chain -> Bool
    Eq, Int -> Chain -> Package -> Package
    [Chain] -> Package -> Package
    Chain -> Package
    (Int -> Chain -> Package -> Package)
    -> (Chain -> Package)
    -> ([Chain] -> Package -> Package)
    -> Show Chain
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [Chain] -> Package -> Package
    $cshowList :: [Chain] -> Package -> Package
    show :: Chain -> Package
    $cshow :: Chain -> Package
    showsPrec :: Int -> Chain -> Package -> Package
    $cshowsPrec :: Int -> Chain -> Package -> Package
    Show)

    instance ConfigurableValue Chain where
    	val :: Chain -> Package
    val INPUT = "INPUT"
    	val OUTPUT = "OUTPUT"
    	val FORWARD = "FORWARD"
    	val PREROUTING = "PREROUTING"
    	val POSTROUTING = "POSTROUTING"
    	val (ChainCustom c :: Package
    c) = Package
    c

    data Proto = TCP | UDP | ICMP
    	deriving (Proto -> Proto -> Bool
    (Proto -> Proto -> Bool) -> (Proto -> Proto -> Bool) -> Eq Proto
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Proto -> Proto -> Bool
    $c/= :: Proto -> Proto -> Bool
    == :: Proto -> Proto -> Bool
    $c== :: Proto -> Proto -> Bool
    Eq, Int -> Proto -> Package -> Package
    [Proto] -> Package -> Package
    Proto -> Package
    (Int -> Proto -> Package -> Package)
    -> (Proto -> Package)
    -> ([Proto] -> Package -> Package)
    -> Show Proto
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [Proto] -> Package -> Package
    $cshowList :: [Proto] -> Package -> Package
    show :: Proto -> Package
    $cshow :: Proto -> Package
    showsPrec :: Int -> Proto -> Package -> Package
    $cshowsPrec :: Int -> Proto -> Package -> Package
    Show)

    data ConnectionState = ESTABLISHED | RELATED | NEW | INVALID
    	deriving (ConnectionState -> ConnectionState -> Bool
    (ConnectionState -> ConnectionState -> Bool)
    -> (ConnectionState -> ConnectionState -> Bool)
    -> Eq ConnectionState
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: ConnectionState -> ConnectionState -> Bool
    $c/= :: ConnectionState -> ConnectionState -> Bool
    == :: ConnectionState -> ConnectionState -> Bool
    $c== :: ConnectionState -> ConnectionState -> Bool
    Eq, Int -> ConnectionState -> Package -> Package
    [ConnectionState] -> Package -> Package
    ConnectionState -> Package
    (Int -> ConnectionState -> Package -> Package)
    -> (ConnectionState -> Package)
    -> ([ConnectionState] -> Package -> Package)
    -> Show ConnectionState
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [ConnectionState] -> Package -> Package
    $cshowList :: [ConnectionState] -> Package -> Package
    show :: ConnectionState -> Package
    $cshow :: ConnectionState -> Package
    showsPrec :: Int -> ConnectionState -> Package -> Package
    $cshowsPrec :: Int -> ConnectionState -> Package -> Package
    Show)

    data ICMPTypeMatch = ICMPTypeName String | ICMPTypeCode Int
    	deriving (ICMPTypeMatch -> ICMPTypeMatch -> Bool
    (ICMPTypeMatch -> ICMPTypeMatch -> Bool)
    -> (ICMPTypeMatch -> ICMPTypeMatch -> Bool) -> Eq ICMPTypeMatch
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    $c/= :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    == :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    $c== :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    Eq, Int -> ICMPTypeMatch -> Package -> Package
    [ICMPTypeMatch] -> Package -> Package
    ICMPTypeMatch -> Package
    (Int -> ICMPTypeMatch -> Package -> Package)
    -> (ICMPTypeMatch -> Package)
    -> ([ICMPTypeMatch] -> Package -> Package)
    -> Show ICMPTypeMatch
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [ICMPTypeMatch] -> Package -> Package
    $cshowList :: [ICMPTypeMatch] -> Package -> Package
    show :: ICMPTypeMatch -> Package
    $cshow :: ICMPTypeMatch -> Package
    showsPrec :: Int -> ICMPTypeMatch -> Package -> Package
    $cshowsPrec :: Int -> ICMPTypeMatch -> Package -> Package
    Show)

    instance ConfigurableValue ICMPTypeMatch where
    	val :: ICMPTypeMatch -> Package
    val (ICMPTypeName t :: Package
    t) = Package
    t
    	val (ICMPTypeCode c :: Int
    c) = Int -> Package
    forall t. ConfigurableValue t => t -> Package
    val Int
    c

    data Frequency = NumBySecond Int
    	deriving (Frequency -> Frequency -> Bool
    (Frequency -> Frequency -> Bool)
    -> (Frequency -> Frequency -> Bool) -> Eq Frequency
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Frequency -> Frequency -> Bool
    $c/= :: Frequency -> Frequency -> Bool
    == :: Frequency -> Frequency -> Bool
    $c== :: Frequency -> Frequency -> Bool
    Eq, Int -> Frequency -> Package -> Package
    [Frequency] -> Package -> Package
    Frequency -> Package
    (Int -> Frequency -> Package -> Package)
    -> (Frequency -> Package)
    -> ([Frequency] -> Package -> Package)
    -> Show Frequency
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [Frequency] -> Package -> Package
    $cshowList :: [Frequency] -> Package -> Package
    show :: Frequency -> Package
    $cshow :: Frequency -> Package
    showsPrec :: Int -> Frequency -> Package -> Package
    $cshowsPrec :: Int -> Frequency -> Package -> Package
    Show)

    instance ConfigurableValue Frequency where
    	val :: Frequency -> Package
    val (NumBySecond n :: Int
    n) = Int -> Package
    forall t. ConfigurableValue t => t -> Package
    val Int
    n Package -> Package -> Package
    forall a. [a] -> [a] -> [a]
    ++ "/second"

    type TCPFlagMask = [TCPFlag]

    type TCPFlagComp = [TCPFlag]

    data TCPFlag = SYN | ACK | FIN | RST | URG | PSH | ALL | NONE
    	deriving (TCPFlag -> TCPFlag -> Bool
    (TCPFlag -> TCPFlag -> Bool)
    -> (TCPFlag -> TCPFlag -> Bool) -> Eq TCPFlag
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: TCPFlag -> TCPFlag -> Bool
    $c/= :: TCPFlag -> TCPFlag -> Bool
    == :: TCPFlag -> TCPFlag -> Bool
    $c== :: TCPFlag -> TCPFlag -> Bool
    Eq, Int -> TCPFlag -> Package -> Package
    TCPFlagMask -> Package -> Package
    TCPFlag -> Package
    (Int -> TCPFlag -> Package -> Package)
    -> (TCPFlag -> Package)
    -> (TCPFlagMask -> Package -> Package)
    -> Show TCPFlag
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: TCPFlagMask -> Package -> Package
    $cshowList :: TCPFlagMask -> Package -> Package
    show :: TCPFlag -> Package
    $cshow :: TCPFlag -> Package
    showsPrec :: Int -> TCPFlag -> Package -> Package
    $cshowsPrec :: Int -> TCPFlag -> Package -> Package
    Show)

    data Rules
    	= Everything
    	| Proto Proto
    	-- ^There is actually some order dependency between proto and port so this should be a specific
    	-- data type with proto + ports
    	| DPort Port
    	| DPortRange (Port, Port)
    	| InIFace Network.Interface
    	| OutIFace Network.Interface
    	| Ctstate [ ConnectionState ]
    	| ICMPType ICMPTypeMatch
    	| RateLimit Frequency
    	| TCPFlags TCPFlagMask TCPFlagComp
    	| TCPSyn
    	| GroupOwner Group
    	| Source [ IPWithMask ]
    	| Destination [ IPWithMask ]
    	| NotDestination [ IPWithMask ]
    	| NatDestination IPAddr (Maybe Port)
    	| Rules :- Rules   -- ^Combine two rules
    	deriving (Rules -> Rules -> Bool
    (Rules -> Rules -> Bool) -> (Rules -> Rules -> Bool) -> Eq Rules
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Rules -> Rules -> Bool
    $c/= :: Rules -> Rules -> Bool
    == :: Rules -> Rules -> Bool
    $c== :: Rules -> Rules -> Bool
    Eq, Int -> Rules -> Package -> Package
    [Rules] -> Package -> Package
    Rules -> Package
    (Int -> Rules -> Package -> Package)
    -> (Rules -> Package)
    -> ([Rules] -> Package -> Package)
    -> Show Rules
    forall a.
    (Int -> a -> Package -> Package)
    -> (a -> Package) -> ([a] -> Package -> Package) -> Show a
    showList :: [Rules] -> Package -> Package
    $cshowList :: [Rules] -> Package -> Package
    show :: Rules -> Package
    $cshow :: Rules -> Package
    showsPrec :: Int -> Rules -> Package -> Package
    $cshowsPrec :: Int -> Rules -> Package -> Package
    Show)

    infixl 0 :-

    instance Sem.Semigroup Rules where
    	<> :: Rules -> Rules -> Rules
    (<>) = Rules -> Rules -> Rules
    (:-)

    instance Monoid Rules where
    	mempty :: Rules
    mempty  = Rules
    Everything
    	mappend :: Rules -> Rules -> Rules
    mappend = Rules -> Rules -> Rules
    forall a. Semigroup a => a -> a -> a
    (Sem.<>)