Skip to content

Commit 7fa71a2

Browse files
author
Steven
committed
Initial commit
1 parent 2bbb990 commit 7fa71a2

File tree

3 files changed

+212
-0
lines changed

3 files changed

+212
-0
lines changed

byte_utils.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import struct
2+
3+
4+
def read_varint(byte, i):
5+
result = 0
6+
bytes = 0
7+
while True:
8+
try:
9+
byte_in = byte[i]
10+
i += 1
11+
result |= (byte_in & 0x7F) << (bytes * 7)
12+
if bytes > 32:
13+
raise IOError("Packet is too long!")
14+
if (byte_in & 0x80) != 0x80:
15+
return result, i
16+
except IndexError:
17+
print("A invalid byte array was requested!")
18+
19+
20+
def read_utf(byte, i):
21+
(length, i) = read_varint(byte, i)
22+
ip = byte[i:(i + length)].decode('utf-8')
23+
i += length
24+
return ip, i
25+
26+
27+
def read_ushort(byte, i):
28+
new_i = i + 2
29+
return struct.unpack(">H", byte[i:new_i]), new_i
30+
31+
32+
def read_long(byte, i):
33+
new_i = i + 8
34+
return struct.unpack(">q", byte[i:new_i]), new_i
35+
36+
37+
def write_varint(byte, value):
38+
part = None
39+
while True:
40+
part = value & 0x7F
41+
value >>= 7
42+
if value != 0:
43+
part |= 0x80
44+
byte.append(part)
45+
if value == 0:
46+
break
47+
48+
49+
def write_utf(byte, value):
50+
write_varint(byte, len(value))
51+
for b in value.encode():
52+
byte.append(b)

main.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env python3
2+
3+
import base64
4+
import json
5+
import os.path
6+
7+
from socket_server import SocketServer
8+
9+
server = None
10+
11+
12+
def main():
13+
if os.path.exists("config.json"):
14+
with open("config.json", 'r') as file:
15+
configuration = json.load(file)
16+
17+
ip = configuration["ip"]
18+
port = configuration["port"]
19+
motd = configuration["motd"]["1"] + "\n" + configuration["motd"]["2"]
20+
version_text = configuration["version_text"]
21+
kick_message = ""
22+
server_icon = None
23+
24+
for message in configuration["kick_message"]:
25+
kick_message += message + "\n"
26+
kick_message = kick_message[:-2]
27+
28+
if not os.path.exists(configuration["server_icon"]):
29+
print("Server icon doesn't exists - submitting none...")
30+
else:
31+
with open(configuration["server_icon"], 'rb') as image:
32+
server_icon = "data:image/png;base64," + base64.b64encode(image.read()).decode()
33+
try:
34+
global server
35+
server = SocketServer(ip, port, motd, version_text, kick_message, server_icon)
36+
server.start()
37+
except KeyboardInterrupt:
38+
server.close()
39+
exit(1)
40+
except Exception as e:
41+
print(e)
42+
else:
43+
configuration = {}
44+
configuration["ip"] = "0.0.0.0"
45+
configuration["port"] = 25565
46+
configuration["motd"] = {}
47+
configuration["motd"]["1"] = "§4Maintenance!"
48+
configuration["motd"]["2"] = "§aCheck example.com for more information!"
49+
configuration["version_text"] = "§4Maintenance"
50+
configuration["kick_message"] = ["§bSorry", "", "§aThis server is offline!"]
51+
configuration["server_icon"] = "server_icon.png"
52+
configuration["samples"] = ["§bexample.com", "", "§4Maintenance"]
53+
54+
with open("config.json", 'w') as file:
55+
json.dump(configuration, file, sort_keys=True, indent=4, ensure_ascii=False)
56+
57+
print("[!] A new configuration was created!")
58+
print("Please check the settings in the config.json!")
59+
exit(1)
60+
61+
62+
if __name__ == '__main__':
63+
main()

socket_server.py

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import _thread
2+
import json
3+
import socket
4+
import uuid
5+
6+
import byte_utils
7+
8+
9+
class SocketServer:
10+
ip = None
11+
port = None
12+
motd = None
13+
version_text = None
14+
kick_message = None
15+
samples = None
16+
server_icon = None
17+
s = None
18+
19+
def __init__(self, ip, port, motd, version_text, kick_message, samples, server_icon):
20+
self.ip = ip
21+
self.port = port
22+
self.motd = motd
23+
self.version_text = version_text
24+
self.kick_message = kick_message
25+
self.samples = samples
26+
self.server_icon = server_icon
27+
28+
def on_new_client(self, client_socket, addr):
29+
data = client_socket.recv(1024)
30+
(length, i) = byte_utils.read_varint(data, 0)
31+
(packetID, i) = byte_utils.read_varint(data, i)
32+
33+
if packetID == 0:
34+
(version, i) = byte_utils.read_varint(data, i)
35+
(ip, i) = byte_utils.read_utf(data, i)
36+
(port_tuple, i) = byte_utils.read_ushort(data, i)
37+
(state, i) = byte_utils.read_varint(data, i)
38+
if state == 1:
39+
print("%s:%s has pinged the server (%s:%s)" % (addr[0], addr[1], ip, port_tuple[0]))
40+
41+
motd = {}
42+
motd["version"] = {}
43+
motd["version"]["name"] = self.version_text
44+
motd["version"]["protocol"] = 2
45+
motd["players"] = {}
46+
motd["players"]["max"] = 0
47+
motd["players"]["online"] = 0
48+
motd["players"]["sample"] = []
49+
50+
for sample in self.samples:
51+
motd["players"]["sample"].append({"name": sample, "id": str(uuid.uuid4())})
52+
53+
motd["description"] = {"text": self.motd}
54+
55+
if len(self.server_icon) > 0:
56+
motd["favicon"] = self.server_icon
57+
58+
print(motd)
59+
60+
self.write_response(client_socket, json.dumps(motd))
61+
elif state == 2:
62+
print("%s:%s has tried to connect to the server (%s:%s)" % (addr[0], addr[1], ip, port_tuple[0]))
63+
self.write_response(client_socket, json.dumps({"text": self.kick_message}))
64+
else:
65+
print("%s:%s tried to request a login/ping with a unknown state: %s" % (addr[0], addr[1], state))
66+
elif packetID == 1:
67+
(long, i) = byte_utils.read_long(data, i)
68+
response = bytearray()
69+
byte_utils.write_varint(response, 9)
70+
byte_utils.write_varint(response, 1)
71+
bytearray.append(long)
72+
client_socket.sendall(bytearray)
73+
print("Send pong to %s" % addr)
74+
else:
75+
print("%s tried to request a unknown packet: %s" % (addr, packetID))
76+
77+
def write_response(self, client_socket, response):
78+
response_array = bytearray()
79+
byte_utils.write_varint(response_array, 0)
80+
byte_utils.write_utf(response_array, response)
81+
length = bytearray()
82+
byte_utils.write_varint(length, len(response_array))
83+
client_socket.sendall(length)
84+
client_socket.sendall(response_array)
85+
86+
def start(self):
87+
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
88+
self.s.bind((self.ip, self.port))
89+
self.s.settimeout(5000)
90+
self.s.listen(30)
91+
print("Server started!")
92+
while 1:
93+
(client, address) = self.s.accept()
94+
_thread.start_new_thread(self.on_new_client, (client, address,))
95+
96+
def close(self):
97+
self.s.close()

0 commit comments

Comments
 (0)