added support for different port w/ different domains on same service
This commit is contained in:
parent
b44fe740af
commit
c1c18b71b0
|
@ -24,8 +24,17 @@ func main() {
|
||||||
defer quit()
|
defer quit()
|
||||||
|
|
||||||
config := client.Config{
|
config := client.Config{
|
||||||
Server: "wss://localhost.daplie.me:9999",
|
Server: "wss://localhost.daplie.me:9999",
|
||||||
Services: map[string]int{"https": 8443},
|
Services: map[string]map[string]int{
|
||||||
|
"https": map[string]int{
|
||||||
|
"*": 8443,
|
||||||
|
"localhost.foo.daplie.me": 4443,
|
||||||
|
},
|
||||||
|
"http": map[string]int{
|
||||||
|
"*": 8443,
|
||||||
|
"localhost.foo.daplie.me": 4443,
|
||||||
|
},
|
||||||
|
},
|
||||||
Token: tokenStr,
|
Token: tokenStr,
|
||||||
Insecure: true,
|
Insecure: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,19 @@ import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The Config struct holds all of the information needed to establish and handle a connection
|
||||||
|
// with the RVPN server.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Server string
|
Server string
|
||||||
Token string
|
Token string
|
||||||
Services map[string]int
|
|
||||||
Insecure bool
|
Insecure bool
|
||||||
|
Services map[string]map[string]int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run establishes a connection with the RVPN server specified in the config. If the first attempt
|
||||||
|
// to connect fails it is assumed that something is wrong with the authentication and it will
|
||||||
|
// return an error. Otherwise it will continuously attempt to reconnect whenever the connection
|
||||||
|
// is broken.
|
||||||
func Run(ctx context.Context, config *Config) error {
|
func Run(ctx context.Context, config *Config) error {
|
||||||
serverURL, err := url.Parse(config.Server)
|
serverURL, err := url.Parse(config.Server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,11 +42,17 @@ func Run(ctx context.Context, config *Config) error {
|
||||||
dialer.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
dialer.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name, portList := range config.Services {
|
||||||
|
if _, ok := portList["*"]; !ok {
|
||||||
|
return fmt.Errorf(`service %s missing port for "*"`, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
handler := NewWsHandler(config.Services)
|
handler := NewWsHandler(config.Services)
|
||||||
|
|
||||||
authenticated := false
|
authenticated := false
|
||||||
for {
|
for {
|
||||||
if conn, _, err := dialer.Dial(serverURL.String(), nil); err == nil {
|
if conn, _, err := dialer.Dial(serverURL.String(), nil); err == nil {
|
||||||
|
loginfo.Println("connected to remote server")
|
||||||
authenticated = true
|
authenticated = true
|
||||||
handler.HandleConn(ctx, conn)
|
handler.HandleConn(ctx, conn)
|
||||||
} else if !authenticated {
|
} else if !authenticated {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -12,15 +13,18 @@ import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/packer"
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/packer"
|
||||||
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/sni"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var hostRegexp = regexp.MustCompile(`(?im)(?:^|[\r\n])Host: *([^\r\n]+)[\r\n]`)
|
||||||
|
|
||||||
// WsHandler handles all of reading and writing for the websocket connection to the RVPN server
|
// WsHandler handles all of reading and writing for the websocket connection to the RVPN server
|
||||||
// and the TCP connections to the local servers.
|
// and the TCP connections to the local servers.
|
||||||
type WsHandler struct {
|
type WsHandler struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
localConns map[string]net.Conn
|
localConns map[string]net.Conn
|
||||||
|
|
||||||
servicePorts map[string]int
|
servicePorts map[string]map[string]int
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
dataChan chan *packer.Packer
|
dataChan chan *packer.Packer
|
||||||
|
@ -28,7 +32,7 @@ type WsHandler struct {
|
||||||
|
|
||||||
// NewWsHandler creates a new handler ready to be given a websocket connection. The services
|
// NewWsHandler creates a new handler ready to be given a websocket connection. The services
|
||||||
// argument specifies what port each service type should be directed to on the local interface.
|
// argument specifies what port each service type should be directed to on the local interface.
|
||||||
func NewWsHandler(services map[string]int) *WsHandler {
|
func NewWsHandler(services map[string]map[string]int) *WsHandler {
|
||||||
h := new(WsHandler)
|
h := new(WsHandler)
|
||||||
h.servicePorts = services
|
h.servicePorts = services
|
||||||
h.localConns = make(map[string]net.Conn)
|
h.localConns = make(map[string]net.Conn)
|
||||||
|
@ -127,9 +131,35 @@ func (h *WsHandler) getLocalConn(p *packer.Packer) net.Conn {
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
|
|
||||||
port := h.servicePorts[p.Service()]
|
service := strings.ToLower(p.Service())
|
||||||
|
portList := h.servicePorts[service]
|
||||||
|
if portList == nil {
|
||||||
|
loginfo.Println("cannot open connection for invalid service", service)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var hostname string
|
||||||
|
if service == "http" {
|
||||||
|
if match := hostRegexp.FindSubmatch(p.Data.Data()); match != nil {
|
||||||
|
hostname = strings.Split(string(match[1]), ":")[0]
|
||||||
|
}
|
||||||
|
} else if service == "https" {
|
||||||
|
hostname, _ = sni.GetHostname(p.Data.Data())
|
||||||
|
} else {
|
||||||
|
hostname = "*"
|
||||||
|
}
|
||||||
|
if hostname == "" {
|
||||||
|
loginfo.Println("missing servername for", service, key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
hostname = strings.ToLower(hostname)
|
||||||
|
|
||||||
|
port := portList[hostname]
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
loginfo.Println("cannot open connection for invalid service", p.Service())
|
port = portList["*"]
|
||||||
|
}
|
||||||
|
if port == 0 {
|
||||||
|
loginfo.Println("unable to determine local port for", service, hostname)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,8 +169,8 @@ func (h *WsHandler) getLocalConn(p *packer.Packer) net.Conn {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
loginfo.Println("opened new connection to port", port, "for", key)
|
|
||||||
h.localConns[key] = conn
|
h.localConns[key] = conn
|
||||||
|
loginfo.Printf("new client %q for %s:%d (%d clients)\n", key, hostname, port, len(h.localConns))
|
||||||
go h.readLocal(key, &p.Header)
|
go h.readLocal(key, &p.Header)
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
|
@ -172,9 +202,9 @@ func (h *WsHandler) readLocal(key string, header *packer.Header) {
|
||||||
defer func() {
|
defer func() {
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
delete(h.localConns, key)
|
delete(h.localConns, key)
|
||||||
|
loginfo.Printf("closing client %q: (%d clients)\n", key, len(h.localConns))
|
||||||
h.lock.Unlock()
|
h.lock.Unlock()
|
||||||
}()
|
}()
|
||||||
defer loginfo.Println("finished with client", key)
|
|
||||||
|
|
||||||
buf := make([]byte, 4096)
|
buf := make([]byte, 4096)
|
||||||
for {
|
for {
|
||||||
|
|
Loading…
Reference in New Issue