telebit/routemux.go

235 lines
6.1 KiB
Go
Raw Normal View History

2020-05-22 10:41:24 +00:00
package telebit
2020-05-21 10:29:05 +00:00
import (
2020-07-08 10:28:32 +00:00
"errors"
2020-05-22 10:07:35 +00:00
"fmt"
"net"
2020-07-21 06:35:45 +00:00
"os"
"strconv"
"strings"
2020-05-21 10:29:05 +00:00
"time"
2020-07-21 06:35:45 +00:00
"git.rootprojects.org/root/telebit/dbg"
2020-05-21 10:29:05 +00:00
)
// A RouteMux is a net.Conn multiplexer.
//
// It matches the port, domain, or connection type of a connection
// and selects the matching handler.
type RouteMux struct {
defaultTimeout time.Duration
2020-05-27 08:53:26 +00:00
routes []meta
2020-05-21 10:29:05 +00:00
}
2020-07-15 09:33:23 +00:00
// ErrNotHandled is returned when the next middleware in the stack should take over
2020-07-08 10:28:32 +00:00
var ErrNotHandled = errors.New("connection not handled")
2020-05-21 10:29:05 +00:00
type meta struct {
2020-05-22 10:07:35 +00:00
addr string
handler Handler
terminate bool
2020-07-15 09:33:23 +00:00
comment string
2020-05-21 10:29:05 +00:00
}
// NewRouteMux allocates and returns a new RouteMux.
func NewRouteMux() *RouteMux {
mux := &RouteMux{
defaultTimeout: 45 * time.Second,
}
return mux
}
// Serve dispatches the connection to the handler whose selectors matches the attributes.
2020-05-22 10:07:35 +00:00
func (m *RouteMux) Serve(client net.Conn) error {
2020-07-21 06:35:45 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "\n\n[debug] mux.Serve(client)\n")
}
2020-07-15 09:33:23 +00:00
var wconn *ConnWrap
switch conn := client.(type) {
case *ConnWrap:
wconn = conn
default:
wconn = &ConnWrap{Conn: client}
}
var servername string
var port string
// TODO go back to Servername on conn, but with SNI
//servername := wconn.Servername()
fam := wconn.LocalAddr().Network()
if "tun" == fam {
switch laddr := wconn.LocalAddr().(type) {
case *Addr:
servername = laddr.Hostname()
port = ":" + strconv.Itoa(laddr.Port())
2020-07-15 09:33:23 +00:00
connServername := wconn.CheckServername()
if "" == connServername {
wconn.SetServername(servername)
} else {
2020-07-21 09:29:49 +00:00
if connServername != servername {
fmt.Fprintf(
os.Stderr,
"[mux] Mismatch Servername: (current) %s != (new) %s\n",
connServername, servername,
)
}
2020-07-15 09:33:23 +00:00
wconn.SetServername(servername)
//panic(errors.New("Can't SetServername() over existing servername"))
}
default:
panic("impossible type switch: Addr is 'tun' but didn't match")
}
} else {
// TODO make an AddrWrap to do this switch
addr := wconn.LocalAddr().String()
parts := strings.Split(addr, ":")
port = ":" + parts[len(parts)-1]
servername = strings.Join(parts[:len(parts)-1], ":")
}
2020-07-21 07:59:32 +00:00
fmt.Println("\nAddr:", fam, servername, port)
2020-05-21 10:29:05 +00:00
2020-05-27 08:53:26 +00:00
for _, meta := range m.routes {
// TODO '*.example.com'
2020-06-22 06:34:42 +00:00
if meta.terminate {
servername = wconn.Servername()
2020-06-09 10:41:38 +00:00
}
if servername == meta.addr || "*" == meta.addr || port == meta.addr {
2020-07-21 06:35:45 +00:00
//fmt.Fprintf(os.Stderr, "[debug] test of route: %v\n", meta)
2020-07-08 10:28:32 +00:00
// Only keep trying handlers if ErrNotHandled was returned
if err := meta.handler.Serve(wconn); ErrNotHandled != err {
2020-07-21 07:59:32 +00:00
fmt.Printf(
"[mux] Match: %s\n\tmeta.addr=%s\n\tservername=%s\n",
meta.comment, meta.addr, servername,
)
2020-05-21 10:29:05 +00:00
return err
}
2020-07-21 07:59:32 +00:00
if dbg.Debug {
fmt.Fprintf(
os.Stderr,
"[debug] [mux] Failed match: %s meta.addr=%s servername=%s\n",
meta.comment, meta.addr, servername,
)
}
} else if dbg.Debug {
fmt.Fprintf(
os.Stderr,
"[debug] [mux] Skip (no match): %s meta.addr=%s servername=%s\n",
meta.comment, meta.addr, servername,
)
2020-05-21 10:29:05 +00:00
}
}
2020-07-19 06:52:31 +00:00
fmt.Printf("No match found for %q %q\n", wconn.Scheme(), wconn.Servername())
2020-05-21 10:29:05 +00:00
return client.Close()
2020-07-15 09:33:23 +00:00
// TODO Chi-style route handling
/*
routes := m.routes
next := func() error {
if 0 == len(routes) {
fmt.Println("No match found for", wconn.Scheme(), wconn.Servername())
return client.Close()
}
route := routes[0]
routes := routes[1:]
handled := false
handler := meta.handler(func () {
if !handled {
handled = true
next()
}
})
return handler.Serve(client)
}
return next()
*/
2020-05-21 10:29:05 +00:00
}
// ForwardTCP creates and returns a connection to a local handler target.
2020-07-15 09:33:23 +00:00
func (m *RouteMux) ForwardTCP(servername string, target string, timeout time.Duration, comment ...string) error {
2020-05-21 10:29:05 +00:00
// TODO check servername
2020-05-27 08:53:26 +00:00
m.routes = append(m.routes, meta{
2020-05-22 10:07:35 +00:00
addr: servername,
terminate: false,
handler: NewForwarder(target, timeout),
2020-07-15 09:33:23 +00:00
comment: append(comment, "")[0],
2020-05-21 10:29:05 +00:00
})
return nil
}
2020-08-13 08:34:39 +00:00
func (m *RouteMux) ReverseProxyHTTPS(servername string, target string, timeout time.Duration, comment ...string) error {
m.routes = append(m.routes, meta{
addr: servername,
terminate: false,
handler: NewTheatricalProxier(target, timeout),
comment: append(comment, "")[0],
})
return nil
}
2020-07-21 09:29:49 +00:00
func (m *RouteMux) ReverseProxyHTTP(servername string, target string, timeout time.Duration, comment ...string) error {
m.routes = append(m.routes, meta{
addr: servername,
terminate: false,
handler: NewReverseProxier(target, timeout),
comment: append(comment, "")[0],
})
return nil
}
2020-05-21 10:29:05 +00:00
// HandleTCP creates and returns a connection to a local handler target.
2020-07-15 09:33:23 +00:00
func (m *RouteMux) HandleTCP(servername string, handler Handler, comment ...string) error {
2020-05-21 10:29:05 +00:00
// TODO check servername
2020-05-27 08:53:26 +00:00
m.routes = append(m.routes, meta{
2020-05-22 10:07:35 +00:00
addr: servername,
terminate: false,
handler: handler,
2020-07-15 09:33:23 +00:00
comment: append(comment, "")[0],
2020-05-21 10:29:05 +00:00
})
return nil
}
// HandleTLS creates and returns a connection to a local handler target.
2020-07-15 09:33:23 +00:00
func (m *RouteMux) HandleTLS(servername string, acme *ACME, next Handler, comment ...string) error {
2020-05-22 10:07:35 +00:00
// TODO check servername
2020-05-27 08:53:26 +00:00
m.routes = append(m.routes, meta{
2020-05-22 10:07:35 +00:00
addr: servername,
terminate: true,
handler: HandlerFunc(func(client net.Conn) error {
var wconn *ConnWrap
switch conn := client.(type) {
case *ConnWrap:
wconn = conn
default:
panic("HandleTLS is special in that it must receive &ConnWrap{ Conn: conn }")
}
2020-07-08 10:28:32 +00:00
if !wconn.isEncrypted() {
2020-07-21 06:35:45 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] HandleTLS: conn is not encrypted\n")
}
2020-07-15 09:33:23 +00:00
// TODO handle underlying Peek() timeout error
2020-07-08 10:28:32 +00:00
return ErrNotHandled
2020-05-22 10:07:35 +00:00
}
2020-07-21 06:35:45 +00:00
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] HandleTLS: decrypted connection, recursing\n")
}
2020-05-22 10:07:35 +00:00
//NewTerminator(acme, handler)(client)
//return handler.Serve(client)
2020-07-21 09:29:49 +00:00
go func() {
if err := next.Serve(TerminateTLS(wconn, acme)); nil != err {
fmt.Fprintf(os.Stderr, "error Terminating TLS: %s\n", err)
}
}()
// at this point, we've handled it
// TODO could we move termination further in?
return nil
2020-05-22 10:07:35 +00:00
}),
2020-07-15 09:33:23 +00:00
comment: append(comment, "")[0],
2020-05-22 10:07:35 +00:00
})
return nil
2020-05-21 10:29:05 +00:00
}