add full SNI peeking, fix TLS routing
This commit is contained in:
parent
1872302d66
commit
2b48a8b8b9
|
@ -208,8 +208,8 @@ func main() {
|
||||||
}
|
}
|
||||||
mux.HandleTLS("*", acme, mux)
|
mux.HandleTLS("*", acme, mux)
|
||||||
for _, fwd := range forwards {
|
for _, fwd := range forwards {
|
||||||
mux.ForwardTCP("*", "localhost:"+fwd.port, 120*time.Second)
|
//mux.ForwardTCP("*", "localhost:"+fwd.port, 120*time.Second)
|
||||||
//mux.ForwardTCP(fwd.pattern, "localhost:"+fwd.port, 120*time.Second)
|
mux.ForwardTCP(fwd.pattern, "localhost:"+fwd.port, 120*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
done := make(chan error)
|
done := make(chan error)
|
||||||
|
|
|
@ -83,13 +83,11 @@ func (c *Conn) LocalAddr() net.Addr {
|
||||||
|
|
||||||
// LocalAddr returns the local network address.
|
// LocalAddr returns the local network address.
|
||||||
func (c *Conn) LocalAddr() net.Addr {
|
func (c *Conn) LocalAddr() net.Addr {
|
||||||
// TODO is this the right one?
|
|
||||||
return &c.relaySourceAddr
|
return &c.relaySourceAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteAddr returns the remote network address.
|
// RemoteAddr returns the remote network address.
|
||||||
func (c *Conn) RemoteAddr() net.Addr {
|
func (c *Conn) RemoteAddr() net.Addr {
|
||||||
// TODO is this the right one?
|
|
||||||
return &c.relayTargetAddr
|
return &c.relayTargetAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,22 @@ package telebit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.coolaj86.com/coolaj86/go-telebitd/sni"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 {
|
||||||
// TODO use io.MultiReader to unbuffer the peeker
|
// TODO use io.MultiReader to unbuffer the peeker
|
||||||
//Conn net.Conn
|
//Conn net.Conn
|
||||||
peeker *bufio.Reader
|
peeker *bufio.Reader
|
||||||
Conn net.Conn
|
servername string
|
||||||
Plain net.Conn
|
scheme string
|
||||||
|
Conn net.Conn
|
||||||
|
Plain net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
type Peeker interface {
|
type Peeker interface {
|
||||||
|
@ -60,11 +65,19 @@ func (c *ConnWrap) Close() error {
|
||||||
|
|
||||||
// Scheme returns one of "https", "http", "tcp", "tls", or ""
|
// Scheme returns one of "https", "http", "tcp", "tls", or ""
|
||||||
func (c *ConnWrap) Scheme() string {
|
func (c *ConnWrap) Scheme() string {
|
||||||
if nil != c.Plain {
|
if "" != c.scheme {
|
||||||
tlsConn := &ConnWrap{Conn: c.Plain}
|
return c.scheme
|
||||||
return tlsConn.Scheme()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if nil != c.Plain {
|
||||||
|
tlsConn := &ConnWrap{Conn: c.Plain}
|
||||||
|
// TODO upgrade tls+http => https
|
||||||
|
c.scheme = tlsConn.Scheme()
|
||||||
|
return c.scheme
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
switch conn := c.Conn.(type) {
|
switch conn := c.Conn.(type) {
|
||||||
case *ConnWrap:
|
case *ConnWrap:
|
||||||
return conn.Scheme()
|
return conn.Scheme()
|
||||||
|
@ -74,20 +87,34 @@ func (c *ConnWrap) Scheme() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (c *ConnWrap) SetServername(name string) {
|
||||||
|
c.servername = name
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Servername may return Servername or Hostname as hinted by a tunnel or buffered peeking
|
// Servername may return Servername or Hostname as hinted by a tunnel or buffered peeking
|
||||||
func (c *ConnWrap) Servername() string {
|
func (c *ConnWrap) Servername() string {
|
||||||
|
if "" != c.servername {
|
||||||
|
return c.servername
|
||||||
|
}
|
||||||
|
|
||||||
if nil != c.Plain {
|
if nil != c.Plain {
|
||||||
tlsConn := &ConnWrap{Conn: c.Plain}
|
tlsConn := &ConnWrap{Conn: c.Plain}
|
||||||
return tlsConn.Servername()
|
c.servername = tlsConn.Servername()
|
||||||
|
return c.servername
|
||||||
}
|
}
|
||||||
|
|
||||||
switch conn := c.Conn.(type) {
|
switch conn := c.Conn.(type) {
|
||||||
case *ConnWrap:
|
case *ConnWrap:
|
||||||
return conn.Scheme()
|
//c.servername = conn.Servername()
|
||||||
|
return conn.Servername()
|
||||||
case *Conn:
|
case *Conn:
|
||||||
return string(conn.relaySourceAddr.scheme)
|
// TODO XXX
|
||||||
|
//c.servername = string(conn.relayTargetAddr.addr)
|
||||||
|
return string(conn.relayTargetAddr.addr)
|
||||||
}
|
}
|
||||||
return ""
|
return c.servername
|
||||||
}
|
}
|
||||||
|
|
||||||
// isTerminated returns true if net.Conn is either a ConnWrap{ tls.Conn },
|
// isTerminated returns true if net.Conn is either a ConnWrap{ tls.Conn },
|
||||||
|
@ -104,16 +131,24 @@ func (c *ConnWrap) isTerminated() bool {
|
||||||
c.SetDeadline(time.Now().Add(5 * time.Second))
|
c.SetDeadline(time.Now().Add(5 * time.Second))
|
||||||
n := 6
|
n := 6
|
||||||
b, _ := c.Peek(n)
|
b, _ := c.Peek(n)
|
||||||
|
fmt.Println("Peek(n)", b)
|
||||||
defer c.SetDeadline(time.Time{})
|
defer c.SetDeadline(time.Time{})
|
||||||
if len(b) >= n {
|
if len(b) >= n {
|
||||||
// SSL v3.x / TLS v1.x
|
// SSL v3.x / TLS v1.x
|
||||||
// 0: TLS Byte
|
// 0: TLS Byte
|
||||||
// 1: Major Version
|
// 1: Major Version
|
||||||
// 2: 0-Indexed Minor Version
|
// 2: Minor Version - 1
|
||||||
// 3-4: Header Length
|
// 3-4: Header Length
|
||||||
|
|
||||||
|
// Payload
|
||||||
// 5: TLS Client Hello Marker Byte
|
// 5: TLS Client Hello Marker Byte
|
||||||
if 0x16 == b[0] && 0x03 == b[1] && 0x01 == b[5] {
|
if 0x16 == b[0] && 0x03 == b[1] && 0x01 == b[5] {
|
||||||
//length := (int(b[3]) << 8) + int(b[4])
|
length := (int(b[3]) << 8) + int(b[4])
|
||||||
|
b, err := c.Peek(n - 1 + length)
|
||||||
|
if nil != err {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
c.servername, _ = sni.GetHostname(b)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Listener transforms a multiplexed websocket connection into individual net.Conn-like connections.
|
// A Listener transforms a multiplexed websocket connection into individual net.Conn-like connections.
|
||||||
|
@ -76,7 +77,7 @@ func Serve(listener net.Listener, mux Handler) error {
|
||||||
go func() {
|
go func() {
|
||||||
err = mux.Serve(client)
|
err = mux.Serve(client)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
if io.EOF != 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.Printf("client could not be served: %q\n", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package telebit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -65,7 +66,11 @@ func (m *RouteMux) Serve(client net.Conn) error {
|
||||||
|
|
||||||
for _, meta := range m.routes {
|
for _, meta := range m.routes {
|
||||||
// TODO '*.example.com'
|
// TODO '*.example.com'
|
||||||
fmt.Println("Meta:", meta.addr)
|
if meta.terminate && "" == servername {
|
||||||
|
wconn.isTerminated()
|
||||||
|
servername = wconn.servername
|
||||||
|
}
|
||||||
|
fmt.Println("Meta:", meta.addr, servername)
|
||||||
if servername == meta.addr || "*" == meta.addr || port == meta.addr {
|
if servername == meta.addr || "*" == meta.addr || port == meta.addr {
|
||||||
//fmt.Println("[debug] test of route:", meta)
|
//fmt.Println("[debug] test of route:", meta)
|
||||||
if err := meta.handler.Serve(wconn); nil != err {
|
if err := meta.handler.Serve(wconn); nil != err {
|
||||||
|
@ -124,7 +129,11 @@ func (m *RouteMux) HandleTLS(servername string, acme *ACME, handler Handler) err
|
||||||
|
|
||||||
//NewTerminator(acme, handler)(client)
|
//NewTerminator(acme, handler)(client)
|
||||||
//return handler.Serve(client)
|
//return handler.Serve(client)
|
||||||
return handler.Serve(TerminateTLS(wconn, acme))
|
err := handler.Serve(TerminateTLS(wconn, acme))
|
||||||
|
if nil == err || io.EOF == err {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
return err
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -180,11 +180,15 @@ type ACME struct {
|
||||||
|
|
||||||
var acmecert *certmagic.Config = nil
|
var acmecert *certmagic.Config = nil
|
||||||
|
|
||||||
func NewTerminator(acme *ACME, handler Handler) HandlerFunc {
|
/*
|
||||||
|
func NewTerminator(servername string, acme *ACME, handler Handler) HandlerFunc {
|
||||||
return func(client net.Conn) error {
|
return func(client net.Conn) error {
|
||||||
return handler.Serve(TerminateTLS(client, acme))
|
return handler.Serve(TerminateTLS("", client, acme))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//func TerminateTLS(client *ConnWrap, acme *ACME) net.Conn
|
||||||
|
|
||||||
func TerminateTLS(client net.Conn, acme *ACME) net.Conn {
|
func TerminateTLS(client net.Conn, acme *ACME) net.Conn {
|
||||||
var magic *certmagic.Config = nil
|
var magic *certmagic.Config = nil
|
||||||
|
@ -231,10 +235,40 @@ func TerminateTLS(client net.Conn, acme *ACME) net.Conn {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var servername string
|
||||||
|
var scheme string
|
||||||
|
// I think this must always be ConnWrap, but I'm not sure
|
||||||
|
switch conn := client.(type) {
|
||||||
|
case *ConnWrap:
|
||||||
|
servername = conn.Servername()
|
||||||
|
scheme = conn.Scheme()
|
||||||
|
client = conn
|
||||||
|
default:
|
||||||
|
wconn := &ConnWrap{
|
||||||
|
Conn: client,
|
||||||
|
}
|
||||||
|
wconn.isTerminated()
|
||||||
|
servername = wconn.Servername()
|
||||||
|
scheme = wconn.Scheme()
|
||||||
|
client = wconn
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO ?
|
||||||
|
if "" == scheme {
|
||||||
|
scheme = "tls"
|
||||||
|
}
|
||||||
|
if "http" == scheme {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
tlsconn := tls.Server(client, tlsConfig)
|
tlsconn := tls.Server(client, tlsConfig)
|
||||||
return &ConnWrap{
|
return &ConnWrap{
|
||||||
Conn: tlsconn,
|
Conn: tlsconn,
|
||||||
Plain: client,
|
Plain: client,
|
||||||
|
servername: servername,
|
||||||
|
scheme: scheme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue