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 "time"
|
||||
import "context"
|
||||
|
||||
const (
|
||||
initialDomains = 0
|
||||
|
@ -62,13 +63,18 @@ func (c *Table) reaper(delay int, idle int) {
|
|||
}
|
||||
|
||||
//Run -- Execute
|
||||
func (c *Table) Run() {
|
||||
func (c *Table) Run(ctx context.Context) {
|
||||
loginfo.Println("ConnectionTable starting")
|
||||
|
||||
go c.reaper(300, 60)
|
||||
|
||||
for {
|
||||
select {
|
||||
|
||||
case <-ctx.Done():
|
||||
loginfo.Println("Cancel signal hit")
|
||||
return
|
||||
|
||||
case registration := <-c.register:
|
||||
loginfo.Println("register fired")
|
||||
|
||||
|
|
|
@ -1,67 +1,148 @@
|
|||
package genericlistener
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"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 (
|
||||
protoHTTP protocol = iota + 1
|
||||
protoHTTPS
|
||||
protoSSLV3
|
||||
protoTLSV1
|
||||
protoTLSV11
|
||||
protoTLSV2
|
||||
encryptNone int = iota
|
||||
encryptSSLV2
|
||||
encryptSSLV3
|
||||
encryptTLS10
|
||||
encryptTLS11
|
||||
encryptTLS12
|
||||
)
|
||||
|
||||
//State -- state of connection
|
||||
type State struct {
|
||||
Protocol protocol
|
||||
}
|
||||
//GenericListenAndServe -- used to lisen for any https traffic on 443 (8443)
|
||||
// - setup generic TCP listener, unencrypted TCP, with a Deadtime out
|
||||
// - 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}}
|
||||
|
||||
//NewState -- Constructor
|
||||
func NewState() (p *State) {
|
||||
p = new(State)
|
||||
listenAddr, err := net.ResolveTCPAddr("tcp", serverBinding)
|
||||
if nil != err {
|
||||
loginfo.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
func handleConnection(conn net.Conn, connectionTable *connection.Table, secretKey string) {
|
||||
defer conn.Close()
|
||||
ln, err := net.ListenTCP("tcp", listenAddr)
|
||||
if err != nil {
|
||||
loginfo.Println("unable to bind", err)
|
||||
return
|
||||
}
|
||||
|
||||
loginfo.Println("conn", conn)
|
||||
loginfo.Println("hank")
|
||||
loginfo.Println("here", conn.LocalAddr().String(), conn.RemoteAddr().String())
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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) {
|
||||
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
|
||||
}
|
||||
|
||||
func handleStream(conn net.Conn) {
|
||||
var buf [512]byte
|
||||
cnt, err := conn.Read(buf[0:])
|
||||
if err != nil {
|
||||
loginfo.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
loginfo.Println(hex.Dump(buf[0:cnt]))
|
||||
|
||||
}
|
||||
|
||||
//state := NewState()
|
||||
//wConn := NewWedgeConnSize(conn, 512)
|
||||
|
@ -84,6 +165,3 @@ func handleConnection(conn net.Conn, connectionTable *connection.Table, secretKe
|
|||
|
||||
//wedgeListener := &WedgeListener{conn: conn}
|
||||
//LaunchWssListener(connectionTable, &secretKey, wedgeListener)
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
//WedgeListener -- used to hand off connections to other protocols via Listen
|
||||
type WedgeListener struct {
|
||||
net.Listener
|
||||
conn net.Conn
|
||||
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
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
|
||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/connection"
|
||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/genericlistener"
|
||||
|
@ -20,17 +24,18 @@ var (
|
|||
argServerBinding string
|
||||
argServerAdminBinding string
|
||||
argServerExternalBinding string
|
||||
argDeadTime int
|
||||
connectionTable *connection.Table
|
||||
wssMapping *xlate.WssMapping
|
||||
secretKey = "abc123"
|
||||
)
|
||||
|
||||
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(&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")
|
||||
|
||||
}
|
||||
|
||||
//Run -- main entry point
|
||||
|
@ -44,18 +49,35 @@ func Run() {
|
|||
|
||||
fmt.Println("-=-=-=-=-=-=-=-=-=-=")
|
||||
|
||||
// certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
||||
// if err != nil {
|
||||
// loginfo.Println(err)
|
||||
// return
|
||||
// }
|
||||
// loginfo.Println(certbundle)
|
||||
certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
||||
if err != nil {
|
||||
loginfo.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
wssMapping = xlate.NewwssMapping()
|
||||
go wssMapping.Run()
|
||||
ctx, cancelContext := context.WithCancel(context.Background())
|
||||
defer cancelContext()
|
||||
|
||||
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 external.LaunchWebRequestExternalListener(&argServerExternalBinding, connectionTable)
|
||||
|
@ -65,5 +87,5 @@ func Run() {
|
|||
// 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