    -- | 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 = [String] -> Property DebianLike
    Apt.installed [String
    "iptables"]

    rule :: Chain -> Table -> Target -> Rules -> Property Linux
    rule :: Chain -> Table -> Target -> Rules -> Property Linux
    rule Chain
    c Table
    tb Target
    tg Rules
    rs = String -> Propellor Result -> Property Linux
    forall {k} (metatypes :: k).
    SingI metatypes =>
    String -> Propellor Result -> Property (MetaTypes metatypes)
    property (String
    "firewall rule: " String -> String -> String
    forall a. Semigroup a => a -> a -> a
    <> Rule -> String
    forall a. Show a => a -> String
    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 a. IO a -> Propellor a
    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
    		exist <- String -> [CommandParam] -> IO Bool
    boolSystem String
    "iptables" ([CommandParam] -> [CommandParam]
    chk [CommandParam]
    args)
    		if exist
    			then return NoChange
    			else toResult <$> boolSystem "iptables" (add args)
    	add :: [CommandParam] -> [CommandParam]
    add [CommandParam]
    params = String -> CommandParam
    Param String
    "-A" CommandParam -> [CommandParam] -> [CommandParam]
    forall a. a -> [a] -> [a]
    : [CommandParam]
    params
    	chk :: [CommandParam] -> [CommandParam]
    chk [CommandParam]
    params = String -> CommandParam
    Param String
    "-C" CommandParam -> [CommandParam] -> [CommandParam]
    forall a. a -> [a] -> [a]
    : [CommandParam]
    params

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

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

    instance ConfigurableValue IPWithMask where
    	val :: IPWithMask -> String
    val (IPWithNoMask IPAddr
    ip) = IPAddr -> String
    forall t. ConfigurableValue t => t -> String
    val IPAddr
    ip
    	val (IPWithIPMask IPAddr
    ip IPAddr
    ipm) = IPAddr -> String
    forall t. ConfigurableValue t => t -> String
    val IPAddr
    ip String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "/" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ IPAddr -> String
    forall t. ConfigurableValue t => t -> String
    val IPAddr
    ipm
    	val (IPWithNumMask IPAddr
    ip Int
    m) = IPAddr -> String
    forall t. ConfigurableValue t => t -> String
    val IPAddr
    ip String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "/" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall t. ConfigurableValue t => t -> String
    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
    $c== :: Rule -> Rule -> Bool
    == :: Rule -> Rule -> Bool
    $c/= :: Rule -> Rule -> Bool
    /= :: Rule -> Rule -> Bool
    Eq, Int -> Rule -> String -> String
    [Rule] -> String -> String
    Rule -> String
    (Int -> Rule -> String -> String)
    -> (Rule -> String) -> ([Rule] -> String -> String) -> Show Rule
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Rule -> String -> String
    showsPrec :: Int -> Rule -> String -> String
    $cshow :: Rule -> String
    show :: Rule -> String
    $cshowList :: [Rule] -> String -> String
    showList :: [Rule] -> String -> String
    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
    $c== :: Table -> Table -> Bool
    == :: Table -> Table -> Bool
    $c/= :: Table -> Table -> Bool
    /= :: Table -> Table -> Bool
    Eq, Int -> Table -> String -> String
    [Table] -> String -> String
    Table -> String
    (Int -> Table -> String -> String)
    -> (Table -> String) -> ([Table] -> String -> String) -> Show Table
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Table -> String -> String
    showsPrec :: Int -> Table -> String -> String
    $cshow :: Table -> String
    show :: Table -> String
    $cshowList :: [Table] -> String -> String
    showList :: [Table] -> String -> String
    Show)

    instance ConfigurableValue Table where
    	val :: Table -> String
    val Table
    Filter = String
    "filter"
    	val Table
    Nat = String
    "nat"
    	val Table
    Mangle = String
    "mangle"
    	val Table
    Raw = String
    "raw"
    	val Table
    Security = String
    "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
    $c== :: Target -> Target -> Bool
    == :: Target -> Target -> Bool
    $c/= :: Target -> Target -> Bool
    /= :: Target -> Target -> Bool
    Eq, Int -> Target -> String -> String
    [Target] -> String -> String
    Target -> String
    (Int -> Target -> String -> String)
    -> (Target -> String)
    -> ([Target] -> String -> String)
    -> Show Target
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Target -> String -> String
    showsPrec :: Int -> Target -> String -> String
    $cshow :: Target -> String
    show :: Target -> String
    $cshowList :: [Target] -> String -> String
    showList :: [Target] -> String -> String
    Show)

    instance ConfigurableValue Target where
    	val :: Target -> String
    val Target
    ACCEPT = String
    "ACCEPT"
    	val Target
    REJECT = String
    "REJECT"
    	val Target
    DROP = String
    "DROP"
    	val Target
    LOG = String
    "LOG"
    	val (TargetCustom String
    t) = String
    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
    $c== :: Chain -> Chain -> Bool
    == :: Chain -> Chain -> Bool
    $c/= :: Chain -> Chain -> Bool
    /= :: Chain -> Chain -> Bool
    Eq, Int -> Chain -> String -> String
    [Chain] -> String -> String
    Chain -> String
    (Int -> Chain -> String -> String)
    -> (Chain -> String) -> ([Chain] -> String -> String) -> Show Chain
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Chain -> String -> String
    showsPrec :: Int -> Chain -> String -> String
    $cshow :: Chain -> String
    show :: Chain -> String
    $cshowList :: [Chain] -> String -> String
    showList :: [Chain] -> String -> String
    Show)

    instance ConfigurableValue Chain where
    	val :: Chain -> String
    val Chain
    INPUT = String
    "INPUT"
    	val Chain
    OUTPUT = String
    "OUTPUT"
    	val Chain
    FORWARD = String
    "FORWARD"
    	val Chain
    PREROUTING = String
    "PREROUTING"
    	val Chain
    POSTROUTING = String
    "POSTROUTING"
    	val (ChainCustom String
    c) = String
    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
    $c== :: Proto -> Proto -> Bool
    == :: Proto -> Proto -> Bool
    $c/= :: Proto -> Proto -> Bool
    /= :: Proto -> Proto -> Bool
    Eq, Int -> Proto -> String -> String
    [Proto] -> String -> String
    Proto -> String
    (Int -> Proto -> String -> String)
    -> (Proto -> String) -> ([Proto] -> String -> String) -> Show Proto
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Proto -> String -> String
    showsPrec :: Int -> Proto -> String -> String
    $cshow :: Proto -> String
    show :: Proto -> String
    $cshowList :: [Proto] -> String -> String
    showList :: [Proto] -> String -> String
    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
    $c== :: ConnectionState -> ConnectionState -> Bool
    == :: ConnectionState -> ConnectionState -> Bool
    $c/= :: ConnectionState -> ConnectionState -> Bool
    /= :: ConnectionState -> ConnectionState -> Bool
    Eq, Int -> ConnectionState -> String -> String
    [ConnectionState] -> String -> String
    ConnectionState -> String
    (Int -> ConnectionState -> String -> String)
    -> (ConnectionState -> String)
    -> ([ConnectionState] -> String -> String)
    -> Show ConnectionState
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> ConnectionState -> String -> String
    showsPrec :: Int -> ConnectionState -> String -> String
    $cshow :: ConnectionState -> String
    show :: ConnectionState -> String
    $cshowList :: [ConnectionState] -> String -> String
    showList :: [ConnectionState] -> String -> String
    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
    $c== :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    == :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    $c/= :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    /= :: ICMPTypeMatch -> ICMPTypeMatch -> Bool
    Eq, Int -> ICMPTypeMatch -> String -> String
    [ICMPTypeMatch] -> String -> String
    ICMPTypeMatch -> String
    (Int -> ICMPTypeMatch -> String -> String)
    -> (ICMPTypeMatch -> String)
    -> ([ICMPTypeMatch] -> String -> String)
    -> Show ICMPTypeMatch
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> ICMPTypeMatch -> String -> String
    showsPrec :: Int -> ICMPTypeMatch -> String -> String
    $cshow :: ICMPTypeMatch -> String
    show :: ICMPTypeMatch -> String
    $cshowList :: [ICMPTypeMatch] -> String -> String
    showList :: [ICMPTypeMatch] -> String -> String
    Show)

    instance ConfigurableValue ICMPTypeMatch where
    	val :: ICMPTypeMatch -> String
    val (ICMPTypeName String
    t) = String
    t
    	val (ICMPTypeCode Int
    c) = Int -> String
    forall t. ConfigurableValue t => t -> String
    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
    $c== :: Frequency -> Frequency -> Bool
    == :: Frequency -> Frequency -> Bool
    $c/= :: Frequency -> Frequency -> Bool
    /= :: Frequency -> Frequency -> Bool
    Eq, Int -> Frequency -> String -> String
    [Frequency] -> String -> String
    Frequency -> String
    (Int -> Frequency -> String -> String)
    -> (Frequency -> String)
    -> ([Frequency] -> String -> String)
    -> Show Frequency
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Frequency -> String -> String
    showsPrec :: Int -> Frequency -> String -> String
    $cshow :: Frequency -> String
    show :: Frequency -> String
    $cshowList :: [Frequency] -> String -> String
    showList :: [Frequency] -> String -> String
    Show)

    instance ConfigurableValue Frequency where
    	val :: Frequency -> String
    val (NumBySecond Int
    n) = Int -> String
    forall t. ConfigurableValue t => t -> String
    val Int
    n String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "/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
    $c== :: TCPFlag -> TCPFlag -> Bool
    == :: TCPFlag -> TCPFlag -> Bool
    $c/= :: TCPFlag -> TCPFlag -> Bool
    /= :: TCPFlag -> TCPFlag -> Bool
    Eq, Int -> TCPFlag -> String -> String
    TCPFlagMask -> String -> String
    TCPFlag -> String
    (Int -> TCPFlag -> String -> String)
    -> (TCPFlag -> String)
    -> (TCPFlagMask -> String -> String)
    -> Show TCPFlag
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> TCPFlag -> String -> String
    showsPrec :: Int -> TCPFlag -> String -> String
    $cshow :: TCPFlag -> String
    show :: TCPFlag -> String
    $cshowList :: TCPFlagMask -> String -> String
    showList :: TCPFlagMask -> String -> String
    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
    $c== :: Rules -> Rules -> Bool
    == :: Rules -> Rules -> Bool
    $c/= :: Rules -> Rules -> Bool
    /= :: Rules -> Rules -> Bool
    Eq, Int -> Rules -> String -> String
    [Rules] -> String -> String
    Rules -> String
    (Int -> Rules -> String -> String)
    -> (Rules -> String) -> ([Rules] -> String -> String) -> Show Rules
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Rules -> String -> String
    showsPrec :: Int -> Rules -> String -> String
    $cshow :: Rules -> String
    show :: Rules -> String
    $cshowList :: [Rules] -> String -> String
    showList :: [Rules] -> String -> String
    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.<>)