mirror of
https://github.com/boringproxy/boringproxy.git
synced 2025-02-25 18:55:29 -06:00
Run go fmt
This commit is contained in:
parent
be91ff62ef
commit
c285f0990f
114
api.go
114
api.go
@ -1,59 +1,57 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"fmt"
|
//"fmt"
|
||||||
//"strings"
|
//"strings"
|
||||||
"net/http"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"encoding/json"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Api struct {
|
type Api struct {
|
||||||
config *BoringProxyConfig
|
config *BoringProxyConfig
|
||||||
auth *Auth
|
auth *Auth
|
||||||
tunMan *TunnelManager
|
tunMan *TunnelManager
|
||||||
mux *http.ServeMux
|
mux *http.ServeMux
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTunnelResponse struct {
|
type CreateTunnelResponse struct {
|
||||||
ServerAddress string `json:"server_address"`
|
ServerAddress string `json:"server_address"`
|
||||||
ServerPort int `json:"server_port"`
|
ServerPort int `json:"server_port"`
|
||||||
ServerPublicKey string `json:"server_public_key"`
|
ServerPublicKey string `json:"server_public_key"`
|
||||||
TunnelPort int `json:"tunnel_port"`
|
TunnelPort int `json:"tunnel_port"`
|
||||||
TunnelPrivateKey string `json:"tunnel_private_key"`
|
TunnelPrivateKey string `json:"tunnel_private_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewApi(config *BoringProxyConfig, auth *Auth, tunMan *TunnelManager) *Api {
|
func NewApi(config *BoringProxyConfig, auth *Auth, tunMan *TunnelManager) *Api {
|
||||||
|
|
||||||
api := &Api{config, auth, tunMan, nil}
|
api := &Api{config, auth, tunMan, nil}
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
mux.Handle("/tunnels", http.StripPrefix("/tunnels", http.HandlerFunc(api.handleTunnels)))
|
mux.Handle("/tunnels", http.StripPrefix("/tunnels", http.HandlerFunc(api.handleTunnels)))
|
||||||
|
|
||||||
api.mux = mux
|
api.mux = mux
|
||||||
|
|
||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (a *Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (a *Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
a.mux.ServeHTTP(w, r)
|
a.mux.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) handleTunnels(w http.ResponseWriter, r *http.Request) {
|
func (a *Api) handleTunnels(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case "POST":
|
case "POST":
|
||||||
a.validateSession(http.HandlerFunc(a.handleCreateTunnel)).ServeHTTP(w, r)
|
a.validateSession(http.HandlerFunc(a.handleCreateTunnel)).ServeHTTP(w, r)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(405)
|
w.WriteHeader(405)
|
||||||
w.Write([]byte("Invalid method for /tunnels"))
|
w.Write([]byte("Invalid method for /tunnels"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
func (a *Api) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
|
|
||||||
if len(query["domain"]) != 1 {
|
if len(query["domain"]) != 1 {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
@ -62,47 +60,47 @@ func (a *Api) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
domain := query["domain"][0]
|
domain := query["domain"][0]
|
||||||
|
|
||||||
port, privKey, err := a.tunMan.CreateTunnel(domain)
|
port, privKey, err := a.tunMan.CreateTunnel(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
io.WriteString(w, err.Error())
|
io.WriteString(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := &CreateTunnelResponse{
|
response := &CreateTunnelResponse{
|
||||||
ServerAddress: a.config.AdminDomain,
|
ServerAddress: a.config.AdminDomain,
|
||||||
ServerPort: 22,
|
ServerPort: 22,
|
||||||
ServerPublicKey: "",
|
ServerPublicKey: "",
|
||||||
TunnelPort: port,
|
TunnelPort: port,
|
||||||
TunnelPrivateKey: privKey,
|
TunnelPrivateKey: privKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
responseJson, err := json.MarshalIndent(response, "", " ")
|
responseJson, err := json.MarshalIndent(response, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
io.WriteString(w, "Error encoding response")
|
io.WriteString(w, "Error encoding response")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(responseJson)
|
w.Write(responseJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) validateSession(h http.Handler) http.Handler {
|
func (a *Api) validateSession(h http.Handler) http.Handler {
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
token, err := extractToken("access_token", r)
|
token, err := extractToken("access_token", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
w.Write([]byte("No token provided"))
|
w.Write([]byte("No token provided"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !a.auth.Authorized(token) {
|
if !a.auth.Authorized(token) {
|
||||||
w.WriteHeader(403)
|
w.WriteHeader(403)
|
||||||
w.Write([]byte("Not authorized"))
|
w.Write([]byte("Not authorized"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
16
auth.go
16
auth.go
@ -20,7 +20,7 @@ type Auth struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LoginRequest struct {
|
type LoginRequest struct {
|
||||||
Email string
|
Email string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
@ -109,16 +109,16 @@ func (a *Auth) Verify(key string) (string, error) {
|
|||||||
|
|
||||||
delete(a.pendingRequests, key)
|
delete(a.pendingRequests, key)
|
||||||
|
|
||||||
token, err := genRandomKey()
|
token, err := genRandomKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("Error generating key")
|
return "", errors.New("Error generating key")
|
||||||
}
|
}
|
||||||
|
|
||||||
a.sessions[token] = &Session{Id: request.Email}
|
a.sessions[token] = &Session{Id: request.Email}
|
||||||
|
|
||||||
saveJson(a.sessions, "sessions.json")
|
saveJson(a.sessions, "sessions.json")
|
||||||
|
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const chars string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
const chars string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
139
boringproxy.go
139
boringproxy.go
@ -4,16 +4,16 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/GeertJohan/go.rice"
|
||||||
|
"github.com/caddyserver/certmagic"
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"html/template"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"github.com/caddyserver/certmagic"
|
|
||||||
"github.com/GeertJohan/go.rice"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BoringProxyConfig struct {
|
type BoringProxyConfig struct {
|
||||||
@ -70,10 +70,10 @@ func NewBoringProxy() *BoringProxy {
|
|||||||
p := &BoringProxy{config, auth, tunMan, adminListener, certConfig}
|
p := &BoringProxy{config, auth, tunMan, adminListener, certConfig}
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
p.handleAdminRequest(w, r)
|
p.handleAdminRequest(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
api := NewApi(config, auth, tunMan)
|
api := NewApi(config, auth, tunMan)
|
||||||
http.Handle("/api/", http.StripPrefix("/api", api))
|
http.Handle("/api/", http.StripPrefix("/api", api))
|
||||||
|
|
||||||
go http.Serve(adminListener, nil)
|
go http.Serve(adminListener, nil)
|
||||||
@ -106,26 +106,26 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
|
|||||||
case "/login":
|
case "/login":
|
||||||
p.handleLogin(w, r)
|
p.handleLogin(w, r)
|
||||||
case "/":
|
case "/":
|
||||||
box, err := rice.FindBox("webui")
|
box, err := rice.FindBox("webui")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
io.WriteString(w, "Error opening webui")
|
io.WriteString(w, "Error opening webui")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := extractToken("access_token", r)
|
token, err := extractToken("access_token", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
loginTemplate, err := box.String("login.tmpl")
|
loginTemplate, err := box.String("login.tmpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
io.WriteString(w, "Error reading login.tmpl")
|
io.WriteString(w, "Error reading login.tmpl")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
io.WriteString(w, loginTemplate)
|
io.WriteString(w, loginTemplate)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,26 +135,24 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indexTemplate, err := box.String("index.tmpl")
|
||||||
indexTemplate, err := box.String("index.tmpl")
|
if err != nil {
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
io.WriteString(w, "Error reading index.tmpl")
|
io.WriteString(w, "Error reading index.tmpl")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.New("test").Parse(indexTemplate)
|
tmpl, err := template.New("test").Parse(indexTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
io.WriteString(w, "Error compiling index.tmpl")
|
io.WriteString(w, "Error compiling index.tmpl")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmpl.Execute(w, p.tunMan.tunnels)
|
||||||
|
|
||||||
tmpl.Execute(w, p.tunMan.tunnels)
|
//io.WriteString(w, indexTemplate)
|
||||||
|
|
||||||
//io.WriteString(w, indexTemplate)
|
|
||||||
|
|
||||||
case "/tunnels":
|
case "/tunnels":
|
||||||
|
|
||||||
@ -174,7 +172,7 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
|
|||||||
p.handleTunnels(w, r)
|
p.handleTunnels(w, r)
|
||||||
|
|
||||||
case "/delete-tunnel":
|
case "/delete-tunnel":
|
||||||
token, err := extractToken("access_token", r)
|
token, err := extractToken("access_token", r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
w.Write([]byte("No token provided"))
|
w.Write([]byte("No token provided"))
|
||||||
@ -187,7 +185,7 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
|
|
||||||
if len(r.Form["host"]) != 1 {
|
if len(r.Form["host"]) != 1 {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
@ -198,7 +196,7 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
|
|||||||
|
|
||||||
p.tunMan.DeleteTunnel(host)
|
p.tunMan.DeleteTunnel(host)
|
||||||
|
|
||||||
http.Redirect(w, r, "/", 307)
|
http.Redirect(w, r, "/", 307)
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
w.Write([]byte("Invalid endpoint"))
|
w.Write([]byte("Invalid endpoint"))
|
||||||
@ -234,49 +232,48 @@ func (p *BoringProxy) handleTunnels(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (p *BoringProxy) handleLogin(w http.ResponseWriter, r *http.Request) {
|
func (p *BoringProxy) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case "GET":
|
case "GET":
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
key, exists := query["key"]
|
key, exists := query["key"]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
fmt.Fprintf(w, "Must provide key for verification")
|
fmt.Fprintf(w, "Must provide key for verification")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := p.auth.Verify(key[0])
|
token, err := p.auth.Verify(key[0])
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
fmt.Fprintf(w, "Invalid key")
|
fmt.Fprintf(w, "Invalid key")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie := &http.Cookie{Name: "access_token", Value: token, Secure: true, HttpOnly: true}
|
cookie := &http.Cookie{Name: "access_token", Value: token, Secure: true, HttpOnly: true}
|
||||||
http.SetCookie(w, cookie)
|
http.SetCookie(w, cookie)
|
||||||
|
|
||||||
http.Redirect(w, r, "/", 307)
|
http.Redirect(w, r, "/", 307)
|
||||||
|
|
||||||
|
case "POST":
|
||||||
|
|
||||||
case "POST":
|
r.ParseForm()
|
||||||
|
|
||||||
r.ParseForm()
|
toEmail, ok := r.Form["email"]
|
||||||
|
|
||||||
toEmail, ok := r.Form["email"]
|
if !ok {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
w.Write([]byte("Email required for login"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !ok {
|
// run in goroutine because it can take some time to send the
|
||||||
w.WriteHeader(400)
|
// email
|
||||||
w.Write([]byte("Email required for login"))
|
go p.auth.Login(toEmail[0], p.config)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// run in goroutine because it can take some time to send the
|
io.WriteString(w, "Check your email to finish logging in")
|
||||||
// email
|
default:
|
||||||
go p.auth.Login(toEmail[0], p.config)
|
|
||||||
|
|
||||||
io.WriteString(w, "Check your email to finish logging in")
|
|
||||||
default:
|
|
||||||
w.WriteHeader(405)
|
w.WriteHeader(405)
|
||||||
w.Write([]byte("Invalid method for login"))
|
w.Write([]byte("Invalid method for login"))
|
||||||
}
|
}
|
||||||
@ -284,7 +281,7 @@ func (p *BoringProxy) handleLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (p *BoringProxy) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
func (p *BoringProxy) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
|
|
||||||
if len(r.Form["host"]) != 1 {
|
if len(r.Form["host"]) != 1 {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
@ -307,13 +304,13 @@ func (p *BoringProxy) handleCreateTunnel(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = p.tunMan.SetTunnel(host, port)
|
err = p.tunMan.SetTunnel(host, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
io.WriteString(w, "Failed to get cert. Ensure your domain is valid")
|
io.WriteString(w, "Failed to get cert. Ensure your domain is valid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/", 303)
|
http.Redirect(w, r, "/", 303)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BoringProxy) handleConnection(clientConn net.Conn) {
|
func (p *BoringProxy) handleConnection(clientConn net.Conn) {
|
||||||
|
55
client.go
55
client.go
@ -1,64 +1,63 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"fmt"
|
||||||
"fmt"
|
"golang.org/x/crypto/ssh"
|
||||||
"golang.org/x/crypto/ssh"
|
"io/ioutil"
|
||||||
"io/ioutil"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type BoringProxyClient struct {
|
type BoringProxyClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBoringProxyClient() *BoringProxyClient {
|
func NewBoringProxyClient() *BoringProxyClient {
|
||||||
return &BoringProxyClient{}
|
return &BoringProxyClient{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *BoringProxyClient) Run() {
|
func (c *BoringProxyClient) Run() {
|
||||||
log.Println("Run client")
|
log.Println("Run client")
|
||||||
|
|
||||||
//var hostKey ssh.PublicKey
|
//var hostKey ssh.PublicKey
|
||||||
|
|
||||||
config := &ssh.ClientConfig{
|
config := &ssh.ClientConfig{
|
||||||
User: "user",
|
User: "user",
|
||||||
Auth: []ssh.AuthMethod{
|
Auth: []ssh.AuthMethod{
|
||||||
ssh.Password("yolo"),
|
ssh.Password("yolo"),
|
||||||
},
|
},
|
||||||
//HostKeyCallback: ssh.FixedHostKey(hostKey),
|
//HostKeyCallback: ssh.FixedHostKey(hostKey),
|
||||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := ssh.Dial("tcp", "boringproxy.io:2022", config)
|
client, err := ssh.Dial("tcp", "boringproxy.io:2022", config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to dial: ", err)
|
log.Fatal("Failed to dial: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnelRequests := client.HandleChannelOpen("boringproxy-tunnel")
|
tunnelRequests := client.HandleChannelOpen("boringproxy-tunnel")
|
||||||
|
|
||||||
for req := range tunnelRequests {
|
for req := range tunnelRequests {
|
||||||
go handleTunnelRequest(req)
|
go handleTunnelRequest(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleTunnelRequest(req ssh.NewChannel) error {
|
func handleTunnelRequest(req ssh.NewChannel) error {
|
||||||
|
|
||||||
tun, reqs, err := req.Accept()
|
tun, reqs, err := req.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go ssh.DiscardRequests(reqs)
|
go ssh.DiscardRequests(reqs)
|
||||||
|
|
||||||
port := req.ExtraData()
|
port := req.ExtraData()
|
||||||
|
|
||||||
fmt.Println(port)
|
fmt.Println(port)
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(tun)
|
data, err := ioutil.ReadAll(tun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(data))
|
fmt.Println(string(data))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
38
main.go
38
main.go
@ -1,31 +1,31 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
fmt.Println("Invalid arguments")
|
fmt.Println("Invalid arguments")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
command := os.Args[1]
|
command := os.Args[1]
|
||||||
|
|
||||||
switch command {
|
switch command {
|
||||||
case "server":
|
case "server":
|
||||||
log.Println("Starting up")
|
log.Println("Starting up")
|
||||||
proxy := NewBoringProxy()
|
proxy := NewBoringProxy()
|
||||||
proxy.Run()
|
proxy.Run()
|
||||||
|
|
||||||
case "client":
|
case "client":
|
||||||
client := NewBoringProxyClient()
|
client := NewBoringProxyClient()
|
||||||
client.Run()
|
client.Run()
|
||||||
default:
|
default:
|
||||||
fmt.Println("Invalid command " + command)
|
fmt.Println("Invalid command " + command)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"golang.org/x/crypto/ssh"
|
||||||
"net"
|
"io/ioutil"
|
||||||
"io/ioutil"
|
"log"
|
||||||
"golang.org/x/crypto/ssh"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type SshServer struct {
|
type SshServer struct {
|
||||||
config *ssh.ServerConfig
|
config *ssh.ServerConfig
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewSshServer() *SshServer {
|
func NewSshServer() *SshServer {
|
||||||
config := &ssh.ServerConfig{}
|
config := &ssh.ServerConfig{}
|
||||||
|
|
||||||
privateBytes, err := ioutil.ReadFile("id_rsa_boringproxy")
|
privateBytes, err := ioutil.ReadFile("id_rsa_boringproxy")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to load private key: ", err)
|
log.Fatal("Failed to load private key: ", err)
|
||||||
}
|
}
|
||||||
@ -30,66 +28,66 @@ func NewSshServer() *SshServer {
|
|||||||
|
|
||||||
config.AddHostKey(private)
|
config.AddHostKey(private)
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", "0.0.0.0:2022")
|
listener, err := net.Listen("tcp", "0.0.0.0:2022")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("failed to listen for connection: ", err)
|
log.Fatal("failed to listen for connection: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
server := &SshServer{config, listener}
|
server := &SshServer{config, listener}
|
||||||
|
|
||||||
go server.acceptAll()
|
go server.acceptAll()
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SshServer) acceptAll() {
|
func (s *SshServer) acceptAll() {
|
||||||
for {
|
for {
|
||||||
nConn, err := s.listener.Accept()
|
nConn, err := s.listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("failed to accept incoming connection: ", err)
|
log.Print("failed to accept incoming connection: ", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
go s.handleServerConn(nConn)
|
go s.handleServerConn(nConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SshServer) handleServerConn(nConn net.Conn) {
|
func (s *SshServer) handleServerConn(nConn net.Conn) {
|
||||||
|
|
||||||
var password string
|
var password string
|
||||||
|
|
||||||
s.config.PasswordCallback = func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
s.config.PasswordCallback = func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
||||||
password = string(pass)
|
password = string(pass)
|
||||||
if c.User() == "user" && string(pass) == "yolo" {
|
if c.User() == "user" && string(pass) == "yolo" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("password rejected for %q", c.User())
|
return nil, fmt.Errorf("password rejected for %q", c.User())
|
||||||
}
|
|
||||||
|
|
||||||
conn, chans, reqs, err := ssh.NewServerConn(nConn, s.config)
|
|
||||||
if err != nil {
|
|
||||||
log.Print("failed to handshake: ", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(password)
|
conn, chans, reqs, err := ssh.NewServerConn(nConn, s.config)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("failed to handshake: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(password)
|
||||||
|
|
||||||
go ssh.DiscardRequests(reqs)
|
go ssh.DiscardRequests(reqs)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for newChannel := range chans {
|
for newChannel := range chans {
|
||||||
newChannel.Reject(ssh.ResourceShortage, "too bad")
|
newChannel.Reject(ssh.ResourceShortage, "too bad")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ch, cReqs, err := conn.OpenChannel("boringproxy-tunnel", []byte{25, 25})
|
ch, cReqs, err := conn.OpenChannel("boringproxy-tunnel", []byte{25, 25})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go ssh.DiscardRequests(cReqs)
|
go ssh.DiscardRequests(cReqs)
|
||||||
|
|
||||||
ch.Write([]byte("Hi there"))
|
ch.Write([]byte("Hi there"))
|
||||||
ch.Close()
|
ch.Close()
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"crypto/rand"
|
||||||
"strings"
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/caddyserver/certmagic"
|
"github.com/caddyserver/certmagic"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/pem"
|
|
||||||
"crypto/x509"
|
|
||||||
"golang.org/x/crypto/ssh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tunnel struct {
|
type Tunnel struct {
|
||||||
@ -27,7 +27,7 @@ func NewTunnels() Tunnels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TunnelManager struct {
|
type TunnelManager struct {
|
||||||
nextPort int
|
nextPort int
|
||||||
tunnels Tunnels
|
tunnels Tunnels
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
certConfig *certmagic.Config
|
certConfig *certmagic.Config
|
||||||
@ -57,7 +57,7 @@ func NewTunnelManager(certConfig *certmagic.Config) *TunnelManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPort := 9001
|
nextPort := 9001
|
||||||
|
|
||||||
mutex := &sync.Mutex{}
|
mutex := &sync.Mutex{}
|
||||||
return &TunnelManager{nextPort, tunnels, mutex, certConfig}
|
return &TunnelManager{nextPort, tunnels, mutex, certConfig}
|
||||||
@ -67,7 +67,7 @@ func (m *TunnelManager) SetTunnel(host string, port int) error {
|
|||||||
err := m.certConfig.ManageSync([]string{host})
|
err := m.certConfig.ManageSync([]string{host})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return errors.New("Failed to get cert")
|
return errors.New("Failed to get cert")
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnel := &Tunnel{port}
|
tunnel := &Tunnel{port}
|
||||||
@ -76,36 +76,36 @@ func (m *TunnelManager) SetTunnel(host string, port int) error {
|
|||||||
saveJson(m.tunnels, "tunnels.json")
|
saveJson(m.tunnels, "tunnels.json")
|
||||||
m.mutex.Unlock()
|
m.mutex.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TunnelManager) CreateTunnel(domain string) (int, string, error) {
|
func (m *TunnelManager) CreateTunnel(domain string) (int, string, error) {
|
||||||
err := m.certConfig.ManageSync([]string{domain})
|
err := m.certConfig.ManageSync([]string{domain})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return 0, "", errors.New("Failed to get cert")
|
return 0, "", errors.New("Failed to get cert")
|
||||||
}
|
}
|
||||||
|
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
_, exists := m.tunnels[domain]
|
_, exists := m.tunnels[domain]
|
||||||
if exists {
|
if exists {
|
||||||
return 0, "", errors.New("Tunnel exists for domain " + domain)
|
return 0, "", errors.New("Tunnel exists for domain " + domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
port := m.nextPort
|
port := m.nextPort
|
||||||
m.nextPort += 1
|
m.nextPort += 1
|
||||||
tunnel := &Tunnel{port}
|
tunnel := &Tunnel{port}
|
||||||
m.tunnels[domain] = tunnel
|
m.tunnels[domain] = tunnel
|
||||||
saveJson(m.tunnels, "tunnels.json")
|
saveJson(m.tunnels, "tunnels.json")
|
||||||
|
|
||||||
privKey, err := m.addToAuthorizedKeys(port)
|
privKey, err := m.addToAuthorizedKeys(port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, "", err
|
return 0, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return port, privKey, nil
|
return port, privKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TunnelManager) DeleteTunnel(host string) {
|
func (m *TunnelManager) DeleteTunnel(host string) {
|
||||||
@ -129,29 +129,29 @@ func (m *TunnelManager) GetPort(serverName string) (int, error) {
|
|||||||
|
|
||||||
func (m *TunnelManager) addToAuthorizedKeys(port int) (string, error) {
|
func (m *TunnelManager) addToAuthorizedKeys(port int) (string, error) {
|
||||||
|
|
||||||
akBytes, err := ioutil.ReadFile("/home/anders/.ssh/authorized_keys")
|
akBytes, err := ioutil.ReadFile("/home/anders/.ssh/authorized_keys")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
akStr := string(akBytes)
|
akStr := string(akBytes)
|
||||||
|
|
||||||
pubKey, privKey, err := MakeSSHKeyPair()
|
pubKey, privKey, err := MakeSSHKeyPair()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
options := fmt.Sprintf(`command="echo This key permits tunnels only",permitopen="fakehost:1",permitlisten="localhost:%d"`, port)
|
options := fmt.Sprintf(`command="echo This key permits tunnels only",permitopen="fakehost:1",permitlisten="localhost:%d"`, port)
|
||||||
|
|
||||||
pubKeyNoNewline := pubKey[:len(pubKey) - 1]
|
pubKeyNoNewline := pubKey[:len(pubKey)-1]
|
||||||
newAk := fmt.Sprintf("%s%s %s %s%d\n", akStr, options, pubKeyNoNewline, "boringproxy-", port)
|
newAk := fmt.Sprintf("%s%s %s %s%d\n", akStr, options, pubKeyNoNewline, "boringproxy-", port)
|
||||||
|
|
||||||
err = ioutil.WriteFile("/home/anders/.ssh/authorized_keys", []byte(newAk), 0600)
|
err = ioutil.WriteFile("/home/anders/.ssh/authorized_keys", []byte(newAk), 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return privKey, nil
|
return privKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adapted from https://stackoverflow.com/a/34347463/943814
|
// Adapted from https://stackoverflow.com/a/34347463/943814
|
||||||
@ -159,27 +159,27 @@ func (m *TunnelManager) addToAuthorizedKeys(port int) (string, error) {
|
|||||||
// Public key is encoded in the format for inclusion in an OpenSSH authorized_keys file.
|
// Public key is encoded in the format for inclusion in an OpenSSH authorized_keys file.
|
||||||
// Private Key generated is PEM encoded
|
// Private Key generated is PEM encoded
|
||||||
func MakeSSHKeyPair() (string, string, error) {
|
func MakeSSHKeyPair() (string, string, error) {
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
|
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate and write private key as PEM
|
// generate and write private key as PEM
|
||||||
var privKeyBuf strings.Builder
|
var privKeyBuf strings.Builder
|
||||||
|
|
||||||
privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
|
privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
|
||||||
if err := pem.Encode(&privKeyBuf, privateKeyPEM); err != nil {
|
if err := pem.Encode(&privKeyBuf, privateKeyPEM); err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate and write public key
|
// generate and write public key
|
||||||
pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
|
pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pubKeyBuf strings.Builder
|
var pubKeyBuf strings.Builder
|
||||||
pubKeyBuf.Write(ssh.MarshalAuthorizedKey(pub))
|
pubKeyBuf.Write(ssh.MarshalAuthorizedKey(pub))
|
||||||
|
|
||||||
return pubKeyBuf.String(), privKeyBuf.String(), nil
|
return pubKeyBuf.String(), privKeyBuf.String(), nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user