{-# LANGUAGE DeriveDataTypeable #-}
{-|
Module      : Network.RADIUS.Types
Description : Provides types and definitions for RADIUS as per RFC 2865
Copyright   : (c) Erick Gonzalez, 2017
License     : BSD3
Maintainer  : erick@codemonkeylabs.de
Stability   : experimental
Portability : POSIX

This module compiles the RADIUS packet definitions and different attributes as specified in
RFC 2865. The naming conventions from the RFC have been preserved as much as possible, so
it should be straightforward to look up a particular element and understand what it means etc.

RADIUS extensions in RFC 2869 are also supported, as well as RFC 3162 for IPv6 related attributes

-}
module Network.RADIUS.Types where

import Data.ByteString.Lazy.Char8    (ByteString)
import Data.Data                     (Data)
import Data.Word                     (Word8, Word16, Word32, Word64)
import Data.IP                       (IPv4, IPv6)
import Data.Int                      (Int8)

data Header = Header { getPacketType          :: PacketType,
                       getPacketId            :: Word8,
                       getPacketLength        :: Word16,
                       getPacketAuthenticator :: ByteString }
              deriving (Show, Eq)

data Packet = Packet { getHeader           :: Header,
                       getPacketAttributes :: [PacketAttribute] }
              deriving (Show, Eq)

data PacketType = AccessRequest
                | AccessAccept
                | AccessReject
                | AccountingRequest
                | AccountingResponse
                | AccessChallenge
                | StatusServer
                | StatusClient
                  deriving (Show, Eq)


instance Enum PacketType where
    fromEnum AccessRequest      = 1
    fromEnum AccessAccept       = 2
    fromEnum AccessReject       = 3
    fromEnum AccountingRequest  = 4
    fromEnum AccountingResponse = 5
    fromEnum AccessChallenge    = 11
    fromEnum StatusServer       = 12
    fromEnum StatusClient       = 13
    toEnum 1  = AccessRequest
    toEnum 2  = AccessAccept
    toEnum 3  = AccessReject
    toEnum 4  = AccountingRequest
    toEnum 5  = AccountingResponse
    toEnum 11 = AccessChallenge
    toEnum 12 = StatusServer
    toEnum 13 = StatusClient
    toEnum x  = error $ "Invalid RADIUS packet type " ++ show x

data PacketAttribute =
    UserNameAttribute               { getUserNameAttribute               :: ByteString        }
  | UserPasswordAttribute           { getUserPasswordAttribute           :: ByteString        }
  | CHAPPassword                    { getCHAPIdentity                    :: Word8,
                                      getCHAPPasswordAttribute           :: ByteString        }
  | NASIPAddress                    { getNASIPAddress                    :: IPv4              }
  | NASIPv6Address                  { getNASIPv6Address                  :: IPv6              }
  | NASPortAttribute                { getNASPortAttribute                :: Word32            }
  | ServiceTypeAttribute            { getServiceTypeAttribute            :: ServiceType       }
  | FramedProtocolAttribute         { getFramedProtocolAttribute         :: FramedProtocol    }
  | FramedIPAddressAttribute        { getFramedIPAddressAttribute        :: IPv4              }
  | FramedIPNetmaskAttribute        { getFramedIPNetmaskAttribute        :: IPv4              }
  | FramedRoutingAttribute          { getFramedRoutingAttribute          :: FramedRouting     }
  | FramedInterfaceIdAttribute      { getFramedInterfaceIdAttribute      :: Word64            }
  | FramedIPv6Prefix                { getFramedIPv6PrefixLength          :: Int8,
                                      getFramedIPv6Prefix                :: IPv6              }
  | FramedIPv6Route                 { getFramedIPv6RouteAttribute        :: ByteString        }
  | FramedIPv6Pool                  { getFramedIPv6PoolAttribute         :: ByteString        }
  | FilterIdAttribute               { getFilterIdAttribute               :: ByteString        }
  | FramedMTUAttribute              { getFramedMTUAttribute              :: Word32            }
  | FramedCompressionAttribute      { getFramedCompressionAttribute      :: FramedCompression }
  | LoginIPHostAttribute            { getLoginIPHostAttribute            :: IPv4              }
  | LoginIPv6HostAttribute          { getLoginIPv6HostAttribute          :: IPv6              }
  | LoginServiceAttribute           { getLoginServiceAttribute           :: LoginService      }
  | LoginTCPPortAttribute           { getLoginTCPPortAttribute           :: Word32            }
  | ReplyMessageAttribute           { getReplyMessageAttribute           :: ByteString        }
  | CallbackNumberAttribute         { getCallbackNumberAttribute         :: ByteString        }
  | CallbackIdAttribute             { getCallbackIdAttribute             :: ByteString        }
  | FramedRouteAttribute            { getFramedRouteAttribute            :: ByteString        }
  | FramedIPXNetworkAttribute       { getFramedIPXNetworkAttribute       :: Word32            }
  | StateAttribute                  { getStateAttribute                  :: ByteString        }
  | ClassAttribute                  { getClassAttribute                  :: ByteString        }
  | VendorSpecificAttribute         { getVendorIdAttribute               :: Word32,
                                      getVendorSpecificAttribute         :: ByteString        }
  | SessionTimeoutAttribute         { getSessionTimeoutAttribute         :: Word32            }
  | IdleTimeoutAttribute            { getIdleTimeoutAttribute            :: Word32            }
  | TerminationActionAttribute      { getTerminationActionAttribute      :: TerminationAction }
  | CalledStationIdAttribute        { getCalledStationIdAttribute        :: ByteString        }
  | CallingStationIdAttribute       { getCallingStationIdAttribute       :: ByteString        }
  | NASIdentifierAttribute          { getNASIdentifierAttribute          :: ByteString        }
  | ProxyStateAttribute             { getProxyStateAttribute             :: ByteString        }
  | LoginLATServiceAttribute        { getLoginLATServiceAttribute        :: ByteString        }
  | LoginLATNodeAttribute           { getLoginLATNodeAttribute           :: ByteString        }
  | LoginLATGroupAttribute          { getLoginLATGroupAttribute          :: ByteString        }
  | FramedAppleTalkLinkAttribute    { getFramedAppleTalkLinkAttribute    :: Word32            }
  | FramedAppleTalkNetworkAttribute { getFramedAppleTalkNetworkAttribute :: Word32            }
  | FramedAppleTalkZoneAttribute    { getFramedAppleTalkZoneAttribute    :: ByteString        }
  | AcctStatusTypeAttribute         { getAcctStatusTypeAttribute         :: StatusType        }
  | AcctDelayTimeAttribute          { getAcctDelayTimeAttribute          :: Word32            }
  | AcctInputOctetsAttribute        { getAcctInputOctetsAttribute        :: Word32            }
  | AcctOutputOctetsAttribute       { getAcctOutputOctetsAttribute       :: Word32            }
  | AcctSessionIdAttribute          { getAcctSessionIdAttribute          :: ByteString        }
  | AcctAuthenticAttribute          { getAcctAuthenticAttribute          :: Authentic         }
  | AcctSessionTimeAttribute        { getAcctSessionTimeAttribute        :: Word32            }
  | AcctInputPacketsAttribute       { getAcctInputPacketsAttribute       :: Word32            }
  | AcctOutputPacketsAttribute      { getAcctOutputPacketsAttribute      :: Word32            }
  | AcctTerminateCauseAttribute     { getAcctTerminateCauseAttribute     :: TerminateCause    }
  | AcctMultiSessionIdAttribute     { getAcctMultiSessionIdAttribute     :: ByteString        }
  | AcctLinkCountAttribute          { getAcctLinkCountAttribute          :: Word32            }
  | CHAPChallengeAttribute          { getCHAPChallengeAttribute          :: ByteString        }
  | NASPortTypeAttribute            { getNASPortTypeAttribute            :: NASPortType       }
  | PortLimitAttribute              { getPortLimitAttribute              :: Word32            }
  | LoginLATPortAttribute           { getLoginLATPortAttribute           :: ByteString        }
  | AccountInputGigawordsAttribute  { getAccountInputGigawordsAttribute  :: Word32            }
  | AccountOutputGigawordsAttribute { getAccountOutputGigawordsAttribute :: Word32            }
  | EventTimeStampAttribute         { getEventTimeStampAttribute         :: Word32            }
  | ARAPPasswordAttribute           { getARAPPasswordAttribute           :: ByteString        }
  | ARAPFeaturesAttribute           { getARAPFeaturesAttribute           :: ByteString        }
  | ARAPZoneAccessAttribute         { getARAPZoneAccessAttribute         :: ARAPZoneAccess    }
  | ARAPSecurityAttribute           { getARAPSecurityAttribute           :: Word32            }
  | ARAPSecurityDataAttribute       { getARAPSecurityDataAttribute       :: ByteString        }
  | PasswordRetryAttribute          { getPasswordRetryAttribute          :: Word32            }
  | PromptAttribute                 { getPromptAttribute                 :: Word32            }
  | ConnectInfoAttribute            { getConnectInfoAttribute            :: ByteString        }
  | ConfigurationTokenAttribute     { getConfigurationTokenAttribute     :: ByteString        }
  | EAPMessageAttribute             { getEAPMessageAttribute             :: ByteString        }
  | MessageAuthenticatorAttribute   { getMessageAuthenticatorAttribute   :: ByteString        }
  | ARAPChallengeResponseAttribute  { getARAPChallengeResponseAttribute  :: ByteString        }
  | AcctInterimIntervalAttribute    { getAcctInterimIntervalAttribute    :: Word32            }
  | NASPortIdAttribute              { getNASPortIdAttribute              :: ByteString        }
  | FramedPoolAttribute             { getFramedPoolAttribute             :: ByteString        }
  deriving (Show, Eq, Data)


data ServiceType = LoginService
                 | FramedService
                 | CallbackLoginService
                 | CallbackFramedService
                 | OutboundService
                 | AdministrativeService
                 | NASPromptService
                 | AuthenticateOnlyService
                 | CallbackNASPrompt
                 | CallCheckService
                 | CallbackAdministrativeService
                   deriving (Show, Eq, Data)

instance Enum ServiceType where
    fromEnum LoginService                  = 1
    fromEnum FramedService                 = 2
    fromEnum CallbackLoginService          = 3
    fromEnum CallbackFramedService         = 4
    fromEnum OutboundService               = 5
    fromEnum AdministrativeService         = 6
    fromEnum NASPromptService              = 7
    fromEnum AuthenticateOnlyService       = 8
    fromEnum CallbackNASPrompt             = 9
    fromEnum CallCheckService              = 10
    fromEnum CallbackAdministrativeService = 11
    toEnum 1  = LoginService
    toEnum 2  = FramedService
    toEnum 3  = CallbackLoginService
    toEnum 4  = CallbackFramedService
    toEnum 5  = OutboundService
    toEnum 6  = AdministrativeService
    toEnum 7  = NASPromptService
    toEnum 8  = AuthenticateOnlyService
    toEnum 9  = CallbackNASPrompt
    toEnum 10 = CallCheckService
    toEnum 11 = CallbackAdministrativeService
    toEnum x  = error $ "Invalid RADIUS service type " ++ show x

data FramedProtocol = PPPFramedProtocol
                    | SLIPFramedProtocol
                    | ARAPFramedProtocol
                    | GandalfFramedProtocol
                    | XylogicsFramedProtocol
                    | X75FramedProtocol
                      deriving (Show, Eq, Data)

instance Enum FramedProtocol where
    fromEnum PPPFramedProtocol      = 1
    fromEnum SLIPFramedProtocol     = 2
    fromEnum ARAPFramedProtocol     = 3
    fromEnum GandalfFramedProtocol  = 4
    fromEnum XylogicsFramedProtocol = 5
    fromEnum X75FramedProtocol      = 6
    toEnum 1 = PPPFramedProtocol
    toEnum 2 = SLIPFramedProtocol
    toEnum 3 = ARAPFramedProtocol
    toEnum 4 = GandalfFramedProtocol
    toEnum 5 = XylogicsFramedProtocol
    toEnum 6 = X75FramedProtocol
    toEnum x = error $ "Invalid framed protocol " ++ show x

data FramedRouting = NoneFramedRouting
                   | SendFramedRouting
                   | ListenFramedRouting
                   | SendAndListenFramedRouting
                     deriving (Show, Eq, Enum, Data)

data FramedCompression = NoCompression
                       | VJTCPIPHeaderCompression
                       | IPXHeaderCompression
                       | StacLZSCompression
                         deriving (Show, Eq, Enum, Data)

data LoginService = TelnetService
                  | RloginService
                  | TCPClearService
                  | PortMasterService
                  | LATService
                  | X25PADService
                  | X25T3POSService
                  | UnusedService
                  | TCPClearQuietService
                    deriving (Show, Eq, Enum, Data)

data TerminationAction = DefaultTerminationAction | RADIUSRequestTerminationAction
                       deriving (Show, Eq, Enum, Data)

data StatusType = Start | Stop | InterimUpdate | AccountingOn | AccountingOff | Failed
  deriving (Show, Eq, Data)

instance Enum StatusType where
  fromEnum Start         = 1
  fromEnum Stop          = 2
  fromEnum InterimUpdate = 3
  fromEnum AccountingOn  = 7
  fromEnum AccountingOff = 8
  fromEnum Failed        = 15
  toEnum 1  = Start
  toEnum 2  = Stop
  toEnum 3  = InterimUpdate
  toEnum 7  = AccountingOn
  toEnum 8  = AccountingOff
  toEnum 15 = Failed
  toEnum x  = error $ "Invalid Acct-Status-Type attribute " ++ show x

data Authentic = Radius | Local | Remote
  deriving (Show, Eq, Data)

instance Enum Authentic where
  fromEnum Radius = 1
  fromEnum Local  = 2
  fromEnum Remote = 3
  toEnum 1 = Radius
  toEnum 2 = Local
  toEnum 3 = Remote
  toEnum x = error $ "Invalid Acc-Authentic attribute " ++ show x

data TerminateCause = UserRequest
                    | LostCarrier
                    | LostService
                    | IdleTimeout
                    | SessionTimeout
                    | AdminReset
                    | AdminReboot
                    | PortError
                    | NASError
                    | NASRequest
                    | NASReboot
                    | PortUnneeded
                    | PortPreempted
                    | PortSuspended
                    | ServiceUnavailable
                    | Callback
                    | UserError
                    | HostRequest
  deriving (Show, Eq, Data)

instance Enum TerminateCause where
  fromEnum UserRequest        = 1
  fromEnum LostCarrier        = 2
  fromEnum LostService        = 3
  fromEnum IdleTimeout        = 4
  fromEnum SessionTimeout     = 5
  fromEnum AdminReset         = 6
  fromEnum AdminReboot        = 7
  fromEnum PortError          = 8
  fromEnum NASError           = 9
  fromEnum NASRequest         = 10
  fromEnum NASReboot          = 11
  fromEnum PortUnneeded       = 12
  fromEnum PortPreempted      = 13
  fromEnum PortSuspended      = 14
  fromEnum ServiceUnavailable = 15
  fromEnum Callback           = 16
  fromEnum UserError          = 17
  fromEnum HostRequest        = 18
  toEnum 1  = UserRequest
  toEnum 2  = LostCarrier
  toEnum 3  = LostService
  toEnum 4  = IdleTimeout
  toEnum 5  = SessionTimeout
  toEnum 6  = AdminReset
  toEnum 7  = AdminReboot
  toEnum 8  = PortError
  toEnum 9  = NASError
  toEnum 10 = NASRequest
  toEnum 11 = NASReboot
  toEnum 12 = PortUnneeded
  toEnum 13 = PortPreempted
  toEnum 14 = PortSuspended
  toEnum 15 = ServiceUnavailable
  toEnum 16 = Callback
  toEnum 17 = UserError
  toEnum 18 = HostRequest
  toEnum x  = error $ "Invalid Acct-Terminate-Cause attribute " ++ show x

data NASPortType = AsyncNASPort
                 | SyncNASPort
                 | ISDNSyncPort
                 | ISDNAsyncV120Port
                 | ISDNAsyncV110Port
                 | VirtualNASPort
                 | PIAFSNASPort
                 | HDLCClearChannelNASPort
                 | X25NASPort
                 | X75NASPort
                 | G3FaxNASPort
                 | SDSLNASPort
                 | ADSLCAPNASPort
                 | ADSLDMTNASPort
                 | IDSLNASPort
                 | EthernetNASPort
                 | XDSLNASPort
                 | CableNASPort
                 | WirelessOtherNASPort
                 | WirelessIEEE80211NASPort
                   deriving (Show, Eq, Enum, Data)

data ARAPZoneAccess = DefaultZoneOnlyARAPAccess
                    | UseZoneFilterInclusivelyARAPAccess
                    | UseZoneFilterExclusivelyARAPAccess
                    deriving (Show, Eq, Data)

instance Enum ARAPZoneAccess where
    toEnum 1 = DefaultZoneOnlyARAPAccess
    toEnum 2 = UseZoneFilterInclusivelyARAPAccess
    toEnum 4 = UseZoneFilterExclusivelyARAPAccess
    toEnum n = error $ "Invalid RADIUS ARAP Zone Access " ++ show n
    fromEnum DefaultZoneOnlyARAPAccess = 1
    fromEnum UseZoneFilterInclusivelyARAPAccess = 2
    fromEnum UseZoneFilterExclusivelyARAPAccess = 4