Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: build # this string appears on badge
on:
- push
- pull_request
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
name: "Unit tests on go ${{ matrix.go }}"
strategy:
matrix:
go:
- "1.21"
- "1.22"
- "1.23"
- "1.24"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "${{ matrix.go }}"
- run: "go build -v -x ."
15 changes: 15 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
name: lint # this string appears on badge
on:
- push
- pull_request
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
name: "Linting"
steps:
- uses: actions/checkout@v4
- uses: golangci/golangci-lint-action@v6
with:
version: "v1.64"
21 changes: 21 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: test # this string appears on badge
on:
- push
- pull_request
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
name: "Unit tests on go ${{ matrix.go }}"
strategy:
matrix:
go:
- "1.23"
- "1.24"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "${{ matrix.go }}"
- run: "go test -v -cover -timeout=5s ."
44 changes: 18 additions & 26 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
run:
deadline: 1m
tests: false
#skip-files:
# - ".*\\.gen\\.go"

linters-settings:
golint:
min-confidence: 0
maligned:
suggest-new: true
goconst:
min-len: 5
min-occurrences: 4
misspell:
locale: US
gosec:
excludes: [G402]
ireturn:
allow:
- context.Context
- error
- io.(Reader|Writer)

linters:
disable-all: true
enable:
- goconst
- misspell
- deadcode
- misspell
- structcheck
- errcheck
- unused
- varcheck
- staticcheck
- unconvert
- gofmt
- goimports
- golint
- ineffassign
enable-all: true
disable:
- depguard
- exhaustruct
- godox # TODOs is ok
- mnd # nice to have
- nlreturn # nice to have
- paralleltest # for now we have only one integration (not parallelable) test
- tenv
- varnamelen
- wsl
38 changes: 20 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ SSH Connection proxified with QUIC
┌───────────────────────────────────────┐ ┌───────────────────────┐
│ bob │ │ wopr │
│ ┌───────────────────────────────────┐ │ │ ┌───────────────────┐ │
│ │ssh -o ProxyCommand "quicssh client│ │ │ │ sshd │ │
│ │ssh -o ProxyCommand="quicssh client│ │ │ │ sshd │ │
│ │ --addr %h:4545" user@wopr │ │ │ └───────────────────┘ │
│ │ │ │ │ ▲ │
│ └───────────────────────────────────┘ │ │ │ │
Expand All @@ -50,52 +50,54 @@ SSH Connection proxified with QUIC
```console
$ quicssh -h
NAME:
quicssh - A new cli application
quicssh - Client and server parts to proxy SSH (TCP) over UDP using QUIC transport

USAGE:
quicssh [global options] command [command options] [arguments...]
quicssh [global options] command [command options]

VERSION:
0.0.0
v0.0.0-20230730133128-1c771b69d1a7+dirty

COMMANDS:
server
client
help, h Shows a list of commands or help for one command
server
client
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--help, -h show help (default: false)
--version, -v print the version (default: false)
```
--help, -h show help
--version, -v print the version
```

### Client

```console
$ quicssh client -h
NAME:
quicssh client -
quicssh client

USAGE:
quicssh client [command options] [arguments...]
quicssh client [command options]

OPTIONS:
--addr value (default: "localhost:4242")
--help, -h show help (default: false)
--addr value address of server (default: "localhost:4242")
--localaddr value source address of UDP packets (default: ":0")
--help, -h show help
```

### Server

```console
$ quicssh server -h
NAME:
quicssh server -
quicssh server

USAGE:
quicssh server [command options] [arguments...]
quicssh server [command options]

OPTIONS:
--bind value (default: "localhost:4242")
--help, -h show help (default: false)
--bind value bind address (default: "localhost:4242")
--sshdaddr value target address of sshd (default: "localhost:22")
--help, -h show help
```

## Install
Expand Down
54 changes: 30 additions & 24 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,62 @@ package main

import (
"crypto/tls"
"log"
"os"
"sync"
"net"
"time"

quic "github.com/quic-go/quic-go"
cli "github.com/urfave/cli/v2"
"golang.org/x/net/context"
)

func client(c *cli.Context) error {
ctx, cancel := context.WithCancel(context.Background())
ctx := withLabel(c.Context, "client")

config := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"quicssh"},
}

log.Printf("Dialing %q...", c.String("addr"))
session, err := quic.DialAddr(ctx, c.String("addr"), config, nil)
udpAddr, err := net.ResolveUDPAddr("udp", c.String("addr"))
if err != nil {
return err
return er(ctx, err)
}
srcAddr, err := net.ResolveUDPAddr("udp", c.String("localaddr"))
if err != nil {
return er(ctx, err)
}

logf(ctx, "Dialing %q->%q...", srcAddr.String(), udpAddr.String())
conn, err := net.ListenUDP("udp", srcAddr)
if err != nil {
return er(ctx, err)
}
quicConfig := &quic.Config{MaxIdleTimeout: 10 * time.Second, KeepAlivePeriod: 5 * time.Second}
session, err := quic.Dial(ctx, conn, udpAddr, config, quicConfig)
if err != nil {
return er(ctx, err)
}
defer func() {
if err := session.CloseWithError(0, "close"); err != nil {
log.Printf("session close error: %v", err)
logf(ctx, "session close error: %v", err)
}
}()

log.Printf("Opening stream sync...")
logf(ctx, "Opening stream sync...")
stream, err := session.OpenStreamSync(ctx)
if err != nil {
return err
return er(ctx, err)
}
defer stream.Close()

log.Printf("Piping stream with QUIC...")
var wg sync.WaitGroup
wg.Add(3)
c1 := readAndWrite(ctx, stream, os.Stdout, &wg)
c2 := readAndWrite(ctx, os.Stdin, stream, &wg)
logf(ctx, "Piping stream with QUIC...")
c1 := readAndWrite(withLabel(ctx, "stdout"), stream, c.App.Writer) // App.Writer is stdout
c2 := readAndWrite(withLabel(ctx, "stdin"), c.App.Reader, stream) // App.Reader is stdin
select {
case err = <-c1:
if err != nil {
return err
}
case err = <-c2:
if err != nil {
return err
}
}
cancel()
wg.Wait()
if err != nil {
return err
}
return nil
}
29 changes: 15 additions & 14 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
module moul.io/quicssh

go 1.20
go 1.23.0

toolchain go1.24.0

require (
github.com/quic-go/quic-go v0.35.1
github.com/urfave/cli/v2 v2.25.6
golang.org/x/net v0.11.0
github.com/quic-go/quic-go v0.50.0
github.com/urfave/cli/v2 v2.27.6
golang.org/x/net v0.37.0
)

require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
github.com/onsi/ginkgo/v2 v2.10.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/tools v0.10.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
go.uber.org/mock v0.5.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/tools v0.22.0 // indirect
)
Loading