packages feed

hprox 0.1.0.2 → 0.1.1

raw patch · 4 files changed

+29/−63 lines, 4 filesdep +http-client-tls

Dependencies added: http-client-tls

Files

README.md view
@@ -12,7 +12,7 @@  * Basic HTTP proxy functionality. * Simple password authentication.-* TLS encryption (requires a valid certificate). Supports TLS 1.3 and HTTP 2, also known as SPDY Proxy.+* TLS encryption (requires a valid certificate). Supports TLS 1.3 and HTTP/2, also known as SPDY Proxy. * TLS SNI validation (blocks all clients with invalid domain name). * Provide PAC file for easy client side configuration (supports Chrome and Firefox). * Websocket redirection (compatible with [v2ray-plugin](https://github.com/shadowsocks/v2ray-plugin)).@@ -32,6 +32,8 @@ stack install ``` +Alternatively, you also can use the statically linked binary for the [latest release](https://github.com/bjin/hprox/releases).+ ### Usage  Use `hprox --help` to list options with detailed explanation.@@ -62,7 +64,6 @@  ### Known Issue -* Only HTTP servers are supported as websocket and reverse proxy redirection destination. * Passwords are currently stored in plain text, please set permission accordingly and   avoid using existing password. 
hprox.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.1.+-- This file has been generated from package.yaml by hpack version 0.31.2. -- -- see: https://github.com/sol/hpack ----- hash: 7456eded738e088a6f5195326db8a89c8149a54e92f46ed9962c9be01f73d762+-- hash: 7b3965e17f09091c9d4a3bdedd075b5d746f3d7c24fc907dde01a2de3168dc85  name:           hprox-version:        0.1.0.2+version:        0.1.1 synopsis:       a lightweight HTTP proxy server, and more description:    Please see the README on GitHub at <https://github.com/bjin/hprox#readme> category:       Web@@ -35,6 +35,7 @@   main-is: Main.hs   other-modules:       HProx+      Paths_hprox   hs-source-dirs:       src   ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N@@ -48,6 +49,7 @@     , conduit >=1.3     , conduit-extra >=1.3     , http-client >=0.5+    , http-client-tls >=0.3.4     , http-reverse-proxy >=0.4.0     , http-types >=0.12     , optparse-applicative >=0.14
src/HProx.hs view
@@ -93,54 +93,10 @@     fromMaybe (hostPort, defaultPort) $ parseHostPort hostPort  isProxyHeader :: HT.HeaderName -> Bool-isProxyHeader k-    | BS.length bs <= 4     = False-    | c0 /= 112 && c0 /= 80 = False -- 'p'-    | c1 /= 114 && c1 /= 82 = False -- 'r'-    | c2 /= 111 && c2 /= 79 = False -- 'o'-    | c3 /= 120 && c3 /= 88 = False -- 'x'-    | c4 /= 121 && c4 /= 89 = False -- 'y'-    | otherwise             = True-  where-    bs = CI.original k-    idx = BS.index bs--    c0 = idx 0-    c1 = idx 1-    c2 = idx 2-    c3 = idx 3-    c4 = idx 4+isProxyHeader k = "proxy" `BS.isPrefixOf` CI.foldedCase k  isForwardedHeader :: HT.HeaderName -> Bool-isForwardedHeader k-    | BS.length bs <= 10    = False-    | c0 /= 120 && c0 /= 88 = False -- 'x'-    | c1 /= 45              = False -- '-'-    | c2 /= 102 && c2 /= 70 = False -- 'f'-    | c3 /= 111 && c3 /= 79 = False -- 'o'-    | c4 /= 114 && c4 /= 82 = False -- 'r'-    | c5 /= 119 && c5 /= 87 = False -- 'w'-    | c6 /= 97  && c6 /= 65 = False -- 'a'-    | c7 /= 114 && c7 /= 82 = False -- 'r'-    | c8 /= 100 && c8 /= 68 = False -- 'd'-    | c9 /= 101 && c9 /= 69 = False -- 'e'-    | ca /= 100 && ca /= 68 = False -- 'd'-    | otherwise             = True-  where-    bs = CI.original k-    idx = BS.index bs--    c0 = idx 0-    c1 = idx 1-    c2 = idx 2-    c3 = idx 3-    c4 = idx 4-    c5 = idx 5-    c6 = idx 6-    c7 = idx 7-    c8 = idx 8-    c9 = idx 9-    ca = idx 10+isForwardedHeader k = "x-forwarded" `BS.isPrefixOf` CI.foldedCase k  isToStripHeader :: HT.HeaderName -> Bool isToStripHeader h = isProxyHeader h || isForwardedHeader h || h == "X-Real-IP" || h == "X-Scheme"@@ -193,8 +149,9 @@      isReverseProxy = isJust (revRemote pset)     (revHost, revPort) = parseHostPortWithDefault 80 (fromJust (revRemote pset))+    revWrapper = if revPort == 443 then WPRModifiedRequestSecure else WPRModifiedRequest -    proxyResponseFor req = WPRModifiedRequest nreq (ProxyDest revHost revPort)+    proxyResponseFor req = revWrapper nreq (ProxyDest revHost revPort)       where         nreq = req           { requestHeaders = hdrs@@ -212,7 +169,7 @@     settings = defaultWaiProxySettings { wpsSetIpHeader = SIHNone }      proxyResponseFor req-        | redirectWebsocket  = WPRProxyDest (ProxyDest wsHost wsPort)+        | redirectWebsocket  = wsWrapper (ProxyDest wsHost wsPort)         | not isGetProxy     = WPRApplication fallback         | checkAuth pset req = WPRModifiedRequest nreq (ProxyDest host port)         | otherwise          = WPRResponse (proxyAuthRequiredResponse pset)@@ -220,6 +177,7 @@         isWebsocket = wpsUpgradeToRaw defaultWaiProxySettings req         redirectWebsocket = isWebsocket && isJust (wsRemote pset)         (wsHost, wsPort) = parseHostPortWithDefault 80 (fromJust (wsRemote pset))+        wsWrapper = if wsPort == 443 then WPRProxyDestSecure else WPRProxyDest          notCONNECT = requestMethod req /= "CONNECT"         rawPath = rawPathInfo req
src/Main.hs view
@@ -7,7 +7,7 @@  import qualified Data.ByteString.Char8       as BS8 import           Data.String                 (fromString)-import qualified Network.HTTP.Client         as HC+import           Network.HTTP.Client.TLS     (newTlsManager) import           Network.TLS                 as TLS import           Network.Wai.Handler.Warp    (HostPreference, defaultSettings,                                               runSettings, setBeforeMainLoop,@@ -22,10 +22,12 @@  import           Data.Maybe import           Data.Monoid                 ((<>))+import           Data.Version                (showVersion) import           Options.Applicative  import           HProx                       (ProxySettings (..), dumbApp,                                               forceSSL, httpProxy, reverseProxy)+import           Paths_hprox                 (version)  data Opts = Opts   { _bind :: Maybe HostPreference@@ -52,12 +54,15 @@   | otherwise = let y:ys = splitBy c xs in (x:y):ys  parser :: ParserInfo Opts-parser = info (helper <*> opts) fullDesc+parser = info (helper <*> ver <*> opts) (fullDesc <> progDesc desc)   where     parseSSL s = case splitBy ':' s of         [host, cert, key] -> Right (host, CertFile cert key)         _                 -> Left "invalid format for ssl certificates" +    desc = "a lightweight HTTP proxy server, and more"+    ver = infoOption (showVersion version) (long "version" <> help "show version")+     opts = Opts <$> bind                 <*> (fromMaybe 3000 <$> port)                 <*> ssl@@ -70,7 +75,7 @@         ( long "bind"        <> short 'b'        <> metavar "bind_ip"-       <> help "the ip address to bind on (default: all interfaces)")+       <> help "ip address to bind on (default: all interfaces)")      port = optional $ option auto         ( long "port"@@ -82,7 +87,7 @@         ( long "tls"        <> short 's'        <> metavar "hostname:cerfile:keyfile"-       <> help "enable TLS and specify a domain and associated TLS certificate (can be used multiple times for multiple domains)")+       <> help "enable TLS and specify a domain and associated TLS certificate (can be specified multiple times for multiple domains)")      user = optional $ strOption         ( long "user"@@ -94,17 +99,17 @@         ( long "auth"        <> short 'a'        <> metavar "userpass.txt"-       <> help "password file for proxy authentication (plain text file with lines each containaing a colon separated user/password pair)")+       <> help "password file for proxy authentication (plain text file with lines each containing a colon separated user/password pair)")      ws = optional $ strOption         ( long "ws"-       <> metavar "remote-host:80"-       <> help "remote host to handle websocket requests (http server only)")+       <> metavar "remote-host:port"+       <> help "remote host to handle websocket requests (port 443 indicates HTTPS remote server)")      rev = optional $ strOption         ( long "rev"-       <> metavar "remote-host:80"-       <> help "remote host for revere proxy (http server only)")+       <> metavar "remote-host:port"+       <> help "remote host for reverse proxy (port 443 indicates HTTPS remote server)")   setuid :: String -> IO ()@@ -144,7 +149,7 @@     pauth <- case _auth opts of         Nothing -> return Nothing         Just f  -> Just . flip elem . filter (isJust . BS8.elemIndex ':') . BS8.lines <$> BS8.readFile f-    manager <- HC.newManager HC.defaultManagerSettings+    manager <- newTlsManager      let pset = ProxySettings pauth Nothing (BS8.pack <$> _ws opts) (BS8.pack <$> _rev opts)         proxy = (if isSSL then forceSSL else id) $ gzip def $ httpProxy pset manager $ reverseProxy pset manager dumbApp