diff --git a/AGENTS.md b/AGENTS.md index 5413f9a..f4692f2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,7 +22,13 @@ - `docs/` contains various documents that describe the reverse engineered vmware APIs and resulting modules. - 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 diff --git a/docs/probing_samples/nfc_write_probe.py b/docs/probing_samples/nfc_write_probe.py new file mode 100644 index 0000000..15235c7 --- /dev/null +++ b/docs/probing_samples/nfc_write_probe.py @@ -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( + "= 36: + chunk_len = struct.unpack_from(" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/docs/probing_samples/sslhook_nfc.c b/docs/probing_samples/sslhook_nfc.c new file mode 100644 index 0000000..5db2585 --- /dev/null +++ b/docs/probing_samples/sslhook_nfc.c @@ -0,0 +1,235 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/docs/probing_samples/vddk_open_trace.py b/docs/probing_samples/vddk_open_trace.py new file mode 100644 index 0000000..73f1a47 --- /dev/null +++ b/docs/probing_samples/vddk_open_trace.py @@ -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"" + params.serverName = b"" + params.thumbPrint = b"" + params.credType = VIXDISKLIB_CRED_UID + params.creds.uid.userName = b"" + params.creds.uid.password = b"" + 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() diff --git a/docs/probing_samples/vddk_read_trace.py b/docs/probing_samples/vddk_read_trace.py new file mode 100644 index 0000000..c8bfe31 --- /dev/null +++ b/docs/probing_samples/vddk_read_trace.py @@ -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"" + params.serverName = b"" + params.thumbPrint = b"" + params.credType = VIXDISKLIB_CRED_UID + params.creds.uid.userName = b"" + params.creds.uid.password = b"" + 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() diff --git a/docs/probing_samples/vddk_write_trace.py b/docs/probing_samples/vddk_write_trace.py new file mode 100644 index 0000000..b1b7405 --- /dev/null +++ b/docs/probing_samples/vddk_write_trace.py @@ -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()