You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
4.3 KiB

4 years ago
package engine
import (
"errors"
"fmt"
"net"
"sync"
"time"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
"github.com/xjasonlyu/tun2socks/v2/core"
"github.com/xjasonlyu/tun2socks/v2/core/device"
"github.com/xjasonlyu/tun2socks/v2/core/option"
"github.com/xjasonlyu/tun2socks/v2/engine/mirror"
"github.com/xjasonlyu/tun2socks/v2/log"
"github.com/xjasonlyu/tun2socks/v2/proxy"
"github.com/xjasonlyu/tun2socks/v2/restapi"
"github.com/xjasonlyu/tun2socks/v2/tunnel"
"github.com/docker/go-units"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/stack"
4 years ago
)
var (
_engineMu sync.Mutex
// _defaultKey holds the default key for the engine.
_defaultKey *Key
// _defaultProxy holds the default proxy for the engine.
_defaultProxy proxy.Proxy
// _defaultDevice holds the default device for the engine.
_defaultDevice device.Device
// _defaultStack holds the default stack for the engine.
_defaultStack *stack.Stack
)
// Start starts the default engine up.
func Start() {
if err := start(); err != nil {
log.Fatalf("[ENGINE] failed to start: %v", err)
}
}
// Stop shuts the default engine down.
func Stop() {
if err := stop(); err != nil {
log.Fatalf("[ENGINE] failed to stop: %v", err)
}
}
// Insert loads *Key to the default engine.
func Insert(k *Key) {
_engineMu.Lock()
_defaultKey = k
_engineMu.Unlock()
}
func start() error {
_engineMu.Lock()
if _defaultKey == nil {
return errors.New("empty key")
}
4 years ago
for _, f := range []func(*Key) error{
general,
restAPI,
netstack,
4 years ago
} {
if err := f(_defaultKey); err != nil {
4 years ago
return err
}
}
_engineMu.Unlock()
4 years ago
return nil
}
func stop() (err error) {
_engineMu.Lock()
if _defaultDevice != nil {
err = _defaultDevice.Close()
4 years ago
}
if _defaultStack != nil {
_defaultStack.Close()
_defaultStack.Wait()
}
_engineMu.Unlock()
return err
}
func general(k *Key) error {
level, err := log.ParseLevel(k.LogLevel)
4 years ago
if err != nil {
return err
}
log.SetLevel(level)
if k.Interface != "" {
iface, err := net.InterfaceByName(k.Interface)
if err != nil {
return err
}
dialer.DefaultInterfaceName.Store(iface.Name)
dialer.DefaultInterfaceIndex.Store(int32(iface.Index))
log.Infof("[DIALER] bind to interface: %s", k.Interface)
4 years ago
}
if k.Mark != 0 {
dialer.DefaultRoutingMark.Store(int32(k.Mark))
log.Infof("[DIALER] set fwmark: %#x", k.Mark)
}
if k.UDPTimeout > 0 {
if k.UDPTimeout < time.Second {
return errors.New("invalid udp timeout value")
}
tunnel.SetUDPTimeout(k.UDPTimeout)
}
4 years ago
return nil
}
func restAPI(k *Key) error {
if k.RestAPI != "" {
u, err := parseRestAPI(k.RestAPI)
if err != nil {
return err
}
host, token := u.Host, u.User.String()
restapi.SetStatsFunc(func() tcpip.Stats {
_engineMu.Lock()
defer _engineMu.Unlock()
// default stack is not initialized.
if _defaultStack == nil {
return tcpip.Stats{}
}
return _defaultStack.Stats()
})
4 years ago
go func() {
if err := restapi.Start(host, token); err != nil {
log.Warnf("[RESTAPI] failed to start: %v", err)
}
4 years ago
}()
log.Infof("[RESTAPI] serve at: %s", u)
4 years ago
}
return nil
}
func netstack(k *Key) (err error) {
if k.Proxy == "" {
return errors.New("empty proxy")
}
if k.Device == "" {
return errors.New("empty device")
}
if _defaultProxy, err = parseProxy(k.Proxy); err != nil {
return
}
proxy.SetDialer(_defaultProxy)
4 years ago
if _defaultDevice, err = parseDevice(k.Device, uint32(k.MTU)); err != nil {
return
}
var opts []option.Option
if k.TCPModerateReceiveBuffer {
opts = append(opts, option.WithTCPModerateReceiveBuffer(true))
}
if k.TCPSendBufferSize != "" {
size, err := units.RAMInBytes(k.TCPSendBufferSize)
if err != nil {
return err
}
opts = append(opts, option.WithTCPSendBufferSize(int(size)))
}
if k.TCPReceiveBufferSize != "" {
size, err := units.RAMInBytes(k.TCPReceiveBufferSize)
if err != nil {
return err
}
opts = append(opts, option.WithTCPReceiveBufferSize(int(size)))
}
if _defaultStack, err = core.CreateStack(&core.Config{
LinkEndpoint: _defaultDevice,
TransportHandler: &mirror.Tunnel{},
PrintFunc: func(format string, v ...any) {
log.Warnf("[STACK] %s", fmt.Sprintf(format, v...))
},
Options: opts,
}); err != nil {
return
}
log.Infof(
"[STACK] %s://%s <-> %s://%s",
_defaultDevice.Type(), _defaultDevice.Name(),
_defaultProxy.Proto(), _defaultProxy.Addr(),
)
return nil
4 years ago
}