Initial commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"relay/registry"
|
||||
"relay/util"
|
||||
|
||||
tunnelpb "relay/proto/tunnel"
|
||||
)
|
||||
|
||||
func handleClientTCP(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
sni, hello, err := peekClientHello(conn)
|
||||
if err != nil {
|
||||
log.Println("peek failed:", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Client SNI:", sni)
|
||||
|
||||
registry.Global.Mu.Lock()
|
||||
dev := registry.Global.Domains[sni]
|
||||
log.Println("Known domains:", util.Keys(registry.Global.Domains))
|
||||
registry.Global.Mu.Unlock()
|
||||
|
||||
if dev == nil {
|
||||
log.Println("No device bound for domain:", sni)
|
||||
conn.Write([]byte("HTTP/1.1 503 No device\r\n\r\n"))
|
||||
return
|
||||
}
|
||||
|
||||
streamID := dev.AllocateStreamID()
|
||||
done := dev.AddStream(streamID, conn)
|
||||
|
||||
log.Printf("Client [%s] → device (stream %d)\n", sni, streamID)
|
||||
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_OPEN,
|
||||
StreamId: streamID,
|
||||
Payload: []byte(sni),
|
||||
})
|
||||
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_DATA,
|
||||
StreamId: streamID,
|
||||
Payload: hello,
|
||||
})
|
||||
|
||||
go func() {
|
||||
buf := util.BufPool.Get().([]byte)
|
||||
defer util.BufPool.Put(buf)
|
||||
|
||||
for {
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_CLOSE,
|
||||
StreamId: streamID,
|
||||
})
|
||||
dev.RemoveStream(streamID)
|
||||
return
|
||||
}
|
||||
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_DATA,
|
||||
StreamId: streamID,
|
||||
Payload: append([]byte(nil), buf[:n]...),
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-dev.Done():
|
||||
}
|
||||
|
||||
dev.RemoveStream(streamID)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
func Listen(addr string) {
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("HTTPS passthrough listening on", addr)
|
||||
|
||||
for {
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Println("accept error:", err)
|
||||
continue
|
||||
}
|
||||
go handleClientTCP(c)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func peekClientHello(r io.Reader) (sni string, hello []byte, err error) {
|
||||
br := bufio.NewReader(r)
|
||||
|
||||
hdr, err := br.Peek(5)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if hdr[0] != 0x16 {
|
||||
return "", nil, errors.New("not TLS handshake")
|
||||
}
|
||||
|
||||
recLen := int(binary.BigEndian.Uint16(hdr[3:5]))
|
||||
total := 5 + recLen
|
||||
|
||||
hello, err = br.Peek(total)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
data := hello[5:]
|
||||
if data[0] != 0x01 {
|
||||
return "", hello, errors.New("not ClientHello")
|
||||
}
|
||||
|
||||
i := 4
|
||||
i += 2 + 32
|
||||
|
||||
sidLen := int(data[i])
|
||||
i += 1 + sidLen
|
||||
|
||||
csLen := int(binary.BigEndian.Uint16(data[i:]))
|
||||
i += 2 + csLen
|
||||
|
||||
compLen := int(data[i])
|
||||
i += 1 + compLen
|
||||
|
||||
extLen := int(binary.BigEndian.Uint16(data[i:]))
|
||||
i += 2
|
||||
end := i + extLen
|
||||
|
||||
for i+4 <= end {
|
||||
typ := binary.BigEndian.Uint16(data[i:])
|
||||
sz := int(binary.BigEndian.Uint16(data[i+2:]))
|
||||
i += 4
|
||||
|
||||
if typ == 0x00 {
|
||||
l := int(binary.BigEndian.Uint16(data[i:]))
|
||||
j := i + 2
|
||||
for j+3 < i+l {
|
||||
nameType := data[j]
|
||||
nameLen := int(binary.BigEndian.Uint16(data[j+1:]))
|
||||
if nameType == 0 {
|
||||
sni = strings.ToLower(string(data[j+3 : j+3+nameLen]))
|
||||
return sni, hello, nil
|
||||
}
|
||||
j += 3 + nameLen
|
||||
}
|
||||
}
|
||||
i += sz
|
||||
}
|
||||
|
||||
return "", hello, nil
|
||||
}
|
||||
Reference in New Issue
Block a user