mirror of
https://github.com/boringproxy/boringproxy.git
synced 2025-02-25 18:55:29 -06:00
Start implementing custom ssh server
Turns out SSH has robust semantics for opening generic channels. Looks like I'll be able to set up tunnels without ever needing to forward ports on the server, since I can connect the channels with a custom protocol. Of course I'll eventually want to support generic SSH clients, but this makes starting much easier.
This commit is contained in:
@@ -34,6 +34,7 @@ type BoringProxy struct {
|
||||
tunMan *TunnelManager
|
||||
adminListener *AdminListener
|
||||
certConfig *certmagic.Config
|
||||
sshServer *SshServer
|
||||
}
|
||||
|
||||
func NewBoringProxy() *BoringProxy {
|
||||
@@ -67,7 +68,9 @@ func NewBoringProxy() *BoringProxy {
|
||||
|
||||
auth := NewAuth()
|
||||
|
||||
p := &BoringProxy{config, auth, tunMan, adminListener, certConfig}
|
||||
sshServer := NewSshServer()
|
||||
|
||||
p := &BoringProxy{config, auth, tunMan, adminListener, certConfig, sshServer}
|
||||
|
||||
http.HandleFunc("/", p.handleAdminRequest)
|
||||
go http.Serve(adminListener, nil)
|
||||
|
||||
55
client.go
55
client.go
@@ -2,8 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
//"bytes"
|
||||
"net/http"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"io/ioutil"
|
||||
@@ -22,40 +20,45 @@ func (c *BoringProxyClient) Run() {
|
||||
|
||||
//var hostKey ssh.PublicKey
|
||||
|
||||
key, err := ioutil.ReadFile("/home/anders/.ssh/id_rsa_test")
|
||||
if err != nil {
|
||||
log.Fatalf("unable to read private key: %v", err)
|
||||
}
|
||||
|
||||
// Create the Signer for this private key.
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to parse private key: %v", err)
|
||||
}
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
User: "anders",
|
||||
User: "user",
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.PublicKeys(signer),
|
||||
ssh.Password("yolo"),
|
||||
},
|
||||
//HostKeyCallback: ssh.FixedHostKey(hostKey),
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
client, err := ssh.Dial("tcp", "boringproxy.io:22", config)
|
||||
client, err := ssh.Dial("tcp", "boringproxy.io:2022", config)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to dial: ", err)
|
||||
}
|
||||
|
||||
// Request the remote side to open port 8080 on all interfaces.
|
||||
l, err := client.Listen("tcp", "0.0.0.0:9001")
|
||||
if err != nil {
|
||||
log.Fatal("unable to register tcp forward: ", err)
|
||||
}
|
||||
defer l.Close()
|
||||
tunnelRequests := client.HandleChannelOpen("boringproxy-tunnel")
|
||||
|
||||
// Serve HTTP with your SSH server acting as a reverse proxy.
|
||||
http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(resp, "Hi there\n")
|
||||
}))
|
||||
for req := range tunnelRequests {
|
||||
go handleTunnelRequest(req)
|
||||
}
|
||||
}
|
||||
|
||||
func handleTunnelRequest(req ssh.NewChannel) error {
|
||||
|
||||
tun, reqs, err := req.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go ssh.DiscardRequests(reqs)
|
||||
|
||||
port := req.ExtraData()
|
||||
|
||||
fmt.Println(port)
|
||||
|
||||
data, err := ioutil.ReadAll(tun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(data))
|
||||
return nil
|
||||
}
|
||||
|
||||
90
ssh_server.go
Normal file
90
ssh_server.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"io/ioutil"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
|
||||
type SshServer struct {
|
||||
config *ssh.ServerConfig
|
||||
listener net.Listener
|
||||
}
|
||||
|
||||
|
||||
func NewSshServer() *SshServer {
|
||||
config := &ssh.ServerConfig{
|
||||
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
||||
if c.User() == "user" && string(pass) == "yolo" {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("password rejected for %q", c.User())
|
||||
},
|
||||
}
|
||||
|
||||
privateBytes, err := ioutil.ReadFile("id_rsa_boringproxy")
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load private key: ", err)
|
||||
}
|
||||
|
||||
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to parse private key: ", err)
|
||||
}
|
||||
|
||||
config.AddHostKey(private)
|
||||
|
||||
listener, err := net.Listen("tcp", "0.0.0.0:2022")
|
||||
if err != nil {
|
||||
log.Fatal("failed to listen for connection: ", err)
|
||||
}
|
||||
|
||||
server := &SshServer{config, listener}
|
||||
|
||||
go server.acceptAll()
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func (s *SshServer) acceptAll() {
|
||||
for {
|
||||
nConn, err := s.listener.Accept()
|
||||
if err != nil {
|
||||
log.Print("failed to accept incoming connection: ", err)
|
||||
continue
|
||||
}
|
||||
|
||||
go s.handleServerConn(nConn)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SshServer) handleServerConn(nConn net.Conn) {
|
||||
|
||||
conn, chans, reqs, err := ssh.NewServerConn(nConn, s.config)
|
||||
if err != nil {
|
||||
log.Print("failed to handshake: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
go ssh.DiscardRequests(reqs)
|
||||
|
||||
go func() {
|
||||
for newChannel := range chans {
|
||||
newChannel.Reject(ssh.ResourceShortage, "too bad")
|
||||
}
|
||||
}()
|
||||
|
||||
ch, cReqs, err := conn.OpenChannel("boringproxy-tunnel", []byte{25, 25})
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
go ssh.DiscardRequests(cReqs)
|
||||
|
||||
ch.Write([]byte("Hi there"))
|
||||
ch.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user