假设我拥有一个net.Listener套接字,如何检测到传入连接正在使用ssl。
我使用下面的代码可以很好地调度bt / http连接。
代码在缓冲的conn上执行字节到字节的比较,如果什么也没找到,它将默认为bt侦听器。
我希望它能够分派ssl tls连接,如果我正确的话,最好是在sni支持下执行主机分派。
package server
import (
"bufio"
"bytes"
"log"
"net"
)
type SocketDispatcher struct {
net.Listener
Dispatchers []*Dispatcher
}
func (l *SocketDispatcher) Accept() (net.Conn, error) {
for {
conn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
var r *bufio.Reader
r, conn = makePeekedConn(conn)
if d := l.Snif(r); d != nil {
d.Handle(conn)
continue
}
return conn, err
}
}
func (l *SocketDispatcher) Snif(r *bufio.Reader) *Dispatcher {
for _, d := range l.Dispatchers {
if d.Snif(r) {
return d
}
}
return nil
}
type Dispatcher struct {
Snif func(r *bufio.Reader) bool
accepted chan net.Conn
}
func (d *Dispatcher) Handle(conn net.Conn) error {
go func() {
d.accepted <- conn
}()
return nil
}
func (d *Dispatcher) Accept() (net.Conn, error) {
conn := <-d.accepted
return conn, nil
}
func CatchAll() *Dispatcher {
return &Dispatcher{
Snif: func(r *bufio.Reader) bool {
return true
},
accepted: make(chan net.Conn),
}
}
func HTTPDispatcher() *Dispatcher {
return &Dispatcher{
Snif: func(r *bufio.Reader) bool {
return HTTPSnif(r)
},
accepted: make(chan net.Conn),
}
}
//HTTPSnif detects http requests
func HTTPSnif(t *bufio.Reader) bool {
ms := []string{"GET", "PUT", "HEAD", "POST", "PATCH", "OPTION", "DELETE"}
longuest := 0
for _, m := range ms {
if longuest < len(m) {
longuest = len(m)
}
}
remains := [][]byte{}
for _, m := range ms {
b := []byte(m + " ")
remains = append(remains, b)
}
for e := 1; e <= longuest; e++ {
p, err := t.Peek(e)
if err != nil {
log.Println("peek", err)
return false
}
remains = filter(remains, p)
if len(remains) == 0 {
return false
}
if len(remains) == 1 {
return true
}
}
return true
}
func filter(remains [][]byte, cur []byte) [][]byte {
rests := [][]byte{}
for _, r := range remains {
if bytes.HasPrefix(r, cur) || bytes.Equal(r, cur) {
rests = append(rests, r)
}
}
return rests
}
func peekCompare(t *bufio.Reader, search []byte) bool {
var p []byte
for i := 1; i <= len(search); i++ {
var err error
p, err = t.Peek(i)
if err != nil {
return false
}
if !bytes.HasPrefix(search, p) {
return false
}
}
return bytes.Equal(search, p)
}