Skip to content

Commit

Permalink
Enable eBPF support. (#3893)
Browse files Browse the repository at this point in the history
* Prerequisits for eBPF settings

* Add basic eBPF function support. But firewall rule
should be investigated in order to reduce system load.

* Disable firewall when using eBPF function.

* Fix firewall settings.

* chore: add translates

* chore: fix error

* Update openclash

---------

Co-authored-by: sangyishuje1123 <152784766+sangyishuje1123@users.noreply.github.com>
Co-authored-by: vernesong <42875168+vernesong@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 16, 2024
1 parent 0212f55 commit 2c6edf7
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ bold_off = [[</strong>]]
local op_mode = string.sub(luci.sys.exec('uci get openclash.config.operation_mode 2>/dev/null'),0,-2)
if not op_mode then op_mode = "redir-host" end
local lan_int_name = uci:get("openclash", "config", "lan_interface_name") or "0"




local lan_ip
if lan_int_name == "0" then
lan_ip = SYS.exec("uci -q get network.lan.ipaddr |awk -F '/' '{print $1}' 2>/dev/null |tr -d '\n'")
Expand Down
12 changes: 12 additions & 0 deletions luci-app-openclash/luasrc/model/cbi/openclash/settings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ o:value("direct", translate("Direct Proxy Mode"))
o:value("script", translate("Script Proxy Mode (Tun Core Only)"))
o.default = "rule"

-- eBPF support setting
o = s:taboption("op_mode", ListValue, "ebpf_action_interface", translate("eBPF Action Interface"))
o.description = translate("Select outbound interface for eBPF to apply traffic management").."<br>"..font_red..bold_on.."1."..translate("Warning! Highly experimental configs. Will disable default firewall traffic inbound").."<br>2."..translate("Needs kernel support for eBPF functionality. And it takes about 130MB memory to starts").."<br>3."..translate("Might improve direct connection performance").."<br>4."..translate("Only support redir-host-tun")..bold_off..font_off
o:value("0", translate("Disable"))
o.default = "0"
local interfaces = SYS.exec("ls -l /sys/class/net/ 2>/dev/null |awk '{print $9}' 2>/dev/null")
for interface in string.gmatch(interfaces, "%S+") do
o:value(interface)
end
o:depends{en_mode = "redir-host-tun"}


o = s:taboption("op_mode", Value, "delay_start", translate("Delay Start (s)"))
o.description = translate("Delay Start On Boot")
o.default = "0"
Expand Down
20 changes: 19 additions & 1 deletion luci-app-openclash/po/zh-cn/openclash.zh-cn.po
Original file line number Diff line number Diff line change
Expand Up @@ -3556,4 +3556,22 @@ msgid "LAN Interface Name"
msgstr "LAN 接口名称"

msgid "Select LAN Interface Name"
msgstr "指定正确的 LAN 接口名称"
msgstr "指定正确的 LAN 接口名称"

msgid "Select outbound interface for eBPF to apply traffic management"
msgstr "为 eBPF 指定流量出站接口"

msgid "Warning! Highly experimental configs. Will disable default firewall traffic inbound"
msgstr "警告!高度实验性的配置。将禁用默认防火墙入站流量"

msgid "Needs kernel support for eBPF functionality. And it takes about 130MB memory to starts"
msgstr "需要内核支持 eBPF 功能。启动时需要大约 130MB 内存"

msgid "Might improve direct connection performance"
msgstr "可提高直连性能"

msgid "Only support redir-host-tun"
msgstr "仅支持 redir-host(TUN)模式"

msgid "eBPF Action Interface"
msgstr "eBPF 出站接口"
1 change: 1 addition & 0 deletions luci-app-openclash/root/etc/config/openclash
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ config openclash 'config'
option servers_update '0'
option log_level '0'
option proxy_mode 'rule'
option ebpf_action_interface '0'
option intranet_allowed '1'
option enable_udp_proxy '1'
option disable_udp_quic '1'
Expand Down
84 changes: 58 additions & 26 deletions luci-app-openclash/root/etc/init.d/openclash
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ LOCK_FILE="/tmp/lock/openclash.lock"
PROXY_FWMARK="0x162"
PROXY_ROUTE_TABLE="0x162"

# Assume we have bpftool sets would set ebpf marker to 1
KERNEL_EBPF_SUPPORT=$(bpftool version > /dev/null 2>&1 && echo '1' || echo '0')

if [[ "${KERNEL_EBPF_SUPPORT}" == "1" ]]; then
# Enhanced capabilities
capabilties="cap_sys_resource,cap_dac_override,cap_net_raw,cap_net_bind_service,cap_net_admin,cap_sys_ptrace,cap_sys_admin,CAP_PERFMON,cap_bpf"
else
# Regular capabilities
capabilties="cap_sys_resource,cap_dac_override,cap_net_raw,cap_net_bind_service,cap_net_admin,cap_sys_ptrace,cap_sys_admin"
fi



set_lock() {
exec 888>"$LOCK_FILE" 2>/dev/null
flock -x 888 2>/dev/null
Expand Down Expand Up @@ -793,7 +806,6 @@ start_run_core()
chmod o+w /tmp/openclash.log 2>/dev/null
chown nobody:nogroup /etc/openclash/core/* 2>/dev/null
#使用nobody启动内核方便代理路由自身流量
capabilties="cap_sys_resource,cap_dac_override,cap_net_raw,cap_net_bind_service,cap_net_admin,cap_sys_ptrace"
capsh --caps="${capabilties}+eip" -- -c "capsh --user=nobody --addamb='${capabilties}' -- -c 'nohup $CLASH -d $CLASH_CONFIG -f \"$CONFIG_FILE\" >> $LOG_FILE 2>&1 &'" >> $LOG_FILE 2>&1
fi
uci -q set openclash.config.config_reload=1
Expand Down Expand Up @@ -1432,6 +1444,7 @@ if [ "$ipv6_enable" -eq 1 ]; then
esac
fi

if [[ "${ebpf_int_name}" == "0" ]]; then
#NFTABLES
if [ -n "$FW4" ]; then
LOG_OUT "Tip: Firewall4 was Detected, Use NFTABLE Rules..."
Expand Down Expand Up @@ -2060,10 +2073,7 @@ if [ -n "$FW4" ]; then
fi
nft add rule inet fw4 openclash_v6 meta nfproto {ipv6} tcp dport { 0-65535 } counter redirect to "$proxy_port"
nft 'add rule inet fw4 dstnat meta nfproto {ipv6} tcp dport { 0-65535 } counter jump openclash_v6'
fi

#tproxy not support output chain
if [ "$ipv6_mode" -eq 0 ] || [ "$ipv6_mode" -eq 1 ]; then
if [ "$router_self_proxy" = "1" ]; then
nft 'add chain inet fw4 openclash_output_v6'
nft 'flush chain inet fw4 openclash_output_v6'
Expand All @@ -2081,12 +2091,18 @@ if [ -n "$FW4" ]; then
nft 'add rule inet fw4 openclash_output_v6 skuid != 65534 ip6 daddr @china_ip6_route counter return'
fi
fi
nft add rule inet fw4 openclash_output_v6 meta nfproto {ipv6} skuid != 65534 tcp dport { 0-65535 } counter redirect to "$proxy_port"

if [ "$ipv6_mode" -eq 2 ]; then
nft add rule inet fw4 openclash_output_v6 meta nfproto {ipv6} skuid != 65534 tcp dport { 0-65535 } mark set "$PROXY_FWMARK" counter
elif [ "$ipv6_mode" -eq 0 ]; then
nft add rule inet fw4 openclash_output_v6 meta nfproto {ipv6} skuid != 65534 tcp dport { 0-65535 } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"OpenClash TCP Tproxy\"
fi

nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
nft 'add rule inet fw4 nat_output meta nfproto {ipv6} counter jump openclash_output_v6'
nft 'add rule inet fw4 nat_output meta nfproto {ipv6} ip protocol tcp counter jump openclash_output_v6'
fi
fi

if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -eq 0 ] || [ "$ipv6_mode" -eq 2 ]; then
nft 'add chain inet fw4 openclash_mangle_v6'
nft 'flush chain inet fw4 openclash_mangle_v6'
Expand Down Expand Up @@ -2127,26 +2143,28 @@ if [ -n "$FW4" ]; then
fi

if [ "$router_self_proxy" = "1" ]; then
if [ "$ipv6_mode" -eq 2 ]; then
nft 'add chain inet fw4 openclash_mangle_output_v6'
nft 'flush chain inet fw4 openclash_mangle_output_v6'
nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 daddr @localnetwork6 counter return'
nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 saddr @localnetwork6 meta nfproto {ipv6} sport @lan_ac_black_ports counter return'
nft 'add rule inet fw4 openclash_mangle_output_v6 skuid != 65534 ip6 daddr @wan_ac_black_ipv6s counter return'
if [ "$en_mode" = "redir-host" ]; then
nft 'add rule inet fw4 openclash_mangle_output_v6 meta nfproto {ipv6} th dport != @common_ports skuid != 65534 counter return'
fi
nft 'add chain inet fw4 openclash_mangle_output_v6'
nft 'flush chain inet fw4 openclash_mangle_output_v6'
nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 daddr @localnetwork6 counter return'
nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 saddr @localnetwork6 meta nfproto {ipv6} sport @lan_ac_black_ports counter return'
nft 'add rule inet fw4 openclash_mangle_output_v6 skuid != 65534 ip6 daddr @wan_ac_black_ipv6s counter return'
if [ "$en_mode" = "redir-host" ]; then
nft 'add rule inet fw4 openclash_mangle_output_v6 meta nfproto {ipv6} th dport != @common_ports skuid != 65534 counter return'
fi

if [ "$china_ip6_route" = "1" ]; then
if [ "$enable_redirect_dns" != "2" ]; then
nft 'add rule inet fw4 openclash_mangle_output_v6 skuid != 65534 ip6 daddr @china_ip6_route ip6 daddr != @china_ip6_route_pass counter return'
else
nft 'add rule inet fw4 openclash_mangle_output_v6 skuid != 65534 ip6 daddr @china_ip6_route counter return'
fi
if [ "$china_ip6_route" = "1" ]; then
if [ "$enable_redirect_dns" != "2" ]; then
nft 'add rule inet fw4 openclash_mangle_output_v6 skuid != 65534 ip6 daddr @china_ip6_route ip6 daddr != @china_ip6_route_pass counter return'
else
nft 'add rule inet fw4 openclash_mangle_output_v6 skuid != 65534 ip6 daddr @china_ip6_route counter return'
fi
fi
if [ "$ipv6_mode" -eq 2 ]; then
nft add rule inet fw4 openclash_mangle_output_v6 meta nfproto {ipv6} skuid != 65534 tcp dport { 0-65535 } mark set "$PROXY_FWMARK" counter
nft 'add rule inet fw4 mangle_output meta nfproto {ipv6} counter jump openclash_mangle_output_v6'
elif [ "$ipv6_mode" -eq 0 ]; then
nft add rule inet fw4 openclash_mangle_output_v6 meta nfproto {ipv6} skuid != 65534 tcp dport { 0-65535 } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"OpenClash TCP Tproxy\"
fi
nft 'add rule inet fw4 mangle_output meta nfproto {ipv6} counter jump openclash_mangle_output_v6'
fi
fi

Expand Down Expand Up @@ -2912,8 +2930,8 @@ if [ -z "$FW4" ]; then
ip6tables -t mangle -A openclash -p tcp -j MARK --set-mark "$PROXY_FWMARK"
fi

if [ "$router_self_proxy" = "1" ]; then
if [ "$ipv6_mode" -eq 2 ]; then
if [ "$ipv6_mode" -eq 2 ]; then
if [ "$router_self_proxy" = "1" ]; then
ip6tables -t mangle -N openclash_output
ip6tables -t mangle -F openclash_output
ip6tables -t mangle -A openclash_output -m set --match-set localnetwork6 dst -j RETURN
Expand Down Expand Up @@ -3021,6 +3039,10 @@ if [ -z "$FW4" ]; then
fi
fi
fi 2>/dev/null
else
LOG_OUT "Escaping firewall settings due to eBPF interface: ${ebpf_int_name}..."

fi

#端口转发
LOG_OUT "Tip: Start Add Port Bypassing Rules For Firewall Redirect and Firewall Rules..."
Expand Down Expand Up @@ -3148,11 +3170,21 @@ get_config()
fi
[ -z "$fakeip_range" ] && fakeip_range="198.18.0.1/16"
lan_interface_name=$(uci -q get openclash.config.lan_interface_name || echo "0")

if [ "$lan_interface_name" = "0" ]; then
lan_ip=$(uci -q get network.lan.ipaddr |awk -F '/' '{print $1}' 2>/dev/null || ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w "inet" 2>/dev/null |grep -Eo 'inet [0-9\.]+' | awk '{print $2}' || ip addr show 2>/dev/null | grep -w 'inet' | grep 'global' | grep 'brd' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1)
else
lan_ip=$(ip address show $lan_interface_name | grep -w "inet" 2>/dev/null |grep -Eo 'inet [0-9\.]+' | awk '{print $2}')
fi

# eBPF configuration

if [[ "$en_mode" == "redir-host" && "$en_mode_tun" == "1" && "${KERNEL_EBPF_SUPPORT}" == "1" ]]; then
ebpf_int_name=$(uci -q get openclash.config.ebpf_action_interface || echo "0")
else
ebpf_int_name=$(echo "0")
fi

wan_ip4s=$(/usr/share/openclash/openclash_get_network.lua "wanip" 2>/dev/null)
wan_ip6s=$(ifconfig | grep 'inet6 addr' | awk '{print $3}' 2>/dev/null)
disable_masq_cache=$(uci -q get openclash.config.disable_masq_cache)
Expand Down Expand Up @@ -3220,7 +3252,7 @@ start()
if ! $quick_start; then
LOG_OUT "Step 3: Modify The Config File..."
config_check
/usr/share/openclash/yml_change.sh 2>/dev/null "$en_mode" "$da_password" "$cn_port" "$proxy_port" "$TMP_CONFIG_FILE" "$ipv6_enable" "$http_port" "$socks_port" "$log_level" "$proxy_mode" "$en_mode_tun" "$stack_type" "$dns_port" "$mixed_port" "$tproxy_port" "$ipv6_dns" "$store_fakeip" "$stream_domains_prefetch" "$enable_meta_core" "$enable_meta_sniffer" "$enable_geoip_dat" "$geodata_loader" "$enable_meta_sniffer_custom" "$interface_name" "$enable_tcp_concurrent" "$core_type" "$append_default_dns" "$enable_meta_sniffer_pure_ip" "$find_process_mode" "$fakeip_range" "$global_client_fingerprint" "$ipv6_mode" "$stack_type_v6" "$enable_unified_delay" "$keep_alive_interval" "$proxy_dns_group"
/usr/share/openclash/yml_change.sh 2>/dev/null "$en_mode" "$da_password" "$cn_port" "$proxy_port" "$TMP_CONFIG_FILE" "$ipv6_enable" "$http_port" "$socks_port" "$log_level" "$proxy_mode" "$en_mode_tun" "$stack_type" "$dns_port" "$mixed_port" "$tproxy_port" "$ipv6_dns" "$store_fakeip" "$stream_domains_prefetch" "$enable_meta_core" "$enable_meta_sniffer" "$enable_geoip_dat" "$geodata_loader" "$enable_meta_sniffer_custom" "$interface_name" "$enable_tcp_concurrent" "$core_type" "$append_default_dns" "$enable_meta_sniffer_pure_ip" "$find_process_mode" "$fakeip_range" "$global_client_fingerprint" "$ipv6_mode" "$stack_type_v6" "$enable_unified_delay" "$keep_alive_interval" "$proxy_dns_group" "$ebpf_int_name"
/usr/share/openclash/yml_rules_change.sh 2>/dev/null "$rule_source" "$enable_custom_clash_rules" "$TMP_CONFIG_FILE" "$enable_rule_proxy" "$CONFIG_NAME" "$router_self_proxy" "$lan_ip" "$proxy_port" "$tproxy_port" "$enable_meta_core" "$enable_redirect_dns" "$fakeip_range" "$en_mode"
/usr/share/openclash/openclash_custom_domain_dns.sh >/dev/null 2>&1
#Custom overwrite
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ STREAM_DOMAINS_PREFETCH=1
STREAM_AUTO_SELECT=1
FW4=$(command -v fw4)

# Enhanced capbilities
capabilties="cap_sys_resource,cap_dac_override,cap_net_raw,cap_net_bind_service,cap_net_admin,cap_sys_ptrace,CAP_PERFMON,cap_bpf,cap_sys_admin"


check_dnsmasq() {
if [ -z "$(echo "$en_mode" |grep "redir-host")" ] && [ "$china_ip_route" -eq 1 ] && [ "$enable_redirect_dns" != "2" ]; then
Expand Down Expand Up @@ -181,7 +184,7 @@ if [ "$enable" -eq 1 ]; then
chmod o+w /tmp/openclash.log 2>/dev/null
chmod o+w /etc/openclash/cache.db 2>/dev/null
chown nobody:nogroup /etc/openclash/core/* 2>/dev/null
capabilties="cap_sys_resource,cap_dac_override,cap_net_raw,cap_net_bind_service,cap_net_admin,cap_sys_ptrace"

capsh --caps="${capabilties}+eip" -- -c "capsh --user=nobody --addamb='${capabilties}' -- -c 'nohup $CLASH -d $CLASH_CONFIG -f \"$CONFIG_FILE\" >> $LOG_FILE 2>&1 &'" >> $LOG_FILE 2>&1
sleep 3
if [ "$core_type" == "TUN" ] || [ "$core_type" == "Meta" ]; then
Expand Down
19 changes: 19 additions & 0 deletions luci-app-openclash/root/usr/share/openclash/yml_change.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ enable_meta_core=$(uci -q get openclash.config.enable_meta_core || echo 0)
china_ip_route=$(uci -q get openclash.config.china_ip_route || echo 0)
proxy_dns_group=${36}

ebpf_action_interface=${37}

KERNEL_EBPF_SUPPORT=$(bpftool version > /dev/null 2>&1 && echo '1' || echo '0')

lan_block_google_dns=$(uci -q get openclash.config.lan_block_google_dns_ips || uci -q get openclash.config.lan_block_google_dns_macs || echo 0)

if [ -n "$(ruby_read "$5" "['tun']")" ]; then
Expand Down Expand Up @@ -506,9 +510,24 @@ Thread.new{
if ${17} == 1 then
Value['profile']['store-fake-ip']=true;
end;
if Value.key?('ebpf') then
Value.delete('ebpf');
end;
if ${en_mode_tun} == 1 and '${1}' == 'redir-host' and '${ebpf_action_interface}' != '0' then
if ${KERNEL_EBPF_SUPPORT} == 1 then
Value_2={'redirect-to-tun'=>['${ebpf_action_interface}']};
Value['ebpf']=Value_2;
else
puts '${LOGTIME} : intend to enable ebpf interface ${ebpf_action_interface}, but no kernel support found. Ignoring...';
end;
end;
if Value.key?('routing-mark') then
Value.delete('routing-mark');
end;
Expand Down

0 comments on commit 2c6edf7

Please sign in to comment.