first commit
This commit is contained in:
commit
9b077dadf2
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
hostkeys/
|
||||||
|
.DS_Store
|
1
.hostkey.pub
Normal file
1
.hostkey.pub
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCg0nrgmQO7Cxt34uuI9pqZq72nqY/CmcTf/ZAtyZydk3kS9JZBckk0iUcT+zWWDcImVw9GWrkAu58mzAMU97LrrVg7Ap+pAZl99UNOUNkC8HeJTN559l/eCZ6gohlAlaKV3qSWia7+aIwRabhjTPAd6oOuaQjifd+/uvfQUTHIIjzsM6g3fQz70IyilH7Iid0OXytNWLh0emRjE/qcJA0R27cGQXxiQEf8Pz6Tl1YFbp3qd7pk0scl8kobdKmNv6LSPUUNuSeJC3AMbrmiHp9XnVTUBh0PB8Yn6kqA0OCtNZ/29RI4boIyDI4Y+wJxZ65E45doEExRPyxMzeoEnaAacUieu97rzGRj0WvfBIKs8kGCPJ8JA9ZvFcWkQbZK2kIQ/AWk8utmpKewlUzdB3VBM2d5nrsr+zo7U92rD7GUy0SEpV7sNy9pmob8M9WB8Qnjtl7+VmC1w5yNnJCfrzXVo+k7RsL71m/EbbJZj35hd6ExhPLgSL+CFRl4sj6TqJrdFYH0LbhQqvTydc8R8N9MhaMxVdEkQ08M3KcjHgFh2jEDJGbd4cChcPt+jWcWKw34Ycf8R7WKPvB1v9FVYOxesBMCaElWLMdrQlVf118WjJ+A25ynCwCpzYOFfsRCb0JbH1e2ANOXV2HdXvTBQxtT6r1MUFVKWJPrfgWlAdA3mQ== jonathan.lundy@ip-10-240-248-37.ec2.internal
|
20
Makefile
Normal file
20
Makefile
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
export SSH_LISTEN?=:2222
|
||||||
|
export SSH_HOSTKEYS?=hostkeys
|
||||||
|
export SSH_AUTHKEYS?=authkeys
|
||||||
|
|
||||||
|
export SSH_HOST?=localhost
|
||||||
|
export SSH_PORT?=2222
|
||||||
|
export SSH_OPTS?=-R 1234:localhost:22
|
||||||
|
|
||||||
|
run:
|
||||||
|
go run .
|
||||||
|
|
||||||
|
genkeys:
|
||||||
|
mkdir -p $(SSH_HOSTKEYS)
|
||||||
|
ssh-keygen -q -N "" -t rsa -b 4096 -f $(SSH_HOSTKEYS)/rsa
|
||||||
|
ssh-keygen -q -N "" -t ecdsa -f $(SSH_HOSTKEYS)/ecdsa
|
||||||
|
ssh-keygen -q -N "" -t ed25519 -f $(SSH_HOSTKEYS)/ed25519
|
||||||
|
rm -f $(SSH_HOSTKEYS)/*.pub
|
||||||
|
|
||||||
|
forward:
|
||||||
|
ssh $(SSH_HOST) -p $(SSH_PORT) $(SSH_OPTS)
|
1
authkeys/jon@xuu.cc
Normal file
1
authkeys/jon@xuu.cc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIUSB+REbjTVPRKuHHCRaMJJlMIw6Ofp0oZvy7wDSZR4 jonathan.lundy@US17020047.local
|
9
go.mod
Normal file
9
go.mod
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module github.com/jonlundy/sshfwd
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||||
|
github.com/gliderlabs/ssh v0.3.2
|
||||||
|
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect
|
||||||
|
)
|
13
go.sum
Normal file
13
go.sum
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
|
github.com/gliderlabs/ssh v0.3.2 h1:gcfd1Aj/9RQxvygu4l3sak711f/5+VOwBw9C/7+N4EI=
|
||||||
|
github.com/gliderlabs/ssh v0.3.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
|
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o=
|
||||||
|
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
104
main.go
Normal file
104
main.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/gliderlabs/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() {
|
||||||
|
var opts []ssh.Option
|
||||||
|
opts = append(
|
||||||
|
opts,
|
||||||
|
ssh.NoPty(),
|
||||||
|
optRemoteAllow(),
|
||||||
|
)
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(envMust("SSH_HOSTKEYS"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
opts = append(opts, ssh.HostKeyFile(filepath.Join(envMust("SSH_HOSTKEYS"), f.Name())))
|
||||||
|
}
|
||||||
|
|
||||||
|
if authKeys := os.Getenv("SSH_AUTHKEYS"); authKeys != "" {
|
||||||
|
opts = append(opts, optPubkeyAllow(authKeys))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal(ssh.ListenAndServe(
|
||||||
|
envMust("SSH_LISTEN"),
|
||||||
|
newSession(context.Background()),
|
||||||
|
opts...,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func envMust(s string) string {
|
||||||
|
v := os.Getenv(s)
|
||||||
|
if v == "" {
|
||||||
|
log.Fatal("missing env ", s)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSession(ctx context.Context) func(ssh.Session) {
|
||||||
|
return func(s ssh.Session) {
|
||||||
|
if _, err := fmt.Fprintf(s, "Hello %s\n", s.User()); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func optRemoteAllow() ssh.Option {
|
||||||
|
return func(cfg *ssh.Server) error {
|
||||||
|
hdlr := ssh.ForwardedTCPHandler{}
|
||||||
|
|
||||||
|
if cfg.RequestHandlers == nil {
|
||||||
|
cfg.RequestHandlers = make(map[string]ssh.RequestHandler, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.RequestHandlers["tcpip-forward"] = hdlr.HandleSSHRequest
|
||||||
|
cfg.RequestHandlers["cancel-tcpip-forward"] = hdlr.HandleSSHRequest
|
||||||
|
|
||||||
|
cfg.ReversePortForwardingCallback = func(ctx ssh.Context, bindHost string, bindPort uint32) bool {
|
||||||
|
log.Println("Allow Remote:", bindHost, bindPort)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func optPubkeyAllow(path string) ssh.Option {
|
||||||
|
return ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
|
||||||
|
files, err := ioutil.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
fname := filepath.Join(path, f.Name())
|
||||||
|
data, _ := ioutil.ReadFile(fname)
|
||||||
|
allowed, _, _, _, _ := ssh.ParseAuthorizedKey(data)
|
||||||
|
if ssh.KeysEqual(key, allowed) {
|
||||||
|
log.Println("Authorized:", fname)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user