mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-04 15:27:55 +07:00
feat: support reload
This commit is contained in:
88
cmd/run.go
88
cmd/run.go
@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mohae/deepcopy"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/v2rayA/dae/cmd/internal"
|
||||
@ -55,6 +56,66 @@ func init() {
|
||||
|
||||
func Run(log *logrus.Logger, conf *config.Config) (err error) {
|
||||
|
||||
// New ControlPlane.
|
||||
c, err := newControlPlane(log, nil, conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Serve tproxy TCP/UDP server util signals.
|
||||
var listener *control.Listener
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGILL, syscall.SIGUSR1)
|
||||
go func() {
|
||||
if listener, err = c.ListenAndServe(conf.Global.TproxyPort); err != nil {
|
||||
log.Errorln("ListenAndServe:", err)
|
||||
}
|
||||
sigs <- nil
|
||||
}()
|
||||
reloading := false
|
||||
loop:
|
||||
for sig := range sigs {
|
||||
switch sig {
|
||||
case nil:
|
||||
if reloading {
|
||||
reloading = false
|
||||
log.Warnln("[Reload] Serve")
|
||||
go func() {
|
||||
if err := c.Serve(listener); err != nil {
|
||||
log.Errorln("ListenAndServe:", err)
|
||||
}
|
||||
sigs <- nil
|
||||
}()
|
||||
} else {
|
||||
break loop
|
||||
}
|
||||
case syscall.SIGUSR1:
|
||||
// Reload signal.
|
||||
log.Warnln("[Reload] Received reload signal; prepare to reload")
|
||||
obj := c.EjectBpf()
|
||||
log.Warnln("[Reload] Load new control plane")
|
||||
newC, err := newControlPlane(log, obj, conf)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"err": err,
|
||||
}).Errorln("failed to reload")
|
||||
continue
|
||||
}
|
||||
log.Warnln("[Reload] Stopped old control plane")
|
||||
c.Close()
|
||||
c = newC
|
||||
reloading = true
|
||||
default:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
if e := c.Close(); e != nil {
|
||||
return fmt.Errorf("close control plane: %w", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newControlPlane(log *logrus.Logger, bpf interface{}, conf *config.Config) (c *control.ControlPlane, err error) {
|
||||
/// Get tag -> nodeList mapping.
|
||||
tagToNodeList := map[string][]string{}
|
||||
if len(conf.Node) > 0 {
|
||||
@ -73,16 +134,18 @@ func Run(log *logrus.Logger, conf *config.Config) (err error) {
|
||||
}
|
||||
}
|
||||
if len(tagToNodeList) == 0 {
|
||||
return fmt.Errorf("no node found, which could because all subscription resolving failed")
|
||||
return nil, fmt.Errorf("no node found, which could because all subscription resolving failed")
|
||||
}
|
||||
|
||||
if len(conf.Global.LanInterface) == 0 && len(conf.Global.WanInterface) == 0 {
|
||||
return fmt.Errorf("LanInterface and WanInterface cannot both be empty")
|
||||
return nil, fmt.Errorf("LanInterface and WanInterface cannot both be empty")
|
||||
}
|
||||
|
||||
// New ControlPlane.
|
||||
t, err := control.NewControlPlane(
|
||||
// Deep copy a conf to avoid modification.
|
||||
conf = deepcopy.Copy(conf).(*config.Config)
|
||||
c, err = control.NewControlPlane(
|
||||
log,
|
||||
bpf,
|
||||
tagToNodeList,
|
||||
conf.Group,
|
||||
&conf.Routing,
|
||||
@ -90,26 +153,13 @@ func Run(log *logrus.Logger, conf *config.Config) (err error) {
|
||||
&conf.Dns,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Call GC to release memory.
|
||||
runtime.GC()
|
||||
|
||||
// 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(conf.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
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func readConfig(cfgFile string) (conf *config.Config, includes []string, err error) {
|
||||
|
@ -15,6 +15,11 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Init = 1 + iota
|
||||
NotAlive
|
||||
)
|
||||
|
||||
type minLatency struct {
|
||||
latency time.Duration
|
||||
dialer *Dialer
|
||||
@ -66,7 +71,7 @@ func NewAliveDialerSet(
|
||||
},
|
||||
}
|
||||
for _, d := range dialers {
|
||||
a.dialerToIndex[d] = -1
|
||||
a.dialerToIndex[d] = -Init
|
||||
}
|
||||
for _, d := range dialers {
|
||||
a.NotifyLatencyChange(d, setAlive)
|
||||
@ -131,10 +136,13 @@ func (a *AliveDialerSet) NotifyLatencyChange(dialer *Dialer, alive bool) {
|
||||
// This dialer is already alive.
|
||||
} else {
|
||||
// Dialer: not alive -> alive.
|
||||
if index == -NotAlive {
|
||||
a.log.WithFields(logrus.Fields{
|
||||
"dialer": dialer.Name(),
|
||||
"group": a.dialerGroupName,
|
||||
"network": a.CheckTyp.StringWithoutDns(),
|
||||
}).Infoln("NOT ALIVE -> ALIVE:")
|
||||
}
|
||||
a.dialerToIndex[dialer] = len(a.inorderedAliveDialerSet)
|
||||
a.inorderedAliveDialerSet = append(a.inorderedAliveDialerSet, dialer)
|
||||
}
|
||||
@ -144,13 +152,14 @@ func (a *AliveDialerSet) NotifyLatencyChange(dialer *Dialer, alive bool) {
|
||||
// Dialer: alive -> not alive.
|
||||
a.log.WithFields(logrus.Fields{
|
||||
"dialer": dialer.Name(),
|
||||
"group": a.dialerGroupName,
|
||||
"network": a.CheckTyp.StringWithoutDns(),
|
||||
}).Infoln("ALIVE -> NOT ALIVE:")
|
||||
// Remove the dialer from inorderedAliveDialerSet.
|
||||
if index >= len(a.inorderedAliveDialerSet) {
|
||||
a.log.Panicf("index:%v >= len(a.inorderedAliveDialerSet):%v", index, len(a.inorderedAliveDialerSet))
|
||||
}
|
||||
a.dialerToIndex[dialer] = -1
|
||||
a.dialerToIndex[dialer] = -NotAlive
|
||||
if index < len(a.inorderedAliveDialerSet)-1 {
|
||||
// Swap this element with the last element.
|
||||
dialerToSwap := a.inorderedAliveDialerSet[len(a.inorderedAliveDialerSet)-1]
|
||||
|
@ -136,3 +136,13 @@ func (s *DialerSet) Filter(filters []*config_parser.Function) (dialers []*dialer
|
||||
}
|
||||
return dialers, nil
|
||||
}
|
||||
|
||||
func (s *DialerSet) Close() error {
|
||||
var err error
|
||||
for _, d := range s.dialers {
|
||||
if e := d.Close(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ var SectionDescription = map[string]Desc{
|
||||
}
|
||||
|
||||
var GlobalDesc = Desc{
|
||||
"tproxy_port": "tproxy port to listen at. It is NOT a HTTP/SOCKS port, and is just used by eBPF program.\nIn normal case, you do not need to use it.",
|
||||
"tproxy_port": "tproxy port to listen on. It is NOT a HTTP/SOCKS port, and is just used by eBPF program.\nIn normal case, you do not need to use it.",
|
||||
"log_level": "Log level: error, warn, info, debug, trace.",
|
||||
"tcp_check_url": "Node connectivity check.\nHost of URL should have both IPv4 and IPv6 if you have double stack in local.\nConsidering traffic consumption, it is recommended to choose a site with anycast IP and less response.",
|
||||
"udp_check_dns": "This DNS will be used to check UDP connectivity of nodes. And if dns_upstream below contains tcp, it also be used to check TCP DNS connectivity of nodes.\nThis DNS should have both IPv4 and IPv6 if you have double stack in local.",
|
||||
|
@ -23,7 +23,7 @@ func FormatL4Proto(l4proto uint8) string {
|
||||
return strconv.Itoa(int(l4proto))
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) OutboundAliveChangeCallback(outbound uint8) func(alive bool, networkType *dialer.NetworkType) {
|
||||
func (c *controlPlaneCore) OutboundAliveChangeCallback(outbound uint8) func(alive bool, networkType *dialer.NetworkType) {
|
||||
return func(alive bool, networkType *dialer.NetworkType) {
|
||||
c.log.WithFields(logrus.Fields{
|
||||
"alive": alive,
|
||||
|
@ -38,7 +38,7 @@ import (
|
||||
type ControlPlane struct {
|
||||
log *logrus.Logger
|
||||
|
||||
core *ControlPlaneCore
|
||||
core *controlPlaneCore
|
||||
deferFuncs []func() error
|
||||
listenIp string
|
||||
|
||||
@ -55,6 +55,7 @@ type ControlPlane struct {
|
||||
|
||||
func NewControlPlane(
|
||||
log *logrus.Logger,
|
||||
_bpf interface{},
|
||||
tagToNodeList map[string][]string,
|
||||
groups []config.Group,
|
||||
routingA *config.Routing,
|
||||
@ -88,6 +89,8 @@ func NewControlPlane(
|
||||
consts.BasicFeatureVersion.String())
|
||||
}
|
||||
|
||||
var deferFuncs []func() error
|
||||
|
||||
/// Allow the current process to lock memory for eBPF resources.
|
||||
if err = rlimit.RemoveMemlock(); err != nil {
|
||||
return nil, fmt.Errorf("rlimit.RemoveMemlock:%v", err)
|
||||
@ -102,7 +105,7 @@ func NewControlPlane(
|
||||
|
||||
/// Load pre-compiled programs and maps into the kernel.
|
||||
log.Infof("Loading eBPF programs and maps into the kernel")
|
||||
var bpf bpfObjects
|
||||
//var bpf bpfObjects
|
||||
var ProgramOptions = ebpf.ProgramOptions{
|
||||
KernelTypes: nil,
|
||||
}
|
||||
@ -116,7 +119,16 @@ func NewControlPlane(
|
||||
},
|
||||
Programs: ProgramOptions,
|
||||
}
|
||||
if err = fullLoadBpfObjects(log, &bpf, &loadBpfOptions{
|
||||
var bpf *bpfObjects
|
||||
if _bpf != nil {
|
||||
if _bpf, ok := _bpf.(*bpfObjects); ok {
|
||||
bpf = _bpf
|
||||
} else {
|
||||
return nil, fmt.Errorf("unexpected bpf type: %T", _bpf)
|
||||
}
|
||||
} else {
|
||||
bpf = new(bpfObjects)
|
||||
if err = fullLoadBpfObjects(log, bpf, &loadBpfOptions{
|
||||
PinPath: pinPath,
|
||||
CollectionOptions: collectionOpts,
|
||||
BindLan: len(global.LanInterface) > 0,
|
||||
@ -127,13 +139,17 @@ func NewControlPlane(
|
||||
}
|
||||
return nil, fmt.Errorf("load eBPF objects: %w", err)
|
||||
}
|
||||
|
||||
core := &ControlPlaneCore{
|
||||
log: log,
|
||||
deferFuncs: []func() error{bpf.Close},
|
||||
bpf: &bpf,
|
||||
kernelVersion: &kernelVersion,
|
||||
}
|
||||
|
||||
// outboundId2Name can be modified later.
|
||||
outboundId2Name := make(map[uint8]string)
|
||||
core := newControlPlaneCore(
|
||||
log,
|
||||
bpf,
|
||||
outboundId2Name,
|
||||
&kernelVersion,
|
||||
_bpf != nil,
|
||||
)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = core.Close()
|
||||
@ -141,16 +157,7 @@ func NewControlPlane(
|
||||
}()
|
||||
|
||||
// Write params.
|
||||
var lanNatDirect uint32
|
||||
if global.LanNatDirect {
|
||||
lanNatDirect = 1
|
||||
} else {
|
||||
lanNatDirect = 0
|
||||
}
|
||||
if err = bpf.ParamMap.Update(consts.ControlPlaneNatDirectKey, lanNatDirect, ebpf.UpdateAny); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = bpf.ParamMap.Update(consts.ControlPlanePidKey, uint32(os.Getpid()), ebpf.UpdateAny); err != nil {
|
||||
if err = core.bpf.ParamMap.Update(consts.ControlPlanePidKey, uint32(os.Getpid()), ebpf.UpdateAny); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -212,6 +219,7 @@ func NewControlPlane(
|
||||
|
||||
// Filter out groups.
|
||||
dialerSet := outbound.NewDialerSetFromLinks(option, tagToNodeList)
|
||||
deferFuncs = append(deferFuncs, dialerSet.Close)
|
||||
for _, group := range groups {
|
||||
// Parse policy.
|
||||
policy, err := outbound.NewDialerSelectionPolicyFromGroupParam(&group)
|
||||
@ -244,7 +252,6 @@ func NewControlPlane(
|
||||
return nil, fmt.Errorf("too many outbounds")
|
||||
}
|
||||
outboundName2Id := make(map[string]uint8)
|
||||
outboundId2Name := make(map[uint8]string)
|
||||
for i, o := range outbounds {
|
||||
if _, exist := outboundName2Id[o.Name]; exist {
|
||||
return nil, fmt.Errorf("duplicated outbound name: %v", o.Name)
|
||||
@ -252,7 +259,6 @@ func NewControlPlane(
|
||||
outboundName2Id[o.Name] = uint8(i)
|
||||
outboundId2Name[uint8(i)] = o.Name
|
||||
}
|
||||
core.outboundId2Name = outboundId2Name
|
||||
// Apply rules optimizers.
|
||||
var rules []*config_parser.RoutingRule
|
||||
if rules, err = routing.ApplyRulesOptimizers(routingA.Rules,
|
||||
@ -272,7 +278,7 @@ func NewControlPlane(
|
||||
log.Debugf("RoutingA:\n%vfallback: %v\n", debugBuilder.String(), routingA.Fallback)
|
||||
}
|
||||
// Parse rules and build.
|
||||
builder, err := NewRoutingMatcherBuilder(log, rules, outboundName2Id, &bpf, routingA.Fallback)
|
||||
builder, err := NewRoutingMatcherBuilder(log, rules, outboundName2Id, core.bpf, routingA.Fallback)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("NewRoutingMatcherBuilder: %w", err)
|
||||
}
|
||||
@ -293,7 +299,7 @@ func NewControlPlane(
|
||||
c = &ControlPlane{
|
||||
log: log,
|
||||
core: core,
|
||||
deferFuncs: nil,
|
||||
deferFuncs: deferFuncs,
|
||||
listenIp: "0.0.0.0",
|
||||
outbounds: outbounds,
|
||||
dialMode: dialMode,
|
||||
@ -332,6 +338,11 @@ func NewControlPlane(
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// EjectBpf will resect bpf from destroying life-cycle of control plane.
|
||||
func (c *ControlPlane) EjectBpf() *bpfObjects {
|
||||
return c.core.EjectBpf()
|
||||
}
|
||||
|
||||
func (c *ControlPlane) dnsUpstreamReadyCallback(raw *url.URL, dnsUpstream *dns.Upstream) (err error) {
|
||||
/// Notify dialers to check.
|
||||
c.onceNetworkReady.Do(func() {
|
||||
@ -424,7 +435,17 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip
|
||||
case consts.DialMode_Ip:
|
||||
dialTarget = dst.String()
|
||||
case consts.DialMode_Domain:
|
||||
if _, err := netip.ParseAddr(domain); err == nil {
|
||||
// domain is IPv4 or IPv6 (has colon)
|
||||
dialTarget = net.JoinHostPort(domain, strconv.Itoa(int(dst.Port())))
|
||||
|
||||
} else if _, _, err := net.SplitHostPort(domain); err == nil {
|
||||
// domain is already domain:port
|
||||
dialTarget = domain
|
||||
|
||||
} else {
|
||||
dialTarget = net.JoinHostPort(domain, strconv.Itoa(int(dst.Port())))
|
||||
}
|
||||
c.log.WithFields(logrus.Fields{
|
||||
"from": dst.String(),
|
||||
"to": dialTarget,
|
||||
@ -433,29 +454,33 @@ func (c *ControlPlane) ChooseDialTarget(outbound consts.OutboundIndex, dst netip
|
||||
return dialTarget, dialMode
|
||||
}
|
||||
|
||||
func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
|
||||
// Listen.
|
||||
var listenConfig = net.ListenConfig{
|
||||
Control: func(network, address string, c syscall.RawConn) error {
|
||||
return dialer.TproxyControl(c)
|
||||
},
|
||||
}
|
||||
listenAddr := net.JoinHostPort(c.listenIp, strconv.Itoa(int(port)))
|
||||
tcpListener, err := listenConfig.Listen(context.TODO(), "tcp", listenAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listenTCP: %w", err)
|
||||
}
|
||||
defer tcpListener.Close()
|
||||
packetConn, err := listenConfig.ListenPacket(context.TODO(), "udp", listenAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listenUDP: %w", err)
|
||||
}
|
||||
defer packetConn.Close()
|
||||
udpConn := packetConn.(*net.UDPConn)
|
||||
type Listener struct {
|
||||
tcpListener net.Listener
|
||||
packetConn net.PacketConn
|
||||
port uint16
|
||||
}
|
||||
|
||||
func (l *Listener) Close() error {
|
||||
var (
|
||||
err error
|
||||
err2 error
|
||||
)
|
||||
if err, err2 = l.tcpListener.Close(), l.packetConn.Close(); err2 != nil {
|
||||
if err == nil {
|
||||
err = err2
|
||||
} else {
|
||||
err = fmt.Errorf("%w: %v", err, err2)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ControlPlane) Serve(listener *Listener) (err error) {
|
||||
|
||||
udpConn := listener.packetConn.(*net.UDPConn)
|
||||
/// Serve.
|
||||
// TCP socket.
|
||||
tcpFile, err := tcpListener.(*net.TCPListener).File()
|
||||
tcpFile, err := listener.tcpListener.(*net.TCPListener).File()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve copy of the underlying TCP connection file")
|
||||
}
|
||||
@ -477,7 +502,7 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
|
||||
return err
|
||||
}
|
||||
// Port.
|
||||
if err := c.core.bpf.ParamMap.Update(consts.BigEndianTproxyPortKey, uint32(common.Htons(port)), ebpf.UpdateAny); err != nil {
|
||||
if err := c.core.bpf.ParamMap.Update(consts.BigEndianTproxyPortKey, uint32(common.Htons(listener.port)), ebpf.UpdateAny); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -489,23 +514,33 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
|
||||
go func() {
|
||||
defer cancel()
|
||||
for {
|
||||
lconn, err := tcpListener.Accept()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
lconn, err := listener.tcpListener.Accept()
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
c.log.Errorf("Error when accept: %v", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
go func() {
|
||||
go func(lconn net.Conn) {
|
||||
if err := c.handleConn(lconn); err != nil {
|
||||
c.log.Warnln("handleConn:", err)
|
||||
}
|
||||
}()
|
||||
}(lconn)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer cancel()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
var buf [65535]byte
|
||||
var oob [120]byte // Size for original dest
|
||||
n, oobn, _, src, err := udpConn.ReadMsgUDPAddrPort(buf[:], oob[:])
|
||||
@ -551,6 +586,42 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ControlPlane) ListenAndServe(port uint16) (listener *Listener, err error) {
|
||||
// Listen.
|
||||
var listenConfig = net.ListenConfig{
|
||||
Control: func(network, address string, c syscall.RawConn) error {
|
||||
return dialer.TproxyControl(c)
|
||||
},
|
||||
}
|
||||
listenAddr := net.JoinHostPort(c.listenIp, strconv.Itoa(int(port)))
|
||||
tcpListener, err := listenConfig.Listen(context.TODO(), "tcp", listenAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listenTCP: %w", err)
|
||||
}
|
||||
packetConn, err := listenConfig.ListenPacket(context.TODO(), "udp", listenAddr)
|
||||
if err != nil {
|
||||
_ = tcpListener.Close()
|
||||
return nil, fmt.Errorf("listenUDP: %w", err)
|
||||
}
|
||||
listener = &Listener{
|
||||
tcpListener: tcpListener,
|
||||
packetConn: packetConn,
|
||||
port: port,
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = listener.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// Serve
|
||||
if err = c.Serve(listener); err != nil {
|
||||
return nil, fmt.Errorf("failed to serve: %w", err)
|
||||
}
|
||||
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
func (c *ControlPlane) chooseBestDnsDialer(
|
||||
req *udpRequest,
|
||||
dnsUpstream *dns.Upstream,
|
||||
|
@ -23,16 +23,39 @@ import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type ControlPlaneCore struct {
|
||||
var coreFlip = 0
|
||||
|
||||
type controlPlaneCore struct {
|
||||
log *logrus.Logger
|
||||
deferFuncs []func() error
|
||||
bpf *bpfObjects
|
||||
outboundId2Name map[uint8]string
|
||||
|
||||
kernelVersion *internal.Version
|
||||
|
||||
flip int
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) Close() (err error) {
|
||||
func newControlPlaneCore(log *logrus.Logger,
|
||||
bpf *bpfObjects,
|
||||
outboundId2Name map[uint8]string,
|
||||
kernelVersion *internal.Version,
|
||||
isReload bool,
|
||||
) *controlPlaneCore {
|
||||
if isReload {
|
||||
coreFlip = ((coreFlip & 1) ^ 1) & 1
|
||||
}
|
||||
return &controlPlaneCore{
|
||||
log: log,
|
||||
deferFuncs: []func() error{bpf.Close},
|
||||
bpf: bpf,
|
||||
outboundId2Name: outboundId2Name,
|
||||
kernelVersion: kernelVersion,
|
||||
flip: coreFlip,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *controlPlaneCore) Close() (err error) {
|
||||
// Invoke defer funcs in reverse order.
|
||||
for i := len(c.deferFuncs) - 1; i >= 0; i-- {
|
||||
if e := c.deferFuncs[i](); e != nil {
|
||||
@ -79,7 +102,7 @@ func getIfParamsFromLink(link netlink.Link) (ifParams bpfIfParams, err error) {
|
||||
return ifParams, nil
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) addQdisc(ifname string) error {
|
||||
func (c *controlPlaneCore) addQdisc(ifname string) error {
|
||||
link, err := netlink.LinkByName(ifname)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -98,7 +121,7 @@ func (c *ControlPlaneCore) addQdisc(ifname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) delQdisc(ifname string) error {
|
||||
func (c *controlPlaneCore) delQdisc(ifname string) error {
|
||||
link, err := netlink.LinkByName(ifname)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -119,9 +142,9 @@ func (c *ControlPlaneCore) delQdisc(ifname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) setupRoutingPolicy() (err error) {
|
||||
func (c *controlPlaneCore) setupRoutingPolicy() (err error) {
|
||||
/// Insert ip rule / ip route.
|
||||
const table = 2023
|
||||
var table = 2023 + c.flip
|
||||
|
||||
/** ip table
|
||||
ip route add local default dev lo table 2023
|
||||
@ -229,7 +252,7 @@ tryRuleAddAgain:
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) bindLan(ifname string) error {
|
||||
func (c *controlPlaneCore) bindLan(ifname string) error {
|
||||
c.log.Infof("Bind to LAN: %v", ifname)
|
||||
|
||||
link, err := netlink.LinkByName(ifname)
|
||||
@ -259,7 +282,7 @@ func (c *ControlPlaneCore) bindLan(ifname string) error {
|
||||
FilterAttrs: netlink.FilterAttrs{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Parent: netlink.HANDLE_MIN_INGRESS,
|
||||
Handle: netlink.MakeHandle(0x2023, 2),
|
||||
Handle: netlink.MakeHandle(0x2023, 0b100+uint16(c.flip)),
|
||||
Protocol: unix.ETH_P_ALL,
|
||||
// Priority should be behind of WAN's
|
||||
Priority: 2,
|
||||
@ -285,7 +308,7 @@ func (c *ControlPlaneCore) bindLan(ifname string) error {
|
||||
FilterAttrs: netlink.FilterAttrs{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Parent: netlink.HANDLE_MIN_EGRESS,
|
||||
Handle: netlink.MakeHandle(0x2023, 1),
|
||||
Handle: netlink.MakeHandle(0x2023, 0b010+uint16(c.flip)),
|
||||
Protocol: unix.ETH_P_ALL,
|
||||
// Priority should be front of WAN's
|
||||
Priority: 1,
|
||||
@ -308,7 +331,7 @@ func (c *ControlPlaneCore) bindLan(ifname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) setupSkPidMonitor() error {
|
||||
func (c *controlPlaneCore) setupSkPidMonitor() error {
|
||||
/// Set-up SrcPidMapper.
|
||||
/// Attach programs to support pname routing.
|
||||
// Get the first-mounted cgroupv2 path.
|
||||
@ -348,7 +371,7 @@ func (c *ControlPlaneCore) setupSkPidMonitor() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *ControlPlaneCore) bindWan(ifname string) error {
|
||||
func (c *controlPlaneCore) bindWan(ifname string) error {
|
||||
c.log.Infof("Bind to WAN: %v", ifname)
|
||||
link, err := netlink.LinkByName(ifname)
|
||||
if err != nil {
|
||||
@ -375,7 +398,7 @@ func (c *ControlPlaneCore) bindWan(ifname string) error {
|
||||
FilterAttrs: netlink.FilterAttrs{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Parent: netlink.HANDLE_MIN_EGRESS,
|
||||
Handle: netlink.MakeHandle(0x2023, 2),
|
||||
Handle: netlink.MakeHandle(0x2023, 0b100+uint16(c.flip)),
|
||||
Protocol: unix.ETH_P_ALL,
|
||||
Priority: 2,
|
||||
},
|
||||
@ -399,7 +422,7 @@ func (c *ControlPlaneCore) bindWan(ifname string) error {
|
||||
FilterAttrs: netlink.FilterAttrs{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Parent: netlink.HANDLE_MIN_INGRESS,
|
||||
Handle: netlink.MakeHandle(0x2023, 1),
|
||||
Handle: netlink.MakeHandle(0x2023, 0b010+uint16(c.flip)),
|
||||
Protocol: unix.ETH_P_ALL,
|
||||
Priority: 1,
|
||||
},
|
||||
@ -423,7 +446,7 @@ func (c *ControlPlaneCore) bindWan(ifname string) error {
|
||||
|
||||
// BatchUpdateDomainRouting update bpf map domain_routing. Since one IP may have multiple domains, this function should
|
||||
// be invoked every A/AAAA-record lookup.
|
||||
func (c *ControlPlaneCore) BatchUpdateDomainRouting(cache *DnsCache) error {
|
||||
func (c *controlPlaneCore) BatchUpdateDomainRouting(cache *DnsCache) error {
|
||||
// Parse ips from DNS resp answers.
|
||||
var ips []netip.Addr
|
||||
for _, ans := range cache.Answers {
|
||||
@ -459,3 +482,9 @@ func (c *ControlPlaneCore) BatchUpdateDomainRouting(cache *DnsCache) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EjectBpf will resect bpf from destroying life-cycle of control plane core.
|
||||
func (c *controlPlaneCore) EjectBpf() *bpfObjects {
|
||||
c.deferFuncs = c.deferFuncs[1:]
|
||||
return c.bpf
|
||||
}
|
||||
|
@ -89,7 +89,8 @@ static const __u32 disable_l4_tx_checksum_key
|
||||
static const __u32 disable_l4_rx_checksum_key
|
||||
__attribute__((unused, deprecated)) = 3;
|
||||
static const __u32 control_plane_pid_key = 4;
|
||||
static const __u32 control_plane_nat_direct_key = 5;
|
||||
static const __u32 control_plane_nat_direct_key
|
||||
__attribute__((unused, deprecated)) = 5;
|
||||
static const __u32 control_plane_dns_routing_key = 6;
|
||||
|
||||
// Outbound Connectivity Map:
|
||||
@ -1358,13 +1359,6 @@ new_connection:
|
||||
#endif
|
||||
if (routing_result.outbound == OUTBOUND_DIRECT ||
|
||||
routing_result.outbound == OUTBOUND_MUST_DIRECT) {
|
||||
__u32 *nat;
|
||||
if ((nat =
|
||||
bpf_map_lookup_elem(¶m_map, &control_plane_nat_direct_key)) &&
|
||||
*nat) {
|
||||
// Do not mark if packet is sent to control_plane.
|
||||
goto control_plane_tproxy;
|
||||
}
|
||||
skb->mark = routing_result.mark;
|
||||
goto direct;
|
||||
} else if (unlikely(routing_result.outbound == OUTBOUND_BLOCK)) {
|
||||
|
@ -45,7 +45,7 @@ func (c *ControlPlane) Route(src, dst netip.AddrPort, domain string, l4proto con
|
||||
return outboundIndex, mark, nil
|
||||
}
|
||||
|
||||
func (c *ControlPlaneCore) RetrieveRoutingResult(src, dst netip.AddrPort, l4proto uint8) (result *bpfRoutingResult, err error) {
|
||||
func (c *controlPlaneCore) RetrieveRoutingResult(src, dst netip.AddrPort, l4proto uint8) (result *bpfRoutingResult, err error) {
|
||||
srcIp6 := src.Addr().As16()
|
||||
dstIp6 := dst.Addr().As16()
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
global {
|
||||
# tproxy port to listen at. It is NOT a HTTP/SOCKS port, and is just used by eBPF program.
|
||||
# tproxy port to listen on. It is NOT a HTTP/SOCKS port, and is just used by eBPF program.
|
||||
# In normal case, you do not need to use it.
|
||||
tproxy_port: 12345
|
||||
|
||||
|
Reference in New Issue
Block a user