wip: SNI detection: add Peek()

This commit is contained in:
AJ ONeal 2020-06-06 03:43:56 -06:00
parent d0910ed07e
commit 8ae19f341b
3 changed files with 46 additions and 3 deletions

View File

@ -1,6 +1,7 @@
package telebit package telebit
import ( import (
"bufio"
"net" "net"
"time" "time"
) )
@ -16,6 +17,7 @@ var encryptedSchemes = map[string]struct{}{
type Conn struct { type Conn struct {
relaySourceAddr Addr relaySourceAddr Addr
relayTargetAddr Addr relayTargetAddr Addr
peeker *bufio.Reader
relay net.Conn relay net.Conn
local net.Conn local net.Conn
//terminated bool //terminated bool
@ -37,9 +39,19 @@ func NewConn(conn *Conn) *Conn {
// Read can be made to time out and return an Error with Timeout() == true // Read can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline. // after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *Conn) Read(b []byte) (n int, err error) { func (c *Conn) Read(b []byte) (n int, err error) {
if nil != c.peeker {
return c.peeker.Read(b)
}
return c.relay.Read(b) return c.relay.Read(b)
} }
func (c *Conn) Peek(n int) (b []byte, err error) {
if nil == c.peeker {
c.peeker = bufio.NewReaderSize(c, defaultPeekerSize)
}
return c.peeker.Peek(n)
}
// Write writes data to the connection. // Write writes data to the connection.
// Write can be made to time out and return an Error with Timeout() == true // Write can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetWriteDeadline. // after a fixed time limit; see SetDeadline and SetWriteDeadline.

View File

@ -1,17 +1,46 @@
package telebit package telebit
import ( import (
"bufio"
"net" "net"
"time" "time"
) )
// ConnWrap is just a cheap way to DRY up some switch conn.(type) statements to handle special features of Conn // ConnWrap is just a cheap way to DRY up some switch conn.(type) statements to handle special features of Conn
type ConnWrap struct { type ConnWrap struct {
Conn net.Conn //Conn net.Conn
Plain net.Conn peeker *bufio.Reader
Conn net.Conn
Plain net.Conn
}
type Peeker interface {
Peek(n int) ([]byte, error)
}
func (c *ConnWrap) Peek(n int) ([]byte, error) {
if nil != c.peeker {
return c.peeker.Peek(n)
}
switch conn := c.Conn.(type) {
case *ConnWrap:
return conn.Peek(n)
case *Conn:
return conn.Peek(n)
default:
// *net.UDPConn,*net.TCPConn,*net.IPConn,*net.UnixConn
if nil == c.peeker {
c.peeker = bufio.NewReaderSize(c, defaultPeekerSize)
}
return c.peeker.Peek(n)
}
} }
func (c *ConnWrap) Read(b []byte) (n int, err error) { func (c *ConnWrap) Read(b []byte) (n int, err error) {
if nil != c.peeker {
return c.peeker.Read(b)
}
return c.Conn.Read(b) return c.Conn.Read(b)
} }
@ -48,7 +77,7 @@ func (c *ConnWrap) Scheme() string {
func (c *ConnWrap) Servername() string { func (c *ConnWrap) Servername() string {
if nil != c.Plain { if nil != c.Plain {
tlsConn := &ConnWrap{Conn: c.Plain} tlsConn := &ConnWrap{Conn: c.Plain}
return tlsConn.Scheme() return tlsConn.Servername()
} }
switch conn := c.Conn.(type) { switch conn := c.Conn.(type) {
@ -63,6 +92,7 @@ func (c *ConnWrap) Servername() string {
// isTerminated returns true if net.Conn is either a ConnWrap{ tls.Conn }, // 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". // or a telebit.Conn with a non-encrypted `scheme` such as "tcp" or "http".
func (c *ConnWrap) isTerminated() bool { func (c *ConnWrap) isTerminated() bool {
// TODO look at SNI, may need context for Peek() timeout
if nil != c.Plain { if nil != c.Plain {
return true return true
} }

View File

@ -22,6 +22,7 @@ import (
// Nerds posting benchmarks on SO show that 8k seems about right, // Nerds posting benchmarks on SO show that 8k seems about right,
// but even 1024b could work well. // but even 1024b could work well.
var defaultBufferSize = 8192 var defaultBufferSize = 8192
var defaultPeekerSize = 1024
// ErrBadGateway means that the target did not accept the connection // ErrBadGateway means that the target did not accept the connection
var ErrBadGateway = errors.New("EBADGATEWAY") var ErrBadGateway = errors.New("EBADGATEWAY")