Files
sing-box-extended/transport/trusttunnel/protocol.go

175 lines
3.4 KiB
Go

package trusttunnel
import (
"bytes"
"encoding/base64"
"io"
"net"
"net/http"
"net/netip"
"strings"
"sync"
"time"
)
const (
UDPMagicAddress = "_udp2"
ICMPMagicAddress = "_icmp"
HealthCheckMagicAddress = "_check"
DefaultConnectionTimeout = 30 * time.Second
DefaultHealthCheckTimeout = 7 * time.Second
DefaultSessionTimeout = 30 * time.Second
)
func buildAuth(username string, password string) string {
return "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password))
}
func parseBasicAuth(auth string) (username, password string, ok bool) {
const prefix = "Basic "
if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) {
return "", "", false
}
c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
if err != nil {
return "", "", false
}
cs := string(c)
username, password, ok = strings.Cut(cs, ":")
return
}
func parse16BytesIP(buffer [16]byte) netip.Addr {
var zeroPrefix [12]byte
isIPv4 := bytes.HasPrefix(buffer[:], zeroPrefix[:])
isIPv4 = isIPv4 && !(buffer[12] == 0 && buffer[13] == 0 && buffer[14] == 0 && buffer[15] == 1)
if isIPv4 {
return netip.AddrFrom4([4]byte(buffer[12:16]))
}
return netip.AddrFrom16(buffer)
}
func buildPaddingIP(addr netip.Addr) (buffer [16]byte) {
if addr.Is6() {
return addr.As16()
}
ipv4 := addr.As4()
copy(buffer[12:16], ipv4[:])
return buffer
}
type httpConn struct {
writer io.Writer
flusher http.Flusher
body io.ReadCloser
setupOnce sync.Once
created chan struct{}
createErr error
cancelFn func()
closeFn func()
remoteAddr net.Addr
localAddr net.Addr
deadline *time.Timer
done chan struct{}
}
func (h *httpConn) setup(body io.ReadCloser, err error) {
h.setupOnce.Do(func() {
h.body = body
h.createErr = err
close(h.created)
})
if h.createErr != nil && body != nil {
_ = body.Close()
}
}
func (h *httpConn) waitCreated() error {
<-h.created
if h.body != nil {
return nil
}
return h.createErr
}
func (h *httpConn) Close() error {
h.setup(nil, net.ErrClosed)
if closer, ok := h.writer.(io.Closer); ok {
_ = closer.Close()
}
if h.body != nil {
_ = h.body.Close()
}
if h.cancelFn != nil {
h.cancelFn()
}
if h.closeFn != nil {
h.closeFn()
}
if h.done != nil {
select {
case <-h.done:
default:
close(h.done)
}
}
return nil
}
func (h *httpConn) writeFlush(p []byte) (n int, err error) {
n, err = h.writer.Write(p)
if h.flusher != nil {
h.flusher.Flush()
}
return n, err
}
func (h *httpConn) RemoteAddr() net.Addr {
if h.remoteAddr != nil {
return h.remoteAddr
}
return &net.TCPAddr{}
}
func (h *httpConn) LocalAddr() net.Addr {
if h.localAddr != nil {
return h.localAddr
}
return &net.TCPAddr{}
}
func (h *httpConn) SetDeadline(t time.Time) error {
if t.IsZero() {
if h.deadline != nil {
h.deadline.Stop()
h.deadline = nil
}
return nil
}
d := time.Until(t)
if h.deadline != nil {
h.deadline.Reset(d)
return nil
}
h.deadline = time.AfterFunc(d, func() { h.Close() })
return nil
}
func (h *httpConn) SetReadDeadline(t time.Time) error { return h.SetDeadline(t) }
func (h *httpConn) SetWriteDeadline(t time.Time) error { return h.SetDeadline(t) }
var _ net.Conn = (*tcpConn)(nil)
type tcpConn struct{ httpConn }
func (t *tcpConn) Read(b []byte) (n int, err error) {
if err = t.waitCreated(); err != nil {
return 0, err
}
return t.body.Read(b)
}
func (t *tcpConn) Write(b []byte) (int, error) {
return t.writeFlush(b)
}