Support for generic listeners, with protocol detection
- connectionWedge supports reading from a connection without consuming bytes (peeking) - allowing protocol detection - was still connections to 3502, it will support any port (443), admin follows this port. - matches RVPN.DAPLIE.INVALID and redirects to admin — AJ to provide authentication framework. - api/servers is also served by this path as we’ll. - listener_generic is the beginngins of protocol detections. - listener_wedge is an matches the net.Listener interface, and allows passing to other processes an already accepted connection - this does not work for HTTP for some reason. - spent a lot of time trying to figure out why. Posted to go-nuts
This commit is contained in:
parent
b179ecef0c
commit
d611757b10
|
@ -0,0 +1,43 @@
|
||||||
|
package genericlistener
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/hex"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
//WedgeConn -- A buffered IO infront of a connection allowing peeking, and switching connections.
|
||||||
|
type WedgeConn struct {
|
||||||
|
reader *bufio.Reader
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewWedgeConn -- Constructor
|
||||||
|
func NewWedgeConn(c net.Conn) (p *WedgeConn) {
|
||||||
|
p = new(WedgeConn)
|
||||||
|
p.reader = bufio.NewReader(c)
|
||||||
|
p.Conn = c
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewWedgeConnSize -- Constructor
|
||||||
|
func NewWedgeConnSize(c net.Conn, size int) (p *WedgeConn) {
|
||||||
|
p = new(WedgeConn)
|
||||||
|
p.reader = bufio.NewReaderSize(c, size)
|
||||||
|
p.Conn = c
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Peek - Get a number of bytes outof the buffer, but allow the buffer to be repled once read
|
||||||
|
func (w *WedgeConn) Peek(n int) ([]byte, error) {
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
package genericlistener
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
|
||||||
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/admin"
|
||||||
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/connection"
|
||||||
|
)
|
||||||
|
|
||||||
|
//LaunchWssListener - obtains a onetime connection from wedge listener
|
||||||
|
func LaunchWssListener(connectionTable *connection.Table, secretKey string, serverBind string, certfile string, keyfile string) (err error) {
|
||||||
|
loginfo.Println("starting LaunchWssListener ")
|
||||||
|
|
||||||
|
router := mux.NewRouter().StrictSlash(true)
|
||||||
|
|
||||||
|
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
loginfo.Println("HandleFunc /")
|
||||||
|
switch url := r.URL.Path; url {
|
||||||
|
case "/":
|
||||||
|
// check to see if we are using the administrative Host
|
||||||
|
if strings.Contains(r.Host, "rvpn.daplie.invalid") {
|
||||||
|
http.Redirect(w, r, "/admin", 301)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleConnectionWebSocket(connectionTable, w, r, secretKey, false)
|
||||||
|
|
||||||
|
default:
|
||||||
|
http.Error(w, "Not Found", 404)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.HandleFunc("/admin", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "Welcome!")
|
||||||
|
})
|
||||||
|
|
||||||
|
router.HandleFunc("/api/servers", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Println("here")
|
||||||
|
serverContainer := admin.NewServerAPIContainer()
|
||||||
|
|
||||||
|
for c := range connectionTable.Connections() {
|
||||||
|
serverAPI := admin.NewServerAPI(c)
|
||||||
|
serverContainer.Servers = append(serverContainer.Servers, serverAPI)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
json.NewEncoder(w).Encode(serverContainer)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: serverBind,
|
||||||
|
Handler: router,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.ListenAndServeTLS(certfile, keyfile)
|
||||||
|
if err != nil {
|
||||||
|
loginfo.Println("ListenAndServeTLS: ", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleConnectionWebSocket handles websocket requests from the peer.
|
||||||
|
func handleConnectionWebSocket(connectionTable *connection.Table, w http.ResponseWriter, r *http.Request, secretKey string, admin bool) {
|
||||||
|
loginfo.Println("websocket opening ", r.RemoteAddr, " ", r.Host)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
w.Write([]byte("Not Authorized"))
|
||||||
|
loginfo.Println("access_token invalid...closing connection")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loginfo.Println("help access_token valid")
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
package genericlistener
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
|
"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
|
||||||
|
)
|
||||||
|
|
||||||
|
//State -- state of connection
|
||||||
|
type State struct {
|
||||||
|
Protocol protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewState -- Constructor
|
||||||
|
func NewState() (p *State) {
|
||||||
|
p = new(State)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleConnection(conn net.Conn, connectionTable *connection.Table, secretKey string) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
loginfo.Println("conn", conn)
|
||||||
|
loginfo.Println("hank")
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package genericlistener
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
//WedgeListener -- used to hand off connections to other protocols via Listen
|
||||||
|
type WedgeListener struct {
|
||||||
|
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()
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package genericlistener
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
loginfo *log.Logger
|
||||||
|
logdebug *log.Logger
|
||||||
|
logFlags = log.Ldate | log.Lmicroseconds | log.Lshortfile
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
loginfo = log.New(os.Stdout, "INFO: external: ", logFlags)
|
||||||
|
logdebug = log.New(os.Stdout, "DEBUG: external:", logFlags)
|
||||||
|
}
|
|
@ -6,11 +6,8 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/admin"
|
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/client"
|
|
||||||
"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/external"
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/genericlistener"
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/packer"
|
|
||||||
"git.daplie.com/Daplie/go-rvpn-server/rvpn/xlate"
|
"git.daplie.com/Daplie/go-rvpn-server/rvpn/xlate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,6 +15,8 @@ var (
|
||||||
loginfo *log.Logger
|
loginfo *log.Logger
|
||||||
logdebug *log.Logger
|
logdebug *log.Logger
|
||||||
logFlags = log.Ldate | log.Lmicroseconds | log.Lshortfile
|
logFlags = log.Ldate | log.Lmicroseconds | log.Lshortfile
|
||||||
|
argWssClientListener string
|
||||||
|
argGenericBinding string
|
||||||
argServerBinding string
|
argServerBinding string
|
||||||
argServerAdminBinding string
|
argServerAdminBinding string
|
||||||
argServerExternalBinding string
|
argServerExternalBinding string
|
||||||
|
@ -27,7 +26,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&argServerBinding, "server-port", ":3502", "server Bind listener")
|
flag.StringVar(&argGenericBinding, "ssl-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(&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")
|
||||||
|
|
||||||
|
@ -42,24 +42,28 @@ func Run() {
|
||||||
|
|
||||||
loginfo.Println("startup")
|
loginfo.Println("startup")
|
||||||
|
|
||||||
p := packer.NewPacker()
|
|
||||||
p.Header.SetAddress("127.0.0.2")
|
|
||||||
p.Header.Port = 32768
|
|
||||||
p.Data.AppendString("A test message")
|
|
||||||
p.PackV1()
|
|
||||||
|
|
||||||
fmt.Println("-=-=-=-=-=-=-=-=-=-=")
|
fmt.Println("-=-=-=-=-=-=-=-=-=-=")
|
||||||
|
|
||||||
|
// certbundle, err := tls.LoadX509KeyPair("certs/fullchain.pem", "certs/privkey.pem")
|
||||||
|
// if err != nil {
|
||||||
|
// loginfo.Println(err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// loginfo.Println(certbundle)
|
||||||
|
|
||||||
wssMapping = xlate.NewwssMapping()
|
wssMapping = xlate.NewwssMapping()
|
||||||
go wssMapping.Run()
|
go wssMapping.Run()
|
||||||
|
|
||||||
connectionTable = connection.NewTable()
|
connectionTable = connection.NewTable()
|
||||||
go connectionTable.Run()
|
go connectionTable.Run()
|
||||||
go client.LaunchClientListener(connectionTable, &secretKey, &argServerBinding)
|
|
||||||
|
//go client.LaunchClientListener(connectionTable, &secretKey, &argServerBinding)
|
||||||
//go external.LaunchWebRequestExternalListener(&argServerExternalBinding, connectionTable)
|
//go external.LaunchWebRequestExternalListener(&argServerExternalBinding, connectionTable)
|
||||||
go external.LaunchExternalServer(argServerExternalBinding, connectionTable)
|
//go external.LaunchExternalServer(argServerExternalBinding, connectionTable)
|
||||||
err := admin.LaunchAdminListener(&argServerAdminBinding, connectionTable)
|
//err = admin.LaunchAdminListener(&argServerAdminBinding, connectionTable)
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
loginfo.Println("LauchAdminListener failed: ", err)
|
// loginfo.Println("LauchAdminListener failed: ", err)
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
genericlistener.LaunchWssListener(connectionTable, secretKey, argWssClientListener, "certs/fullchain.pem", "certs/privkey.pem")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue