mirror of
https://github.com/boringproxy/boringproxy.git
synced 2026-11-01 09:38:01 -06:00
Add ClientAddress
Allows tunnels to specify what address the client with connect to for upstream connections. Also changed the tunnel-adder UI. Also fixed a bug where invalid domains would crash. Needed to properly return an error dialog.
This commit is contained in:
1 parent
ef660f61ae
commit
9882017d5a
8 files changed
+117
-49
No files matched your search
@@ -72,7 +72,20 @@ func (a *Api) CreateTunnel(tokenData TokenData, params url.Values) (*Tunnel, err
|
||||
return nil, errors.New("Invalid client-port parameter")
|
||||
}
|
||||
|
||||
tunnel, err := a.tunMan.CreateTunnelForClient(domain, tokenData.Owner, clientName, clientPort)
|
||||
clientAddr := params.Get("client-addr")
|
||||
if clientAddr == "" {
|
||||
clientAddr = "127.0.0.1"
|
||||
}
|
||||
|
||||
request := Tunnel{
|
||||
Domain: domain,
|
||||
Owner: tokenData.Owner,
|
||||
ClientName: clientName,
|
||||
ClientPort: clientPort,
|
||||
ClientAddress: clientAddr,
|
||||
}
|
||||
|
||||
tunnel, err := a.tunMan.RequestCreateTunnel(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -162,7 +175,12 @@ func (a *Api) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
owner := query["owner"][0]
|
||||
|
||||
tunnel, err := a.tunMan.CreateTunnel(domain, owner)
|
||||
request := Tunnel{
|
||||
Domain: domain,
|
||||
Owner: owner,
|
||||
}
|
||||
|
||||
tunnel, err := a.tunMan.RequestCreateTunnel(request)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
io.WriteString(w, err.Error())
|
||||
|
||||
@@ -190,18 +190,18 @@ func (c *BoringProxyClient) BoreTunnel(tunnel Tunnel) context.CancelFunc {
|
||||
break
|
||||
//continue
|
||||
}
|
||||
go c.handleConnection(conn, tunnel.ClientPort)
|
||||
go c.handleConnection(conn, tunnel.ClientAddress, tunnel.ClientPort)
|
||||
}
|
||||
}()
|
||||
|
||||
return cancelFunc
|
||||
}
|
||||
|
||||
func (c *BoringProxyClient) handleConnection(conn net.Conn, port int) {
|
||||
func (c *BoringProxyClient) handleConnection(conn net.Conn, addr string, port int) {
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
upstreamConn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
upstreamConn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", addr, port))
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
|
||||
@@ -25,6 +25,7 @@ type User struct {
|
||||
|
||||
type Tunnel struct {
|
||||
Owner string `json:"owner"`
|
||||
Domain string `json:"domain"`
|
||||
ServerAddress string `json:"server_address"`
|
||||
ServerPort int `json:"server_port"`
|
||||
ServerPublicKey string `json:"server_public_key"`
|
||||
@@ -32,6 +33,7 @@ type Tunnel struct {
|
||||
TunnelPort int `json:"tunnel_port"`
|
||||
TunnelPrivateKey string `json:"tunnel_private_key"`
|
||||
ClientName string `json:"client_name"`
|
||||
ClientAddress string `json:"client_address"`
|
||||
ClientPort int `json:"client_port"`
|
||||
CssId string `json:"css_id"`
|
||||
}
|
||||
|
||||
+17
-21
@@ -49,35 +49,27 @@ func (m *TunnelManager) GetTunnels() map[string]Tunnel {
|
||||
return m.db.GetTunnels()
|
||||
}
|
||||
|
||||
func (m *TunnelManager) CreateTunnelForClient(domain, owner, clientName string, clientPort int) (Tunnel, error) {
|
||||
tun, err := m.CreateTunnel(domain, owner)
|
||||
if err != nil {
|
||||
return Tunnel{}, err
|
||||
func (m *TunnelManager) RequestCreateTunnel(tunReq Tunnel) (Tunnel, error) {
|
||||
|
||||
if tunReq.Domain == "" {
|
||||
return Tunnel{}, errors.New("Domain required")
|
||||
}
|
||||
|
||||
tun.ClientName = clientName
|
||||
tun.ClientPort = clientPort
|
||||
if tunReq.Owner == "" {
|
||||
return Tunnel{}, errors.New("Owner required")
|
||||
}
|
||||
|
||||
// TODO: It's a bit hacky that we call db.SetTunnel in CreateTunnel and
|
||||
// then again here
|
||||
m.db.SetTunnel(domain, tun)
|
||||
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func (m *TunnelManager) CreateTunnel(domain, owner string) (Tunnel, error) {
|
||||
err := m.certConfig.ManageSync([]string{domain})
|
||||
err := m.certConfig.ManageSync([]string{tunReq.Domain})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return Tunnel{}, errors.New("Failed to get cert")
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
_, exists := m.db.GetTunnel(domain)
|
||||
_, exists := m.db.GetTunnel(tunReq.Domain)
|
||||
if exists {
|
||||
return Tunnel{}, errors.New("Tunnel exists for domain " + domain)
|
||||
return Tunnel{}, errors.New("Tunnel exists for domain " + tunReq.Domain)
|
||||
}
|
||||
|
||||
port, err := randomPort()
|
||||
@@ -85,22 +77,26 @@ func (m *TunnelManager) CreateTunnel(domain, owner string) (Tunnel, error) {
|
||||
return Tunnel{}, err
|
||||
}
|
||||
|
||||
privKey, err := m.addToAuthorizedKeys(domain, port)
|
||||
privKey, err := m.addToAuthorizedKeys(tunReq.Domain, port)
|
||||
if err != nil {
|
||||
return Tunnel{}, err
|
||||
}
|
||||
|
||||
tunnel := Tunnel{
|
||||
Owner: owner,
|
||||
Owner: tunReq.Owner,
|
||||
Domain: tunReq.Domain,
|
||||
ServerAddress: m.config.WebUiDomain,
|
||||
ServerPort: 22,
|
||||
ServerPublicKey: "",
|
||||
TunnelPort: port,
|
||||
TunnelPrivateKey: privKey,
|
||||
ClientName: tunReq.ClientName,
|
||||
ClientPort: tunReq.ClientPort,
|
||||
ClientAddress: tunReq.ClientAddress,
|
||||
Username: m.user.Username,
|
||||
}
|
||||
|
||||
m.db.SetTunnel(domain, tunnel)
|
||||
m.db.SetTunnel(tunReq.Domain, tunnel)
|
||||
|
||||
return tunnel, nil
|
||||
}
|
||||
|
||||
+25
-12
@@ -21,10 +21,15 @@ type WebUiHandler struct {
|
||||
tunMan *TunnelManager
|
||||
box *rice.Box
|
||||
headHtml template.HTML
|
||||
pendingRequests map[string]chan string
|
||||
pendingRequests map[string]chan ReqResult
|
||||
mutex *sync.Mutex
|
||||
}
|
||||
|
||||
type ReqResult struct {
|
||||
err error
|
||||
redirectUrl string
|
||||
}
|
||||
|
||||
type IndexData struct {
|
||||
Head template.HTML
|
||||
Tunnels map[string]Tunnel
|
||||
@@ -91,7 +96,7 @@ func NewWebUiHandler(config *BoringProxyConfig, db *Database, api *Api, auth *Au
|
||||
api: api,
|
||||
auth: auth,
|
||||
tunMan: tunMan,
|
||||
pendingRequests: make(map[string]chan string),
|
||||
pendingRequests: make(map[string]chan ReqResult),
|
||||
mutex: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
@@ -427,7 +432,7 @@ func (h *WebUiHandler) handleCreateTunnel(w http.ResponseWriter, r *http.Request
|
||||
h.alertDialog(w, r, err.Error(), "/#/tunnels")
|
||||
}
|
||||
|
||||
doneSignal := make(chan string)
|
||||
doneSignal := make(chan ReqResult)
|
||||
h.mutex.Lock()
|
||||
h.pendingRequests[pendingId] = doneSignal
|
||||
h.mutex.Unlock()
|
||||
@@ -437,12 +442,8 @@ func (h *WebUiHandler) handleCreateTunnel(w http.ResponseWriter, r *http.Request
|
||||
r.ParseForm()
|
||||
|
||||
_, err := h.api.CreateTunnel(tokenData, r.Form)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
h.alertDialog(w, r, err.Error(), "/#/tunnels")
|
||||
}
|
||||
|
||||
doneSignal <- "/#/tunnels"
|
||||
doneSignal <- ReqResult{err, "/#/tunnels"}
|
||||
}()
|
||||
|
||||
timeout := make(chan bool, 1)
|
||||
@@ -469,8 +470,14 @@ func (h *WebUiHandler) handleCreateTunnel(w http.ResponseWriter, r *http.Request
|
||||
|
||||
tmpl.Execute(w, data)
|
||||
|
||||
case <-doneSignal:
|
||||
http.Redirect(w, r, "/#/tunnels", 303)
|
||||
case result := <-doneSignal:
|
||||
if result.err != nil {
|
||||
w.WriteHeader(400)
|
||||
h.alertDialog(w, r, result.err.Error(), result.redirectUrl)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, result.redirectUrl, 303)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,9 +661,15 @@ func (h *WebUiHandler) handleLoading(w http.ResponseWriter, r *http.Request) {
|
||||
delete(h.pendingRequests, pendingId)
|
||||
h.mutex.Unlock()
|
||||
|
||||
redirUrl := <-doneSignal
|
||||
result := <-doneSignal
|
||||
|
||||
http.Redirect(w, r, redirUrl, 303)
|
||||
if result.err != nil {
|
||||
w.WriteHeader(400)
|
||||
h.alertDialog(w, r, result.err.Error(), result.redirectUrl)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, result.redirectUrl, 303)
|
||||
}
|
||||
|
||||
func (h *WebUiHandler) loadTemplate(name string) (*template.Template, error) {
|
||||
|
||||
+10
-3
@@ -2,11 +2,18 @@
|
||||
<html>
|
||||
<head>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
.dialog {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<div class='dialog'>
|
||||
<div class='dialog'>
|
||||
<div class='dialog__overlay'>
|
||||
<div class='dialog__content'>
|
||||
<p>
|
||||
{{.Message}}
|
||||
</p>
|
||||
@@ -16,6 +23,6 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+19
-8
@@ -24,7 +24,7 @@
|
||||
<input autocomplete='off' type='checkbox' class='toggle' id='toggle-tunnel-hide-deleted-{{$tunnel.CssId}}'>
|
||||
<div class='list-item'>
|
||||
<div>
|
||||
<a href="https://{{$domain}}">{{$domain}}</a>:{{$tunnel.TunnelPort}} -> {{$tunnel.ClientName}}:{{$tunnel.ClientPort}}
|
||||
<a href="https://{{$domain}}">{{$domain}}</a>:{{$tunnel.TunnelPort}} -> {{$tunnel.ClientName}} -> {{$tunnel.ClientAddress}}:{{$tunnel.ClientPort}}
|
||||
</div>
|
||||
|
||||
<label class='button' for='toggle-tunnel-delete-dialog-{{$tunnel.CssId}}'>
|
||||
@@ -54,14 +54,25 @@
|
||||
</div>
|
||||
|
||||
<div class='tunnel-adder'>
|
||||
<h1>Add Tunnel</h1>
|
||||
<form action="/tunnels" method="POST">
|
||||
<label for="domain">Domain:</label>
|
||||
<input type="text" id="domain" name="domain" required>
|
||||
<label for="client-name">Client Name:</label>
|
||||
<input type="text" id="client-name" name="client-name" required>
|
||||
<label for="client-port">Client Port:</label>
|
||||
<input type="text" id="client-port" name="client-port" required>
|
||||
<button class='button' type="submit">Add/Update Tunnel</button>
|
||||
<div class='input'>
|
||||
<label for="domain">Domain:</label>
|
||||
<input type="text" id="domain" name="domain" required>
|
||||
</div>
|
||||
<div class='input'>
|
||||
<label for="client-name">Client Name:</label>
|
||||
<input type="text" id="client-name" name="client-name" required>
|
||||
</div>
|
||||
<div class='input'>
|
||||
<label for="client-addr">Client Address:</label>
|
||||
<input type="text" id="client-addr" name="client-addr" value='127.0.0.1' required>
|
||||
</div>
|
||||
<div class='input'>
|
||||
<label for="client-port">Client Port:</label>
|
||||
<input type="text" id="client-port" name="client-port" required>
|
||||
</div>
|
||||
<button class='button' type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -140,7 +140,28 @@ main {
|
||||
|
||||
.tunnel-adder {
|
||||
padding: 5px;
|
||||
}
|
||||
.tunnel-adder h1 {
|
||||
margin: .2em;
|
||||
}
|
||||
|
||||
.tunnel-adder form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: .7em;
|
||||
margin: .2em;
|
||||
border: 1px solid var(--main-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.input label {
|
||||
padding: .2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token-adder {
|
||||
|
||||
Reference in new issue
Block a user