feat: add JD native read-only service surface
This commit is contained in:
parent
a5a1cdc185
commit
856a6c9ffb
8 changed files with 317 additions and 18 deletions
|
|
@ -18,6 +18,8 @@ NATIVE_ACK_MAGIC = b"HLDP-NATIVE-ACK!"
|
|||
ANCHOR_PORT = 3922
|
||||
ANCHOR_CLIENT_PORT = 40392
|
||||
ANCHOR_CLIENT_SEQUENCE = 0x10203040
|
||||
CODE_CLIENT_PORT = 40393
|
||||
CODE_CLIENT_SEQUENCE = 0x20304050
|
||||
ANCHOR_BODY = (
|
||||
b'{"schema":"guanghu.native-public-anchor/v1",'
|
||||
b'"anchor_id":"GLW-PUBLIC-NAV-ANCHOR-001",'
|
||||
|
|
@ -26,6 +28,13 @@ ANCHOR_BODY = (
|
|||
b'"code_entry":"https://guanghulab.com/code/bingshuo/guanghu-ice-heart",'
|
||||
b'"runtime":"GUANGHU_OS_NATIVE"}'
|
||||
)
|
||||
CODE_BODY = (
|
||||
b'{"schema":"guanghu.native-code-channel-read-only/v1",'
|
||||
b'"repository_id":"REPO-012","branch":"main",'
|
||||
b'"commit":"fb1096c5ecdcfb36015d51273f487c2f36d9c9cd",'
|
||||
b'"mode":"READ_ONLY_DISCOVERY","runtime":"GUANGHU_OS_NATIVE",'
|
||||
b'"full_forgejo_equivalence":false}'
|
||||
)
|
||||
|
||||
|
||||
def checksum(payload: bytes) -> int:
|
||||
|
|
@ -105,13 +114,14 @@ def tcp_frame(
|
|||
acknowledgement: int,
|
||||
payload: bytes = b"",
|
||||
options: bytes = b"",
|
||||
client_port: int = ANCHOR_CLIENT_PORT,
|
||||
) -> bytes:
|
||||
if len(options) % 4 or len(options) > 40:
|
||||
raise ValueError("TCP options must be 32-bit aligned and no more than 40 bytes")
|
||||
tcp = bytearray(
|
||||
struct.pack(
|
||||
"!HHIIBBHHH",
|
||||
ANCHOR_CLIENT_PORT,
|
||||
client_port,
|
||||
ANCHOR_PORT,
|
||||
sequence,
|
||||
acknowledgement,
|
||||
|
|
@ -137,7 +147,9 @@ def tcp_frame(
|
|||
return GUEST_MAC + PEER_MAC + b"\x08\x00" + bytes(ip) + bytes(tcp)
|
||||
|
||||
|
||||
def verify_anchor_tcp(frame: bytes, expected_flags: int) -> tuple[int, int, bytes]:
|
||||
def verify_anchor_tcp(
|
||||
frame: bytes, expected_flags: int, client_port: int = ANCHOR_CLIENT_PORT
|
||||
) -> tuple[int, int, bytes]:
|
||||
assert frame[0:6] == PEER_MAC
|
||||
assert frame[6:12] == GUEST_MAC
|
||||
assert frame[12:14] == b"\x08\x00"
|
||||
|
|
@ -148,7 +160,7 @@ def verify_anchor_tcp(frame: bytes, expected_flags: int) -> tuple[int, int, byte
|
|||
total_length = int.from_bytes(frame[16:18], "big")
|
||||
tcp = frame[34 : 14 + total_length]
|
||||
assert int.from_bytes(tcp[0:2], "big") == ANCHOR_PORT
|
||||
assert int.from_bytes(tcp[2:4], "big") == ANCHOR_CLIENT_PORT
|
||||
assert int.from_bytes(tcp[2:4], "big") == client_port
|
||||
assert tcp[13] == expected_flags
|
||||
pseudo = GUEST_IP + GATEWAY_IP + b"\0\x06" + struct.pack("!H", len(tcp))
|
||||
assert checksum(pseudo + tcp) == 0
|
||||
|
|
@ -170,6 +182,7 @@ def main() -> None:
|
|||
parser.add_argument("--recovery-token-file")
|
||||
parser.add_argument("--login-only", action="store_true")
|
||||
parser.add_argument("--anchor-http", action="store_true")
|
||||
parser.add_argument("--service-equivalence", action="store_true")
|
||||
parser.add_argument("--guest-ip", default="172.16.0.6")
|
||||
parser.add_argument("--peer-ip", default="172.16.0.1")
|
||||
parser.add_argument("--relay-ip", default="43.153.193.169")
|
||||
|
|
@ -192,7 +205,7 @@ def main() -> None:
|
|||
peer.bind(("127.0.0.1", args.listen_port))
|
||||
peer.settimeout(0.2)
|
||||
qemu = ("127.0.0.1", args.qemu_port)
|
||||
deadline = time.monotonic() + 15
|
||||
deadline = time.monotonic() + (30 if args.service_equivalence else 15)
|
||||
arp_verified = False
|
||||
login_count = 0
|
||||
resident_login_count = 0
|
||||
|
|
@ -204,6 +217,11 @@ def main() -> None:
|
|||
anchor_server_sequence = None
|
||||
anchor_get_sent = False
|
||||
anchor_http_verified = False
|
||||
code_syn_sent = False
|
||||
code_syn_ack_verified = False
|
||||
code_server_sequence = None
|
||||
code_get_sent = False
|
||||
code_http_verified = False
|
||||
|
||||
while time.monotonic() < deadline:
|
||||
try:
|
||||
|
|
@ -217,6 +235,46 @@ def main() -> None:
|
|||
if frame[12:14] != b"\x08\x00":
|
||||
continue
|
||||
if frame[23] == 6:
|
||||
response_client_port = int.from_bytes(frame[36:38], "big")
|
||||
if response_client_port == CODE_CLIENT_PORT:
|
||||
if not code_syn_ack_verified:
|
||||
server_sequence, acknowledgement, payload = verify_anchor_tcp(
|
||||
frame, 0x12, CODE_CLIENT_PORT
|
||||
)
|
||||
assert acknowledgement == CODE_CLIENT_SEQUENCE + 1
|
||||
assert payload == b""
|
||||
code_server_sequence = server_sequence
|
||||
code_syn_ack_verified = True
|
||||
request = (
|
||||
b"GET /v1/code-channel HTTP/1.1\r\n"
|
||||
b"Host: native.guanghulab.com\r\n"
|
||||
b"Connection: close\r\n\r\n"
|
||||
)
|
||||
peer.sendto(
|
||||
tcp_frame(
|
||||
0x18,
|
||||
CODE_CLIENT_SEQUENCE + 1,
|
||||
server_sequence + 1,
|
||||
request,
|
||||
options=b"\x01\x01\x08\x0a\xd8\x8d\xec\x57\x00\x00\x00\x01",
|
||||
client_port=CODE_CLIENT_PORT,
|
||||
),
|
||||
qemu,
|
||||
)
|
||||
code_get_sent = True
|
||||
continue
|
||||
server_sequence, acknowledgement, payload = verify_anchor_tcp(
|
||||
frame, 0x19, CODE_CLIENT_PORT
|
||||
)
|
||||
assert code_server_sequence is not None
|
||||
assert server_sequence == code_server_sequence + 1
|
||||
assert acknowledgement > CODE_CLIENT_SEQUENCE + 1
|
||||
header, body = payload.split(b"\r\n\r\n", 1)
|
||||
assert b"HTTP/1.1 200 OK" in header
|
||||
assert f"Content-Length: {len(CODE_BODY)}".encode() in header
|
||||
assert body == CODE_BODY
|
||||
code_http_verified = True
|
||||
continue
|
||||
if not anchor_syn_ack_verified:
|
||||
server_sequence, acknowledgement, payload = verify_anchor_tcp(frame, 0x12)
|
||||
assert acknowledgement == ANCHOR_CLIENT_SEQUENCE + 1
|
||||
|
|
@ -249,6 +307,21 @@ def main() -> None:
|
|||
assert b"Content-Length: 286" in header
|
||||
assert body == ANCHOR_BODY
|
||||
anchor_http_verified = True
|
||||
if args.service_equivalence and not code_syn_sent:
|
||||
peer.sendto(
|
||||
tcp_frame(
|
||||
0x02,
|
||||
CODE_CLIENT_SEQUENCE,
|
||||
0,
|
||||
options=(
|
||||
b"\x02\x04\x05\x90\x04\x02\x08\x0a"
|
||||
b"\xd8\x8d\xec\x57\x00\x00\x00\x00\x01\x03\x03\x07"
|
||||
),
|
||||
client_port=CODE_CLIENT_PORT,
|
||||
),
|
||||
qemu,
|
||||
)
|
||||
code_syn_sent = True
|
||||
continue
|
||||
sequence = int.from_bytes(frame[40:42], "big")
|
||||
if sequence <= 3:
|
||||
|
|
@ -273,12 +346,13 @@ def main() -> None:
|
|||
raise AssertionError(f"unexpected native sequence {sequence}")
|
||||
verified_request(frame, sequence, magic)
|
||||
peer.sendto(ordinary_reply(frame), qemu)
|
||||
time.sleep(0.05)
|
||||
time.sleep(0.005 if args.service_equivalence else 0.05)
|
||||
response_capability = NATIVE_ACK_MAGIC
|
||||
if (
|
||||
args.final_resident
|
||||
and resident_login_count >= 3
|
||||
and (not args.anchor_http or anchor_http_verified)
|
||||
and (not args.service_equivalence or code_http_verified)
|
||||
):
|
||||
response_capability = recovery_capability
|
||||
recovery_verified = True
|
||||
|
|
@ -286,9 +360,9 @@ def main() -> None:
|
|||
for repetition in range(4):
|
||||
peer.sendto(reply, qemu)
|
||||
if repetition < 3:
|
||||
time.sleep(0.01)
|
||||
time.sleep(0.001 if args.service_equivalence else 0.01)
|
||||
if (
|
||||
args.anchor_http
|
||||
(args.anchor_http or args.service_equivalence)
|
||||
and args.final_resident
|
||||
and sequence == 6
|
||||
and not anchor_syn_sent
|
||||
|
|
@ -336,12 +410,24 @@ def main() -> None:
|
|||
f"anchor_syn_sent: {str(anchor_syn_sent).lower()}\n"
|
||||
f"anchor_syn_ack_verified: {str(anchor_syn_ack_verified).lower()}\n"
|
||||
f"anchor_get_sent: {str(anchor_get_sent).lower()}\n"
|
||||
f"anchor_http_verified: {str(anchor_http_verified).lower()}\n"
|
||||
f"anchor_http_verified: {str(anchor_http_verified).lower()}\n"
|
||||
f"code_syn_sent: {str(code_syn_sent).lower()}\n"
|
||||
f"code_syn_ack_verified: {str(code_syn_ack_verified).lower()}\n"
|
||||
f"code_get_sent: {str(code_get_sent).lower()}\n"
|
||||
f"code_http_verified: {str(code_http_verified).lower()}\n"
|
||||
"recovery_selected_by_native: false\n"
|
||||
"login_magic: HLDP-GHOS-LOGIN!\n"
|
||||
)
|
||||
return
|
||||
raise SystemExit("timed out waiting for native outbound ICMP exchange")
|
||||
raise SystemExit(
|
||||
"timed out waiting for native service equivalence: "
|
||||
f"anchor_syn_sent={anchor_syn_sent}, "
|
||||
f"anchor_syn_ack_verified={anchor_syn_ack_verified}, "
|
||||
f"anchor_http_verified={anchor_http_verified}, "
|
||||
f"code_syn_sent={code_syn_sent}, "
|
||||
f"code_syn_ack_verified={code_syn_ack_verified}, "
|
||||
f"code_http_verified={code_http_verified}"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ python3 "${source_root}/scripts/qemu-native-net-peer.py" \
|
|||
--qemu-port "${qemu_port}" \
|
||||
--receipt "${test_root}/peer.hldp" \
|
||||
--final-resident \
|
||||
--anchor-http \
|
||||
--service-equivalence \
|
||||
--recovery-token-file "${token_file}" >"${test_root}/peer.log" 2>&1 &
|
||||
peer_pid=$!
|
||||
set +e
|
||||
timeout 40 qemu-system-x86_64 \
|
||||
timeout "${GHOS_QEMU_TIMEOUT_SECONDS:-40}" qemu-system-x86_64 \
|
||||
-machine pc,accel=tcg \
|
||||
-m 64M \
|
||||
-drive "if=none,id=ghboot,format=raw,file=${test_root}/disk.img" \
|
||||
|
|
@ -78,7 +78,10 @@ grep -q '^recovery_reply_verified: true$' "${test_root}/peer.hldp"
|
|||
grep -q '^recovery_selected_by_native: false$' "${test_root}/peer.hldp"
|
||||
grep -q '^anchor_syn_ack_verified: true$' "${test_root}/peer.hldp"
|
||||
grep -q '^anchor_http_verified: true$' "${test_root}/peer.hldp"
|
||||
grep -q '^code_syn_ack_verified: true$' "${test_root}/peer.hldp"
|
||||
grep -q '^code_http_verified: true$' "${test_root}/peer.hldp"
|
||||
grep -q '^GHOS_NATIVE_ANCHOR_HTTP=RESPONSE_TX' "${test_root}/serial.log"
|
||||
grep -q '^GHOS_NATIVE_CODE_CHANNEL_HTTP=RESPONSE_TX' "${test_root}/serial.log"
|
||||
grep -q '^GHOS_NATIVE_RECOVERY_BEACON=WRITE_READ_VERIFIED' "${test_root}/serial.log"
|
||||
grep -q '^GHOS_DISK_PROOF_OBSERVED_AFTER_RESET=LBA134' "${test_root}/serial.log"
|
||||
|
||||
|
|
@ -172,6 +175,13 @@ native_anchor_service:
|
|||
world_node_id: SYS-GLW-0001
|
||||
repository_id: REPO-012
|
||||
runtime: GUANGHU_OS_NATIVE
|
||||
native_code_channel_read_only:
|
||||
http_get_v1_code_channel: PASS_100
|
||||
response_schema: guanghu.native-code-channel-read-only/v1
|
||||
repository_id: REPO-012
|
||||
branch: main
|
||||
commit: fb1096c5ecdcfb36015d51273f487c2f36d9c9cd
|
||||
full_forgejo_equivalence: false
|
||||
recovery_control:
|
||||
selected_by_native_runtime: false
|
||||
per_deployment_capability_required: true
|
||||
|
|
@ -183,7 +193,8 @@ boundary:
|
|||
physical_server_capability: 0
|
||||
native_anchor_http_qemu_capability: 100
|
||||
native_anchor_http_physical_capability: 0
|
||||
code_channel_service_equivalence: 0
|
||||
native_code_channel_read_only_qemu_capability: 100
|
||||
public_code_channel_service_equivalence: 0
|
||||
final_native_residency_proven: false
|
||||
next_action: PHYSICAL_ONE_TIME_NATIVE_ANCHOR_HTTP_GATE_WITH_PROTECTED_RECOVERY
|
||||
next_action: IMPLEMENT_AUTHENTICATED_NATIVE_TO_BS_GZ_006_TRANSPORT_AND_SEPARATE_PUBLIC_ANCHOR_FROM_FULL_CODE_CHANNEL_ACCEPTANCE
|
||||
EOF
|
||||
|
|
|
|||
Loading…
Reference in a new issue