Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

luci-app-ssr-plus: Add a script that gets dnsmasq configuration path separately. #1591

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions luci-app-ssr-plus/root/etc/init.d/shadowsocksr
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,10 @@ LOCK_FILE=/var/lock/ssrplus.lock
LOG_FILE=/var/log/ssrplus.log
TMP_PATH=/var/etc/ssrplus
TMP_BIN_PATH=$TMP_PATH/bin
# 获取默认的 DNSMasq 配置 ID
DEFAULT_DNSMASQ_CFGID=$(uci show dhcp.@dnsmasq[0] | awk -F '.' '{print $2}' | awk -F '=' '{print $1}' | head -1)
# 查找包含 conf-dir 选项的 dnsmasq.conf 文件路径
DNSMASQ_CONF_PATH=$(grep -l "^conf-dir=" "/tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID}")
# 从 conf-dir 行中提取目录路径
DNSMASQ_CONF_DIR=$(grep '^conf-dir=' "$DNSMASQ_CONF_PATH" | cut -d'=' -f2 | head -n 1)
# 设置 TMP_DNSMASQ_PATH,并去除路径末尾的斜杠
TMP_DNSMASQ_PATH=${DNSMASQ_CONF_DIR%*/}/dnsmasq-ssrplus.d
# Ensure DNSMASQ_CONF_DIR and TMP_DNSMASQ_PATH is set correctly
[ -f /etc/openwrt_release ] && {
eval $(lua /usr/share/shadowsocksr/dnsmasqconfdir.lua)
}

chain_config_file= #generate shadowtls chain proxy config file
tcp_config_file=
Expand Down
40 changes: 40 additions & 0 deletions luci-app-ssr-plus/root/usr/share/shadowsocksr/dnsmasqconfdir.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/lua

local uci = require("uci")
local cursor = uci.cursor()

-- Function to get the DNSMasq configuration ID
local function get_dnsmasq_cfg_id()
local id = nil
cursor:foreach("dhcp", "dnsmasq", function(s)
if not id then
id = s[".name"] -- Get the internal ID of the first dnsmasq entry
end
end)
return id
end

-- Get the DNSMasq configuration ID
local DEFAULT_DNSMASQ_CFGID = get_dnsmasq_cfg_id()
local DNSMASQ_CONF_DIR = nil
local TMP_DNSMASQ_PATH = nil

