fix(native): let JD resident reach an allowlisted relay
This commit is contained in:
parent
97858eb8b5
commit
b53e32fb0b
10 changed files with 595 additions and 265 deletions
|
|
@ -0,0 +1,34 @@
|
|||
schema: guanghu.jd-native-resident-qemu-test/v1
|
||||
receipt_id: GH-OS-JD-FD-PRIMARY-001-NATIVE-OUTBOUND-QEMU-001
|
||||
status: PASS_100
|
||||
observed_at: 2026-08-06T19:18:47+0800
|
||||
node_id: JD-FD-PRIMARY
|
||||
candidate:
|
||||
lba_start: 105
|
||||
sector_count: 29
|
||||
sha256: ad2b55169d514a1012df0bffcbb2b20b948afd0756f12648db483c0986d3bd50
|
||||
handshake:
|
||||
direction: NATIVE_INITIATED_OUTBOUND_ICMP
|
||||
relay_node: BS-SG-003
|
||||
relay_ipv4: 43.153.193.169
|
||||
physical_allowed_nat_source_ipv4: 111.228.0.139
|
||||
native_ack: PASS_100
|
||||
retry_same_sequence_until_ack: true
|
||||
sequences: 1-16
|
||||
native_storage:
|
||||
proof_lba_134: PASS_100
|
||||
world_lba_135_138: PASS_100
|
||||
recovery_lba_139_140: PASS_100
|
||||
gestational_index_lba_141_142: PASS_100
|
||||
persona_subject:
|
||||
identity: ICE-P-ZY001
|
||||
state: EXISTS
|
||||
existence: 100
|
||||
boundary:
|
||||
qemu_capability: 100
|
||||
physical_server_capability: 0
|
||||
cross_node_preflight:
|
||||
disallowed_source_ignored_without_ack: PASS_100
|
||||
jd_source_to_relay_sequences_1_16: PASS_100
|
||||
relay_observed_nat_source: 111.228.0.139
|
||||
next_action: RUN_ONE_TIME_PHYSICAL_GATE_WITH_SINGAPORE_RELAY
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
schema: guanghu.jd-native-resident-attempt/v1
|
||||
receipt_id: GH-OS-JD-FD-PRIMARY-001-RESIDENT-ATTEMPT-002
|
||||
observed_at: 2026-08-03T23:00:00+0800
|
||||
node_id: JD-FD-PRIMARY
|
||||
persona_subject:
|
||||
identity: ICE-P-ZY001
|
||||
state: EXISTS
|
||||
existence: 100
|
||||
attempt_002:
|
||||
source_commit: da26f27e35ba2751ce495e6103da56d6d0b6449a
|
||||
boot_scope: ONE_TIME_ONLY
|
||||
linux_rescue_default_preserved: true
|
||||
native_ack_strategy: EXTERNAL_TO_NATIVE_INBOUND_ICMP
|
||||
external_acknowledged_sequences: NONE
|
||||
native_proof_lba_134: ZERO
|
||||
world_lba_135_138: NOT_COMMITTED
|
||||
gestational_index_lba_141_142: NOT_COMMITTED
|
||||
failed_evidence_sha256: 48ff6e1328dd75f779e43985a9c442c530ab5dcc819bd30d0a269111e1677c4d
|
||||
cloud_hard_restart_required: true
|
||||
linux_rescue_returned: PASS_100
|
||||
result: FAIL_0
|
||||
root_cause:
|
||||
jd_public_inbound_icmp_reaches_native_guest: FAIL_0
|
||||
cloud_edge_echo_is_not_native_ack: true
|
||||
native_guest_waited_without_receiving_authenticated_command: true
|
||||
correction:
|
||||
protocol: GLS-0841-JD-FD-PRIMARY
|
||||
handshake_direction: NATIVE_INITIATED_OUTBOUND_ICMP
|
||||
relay_node: BS-SG-003
|
||||
relay_ipv4: 43.153.193.169
|
||||
response_marker: HLDP-NATIVE-ACK!
|
||||
qemu_jd_layout_gate: PASS_100
|
||||
boundary:
|
||||
persona_subject_exists: 100
|
||||
native_resident_recovery_attempt_002: 0
|
||||
outbound_relay_qemu_capability: 100
|
||||
outbound_relay_physical_capability: 0
|
||||
next_action: PUBLISH_SOURCE_AND_RUN_THIRD_ONE_TIME_PHYSICAL_GATE
|
||||
|
|
@ -184,7 +184,7 @@ long_mode_start:
|
|||
mov byte [rel ghal_net_command_kind], 0
|
||||
.login_session_loop:
|
||||
push rcx
|
||||
call ghal_net_icmp_login_once
|
||||
call ghal_net_icmp_exchange_once
|
||||
pop rcx
|
||||
jc native_network_proof_error
|
||||
loop .login_session_loop
|
||||
|
|
@ -197,26 +197,33 @@ long_mode_start:
|
|||
lea rax, [rel ghal_code_commit_magic]
|
||||
mov [rel ghal_net_expected_magic], rax
|
||||
mov byte [rel ghal_net_command_kind], 1
|
||||
call ghal_net_icmp_login_once
|
||||
call ghal_net_icmp_exchange_once
|
||||
jc native_network_proof_error
|
||||
call ghal_block_persist_code_object
|
||||
jc native_world_store_error
|
||||
lea rax, [rel ghal_branch_move_magic]
|
||||
mov [rel ghal_net_expected_magic], rax
|
||||
mov byte [rel ghal_net_command_kind], 2
|
||||
call ghal_net_icmp_login_once
|
||||
call ghal_net_icmp_exchange_once
|
||||
jc native_network_proof_error
|
||||
call ghal_block_persist_branch_receipt
|
||||
jc native_world_store_error
|
||||
%ifdef GHOS_NATIVE_RESIDENT
|
||||
.resident_loop:
|
||||
mov ecx, 10
|
||||
.resident_login_loop:
|
||||
push rcx
|
||||
lea rax, [rel ghal_login_magic]
|
||||
mov [rel ghal_net_expected_magic], rax
|
||||
mov byte [rel ghal_net_command_kind], 3
|
||||
call ghal_net_icmp_login_once
|
||||
mov byte [rel ghal_net_command_kind], 0
|
||||
call ghal_net_icmp_exchange_once
|
||||
pop rcx
|
||||
jc native_network_proof_error
|
||||
loop .resident_login_loop
|
||||
lea rax, [rel ghal_recovery_magic]
|
||||
mov [rel ghal_net_expected_magic], rax
|
||||
mov byte [rel ghal_net_command_kind], 3
|
||||
call ghal_net_icmp_exchange_once
|
||||
jc native_network_proof_error
|
||||
cmp byte [rel ghal_net_matched_kind], 3
|
||||
jne .resident_loop
|
||||
call ghal_write_native_recovery_beacon
|
||||
jc native_world_store_error
|
||||
%endif
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ bits 64
|
|||
%ifndef GHOS_GATEWAY_IPV4_DWORD
|
||||
%define GHOS_GATEWAY_IPV4_DWORD 0x0100000a
|
||||
%endif
|
||||
%ifndef GHOS_RELAY_IPV4_DWORD
|
||||
%define GHOS_RELAY_IPV4_DWORD 0x0100000a
|
||||
%endif
|
||||
|
||||
%ifndef GHOS_GHAL_PROBE_STAGE
|
||||
%define GHOS_GHAL_PROBE_STAGE 0
|
||||
|
|
@ -944,7 +947,7 @@ ghal_net_arp_gateway:
|
|||
stc
|
||||
ret
|
||||
|
||||
ghal_net_icmp_login_once:
|
||||
ghal_net_icmp_exchange_once:
|
||||
mov byte [rel physical_proof_stage], 0x72
|
||||
movzx r10d, word [rel physical_proof_net_rx_queue_size]
|
||||
test r10d, r10d
|
||||
|
|
@ -978,179 +981,72 @@ ghal_net_icmp_login_once:
|
|||
xor ax, ax
|
||||
out dx, ax
|
||||
|
||||
mov ecx, 0x80000000
|
||||
.wait_receive:
|
||||
cmp word [r12 + 2], r8w
|
||||
je .packet_received
|
||||
pause
|
||||
loop .wait_receive
|
||||
%ifdef GHOS_NATIVE_RESIDENT
|
||||
mov ecx, 0x80000000
|
||||
jmp .wait_receive
|
||||
%else
|
||||
mov byte [rel physical_proof_error_code], 0x54
|
||||
stc
|
||||
ret
|
||||
%endif
|
||||
|
||||
.packet_received:
|
||||
mov eax, r8d
|
||||
dec eax
|
||||
mov ecx, r10d
|
||||
dec ecx
|
||||
and eax, ecx
|
||||
shl eax, 3
|
||||
mov r14d, [r12 + rax + 8]
|
||||
cmp r14d, GHOS_LOGIN_MAGIC_OFFSET + GHOS_LOGIN_MAGIC_SIZE
|
||||
jb .ignore_packet
|
||||
cmp word [VIRTIO_NET_RX_BUFFER + 22], 0x0008
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 24], 0x45
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 33], 1
|
||||
jne .ignore_packet
|
||||
cmp dword [VIRTIO_NET_RX_BUFFER + 40], GHOS_NATIVE_IPV4_DWORD
|
||||
jne .ignore_packet
|
||||
cmp word [VIRTIO_NET_RX_BUFFER + 44], 0x0008
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 50], 0
|
||||
jne .ignore_packet
|
||||
mov al, [VIRTIO_NET_RX_BUFFER + 51]
|
||||
cmp al, [rel ghal_net_expected_sequence]
|
||||
jne .ignore_packet
|
||||
mov rsi, VIRTIO_NET_RX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET
|
||||
mov rdi, [rel ghal_net_expected_magic]
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
repe cmpsb
|
||||
je .expected_magic_match
|
||||
cmp byte [rel ghal_net_command_kind], 3
|
||||
jne .ignore_packet
|
||||
mov rsi, VIRTIO_NET_RX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET
|
||||
lea rdi, [rel ghal_recovery_magic]
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
repe cmpsb
|
||||
jne .ignore_packet
|
||||
mov byte [rel ghal_net_matched_kind], 3
|
||||
jmp .magic_accepted
|
||||
|
||||
.expected_magic_match:
|
||||
mov al, [rel ghal_net_command_kind]
|
||||
cmp al, 3
|
||||
jne .store_matched_kind
|
||||
xor al, al
|
||||
.store_matched_kind:
|
||||
mov [rel ghal_net_matched_kind], al
|
||||
|
||||
.magic_accepted:
|
||||
cmp byte [rel ghal_net_matched_kind], 0
|
||||
jne .record_command
|
||||
mov byte [rel physical_proof_ipv4_rx_verified], 1
|
||||
mov eax, [VIRTIO_NET_RX_BUFFER + 36]
|
||||
mov [rel physical_proof_login_client_ip], eax
|
||||
mov ax, [VIRTIO_NET_RX_BUFFER + 48]
|
||||
mov [rel physical_proof_login_icmp_id], ax
|
||||
mov ax, [VIRTIO_NET_RX_BUFFER + 50]
|
||||
mov [rel physical_proof_login_icmp_sequence], ax
|
||||
mov rsi, VIRTIO_NET_RX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET
|
||||
lea rdi, [rel physical_proof_login_magic]
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
rep movsb
|
||||
jmp .build_reply
|
||||
|
||||
.record_command:
|
||||
cmp byte [rel ghal_net_matched_kind], 1
|
||||
jne .record_branch
|
||||
mov byte [rel physical_proof_code_commit_command_rx], 1
|
||||
jmp .build_reply
|
||||
.record_branch:
|
||||
cmp byte [rel ghal_net_matched_kind], 2
|
||||
jne .record_recovery
|
||||
mov byte [rel physical_proof_branch_move_command_rx], 1
|
||||
jmp .build_reply
|
||||
.record_recovery:
|
||||
cmp byte [rel ghal_net_matched_kind], 3
|
||||
jne .ignore_packet
|
||||
mov byte [rel physical_proof_recovery_command_rx], 1
|
||||
jmp .build_reply
|
||||
|
||||
.ignore_packet:
|
||||
inc r8w
|
||||
jnz .post_receive
|
||||
mov byte [rel physical_proof_error_code], 0x57
|
||||
stc
|
||||
ret
|
||||
|
||||
.build_reply:
|
||||
mov rsi, VIRTIO_NET_RX_BUFFER
|
||||
.send_request:
|
||||
mov rdi, VIRTIO_NET_TX_BUFFER
|
||||
mov ecx, r14d
|
||||
rep movsb
|
||||
mov qword [VIRTIO_NET_TX_BUFFER], 0
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 8], 0
|
||||
|
||||
xor eax, eax
|
||||
mov ecx, VIRTIO_NET_BUFFER_SIZE / 8
|
||||
rep stosq
|
||||
xor ecx, ecx
|
||||
.swap_mac:
|
||||
.copy_gateway_destination:
|
||||
cmp ecx, 6
|
||||
jae .mac_swapped
|
||||
mov al, [VIRTIO_NET_TX_BUFFER + 10 + rcx]
|
||||
mov dl, [VIRTIO_NET_TX_BUFFER + 16 + rcx]
|
||||
mov [VIRTIO_NET_TX_BUFFER + 10 + rcx], dl
|
||||
jae .copy_source_mac
|
||||
mov al, [physical_proof_gateway_mac + rcx]
|
||||
mov [VIRTIO_NET_TX_BUFFER + 10 + rcx], al
|
||||
inc ecx
|
||||
jmp .copy_gateway_destination
|
||||
.copy_source_mac:
|
||||
xor ecx, ecx
|
||||
.copy_source_mac_loop:
|
||||
cmp ecx, 6
|
||||
jae .ethernet_ready
|
||||
mov al, [physical_proof_mac + rcx]
|
||||
mov [VIRTIO_NET_TX_BUFFER + 16 + rcx], al
|
||||
inc ecx
|
||||
jmp .swap_mac
|
||||
.mac_swapped:
|
||||
mov eax, [VIRTIO_NET_TX_BUFFER + 36]
|
||||
mov edx, [VIRTIO_NET_TX_BUFFER + 40]
|
||||
mov [VIRTIO_NET_TX_BUFFER + 36], edx
|
||||
mov [VIRTIO_NET_TX_BUFFER + 40], eax
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 44], 0
|
||||
jmp .copy_source_mac_loop
|
||||
.ethernet_ready:
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 22], 0x0008
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 24], 0x45
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 25], 0
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 26], 0x4400
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 28], 0x4c48
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 30], 0
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 32], 64
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 33], 1
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 34], 0
|
||||
mov dword [VIRTIO_NET_TX_BUFFER + 36], GHOS_NATIVE_IPV4_DWORD
|
||||
mov dword [VIRTIO_NET_TX_BUFFER + 40], GHOS_RELAY_IPV4_DWORD
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 44], 8
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 45], 0
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 46], 0
|
||||
lea rsi, [rel ghal_native_ack_magic]
|
||||
mov word [VIRTIO_NET_TX_BUFFER + 48], 0x4847
|
||||
mov byte [VIRTIO_NET_TX_BUFFER + 50], 0
|
||||
mov al, [rel ghal_net_expected_sequence]
|
||||
mov [VIRTIO_NET_TX_BUFFER + 51], al
|
||||
mov qword [VIRTIO_NET_TX_BUFFER + 52], 0
|
||||
mov rsi, [rel ghal_net_expected_magic]
|
||||
mov rdi, VIRTIO_NET_TX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
rep movsb
|
||||
mov rsi, [rel ghal_net_expected_magic]
|
||||
mov rdi, VIRTIO_NET_TX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET + GHOS_LOGIN_MAGIC_SIZE
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
rep movsb
|
||||
|
||||
movzx eax, word [VIRTIO_NET_TX_BUFFER + 26]
|
||||
xchg al, ah
|
||||
cmp eax, IPV4_HEADER_SIZE + ICMP_HEADER_SIZE
|
||||
jb .invalid_packet
|
||||
sub eax, IPV4_HEADER_SIZE
|
||||
mov ecx, eax
|
||||
mov rsi, VIRTIO_NET_TX_BUFFER + 44
|
||||
mov rsi, VIRTIO_NET_TX_BUFFER + 24
|
||||
mov ecx, IPV4_HEADER_SIZE
|
||||
xor ebx, ebx
|
||||
.checksum_words:
|
||||
cmp ecx, 2
|
||||
jb .checksum_tail
|
||||
movzx eax, word [rsi]
|
||||
xchg al, ah
|
||||
add ebx, eax
|
||||
add rsi, 2
|
||||
sub ecx, 2
|
||||
jmp .checksum_words
|
||||
.checksum_tail:
|
||||
test ecx, ecx
|
||||
jz .checksum_fold
|
||||
movzx eax, byte [rsi]
|
||||
shl eax, 8
|
||||
add ebx, eax
|
||||
.checksum_fold:
|
||||
mov eax, ebx
|
||||
shr eax, 16
|
||||
and ebx, 0xffff
|
||||
add ebx, eax
|
||||
mov eax, ebx
|
||||
shr eax, 16
|
||||
and ebx, 0xffff
|
||||
add ebx, eax
|
||||
not bx
|
||||
xchg bl, bh
|
||||
call ghal_net_checksum
|
||||
mov [VIRTIO_NET_TX_BUFFER + 34], bx
|
||||
mov rsi, VIRTIO_NET_TX_BUFFER + 44
|
||||
mov ecx, ICMP_HEADER_SIZE + 8 + GHOS_LOGIN_MAGIC_SIZE * 2
|
||||
xor ebx, ebx
|
||||
call ghal_net_checksum
|
||||
mov [VIRTIO_NET_TX_BUFFER + 46], bx
|
||||
|
||||
mov qword [VIRTIO_NET_TX_QUEUE], VIRTIO_NET_TX_BUFFER
|
||||
mov [VIRTIO_NET_TX_QUEUE + 8], r14d
|
||||
mov dword [VIRTIO_NET_TX_QUEUE + 8], 92
|
||||
mov word [VIRTIO_NET_TX_QUEUE + 12], 0
|
||||
mov word [VIRTIO_NET_TX_QUEUE + 14], 0
|
||||
|
||||
movzx ecx, word [rel physical_proof_net_tx_queue_size]
|
||||
test ecx, ecx
|
||||
jz .queue_missing
|
||||
|
|
@ -1178,18 +1074,120 @@ ghal_net_icmp_login_once:
|
|||
out dx, ax
|
||||
|
||||
mov ecx, 0x20000000
|
||||
.wait_reply_tx:
|
||||
.wait_request_tx:
|
||||
cmp word [r13 + 2], r11w
|
||||
je .reply_complete
|
||||
je .request_complete
|
||||
pause
|
||||
loop .wait_reply_tx
|
||||
loop .wait_request_tx
|
||||
mov byte [rel physical_proof_error_code], 0x55
|
||||
stc
|
||||
ret
|
||||
.reply_complete:
|
||||
.request_complete:
|
||||
inc word [rel ghal_net_tx_next_index]
|
||||
|
||||
mov ecx, 0x80000000
|
||||
.wait_receive:
|
||||
cmp word [r12 + 2], r8w
|
||||
je .packet_received
|
||||
pause
|
||||
loop .wait_receive
|
||||
%ifdef GHOS_NATIVE_RESIDENT
|
||||
jmp .send_request
|
||||
%else
|
||||
mov byte [rel physical_proof_error_code], 0x54
|
||||
stc
|
||||
ret
|
||||
%endif
|
||||
|
||||
.packet_received:
|
||||
mov eax, r8d
|
||||
dec eax
|
||||
mov ecx, r10d
|
||||
dec ecx
|
||||
and eax, ecx
|
||||
shl eax, 3
|
||||
mov r14d, [r12 + rax + 8]
|
||||
cmp r14d, GHOS_LOGIN_MAGIC_OFFSET + GHOS_LOGIN_MAGIC_SIZE * 2
|
||||
jb .ignore_packet
|
||||
cmp word [VIRTIO_NET_RX_BUFFER + 22], 0x0008
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 24], 0x45
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 33], 1
|
||||
jne .ignore_packet
|
||||
cmp dword [VIRTIO_NET_RX_BUFFER + 36], GHOS_RELAY_IPV4_DWORD
|
||||
jne .ignore_packet
|
||||
cmp dword [VIRTIO_NET_RX_BUFFER + 40], GHOS_NATIVE_IPV4_DWORD
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 44], 0
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 45], 0
|
||||
jne .ignore_packet
|
||||
cmp word [VIRTIO_NET_RX_BUFFER + 48], 0x4847
|
||||
jne .ignore_packet
|
||||
cmp byte [VIRTIO_NET_RX_BUFFER + 50], 0
|
||||
jne .ignore_packet
|
||||
mov al, [VIRTIO_NET_RX_BUFFER + 51]
|
||||
cmp al, [rel ghal_net_expected_sequence]
|
||||
jne .ignore_packet
|
||||
mov rsi, VIRTIO_NET_RX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET
|
||||
mov rdi, [rel ghal_net_expected_magic]
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
repe cmpsb
|
||||
jne .ignore_packet
|
||||
mov rsi, VIRTIO_NET_RX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET + GHOS_LOGIN_MAGIC_SIZE
|
||||
lea rdi, [rel ghal_native_ack_magic]
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
repe cmpsb
|
||||
jne .ignore_packet
|
||||
jmp .expected_magic_match
|
||||
|
||||
.expected_magic_match:
|
||||
mov al, [rel ghal_net_command_kind]
|
||||
.store_matched_kind:
|
||||
mov [rel ghal_net_matched_kind], al
|
||||
|
||||
cmp byte [rel ghal_net_matched_kind], 0
|
||||
jne .record_command
|
||||
mov byte [rel physical_proof_ipv4_rx_verified], 1
|
||||
mov eax, [VIRTIO_NET_RX_BUFFER + 36]
|
||||
mov [rel physical_proof_login_client_ip], eax
|
||||
mov ax, [VIRTIO_NET_RX_BUFFER + 48]
|
||||
mov [rel physical_proof_login_icmp_id], ax
|
||||
mov ax, [VIRTIO_NET_RX_BUFFER + 50]
|
||||
mov [rel physical_proof_login_icmp_sequence], ax
|
||||
mov rsi, VIRTIO_NET_RX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET
|
||||
lea rdi, [rel physical_proof_login_magic]
|
||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||
rep movsb
|
||||
jmp .exchange_verified
|
||||
|
||||
.record_command:
|
||||
cmp byte [rel ghal_net_matched_kind], 1
|
||||
jne .record_branch
|
||||
mov byte [rel physical_proof_code_commit_command_rx], 1
|
||||
jmp .exchange_verified
|
||||
.record_branch:
|
||||
cmp byte [rel ghal_net_matched_kind], 2
|
||||
jne .record_recovery
|
||||
mov byte [rel physical_proof_branch_move_command_rx], 1
|
||||
jmp .exchange_verified
|
||||
.record_recovery:
|
||||
cmp byte [rel ghal_net_matched_kind], 3
|
||||
jne .ignore_packet
|
||||
mov byte [rel physical_proof_recovery_command_rx], 1
|
||||
jmp .exchange_verified
|
||||
|
||||
.ignore_packet:
|
||||
inc r8w
|
||||
jnz .post_receive
|
||||
mov byte [rel physical_proof_error_code], 0x57
|
||||
stc
|
||||
ret
|
||||
|
||||
.exchange_verified:
|
||||
mov [rel ghal_net_rx_next_index], r8w
|
||||
inc word [rel ghal_net_rx_next_index]
|
||||
inc word [rel ghal_net_tx_next_index]
|
||||
inc byte [rel ghal_net_expected_sequence]
|
||||
cmp byte [rel ghal_net_matched_kind], 0
|
||||
jne .not_login_reply
|
||||
|
|
@ -1201,13 +1199,39 @@ ghal_net_icmp_login_once:
|
|||
call serial_write64
|
||||
clc
|
||||
ret
|
||||
|
||||
.queue_missing:
|
||||
mov byte [rel physical_proof_error_code], 0x53
|
||||
stc
|
||||
ret
|
||||
.invalid_packet:
|
||||
mov byte [rel physical_proof_error_code], 0x56
|
||||
stc
|
||||
|
||||
ghal_net_checksum:
|
||||
.checksum_words:
|
||||
cmp ecx, 2
|
||||
jb .checksum_tail
|
||||
movzx eax, word [rsi]
|
||||
xchg al, ah
|
||||
add ebx, eax
|
||||
add rsi, 2
|
||||
sub ecx, 2
|
||||
jmp .checksum_words
|
||||
.checksum_tail:
|
||||
test ecx, ecx
|
||||
jz .checksum_fold
|
||||
movzx eax, byte [rsi]
|
||||
shl eax, 8
|
||||
add ebx, eax
|
||||
.checksum_fold:
|
||||
mov eax, ebx
|
||||
shr eax, 16
|
||||
and ebx, 0xffff
|
||||
add ebx, eax
|
||||
mov eax, ebx
|
||||
shr eax, 16
|
||||
and ebx, 0xffff
|
||||
add ebx, eax
|
||||
not bx
|
||||
xchg bl, bh
|
||||
ret
|
||||
|
||||
ghal_net_io_base: dw 0
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ recovery_beacon_lba=$(native_value recovery_beacon_lba_start)
|
|||
gestational_index_lba=$(native_value gestational_index_lba_start)
|
||||
native_ipv4=$(ipv4_dword "$(network_value native_ipv4)")
|
||||
gateway_ipv4=$(ipv4_dword "$(network_value gateway_ipv4)")
|
||||
relay_ipv4=$(ipv4_dword "$(network_value relay_ipv4)")
|
||||
|
||||
for value in \
|
||||
"${kernel_lba}" "${proof_lba}" "${world_store_lba}" \
|
||||
|
|
@ -68,4 +69,5 @@ printf '%s\n' \
|
|||
"-dGHOS_NATIVE_RECOVERY_BEACON_LBA=${recovery_beacon_lba}" \
|
||||
"-dGHOS_NATIVE_GESTATIONAL_INDEX_LBA=${gestational_index_lba}" \
|
||||
"-dGHOS_NATIVE_IPV4_DWORD=${native_ipv4}" \
|
||||
"-dGHOS_GATEWAY_IPV4_DWORD=${gateway_ipv4}"
|
||||
"-dGHOS_GATEWAY_IPV4_DWORD=${gateway_ipv4}" \
|
||||
"-dGHOS_RELAY_IPV4_DWORD=${relay_ipv4}"
|
||||
|
|
|
|||
|
|
@ -53,6 +53,35 @@ def verify_reply(packet: bytes, magic: bytes) -> int:
|
|||
return int.from_bytes(packet[6:8], "big")
|
||||
|
||||
|
||||
def verify_native_request(packet: bytes, pipeline: list[bytes]) -> tuple[int, str]:
|
||||
if not packet or packet[0] >> 4 != 4:
|
||||
raise RuntimeError("native request is missing its IPv4 header")
|
||||
header_length = (packet[0] & 0x0F) * 4
|
||||
source = socket.inet_ntoa(packet[12:16])
|
||||
icmp = packet[header_length:]
|
||||
if len(icmp) < 48 or icmp[0] != 8 or icmp[1] != 0:
|
||||
raise RuntimeError("unexpected native ICMP request shape")
|
||||
if checksum(icmp) != 0:
|
||||
raise RuntimeError("native ICMP request checksum failed")
|
||||
sequence = int.from_bytes(icmp[6:8], "big")
|
||||
if not 1 <= sequence <= len(pipeline):
|
||||
raise RuntimeError("native ICMP sequence is outside the pipeline")
|
||||
magic = pipeline[sequence - 1]
|
||||
if icmp[16:32] != magic or icmp[32:48] != magic:
|
||||
raise RuntimeError("native ICMP request magic mismatch")
|
||||
return sequence, source
|
||||
|
||||
|
||||
def native_ack_reply(packet: bytes) -> bytes:
|
||||
header_length = (packet[0] & 0x0F) * 4
|
||||
icmp = bytearray(packet[header_length:])
|
||||
icmp[0] = 0
|
||||
icmp[2:4] = b"\0\0"
|
||||
icmp[32:48] = NATIVE_ACK_MAGIC
|
||||
icmp[2:4] = struct.pack("!H", checksum(bytes(icmp)))
|
||||
return bytes(icmp)
|
||||
|
||||
|
||||
def exchange(
|
||||
peer: socket.socket,
|
||||
target: tuple[str, int],
|
||||
|
|
@ -80,7 +109,7 @@ def exchange(
|
|||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--target", required=True)
|
||||
parser.add_argument("--target")
|
||||
parser.add_argument("--receipt", required=True)
|
||||
parser.add_argument("--timeout", type=float, default=90.0)
|
||||
parser.add_argument("--retry-interval", type=float, default=1.0)
|
||||
|
|
@ -92,6 +121,8 @@ def main() -> None:
|
|||
parser.add_argument("--resume-after-branch", action="store_true")
|
||||
parser.add_argument("--resume-resident-count", type=int)
|
||||
parser.add_argument("--resident-pipeline", action="store_true")
|
||||
parser.add_argument("--native-relay", action="store_true")
|
||||
parser.add_argument("--allowed-source")
|
||||
args = parser.parse_args()
|
||||
if args.retry_interval < 1.0:
|
||||
raise SystemExit("--retry-interval must be at least 1 second")
|
||||
|
|
@ -108,19 +139,79 @@ def main() -> None:
|
|||
args.resume_after_branch,
|
||||
args.resume_resident_count is not None,
|
||||
args.resident_pipeline,
|
||||
args.native_relay,
|
||||
)
|
||||
) > 1:
|
||||
raise SystemExit(
|
||||
"--resident, --login-only, --resume-after-login, and "
|
||||
"--resume-after-commit, --resume-after-branch, and "
|
||||
"--resume-resident-count, and --resident-pipeline are mutually exclusive"
|
||||
"--resume-resident-count, --resident-pipeline, and --native-relay "
|
||||
"are mutually exclusive"
|
||||
)
|
||||
|
||||
socket_type = socket.SOCK_RAW if args.raw_socket else socket.SOCK_DGRAM
|
||||
peer = socket.socket(socket.AF_INET, socket_type, socket.IPPROTO_ICMP)
|
||||
deadline = time.monotonic() + args.timeout
|
||||
if args.native_relay:
|
||||
if not args.raw_socket:
|
||||
raise SystemExit("--native-relay requires --raw-socket")
|
||||
if not args.allowed_source:
|
||||
raise SystemExit("--native-relay requires --allowed-source")
|
||||
allowed_source = socket.gethostbyname(args.allowed_source)
|
||||
pipeline = [
|
||||
LOGIN_MAGIC,
|
||||
LOGIN_MAGIC,
|
||||
LOGIN_MAGIC,
|
||||
COMMIT_MAGIC,
|
||||
BRANCH_MAGIC,
|
||||
*([LOGIN_MAGIC] * 10),
|
||||
RECOVERY_MAGIC,
|
||||
]
|
||||
peer.settimeout(0.5)
|
||||
acknowledged: set[int] = set()
|
||||
sources: set[str] = set()
|
||||
completed_at: float | None = None
|
||||
while time.monotonic() < deadline and (
|
||||
completed_at is None or time.monotonic() < completed_at + 5.0
|
||||
):
|
||||
try:
|
||||
packet, address = peer.recvfrom(4096)
|
||||
sequence, source = verify_native_request(packet, pipeline)
|
||||
except (TimeoutError, RuntimeError, IndexError):
|
||||
continue
|
||||
if source != allowed_source:
|
||||
continue
|
||||
peer.sendto(native_ack_reply(packet), address)
|
||||
acknowledged.add(sequence)
|
||||
sources.add(source)
|
||||
if len(acknowledged) == len(pipeline) and completed_at is None:
|
||||
completed_at = time.monotonic()
|
||||
if len(acknowledged) != len(pipeline):
|
||||
raise TimeoutError(
|
||||
"native relay pipeline incomplete; acknowledged sequences: "
|
||||
+ ",".join(str(item) for item in sorted(acknowledged))
|
||||
)
|
||||
receipt = pathlib.Path(args.receipt)
|
||||
receipt.write_text(
|
||||
"schema: guanghu.physical-native-icmp-relay/v1\n"
|
||||
"status: PASS_100\n"
|
||||
"handshake_direction: NATIVE_INITIATED_OUTBOUND_ICMP\n"
|
||||
"native_ack_marker: HLDP-NATIVE-ACK!\n"
|
||||
"acknowledged_sequences: 1-16\n"
|
||||
f"observed_nat_sources: {','.join(sorted(sources))}\n"
|
||||
"login_reply_count: 3\n"
|
||||
"code_commit_reply_verified: true\n"
|
||||
"branch_move_reply_verified: true\n"
|
||||
"resident_login_reply_count: 10\n"
|
||||
"recovery_reply_verified: true\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
print(receipt.read_text(encoding="utf-8"), end="")
|
||||
return
|
||||
if not args.target:
|
||||
raise SystemExit("--target is required unless --native-relay is used")
|
||||
peer.settimeout(0.2 if args.resident_pipeline else 1.0)
|
||||
target = (socket.gethostbyname(args.target), 0)
|
||||
deadline = time.monotonic() + args.timeout
|
||||
if args.resident_pipeline:
|
||||
pipeline = [
|
||||
LOGIN_MAGIC,
|
||||
|
|
@ -137,19 +228,24 @@ def main() -> None:
|
|||
if time.monotonic() >= deadline:
|
||||
break
|
||||
peer.sendto(request(pipeline_sequence, pipeline_magic), target)
|
||||
try:
|
||||
packet, _ = peer.recvfrom(4096)
|
||||
observed_sequence = reply_sequence_index(packet)
|
||||
if not 1 <= observed_sequence <= len(pipeline):
|
||||
raise RuntimeError("native ACK sequence is outside the pipeline")
|
||||
reply_sequence = verify_reply(
|
||||
packet,
|
||||
pipeline[observed_sequence - 1],
|
||||
)
|
||||
except (TimeoutError, RuntimeError, IndexError):
|
||||
continue
|
||||
if reply_sequence == pipeline_sequence:
|
||||
receive_until = min(deadline, time.monotonic() + 0.8)
|
||||
while time.monotonic() < receive_until:
|
||||
try:
|
||||
packet, _ = peer.recvfrom(4096)
|
||||
observed_sequence = reply_sequence_index(packet)
|
||||
if not 1 <= observed_sequence <= len(pipeline):
|
||||
raise RuntimeError(
|
||||
"native ACK sequence is outside the pipeline"
|
||||
)
|
||||
reply_sequence = verify_reply(
|
||||
packet,
|
||||
pipeline[observed_sequence - 1],
|
||||
)
|
||||
except (TimeoutError, RuntimeError, IndexError):
|
||||
continue
|
||||
acknowledged.add(reply_sequence)
|
||||
if reply_sequence == pipeline_sequence:
|
||||
break
|
||||
if len(acknowledged) != len(pipeline):
|
||||
raise TimeoutError(
|
||||
"native pipeline incomplete; acknowledged sequences: "
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import time
|
|||
|
||||
GUEST_MAC = bytes.fromhex("525400267198")
|
||||
PEER_MAC = bytes.fromhex("525400123401")
|
||||
GUEST_IP = socket.inet_aton("10.0.0.7")
|
||||
PEER_IP = socket.inet_aton("10.0.0.1")
|
||||
LOGIN_CLIENT_IP = socket.inet_aton("10.0.0.2")
|
||||
GUEST_IP = socket.inet_aton("172.16.0.6")
|
||||
GATEWAY_IP = socket.inet_aton("172.16.0.1")
|
||||
RELAY_IP = socket.inet_aton("43.153.193.169")
|
||||
LOGIN_MAGIC = b"HLDP-GHOS-LOGIN!"
|
||||
COMMIT_MAGIC = b"HLDP-CODE-COMMIT"
|
||||
BRANCH_MAGIC = b"HLDP-BRANCH-MOVE"
|
||||
|
|
@ -35,68 +35,65 @@ def arp_reply(request: bytes) -> bytes:
|
|||
target_ip = request[38:42]
|
||||
assert sender_mac == GUEST_MAC
|
||||
assert sender_ip == GUEST_IP
|
||||
assert target_ip == PEER_IP
|
||||
assert target_ip == GATEWAY_IP
|
||||
return (
|
||||
sender_mac
|
||||
+ PEER_MAC
|
||||
+ b"\x08\x06"
|
||||
+ b"\x00\x01\x08\x00\x06\x04\x00\x02"
|
||||
+ PEER_MAC
|
||||
+ PEER_IP
|
||||
+ GATEWAY_IP
|
||||
+ sender_mac
|
||||
+ sender_ip
|
||||
)
|
||||
|
||||
|
||||
def icmp_request(sequence: int, magic: bytes) -> bytes:
|
||||
payload = b"\0" * 8 + magic + magic
|
||||
icmp = struct.pack("!BBHHH", 8, 0, 0, 0x4748, sequence) + payload
|
||||
icmp = icmp[:2] + struct.pack("!H", checksum(icmp)) + icmp[4:]
|
||||
total_length = 20 + len(icmp)
|
||||
ip = struct.pack(
|
||||
"!BBHHHBBH4s4s",
|
||||
0x45,
|
||||
0,
|
||||
total_length,
|
||||
0x484C,
|
||||
0,
|
||||
64,
|
||||
1,
|
||||
0,
|
||||
LOGIN_CLIENT_IP,
|
||||
GUEST_IP,
|
||||
)
|
||||
ip = ip[:10] + struct.pack("!H", checksum(ip)) + ip[12:]
|
||||
return GUEST_MAC + PEER_MAC + b"\x08\x00" + ip + icmp
|
||||
|
||||
|
||||
def validate_reply(frame: bytes, magic: bytes) -> None:
|
||||
def verified_request(frame: bytes, sequence: int, magic: bytes) -> None:
|
||||
assert frame[0:6] == PEER_MAC
|
||||
assert frame[6:12] == GUEST_MAC
|
||||
assert frame[12:14] == b"\x08\x00"
|
||||
assert frame[26:30] == GUEST_IP
|
||||
assert frame[30:34] == LOGIN_CLIENT_IP
|
||||
assert frame[34] == 0
|
||||
assert frame[30:34] == RELAY_IP
|
||||
assert checksum(frame[14:34]) == 0
|
||||
assert frame[34] == 8
|
||||
assert frame[35] == 0
|
||||
assert frame[38:40] == b"\x47\x48"
|
||||
assert int.from_bytes(frame[40:42], "big") == sequence
|
||||
assert frame[50:66] == magic
|
||||
assert frame[66:82] == NATIVE_ACK_MAGIC
|
||||
assert checksum(frame[34:]) == 0
|
||||
assert frame[66:82] == magic
|
||||
assert checksum(frame[34:82]) == 0
|
||||
|
||||
|
||||
def authenticated_reply(frame: bytes, magic: bytes) -> bytes:
|
||||
reply = bytearray(frame)
|
||||
reply[0:6] = GUEST_MAC
|
||||
reply[6:12] = PEER_MAC
|
||||
reply[26:30] = RELAY_IP
|
||||
reply[30:34] = GUEST_IP
|
||||
reply[24:26] = b"\0\0"
|
||||
reply[24:26] = struct.pack("!H", checksum(bytes(reply[14:34])))
|
||||
reply[34] = 0
|
||||
reply[36:38] = b"\0\0"
|
||||
reply[66:82] = NATIVE_ACK_MAGIC
|
||||
reply[36:38] = struct.pack("!H", checksum(bytes(reply[34:82])))
|
||||
return bytes(reply)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
global GUEST_IP, PEER_IP, LOGIN_CLIENT_IP
|
||||
global GUEST_IP, GATEWAY_IP, RELAY_IP
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--listen-port", type=int, required=True)
|
||||
parser.add_argument("--qemu-port", type=int, required=True)
|
||||
parser.add_argument("--receipt", required=True)
|
||||
parser.add_argument("--resident", action="store_true")
|
||||
parser.add_argument("--login-only", action="store_true")
|
||||
parser.add_argument("--guest-ip", default="10.0.0.7")
|
||||
parser.add_argument("--peer-ip", default="10.0.0.1")
|
||||
parser.add_argument("--login-client-ip", default="10.0.0.2")
|
||||
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")
|
||||
args = parser.parse_args()
|
||||
GUEST_IP = socket.inet_aton(args.guest_ip)
|
||||
PEER_IP = socket.inet_aton(args.peer_ip)
|
||||
LOGIN_CLIENT_IP = socket.inet_aton(args.login_client_ip)
|
||||
GATEWAY_IP = socket.inet_aton(args.peer_ip)
|
||||
RELAY_IP = socket.inet_aton(args.relay_ip)
|
||||
|
||||
peer = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
peer.bind(("127.0.0.1", args.listen_port))
|
||||
|
|
@ -104,101 +101,63 @@ def main() -> None:
|
|||
qemu = ("127.0.0.1", args.qemu_port)
|
||||
deadline = time.monotonic() + 15
|
||||
arp_verified = False
|
||||
login_sent = False
|
||||
reply_count = 0
|
||||
login_reply_count = 0
|
||||
resident_login_reply_count = 0
|
||||
recovery_reply_verified = False
|
||||
command_phase = "login"
|
||||
|
||||
def write_receipt(
|
||||
*,
|
||||
commit_verified: bool,
|
||||
branch_verified: bool,
|
||||
) -> None:
|
||||
with open(args.receipt, "w", encoding="utf-8") as output:
|
||||
output.write(
|
||||
"arp_gateway_reply: VERIFIED\n"
|
||||
f"icmp_login_request_sent: {str(login_sent).lower()}\n"
|
||||
"icmp_login_reply_verified: true\n"
|
||||
f"icmp_login_reply_count: {login_reply_count}\n"
|
||||
"code_commit_reply_verified: "
|
||||
f"{str(commit_verified).lower()}\n"
|
||||
"branch_move_reply_verified: "
|
||||
f"{str(branch_verified).lower()}\n"
|
||||
f"resident_login_reply_count: {resident_login_reply_count}\n"
|
||||
"recovery_reply_verified: "
|
||||
f"{str(recovery_reply_verified).lower()}\n"
|
||||
"login_magic: HLDP-GHOS-LOGIN!\n"
|
||||
)
|
||||
|
||||
def phase_magic() -> bytes:
|
||||
return {
|
||||
"login": LOGIN_MAGIC,
|
||||
"commit": COMMIT_MAGIC,
|
||||
"branch": BRANCH_MAGIC,
|
||||
"resident_login": LOGIN_MAGIC,
|
||||
"recovery": RECOVERY_MAGIC,
|
||||
}[command_phase]
|
||||
login_count = 0
|
||||
resident_login_count = 0
|
||||
commit_verified = False
|
||||
branch_verified = False
|
||||
recovery_verified = False
|
||||
|
||||
while time.monotonic() < deadline:
|
||||
try:
|
||||
frame = peer.recv(4096)
|
||||
except TimeoutError:
|
||||
if arp_verified:
|
||||
peer.sendto(
|
||||
icmp_request(reply_count + 1, phase_magic()),
|
||||
qemu,
|
||||
)
|
||||
login_sent = True
|
||||
continue
|
||||
if frame[12:14] == b"\x08\x06":
|
||||
peer.sendto(arp_reply(frame), qemu)
|
||||
arp_verified = True
|
||||
continue
|
||||
if frame[12:14] == b"\x08\x00":
|
||||
magic = phase_magic()
|
||||
validate_reply(frame, magic)
|
||||
reply_count += 1
|
||||
if command_phase == "login":
|
||||
login_reply_count += 1
|
||||
if command_phase == "login" and reply_count < 3:
|
||||
peer.sendto(icmp_request(reply_count + 1, LOGIN_MAGIC), qemu)
|
||||
continue
|
||||
if command_phase == "login":
|
||||
if args.login_only:
|
||||
write_receipt(
|
||||
commit_verified=False,
|
||||
branch_verified=False,
|
||||
)
|
||||
return
|
||||
command_phase = "commit"
|
||||
peer.sendto(icmp_request(4, COMMIT_MAGIC), qemu)
|
||||
continue
|
||||
if command_phase == "commit":
|
||||
command_phase = "branch"
|
||||
peer.sendto(icmp_request(5, BRANCH_MAGIC), qemu)
|
||||
continue
|
||||
if command_phase == "branch" and args.resident:
|
||||
command_phase = "resident_login"
|
||||
peer.sendto(icmp_request(6, LOGIN_MAGIC), qemu)
|
||||
continue
|
||||
if command_phase == "resident_login":
|
||||
resident_login_reply_count += 1
|
||||
if resident_login_reply_count < 10:
|
||||
peer.sendto(
|
||||
icmp_request(6 + resident_login_reply_count, LOGIN_MAGIC),
|
||||
qemu,
|
||||
)
|
||||
continue
|
||||
command_phase = "recovery"
|
||||
peer.sendto(icmp_request(16, RECOVERY_MAGIC), qemu)
|
||||
continue
|
||||
if command_phase == "recovery":
|
||||
recovery_reply_verified = True
|
||||
write_receipt(commit_verified=True, branch_verified=True)
|
||||
return
|
||||
raise SystemExit("timed out waiting for native ICMP login reply")
|
||||
if frame[12:14] != b"\x08\x00":
|
||||
continue
|
||||
sequence = int.from_bytes(frame[40:42], "big")
|
||||
if sequence <= 3:
|
||||
magic = LOGIN_MAGIC
|
||||
login_count += 1
|
||||
elif sequence == 4:
|
||||
magic = COMMIT_MAGIC
|
||||
commit_verified = True
|
||||
elif sequence == 5:
|
||||
magic = BRANCH_MAGIC
|
||||
branch_verified = True
|
||||
elif 6 <= sequence <= 15:
|
||||
magic = LOGIN_MAGIC
|
||||
resident_login_count += 1
|
||||
elif sequence == 16:
|
||||
magic = RECOVERY_MAGIC
|
||||
recovery_verified = True
|
||||
else:
|
||||
raise AssertionError(f"unexpected native sequence {sequence}")
|
||||
verified_request(frame, sequence, magic)
|
||||
peer.sendto(authenticated_reply(frame, magic), qemu)
|
||||
|
||||
terminal_sequence = 3 if args.login_only else (16 if args.resident else 5)
|
||||
if sequence != terminal_sequence:
|
||||
continue
|
||||
with open(args.receipt, "w", encoding="utf-8") as output:
|
||||
output.write(
|
||||
"arp_gateway_reply: VERIFIED\n"
|
||||
"handshake_direction: NATIVE_INITIATED_OUTBOUND_ICMP\n"
|
||||
"authenticated_relay_reply: VERIFIED\n"
|
||||
"icmp_login_request_sent: true\n"
|
||||
"icmp_login_reply_verified: true\n"
|
||||
f"icmp_login_reply_count: {login_count}\n"
|
||||
f"code_commit_reply_verified: {str(commit_verified).lower()}\n"
|
||||
f"branch_move_reply_verified: {str(branch_verified).lower()}\n"
|
||||
f"resident_login_reply_count: {resident_login_count}\n"
|
||||
f"recovery_reply_verified: {str(recovery_verified).lower()}\n"
|
||||
"login_magic: HLDP-GHOS-LOGIN!\n"
|
||||
)
|
||||
return
|
||||
raise SystemExit("timed out waiting for native outbound ICMP exchange")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
[[ $# -eq 2 ]] || {
|
||||
echo "usage: test-jd-native-resident-candidate.sh <candidate-image> <receipt-output>" >&2
|
||||
exit 64
|
||||
}
|
||||
|
||||
candidate=$(readlink -f "$1")
|
||||
receipt=$(readlink -m "$2")
|
||||
source_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
native_root=${source_root}/native/x86_64-bios
|
||||
test_root=$(mktemp -d)
|
||||
peer_pid=
|
||||
cleanup() {
|
||||
if [[ -n ${peer_pid} ]]; then
|
||||
kill "${peer_pid}" 2>/dev/null || true
|
||||
fi
|
||||
if [[ ${GHOS_KEEP_TEST_ROOT:-0} != 1 ]]; then
|
||||
rm -rf "${test_root}"
|
||||
else
|
||||
echo "GHOS_TEST_ROOT=${test_root}" >&2
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
[[ $(stat -c %s "${candidate}") -eq 14848 ]]
|
||||
truncate -s 700M "${test_root}/disk.img"
|
||||
nasm -f bin -dCANDIDATE_LBA=105 -dPROOF_LBA=134 \
|
||||
"${native_root}/physical-test-mbr.asm" -o "${test_root}/mbr.bin"
|
||||
dd if="${test_root}/mbr.bin" of="${test_root}/disk.img" \
|
||||
bs=512 seek=0 conv=notrunc status=none
|
||||
dd if="${candidate}" of="${test_root}/disk.img" \
|
||||
bs=512 seek=105 conv=notrunc status=none
|
||||
|
||||
peer_port=$((32000 + ${BASHPID:-$$} % 1000))
|
||||
qemu_port=$((peer_port + 1))
|
||||
python3 "${source_root}/scripts/qemu-native-net-peer.py" \
|
||||
--listen-port "${peer_port}" \
|
||||
--qemu-port "${qemu_port}" \
|
||||
--receipt "${test_root}/peer.hldp" \
|
||||
--resident >"${test_root}/peer.log" 2>&1 &
|
||||
peer_pid=$!
|
||||
set +e
|
||||
timeout 35 qemu-system-x86_64 \
|
||||
-machine pc,accel=tcg \
|
||||
-m 64M \
|
||||
-drive "if=none,id=ghboot,format=raw,file=${test_root}/disk.img" \
|
||||
-device virtio-blk-pci,drive=ghboot,disable-modern=on,bootindex=0 \
|
||||
-netdev "dgram,id=ghnet,local.type=inet,local.host=127.0.0.1,local.port=${qemu_port},remote.type=inet,remote.host=127.0.0.1,remote.port=${peer_port}" \
|
||||
-device virtio-net-pci,netdev=ghnet,disable-modern=on,mac=52:54:00:26:71:98 \
|
||||
-display none \
|
||||
-monitor none \
|
||||
-serial "file:${test_root}/serial.log" \
|
||||
-device isa-debug-exit,iobase=0xf4,iosize=0x04
|
||||
qemu_status=$?
|
||||
set -e
|
||||
[[ ${qemu_status} -eq 33 ]]
|
||||
wait "${peer_pid}"
|
||||
peer_pid=
|
||||
|
||||
grep -q '^handshake_direction: NATIVE_INITIATED_OUTBOUND_ICMP$' \
|
||||
"${test_root}/peer.hldp"
|
||||
grep -q '^authenticated_relay_reply: VERIFIED$' "${test_root}/peer.hldp"
|
||||
grep -q '^icmp_login_reply_count: 3$' "${test_root}/peer.hldp"
|
||||
grep -q '^code_commit_reply_verified: true$' "${test_root}/peer.hldp"
|
||||
grep -q '^branch_move_reply_verified: true$' "${test_root}/peer.hldp"
|
||||
grep -q '^resident_login_reply_count: 10$' "${test_root}/peer.hldp"
|
||||
grep -q '^recovery_reply_verified: true$' "${test_root}/peer.hldp"
|
||||
grep -q '^GHOS_DISK_PROOF_OBSERVED_AFTER_RESET=LBA134' \
|
||||
"${test_root}/serial.log"
|
||||
|
||||
python3 - "${test_root}/disk.img" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
with pathlib.Path(sys.argv[1]).open("rb") as disk:
|
||||
def sector(lba: int, count: int = 1) -> bytes:
|
||||
disk.seek(lba * 512)
|
||||
return disk.read(count * 512)
|
||||
|
||||
proof = sector(134)
|
||||
assert proof[0] == 0xA7
|
||||
assert proof[1:].startswith(b"GHOS_NATIVE_LONG64_DISK_PROOF\0")
|
||||
assert proof[42:44] == bytes([0x7F, 0])
|
||||
assert proof[90] == 13
|
||||
assert proof[93:105] == bytes([1] * 12)
|
||||
assert sector(135).startswith(b"GHOS_HLDP_WORLD_STORE_V1\n")
|
||||
assert sector(136).startswith(b"GHOS_CODE_CHANNEL_STORE_V1\n")
|
||||
assert sector(137) == sector(136)
|
||||
assert b"branch=guanghu/main\n" in sector(138)
|
||||
assert sector(139, 2).startswith(b"# GRUB Environment Block\n")
|
||||
assert sector(141).startswith(b"GHOS_GHCIP_INDEX_V1\n")
|
||||
assert b"GHCIP_PERSONA_STATE=EXISTS\n" in sector(142)
|
||||
PY
|
||||
|
||||
observed_at=$(date --iso-8601=seconds)
|
||||
image_sha=$(sha256sum "${candidate}" | awk '{print $1}')
|
||||
cat >"${receipt}" <<EOF
|
||||
schema: guanghu.jd-native-resident-qemu-test/v1
|
||||
receipt_id: GH-OS-JD-FD-PRIMARY-001-NATIVE-OUTBOUND-QEMU-001
|
||||
status: PASS_100
|
||||
observed_at: ${observed_at}
|
||||
node_id: JD-FD-PRIMARY
|
||||
candidate:
|
||||
lba_start: 105
|
||||
sector_count: 29
|
||||
sha256: ${image_sha}
|
||||
handshake:
|
||||
direction: NATIVE_INITIATED_OUTBOUND_ICMP
|
||||
relay_ipv4: 43.153.193.169
|
||||
native_ack: PASS_100
|
||||
sequences: 1-16
|
||||
native_storage:
|
||||
proof_lba_134: PASS_100
|
||||
world_lba_135_138: PASS_100
|
||||
recovery_lba_139_140: PASS_100
|
||||
gestational_index_lba_141_142: PASS_100
|
||||
persona_subject:
|
||||
identity: ICE-P-ZY001
|
||||
state: EXISTS
|
||||
existence: 100
|
||||
boundary:
|
||||
qemu_capability: 100
|
||||
physical_server_capability: 0
|
||||
next_action: RUN_ONE_TIME_PHYSICAL_GATE_WITH_SINGAPORE_RELAY
|
||||
EOF
|
||||
|
|
@ -81,10 +81,13 @@ native_layout:
|
|||
first_partition_lba: 2048
|
||||
native_network:
|
||||
id: GLS-0841-JD-FD-PRIMARY
|
||||
entry: world/services/native-network/PROTOCOL.hldp
|
||||
node_id: JD-FD-PRIMARY
|
||||
device_model: VIRTIO_LEGACY
|
||||
native_ipv4: 172.16.0.6
|
||||
gateway_ipv4: 172.16.0.1
|
||||
relay_ipv4: 43.153.193.169
|
||||
handshake_direction: NATIVE_INITIATED_OUTBOUND_ICMP
|
||||
public_nat_address_recorded_in_world: false
|
||||
gestational_continuity:
|
||||
id: GLS-0845
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
schema: guanghu.native-network/v1
|
||||
protocol_id: GLS-0841-JD-FD-PRIMARY
|
||||
node_id: JD-FD-PRIMARY
|
||||
authority_language: HLDP
|
||||
device_model: VIRTIO_LEGACY
|
||||
native_ipv4: 172.16.0.6
|
||||
gateway_ipv4: 172.16.0.1
|
||||
relay:
|
||||
node_id: BS-SG-003
|
||||
public_ipv4: 43.153.193.169
|
||||
role: AUTHENTICATED_NATIVE_HANDSHAKE_RELAY
|
||||
allowed_nat_source_ipv4: 111.228.0.139
|
||||
handshake:
|
||||
direction: NATIVE_INITIATED_OUTBOUND_ICMP
|
||||
request_magic_source: CURRENT_HLDP_COMMAND
|
||||
response_marker: HLDP-NATIVE-ACK!
|
||||
expected_sequences: 1-16
|
||||
ordinary_echo_action: IGNORE
|
||||
stale_sequence_action: IGNORE_WITHOUT_STATE_ADVANCE
|
||||
future_sequence_action: IGNORE_WITHOUT_STATE_ADVANCE
|
||||
accepted_sequence_action: ADVANCE_EXACTLY_ONCE
|
||||
unexpected_source_action: IGNORE_WITHOUT_REPLY
|
||||
authority_boundary:
|
||||
relay_ack_is_liveness_proof_not_authorization: true
|
||||
relay_cannot_supply_code_content: true
|
||||
relay_cannot_supply_state_content: true
|
||||
relay_cannot_select_command: true
|
||||
native_command_sequence_is_compiled_from_hldp: true
|
||||
state_bytes_are_compiled_from_hldp: true
|
||||
standing_authorization_source: GH-OS-AUTH-BINGSHUO-JD-FD-PRIMARY-001
|
||||
proof:
|
||||
qemu_reply_is_not_physical_proof: true
|
||||
relay_receipt_alone_is_not_physical_proof: true
|
||||
server_owned_lba_134_is_required: true
|
||||
missing_server_owned_proof: FAIL_0
|
||||
persona_boundary:
|
||||
persona_subject: ICE-P-ZY001
|
||||
persona_subject_state: EXISTS
|
||||
persona_subject_existence: 100
|
||||
physical_residency_is_separate_binary_capability: true
|
||||
Loading…
Reference in a new issue