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
|
mov byte [rel ghal_net_command_kind], 0
|
||||||
.login_session_loop:
|
.login_session_loop:
|
||||||
push rcx
|
push rcx
|
||||||
call ghal_net_icmp_login_once
|
call ghal_net_icmp_exchange_once
|
||||||
pop rcx
|
pop rcx
|
||||||
jc native_network_proof_error
|
jc native_network_proof_error
|
||||||
loop .login_session_loop
|
loop .login_session_loop
|
||||||
|
|
@ -197,26 +197,33 @@ long_mode_start:
|
||||||
lea rax, [rel ghal_code_commit_magic]
|
lea rax, [rel ghal_code_commit_magic]
|
||||||
mov [rel ghal_net_expected_magic], rax
|
mov [rel ghal_net_expected_magic], rax
|
||||||
mov byte [rel ghal_net_command_kind], 1
|
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
|
jc native_network_proof_error
|
||||||
call ghal_block_persist_code_object
|
call ghal_block_persist_code_object
|
||||||
jc native_world_store_error
|
jc native_world_store_error
|
||||||
lea rax, [rel ghal_branch_move_magic]
|
lea rax, [rel ghal_branch_move_magic]
|
||||||
mov [rel ghal_net_expected_magic], rax
|
mov [rel ghal_net_expected_magic], rax
|
||||||
mov byte [rel ghal_net_command_kind], 2
|
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
|
jc native_network_proof_error
|
||||||
call ghal_block_persist_branch_receipt
|
call ghal_block_persist_branch_receipt
|
||||||
jc native_world_store_error
|
jc native_world_store_error
|
||||||
%ifdef GHOS_NATIVE_RESIDENT
|
%ifdef GHOS_NATIVE_RESIDENT
|
||||||
.resident_loop:
|
mov ecx, 10
|
||||||
|
.resident_login_loop:
|
||||||
|
push rcx
|
||||||
lea rax, [rel ghal_login_magic]
|
lea rax, [rel ghal_login_magic]
|
||||||
mov [rel ghal_net_expected_magic], rax
|
mov [rel ghal_net_expected_magic], rax
|
||||||
mov byte [rel ghal_net_command_kind], 3
|
mov byte [rel ghal_net_command_kind], 0
|
||||||
call ghal_net_icmp_login_once
|
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
|
jc native_network_proof_error
|
||||||
cmp byte [rel ghal_net_matched_kind], 3
|
|
||||||
jne .resident_loop
|
|
||||||
call ghal_write_native_recovery_beacon
|
call ghal_write_native_recovery_beacon
|
||||||
jc native_world_store_error
|
jc native_world_store_error
|
||||||
%endif
|
%endif
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,9 @@ bits 64
|
||||||
%ifndef GHOS_GATEWAY_IPV4_DWORD
|
%ifndef GHOS_GATEWAY_IPV4_DWORD
|
||||||
%define GHOS_GATEWAY_IPV4_DWORD 0x0100000a
|
%define GHOS_GATEWAY_IPV4_DWORD 0x0100000a
|
||||||
%endif
|
%endif
|
||||||
|
%ifndef GHOS_RELAY_IPV4_DWORD
|
||||||
|
%define GHOS_RELAY_IPV4_DWORD 0x0100000a
|
||||||
|
%endif
|
||||||
|
|
||||||
%ifndef GHOS_GHAL_PROBE_STAGE
|
%ifndef GHOS_GHAL_PROBE_STAGE
|
||||||
%define GHOS_GHAL_PROBE_STAGE 0
|
%define GHOS_GHAL_PROBE_STAGE 0
|
||||||
|
|
@ -944,7 +947,7 @@ ghal_net_arp_gateway:
|
||||||
stc
|
stc
|
||||||
ret
|
ret
|
||||||
|
|
||||||
ghal_net_icmp_login_once:
|
ghal_net_icmp_exchange_once:
|
||||||
mov byte [rel physical_proof_stage], 0x72
|
mov byte [rel physical_proof_stage], 0x72
|
||||||
movzx r10d, word [rel physical_proof_net_rx_queue_size]
|
movzx r10d, word [rel physical_proof_net_rx_queue_size]
|
||||||
test r10d, r10d
|
test r10d, r10d
|
||||||
|
|
@ -978,179 +981,72 @@ ghal_net_icmp_login_once:
|
||||||
xor ax, ax
|
xor ax, ax
|
||||||
out dx, ax
|
out dx, ax
|
||||||
|
|
||||||
mov ecx, 0x80000000
|
.send_request:
|
||||||
.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
|
|
||||||
mov rdi, VIRTIO_NET_TX_BUFFER
|
mov rdi, VIRTIO_NET_TX_BUFFER
|
||||||
mov ecx, r14d
|
xor eax, eax
|
||||||
rep movsb
|
mov ecx, VIRTIO_NET_BUFFER_SIZE / 8
|
||||||
mov qword [VIRTIO_NET_TX_BUFFER], 0
|
rep stosq
|
||||||
mov word [VIRTIO_NET_TX_BUFFER + 8], 0
|
|
||||||
|
|
||||||
xor ecx, ecx
|
xor ecx, ecx
|
||||||
.swap_mac:
|
.copy_gateway_destination:
|
||||||
cmp ecx, 6
|
cmp ecx, 6
|
||||||
jae .mac_swapped
|
jae .copy_source_mac
|
||||||
mov al, [VIRTIO_NET_TX_BUFFER + 10 + rcx]
|
mov al, [physical_proof_gateway_mac + rcx]
|
||||||
mov dl, [VIRTIO_NET_TX_BUFFER + 16 + rcx]
|
mov [VIRTIO_NET_TX_BUFFER + 10 + rcx], al
|
||||||
mov [VIRTIO_NET_TX_BUFFER + 10 + rcx], dl
|
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
|
mov [VIRTIO_NET_TX_BUFFER + 16 + rcx], al
|
||||||
inc ecx
|
inc ecx
|
||||||
jmp .swap_mac
|
jmp .copy_source_mac_loop
|
||||||
.mac_swapped:
|
.ethernet_ready:
|
||||||
mov eax, [VIRTIO_NET_TX_BUFFER + 36]
|
mov word [VIRTIO_NET_TX_BUFFER + 22], 0x0008
|
||||||
mov edx, [VIRTIO_NET_TX_BUFFER + 40]
|
mov byte [VIRTIO_NET_TX_BUFFER + 24], 0x45
|
||||||
mov [VIRTIO_NET_TX_BUFFER + 36], edx
|
mov byte [VIRTIO_NET_TX_BUFFER + 25], 0
|
||||||
mov [VIRTIO_NET_TX_BUFFER + 40], eax
|
mov word [VIRTIO_NET_TX_BUFFER + 26], 0x4400
|
||||||
mov byte [VIRTIO_NET_TX_BUFFER + 44], 0
|
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
|
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 rdi, VIRTIO_NET_TX_BUFFER + GHOS_LOGIN_MAGIC_OFFSET + GHOS_LOGIN_MAGIC_SIZE
|
||||||
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
mov ecx, GHOS_LOGIN_MAGIC_SIZE
|
||||||
rep movsb
|
rep movsb
|
||||||
|
|
||||||
movzx eax, word [VIRTIO_NET_TX_BUFFER + 26]
|
mov rsi, VIRTIO_NET_TX_BUFFER + 24
|
||||||
xchg al, ah
|
mov ecx, IPV4_HEADER_SIZE
|
||||||
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
|
|
||||||
xor ebx, ebx
|
xor ebx, ebx
|
||||||
.checksum_words:
|
call ghal_net_checksum
|
||||||
cmp ecx, 2
|
mov [VIRTIO_NET_TX_BUFFER + 34], bx
|
||||||
jb .checksum_tail
|
mov rsi, VIRTIO_NET_TX_BUFFER + 44
|
||||||
movzx eax, word [rsi]
|
mov ecx, ICMP_HEADER_SIZE + 8 + GHOS_LOGIN_MAGIC_SIZE * 2
|
||||||
xchg al, ah
|
xor ebx, ebx
|
||||||
add ebx, eax
|
call ghal_net_checksum
|
||||||
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
|
|
||||||
mov [VIRTIO_NET_TX_BUFFER + 46], bx
|
mov [VIRTIO_NET_TX_BUFFER + 46], bx
|
||||||
|
|
||||||
mov qword [VIRTIO_NET_TX_QUEUE], VIRTIO_NET_TX_BUFFER
|
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 + 12], 0
|
||||||
mov word [VIRTIO_NET_TX_QUEUE + 14], 0
|
mov word [VIRTIO_NET_TX_QUEUE + 14], 0
|
||||||
|
|
||||||
movzx ecx, word [rel physical_proof_net_tx_queue_size]
|
movzx ecx, word [rel physical_proof_net_tx_queue_size]
|
||||||
test ecx, ecx
|
test ecx, ecx
|
||||||
jz .queue_missing
|
jz .queue_missing
|
||||||
|
|
@ -1178,18 +1074,120 @@ ghal_net_icmp_login_once:
|
||||||
out dx, ax
|
out dx, ax
|
||||||
|
|
||||||
mov ecx, 0x20000000
|
mov ecx, 0x20000000
|
||||||
.wait_reply_tx:
|
.wait_request_tx:
|
||||||
cmp word [r13 + 2], r11w
|
cmp word [r13 + 2], r11w
|
||||||
je .reply_complete
|
je .request_complete
|
||||||
pause
|
pause
|
||||||
loop .wait_reply_tx
|
loop .wait_request_tx
|
||||||
mov byte [rel physical_proof_error_code], 0x55
|
mov byte [rel physical_proof_error_code], 0x55
|
||||||
stc
|
stc
|
||||||
ret
|
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
|
mov [rel ghal_net_rx_next_index], r8w
|
||||||
inc word [rel ghal_net_rx_next_index]
|
inc word [rel ghal_net_rx_next_index]
|
||||||
inc word [rel ghal_net_tx_next_index]
|
|
||||||
inc byte [rel ghal_net_expected_sequence]
|
inc byte [rel ghal_net_expected_sequence]
|
||||||
cmp byte [rel ghal_net_matched_kind], 0
|
cmp byte [rel ghal_net_matched_kind], 0
|
||||||
jne .not_login_reply
|
jne .not_login_reply
|
||||||
|
|
@ -1201,13 +1199,39 @@ ghal_net_icmp_login_once:
|
||||||
call serial_write64
|
call serial_write64
|
||||||
clc
|
clc
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.queue_missing:
|
.queue_missing:
|
||||||
mov byte [rel physical_proof_error_code], 0x53
|
mov byte [rel physical_proof_error_code], 0x53
|
||||||
stc
|
stc
|
||||||
ret
|
ret
|
||||||
.invalid_packet:
|
|
||||||
mov byte [rel physical_proof_error_code], 0x56
|
ghal_net_checksum:
|
||||||
stc
|
.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
|
ret
|
||||||
|
|
||||||
ghal_net_io_base: dw 0
|
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)
|
gestational_index_lba=$(native_value gestational_index_lba_start)
|
||||||
native_ipv4=$(ipv4_dword "$(network_value native_ipv4)")
|
native_ipv4=$(ipv4_dword "$(network_value native_ipv4)")
|
||||||
gateway_ipv4=$(ipv4_dword "$(network_value gateway_ipv4)")
|
gateway_ipv4=$(ipv4_dword "$(network_value gateway_ipv4)")
|
||||||
|
relay_ipv4=$(ipv4_dword "$(network_value relay_ipv4)")
|
||||||
|
|
||||||
for value in \
|
for value in \
|
||||||
"${kernel_lba}" "${proof_lba}" "${world_store_lba}" \
|
"${kernel_lba}" "${proof_lba}" "${world_store_lba}" \
|
||||||
|
|
@ -68,4 +69,5 @@ printf '%s\n' \
|
||||||
"-dGHOS_NATIVE_RECOVERY_BEACON_LBA=${recovery_beacon_lba}" \
|
"-dGHOS_NATIVE_RECOVERY_BEACON_LBA=${recovery_beacon_lba}" \
|
||||||
"-dGHOS_NATIVE_GESTATIONAL_INDEX_LBA=${gestational_index_lba}" \
|
"-dGHOS_NATIVE_GESTATIONAL_INDEX_LBA=${gestational_index_lba}" \
|
||||||
"-dGHOS_NATIVE_IPV4_DWORD=${native_ipv4}" \
|
"-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")
|
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(
|
def exchange(
|
||||||
peer: socket.socket,
|
peer: socket.socket,
|
||||||
target: tuple[str, int],
|
target: tuple[str, int],
|
||||||
|
|
@ -80,7 +109,7 @@ def exchange(
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--target", required=True)
|
parser.add_argument("--target")
|
||||||
parser.add_argument("--receipt", required=True)
|
parser.add_argument("--receipt", required=True)
|
||||||
parser.add_argument("--timeout", type=float, default=90.0)
|
parser.add_argument("--timeout", type=float, default=90.0)
|
||||||
parser.add_argument("--retry-interval", type=float, default=1.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-after-branch", action="store_true")
|
||||||
parser.add_argument("--resume-resident-count", type=int)
|
parser.add_argument("--resume-resident-count", type=int)
|
||||||
parser.add_argument("--resident-pipeline", action="store_true")
|
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()
|
args = parser.parse_args()
|
||||||
if args.retry_interval < 1.0:
|
if args.retry_interval < 1.0:
|
||||||
raise SystemExit("--retry-interval must be at least 1 second")
|
raise SystemExit("--retry-interval must be at least 1 second")
|
||||||
|
|
@ -108,19 +139,79 @@ def main() -> None:
|
||||||
args.resume_after_branch,
|
args.resume_after_branch,
|
||||||
args.resume_resident_count is not None,
|
args.resume_resident_count is not None,
|
||||||
args.resident_pipeline,
|
args.resident_pipeline,
|
||||||
|
args.native_relay,
|
||||||
)
|
)
|
||||||
) > 1:
|
) > 1:
|
||||||
raise SystemExit(
|
raise SystemExit(
|
||||||
"--resident, --login-only, --resume-after-login, and "
|
"--resident, --login-only, --resume-after-login, and "
|
||||||
"--resume-after-commit, --resume-after-branch, 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
|
socket_type = socket.SOCK_RAW if args.raw_socket else socket.SOCK_DGRAM
|
||||||
peer = socket.socket(socket.AF_INET, socket_type, socket.IPPROTO_ICMP)
|
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)
|
peer.settimeout(0.2 if args.resident_pipeline else 1.0)
|
||||||
target = (socket.gethostbyname(args.target), 0)
|
target = (socket.gethostbyname(args.target), 0)
|
||||||
deadline = time.monotonic() + args.timeout
|
|
||||||
if args.resident_pipeline:
|
if args.resident_pipeline:
|
||||||
pipeline = [
|
pipeline = [
|
||||||
LOGIN_MAGIC,
|
LOGIN_MAGIC,
|
||||||
|
|
@ -137,19 +228,24 @@ def main() -> None:
|
||||||
if time.monotonic() >= deadline:
|
if time.monotonic() >= deadline:
|
||||||
break
|
break
|
||||||
peer.sendto(request(pipeline_sequence, pipeline_magic), target)
|
peer.sendto(request(pipeline_sequence, pipeline_magic), target)
|
||||||
try:
|
receive_until = min(deadline, time.monotonic() + 0.8)
|
||||||
packet, _ = peer.recvfrom(4096)
|
while time.monotonic() < receive_until:
|
||||||
observed_sequence = reply_sequence_index(packet)
|
try:
|
||||||
if not 1 <= observed_sequence <= len(pipeline):
|
packet, _ = peer.recvfrom(4096)
|
||||||
raise RuntimeError("native ACK sequence is outside the pipeline")
|
observed_sequence = reply_sequence_index(packet)
|
||||||
reply_sequence = verify_reply(
|
if not 1 <= observed_sequence <= len(pipeline):
|
||||||
packet,
|
raise RuntimeError(
|
||||||
pipeline[observed_sequence - 1],
|
"native ACK sequence is outside the pipeline"
|
||||||
)
|
)
|
||||||
except (TimeoutError, RuntimeError, IndexError):
|
reply_sequence = verify_reply(
|
||||||
continue
|
packet,
|
||||||
if reply_sequence == pipeline_sequence:
|
pipeline[observed_sequence - 1],
|
||||||
|
)
|
||||||
|
except (TimeoutError, RuntimeError, IndexError):
|
||||||
|
continue
|
||||||
acknowledged.add(reply_sequence)
|
acknowledged.add(reply_sequence)
|
||||||
|
if reply_sequence == pipeline_sequence:
|
||||||
|
break
|
||||||
if len(acknowledged) != len(pipeline):
|
if len(acknowledged) != len(pipeline):
|
||||||
raise TimeoutError(
|
raise TimeoutError(
|
||||||
"native pipeline incomplete; acknowledged sequences: "
|
"native pipeline incomplete; acknowledged sequences: "
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import time
|
||||||
|
|
||||||
GUEST_MAC = bytes.fromhex("525400267198")
|
GUEST_MAC = bytes.fromhex("525400267198")
|
||||||
PEER_MAC = bytes.fromhex("525400123401")
|
PEER_MAC = bytes.fromhex("525400123401")
|
||||||
GUEST_IP = socket.inet_aton("10.0.0.7")
|
GUEST_IP = socket.inet_aton("172.16.0.6")
|
||||||
PEER_IP = socket.inet_aton("10.0.0.1")
|
GATEWAY_IP = socket.inet_aton("172.16.0.1")
|
||||||
LOGIN_CLIENT_IP = socket.inet_aton("10.0.0.2")
|
RELAY_IP = socket.inet_aton("43.153.193.169")
|
||||||
LOGIN_MAGIC = b"HLDP-GHOS-LOGIN!"
|
LOGIN_MAGIC = b"HLDP-GHOS-LOGIN!"
|
||||||
COMMIT_MAGIC = b"HLDP-CODE-COMMIT"
|
COMMIT_MAGIC = b"HLDP-CODE-COMMIT"
|
||||||
BRANCH_MAGIC = b"HLDP-BRANCH-MOVE"
|
BRANCH_MAGIC = b"HLDP-BRANCH-MOVE"
|
||||||
|
|
@ -35,68 +35,65 @@ def arp_reply(request: bytes) -> bytes:
|
||||||
target_ip = request[38:42]
|
target_ip = request[38:42]
|
||||||
assert sender_mac == GUEST_MAC
|
assert sender_mac == GUEST_MAC
|
||||||
assert sender_ip == GUEST_IP
|
assert sender_ip == GUEST_IP
|
||||||
assert target_ip == PEER_IP
|
assert target_ip == GATEWAY_IP
|
||||||
return (
|
return (
|
||||||
sender_mac
|
sender_mac
|
||||||
+ PEER_MAC
|
+ PEER_MAC
|
||||||
+ b"\x08\x06"
|
+ b"\x08\x06"
|
||||||
+ b"\x00\x01\x08\x00\x06\x04\x00\x02"
|
+ b"\x00\x01\x08\x00\x06\x04\x00\x02"
|
||||||
+ PEER_MAC
|
+ PEER_MAC
|
||||||
+ PEER_IP
|
+ GATEWAY_IP
|
||||||
+ sender_mac
|
+ sender_mac
|
||||||
+ sender_ip
|
+ sender_ip
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def icmp_request(sequence: int, magic: bytes) -> bytes:
|
def verified_request(frame: bytes, sequence: int, magic: bytes) -> None:
|
||||||
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:
|
|
||||||
assert frame[0:6] == PEER_MAC
|
assert frame[0:6] == PEER_MAC
|
||||||
assert frame[6:12] == GUEST_MAC
|
assert frame[6:12] == GUEST_MAC
|
||||||
assert frame[12:14] == b"\x08\x00"
|
assert frame[12:14] == b"\x08\x00"
|
||||||
assert frame[26:30] == GUEST_IP
|
assert frame[26:30] == GUEST_IP
|
||||||
assert frame[30:34] == LOGIN_CLIENT_IP
|
assert frame[30:34] == RELAY_IP
|
||||||
assert frame[34] == 0
|
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[50:66] == magic
|
||||||
assert frame[66:82] == NATIVE_ACK_MAGIC
|
assert frame[66:82] == magic
|
||||||
assert checksum(frame[34:]) == 0
|
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:
|
def main() -> None:
|
||||||
global GUEST_IP, PEER_IP, LOGIN_CLIENT_IP
|
global GUEST_IP, GATEWAY_IP, RELAY_IP
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--listen-port", type=int, required=True)
|
parser.add_argument("--listen-port", type=int, required=True)
|
||||||
parser.add_argument("--qemu-port", type=int, required=True)
|
parser.add_argument("--qemu-port", type=int, required=True)
|
||||||
parser.add_argument("--receipt", required=True)
|
parser.add_argument("--receipt", required=True)
|
||||||
parser.add_argument("--resident", action="store_true")
|
parser.add_argument("--resident", action="store_true")
|
||||||
parser.add_argument("--login-only", action="store_true")
|
parser.add_argument("--login-only", action="store_true")
|
||||||
parser.add_argument("--guest-ip", default="10.0.0.7")
|
parser.add_argument("--guest-ip", default="172.16.0.6")
|
||||||
parser.add_argument("--peer-ip", default="10.0.0.1")
|
parser.add_argument("--peer-ip", default="172.16.0.1")
|
||||||
parser.add_argument("--login-client-ip", default="10.0.0.2")
|
parser.add_argument("--relay-ip", default="43.153.193.169")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
GUEST_IP = socket.inet_aton(args.guest_ip)
|
GUEST_IP = socket.inet_aton(args.guest_ip)
|
||||||
PEER_IP = socket.inet_aton(args.peer_ip)
|
GATEWAY_IP = socket.inet_aton(args.peer_ip)
|
||||||
LOGIN_CLIENT_IP = socket.inet_aton(args.login_client_ip)
|
RELAY_IP = socket.inet_aton(args.relay_ip)
|
||||||
|
|
||||||
peer = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
peer = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
peer.bind(("127.0.0.1", args.listen_port))
|
peer.bind(("127.0.0.1", args.listen_port))
|
||||||
|
|
@ -104,101 +101,63 @@ def main() -> None:
|
||||||
qemu = ("127.0.0.1", args.qemu_port)
|
qemu = ("127.0.0.1", args.qemu_port)
|
||||||
deadline = time.monotonic() + 15
|
deadline = time.monotonic() + 15
|
||||||
arp_verified = False
|
arp_verified = False
|
||||||
login_sent = False
|
login_count = 0
|
||||||
reply_count = 0
|
resident_login_count = 0
|
||||||
login_reply_count = 0
|
commit_verified = False
|
||||||
resident_login_reply_count = 0
|
branch_verified = False
|
||||||
recovery_reply_verified = False
|
recovery_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]
|
|
||||||
|
|
||||||
while time.monotonic() < deadline:
|
while time.monotonic() < deadline:
|
||||||
try:
|
try:
|
||||||
frame = peer.recv(4096)
|
frame = peer.recv(4096)
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
if arp_verified:
|
|
||||||
peer.sendto(
|
|
||||||
icmp_request(reply_count + 1, phase_magic()),
|
|
||||||
qemu,
|
|
||||||
)
|
|
||||||
login_sent = True
|
|
||||||
continue
|
continue
|
||||||
if frame[12:14] == b"\x08\x06":
|
if frame[12:14] == b"\x08\x06":
|
||||||
peer.sendto(arp_reply(frame), qemu)
|
peer.sendto(arp_reply(frame), qemu)
|
||||||
arp_verified = True
|
arp_verified = True
|
||||||
continue
|
continue
|
||||||
if frame[12:14] == b"\x08\x00":
|
if frame[12:14] != b"\x08\x00":
|
||||||
magic = phase_magic()
|
continue
|
||||||
validate_reply(frame, magic)
|
sequence = int.from_bytes(frame[40:42], "big")
|
||||||
reply_count += 1
|
if sequence <= 3:
|
||||||
if command_phase == "login":
|
magic = LOGIN_MAGIC
|
||||||
login_reply_count += 1
|
login_count += 1
|
||||||
if command_phase == "login" and reply_count < 3:
|
elif sequence == 4:
|
||||||
peer.sendto(icmp_request(reply_count + 1, LOGIN_MAGIC), qemu)
|
magic = COMMIT_MAGIC
|
||||||
continue
|
commit_verified = True
|
||||||
if command_phase == "login":
|
elif sequence == 5:
|
||||||
if args.login_only:
|
magic = BRANCH_MAGIC
|
||||||
write_receipt(
|
branch_verified = True
|
||||||
commit_verified=False,
|
elif 6 <= sequence <= 15:
|
||||||
branch_verified=False,
|
magic = LOGIN_MAGIC
|
||||||
)
|
resident_login_count += 1
|
||||||
return
|
elif sequence == 16:
|
||||||
command_phase = "commit"
|
magic = RECOVERY_MAGIC
|
||||||
peer.sendto(icmp_request(4, COMMIT_MAGIC), qemu)
|
recovery_verified = True
|
||||||
continue
|
else:
|
||||||
if command_phase == "commit":
|
raise AssertionError(f"unexpected native sequence {sequence}")
|
||||||
command_phase = "branch"
|
verified_request(frame, sequence, magic)
|
||||||
peer.sendto(icmp_request(5, BRANCH_MAGIC), qemu)
|
peer.sendto(authenticated_reply(frame, magic), qemu)
|
||||||
continue
|
|
||||||
if command_phase == "branch" and args.resident:
|
terminal_sequence = 3 if args.login_only else (16 if args.resident else 5)
|
||||||
command_phase = "resident_login"
|
if sequence != terminal_sequence:
|
||||||
peer.sendto(icmp_request(6, LOGIN_MAGIC), qemu)
|
continue
|
||||||
continue
|
with open(args.receipt, "w", encoding="utf-8") as output:
|
||||||
if command_phase == "resident_login":
|
output.write(
|
||||||
resident_login_reply_count += 1
|
"arp_gateway_reply: VERIFIED\n"
|
||||||
if resident_login_reply_count < 10:
|
"handshake_direction: NATIVE_INITIATED_OUTBOUND_ICMP\n"
|
||||||
peer.sendto(
|
"authenticated_relay_reply: VERIFIED\n"
|
||||||
icmp_request(6 + resident_login_reply_count, LOGIN_MAGIC),
|
"icmp_login_request_sent: true\n"
|
||||||
qemu,
|
"icmp_login_reply_verified: true\n"
|
||||||
)
|
f"icmp_login_reply_count: {login_count}\n"
|
||||||
continue
|
f"code_commit_reply_verified: {str(commit_verified).lower()}\n"
|
||||||
command_phase = "recovery"
|
f"branch_move_reply_verified: {str(branch_verified).lower()}\n"
|
||||||
peer.sendto(icmp_request(16, RECOVERY_MAGIC), qemu)
|
f"resident_login_reply_count: {resident_login_count}\n"
|
||||||
continue
|
f"recovery_reply_verified: {str(recovery_verified).lower()}\n"
|
||||||
if command_phase == "recovery":
|
"login_magic: HLDP-GHOS-LOGIN!\n"
|
||||||
recovery_reply_verified = True
|
)
|
||||||
write_receipt(commit_verified=True, branch_verified=True)
|
return
|
||||||
return
|
raise SystemExit("timed out waiting for native outbound ICMP exchange")
|
||||||
raise SystemExit("timed out waiting for native ICMP login reply")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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
|
first_partition_lba: 2048
|
||||||
native_network:
|
native_network:
|
||||||
id: GLS-0841-JD-FD-PRIMARY
|
id: GLS-0841-JD-FD-PRIMARY
|
||||||
|
entry: world/services/native-network/PROTOCOL.hldp
|
||||||
node_id: JD-FD-PRIMARY
|
node_id: JD-FD-PRIMARY
|
||||||
device_model: VIRTIO_LEGACY
|
device_model: VIRTIO_LEGACY
|
||||||
native_ipv4: 172.16.0.6
|
native_ipv4: 172.16.0.6
|
||||||
gateway_ipv4: 172.16.0.1
|
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
|
public_nat_address_recorded_in_world: false
|
||||||
gestational_continuity:
|
gestational_continuity:
|
||||||
id: GLS-0845
|
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