if DEFAULT_DNSMASQ_CFGID then
local dnsmasq_conf_path = io.popen("grep -l '^conf-dir=' /tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID):read("*a")
dnsmasq_conf_path = dnsmasq_conf_path:gsub("%s+", "") -- Trim whitespace

if dnsmasq_conf_path ~= "" then
local dnsmasq_conf_dir = io.popen("grep '^conf-dir=' " .. dnsmasq_conf_path .. " | cut -d'=' -f2 | head -n 1"):read("*a")
dnsmasq_conf_dir = dnsmasq_conf_dir:gsub("%s+", "") -- Trim whitespace

if dnsmasq_conf_dir ~= "" then
DNSMASQ_CONF_DIR = dnsmasq_conf_dir:gsub("/$", "") -- Remove trailing slash
TMP_DNSMASQ_PATH = DNSMASQ_CONF_DIR .. "/dnsmasq-ssrplus.d"
end
end
end

-- Output variables in a format usable by shell scripts
io.write("DNSMASQ_CONF_DIR='", DNSMASQ_CONF_DIR or "", "'\n")
io.write("TMP_DNSMASQ_PATH='", TMP_DNSMASQ_PATH or "", "'\n")

6 changes: 5 additions & 1 deletion luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ require "luci.model.uci"
local icount = 0
local args = arg[1]
local uci = luci.model.uci.cursor()
local TMP_DNSMASQ_PATH = luci.sys.exec("find /tmp/dnsmasq.*/dnsmasq-ssrplus.d -type d -print 2>/dev/null"):gsub("%s+", "")

-- Execute the Lua script and capture its output
local TMP_DNSMASQ_CONF_OUTPUT = io.popen("lua /usr/share/shadowsocksr/dnsmasqconfdir.lua"):read("*a")
-- Extract only the TMP_DNSMASQ_PATH value using a pattern
local TMP_DNSMASQ_PATH = TMP_DNSMASQ_CONF_OUTPUT:match("TMP_DNSMASQ_PATH=['\"]([^\"]+)['\"]")
local TMP_PATH = "/var/etc/ssrplus"
-- match comments/title/whitelist/ip address/excluded_domain
local comment_pattern = "^[!\\[@]+"
Expand Down
132 changes: 132 additions & 0 deletions shadowsocks-libev/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#
# Copyright (C) 2017-2020 Yousong Zhou <[email protected]>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk

# Checklist when bumping versions
#
# - update cipher list by checking src/crypto.c:crypto_init()
# - check if default mode has changed from being tcp_only
#
PKG_NAME:=shadowsocks-libev
PKG_VERSION:=3.3.5
PKG_RELEASE:=12

PKG_SOURCE_PROTO:=git
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/shadowsocks/shadowsocks-libev.git
PKG_SOURCE_VERSION:=d83ace0f0d9c05656c13d66aa4a449bf70143254
PKG_MIRROR_HASH:=fdcd84cadd5b0b9162b2e81c4ce8e135d944e735a8c5bb79d349627df6ca76c2

PKG_MAINTAINER:=Yousong Zhou <[email protected]>

PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=LICENSE
PKG_CPE_ID:=cpe:/a:shadowsocks:shadowsocks-libev

PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
PKG_BUILD_FLAGS:=no-mips16 lto
PKG_BUILD_PARALLEL:=1
PKG_BUILD_DEPENDS:=c-ares pcre2

include $(INCLUDE_DIR)/package.mk


define Package/shadowsocks-libev-config
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocks-libev config scripts
URL:=https://github.com/shadowsocks/shadowsocks-libev
endef

define Package/shadowsocks-libev-config/conffiles
/etc/config/shadowsocks-libev
endef

define Package/shadowsocks-libev-config/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/shadowsocks-libev.config $(1)/etc/config/shadowsocks-libev
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/shadowsocks-libev.init $(1)/etc/init.d/shadowsocks-libev
endef


define Package/shadowsocks-libev/Default
define Package/shadowsocks-libev-$(1)
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocks-libev $(1)
URL:=https://github.com/shadowsocks/shadowsocks-libev
DEPENDS:=+libev +libmbedtls +libpthread +libsodium +shadowsocks-libev-config $(DEPENDS_$(1))
endef

define Package/shadowsocks-libev-$(1)/install
$$(INSTALL_DIR) $$(1)/usr/bin
$$(INSTALL_BIN) $$(PKG_INSTALL_DIR)/usr/bin/$(1) $$(1)/usr/bin
endef

endef

DEPENDS_ss-local = +libpcre2
DEPENDS_ss-server = +libcares +libpcre2

SHADOWSOCKS_COMPONENTS:=ss-local ss-redir ss-tunnel ss-server
define shadowsocks-libev/templates
$(foreach component,$(SHADOWSOCKS_COMPONENTS),
$(call Package/shadowsocks-libev/Default,$(component))
)
endef
$(eval $(call shadowsocks-libev/templates))


define Package/shadowsocks-libev-ss-rules
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocks-libev ss-rules
URL:=https://github.com/shadowsocks/shadowsocks-libev
DEPENDS:=+firewall4 \
+ip \
+resolveip \
+ucode \
+ucode-mod-fs \
+shadowsocks-libev-ss-redir \
+shadowsocks-libev-config \
+kmod-nft-tproxy
endef

define Package/shadowsocks-libev-ss-rules/install
$(INSTALL_DIR) $(1)/usr/share/ss-rules
$(INSTALL_DATA) ./files/ss-rules/* $(1)/usr/share/ss-rules/
endef

define Build/Prepare
$(call Build/Prepare/Default)
$(FIND) $(PKG_BUILD_DIR) \
-name '*.o' \
-o -name '*.lo' \
-o -name '.deps' \
-o -name '.libs' \
| $(XARGS) rm -rvf
endef

CONFIGURE_ARGS += \
--disable-documentation \
--disable-silent-rules \
--disable-assert \
--disable-ssp \

TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed

$(eval $(call BuildPackage,shadowsocks-libev-config))
$(eval $(call BuildPackage,shadowsocks-libev-ss-rules))
$(foreach component,$(SHADOWSOCKS_COMPONENTS), \
$(eval $(call BuildPackage,shadowsocks-libev-$(component))) \
)
185 changes: 185 additions & 0 deletions shadowsocks-libev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
Skip to [recipes](#recipes) for quick setup instructions

# components

`ss-local` provides SOCKS5 proxy with UDP associate support.

socks5 ss plain
--------> tcp:local_address:local_port ----> ss server -------> dest

`ss-redir`. The REDIRECT and TPROXY part are to be provided by `ss-rules` script. REDIRECT is for tcp traffic (`SO_ORIGINAL_DST` only supports TCP). TPROXY is for udp messages, but it's only available in the PREROUTING chain and as such cannot proxy local out traffic.

plain plain ss plain
---------> REDIRECT ------> tcp:local_address:local_port ----> ss server -----> original dest

plain plain ss plain
---------> TPROXY -------> udp:local_address:local_port -----> ss server -----> original dest

`ss-tunnel` provides ssh `-L` local-forwarding-like tunnel. Typically it's used to tunnel DNS traffic to the remote.

plain ss plain
---------> tcp|udp:local_address:local_port ------> ss server -------> tunnel_address

`ss-server`, the "ss server" in the above diagram

# uci

Option names are the same as those used in json config files. Check `validate_xxx` func definition of the [service script](files/shadowsocks-libev.init) and shadowsocks-libev's own documentation for supported options and expected value types. A [sample config file](files/shadowsocks-libev.config) is also provided for reference.

Every section have a `disabled` option to temporarily turn off the component instance or component instances referring to it.

Section type `server` is for definition of remote shadowsocks servers. They will be referred to from other component sections and as such should be named (as compared to anonymous section).

Section type `ss_local`, `ss_redir`, `ss_tunnel` are for specification of shadowsocks-libev components. They share mostly a common set of options like `local_port`, `verbose`, `fast_open`, `timeout`, etc.

Plugin options should be specified in `server` section and will be inherited by other compoenents referring to it.

We can have multiple instances of component and `server` sections. The relationship between them is many-to-one. This will have the following implications

- It's possible to have both `ss_local` and `ss_redir` referring to the same `server` definition
- It's possible to have multiple instances of `ss_redir` listening on the same address:port with `reuse_port` enabled referring to the same or different `server` sections

`ss_rules` section is for configuring the behaviour of `ss-rules` script. There can only exist at most one such section with the name also being `ss_rules`

redir_tcp name of ss_redir section with mode tcp_only or tcp_and_udp
redir_udp name of ss_redir section with mode udp_only or tcp_and_udp
ifnames only apply rules on packets from these ifnames

--- for incoming packets having source address in

src_ips_bypass will bypass the redir chain
src_ips_forward will always go through the redir chain
src_ips_checkdst will continue to have their destination addresses checked

--- otherwise, the default action can be specified with

src_default bypass, forward, [checkdst]

--- if the previous check result is checkdst,
--- then packets having destination address in

dst_ips_bypass_file
dst_ips_bypass will bypass the redir chain
dst_ips_forward_file
dst_ips_forward will go through the redir chain

--- otherwise, the default action can be specified with

dst_default [bypass], forward

--- for local out tcp packets, the default action can be specified with

local_default [bypass], forward, checkdst

ss-rules now uses nft set for storing addresses/networks. Those set names are also part of the API and can be populated by other programs, e.g. dnsmasq with builtin nft set support. Note that while nftables set supports storing cidr networks when `interval` flag is on, it rejects elements with overlaping intervals.

Extra nftables expressions can be specified with `nft_tcp_extra` and `nft_udp_extra` to apply ss_rules only to selected tcp/udp traffics. E.g. `tcp dport { 80, 443 }`, `udp dport 53`, etc.

# incompatible changes

| Commit date | Commit ID | Subject | Comment |
| ----------- | --------- | ------- | ------- |
| 2022-03-01 | fdaf2de2a | shadowsocks-libev: ss-rules: convert to using nft | ss-rules now uses nftables. UCI option ipt_args and dst_forward_recentrst are now deprecated and removed |
| 2020-08-03 | 7d7cbae75 | shadowsocks-libev: support ss-server option local_address_{v4,v6} | ss_server bind_address now deprecated, use local_address |
| 2019-05-09 | afe7d3424 | shadowsocks-libev: move plugin options to server section | This is a revision against c19e949 committed 2019-05-06 |
| 2017-07-02 | b61af9703 | shadowsocks-libev: rewrite | Packaging of shadowsocks-libev was rewritten from scratch |

# notes and faq

Useful paths and commands for debugging

# check current running status
ubus call service list '{"name": "shadowsocks-libev"}'
ubus call service list '{"name": "shadowsocks-libev", "verbose": true}'

# dump validate definition
ubus call service validate '{"package": "shadowsocks-libev"}'
ubus call service validate '{"package": "shadowsocks-libev"}' \
| jsonfilter -e '$["shadowsocks-libev"]["ss_tunnel"]'

# check json config
ls -l /var/etc/shadowsocks-libev/

# set uci config option verbose to 1, restart the service and follow the log
logread -f

ss-redir needs to open a new socket and setsockopt IP_TRANSPARENT when sending udp reply to client. This requires `CAP_NET_ADMIN` and as such the process cannot run as `nobody`

ss-local, ss-redir, etc. supports specifying an array of remote ss server, but supporting this in uci seems to be overkill. The workaround can be defining multiple `server` sections and multiple `ss-redir` instances with `reuse_port` enabled

# recipes

## forward all

This will setup firewall rules to forward almost all incoming tcp/udp and locally generated tcp traffic (excluding those to private addresses like 192.168.0.0/16 etc.) through remote shadowsocks server

Install components.
Retry each command till it succeed

opkg install shadowsocks-libev-ss-redir
opkg install shadowsocks-libev-ss-rules
opkg install shadowsocks-libev-ss-tunnel

Edit uci config `/etc/config/shadowsocks-libev`.
Replace `config server 'sss0'` section with parameters of your own remote shadowsocks server.
As for other options, change them only when you know the effect.

config server 'sss0'
option disabled 0
option server '_sss_addr_'
option server_port '_sss_port_'
option password '********'
option method 'aes-256-cfb'

config ss_tunnel
option disabled 0
option server 'sss0'
option local_address '0.0.0.0'
option local_port '8053'
option tunnel_address '8.8.8.8:53'
option mode 'tcp_and_udp'

config ss_redir ssr0
option disabled 0
option server 'sss0'
option local_address '0.0.0.0'
option local_port '1100'
option mode 'tcp_and_udp'
option reuse_port 1

config ss_rules 'ss_rules'
option disabled 0
option redir_tcp 'ssr0'
option redir_udp 'ssr0'
option src_default 'checkdst'
option dst_default 'forward'
option local_default 'forward'

Restart shadowsocks-libev components

/etc/init.d/shadowsocks-libev restart

Check if things are in place

nft list ruleset | sed -r -n '/^\t[a-z]+ ss_rules[^ ]+ \{/,/^\t\}/p'
netstat -lntp | grep -E '8053|1100'
ps ww | grep ss-

Edit `/etc/config/dhcp`, making sure options are present in the first dnsmasq section like the following to let it use local tunnel endpoint for upstream dns query.
Option `noresolv` instructs dnsmasq to not use other dns servers like advertised by local isp.
Option `localuse` intends to make sure the device you are configuring also uses this dnsmasq instance as the resolver, not the ones from other sources.

config dnsmasq
...
list server '127.0.0.1#8053'
option noresolv 1
option localuse 1

Restart dnsmasq

/etc/init.d/dnsmasq restart

Check network on your computer

nslookup www.google.com
curl -vv https://www.google.com
Loading
Loading