From 74591fd150217e6d58ec288d44e9544f39c7e93b Mon Sep 17 00:00:00 2001 From: Henry Camacho Date: Sat, 11 Mar 2017 14:28:49 -0600 Subject: [PATCH] Added support for YAML configuration file - implemented viper module in code. - removed all the older configuration, not sure if we want to use flags or just the configuration files. - added support for dwell, idle and cancelceck timers - generic binding is now an int passing to the generic manager. - passing dwell, and idle directly to connection table. - adjusted all dead time structures, the system supports a map(string)interface{} of various dead time counters - this version also supports variable sized buffers for each request by using the bufio.reader - we peek all, and then pass everything down the channel we have. - I am wondering if this will be a problem is someone just starts pouring data down never ending. - direct support now for terminating domains - there is a domain for admin, and wss. Each shared the external address listener (testing 9999) Additions - added support for Discard for wedge connections - added support for ReadByte to wedge conn --- go-rvpn-server.yaml | 16 +++++ main.go | 42 +++++++++---- rvpn/genericlistener/conn_wedge.go | 10 ++++ rvpn/genericlistener/connection_table.go | 8 ++- rvpn/genericlistener/listener_generic.go | 75 ++++++++++++++++-------- rvpn/genericlistener/manager.go | 11 ++-- 6 files changed, 120 insertions(+), 42 deletions(-) create mode 100644 go-rvpn-server.yaml diff --git a/go-rvpn-server.yaml b/go-rvpn-server.yaml new file mode 100644 index 0000000..d0f88e1 --- /dev/null +++ b/go-rvpn-server.yaml @@ -0,0 +1,16 @@ +rvpn: + wssdomain: localhost.daplie.me + admindomain: rvpn.daplie.invalid + genericlistener: 9999 + deadtime: + dwell: 600 + idle: 60 + cancelcheck: 10 + domains: + test.daplie.me: + secret: abc123 + test2.daplie.me: + secret: abc123 + test3.daplie.me: + secret: abc123 + diff --git a/main.go b/main.go index c53838d..21ca4b9 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,8 @@ import ( "os" "time" + "github.com/spf13/viper" + "context" "git.daplie.com/Daplie/go-rvpn-server/rvpn/genericlistener" @@ -18,7 +20,7 @@ var ( logdebug *log.Logger logFlags = log.Ldate | log.Lmicroseconds | log.Lshortfile argWssClientListener string - argGenericBinding string + argGenericBinding int argServerBinding string argServerAdminBinding string argServerExternalBinding string @@ -26,25 +28,43 @@ var ( connectionTable *genericlistener.Table secretKey = "abc123" wssHostName = "localhost.daplie.me" + adminHostName = "rvpn.daplie.invalid" + idle int + dwell int + cancelcheck int ) func init() { - flag.IntVar(&argDeadTime, "dead-time-counter", 5, "deadtime counter in seconds") - flag.StringVar(&argGenericBinding, "generic-listener", ":8443", "generic SSL Listener") - flag.StringVar(&argWssClientListener, "wss-client-listener", ":3502", "wss client listener address:port") - flag.StringVar(&argServerAdminBinding, "admin-server-port", "127.0.0.2:8000", "admin server Bind listener") - flag.StringVar(&argServerExternalBinding, "external-server-port", "127.0.0.1:8080", "external server Bind listener") + } //Main -- main entry point func main() { flag.Parse() + loginfo = log.New(os.Stdout, "INFO: main: ", logFlags) + logdebug = log.New(os.Stdout, "DEBUG: main:", logFlags) + viper.SetConfigName("go-rvpn-server") + viper.AddConfigPath("./") + err := viper.ReadInConfig() + if err != nil { + panic(fmt.Errorf("Fatal error config file: %s \n", err)) + } - loginfo = log.New(os.Stdout, "INFO: packer: ", logFlags) - logdebug = log.New(os.Stdout, "DEBUG: packer:", logFlags) + flag.IntVar(&argDeadTime, "dead-time-counter", 5, "deadtime counter in seconds") + + wssHostName = viper.Get("rvpn.wssdomain").(string) + adminHostName = viper.Get("rvpn.admindomain").(string) + argGenericBinding = viper.GetInt("rvpn.genericlistener") + deadtime := viper.Get("rvpn.deadtime") + idle = deadtime.(map[string]interface{})["idle"].(int) + dwell = deadtime.(map[string]interface{})["dwell"].(int) + cancelcheck = deadtime.(map[string]interface{})["cancelcheck"].(int) loginfo.Println("startup") + loginfo.Println(viper.Get("rvpn.genericlisteners")) + loginfo.Println(viper.Get("rvpn.domains")) + fmt.Println("-=-=-=-=-=-=-=-=-=-=") certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem") @@ -68,11 +88,11 @@ func main() { connectionTracking := genericlistener.NewTracking() go connectionTracking.Run(ctx) - connectionTable = genericlistener.NewTable() + connectionTable = genericlistener.NewTable(dwell, idle) go connectionTable.Run(ctx) - genericListeners := genericlistener.NewGenerListeners(ctx, connectionTable, connectionTracking, secretKey, certbundle, argDeadTime, wssHostName) - go genericListeners.Run(ctx, 9999) + genericListeners := genericlistener.NewGenerListeners(ctx, connectionTable, connectionTracking, secretKey, certbundle, wssHostName, adminHostName, cancelcheck) + go genericListeners.Run(ctx, argGenericBinding) //Run for 10 minutes and then shutdown cleanly time.Sleep(600 * time.Second) diff --git a/rvpn/genericlistener/conn_wedge.go b/rvpn/genericlistener/conn_wedge.go index 4eafe5a..579db3c 100644 --- a/rvpn/genericlistener/conn_wedge.go +++ b/rvpn/genericlistener/conn_wedge.go @@ -27,11 +27,21 @@ func NewWedgeConnSize(c net.Conn, size int) (p *WedgeConn) { return } +//Discard - discard a number of bytes, perhaps after peeking at the +func (w *WedgeConn) Discard(n int) (discarded int, err error) { + return w.reader.Discard(n) +} + //Peek - Get a number of bytes outof the buffer, but allow the buffer to be replayed once read func (w *WedgeConn) Peek(n int) ([]byte, error) { return w.reader.Peek(n) } +//ReadByte -- A normal reader. +func (w *WedgeConn) ReadByte() (byte, error) { + return w.reader.ReadByte() +} + //Read -- A normal reader. func (w *WedgeConn) Read(p []byte) (int, error) { cnt, err := w.reader.Read(p) diff --git a/rvpn/genericlistener/connection_table.go b/rvpn/genericlistener/connection_table.go index af29144..ff57042 100755 --- a/rvpn/genericlistener/connection_table.go +++ b/rvpn/genericlistener/connection_table.go @@ -17,10 +17,12 @@ type Table struct { unregister chan *Connection domainAnnounce chan *DomainMapping domainRevoke chan *DomainMapping + dwell int + idle int } //NewTable -- consructor -func NewTable() (p *Table) { +func NewTable(dwell int, idle int) (p *Table) { p = new(Table) p.connections = make(map[*Connection][]string) p.domains = make(map[string]*Connection) @@ -28,6 +30,8 @@ func NewTable() (p *Table) { p.unregister = make(chan *Connection) p.domainAnnounce = make(chan *DomainMapping) p.domainRevoke = make(chan *DomainMapping) + p.dwell = dwell + p.idle = idle return } @@ -66,7 +70,7 @@ func (c *Table) reaper(delay int, idle int) { func (c *Table) Run(ctx context.Context) { loginfo.Println("ConnectionTable starting") - go c.reaper(3000, 60) + go c.reaper(c.dwell, c.idle) for { select { diff --git a/rvpn/genericlistener/listener_generic.go b/rvpn/genericlistener/listener_generic.go index 16c1418..07baf22 100644 --- a/rvpn/genericlistener/listener_generic.go +++ b/rvpn/genericlistener/listener_generic.go @@ -31,10 +31,11 @@ const ( ctxSecretKey contextKey = "secretKey" ctxConnectionTable contextKey = "connectionTable" ctxConfig contextKey = "config" - ctxDeadTime contextKey = "deadtime" ctxListenerRegistration contextKey = "listenerRegistration" ctxConnectionTrack contextKey = "connectionTrack" ctxWssHostName contextKey = "wsshostname" + ctxAdminHostName contextKey = "adminHostName" + ctxCancelCheck contextKey = "cancelcheck" ) const ( @@ -52,11 +53,10 @@ const ( // - 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) { - loginfo.Println(":" + string(listenerRegistration.port)) + cancelCheck := ctx.Value(ctxCancelCheck).(int) listenAddr, err := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(listenerRegistration.port)) - deadTime := ctx.Value(ctxDeadTime).(int) if nil != err { loginfo.Println(err) @@ -81,12 +81,10 @@ func GenericListenAndServe(ctx context.Context, listenerRegistration *ListenerRe loginfo.Println("Cancel signal hit") return default: - ln.SetDeadline(time.Now().Add(time.Duration(deadTime) * time.Second)) + ln.SetDeadline(time.Now().Add(time.Duration(cancelCheck) * time.Second)) conn, err := ln.Accept() - loginfo.Println("Deadtime reached") - if nil != err { if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { continue @@ -160,6 +158,8 @@ func handleConnection(ctx context.Context, wConn *WedgeConn) { } wssHostName := ctx.Value(ctxWssHostName).(string) + adminHostName := ctx.Value(ctxAdminHostName).(string) + sniHostName, err := getHello(peek) if err != nil { loginfo.Println(err) @@ -168,25 +168,39 @@ func handleConnection(ctx context.Context, wConn *WedgeConn) { loginfo.Println("sni:", sniHostName) - if wssHostName != sniHostName { + if sniHostName == wssHostName { + //handle WSS 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 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") + loginfo.Println("processing non terminating traffic", wssHostName, sniHostName) handleExternalHTTPRequest(ctx, wConn, sniHostName, "https") } - - loginfo.Println("processing traffic terminating on RVPN") - - tlsListener := tls.NewListener(oneConn, config) - - conn, err := tlsListener.Accept() - if err != nil { - loginfo.Println(err) - return - } - - tlsWedgeConn := NewWedgeConn(conn) - handleStream(ctx, tlsWedgeConn) - return } loginfo.Println("Handle Unencrypted") @@ -257,7 +271,7 @@ func handleStream(ctx context.Context, wConn *WedgeConn) { //handleExternalHTTPRequest - // - get a wConn and start processing requests -func handleExternalHTTPRequest(ctx context.Context, extConn net.Conn, hostname string, service string) { +func handleExternalHTTPRequest(ctx context.Context, extConn *WedgeConn, hostname string, service string) { connectionTracking := ctx.Value(ctxConnectionTrack).(*Tracking) defer func() { @@ -286,13 +300,17 @@ func handleExternalHTTPRequest(ctx context.Context, extConn net.Conn, hostname s return } - var buffer [1024]byte for { - cnt, err := extConn.Read(buffer[0:]) + buffer, err := extConn.PeekAll() if err != nil { + loginfo.Println("unable to peekAll", err) return } + loginfo.Println("Before Packer", hex.Dump(buffer)) + + cnt := len(buffer) + p := packer.NewPacker() p.Header.SetAddress(rAddr) p.Header.Port, err = strconv.Atoi(rPort) @@ -309,6 +327,13 @@ func handleExternalHTTPRequest(ctx context.Context, extConn net.Conn, hostname s sendTrack := NewSendTrack(buf.Bytes(), hostname) conn.SendCh() <- sendTrack + + _, err = extConn.Discard(cnt) + if err != nil { + loginfo.Println("unable to discard", cnt, err) + return + } + } } diff --git a/rvpn/genericlistener/manager.go b/rvpn/genericlistener/manager.go index f31c305..c05c58f 100644 --- a/rvpn/genericlistener/manager.go +++ b/rvpn/genericlistener/manager.go @@ -51,14 +51,15 @@ type GenericListeners struct { connectionTracking *Tracking secretKey string certbundle tls.Certificate - deadTime int register chan *ListenerRegistration genericListeners *GenericListeners wssHostName string + adminHostName string + cancelCheck int } //NewGenerListeners -- -func NewGenerListeners(ctx context.Context, connectionTable *Table, connectionTrack *Tracking, secretKey string, certbundle tls.Certificate, deadTime int, wssHostName string) (p *GenericListeners) { +func NewGenerListeners(ctx context.Context, connectionTable *Table, connectionTrack *Tracking, secretKey string, certbundle tls.Certificate, wssHostName string, adminHostName string, cancelCheck int) (p *GenericListeners) { p = new(GenericListeners) p.listeners = make(map[*net.Listener]int) p.ctx = ctx @@ -66,9 +67,10 @@ func NewGenerListeners(ctx context.Context, connectionTable *Table, connectionTr p.connectionTracking = connectionTrack p.secretKey = secretKey p.certbundle = certbundle - p.deadTime = deadTime p.register = make(chan *ListenerRegistration) p.wssHostName = wssHostName + p.adminHostName = adminHostName + p.cancelCheck = cancelCheck return } @@ -87,9 +89,10 @@ func (gl *GenericListeners) Run(ctx context.Context, initialPort int) { ctx = context.WithValue(ctx, ctxConnectionTrack, gl.connectionTracking) ctx = context.WithValue(ctx, ctxConfig, config) - ctx = context.WithValue(ctx, ctxDeadTime, gl.deadTime) 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) go func(ctx context.Context) { for {