core: access messaging servers via SOCKS5 proxy (#835)

* core: access messaging servers via SOCKS5 proxy

* update option info

* update simplexmq
This commit is contained in:
Evgeny Poberezkin 2022-07-23 14:49:04 +01:00 committed by GitHub
parent 88d1d3448d
commit 4fd13c637c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 97 additions and 12 deletions

View file

@ -140,7 +140,7 @@ What is already implemented:
We plan to add soon: We plan to add soon:
1. Access to messaging servers via Tor. Currently clients access servers via public Internet, and the servers can observe IP addresses of the clients. Depending which platform you use, you might be able to configure access via Tor independently. The servers provided by SimpleX Chat do not correlate users by or log IP addresses, and you can use your own servers, but in some scenarios that may be not a sufficient level of privacy. 1. Access to messaging servers via Tor. Currently it is supported only for [terminal CLI clients](./docs/CLI.md); mobile clients access servers via public Internet, and the servers can observe IP addresses of the clients. Depending which platform you use, you might be able to configure access via Tor independently. The servers provided by SimpleX Chat do not correlate users by or log IP addresses, and you can use your own servers, but in some scenarios that may be not a sufficient level of privacy.
2. Message queue rotation. Currently the queues created between two users are used until the contact is deleted, providing a long-term pairwise identifiers of the conversation. We are planning to add queue rotation to make these identifiers termporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days). 2. Message queue rotation. Currently the queues created between two users are used until the contact is deleted, providing a long-term pairwise identifiers of the conversation. We are planning to add queue rotation to make these identifiers termporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days).
3. Local database encryption. Currently the local chat database stored on your device is not encrypted. 3. Local database encryption. Currently the local chat database stored on your device is not encrypted.
4. Independent implementation audit. 4. Independent implementation audit.

View file

@ -3,6 +3,7 @@
module Main where module Main where
import Control.Concurrent (threadDelay) import Control.Concurrent (threadDelay)
import Network.Socks5 (SocksConf (..))
import Server import Server
import Simplex.Chat.Controller (versionNumber) import Simplex.Chat.Controller (versionNumber)
import Simplex.Chat.Core import Simplex.Chat.Core
@ -30,7 +31,10 @@ main = do
threadDelay $ chatCmdDelay opts * 1000000 threadDelay $ chatCmdDelay opts * 1000000
welcome :: ChatOpts -> IO () welcome :: ChatOpts -> IO ()
welcome ChatOpts {dbFilePrefix} = do welcome ChatOpts {dbFilePrefix, socksProxy} = do
putStrLn $ "SimpleX Chat v" ++ versionNumber putStrLn $ "SimpleX Chat v" ++ versionNumber
putStrLn $ "db: " <> dbFilePrefix <> "_chat.db, " <> dbFilePrefix <> "_agent.db" putStrLn $ "db: " <> dbFilePrefix <> "_chat.db, " <> dbFilePrefix <> "_agent.db"
case socksProxy of
Just (SocksConf s _) -> putStrLn $ "using SOCKS5 proxy " <> show s
_ -> putStrLn "use -x CLI option to connect via SOCKS5 at :9050"
putStrLn "type \"/help\" or \"/h\" for usage info" putStrLn "type \"/help\" or \"/h\" for usage info"

View file

@ -5,7 +5,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package source-repository-package
type: git type: git
location: https://github.com/simplex-chat/simplexmq.git location: https://github.com/simplex-chat/simplexmq.git
tag: eb1f9370c1f254022019906fb6cf741d7687c525 tag: d788c3ca95f74d7ec2d737f3ef3ad8dc69d32abc
source-repository-package source-repository-package
type: git type: git

View file

