Skip to content

Commit 1f9a973

Browse files
WillowSauceRWillowSauceR
authored andcommitted
Support IPv6 & Add tool recv.py
1 parent efe565c commit 1f9a973

File tree

6 files changed

+87
-24
lines changed

6 files changed

+87
-24
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@
55

66
## 直接在 [Releases](https://github.com/WillowSauceR/BedrockProtocolTools/releases/latest) 页面下载最新的版本,然后解压打开其中的exe文件进行使用
77

8-
## 或者使用 ``git clone https://github.com/WillowSauceR/BedrockProtocolTools``将本项目克隆到本地或直接下载本项目,然后使用python3来运
8+
## 或者使用 ``git clone https://github.com/WillowSauceR/BedrockProtocolTools``将本项目克隆到本地或直接下载本项目,然后使用Python3来运行
99

1010
## 行每个工具都可以单独使用参数 ``-h``来获取英文帮助,如 ``python3 scan.py -h``
1111

1212
## scan.py
1313

14-
### 使用方法: ``python3 scan.py [目标地址] -i [可选:发包间隔] -p [可选:本地端口] -do [可选:只显示玩家在线数量大于或等于此数值的服务器] -e [在扫描到服务器后立刻执行的cmd命令,需要用双引号包含,具体使用请使用 -h 参数获取帮助]``
14+
### 使用方法: ``python3 scan.py [目标地址] -i [可选:发包间隔] -p [可选:本地端口] -do [可选:只显示玩家在线数量大于或等于此数值的服务器] -e [在扫描到服务器后立刻执行的cmd命令,需要用双引号包含,具体使用请使用 -h 参数获取帮助] -v6 [使用IPv6协议]``
1515

1616
#### 描述: 扫描IP上的所有BE协议服务器
1717

1818
#### 注意:目标地址可以填域名,IP或者IP段。如 mc.163.com,11.4.5.14,191.191.81-255.0-255
1919

2020
## send.py
2121

22-
### 使用方法: ``python3 send.py [目标地址] [载体包文件] -p [可选:端口:默认19132] -l [可选:次数,默认1] -i [可选:间隔:秒,默认10] -d(自动显示MOTD) -pu(使用代理) -pc [代理的国家,如cn, ru, us] -q [安静模式,不输出任何日志]``
22+
### 使用方法: ``python3 send.py [目标地址] [载体包文件] -p [可选:端口:默认19132] -l [可选:次数,默认1] -i [可选:间隔:秒,默认10] -d(自动显示MOTD) -pu(使用代理) -pc [代理的国家,如cn, ru, us] -v6 [使用IPv6协议] -q [安静模式,不输出任何日志]``
2323

2424
#### 描述: 发包复现工具, 需要一个内含byte数据的文件,一般为.dmp后缀名
2525

@@ -32,3 +32,9 @@
3232
### 使用方法: ``python3 motd.py [目标地址] [端口] -t [可选:超时时间]``
3333

3434
#### 描述: motd一个BE服务器,支持自动解析返回的数据
35+
36+
## recv.py
37+
38+
### 使用方法:``python3 recv.py -i [可选:本地地址] -p [可选:本地端口] -v6 [可选:使用IPv6协议] -de [可选:关闭错误显示]``
39+
40+
#### 描述:在指定的地址和端口上接受UDP数据包并打印其原始数据到控制台

api.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import socket
22
import time
3-
import sys
43
import random
54

65
MOTD_PKT = b'\x01\x00\x00\x00\x00$\r\x12\xd3\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x124Vx\n'
@@ -25,17 +24,13 @@ def log(*content, level: str = "INFO", info: str = "", quiet: bool = False):
2524
if quiet:
2625
return
2726
date = time.strftime('%H:%M:%S')
28-
strs = ""
29-
for string in content:
30-
strs += str(string)
31-
content = strs[0:]
3227
if info != "":
33-
print(f"[{date} {info}] {content}")
28+
print(f"[{date} {info}] ", *content, sep="")
3429
else:
35-
print(f"[{date}] {content}")
30+
print(f"[{date}] ", *content, sep="")
3631

3732

38-
def get_ip_list(addr: str):
33+
def get_ip_list(addr: str) -> list:
3934
# ip = "42.186.0-255.0-255" -> len(ip_list) == 65536
4035
try:
4136
int(addr[-1])
@@ -65,7 +60,7 @@ def get_ip_list(addr: str):
6560
return ip_list
6661

6762

68-
def decode_unicode(string: str):
63+
def decode_unicode(string: str) -> str:
6964
is_special_unicode = False
7065
for index in range(0, len(string), 5):
7166
if string[index] != "u":
@@ -85,14 +80,28 @@ def decode_unicode(string: str):
8580
return string.encode("utf-8").decode("unicode-escape")
8681

8782

88-
def get_udp_socket(port=random.randint(1024, 65535), timeout: int=1) -> socket.socket:
89-
if not port:
90-
port = random.randint(1024, 65535)
91-
sockets = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
92-
sockets.settimeout(timeout)
93-
sockets.bind(("", port))
83+
def get_udp_socket(loc_port=random.randint(1024, 65535), timeout: int=1, use_ipv6: bool=False, loc_addr: str="") -> socket.socket:
84+
if not loc_port:
85+
loc_port = random.randint(1024, 65535)
86+
if use_ipv6:
87+
sockets = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
88+
else:
89+
sockets = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
90+
if timeout:
91+
sockets.settimeout(timeout)
92+
sockets.bind((loc_addr, loc_port))
9493
return sockets
9594

95+
def is_ipv6_addr(addr: str) -> bool:
96+
try:
97+
addr = socket.gethostbyname(addr)
98+
except socket.gaierror:
99+
pass
100+
try:
101+
socket.inet_pton(socket.AF_INET6, addr)
102+
return True
103+
except socket.error:
104+
return False
96105

