2023-01-28 00:50:21 +07:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/spf13/cobra"
|
2023-01-28 12:27:54 +07:00
|
|
|
"github.com/v2rayA/dae/cmd/internal"
|
2023-01-28 00:50:21 +07:00
|
|
|
"github.com/v2rayA/dae/config"
|
2023-02-07 22:49:30 +07:00
|
|
|
"github.com/v2rayA/dae/control"
|
2023-01-28 00:50:21 +07:00
|
|
|
"github.com/v2rayA/dae/pkg/logger"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
2023-02-09 19:17:45 +07:00
|
|
|
"path/filepath"
|
2023-02-09 22:17:49 +07:00
|
|
|
"strings"
|
2023-01-28 00:50:21 +07:00
|
|
|
"syscall"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2023-02-04 21:02:37 +07:00
|
|
|
cfgFile string
|
|
|
|
disableTimestamp bool
|
2023-01-28 00:50:21 +07:00
|
|
|
|
|
|
|
runCmd = &cobra.Command{
|
|
|
|
Use: "run",
|
|
|
|
Short: "Run dae in the foreground",
|
|
|
|
Run: func(cmd *cobra.Command, args []string) {
|
2023-02-01 10:10:41 +07:00
|
|
|
if cfgFile == "" {
|
|
|
|
logrus.Fatalln("Argument \"--config\" or \"-c\" is required but not provided.")
|
|
|
|
}
|
2023-02-05 13:03:34 +07:00
|
|
|
|
2023-02-07 12:49:47 +07:00
|
|
|
// Require "sudo" if necessary.
|
|
|
|
internal.AutoSu()
|
|
|
|
|
2023-02-05 13:03:34 +07:00
|
|
|
// Read config from --config cfgFile.
|
2023-02-09 22:17:49 +07:00
|
|
|
param, includes, err := readConfig(cfgFile)
|
2023-02-05 13:03:34 +07:00
|
|
|
if err != nil {
|
2023-02-05 20:05:23 +07:00
|
|
|
logrus.Fatalln("readConfig:", err)
|
2023-02-05 13:03:34 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
log := logger.NewLogger(param.Global.LogLevel, disableTimestamp)
|
|
|
|
logrus.SetLevel(log.Level)
|
2023-02-09 22:17:49 +07:00
|
|
|
|
|
|
|
log.Infof("Include config files: [%v]", strings.Join(includes, ", "))
|
2023-02-05 13:03:34 +07:00
|
|
|
if err := Run(log, param); err != nil {
|
2023-01-28 00:50:21 +07:00
|
|
|
logrus.Fatalln(err)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2023-02-01 10:10:41 +07:00
|
|
|
runCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file")
|
2023-02-04 21:02:37 +07:00
|
|
|
runCmd.PersistentFlags().BoolVarP(&disableTimestamp, "disable-timestamp", "", false, "disable timestamp")
|
2023-01-28 00:50:21 +07:00
|
|
|
}
|
|
|
|
|
2023-02-05 13:03:34 +07:00
|
|
|
func Run(log *logrus.Logger, param *config.Params) (err error) {
|
2023-01-28 00:50:21 +07:00
|
|
|
|
2023-02-10 10:04:16 +07:00
|
|
|
/// Get tag -> nodeList mapping.
|
|
|
|
tagToNodeList := map[string][]string{}
|
|
|
|
if len(param.Node) > 0 {
|
|
|
|
tagToNodeList[""] = append(tagToNodeList[""], param.Node...)
|
|
|
|
}
|
2023-01-28 00:50:21 +07:00
|
|
|
// Resolve subscriptions to nodes.
|
|
|
|
for _, sub := range param.Subscription {
|
2023-02-10 10:04:16 +07:00
|
|
|
tag, nodes, err := internal.ResolveSubscription(log, filepath.Dir(cfgFile), sub)
|
2023-01-28 00:50:21 +07:00
|
|
|
if err != nil {
|
|
|
|
log.Warnf(`failed to resolve subscription "%v": %v`, sub, err)
|
|
|
|
}
|
2023-02-10 10:04:16 +07:00
|
|
|
if len(nodes) > 0 {
|
|
|
|
tagToNodeList[tag] = append(tagToNodeList[tag], nodes...)
|
|
|
|
}
|
2023-01-28 00:50:21 +07:00
|
|
|
}
|
2023-02-10 10:04:16 +07:00
|
|
|
if len(tagToNodeList) == 0 {
|
2023-02-04 21:02:37 +07:00
|
|
|
return fmt.Errorf("no node found, which could because all subscription resolving failed")
|
|
|
|
}
|
2023-01-28 00:50:21 +07:00
|
|
|
|
2023-02-01 11:30:26 +07:00
|
|
|
if len(param.Global.LanInterface) == 0 && len(param.Global.WanInterface) == 0 {
|
2023-02-01 09:59:57 +07:00
|
|
|
return fmt.Errorf("LanInterface and WanInterface cannot both be empty")
|
|
|
|
}
|
|
|
|
|
2023-01-28 00:50:21 +07:00
|
|
|
// New ControlPlane.
|
|
|
|
t, err := control.NewControlPlane(
|
|
|
|
log,
|
2023-02-10 10:04:16 +07:00
|
|
|
tagToNodeList,
|
2023-01-28 00:50:21 +07:00
|
|
|
param.Group,
|
|
|
|
¶m.Routing,
|
2023-02-08 15:07:23 +07:00
|
|
|
¶m.Global,
|
2023-01-28 00:50:21 +07:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Serve tproxy TCP/UDP server util signals.
|
|
|
|
sigs := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGILL)
|
|
|
|
go func() {
|
|
|
|
if err := t.ListenAndServe(param.Global.TproxyPort); err != nil {
|
|
|
|
log.Errorln("ListenAndServe:", err)
|
|
|
|
sigs <- nil
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
<-sigs
|
|
|
|
if e := t.Close(); e != nil {
|
|
|
|
return fmt.Errorf("close control plane: %w", e)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-02-09 22:17:49 +07:00
|
|
|
func readConfig(cfgFile string) (params *config.Params, entries []string, err error) {
|
|
|
|
merger := config.NewMerger(cfgFile)
|
|
|
|
sections, entries, err := merger.Merge()
|
2023-01-28 00:50:21 +07:00
|
|
|
if err != nil {
|
2023-02-09 22:17:49 +07:00
|
|
|
return nil, nil, err
|
2023-01-28 00:50:21 +07:00
|
|
|
}
|
|
|
|
if params, err = config.New(sections); err != nil {
|
2023-02-09 22:17:49 +07:00
|
|
|
return nil, nil, err
|
2023-01-28 00:50:21 +07:00
|
|
|
}
|
2023-02-09 22:17:49 +07:00
|
|
|
return params, entries, nil
|
2023-01-28 00:50:21 +07:00
|
|
|
}
|