This commit is contained in:
mzz2017
2023-02-19 22:16:59 +08:00
parent f29353bcf0
commit 9efeada72d
8 changed files with 128 additions and 100 deletions

View File

@ -49,22 +49,18 @@ Use following command to show kernel configuration items on your machine.
zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)} zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)}
``` ```
**Bind to LAN** dae needs:
``` ```
CONFIG_DEBUG_INFO_BTF CONFIG_DEBUG_INFO_BTF=y
CONFIG_NET_CLS_ACT=y
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_INGRESS=y
CONFIG_NET_EGRESS=y
``` ```
**Bind to WAN**:
```
CONFIG_DEBUG_INFO_BTF
```
Check them using command like: Check them using command like:
```shell ```shell
(zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)}) | grep 'CONFIG_DEBUG_INFO_BTF=' (zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)}) | grep -E 'CONFIG_(DEBUG_INFO_BTF|NET_CLS_ACT|NET_SCH_INGRESS|NET_INGRESS|NET_EGRESS)='
``` ```
### Enable IP Forwarding ### Enable IP Forwarding

View File

@ -90,6 +90,9 @@ func (a *AliveDialerSet) GetMinLatency() (d *Dialer, latency time.Duration) {
} }
func (a *AliveDialerSet) printLatencies() { func (a *AliveDialerSet) printLatencies() {
if !a.log.IsLevelEnabled(logrus.TraceLevel) {
return
}
var builder strings.Builder var builder strings.Builder
builder.WriteString(fmt.Sprintf("%v (%v):\n", a.dialerGroupName, a.CheckTyp.String())) builder.WriteString(fmt.Sprintf("%v (%v):\n", a.dialerGroupName, a.CheckTyp.String()))
for _, d := range a.inorderedAliveDialerSet { for _, d := range a.inorderedAliveDialerSet {

View File

@ -523,33 +523,32 @@ func (c *ControlPlane) ListenAndServe(port uint16) (err error) {
} }
break break
} }
pktDst := RetrieveOriginalDest(oob[:oobn]) newBuf := pool.Get(n)
var newBuf []byte copy(newBuf, buf[:n])
var realDst netip.AddrPort go func(data []byte, src netip.AddrPort) {
outboundIndex, err := c.core.RetrieveOutboundIndex(src, pktDst, unix.IPPROTO_UDP) defer pool.Put(data)
if err != nil { var realDst netip.AddrPort
// WAN. Old method. var outboundIndex consts.OutboundIndex
addrHdr, dataOffset, err := ParseAddrHdr(buf[:n]) pktDst := RetrieveOriginalDest(oob[:oobn])
outboundIndex, err := c.core.RetrieveOutboundIndex(src, pktDst, unix.IPPROTO_UDP)
if err != nil { if err != nil {
c.log.Warnf("No AddrPort presented") // WAN. Old method.
continue addrHdr, dataOffset, err := ParseAddrHdr(data)
if err != nil {
c.log.Warnf("No AddrPort presented")
return
}
copy(data, data[dataOffset:])
outboundIndex = consts.OutboundIndex(addrHdr.Outbound)
src = netip.AddrPortFrom(addrHdr.Dest.Addr(), src.Port())
realDst = addrHdr.Dest
} else {
realDst = pktDst
} }
newBuf = pool.Get(n - dataOffset) if e := c.handlePkt(udpConn, data, src, pktDst, realDst, outboundIndex); e != nil {
copy(newBuf, buf[dataOffset:n])
outboundIndex = consts.OutboundIndex(addrHdr.Outbound)
src = netip.AddrPortFrom(addrHdr.Dest.Addr(), src.Port())
realDst = addrHdr.Dest
} else {
newBuf = pool.Get(n)
copy(newBuf, buf[:n])
realDst = pktDst
}
go func(data []byte, src, pktDst, realDst netip.AddrPort, outboundIndex consts.OutboundIndex) {
if e := c.handlePkt(udpConn, newBuf, src, pktDst, realDst, outboundIndex); e != nil {
c.log.Warnln("handlePkt:", e) c.log.Warnln("handlePkt:", e)
} }
pool.Put(newBuf) }(newBuf, src)
}(newBuf, src, pktDst, realDst, outboundIndex)
} }
}() }()
<-ctx.Done() <-ctx.Done()

View File

@ -85,6 +85,9 @@ func (c *ControlPlane) BatchUpdateDomainRouting(cache *dnsCache) error {
ips = append(ips, netip.AddrFrom16(ans.Body.(*dnsmessage.AAAAResource).AAAA)) ips = append(ips, netip.AddrFrom16(ans.Body.(*dnsmessage.AAAAResource).AAAA))
} }
} }
if len(ips) == 0 {
return nil
}
// Update bpf map. // Update bpf map.
// Construct keys and vals, and BpfMapBatchUpdate. // Construct keys and vals, and BpfMapBatchUpdate.
@ -316,13 +319,15 @@ loop:
} }
// Update dnsCache. // Update dnsCache.
c.log.WithFields(logrus.Fields{ if c.log.IsLevelEnabled(logrus.TraceLevel) {
"qname": q.Name, c.log.WithFields(logrus.Fields{
"rcode": msg.RCode, "qname": q.Name,
"ans": FormatDnsRsc(msg.Answers), "rcode": msg.RCode,
"auth": FormatDnsRsc(msg.Authorities), "ans": FormatDnsRsc(msg.Answers),
"addi": FormatDnsRsc(msg.Additionals), "auth": FormatDnsRsc(msg.Authorities),
}).Tracef("Update DNS record cache") "addi": FormatDnsRsc(msg.Additionals),
}).Tracef("Update DNS record cache")
}
if err = c.UpdateDnsCache(q.Name.String(), q.Type, msg.Answers, time.Now().Add(time.Duration(ttl)*time.Second+DnsNatTimeout)); err != nil { if err = c.UpdateDnsCache(q.Name.String(), q.Type, msg.Answers, time.Now().Add(time.Duration(ttl)*time.Second+DnsNatTimeout)); err != nil {
return nil, err return nil, err
} }

View File

@ -49,10 +49,11 @@
#define MAX_LPM_SIZE 20480 #define MAX_LPM_SIZE 20480
#define MAX_LPM_NUM (MAX_MATCH_SET_LEN + 8) #define MAX_LPM_NUM (MAX_MATCH_SET_LEN + 8)
#define MAX_DST_MAPPING_NUM (65536 * 2) #define MAX_DST_MAPPING_NUM (65536 * 2)
#define MAX_SRC_PID_PNAME_MAPPING_NUM (65536) #define MAX_COOKIE_PID_PNAME_MAPPING_NUM (65536)
#define IPV6_MAX_EXTENSIONS 4 #define MAX_DOMAIN_ROUTING_NUM 65536
#define MAX_ARG_LEN_TO_PROBE 192 #define MAX_ARG_LEN_TO_PROBE 192
#define MAX_ARG_SCANNER_BUFFER_SIZE (TASK_COMM_LEN * 4) #define MAX_ARG_SCANNER_BUFFER_SIZE (TASK_COMM_LEN * 4)
#define IPV6_MAX_EXTENSIONS 4
#define OUTBOUND_DIRECT 0 #define OUTBOUND_DIRECT 0
#define OUTBOUND_BLOCK 1 #define OUTBOUND_BLOCK 1
@ -327,7 +328,7 @@ struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(type, BPF_MAP_TYPE_LRU_HASH);
__type(key, __be32[4]); __type(key, __be32[4]);
__type(value, struct domain_routing); __type(value, struct domain_routing);
__uint(max_entries, 65535); __uint(max_entries, MAX_DOMAIN_ROUTING_NUM);
/// NOTICE: No persistence. /// NOTICE: No persistence.
// __uint(pinning, LIBBPF_PIN_BY_NAME); // __uint(pinning, LIBBPF_PIN_BY_NAME);
} domain_routing_map SEC(".maps"); } domain_routing_map SEC(".maps");
@ -347,7 +348,7 @@ struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(type, BPF_MAP_TYPE_LRU_HASH);
__type(key, __u64); __type(key, __u64);
__type(value, struct pid_pname); __type(value, struct pid_pname);
__uint(max_entries, MAX_SRC_PID_PNAME_MAPPING_NUM); __uint(max_entries, MAX_COOKIE_PID_PNAME_MAPPING_NUM);
/// NOTICE: No persistence. /// NOTICE: No persistence.
__uint(pinning, LIBBPF_PIN_BY_NAME); __uint(pinning, LIBBPF_PIN_BY_NAME);
} cookie_pid_map SEC(".maps"); } cookie_pid_map SEC(".maps");

View File

@ -66,10 +66,12 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
case consts.OutboundMustDirect: case consts.OutboundMustDirect:
fallthrough fallthrough
case consts.OutboundControlPlaneDirect: case consts.OutboundControlPlaneDirect:
c.log.Tracef("outbound: %v => %v", if c.log.IsLevelEnabled(logrus.TraceLevel) {
outboundIndex.String(), c.log.Tracef("outbound: %v => %v",
consts.OutboundDirect.String(), outboundIndex.String(),
) consts.OutboundDirect.String(),
)
}
outboundIndex = consts.OutboundDirect outboundIndex = consts.OutboundDirect
default: default:
} }
@ -87,13 +89,16 @@ func (c *ControlPlane) handleConn(lConn net.Conn) (err error) {
if err != nil { if err != nil {
return fmt.Errorf("failed to select dialer from group %v (%v): %w", outbound.Name, networkType.String(), err) return fmt.Errorf("failed to select dialer from group %v (%v): %w", outbound.Name, networkType.String(), err)
} }
c.log.WithFields(logrus.Fields{
"network": networkType.String(), if c.log.IsLevelEnabled(logrus.InfoLevel) {
"outbound": outbound.Name, c.log.WithFields(logrus.Fields{
"policy": outbound.GetSelectionPolicy(), "network": networkType.String(),
"dialer": d.Name(), "outbound": outbound.Name,
"domain": domain, "policy": outbound.GetSelectionPolicy(),
}).Infof("%v <-> %v", RefineSourceToShow(src, dst.Addr(), consts.LanWanFlag_NotApplicable), RefineAddrPortToShow(dst)) "dialer": d.Name(),
"domain": domain,
}).Infof("%v <-> %v", RefineSourceToShow(src, dst.Addr(), consts.LanWanFlag_NotApplicable), RefineAddrPortToShow(dst))
}
// Dial and relay. // Dial and relay.
dst = netip.AddrPortFrom(common.ConvergeIp(dst.Addr()), dst.Port()) dst = netip.AddrPortFrom(common.ConvergeIp(dst.Addr()), dst.Port())

View File

@ -35,7 +35,7 @@ var (
UnspecifiedAddr6 = netip.AddrFrom16([16]byte{}) UnspecifiedAddr6 = netip.AddrFrom16([16]byte{})
) )
func ChooseNatTimeout(data []byte) (dmsg *dnsmessage.Message, timeout time.Duration) { func ChooseNatTimeout(data []byte, sniffDns bool) (dmsg *dnsmessage.Message, timeout time.Duration) {
var dnsmsg dnsmessage.Message var dnsmsg dnsmessage.Message
if err := dnsmsg.Unpack(data); err == nil { if err := dnsmsg.Unpack(data); err == nil {
//log.Printf("DEBUG: lookup %v", dnsmsg.Questions[0].Name) //log.Printf("DEBUG: lookup %v", dnsmsg.Questions[0].Name)
@ -125,7 +125,9 @@ func (c *ControlPlane) WriteToUDP(lanWanFlag consts.LanWanFlag, lConn *net.UDPCo
}).Tracef("DNS rush-answer rejected") }).Tracef("DNS rush-answer rejected")
return err return err
} }
c.log.Debugf("DnsRespHandler: %v", err) if c.log.IsLevelEnabled(logrus.DebugLevel) {
c.log.Debugf("DnsRespHandler: %v", err)
}
if data == nil { if data == nil {
return nil return nil
} }
@ -159,10 +161,12 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
mustDirect = true mustDirect = true
fallthrough fallthrough
case consts.OutboundControlPlaneDirect: case consts.OutboundControlPlaneDirect:
c.log.Tracef("outbound: %v => %v", if c.log.IsLevelEnabled(logrus.TraceLevel) {
outboundIndex.String(), c.log.Tracef("outbound: %v => %v",
consts.OutboundDirect.String(), outboundIndex.String(),
) consts.OutboundDirect.String(),
)
}
outboundIndex = consts.OutboundDirect outboundIndex = consts.OutboundDirect
default: default:
} }
@ -170,7 +174,8 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
return fmt.Errorf("outbound %v out of range [0, %v]", outboundIndex, len(c.outbounds)-1) return fmt.Errorf("outbound %v out of range [0, %v]", outboundIndex, len(c.outbounds)-1)
} }
outbound := c.outbounds[outboundIndex] outbound := c.outbounds[outboundIndex]
dnsMessage, natTimeout := ChooseNatTimeout(data) // To keep consistency with kernel program, we only sniff DNS request sent to 53.
dnsMessage, natTimeout := ChooseNatTimeout(data, realDst.Port() == 53)
// We should cache DNS records and set record TTL to 0, in order to monitor the dns req and resp in real time. // We should cache DNS records and set record TTL to 0, in order to monitor the dns req and resp in real time.
isDns := dnsMessage != nil isDns := dnsMessage != nil
var dummyFrom *netip.AddrPort var dummyFrom *netip.AddrPort
@ -234,11 +239,13 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
bestLatency time.Duration bestLatency time.Duration
bestTarget netip.AddrPort bestTarget netip.AddrPort
) )
c.log.WithFields(logrus.Fields{ if c.log.IsLevelEnabled(logrus.TraceLevel) {
"ipversions": ipversions, c.log.WithFields(logrus.Fields{
"l4protos": l4protos, "ipversions": ipversions,
"src": realSrc.String(), "l4protos": l4protos,
}).Traceln("Choose DNS path") "src": realSrc.String(),
}).Traceln("Choose DNS path")
}
// Get the min latency path. // Get the min latency path.
networkType := dialer.NetworkType{ networkType := dialer.NetworkType{
IsDns: isDns, IsDns: isDns,
@ -251,12 +258,14 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
if err != nil { if err != nil {
continue continue
} }
c.log.WithFields(logrus.Fields{ if c.log.IsLevelEnabled(logrus.TraceLevel) {
"name": d.Name(), c.log.WithFields(logrus.Fields{
"latency": latency, "name": d.Name(),
"network": networkType.String(), "latency": latency,
"outbound": outbound.Name, "network": networkType.String(),
}).Traceln("Choice") "outbound": outbound.Name,
}).Traceln("Choice")
}
if bestDialer == nil || latency < bestLatency { if bestDialer == nil || latency < bestLatency {
bestDialer = d bestDialer = d
bestLatency = latency bestLatency = latency
@ -274,11 +283,13 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
dialerForNew = bestDialer dialerForNew = bestDialer
dummyFrom = &realDst dummyFrom = &realDst
destToSend = bestTarget destToSend = bestTarget
c.log.WithFields(logrus.Fields{ if c.log.IsLevelEnabled(logrus.TraceLevel) {
"Original": RefineAddrPortToShow(realDst), c.log.WithFields(logrus.Fields{
"New": destToSend, "Original": RefineAddrPortToShow(realDst),
"Network": string(l4proto) + string(ipversion), "New": destToSend,
}).Traceln("Modify DNS target") "Network": string(l4proto) + string(ipversion),
}).Traceln("Modify DNS target")
}
} }
networkType := &dialer.NetworkType{ networkType := &dialer.NetworkType{
L4Proto: l4proto, L4Proto: l4proto,
@ -329,12 +340,15 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
// If the udp endpoint has been not alive, remove it from pool and get a new one. // If the udp endpoint has been not alive, remove it from pool and get a new one.
if !isNew && outbound.GetSelectionPolicy() != consts.DialerSelectionPolicy_Fixed && !ue.Dialer.MustGetAlive(networkType) { if !isNew && outbound.GetSelectionPolicy() != consts.DialerSelectionPolicy_Fixed && !ue.Dialer.MustGetAlive(networkType) {
c.log.WithFields(logrus.Fields{
"src": RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag), if c.log.IsLevelEnabled(logrus.DebugLevel) {
"network": networkType.String(), c.log.WithFields(logrus.Fields{
"dialer": ue.Dialer.Name(), "src": RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag),
"retry": retry, "network": networkType.String(),
}).Debugln("Old udp endpoint was not alive and removed.") "dialer": ue.Dialer.Name(),
"retry": retry,
}).Debugln("Old udp endpoint was not alive and removed.")
}
_ = DefaultUdpEndpointPool.Remove(realSrc, ue) _ = DefaultUdpEndpointPool.Remove(realSrc, ue)
retry++ retry++
goto getNew goto getNew
@ -344,14 +358,16 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
_, err = ue.WriteTo(data, tgtToSend) _, err = ue.WriteTo(data, tgtToSend)
if err != nil { if err != nil {
c.log.WithFields(logrus.Fields{ if c.log.IsLevelEnabled(logrus.DebugLevel) {
"to": destToSend.String(), c.log.WithFields(logrus.Fields{
"domain": domain, "to": destToSend.String(),
"from": realSrc.String(), "domain": domain,
"network": networkType.String(), "from": realSrc.String(),
"err": err.Error(), "network": networkType.String(),
"retry": retry, "err": err.Error(),
}).Debugln("Failed to write UDP packet request. Try to remove old UDP endpoint and retry.") "retry": retry,
}).Debugln("Failed to write UDP packet request. Try to remove old UDP endpoint and retry.")
}
_ = DefaultUdpEndpointPool.Remove(realSrc, ue) _ = DefaultUdpEndpointPool.Remove(realSrc, ue)
retry++ retry++
goto getNew goto getNew
@ -420,8 +436,7 @@ func (c *ControlPlane) handlePkt(lConn *net.UDPConn, data []byte, src, pktDst, r
}).Infof("%v <-> %v", }).Infof("%v <-> %v",
RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag), RefineAddrPortToShow(destToSend), RefineSourceToShow(realSrc, realDst.Addr(), lanWanFlag), RefineAddrPortToShow(destToSend),
) )
} else { } else if c.log.IsLevelEnabled(logrus.InfoLevel) {
// TODO: Set-up ip to domain mapping and show domain if possible.
c.log.WithFields(logrus.Fields{ c.log.WithFields(logrus.Fields{
"network": string(l4proto) + string(ipversion), "network": string(l4proto) + string(ipversion),
"outbound": outbound.Name, "outbound": outbound.Name,

View File

@ -22,7 +22,7 @@ type UdpEndpoint struct {
conn netproxy.PacketConn conn netproxy.PacketConn
// mu protects deadlineTimer // mu protects deadlineTimer
mu sync.Mutex mu sync.Mutex
deadlineTimer *time.Timer deadlineTimer *time.Timer // nil means UdpEndpoint was closed
handler UdpHandler handler UdpHandler
NatTimeout time.Duration NatTimeout time.Duration
@ -48,7 +48,7 @@ func (ue *UdpEndpoint) start() {
} }
} }
ue.mu.Lock() ue.mu.Lock()
ue.deadlineTimer.Stop() ue.Close()
ue.mu.Unlock() ue.mu.Unlock()
} }
@ -56,13 +56,15 @@ func (ue *UdpEndpoint) WriteTo(b []byte, addr string) (int, error) {
return ue.conn.WriteTo(b, addr) return ue.conn.WriteTo(b, addr)
} }
func (ue *UdpEndpoint) Close() error { func (ue *UdpEndpoint) Close() (err error) {
ue.mu.Lock() ue.mu.Lock()
if ue.deadlineTimer != nil { if ue.deadlineTimer != nil {
err = ue.conn.Close()
ue.deadlineTimer.Stop() ue.deadlineTimer.Stop()
ue.deadlineTimer = nil
} }
ue.mu.Unlock() ue.mu.Unlock()
return ue.conn.Close() return err
} }
// UdpEndpointPool is a full-cone udp conn pool // UdpEndpointPool is a full-cone udp conn pool
@ -149,7 +151,9 @@ func (p *UdpEndpointPool) GetOrCreate(lAddr netip.AddrPort, createOption *UdpEnd
} else { } else {
// Postpone the deadline. // Postpone the deadline.
ue.mu.Lock() ue.mu.Lock()
ue.deadlineTimer.Reset(ue.NatTimeout) if ue.deadlineTimer != nil {
ue.deadlineTimer.Reset(ue.NatTimeout)
}
ue.mu.Unlock() ue.mu.Unlock()
} }
return ue, isNew, nil return ue, isNew, nil