diff --git a/README.md b/README.md
index 54f494b8f3..98a9fd513d 100644
--- a/README.md
+++ b/README.md
@@ -25,8 +25,8 @@
### 最新公告:
- 2024-02-25
-* 最新版5.9.9, 修复5.9.7智能策略更新的bug。
+ 2024-03-06
+* 最新版5.9.10, 更新黑名单列表。
* 5.9.0 升级GAE服务端到python3
* 5.8.8 改进iOS下连接性能
* 5.7.0 为X-Tunnel增加新通道
diff --git a/code/default/launcher/web_control.py b/code/default/launcher/web_control.py
index 71c549f730..bed1ee7bff 100644
--- a/code/default/launcher/web_control.py
+++ b/code/default/launcher/web_control.py
@@ -923,7 +923,7 @@ def req_log_files(self):
sys.path.append(x_tunnel_local)
from upload_logs import pack_logs
- data = pack_logs(10 * 1024 * 1024)
+ data = pack_logs(200 * 1024 * 1024)
self.send_response("application/zip", data)
def req_mem_info_handler(self):
diff --git a/code/default/lib/noarch/front_base/http1.py b/code/default/lib/noarch/front_base/http1.py
index b8e7f529b3..d4f207c1d2 100644
--- a/code/default/lib/noarch/front_base/http1.py
+++ b/code/default/lib/noarch/front_base/http1.py
@@ -68,8 +68,9 @@ def request(self, task):
def keep_alive_thread(self):
while time.time() - self.ssl_sock.create_time < self.config.http1_first_ping_wait:
if not self.keep_running:
- self.close("exit ")
+ self.close("exit")
return
+
time.sleep(3)
if self.config.http1_first_ping_wait and self.processed_tasks == 0:
@@ -87,7 +88,7 @@ def keep_alive_thread(self):
elif self.config.http1_idle_time:
while self.keep_running:
- time_to_sleep = max(self.config.http1_idle_time - (time.time() - self.last_recv_time), 0.2)
+ time_to_sleep = max(self.config.http1_idle_time - (time.time() - self.last_recv_time), 3)
time.sleep(time_to_sleep)
if not self.request_onway and time.time() - self.last_recv_time > self.config.http1_idle_time:
@@ -113,7 +114,6 @@ def work_loop(self):
self.close("keep alive")
return
- self.last_recv_time = time.time()
continue
# self.logger.debug("http1 get task")
@@ -127,7 +127,6 @@ def work_loop(self):
self.request_task(task)
self.request_onway = False
self.last_send_time = time_now
- self.last_recv_time = time_now
life_end_reason = self.is_life_end()
if life_end_reason:
@@ -138,7 +137,6 @@ def request_task(self, task):
timeout = task.timeout
self.request_onway = True
start_time = time.time()
- self.last_recv_time = start_time
self.record_active("request")
task.set_state("h1_req")
@@ -160,10 +158,11 @@ def request_task(self, task):
sended = self.ssl_sock.send(task.body[start:start + send_size])
start += sended
- task.set_state("h1_req_sended")
+ task.set_state("h1_req_sent")
except Exception as e:
- self.logger.warn("%s h1_request send:%r inactive_time:%d task.timeout:%d",
- self.ip_str, e, time.time() - self.last_recv_time, task.timeout)
+ self.logger.warn("%s %s h1_request send:%r inactive_time:%d task.timeout:%d",
+ self.ip_str, self.ssl_sock.getsockname(),
+ e, time.time() - self.last_recv_time, task.timeout)
self.logger.warn('%s trace:%s', self.ip_str, self.get_trace())
self.retry_task_cb(task)
@@ -175,6 +174,7 @@ def request_task(self, task):
response = simple_http_client.Response(self.ssl_sock)
response.begin(timeout=timeout)
task.set_state("response_begin")
+ self.last_recv_time = time.time()
except Exception as e:
self.logger.warn("%s h1_request recv:%r inactive_time:%d task.timeout:%d",
self.ip_str, e, time.time() - self.last_recv_time, task.timeout)
@@ -201,7 +201,7 @@ def request_task(self, task):
task.queue.put(response)
else:
if self.config.http2_show_debug:
- self.logger.debug("got pong for %s status:%d", self.ip_str, response.status)
+ self.logger.debug("got res for %s status:%d", self.ip_str, response.status)
try:
read_target = int(response.content_length)
@@ -290,6 +290,7 @@ def head_request(self):
self.record_active("head end")
rtt = (time.time() - start_time) * 1000
self.update_rtt(rtt)
+ self.last_recv_time = time.time()
return True
except Exception as e:
self.logger.warn("h1 %s HEAD keep alive request fail:%r", self.ssl_sock.ip_str, e)
diff --git a/code/default/lib/noarch/front_base/http_common.py b/code/default/lib/noarch/front_base/http_common.py
index 5ebd465365..bb946183d0 100644
--- a/code/default/lib/noarch/front_base/http_common.py
+++ b/code/default/lib/noarch/front_base/http_common.py
@@ -217,7 +217,7 @@ def __init__(self, logger, ip_manager, config, ssl_sock, close_cb, retry_task_cb
self.last_send_time = self.ssl_sock.create_time
self.life_end_time = self.ssl_sock.create_time + \
random.randint(self.config.connection_max_life, int(self.config.connection_max_life * 1.5))
- # self.logger.debug("worker.init %s", self.ip_str)
+ # self.logger.debug("worker.init %s %s", self.ip_str, self.ssl_sock.getsockname())
def __str__(self):
o = ""
diff --git a/code/default/smart_router/local/dns_query.py b/code/default/smart_router/local/dns_query.py
index c2645f722d..f8c4d1055c 100644
--- a/code/default/smart_router/local/dns_query.py
+++ b/code/default/smart_router/local/dns_query.py
@@ -635,6 +635,10 @@ def query_blocked_domain(self, domain, dns_type):
])
def query_unknown_domain(self, domain, dns_type):
+ res = self.local_dns_resolve.query(domain, dns_type)
+ if res:
+ return res
+
return self.parallel_query.query(domain, dns_type, [
self.https_query.query,
self.tls_query.query,
@@ -662,7 +666,7 @@ def query(self, domain, dns_type=1, history=[]):
xlog.debug("DNS query:%s in black", domain)
return ips
- elif b"." not in domain or g.gfwlist.in_white_list(domain) or rule in ["direct"]:
+ elif b"." not in domain or g.gfwlist.in_white_list(domain) or rule in ["direct"] or g.config.pac_policy == "all_Direct":
ips = self.local_dns_resolve.query(domain, timeout=1)
g.domain_cache.set_ips(domain, ips, dns_type)
return ips
diff --git a/code/default/smart_router/local/gfw_white_list.txt b/code/default/smart_router/local/gfw_white_list.txt
index a478c62ad1..b4cbfa5083 100644
--- a/code/default/smart_router/local/gfw_white_list.txt
+++ b/code/default/smart_router/local/gfw_white_list.txt
@@ -6,6 +6,7 @@
178.com
2345.com
360safe.com
+51.la
56.com
5eplay.com
5ewin.com
@@ -26,6 +27,7 @@ alipay.com
alipayobjects.com
alivecdn.com
aliyuncs.com
+aliyunddos1030.com
allrace.com
amap.com
amemv.com
@@ -53,6 +55,10 @@ bokecs.net
bootcss.com
btigroup.io
bytedance.com
+bytedns1.com
+bytefcdn.com
+byteimg.com
+bytegecko.co
cccpan.com
cdncl.net
chiphell.com
@@ -76,6 +82,8 @@ douyin.com
douyincdn.com
douyinliving.com
douyinpic.com
+douyinstatic.com.w.cdngslb.com
+douyinstatic.com.queniuuf.com
douyinvod.com
douyu.com
duoduocdn.com
@@ -125,6 +133,7 @@ kmf.com
ksyungslb.com
kugou.com
kuiniuca.com
+kunluncan.com
le.com
lecloud.com
leisu.com
@@ -174,6 +183,7 @@ qq-zuidazy.com
qq.com
qqmail.com
qtlglb.com
+queniusy.com
remuxhdr.com
ruioushang.com
sandai.net
@@ -207,6 +217,7 @@ ubuntu.com
uniqueway.com
umeng.com
videocc.net
+volcfcdndvs.com
vzan.cc
vzuu.com
wangyuan.com
diff --git a/code/default/smart_router/local/ip_region.py b/code/default/smart_router/local/ip_region.py
index e0bafa32e7..5d947f0034 100644
--- a/code/default/smart_router/local/ip_region.py
+++ b/code/default/smart_router/local/ip_region.py
@@ -119,7 +119,7 @@ def generate_db(self):
'198.51.100.0/24', # TEST-NET-2
'203.0.113.0/24', # TEST-NET-3
# 连续地址直到 IP 结束,特殊处理
- # '224.0.0.0/4', #组播地址(D类)
+ '224.0.0.0/4', #组播地址(D类)
# '240.0.0.0/4', #保留地址(E类)
)
keeplist = []
diff --git a/code/default/smart_router/local/pac_server.py b/code/default/smart_router/local/pac_server.py
index dc3509c03b..d0be0ce839 100644
--- a/code/default/smart_router/local/pac_server.py
+++ b/code/default/smart_router/local/pac_server.py
@@ -27,7 +27,7 @@
gae_ca_file = os.path.join(env_info.data_path, "gae_proxy", "CA.crt")
-allow_policy = ["black_GAE", "black_X-Tunnel", "smart-router", "all_X-Tunnel"]
+allow_policy = ["black_GAE", "black_X-Tunnel", "smart-router", "all_X-Tunnel", "all_Direct"]
def get_serving_pacfile():
@@ -52,6 +52,10 @@ def policy_all_to_proxy(self, host, port):
content = content.replace(self.PROXY_LISTEN, proxy)
return content
+ def policy_all_to_direct(self):
+ content = """function FindProxyForURL(url, host) { return 'DIRECT';}"""
+ return content
+
def policy_blacklist_to_proxy(self, host, port):
content = get_serving_pacfile()
@@ -89,6 +93,8 @@ def do_GET(self):
content = self.policy_blacklist_to_proxy(host, "%s" % g.x_tunnel_socks_port)
elif g.config.pac_policy == "all_X-Tunnel":
content = self.policy_all_to_proxy(host, "%s" % g.x_tunnel_socks_port)
+ elif g.config.pac_policy == "all_Direct":
+ content = self.policy_all_to_direct()
else:
content = self.policy_all_to_proxy(host, g.config.proxy_port)
diff --git a/code/default/smart_router/local/pipe_socks.py b/code/default/smart_router/local/pipe_socks.py
index c6b3f35d9c..56905e535e 100644
--- a/code/default/smart_router/local/pipe_socks.py
+++ b/code/default/smart_router/local/pipe_socks.py
@@ -1,6 +1,8 @@
import threading
import time
import sys
+import socket
+import errno
from xx_six import BlockingIOError
import utils
@@ -214,18 +216,21 @@ def flush_send_s(s2, d1):
try:
d = s1.recv(65535)
+ except BlockingIOError as e:
+ xlog.debug("%s recv BlockingIOError:%r", s1, e)
+ continue
except Exception as e:
- # xlog.debug("%s recv e:%r", s1, e)
+ xlog.debug("%s recv e:%r", s1, e)
self.close(s1, "r")
continue
if not d:
# socket closed by peer.
- # xlog.debug("%s recv empty, close", s1)
+ xlog.debug("%s recv empty, close", s1)
self.close(s1, "r")
continue
- # xlog.debug("direct received %d bytes from:%s", len(d), s1)
+ xlog.debug("direct received %d bytes from:%s", len(d), s1)
s1.recved_data += len(d)
s1.recved_times += 1
@@ -253,6 +258,10 @@ def flush_send_s(s2, d1):
flush_send_s(s2, d1)
s2.sent_data += len(d1)
s2.sent_times += 1
+ except BlockingIOError as e:
+ xlog.warn("Except %s flush_send_s BlockingIOError %r", s2, e)
+ self.close(s2, "w")
+ continue
except Exception as e:
xlog.warn("send split SNI:%s fail:%r", s2.host, e)
self.close(s2, "w")
@@ -268,12 +277,24 @@ def flush_send_s(s2, d1):
s2.sent_data += sent
s2.sent_times += 1
# xlog.debug("direct send %d to %s from:%s total:%d", sent, s2, s1, len(d))
+ except BlockingIOError as e:
+ xlog.warn("Except %s send BlockingIOError %r", s2, e)
+ sent = 0
+ except socket.error as e:
+ if e.errno == errno.EAGAIN:
+ # if str(e) == "[Errno 35] Resource temporarily unavailable":
+ xlog.warn("%s send errno.EAGAIN %r", s2, e)
+ time.sleep(0.1)
+ sent = 0
+ else:
+ self.close(s2, "w")
+ continue
except Exception as e:
# xlog.debug("%s send e:%r", s2, e)
if sys.version_info[0] == 3 and isinstance(e, BlockingIOError):
# This error happened on upload large file or speed test
# Just ignore this error and will be fine
- # xlog.warn("%s send BlockingIOError %r", s2, e)
+ xlog.warn("%s send BlockingIOError %r", s2, e)
sent = 0
else:
# xlog.warn("%s send except:%r", s2, e)
@@ -320,11 +341,23 @@ def flush_send_s(s2, d1):
s1.sent_data += sent
s1.sent_times += 1
# xlog.debug("send buffered %d bytes to %s", sent, s1)
+ except BlockingIOError as e:
+ xlog.warn("Except %s send BlockingIOError %r", s1, e)
+ sent = 0
+ except socket.error as e:
+ if e.errno == errno.EAGAIN:
+ # if str(e) == "[Errno 35] Resource temporarily unavailable":
+ xlog.warn("%s send errno.EAGAIN %r", s1, e)
+ time.sleep(0.1)
+ sent = 0
+ else:
+ self.close(s1, "w")
+ continue
except Exception as e:
if sys.version_info[0] == 3 and isinstance(e, BlockingIOError):
# This error happened on upload large file or speed test
# Just ignore this error and will be fine
- # xlog.debug("%s sent BlockingIOError %r", s1, e)
+ xlog.debug("%s sent BlockingIOError %r", s1, e)
sent = 0
else:
# xlog.debug("%s sent e:%r", s1, e)
diff --git a/code/default/smart_router/local/smart_route.py b/code/default/smart_router/local/smart_route.py
index 75224bead7..a143fbbaad 100644
--- a/code/default/smart_router/local/smart_route.py
+++ b/code/default/smart_router/local/smart_route.py
@@ -497,6 +497,8 @@ def handle_ip_proxy(sock, ip, port, client_address):
rule = "direct"
elif g.config.pac_policy == "all_X-Tunnel":
rule = "socks"
+ elif g.config.pac_policy == "all_Direct":
+ rule = "direct"
if rule:
return try_loop("ip user", [rule], sock, ip, port, client_address)
@@ -556,6 +558,8 @@ def handle_domain_proxy(sock, host, port, client_address, left_buf=""):
rule = "gae"
elif utils.check_ip_valid(host) and utils.is_private_ip(host):
rule = "direct"
+ elif g.config.pac_policy == "all_Direct":
+ rule = "direct"
if not rule and (g.config.bypass_speedtest and g.gfwlist.in_speedtest_whitelist(host)):
xlog.debug("speedtest %s", host)
diff --git a/code/default/smart_router/scripts/update_domain_list.py b/code/default/smart_router/scripts/update_domain_list.py
new file mode 100644
index 0000000000..9fc4b000b0
--- /dev/null
+++ b/code/default/smart_router/scripts/update_domain_list.py
@@ -0,0 +1,63 @@
+import os
+import sys
+from os.path import join
+
+current_path = os.path.dirname(os.path.abspath(__file__))
+local_path = os.path.abspath( os.path.join(current_path, os.pardir, "local"))
+root_path = os.path.abspath(os.path.join(current_path, os.pardir, os.pardir))
+noarch_path = join(root_path, "lib", "noarch")
+sys.path.append(noarch_path)
+
+
+import simple_http_client
+import utils
+
+
+def download_list(url):
+ res = simple_http_client.request("GET", url)
+ content = res.text
+ return utils.to_str(content)
+
+
+def parse_list(content):
+ black_suffix = []
+ black_keyword = []
+ black_ipmask = []
+ for line in content.split():
+ if not line or line.startswith("#"):
+ continue
+
+ if line.startswith("DOMAIN-SUFFIX,") and line.endswith(",Proxy"):
+ _, suffix, _ = line.split(",")[0:3]
+ black_suffix.append(suffix)
+
+ if line.startswith("DOMAIN-KEYWORD,") and line.endswith(",Proxy"):
+ _, keyword, _ = line.split(",")[0:3]
+ black_keyword.append(keyword)
+
+ if line.startswith("IP-CIDR,") and line.endswith(",Proxy"):
+ _, ipmask, _ = line.split(",")[0:3]
+ black_ipmask.append(ipmask)
+
+ black_suffix.sort()
+ black_keyword.sort()
+ black_ipmask.sort()
+
+ return black_suffix, black_keyword, black_ipmask
+
+
+def update_blacklist():
+ # url = "https://github.com/Johnshall/Shadowrocket-ADBlock-Rules-Forever/raw/release/sr_top500_banlist.conf"
+ url = "https://github.com/raw/Johnshall/Shadowrocket-ADBlock-Rules-Forever/release/sr_top500_banlist.conf"
+ content = download_list(url)
+ black_suffix, black_keyword, black_ipmask = parse_list(content)
+
+ with open(join(local_path, "gfw_black_list.txt"), "w") as fd:
+ fd.write("\r\n".join(black_suffix))
+
+ with open(join(local_path, "gfw_black_keywords.txt"), "w") as fd:
+ fd.write("\r\n".join(black_keyword))
+
+
+if __name__ == "__main__":
+ update_blacklist()
diff --git a/code/default/smart_router/tests/test_black_list.py b/code/default/smart_router/tests/test_black_list.py
new file mode 100644
index 0000000000..9c2cce2d77
--- /dev/null
+++ b/code/default/smart_router/tests/test_black_list.py
@@ -0,0 +1,40 @@
+import os
+from os.path import join
+import sys
+import unittest
+
+
+current_path = os.path.dirname(os.path.abspath(__file__))
+smart_route_path = os.path.abspath(os.path.join(current_path, os.path.pardir))
+local_path = os.path.join(smart_route_path, "local")
+sys.path.append(local_path)
+
+default_path = os.path.abspath(join(smart_route_path, os.path.pardir))
+noarch_path = join(default_path, "lib", "noarch")
+sys.path.append(noarch_path)
+
+import gfwlist
+
+
+class TestGFW(unittest.TestCase):
+ def test_Ip_Mask(self):
+ ip = "1.2.3.4"
+ ip_mask = "1.2.3.0/24"
+ ip_masks = [ip_mask]
+ subnets = gfwlist.IpMask(ip_masks)
+ c = subnets.check_ip(ip)
+ print(c)
+
+ print(subnets.check_ip("1.2.3.5"))
+ print(subnets.check_ip("1.2.4.5"))
+ print(subnets.check_ip("1.3.4.5"))
+
+ def test_domain(self):
+ gfw = gfwlist.GfwList()
+ print(gfw.ip_in_black_list("91.108.56.1"))
+ print(gfw.ip_in_black_list("1.1.1.1"))
+
+ def test_keyword(self):
+ gfw = gfwlist.GfwList()
+ print(gfw.in_block_list(b"www.amazon.com"))
+ print(gfw.in_block_list(b"www.apple.com"))
diff --git a/code/default/smart_router/tests/test_set_policy.py b/code/default/smart_router/tests/test_set_policy.py
new file mode 100644
index 0000000000..fba166814a
--- /dev/null
+++ b/code/default/smart_router/tests/test_set_policy.py
@@ -0,0 +1,46 @@
+import requests
+import re
+from unittest import TestCase
+
+
+class TestSetPolicy(TestCase):
+ def test_set_global(self):
+ url = "http://localhost:8085/module/smart_router/control/config"
+ headers = {
+ "Content-Type": "application/json"
+ }
+ data = {
+ "cmd": "set",
+ "pac_policy": "all_X-Tunnel"
+ }
+ r = requests.post(url, json=data, headers=headers)
+ print(r.text)
+
+ def test_set_smart(self):
+ url = "http://localhost:8085/module/smart_router/control/config"
+ headers = {
+ "Content-Type": "application/json"
+ }
+ data = {
+ "cmd": "set",
+ "pac_policy": "smart-router"
+ }
+ r = requests.post(url, json=data, headers=headers)
+ print(r.text)
+
+ def test_match(self):
+ r = re.compile("google|apple")
+ s1 = "www.google.com"
+ s2 = "www.apple.com"
+ s3 = "www.ms.com"
+ g1 = r.search(s1)
+ print(g1)
+ g2 = r.search(s2)
+ print(g2)
+ g3 = r.search(s3)
+ print(g3)
+
+ def test_re(self):
+ strs = 'Test result 1: Not Ok -31.08'
+ g = re.search(r'\bNot Ok\b', strs).group(0)
+ print(g)
\ No newline at end of file
diff --git a/code/default/smart_router/web_ui/config_general.html b/code/default/smart_router/web_ui/config_general.html
index 1c3a25a24a..8eb0374d68 100644
--- a/code/default/smart_router/web_ui/config_general.html
+++ b/code/default/smart_router/web_ui/config_general.html
@@ -23,6 +23,7 @@
+
diff --git a/code/default/version.txt b/code/default/version.txt
index 76d1514dde..c55621169c 100644
--- a/code/default/version.txt
+++ b/code/default/version.txt
@@ -1 +1 @@
-5.9.9
\ No newline at end of file
+5.9.10
\ No newline at end of file
diff --git a/code/default/x_tunnel/local/proxy_handler.py b/code/default/x_tunnel/local/proxy_handler.py
index 1bdca22898..95dfba1ea9 100644
--- a/code/default/x_tunnel/local/proxy_handler.py
+++ b/code/default/x_tunnel/local/proxy_handler.py
@@ -268,7 +268,7 @@ def socks5_handler(self):
conn_id = proxy_session.create_conn(sock, addr, port)
if not conn_id:
- xlog.warn("create conn fail")
+ xlog.warn("socks5 create conn to %s:%d fail", addr, port)
reply = b"\x05\x01\x00" + addrtype_pack + addr_pack + struct.pack(">H", port)
sock.send(reply)
return
@@ -314,7 +314,7 @@ def https_handler(self):
sock = self.connection
conn_id = proxy_session.create_conn(sock, host, port)
if not conn_id:
- xlog.warn("create conn fail")
+ xlog.warn("https create conn to %s:%d fail", host, port)
sock.send(b'HTTP/1.1 500 Fail\r\n\r\n')
return
@@ -378,7 +378,7 @@ def http_handler(self, first_char):
sock = self.connection
conn_id = proxy_session.create_conn(sock, host, port)
if not conn_id:
- xlog.warn("create conn fail")
+ xlog.warn("http create conn to %s:%d fail", host, port)
sock.send(b'HTTP/1.1 500 Fail\r\n\r\n')
return
diff --git a/code/default/x_tunnel/local/seley_front/rc4_wrap.py b/code/default/x_tunnel/local/seley_front/rc4_wrap.py
index 72b536aee0..344f4dfa62 100644
--- a/code/default/x_tunnel/local/seley_front/rc4_wrap.py
+++ b/code/default/x_tunnel/local/seley_front/rc4_wrap.py
@@ -3,6 +3,7 @@
import struct
import json
import os
+import errno
import env_info
import xlog
@@ -110,6 +111,9 @@ def is_support_h2(self):
def setblocking(self, block):
self._sock.setblocking(block)
+ def getsockname(self):
+ self._sock.getsockname()
+
def __getattr__(self, attr):
if attr == "socket_closed":
# work around in case close before finished init.
@@ -144,11 +148,19 @@ def connect(self, *args, **kwargs):
def send(self, data, flags=0):
data = self.encode(data)
- try:
- return self._sock.send(data)
- except Exception as e:
- #self.logger.exception("ssl send:%r", e)
- raise e
+ while True:
+ try:
+ bytes_sent = self._sock.send(data)
+ return bytes_sent
+ except BlockingIOError as e:
+ time.sleep(0.1)
+ continue
+ except socket.error as e:
+ if e.errno == errno.EAGAIN:
+ # if str(e) == "[Errno 35] Resource temporarily unavailable":
+ time.sleep(0.1)
+ else:
+ raise e
def recv(self, bufsiz, flags=0):
data = self._sock.recv(bufsiz)
diff --git a/code/default/x_tunnel/local/web_control.py b/code/default/x_tunnel/local/web_control.py
index e96a17dfe6..cf561a0594 100644
--- a/code/default/x_tunnel/local/web_control.py
+++ b/code/default/x_tunnel/local/web_control.py
@@ -275,6 +275,7 @@ def req_token_login_handler(self):
"reason": "Password format fail"
})
+ g.config.api_server = g.config.default_config["api_server"]
if g.config.update_cloudflare_domains and cloudflare_domains:
g.http_client.save_cloudflare_domain(cloudflare_domains)
if g.tls_relay_front and tls_relay.get("ips"):
diff --git a/code/default/x_tunnel/tests/test_proxy.py b/code/default/x_tunnel/tests/test_proxy.py
new file mode 100644
index 0000000000..6bfb049d54
--- /dev/null
+++ b/code/default/x_tunnel/tests/test_proxy.py
@@ -0,0 +1,129 @@
+from unittest import TestCase
+import json
+import os
+import time
+import sys
+
+current_path = os.path.dirname(os.path.abspath(__file__))
+default_path = os.path.abspath(os.path.join(current_path, os.path.pardir, os.path.pardir))
+root_path = os.path.abspath(os.path.join(default_path, os.path.pardir, os.path.pardir))
+
+noarch_lib = os.path.abspath(os.path.join(default_path, 'lib', 'noarch'))
+sys.path.append(noarch_lib)
+
+import utils
+import simple_http_server
+from dnslib.dns import DNSRecord, DNSHeader, DNSQuestion
+import socket
+
+import simple_http_client
+from xlog import getLogger
+xlog = getLogger("test")
+
+
+class ProxyTest(TestCase):
+ def __init__(self):
+ super().__init__()
+
+ def test_xtunnel_logout(self):
+ xlog.info("Start testing XTunnel logout")
+ res = simple_http_client.request("POST", "http://127.0.0.1:8085/module/x_tunnel/control/logout", timeout=10)
+ self.assertEqual(res.status, 200)
+ self.xtunnel_login_status = False
+ xlog.info("Finished testing XTunnel logout")
+
+ def smart_route_proxy_http(self):
+ xlog.info("Start testing SmartRouter HTTP proxy protocol")
+ proxy = "http://localhost:8086"
+ res = simple_http_client.request("GET", "https://github.com/", proxy=proxy, timeout=20)
+ self.assertEqual(res.status, 200)
+ xlog.info("Finished testing SmartRouter HTTP proxy protocol")
+
+ def smart_route_proxy_socks4(self):
+ xlog.info("Start testing SmartRouter SOCKS4 proxy protocol")
+ proxy = "socks4://localhost:8086"
+ res = simple_http_client.request("GET", "https://github.com/", proxy=proxy, timeout=15)
+ self.assertEqual(res.status, 200)
+ xlog.info("Finished testing SmartRouter SOCKS4 proxy protocol")
+
+ def smart_route_proxy_socks5(self):
+ xlog.info("Start testing SmartRouter SOCKS5 proxy protocol")
+ proxy = "socks5://localhost:8086"
+ res = simple_http_client.request("GET", "https://github.com/", proxy=proxy, timeout=15)
+ self.assertEqual(res.status, 200)
+ xlog.info("Finished testing SmartRouter SOCKS5 proxy protocol")
+
+ def smart_route_dns_query(self):
+ xlog.info("Start testing SmartRouter DNS Query")
+ domain = "appsec.hicloud.com"
+ d = DNSRecord(DNSHeader(123))
+ d.add_question(DNSQuestion(domain, 1))
+ req4_pack = d.pack()
+
+ for port in [8053, 53]:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.sendto(req4_pack, ("127.0.0.1", port))
+ sock.settimeout(5)
+
+ try:
+ response, server = sock.recvfrom(8192)
+ except Exception as e:
+ xlog.warn("recv fail for port:%s e:%r", port, e)
+ continue
+
+ p = DNSRecord.parse(response)
+ for r in p.rr:
+ ip = utils.to_bytes(str(r.rdata))
+ xlog.info("IP:%s" % ip)
+ self.assertEqual(utils.check_ip_valid(ip), True)
+
+ xlog.info("Finished testing SmartRouter DNS Query")
+ return
+
+ def xtunnel_token_login(self):
+ xlog.info("Start testing XTunnel login")
+ headers = {
+ "Content-Type": "application/json"
+ }
+ data = {
+ "login_token": os.getenv("XTUNNEL_TOKEN"),
+ }
+ data = json.dumps(data)
+ res = simple_http_client.request("POST", "http://127.0.0.1:8085/module/x_tunnel/control/token_login",
+ headers=headers, body=data, timeout=60)
+ self.assertEqual(res.status, 200)
+ self.xtunnel_login_status = True
+ xlog.info("Finished testing XTunnel login")
+
+ def test_xtunnel_proxy_http(self):
+ xlog.info("Start testing XTunnel HTTP proxy protocol")
+ # if not self.xtunnel_login_status:
+ # self.xtunnel_token_login()
+ proxy = "http://localhost:1080"
+ for _ in range(3):
+ res = simple_http_client.request("GET", "https://github.com/", proxy=proxy, timeout=30)
+ if not res:
+ time.sleep(5)
+ continue
+ self.assertEqual(res.status, 200)
+ xlog.info("Finished testing XTunnel HTTP proxy protocol")
+
+ self.assertEqual(res.status, 200)
+
+ def xtunnel_proxy_socks4(self):
+ xlog.info("Start testing XTunnel Socks4 proxy protocol")
+ if not self.xtunnel_login_status:
+ self.xtunnel_token_login()
+ proxy = "socks4://localhost:1080"
+ res = simple_http_client.request("GET", "https://github.com/", proxy=proxy, timeout=15)
+ self.assertEqual(res.status, 200)
+ xlog.info("Finished testing XTunnel Socks4 proxy protocol")
+
+ def xtunnel_proxy_socks5(self):
+ xlog.info("Start testing XTunnel Socks5 proxy protocol")
+ if not self.xtunnel_login_status:
+ self.xtunnel_token_login()
+ proxy = "socks5://localhost:1080"
+ res = simple_http_client.request("GET", "https://github.com/", proxy=proxy, timeout=15)
+ self.assertEqual(res.status, 200)
+ xlog.info("Finished testing XTunnel Socks5 proxy protocol")