|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/core/device"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/core/stack"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/log"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/proxy"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/stats"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/tunnel"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/version"
|
|
|
|
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _engine = &engine{}
|
|
|
|
|
|
|
|
// Start starts the default engine up.
|
|
|
|
func Start() error {
|
|
|
|
return _engine.start()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop shuts the default engine down.
|
|
|
|
func Stop() error {
|
|
|
|
return _engine.stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert loads *Key to the default engine.
|
|
|
|
func Insert(k *Key) {
|
|
|
|
_engine.insert(k)
|
|
|
|
}
|
|
|
|
|
|
|
|
type Key struct {
|
|
|
|
MTU int `yaml:"mtu"`
|
|
|
|
Mark int `yaml:"fwmark"`
|
|
|
|
UDPTimeout int `yaml:"udp-timeout"`
|
|
|
|
Proxy string `yaml:"proxy"`
|
|
|
|
Stats string `yaml:"stats"`
|
|
|
|
Token string `yaml:"token"`
|
|
|
|
Device string `yaml:"device"`
|
|
|
|
LogLevel string `yaml:"loglevel"`
|
|
|
|
Interface string `yaml:"interface"`
|
|
|
|
Config string `yaml:"-"`
|
|
|
|
Version bool `yaml:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type engine struct {
|
|
|
|
*Key
|
|
|
|
|
|
|
|
stack *stack.Stack
|
|
|
|
proxy proxy.Proxy
|
|
|
|
device device.Device
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) start() error {
|
|
|
|
if e.Key == nil {
|
|
|
|
return errors.New("empty key")
|
|
|
|
}
|
|
|
|
|
|
|
|
if e.Version {
|
|
|
|
fmt.Println(version.String())
|
|
|
|
fmt.Println(version.BuildString())
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range []func() error{
|
|
|
|
e.setConfig,
|
|
|
|
e.setLogLevel,
|
|
|
|
e.setMark,
|
|
|
|
e.setInterface,
|
|
|
|
e.setStats,
|
|
|
|
e.setUDPTimeout,
|
|
|
|
e.setProxy,
|
|
|
|
e.setDevice,
|
|
|
|
e.setStack,
|
|
|
|
} {
|
|
|
|
if err := f(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) stop() error {
|
|
|
|
if e.device != nil {
|
|
|
|
return e.device.Close()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) insert(k *Key) {
|
|
|
|
e.Key = k
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setConfig() error {
|
|
|
|
if e.Config == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := os.ReadFile(e.Config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return yaml.Unmarshal(data, e.Key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setLogLevel() error {
|
|
|
|
level, err := log.ParseLevel(e.LogLevel)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.SetLevel(level)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setMark() error {
|
|
|
|
if e.Mark != 0 {
|
|
|
|
dialer.SetMark(e.Mark)
|
|
|
|
log.Infof("[DIALER] set fwmark: %#x", e.Mark)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setInterface() error {
|
|
|
|
if e.Interface != "" {
|
|
|
|
if err := dialer.BindToInterface(e.Interface); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Infof("[DIALER] use interface: %s", e.Interface)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setStats() error {
|
|
|
|
if e.Stats != "" {
|
|
|
|
go func() {
|
|
|
|
_ = stats.Start(e.Stats, e.Token)
|
|
|
|
}()
|
|
|
|
log.Infof("[STATS] serve at: http://%s", e.Stats)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setUDPTimeout() error {
|
|
|
|
if e.UDPTimeout > 0 {
|
|
|
|
tunnel.SetUDPTimeout(e.UDPTimeout)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setProxy() (err error) {
|
|
|
|
if e.Proxy == "" {
|
|
|
|
return errors.New("empty proxy")
|
|
|
|
}
|
|
|
|
|
|
|
|
e.proxy, err = parseProxy(e.Proxy)
|
|
|
|
proxy.SetDialer(e.proxy)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setDevice() (err error) {
|
|
|
|
if e.Device == "" {
|
|
|
|
return errors.New("empty device")
|
|
|
|
}
|
|
|
|
|
|
|
|
e.device, err = parseDevice(e.Device, uint32(e.MTU))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *engine) setStack() (err error) {
|
|
|
|
defer func() {
|
|
|
|
if err == nil {
|
|
|
|
log.Infof(
|
|
|
|
"[STACK] %s://%s <-> %s://%s",
|
|
|
|
e.device.Type(), e.device.Name(),
|
|
|
|
e.proxy.Proto(), e.proxy.Addr(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
e.stack, err = stack.New(e.device, &fakeTunnel{}, stack.WithDefault())
|
|
|
|
return
|
|
|
|
}
|