heavier refactoring
This commit is contained in:
parent
09d296df2a
commit
e740d2ca0f
|
@ -1,3 +1,5 @@
|
|||
.env
|
||||
.env.*
|
||||
certs
|
||||
*.exe
|
||||
/telebitd
|
||||
|
|
|
@ -32,7 +32,12 @@ tmp $ serve-https -p 8080 -d /tmp --servername hfc.rootprojects.org --agree-tos
|
|||
### Start Tunnel Client
|
||||
|
||||
```bash
|
||||
node-tunnel-client $ bin/stunnel.js --locals http://hfc.rootprojects.org:8080,http://test1.hfc.rootprojects.org:8080 --stunneld wss://localhost.rootprojects.org:8443 --secret abc123
|
||||
# For .env
|
||||
TELEBIT_SECRET=abcdef1234567890
|
||||
```
|
||||
|
||||
```bash
|
||||
node-tunnel-client $ bin/stunnel.js --locals http://hfc.rootprojects.org:8080,http://test1.hfc.rootprojects.org:8080 --stunneld wss://localhost.rootprojects.org:8443 --secret abcdef1234567890
|
||||
```
|
||||
|
||||
### Execute RVPN
|
||||
|
|
|
@ -8,46 +8,49 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
telebit "git.coolaj86.com/coolaj86/go-telebitd"
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/relay"
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/server"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
"github.com/spf13/viper"
|
||||
lumberjack "gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
telebit "git.coolaj86.com/coolaj86/go-telebitd"
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/server"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
)
|
||||
|
||||
var (
|
||||
logfile = "stdout"
|
||||
configPath = "./"
|
||||
configFile = "go-rvpn-server"
|
||||
configFile = "telebit-relay"
|
||||
|
||||
loginfo *log.Logger
|
||||
logdebug *log.Logger
|
||||
logFlags = log.Ldate | log.Lmicroseconds | log.Lshortfile
|
||||
argWssClientListener string
|
||||
argGenericBinding int
|
||||
tcpPort int
|
||||
argServerBinding string
|
||||
argServerAdminBinding string
|
||||
argServerExternalBinding string
|
||||
argDeadTime int
|
||||
connectionTable *server.Table
|
||||
secretKey = "abc123"
|
||||
secretKey string
|
||||
wssHostName = "localhost.rootprojects.org"
|
||||
adminHostName = telebit.InvalidAdminDomain
|
||||
idle int
|
||||
dwell int
|
||||
cancelcheck int
|
||||
lbDefaultMethod string
|
||||
serverName string
|
||||
nickname string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&logfile, "log", logfile, "Log file (or stdout/stderr; empty for none)")
|
||||
flag.StringVar(&configPath, "config-path", configPath, "Configuration File Path")
|
||||
flag.StringVar(&configFile, "config-file", configFile, "Configuration File Name")
|
||||
|
||||
flag.StringVar(&secretKey, "secret", "", "a >= 16-character random string for JWT key signing")
|
||||
}
|
||||
|
||||
var logoutput io.Writer
|
||||
|
@ -55,6 +58,15 @@ var logoutput io.Writer
|
|||
//Main -- main entry point
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if "" == secretKey {
|
||||
secretKey = os.Getenv("TELEBIT_SECRET")
|
||||
}
|
||||
if len(secretKey) < 16 {
|
||||
fmt.Fprintf(os.Stderr, "Invalid secret: %q. See --help for details.\n", secretKey)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
switch logfile {
|
||||
case "stdout":
|
||||
logoutput = os.Stdout
|
||||
|
@ -89,54 +101,51 @@ func main() {
|
|||
|
||||
wssHostName = viper.Get("rvpn.wssdomain").(string)
|
||||
adminHostName = viper.Get("rvpn.admindomain").(string)
|
||||
argGenericBinding = viper.GetInt("rvpn.genericlistener")
|
||||
tcpPort = viper.GetInt("rvpn.port")
|
||||
deadtime := viper.Get("rvpn.deadtime").(map[string]interface{})
|
||||
idle = deadtime["idle"].(int)
|
||||
dwell = deadtime["dwell"].(int)
|
||||
cancelcheck = deadtime["cancelcheck"].(int)
|
||||
lbDefaultMethod = viper.Get("rvpn.loadbalancing.defaultmethod").(string)
|
||||
serverName = viper.Get("rvpn.serverName").(string)
|
||||
nickname = viper.Get("rvpn.serverName").(string)
|
||||
|
||||
loginfo.Println("startup")
|
||||
|
||||
certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
||||
if err != nil {
|
||||
loginfo.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancelContext := context.WithCancel(context.Background())
|
||||
defer cancelContext()
|
||||
|
||||
serverStatus := server.NewStatus(ctx)
|
||||
serverStatus.AdminDomain = adminHostName
|
||||
serverStatus.WssDomain = wssHostName
|
||||
serverStatus.Name = serverName
|
||||
serverStatus.StartTime = time.Now()
|
||||
serverStatus.Name = nickname
|
||||
serverStatus.DeadTime = server.NewStatusDeadTime(dwell, idle, cancelcheck)
|
||||
serverStatus.LoadbalanceDefaultMethod = lbDefaultMethod
|
||||
|
||||
// Setup for GenericListenServe.
|
||||
// - establish context for the generic listener
|
||||
// - startup listener
|
||||
// - accept with peek buffer.
|
||||
// - peek at the 1st 30 bytes.
|
||||
// - check for tls
|
||||
// - if tls, establish, protocol peek buffer, else decrypted
|
||||
// - match protocol
|
||||
connectionTable := server.NewTable(dwell, idle, lbDefaultMethod)
|
||||
|
||||
connectionTracking := server.NewTracking()
|
||||
serverStatus.ConnectionTracking = connectionTracking
|
||||
go connectionTracking.Run(ctx)
|
||||
tlsConfig := &tls.Config{
|
||||
GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
// TODO
|
||||
// 1. call out to greenlock for validation
|
||||
// 2. push challenges through http channel
|
||||
// 3. receive certificates (or don't)
|
||||
certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &certbundle, nil
|
||||
},
|
||||
}
|
||||
|
||||
connectionTable = server.NewTable(dwell, idle)
|
||||
serverStatus.ConnectionTable = connectionTable
|
||||
go connectionTable.Run(ctx, lbDefaultMethod)
|
||||
authorizer := func(r *http.Request) (*server.Authz, error) {
|
||||
// do we have a valid wss_client?
|
||||
tokenString := r.URL.Query().Get("access_token")
|
||||
_, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(secretKey), nil
|
||||
})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
genericListeners := server.NewGenerListeners(ctx, secretKey, certbundle, serverStatus)
|
||||
//serverStatus.GenericListeners = genericListeners
|
||||
|
||||
go genericListeners.Run(ctx, argGenericBinding)
|
||||
|
||||
select {}
|
||||
r := relay.New(ctx, tlsConfig, authorizer, serverStatus, connectionTable)
|
||||
r.ListenAndServe(tcpPort)
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gorilla/mux v1.7.4
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.6.3
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -49,6 +49,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
|
|||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package relay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/server"
|
||||
)
|
||||
|
||||
type Relay struct {
|
||||
ctx context.Context
|
||||
status *server.Status
|
||||
mx *server.MPlexy
|
||||
table *server.Table
|
||||
}
|
||||
|
||||
func New(ctx context.Context, tlsConfig *tls.Config, authz server.Authorizer, status *server.Status, table *server.Table) *Relay {
|
||||
return &Relay{
|
||||
ctx: ctx,
|
||||
status: status,
|
||||
table: table,
|
||||
mx: server.New(ctx, tlsConfig, authz, status),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Relay) ListenAndServe(port int) error {
|
||||
|
||||
serverStatus := r.status
|
||||
|
||||
// Setup for GenericListenServe.
|
||||
// - establish context for the generic listener
|
||||
// - startup listener
|
||||
// - accept with peek buffer.
|
||||
// - peek at the 1st 30 bytes.
|
||||
// - check for tls
|
||||
// - if tls, establish, protocol peek buffer, else decrypted
|
||||
// - match protocol
|
||||
|
||||
connectionTracking := server.NewTracking()
|
||||
serverStatus.ConnectionTracking = connectionTracking
|
||||
go connectionTracking.Run(r.ctx)
|
||||
|
||||
serverStatus.ConnectionTable = r.table
|
||||
go serverStatus.ConnectionTable.Run(r.ctx)
|
||||
|
||||
//serverStatus.GenericListeners = genericListeners
|
||||
|
||||
// blocks until it can listen, which it can't until started
|
||||
go r.mx.MultiListenAndServe(port)
|
||||
|
||||
return r.mx.Run()
|
||||
}
|
|
@ -17,7 +17,7 @@ Docker version 17.03.0-ce, build 60ccb22
|
|||
cd $GOPATH/src/git.coolaj86.com/coolaj86
|
||||
git clone git@git.coolaj86.com:coolaj86/go-telebitd.git
|
||||
|
||||
cd go-rvpn-server
|
||||
cd telebit-relay
|
||||
go get
|
||||
|
||||
```
|
||||
|
@ -36,7 +36,7 @@ Step 2/3 : LABEL maintainer "henry.f.camacho@gmail.com"
|
|||
---> Running in 5cdffef8e33d
|
||||
---> f7e09c097612
|
||||
Removing intermediate container 5cdffef8e33d
|
||||
Step 3/3 : WORKDIR "/go-rvpn-server"
|
||||
Step 3/3 : WORKDIR "/telebit-relay"
|
||||
---> 182aa9c814f2
|
||||
Removing intermediate container f136550d6d48
|
||||
Successfully built 182aa9c814f2
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
FROM golang:1.7.5
|
||||
LABEL maintainer "henry.f.camacho@gmail.com"
|
||||
FROM golang:1.14
|
||||
LABEL maintainer "aj@therootcompany.com"
|
||||
|
||||
|
||||
WORKDIR "/go-rvpn-server"
|
||||
WORKDIR "/telebit-relay"
|
||||
|
|
|
@ -21,10 +21,11 @@ type Table struct {
|
|||
domainRevoke chan *DomainMapping
|
||||
dwell int
|
||||
idle int
|
||||
balanceMethod string
|
||||
}
|
||||
|
||||
//NewTable -- consructor
|
||||
func NewTable(dwell, idle int) (p *Table) {
|
||||
func NewTable(dwell, idle int, balanceMethod string) (p *Table) {
|
||||
p = new(Table)
|
||||
p.connections = make(map[*Connection][]string)
|
||||
p.domains = make(map[string]*DomainLoadBalance)
|
||||
|
@ -34,6 +35,7 @@ func NewTable(dwell, idle int) (p *Table) {
|
|||
p.domainRevoke = make(chan *DomainMapping)
|
||||
p.dwell = dwell
|
||||
p.idle = idle
|
||||
p.balanceMethod = balanceMethod
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -88,7 +90,7 @@ func (c *Table) GetConnection(serverID int64) (*Connection, error) {
|
|||
}
|
||||
|
||||
//Run -- Execute
|
||||
func (c *Table) Run(ctx context.Context, defaultMethod string) {
|
||||
func (c *Table) Run(ctx context.Context) {
|
||||
loginfo.Println("ConnectionTable starting")
|
||||
|
||||
go c.reaper(c.dwell, c.idle)
|
||||
|
@ -122,7 +124,7 @@ func (c *Table) Run(ctx context.Context, defaultMethod string) {
|
|||
c.domains[newDomain].AddConnection(connection)
|
||||
} else {
|
||||
//if not, then add as the 1st to the list of connections
|
||||
c.domains[newDomain] = NewDomainLoadBalance(defaultMethod)
|
||||
c.domains[newDomain] = NewDomainLoadBalance(c.balanceMethod)
|
||||
c.domains[newDomain].AddConnection(connection)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -31,7 +32,7 @@ const (
|
|||
|
||||
//ctxConnectionTable contextKey = "connectionTable"
|
||||
|
||||
ctxConfig contextKey = "config"
|
||||
ctxConfig contextKey = "tlsConfig"
|
||||
ctxListenerRegistration contextKey = "listenerRegistration"
|
||||
ctxConnectionTrack contextKey = "connectionTrack"
|
||||
ctxWssHostName contextKey = "wsshostname"
|
||||
|
@ -40,21 +41,26 @@ const (
|
|||
ctxLoadbalanceDefaultMethod contextKey = "lbdefaultmethod"
|
||||
)
|
||||
|
||||
// TODO isn't this restriction in the TLS lib?
|
||||
// or are we just pre-checking for remote hosts?
|
||||
type tlsScheme int
|
||||
|
||||
const (
|
||||
encryptNone int = iota
|
||||
encryptNone tlsScheme = iota
|
||||
encryptSSLV2
|
||||
encryptSSLV3
|
||||
encryptTLS10
|
||||
encryptTLS11
|
||||
encryptTLS12
|
||||
encryptTLS13
|
||||
)
|
||||
|
||||
//GenericListenAndServe -- used to lisen for any https traffic on 443 (8443)
|
||||
// multiListenAndServe -- used to lisen for any https traffic on 443 (8443)
|
||||
// - setup generic TCP listener, unencrypted TCP, with a Deadtime out
|
||||
// - leaverage the wedgeConn to peek into the buffer.
|
||||
// - if TLS, consume connection with TLS certbundle, pass to request identifier
|
||||
// - else, just pass to the request identififer
|
||||
func GenericListenAndServe(ctx context.Context, listenerRegistration *ListenerRegistration) {
|
||||
func (mx *MPlexy) multiListenAndServe(ctx context.Context, listenerRegistration *ListenerRegistration) {
|
||||
loginfo.Println(":" + string(listenerRegistration.port))
|
||||
cancelCheck := ctx.Value(ctxCancelCheck).(int)
|
||||
|
||||
|
@ -95,18 +101,24 @@ func GenericListenAndServe(ctx context.Context, listenerRegistration *ListenerRe
|
|||
return
|
||||
}
|
||||
|
||||
fmt.Println("New connection from %v on %v", conn.LocalAddr(), conn.RemoteAddr())
|
||||
|
||||
// TODO maybe put these into something like mx.newConnCh and have an mx.Accept()?
|
||||
wedgeConn := NewWedgeConn(conn)
|
||||
go acceptTCPOrTLS(ctx, wedgeConn)
|
||||
go mx.accept(ctx, wedgeConn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//acceptTCPOrTLS -
|
||||
//accept -
|
||||
// - accept a wedgeConnection along with all the other required attritvues
|
||||
// - peek into the buffer, determine TLS or unencrypted
|
||||
// - if TSL, then terminate with a TLS endpoint, pass to handleStream
|
||||
// - if clearText, pass to handleStream
|
||||
func acceptTCPOrTLS(ctx context.Context, wConn *WedgeConn) {
|
||||
func (mx *MPlexy) accept(ctx context.Context, wConn *WedgeConn) {
|
||||
// TODO shouldn't this responsibility fall elsewhere?
|
||||
// (otherwise I think we're keeping this function in memory while something else fails to end)
|
||||
// (i.e. something, somewhere is missing a `go doStuff()`
|
||||
defer wConn.Close()
|
||||
peekCnt := 10
|
||||
|
||||
|
@ -136,20 +148,24 @@ func acceptTCPOrTLS(ctx context.Context, wConn *WedgeConn) {
|
|||
|
||||
} else if bytes.Contains(peek[0:3], []byte{0x16, 0x03, 0x03}) {
|
||||
encryptMode = encryptTLS12
|
||||
|
||||
} else if bytes.Contains(peek[0:3], []byte{0x16, 0x03, 0x04}) {
|
||||
encryptMode = encryptTLS13
|
||||
|
||||
}
|
||||
|
||||
oneConn := &oneConnListener{wConn}
|
||||
config := ctx.Value(ctxConfig).(*tls.Config)
|
||||
tlsConfig := ctx.Value(ctxConfig).(*tls.Config)
|
||||
|
||||
if encryptMode == encryptSSLV2 {
|
||||
loginfo.Println("SSLv2 is not accepted")
|
||||
loginfo.Println("<= SSLv2 is not accepted")
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
if encryptMode == encryptNone {
|
||||
loginfo.Println("Handle Unencrypted")
|
||||
handleStream(ctx, wConn)
|
||||
mx.handleStream(ctx, wConn)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -177,9 +193,10 @@ func acceptTCPOrTLS(ctx context.Context, wConn *WedgeConn) {
|
|||
|
||||
loginfo.Println("sni:", sniHostName)
|
||||
|
||||
// This is where a target device connects to receive traffic
|
||||
if sniHostName == wssHostName {
|
||||
//handle WSS Path
|
||||
tlsListener := tls.NewListener(oneConn, config)
|
||||
tlsListener := tls.NewListener(oneConn, tlsConfig)
|
||||
|
||||
conn, err := tlsListener.Accept()
|
||||
if err != nil {
|
||||
|
@ -188,30 +205,31 @@ func acceptTCPOrTLS(ctx context.Context, wConn *WedgeConn) {
|
|||
}
|
||||
|
||||
tlsWedgeConn := NewWedgeConn(conn)
|
||||
handleStream(ctx, tlsWedgeConn)
|
||||
mx.handleStream(ctx, tlsWedgeConn)
|
||||
return
|
||||
|
||||
} else if sniHostName == adminHostName {
|
||||
// handle admin path
|
||||
tlsListener := tls.NewListener(oneConn, config)
|
||||
|
||||
conn, err := tlsListener.Accept()
|
||||
if err != nil {
|
||||
loginfo.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
tlsWedgeConn := NewWedgeConn(conn)
|
||||
handleStream(ctx, tlsWedgeConn)
|
||||
return
|
||||
|
||||
} else {
|
||||
//traffic not terminating on the rvpn do not decrypt
|
||||
loginfo.Println("processing non terminating traffic", wssHostName, sniHostName)
|
||||
handleExternalHTTPRequest(ctx, wConn, sniHostName, "https")
|
||||
}
|
||||
|
||||
return
|
||||
// This is where an admin of the relay manages it
|
||||
if sniHostName == adminHostName {
|
||||
// TODO mx.Admin.CheckRemoteIP(conn) here
|
||||
|
||||
// handle admin path
|
||||
tlsListener := tls.NewListener(oneConn, tlsConfig)
|
||||
|
||||
conn, err := tlsListener.Accept()
|
||||
if err != nil {
|
||||
loginfo.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
tlsWedgeConn := NewWedgeConn(conn)
|
||||
mx.handleStream(ctx, tlsWedgeConn)
|
||||
return
|
||||
}
|
||||
|
||||
//traffic not terminating on the rvpn do not decrypt
|
||||
loginfo.Println("processing non terminating traffic", wssHostName, sniHostName)
|
||||
handleExternalHTTPRequest(ctx, wConn, sniHostName, "https")
|
||||
}
|
||||
|
||||
//handleStream --
|
||||
|
@ -222,7 +240,7 @@ func acceptTCPOrTLS(ctx context.Context, wConn *WedgeConn) {
|
|||
// - attempt to identify as ADMIN/API session
|
||||
// - else handle as raw http
|
||||
// - handle other?
|
||||
func handleStream(ctx context.Context, wConn *WedgeConn) {
|
||||
func (mx *MPlexy) handleStream(ctx context.Context, wConn *WedgeConn) {
|
||||
loginfo.Println("handle Stream")
|
||||
loginfo.Println("conn", wConn.LocalAddr().String(), wConn.RemoteAddr().String())
|
||||
|
||||
|
@ -234,6 +252,9 @@ func handleStream(ctx context.Context, wConn *WedgeConn) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO handle by TCP port as well
|
||||
// (which needs a short read timeout since servers expect clients to say hello)
|
||||
|
||||
// HTTP Identifcation // CRLF
|
||||
if !bytes.Contains(peek[:], []byte{0x0d, 0x0a}) {
|
||||
return
|
||||
|
@ -252,14 +273,11 @@ func handleStream(ctx context.Context, wConn *WedgeConn) {
|
|||
return
|
||||
}
|
||||
|
||||
// do we have a valid wss_client?
|
||||
secretKey := ctx.Value(ctxSecretKey).(string)
|
||||
tokenString := r.URL.Query().Get("access_token")
|
||||
result, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(secretKey), nil
|
||||
})
|
||||
// TODO add newtypes
|
||||
// TODO check if this is a websocket
|
||||
_, err = mx.authorize(r)
|
||||
|
||||
if err == nil && result.Valid {
|
||||
if err == nil {
|
||||
loginfo.Println("Valid WSS dected...sending to handler")
|
||||
oneConn := &oneConnListener{wConn}
|
||||
handleWssClient(ctx, oneConn)
|
||||
|
@ -268,6 +286,7 @@ func handleStream(ctx context.Context, wConn *WedgeConn) {
|
|||
//if yes, prep the oneConn and send it to the handler
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(r.Host, telebit.InvalidAdminDomain) {
|
||||
loginfo.Println("admin")
|
||||
oneConn := &oneConnListener{wConn}
|
||||
|
|
|
@ -4,11 +4,28 @@ import (
|
|||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
//ListenerRegistrationStatus - post registration status
|
||||
type ListenerRegistrationStatus int
|
||||
|
||||
// Authz represents grants or privileges of a client
|
||||
// clientID
|
||||
// domains that may be forwarded
|
||||
// # of domains that may be forwarded
|
||||
// ports that may be forwarded (i.e. allow special ports < 1024, exclude 443, 25, etc)
|
||||
// # of ports that may be forwarded
|
||||
// # of concurrent conections
|
||||
// # bandwith rate (i.e. 5 mbps)
|
||||
// # bandwith cap per time period (i.e. 100 MB / hour)
|
||||
// # throttled rate (i.e. 0 (kill), or 1 mbps)
|
||||
type Authz struct {
|
||||
}
|
||||
|
||||
// Authorizer is called when a new client connects and we need to know something about it
|
||||
type Authorizer func(*http.Request) (*Authz, error)
|
||||
|
||||
const (
|
||||
listenerAdded ListenerRegistrationStatus = iota
|
||||
listenerExists
|
||||
|
@ -40,99 +57,107 @@ func NewListenerRegistration(port int) (p *ListenerRegistration) {
|
|||
p = new(ListenerRegistration)
|
||||
p.port = port
|
||||
p.commCh = make(chan *ListenerRegistration)
|
||||
return
|
||||
return p
|
||||
}
|
||||
|
||||
// Servers -
|
||||
type Servers struct {
|
||||
// MPlexy -
|
||||
type MPlexy struct {
|
||||
listeners map[*net.Listener]int
|
||||
ctx context.Context
|
||||
connnectionTable *Table
|
||||
connectionTracking *Tracking
|
||||
secretKey string
|
||||
certbundle tls.Certificate
|
||||
authorize Authorizer
|
||||
tlsConfig *tls.Config
|
||||
register chan *ListenerRegistration
|
||||
servers *Servers
|
||||
wssHostName string
|
||||
adminHostName string
|
||||
cancelCheck int
|
||||
lbDefaultMethod string
|
||||
serverStatus *Status
|
||||
//xservers *MPlexy
|
||||
}
|
||||
|
||||
// NewGenerListeners creates tcp (and https and wss?) listeners
|
||||
func NewGenerListeners(ctx context.Context, secretKey string, certbundle tls.Certificate, serverStatus *Status) (p *Servers) {
|
||||
p = &Servers{}
|
||||
p.listeners = make(map[*net.Listener]int)
|
||||
p.ctx = ctx
|
||||
p.connnectionTable = serverStatus.ConnectionTable
|
||||
p.connectionTracking = serverStatus.ConnectionTracking
|
||||
p.secretKey = secretKey
|
||||
p.certbundle = certbundle
|
||||
p.register = make(chan *ListenerRegistration)
|
||||
p.wssHostName = serverStatus.WssDomain
|
||||
p.adminHostName = serverStatus.AdminDomain
|
||||
p.cancelCheck = serverStatus.DeadTime.cancelcheck
|
||||
p.lbDefaultMethod = serverStatus.LoadbalanceDefaultMethod
|
||||
p.serverStatus = serverStatus
|
||||
return
|
||||
// New creates tcp (and https and wss?) listeners
|
||||
func New(ctx context.Context, tlsConfig *tls.Config, authz Authorizer, serverStatus *Status) (mx *MPlexy) {
|
||||
mx = &MPlexy{
|
||||
listeners: make(map[*net.Listener]int),
|
||||
ctx: ctx,
|
||||
connnectionTable: serverStatus.ConnectionTable,
|
||||
connectionTracking: serverStatus.ConnectionTracking,
|
||||
authorize: authz,
|
||||
tlsConfig: tlsConfig,
|
||||
register: make(chan *ListenerRegistration),
|
||||
wssHostName: serverStatus.WssDomain,
|
||||
adminHostName: serverStatus.AdminDomain,
|
||||
cancelCheck: serverStatus.DeadTime.cancelcheck,
|
||||
lbDefaultMethod: serverStatus.LoadbalanceDefaultMethod,
|
||||
serverStatus: serverStatus,
|
||||
}
|
||||
return mx
|
||||
}
|
||||
|
||||
//Run -- Execute
|
||||
// - execute the GenericLister
|
||||
// - pass initial port, we'll announce that
|
||||
func (gl *Servers) Run(ctx context.Context, initialPort int) {
|
||||
func (mx *MPlexy) Run() error {
|
||||
loginfo.Println("ConnectionTable starting")
|
||||
|
||||
config := &tls.Config{Certificates: []tls.Certificate{gl.certbundle}}
|
||||
loginfo.Println(mx.connectionTracking)
|
||||
|
||||
ctx = context.WithValue(ctx, ctxSecretKey, gl.secretKey)
|
||||
ctx := mx.ctx
|
||||
|
||||
loginfo.Println(gl.connectionTracking)
|
||||
// For just this bit
|
||||
ctx = context.WithValue(ctx, ctxConnectionTrack, mx.connectionTracking)
|
||||
|
||||
ctx = context.WithValue(ctx, ctxConnectionTrack, gl.connectionTracking)
|
||||
ctx = context.WithValue(ctx, ctxConfig, config)
|
||||
ctx = context.WithValue(ctx, ctxListenerRegistration, gl.register)
|
||||
ctx = context.WithValue(ctx, ctxWssHostName, gl.wssHostName)
|
||||
ctx = context.WithValue(ctx, ctxAdminHostName, gl.adminHostName)
|
||||
ctx = context.WithValue(ctx, ctxCancelCheck, gl.cancelCheck)
|
||||
ctx = context.WithValue(ctx, ctxLoadbalanceDefaultMethod, gl.lbDefaultMethod)
|
||||
ctx = context.WithValue(ctx, ctxServerStatus, gl.serverStatus)
|
||||
// For all Listeners
|
||||
ctx = context.WithValue(ctx, ctxConfig, mx.tlsConfig)
|
||||
ctx = context.WithValue(ctx, ctxListenerRegistration, mx.register)
|
||||
ctx = context.WithValue(ctx, ctxWssHostName, mx.wssHostName)
|
||||
ctx = context.WithValue(ctx, ctxAdminHostName, mx.adminHostName)
|
||||
ctx = context.WithValue(ctx, ctxCancelCheck, mx.cancelCheck)
|
||||
ctx = context.WithValue(ctx, ctxLoadbalanceDefaultMethod, mx.lbDefaultMethod)
|
||||
ctx = context.WithValue(ctx, ctxServerStatus, mx.serverStatus)
|
||||
|
||||
go func(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
for {
|
||||
select {
|
||||
|
||||
case <-ctx.Done():
|
||||
loginfo.Println("Cancel signal hit")
|
||||
return
|
||||
case <-ctx.Done():
|
||||
loginfo.Println("Cancel signal hit")
|
||||
return nil
|
||||
|
||||
case registration := <-gl.register:
|
||||
loginfo.Println("register fired", registration.port)
|
||||
case registration := <-mx.register:
|
||||
loginfo.Println("register fired", registration.port)
|
||||
|
||||
// check to see if port is already running
|
||||
for listener := range gl.listeners {
|
||||
if gl.listeners[listener] == registration.port {
|
||||
loginfo.Println("listener already running", registration.port)
|
||||
registration.status = listenerExists
|
||||
registration.commCh <- registration
|
||||
}
|
||||
}
|
||||
loginfo.Println("listener starting up ", registration.port)
|
||||
loginfo.Println(ctx.Value(ctxConnectionTrack).(*Tracking))
|
||||
go GenericListenAndServe(ctx, registration)
|
||||
|
||||
status := <-registration.commCh
|
||||
if status.status == listenerAdded {
|
||||
gl.listeners[status.listener] = status.port
|
||||
} else if status.status == listenerFault {
|
||||
loginfo.Println("Unable to create a new listerer", registration.port)
|
||||
// check to see if port is already running
|
||||
for listener := range mx.listeners {
|
||||
if mx.listeners[listener] == registration.port {
|
||||
loginfo.Println("listener already running", registration.port)
|
||||
registration.status = listenerExists
|
||||
registration.commCh <- registration
|
||||
}
|
||||
}
|
||||
loginfo.Println("listener starting up ", registration.port)
|
||||
loginfo.Println(ctx.Value(ctxConnectionTrack).(*Tracking))
|
||||
go mx.multiListenAndServe(ctx, registration)
|
||||
|
||||
status := <-registration.commCh
|
||||
if status.status == listenerAdded {
|
||||
mx.listeners[status.listener] = status.port
|
||||
} else if status.status == listenerFault {
|
||||
loginfo.Println("Unable to create a new listerer", registration.port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}(ctx)
|
||||
|
||||
newListener := NewListenerRegistration(initialPort)
|
||||
gl.register <- newListener
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mx *MPlexy) Start() {
|
||||
go mx.Run()
|
||||
}
|
||||
|
||||
// MultiListenAndServe starts another listener (to the same application) on a new port
|
||||
func (mx *MPlexy) MultiListenAndServe(port int) {
|
||||
// TODO how to associate a listening device with a given plain port
|
||||
mx.register <- NewListenerRegistration(port)
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ type Status struct {
|
|||
DeadTime *StatusDeadTime
|
||||
ConnectionTracking *Tracking
|
||||
ConnectionTable *Table
|
||||
servers *Servers
|
||||
LoadbalanceDefaultMethod string
|
||||
AdminStats *TrafficStats
|
||||
AdminReqTyoe *AdminReqType
|
||||
TrafficStats *TrafficStats
|
||||
ExtConnections *ConnectionStats
|
||||
WSSConnections *ConnectionStats
|
||||
//servers *MPlexy
|
||||
}
|
||||
|
||||
//NewStatus --
|
||||
|
@ -32,7 +32,9 @@ func NewStatus(ctx context.Context) (p *Status) {
|
|||
p.TrafficStats = new(TrafficStats)
|
||||
p.ExtConnections = new(ConnectionStats)
|
||||
p.WSSConnections = new(ConnectionStats)
|
||||
return
|
||||
// TODO any reason not to set StartTime like this?
|
||||
p.StartTime = time.Now()
|
||||
return p
|
||||
}
|
||||
|
||||
// South Facing Functions
|
||||
|
|
|
@ -2,4 +2,7 @@ package telebit
|
|||
|
||||
// InvalidAdminDomain is a domain that can only be accessed by Domain Fronting
|
||||
// (i.e. trixy clients sending fake headers), not browsers
|
||||
var InvalidAdminDomain = "rvpn.rootprojects.invalid"
|
||||
var InvalidAdminDomain = "chilly-bobcat-15.telebit.io"
|
||||
|
||||
//var InvalidAdminDomain = "invalid.rootprojects.org"
|
||||
//var InvalidAdminDomain = "rvpn.rootprojects.invalid"
|
||||
|
|
Loading…
Reference in New Issue