mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-05 18:57:30 +03:00
175 lines
3.4 KiB
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)
|
|
}
|