diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index f03353d..d820b8e 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -37,7 +37,7 @@ jobs: - name: Set a different ld for each arch # ugly but there are no working flags to explicitly set the ld to use... run: sudo cp /usr/bin/x86_64-linux-gnu-ld /usr/bin/amd64-ld && sudo cp /tmp/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc /usr/bin/arm64-ld - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '1.21.x' - name: Run GoReleaser diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9b70a21..364ec9f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ jobs: build-linux: strategy: matrix: - go-version: [ '1.20.x', '1.21.x' ] + go-version: [ '1.21.x', '1.22.0-rc.1' ] goos: [linux] testuser: [ssh3-testuser] testpasswd: [ssh3-testpasswd] @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '${{matrix.go-version}}' - name: Install dependencies to generate ssh keys and certificates @@ -46,7 +46,7 @@ jobs: - name: log authorized_identities run: cat ${{matrix.testuserhome}}/.ssh3/authorized_identities - name: Integration tests - run: sudo -E make -e integration-tests + run: sudo -E PATH=$PATH make -e integration-tests env: CERT_PEM: /cert.pem CERT_PRIV_KEY: /priv.key @@ -62,14 +62,14 @@ jobs: build-macos: strategy: matrix: - go-version: [ '1.20.x', '1.21.x' ] + go-version: [ '1.21.x', '1.22.0-rc.1' ] goos: [darwin] goarch: [amd64,arm64] runs-on: macos-latest steps: - uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '${{matrix.go-version}}' - name: Install dependencies @@ -89,7 +89,7 @@ jobs: build-other-unix: strategy: matrix: - go-version: [ '1.20.x', '1.21.x' ] + go-version: [ '1.21.x', '1.22.0-rc.1' ] goos: [openbsd,freebsd,linux] goarch: [amd64,"386",arm64,arm] exclude: @@ -101,7 +101,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '${{matrix.go-version}}' - name: Install dependencies diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f1dd477..1b6e546 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ jobs: build-linux: strategy: matrix: - go-version: [ '1.20.x', '1.21.x' ] + go-version: [ '1.21.x', '1.22.0-rc.1' ] goos: [linux] testuser: [ssh3-testuser] testpasswd: [ssh3-testpasswd] @@ -32,7 +32,7 @@ jobs: # - name: Install lcrypt for arm64 # run: sudo apt-get -y install libc6:arm64 libcrypt-dev:arm64 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '${{matrix.go-version}}' - name: Lint and vet code diff --git a/cmd/ssh3/main.go b/cmd/ssh3/main.go index 49b8452..4fe5e8d 100644 --- a/cmd/ssh3/main.go +++ b/cmd/ssh3/main.go @@ -47,21 +47,24 @@ func homedir() string { // If non-nil, use udpConn as transport (can be used for proxy jump) // Otherwise, create a UDPConn from udp://host:port func setupQUICConnection(ctx context.Context, skipHostVerification bool, keylog io.Writer, ssh3Dir string, certPool *x509.CertPool, knownHostsPath string, knownHosts ssh3.KnownHosts, - oidcConfig []*auth.OIDCConfig, options *client.Options, udpConn *net.UDPConn, tty *os.File) (quic.EarlyConnection, int) { + oidcConfig []*auth.OIDCConfig, options *client.Options, proxyRemoteAddr *net.UDPAddr, tty *os.File) (quic.EarlyConnection, int) { - remoteAddr, err := net.ResolveUDPAddr("udp", options.URLHostnamePort()) - if err != nil { - log.Error().Msgf("could not resolve UDP address: %s", err) - return nil, -1 - } - if udpConn == nil { - udpConn, err = net.ListenUDP("udp", nil) + var err error + remoteAddr := proxyRemoteAddr + if remoteAddr == nil { + remoteAddr, err = net.ResolveUDPAddr("udp", options.URLHostnamePort()) if err != nil { - log.Error().Msgf("could not create UDP connection: %s", err) + log.Error().Msgf("could not resolve UDP address: %s", err) return nil, -1 } } + udpConn, err := net.ListenUDP("udp", nil) + if err != nil { + log.Error().Msgf("could not create UDP connection: %s", err) + return nil, -1 + } + tlsConf := &tls.Config{ RootCAs: certPool, InsecureSkipVerify: skipHostVerification, @@ -299,6 +302,7 @@ func mainWithStatusCode() int { forwardSSHAgent := flag.Bool("forward-agent", false, "if set, forwards ssh agent to be used with sshv2 connections on the remote host") forwardUDP := flag.String("forward-udp", "", "if set, take a localport/remoteip@remoteport forwarding localhost@localport towards remoteip@remoteport") forwardTCP := flag.String("forward-tcp", "", "if set, take a localport/remoteip@remoteport forwarding localhost@localport towards remoteip@remoteport") + proxyJump := flag.String("proxy-jump", "", "if set, performs a proxy jump using the specified remote host as proxy") flag.Parse() args := flag.Args() @@ -524,7 +528,69 @@ func mainWithStatusCode() int { log.Error().Msgf("Could not get connection material for %s: %s", parsedUrl, err) return -1 } - qconn, status := setupQUICConnection(ctx, *insecure, keyLog, ssh3Dir, pool, knownHostsPath, knownHosts, oidcConfig, options, nil, tty) + + if *proxyJump == "" && sshConfig != nil { + *proxyJump, err = sshConfig.Get(parsedUrl.Hostname(), "UDPProxyJump") + if err != nil { + log.Error().Msgf("Could not get UDPProxyJump config value: %s", err) + return -1 + } + } + + var proxyAddress *net.UDPAddr + if *proxyJump != "" { + if !strings.HasPrefix(*proxyJump, "https://") { + *proxyJump = fmt.Sprintf("https://%s", *proxyJump) + } + proxyParsedUrl, err := url.Parse(*proxyJump) + if err != nil { + log.Error().Msgf("Could not parse proxy host URL %s: %s", *proxyJump, err) + return -1 + } + proxyAgentClient, proxyOptions, err := getConnectionMaterialFromURL(proxyParsedUrl, sshConfig, cliAuthMethods) + if err != nil { + log.Error().Msgf("Could not get connection material for proxy %s: %s", proxyParsedUrl, err) + return -1 + } + qconn, status := setupQUICConnection(ctx, *insecure, keyLog, ssh3Dir, pool, knownHostsPath, knownHosts, oidcConfig, proxyOptions, nil, tty) + + if qconn == nil { + if status != 0 { + log.Error().Msgf("could not setup transport for proxy client: %s", err) + } + return status + } + + roundTripper := &http3.RoundTripper{ + EnableDatagrams: true, + } + + proxyClient, err := client.Dial(ctx, proxyOptions, qconn, roundTripper, proxyAgentClient) + if err != nil { + log.Error().Msgf("could not establish SSH3 proxy conversation: %s", err) + return -1 + } + + baseAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") + if err != nil { + log.Error().Msgf("Could not resolve 127.0.0.1:0: %s", err) + return -1 + } + remoteAddr, err := net.ResolveUDPAddr("udp", options.URLHostnamePort()) + if err != nil { + log.Error().Msgf("Could not resolve remote address %s: %s", options.URLHostnamePort(), err) + return -1 + } + addr, err := proxyClient.ForwardUDP(ctx, baseAddr, remoteAddr) + if err != nil { + log.Error().Msgf("Could not forward UDP for proxy jump: %s", err) + return -1 + } + proxyAddress = addr + log.Debug().Msgf("started proxy jump at %s", proxyAddress) + } + + qconn, status := setupQUICConnection(ctx, *insecure, keyLog, ssh3Dir, pool, knownHostsPath, knownHosts, oidcConfig, options, proxyAddress, tty) if qconn == nil { if status != 0 { diff --git a/conversation.go b/conversation.go index d1f863d..e38f3fb 100644 --- a/conversation.go +++ b/conversation.go @@ -29,7 +29,7 @@ type Conversation struct { maxPacketSize uint64 defaultDatagramsQueueSize uint64 streamCreator http3.StreamCreator - messageSender util.MessageSender + messageSender util.DatagramSender channelsManager *channelsManager context context.Context cancelContext context.CancelCauseFunc @@ -134,7 +134,7 @@ func (c *Conversation) EstablishClientConversation(req *http.Request, roundTripp // currently does not work for several conversations in the same QUIC connection for { - dgram, err := qconn.ReceiveMessage(c.Context()) + dgram, err := qconn.ReceiveDatagram(c.Context()) if err != nil { if err != context.Canceled { log.Error().Msgf("could not receive message from conn: %s", err) @@ -166,7 +166,7 @@ func (c *Conversation) EstablishClientConversation(req *http.Request, roundTripp } } -func NewServerConversation(ctx context.Context, controlStream http3.Stream, qconn quic.Connection, messageSender util.MessageSender, maxPacketsize uint64) (*Conversation, error) { +func NewServerConversation(ctx context.Context, controlStream http3.Stream, qconn quic.Connection, messageSender util.DatagramSender, maxPacketsize uint64) (*Conversation, error) { backgroundContext, backgroundCancelFunc := context.WithCancelCause(ctx) tls := qconn.ConnectionState().TLS @@ -290,7 +290,7 @@ func (c *Conversation) getDatagramSenderForChannel(channelID util.ChannelID) fun buf := util.AppendVarInt(nil, uint64(c.controlStream.StreamID())) buf = util.AppendVarInt(buf, channelID) buf = append(buf, datagram...) - return c.messageSender.SendMessage(buf) + return c.messageSender.SendDatagram(buf) } } diff --git a/go.mod b/go.mod index 1ab0974..5b4fe40 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/kevinburke/ssh_config v1.2.0 github.com/onsi/ginkgo/v2 v2.13.0 github.com/onsi/gomega v1.29.0 - github.com/quic-go/quic-go v0.38.1 + github.com/quic-go/quic-go v0.40.1-0.20240102075208-1083d1fb8f98 github.com/rs/zerolog v1.31.0 golang.org/x/crypto v0.14.0 golang.org/x/oauth2 v0.13.0 @@ -18,7 +18,6 @@ require ( github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect @@ -26,7 +25,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.3 // indirect + go.uber.org/mock v0.3.0 // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/net v0.17.0 // indirect diff --git a/go.sum b/go.sum index 877e79b..8c0c890 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eU github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE= github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4= +github.com/quic-go/quic-go v0.40.1-0.20240102075208-1083d1fb8f98 h1:XSdekoU+UVlq/Mav+6dYyPuyy5+qzDa/TglBVi+L7Rs= +github.com/quic-go/quic-go v0.40.1-0.20240102075208-1083d1fb8f98/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -68,6 +70,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/integration_tests/ssh3_test.go b/integration_tests/ssh3_test.go index cb80512..048f73a 100644 --- a/integration_tests/ssh3_test.go +++ b/integration_tests/ssh3_test.go @@ -19,16 +19,19 @@ var ssh3Path string var ssh3ServerPath string const DEFAULT_URL_PATH = "/ssh3-tests" +const DEFAULT_PROXY_URL_PATH = "/ssh3-tests-proxy" var serverCommand *exec.Cmd var serverSession *Session +var proxyServerCommand *exec.Cmd +var proxyServerSession *Session var rsaPrivKeyPath string var ed25519PrivKeyPath string var attackerPrivKeyPath string var username string -// must exist on the machine to successfully run the tests const serverBind = "127.0.0.1:4433" +const proxyServerBind = "127.0.0.1:4444" func IPv6LoopbackAvailable(addrs []net.Addr) bool { for _, addr := range addrs { @@ -69,6 +72,17 @@ var _ = BeforeSuite(func() { serverSession, err = Start(serverCommand, GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) + proxyServerCommand = exec.Command(ssh3ServerPath, + "-bind", proxyServerBind, + "-v", + "-enable-password-login", + "-url-path", DEFAULT_PROXY_URL_PATH, + "-cert", os.Getenv("CERT_PEM"), + "-key", os.Getenv("CERT_PRIV_KEY")) + proxyServerCommand.Env = append(proxyServerCommand.Env, "SSH3_LOG_LEVEL=debug") + proxyServerSession, err = Start(proxyServerCommand, GinkgoWriter, GinkgoWriter) + Expect(err).ToNot(HaveOccurred()) + rsaPrivKeyPath = os.Getenv("TESTUSER_PRIVKEY") ed25519PrivKeyPath = os.Getenv("TESTUSER_ED25519_PRIVKEY") attackerPrivKeyPath = os.Getenv("ATTACKER_PRIVKEY") @@ -130,6 +144,15 @@ var _ = Describe("Testing the ssh3 cli", func() { Eventually(session).Should(Say("Hello, World!\n")) }) + It("Should connect using an RSA privkey through proxy jump", func() { + clientArgs = append(getClientArgs(rsaPrivKeyPath, "-proxy-jump", fmt.Sprintf("%s@%s%s", username, proxyServerBind, DEFAULT_PROXY_URL_PATH)), "echo", "Hello, World!") + command := exec.Command(ssh3Path, clientArgs...) + session, err := Start(command, GinkgoWriter, GinkgoWriter) + Expect(err).ToNot(HaveOccurred()) + Eventually(session).Should(Exit(0)) + Eventually(session).Should(Say("Hello, World!\n")) + }) + It("Should connect using an ed25519 privkey", func() { clientArgs = append(getClientArgs(ed25519PrivKeyPath), "echo", "Hello, World!") command := exec.Command(ssh3Path, clientArgs...) @@ -184,7 +207,7 @@ var _ = Describe("Testing the ssh3 cli", func() { // a TCP socket is indeed well open on the client and is indeed forwarded // through the SSH3 connection towards the specified remote IP and port. Context("TCP port forwarding", func() { - testTCPPortForwarding := func(localPort uint16, remoteAddr *net.TCPAddr, messageFromClient string, messageFromServer string) { + testTCPPortForwarding := func(localPort uint16, proxyJump bool, remoteAddr *net.TCPAddr, messageFromClient string, messageFromServer string) { localIP := "[::1]" if remoteAddr.IP.To4() != nil { localIP = "127.0.0.1" @@ -223,7 +246,13 @@ var _ = Describe("Testing the ssh3 cli", func() { Eventually(serverStarted).Should(Receive()) // Execute the client with TCP port forwarding - clientArgs := getClientArgs(rsaPrivKeyPath, "-forward-tcp", fmt.Sprintf("%d/%s@%d", localPort, remoteAddr.IP, remoteAddr.Port)) + + additionalArgs := []string{} + if proxyJump { + additionalArgs = append(additionalArgs, "-proxy-jump", fmt.Sprintf("%s@%s%s", username, proxyServerBind, DEFAULT_PROXY_URL_PATH)) + } + additionalArgs = append(additionalArgs, "-forward-tcp", fmt.Sprintf("%d/%s@%d", localPort, remoteAddr.IP, remoteAddr.Port)) + clientArgs := getClientArgs(rsaPrivKeyPath, additionalArgs...) command := exec.Command(ssh3Path, clientArgs...) session, err := Start(command, GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) @@ -265,7 +294,11 @@ var _ = Describe("Testing the ssh3 cli", func() { } It("works with small messages", func() { - testTCPPortForwarding(8080, &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, "hello from client", "hello from server") + testTCPPortForwarding(8080, false, &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, "hello from client", "hello from server") + }) + + It("works through proxy jump", func() { + testTCPPortForwarding(8080, true, &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, "hello from client", "hello from server") }) It("works with messages larger than a typical MTU", func() { @@ -278,7 +311,7 @@ var _ = Describe("Testing the ssh3 cli", func() { n, err = rng.Read(messageFromServer) Expect(n).To(Equal(len(messageFromServer))) Expect(err).ToNot(HaveOccurred()) - testTCPPortForwarding(8081, &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, string(messageFromClient), string(messageFromServer)) + testTCPPortForwarding(8081, false, &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, string(messageFromClient), string(messageFromServer)) }) It("works with IPv6 addresses", func() { @@ -289,7 +322,7 @@ var _ = Describe("Testing the ssh3 cli", func() { if !IPv6LoopbackAvailable(addrs) { Skip("IPv6 not available on this host") } - testTCPPortForwarding(8082, &net.TCPAddr{IP: net.ParseIP("::1"), Port: 9091}, "hello from client", "hello from server") + testTCPPortForwarding(8082, false, &net.TCPAddr{IP: net.ParseIP("::1"), Port: 9091}, "hello from client", "hello from server") }) }) }) @@ -298,7 +331,7 @@ var _ = Describe("Testing the ssh3 cli", func() { // a UDP socket is indeed well open on the client and is indeed forwarded // through the SSH3 connection towards the specified remote IP and port. Context("UDP port forwarding", func() { - testUDPPortForwarding := func(localPort uint16, remoteAddr *net.UDPAddr, messageFromClient, messageFromServer string) { + testUDPPortForwarding := func(localPort uint16, proxyJump bool, remoteAddr *net.UDPAddr, messageFromClient, messageFromServer string) { localIP := "[::1]" localIPWithoutBrackets := "::1" if remoteAddr.IP.To4() != nil { @@ -329,7 +362,13 @@ var _ = Describe("Testing the ssh3 cli", func() { Eventually(serverStarted).Should(Receive()) // Execute the client with UDP port forwarding - clientArgs := getClientArgs(rsaPrivKeyPath, "-forward-udp", fmt.Sprintf("%d/%s@%d", localPort, remoteAddr.IP, remoteAddr.Port)) + + additionalArgs := []string{} + if proxyJump { + additionalArgs = append(additionalArgs, "-proxy-jump", fmt.Sprintf("%s@%s%s", username, proxyServerBind, DEFAULT_PROXY_URL_PATH)) + } + additionalArgs = append(additionalArgs, "-forward-udp", fmt.Sprintf("%d/%s@%d", localPort, remoteAddr.IP, remoteAddr.Port)) + clientArgs := getClientArgs(rsaPrivKeyPath, additionalArgs...) command := exec.Command(ssh3Path, clientArgs...) session, err := Start(command, GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) @@ -365,7 +404,11 @@ var _ = Describe("Testing the ssh3 cli", func() { } It("works with small messages", func() { - testUDPPortForwarding(8080, &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, "hello from client", "hello from server") + testUDPPortForwarding(8080, false, &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, "hello from client", "hello from server") + }) + + It("works through proxy jump", func() { + testUDPPortForwarding(8080, true, &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, "hello from client", "hello from server") }) // Due to current quic-go limitations, the max datagram size is limited to 1200, whatever the real MTU is, @@ -380,7 +423,7 @@ var _ = Describe("Testing the ssh3 cli", func() { n, err = rng.Read(messageFromServer) Expect(n).To(Equal(len(messageFromServer))) Expect(err).ToNot(HaveOccurred()) - testUDPPortForwarding(8081, &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, string(messageFromClient), string(messageFromServer)) + testUDPPortForwarding(8081, false, &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9090}, string(messageFromClient), string(messageFromServer)) }) It("works with IPv6 addresses", func() { @@ -390,8 +433,9 @@ var _ = Describe("Testing the ssh3 cli", func() { if !IPv6LoopbackAvailable(addrs) { Skip("IPv6 not available on this host") } - testUDPPortForwarding(8082, &net.UDPAddr{IP: net.ParseIP("::1"), Port: 9091}, "hello from client", "hello from server") + testUDPPortForwarding(8082, false, &net.UDPAddr{IP: net.ParseIP("::1"), Port: 9091}, "hello from client", "hello from server") }) + }) Context("Server behaviour", func() { diff --git a/server.go b/server.go index f9b088e..679ee3e 100644 --- a/server.go +++ b/server.go @@ -147,7 +147,7 @@ func (s *Server) GetHTTPHandlerFunc(ctx context.Context) AuthenticatedHandlerFun // TODO: this hijacks the datagrams for the whole quic connection, so the server // currently does not work for several conversations in the same QUIC connection for { - dgram, err := qconn.ReceiveMessage(ctx) + dgram, err := qconn.ReceiveDatagram(ctx) if err != nil { if !errors.Is(err, context.Canceled) && !errors.Is(err, net.ErrClosed) { log.Error().Msgf("could not receive message from conn: %s", err) diff --git a/util/types.go b/util/types.go index 1f410a8..7af5f0b 100644 --- a/util/types.go +++ b/util/types.go @@ -64,6 +64,6 @@ func (b *BytesReadCloser) Close() error { return nil } // sends an ssh3 datagram. The function must know the ID of the channel type SSH3DatagramSenderFunc func(p []byte) error -type MessageSender interface { - SendMessage(p []byte) error +type DatagramSender interface { + SendDatagram(p []byte) error }