@ -12,6 +12,7 @@
- [Using Haskell stack](#using-haskell-stack) - [Using Haskell stack](#using-haskell-stack)
- [Usage](#usage) - [Usage](#usage)
- [Running the chat client](#running-the-chat-client) - [Running the chat client](#running-the-chat-client)
- [Access messaging servers via Tor (BETA)](#access-messaging-servers-via-tor-beta)
- [How to use SimpleX chat](#how-to-use-simplex-chat) - [How to use SimpleX chat](#how-to-use-simplex-chat)
- [Groups](#groups) - [Groups](#groups)
- [Sending files](#sending-files) - [Sending files](#sending-files)
@ -139,6 +140,23 @@ You can still talk to people using default or any other server - it only affects
Run `simplex-chat -h` to see all available options. Run `simplex-chat -h` to see all available options.
### Access messaging servers via Tor (BETA)
Install Tor and run it as SOCKS5 proxy on port 9050, e.g. on Mac you can:
```
brew install tor
brew services start tor
```
Use `-x` option to access servers via Tor:
```
simplex-chat -x
```
You can also use option `--socks-proxy=ipv4:port` or `--socks-proxy=:port` to configure host and port of your SOCKS5 proxy, e.g. if you are running it on some other host or port.
### How to use SimpleX chat ### How to use SimpleX chat
Once you have started the chat, you will be prompted to specify your "display name" and an optional "full name" to create a local chat profile. Your display name is an alias for your contacts to refer to you by - it is not unique and does not serve as a global identity. If some of your contacts chose the same display name, the chat client adds a numeric suffix to their local display name. Once you have started the chat, you will be prompted to specify your "display name" and an optional "full name" to create a local chat profile. Your display name is an alias for your contacts to refer to you by - it is not unique and does not serve as a global identity. If some of your contacts chose the same display name, the chat client adds a numeric suffix to their local display name.

View file

@ -28,10 +28,12 @@ dependencies:
- filepath == 1.4.* - filepath == 1.4.*
- http-types == 0.12.* - http-types == 0.12.*
- mtl == 2.2.* - mtl == 2.2.*
- network >= 3.1.2.7 && < 3.2
- optparse-applicative >= 0.15 && < 0.17 - optparse-applicative >= 0.15 && < 0.17
- process == 1.6.* - process == 1.6.*
- simple-logger == 0.1.* - simple-logger == 0.1.*
- simplexmq >= 3.0 - simplexmq >= 3.0
- socks == 0.6.*
- sqlite-simple == 0.4.* - sqlite-simple == 0.4.*
- stm == 2.5.* - stm == 2.5.*
- terminal == 0.2.* - terminal == 0.2.*

View file

@ -1,5 +1,5 @@
{ {
"https://github.com/simplex-chat/simplexmq.git"."eb1f9370c1f254022019906fb6cf741d7687c525" = "0lwzs3gy2ajjf2iv53ajmm32zix3zi06njgjpr096fv6xhzypbdb"; "https://github.com/simplex-chat/simplexmq.git"."d788c3ca95f74d7ec2d737f3ef3ad8dc69d32abc" = "0sxaf8by830cc2pfkpn1bkfyr68b9iz901pihip12r9g6v3asssh";
"https://github.com/simplex-chat/aeson.git"."3eb66f9a68f103b5f1489382aad89f5712a64db7" = "0kilkx59fl6c3qy3kjczqvm8c3f4n3p0bdk9biyflf51ljnzp4yp"; "https://github.com/simplex-chat/aeson.git"."3eb66f9a68f103b5f1489382aad89f5712a64db7" = "0kilkx59fl6c3qy3kjczqvm8c3f4n3p0bdk9biyflf51ljnzp4yp";
"https://github.com/simplex-chat/haskell-terminal.git"."f708b00009b54890172068f168bf98508ffcd495" = "0zmq7lmfsk8m340g47g5963yba7i88n4afa6z93sg9px5jv1mijj"; "https://github.com/simplex-chat/haskell-terminal.git"."f708b00009b54890172068f168bf98508ffcd495" = "0zmq7lmfsk8m340g47g5963yba7i88n4afa6z93sg9px5jv1mijj";
"https://github.com/zw3rk/android-support.git"."3c3a5ab0b8b137a072c98d3d0937cbdc96918ddb" = "1r6jyxbim3dsvrmakqfyxbd6ms6miaghpbwyl0sr6dzwpgaprz97"; "https://github.com/zw3rk/android-support.git"."3c3a5ab0b8b137a072c98d3d0937cbdc96918ddb" = "1r6jyxbim3dsvrmakqfyxbd6ms6miaghpbwyl0sr6dzwpgaprz97";

View file

@ -76,10 +76,12 @@ library
, filepath ==1.4.* , filepath ==1.4.*
, http-types ==0.12.* , http-types ==0.12.*
, mtl ==2.2.* , mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, optparse-applicative >=0.15 && <0.17 , optparse-applicative >=0.15 && <0.17
, process ==1.6.* , process ==1.6.*
, simple-logger ==0.1.* , simple-logger ==0.1.*
, simplexmq >=3.0 , simplexmq >=3.0
, socks ==0.6.*
, sqlite-simple ==0.4.* , sqlite-simple ==0.4.*
, stm ==2.5.* , stm ==2.5.*
, terminal ==0.2.* , terminal ==0.2.*
@ -114,11 +116,13 @@ executable simplex-bot
, filepath ==1.4.* , filepath ==1.4.*
, http-types ==0.12.* , http-types ==0.12.*
, mtl ==2.2.* , mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, optparse-applicative >=0.15 && <0.17 , optparse-applicative >=0.15 && <0.17
, process ==1.6.* , process ==1.6.*
, simple-logger ==0.1.* , simple-logger ==0.1.*
, simplex-chat , simplex-chat
, simplexmq >=3.0 , simplexmq >=3.0
, socks ==0.6.*
, sqlite-simple ==0.4.* , sqlite-simple ==0.4.*
, stm ==2.5.* , stm ==2.5.*
, terminal ==0.2.* , terminal ==0.2.*
@ -153,11 +157,13 @@ executable simplex-bot-advanced
, filepath ==1.4.* , filepath ==1.4.*
, http-types ==0.12.* , http-types ==0.12.*
, mtl ==2.2.* , mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, optparse-applicative >=0.15 && <0.17 , optparse-applicative >=0.15 && <0.17
, process ==1.6.* , process ==1.6.*
, simple-logger ==0.1.* , simple-logger ==0.1.*
, simplex-chat , simplex-chat
, simplexmq >=3.0 , simplexmq >=3.0
, socks ==0.6.*
, sqlite-simple ==0.4.* , sqlite-simple ==0.4.*
, stm ==2.5.* , stm ==2.5.*
, terminal ==0.2.* , terminal ==0.2.*
@ -199,6 +205,7 @@ executable simplex-chat
, simple-logger ==0.1.* , simple-logger ==0.1.*
, simplex-chat , simplex-chat
, simplexmq >=3.0 , simplexmq >=3.0
, socks ==0.6.*
, sqlite-simple ==0.4.* , sqlite-simple ==0.4.*
, stm ==2.5.* , stm ==2.5.*
, terminal ==0.2.* , terminal ==0.2.*
@ -249,6 +256,7 @@ test-suite simplex-chat-test
, simple-logger ==0.1.* , simple-logger ==0.1.*
, simplex-chat , simplex-chat
, simplexmq >=3.0 , simplexmq >=3.0
, socks ==0.6.*
, sqlite-simple ==0.4.* , sqlite-simple ==0.4.*
, stm ==2.5.* , stm ==2.5.*
, terminal ==0.2.* , terminal ==0.2.*

View file

@ -87,7 +87,13 @@ defaultChatConfig =
yesToMigrations = False yesToMigrations = False
}, },
yesToMigrations = False, yesToMigrations = False,
defaultServers = InitialAgentServers {smp = _defaultSMPServers, ntf = _defaultNtfServers}, defaultServers =
InitialAgentServers
{ smp = _defaultSMPServers,
ntf = _defaultNtfServers,
socksProxy = Nothing,
tcpTimeout = 5000000
},
tbqSize = 64, tbqSize = 64,
fileChunkSize = 15780, fileChunkSize = 15780,
subscriptionConcurrency = 16, subscriptionConcurrency = 16,
@ -116,7 +122,7 @@ logCfg :: LogConfig
logCfg = LogConfig {lc_file = Nothing, lc_stderr = True} logCfg = LogConfig {lc_file = Nothing, lc_stderr = True}
newChatController :: SQLiteStore -> Maybe User -> ChatConfig -> ChatOpts -> Maybe (Notification -> IO ()) -> IO ChatController newChatController :: SQLiteStore -> Maybe User -> ChatConfig -> ChatOpts -> Maybe (Notification -> IO ()) -> IO ChatController
newChatController chatStore user cfg@ChatConfig {agentConfig = aCfg, tbqSize, defaultServers} ChatOpts {dbFilePrefix, smpServers, logConnections} sendToast = do newChatController chatStore user cfg@ChatConfig {agentConfig = aCfg, tbqSize, defaultServers} ChatOpts {dbFilePrefix, smpServers, socksProxy, tcpTimeout, logConnections} sendToast = do
let f = chatStoreFile dbFilePrefix let f = chatStoreFile dbFilePrefix
config = cfg {subscriptionEvents = logConnections} config = cfg {subscriptionEvents = logConnections}
sendNotification = fromMaybe (const $ pure ()) sendToast sendNotification = fromMaybe (const $ pure ()) sendToast
@ -124,7 +130,7 @@ newChatController chatStore user cfg@ChatConfig {agentConfig = aCfg, tbqSize, de
firstTime <- not <$> doesFileExist f firstTime <- not <$> doesFileExist f
currentUser <- newTVarIO user currentUser <- newTVarIO user
servers <- resolveServers defaultServers servers <- resolveServers defaultServers
smpAgent <- getSMPAgentClient aCfg {dbFile = dbFilePrefix <> "_agent.db"} servers smpAgent <- getSMPAgentClient aCfg {dbFile = dbFilePrefix <> "_agent.db"} servers {socksProxy, tcpTimeout}
agentAsync <- newTVarIO Nothing agentAsync <- newTVarIO Nothing
idsDrg <- newTVarIO =<< drgNew idsDrg <- newTVarIO =<< drgNew
inputQ <- newTBQueueIO tbqSize inputQ <- newTBQueueIO tbqSize

View file

@ -67,6 +67,8 @@ mobileChatOpts =
ChatOpts ChatOpts
{ dbFilePrefix = undefined, { dbFilePrefix = undefined,
smpServers = [], smpServers = [],
socksProxy = Nothing,
tcpTimeout = 5000000,
logConnections = False, logConnections = False,
logAgent = False, logAgent = False,
chatCmd = "", chatCmd = "",

View file

@ -1,6 +1,8 @@
{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Simplex.Chat.Options module Simplex.Chat.Options
( ChatOpts (..), ( ChatOpts (..),
@ -11,6 +13,9 @@ where
import qualified Data.Attoparsec.ByteString.Char8 as A import qualified Data.Attoparsec.ByteString.Char8 as A
import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Char8 as B
import Data.Maybe (fromMaybe)
import Network.Socket (HostAddress, SockAddr (..), tupleToHostAddress)
import Network.Socks5 (SocksConf, defaultSocksConf)
import Options.Applicative import Options.Applicative
import Simplex.Chat.Controller (updateStr, versionStr) import Simplex.Chat.Controller (updateStr, versionStr)
import Simplex.Messaging.Agent.Protocol (SMPServer) import Simplex.Messaging.Agent.Protocol (SMPServer)
@ -21,6 +26,8 @@ import System.FilePath (combine)
data ChatOpts = ChatOpts data ChatOpts = ChatOpts
{ dbFilePrefix :: String, { dbFilePrefix :: String,
smpServers :: [SMPServer], smpServers :: [SMPServer],
socksProxy :: Maybe SocksConf,
tcpTimeout :: Int,
logConnections :: Bool, logConnections :: Bool,
logAgent :: Bool, logAgent :: Bool,
chatCmd :: String, chatCmd :: String,
@ -46,10 +53,26 @@ chatOpts appDir defaultDbFileName = do
( long "server" ( long "server"
<> short 's' <> short 's'
<> metavar "SERVER" <> metavar "SERVER"
<> help <> help "Comma separated list of SMP server(s) to use"
"Comma separated list of SMP server(s) to use"
<> value [] <> value []
) )
socksProxy <-
flag' (Just defaultSocksProxy) (short 'x' <> help "use local SOCKS5 proxy at :9050")
<|> option
parseSocksConf
( long "socks-proxy"
<> metavar "SOCKS5"
<> help "`ipv4:port` or `:port` of SOCKS5 proxy"
<> value Nothing
)
t <-
option
auto
( long "tcp-timeout"
<> metavar "TIMEOUT"
<> help "TCP timeout, seconds (default: 5/10 without/with SOCKS5 proxy)"
<> value 0
)
logConnections <- logConnections <-
switch switch
( long "connections" ( long "connections"
@ -95,13 +118,30 @@ chatOpts appDir defaultDbFileName = do
<> short 'm' <> short 'm'
<> help "Run in maintenance mode (/_start to start chat)" <> help "Run in maintenance mode (/_start to start chat)"
) )
pure ChatOpts {dbFilePrefix, smpServers, logConnections, logAgent, chatCmd, chatCmdDelay, chatServerPort, maintenance} pure ChatOpts {dbFilePrefix, smpServers, socksProxy, tcpTimeout = useTcpTimeout socksProxy t, logConnections, logAgent, chatCmd, chatCmdDelay, chatServerPort, maintenance}
where where
useTcpTimeout p t = 1000000 * if t > 0 then t else maybe 5 (const 10) p
defaultDbFilePath = combine appDir defaultDbFileName defaultDbFilePath = combine appDir defaultDbFileName
parseSMPServers :: ReadM [SMPServer] parseSMPServers :: ReadM [SMPServer]
parseSMPServers = eitherReader $ parseAll smpServersP . B.pack parseSMPServers = eitherReader $ parseAll smpServersP . B.pack
defaultSocksHost :: HostAddress
defaultSocksHost = tupleToHostAddress (127, 0, 0, 1)
defaultSocksProxy :: SocksConf
defaultSocksProxy = defaultSocksConf $ SockAddrInet 9050 defaultSocksHost
parseSocksConf :: ReadM (Maybe SocksConf)
parseSocksConf = eitherReader $ parseAll socksConfP . B.pack
where
socksConfP = do
host <- maybe defaultSocksHost tupleToHostAddress <$> optional ipv4P
port <- fromMaybe 9050 <$> optional (A.char ':' *> (fromInteger <$> A.decimal))
pure . Just . defaultSocksConf $ SockAddrInet port host
ipv4P = (,,,) <$> ipNum <*> ipNum <*> ipNum <*> A.decimal
ipNum = A.decimal <* A.char '.'
parseServerPort :: ReadM (Maybe String) parseServerPort :: ReadM (Maybe String)
parseServerPort = eitherReader $ parseAll serverPortP . B.pack parseServerPort = eitherReader $ parseAll serverPortP . B.pack

View file

@ -1,3 +1,4 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
@ -28,7 +29,9 @@ terminalChatConfig =
"smp://hpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg=@smp5.simplex.im", "smp://hpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg=@smp5.simplex.im",
"smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im" "smp://PQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo=@smp6.simplex.im"
], ],
ntf = ["ntf://FB-Uop7RTaZZEG0ZLD2CIaTjsPh-Fw0zFAnb7QyA8Ks=@ntf2.simplex.im"] ntf = ["ntf://FB-Uop7RTaZZEG0ZLD2CIaTjsPh-Fw0zFAnb7QyA8Ks=@ntf2.simplex.im"],
socksProxy = Nothing,
tcpTimeout = 5000000
} }
} }

View file

@ -49,7 +49,7 @@ extra-deps:
# - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561 # - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561
# - ../simplexmq # - ../simplexmq
- github: simplex-chat/simplexmq - github: simplex-chat/simplexmq
commit: eb1f9370c1f254022019906fb6cf741d7687c525 commit: d788c3ca95f74d7ec2d737f3ef3ad8dc69d32abc
# - terminal-0.2.0.0@sha256:de6770ecaae3197c66ac1f0db5a80cf5a5b1d3b64a66a05b50f442de5ad39570,2977 # - terminal-0.2.0.0@sha256:de6770ecaae3197c66ac1f0db5a80cf5a5b1d3b64a66a05b50f442de5ad39570,2977
- github: simplex-chat/aeson - github: simplex-chat/aeson
commit: 3eb66f9a68f103b5f1489382aad89f5712a64db7 commit: 3eb66f9a68f103b5f1489382aad89f5712a64db7

View file

@ -49,6 +49,8 @@ testOpts =
ChatOpts ChatOpts
{ dbFilePrefix = undefined, { dbFilePrefix = undefined,
smpServers = ["smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=@localhost:5001"], smpServers = ["smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=@localhost:5001"],
socksProxy = Nothing,
tcpTimeout = 5000000,
logConnections = False, logConnections = False,
logAgent = False, logAgent = False,
chatCmd = "", chatCmd = "",