97106
def parse_raw_pkt(pkt):
98107
server_data, addr = pkt

motd.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import argparse
22
import socket
3-
from api import get_udp_socket, log, parse_raw_pkt, MOTD_PKT
3+
from api import get_udp_socket, is_ipv6_addr, log, parse_raw_pkt, MOTD_PKT
44

55

66
def send_pkt(addr, port, timeout: float=3.0, local_port: int=None):
7-
udp_skt = get_udp_socket(local_port, timeout)
7+
udp_skt = get_udp_socket(local_port, timeout, is_ipv6_addr(addr))
88
udp_skt.sendto(
99
MOTD_PKT,
1010
(addr, port))

recv.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import argparse
2+
from threading import Thread
3+
from api import get_udp_socket, log
4+
5+
6+
def recv_pkt(loc_addr, loc_port, disable_errors=False):
7+
udp_skt = get_udp_socket(loc_port=loc_port, timeout=0, use_ipv6=use_ipv6, loc_addr=loc_addr)
8+
err_count = 0
9+
while True:
10+
try:
11+
data, addr = udp_skt.recvfrom(10240)
12+
log(data, info=addr)
13+
except Exception as exc:
14+
err_count += 1
15+
log(exc, level="ERROR", info=err_count, quiet=disable_errors)
16+
17+
18+
if __name__ == "__main__":
19+
parser = argparse.ArgumentParser()
20+
parser.add_argument("-i", "--address", type=str,
21+
default="", help="local address to bind")
22+
parser.add_argument("-p", "--port", type=int,
23+
default=19132, help="local port to bind")
24+
parser.add_argument("-v6", "--use-ipv6", action="store_true",
25+
default=False, help="use IPv6 instead of IPv4")
26+
parser.add_argument("-de", "--disable-errors", action="store_true",
27+
default=False, help="disable error message output")
28+
args = parser.parse_args()
29+
30+
loc_addr = args.address
31+
loc_port = args.port
32+
use_ipv6 = args.use_ipv6
33+
disable_errors = args.disable_errors
34+
35+
log(f"Starting listening {loc_addr}:{loc_port}, type q to exit.")
36+
Thread(target=recv_pkt, args=(loc_addr, loc_port, disable_errors), daemon=True).start()
37+
while True:
38+
if input() == "q":
39+
log("Exit...")
40+
exit()

scan.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ def exec_cmd_async(cmd: str, variables: dict = [None]) -> None:
137137
help="the cmd command that is executed immediately after scanning the server can use {var} as a variable, "
138138
+ "the command needs to be enclosed in double quotes, the available variables are: motd, version_id, "
139139
+ "version, online, max_player, unique_id, map, gamemode, source_port_v4, source_port_v6, addr and ip")
140+
parser.add_argument("-v6", "--use-ipv6", action="store_true", default=False,
141+
help="use IPv6 instead of IPv4")
140142

141143
args, unparsed = parser.parse_known_args()
142144

@@ -145,8 +147,9 @@ def exec_cmd_async(cmd: str, variables: dict = [None]) -> None:
145147
local_port = args.port
146148
display_online = args.display_online
147149
exec_cmd = args.exec_cmd
150+
use_ipv6 = args.use_ipv6
148151

149-
udp_skt = get_udp_socket(local_port)
152+
udp_skt = get_udp_socket(local_port, use_ipv6=use_ipv6)
150153

151154
for addr in get_ip_list(addr):
152155
scanner(udp_skt, addr, interval)

send.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import argparse
77

88
from motd import send_pkt as send_motd_pkt
9-
from api import get_udp_socket, log
9+
from api import get_udp_socket, is_ipv6_addr, log
1010

1111

1212
def get_proxy() -> list:
@@ -42,7 +42,7 @@ def create_socket():
4242
if proxy_used:
4343
log(f"Used proxy: {proxy_addr}:{proxy_port}")
4444
else:
45-
udp_skt = get_udp_socket(local_port)
45+
udp_skt = get_udp_socket(local_port, 1, use_ipv6)
4646
return local_port, udp_skt
4747

4848

@@ -91,6 +91,7 @@ def send_pkt(target_addr: str, port: int, payload_file: str, loops: int, interva
9191
parser.add_argument("-d", "--display_motd", action="store_true", default=False, help="Display Motd")
9292
parser.add_argument("-pu", "--proxy_used", action="store_true", default=False, help="Use Proxy")
9393
parser.add_argument("-pc", "--proxy_country", type=str, default="us", help="ProxyCountry (like cn, ru, us or enter to use all)")
94+
parser.add_argument("-v6", "--use-ipv6", action="store_true", default=False, help="use IPv6 instead of IPv4")
9495
args = parser.parse_args()
9596

9697
target = args.target
@@ -102,6 +103,7 @@ def send_pkt(target_addr: str, port: int, payload_file: str, loops: int, interva
102103
quiet_mode = args.quiet
103104
proxy_used = args.proxy_used
104105
proxyCountry = args.proxy_country
106+
use_ipv6 = args.use_ipv6
105107

106108
if proxy_used:
107109
try:
@@ -110,7 +112,10 @@ def send_pkt(target_addr: str, port: int, payload_file: str, loops: int, interva
110112
import requests
111113
except Exception as error:
112114
print(error)
113-
log("Import module error! Please run \"pip install -r requirements.txt\"")
115+
log("Import module error! Run \"pip install -r requirements.txt\" to install dependent modules? [y/n] ")
116+
if input() == "y":
117+
os.system("pip install -r requirements.txt")
118+
log("Success. Please restart this program!")
114119
os._exit(1)
115120
log("Proxy mode is under development!")
116121

0 commit comments

Comments
 (0)