fix: should update system DNS every 5 seconds

This commit is contained in:
mzz2017 2023-04-02 17:43:50 +08:00
parent 648710a40e
commit 85343ac141
9 changed files with 61 additions and 41 deletions

View File

@ -1,6 +1,7 @@
package cmd
import (
"errors"
"fmt"
"github.com/daeuniverse/dae/cmd/internal"
"github.com/daeuniverse/dae/common"
@ -14,6 +15,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"math/rand"
"net"
"net/http"
"os"
"os/signal"
@ -238,11 +240,21 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
// Resolve subscriptions to nodes.
resolvingfailed := false
if !conf.Global.DisableWaitingNetwork && len(conf.Subscription) > 0 {
epo := 5 * time.Second
client := http.Client{
Timeout: epo,
}
log.Infoln("Waiting for network...")
for i := 0; ; i++ {
resp, err := http.Get(CheckNetworkLinks[i%len(CheckNetworkLinks)])
resp, err := client.Get(CheckNetworkLinks[i%len(CheckNetworkLinks)])
if err != nil {
time.Sleep(5 * time.Second)
log.Debugln("CheckNetwork:", err)
var neterr net.Error
if errors.As(err, &neterr) && neterr.Timeout() {
// Do not sleep.
continue
}
time.Sleep(epo)
continue
}
resp.Body.Close()
@ -250,7 +262,7 @@ func newControlPlane(log *logrus.Logger, bpf interface{}, dnsCache map[string]*c
break
}
log.Infof("Bad status: %v (%v)", resp.Status, resp.StatusCode)
time.Sleep(5 * time.Second)
time.Sleep(epo)
}
log.Infoln("Network online.")
}

View File

@ -139,6 +139,7 @@ var (
CgSocketCookieFeatureVersion = internal.Version{5, 7, 0}
SkAssignFeatureVersion = internal.Version{5, 7, 0}
ChecksumFeatureVersion = internal.Version{5, 8, 0}
ProgTypeSkLookupFeatureVersion = internal.Version{5, 9, 0}
UserspaceBatchUpdateLpmTrieFeatureVersion = internal.Version{5, 13, 0}
)

View File

@ -37,10 +37,13 @@ func TryUpdateSystemDns() (err error) {
return err
}
// TryUpdateSystemDns1s will update system DNS if 1 second has elapsed since the last TryUpdateSystemDns1s call.
func TryUpdateSystemDns1s() (err error) {
// TryUpdateSystemDnsElapse will update system DNS if duration has elapsed since the last TryUpdateSystemDns1s call.
func TryUpdateSystemDnsElapse(k time.Duration) (err error) {
systemDnsMu.Lock()
defer systemDnsMu.Unlock()
return tryUpdateSystemDnsElapse(k)
}
func tryUpdateSystemDnsElapse(k time.Duration) (err error) {
if time.Now().Before(systemDnsNextUpdateAfter) {
return fmt.Errorf("update too quickly")
}
@ -48,7 +51,7 @@ func TryUpdateSystemDns1s() (err error) {
if err != nil {
return err
}
systemDnsNextUpdateAfter = time.Now().Add(time.Second)
systemDnsNextUpdateAfter = time.Now().Add(k)
return nil
}
@ -70,6 +73,8 @@ func SystemDns() (dns netip.AddrPort, err error) {
return netip.AddrPort{}, err
}
}
// To avoid environment changing.
_ = tryUpdateSystemDnsElapse(5 * time.Second)
return systemDns, nil
}

View File

@ -83,7 +83,7 @@ func NewUpstream(ctx context.Context, upstream *url.URL) (up *Upstream, err erro
}
defer func() {
if err != nil {
_ = netutils.TryUpdateSystemDns1s()
_ = netutils.TryUpdateSystemDnsElapse(time.Second)
}
}()

View File

@ -110,7 +110,7 @@ func ParseTcpCheckOption(ctx context.Context, rawURL string) (opt *TcpCheckOptio
}
defer func() {
if err != nil {
_ = netutils.TryUpdateSystemDns1s()
_ = netutils.TryUpdateSystemDnsElapse(time.Second)
}
}()
@ -141,7 +141,7 @@ func ParseCheckDnsOption(ctx context.Context, dnsHostPort string) (opt *CheckDns
}
defer func() {
if err != nil {
_ = netutils.TryUpdateSystemDns1s()
_ = netutils.TryUpdateSystemDnsElapse(time.Second)
}
}()

View File

@ -62,6 +62,9 @@ type ControlPlane struct {
muRealDomainSet sync.Mutex
realDomainSet *bloom.BloomFilter
wanInterface []string
lanInterface []string
}
func NewControlPlane(
@ -83,20 +86,20 @@ func NewControlPlane(
}
/// Check linux kernel requirements.
// Check version from high to low to reduce the number of user upgrading kernel.
if kernelVersion.Less(consts.ChecksumFeatureVersion) {
if requirement := consts.ChecksumFeatureVersion; kernelVersion.Less(requirement) {
return nil, fmt.Errorf("your kernel version %v does not support checksum related features; expect >=%v; upgrade your kernel and try again",
kernelVersion.String(),
consts.ChecksumFeatureVersion.String())
requirement.String())
}
if len(global.WanInterface) > 0 && kernelVersion.Less(consts.CgSocketCookieFeatureVersion) {
if requirement := consts.CgSocketCookieFeatureVersion; len(global.WanInterface) > 0 && kernelVersion.Less(requirement) {
return nil, fmt.Errorf("your kernel version %v does not support bind to WAN; expect >=%v; remove wan_interface in config file and try again",
kernelVersion.String(),
consts.CgSocketCookieFeatureVersion.String())
requirement.String())
}
if len(global.LanInterface) > 0 && kernelVersion.Less(consts.SkAssignFeatureVersion) {
if requirement := consts.SkAssignFeatureVersion; len(global.LanInterface) > 0 && kernelVersion.Less(requirement) {
return nil, fmt.Errorf("your kernel version %v does not support bind to LAN; expect >=%v; remove lan_interface in config file and try again",
kernelVersion.String(),
consts.SkAssignFeatureVersion.String())
requirement.String())
}
if kernelVersion.Less(consts.BasicFeatureVersion) {
return nil, fmt.Errorf("your kernel version %v does not satisfy basic requirement; expect >=%v",
@ -339,6 +342,8 @@ func NewControlPlane(
ready: make(chan struct{}),
muRealDomainSet: sync.Mutex{},
realDomainSet: bloom.NewWithEstimates(2048, 0.001),
lanInterface: global.LanInterface,
wanInterface: global.WanInterface,
}
defer func() {
if err != nil {
@ -790,20 +795,21 @@ func (c *ControlPlane) chooseBestDnsDialer(
if bestDialer == nil {
return nil, fmt.Errorf("no proper dialer for DNS upstream: %v", dnsUpstream.String())
}
switch ipversion {
case consts.IpVersionStr_4:
bestTarget = netip.AddrPortFrom(dnsUpstream.Ip4, dnsUpstream.Port)
case consts.IpVersionStr_6:
bestTarget = netip.AddrPortFrom(dnsUpstream.Ip6, dnsUpstream.Port)
}
if c.log.IsLevelEnabled(logrus.TraceLevel) {
c.log.WithFields(logrus.Fields{
"ipversions": ipversions,
"l4protos": l4protos,
"upstream": dnsUpstream.String(),
"choose": string(l4proto) + "+" + string(ipversion),
"use": bestTarget.String(),
}).Traceln("Choose DNS path")
}
switch ipversion {
case consts.IpVersionStr_4:
bestTarget = netip.AddrPortFrom(dnsUpstream.Ip4, dnsUpstream.Port)
case consts.IpVersionStr_6:
bestTarget = netip.AddrPortFrom(dnsUpstream.Ip6, dnsUpstream.Port)
}
return &dialArgument{
l4proto: l4proto,
ipversion: ipversion,

View File

@ -409,7 +409,7 @@ func (c *controlPlaneCore) setupSkPidMonitor() error {
Program: prog.Prog,
})
if err != nil {
return fmt.Errorf("AttachTracing: %v: %w", prog.Prog.String(), err)
return fmt.Errorf("AttachCgroup: %v: %w", prog.Prog.String(), err)
}
c.deferFuncs = append(c.deferFuncs, func() error {
if err := attached.Close(); err != nil {

View File

@ -20,11 +20,6 @@
// #define __PRINT_SETUP_PROCESS_CONNNECTION
// #define __REMOVE_BPF_PRINTK
#ifdef __REMOVE_BPF_PRINTK
#undef bpf_printk
#define bpf_printk(...) (void)0
#endif
// #define likely(x) x
// #define unlikely(x) x
#define likely(x) __builtin_expect((x), 1)
@ -41,7 +36,6 @@
#define NOWHERE_IFINDEX 0
#define LOOPBACK_IFINDEX 1
#define LOOPBACK_ADDR 0x7f000001
#define MAX_PARAM_LEN 16
#define MAX_INTERFACE_NUM 128
@ -1398,16 +1392,16 @@ new_connection:
// TCP.
sk = bpf_map_lookup_elem(&listen_socket_map, &zero_key);
if (!sk || sk->state != BPF_TCP_LISTEN) {
bpf_printk("shot tcp tproxy not listen: %d", ret);
goto sk_shot;
bpf_printk("accpet tcp tproxy not listen");
goto sk_accept;
}
} else {
// UDP.
sk = bpf_map_lookup_elem(&listen_socket_map, &one_key);
if (!sk) {
bpf_printk("shot udp tproxy not listen: %d", ret);
goto sk_shot;
bpf_printk("accpet udp tproxy not listen");
goto sk_accept;
}
}
@ -1427,11 +1421,10 @@ assign:
}
return TC_ACT_OK;
sk_shot:
sk_accept:
if (sk) {
bpf_sk_release(sk);
}
return TC_ACT_SHOT;
direct:
return TC_ACT_OK;
@ -2118,8 +2111,8 @@ static int __always_inline _update_map_elem_by_cookie(const __u64 cookie) {
// bpf_printk("b start_end: %lu %lu", arg_start + last_slash, arg_start + j);
// Update map.
if (unlikely(ret = bpf_map_update_elem(&cookie_pid_map, &cookie, &val,
BPF_NOEXIST))) {
if (unlikely(
ret = bpf_map_update_elem(&cookie_pid_map, &cookie, &val, BPF_ANY))) {
// bpf_printk("setup_mapping_from_sk: failed update map: %d", ret);
return ret;
}
@ -2133,6 +2126,7 @@ static int __always_inline _update_map_elem_by_cookie(const __u64 cookie) {
static int __always_inline update_map_elem_by_cookie(const __u64 cookie) {
int ret;
if ((ret = _update_map_elem_by_cookie(cookie))) {
// Fallback to only write pid to avoid loop due to packets sent by dae.
struct pid_pname val = {0};
@ -2146,7 +2140,7 @@ static int __always_inline update_map_elem_by_cookie(const __u64 cookie) {
} else {
bpf_printk("failed [retrieve pname]: %u", val.pid);
}
bpf_map_update_elem(&cookie_pid_map, &cookie, &val, BPF_NOEXIST);
bpf_map_update_elem(&cookie_pid_map, &cookie, &val, BPF_ANY);
return ret;
}
return 0;

View File

@ -7,7 +7,7 @@ If you use a external DNS like AdguardHome, you could refer to the following gui
## External DNS on localhost
If you set up a external DNS on localhost, you may want to let the DNS queries to dns.google.com proxied. For example, if you have following configuration in AdguardHome:
If you set up an external DNS on localhost, you may want to let the DNS queries to dns.google.com proxied. For example, if you have the following configuration in AdguardHome:
```
Listen on: the same machine with dae, port 53.
@ -43,11 +43,13 @@ You should configure dae as follows:
}
```
4. If you bind to LAN, make sure your DHCP server will distribute dae as the DNS server (DNS request should be forwarded by dae for domain based traffic split).
4. If you bind to WAN, make sure your `/etc/resolv.conf` does NOT use your local external DNS directly. For example, you can set it as `nameserver 119.29.29.29`, and then DNS traffic will be hijacked by dae when the packets are sent through NIC. Most of the time, `/etc/resolv.conf` will be modified back by your DNS service like dnsmasq after rebooting, which is hard to deal with. We recommended you to uninstall them or give `sudo chattr +i /etc/resolv.conf` if you encounter such situation.
5. If there is still a DNS issue and there are no warn/error logs, you have to change your listening port of external DNS (here is AdGuardHome) from 53 to non-53 port. See [#31](https://github.com/daeuniverse/dae/issues/31#issuecomment-1467358364).
5. If you bind to LAN, make sure your DHCP server will distribute dae as the DNS server (DNS request should be forwarded by dae for domain based traffic split).
6. If you use PVE, refer to [#37](https://github.com/daeuniverse/dae/discussions/37).
6. If there is still a DNS issue and there are no warn/error logs, you have to change your listening port of external DNS (here is AdGuardHome) from 53 to non-53 port. See [#31](https://github.com/daeuniverse/dae/issues/31#issuecomment-1467358364).
7. If you use PVE, refer to [#37](https://github.com/daeuniverse/dae/discussions/37).
## External DNS on another machine in LAN