Update sing-box core, refactor MASQUE, update XHTTP

This commit is contained in:
Shtorm
2026-05-29 01:31:57 +03:00
parent 1cb7950810
commit b953954b60
111 changed files with 1291 additions and 1660 deletions

View File

@@ -1,34 +0,0 @@
package masque
import "sync"
type NetBuffer struct {
capacity uint32
buf sync.Pool
}
func (n *NetBuffer) Get() []byte {
return *n.buf.Get().(*[]byte)
}
func (n *NetBuffer) Put(buf []byte) {
if cap(buf) != int(n.capacity) {
return
}
n.buf.Put(&buf)
}
func NewNetBuffer(capacity uint32) *NetBuffer {
if capacity == 0 {
panic("capacity must be greater than 0")
}
return &NetBuffer{
capacity: capacity,
buf: sync.Pool{
New: func() interface{} {
b := make([]byte, capacity)
return &b
},
},
}
}

View File

@@ -1,3 +1,5 @@
//go:build with_gvisor
package masque
import (

View File

@@ -0,0 +1,13 @@
//go:build !with_gvisor
package masque
import "github.com/sagernet/sing-tun"
func newStackDevice(options DeviceOptions) (Device, error) {
return nil, tun.ErrGVisorNotIncluded
}
func newSystemStackDevice(options DeviceOptions) (Device, error) {
return nil, tun.ErrGVisorNotIncluded
}

View File

@@ -8,7 +8,6 @@ import (
"net"
"net/http"
"net/netip"
"net/url"
"strings"
connectip "github.com/Diniboy1123/connect-ip-go"
@@ -85,7 +84,9 @@ func ConnectTunnel(ctx context.Context, dialer N.Dialer, tlsConfig aTLS.Config,
hconn := tr.NewClientConn(conn)
ipConn, rsp, err := connectip.Dial(ctx, hconn, template, "cf-connect-ip", additionalHeaders, true)
if err != nil {
if err.Error() == "CRYPTO_ERROR 0x131 (remote): tls: access denied" {
_ = tr.Close()
_ = conn.CloseWithError(0, "connect-ip dial failed")
if strings.Contains(err.Error(), "tls: access denied") {
return udpConn, nil, nil, nil, errors.New("login failed! Please double-check if your tls key and cert is enrolled in the Cloudflare Access service")
}
return udpConn, nil, nil, nil, fmt.Errorf("failed to dial connect-ip: %w", err)
@@ -139,28 +140,3 @@ func newHTTP2Client(dialer N.Dialer, baseTLSConfig aTLS.Config, endpoint *net.TC
},
}, nil
}
func authorityWithDefaultPort(u *url.URL, defaultPort string) string {
if u == nil {
return ""
}
host := u.Hostname()
if host == "" {
return u.Host
}
port := u.Port()
if port == "" {
port = defaultPort
}
return net.JoinHostPort(host, port)
}
func proxyDefaultPort(u *url.URL) string {
if u != nil && u.Scheme == "https" {
return "443"
}
return "80"
}

View File

@@ -6,9 +6,11 @@ import (
"fmt"
"net"
"os"
"sync"
"time"
connectip "github.com/Diniboy1123/connect-ip-go"
"github.com/sagernet/quic-go/http3"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
@@ -25,6 +27,12 @@ type Tunnel struct {
options TunnelOptions
tunDevice Device
tunnelDevice TunnelDevice
udpConn net.PacketConn
tr *http3.Transport
ipConn *connectip.Conn
mtx sync.Mutex
}
func NewTunnel(ctx context.Context, logger logger.ContextLogger, options TunnelOptions) (*Tunnel, error) {
@@ -55,7 +63,7 @@ func (e *Tunnel) Start(resolve bool) error {
if err != nil {
return err
}
go e.MaintainTunnel()
go e.maintainTunnel()
}
return nil
}
@@ -75,19 +83,95 @@ func (e *Tunnel) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
}
func (e *Tunnel) Close() error {
e.mtx.Lock()
defer e.mtx.Unlock()
if e.ipConn != nil {
e.ipConn.Close()
if e.udpConn != nil {
e.udpConn.Close()
}
if e.tr != nil {
e.tr.Close()
}
e.ipConn = nil
}
return e.tunDevice.Close()
}
func (e *Tunnel) MaintainTunnel() {
packetBufferPool := NewNetBuffer(1280)
func (e *Tunnel) maintainTunnel() {
go func() {
buf := make([]byte, 1280)
for e.ctx.Err() == nil {
n, err := e.tunnelDevice.ReadPacket(buf)
if err != nil {
e.logger.ErrorContext(e.ctx, fmt.Errorf("failed to read from TUN device: %v", err))
continue
}
ipConn, err := e.getIpConn()
if err != nil {
return
}
icmp, err := ipConn.WritePacket(buf[:n])
if err != nil {
if errors.As(err, new(*connectip.CloseError)) {
if ok := e.closeIpConn(ipConn); ok {
e.logger.ErrorContext(e.ctx, fmt.Errorf("connection closed while writing to IP connection: %w", err))
}
continue
}
e.logger.ErrorContext(e.ctx, fmt.Errorf("Error writing to IP connection: %v, continuing...", err))
continue
}
if len(icmp) > 0 {
if err := e.tunnelDevice.WritePacket(icmp); err != nil {
if errors.As(err, new(*connectip.CloseError)) {
e.logger.ErrorContext(e.ctx, fmt.Errorf("connection closed while writing ICMP to TUN device: %v", err))
continue
}
e.logger.ErrorContext(e.ctx, fmt.Errorf("Error writing ICMP to TUN device: %v, continuing...", err))
}
}
}
}()
go func() {
buf := make([]byte, 1280)
for e.ctx.Err() == nil {
ipConn, err := e.getIpConn()
if err != nil {
return
}
n, err := ipConn.ReadPacket(buf, true)
if err != nil {
if e.options.UseHTTP2 || errors.As(err, new(*connectip.CloseError)) {
if ok := e.closeIpConn(ipConn); ok {
e.logger.ErrorContext(e.ctx, fmt.Errorf("connection closed while reading from IP connection: %v", err))
}
continue
}
e.logger.ErrorContext(e.ctx, fmt.Errorf("Error reading from IP connection: %v, continuine...", err))
continue
}
if err := e.tunnelDevice.WritePacket(buf[:n]); err != nil {
continue
}
}
}()
<-e.ctx.Done()
}
func (e *Tunnel) getIpConn() (*connectip.Conn, error) {
e.mtx.Lock()
defer e.mtx.Unlock()
if e.ctx.Err() != nil {
return nil, e.ctx.Err()
}
if e.ipConn != nil {
return e.ipConn, nil
}
e.logger.InfoContext(e.ctx, "Establishing MASQUE connection to ", e.options.Endpoint)
timer := time.NewTimer(0)
defer timer.Stop()
for {
select {
case <-e.ctx.Done():
return
default:
}
e.logger.InfoContext(e.ctx, fmt.Errorf("Establishing MASQUE connection to %s", e.options.Endpoint))
udpConn, tr, ipConn, rsp, err := ConnectTunnel(
e.ctx,
@@ -99,17 +183,17 @@ func (e *Tunnel) MaintainTunnel() {
e.options.UseHTTP2,
)
if err != nil {
e.logger.InfoContext(e.ctx, fmt.Errorf("Failed to connect tunnel: %v", err))
e.logger.ErrorContext(e.ctx, fmt.Errorf("Failed to connect tunnel: %v", err))
timer.Reset(e.options.ReconnectDelay)
select {
case <-e.ctx.Done():
return
return nil, err
case <-timer.C:
}
continue
}
if rsp.StatusCode != 200 {
e.logger.InfoContext(e.ctx, fmt.Errorf("Tunnel connection failed: %s", rsp.Status))
e.logger.ErrorContext(e.ctx, fmt.Errorf("Tunnel connection failed: %s", rsp.Status))
ipConn.Close()
if udpConn != nil {
udpConn.Close()
@@ -120,81 +204,32 @@ func (e *Tunnel) MaintainTunnel() {
timer.Reset(e.options.ReconnectDelay)
select {
case <-e.ctx.Done():
return
return nil, err
case <-timer.C:
}
continue
}
e.logger.InfoContext(e.ctx, "Connected to MASQUE server")
errChan := make(chan error, 2)
go func() {
for {
buf := packetBufferPool.Get()
n, err := e.tunnelDevice.ReadPacket(buf)
if err != nil {
packetBufferPool.Put(buf)
errChan <- fmt.Errorf("failed to read from TUN device: %w", err)
return
}
icmp, err := ipConn.WritePacket(buf[:n])
if err != nil {
packetBufferPool.Put(buf)
if errors.As(err, new(*connectip.CloseError)) {
errChan <- fmt.Errorf("connection closed while writing to IP connection: %w", err)
return
}
e.logger.InfoContext(e.ctx, fmt.Errorf("Error writing to IP connection: %v, continuing...", err))
continue
}
packetBufferPool.Put(buf)
if len(icmp) > 0 {
if err := e.tunnelDevice.WritePacket(icmp); err != nil {
if errors.As(err, new(*connectip.CloseError)) {
errChan <- fmt.Errorf("connection closed while writing ICMP to TUN device: %w", err)
return
}
e.logger.InfoContext(e.ctx, fmt.Errorf("Error writing ICMP to TUN device: %v, continuing...", err))
}
}
}
}()
go func() {
buf := packetBufferPool.Get()
defer packetBufferPool.Put(buf)
for {
n, err := ipConn.ReadPacket(buf, true)
if err != nil {
if e.options.UseHTTP2 {
errChan <- fmt.Errorf("connection closed while reading from IP connection: %w", err)
return
}
if errors.As(err, new(*connectip.CloseError)) {
errChan <- fmt.Errorf("connection closed while reading from IP connection: %w", err)
return
}
e.logger.InfoContext(e.ctx, fmt.Errorf("Error reading from IP connection: %v, continuing...", err))
continue
}
if err := e.tunnelDevice.WritePacket(buf[:n]); err != nil {
errChan <- fmt.Errorf("failed to write to TUN device: %w", err)
return
}
}
}()
err = <-errChan
e.logger.InfoContext(e.ctx, fmt.Errorf("Tunnel connection lost: %v. Reconnecting...", err))
ipConn.Close()
if udpConn != nil {
udpConn.Close()
}
if tr != nil {
tr.Close()
}
timer.Reset(e.options.ReconnectDelay)
select {
case <-e.ctx.Done():
return
case <-timer.C:
}
e.udpConn = udpConn
e.tr = tr
e.ipConn = ipConn
e.logger.InfoContext(e.ctx, "Connected to MASQUE server", e.options.Endpoint)
return ipConn, nil
}
}
func (e *Tunnel) closeIpConn(ipConn *connectip.Conn) bool {
e.mtx.Lock()
defer e.mtx.Unlock()
if ipConn == e.ipConn {
e.ipConn.Close()
if e.udpConn != nil {
e.udpConn.Close()
}
if e.tr != nil {
e.tr.Close()
}
e.ipConn = nil
return true
}
return false
}

View File

@@ -105,15 +105,3 @@ func ParsePluginOptions(s string) (opts Args, err error) {
}
return opts, nil
}
// Escape backslashes and all the bytes that are in set.
func backslashEscape(s string, set []byte) string {
var buf bytes.Buffer
for _, b := range []byte(s) {
if b == '\\' || bytes.IndexByte(set, b) != -1 {
buf.WriteByte('\\')
}
buf.WriteByte(b)
}
return buf.String()
}

View File

@@ -10,7 +10,6 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -100,7 +99,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
return nil, err
}
client := NewGunServiceClient(clientConn).(GunServiceCustomNameClient)
ctx, cancel := common.ContextWithCancelCause(ctx)
ctx, cancel := context.WithCancelCause(ctx)
stream, err := client.TunCustomName(ctx, c.serviceName)
if err != nil {
cancel(err)

View File

@@ -25,12 +25,12 @@ import (
type requestInfoKey struct{}
// NewRequestInfoContext creates a context with ri.
func NewRequestInfoContext(ctx context.Context, ri interface{}) context.Context {
func NewRequestInfoContext(ctx context.Context, ri any) context.Context {
return context.WithValue(ctx, requestInfoKey{}, ri)
}
// RequestInfoFromContext extracts the RequestInfo from ctx.
func RequestInfoFromContext(ctx context.Context) interface{} {
func RequestInfoFromContext(ctx context.Context) any {
return ctx.Value(requestInfoKey{})
}
@@ -39,11 +39,11 @@ func RequestInfoFromContext(ctx context.Context) interface{} {
type clientHandshakeInfoKey struct{}
// ClientHandshakeInfoFromContext extracts the ClientHandshakeInfo from ctx.
func ClientHandshakeInfoFromContext(ctx context.Context) interface{} {
func ClientHandshakeInfoFromContext(ctx context.Context) any {
return ctx.Value(clientHandshakeInfoKey{})
}
// NewClientHandshakeInfoContext creates a context with chi.
func NewClientHandshakeInfoContext(ctx context.Context, chi interface{}) context.Context {
func NewClientHandshakeInfoContext(ctx context.Context, chi any) context.Context {
return context.WithValue(ctx, clientHandshakeInfoKey{}, chi)
}

View File

@@ -20,16 +20,15 @@ package credentials
import (
"crypto/tls"
"slices"
)
const alpnProtoStrH2 = "h2"
// AppendH2ToNextProtos appends h2 to next protos.
func AppendH2ToNextProtos(ps []string) []string {
for _, p := range ps {
if p == alpnProtoStrH2 {
return ps
}
if slices.Contains(ps, alpnProtoStrH2) {
return ps
}
ret := make([]string, 0, len(ps)+1)
ret = append(ret, ps...)

View File

@@ -60,7 +60,7 @@ func (s *Server) Tun(server GunService_TunServer) error {
if grpcMetadata, loaded := gM.FromIncomingContext(server.Context()); loaded {
forwardFrom := strings.Join(grpcMetadata.Get("X-Forwarded-For"), ",")
if forwardFrom != "" {
for _, from := range strings.Split(forwardFrom, ",") {
for from := range strings.SplitSeq(forwardFrom, ",") {
originAddr := M.ParseSocksaddr(from)
if originAddr.IsValid() {
source = originAddr.Unwrap()

View File

@@ -1,17 +1,12 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.31.1
// source: transport/v2raygrpc/stream.proto
package v2raygrpc
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
@@ -88,10 +83,12 @@ func file_transport_v2raygrpc_stream_proto_rawDescGZIP() []byte {
return file_transport_v2raygrpc_stream_proto_rawDescData
}
var file_transport_v2raygrpc_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_v2raygrpc_stream_proto_goTypes = []any{
(*Hunk)(nil), // 0: transport.v2raygrpc.Hunk
}
var (
file_transport_v2raygrpc_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
file_transport_v2raygrpc_stream_proto_goTypes = []any{
(*Hunk)(nil), // 0: transport.v2raygrpc.Hunk
}
)
var file_transport_v2raygrpc_stream_proto_depIdxs = []int32{
0, // 0: transport.v2raygrpc.GunService.Tun:input_type -> transport.v2raygrpc.Hunk
0, // 1: transport.v2raygrpc.GunService.Tun:output_type -> transport.v2raygrpc.Hunk

View File

@@ -1,13 +1,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.1
// - protoc v6.31.1
// source: transport/v2raygrpc/stream.proto
package v2raygrpc
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"

View File

@@ -192,6 +192,8 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
go func() {
var seq int64
var lastWrite time.Time
dynamicHTTPClient := httpClient
dynamicXmuxClient := xmuxClient
for {
// by offloading the uploads into a buffered pipe, multiple conn.Write
// calls get automatically batched together into larger POST requests.
@@ -219,12 +221,12 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
time.Sleep(time.Duration(scMinPostsIntervalMs.Rand())*time.Millisecond - time.Since(lastWrite))
}
lastWrite = time.Now()
if xmuxClient != nil && (xmuxClient.LeftRequests.Add(-1) <= 0 ||
(xmuxClient.UnreusableAt != time.Time{} && lastWrite.After(xmuxClient.UnreusableAt))) {
httpClient, xmuxClient = c.getHTTPClient()
if dynamicXmuxClient != nil && (dynamicXmuxClient.LeftRequests.Add(-1) <= 0 ||
(dynamicXmuxClient.UnreusableAt != time.Time{} && lastWrite.After(dynamicXmuxClient.UnreusableAt))) {
dynamicHTTPClient, dynamicXmuxClient = c.getHTTPClient()
}
go func() {
err := httpClient.PostPacket(
go func(hClient DialerClient) {
err := hClient.PostPacket(
ctx,
requestURL.String(),
sessionId,
@@ -236,8 +238,8 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
uploadPipeReader.Interrupt()
doSplit.Store(false)
}
}()
if _, ok := httpClient.(*DefaultDialerClient); ok {
}(dynamicHTTPClient)
if _, ok := dynamicHTTPClient.(*DefaultDialerClient); ok {
<-wroteRequest.Wait()
}
}

View File

@@ -70,12 +70,14 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessio
c.closed = true
}
gotConn.Close()
common.Close(body)
wrc.Close()
return
}
if resp.StatusCode != 200 || uploadOnly { // stream-up
io.Copy(io.Discard, resp.Body)
resp.Body.Close() // if it is called immediately, the upload will be interrupted also
common.Close(body)
wrc.Close()
return
}

View File

@@ -136,7 +136,7 @@ func (c *ClientBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint)
sizes[0] = n
if n > 3 {
b := packets[0]
common.ClearArray(b[1:4])
clear(b[1:4])
}
eps[0] = remoteEndpoint(M.SocksaddrFromNet(addr).Unwrap().AddrPort())
count = 1

View File

@@ -7,6 +7,7 @@ import (
"net"
"net/netip"
"os"
"sync"
"time"
"github.com/sagernet/gvisor/pkg/buffer"
@@ -42,6 +43,7 @@ type stackDevice struct {
outbound chan *stack.PacketBuffer
packetOutbound chan *buf.Buffer
done chan struct{}
closeOnce sync.Once
dispatcher stack.NetworkDispatcher
inet4Address netip.Addr
inet6Address netip.Addr
@@ -146,11 +148,17 @@ func (w *stackDevice) ListenPacket(ctx context.Context, destination M.Socksaddr)
}
var networkProtocol tcpip.NetworkProtocolNumber
if destination.IsIPv4() {
if !w.inet4Address.IsValid() {
return nil, E.New("missing IPv4 local address")
}
networkProtocol = header.IPv4ProtocolNumber
bind.Addr = tun.AddressFromAddr(w.inet4Address)
} else {
if !w.inet6Address.IsValid() {
return nil, E.New("missing IPv6 local address")
}
networkProtocol = header.IPv6ProtocolNumber
bind.Addr = tun.AddressFromAddr(w.inet4Address)
bind.Addr = tun.AddressFromAddr(w.inet6Address)
}
udpConn, err := gonet.DialUDP(w.stack, &bind, nil, networkProtocol)
if err != nil {
@@ -244,13 +252,15 @@ func (w *stackDevice) Events() <-chan wgTun.Event {
}
func (w *stackDevice) Close() error {
close(w.done)
close(w.events)
w.stack.Close()
for _, endpoint := range w.stack.CleanupEndpoints() {
endpoint.Abort()
}
w.stack.Wait()
w.closeOnce.Do(func() {
close(w.done)
close(w.events)
w.stack.Close()
for _, endpoint := range w.stack.CleanupEndpoints() {
endpoint.Abort()
}
w.stack.Wait()
})
return nil
}

View File

@@ -111,6 +111,7 @@ func (w *systemDevice) Start() error {
}
err = tunInterface.Start()
if err != nil {
tunInterface.Close()
return err
}
w.options.Logger.Info("started at ", w.options.Name)
@@ -147,7 +148,7 @@ func (w *systemDevice) Write(bufs [][]byte, offset int) (count int, err error) {
} else {
for _, packet := range bufs {
if tun.PacketOffset > 0 {
common.ClearArray(packet[offset-tun.PacketOffset : offset])
clear(packet[offset-tun.PacketOffset : offset])
tun.PacketFillHeader(packet[offset-tun.PacketOffset:], tun.PacketIPVersion(packet[offset:]))
}
_, err = w.device.Write(packet[offset-tun.PacketOffset:])
@@ -177,8 +178,14 @@ func (w *systemDevice) Events() <-chan wgTun.Event {
}
func (w *systemDevice) Close() error {
close(w.events)
return w.device.Close()
var err error
w.closeOnce.Do(func() {
close(w.events)
if w.device != nil {
err = w.device.Close()
}
})
return err
}
func (w *systemDevice) BatchSize() int {

View File

@@ -5,6 +5,7 @@ package wireguard
import (
"context"
"net/netip"
"sync"
"time"
"github.com/sagernet/gvisor/pkg/buffer"
@@ -20,7 +21,6 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing-tun/ping"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/wireguard-go/device"
@@ -35,6 +35,7 @@ type systemStackDevice struct {
stack *stack.Stack
endpoint *deviceEndpoint
writeBufs [][]byte
closeOnce sync.Once
}
func newSystemStackDevice(options DeviceOptions) (*systemStackDevice, error) {
@@ -104,13 +105,13 @@ func (w *systemStackDevice) Write(bufs [][]byte, offset int) (count int, err err
}
}
if len(w.writeBufs) > 0 {
return w.batchDevice.BatchWrite(bufs, offset)
return w.batchDevice.BatchWrite(w.writeBufs, offset)
}
} else {
for _, packet := range bufs {
if !w.writeStack(packet[offset:]) {
if tun.PacketOffset > 0 {
common.ClearArray(packet[offset-tun.PacketOffset : offset])
clear(packet[offset-tun.PacketOffset : offset])
tun.PacketFillHeader(packet[offset-tun.PacketOffset:], tun.PacketIPVersion(packet[offset:]))
}
_, err = w.device.Write(packet[offset-tun.PacketOffset:])
@@ -125,13 +126,17 @@ func (w *systemStackDevice) Write(bufs [][]byte, offset int) (count int, err err
}
func (w *systemStackDevice) Close() error {
close(w.endpoint.done)
w.stack.Close()
for _, endpoint := range w.stack.CleanupEndpoints() {
endpoint.Abort()
}
w.stack.Wait()
return w.systemDevice.Close()
var err error
w.closeOnce.Do(func() {
close(w.endpoint.done)
w.stack.Close()
for _, endpoint := range w.stack.CleanupEndpoints() {
endpoint.Abort()
}
w.stack.Wait()
err = w.systemDevice.Close()
})
return err
}
func (w *systemStackDevice) writeStack(packet []byte) bool {

View File

@@ -183,10 +183,10 @@ func (e *Endpoint) Start(resolve bool) error {
return err
}
logger := &device.Logger{
Verbosef: func(format string, args ...interface{}) {
Verbosef: func(format string, args ...any) {
e.options.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
},
Errorf: func(format string, args ...interface{}) {
Errorf: func(format string, args ...any) {
e.options.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...))
},
}
@@ -198,75 +198,77 @@ func (e *Endpoint) Start(resolve bool) error {
}
wgDevice := device.NewDevice(e.options.Context, deviceInput, bind, logger, e.options.Workers, e.options.PreallocatedBuffersPerPool, e.options.DisablePauses)
e.tunDevice.SetDevice(wgDevice)
ipcConf := e.ipcConf
var ipcConf strings.Builder
ipcConf.WriteString(e.ipcConf)
if e.options.Amnezia != nil {
if e.options.Amnezia.JC > 0 {
ipcConf += "\njc=" + strconv.Itoa(e.options.Amnezia.JC)
ipcConf.WriteString("\njc=" + strconv.Itoa(e.options.Amnezia.JC))
}
if e.options.Amnezia.JMin > 0 {
ipcConf += "\njmin=" + strconv.Itoa(e.options.Amnezia.JMin)
ipcConf.WriteString("\njmin=" + strconv.Itoa(e.options.Amnezia.JMin))
}
if e.options.Amnezia.JMax > 0 {
ipcConf += "\njmax=" + strconv.Itoa(e.options.Amnezia.JMax)
ipcConf.WriteString("\njmax=" + strconv.Itoa(e.options.Amnezia.JMax))
}
if e.options.Amnezia.S1 > 0 {
ipcConf += "\ns1=" + strconv.Itoa(e.options.Amnezia.S1)
ipcConf.WriteString("\ns1=" + strconv.Itoa(e.options.Amnezia.S1))
}
if e.options.Amnezia.S2 > 0 {
ipcConf += "\ns2=" + strconv.Itoa(e.options.Amnezia.S2)
ipcConf.WriteString("\ns2=" + strconv.Itoa(e.options.Amnezia.S2))
}
if e.options.Amnezia.S3 > 0 {
ipcConf += "\ns3=" + strconv.Itoa(e.options.Amnezia.S3)
ipcConf.WriteString("\ns3=" + strconv.Itoa(e.options.Amnezia.S3))
}
if e.options.Amnezia.S4 > 0 {
ipcConf += "\ns4=" + strconv.Itoa(e.options.Amnezia.S4)
ipcConf.WriteString("\ns4=" + strconv.Itoa(e.options.Amnezia.S4))
}
if e.options.Amnezia.H1 != nil {
ipcConf += "\nh1=" + e.options.Amnezia.H1.String()
ipcConf.WriteString("\nh1=" + e.options.Amnezia.H1.String())
}
if e.options.Amnezia.H2 != nil {
ipcConf += "\nh2=" + e.options.Amnezia.H2.String()
ipcConf.WriteString("\nh2=" + e.options.Amnezia.H2.String())
}
if e.options.Amnezia.H3 != nil {
ipcConf += "\nh3=" + e.options.Amnezia.H3.String()
ipcConf.WriteString("\nh3=" + e.options.Amnezia.H3.String())
}
if e.options.Amnezia.H4 != nil {
ipcConf += "\nh4=" + e.options.Amnezia.H4.String()
ipcConf.WriteString("\nh4=" + e.options.Amnezia.H4.String())
}
if e.options.Amnezia.I1 != "" {
ipcConf += "\ni1=" + e.options.Amnezia.I1
ipcConf.WriteString("\ni1=" + e.options.Amnezia.I1)
}
if e.options.Amnezia.I2 != "" {
ipcConf += "\ni2=" + e.options.Amnezia.I2
ipcConf.WriteString("\ni2=" + e.options.Amnezia.I2)
}
if e.options.Amnezia.I3 != "" {
ipcConf += "\ni3=" + e.options.Amnezia.I3
ipcConf.WriteString("\ni3=" + e.options.Amnezia.I3)
}
if e.options.Amnezia.I4 != "" {
ipcConf += "\ni4=" + e.options.Amnezia.I4
ipcConf.WriteString("\ni4=" + e.options.Amnezia.I4)
}
if e.options.Amnezia.I5 != "" {
ipcConf += "\ni5=" + e.options.Amnezia.I5
ipcConf.WriteString("\ni5=" + e.options.Amnezia.I5)
}
if e.options.Amnezia.J1 != "" {
ipcConf += "\nj1=" + e.options.Amnezia.J1
ipcConf.WriteString("\nj1=" + e.options.Amnezia.J1)
}
if e.options.Amnezia.J2 != "" {
ipcConf += "\nj2=" + e.options.Amnezia.J2
ipcConf.WriteString("\nj2=" + e.options.Amnezia.J2)
}
if e.options.Amnezia.J3 != "" {
ipcConf += "\nj3=" + e.options.Amnezia.J3
ipcConf.WriteString("\nj3=" + e.options.Amnezia.J3)
}
if e.options.Amnezia.ITime > 0 {
ipcConf += "\nitime=" + strconv.FormatInt(e.options.Amnezia.ITime, 10)
ipcConf.WriteString("\nitime=" + strconv.FormatInt(e.options.Amnezia.ITime, 10))
}
}
for _, peer := range e.peers {
ipcConf += peer.GenerateIpcLines()
ipcConf.WriteString(peer.GenerateIpcLines())
}
err = wgDevice.IpcSet(ipcConf)
err = wgDevice.IpcSet(ipcConf.String())
if err != nil {
return E.Cause(err, "setup wireguard: \n", ipcConf)
wgDevice.Close()
return E.Cause(err, "setup wireguard: \n", ipcConf.String())
}
e.device = wgDevice
e.pause = service.FromContext[pause.Manager](e.options.Context)
@@ -294,10 +296,12 @@ func (e *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
func (e *Endpoint) Close() error {
if e.pauseCallback != nil {
e.pause.UnregisterCallback(e.pauseCallback)
e.pauseCallback = nil
}
if e.device != nil {
e.device.Down()
e.device.Close()
e.device = nil
}
return nil
}
@@ -336,18 +340,19 @@ type peerConfig struct {
}
func (c peerConfig) GenerateIpcLines() string {
ipcLines := "\npublic_key=" + c.publicKeyHex
var ipcLines strings.Builder
ipcLines.WriteString("\npublic_key=" + c.publicKeyHex)
if c.endpoint.IsValid() {
ipcLines += "\nendpoint=" + c.endpoint.String()
ipcLines.WriteString("\nendpoint=" + c.endpoint.String())
}
if c.preSharedKeyHex != "" {
ipcLines += "\npreshared_key=" + c.preSharedKeyHex
ipcLines.WriteString("\npreshared_key=" + c.preSharedKeyHex)
}
for _, allowedIP := range c.allowedIPs {
ipcLines += "\nallowed_ip=" + allowedIP.String()
ipcLines.WriteString("\nallowed_ip=" + allowedIP.String())
}
if c.keepalive > 0 {
ipcLines += "\npersistent_keepalive_interval=" + F.ToString(c.keepalive)
ipcLines.WriteString("\npersistent_keepalive_interval=" + F.ToString(c.keepalive))
}
return ipcLines
return ipcLines.String()
}