Skip to content

Commit efc0efb

Browse files
committed
[feature] adblock filter and improve perfomance
1 parent 73f9a54 commit efc0efb

18 files changed

Lines changed: 1336 additions & 107 deletions

File tree

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ set(FPTN_DEFAULT_BLACKLIST_DOMAINS
5858
add_compile_definitions(FPTN_CLIENT_DEFAULT_BLACKLIST_DOMAINS=\"${FPTN_DEFAULT_BLACKLIST_DOMAINS}\")
5959
# server
6060
add_compile_definitions(FPTN_SERVER_DEFAULT_BLACKLIST_DOMAINS=\"${FPTN_DEFAULT_BLACKLIST_DOMAINS}\")
61+
set(FPTN_SERVER_DEFAULT_DOMAIN_BLACKLIST_URLS
62+
"https://raw.githubusercontent.com/fptn-project/fptn/refs/heads/master/deploy/domain_blacklist/russia.txt")
63+
add_compile_definitions(FPTN_SERVER_DEFAULT_DOMAIN_BLACKLIST_URLS=\"${FPTN_SERVER_DEFAULT_DOMAIN_BLACKLIST_URLS}\")
64+
set(FPTN_SERVER_DEFAULT_ADS_BLOCKLIST_URLS
65+
"https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/ultimate-onlydomains.txt,https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts")
66+
add_compile_definitions(FPTN_SERVER_DEFAULT_ADS_BLOCKLIST_URLS=\"${FPTN_SERVER_DEFAULT_ADS_BLOCKLIST_URLS}\")
6167
add_compile_definitions(FPTN_SERVER_DEFAULT_ADDRESS_IP6=\"fc00:1::1\")
6268
add_compile_definitions(FPTN_SERVER_DEFAULT_NET_ADDRESS_IP6=\"fc00:1::\")
6369
add_compile_definitions(FPTN_SERVER_DEFAULT_ADDRESS_IP4=\"172.20.0.1\")

deploy/docker/scripts/start-fptn.sh

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,6 @@
33
export OUT_NETWORK_INTERFACE=$(ip -o -4 route show to default | awk '{print $5}')
44
echo "[FPTN] Using network interface: $OUT_NETWORK_INTERFACE"
55

6-
# Download the domain blacklist before starting the server.
7-
BLACKLIST_FILE=/tmp/fptn-blacklist.txt
8-
BLACKLIST_ARG=""
9-
rm -f "${BLACKLIST_FILE}"
10-
if [ -n "${BLACKLIST_URL}" ]; then
11-
echo "[FPTN] Downloading domain blacklist from: ${BLACKLIST_URL}"
12-
if wget -4 -q --timeout=10 --tries=2 -O "${BLACKLIST_FILE}.tmp" "${BLACKLIST_URL}"; then
13-
mv "${BLACKLIST_FILE}.tmp" "${BLACKLIST_FILE}"
14-
BLACKLIST_ARG="--domain-blacklist-file=${BLACKLIST_FILE}"
15-
echo "[FPTN] Domain blacklist saved to ${BLACKLIST_FILE}"
16-
else
17-
rm -f "${BLACKLIST_FILE}.tmp"
18-
echo "[FPTN] WARNING: failed to download blacklist; using built-in list only"
19-
fi
20-
fi
21-
226
exec /usr/local/bin/fptn-server \
237
--server-key=/etc/fptn/server.key \
248
--server-crt=/etc/fptn/server.crt \
@@ -28,13 +12,17 @@ exec /usr/local/bin/fptn-server \
2812
--default-proxy-domain="${DEFAULT_PROXY_DOMAIN}" \
2913
--allowed-sni-list="${ALLOWED_SNI_LIST}" \
3014
--tun-interface-name=fptn0 \
31-
--disable-torrent-filter="$DISABLE_TORRENT_FILTER" \
32-
--disable-spam-filter="$DISABLE_SPAM_FILTER" \
15+
--enable-domain-blacklist-filter="$ENABLE_DOMAIN_BLACKLIST_FILTER" \
16+
--domain-blacklist-urls="$DOMAIN_BLACKLIST_URLS" \
17+
--enable-ads-filter="$ENABLE_ADS_FILTER" \
18+
--ads-blocklist-urls="$ADS_BLOCKLIST_URLS" \
19+
--data-dir="$DATA_DIR" \
20+
--enable-torrent-filter="$ENABLE_TORRENT_FILTER" \
21+
--enable-spam-filter="$ENABLE_SPAM_FILTER" \
3322
--prometheus-access-key="$PROMETHEUS_SECRET_ACCESS_KEY" \
3423
--use-remote-server-auth="$USE_REMOTE_SERVER_AUTH" \
3524
--remote-server-auth-host="$REMOTE_SERVER_AUTH_HOST" \
3625
--remote-server-auth-port="$REMOTE_SERVER_AUTH_PORT" \
3726
--max-active-sessions-per-user="$MAX_ACTIVE_SESSIONS_PER_USER" \
3827
--server-external-ips="${SERVER_EXTERNAL_IPS}" \
39-
--mtu-size="${MTU_SIZE}" \
40-
${BLACKLIST_ARG}
28+
--mtu-size="${MTU_SIZE}"

docker-compose/.env.demo

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,24 @@ DEFAULT_PROXY_DOMAIN=yandex.ru
3434
# ALLOWED_SNI_LIST=
3535
ALLOWED_SNI_LIST=vprok.ru,vk.com,perekrestok.ru,x5.ru,yandex.ru,yandex.com,max.ru,alfabank.ru,ozone.ru,rutube.ru
3636

37+
# Block ads and trackers
38+
# (accepted values: true or false; enabled unless set to false).
39+
# A TLS handshake whose SNI is a listed domain (or a subdomain of one) is
40+
# dropped, and so is every packet addressed to an IP such a domain resolves to.
41+
ENABLE_ADS_FILTER=true
42+
43+
# Comma-separated URLs of the ad/tracker domain lists. Each one is cached in
44+
# DATA_DIR and downloaded again once the cached copy is older than three days.
45+
# Empty (default) uses the built-in URLs.
46+
ADS_BLOCKLIST_URLS=https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/ultimate-onlydomains.txt,https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
47+
48+
# Directory for the files the server downloads at runtime (the ad/tracker
49+
# domain lists). It lives on the mounted volume, so the cache survives restarts.
50+
DATA_DIR=/etc/fptn/data
51+
3752
# Block BitTorrent traffic to prevent abuse
3853
# (accepted values: true or false; enabled unless set to false)
39-
DISABLE_TORRENT_FILTER=false
54+
ENABLE_TORRENT_FILTER=false
4055

4156
# Block the client traffic that gets this server blacklisted
4257
# (accepted values: true or false; enabled unless set to false). It drops:
@@ -47,11 +62,18 @@ DISABLE_TORRENT_FILTER=false
4762
# - amplification reflectors: UDP 1900, 11211
4863
# NOTE: the mail part also stops desktop mail clients (Thunderbird, Outlook)
4964
# of your legitimate users from sending mail through the tunnel.
50-
DISABLE_SPAM_FILTER=false
65+
ENABLE_SPAM_FILTER=false
66+
67+
# Block the blacklisted domains: a TLS handshake whose SNI is a listed domain
68+
# (or a subdomain of one) is dropped, and so are the QUIC and ICMP packets
69+
# addressed to an IP such a domain resolves to
70+
# (accepted values: true or false; enabled unless set to false).
71+
ENABLE_DOMAIN_BLACKLIST_FILTER=true
5172

52-
# URL of the domain blacklist, downloaded on every container start.
53-
# Set it to empty to use only the built-in list.
54-
BLACKLIST_URL=https://raw.githubusercontent.com/fptn-project/fptn/refs/heads/master/deploy/domain_blacklist/russia.txt
73+
# Comma-separated URLs of the domain lists to block. Each one is cached in
74+
# DATA_DIR/blacklist and downloaded again once the cached copy is older than
75+
# an hour. Empty uses the built-in URLs.
76+
DOMAIN_BLACKLIST_URLS=https://raw.githubusercontent.com/fptn-project/fptn/refs/heads/master/deploy/domain_blacklist/russia.txt
5577

5678
# Maximum IP packet size (actual packet size will be padded to 1450 due to obfuscation)
5779
MTU_SIZE=1400

docker-compose/README.md

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,13 @@ services:
8080
- ENABLE_DETECT_PROBING=${ENABLE_DETECT_PROBING}
8181
- DEFAULT_PROXY_DOMAIN=${DEFAULT_PROXY_DOMAIN}
8282
- ALLOWED_SNI_LIST=${ALLOWED_SNI_LIST}
83-
- DISABLE_TORRENT_FILTER=${DISABLE_TORRENT_FILTER}
84-
- DISABLE_SPAM_FILTER=${DISABLE_SPAM_FILTER}
85-
- BLACKLIST_URL=${BLACKLIST_URL:-}
83+
- ENABLE_DOMAIN_BLACKLIST_FILTER=${ENABLE_DOMAIN_BLACKLIST_FILTER:-true}
84+
- DOMAIN_BLACKLIST_URLS=${DOMAIN_BLACKLIST_URLS:-}
85+
- ENABLE_ADS_FILTER=${ENABLE_ADS_FILTER:-true}
86+
- ADS_BLOCKLIST_URLS=${ADS_BLOCKLIST_URLS:-}
87+
- DATA_DIR=${DATA_DIR:-/etc/fptn/data}
88+
- ENABLE_TORRENT_FILTER=${ENABLE_TORRENT_FILTER}
89+
- ENABLE_SPAM_FILTER=${ENABLE_SPAM_FILTER}
8690
- PROMETHEUS_SECRET_ACCESS_KEY=${PROMETHEUS_SECRET_ACCESS_KEY}
8791
- USE_REMOTE_SERVER_AUTH=${USE_REMOTE_SERVER_AUTH}
8892
- REMOTE_SERVER_AUTH_HOST=${REMOTE_SERVER_AUTH_HOST}
@@ -156,9 +160,24 @@ DEFAULT_PROXY_DOMAIN=rutube.ru
156160
# ALLOWED_SNI_LIST=vprok.ru,vk.com,perekrestok.ru,x5.ru,yandex.ru,yandex.com,max.ru,alfabank.ru,ozone.ru,rutube.ru
157161
ALLOWED_SNI_LIST=
158162
163+
# Block ads and trackers
164+
# (accepted values: true or false; enabled unless set to false).
165+
# A TLS handshake whose SNI is a listed domain (or a subdomain of one) is
166+
# dropped, and so is every packet addressed to an IP such a domain resolves to.
167+
ENABLE_ADS_FILTER=true
168+
169+
# Comma-separated URLs of the ad/tracker domain lists. Each one is cached in
170+
# DATA_DIR and downloaded again once the cached copy is older than three days.
171+
# Empty (default) uses the built-in URLs.
172+
ADS_BLOCKLIST_URLS=https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/ultimate-onlydomains.txt,https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
173+
174+
# Directory for the files the server downloads at runtime (the ad/tracker
175+
# domain lists). It lives on the mounted volume, so the cache survives restarts.
176+
DATA_DIR=/etc/fptn/data
177+
159178
# Block BitTorrent traffic to prevent abuse
160179
# (accepted values: true or false; enabled unless set to false)
161-
DISABLE_TORRENT_FILTER=true
180+
ENABLE_TORRENT_FILTER=true
162181
163182
# Block the client traffic that gets this server blacklisted
164183
# (accepted values: true or false; enabled unless set to false). It drops:
@@ -169,12 +188,18 @@ DISABLE_TORRENT_FILTER=true
169188
# - amplification reflectors: UDP 1900, 11211
170189
# NOTE: the mail part also stops desktop mail clients (Thunderbird, Outlook)
171190
# of your legitimate users from sending mail through the tunnel.
172-
DISABLE_SPAM_FILTER=true
173-
174-
# URL of the domain blacklist, downloaded on every container start.
175-
# Traffic to the addresses a listed domain or any of its subdomains resolves
176-
# to is dropped. Set it to empty to use only the built-in list.
177-
BLACKLIST_URL=https://raw.githubusercontent.com/fptn-project/fptn/refs/heads/master/deploy/domain_blacklist/russia.txt
191+
ENABLE_SPAM_FILTER=true
192+
193+
# Block the blacklisted domains: a TLS handshake whose SNI is a listed domain
194+
# (or a subdomain of one) is dropped, and so are the QUIC and ICMP packets
195+
# addressed to an IP such a domain resolves to
196+
# (accepted values: true or false; enabled unless set to false).
197+
ENABLE_DOMAIN_BLACKLIST_FILTER=true
198+
199+
# Comma-separated URLs of the domain lists to block. Each one is cached in
200+
# DATA_DIR/blacklist and downloaded again once the cached copy is older than
201+
# an hour. Empty uses the built-in URLs.
202+
DOMAIN_BLACKLIST_URLS=https://raw.githubusercontent.com/fptn-project/fptn/refs/heads/master/deploy/domain_blacklist/russia.txt
178203
179204
# Set the USE_REMOTE_SERVER_AUTH variable to true if you need to
180205
# redirect requests to a master FPTN server for authorization.

docker-compose/docker-compose.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,13 @@ services:
3636
- ENABLE_DETECT_PROBING=${ENABLE_DETECT_PROBING}
3737
- DEFAULT_PROXY_DOMAIN=${DEFAULT_PROXY_DOMAIN}
3838
- ALLOWED_SNI_LIST=${ALLOWED_SNI_LIST}
39-
- DISABLE_TORRENT_FILTER=${DISABLE_TORRENT_FILTER}
40-
- DISABLE_SPAM_FILTER=${DISABLE_SPAM_FILTER}
41-
- BLACKLIST_URL=${BLACKLIST_URL:-}
39+
- ENABLE_DOMAIN_BLACKLIST_FILTER=${ENABLE_DOMAIN_BLACKLIST_FILTER:-true}
40+
- DOMAIN_BLACKLIST_URLS=${DOMAIN_BLACKLIST_URLS:-}
41+
- ENABLE_ADS_FILTER=${ENABLE_ADS_FILTER:-true}
42+
- ADS_BLOCKLIST_URLS=${ADS_BLOCKLIST_URLS:-}
43+
- DATA_DIR=${DATA_DIR:-/etc/fptn/data}
44+
- ENABLE_TORRENT_FILTER=${ENABLE_TORRENT_FILTER}
45+
- ENABLE_SPAM_FILTER=${ENABLE_SPAM_FILTER}
4246
- PROMETHEUS_SECRET_ACCESS_KEY=${PROMETHEUS_SECRET_ACCESS_KEY}
4347
- USE_REMOTE_SERVER_AUTH=${USE_REMOTE_SERVER_AUTH}
4448
- REMOTE_SERVER_AUTH_HOST=${REMOTE_SERVER_AUTH_HOST}

src/fptn-server/CMakeLists.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@ find_package(fmt REQUIRED)
2626
find_package(nlohmann_json REQUIRED)
2727
find_package(jwt-cpp REQUIRED)
2828
find_package(prometheus-cpp REQUIRED)
29+
find_package(httplib REQUIRED)
2930

3031

3132
# Include Boost directory
3233
include_directories(${Boost_INCLUDE_DIRS})
3334

35+
set(PLATFORM_SPECIFIC_LIBS "")
36+
if(APPLE)
37+
set(PLATFORM_SPECIFIC_LIBS "-framework Security" "-framework CoreFoundation")
38+
endif()
39+
3440
add_executable(
3541
"${PROJECT_NAME}"
3642
fptn-server.cpp
@@ -68,6 +74,10 @@ add_executable(
6874
filter/filters/bittorrent/bittorrent.cpp
6975
filter/filters/domain_blacklist/domain_blacklist.h
7076
filter/filters/domain_blacklist/domain_blacklist.cpp
77+
filter/filters/adblock/adblock.h
78+
filter/filters/adblock/adblock.cpp
79+
filter/domain_list/domain_list.h
80+
filter/domain_list/domain_list.cpp
7181
vpn/manager.h
7282
vpn/manager.cpp
7383
statistic/metrics.h
@@ -89,9 +99,11 @@ target_link_libraries(
8999
OpenSSL::Crypto
90100
argparse::argparse
91101
nlohmann_json::nlohmann_json
102+
httplib::httplib
92103
jwt-cpp::jwt-cpp
93104
spdlog::spdlog
94105
fmt::fmt
95106
tuntap++
96107
fptn-protocol-lib_static
97-
prometheus-cpp::prometheus-cpp)
108+
prometheus-cpp::prometheus-cpp
109+
${PLATFORM_SPECIFIC_LIBS})

src/fptn-server/config/server_config.cpp

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,22 +129,72 @@ ServerConfig::ServerConfig(int argc, char* argv[])
129129
return v.empty() ? "/etc/fptn/users.list" : v;
130130
});
131131
// Packet filters
132+
args_.add_argument("--enable-domain-blacklist-filter")
133+
.help(
134+
"Block the blacklisted domains: a TLS handshake whose SNI is a "
135+
"listed domain (or a subdomain of one) is dropped, and so are the "
136+
"QUIC and ICMP packets addressed to an IP such a domain resolves "
137+
"to. Enabled by default, set to 'false' to let this traffic "
138+
"through.")
139+
.default_value("true")
140+
.action([](const std::string& v) -> std::string {
141+
return v.empty() ? "true" : v;
142+
});
143+
args_.add_argument("--domain-blacklist-urls")
144+
.help(
145+
"Comma-separated URLs of the domain lists to block, one domain per "
146+
"line ('#' starts a comment). Every list is cached in --data-dir and "
147+
"downloaded again once it is older than an hour. The lists extend "
148+
"the built-in one.")
149+
.default_value(FPTN_SERVER_DEFAULT_DOMAIN_BLACKLIST_URLS)
150+
.action([](const std::string& v) -> std::string {
151+
return v.empty() ? FPTN_SERVER_DEFAULT_DOMAIN_BLACKLIST_URLS : v;
152+
});
132153
args_.add_argument("--domain-blacklist-file")
133154
.help(
134155
"Path to a file with domains to block, one per line ('#' starts a "
135156
"comment). Traffic to the addresses a listed domain or any of its "
136157
"subdomains resolves to is dropped. The list extends the built-in "
137158
"one. Empty (default) uses only the built-in list.")
138159
.default_value("");
139-
args_.add_argument("--disable-torrent-filter")
160+
args_.add_argument("--enable-ads-filter")
161+
.help(
162+
"Block ads and trackers using the domain lists downloaded from "
163+
"--ads-blocklist-urls. A TLS handshake whose SNI is a listed domain "
164+
"(or a subdomain of one) is dropped, and every packet addressed to "
165+
"an IP such a domain resolves to is dropped as well. Enabled by "
166+
"default, set to 'false' to let this traffic through.")
167+
.default_value("true")
168+
.action([](const std::string& v) -> std::string {
169+
return v.empty() ? "true" : v;
170+
});
171+
args_.add_argument("--ads-blocklist-urls")
172+
.help(
173+
"Comma-separated URLs of the ad/tracker domain lists (the hosts "
174+
"format and a bare domain per line are both accepted). Every list is "
175+
"cached in --data-dir and downloaded again once it is older than an "
176+
"hour.")
177+
.default_value(FPTN_SERVER_DEFAULT_ADS_BLOCKLIST_URLS)
178+
.action([](const std::string& v) -> std::string {
179+
return v.empty() ? FPTN_SERVER_DEFAULT_ADS_BLOCKLIST_URLS : v;
180+
});
181+
args_.add_argument("--data-dir")
182+
.help(
183+
"Directory for the files the server downloads at runtime, such as "
184+
"the ad/tracker domain lists (default: /etc/fptn/data)")
185+
.default_value("/etc/fptn/data")
186+
.action([](const std::string& v) -> std::string {
187+
return v.empty() ? "/etc/fptn/data" : v;
188+
});
189+
args_.add_argument("--enable-torrent-filter")
140190
.help(
141191
"Block BitTorrent traffic. Enabled by default, set to 'false' to let "
142192
"BitTorrent packets through.")
143193
.default_value("true")
144194
.action([](const std::string& v) -> std::string {
145195
return v.empty() ? "true" : v;
146196
});
147-
args_.add_argument("--disable-spam-filter")
197+
args_.add_argument("--enable-spam-filter")
148198
.help(
149199
"Block the client traffic that gets this server blacklisted: "
150200
"outgoing mail (the SMTP ports, any TCP stream that starts with an "
@@ -279,12 +329,35 @@ std::string ServerConfig::UserFile() const {
279329
return args_.get<std::string>("--userfile");
280330
}
281331

282-
bool ServerConfig::DisableTorrentFilter() const {
283-
return ParseBoolean(args_.get<std::string>("--disable-torrent-filter"));
332+
bool ServerConfig::EnableAdsFilter() const {
333+
return ParseBoolean(args_.get<std::string>("--enable-ads-filter"));
334+
}
335+
336+
std::vector<std::string> ServerConfig::AdsBlocklistUrls() const {
337+
return fptn::common::utils::SplitCommaSeparated(
338+
args_.get<std::string>("--ads-blocklist-urls"));
339+
}
340+
341+
std::string ServerConfig::DataDir() const {
342+
return args_.get<std::string>("--data-dir");
343+
}
344+
345+
bool ServerConfig::EnableTorrentFilter() const {
346+
return ParseBoolean(args_.get<std::string>("--enable-torrent-filter"));
347+
}
348+
349+
bool ServerConfig::EnableSpamFilter() const {
350+
return ParseBoolean(args_.get<std::string>("--enable-spam-filter"));
351+
}
352+
353+
bool ServerConfig::EnableDomainBlacklistFilter() const {
354+
return ParseBoolean(
355+
args_.get<std::string>("--enable-domain-blacklist-filter"));
284356
}
285357

286-
bool ServerConfig::DisableSpamFilter() const {
287-
return ParseBoolean(args_.get<std::string>("--disable-spam-filter"));
358+
std::vector<std::string> ServerConfig::DomainBlacklistUrls() const {
359+
return fptn::common::utils::SplitCommaSeparated(
360+
args_.get<std::string>("--domain-blacklist-urls"));
288361
}
289362

290363
std::string ServerConfig::DomainBlacklistFile() const {

src/fptn-server/config/server_config.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,13 @@ class ServerConfig {
4242
[[nodiscard]] std::uint32_t TunInterfaceNetworkIPv6Mask() const;
4343

4444
[[nodiscard]] std::string UserFile() const;
45-
[[nodiscard]] bool DisableTorrentFilter() const;
46-
[[nodiscard]] bool DisableSpamFilter() const;
45+
[[nodiscard]] bool EnableAdsFilter() const;
46+
[[nodiscard]] std::vector<std::string> AdsBlocklistUrls() const;
47+
[[nodiscard]] std::string DataDir() const;
48+
[[nodiscard]] bool EnableTorrentFilter() const;
49+
[[nodiscard]] bool EnableSpamFilter() const;
50+
[[nodiscard]] bool EnableDomainBlacklistFilter() const;
51+
[[nodiscard]] std::vector<std::string> DomainBlacklistUrls() const;
4752
[[nodiscard]] std::string DomainBlacklistFile() const;
4853
[[nodiscard]] std::string PrometheusAccessKey() const;
4954

0 commit comments

Comments
 (0)