Add nbdssl support
This commit is contained in:
+38
-20
@@ -25,16 +25,17 @@ password to ESXi port 902. It:
|
||||
3. Connects to the ESXi **authd** daemon on TCP 902, upgrades to TLS,
|
||||
and presents that ticket.
|
||||
|
||||
| VDDK call | What actually happens |
|
||||
| --------------------------------- | ---------------------------------------------------------- |
|
||||
| `VixDiskLib_InitEx` | Load plugins, SSL, logging |
|
||||
| `VixDiskLib_ConnectEx` | SOAP `SessionManager.Login` to vCenter |
|
||||
| `VixDiskLib_Open` (read-only) | `NfcGetVmFiles` ticket, then authd handshake, then NFC I/O |
|
||||
| `VixDiskLib_Open` (read-write) | `NfcRandomAccessOpenDisk` ticket (disk key + host) |
|
||||
| `transport_modes="nbd"` | NBD over NFC (`vpxa-nfc://...@esxi:902`) |
|
||||
| `vmxSpec=moref=vm-13098` | VM managed object used as the ticket target |
|
||||
| `snapshot_ref` | Not consumed by the ticket call itself |
|
||||
| `VIXDISKLIB_CRED_UID` | Username/password for VIM only |
|
||||
| VDDK call | What actually happens |
|
||||
| ------------------------------------ | ---------------------------------------------------------- |
|
||||
| `VixDiskLib_InitEx` | Load plugins, SSL, logging |
|
||||
| `VixDiskLib_ConnectEx` | SOAP `SessionManager.Login` to vCenter |
|
||||
| `VixDiskLib_Open` (read-only) | `NfcGetVmFiles` ticket, then authd handshake, then NFC I/O |
|
||||
| `VixDiskLib_Open` (read-write) | `NfcRandomAccessOpenDisk` ticket (disk key + host) |
|
||||
| `transport_modes="nbdssl"` (default) | NBDSSL (`vpxa-nfcssl://...@esxi:902`, second TLS wrap) |
|
||||
| `transport_modes="nbd"` | NBD over NFC (`vpxa-nfc://...@esxi:902`) |
|
||||
| `vmxSpec=moref=vm-13098` | VM managed object used as the ticket target |
|
||||
| `snapshot_ref` | Not consumed by the ticket call itself |
|
||||
| `VIXDISKLIB_CRED_UID` | Username/password for VIM only |
|
||||
|
||||
Lab topology used for capture:
|
||||
|
||||
@@ -185,8 +186,9 @@ Plain-text connection is deprecated; use SSL to connect to NFC server
|
||||
```
|
||||
|
||||
`useSSL=0` does **not** mean skip TLS on 902. It means skip a second
|
||||
NFCSSL wrap after authd TLS (`THUMBPRINT_SHA2 PlainText`). The
|
||||
management channel is still TLS.
|
||||
NFCSSL wrap after authd TLS. The management channel is still TLS.
|
||||
`useSSL=1` (nbdssl) is the same authd commands with `PROXY vpxa-nfcssl`
|
||||
and a second TLS handshake after `200 Connect`.
|
||||
|
||||
Intercepted writes/reads after the TLS handshake:
|
||||
|
||||
@@ -200,6 +202,20 @@ C -> PROXY vpxa-nfc\r\n
|
||||
S -> 200 Connect ha-nfc\r\n
|
||||
```
|
||||
|
||||
NBDSSL uses the same `SESSION` / `BANNER` / `THUMBPRINT_SHA2 PlainText`
|
||||
sequence. The ticket still has `service=vpxa-nfc`; the client rewrites
|
||||
the PROXY argument:
|
||||
|
||||
```
|
||||
C -> PROXY vpxa-nfcssl\r\n
|
||||
S -> 200 Connect ha-nfcssl\r\n
|
||||
```
|
||||
|
||||
After that reply, authd TLS is finished and `ha-nfcssl` expects a **new**
|
||||
TLS ClientHello on the same TCP connection (`useSSL=1`). NFC frames then
|
||||
travel as TLS application data of that second session. NBD (`useSSL=0`)
|
||||
skips the second wrap and sends NFC as raw TCP instead.
|
||||
|
||||
Notes:
|
||||
|
||||
- `SESSION` does not get a reply of its own. Waiting for a line after
|
||||
@@ -209,10 +225,11 @@ Notes:
|
||||
commands, so `THUMBPRINT_SHA2 <colon-thumbprint>` is parsed as one
|
||||
token and returns `501 Invalid arguments`. `PlainText` has no extra
|
||||
spaces/colons and is the argument VDDK sends.
|
||||
- `PROXY` uses `ticket.service` (`vpxa-nfc` via vCenter). The success
|
||||
line names the host-side NFC endpoint (`ha-nfc`).
|
||||
- After `200 Connect`, the socket speaks binary NFC (not documented
|
||||
here).
|
||||
- `PROXY` uses `ticket.service` (`vpxa-nfc` via vCenter) for NBD. NBDSSL
|
||||
appends `ssl` (`vpxa-nfcssl`). The success line names the host-side
|
||||
endpoint (`ha-nfc` or `ha-nfcssl`).
|
||||
- After `200 Connect`, NBD speaks binary NFC on the raw fd. NBDSSL
|
||||
starts a second TLS handshake, then the same NFC protocol.
|
||||
|
||||
### Commands that are not used for this ticket type
|
||||
|
||||
@@ -259,7 +276,8 @@ and asserts an established TLS socket on `ticket.host:ticket.port`.
|
||||
|
||||
## What comes after authentication
|
||||
|
||||
Authentication stops at `200 Connect ha-nfc`. Opening the VMDK and
|
||||
reading or writing sectors is documented in `docs/nfc_open.md` and
|
||||
implemented in `openvixdisklib/nfc_open.py`. The datastore path is
|
||||
consumed there (and, for writes, as `diskDeviceKey` on the ticket).
|
||||
Authentication stops at `200 Connect ha-nfc` (NBD) or `200 Connect
|
||||
ha-nfcssl` (NBDSSL). Opening the VMDK and reading or writing sectors is
|
||||
documented in `docs/nfc_open.md` and implemented in
|
||||
`openvixdisklib/nfc_open.py`. The datastore path is consumed there
|
||||
(and, for writes, as `diskDeviceKey` on the ticket).
|
||||
|
||||
+42
-35
@@ -11,53 +11,60 @@ VDDK 8.0.2 verbose logs
|
||||
Authentication is already done: VIM login, NFC ticket (`NfcGetVmFiles`
|
||||
for read-only, `NfcRandomAccessOpenDisk` for write), TLS to authd,
|
||||
`SESSION` / `BANNER` / `THUMBPRINT_SHA2 PlainText` / `PROXY`. This
|
||||
stage starts at `200 Connect ha-nfc` and ends with an open file handle
|
||||
that can read and write sectors. Flags `0x1a` require the writable
|
||||
ticket; the same flags on a `GetVmFiles` ticket fail with
|
||||
`VIX_E_FILE_READ_ONLY`.
|
||||
stage starts at `200 Connect ha-nfc` (NBD) or `200 Connect ha-nfcssl`
|
||||
(NBDSSL) and ends with an open file handle that can read and write
|
||||
sectors. Flags `0x1a` require the writable ticket; the same flags on a
|
||||
`GetVmFiles` ticket fail with `VIX_E_FILE_READ_ONLY`.
|
||||
|
||||
## Mapping from VDDK
|
||||
|
||||
| VDDK call / log | Wire effect |
|
||||
| ---------------------------------------------------- | -------------------------------------------------------- |
|
||||
| `VixDiskLib_Open` | Ticket + authd (see `nfc_auth.md`), then this protocol |
|
||||
| `NBD_ClientOpen` `vpxa-nfc://[ds] path.vmdk@esxi:902` | Datastore path is the NFC open argument, not the ticket |
|
||||
| `useSSL=0` | NFC bytes are raw TCP, not `SSL_write` |
|
||||
| `NfcProcessSessionParams` flags `0x3` | Classic 264-byte session messages |
|
||||
| `SendConnectionDataMsg` payloadInfo 4 and 7 | Client name `vddk` (4) and opId `nbdmode` (7) |
|
||||
| Server version 11 | Classic version message; 11 on this ESXi 8 lab |
|
||||
| `NfcAio_OpenSession` | AIO framing after the classic handshake |
|
||||
| `NfcUtil_PrintFileInfoOpenFlag` `NFC_DISK` `0x1e` | `NFC_AIO_MSG_OPEN_FILE` (read-only) |
|
||||
| Open without `VIXDISKLIB_FLAG_OPEN_READ_ONLY` | `OPEN_FILE` flags `0x1a` (read-write) |
|
||||
| `VixDiskLib_Read` / `VixDiskLib_Write` | `NFC_AIO_MSG_IO` + sector bytes |
|
||||
| VDDK call / log | Wire effect |
|
||||
| ------------------------------------------------------------- | ---------------------------------------------------------- |
|
||||
| `VixDiskLib_Open` | Ticket + authd (see `nfc_auth.md`), then this protocol |
|
||||
| `NBD_ClientOpen` `vpxa-nfc://[ds] path.vmdk@esxi:902` | Datastore path is the NFC open argument, not the ticket |
|
||||
| `NBD_ClientOpen` `vpxa-nfcssl://…` / `useSSL=1` | Same NFC after a second TLS handshake on the authd fd |
|
||||
| `useSSL=0` | NFC bytes are raw TCP, not `SSL_write` |
|
||||
| `NfcProcessSessionParams` flags `0x3` | Classic 264-byte session messages |
|
||||
| `SendConnectionDataMsg` payloadInfo 4 and 7 | Client name `vddk` (4) and opId `nbdmode` (7) |
|
||||
| Server version 11 | Classic version message; 11 on this ESXi 8 lab |
|
||||
| `NfcAio_OpenSession` | AIO framing after the classic handshake |
|
||||
| `NfcUtil_PrintFileInfoOpenFlag` `NFC_DISK` `0x1e` | `NFC_AIO_MSG_OPEN_FILE` (read-only) |
|
||||
| Open without `VIXDISKLIB_FLAG_OPEN_READ_ONLY` | `OPEN_FILE` flags `0x1a` (read-write) |
|
||||
| `VixDiskLib_Read` / `VixDiskLib_Write` | `NFC_AIO_MSG_IO` + sector bytes |
|
||||
|
||||
`snapshot_ref` is still not on the wire. Integration tests pass the
|
||||
flat VMDK created with the temporary lab VM.
|
||||
|
||||
## After PROXY: plaintext on the TLS fd
|
||||
## After PROXY: NBD plaintext vs NBDSSL wrap
|
||||
|
||||
`THUMBPRINT_SHA2 PlainText` tells authd not to wrap NFC in a second
|
||||
TLS session. VDDK logs `useSSL=0` and “Plain-text connection is
|
||||
deprecated”.
|
||||
`THUMBPRINT_SHA2 PlainText` is used for both transports. The PROXY
|
||||
service name selects whether NFC gets a second TLS session.
|
||||
|
||||
On the wire that means:
|
||||
NBD (`PROXY vpxa-nfc` → `200 Connect ha-nfc`, VDDK `useSSL=0`):
|
||||
|
||||
1. Authd commands stay inside the original TLS session (`SSL_write` /
|
||||
`SSL_read`).
|
||||
2. After `200 Connect ha-nfc`, VDDK calls `write(SSL_get_fd(ssl), …)`
|
||||
and `read` on that same descriptor. Those buffers are NFC, not TLS
|
||||
records (`0x17 0x03 …`).
|
||||
3. ESXi’s `ha-nfc` side does the same: replies are plaintext NFC.
|
||||
2. After `200 Connect ha-nfc`, NFC is `write(SSL_get_fd(ssl), …)` /
|
||||
`read` on that descriptor. Those buffers are not TLS records
|
||||
(`0x17 0x03 …`).
|
||||
3. An SSL hook that only interposes `SSL_write` / `SSL_read` goes
|
||||
silent after PROXY; a `write` / `read` hook on port 902 shows the
|
||||
frames.
|
||||
4. Python must not use `SSLSocket.send` here: that would encrypt bytes
|
||||
the server now reads as NFC. `nfc_open.takeover_authd_socket` dups
|
||||
the fd. `unwrap()` / `SSL_shutdown` is not used.
|
||||
|
||||
An SSL hook that only interposes `SSL_write` / `SSL_read` therefore
|
||||
goes silent after PROXY. Interposing `write` / `read` and filtering
|
||||
`getpeername` port 902 shows the frames.
|
||||
NBDSSL (`PROXY vpxa-nfcssl` → `200 Connect ha-nfcssl`, `useSSL=1`):
|
||||
|
||||
Python must not use `SSLSocket.send` for this stage: that would
|
||||
`SSL_write` and encrypt bytes the server now reads as NFC.
|
||||
`nfc_open.takeover_authd_socket` dups `SSL_get_fd` and uses a raw
|
||||
`socket.socket`. `unwrap()` / `SSL_shutdown` is not used; VDDK does
|
||||
not send `close_notify` before NFC.
|
||||
1. Authd commands are the same, including `THUMBPRINT_SHA2 PlainText`.
|
||||
2. After `200 Connect ha-nfcssl`, both sides abandon the authd TLS
|
||||
session. `ha-nfcssl` expects a new ClientHello on the same TCP
|
||||
connection.
|
||||
3. `nfc_open.wrap_nfcssl_socket` dups the fd and
|
||||
`SSLContext.wrap_socket`s it. NFC then uses `SSLSocket.sendall` /
|
||||
`recv` (TLS application data). The classic 264-byte handshake still
|
||||
sends the ASCII body `PlainText`; that is NFC's own encoding, not
|
||||
the authd transport.
|
||||
|
||||
## Classic 264-byte messages
|
||||
|
||||
@@ -200,6 +207,7 @@ classic type 4 `NFC_SESSION_COMPLETE`.
|
||||
| ----------------------------- | ----------------------------------------------- |
|
||||
| VIM + authd | `openvixdisklib.nfc_auth.authenticate` |
|
||||
| Dup fd, skip TLS for NFC | `openvixdisklib.nfc_open.takeover_authd_socket` |
|
||||
| Second TLS for nbdssl | `openvixdisklib.nfc_open.wrap_nfcssl_socket` |
|
||||
| Handshake + AIO + OPEN_FILE | `openvixdisklib.nfc_open.open_disk` |
|
||||
| Sector read / write / close | `openvixdisklib.nfc_open.NfcDisk` |
|
||||
|
||||
@@ -218,8 +226,7 @@ I/O: `docs/nfc_read.md`, `docs/nfc_write.md`, and
|
||||
|
||||
- `DDB_GET` / geometry / compression / encryption keys
|
||||
- `NFC_DELTA_DISK`, change-block tracking
|
||||
- Host-switch (`NFC_AIO_SWITCH_HOST_*`) and a second NFCSSL wrap
|
||||
(`useSSL=1`, not what VDDK NBD used here)
|
||||
- Host-switch (`NFC_AIO_SWITCH_HOST_*`)
|
||||
- Direct ESXi `ha-nfc` without vCenter `vpxa-nfc`
|
||||
|
||||
Reads after open are in `docs/nfc_read.md`. Writes are in
|
||||
|
||||
@@ -9,9 +9,9 @@ NFC work can follow the same loop instead of rediscovering it.
|
||||
|
||||
Scope so far: `VixDiskLib_ConnectEx` + `VixDiskLib_Open` +
|
||||
`VixDiskLib_Read` + `VixDiskLib_Write` against lab vCenter 8.0.1 /
|
||||
ESXi 8, transport `nbd`. Driver: `tests/integration/` (the session-scoped
|
||||
`lab` fixture creates a temporary empty VM with a 10 GiB disk and
|
||||
destroys it when the pytest session ends).
|
||||
ESXi 8, transports `nbd` and `nbdssl`. Driver: `tests/integration/` (the
|
||||
session-scoped `lab` fixture creates a temporary empty VM with a 10 GiB
|
||||
disk and destroys it when the pytest session ends).
|
||||
|
||||
Rule from `AGENTS.md`: reuse pyVmomi for every public VIM operation.
|
||||
Only reimplement what pyVmomi does not expose.
|
||||
@@ -254,6 +254,32 @@ single oversized write the way VDDK sends an oversized read. Details:
|
||||
`tests/integration/test_nfc_read_write.py` and the VDDK cross-check in
|
||||
`tests/integration/test_crosscheck.py`.
|
||||
|
||||
## Step 11 — NBDSSL: second TLS after `PROXY vpxa-nfcssl`
|
||||
|
||||
VDDK strings name `nbdssl`, `vpxa-nfcssl://`, and `ha-nfcssl`. The NFC
|
||||
ticket SOAP call is unchanged (`service` stays `vpxa-nfc`). Transport is
|
||||
an authd/client choice:
|
||||
|
||||
1. Same `SESSION` / `BANNER` / `THUMBPRINT_SHA2 PlainText` as NBD.
|
||||
2. `PROXY vpxa-nfcssl` → `200 Connect ha-nfcssl`.
|
||||
3. A new TLS handshake on the **same TCP connection** (not TLS-in-TLS
|
||||
and not `THUMBPRINT_SHA2 <sha256>`). The colon thumbprint is still
|
||||
`501 Invalid arguments`.
|
||||
4. Classic NFC handshake type 43 still sends ASCII `PlainText`. I/O
|
||||
framing is unchanged.
|
||||
|
||||
Replay: `connect_authd(..., nfc_ssl=True)` plus
|
||||
`nfc_open.wrap_nfcssl_socket`. Sending NFC on the first authd
|
||||
`SSLSocket` after `ha-nfcssl` fails (`BAD_RECORD_TYPE`); sending
|
||||
plaintext NFC on the dup'd fd gets EOF. Dup + `wrap_socket` is the
|
||||
working subset. Proof: `tests/integration/test_nfc_open.py` (`nbdssl`)
|
||||
and `test_openvixdisklib.py` with `transport_modes="nbdssl"`.
|
||||
|
||||
Native `VixDiskLib_ConnectEx(..., transport_modes="nbdssl")` through
|
||||
the old `VixDiskLibConnectParams` ctypes struct can still log nbdssl
|
||||
and then fall back to `vpxa-nfc` / `useSSL=0`. Do not treat that log
|
||||
line as a wire capture of NFCSSL.
|
||||
|
||||
## What to write down
|
||||
|
||||
After a stage works:
|
||||
@@ -278,5 +304,4 @@ Not yet reversed, same loop as above:
|
||||
- `NFC_DELTA_DISK`, CBT / `QueryAllocatedBlocks`
|
||||
- `VixDiskLib_GetInfo` capacity
|
||||
- Host-switch AIO messages
|
||||
- `useSSL=1` (second NFCSSL wrap)
|
||||
- Direct ESXi `ha-nfc` without vCenter `vpxa-nfc`
|
||||
|
||||
Reference in New Issue
Block a user