fix accidental early client.Close()

This commit is contained in:
AJ ONeal 2020-07-08 10:28:32 +00:00
parent c951ce1254
commit 2f1f138bda
5 changed files with 29 additions and 45 deletions

View File

@ -251,9 +251,9 @@ func main() {
fmt.Printf("[debug] Accepting API or WebSocket client %q\n", *apiHostname)
listener.Feed(client)
fmt.Printf("[debug] done with %q client\n", *apiHostname)
// TODO use a more correct non-error error?
// or perhaps (ok, error) or (handled, error)?
return io.EOF
// nil now means handler in-progress (go routine)
// EOF now means handler finished
return nil
}))
}
for _, fwd := range forwards {
@ -369,7 +369,8 @@ func routeSubscribersAndClients(client net.Conn) error {
labels := strings.Split(servername, ".")
n := len(labels)
if n < 3 {
return nil
// skip
return telebit.ErrNotHandled
}
for i := 1; i < n-1; i++ {
wildname := "*." + strings.Join(labels[1:], ".")
@ -379,7 +380,7 @@ func routeSubscribersAndClients(client net.Conn) error {
}
// skip
return nil
return telebit.ErrNotHandled
}
// tryToServeName picks the server tunnel with the least connections, if any

View File

@ -117,28 +117,21 @@ func (c *ConnWrap) Servername() string {
}
// this will get the servername
c.isTerminated()
_ = c.isEncrypted()
return c.servername
}
// isTerminated returns true if net.Conn is either a ConnWrap{ tls.Conn },
// or a telebit.Conn with a non-encrypted `scheme` such as "tcp" or "http".
func (c *ConnWrap) isTerminated() bool {
// TODO look at SNI, may need context for Peek() timeout
/*
if nil != c.Plain {
return true
}
*/
// isEncrypted returns true if peeking at net.Conn reveals that it is TLS-encrypted
func (c *ConnWrap) isEncrypted() bool {
if nil != c.encrypted {
return !*c.encrypted
return *c.encrypted
}
// how to know how many bytes to read? really needs timeout
// TODO: how to allow / detect / handle protocols where the server hello happens first?
c.SetDeadline(time.Now().Add(5 * time.Second))
n := 6
b, _ := c.Peek(n)
fmt.Println("Peek(n)", b, string(b))
fmt.Println("[debug] Peek(n)", b, string(b))
defer c.SetDeadline(time.Time{})
var encrypted bool
if len(b) >= n {
@ -155,30 +148,16 @@ func (c *ConnWrap) isTerminated() bool {
b, err := c.Peek(n - 1 + length)
if nil != err {
c.encrypted = &encrypted
return !*c.encrypted
return *c.encrypted
}
c.servername, _ = sni.GetHostname(b)
encrypted = true
c.encrypted = &encrypted
return !*c.encrypted
return *c.encrypted
}
}
c.encrypted = &encrypted
return !*c.encrypted
/*
if nil != err {
return true
}
switch conn := c.Conn.(type) {
case *ConnWrap:
return conn.isTerminated()
case *Conn:
_, ok := encryptedSchemes[string(conn.relayTargetAddr.scheme)]
return !ok
}
return false
*/
return *c.encrypted
}
// LocalAddr returns the local network address.

View File

@ -76,13 +76,16 @@ func Serve(listener net.Listener, mux Handler) error {
}
go func() {
err = mux.Serve(client)
if nil != err {
// nil means being handled
// non-nil means handled
// io.EOF means handled with success
if err := mux.Serve(client); nil != err {
if io.EOF != err && io.ErrClosedPipe != err && !strings.Contains(err.Error(), errNetClosing) {
fmt.Printf("client could not be served: %q\n", err.Error())
}
fmt.Println("[debug] closing original client", err)
client.Close()
}
client.Close()
}()
}
}

View File

@ -1,6 +1,7 @@
package telebit
import (
"errors"
"fmt"
"io"
"net"
@ -18,6 +19,8 @@ type RouteMux struct {
routes []meta
}
var ErrNotHandled = errors.New("connection not handled")
type meta struct {
addr string
handler Handler
@ -72,11 +75,10 @@ func (m *RouteMux) Serve(client net.Conn) error {
fmt.Println("Meta:", meta.addr, servername)
if servername == meta.addr || "*" == meta.addr || port == meta.addr {
//fmt.Println("[debug] test of route:", meta)
if err := meta.handler.Serve(wconn); nil != err {
// error should be EOF if successful
// Only keep trying handlers if ErrNotHandled was returned
if err := meta.handler.Serve(wconn); ErrNotHandled != err {
return err
}
// nil err means skipped
}
}
@ -121,9 +123,8 @@ func (m *RouteMux) HandleTLS(servername string, acme *ACME, handler Handler) err
panic("HandleTLS is special in that it must receive &ConnWrap{ Conn: conn }")
}
if wconn.isTerminated() {
// nil to skip
return nil
if !wconn.isEncrypted() {
return ErrNotHandled
}
//NewTerminator(acme, handler)(client)

View File

@ -253,7 +253,7 @@ func TerminateTLS(client net.Conn, acme *ACME) net.Conn {
wconn := &ConnWrap{
Conn: client,
}
wconn.isTerminated()
_ = wconn.isEncrypted()
servername = wconn.Servername()
scheme = wconn.Scheme()
client = wconn