[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 4/4] added qga processes and connections enumeration
From: |
itamar . tal4 |
Subject: |
[Qemu-devel] [PATCH 4/4] added qga processes and connections enumeration commands (win/linux) |
Date: |
Tue, 31 Mar 2015 11:34:37 +0300 |
From: Itamar Tal <address@hidden>
This patch add more missing commands to the qga (both Windows and Linux):
- current active process list
- current active connections list
the abovementioned commands are added to align the guest agent functionality
with other common hypervisor agents.
---
qga/commands-posix.c | 608 ++++++++++++++++++++++++++++++++++++++++++++++++
qga/commands-win32.c | 404 +++++++++++++++++++++++++++++++-
qga/qapi-schema.json | 99 ++++++++
qga/win32-definitions.h | 110 +++++++++
qga/win32-iptypes.h | 412 ++++++++++++++++++++++++++++++++
5 files changed, 1631 insertions(+), 2 deletions(-)
create mode 100644 qga/win32-definitions.h
create mode 100644 qga/win32-iptypes.h
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 38b639c..c4b82eb 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -9,6 +9,7 @@
*
* Changes (address@hidden):
* - file attributes, removal, hashes
+ * - added process and connection enumeration support
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -50,6 +51,53 @@ extern char **environ;
#include <sys/socket.h>
#include <net/if.h>
+#define PRG_HASH_SIZE (211)
+
+typedef
+struct prg_node {
+ struct prg_node *next;
+ int inode;
+ int pid;
+} prg_node;
+
+typedef
+struct prg_hash {
+ struct prg_node *hash[PRG_HASH_SIZE];
+} prg_hash;
+
+#define PRG_LOCAL_ADDRESS "local_address"
+#define PRG_INODE "inode"
+#define PRG_SOCKET_PFX "socket:["
+#define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
+#define PRG_SOCKET_PFX2 "[0000]:"
+#define PRG_SOCKET_PFX2l (strlen(PRG_SOCKET_PFX2))
+
+#define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
+#ifndef LINE_MAX
+#define LINE_MAX 4096
+#endif
+#define PATH_PROC "/proc"
+#define PATH_FD_SUFF "fd"
+#define PATH_FD_SUFFl strlen(PATH_FD_SUFF)
+#define PATH_PROC_X_FD PATH_PROC "/%s/" PATH_FD_SUFF
+#define PATH_CMDLINE "cmdline"
+#define PATH_CMDLINEl strlen(PATH_CMDLINE)
+
+/* These enums are used by IPX too. :-( */
+enum {
+ TCP_ESTABLISHED = 1,
+ TCP_SYN_SENT,
+ TCP_SYN_RECV,
+ TCP_FIN_WAIT1,
+ TCP_FIN_WAIT2,
+ TCP_TIME_WAIT,
+ TCP_CLOSE,
+ TCP_CLOSE_WAIT,
+ TCP_LAST_ACK,
+ TCP_LISTEN,
+ TCP_CLOSING /* now a valid state */
+};
+
#ifdef FIFREEZE
#define CONFIG_FSFREEZE
#endif
@@ -2491,4 +2539,564 @@ uint32_t qmp_guest_uptime(Error **errp)
return sys_info.uptime;
}
+GuestProcessInfoList *qmp_guest_get_process_list(Error **errp)
+{
+ struct dirent *ent = NULL;
+ GuestProcessInfoList *process_list_head = NULL;
+ GuestProcessInfoList *process_list_last = NULL;
+
+ DIR *procfs = opendir("/proc");
+
+ if (NULL == procfs) {
+ error_setg(errp, "Failed opening procfs (error %d)", errno);
+ return NULL;
+ }
+
+ /* read entries until EOD */
+ errno = 0;
+ while (NULL != (ent = readdir(procfs))) {
+ int pid = strtoul(ent->d_name, NULL, 10);
+ GuestProcessInfoList *list_item = NULL;
+ char local_path[256];
+ FILE *info_file = NULL;
+ char info[256];
+ size_t len;
+
+ /* ensure directory name is a number */
+ if ((0 == pid) || (ULONG_MAX == pid)) {
+ continue;
+ }
+
+ list_item = g_malloc0(sizeof(GuestProcessInfoList));
+ if (NULL == process_list_head) {
+ process_list_head = list_item;
+ }
+ if (NULL != process_list_last) {
+ process_list_last->next = list_item;
+ }
+ process_list_last = list_item;
+
+ list_item->next = NULL;
+ list_item->value = g_malloc0(sizeof(GuestProcessInfo));
+ list_item->value->process_id = pid;
+
+ /* read process name */
+ snprintf(local_path, 256, "/proc/%d/comm", pid);
+ info_file = fopen(local_path, "rb");
+ if (NULL != info_file) {
+ len = fread(info, 1, 256, info_file);
+ info[len] = '\0';
+ if ((0 < len) && ('\n' == info[len - 1])) {
+ info[len - 1] = '\0';
+ }
+ list_item->value->process_name = g_strdup(info);
+
+ fclose(info_file);
+ }
+
+ /* read process parent id */
+ snprintf(local_path, 256, "/proc/%d/status", pid);
+ info_file = fopen(local_path, "rb");
+ if (NULL != info_file) {
+ char *line = NULL;
+ size_t line_size = 0;
+
+ /* read lines, search for ppid */
+ for (;;) {
+ len = getline(&line, &line_size, info_file);
+ if (-1 == len) {
+ break;
+ }
+
+ if (line == strstr(line, "PPid:")) {
+ list_item->value->parent_id = strtoul(line + 5, NULL, 10);
+ }
+ }
+
+ fclose(info_file);
+ }
+
+ /* read process session id */
+ snprintf(local_path, 256, "/proc/%d/sessionid", pid);
+ info_file = fopen(local_path, "rb");
+ if (NULL != info_file) {
+ len = fread(info, 1, 256, info_file);
+ info[len] = '\0';
+ list_item->value->session_id = strtoul(info, NULL, 10);
+
+ fclose(info_file);
+ }
+
+ /* read process image path */
+ snprintf(local_path, 256, "/proc/%d/exe", pid);
+ len = readlink(local_path, info, sizeof(info) - 1);
+ if (-1 != len) {
+ info[len] = '\0';
+ list_item->value->image_path = g_strdup(info);
+ }
+
+ errno = 0;
+ }
+
+ (void)closedir(procfs);
+
+ if (0 != errno) {
+ error_setg(errp, "Error while reading procfs directory (error %d)",
+ errno);
+ return NULL;
+ }
+
+ return process_list_head;
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static void prg_cache_add(prg_hash *hash, int inode, int pid)
+{
+ unsigned hi = PRG_HASHIT(inode);
+ struct prg_node **pnp = NULL, *pn = NULL;
+
+ /* look for the inode in the table or find next free entry for the inode */
+ for (pnp = &hash->hash[hi]; (pn = *pnp); pnp = &pn->next) {
+ if (pn->inode == inode) {
+ /* Some warning should be appropriate here
+ as we got multiple processes for one i-node */
+ return;
+ }
+ }
+
+ /* allocate new entry for this inode */
+ *pnp = g_malloc0(sizeof(struct prg_node));
+ if (NULL == *pnp) {
+ return;
+ }
+
+ pn = *pnp;
+ pn->next = NULL;
+ pn->inode = inode;
+ pn->pid = pid;
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static int prg_cache_get(prg_hash *hash, int inode)
+{
+ unsigned hi = PRG_HASHIT(inode);
+ struct prg_node *pn = NULL;
+
+ for (pn = hash->hash[hi]; pn; pn = pn->next) {
+ if (pn->inode == inode) {
+ return pn->pid;
+ }
+ }
+
+ return -1;
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static void prg_cache_clear(prg_hash *hash)
+{
+ struct prg_node **pnp = NULL, *pn = NULL;
+
+
+ for (pnp = hash->hash; pnp < hash->hash + PRG_HASH_SIZE; pnp++) {
+ pn = *pnp;
+ while (NULL != pn) {
+ *pnp = pn->next;
+ free(pn);
+ pn = *pnp;
+ }
+ }
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static void extract_type_1_socket_inode(const char lname[], long *inode_p)
+{
+
+ /* If lname is of the form "socket:[12345]", extract the "12345"
+ as *inode_p. Otherwise, return -1 as *inode_p.
+ */
+
+ if (strlen(lname) < PRG_SOCKET_PFXl+3) {
+ *inode_p = -1;
+ } else if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) {
+ *inode_p = -1;
+ } else if (lname[strlen(lname)-1] != ']') {
+ *inode_p = -1;
+ } else {
+ char inode_str[strlen(lname + 1)]; /* e.g. "12345" */
+ const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
+ char *serr = NULL;
+
+ strncpy(inode_str, lname + PRG_SOCKET_PFXl, inode_str_len);
+ inode_str[inode_str_len] = '\0';
+ *inode_p = strtol(inode_str, &serr, 0);
+ if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX) {
+ *inode_p = -1;
+ }
+ }
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static void extract_type_2_socket_inode(const char lname[], long *inode_p)
+{
+
+ /* If lname is of the form "[0000]:12345", extract the "12345"
+ as *inode_p. Otherwise, return -1 as *inode_p.
+ */
+
+ if (strlen(lname) < PRG_SOCKET_PFX2l+1) {
+ *inode_p = -1;
+ } else if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) {
+ *inode_p = -1;
+ } else {
+ char *serr = NULL;
+
+ *inode_p = strtol(lname + PRG_SOCKET_PFX2l, &serr, 0);
+ if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX) {
+ *inode_p = -1;
+ }
+ }
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static int prg_cache_load(prg_hash *hash)
+{
+ char line[LINE_MAX];
+ int procfdlen, lnamelen;
+ char lname[30];
+ long inode;
+ const char *cs = NULL;
+ DIR *dirproc = NULL, *dirfd = NULL;
+ struct dirent *direproc = NULL, *direfd = NULL;
+
+ /* reset the hash table */
+ memset(hash, 0, sizeof(prg_hash));
+
+ dirproc = opendir(PATH_PROC);
+ if (NULL == dirproc) {
+ return 0;
+ }
+
+ for (;;) {
+ int pid = 0;
+
+ errno = 0;
+ direproc = readdir(dirproc);
+ if (NULL == direproc) {
+ break;
+ }
+
+#ifdef DIRENT_HAVE_D_TYPE_WORKS
+ if (direproc->d_type != DT_DIR) {
+ continue;
+ }
+#endif
+ for (cs = direproc->d_name; *cs; cs++) {
+ if (!isdigit(*cs)) {
+ break;
+ }
+ }
+ if (*cs) {
+ continue;
+ }
+
+ procfdlen = snprintf(line, sizeof(line),
+ PATH_PROC_X_FD, direproc->d_name);
+ if ((procfdlen <= 0) || (procfdlen >= sizeof(line) - 5)) {
+ continue;
+ }
+ errno = 0;
+ dirfd = opendir(line);
+ if (NULL == dirfd) {
+ continue;
+ }
+ line[procfdlen] = '/';
+ for (;;) {
+ errno = 0;
+ direfd = readdir(dirfd);
+ if (NULL == direfd) {
+ break;
+ }
+
+#ifdef DIRENT_HAVE_D_TYPE_WORKS
+ if (direfd->d_type != DT_LNK) {
+ continue;
+ }
+#endif
+ if (procfdlen + 1 + strlen(direfd->d_name) + 1 > sizeof(line)) {
+ continue;
+ }
+ memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
+ PATH_FD_SUFFl + 1);
+ strcpy(line + procfdlen + 1, direfd->d_name);
+ lnamelen = readlink(line, lname, sizeof(lname)-1);
+ lname[lnamelen] = '\0'; /*make it a null-terminated string*/
+
+ extract_type_1_socket_inode(lname, &inode);
+
+ if (inode < 0) {
+ extract_type_2_socket_inode(lname, &inode);
+ }
+
+ if (inode < 0) {
+ continue;
+ }
+
+ pid = strtoul(direproc->d_name, NULL, 10);
+ prg_cache_add(hash, inode, pid);
+ }
+ closedir(dirfd);
+ dirfd = NULL;
+ }
+ if (dirproc) {
+ closedir(dirproc);
+ }
+ if (dirfd) {
+ closedir(dirfd);
+ }
+
+ return 1;
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static GuestActiveConnection *udp_do_one(prg_hash *hash, const char *line)
+{
+ GuestActiveConnection *conn = NULL;
+ char local_addr[64], rem_addr[64];
+ char more[512];
+ int num, local_port, rem_port, d, state, timer_run, uid, timeout;
+ struct sockaddr_in localaddr, remaddr;
+ unsigned long rxq, txq, time_len, retr, inode;
+
+ more[0] = '\0';
+ num = sscanf(line,
+ "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X"
+ " %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
+ &d, local_addr, &local_port,
+ rem_addr, &rem_port, &state,
+ &txq, &rxq, &timer_run, &time_len,
+ &retr, &uid, &timeout, &inode, more);
+
+ if (strlen(local_addr) > 8) {
+ /* ipv6 support is missing */
+ } else {
+ sscanf(local_addr, "%X",
+ &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
+ sscanf(rem_addr, "%X",
+ &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
+ ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
+ ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
+ }
+
+ retr = 0L;
+
+ if (num < 10) {
+ return NULL;
+ }
+
+ conn = g_malloc0(sizeof(GuestActiveConnection));
+
+ if (AF_INET == localaddr.sin_family) {
+ conn->source_addr = g_strdup(inet_ntoa(localaddr.sin_addr));
+ conn->dest_addr = g_strdup(inet_ntoa(remaddr.sin_addr));
+ }
+
+ conn->source_port = local_port;
+ conn->dest_port = rem_port;
+ conn->owner_process_id = prg_cache_get(hash, inode);
+ conn->if_family = GUEST_IP_ADDRESS_TYPE_IPV4;
+ conn->protocol = GUEST_IP_PROTOCOL_UDP;
+
+ switch (state) {
+ case TCP_CLOSE:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_CLOSED;
+ break;
+ case TCP_ESTABLISHED:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_ESTABLISHED;
+ break;
+ default:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_LISTEN;
+ break;
+ }
+
+ return conn;
+}
+
+/* this function is taken out of netstat (found in net-tools) and modified */
+static GuestActiveConnection *tcp_do_one(prg_hash *hash, const char *line)
+{
+ unsigned long rxq, txq, time_len, retr, inode;
+ int num, local_port, rem_port, d, state, uid, timer_run, timeout;
+ char rem_addr[128], local_addr[128], more[512];
+ struct sockaddr_in localaddr, remaddr;
+ GuestActiveConnection *conn = NULL;
+
+ num = sscanf(line,
+ "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X"
+ " %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
+ &d, local_addr, &local_port, rem_addr, &rem_port, &state,
+ &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout,
+ &inode, more);
+
+ if (strlen(local_addr) > 8) {
+ /* ipv6 support is missing */
+ } else {
+ sscanf(local_addr, "%X",
+ &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
+ sscanf(rem_addr, "%X",
+ &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
+ ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
+ ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
+ }
+
+ if (num < 11) {
+ return NULL;
+ }
+
+ if (state == TCP_LISTEN) {
+ time_len = 0;
+ retr = 0L;
+ rxq = 0L;
+ txq = 0L;
+ }
+
+ conn = g_malloc0(sizeof(GuestActiveConnection));
+
+ if (AF_INET == localaddr.sin_family) {
+ conn->source_addr = g_strdup(inet_ntoa(localaddr.sin_addr));
+ conn->dest_addr = g_strdup(inet_ntoa(remaddr.sin_addr));
+ }
+
+ conn->source_port = local_port;
+ conn->dest_port = rem_port;
+ conn->owner_process_id = prg_cache_get(hash, inode);
+ conn->if_family = GUEST_IP_ADDRESS_TYPE_IPV4;
+ conn->protocol = GUEST_IP_PROTOCOL_TCP;
+
+ switch (state) {
+ case TCP_CLOSE:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_CLOSED;
+ break;
+ case TCP_LISTEN:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_LISTEN;
+ break;
+ case TCP_SYN_SENT:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_SYN_SENT;
+ break;
+ case TCP_SYN_RECV:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_SYN_RCVD;
+ break;
+ case TCP_ESTABLISHED:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_ESTABLISHED;
+ break;
+ case TCP_FIN_WAIT1:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_FIN_WAIT1;
+ break;
+ case TCP_FIN_WAIT2:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_FIN_WAIT2;
+ break;
+ case TCP_CLOSE_WAIT:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_CLOSE_WAIT;
+ break;
+ case TCP_CLOSING:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_CLOSING;
+ break;
+ case TCP_LAST_ACK:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_LAST_ACK;
+ break;
+ case TCP_TIME_WAIT:
+ conn->state = GUEST_TCP_PROTOCOL_STATE_TIME_WAIT;
+ break;
+ }
+
+ return conn;
+}
+
+GuestActiveConnectionList *qmp_guest_get_active_connections(Error **errp)
+{
+ GuestActiveConnectionList *conn_list_head = NULL;
+ GuestActiveConnectionList *conn_list_last = NULL;
+ prg_hash hash;
+ FILE *udp_info = NULL;
+ FILE *tcp_info = fopen("/proc/net/tcp", "r");
+ int i = 0;
+
+ if (NULL == tcp_info) {
+ error_setg(errp, "Error opening '/proc/net/tcp' (error %d)", errno);
+ return NULL;
+ }
+
+ prg_cache_load(&hash);
+
+ for (i = 0; !feof(tcp_info); ++i) {
+ char tcp_info_line[1024];
+ GuestActiveConnectionList *conn_item = NULL;
+ GuestActiveConnection *conn = NULL;
+
+ if (NULL == fgets(tcp_info_line, 1024, tcp_info)) {
+ continue;
+ }
+
+ if (i == 0) {
+ continue;
+ }
+
+ conn = tcp_do_one(&hash, tcp_info_line);
+ if (NULL == conn) {
+ continue;
+ }
+
+ /* add connection to the end of list */
+ conn_item = g_malloc0(sizeof(GuestActiveConnectionList));
+ if (NULL == conn_list_head) {
+ conn_list_head = conn_item;
+ }
+ if (NULL != conn_list_last) {
+ conn_list_last->next = conn_item;
+ }
+ conn_list_last = conn_item;
+ conn_item->value = conn;
+ }
+
+ fclose(tcp_info);
+
+ udp_info = fopen("/proc/net/udp", "r");
+ if (NULL == udp_info) {
+ error_setg(errp, "Error opening '/proc/net/udp' (error %d)", errno);
+ return NULL;
+ }
+
+ for (i = 0; !feof(udp_info); ++i) {
+ char udp_info_line[1024];
+ GuestActiveConnectionList *conn_item = NULL;
+ GuestActiveConnection *conn = NULL;
+
+ if (NULL == fgets(udp_info_line, 1024, udp_info)) {
+ continue;
+ }
+
+ if (i == 0) {
+ continue;
+ }
+
+ conn = udp_do_one(&hash, udp_info_line);
+ if (NULL == conn) {
+ continue;
+ }
+
+ /* add connection to the end of list */
+ conn_item = g_malloc0(sizeof(GuestActiveConnectionList));
+ if (NULL == conn_list_head) {
+ conn_list_head = conn_item;
+ }
+ if (NULL != conn_list_last) {
+ conn_list_last->next = conn_item;
+ }
+ conn_list_last = conn_item;
+ conn_item->value = conn;
+ }
+
+ prg_cache_clear(&hash);
+
+ return conn_list_head;
+}
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 6987f4e..30dcd50 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -9,6 +9,7 @@
*
* Changes (address@hidden):
* - file attributes, removal, hashes
+ * - added process and connection enumeration support
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -22,6 +23,7 @@
#include "qga/guest-agent-core.h"
#include "qga/vss-win32.h"
#include "qga-qmp-commands.h"
+#include "qga/win32-definitions.h"
#include "qapi/qmp/qerror.h"
#include "qemu/queue.h"
@@ -29,6 +31,10 @@
#define SHTDN_REASON_FLAG_PLANNED 0x80000000
#endif
+#ifndef MAX_PATH
+#define MAX_PATH (256)
+#endif
+
/* multiple of 100 nanoseconds elapsed between windows baseline
* (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */
#define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \
@@ -37,6 +43,38 @@
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+DWORD (__stdcall * GetExtendedTcpTable)(void *pTcpTable,
+ DWORD * pdwSize,
+ BOOL bOrder,
+ ULONG ulAf,
+ TCP_TABLE_CLASS TableClass,
+ ULONG Reserved) = NULL;
+
+DWORD (__stdcall * GetExtendedUdpTable)(void *pUdpTable,
+ DWORD * pdwSize,
+ BOOL bOrder,
+ ULONG ulAf,
+ UDP_TABLE_CLASS TableClass,
+ ULONG Reserved) = NULL;
+
+NTSTATUS (__stdcall * RtlUnicodeStringToAnsiString)(
+ ANSI_STRING *DestinationString,
+ UNICODE_STRING *SourceString,
+ BOOL AllocateDestinationString) = NULL;
+
+NTSTATUS (__stdcall * NtQueryInformationProcess)(
+ HANDLE ProcessHandle,
+ PROCESSINFOCLASS ProcessInformationClass,
+ void *ProcessInformation,
+ uint32_t ProcessInformationLength,
+ uint32_t *ReturnLength) = NULL;
+
+NTSTATUS (__stdcall * NtQuerySystemInformation)(
+ SYSTEM_INFORMATION_CLASS SystemInformationClass,
+ void *SystemInformation,
+ uint32_t SystemInformationLength,
+ uint32_t *ReturnLength) = NULL;
+
typedef struct GuestFileHandle {
int64_t id;
HANDLE fh;
@@ -386,17 +424,59 @@ static void guest_file_init(void)
}
int ga_win_commands_init(void)
-{
+ {
+ HMODULE ntdll_module = GetModuleHandle("ntdll.dll");
+ HMODULE iphlpapi_module = LoadLibrary("iphlpapi.dll");
WSADATA wsa_data = {0};
+ if ((NULL == ntdll_module) ||
+ (NULL == iphlpapi_module)) {
+ goto error;
+ }
+
if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) {
g_critical("failed to initialize WSA engine");
goto error;
}
+ NtQuerySystemInformation =
+ (void *)GetProcAddress(ntdll_module,
+ "NtQuerySystemInformation");
+ if (NULL == NtQuerySystemInformation) {
+ goto error;
+ }
+
+ RtlUnicodeStringToAnsiString =
+ (void *)GetProcAddress(ntdll_module,
+ "RtlUnicodeStringToAnsiString");
+ if (NULL == RtlUnicodeStringToAnsiString) {
+ goto error;
+ }
+
+ NtQueryInformationProcess =
+ (void *)GetProcAddress(ntdll_module,
+ "NtQueryInformationProcess");
+ if (NULL == NtQueryInformationProcess) {
+ goto error;
+ }
+
+ GetExtendedTcpTable = (void *)GetProcAddress(iphlpapi_module,
+ "GetExtendedTcpTable");
+ if (NULL == GetExtendedTcpTable) {
+ goto error;
+ }
+
+ GetExtendedUdpTable = (void *)GetProcAddress(iphlpapi_module,
+ "GetExtendedUdpTable");
+ if (NULL == GetExtendedUdpTable) {
+ goto error;
+ }
+
return 1;
-error:
+ error:
+ (void)FreeLibrary(iphlpapi_module);
+
return 0;
}
@@ -902,4 +982,324 @@ uint32_t qmp_guest_uptime(Error **errp)
return uptime_milli / 1000;
}
+GuestProcessInfoList *qmp_guest_get_process_list(Error **errp)
+{
+ uint32_t bytes_needed = sizeof(SYSTEM_PROCESS_INFORMATION) * 20;
+ SYSTEM_PROCESS_INFORMATION *process_list = NULL;
+ SYSTEM_PROCESS_INFORMATION *process_list_iter = NULL;
+ GuestProcessInfoList *process_list_head = NULL;
+ GuestProcessInfoList *process_list_last = NULL;
+ DWORD current_process_id = GetCurrentProcessId();
+ NTSTATUS status = STATUS_SUCCESS;
+
+ /* find the minimal buffer for the process list */
+ for (;;) {
+ process_list = g_malloc0(bytes_needed);
+ if (NULL == process_list) {
+ error_setg(errp, "No memory for process list (%d bytes)",
+ bytes_needed);
+ return NULL;
+ }
+
+ /* query the process list (if enough bytes are given) */
+ status = NtQuerySystemInformation(SystemProcessInformation,
+ process_list,
+ bytes_needed,
+ &bytes_needed);
+ if (STATUS_SUCCESS != status) {
+ (void)g_free(process_list);
+
+ if (STATUS_INFO_LENGTH_MISMATCH == status) {
+ bytes_needed <<= 1;
+ continue;
+ }
+
+ error_setg(errp, "Failed quering process list (status %08X)",
+ (int)status);
+ return NULL;
+ }
+
+ break;
+ }
+
+ /* iterate the process list and build the JSON reply */
+ for (process_list_iter = process_list;;) {
+ GuestProcessInfoList *list_item =
+ g_malloc0(sizeof(GuestProcessInfoList));
+ ANSI_STRING process_name;
+ HANDLE process_handle = NULL;
+ UNICODE_STRING *process_image_path = NULL;
+ PROCESS_BASIC_INFORMATION process_basic_info = {0};
+
+ if (NULL == process_list_head) {
+ process_list_head = list_item;
+ }
+ if (NULL != process_list_last) {
+ process_list_last->next = list_item;
+ }
+ process_list_last = list_item;
+
+ list_item->next = NULL;
+ list_item->value = g_malloc0(sizeof(GuestProcessInfo));
+ list_item->value->process_id = (int)process_list_iter->UniqueProcessId;
+ list_item->value->session_id = (int)process_list_iter->SessionId;
+
+ if (0 == list_item->value->process_id) {
+ list_item->value->process_name = g_strdup("System Idle Process");
+ process_list_iter = (void *)((uint32_t)process_list_iter +
+ process_list_iter->NextEntryOffset);
+ continue;
+ } else if (4 == list_item->value->process_id) {
+ list_item->value->process_name = g_strdup("System");
+ process_list_iter = (void *)((uint32_t)process_list_iter +
+ process_list_iter->NextEntryOffset);
+ continue;
+ }
+
+ process_name.MaximumLength =
+ process_list_iter->ImageName.MaximumLength;
+ process_name.Length = 0;
+ process_name.Buffer = g_malloc0(process_name.MaximumLength);
+
+ /* convert the image name to ansi string */
+ (void)RtlUnicodeStringToAnsiString(&process_name,
+ &process_list_iter->ImageName,
+ FALSE);
+ list_item->value->process_name = process_name.Buffer;
+
+ if (!process_list_iter->NextEntryOffset) {
+ break;
+ }
+
+ if (current_process_id != list_item->value->process_id) {
+ process_handle = OpenProcess(PROCESS_QUERY_INFORMATION,
+ FALSE,
+ list_item->value->process_id);
+ } else {
+ char curr_image_path[MAX_PATH];
+
+ process_handle = GetCurrentProcess();
+
+ if (GetModuleFileName(NULL,
+ curr_image_path,
+ MAX_PATH)) {
+ list_item->value->image_path = g_strdup(&curr_image_path[0]);
+ }
+ }
+
+ if (NULL != process_handle) {
+ /* get process parent ID */
+ status = NtQueryInformationProcess(
+ process_handle,
+ ProcessBasicInformation,
+ &process_basic_info,
+ sizeof(PROCESS_BASIC_INFORMATION),
+ NULL);
+ if (STATUS_SUCCESS == status) {
+ list_item->value->parent_id =
+ (int)process_basic_info.InheritedFromUniqueProcessId;
+ }
+
+ /* get process image path */
+ if (NULL == list_item->value->image_path) {
+ process_image_path = g_malloc0(sizeof(UNICODE_STRING) +
+ MAX_PATH * sizeof(wchar_t));
+
+ status = NtQueryInformationProcess(process_handle,
+ ProcessImageFileName,
+ process_image_path,
+ sizeof(UNICODE_STRING) +
+ MAX_PATH * sizeof(wchar_t),
+ NULL);
+ if (STATUS_SUCCESS == status) {
+ process_name.MaximumLength =
+ process_image_path->MaximumLength;
+ process_name.Length = 0;
+ process_name.Buffer =
+ g_malloc0(process_name.MaximumLength);
+
+ /* convert the image name to ANSI string */
+ (void)RtlUnicodeStringToAnsiString(&process_name,
+ process_image_path,
+ FALSE);
+ list_item->value->image_path = process_name.Buffer;
+ }
+
+ (void)g_free(process_image_path);
+ }
+
+ (void)CloseHandle(process_handle);
+ }
+
+ process_list_iter = (void *)((uint32_t)process_list_iter +
+ process_list_iter->NextEntryOffset);
+ }
+
+ (void)g_free(process_list);
+
+ return process_list_head;
+}
+
+GuestActiveConnectionList *qmp_guest_get_active_connections(Error **errp)
+{
+ MIB_UDPTABLE_OWNER_MODULE *udp_table = NULL;
+ MIB_TCPTABLE_OWNER_MODULE *tcp_table = NULL;
+ DWORD bytes_needed = sizeof(MIB_UDPTABLE_OWNER_MODULE) * 30;
+ GuestActiveConnectionList *connections = NULL;
+ int entry_index = 0;
+ DWORD ret;
+
+ /* get the UDP table */
+ for (;;) {
+ udp_table = g_malloc0(bytes_needed);
+ if (NULL == udp_table) {
+ error_setg(errp, "Failed allocating active UDP connections table");
+ return NULL;
+ }
+
+ ret = GetExtendedUdpTable(udp_table,
+ &bytes_needed,
+ TRUE,
+ AF_INET,
+ UDP_TABLE_OWNER_MODULE,
+ 0);
+ if (NO_ERROR != ret) {
+ (void)g_free(tcp_table);
+ udp_table = NULL;
+
+ if (ERROR_INSUFFICIENT_BUFFER == ret) {
+ bytes_needed <<= 1;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ /* add the UDP connections to the list backward */
+ for (entry_index = udp_table->dwNumEntries - 1;
+ entry_index >= 0;
+ --entry_index) {
+ MIB_UDPROW_OWNER_MODULE *udp_row = &udp_table->table[entry_index];
+
+ /* allocate new active connection item */
+ GuestActiveConnectionList *new_item =
+ g_malloc0(sizeof(GuestActiveConnectionList));
+ new_item->value = g_malloc0(sizeof(GuestActiveConnection));
+
+ /* push the connection to the head of the list */
+ new_item->next = connections;
+ connections = new_item;
+
+ new_item->value->source_addr =
+ g_strdup(inet_ntoa(*(struct in_addr *)&udp_row->dwLocalAddr));
+ new_item->value->source_port = htons(udp_row->dwLocalPort);
+ new_item->value->owner_process_id = udp_row->dwOwningPid;
+ new_item->value->if_family = GUEST_IP_ADDRESS_TYPE_IPV4;
+ new_item->value->protocol = GUEST_IP_PROTOCOL_UDP;
+ new_item->value->start_time = udp_row->liCreateTimestamp.QuadPart;
+ }
+
+ (void)g_free(udp_table);
+ udp_table = NULL;
+
+ bytes_needed = sizeof(MIB_TCPROW_OWNER_PID) * 30;
+
+ /* get the TCP table */
+ for (;;) {
+ tcp_table = g_malloc0(bytes_needed);
+ if (NULL == tcp_table) {
+ error_setg(errp, "Failed allocating active connections table");
+ return NULL;
+ }
+
+ ret = GetExtendedTcpTable(tcp_table,
+ &bytes_needed,
+ TRUE,
+ AF_INET,
+ TCP_TABLE_OWNER_MODULE_ALL,
+ 0);
+ if (NO_ERROR != ret) {
+ (void)g_free(tcp_table);
+ tcp_table = NULL;
+
+ if (ERROR_INSUFFICIENT_BUFFER == ret) {
+ bytes_needed <<= 1;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ /* add the TCP connections to the list backward */
+ for (entry_index = tcp_table->dwNumEntries - 1;
+ entry_index >= 0;
+ --entry_index) {
+ MIB_TCPROW_OWNER_MODULE *tcp_row = &tcp_table->table[entry_index];
+
+ /* allocate new active connection item */
+ GuestActiveConnectionList *new_item =
+ g_malloc0(sizeof(GuestActiveConnectionList));
+ new_item->value = g_malloc0(sizeof(GuestActiveConnection));
+
+ /* push the connection to the head of the list */
+ new_item->next = connections;
+ connections = new_item;
+
+ new_item->value->source_addr =
+ g_strdup(inet_ntoa(*(struct in_addr *)&tcp_row->dwLocalAddr));
+ new_item->value->source_port = htons(tcp_row->dwLocalPort);
+ new_item->value->dest_addr =
+ g_strdup(inet_ntoa(*(struct in_addr *)&tcp_row->dwRemoteAddr));
+ new_item->value->dest_port = htons(tcp_row->dwRemotePort);
+ new_item->value->owner_process_id = tcp_row->dwOwningPid;
+ new_item->value->if_family = GUEST_IP_ADDRESS_TYPE_IPV4;
+ new_item->value->protocol = GUEST_IP_PROTOCOL_TCP;
+ new_item->value->start_time = tcp_row->liCreateTimestamp.QuadPart;
+
+ switch (tcp_row->dwState) {
+ case MIB_TCP_STATE_CLOSED:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_CLOSED;
+ break;
+ case MIB_TCP_STATE_LISTEN:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_LISTEN;
+ break;
+ case MIB_TCP_STATE_SYN_SENT:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_SYN_SENT;
+ break;
+ case MIB_TCP_STATE_SYN_RCVD:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_SYN_RCVD;
+ break;
+ case MIB_TCP_STATE_ESTAB:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_ESTABLISHED;
+ break;
+ case MIB_TCP_STATE_FIN_WAIT1:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_FIN_WAIT1;
+ break;
+ case MIB_TCP_STATE_FIN_WAIT2:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_FIN_WAIT2;
+ break;
+ case MIB_TCP_STATE_CLOSE_WAIT:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_CLOSE_WAIT;
+ break;
+ case MIB_TCP_STATE_CLOSING:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_CLOSING;
+ break;
+ case MIB_TCP_STATE_LAST_ACK:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_LAST_ACK;
+ break;
+ case MIB_TCP_STATE_TIME_WAIT:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_TIME_WAIT;
+ break;
+ case MIB_TCP_STATE_DELETE_TCB:
+ new_item->value->state = GUEST_TCP_PROTOCOL_STATE_DELETE_TCB;
+ break;
+ }
+ }
+
+ (void)g_free(tcp_table);
+
+ return connections;
+}
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 61f8a5a..9df985d 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -971,3 +971,102 @@
{ 'command': 'guest-uptime',
'returns': 'uint32' }
+##
+# @GuestProcessInfo
+#
+# @process-id: the process unique id
+# @parent-id: the process parent unique id
+# @process-name: the name of the process
+# @image-path: full path of the process image
+# @session-id: the session id of the process
+#
+# Since: 2.4
+##
+{ 'type': 'GuestProcessInfo',
+ 'data': {'process-id': 'int', 'parent-id': 'int', 'process-name': 'str',
+ 'image-path': 'str', 'session-id': 'int'}}
+
+##
+# @guest-get-process-list:
+#
+# Get the list of active processes on the guest operating system
+#
+# Returns: array of active processes
+#
+# Since 2.4
+##
+{ 'command': 'guest-get-process-list',
+ 'returns': ['GuestProcessInfo'] }
+
+##
+# @GuestIpProtocol:
+#
+# An enumeration of supported IP protocols
+#
+# @tcp: TCP
+#
+# @udp: UDP
+#
+# Since: 2.4
+##
+{ 'enum': 'GuestIpProtocol',
+ 'data': [ 'tcp', 'udp' ] }
+
+##
+# @GuestTcpProtocolState:
+#
+# An enumeration of TCP connection state
+#
+# @closed: CLOSED
+# @listen: LISTEN
+# @syn-sent: SYN_SENT
+# @syn-rcvd: SYN_RCVD
+# @established: ESTABLISHED
+# @fin-wait1: FIN_WAIT1
+# @fin-wait2: FIN_WAIT2
+# @close-wait: CLOSE_WAIT
+# @closing: CLOSING
+# @last-ack: LAST_ACK
+# @time-wait: TIME_WAIT
+# @delete-tcb: DELETE_TCB
+#
+# Since: 2.4
+##
+{ 'enum': 'GuestTcpProtocolState',
+ 'data': [ 'closed', 'listen', 'syn-sent', 'syn-rcvd', 'established',
+ 'fin-wait1', 'fin-wait2', 'close-wait', 'closing',
+ 'last-ack', 'time-wait', 'delete-tcb' ] }
+
+##
+# @GuestActiveConnection
+#
+# @if-family: ipv4 / ipv6
+# @protocol: TCP / UDP
+# @source-addr: the source IP address of the connection
+# @source-port: the source port of the connection
+# @dest-addr: the destination IP address of the connection
+# @dest-port: the destination port of the connection
+# @owner-process_id: the process unique id for the connection owner
+# @state: connection protocol state
+# @start-time: time where bind() was called for the connection
+#
+# Since: 2.4
+##
+{ 'type': 'GuestActiveConnection',
+ 'data': { 'source-addr': 'str', 'source-port': 'int', 'dest-addr': 'str',
+ 'dest-port': 'int', 'owner-process-id': 'int', 'state':
'GuestTcpProtocolState',
+ 'if-family': 'GuestIpAddressType', 'protocol': 'GuestIpProtocol',
+ 'start-time': 'uint64'}}
+
+##
+# @guest-get-active-connections:
+#
+# Get the list of active connections on the guest operating system
+#
+# Returns: array of active connections
+#
+# Since 2.4
+##
+{ 'command': 'guest-get-active-connections',
+ 'returns': ['GuestActiveConnection'] }
+
diff --git a/qga/win32-definitions.h b/qga/win32-definitions.h
new file mode 100644
index 0000000..c4f0a2b
--- /dev/null
+++ b/qga/win32-definitions.h
@@ -0,0 +1,110 @@
+
+#ifndef WIN32_DEFINITIONS_H_
+#define WIN32_DEFINITIONS_H_ 1
+
+#include "win32-iptypes.h"
+
+#define STATUS_INFO_LENGTH_MISMATCH (0xC0000004)
+
+typedef
+enum _PROCESSINFOCLASS {
+ ProcessBasicInformation = 0x0000,
+ ProcessDebugPort = 0x0007,
+ ProcessWow64Information = 0x001a,
+ ProcessImageFileName = 0x001b,
+ ProcessBreakOnTermination = 0x001d,
+} PROCESSINFOCLASS;
+
+typedef struct {
+ ULONG AllocationSize;
+ ULONG ActualSize;
+ ULONG Flags;
+ ULONG Unknown1;
+ UNICODE_STRING Unknown2;
+ HANDLE InputHandle;
+ HANDLE OutputHandle;
+ HANDLE ErrorHandle;
+ UNICODE_STRING CurrentDirectory;
+ HANDLE CurrentDirectoryHandle;
+ UNICODE_STRING SearchPaths;
+ UNICODE_STRING ApplicationName;
+ UNICODE_STRING CommandLine;
+ PVOID EnvironmentBlock;
+ ULONG Unknown[9];
+ UNICODE_STRING Unknown3;
+ UNICODE_STRING Unknown4;
+ UNICODE_STRING Unknown5;
+ UNICODE_STRING Unknown6;
+} PROCESS_PARAMETERS, *PPROCESS_PARAMETERS;
+
+typedef struct {
+ ULONG AllocationSize;
+ ULONG Unknown1;
+ HINSTANCE ProcessHinstance;
+ PVOID ListDlls;
+ PPROCESS_PARAMETERS ProcessParameters;
+ ULONG Unknown2;
+ HANDLE Heap;
+} PEB, *PPEB;
+
+typedef struct {
+ DWORD ExitStatus;
+ PPEB PebBaseAddress;
+ DWORD AffinityMask;
+ DWORD BasePriority;
+ ULONG UniqueProcessId;
+ ULONG InheritedFromUniqueProcessId;
+} PROCESS_BASIC_INFORMATION;
+
+typedef
+enum _SYSTEM_INFORMATION_CLASS {
+ SystemBasicInformation = 0x0000,
+ SystemProcessorInformation = 0x0001,
+ SystemPerformanceInformation = 0x0002,
+ SystemTimeOfDayInformation = 0x0003,
+ SystemPathInformation = 0x0004,
+ SystemProcessInformation = 0x0005,
+ SystemDeviceInformation = 0x0007,
+ SystemModuleInformation = 0x000B,
+} SYSTEM_INFORMATION_CLASS;
+
+typedef
+struct _SYSTEM_PROCESS_INFORMATION /* Size=184 */ {
+ ULONG NextEntryOffset; /* Size=4 Offset=0 */
+ ULONG NumberOfThreads; /* Size=4 Offset=4 */
+ LARGE_INTEGER WorkingSetPrivateSize; /* Size=8 Offset=8 */
+ ULONG HardFaultCount; /* Size=4 Offset=16 */
+ ULONG NumberOfThreadsHighWatermark; /* Size=4 Offset=20 */
+ ULONGLONG CycleTime; /* Size=8 Offset=24 */
+ LARGE_INTEGER CreateTime; /* Size=8 Offset=32 */
+ LARGE_INTEGER UserTime; /* Size=8 Offset=40 */
+ LARGE_INTEGER KernelTime; /* Size=8 Offset=48 */
+ UNICODE_STRING ImageName; /* Size=8 Offset=56 */
+ LONG BasePriority; /* Size=4 Offset=64 */
+ PVOID UniqueProcessId; /* Size=4 Offset=68 */
+ PVOID InheritedFromUniqueProcessId; /* Size=4 Offset=72 */
+ ULONG HandleCount; /* Size=4 Offset=76 */
+ ULONG SessionId; /* Size=4 Offset=80 */
+ ULONG UniqueProcessKey; /* Size=4 Offset=84 */
+ ULONG PeakVirtualSize; /* Size=4 Offset=88 */
+ ULONG VirtualSize; /* Size=4 Offset=92 */
+ ULONG PageFaultCount; /* Size=4 Offset=96 */
+ ULONG PeakWorkingSetSize; /* Size=4 Offset=100 */
+ ULONG WorkingSetSize; /* Size=4 Offset=104 */
+ ULONG QuotaPeakPagedPoolUsage; /* Size=4 Offset=108 */
+ ULONG QuotaPagedPoolUsage; /* Size=4 Offset=112 */
+ ULONG QuotaPeakNonPagedPoolUsage; /* Size=4 Offset=116 */
+ ULONG QuotaNonPagedPoolUsage; /* Size=4 Offset=120 */
+ ULONG PagefileUsage; /* Size=4 Offset=124 */
+ ULONG PeakPagefileUsage; /* Size=4 Offset=128 */
+ ULONG PrivatePageCount; /* Size=4 Offset=132 */
+ LARGE_INTEGER ReadOperationCount; /* Size=8 Offset=136 */
+ LARGE_INTEGER WriteOperationCount; /* Size=8 Offset=144 */
+ LARGE_INTEGER OtherOperationCount; /* Size=8 Offset=152 */
+ LARGE_INTEGER ReadTransferCount; /* Size=8 Offset=160 */
+ LARGE_INTEGER WriteTransferCount; /* Size=8 Offset=168 */
+ LARGE_INTEGER OtherTransferCount; /* Size=8 Offset=176 */
+} SYSTEM_PROCESS_INFORMATION;
+
+#endif /* WIN32_DEFINITIONS_H_ */
+
diff --git a/qga/win32-iptypes.h b/qga/win32-iptypes.h
new file mode 100644
index 0000000..ec55300
--- /dev/null
+++ b/qga/win32-iptypes.h
@@ -0,0 +1,412 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ iptypes.h
+
+--*/
+
+#ifndef IP_TYPES_INCLUDED
+#define IP_TYPES_INCLUDED
+
+#include <time.h>
+
+#define INET_ADDRSTRLEN (16)
+#define INET6_ADDRSTRLEN (48)
+
+/* Definitions and structures used by getnetworkparams and
+ getadaptersinfo apis */
+#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
+#define MAX_ADAPTER_NAME_LENGTH 256
+#define MAX_ADAPTER_ADDRESS_LENGTH 8
+#define DEFAULT_MINIMUM_ENTITIES 32
+#define MAX_HOSTNAME_LEN 128
+#define MAX_DOMAIN_NAME_LEN 128
+#define MAX_SCOPE_ID_LEN 256
+
+/*
+ types
+*/
+
+/* Node Type */
+
+#define BROADCAST_NODETYPE 1
+#define PEER_TO_PEER_NODETYPE 2
+#define MIXED_NODETYPE 4
+#define HYBRID_NODETYPE 8
+
+/*
+IP_ADDRESS_STRING - store an IP address as a dotted decimal string
+*/
+
+typedef struct {
+ char String[4 * 4];
+} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
+
+/*
+IP_ADDR_STRING - store an IP address with its corresponding subnet mask,
+both as dotted decimal strings
+*/
+
+typedef struct _IP_ADDR_STRING {
+ struct _IP_ADDR_STRING *Next;
+ IP_ADDRESS_STRING IpAddress;
+ IP_MASK_STRING IpMask;
+ DWORD Context;
+} IP_ADDR_STRING, *PIP_ADDR_STRING;
+
+/*
+ADAPTER_INFO - per-adapter information. All IP addresses are stored as
+strings
+*/
+
+typedef struct _IP_ADAPTER_INFO {
+ struct _IP_ADAPTER_INFO *Next;
+ DWORD ComboIndex;
+ char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
+ char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
+ UINT AddressLength;
+ BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
+ DWORD Index;
+ UINT Type;
+ UINT DhcpEnabled;
+ PIP_ADDR_STRING CurrentIpAddress;
+ IP_ADDR_STRING IpAddressList;
+ IP_ADDR_STRING GatewayList;
+ IP_ADDR_STRING DhcpServer;
+ BOOL HaveWins;
+ IP_ADDR_STRING PrimaryWinsServer;
+ IP_ADDR_STRING SecondaryWinsServer;
+ time_t LeaseObtained;
+ time_t LeaseExpires;
+} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
+
+/*
+The following types require Winsock2.
+*/
+
+typedef enum {
+ IpPrefixOriginOther = 0,
+ IpPrefixOriginManual,
+ IpPrefixOriginWellKnown,
+ IpPrefixOriginDhcp,
+ IpPrefixOriginRouterAdvertisement,
+} IP_PREFIX_ORIGIN;
+
+typedef enum {
+ IpSuffixOriginOther = 0,
+ IpSuffixOriginManual,
+ IpSuffixOriginWellKnown,
+ IpSuffixOriginDhcp,
+ IpSuffixOriginLinkLayerAddress,
+ IpSuffixOriginRandom,
+} IP_SUFFIX_ORIGIN;
+
+typedef enum {
+ IpDadStateInvalid = 0,
+ IpDadStateTentative,
+ IpDadStateDuplicate,
+ IpDadStateDeprecated,
+ IpDadStatePreferred,
+} IP_DAD_STATE;
+
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS *Next;
+ SOCKET_ADDRESS Address;
+
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+} IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS;
+
+typedef struct _IP_ADAPTER_ANYCAST_ADDRESS {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_ANYCAST_ADDRESS *Next;
+ SOCKET_ADDRESS Address;
+} IP_ADAPTER_ANYCAST_ADDRESS, *PIP_ADAPTER_ANYCAST_ADDRESS;
+
+typedef struct _IP_ADAPTER_MULTICAST_ADDRESS {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_MULTICAST_ADDRESS *Next;
+ SOCKET_ADDRESS Address;
+} IP_ADAPTER_MULTICAST_ADDRESS, *PIP_ADAPTER_MULTICAST_ADDRESS;
+
+/*
+Per-address Flags
+*/
+#define IP_ADAPTER_ADDRESS_DNS_ELIGIBLE 0x01
+#define IP_ADAPTER_ADDRESS_TRANSIENT 0x02
+
+typedef struct _IP_ADAPTER_DNS_SERVER_ADDRESS {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Reserved;
+ };
+ };
+ struct _IP_ADAPTER_DNS_SERVER_ADDRESS *Next;
+ SOCKET_ADDRESS Address;
+} IP_ADAPTER_DNS_SERVER_ADDRESS, *PIP_ADAPTER_DNS_SERVER_ADDRESS;
+
+typedef struct _IP_ADAPTER_PREFIX {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_PREFIX *Next;
+ SOCKET_ADDRESS Address;
+ ULONG PrefixLength;
+} IP_ADAPTER_PREFIX, *PIP_ADAPTER_PREFIX;
+
+/*
+Per-adapter Flags
+*/
+#define IP_ADAPTER_DDNS_ENABLED 0x01
+#define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02
+#define IP_ADAPTER_DHCP_ENABLED 0x04
+#define IP_ADAPTER_RECEIVE_ONLY 0x08
+#define IP_ADAPTER_NO_MULTICAST 0x10
+#define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
+
+/*
+OperStatus values from RFC 2863
+*/
+typedef enum {
+ IfOperStatusUp = 1,
+ IfOperStatusDown,
+ IfOperStatusTesting,
+ IfOperStatusUnknown,
+ IfOperStatusDormant,
+ IfOperStatusNotPresent,
+ IfOperStatusLowerLayerDown
+} IF_OPER_STATUS;
+
+/*
+Scope levels from RFC 2373 used with ZoneIndices array.
+*/
+typedef enum {
+ ScopeLevelInterface = 1,
+ ScopeLevelLink = 2,
+ ScopeLevelSubnet = 3,
+ ScopeLevelAdmin = 4,
+ ScopeLevelSite = 5,
+ ScopeLevelOrganization = 8,
+ ScopeLevelGlobal = 14
+} SCOPE_LEVEL;
+
+typedef struct _IP_ADAPTER_ADDRESSES {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD IfIndex;
+ };
+ };
+ struct _IP_ADAPTER_ADDRESSES *Next;
+ PCHAR AdapterName;
+ PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress;
+ PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress;
+ PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress;
+ PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress;
+ PWCHAR DnsSuffix;
+ PWCHAR Description;
+ PWCHAR FriendlyName;
+ BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
+ DWORD PhysicalAddressLength;
+ DWORD Flags;
+ DWORD Mtu;
+ DWORD IfType;
+ IF_OPER_STATUS OperStatus;
+ DWORD Ipv6IfIndex;
+ DWORD ZoneIndices[16];
+ PIP_ADAPTER_PREFIX FirstPrefix;
+} IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES;
+
+/*
+Flags used as argument to GetAdaptersAddresses().
+"SKIP" flags are added when the default is to include the information.
+"INCLUDE" flags are added when the default is to skip the information.
+*/
+#define GAA_FLAG_SKIP_UNICAST 0x0001
+#define GAA_FLAG_SKIP_ANYCAST 0x0002
+#define GAA_FLAG_SKIP_MULTICAST 0x0004
+#define GAA_FLAG_SKIP_DNS_SERVER 0x0008
+#define GAA_FLAG_INCLUDE_PREFIX 0x0010
+#define GAA_FLAG_SKIP_FRIENDLY_NAME 0x0020
+
+/*
+IP_PER_ADAPTER_INFO - per-adapter IP information such as DNS server list.
+*/
+
+typedef struct _IP_PER_ADAPTER_INFO {
+ UINT AutoconfigEnabled;
+ UINT AutoconfigActive;
+ PIP_ADDR_STRING CurrentDnsServer;
+ IP_ADDR_STRING DnsServerList;
+} IP_PER_ADAPTER_INFO, *PIP_PER_ADAPTER_INFO;
+
+/*
+FIXED_INFO - the set of IP-related information which does not depend on DHCP
+*/
+
+typedef struct {
+ char HostName[MAX_HOSTNAME_LEN + 4] ;
+ char DomainName[MAX_DOMAIN_NAME_LEN + 4];
+ PIP_ADDR_STRING CurrentDnsServer;
+ IP_ADDR_STRING DnsServerList;
+ UINT NodeType;
+ char ScopeId[MAX_SCOPE_ID_LEN + 4];
+ UINT EnableRouting;
+ UINT EnableProxy;
+ UINT EnableDns;
+} FIXED_INFO, *PFIXED_INFO;
+
+typedef struct ip_interface_name_info {
+ ULONG Index; /* Interface Index */
+ ULONG MediaType; /* Interface Types - see ipifcons.h */
+ UCHAR ConnectionType;
+ UCHAR AccessType;
+ GUID DeviceGuid; /* Device GUID is the guid of the device */
+ /* that IP exposes */
+ GUID InterfaceGuid; /* Interface GUID, if not GUID_NULL is the
+ GUID for the interface mapped to the device */
+} IP_INTERFACE_NAME_INFO, *PIP_INTERFACE_NAME_INFO;
+
+typedef enum {
+ TCP_TABLE_BASIC_LISTENER,
+ TCP_TABLE_BASIC_CONNECTIONS,
+ TCP_TABLE_BASIC_ALL,
+ TCP_TABLE_OWNER_PID_LISTENER,
+ TCP_TABLE_OWNER_PID_CONNECTIONS,
+ TCP_TABLE_OWNER_PID_ALL,
+ TCP_TABLE_OWNER_MODULE_LISTENER,
+ TCP_TABLE_OWNER_MODULE_CONNECTIONS,
+ TCP_TABLE_OWNER_MODULE_ALL
+} TCP_TABLE_CLASS, *PTCP_TABLE_CLASS;
+
+typedef enum {
+ UDP_TABLE_BASIC,
+ UDP_TABLE_OWNER_PID,
+ UDP_TABLE_OWNER_MODULE
+} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS;
+
+#define TCPIP_OWNING_MODULE_SIZE (16)
+#define ANY_SIZE (1)
+
+typedef enum {
+ MIB_TCP_STATE_UNKNOWN = 0,
+ MIB_TCP_STATE_CLOSED = 1,
+ MIB_TCP_STATE_LISTEN = 2,
+ MIB_TCP_STATE_SYN_SENT = 3,
+ MIB_TCP_STATE_SYN_RCVD = 4,
+ MIB_TCP_STATE_ESTAB = 5,
+ MIB_TCP_STATE_FIN_WAIT1 = 6,
+ MIB_TCP_STATE_FIN_WAIT2 = 7,
+ MIB_TCP_STATE_CLOSE_WAIT = 8,
+ MIB_TCP_STATE_CLOSING = 9,
+ MIB_TCP_STATE_LAST_ACK = 10,
+ MIB_TCP_STATE_TIME_WAIT = 11,
+ MIB_TCP_STATE_DELETE_TCB = 12
+} MIB_TCP_STATE;
+
+typedef struct _MIB_UDPROW {
+ DWORD dwLocalAddr;
+ DWORD dwLocalPort;
+} MIB_UDPROW, *PMIB_UDPROW;
+
+typedef struct _MIB_UDPTABLE {
+ DWORD dwNumEntries;
+ MIB_UDPROW table[ANY_SIZE];
+} MIB_UDPTABLE, *PMIB_UDPTABLE;
+
+typedef struct _MIB_UDPROW_OWNER_PID {
+ DWORD dwLocalAddr;
+ DWORD dwLocalPort;
+ DWORD dwOwningPid;
+} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID;
+
+typedef struct _MIB_UDPTABLE_OWNER_PID {
+ DWORD dwNumEntries;
+ MIB_UDPROW_OWNER_PID table[ANY_SIZE];
+} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID;
+
+typedef struct _MIB_UDPROW_OWNER_MODULE {
+ DWORD dwLocalAddr;
+ DWORD dwLocalPort;
+ DWORD dwOwningPid;
+ LARGE_INTEGER liCreateTimestamp;
+ union {
+ struct {
+ int SpecificPortBind:1;
+ };
+ int dwFlags;
+ };
+ ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE];
+} MIB_UDPROW_OWNER_MODULE, *PMIB_UDPROW_OWNER_MODULE;
+
+typedef struct _MIB_UDPTABLE_OWNER_MODULE {
+ DWORD dwNumEntries;
+ MIB_UDPROW_OWNER_MODULE table[ANY_SIZE];
+} MIB_UDPTABLE_OWNER_MODULE, *PMIB_UDPTABLE_OWNER_MODULE;
+
+typedef struct _MIB_TCPROW_OWNER_MODULE {
+ DWORD dwState;
+ DWORD dwLocalAddr;
+ DWORD dwLocalPort;
+ DWORD dwRemoteAddr;
+ DWORD dwRemotePort;
+ DWORD dwOwningPid;
+ LARGE_INTEGER liCreateTimestamp;
+ ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE];
+} MIB_TCPROW_OWNER_MODULE, *PMIB_TCPROW_OWNER_MODULE;
+
+typedef struct {
+ DWORD dwNumEntries;
+ MIB_TCPROW_OWNER_MODULE table[ANY_SIZE];
+} MIB_TCPTABLE_OWNER_MODULE, *PMIB_TCPTABLE_OWNER_MODULE;
+
+typedef struct _MIB_TCPROW_OWNER_PID {
+ DWORD dwState;
+ DWORD dwLocalAddr;
+ DWORD dwLocalPort;
+ DWORD dwRemoteAddr;
+ DWORD dwRemotePort;
+ DWORD dwOwningPid;
+} MIB_TCPROW_OWNER_PID, *PMIB_TCPROW_OWNER_PID;
+
+typedef struct {
+ DWORD dwNumEntries;
+ MIB_TCPROW_OWNER_PID table[ANY_SIZE];
+} MIB_TCPTABLE_OWNER_PID, *PMIB_TCPTABLE_OWNER_PID;
+
+#endif /* IP_TYPES_INCLUDED */
+
--
2.3.4