pybedrock-net 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pybedrock_net-0.0.1/PKG-INFO +179 -0
- pybedrock_net-0.0.1/README.md +159 -0
- pybedrock_net-0.0.1/pybedrock_net/__init__.py +7 -0
- pybedrock_net-0.0.1/pybedrock_net/cli.py +53 -0
- pybedrock_net-0.0.1/pybedrock_net/protocol/__init__.py +1 -0
- pybedrock_net-0.0.1/pybedrock_net/protocol/raknet/__init__.py +12 -0
- pybedrock_net-0.0.1/pybedrock_net/protocol/raknet/constants.py +33 -0
- pybedrock_net-0.0.1/pybedrock_net/protocol/raknet/offline.py +81 -0
- pybedrock_net-0.0.1/pybedrock_net/protocol/raknet/packets.py +5 -0
- pybedrock_net-0.0.1/pybedrock_net/protocol/raknet/session.py +66 -0
- pybedrock_net-0.0.1/pybedrock_net/protocol/raknet/transport.py +47 -0
- pybedrock_net-0.0.1/pybedrock_net.egg-info/PKG-INFO +179 -0
- pybedrock_net-0.0.1/pybedrock_net.egg-info/SOURCES.txt +18 -0
- pybedrock_net-0.0.1/pybedrock_net.egg-info/dependency_links.txt +1 -0
- pybedrock_net-0.0.1/pybedrock_net.egg-info/entry_points.txt +2 -0
- pybedrock_net-0.0.1/pybedrock_net.egg-info/requires.txt +3 -0
- pybedrock_net-0.0.1/pybedrock_net.egg-info/top_level.txt +1 -0
- pybedrock_net-0.0.1/pyproject.toml +35 -0
- pybedrock_net-0.0.1/setup.cfg +4 -0
- pybedrock_net-0.0.1/tests/test_offline.py +38 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pybedrock-net
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A Python-native RakNet foundation for Minecraft Bedrock protocol experiments.
|
|
5
|
+
Author: ZENKAI
|
|
6
|
+
Project-URL: Homepage, https://pypi.org/project/pybedrock-net/
|
|
7
|
+
Project-URL: YouTube, https://www.youtube.com/@szewq
|
|
8
|
+
Keywords: minecraft,bedrock,raknet,udp,protocol,bot
|
|
9
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Topic :: Internet
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: build>=1.4.4
|
|
18
|
+
Requires-Dist: pytest>=8.4.2
|
|
19
|
+
Requires-Dist: twine>=6.2.0
|
|
20
|
+
|
|
21
|
+
# pybedrock-net
|
|
22
|
+
|
|
23
|
+
Python-native RakNet foundations for Minecraft Bedrock protocol experiments.
|
|
24
|
+
|
|
25
|
+
Developed by ZENKAI, with Sader (سادر) leading the development and protocol
|
|
26
|
+
implementation work.
|
|
27
|
+
|
|
28
|
+
## Overview
|
|
29
|
+
|
|
30
|
+
`pybedrock-net` is an early development project focused on understanding and
|
|
31
|
+
implementing Minecraft Bedrock networking directly in Python. Bedrock uses
|
|
32
|
+
RakNet as an important networking foundation. The long-term goal is a reusable
|
|
33
|
+
Python foundation for programmable Bedrock clients, bots, protocol tools,
|
|
34
|
+
testing tools, experiments, and automation systems.
|
|
35
|
+
|
|
36
|
+
This project targets the network protocol rather than requiring a complete
|
|
37
|
+
Minecraft game client. It is not a Minecraft server and is not a replacement
|
|
38
|
+
for Minecraft.
|
|
39
|
+
|
|
40
|
+
## Current implementation
|
|
41
|
+
|
|
42
|
+
Version 0.0.1 contains a real UDP implementation of the RakNet offline
|
|
43
|
+
handshake:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
0x05 OpenConnectionRequest1
|
|
47
|
+
↓
|
|
48
|
+
0x06 OpenConnectionReply1
|
|
49
|
+
↓
|
|
50
|
+
0x07 OpenConnectionRequest2
|
|
51
|
+
↓
|
|
52
|
+
0x08 OpenConnectionReply2
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`RakNetSession` creates a UDP socket, sends Request1, parses Reply1, sends
|
|
56
|
+
Request2, and parses Reply2. The command-line probe performs this exchange
|
|
57
|
+
against a reachable Bedrock UDP endpoint.
|
|
58
|
+
|
|
59
|
+
Successful Reply2 means only that the RakNet offline handshake completed. It
|
|
60
|
+
does not mean the client logged into Minecraft or entered the world.
|
|
61
|
+
|
|
62
|
+
## Architecture
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Python application / Bot
|
|
66
|
+
↓
|
|
67
|
+
UDP transport
|
|
68
|
+
↓
|
|
69
|
+
RakNet
|
|
70
|
+
↓
|
|
71
|
+
Minecraft Bedrock protocol
|
|
72
|
+
↓
|
|
73
|
+
Minecraft Bedrock server
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The transport layer owns UDP communication. RakNet provides the connection and
|
|
77
|
+
reliability foundation. The Bedrock layer will eventually provide login, world,
|
|
78
|
+
player, chat, and command protocol support.
|
|
79
|
+
|
|
80
|
+
## Live connection probe
|
|
81
|
+
|
|
82
|
+
Run this against a real Bedrock UDP endpoint:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pybedrock-net example.org --port 19132
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The host and port are supplied by the user and are never embedded in the
|
|
89
|
+
package. No credentials or server infrastructure are included.
|
|
90
|
+
|
|
91
|
+
## Usage
|
|
92
|
+
|
|
93
|
+
The current session API is experimental:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import asyncio
|
|
97
|
+
from pybedrock_net import RakNetSession
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
async def main() -> None:
|
|
101
|
+
session = RakNetSession("example.org", port=19132)
|
|
102
|
+
try:
|
|
103
|
+
reply = await session.connect()
|
|
104
|
+
print(reply.server_guid, reply.mtu)
|
|
105
|
+
finally:
|
|
106
|
+
session.close()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
asyncio.run(main())
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This connects to RakNet only. It does not log in, move a player, follow a
|
|
113
|
+
player, send chat, or execute commands yet.
|
|
114
|
+
|
|
115
|
+
## Current limitations
|
|
116
|
+
|
|
117
|
+
- Connected RakNet framing is not implemented.
|
|
118
|
+
- Complete reliability, ACK, NAK, ordering, and channel handling are not
|
|
119
|
+
implemented.
|
|
120
|
+
- RakNet connection request and accepted-connection stages are not implemented.
|
|
121
|
+
- Bedrock login, encryption, network settings, start game, and play state are
|
|
122
|
+
not implemented.
|
|
123
|
+
- Player position tracking and movement packets are not implemented.
|
|
124
|
+
- Following a player, chat messages, and command execution are not implemented.
|
|
125
|
+
- No stable high-level bot API is available.
|
|
126
|
+
|
|
127
|
+
These limitations are explicit because sending guessed Bedrock packets can
|
|
128
|
+
disconnect a server or corrupt a session.
|
|
129
|
+
|
|
130
|
+
## Roadmap
|
|
131
|
+
|
|
132
|
+
1. **RakNet offline handshake** — implemented and locally tested; real-server
|
|
133
|
+
verification depends on a reachable endpoint.
|
|
134
|
+
2. **Connected RakNet framing** — in development.
|
|
135
|
+
3. **Reliability, ACK/NAK, ordering, and session lifecycle** — planned.
|
|
136
|
+
4. **Bedrock login and encryption** — planned.
|
|
137
|
+
5. **Bedrock play protocol and player tracking** — planned.
|
|
138
|
+
6. **Movement, follow-player behavior, chat, and permitted commands** — planned.
|
|
139
|
+
7. **High-level Bedrock bot API** — long-term goal.
|
|
140
|
+
|
|
141
|
+
## Installation
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pip install pybedrock-net
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Version 0.0.1 is an early foundation/development release. APIs may change,
|
|
148
|
+
protocol implementation is incomplete, and the package is not production-ready.
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python -m pytest
|
|
154
|
+
python -m build
|
|
155
|
+
python -m twine check dist/*
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Developer & Community
|
|
159
|
+
|
|
160
|
+
- **Developer:** ZENKAI
|
|
161
|
+
- **Development:** Sader (سادر)
|
|
162
|
+
- **Telegram:** `s_xwn`
|
|
163
|
+
- **TikTok:** `s_xwn`
|
|
164
|
+
- **YouTube:** https://www.youtube.com/@szewq
|
|
165
|
+
|
|
166
|
+
An official support/community link may be added in a future release.
|
|
167
|
+
|
|
168
|
+
## Future Support
|
|
169
|
+
|
|
170
|
+
The intended future bot layer may allow Python programs to connect to Bedrock
|
|
171
|
+
servers where supported, authenticate, receive player events, follow a target
|
|
172
|
+
player, move, send chat, issue permitted commands, and automate protocol-level
|
|
173
|
+
tasks. These are future capabilities, not features available in 0.0.1.
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
No license file was present when this distribution was prepared. A license
|
|
178
|
+
should be selected before the project is treated as a fully licensed
|
|
179
|
+
open-source distribution.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# pybedrock-net
|
|
2
|
+
|
|
3
|
+
Python-native RakNet foundations for Minecraft Bedrock protocol experiments.
|
|
4
|
+
|
|
5
|
+
Developed by ZENKAI, with Sader (سادر) leading the development and protocol
|
|
6
|
+
implementation work.
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
`pybedrock-net` is an early development project focused on understanding and
|
|
11
|
+
implementing Minecraft Bedrock networking directly in Python. Bedrock uses
|
|
12
|
+
RakNet as an important networking foundation. The long-term goal is a reusable
|
|
13
|
+
Python foundation for programmable Bedrock clients, bots, protocol tools,
|
|
14
|
+
testing tools, experiments, and automation systems.
|
|
15
|
+
|
|
16
|
+
This project targets the network protocol rather than requiring a complete
|
|
17
|
+
Minecraft game client. It is not a Minecraft server and is not a replacement
|
|
18
|
+
for Minecraft.
|
|
19
|
+
|
|
20
|
+
## Current implementation
|
|
21
|
+
|
|
22
|
+
Version 0.0.1 contains a real UDP implementation of the RakNet offline
|
|
23
|
+
handshake:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
0x05 OpenConnectionRequest1
|
|
27
|
+
↓
|
|
28
|
+
0x06 OpenConnectionReply1
|
|
29
|
+
↓
|
|
30
|
+
0x07 OpenConnectionRequest2
|
|
31
|
+
↓
|
|
32
|
+
0x08 OpenConnectionReply2
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`RakNetSession` creates a UDP socket, sends Request1, parses Reply1, sends
|
|
36
|
+
Request2, and parses Reply2. The command-line probe performs this exchange
|
|
37
|
+
against a reachable Bedrock UDP endpoint.
|
|
38
|
+
|
|
39
|
+
Successful Reply2 means only that the RakNet offline handshake completed. It
|
|
40
|
+
does not mean the client logged into Minecraft or entered the world.
|
|
41
|
+
|
|
42
|
+
## Architecture
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
Python application / Bot
|
|
46
|
+
↓
|
|
47
|
+
UDP transport
|
|
48
|
+
↓
|
|
49
|
+
RakNet
|
|
50
|
+
↓
|
|
51
|
+
Minecraft Bedrock protocol
|
|
52
|
+
↓
|
|
53
|
+
Minecraft Bedrock server
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The transport layer owns UDP communication. RakNet provides the connection and
|
|
57
|
+
reliability foundation. The Bedrock layer will eventually provide login, world,
|
|
58
|
+
player, chat, and command protocol support.
|
|
59
|
+
|
|
60
|
+
## Live connection probe
|
|
61
|
+
|
|
62
|
+
Run this against a real Bedrock UDP endpoint:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pybedrock-net example.org --port 19132
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The host and port are supplied by the user and are never embedded in the
|
|
69
|
+
package. No credentials or server infrastructure are included.
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
The current session API is experimental:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
import asyncio
|
|
77
|
+
from pybedrock_net import RakNetSession
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
async def main() -> None:
|
|
81
|
+
session = RakNetSession("example.org", port=19132)
|
|
82
|
+
try:
|
|
83
|
+
reply = await session.connect()
|
|
84
|
+
print(reply.server_guid, reply.mtu)
|
|
85
|
+
finally:
|
|
86
|
+
session.close()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
asyncio.run(main())
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This connects to RakNet only. It does not log in, move a player, follow a
|
|
93
|
+
player, send chat, or execute commands yet.
|
|
94
|
+
|
|
95
|
+
## Current limitations
|
|
96
|
+
|
|
97
|
+
- Connected RakNet framing is not implemented.
|
|
98
|
+
- Complete reliability, ACK, NAK, ordering, and channel handling are not
|
|
99
|
+
implemented.
|
|
100
|
+
- RakNet connection request and accepted-connection stages are not implemented.
|
|
101
|
+
- Bedrock login, encryption, network settings, start game, and play state are
|
|
102
|
+
not implemented.
|
|
103
|
+
- Player position tracking and movement packets are not implemented.
|
|
104
|
+
- Following a player, chat messages, and command execution are not implemented.
|
|
105
|
+
- No stable high-level bot API is available.
|
|
106
|
+
|
|
107
|
+
These limitations are explicit because sending guessed Bedrock packets can
|
|
108
|
+
disconnect a server or corrupt a session.
|
|
109
|
+
|
|
110
|
+
## Roadmap
|
|
111
|
+
|
|
112
|
+
1. **RakNet offline handshake** — implemented and locally tested; real-server
|
|
113
|
+
verification depends on a reachable endpoint.
|
|
114
|
+
2. **Connected RakNet framing** — in development.
|
|
115
|
+
3. **Reliability, ACK/NAK, ordering, and session lifecycle** — planned.
|
|
116
|
+
4. **Bedrock login and encryption** — planned.
|
|
117
|
+
5. **Bedrock play protocol and player tracking** — planned.
|
|
118
|
+
6. **Movement, follow-player behavior, chat, and permitted commands** — planned.
|
|
119
|
+
7. **High-level Bedrock bot API** — long-term goal.
|
|
120
|
+
|
|
121
|
+
## Installation
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pip install pybedrock-net
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Version 0.0.1 is an early foundation/development release. APIs may change,
|
|
128
|
+
protocol implementation is incomplete, and the package is not production-ready.
|
|
129
|
+
|
|
130
|
+
## Development
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
python -m pytest
|
|
134
|
+
python -m build
|
|
135
|
+
python -m twine check dist/*
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Developer & Community
|
|
139
|
+
|
|
140
|
+
- **Developer:** ZENKAI
|
|
141
|
+
- **Development:** Sader (سادر)
|
|
142
|
+
- **Telegram:** `s_xwn`
|
|
143
|
+
- **TikTok:** `s_xwn`
|
|
144
|
+
- **YouTube:** https://www.youtube.com/@szewq
|
|
145
|
+
|
|
146
|
+
An official support/community link may be added in a future release.
|
|
147
|
+
|
|
148
|
+
## Future Support
|
|
149
|
+
|
|
150
|
+
The intended future bot layer may allow Python programs to connect to Bedrock
|
|
151
|
+
servers where supported, authenticate, receive player events, follow a target
|
|
152
|
+
player, move, send chat, issue permitted commands, and automate protocol-level
|
|
153
|
+
tasks. These are future capabilities, not features available in 0.0.1.
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
No license file was present when this distribution was prepared. A license
|
|
158
|
+
should be selected before the project is treated as a fully licensed
|
|
159
|
+
open-source distribution.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Command-line tools for checking a Bedrock server's RakNet endpoint."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from .protocol.raknet.session import RakNetSession
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="pybedrock-net",
|
|
15
|
+
description="Run the RakNet offline handshake against a Bedrock server.",
|
|
16
|
+
)
|
|
17
|
+
parser.add_argument("host", help="Bedrock server hostname or IPv4 address")
|
|
18
|
+
parser.add_argument("--port", type=int, default=19132, help="Bedrock UDP port")
|
|
19
|
+
parser.add_argument("--mtu", type=int, default=1492, help="Requested MTU (576-1492)")
|
|
20
|
+
parser.add_argument("--timeout", type=float, default=5.0, help="Reply timeout in seconds")
|
|
21
|
+
return parser
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def _run(args: argparse.Namespace) -> int:
|
|
25
|
+
session = RakNetSession(
|
|
26
|
+
args.host, port=args.port, mtu=args.mtu, timeout=args.timeout
|
|
27
|
+
)
|
|
28
|
+
try:
|
|
29
|
+
reply = await session.connect()
|
|
30
|
+
print(f"Connected to {args.host}:{args.port}")
|
|
31
|
+
print(f"Server GUID: {reply.server_guid}")
|
|
32
|
+
print(f"Negotiated MTU: {reply.mtu}")
|
|
33
|
+
print(f"Security enabled: {reply.security_enabled}")
|
|
34
|
+
print("RakNet offline handshake complete (0x05 → 0x06 → 0x07 → 0x08).")
|
|
35
|
+
print(
|
|
36
|
+
"Bedrock login/play is not completed by this release; "
|
|
37
|
+
"no movement or chat packets are sent."
|
|
38
|
+
)
|
|
39
|
+
return 0
|
|
40
|
+
except (OSError, TimeoutError, ValueError) as exc:
|
|
41
|
+
print(f"Connection failed: {exc}", file=sys.stderr)
|
|
42
|
+
return 1
|
|
43
|
+
finally:
|
|
44
|
+
session.close()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def main() -> int:
|
|
48
|
+
args = build_parser().parse_args()
|
|
49
|
+
return asyncio.run(_run(args))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Minecraft protocol implementations."""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""RakNet protocol primitives used by Minecraft Bedrock."""
|
|
2
|
+
|
|
3
|
+
from .constants import OFFLINE_MAGIC
|
|
4
|
+
from .packets import OpenConnectionReply1, OpenConnectionReply2
|
|
5
|
+
from .session import RakNetSession
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"OFFLINE_MAGIC",
|
|
9
|
+
"OpenConnectionReply1",
|
|
10
|
+
"OpenConnectionReply2",
|
|
11
|
+
"RakNetSession",
|
|
12
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""RakNet constants."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import struct
|
|
6
|
+
|
|
7
|
+
OFFLINE_MAGIC = bytes.fromhex("00ffff00fefefefefdfdfdfd12345678")
|
|
8
|
+
OPEN_CONNECTION_REQUEST_1 = 0x05
|
|
9
|
+
OPEN_CONNECTION_REPLY_1 = 0x06
|
|
10
|
+
OPEN_CONNECTION_REQUEST_2 = 0x07
|
|
11
|
+
OPEN_CONNECTION_REPLY_2 = 0x08
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def pack_u16(value: int) -> bytes:
|
|
15
|
+
return struct.pack(">H", value)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def pack_u64(value: int) -> bytes:
|
|
19
|
+
return struct.pack(">Q", value)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def unpack_u16(data: bytes, offset: int) -> tuple[int, int]:
|
|
23
|
+
end = offset + 2
|
|
24
|
+
if len(data) < end:
|
|
25
|
+
raise ValueError("packet ended while reading uint16")
|
|
26
|
+
return struct.unpack(">H", data[offset:end])[0], end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def unpack_u64(data: bytes, offset: int) -> tuple[int, int]:
|
|
30
|
+
end = offset + 8
|
|
31
|
+
if len(data) < end:
|
|
32
|
+
raise ValueError("packet ended while reading uint64")
|
|
33
|
+
return struct.unpack(">Q", data[offset:end])[0], end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""RakNet offline packet encoding and decoding."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ipaddress
|
|
6
|
+
|
|
7
|
+
from .constants import (
|
|
8
|
+
OFFLINE_MAGIC,
|
|
9
|
+
OPEN_CONNECTION_REPLY_1,
|
|
10
|
+
OPEN_CONNECTION_REPLY_2,
|
|
11
|
+
OPEN_CONNECTION_REQUEST_1,
|
|
12
|
+
OPEN_CONNECTION_REQUEST_2,
|
|
13
|
+
pack_u16,
|
|
14
|
+
pack_u64,
|
|
15
|
+
unpack_u16,
|
|
16
|
+
unpack_u64,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def encode_ipv4(address: str) -> bytes:
|
|
21
|
+
ip = ipaddress.ip_address(address)
|
|
22
|
+
if ip.version != 4:
|
|
23
|
+
raise ValueError("RakNet Bedrock transport currently requires an IPv4 address")
|
|
24
|
+
return bytes((0x04,)) + bytes((octet ^ 0xFF for octet in ip.packed))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def decode_ipv4(data: bytes, offset: int = 0) -> tuple[str, int]:
|
|
28
|
+
if len(data) < offset + 5 or data[offset] != 0x04:
|
|
29
|
+
raise ValueError("expected RakNet IPv4 address")
|
|
30
|
+
raw = bytes(octet ^ 0xFF for octet in data[offset + 1 : offset + 5])
|
|
31
|
+
return str(ipaddress.ip_address(raw)), offset + 5
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def build_open_connection_request_1(mtu: int, protocol_version: int = 11) -> bytes:
|
|
35
|
+
if not 576 <= mtu <= 1492:
|
|
36
|
+
raise ValueError("MTU must be between 576 and 1492 bytes")
|
|
37
|
+
# Request1 is padded to the requested datagram size.
|
|
38
|
+
header = bytes((OPEN_CONNECTION_REQUEST_1,)) + OFFLINE_MAGIC + bytes((protocol_version,))
|
|
39
|
+
return header + bytes(max(0, mtu - len(header)))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def build_open_connection_request_2(
|
|
43
|
+
server_host: str, server_port: int, mtu: int, client_guid: int
|
|
44
|
+
) -> bytes:
|
|
45
|
+
if not 0 <= server_port <= 65535:
|
|
46
|
+
raise ValueError("server port must be between 0 and 65535")
|
|
47
|
+
return (
|
|
48
|
+
bytes((OPEN_CONNECTION_REQUEST_2,))
|
|
49
|
+
+ OFFLINE_MAGIC
|
|
50
|
+
+ encode_ipv4(server_host)
|
|
51
|
+
+ pack_u16(server_port)
|
|
52
|
+
+ pack_u16(mtu)
|
|
53
|
+
+ pack_u64(client_guid)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class OpenConnectionReply1:
|
|
58
|
+
"""Parsed 0x06 OpenConnectionReply1."""
|
|
59
|
+
|
|
60
|
+
def __init__(self, data: bytes) -> None:
|
|
61
|
+
if len(data) < 28 or data[0] != OPEN_CONNECTION_REPLY_1:
|
|
62
|
+
raise ValueError("not an OpenConnectionReply1 packet")
|
|
63
|
+
if data[1:17] != OFFLINE_MAGIC:
|
|
64
|
+
raise ValueError("invalid RakNet offline magic")
|
|
65
|
+
self.server_guid, offset = unpack_u64(data, 17)
|
|
66
|
+
self.security_enabled = bool(data[offset])
|
|
67
|
+
self.mtu, _ = unpack_u16(data, offset + 1)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class OpenConnectionReply2:
|
|
71
|
+
"""Parsed 0x08 OpenConnectionReply2."""
|
|
72
|
+
|
|
73
|
+
def __init__(self, data: bytes) -> None:
|
|
74
|
+
if len(data) < 35 or data[0] != OPEN_CONNECTION_REPLY_2:
|
|
75
|
+
raise ValueError("not an OpenConnectionReply2 packet")
|
|
76
|
+
if data[1:17] != OFFLINE_MAGIC:
|
|
77
|
+
raise ValueError("invalid RakNet offline magic")
|
|
78
|
+
self.server_guid, offset = unpack_u64(data, 17)
|
|
79
|
+
self.client_address, offset = decode_ipv4(data, offset)
|
|
80
|
+
self.server_port, offset = unpack_u16(data, offset)
|
|
81
|
+
self.mtu, _ = unpack_u16(data, offset)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""RakNet session lifecycle for the offline Bedrock handshake."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import secrets
|
|
7
|
+
|
|
8
|
+
from .offline import (
|
|
9
|
+
OpenConnectionReply1,
|
|
10
|
+
OpenConnectionReply2,
|
|
11
|
+
build_open_connection_request_1,
|
|
12
|
+
build_open_connection_request_2,
|
|
13
|
+
)
|
|
14
|
+
from .transport import UdpTransport
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RakNetSession:
|
|
18
|
+
"""Perform the real RakNet offline handshake over UDP.
|
|
19
|
+
|
|
20
|
+
This intentionally stops after Reply2. Connected RakNet and Bedrock login
|
|
21
|
+
require additional protocol stages and encryption that are not silently
|
|
22
|
+
approximated here.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
host: str,
|
|
28
|
+
*,
|
|
29
|
+
port: int = 19132,
|
|
30
|
+
mtu: int = 1492,
|
|
31
|
+
timeout: float = 5.0,
|
|
32
|
+
client_guid: int | None = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
self.host = host
|
|
35
|
+
self.port = port
|
|
36
|
+
self.mtu = mtu
|
|
37
|
+
self.timeout = timeout
|
|
38
|
+
self.client_guid = client_guid if client_guid is not None else secrets.randbits(64)
|
|
39
|
+
self.transport = UdpTransport(host, port, timeout)
|
|
40
|
+
self.reply1: OpenConnectionReply1 | None = None
|
|
41
|
+
self.reply2: OpenConnectionReply2 | None = None
|
|
42
|
+
|
|
43
|
+
async def connect(self) -> OpenConnectionReply2:
|
|
44
|
+
await self.transport.open()
|
|
45
|
+
await self.transport.send(build_open_connection_request_1(self.mtu))
|
|
46
|
+
self.reply1 = OpenConnectionReply1(await self.transport.receive())
|
|
47
|
+
await self.transport.send(
|
|
48
|
+
build_open_connection_request_2(
|
|
49
|
+
self.transport.peer_host or self.host,
|
|
50
|
+
self.port,
|
|
51
|
+
self.reply1.mtu,
|
|
52
|
+
self.client_guid,
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
self.reply2 = OpenConnectionReply2(await self.transport.receive())
|
|
56
|
+
return self.reply2
|
|
57
|
+
|
|
58
|
+
async def run(self) -> None:
|
|
59
|
+
"""Keep the UDP session available for future connected-RakNet work."""
|
|
60
|
+
if self.reply2 is None:
|
|
61
|
+
raise RuntimeError("call connect() before run()")
|
|
62
|
+
while True:
|
|
63
|
+
await self.transport.receive()
|
|
64
|
+
|
|
65
|
+
def close(self) -> None:
|
|
66
|
+
self.transport.close()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Async UDP transport for RakNet datagrams."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import socket
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UdpTransport:
|
|
10
|
+
def __init__(self, host: str, port: int, timeout: float) -> None:
|
|
11
|
+
self.host = host
|
|
12
|
+
self.port = port
|
|
13
|
+
self.timeout = timeout
|
|
14
|
+
self._socket: socket.socket | None = None
|
|
15
|
+
self.peer_host: str | None = None
|
|
16
|
+
|
|
17
|
+
async def open(self) -> None:
|
|
18
|
+
infos = await asyncio.get_running_loop().getaddrinfo(
|
|
19
|
+
self.host, self.port, type=socket.SOCK_DGRAM
|
|
20
|
+
)
|
|
21
|
+
if not infos:
|
|
22
|
+
raise OSError(f"could not resolve {self.host}")
|
|
23
|
+
family, socktype, proto, _, address = infos[0]
|
|
24
|
+
self.peer_host = address[0]
|
|
25
|
+
sock = socket.socket(family, socktype, proto)
|
|
26
|
+
sock.setblocking(False)
|
|
27
|
+
await asyncio.get_running_loop().sock_connect(sock, address)
|
|
28
|
+
self._socket = sock
|
|
29
|
+
|
|
30
|
+
async def send(self, packet: bytes) -> None:
|
|
31
|
+
if self._socket is None:
|
|
32
|
+
raise RuntimeError("transport is not open")
|
|
33
|
+
await asyncio.get_running_loop().sock_sendall(self._socket, packet)
|
|
34
|
+
|
|
35
|
+
async def receive(self, max_size: int = 2048) -> bytes:
|
|
36
|
+
if self._socket is None:
|
|
37
|
+
raise RuntimeError("transport is not open")
|
|
38
|
+
return await asyncio.wait_for(
|
|
39
|
+
asyncio.get_running_loop().sock_recv(self._socket, max_size),
|
|
40
|
+
timeout=self.timeout,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def close(self) -> None:
|
|
44
|
+
if self._socket is not None:
|
|
45
|
+
self._socket.close()
|
|
46
|
+
self._socket = None
|
|
47
|
+
self.peer_host = None
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pybedrock-net
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A Python-native RakNet foundation for Minecraft Bedrock protocol experiments.
|
|
5
|
+
Author: ZENKAI
|
|
6
|
+
Project-URL: Homepage, https://pypi.org/project/pybedrock-net/
|
|
7
|
+
Project-URL: YouTube, https://www.youtube.com/@szewq
|
|
8
|
+
Keywords: minecraft,bedrock,raknet,udp,protocol,bot
|
|
9
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Topic :: Internet
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: build>=1.4.4
|
|
18
|
+
Requires-Dist: pytest>=8.4.2
|
|
19
|
+
Requires-Dist: twine>=6.2.0
|
|
20
|
+
|
|
21
|
+
# pybedrock-net
|
|
22
|
+
|
|
23
|
+
Python-native RakNet foundations for Minecraft Bedrock protocol experiments.
|
|
24
|
+
|
|
25
|
+
Developed by ZENKAI, with Sader (سادر) leading the development and protocol
|
|
26
|
+
implementation work.
|
|
27
|
+
|
|
28
|
+
## Overview
|
|
29
|
+
|
|
30
|
+
`pybedrock-net` is an early development project focused on understanding and
|
|
31
|
+
implementing Minecraft Bedrock networking directly in Python. Bedrock uses
|
|
32
|
+
RakNet as an important networking foundation. The long-term goal is a reusable
|
|
33
|
+
Python foundation for programmable Bedrock clients, bots, protocol tools,
|
|
34
|
+
testing tools, experiments, and automation systems.
|
|
35
|
+
|
|
36
|
+
This project targets the network protocol rather than requiring a complete
|
|
37
|
+
Minecraft game client. It is not a Minecraft server and is not a replacement
|
|
38
|
+
for Minecraft.
|
|
39
|
+
|
|
40
|
+
## Current implementation
|
|
41
|
+
|
|
42
|
+
Version 0.0.1 contains a real UDP implementation of the RakNet offline
|
|
43
|
+
handshake:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
0x05 OpenConnectionRequest1
|
|
47
|
+
↓
|
|
48
|
+
0x06 OpenConnectionReply1
|
|
49
|
+
↓
|
|
50
|
+
0x07 OpenConnectionRequest2
|
|
51
|
+
↓
|
|
52
|
+
0x08 OpenConnectionReply2
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`RakNetSession` creates a UDP socket, sends Request1, parses Reply1, sends
|
|
56
|
+
Request2, and parses Reply2. The command-line probe performs this exchange
|
|
57
|
+
against a reachable Bedrock UDP endpoint.
|
|
58
|
+
|
|
59
|
+
Successful Reply2 means only that the RakNet offline handshake completed. It
|
|
60
|
+
does not mean the client logged into Minecraft or entered the world.
|
|
61
|
+
|
|
62
|
+
## Architecture
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Python application / Bot
|
|
66
|
+
↓
|
|
67
|
+
UDP transport
|
|
68
|
+
↓
|
|
69
|
+
RakNet
|
|
70
|
+
↓
|
|
71
|
+
Minecraft Bedrock protocol
|
|
72
|
+
↓
|
|
73
|
+
Minecraft Bedrock server
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The transport layer owns UDP communication. RakNet provides the connection and
|
|
77
|
+
reliability foundation. The Bedrock layer will eventually provide login, world,
|
|
78
|
+
player, chat, and command protocol support.
|
|
79
|
+
|
|
80
|
+
## Live connection probe
|
|
81
|
+
|
|
82
|
+
Run this against a real Bedrock UDP endpoint:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pybedrock-net example.org --port 19132
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The host and port are supplied by the user and are never embedded in the
|
|
89
|
+
package. No credentials or server infrastructure are included.
|
|
90
|
+
|
|
91
|
+
## Usage
|
|
92
|
+
|
|
93
|
+
The current session API is experimental:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import asyncio
|
|
97
|
+
from pybedrock_net import RakNetSession
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
async def main() -> None:
|
|
101
|
+
session = RakNetSession("example.org", port=19132)
|
|
102
|
+
try:
|
|
103
|
+
reply = await session.connect()
|
|
104
|
+
print(reply.server_guid, reply.mtu)
|
|
105
|
+
finally:
|
|
106
|
+
session.close()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
asyncio.run(main())
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This connects to RakNet only. It does not log in, move a player, follow a
|
|
113
|
+
player, send chat, or execute commands yet.
|
|
114
|
+
|
|
115
|
+
## Current limitations
|
|
116
|
+
|
|
117
|
+
- Connected RakNet framing is not implemented.
|
|
118
|
+
- Complete reliability, ACK, NAK, ordering, and channel handling are not
|
|
119
|
+
implemented.
|
|
120
|
+
- RakNet connection request and accepted-connection stages are not implemented.
|
|
121
|
+
- Bedrock login, encryption, network settings, start game, and play state are
|
|
122
|
+
not implemented.
|
|
123
|
+
- Player position tracking and movement packets are not implemented.
|
|
124
|
+
- Following a player, chat messages, and command execution are not implemented.
|
|
125
|
+
- No stable high-level bot API is available.
|
|
126
|
+
|
|
127
|
+
These limitations are explicit because sending guessed Bedrock packets can
|
|
128
|
+
disconnect a server or corrupt a session.
|
|
129
|
+
|
|
130
|
+
## Roadmap
|
|
131
|
+
|
|
132
|
+
1. **RakNet offline handshake** — implemented and locally tested; real-server
|
|
133
|
+
verification depends on a reachable endpoint.
|
|
134
|
+
2. **Connected RakNet framing** — in development.
|
|
135
|
+
3. **Reliability, ACK/NAK, ordering, and session lifecycle** — planned.
|
|
136
|
+
4. **Bedrock login and encryption** — planned.
|
|
137
|
+
5. **Bedrock play protocol and player tracking** — planned.
|
|
138
|
+
6. **Movement, follow-player behavior, chat, and permitted commands** — planned.
|
|
139
|
+
7. **High-level Bedrock bot API** — long-term goal.
|
|
140
|
+
|
|
141
|
+
## Installation
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pip install pybedrock-net
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Version 0.0.1 is an early foundation/development release. APIs may change,
|
|
148
|
+
protocol implementation is incomplete, and the package is not production-ready.
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python -m pytest
|
|
154
|
+
python -m build
|
|
155
|
+
python -m twine check dist/*
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Developer & Community
|
|
159
|
+
|
|
160
|
+
- **Developer:** ZENKAI
|
|
161
|
+
- **Development:** Sader (سادر)
|
|
162
|
+
- **Telegram:** `s_xwn`
|
|
163
|
+
- **TikTok:** `s_xwn`
|
|
164
|
+
- **YouTube:** https://www.youtube.com/@szewq
|
|
165
|
+
|
|
166
|
+
An official support/community link may be added in a future release.
|
|
167
|
+
|
|
168
|
+
## Future Support
|
|
169
|
+
|
|
170
|
+
The intended future bot layer may allow Python programs to connect to Bedrock
|
|
171
|
+
servers where supported, authenticate, receive player events, follow a target
|
|
172
|
+
player, move, send chat, issue permitted commands, and automate protocol-level
|
|
173
|
+
tasks. These are future capabilities, not features available in 0.0.1.
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
No license file was present when this distribution was prepared. A license
|
|
178
|
+
should be selected before the project is treated as a fully licensed
|
|
179
|
+
open-source distribution.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
pybedrock_net/__init__.py
|
|
4
|
+
pybedrock_net/cli.py
|
|
5
|
+
pybedrock_net.egg-info/PKG-INFO
|
|
6
|
+
pybedrock_net.egg-info/SOURCES.txt
|
|
7
|
+
pybedrock_net.egg-info/dependency_links.txt
|
|
8
|
+
pybedrock_net.egg-info/entry_points.txt
|
|
9
|
+
pybedrock_net.egg-info/requires.txt
|
|
10
|
+
pybedrock_net.egg-info/top_level.txt
|
|
11
|
+
pybedrock_net/protocol/__init__.py
|
|
12
|
+
pybedrock_net/protocol/raknet/__init__.py
|
|
13
|
+
pybedrock_net/protocol/raknet/constants.py
|
|
14
|
+
pybedrock_net/protocol/raknet/offline.py
|
|
15
|
+
pybedrock_net/protocol/raknet/packets.py
|
|
16
|
+
pybedrock_net/protocol/raknet/session.py
|
|
17
|
+
pybedrock_net/protocol/raknet/transport.py
|
|
18
|
+
tests/test_offline.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pybedrock_net
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pybedrock-net"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "A Python-native RakNet foundation for Minecraft Bedrock protocol experiments."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
authors = [{ name = "ZENKAI" }]
|
|
12
|
+
keywords = ["minecraft", "bedrock", "raknet", "udp", "protocol", "bot"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
"Topic :: Internet",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"build>=1.4.4",
|
|
23
|
+
"pytest>=8.4.2",
|
|
24
|
+
"twine>=6.2.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
pybedrock-net = "pybedrock_net.cli:main"
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://pypi.org/project/pybedrock-net/"
|
|
32
|
+
YouTube = "https://www.youtube.com/@szewq"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
include = ["pybedrock_net*"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from pybedrock_net.protocol.raknet.constants import OFFLINE_MAGIC
|
|
4
|
+
from pybedrock_net.protocol.raknet.offline import (
|
|
5
|
+
OpenConnectionReply1,
|
|
6
|
+
build_open_connection_request_1,
|
|
7
|
+
encode_ipv4,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_request_one_has_magic_and_requested_mtu():
|
|
12
|
+
packet = build_open_connection_request_1(1492)
|
|
13
|
+
assert packet[0] == 0x05
|
|
14
|
+
assert packet[1:17] == OFFLINE_MAGIC
|
|
15
|
+
assert len(packet) == 1492
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_ipv4_is_encoded_in_raknet_complement_form():
|
|
19
|
+
assert encode_ipv4("127.0.0.1") == b"\x04\x80\xff\xff\xfe"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_reply_one_parses_fields():
|
|
23
|
+
packet = (
|
|
24
|
+
b"\x06"
|
|
25
|
+
+ OFFLINE_MAGIC
|
|
26
|
+
+ (123).to_bytes(8, "big")
|
|
27
|
+
+ b"\x00"
|
|
28
|
+
+ (1400).to_bytes(2, "big")
|
|
29
|
+
)
|
|
30
|
+
reply = OpenConnectionReply1(packet)
|
|
31
|
+
assert reply.server_guid == 123
|
|
32
|
+
assert reply.mtu == 1400
|
|
33
|
+
assert reply.security_enabled is False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_bad_magic_is_rejected():
|
|
37
|
+
with pytest.raises(ValueError, match="offline magic"):
|
|
38
|
+
OpenConnectionReply1(b"\x06" + b"\x00" * 30)
|