wip: SNI detection: add Peek()
This commit is contained in:
parent
d0910ed07e
commit
8ae19f341b
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue