Implemet connless packing

This commit is contained in:
ChillerDragon 2023-05-10 12:31:27 +02:00
parent 04945c770a
commit ad8511d551
4 changed files with 49 additions and 14 deletions

View file

@ -113,14 +113,24 @@ def test_lis2_connless7():
server = msg.servers[0] server = msg.servers[0]
assert server.port == 8298 assert server.port == 8298
assert server.ipaddr == "5.78.73.17" # hetzner
server = msg.servers[1] server = msg.servers[1]
assert server.port == 8300 assert server.port == 8300
assert server.ipaddr == "5.78.73.17"
server = msg.servers[2] server = msg.servers[2]
assert server.port == 8303 assert server.port == 8303
assert server.ipaddr == "5.78.73.17"
server = msg.servers[3] server = msg.servers[3]
assert server.port == 8304 assert server.port == 8304
assert server.ipaddr == "5.78.73.17"
server = msg.servers[4] server = msg.servers[4]
assert server.port == 8305 assert server.port == 8305
assert server.ipaddr == "5.78.73.17"
# .. # ..
server = msg.servers[74] server = msg.servers[74]
assert server.port == 8346 assert server.port == 8346
assert server.ipaddr == "37.230.210.231" # rus4.ddnet.org
repack: bytes = packet.pack()
assert repack == data

View file

@ -1,11 +1,13 @@
from typing import Annotated from typing import Literal
class MastersrvAddr(): class MastersrvAddr():
def __init__( def __init__(
self, self,
ipaddr: Annotated[bytes, 16] = bytes(16), family: Literal[4, 6] = 4,
port: int = 0 ipaddr: str = '127.0.0.1',
port: int = 8303
) -> None: ) -> None:
self.ipaddr: Annotated[bytes, 16] = ipaddr self.family: Literal[4, 6] = family
self.ipaddr: str = ipaddr
self.port: int = port self.port: int = port

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
from typing import Final from typing import Final, Literal
from twnet_parser.master_server import MastersrvAddr from twnet_parser.master_server import MastersrvAddr
@ -46,8 +46,17 @@ class Unpacker():
servers: list[MastersrvAddr] = [] servers: list[MastersrvAddr] = []
while len(self.data()) >= 18: while len(self.data()) >= 18:
ipaddr = self.get_raw(16) ipaddr = self.get_raw(16)
ipv4_mapping = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF'
family: Literal[4, 6] = 4
addr_str: str = ''
if ipaddr[0:12] == ipv4_mapping:
addr_str = f"{ipaddr[12]}.{ipaddr[13]}.{ipaddr[14]}.{ipaddr[15]}"
else:
# TODO: make ipv6 nicer
addr_str = str(ipaddr)
family = 6
port = self.get_be_uint16() # TODO: i randomly assumed this would work port = self.get_be_uint16() # TODO: i randomly assumed this would work
servers.append(MastersrvAddr(ipaddr, int(port))) servers.append(MastersrvAddr(family, addr_str, int(port)))
return servers return servers
def get_uint8(self) -> int: def get_uint8(self) -> int:
@ -154,7 +163,13 @@ def pack_uint8(num: int) -> bytes:
def pack_packed_addresses(servers: list[MastersrvAddr]) -> bytes: def pack_packed_addresses(servers: list[MastersrvAddr]) -> bytes:
res: bytes = b'' res: bytes = b''
for server in servers: for server in servers:
res += server.ipaddr if server.family == 4:
ipv4_mapping = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF'
res += ipv4_mapping
res += bytes([int(x) for x in server.ipaddr.split('.')])
else:
# TODO: ipv6 is wrong
res += server.ipaddr.encode('utf-8')
res += pack_be_uint16(server.port) res += pack_be_uint16(server.port)
return res return res

View file

@ -98,6 +98,10 @@ class PacketHeader(PrettyPrint):
flags |= PACKETFLAG7_CONNLESS flags |= PACKETFLAG7_CONNLESS
if self.num_chunks is None: if self.num_chunks is None:
self.num_chunks = 0 self.num_chunks = 0
if self.flags.connless:
return bytes([ \
((PACKETFLAG7_CONNLESS<<2)&0xfc) | (self.connless_version&0x03)
]) + self.token + self.response_token
return bytes([ \ return bytes([ \
((flags << 2)&0xfc) | ((self.ack>>8)&0x03), \ ((flags << 2)&0xfc) | ((self.ack>>8)&0x03), \
self.ack&0xff, \ self.ack&0xff, \
@ -116,18 +120,19 @@ class TwPacket(PrettyPrint):
payload: bytes = b'' payload: bytes = b''
msg: Union[CtrlMessage, NetMessage, ConnlessMessage] msg: Union[CtrlMessage, NetMessage, ConnlessMessage]
is_control: bool = False is_control: bool = False
is_connless: bool = False
for msg in self.messages: for msg in self.messages:
# TODO: this is super ugly if msg.message_type == 'connless':
# revist https://gitlab.com/teeworlds-network/twnet_parser/-/issues/1 is_connless = True
# we can not check isinstance() not sure why msg = cast(ConnlessMessage, msg)
# maybe because CtrlMessage and NetMessage are no actual classes payload += bytes(msg.message_id)
# but just ducktyping helpers payload += msg.pack()
if not hasattr(msg, 'system_message'): elif msg.message_type == 'control':
is_control = True is_control = True
msg = cast(CtrlMessage, msg) msg = cast(CtrlMessage, msg)
payload += pack_int(msg.message_id) payload += pack_int(msg.message_id)
payload += msg.pack(we_are_a_client) payload += msg.pack(we_are_a_client)
else: else: # game or system message
msg = cast(NetMessage, msg) msg = cast(NetMessage, msg)
msg_payload: bytes = pack_int( msg_payload: bytes = pack_int(
(msg.message_id<<1) | (msg.message_id<<1) |
@ -146,6 +151,9 @@ class TwPacket(PrettyPrint):
if is_control: if is_control:
if self.header.flags.control is None: if self.header.flags.control is None:
self.header.flags.control = True self.header.flags.control = True
if is_connless:
if self.header.flags.connless is None:
self.header.flags.connless = True
return self.header.pack() + payload return self.header.pack() + payload
class PacketHeaderParser7(): class PacketHeaderParser7():