From 9e2a04c8a76f649c4ea320f35dc0acb7682fc0a1 Mon Sep 17 00:00:00 2001 From: Henry Camacho Date: Sun, 26 Feb 2017 12:35:06 -0600 Subject: [PATCH] =?UTF-8?q?WSS=20Client=20now=20working=20with=20protocol?= =?UTF-8?q?=20detection=20-=20added=20support=20for=20PeekAll=E2=80=A6stil?= =?UTF-8?q?l=20not=20working=20100%.=20-=20passing=20important=20values=20?= =?UTF-8?q?inside=20the=20context,=20no=20longer=20on=20arguments=20-=20st?= =?UTF-8?q?ream=20handler=20now=20detects=20wss=5Fclient,=20validates=20th?= =?UTF-8?q?e=20token=20to=20make=20sure.=20-=20then=20passes=20to=20was=20?= =?UTF-8?q?handler=20which=20invokes=20http.Server=20with=20oneConnListene?= =?UTF-8?q?r=20-=20removing=20listener=20wedge,=20going=20to=20stay=20with?= =?UTF-8?q?=20oneConnListener.=20=20It=20is=20working.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rvpn/genericlistener/conn_wedge.go | 36 ++++- rvpn/genericlistener/listener_generic.go | 179 +++++++++++++++++++---- rvpn/genericlistener/listener_wedge.go | 59 -------- rvpn/rvpnmain/run.go | 2 +- 4 files changed, 185 insertions(+), 91 deletions(-) delete mode 100644 rvpn/genericlistener/listener_wedge.go diff --git a/rvpn/genericlistener/conn_wedge.go b/rvpn/genericlistener/conn_wedge.go index 64dce2b..542fbda 100644 --- a/rvpn/genericlistener/conn_wedge.go +++ b/rvpn/genericlistener/conn_wedge.go @@ -2,7 +2,6 @@ package genericlistener import ( "bufio" - "encoding/hex" "net" ) @@ -28,16 +27,45 @@ func NewWedgeConnSize(c net.Conn, size int) (p *WedgeConn) { return } -//Peek - Get a number of bytes outof the buffer, but allow the buffer to be repled once read +//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) { + loginfo.Println("Peek") + loginfo.Println("buffered=", w.reader.Buffered()) return w.reader.Peek(n) + } //Read -- A normal reader. func (w *WedgeConn) Read(p []byte) (int, error) { loginfo.Println("read", w.Conn) cnt, err := w.reader.Read(p) - loginfo.Println("read", hex.Dump(p[0:cnt])) - loginfo.Println(cnt, err) return cnt, err } + +//Buffered -- +func (w *WedgeConn) Buffered() int { + return w.reader.Buffered() +} + +//PeekAll -- +// - get all the chars available +// - pass then back +func (w *WedgeConn) PeekAll() (buf []byte, err error) { + loginfo.Println("PeekAll") + + var peek []byte + for { + b, err := w.reader.Peek(1) + if err != nil { + if len(peek) > 0 { + return peek, nil + } + + var t byte + t = b[0] + + peek = append(peek, t) + loginfo.Println("len", len(peek)) + } + } +} diff --git a/rvpn/genericlistener/listener_generic.go b/rvpn/genericlistener/listener_generic.go index 993b83e..69d4986 100644 --- a/rvpn/genericlistener/listener_generic.go +++ b/rvpn/genericlistener/listener_generic.go @@ -9,9 +9,25 @@ import ( "net" "time" + jwt "github.com/dgrijalva/jwt-go" + "github.com/gorilla/mux" + "github.com/gorilla/websocket" + + "net/http" + + "bufio" + "git.daplie.com/Daplie/go-rvpn-server/rvpn/connection" ) +type contextKey string + +const ( + ctxSecretKey contextKey = "secretKey" + ctxConnectionTable contextKey = "connectionTable" + ctxConfig contextKey = "config" +) + const ( encryptNone int = iota encryptSSLV2 @@ -29,6 +45,10 @@ const ( func GenericListenAndServe(ctx context.Context, connectionTable *connection.Table, secretKey string, serverBinding string, certbundle tls.Certificate, deadTime int) { config := &tls.Config{Certificates: []tls.Certificate{certbundle}} + ctx = context.WithValue(ctx, ctxSecretKey, secretKey) + ctx = context.WithValue(ctx, ctxConnectionTable, connectionTable) + ctx = context.WithValue(ctx, ctxConfig, config) + listenAddr, err := net.ResolveTCPAddr("tcp", serverBinding) if nil != err { loginfo.Println(err) @@ -62,7 +82,7 @@ func GenericListenAndServe(ctx context.Context, connectionTable *connection.Tabl } wedgeConn := NewWedgeConn(conn) - go handleConnection(ctx, wedgeConn, connectionTable, secretKey, config) + go handleConnection(ctx, wedgeConn) } } } @@ -70,8 +90,9 @@ func GenericListenAndServe(ctx context.Context, connectionTable *connection.Tabl //handleConnection - // - accept a wedgeConnection along with all the other required attritvues // - peek into the buffer, determine TLS or unencrypted - -func handleConnection(ctx context.Context, wConn *WedgeConn, connectionTable *connection.Table, secretKey string, config *tls.Config) { +// - if TSL, then terminate with a TLS endpoint, pass to handleStream +// - if clearText, pass to handleStream +func handleConnection(ctx context.Context, wConn *WedgeConn) { defer wConn.Close() peekCnt := 10 @@ -107,6 +128,7 @@ func handleConnection(ctx context.Context, wConn *WedgeConn, connectionTable *co } oneConn := &oneConnListener{wConn} + config := ctx.Value(ctxConfig).(*tls.Config) if encryptMode == encryptSSLV2 { loginfo.Println("SSLv2 is not accepted") @@ -121,47 +143,150 @@ func handleConnection(ctx context.Context, wConn *WedgeConn, connectionTable *co loginfo.Println(err) return } - loginfo.Println(conn) - handleStream(conn) + + tlsWedgeConn := NewWedgeConn(conn) + handleStream(ctx, tlsWedgeConn) return } loginfo.Println("Handle Unencrypted") - handleStream(wConn) + handleStream(ctx, wConn) return } -func handleStream(conn net.Conn) { - var buf [512]byte - cnt, err := conn.Read(buf[0:]) +//handleStream -- +// - we have an unencrypted stream connection with the ability to peek +// - attempt to identify HTTP +// - handle http +// - attempt to identify as WSS session +// - attempt to identify as ADMIN/API session +// - else handle as raw https +// - handle other? +func handleStream(ctx context.Context, wConn *WedgeConn) { + loginfo.Println("handle Stream") + loginfo.Println("conn", wConn, wConn.LocalAddr().String(), wConn.RemoteAddr().String()) + + //peek for one byte to get the readers to converge + //look at buffer + //get the realrequest + peek, err := wConn.Peek(1) + loginfo.Println(hex.Dump(peek[0:])) + peek, err = wConn.Peek(wConn.Buffered()) + loginfo.Println(hex.Dump(peek[0:])) + if err != nil { - loginfo.Println(err) + loginfo.Println("error while peeking") + loginfo.Println(hex.Dump(peek[0:])) return } - loginfo.Println(hex.Dump(buf[0:cnt])) + // HTTP Identifcation + if bytes.Contains(peek[:], []byte{0x0d, 0x0a}) { + //string protocol + if bytes.ContainsAny(peek[:], "HTTP/") { + loginfo.Println("identifed HTTP") + r, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(peek))) + if err != nil { + loginfo.Println("identifed as HTTP, failed request", err) + return + } + + loginfo.Println(r) + + //now we have a request. Check to see if it is one of our own + 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 + }) + + if err == nil && result.Valid { + loginfo.Println("Valid WSS dected...sending to handler") + oneConn := &oneConnListener{wConn} + handleWssClient(ctx, oneConn) + } else { + loginfo.Println("not a valid WSS connection") + } + } + } + + loginfo.Println(hex.Dump(peek[0:])) } -//state := NewState() -//wConn := NewWedgeConnSize(conn, 512) -//var buffer [512]byte +//handleWssClient - +// - expecting an existing oneConnListener with a qualified wss client connected. +// - auth will happen again since we were just peeking at the token. +func handleWssClient(ctx context.Context, oneConn *oneConnListener) { + secretKey := ctx.Value(ctxSecretKey).(string) + connectionTable := ctx.Value(ctxConnectionTable).(*connection.Table) -// Peek for data to figure out what connection we have -//peekcnt := 32 -//peek, err := wConn.Peek(peekcnt) + router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + loginfo.Println("HandleFunc /") + switch url := r.URL.Path; url { + case "/": + loginfo.Println("websocket opening ", r.RemoteAddr, " ", r.Host) -//if err != nil { -// loginfo.Println("error while peeking") -// return -// } -//loginfo.Println(hex.Dump(peek[0:peekcnt])) -//loginfo.Println("after peek") + tokenString := r.URL.Query().Get("access_token") + result, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return []byte(secretKey), nil + }) -// assume http websocket. + if err != nil || !result.Valid { + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("Not Authorized")) + loginfo.Println("access_token invalid...closing connection") + return + } -//loginfo.Println("wConn", wConn) + loginfo.Println("help access_token valid") -//wedgeListener := &WedgeListener{conn: conn} -//LaunchWssListener(connectionTable, &secretKey, wedgeListener) + claims := result.Claims.(jwt.MapClaims) + domains, ok := claims["domains"].([]interface{}) + + var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + } + + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + loginfo.Println("WebSocket upgrade failed", err) + return + } + + loginfo.Println("before connection table") + + //newConnection := connection.NewConnection(connectionTable, conn, r.RemoteAddr, domains) + + newRegistration := connection.NewRegistration(conn, r.RemoteAddr, domains) + connectionTable.Register() <- newRegistration + ok = <-newRegistration.CommCh() + if !ok { + loginfo.Println("connection registration failed ", newRegistration) + return + } + + loginfo.Println("connection registration accepted ", newRegistration) + } + }) + + s := &http.Server{ + Addr: ":80", + Handler: router, + } + + err := s.Serve(oneConn) + if err != nil { + loginfo.Println("Serve error: ", err) + } + + select { + case <-ctx.Done(): + loginfo.Println("Cancel signal hit") + return + } + +} diff --git a/rvpn/genericlistener/listener_wedge.go b/rvpn/genericlistener/listener_wedge.go deleted file mode 100644 index 62a6316..0000000 --- a/rvpn/genericlistener/listener_wedge.go +++ /dev/null @@ -1,59 +0,0 @@ -package genericlistener - -import ( - "encoding/hex" - "io" - "net" - "sync" -) - -//WedgeListener -- used to hand off connections to other protocols via Listen -type WedgeListener struct { - net.Listener - conn net.Conn - once sync.Once -} - -//Accept -- -func (s *WedgeListener) Accept() (net.Conn, error) { - var c net.Conn - - loginfo.Println("Accept") - - if 1 == 2 { - - var buffer [512]byte - cnt, err := s.conn.Read(buffer[0:]) - if err != nil { - loginfo.Println("Errpr radomg") - } - loginfo.Println("buffer") - loginfo.Println(hex.Dump(buffer[0:cnt])) - } - - s.once.Do(func() { - loginfo.Println("Do Once") - c = s.conn - }) - - if c != nil { - loginfo.Println("accepted") - return c, nil - } - return nil, io.EOF -} - -//Close -- -func (s *WedgeListener) Close() error { - s.once.Do(func() { - loginfo.Println("close called") - s.conn.Close() - }) - return nil -} - -//Addr -- -func (s *WedgeListener) Addr() net.Addr { - loginfo.Println("Add Called", s.conn.LocalAddr()) - return s.conn.LocalAddr() -} diff --git a/rvpn/rvpnmain/run.go b/rvpn/rvpnmain/run.go index a39b3fa..47fe43d 100644 --- a/rvpn/rvpnmain/run.go +++ b/rvpn/rvpnmain/run.go @@ -72,7 +72,7 @@ func Run() { go genericlistener.GenericListenAndServe(ctx, connectionTable, secretKey, argGenericBinding, certbundle, argDeadTime) - time.Sleep(300 * time.Second) + time.Sleep(20 * time.Second) cancelContext() time.Sleep(60 * time.Second)