WSS Client now working with protocol detection

- added support for PeekAll…still not working 100%.
- passing important values inside the context, no longer on arguments
- stream handler now detects wss_client, validates the token to make sure.
- then passes to was handler which invokes http.Server with oneConnListener
- removing listener wedge, going to stay with oneConnListener.  It is working.
This commit is contained in:
Henry Camacho 2017-02-26 12:35:06 -06:00
parent ebafa277df
commit 9e2a04c8a7
4 changed files with 185 additions and 91 deletions

View File

@ -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))
}
}
}

View File

@ -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
}
}

View File

@ -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()
}

View File

@ -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)