diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f696dd27..360e388fc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,10 +52,10 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') shell: bash run: | - mv $(cabal list-bin smp-server) smp-server-ubuntu-$platform_name - mv $(cabal list-bin ntf-server) ntf-server-ubuntu-$platform_name - mv $(cabal list-bin xftp-server) xftp-server-ubuntu-$platform_name - mv $(cabal list-bin xftp) xftp-ubuntu-$platform_name + mv $(cabal list-bin smp-server) smp-server-ubuntu-${{ matrix.platform_name}} + mv $(cabal list-bin ntf-server) ntf-server-ubuntu-${{ matrix.platform_name}} + mv $(cabal list-bin xftp-server) xftp-server-ubuntu-${{ matrix.platform_name}} + mv $(cabal list-bin xftp) xftp-ubuntu-${{ matrix.platform_name}} - name: Build changelog if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-20.04' @@ -81,10 +81,10 @@ jobs: prerelease: true files: | LICENSE - smp-server-ubuntu-$platform_name - ntf-server-ubuntu-$platform_name - xftp-server-ubuntu-$platform_name - xftp-ubuntu-$platform_name + smp-server-ubuntu-${{ matrix.platform_name}} + ntf-server-ubuntu-${{ matrix.platform_name}} + xftp-server-ubuntu-${{ matrix.platform_name}} + xftp-ubuntu-${{ matrix.platform_name}} fail_on_unmatched_files: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.yaml b/package.yaml index eb10dac51..c90a10980 100644 --- a/package.yaml +++ b/package.yaml @@ -45,6 +45,7 @@ dependencies: - http2 == 4.1.* - generic-random >= 1.3 && < 1.5 - ini == 0.4.1 + - iproute == 1.7.* - iso8601-time == 0.1.* - memory == 0.15.* - mtl == 2.2.* diff --git a/simplexmq.cabal b/simplexmq.cabal index 5c9aa0de2..8afbf6e16 100644 --- a/simplexmq.cabal +++ b/simplexmq.cabal @@ -155,6 +155,7 @@ library , http-types ==0.12.* , http2 ==4.1.* , ini ==0.4.1 + , iproute ==1.7.* , iso8601-time ==0.1.* , memory ==0.15.* , mtl ==2.2.* @@ -218,6 +219,7 @@ executable ntf-server , http-types ==0.12.* , http2 ==4.1.* , ini ==0.4.1 + , iproute ==1.7.* , iso8601-time ==0.1.* , memory ==0.15.* , mtl ==2.2.* @@ -282,6 +284,7 @@ executable smp-agent , http-types ==0.12.* , http2 ==4.1.* , ini ==0.4.1 + , iproute ==1.7.* , iso8601-time ==0.1.* , memory ==0.15.* , mtl ==2.2.* @@ -346,6 +349,7 @@ executable smp-server , http-types ==0.12.* , http2 ==4.1.* , ini ==0.4.1 + , iproute ==1.7.* , iso8601-time ==0.1.* , memory ==0.15.* , mtl ==2.2.* @@ -410,6 +414,7 @@ executable xftp , http-types ==0.12.* , http2 ==4.1.* , ini ==0.4.1 + , iproute ==1.7.* , iso8601-time ==0.1.* , memory ==0.15.* , mtl ==2.2.* @@ -474,6 +479,7 @@ executable xftp-server , http-types ==0.12.* , http2 ==4.1.* , ini ==0.4.1 + , iproute ==1.7.* , iso8601-time ==0.1.* , memory ==0.15.* , mtl ==2.2.* @@ -567,6 +573,7 @@ test-suite simplexmq-test , http-types ==0.12.* , http2 ==4.1.* , ini ==0.4.1 + , iproute ==1.7.* , iso8601-time ==0.1.* , main-tester ==0.2.* , memory ==0.15.* diff --git a/src/Simplex/Messaging/Transport/Client.hs b/src/Simplex/Messaging/Transport/Client.hs index 1a7f81992..464d3230e 100644 --- a/src/Simplex/Messaging/Transport/Client.hs +++ b/src/Simplex/Messaging/Transport/Client.hs @@ -26,13 +26,14 @@ import Data.Aeson (FromJSON (..), ToJSON (..)) import qualified Data.Attoparsec.ByteString.Char8 as A import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as B -import Data.Char (isAsciiLower, isDigit) +import Data.Char (isAsciiLower, isDigit, isHexDigit) import Data.Default (def) +import Data.IP import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as L import Data.Maybe (fromMaybe) import Data.String -import Data.Word (Word8) +import Data.Word (Word32, Word8) import qualified Data.X509 as X import qualified Data.X509.CertificateStore as XS import Data.X509.Validation (Fingerprint (..)) @@ -55,6 +56,7 @@ import qualified UnliftIO.Exception as E data TransportHost = THIPv4 (Word8, Word8, Word8, Word8) + | THIPv6 (Word32, Word32, Word32, Word32) | THOnionHost ByteString | THDomainName HostName deriving (Eq, Ord, Show) @@ -66,11 +68,13 @@ instance Encoding TransportHost where instance StrEncoding TransportHost where strEncode = \case THIPv4 (a1, a2, a3, a4) -> B.intercalate "." $ map bshow [a1, a2, a3, a4] + THIPv6 addr -> bshow $ toIPv6w addr THOnionHost host -> host THDomainName host -> B.pack host strP = A.choice [ THIPv4 <$> ((,,,) <$> ipNum <*> ipNum <*> ipNum <*> A.decimal), + maybe (Left "bad IPv6") (Right . THIPv6 . fromIPv6w) . readMaybe . B.unpack <$?> A.takeWhile1 (\c -> isHexDigit c || c == ':'), THOnionHost <$> ((<>) <$> A.takeWhile (\c -> isAsciiLower c || isDigit c) <*> A.string ".onion"), THDomainName . B.unpack <$> (notOnion <$?> A.takeWhile1 (A.notInClass ":#,;/ \n\r\t")) ] @@ -129,6 +133,7 @@ runTLSTransportClient tlsParams caStore_ TransportClientConfig {socksProxy, tcpK where hostAddr = \case THIPv4 addr -> SocksAddrIPV4 $ tupleToHostAddress addr + THIPv6 addr -> SocksAddrIPV6 addr THOnionHost h -> SocksAddrDomainName h THDomainName h -> SocksAddrDomainName $ B.pack h diff --git a/src/Simplex/Messaging/Transport/Server.hs b/src/Simplex/Messaging/Transport/Server.hs index d7ce49d9b..536ebb0db 100644 --- a/src/Simplex/Messaging/Transport/Server.hs +++ b/src/Simplex/Messaging/Transport/Server.hs @@ -1,5 +1,7 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} module Simplex.Messaging.Transport.Server @@ -12,11 +14,15 @@ module Simplex.Messaging.Transport.Server ) where +import Control.Applicative ((<|>)) import Control.Concurrent.STM (stateTVar) +import Control.Logger.Simple import Control.Monad.Except import Control.Monad.IO.Unlift import qualified Crypto.Store.X509 as SX import Data.Default (def) +import Data.List (find) +import Data.Maybe (fromJust) import qualified Data.X509 as X import Data.X509.Validation (Fingerprint (..)) import qualified Data.X509.Validation as XV @@ -25,7 +31,7 @@ import qualified Network.TLS as T import Simplex.Messaging.TMap (TMap) import qualified Simplex.Messaging.TMap as TM import Simplex.Messaging.Transport -import Simplex.Messaging.Util (catchAll_) +import Simplex.Messaging.Util (catchAll_, tshow) import System.Exit (exitFailure) import System.Mem.Weak (Weak, deRefWeak) import UnliftIO.Concurrent @@ -70,14 +76,18 @@ startTCPServer started port = withSocketsDo $ resolve >>= open >>= setStarted where resolve = let hints = defaultHints {addrFlags = [AI_PASSIVE], addrSocketType = Stream} - in head <$> getAddrInfo (Just hints) Nothing (Just port) + in select <$> getAddrInfo (Just hints) Nothing (Just port) + select as = fromJust $ family AF_INET6 <|> family AF_INET + where + family f = find ((== f) . addrFamily) as open addr = do sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) setSocketOption sock ReuseAddr 1 withFdSocket sock setCloseOnExecIfNeeded + logInfo $ "binding to " <> tshow (addrAddress addr) bind sock $ addrAddress addr listen sock 1024 - return sock + pure sock setStarted sock = atomically (tryPutTMVar started True) >> pure sock loadTLSServerParams :: FilePath -> FilePath -> FilePath -> IO T.ServerParams