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:
parent
ebafa277df
commit
9e2a04c8a7
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue