Arch linux dae Transparent Proxy

Recently, while researching, I discovered a transparent proxy called dae, also known as "Big Goose" (or "Eating Goose" in Chinese). Compared to sing-box, v2ray, etc., it's based on Linux eBPF.

eBPF (extended Berkeley Packet Filter) is a powerful kernel technology, originally derived from BPF (Berkeley Packet Filter) in BSD systems, used for efficiently filtering network packets. In Linux, eBPF has evolved into a general-purpose, secure, and high-performance kernel-programmable mechanism, allowing users to run sandboxed programs within the kernel without modifying the kernel source code or loading kernel modules (such as LKM). It has applications in observability, networking, security, and performance optimization, and I've even seen it mentioned in some job postings. I never expected it would be associated with transparent proxies, which theoretically offer better performance than pure user-space proxies.

This technology is ideally suited for deployment on routers or Raspberry Pi devices for use by other devices, but dae (daemon-based application development) has kernel version requirements, and ARM devices require additional kernel compilation. My sing-box has been running stably on my Raspberry Pi for years, and I'm too lazy to bother with it.

Therefore, the installation can only be experienced on an Arch Linux host. The process is as follows:

1. Installation

1paru -S daed

Check package information, dependencies are as follows:

1➜ ~ paru -Qi dae | grep Depends
2Depends On : glibc v2ray-geoip v2ray-domain-list-community

v2ray probably provides geoip and other traffic distribution data (as can be seen in the symbolic links below)

1➜ ~ ls -al /usr/share/dae/geoip.dat
2lrwxrwxrwx 1 root root 26 Dec 28 14:36 ​​/usr/share/dae/geoip.dat -> /usr/share/v2ray/geoip.dat

2. Configuration

From my personal experience, the configuration logic of this is much clearer and simpler compared to sing-box. Sing-box's configuration is prone to incompatibility issues, and it stops working after an update.

The official dae configuration is stable and provides some examples. It requires very little configuration to set up traffic splitting rules, which is commendable 👍

My configuration is as follows (hysteria2 parts have been anonymized):

 1➜  ~ sudo cat /etc/dae/config.dae
 2global {
 3    # lan_interface: auto
 4    wan_interface: auto
 5    log_level: info
 6    auto_config_kernel_parameter: true
 7    allow_insecure: true
 8    bandwidth_max_tx: '20 m' # uplink, or '200 m' or '200 mb' or '200 mbps' or 25000000(which is 200/8*1000*1000)
 9    bandwidth_max_rx: '100 m'
10}
11
12node {
13    hy2: "hysteria2://password@host:port/?sni=your_name"
14}
15
16dns {
17    upstream {
18        alidns: "udp://dns.alidns.com:53"
19        googledns: "tcp+udp://dns.google:53"
20    }
21    routing {
22        request {
23            fallback: alidns
24        }
25        response {
26      	    upstream(googledns) -> accept
27            ip(geoip:private) && !qname(geosite:cn) -> googledns
28            fallback: accept
29        }
30    }
31}
32
33group {
34    proxy_group {
35        filter: name(hy2)
36        policy: random
37    }
38}
39
40routing {
41
42    pname(NetworkManager) -> direct
43    pname("dnsmasq") -> direct
44
45    #game
46    pname("Counter-Strike") -> direct
47
48    dip("127.0.0.0/8") -> direct
49
50    dip("::1/128") -> direct
51
52    dip(224.0.0.0/3, 'ff00::/8') -> direct
53
54    dip(geoip:private) -> direct
55
56    dip(geoip:cn) -> direct
57    domain(geosite:cn) -> direct
58
59    fallback: proxy_group
60}

The general meaning is:

  • global sets some global configurations
  • node configures the actual backend proxy, such as hysteria2 in this example. Each proxy can have a custom name (e.g., hy2 in this example).
  • group groups and categorizes proxies for easier traffic distribution.
  • dns is DNS-related configuration. The example above means that if a private IP and a non-Chinese domain name are returned, Google DNS will be used to query the domain again, defaulting to Alidns.
  • routing is the most crucial part, containing traffic distribution rules. pname matches the process name, dip matches the IP address, domain matches the domain name, direct means direct connection without going through the backend proxy, and fallabck means the request goes through the proxy if none of the rules are matched. This should make the traffic splitting rules easy to understand. You can write your own rules based on your understanding.

How to check for configuration errors? dae has a built-in verification command, as shown below:

1sudo dae validate -c /etc/dae/config.dae

If no errors are reported, the configuration is compliant.

How to know if a request went through the proxy? I personally determine this through logs.

Set the log level log_level: info to above info. Filter the logs using the command line.

1➜ ~ sudo journalctl -u dae -f |grep hy2
2Jan 03 19:04:58 minipc dae[199596]: level=info msg="192.168.124.5:39926 <-> api.zed.dev:443" dialer=hy2 dscp=0 ip="104.20.29.242:443" mac="e4:c7:67:3f:6a:06" network=tcp4 outbound="proxy_group" pid=0 pname=zed-editor policy=random sniffed=api.zed.dev
3Jan 03 19:06:07 minipc dae[199596]: level=info msg="192.168.124.5:52356 <-> alive.github.com:443" dialer=hy2 dscp=0 ip="140.82.112.26:443" mac="e4:c7:67:3f:6a:06" network=tcp4 outbound="proxy_group" pid=0 pname=firefox policy=random sniffed=alive.github.com

For example, the log output above shows that api.zed.dev and alive.github.com are using the proxy hy2 via dialer=hy2. If dialer=direct, it indicates a direct connection.

3. Startup and Information Viewing

Setting up startup

1sudo systemctl enable dae.service

Startup

1sudo systemctl start dae.service

If startup is successful without errors, you'll see an additional virtual network adapter dae0@if15. I've masked its identity; I manually deleted the other network adapter information.

 1➜  ~ ip a
 21: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
 3    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 4    inet 127.0.0.1/8 scope host lo
 5       valid_lft forever preferred_lft forever
 6    inet6 ::1/128 scope host noprefixroute
 7       valid_lft forever preferred_lft forever
 8
 916: dae0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
10    link/ether be:62:be:53:a7:f6 brd ff:ff:ff:ff:ff:ff link-netns daens
11    inet6 fe80::ecee:eeff:feee:eeee/128 scope link
12       valid_lft forever preferred_lft forever
13    inet6 fe80::b02d:10ff:fea8:77b2/64 scope link proto kernel_ll
14       valid_lft forever preferred_lft forever

View processes

1➜ ~ ps -ef |grep config.dae
2root 199596 1 0 18:19 ? 00:00:06 /usr/bin/dae run --disable-timestamp -c /etc/dae/config.dae

You can also use the lsof command to see which files are open, making it easier to infer what dependencies exist. An example is not provided here.

You can also use the bpftool command to view more detailed information.

 1➜ ~ sudo bpftool prog show | grep -A3 -B3 dae
 2loaded_at 2026-01-03T18:19:08+0800 uid 0
 3xlated 976B jited 527B memlock 4096B map_ids 22,105
 4btf_id 330
 5pidsdae(199596)
 6192: sk_msg name sk_msg_fast_redirect tag 61fe221e8612c076 gpl
 7loaded_at 2026-01-03T18:19:08+0800 uid 0
 8xlated 528B jited 328B memlock 4096B map_ids 105
 9btf_id 331
10pidsdae(199596)
11193: sched_cls name tproxy_dae0_ingress tag 8e50bed694efcc1a gpl
12loaded_at 2026-01-03T18:19:08+0800 uid 0
13xlated 600B jited 344B memlock 4096B map_ids 106
14btf_id 333
15pids dae(199596)
16......

In actual experience, starting dae is slower than starting sing-box.

4. Test Results

Using the curl command to test accessing Google and Baidu, both accesses were normal.

1➜ ~ curl google.com
2<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
3<TITLE>301 Moved</TITLE></HEAD><BODY>
4<H1>301 Moved</H1>
5The document has moved
6<A HREF="http://www.google.com/">here</A>.
7</BODY></HTML>
8➜ ~ curl baidu.com
9<a href="http://www.baidu.com/">Moved Permanently</a>.

Check the logs to see if the traffic splitting is correct.

1➜ ~ sudo journalctl -u dae -f
2Jan 03 19:27:15 minipc dae[199596]: level=info msg="192.168.124.5:44187 <-> 223.5.5.5:53" _qname=google.com. dialer=direct dscp=0 mac="e4:c7:67:3f:6a:06" network="udp4(DNS)" outbound=direct pid=849 pname=dnsmasq policy=fixed qtype=AAAA
3Jan 03 19:27:15 minipc dae[199596]: level=info msg="192.168.124.5:52111 <-> 223.5.5.5:53" _qname=google.com. dialer=direct dscp=0 mac="e4:c7:67:3f:6a:06" network="udp4(DNS)" outbound=direct pid=849 pname=dnsmasq policy=fixed qtype=A
4Jan 03 19:27:15 minipc dae[199596]: level=info msg="192.168.124.5:54620 <-> google.com:80" dialer=hy2 dscp=0 ip="142.251.33.78:80" mac="e4:c7:67:3f:6a:06" network=tcp4 outbound="proxy_group" pid=0 pname=curl policy=random sniffed=google.com
5Jan 03 19:28:14 minipc dae[199596]: level=info msg="192.168.124.5:59191 <-> 223.5.5.5:53" _qname=baidu.com. dialer=direct dscp=0 mac="e4:c7:67:3f:6a:06" network="udp4(DNS)" outbound=direct pid=849 pname=dnsmasq policy=fixed qtype=AAAA
6Jan 03 19:28:14 minipc dae[199596]: level=info msg="192.168.124.5:36765 <-> 223.5.5.5:53" _qname=baidu.com. dialer=direct dscp=0 mac="e4:c7:67:3f:6a:06" `network="udp4(DNS)" outbound=direct pid=849 pname=dnsmasq policy=fixed qtype=A`

It can be seen that the DNS lookup is always with alidns, indicating one connection is through a proxy and the other is a direct connection.

This globally transparent proxy is much more convenient than setting up proxy.pac in my previous Firefox browser. Many software programs don't support it, or you might not want to configure a proxy. For example, setting up Paru is quite complicated, and downloading external software packages can be very slow; for games like Steam, you definitely don't want the default route to a foreign country. If you're not playing games and only checking the Steam game store, enabling a proxy has a significant advantage, resulting in very fast access speeds—you know why.

As for speed, I feel it's slightly faster than Sing-box, but that could be a misperception. Sing-box also meets my needs, and having another option is good.

If one day you don't need to perform these traffic splitting actions, the scene would be unimaginable. We must face reality; the current situation is that we must learn proxy technology.

In addition, there is a web interface version of dae, which is convenient for people to configure on the web. After a brief look, I was not interested. Readers can try it out themselves.

Lastmod: Friday, January 16, 2026

See Also:

Translations: