diff --git a/.gitignore b/.gitignore index 6de2fb8..55e2e3b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ dae outline.json go-mod/ node_modules/ +*.log diff --git a/cmd/run.go b/cmd/run.go index 452db84..31e0958 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -18,6 +18,7 @@ import ( "github.com/mzz2017/softwind/netproxy" "github.com/mzz2017/softwind/pkg/fastrand" "github.com/mzz2017/softwind/protocol/direct" + "gopkg.in/natefinch/lumberjack.v2" "github.com/daeuniverse/dae/cmd/internal" "github.com/daeuniverse/dae/common" @@ -45,9 +46,12 @@ var ( ) func init() { - runCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file") - runCmd.PersistentFlags().BoolVarP(&disableTimestamp, "disable-timestamp", "", false, "disable timestamp") - runCmd.PersistentFlags().BoolVarP(&disableTimestamp, "disable-pidfile", "", false, "not generate /var/run/dae.pid") + runCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "Config file of dae.") + runCmd.PersistentFlags().StringVar(&logFile, "logfile", "", "Log file to write. Empty means writing to stdout and stderr.") + runCmd.PersistentFlags().IntVar(&logFileMaxSize, "logfile-maxsize", 30, "Unit: MB. The maximum size in megabytes of the log file before it gets rotated.") + runCmd.PersistentFlags().IntVar(&logFileMaxBackups, "logfile-maxbackups", 3, "The maximum number of old log files to retain.") + runCmd.PersistentFlags().BoolVarP(&disableTimestamp, "disable-timestamp", "", false, "Disable timestamp.") + runCmd.PersistentFlags().BoolVarP(&disablePidFile, "disable-pidfile", "", false, "Not generate /var/run/dae.pid.") fastrand.Rand().Shuffle(len(CheckNetworkLinks), func(i, j int) { CheckNetworkLinks[i], CheckNetworkLinks[j] = CheckNetworkLinks[j], CheckNetworkLinks[i] @@ -55,9 +59,12 @@ func init() { } var ( - cfgFile string - disableTimestamp bool - disablePidFile bool + cfgFile string + logFile string + logFileMaxSize int + logFileMaxBackups int + disableTimestamp bool + disablePidFile bool runCmd = &cobra.Command{ Use: "run", @@ -78,7 +85,18 @@ var ( }).Fatalln("Failed to read config") } - log := logger.NewLogger(conf.Global.LogLevel, disableTimestamp) + var logOpts *lumberjack.Logger + if logFile != "" { + logOpts = &lumberjack.Logger{ + Filename: logFile, + MaxSize: logFileMaxSize, + MaxAge: 0, + MaxBackups: logFileMaxBackups, + LocalTime: true, + Compress: true, + } + } + log := logger.NewLogger(conf.Global.LogLevel, disableTimestamp, logOpts) logrus.SetLevel(log.Level) log.Infof("Include config files: [%v]", strings.Join(includes, ", ")) @@ -181,7 +199,9 @@ loop: log.Infof("Include config files: [%v]", strings.Join(includes, ", ")) } // New logger. - log = logger.NewLogger(newConf.Global.LogLevel, disableTimestamp) + oldLogOutput := log.Out + log = logger.NewLogger(newConf.Global.LogLevel, disableTimestamp, nil) + log.SetOutput(oldLogOutput) // FIXME: THIS IS A HACK. logrus.SetLevel(log.Level) // New control plane. diff --git a/common/consts/ebpf.go b/common/consts/ebpf.go index a22a482..0b27802 100644 --- a/common/consts/ebpf.go +++ b/common/consts/ebpf.go @@ -65,6 +65,8 @@ const ( OutboundDirect OutboundIndex = iota OutboundBlock + OutboundUserDefinedMin + OutboundMustRules OutboundIndex = 0xFC OutboundControlPlaneRouting OutboundIndex = 0xFD OutboundLogicalOr OutboundIndex = 0xFE diff --git a/component/outbound/dialer_group_test.go b/component/outbound/dialer_group_test.go index ca200d8..43498f5 100644 --- a/component/outbound/dialer_group_test.go +++ b/component/outbound/dialer_group_test.go @@ -26,8 +26,9 @@ var TestNetworkType = &dialer.NetworkType{ IsDns: false, } +var log = logger.NewLogger("trace", false, nil) + func TestDialerGroup_Select_Fixed(t *testing.T) { - log := logger.NewLogger("trace", false) option := &dialer.GlobalOption{ Log: log, TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: []string{testTcpCheckUrl}}, @@ -69,7 +70,6 @@ func TestDialerGroup_Select_Fixed(t *testing.T) { } func TestDialerGroup_Select_MinLastLatency(t *testing.T) { - log := logger.NewLogger("trace", false) option := &dialer.GlobalOption{ Log: log, @@ -139,7 +139,6 @@ func TestDialerGroup_Select_MinLastLatency(t *testing.T) { } func TestDialerGroup_Select_Random(t *testing.T) { - log := logger.NewLogger("trace", false) option := &dialer.GlobalOption{ Log: log, @@ -179,7 +178,6 @@ func TestDialerGroup_Select_Random(t *testing.T) { } func TestDialerGroup_SetAlive(t *testing.T) { - log := logger.NewLogger("trace", false) option := &dialer.GlobalOption{ Log: log, diff --git a/control/control_plane.go b/control/control_plane.go index b21b4a0..332af41 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -565,6 +565,9 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip if c.realDomainSet.TestString(domain) { c.muRealDomainSet.Unlock() dialMode = consts.DialMode_Domain + + // Should use this domain to reroute + shouldReroute = true } else { c.muRealDomainSet.Unlock() // Lookup A/AAAA to make sure it is a real domain. @@ -589,6 +592,7 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip } case consts.DialMode_DomainCao: + shouldReroute = true fallthrough case consts.DialMode_DomainPlus: dialMode = consts.DialMode_Domain diff --git a/control/tcp.go b/control/tcp.go index fb3e7b2..15660bb 100644 --- a/control/tcp.go +++ b/control/tcp.go @@ -127,9 +127,6 @@ func (c *ControlPlane) RouteDialTcp(p *RouteDialParam) (conn netproxy.Conn, err domain := p.Domain src := p.Src dst := p.Dest - if c.dialMode == consts.DialMode_DomainCao && domain != "" { - outboundIndex = consts.OutboundControlPlaneRouting - } dialTarget, shouldReroute, dialIp := c.ChooseDialTarget(outboundIndex, dst, domain) if shouldReroute { @@ -159,6 +156,9 @@ func (c *ControlPlane) RouteDialTcp(p *RouteDialParam) (conn netproxy.Conn, err } // TODO: Set-up ip to domain mapping and show domain if possible. if int(outboundIndex) >= len(c.outbounds) { + if len(c.outbounds) == int(consts.OutboundUserDefinedMin) { + return nil, fmt.Errorf("traffic was dropped due to no-load configuration") + } return nil, fmt.Errorf("outbound id from bpf is out of range: %v not in [0, %v]", outboundIndex, len(c.outbounds)-1) } outbound := c.outbounds[outboundIndex] diff --git a/control/udp.go b/control/udp.go index 5419bb7..c05f45e 100644 --- a/control/udp.go +++ b/control/udp.go @@ -179,9 +179,6 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r } // Get outbound. outboundIndex := consts.OutboundIndex(routingResult.Outbound) - if c.dialMode == consts.DialMode_DomainCao && domain != "" { - outboundIndex = consts.OutboundControlPlaneRouting - } dialTarget, shouldReroute, dialIp := c.ChooseDialTarget(outboundIndex, realDst, domain) getNew: if retry > MaxRetry { @@ -229,6 +226,9 @@ getNew: } if int(outboundIndex) >= len(c.outbounds) { + if len(c.outbounds) == int(consts.OutboundUserDefinedMin) { + return nil, fmt.Errorf("traffic was dropped due to no-load configuration") + } return nil, fmt.Errorf("outbound %v out of range [0, %v]", outboundIndex, len(c.outbounds)-1) } outbound := c.outbounds[outboundIndex] diff --git a/go.mod b/go.mod index fbf4fcb..7446ada 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( golang.org/x/net v0.12.0 // indirect golang.org/x/tools v0.11.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect ) require ( diff --git a/go.sum b/go.sum index 7d8bf24..6476a6d 100644 --- a/go.sum +++ b/go.sum @@ -231,6 +231,8 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 7a42e0b..d0e905b 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -8,9 +8,10 @@ package logger import ( "github.com/sirupsen/logrus" prefixed "github.com/x-cray/logrus-prefixed-formatter" + "gopkg.in/natefinch/lumberjack.v2" ) -func NewLogger(logLevel string, disableTimestamp bool) *logrus.Logger { +func NewLogger(logLevel string, disableTimestamp bool, logFileOpt *lumberjack.Logger) *logrus.Logger { log := logrus.New() level, err := logrus.ParseLevel(logLevel) @@ -24,6 +25,9 @@ func NewLogger(logLevel string, disableTimestamp bool) *logrus.Logger { FullTimestamp: true, TimestampFormat: "Jan 02 15:04:05", }) + if logFileOpt != nil { + log.SetOutput(logFileOpt) + } return log }