Document probing samples

This commit is contained in:
Lucian Petrut
2026-09-08 14:41:24 +00:00
parent f70a1d485e
commit 14ed40548e
7 changed files with 853 additions and 1 deletions
+7 -1
View File
@@ -22,7 +22,13 @@
- `docs/` contains various documents that describe the reverse engineered - `docs/` contains various documents that describe the reverse engineered
vmware APIs and resulting modules. vmware APIs and resulting modules.
- Use `docs/reverse_engineering_procedure.md` to best describe the steps that - Use `docs/reverse_engineering_procedure.md` to best describe the steps that
were undertaken to reverse engineer the Vmware APIs. were undertaken to reverse engineer the Vmware APIs. Make sure to cover the
tools that were used (e.g. tcpdump, strace), when and how Python pickled objects
were stored.
- `docs/probing_samples` contains examples of scripts that were used for
reverse engineering purposes. The goal is to provide a better insight over
the reverse engineering procedure. Sanitize any sensitive information such
as credentials and ips.
## Architecture ## Architecture
+135
View File
@@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""Probe NFC write open-flags / opcode. Not part of the library."""
from __future__ import annotations
import os
import struct
import sys
import unittest
sys.path.insert(0, "/home/ubuntu/workspace/vmware_nbd_tests")
os.environ.pop("LD_PRELOAD", None)
from openvixdisklib import nfc_open
from tests.integration.base import TestBase
NFC_AIO_MSG_ERROR = 1
NFC_AIO_MSG_IO = 7
def recvn(sock, size):
buf = bytearray()
while len(buf) < size:
chunk = sock.recv(size - len(buf))
if not chunk:
raise RuntimeError(f"closed, got {len(buf)}/{size}")
buf.extend(chunk)
return bytes(buf)
def open_rw(session, disk_path, oflag):
sock = nfc_open.takeover_authd_socket(session.authd_sock)
nfc_open._handshake(sock, "vddk", "nbdmode", nfc_open.NFC_PROTOCOL_VERSION)
disk = nfc_open.NfcDisk(
sock, disk_path, handle=0, sector_size=nfc_open.NFC_SECTOR_SIZE)
nfc_open._aio_prepare(disk)
path_b = disk_path.encode("utf-8")
open_body = struct.pack(
"<IIIIII", len(path_b), 0, 0, 0, nfc_open.NFC_DISK, oflag)
open_body = open_body.ljust(60, b"\x00")
reply = disk._aio_roundtrip(
nfc_open.NFC_AIO_MSG_OPEN_FILE, open_body, extra=path_b)
handle, sector_size = nfc_open._parse_open_reply(reply)
disk.handle = handle
disk.sector_size = sector_size
echoed = struct.unpack_from("<I", reply, 20)[0]
print(f"OPEN sent=0x{oflag:x} echoed=0x{echoed:x} handle={handle}")
return disk
def try_io(disk, opcode, flags_field, data, send_extra=True):
length = len(data)
payload = struct.pack(
"<QQQQIII",
disk.handle, opcode, 0, length, length, length, flags_field)
op_id = disk._next_op_id()
disk._sock.sendall(
nfc_open._pack_aio_hdr(NFC_AIO_MSG_IO, len(payload), op_id) + payload)
if send_extra:
disk._sock.sendall(data)
rhdr = recvn(disk._sock, 16)
magic, rtype, rsize, rop = struct.unpack_from("<IIII", rhdr)
body = recvn(disk._sock, rsize) if rsize else b""
extra = b""
if rtype == NFC_AIO_MSG_IO and rsize >= 36:
chunk_len = struct.unpack_from("<I", body, 32)[0]
if 0 < chunk_len <= 65536:
extra = recvn(disk._sock, chunk_len)
return rtype, rsize, body, extra
class Probe(TestBase):
def test_probe(self):
data = self.pattern_bytes(self.SECTOR_SIZE, b"PROBE-S0")
open_flags = [
0x1C, 0x00, 0x1F, 0x0E, 0x0C, 0x04, 0x06, 0x02,
0x3E, 0x5E, 0x16, 0x1A, 0x1D, 0x0A, 0x08, 0x20,
0x3C, 0x7E, 0xFE, 0x100, 0x1E, 0x0F, 0x18,
]
# First: opcode 2 (guessed write) across open flags
for oflag in open_flags:
with self.authenticate() as session:
try:
disk = open_rw(session, self.DISK_PATH, oflag)
except Exception as exc:
print(f"OPEN FAIL 0x{oflag:x} {exc}")
continue
rtype, rsize, body, extra = try_io(disk, 2, 0, data)
print(
f" IO op=2 flags=0x{oflag:x} rtype={rtype} "
f"extra={len(extra)} body={body.hex()}")
if rtype == NFC_AIO_MSG_IO:
got = disk.read(0, 1)
print(f" readback match={got==data} {got[:16]!r}")
if got == data:
print("SUCCESS opcode=2")
disk.close()
return
try:
disk.close()
except Exception:
disk._sock.close()
# Then: opcode 1 with ioflags as write bit, open 0x1C and 0x00
for oflag in (0x1C, 0x00, 0x0E):
for opcode, ioflags, send_extra in (
(1, 1, True), (1, 2, True), (2, 1, True),
(4, 0, True), (5, 0, True), (8, 0, True),
(2, 0, True)):
with self.authenticate() as session:
disk = open_rw(session, self.DISK_PATH, oflag)
rtype, rsize, body, extra = try_io(
disk, opcode, ioflags, data, send_extra)
print(
f" IO op={opcode} iofl={ioflags} of=0x{oflag:x} "
f"rtype={rtype} extra={len(extra)} body={body[:16].hex()}")
if rtype == NFC_AIO_MSG_IO:
try:
got = disk.read(0, 1)
print(f" readback match={got==data} {got[:16]!r}")
if got == data:
print("SUCCESS")
disk.close()
return
except Exception as exc:
print(f" readback exc {exc}")
try:
disk.close()
except Exception:
disk._sock.close()
print("NO SUCCESS")
if __name__ == "__main__":
unittest.main()
+173
View File
@@ -0,0 +1,173 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <unistd.h>
static FILE *out;
static pthread_mutex_t log_mu = PTHREAD_MUTEX_INITIALIZER;
static int log_fd = -1;
static void init_out(void) {
if (out) {
return;
}
const char *path = getenv("SSLHOOK_LOG");
if (!path) {
path = "/tmp/sslhook-open.log";
}
out = fopen(path, "w");
if (!out) {
out = stderr;
}
log_fd = fileno(out);
setvbuf(out, NULL, _IONBF, 0);
}
static int peer_port(int fd) {
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
if (getpeername(fd, (struct sockaddr *)&ss, &len) != 0) {
return -1;
}
if (ss.ss_family == AF_INET) {
return ntohs(((struct sockaddr_in *)&ss)->sin_port);
}
if (ss.ss_family == AF_INET6) {
return ntohs(((struct sockaddr_in6 *)&ss)->sin6_port);
}
return -1;
}
static void dump(const char *tag, const void *id, int fd, const void *buf, int num) {
init_out();
pthread_mutex_lock(&log_mu);
fprintf(out, "\n==== %s %p fd=%d port=%d %d ====\n",
tag, id, fd, fd >= 0 ? peer_port(fd) : -1, num);
const unsigned char *p = buf;
for (int i = 0; i < num; i++) {
fprintf(out, "%02x", p[i]);
}
fprintf(out, "\n");
pthread_mutex_unlock(&log_mu);
}
typedef int (*ssl_write_fn)(void *, const void *, int);
typedef int (*ssl_read_fn)(void *, void *, int);
typedef int (*ssl_get_fd_fn)(const void *);
typedef int (*ssl_write_ex_fn)(void *, const void *, size_t, size_t *);
typedef int (*ssl_read_ex_fn)(void *, void *, size_t, size_t *);
static ssl_get_fd_fn real_ssl_get_fd(void) {
static ssl_get_fd_fn fn;
if (!fn) {
fn = (ssl_get_fd_fn)dlsym(RTLD_NEXT, "SSL_get_fd");
}
return fn;
}
int SSL_write(void *ssl, const void *buf, int num) {
static ssl_write_fn real;
if (!real) {
real = (ssl_write_fn)dlsym(RTLD_NEXT, "SSL_write");
}
int fd = real_ssl_get_fd() ? real_ssl_get_fd()(ssl) : -1;
dump("SSL_W", ssl, fd, buf, num);
return real(ssl, buf, num);
}
int SSL_read(void *ssl, void *buf, int num) {
static ssl_read_fn real;
if (!real) {
real = (ssl_read_fn)dlsym(RTLD_NEXT, "SSL_read");
}
int n = real(ssl, buf, num);
if (n > 0) {
int fd = real_ssl_get_fd() ? real_ssl_get_fd()(ssl) : -1;
dump("SSL_R", ssl, fd, buf, n);
}
return n;
}
int SSL_write_ex(void *ssl, const void *buf, size_t num, size_t *written) {
static ssl_write_ex_fn real;
if (!real) {
real = (ssl_write_ex_fn)dlsym(RTLD_NEXT, "SSL_write_ex");
}
int fd = real_ssl_get_fd() ? real_ssl_get_fd()(ssl) : -1;
dump("SSL_WEX", ssl, fd, buf, (int)num);
return real(ssl, buf, num, written);
}
int SSL_read_ex(void *ssl, void *buf, size_t num, size_t *readbytes) {
static ssl_read_ex_fn real;
if (!real) {
real = (ssl_read_ex_fn)dlsym(RTLD_NEXT, "SSL_read_ex");
}
int rc = real(ssl, buf, num, readbytes);
if (rc && readbytes && *readbytes > 0) {
int fd = real_ssl_get_fd() ? real_ssl_get_fd()(ssl) : -1;
dump("SSL_REX", ssl, fd, buf, (int)*readbytes);
}
return rc;
}
static int interesting_fd(int fd) {
if (fd < 0 || fd == log_fd) {
return 0;
}
int port = peer_port(fd);
return port == 902 || port == 9020;
}
ssize_t write(int fd, const void *buf, size_t count) {
static ssize_t (*real)(int, const void *, size_t);
if (!real) {
real = (ssize_t (*)(int, const void *, size_t))dlsym(RTLD_NEXT, "write");
}
if (interesting_fd(fd) && count > 0 && buf) {
dump("WRITE", NULL, fd, buf, (int)count);
}
return real(fd, buf, count);
}
ssize_t send(int fd, const void *buf, size_t len, int flags) {
static ssize_t (*real)(int, const void *, size_t, int);
if (!real) {
real = (ssize_t (*)(int, const void *, size_t, int))dlsym(RTLD_NEXT, "send");
}
if (interesting_fd(fd) && len > 0 && buf) {
dump("SEND", NULL, fd, buf, (int)len);
}
return real(fd, buf, len, flags);
}
ssize_t read(int fd, void *buf, size_t count) {
static ssize_t (*real)(int, void *, size_t);
if (!real) {
real = (ssize_t (*)(int, void *, size_t))dlsym(RTLD_NEXT, "read");
}
ssize_t n = real(fd, buf, count);
if (n > 0 && interesting_fd(fd)) {
dump("READ", NULL, fd, buf, (int)n);
}
return n;
}
ssize_t recv(int fd, void *buf, size_t len, int flags) {
static ssize_t (*real)(int, void *, size_t, int);
if (!real) {
real = (ssize_t (*)(int, void *, size_t, int))dlsym(RTLD_NEXT, "recv");
}
ssize_t n = real(fd, buf, len, flags);
if (n > 0 && interesting_fd(fd)) {
dump("RECV", NULL, fd, buf, (int)n);
}
return n;
}
+235
View File
@@ -0,0 +1,235 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/uio.h>
#include <unistd.h>
static FILE *out;
static pthread_mutex_t log_mu = PTHREAD_MUTEX_INITIALIZER;
static int log_fd = -1;
static int ready;
static ssize_t (*real_write)(int, const void *, size_t);
static ssize_t (*real_read)(int, void *, size_t);
static ssize_t (*real_send)(int, const void *, size_t, int);
static ssize_t (*real_recv)(int, void *, size_t, int);
static ssize_t (*real_writev)(int, const struct iovec *, int);
static ssize_t (*real_readv)(int, const struct iovec *, int);
static ssize_t (*real_sendmsg)(int, const struct msghdr *, int);
static ssize_t (*real_recvmsg)(int, struct msghdr *, int);
static int (*real_ssl_write)(void *, const void *, int);
static int (*real_ssl_read)(void *, void *, int);
static int (*real_ssl_get_fd)(const void *);
__attribute__((constructor))
static void init_syms(void) {
real_write = dlsym(RTLD_NEXT, "write");
real_read = dlsym(RTLD_NEXT, "read");
real_send = dlsym(RTLD_NEXT, "send");
real_recv = dlsym(RTLD_NEXT, "recv");
real_writev = dlsym(RTLD_NEXT, "writev");
real_readv = dlsym(RTLD_NEXT, "readv");
real_sendmsg = dlsym(RTLD_NEXT, "sendmsg");
real_recvmsg = dlsym(RTLD_NEXT, "recvmsg");
real_ssl_write = dlsym(RTLD_NEXT, "SSL_write");
real_ssl_read = dlsym(RTLD_NEXT, "SSL_read");
real_ssl_get_fd = dlsym(RTLD_NEXT, "SSL_get_fd");
const char *path = getenv("SSLHOOK_LOG");
if (!path) {
path = "/tmp/sslhook-write.log";
}
out = fopen(path, "w");
if (!out) {
out = stderr;
}
log_fd = fileno(out);
setvbuf(out, NULL, _IONBF, 0);
ready = 1;
fprintf(out, "hook loaded write=%p ssl_write=%p\n",
(void *)real_write, (void *)real_ssl_write);
}
static int peer_port(int fd) {
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
if (getpeername(fd, (struct sockaddr *)&ss, &len) != 0) {
return -1;
}
if (ss.ss_family == AF_INET) {
return ntohs(((struct sockaddr_in *)&ss)->sin_port);
}
if (ss.ss_family == AF_INET6) {
return ntohs(((struct sockaddr_in6 *)&ss)->sin6_port);
}
return -1;
}
static void dump(const char *tag, int fd, const void *buf, int num) {
if (!ready || !out || fd == log_fd || num <= 0 || num > 1024 * 1024) {
return;
}
int port = peer_port(fd);
if (port <= 0 || port == 443) {
return;
}
const unsigned char *p = buf;
/* Skip TLS records. */
if (num >= 3 && p[0] == 0x16 && p[1] == 0x03) {
return;
}
if (num >= 3 && p[0] == 0x17 && p[1] == 0x03) {
return;
}
pthread_mutex_lock(&log_mu);
fprintf(out, "\n==== %s fd=%d port=%d %d ====\n", tag, fd, port, num);
for (int i = 0; i < num; i++) {
fprintf(out, "%02x", p[i]);
}
fprintf(out, "\n");
pthread_mutex_unlock(&log_mu);
}
ssize_t write(int fd, const void *buf, size_t count) {
if (real_write == NULL) {
return syscall(SYS_write, fd, buf, count);
}
if (ready && out && fd != log_fd) {
static int nlogged;
if (nlogged < 40) {
fprintf(out, "write fd=%d port=%d n=%zu\n", fd, peer_port(fd), count);
nlogged++;
}
}
dump("WRITE", fd, buf, (int)count);
return real_write(fd, buf, count);
}
ssize_t read(int fd, void *buf, size_t count) {
if (real_read == NULL) {
return syscall(SYS_read, fd, buf, count);
}
ssize_t n = real_read(fd, buf, count);
if (n > 0) {
dump("READ", fd, buf, (int)n);
}
return n;
}
ssize_t send(int fd, const void *buf, size_t len, int flags) {
if (real_send == NULL) {
return syscall(SYS_sendto, fd, buf, len, flags, NULL, 0);
}
dump("SEND", fd, buf, (int)len);
return real_send(fd, buf, len, flags);
}
ssize_t recv(int fd, void *buf, size_t len, int flags) {
if (real_recv == NULL) {
return syscall(SYS_recvfrom, fd, buf, len, flags, NULL, 0);
}
ssize_t n = real_recv(fd, buf, len, flags);
if (n > 0) {
dump("RECV", fd, buf, (int)n);
}
return n;
}
ssize_t writev(int fd, const struct iovec *iov, int iovcnt) {
if (real_writev == NULL) {
return syscall(SYS_writev, fd, iov, iovcnt);
}
size_t total = 0;
for (int i = 0; i < iovcnt; i++) {
total += iov[i].iov_len;
}
if (total > 0 && total <= 1024 * 1024) {
unsigned char *buf = malloc(total);
if (buf) {
size_t off = 0;
for (int i = 0; i < iovcnt; i++) {
memcpy(buf + off, iov[i].iov_base, iov[i].iov_len);
off += iov[i].iov_len;
}
dump("WRITEV", fd, buf, (int)total);
free(buf);
}
}
return real_writev(fd, iov, iovcnt);
}
int SSL_write(void *ssl, const void *buf, int num) {
if (real_ssl_write == NULL) {
real_ssl_write = dlsym(RTLD_NEXT, "SSL_write");
}
int fd = real_ssl_get_fd ? real_ssl_get_fd(ssl) : -1;
dump("SSL_W", fd, buf, num);
return real_ssl_write(ssl, buf, num);
}
int SSL_read(void *ssl, void *buf, int num) {
if (real_ssl_read == NULL) {
real_ssl_read = dlsym(RTLD_NEXT, "SSL_read");
}
int n = real_ssl_read(ssl, buf, num);
if (n > 0) {
int fd = real_ssl_get_fd ? real_ssl_get_fd(ssl) : -1;
dump("SSL_R", fd, buf, n);
}
return n;
}
static void dump_msghdr(const char *tag, int fd, const struct msghdr *msg) {
if (!msg || !msg->msg_iov) {
return;
}
size_t total = 0;
for (size_t i = 0; i < (size_t)msg->msg_iovlen; i++) {
total += msg->msg_iov[i].iov_len;
}
if (total == 0 || total > 1024 * 1024) {
return;
}
unsigned char *buf = malloc(total);
if (!buf) {
return;
}
size_t off = 0;
for (size_t i = 0; i < (size_t)msg->msg_iovlen; i++) {
memcpy(buf + off, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
off += msg->msg_iov[i].iov_len;
}
dump(tag, fd, buf, (int)total);
free(buf);
}
ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
if (real_sendmsg == NULL) {
real_sendmsg = dlsym(RTLD_NEXT, "sendmsg");
}
if (ready && out && fd != log_fd) {
static int nlogged;
if (nlogged < 20) {
fprintf(out, "sendmsg fd=%d port=%d\n", fd, peer_port(fd));
nlogged++;
}
}
dump_msghdr("SENDMSG", fd, msg);
return real_sendmsg(fd, msg, flags);
}
ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
if (real_recvmsg == NULL) {
real_recvmsg = dlsym(RTLD_NEXT, "recvmsg");
}
ssize_t n = real_recvmsg(fd, msg, flags);
if (n > 0) {
dump_msghdr("RECVMSG", fd, msg);
}
return n;
}
+125
View File
@@ -0,0 +1,125 @@
#!/usr/bin/env python3
"""Trace VDDK Open+Read for NFC protocol capture."""
import ctypes
import os
VDDK_DIR = "/home/ubuntu/workspace/vmware_nbd_tests/vddk"
lib = ctypes.CDLL(os.path.join(VDDK_DIR, "libvixDiskLib.so"))
VIXDISKLIB_CRED_UID = 1
VIXDISKLIB_FLAG_OPEN_READ_ONLY = 4
class VixDiskLibUidPasswdCreds(ctypes.Structure):
_fields_ = [
("userName", ctypes.c_char_p),
("password", ctypes.c_char_p),
]
class VixDiskLibSessionIdCreds(ctypes.Structure):
_fields_ = [
("cookie", ctypes.c_char_p),
("userName", ctypes.c_char_p),
("key", ctypes.c_char_p),
]
class VixDiskLibCreds(ctypes.Union):
_fields_ = [
("uid", VixDiskLibUidPasswdCreds),
("sessionId", VixDiskLibSessionIdCreds),
]
class VixDiskLibConnectParams(ctypes.Structure):
_fields_ = [
("vmxSpec", ctypes.c_char_p),
("serverName", ctypes.c_char_p),
("thumbPrint", ctypes.c_char_p),
("privateUse", ctypes.c_longlong),
("credType", ctypes.c_uint32),
("creds", VixDiskLibCreds),
("port", ctypes.c_uint32),
("nfcHostPort", ctypes.c_uint32),
("vimApiVer", ctypes.c_char_p),
]
def check(err, what):
if err != 0:
lib.VixDiskLib_GetErrorText.restype = ctypes.c_void_p
lib.VixDiskLib_GetErrorText.argtypes = [ctypes.c_uint64, ctypes.c_char_p]
msg = lib.VixDiskLib_GetErrorText(err, None)
text = ctypes.cast(msg, ctypes.c_char_p).value
lib.VixDiskLib_FreeErrorText.argtypes = [ctypes.c_char_p]
lib.VixDiskLib_FreeErrorText(ctypes.cast(msg, ctypes.c_char_p))
raise SystemExit(f"{what} failed: {err} {text}")
def main():
os.makedirs("/tmp/vddk-open-trace", exist_ok=True)
config_path = "/tmp/vddk-open-trace/vddk.config"
with open(config_path, "w") as f:
f.write("tmpDirectory=/tmp/vddk-open-trace\n")
f.write("log.fileName=/tmp/vddk-open-trace/vddk.log\n")
f.write("log.fileLevel=verbose\n")
f.write("vixDiskLib.nfc.LogLevel=4\n")
f.write("vixDiskLib.transport.LogLevel=4\n")
lib.VixDiskLib_InitEx.argtypes = [
ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p,
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
lib.VixDiskLib_InitEx.restype = ctypes.c_uint64
check(lib.VixDiskLib_InitEx(
8, 0, None, None, None, VDDK_DIR.encode(), config_path.encode()),
"InitEx")
params = VixDiskLibConnectParams()
params.vmxSpec = b"<sanitized>"
params.serverName = b"<sanitized>"
params.thumbPrint = b"<sanitized>"
params.credType = VIXDISKLIB_CRED_UID
params.creds.uid.userName = b"<sanitized>"
params.creds.uid.password = b"<sanitized>"
params.port = 443
lib.VixDiskLib_ConnectEx.argtypes = [
ctypes.POINTER(VixDiskLibConnectParams), ctypes.c_char,
ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)]
lib.VixDiskLib_ConnectEx.restype = ctypes.c_uint64
conn = ctypes.c_void_p()
check(lib.VixDiskLib_ConnectEx(
params, True, b"snapshot-13442", b"nbd", ctypes.byref(conn)),
"ConnectEx")
print("ConnectEx ok", flush=True)
lib.VixDiskLib_Open.argtypes = [
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_void_p)]
lib.VixDiskLib_Open.restype = ctypes.c_uint64
disk = ctypes.c_void_p()
path = b"[datastore0] test-coriolis-jenkins-rocky9/test-coriolis-jenkins-rocky9-000007.vmdk"
check(lib.VixDiskLib_Open(conn, path, VIXDISKLIB_FLAG_OPEN_READ_ONLY, ctypes.byref(disk)),
"Open")
print("Open ok", flush=True)
buf = ctypes.create_string_buffer(512)
lib.VixDiskLib_Read.argtypes = [
ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_char_p]
lib.VixDiskLib_Read.restype = ctypes.c_uint64
check(lib.VixDiskLib_Read(disk, 0, 1, buf), "Read")
print("Read ok first16", buf.raw[:16].hex(), flush=True)
lib.VixDiskLib_Close.argtypes = [ctypes.c_void_p]
lib.VixDiskLib_Close.restype = ctypes.c_uint64
lib.VixDiskLib_Disconnect.argtypes = [ctypes.c_void_p]
lib.VixDiskLib_Disconnect.restype = ctypes.c_uint64
lib.VixDiskLib_Close(disk)
lib.VixDiskLib_Disconnect(conn)
lib.VixDiskLib_Exit()
if __name__ == "__main__":
main()
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
"""Trace VDDK Read at several offsets/sizes for NFC IO capture."""
import ctypes
import os
VDDK_DIR = "/home/ubuntu/workspace/vmware_nbd_tests/vddk"
lib = ctypes.CDLL(os.path.join(VDDK_DIR, "libvixDiskLib.so"))
VIXDISKLIB_CRED_UID = 1
VIXDISKLIB_FLAG_OPEN_READ_ONLY = 4
SECTOR = 512
class VixDiskLibUidPasswdCreds(ctypes.Structure):
_fields_ = [
("userName", ctypes.c_char_p),
("password", ctypes.c_char_p),
]
class VixDiskLibSessionIdCreds(ctypes.Structure):
_fields_ = [
("cookie", ctypes.c_char_p),
("userName", ctypes.c_char_p),
("key", ctypes.c_char_p),
]
class VixDiskLibCreds(ctypes.Union):
_fields_ = [
("uid", VixDiskLibUidPasswdCreds),
("sessionId", VixDiskLibSessionIdCreds),
]
class VixDiskLibConnectParams(ctypes.Structure):
_fields_ = [
("vmxSpec", ctypes.c_char_p),
("serverName", ctypes.c_char_p),
("thumbPrint", ctypes.c_char_p),
("privateUse", ctypes.c_longlong),
("credType", ctypes.c_uint32),
("creds", VixDiskLibCreds),
("port", ctypes.c_uint32),
("nfcHostPort", ctypes.c_uint32),
("vimApiVer", ctypes.c_char_p),
]
def check(err, what):
if err != 0:
lib.VixDiskLib_GetErrorText.restype = ctypes.c_void_p
lib.VixDiskLib_GetErrorText.argtypes = [ctypes.c_uint64, ctypes.c_char_p]
msg = lib.VixDiskLib_GetErrorText(err, None)
text = ctypes.cast(msg, ctypes.c_char_p).value
lib.VixDiskLib_FreeErrorText.argtypes = [ctypes.c_char_p]
lib.VixDiskLib_FreeErrorText(ctypes.cast(msg, ctypes.c_char_p))
raise SystemExit(f"{what} failed: {err} {text}")
def main():
os.makedirs("/tmp/vddk-read-trace", exist_ok=True)
config_path = "/tmp/vddk-read-trace/vddk.config"
with open(config_path, "w") as f:
f.write("tmpDirectory=/tmp/vddk-read-trace\n")
f.write("log.fileName=/tmp/vddk-read-trace/vddk.log\n")
f.write("log.fileLevel=verbose\n")
f.write("vixDiskLib.nfc.LogLevel=4\n")
f.write("vixDiskLib.transport.LogLevel=4\n")
lib.VixDiskLib_InitEx.argtypes = [
ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p,
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p]
lib.VixDiskLib_InitEx.restype = ctypes.c_uint64
check(lib.VixDiskLib_InitEx(
8, 0, None, None, None, VDDK_DIR.encode(), config_path.encode()),
"InitEx")
params = VixDiskLibConnectParams()
params.vmxSpec = b"<sanitized>"
params.serverName = b"<sanitized>"
params.thumbPrint = b"<sanitized>"
params.credType = VIXDISKLIB_CRED_UID
params.creds.uid.userName = b"<sanitized>"
params.creds.uid.password = b"<sanitized>"
params.port = 443
lib.VixDiskLib_ConnectEx.argtypes = [
ctypes.POINTER(VixDiskLibConnectParams), ctypes.c_char,
ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)]
lib.VixDiskLib_ConnectEx.restype = ctypes.c_uint64
conn = ctypes.c_void_p()
check(lib.VixDiskLib_ConnectEx(
params, True, b"snapshot-13442", b"nbd", ctypes.byref(conn)),
"ConnectEx")
print("ConnectEx ok", flush=True)
lib.VixDiskLib_Open.argtypes = [
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_void_p)]
lib.VixDiskLib_Open.restype = ctypes.c_uint64
disk = ctypes.c_void_p()
path = b"[datastore0] test-coriolis-jenkins-rocky9/test-coriolis-jenkins-rocky9-000007.vmdk"
check(lib.VixDiskLib_Open(conn, path, VIXDISKLIB_FLAG_OPEN_READ_ONLY, ctypes.byref(disk)),
"Open")
print("Open ok", flush=True)
lib.VixDiskLib_Read.argtypes = [
ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_char_p]
lib.VixDiskLib_Read.restype = ctypes.c_uint64
reads = [
(0, 1),
(0, 2),
(1, 1),
(8, 8),
(0, 128),
(0, 129),
(256, 64),
]
for start, n in reads:
buf = ctypes.create_string_buffer(n * SECTOR)
check(lib.VixDiskLib_Read(disk, start, n, buf), f"Read {start}+{n}")
nz = sum(1 for b in buf.raw if b)
print(f"Read start={start} n={n} first16={buf.raw[:16].hex()} nonzero={nz}",
flush=True)
lib.VixDiskLib_Close.argtypes = [ctypes.c_void_p]
lib.VixDiskLib_Close.restype = ctypes.c_uint64
lib.VixDiskLib_Disconnect.argtypes = [ctypes.c_void_p]
lib.VixDiskLib_Disconnect.restype = ctypes.c_uint64
lib.VixDiskLib_Close(disk)
lib.VixDiskLib_Disconnect(conn)
lib.VixDiskLib_Exit()
if __name__ == "__main__":
main()
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""One-off: VDDK write with verbose NFC logs. Not part of the library."""
import os
import sys
import unittest
sys.path.insert(0, "/home/ubuntu/workspace/vmware_nbd_tests")
os.environ.pop("LD_PRELOAD", None)
os.environ["LD_LIBRARY_PATH"] = (
"/home/ubuntu/workspace/vmware_nbd_tests/.vddk:"
+ os.environ.get("LD_LIBRARY_PATH", ""))
from tests.integration.base import TestBase
from tests.integration import vixdisklib
class _T(TestBase):
@classmethod
def setUpClass(cls):
cls.require_vddk()
super().setUpClass()
def test_write(self):
handle = vixdisklib.VixDiskLibHandle(
vixdisklib_compatibility_version="8.0",
config_path="/tmp/vddk_nfc.conf")
buf = vixdisklib.get_buffer(self.SECTOR_SIZE)
expected = self.pattern_bytes(self.SECTOR_SIZE, b"TRACE-S0")
buf[:self.SECTOR_SIZE] = expected
with handle.connect(**self.vixdisklib_connect_kwargs()) as conn:
with handle.open(conn, self.DISK_PATH, flags=0) as disk:
handle.write(disk, 0, 1, buf)
handle.read(disk, 0, 1, buf)
print("DISK_PATH", self.DISK_PATH, "ok", buf.raw[:8])
if __name__ == "__main__":
unittest.main()