vpn-router-0.0.1: src/VpnRouter/CmdArgs.hs
module VpnRouter.CmdArgs where
import Options.Applicative
import System.IO.Unsafe ( unsafePerformIO )
import VpnRouter.Net.IpTool
( mainRoutingTableName, listDefaultsOfRoutingTable )
import VpnRouter.Net.Types
( RoutingTableId(RoutingTableId),
PacketMark(..),
HostIp,
Gateway,
IspNic,
parseIpV4 )
import VpnRouter.Prelude
( ($),
Eq,
untag,
Monad((>>=)),
Show,
Semigroup((<>)),
Int,
Tagged(Tagged),
(=<<),
fst,
snd,
putStrLn,
show,
MonadIO(..),
Text )
data HttpPort
data CmdArgs
= RunService
{ ispNic :: Tagged IspNic Text
, gatewayHost :: Tagged Gateway HostIp
, routingTableId :: RoutingTableId
, packetMark :: PacketMark
, httpPortToListen :: Tagged HttpPort Int
}
| VpnRouterVersion
deriving (Eq, Show)
execWithArgs :: MonadIO m => (CmdArgs -> m a) -> m a
execWithArgs a = a =<< liftIO (execParser $ info (cmdp <**> helper) phelp)
where
routingTableOp = RoutingTableId <$>
option auto
( long "routing-table"
<> short 't'
<> value 7
<> showDefault
<> help "routing table id"
)
packetMarkOp = PacketMark <$>
option auto
( long "packet-mark"
<> short 'm'
<> value 2
<> showDefault
<> help "packet mark"
)
serviceP =
RunService
<$> (Tagged @IspNic <$> ispNicOp)
<*> (Tagged @Gateway <$> gatewayHostOp)
<*> routingTableOp
<*> packetMarkOp
<*> portOption
cmdp =
hsubparser
( command "run" (infoP serviceP $ "launch the service exposed over HTTP")
<> command "version" (infoP (pure VpnRouterVersion) "print program version"))
infoP p h = info p (progDesc h <> fullDesc)
phelp =
progDesc
"HTML interface for VPN bypass"
ispNicOp :: Parser Text
ispNicOp =
strOption (long "dev" <> short 'd' <>
value (untag $ snd defaultGwNic) <>
showDefault <>
help "network device name connected to the Internet")
-- default via 192.168.1.1 dev wlp2s0 proto dhcp src 192.168.1.103 metric 600
defaultGwNic :: (Tagged Gateway HostIp, Tagged IspNic Text)
defaultGwNic = unsafePerformIO go
where
defDef = ("192.168.1.1", "wlp2s0")
go = do
listDefaultsOfRoutingTable mainRoutingTableName >>= \case
[(gw, nic)] ->
pure (gw, nic)
[] -> do
putStrLn $ "No default route in the main routing table"
pure defDef
o -> do
putStrLn $ "Multiple default routes in the main routing table: " <> show o
pure defDef
portOption :: Parser (Tagged HttpPort Int)
portOption = Tagged <$>
option auto
( long "port"
<> short 'p'
<> showDefault
<> value 3000
<> help "HTTP port to listen"
<> metavar "PORT"
)
gatewayHostOp :: Parser HostIp
gatewayHostOp =
option (maybeReader parseIpV4)
( long "gateway"
<> short 'g'
<> value (untag $ fst defaultGwNic)
<> showDefault
<> help "network device name connected to the Internet"
)