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-06-09 08:42:56 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2020-05-21 10:29:05 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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-15 09:33:23 +00:00
|
|
|
fmt.Println("\n\n[debug] mux.Serve(client)")
|
|
|
|
|
2020-06-09 08:42:56 +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 {
|
|
|
|
fmt.Printf("Has servername: current=%s new=%s\n", connServername, servername)
|
|
|
|
wconn.SetServername(servername)
|
|
|
|
//panic(errors.New("Can't SetServername() over existing servername"))
|
|
|
|
}
|
2020-06-09 08:42:56 +00:00
|
|
|
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], ":")
|
|
|
|
}
|
|
|
|
fmt.Println("Addr:", fam, servername, port)
|
2020-05-21 10:29:05 +00:00
|
|
|
|
2020-05-27 08:53:26 +00:00
|
|
|
for _, meta := range m.routes {
|
2020-06-09 08:42:56 +00:00
|
|
|
// 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
|
|
|
}
|
2020-07-15 09:33:23 +00:00
|
|
|
fmt.Println("\nMeta:", meta.comment, "meta.addr="+meta.addr, "servername="+servername)
|
2020-06-09 08:42:56 +00:00
|
|
|
if servername == meta.addr || "*" == meta.addr || port == meta.addr {
|
2020-05-22 10:34:37 +00:00
|
|
|
//fmt.Println("[debug] test of route:", 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-05-21 10:29:05 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2020-06-09 08:42:56 +00:00
|
|
|
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-15 09:33:23 +00:00
|
|
|
fmt.Println("[debug] HandleTLS: conn is not encrypted")
|
|
|
|
// 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-06-09 08:42:56 +00:00
|
|
|
|
2020-07-15 09:33:23 +00:00
|
|
|
fmt.Println("[debug] HandleTLS: decrypted connection, recursing")
|
2020-07-12 05:59:34 +00:00
|
|
|
|
2020-05-22 10:07:35 +00:00
|
|
|
//NewTerminator(acme, handler)(client)
|
|
|
|
//return handler.Serve(client)
|
2020-07-15 09:33:23 +00:00
|
|
|
return next.Serve(TerminateTLS(wconn, acme))
|
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
|
|
|
}
|