From e47ecba6655e985137dff1fef195eb2e256a2513 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Tue, 25 Aug 2020 02:08:56 -0600 Subject: [PATCH] add client connection whitelist --- cmd/telebit/telebit.go | 43 +++++++++++++++++++++++++++++++++++++++--- iplist/iplist.go | 3 +++ websocket.go | 6 ++++-- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/cmd/telebit/telebit.go b/cmd/telebit/telebit.go index 7d47bd5..5a5c0ef 100644 --- a/cmd/telebit/telebit.go +++ b/cmd/telebit/telebit.go @@ -21,6 +21,7 @@ import ( telebit "git.rootprojects.org/root/telebit" "git.rootprojects.org/root/telebit/dbg" tbDns01 "git.rootprojects.org/root/telebit/dns01" + "git.rootprojects.org/root/telebit/iplist" "git.rootprojects.org/root/telebit/mgmt" "git.rootprojects.org/root/telebit/mgmt/authstore" "git.rootprojects.org/root/telebit/table" @@ -81,6 +82,7 @@ func main() { var forwards []Forward var portForwards []Forward + spfDomain := flag.String("spf-domain", "", "domain with SPF-like list of IP addresses which are allowed to connect to clients") // TODO replace the websocket connection with a mock server vendorID := flag.String("vendor-id", "", "a unique identifier for a deploy target environment") email := flag.String("acme-email", "", "email to use for Let's Encrypt / ACME registration") @@ -107,6 +109,14 @@ func main() { dbg.Debug = *verbose } + spfRecords := iplist.Init(*spfDomain) + if len(spfRecords) > 0 { + fmt.Println( + "Allow client connections from:", + strings.Join(spfRecords, " "), + ) + } + if len(os.Args) >= 2 { if "version" == os.Args[1] { fmt.Printf("telebit %s %s %s\n", GitVersion, GitRev[:7], GitTimestamp) @@ -477,8 +487,6 @@ func muxAll( fmt.Println(msg) mux.ForwardTCP(fwd.pattern, "localhost:"+fwd.port, 120*time.Second, msg, "[Port Forward]") } - // TODO close connection on invalid hostname - mux.HandleTCP("*", telebit.HandlerFunc(routeSubscribersAndClients), "[Tun => Remote Servers]") if 0 == len(*apiHostname) { *apiHostname = os.Getenv("API_HOSTNAME") @@ -506,6 +514,9 @@ func muxAll( }), "[Admin API & Server Relays]") } + // TODO close connection on invalid hostname + mux.HandleTCP("*", telebit.HandlerFunc(routeSubscribersAndClients), "[Tun => Remote Servers]") + if nil != grants { for i, domainname := range grants.Domains { fmt.Printf("[%d] Will decrypt remote requests to %q\n", i, domainname) @@ -544,7 +555,7 @@ func routeSubscribersAndClients(client net.Conn) error { case *telebit.ConnWrap: wconn = conn default: - panic("HandleTun is special in that it must receive &ConnWrap{ Conn: conn }") + panic("routeSubscribersAndClients is special in that it must receive &ConnWrap{ Conn: conn }") } // We know this to be two parts "ip:port" @@ -618,6 +629,32 @@ func tryToServeName(servername string, wconn *telebit.ConnWrap) bool { } return false } + // Note: timing can reveal if the client exists + + if allowAll, _ := iplist.IsAllowed(nil); !allowAll { + addr := wconn.RemoteAddr() + if nil == addr { + // handled by denial + wconn.Close() + return true + } + + remoteAddr := addr.String() + if "127.0.0.1" != remoteAddr && + "::1" != remoteAddr && + "localhost" != remoteAddr { + ipAddr := net.ParseIP(remoteAddr) + if nil == ipAddr { + wconn.Close() + return true + } + + if ok, err := iplist.IsAllowed(ipAddr); !ok || nil != err { + wconn.Close() + return true + } + } + } // async so that the call stack can complete and be released //srv.clients.Store(wconn.LocalAddr().String(), wconn) diff --git a/iplist/iplist.go b/iplist/iplist.go index c1d4a68..78cecaa 100644 --- a/iplist/iplist.go +++ b/iplist/iplist.go @@ -92,6 +92,9 @@ func IsAllowed(remoteIP net.IP) (bool, error) { if 0 == len(fields) { return true, nil } + if nil == remoteIP { + return false, nil + } for _, section := range fields { parts := strings.Split(section, ":") diff --git a/websocket.go b/websocket.go index 596663f..b8b0024 100644 --- a/websocket.go +++ b/websocket.go @@ -186,14 +186,16 @@ func (wsw *WebsocketTunnel) Close() error { func (wsw *WebsocketTunnel) LocalAddr() net.Addr { // TODO do we reverse this since the "local" address is that of the relay? // return wsw.wsconn.RemoteAddr() - panic("no LocalAddr() implementation") + fmt.Fprintf(os.Stderr, "no LocalAddr() implementation\n") + return nil } // RemoteAddr is not implemented and will panic. Additionally, it wouldn't mean anything useful anyway. func (wsw *WebsocketTunnel) RemoteAddr() net.Addr { // TODO do we reverse this since the "remote" address means nothing / is that of one of the clients? // return wsw.wsconn.LocalAddr() - panic("no RemoteAddr() implementation") + fmt.Fprintf(os.Stderr, "no RemoteAddr() implementation\n") + return nil } // SetDeadline sets the read and write deadlines associated