Generic Listener supporting unencrypted, encrypted, with TLS version detection before TLS Accept
- added support for context passing between the various functions - support for withCancel, allowing administrative canceling, and a clean up of Go Routines. - generic listener now supports a single port for both encrypted and clear text protocols. - employee the buffered wedge connection for peaking into the protocol - implementation of the oneListener. - when TLS, leveraged the NewListener which uses oneListener as n inner lister. - once the stream is decrypted, or if it was already clear text it is passed to handleStream which performs application detection.
This commit is contained in:
parent
d611757b10
commit
ebafa277df
|
@ -2,6 +2,7 @@ package connection
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "time"
|
import "time"
|
||||||
|
import "context"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
initialDomains = 0
|
initialDomains = 0
|
||||||
|
@ -62,13 +63,18 @@ func (c *Table) reaper(delay int, idle int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Run -- Execute
|
//Run -- Execute
|
||||||
func (c *Table) Run() {
|
func (c *Table) Run(ctx context.Context) {
|
||||||
loginfo.Println("ConnectionTable starting")
|
loginfo.Println("ConnectionTable starting")
|
||||||
|
|
||||||
go c.reaper(300, 60)
|
go c.reaper(300, 60)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|
||||||
|
case <-ctx.Done():
|
||||||
|
loginfo.Println("Cancel signal hit")
|
||||||
|
return
|
||||||
|
|
||||||
case registration := <-c.register:
|
case registration := <-c.register:
|
||||||
loginfo.Println("register fired")
|
loginfo.Println("register fired")
|
||||||
|
|
||||||
|
|
|
@ -1,89 +1,167 @@
|
||||||
package genericlistener
|
package genericlistener
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/hex"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/connection"
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/connection"
|
||||||
)
|
)
|
||||||
|
|
||||||
//LaunchGenericServer -- used to lisen for any https traffic on 443 (8443)
|
|
||||||
//used to make sure customer devices can reach 443. wss or client
|
|
||||||
func LaunchGenericServer(connectionTable *connection.Table, secretKey string, serverBinding string, certbundle tls.Certificate) {
|
|
||||||
|
|
||||||
config := &tls.Config{Certificates: []tls.Certificate{certbundle}}
|
|
||||||
|
|
||||||
listener, err := tls.Listen("tcp", serverBinding, config)
|
|
||||||
if err != nil {
|
|
||||||
loginfo.Println("unable to bind ", serverBinding)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer listener.Close()
|
|
||||||
|
|
||||||
for {
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
loginfo.Println("Bad accept ", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
go handleConnection(conn, connectionTable, secretKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type protocol int
|
|
||||||
|
|
||||||
//Family -- ENUM for Address Family
|
|
||||||
const (
|
const (
|
||||||
protoHTTP protocol = iota + 1
|
encryptNone int = iota
|
||||||
protoHTTPS
|
encryptSSLV2
|
||||||
protoSSLV3
|
encryptSSLV3
|
||||||
protoTLSV1
|
encryptTLS10
|
||||||
protoTLSV11
|
encryptTLS11
|
||||||
protoTLSV2
|
encryptTLS12
|
||||||
)
|
)
|
||||||
|
|
||||||
//State -- state of connection
|
//GenericListenAndServe -- used to lisen for any https traffic on 443 (8443)
|
||||||
type State struct {
|
// - setup generic TCP listener, unencrypted TCP, with a Deadtime out
|
||||||
Protocol protocol
|
// - 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, connectionTable *connection.Table, secretKey string, serverBinding string, certbundle tls.Certificate, deadTime int) {
|
||||||
|
config := &tls.Config{Certificates: []tls.Certificate{certbundle}}
|
||||||
|
|
||||||
|
listenAddr, err := net.ResolveTCPAddr("tcp", serverBinding)
|
||||||
|
if nil != err {
|
||||||
|
loginfo.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := net.ListenTCP("tcp", listenAddr)
|
||||||
|
if err != nil {
|
||||||
|
loginfo.Println("unable to bind", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
loginfo.Println("Cancel signal hit")
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
ln.SetDeadline(time.Now().Add(time.Duration(deadTime) * time.Second))
|
||||||
|
|
||||||
|
conn, err := ln.Accept()
|
||||||
|
|
||||||
|
loginfo.Println("Deadtime reached")
|
||||||
|
|
||||||
|
if nil != err {
|
||||||
|
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wedgeConn := NewWedgeConn(conn)
|
||||||
|
go handleConnection(ctx, wedgeConn, connectionTable, secretKey, config)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewState -- Constructor
|
//handleConnection -
|
||||||
func NewState() (p *State) {
|
// - accept a wedgeConnection along with all the other required attritvues
|
||||||
p = new(State)
|
// - peek into the buffer, determine TLS or unencrypted
|
||||||
|
|
||||||
|
func handleConnection(ctx context.Context, wConn *WedgeConn, connectionTable *connection.Table, secretKey string, config *tls.Config) {
|
||||||
|
defer wConn.Close()
|
||||||
|
peekCnt := 10
|
||||||
|
|
||||||
|
encryptMode := encryptNone
|
||||||
|
|
||||||
|
loginfo.Println("conn", wConn, wConn.LocalAddr().String(), wConn.RemoteAddr().String())
|
||||||
|
peek, err := wConn.Peek(peekCnt)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
loginfo.Println("error while peeking")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loginfo.Println(hex.Dump(peek[0:peekCnt]))
|
||||||
|
loginfo.Println(hex.Dump(peek[2:4]))
|
||||||
|
loginfo.Println("after peek")
|
||||||
|
|
||||||
|
//take a look for a TLS header.
|
||||||
|
if bytes.Contains(peek[0:0], []byte{0x80}) && bytes.Contains(peek[2:4], []byte{0x01, 0x03}) {
|
||||||
|
encryptMode = encryptSSLV2
|
||||||
|
|
||||||
|
} else if bytes.Contains(peek[0:3], []byte{0x16, 0x03, 0x00}) {
|
||||||
|
encryptMode = encryptSSLV3
|
||||||
|
|
||||||
|
} else if bytes.Contains(peek[0:3], []byte{0x16, 0x03, 0x01}) {
|
||||||
|
encryptMode = encryptTLS10
|
||||||
|
loginfo.Println("TLS10")
|
||||||
|
|
||||||
|
} else if bytes.Contains(peek[0:3], []byte{0x16, 0x03, 0x02}) {
|
||||||
|
encryptMode = encryptTLS11
|
||||||
|
|
||||||
|
} else if bytes.Contains(peek[0:3], []byte{0x16, 0x03, 0x03}) {
|
||||||
|
encryptMode = encryptTLS12
|
||||||
|
}
|
||||||
|
|
||||||
|
oneConn := &oneConnListener{wConn}
|
||||||
|
|
||||||
|
if encryptMode == encryptSSLV2 {
|
||||||
|
loginfo.Println("SSLv2 is not accepted")
|
||||||
|
return
|
||||||
|
|
||||||
|
} else if encryptMode != encryptNone {
|
||||||
|
loginfo.Println("Handle Encryption")
|
||||||
|
tlsListener := tls.NewListener(oneConn, config)
|
||||||
|
|
||||||
|
conn, err := tlsListener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
loginfo.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loginfo.Println(conn)
|
||||||
|
handleStream(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loginfo.Println("Handle Unencrypted")
|
||||||
|
handleStream(wConn)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleConnection(conn net.Conn, connectionTable *connection.Table, secretKey string) {
|
func handleStream(conn net.Conn) {
|
||||||
defer conn.Close()
|
var buf [512]byte
|
||||||
|
cnt, err := conn.Read(buf[0:])
|
||||||
loginfo.Println("conn", conn)
|
if err != nil {
|
||||||
loginfo.Println("hank")
|
loginfo.Println(err)
|
||||||
loginfo.Println("here", conn.LocalAddr().String(), conn.RemoteAddr().String())
|
|
||||||
|
|
||||||
//state := NewState()
|
|
||||||
//wConn := NewWedgeConnSize(conn, 512)
|
|
||||||
//var buffer [512]byte
|
|
||||||
|
|
||||||
// Peek for data to figure out what connection we have
|
|
||||||
//peekcnt := 32
|
|
||||||
//peek, err := wConn.Peek(peekcnt)
|
|
||||||
|
|
||||||
//if err != nil {
|
|
||||||
// loginfo.Println("error while peeking")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//loginfo.Println(hex.Dump(peek[0:peekcnt]))
|
|
||||||
//loginfo.Println("after peek")
|
|
||||||
|
|
||||||
// assume http websocket.
|
|
||||||
|
|
||||||
//loginfo.Println("wConn", wConn)
|
|
||||||
|
|
||||||
//wedgeListener := &WedgeListener{conn: conn}
|
|
||||||
//LaunchWssListener(connectionTable, &secretKey, wedgeListener)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loginfo.Println(hex.Dump(buf[0:cnt]))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//state := NewState()
|
||||||
|
//wConn := NewWedgeConnSize(conn, 512)
|
||||||
|
//var buffer [512]byte
|
||||||
|
|
||||||
|
// Peek for data to figure out what connection we have
|
||||||
|
//peekcnt := 32
|
||||||
|
//peek, err := wConn.Peek(peekcnt)
|
||||||
|
|
||||||
|
//if err != nil {
|
||||||
|
// loginfo.Println("error while peeking")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//loginfo.Println(hex.Dump(peek[0:peekcnt]))
|
||||||
|
//loginfo.Println("after peek")
|
||||||
|
|
||||||
|
// assume http websocket.
|
||||||
|
|
||||||
|
//loginfo.Println("wConn", wConn)
|
||||||
|
|
||||||
|
//wedgeListener := &WedgeListener{conn: conn}
|
||||||
|
//LaunchWssListener(connectionTable, &secretKey, wedgeListener)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
//WedgeListener -- used to hand off connections to other protocols via Listen
|
//WedgeListener -- used to hand off connections to other protocols via Listen
|
||||||
type WedgeListener struct {
|
type WedgeListener struct {
|
||||||
|
net.Listener
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
once sync.Once
|
once sync.Once
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package genericlistener
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type oneConnListener struct {
|
||||||
|
conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *oneConnListener) Accept() (c net.Conn, err error) {
|
||||||
|
c = l.conn
|
||||||
|
|
||||||
|
if c == nil {
|
||||||
|
err = io.EOF
|
||||||
|
loginfo.Println("Accept")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = nil
|
||||||
|
l.conn = nil
|
||||||
|
loginfo.Println("Accept", c.LocalAddr().String(), c.RemoteAddr().String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *oneConnListener) Close() error {
|
||||||
|
loginfo.Println("close")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *oneConnListener) Addr() net.Addr {
|
||||||
|
loginfo.Println("addr")
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
package rvpnmain
|
package rvpnmain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/connection"
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/connection"
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/genericlistener"
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/genericlistener"
|
||||||
|
@ -20,17 +24,18 @@ var (
|
||||||
argServerBinding string
|
argServerBinding string
|
||||||
argServerAdminBinding string
|
argServerAdminBinding string
|
||||||
argServerExternalBinding string
|
argServerExternalBinding string
|
||||||
|
argDeadTime int
|
||||||
connectionTable *connection.Table
|
connectionTable *connection.Table
|
||||||
wssMapping *xlate.WssMapping
|
wssMapping *xlate.WssMapping
|
||||||
secretKey = "abc123"
|
secretKey = "abc123"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&argGenericBinding, "ssl-listener", ":8443", "generic SSL Listener")
|
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(&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(&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")
|
flag.StringVar(&argServerExternalBinding, "external-server-port", "127.0.0.1:8080", "external server Bind listener")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Run -- main entry point
|
//Run -- main entry point
|
||||||
|
@ -44,18 +49,35 @@ func Run() {
|
||||||
|
|
||||||
fmt.Println("-=-=-=-=-=-=-=-=-=-=")
|
fmt.Println("-=-=-=-=-=-=-=-=-=-=")
|
||||||
|
|
||||||
// certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// loginfo.Println(err)
|
loginfo.Println(err)
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// loginfo.Println(certbundle)
|
|
||||||
|
|
||||||
wssMapping = xlate.NewwssMapping()
|
ctx, cancelContext := context.WithCancel(context.Background())
|
||||||
go wssMapping.Run()
|
defer cancelContext()
|
||||||
|
|
||||||
connectionTable = connection.NewTable()
|
connectionTable = connection.NewTable()
|
||||||
go connectionTable.Run()
|
go connectionTable.Run(ctx)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
go genericlistener.GenericListenAndServe(ctx, connectionTable, secretKey, argGenericBinding, certbundle, argDeadTime)
|
||||||
|
|
||||||
|
time.Sleep(300 * time.Second)
|
||||||
|
cancelContext()
|
||||||
|
time.Sleep(60 * time.Second)
|
||||||
|
|
||||||
|
//wssMapping = xlate.NewwssMapping()
|
||||||
|
//go wssMapping.Run()
|
||||||
|
|
||||||
//go client.LaunchClientListener(connectionTable, &secretKey, &argServerBinding)
|
//go client.LaunchClientListener(connectionTable, &secretKey, &argServerBinding)
|
||||||
//go external.LaunchWebRequestExternalListener(&argServerExternalBinding, connectionTable)
|
//go external.LaunchWebRequestExternalListener(&argServerExternalBinding, connectionTable)
|
||||||
|
@ -65,5 +87,5 @@ func Run() {
|
||||||
// loginfo.Println("LauchAdminListener failed: ", err)
|
// loginfo.Println("LauchAdminListener failed: ", err)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
genericlistener.LaunchWssListener(connectionTable, secretKey, argWssClientListener, "certs/fullchain.pem", "certs/privkey.pem")
|
//genericlistener.LaunchWssListener(connectionTable, secretKey, argWssClientListener, "certs/fullchain.pem", "certs/privkey.pem")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue