Skip to content

Commit a8c1135

Browse files
authored
feat: POC (#1)
feat: POC
2 parents 59fab45 + 3bbaf75 commit a8c1135

File tree

12 files changed

+359
-22
lines changed

12 files changed

+359
-22
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defaults: &defaults
2-
working_directory: /go/src/moul.io/golang-repo-template
2+
working_directory: /go/src/moul.io/quicssh
33
docker:
44
- image: circleci/golang:1.12
55
environment:

.goreleaser.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ changelog:
1818
- '^docs:'
1919
- '^test:'
2020
brew:
21-
name: golang-repo-template
21+
name: quicssh
2222
github:
2323
owner: moul
2424
name: homebrew-moul
2525
commit_author:
2626
name: moul-bot
2727
2828
homepage: https://manfred.life/
29-
description: "golang-repo-template"
29+
description: "quicssh"

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
FROM golang:1.12-alpine as builder
33
RUN apk add --no-cache git gcc musl-dev make
44
ENV GO111MODULE=on
5-
WORKDIR /go/src/moul.io/golang-repo-template
5+
WORKDIR /go/src/moul.io/quicssh
66
COPY go.* ./
77
RUN go mod download
88
COPY . ./
99
RUN make install
1010

1111
# minimalist runtime
1212
FROM alpine:3.10
13-
COPY --from=builder /go/bin/golang-repo-template /bin/
14-
ENTRYPOINT ["/bin/golang-repo-template"]
13+
COPY --from=builder /go/bin/quicssh /bin/
14+
ENTRYPOINT ["/bin/quicssh"]
1515
CMD []

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
# golang-repo-template
1+
# quicssh
22

3-
:smile: golang-repo-template does
3+
:smile: quicssh does
44

5-
[![CircleCI](https://circleci.com/gh/moul/golang-repo-template.svg?style=shield)](https://circleci.com/gh/moul/golang-repo-template)
6-
[![GoDoc](https://godoc.org/moul.io/golang-repo-template?status.svg)](https://godoc.org/moul.io/golang-repo-template)
7-
[![License](https://img.shields.io/github/license/moul/golang-repo-template.svg)](https://github.com/moul/golang-repo-template/blob/master/LICENSE)
8-
[![GitHub release](https://img.shields.io/github/release/moul/golang-repo-template.svg)](https://github.com/moul/golang-repo-template/releases)
9-
[![Go Report Card](https://goreportcard.com/badge/moul.io/golang-repo-template)](https://goreportcard.com/report/moul.io/golang-repo-template)
10-
[![Docker Metrics](https://images.microbadger.com/badges/image/moul/golang-repo-template.svg)](https://microbadger.com/images/moul/golang-repo-template)
5+
[![CircleCI](https://circleci.com/gh/moul/quicssh.svg?style=shield)](https://circleci.com/gh/moul/quicssh)
6+
[![GoDoc](https://godoc.org/moul.io/quicssh?status.svg)](https://godoc.org/moul.io/quicssh)
7+
[![License](https://img.shields.io/github/license/moul/quicssh.svg)](https://github.com/moul/quicssh/blob/master/LICENSE)
8+
[![GitHub release](https://img.shields.io/github/release/moul/quicssh.svg)](https://github.com/moul/quicssh/releases)
9+
[![Go Report Card](https://goreportcard.com/badge/moul.io/quicssh)](https://goreportcard.com/report/moul.io/quicssh)
10+
[![Docker Metrics](https://images.microbadger.com/badges/image/moul/quicssh.svg)](https://microbadger.com/images/moul/quicssh)
1111
[![Made by Manfred Touron](https://img.shields.io/badge/made%20by-Manfred%20Touron-blue.svg?style=flat)](https://manfred.life/)
1212

1313
## Usage
1414

1515
```console
16-
$ golang-repo-template -h
16+
$ quicssh -h
1717
...
1818
```
1919

2020
## Install
2121

2222
```console
23-
$ go get -u moul.io/golang-repo-template
23+
$ go get -u moul.io/quicssh
2424
```
2525

2626
## License
2727

2828
© 2019 [Manfred Touron](https://manfred.life) -
29-
[Apache-2.0 License](https://github.com/moul/golang-repo-template/blob/master/LICENSE)
29+
[Apache-2.0 License](https://github.com/moul/quicssh/blob/master/LICENSE)

client.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package main
2+
3+
import (
4+
"crypto/tls"
5+
"log"
6+
"os"
7+
"sync"
8+
9+
quic "github.com/lucas-clemente/quic-go"
10+
"golang.org/x/net/context"
11+
cli "gopkg.in/urfave/cli.v2"
12+
)
13+
14+
func client(c *cli.Context) error {
15+
ctx, cancel := context.WithCancel(context.Background())
16+
17+
config := &tls.Config{
18+
InsecureSkipVerify: true,
19+
NextProtos: []string{"quicssh"},
20+
}
21+
22+
log.Printf("Dialing %q...", c.String("addr"))
23+
session, err := quic.DialAddr(c.String("addr"), config, nil)
24+
if err != nil {
25+
return err
26+
}
27+
defer session.Close()
28+
29+
log.Printf("Opening stream sync...")
30+
stream, err := session.OpenStreamSync(ctx)
31+
if err != nil {
32+
return err
33+
}
34+
35+
log.Printf("Piping stream with QUIC...")
36+
var wg sync.WaitGroup
37+
wg.Add(3)
38+
c1 := readAndWrite(ctx, stream, os.Stdout, &wg)
39+
c2 := readAndWrite(ctx, os.Stdin, stream, &wg)
40+
select {
41+
case err = <-c1:
42+
if err != nil {
43+
return err
44+
}
45+
case err = <-c2:
46+
if err != nil {
47+
return err
48+
}
49+
}
50+
cancel()
51+
wg.Wait()
52+
return nil
53+
}

doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
// limitations under the License.
1414

1515
// Package main is ...
16-
package main // import "moul.io/golang-repo-template"
16+
package main // import "moul.io/quicssh"

go.mod

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1-
module moul.io/golang-repo-template
1+
module moul.io/quicssh
22

33
go 1.12
4+
5+
require (
6+
github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031
7+
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7
8+
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8
9+
)

go.sum

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
2+
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
3+
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
4+
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
5+
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
6+
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
7+
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
8+
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
9+
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
10+
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
11+
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
12+
github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031 h1:wjcGvgllMOQw8wNYFH6acq/KlTAdjKMSo1EUYybHXto=
13+
github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031/go.mod h1:lb5aAxL68VvhZ00e7yYuQVK/9FLggtYy4qo7oI5qzqA=
14+
github.com/marten-seemann/qpack v0.1.0 h1:/0M7lkda/6mus9B8u34Asqm8ZhHAAt9Ho0vniNuVSVg=
15+
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
16+
github.com/marten-seemann/qtls v0.3.1 h1:ySYIvhFjFY2JsNHY6VACvomMEDy3EvdPA6yciUFAiHw=
17+
github.com/marten-seemann/qtls v0.3.1/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
18+
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
19+
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
20+
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
21+
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
22+
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
23+
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28DveNzzgmbXR+ENoPjUeIU=
24+
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
25+
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
26+
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7 h1:Qe/u+eY379X4He4GBMFZYu3pmh1ML5yT1aL1ndNM1zQ=
27+
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
28+
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
29+
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
30+
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
31+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
32+
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c=
33+
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
34+
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
35+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
36+
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
37+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
38+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
39+
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
40+
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
41+
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
42+
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
43+
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8 h1:Ggy3mWN4l3PUFPfSG0YB3n5fVYggzysUmiUQ89SnX6Y=
44+
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8/go.mod h1:cKXr3E0k4aosgycml1b5z33BVV6hai1Kh7uDgFOkbcs=
45+
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
46+
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

main.go

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,63 @@
1-
package main // import "moul.io/golang-repo-template"
1+
package main
22

3-
import "fmt"
3+
import (
4+
"io"
5+
"os"
6+
"sync"
7+
8+
"golang.org/x/net/context"
9+
cli "gopkg.in/urfave/cli.v2"
10+
)
411

512
func main() {
6-
fmt.Println("Hello World!")
13+
app := &cli.App{
14+
Commands: []*cli.Command{
15+
{
16+
Name: "server",
17+
Flags: []cli.Flag{
18+
&cli.StringFlag{Name: "bind", Value: "localhost:4242"},
19+
},
20+
Action: server,
21+
},
22+
{
23+
Name: "client",
24+
Flags: []cli.Flag{
25+
&cli.StringFlag{Name: "addr", Value: "localhost:4242"},
26+
},
27+
Action: client,
28+
},
29+
},
30+
}
31+
if err := app.Run(os.Args); err != nil {
32+
panic(err)
33+
}
34+
}
35+
36+
func readAndWrite(ctx context.Context, r io.Reader, w io.Writer, wg *sync.WaitGroup) <-chan error {
37+
c := make(chan error)
38+
go func() {
39+
if wg != nil {
40+
defer wg.Done()
41+
}
42+
buff := make([]byte, 1024)
43+
44+
for {
45+
select {
46+
case <-ctx.Done():
47+
return
48+
default:
49+
nr, err := r.Read(buff)
50+
if err != nil {
51+
return
52+
}
53+
if nr > 0 {
54+
_, err := w.Write(buff[:nr])
55+
if err != nil {
56+
return
57+
}
58+
}
59+
}
60+
}
61+
}()
62+
return c
763
}

server.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package main
2+
3+
import (
4+
"crypto/rand"
5+
"crypto/rsa"
6+
"crypto/tls"
7+
"crypto/x509"
8+
"encoding/pem"
9+
"io"
10+
"log"
11+
"math/big"
12+
"net"
13+
"sync"
14+
15+
quic "github.com/lucas-clemente/quic-go"
16+
"golang.org/x/net/context"
17+
cli "gopkg.in/urfave/cli.v2"
18+
)
19+
20+
func server(c *cli.Context) error {
21+
// generate TLS certificate
22+
key, err := rsa.GenerateKey(rand.Reader, 1024)
23+
if err != nil {
24+
return err
25+
}
26+
template := x509.Certificate{SerialNumber: big.NewInt(1)}
27+
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
28+
if err != nil {
29+
return err
30+
}
31+
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
32+
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
33+
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
34+
if err != nil {
35+
return err
36+
}
37+
config := &tls.Config{
38+
Certificates: []tls.Certificate{tlsCert},
39+
NextProtos: []string{"quicssh"},
40+
}
41+
42+
// configure listener
43+
listener, err := quic.ListenAddr(c.String("bind"), config, nil)
44+
if err != nil {
45+
return err
46+
}
47+
defer listener.Close()
48+
log.Printf("Listening at %q...", c.String("bind"))
49+
50+
ctx := context.Background()
51+
for {
52+
log.Printf("Accepting connection...")
53+
session, err := listener.Accept(ctx)
54+
if err != nil {
55+
log.Printf("listener error: %v", err)
56+
continue
57+
}
58+
59+
go serverSessionHandler(ctx, session)
60+
}
61+
return nil
62+
}
63+
64+
func serverSessionHandler(ctx context.Context, session quic.Session) {
65+
log.Printf("hanling session...")
66+
defer session.Close()
67+
for {
68+
stream, err := session.AcceptStream(ctx)
69+
if err != nil {
70+
log.Printf("session error: %v", err)
71+
break
72+
}
73+
go serverStreamHandler(ctx, stream)
74+
}
75+
}
76+
77+
func serverStreamHandler(ctx context.Context, conn io.ReadWriteCloser) {
78+
log.Printf("handling stream...")
79+
defer conn.Close()
80+
81+
rConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: net.IP{127, 0, 0, 1}, Port: 22})
82+
if err != nil {
83+
log.Printf("dial error: %v", err)
84+
return
85+
}
86+
defer rConn.Close()
87+
88+
ctx, cancel := context.WithCancel(ctx)
89+
90+
var wg sync.WaitGroup
91+
wg.Add(2)
92+
c1 := readAndWrite(ctx, conn, rConn, &wg)
93+
c2 := readAndWrite(ctx, rConn, conn, &wg)
94+
select {
95+
case err = <-c1:
96+
if err != nil {
97+
log.Printf("readAndWrite error on c1: %v", err)
98+
return
99+
}
100+
case err = <-c2:
101+
if err != nil {
102+
log.Printf("readAndWrite error on c2: %v", err)
103+
return
104+
}
105+
}
106+
cancel()
107+
wg.Wait()
108+
log.Printf("Piping finished")
109+
}
110+
111+
func netCopy(input io.Reader, output io.Writer) (err error) {
112+
buf := make([]byte, 8192)
113+
for {
114+
count, err := input.Read(buf)
115+
if err != nil {
116+
if err == io.EOF && count > 0 {
117+
output.Write(buf[:count])
118+
}
119+
break
120+
}
121+
if count > 0 {
122+
log.Println(buf, count)
123+
output.Write(buf[:count])
124+
}
125+
}
126+
return
127+
}

0 commit comments

Comments
 (0)