qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4] qga added functionality
@ 2015-03-31  8:34 itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 1/4] added qga hash file command (win/linux) itamar.tal4
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: itamar.tal4 @ 2015-03-31  8:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: ori, ariel, mdroth, pavel, Itamar Tal

From: Itamar Tal <itamar@guardicore.com>

This bundle of patches adds support for some more functionality in the
qemu-guest-agent, both for Windows and Linux. Main added features are:
- Process list enumeration
- Network connections enumeration
- File removal and attributes
- File hashing
- System information such as uptime and hostname
 
Itamar,
Guardicore
itamar@guardicore.com

Itamar Tal (4):
  added qga hash file command (win/linux)
  addedd missing file commands (attributes, deletion)
  added qga system uptime and hostname commands
  added qga processes and connections enumeration commands (win/linux)

 qga/Makefile.objs       |   2 +-
 qga/commands-posix.c    | 644 ++++++++++++++++++++++++++++++++++++++++++++++++
 qga/commands-win32.c    | 561 +++++++++++++++++++++++++++++++++++++++++
 qga/commands.c          |  69 ++++++
 qga/guest-agent-core.h  |   8 +
 qga/main.c              |   5 +
 qga/qapi-schema.json    | 179 ++++++++++++++
 qga/sha256.c            | 171 +++++++++++++
 qga/sha256.h            |  40 +++
 qga/win32-definitions.h | 110 +++++++++
 qga/win32-iptypes.h     | 412 +++++++++++++++++++++++++++++++
 11 files changed, 2200 insertions(+), 1 deletion(-)
 create mode 100644 qga/sha256.c
 create mode 100644 qga/sha256.h
 create mode 100644 qga/win32-definitions.h
 create mode 100644 qga/win32-iptypes.h

-- 
2.3.4

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 1/4] added qga hash file command (win/linux)
  2015-03-31  8:34 [Qemu-devel] [PATCH 0/4] qga added functionality itamar.tal4
@ 2015-03-31  8:34 ` itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 2/4] added missing file commands (attributes, deletion) itamar.tal4
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: itamar.tal4 @ 2015-03-31  8:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: ori, ariel, mdroth, pavel, Itamar Tal

From: Itamar Tal <itamar@guardicore.com>

Added support for retrieving file hash from the guest machine.
This is command is useful for ensuring that no changes were made for a given
file between consecutive read operations and reduce read/write operations.

---
 qga/Makefile.objs      |   2 +-
 qga/commands.c         |  43 +++++++++++++
 qga/guest-agent-core.h |   6 ++
 qga/qapi-schema.json   |  13 ++++
 qga/sha256.c           | 171 +++++++++++++++++++++++++++++++++++++++++++++++++
 qga/sha256.h           |  40 ++++++++++++
 6 files changed, 274 insertions(+), 1 deletion(-)
 create mode 100644 qga/sha256.c
 create mode 100644 qga/sha256.h

diff --git a/qga/Makefile.objs b/qga/Makefile.objs
index 1c5986c..a68d78d 100644
--- a/qga/Makefile.objs
+++ b/qga/Makefile.objs
@@ -1,4 +1,4 @@
-qga-obj-y = commands.o guest-agent-command-state.o main.o
+qga-obj-y = commands.o guest-agent-command-state.o main.o sha256.o
 qga-obj-$(CONFIG_POSIX) += commands-posix.o channel-posix.o
 qga-obj-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o
 qga-obj-$(CONFIG_WIN32) += vss-win32.o
diff --git a/qga/commands.c b/qga/commands.c
index 7834967..f9378f4 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -11,6 +11,7 @@
  */
 
 #include <glib.h>
+#include "qga/sha256.h"
 #include "qga/guest-agent-core.h"
 #include "qga-qmp-commands.h"
 #include "qapi/qmp/qerror.h"
@@ -70,3 +71,45 @@ struct GuestAgentInfo *qmp_guest_info(Error **errp)
     qmp_for_each_command(qmp_command_info, info);
     return info;
 }
+
+char *qmp_guest_file_hash(const char *path, Error **errp)
+{
+    const char *hex = "0123456789abcdef";
+    BYTE sha256_block[SHA256_BLOCK_SIZE];
+    char sha256_hexdigest[SHA256_BLOCK_SIZE * 2 + 1];
+    BYTE buffer[1024];
+    size_t len = 0;
+    SHA256_CTX ctx;
+    FILE *file = NULL;
+    int i = 0;
+
+    sha256_init(&ctx);
+
+    file = fopen(path, "rb");
+    if (NULL == file) {
+        error_setg(errp, "Error opening file '%s'", path);
+        return NULL;
+    }
+
+    for (;;) {
+        len = fread(buffer, 1, 1024, file);
+        if (0 == len) {
+            break;
+        }
+
+        sha256_update(&ctx, buffer, len);
+    }
+
+    fclose(file);
+
+    sha256_final(&ctx, sha256_block);
+
+    /* transform the digest to hex string */
+    for (i = 0; i < SHA256_BLOCK_SIZE; ++i) {
+        sha256_hexdigest[i * 2] = hex[(sha256_block[i] >> 4) & 0xF];
+        sha256_hexdigest[i * 2 + 1] = hex[sha256_block[i] & 0xF];
+    }
+    sha256_hexdigest[SHA256_BLOCK_SIZE * 2] = '\0';
+
+    return g_strdup((char *)sha256_hexdigest);
+}
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
index e92c6ab..b496c47 100644
--- a/qga/guest-agent-core.h
+++ b/qga/guest-agent-core.h
@@ -10,6 +10,10 @@
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
+
+#ifndef _GUEST_AGENT_CORE_H_
+#define _GUEST_AGENT_CORE_H_
+
 #include "qapi/qmp/dispatch.h"
 #include "qemu-common.h"
 
@@ -41,3 +45,5 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp);
 #ifndef _WIN32
 void reopen_fd_to_null(int fd);
 #endif
+
+#endif /* _GUEST_AGENT_CORE_H_ */
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 95f49e3..68b420d 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -891,3 +891,16 @@
 ##
 { 'command': 'guest-get-memory-block-info',
   'returns': 'GuestMemoryBlockInfo' }
+
+##
+# @guest-file-hash:
+#
+# Get the a SHA256 hash for a file in the guest's operating system
+#
+# Returns: file SHA256 hash string
+#
+# Since 2.4
+##
+{ 'command': 'guest-file-hash',
+  'data': { 'path': 'str' },
+  'returns': 'str' }
diff --git a/qga/sha256.c b/qga/sha256.c
new file mode 100644
index 0000000..40abb42
--- /dev/null
+++ b/qga/sha256.c
@@ -0,0 +1,171 @@
+/*********************************************************************
+* Filename:   sha256.c
+* Author:     Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details:    Implementation of the SHA-256 hashing algorithm.
+              SHA-256 is one of the three algorithms in the SHA2
+              specification. The others, SHA-384 and SHA-512, are not
+              offered in this implementation.
+              Algorithm specification can be found here:
+               * http://csrc.nist.gov/publications/fips/fips180-2/
+                 fips180-2withchangenotice.pdf
+              This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+
+#include <memory.h>
+#include "sha256.h"
+
+/****************************** MACROS ******************************/
+#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32-(b))))
+
+#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22))
+#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25))
+#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10))
+
+/**************************** VARIABLES *****************************/
+static const uint32_t k[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+    0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+    0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+    0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+    0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+    0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+
+void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
+{
+    uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+
+    for (i = 0, j = 0; i < 16; ++i, j += 4) {
+        m[i] = (data[j] << 24) |
+               (data[j + 1] << 16) |
+               (data[j + 2] << 8) |
+               (data[j + 3]);
+    }
+    for ( ; i < 64; ++i) {
+        m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+    }
+
+    a = ctx->state[0];
+    b = ctx->state[1];
+    c = ctx->state[2];
+    d = ctx->state[3];
+    e = ctx->state[4];
+    f = ctx->state[5];
+    g = ctx->state[6];
+    h = ctx->state[7];
+
+    for (i = 0; i < 64; ++i) {
+        t1 = h + EP1(e) + CH(e, f, g) + k[i] + m[i];
+        t2 = EP0(a) + MAJ(a, b, c);
+        h = g;
+        g = f;
+        f = e;
+        e = d + t1;
+        d = c;
+        c = b;
+        b = a;
+        a = t1 + t2;
+    }
+
+    ctx->state[0] += a;
+    ctx->state[1] += b;
+    ctx->state[2] += c;
+    ctx->state[3] += d;
+    ctx->state[4] += e;
+    ctx->state[5] += f;
+    ctx->state[6] += g;
+    ctx->state[7] += h;
+}
+
+void sha256_init(SHA256_CTX *ctx)
+{
+    ctx->datalen = 0;
+    ctx->bitlen = 0;
+    ctx->state[0] = 0x6a09e667;
+    ctx->state[1] = 0xbb67ae85;
+    ctx->state[2] = 0x3c6ef372;
+    ctx->state[3] = 0xa54ff53a;
+    ctx->state[4] = 0x510e527f;
+    ctx->state[5] = 0x9b05688c;
+    ctx->state[6] = 0x1f83d9ab;
+    ctx->state[7] = 0x5be0cd19;
+}
+
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
+{
+    uint32_t i;
+
+    for (i = 0; i < len; ++i) {
+        ctx->data[ctx->datalen] = data[i];
+        ctx->datalen++;
+        if (ctx->datalen == 64) {
+            sha256_transform(ctx, ctx->data);
+            ctx->bitlen += 512;
+            ctx->datalen = 0;
+        }
+    }
+}
+
+void sha256_final(SHA256_CTX *ctx, BYTE hash[])
+{
+    uint32_t i;
+
+    i = ctx->datalen;
+
+    /* Pad whatever data is left in the buffer */
+    if (ctx->datalen < 56) {
+        ctx->data[i++] = 0x80;
+        while (i < 56) {
+            ctx->data[i++] = 0x00;
+        }
+    } else {
+        ctx->data[i++] = 0x80;
+        while (i < 64) {
+            ctx->data[i++] = 0x00;
+        }
+        sha256_transform(ctx, ctx->data);
+        memset(ctx->data, 0, 56);
+    }
+
+    /* Append to the padding the total message's length in bits and
+    transform */
+    ctx->bitlen += ctx->datalen * 8;
+    ctx->data[63] = ctx->bitlen;
+    ctx->data[62] = ctx->bitlen >> 8;
+    ctx->data[61] = ctx->bitlen >> 16;
+    ctx->data[60] = ctx->bitlen >> 24;
+    ctx->data[59] = ctx->bitlen >> 32;
+    ctx->data[58] = ctx->bitlen >> 40;
+    ctx->data[57] = ctx->bitlen >> 48;
+    ctx->data[56] = ctx->bitlen >> 56;
+    sha256_transform(ctx, ctx->data);
+
+    /* Since this implementation uses little endian byte ordering and SHA uses
+    big endian, reverse all the bytes when copying the final state to the
+    output hash. */
+    for (i = 0; i < 4; ++i) {
+        hash[i]      = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 4]  = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 8]  = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
+    }
+}
diff --git a/qga/sha256.h b/qga/sha256.h
new file mode 100644
index 0000000..e62f99b
--- /dev/null
+++ b/qga/sha256.h
@@ -0,0 +1,40 @@
+/*********************************************************************
+* Filename:   sha256.h
+* Author:     Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details:    Defines the API for the corresponding SHA1 implementation.
+*********************************************************************/
+
+#ifndef _SHA256_H_INCLUDE
+#define _SHA256_H_INCLUDE
+
+/*************************** HEADER FILES ***************************/
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "qga/guest-agent-core.h"
+
+/****************************** MACROS ******************************/
+#define SHA256_BLOCK_SIZE 32            /* SHA256 outputs a 32 byte digest */
+
+/**************************** DATA TYPES ****************************/
+
+typedef unsigned char BYTE;             /* 8-bit byte */
+
+typedef struct {
+    BYTE data[64];
+    unsigned int datalen;
+    unsigned long long bitlen;
+    unsigned int state[8];
+} SHA256_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+
+void sha256_init(SHA256_CTX *ctx);
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
+void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
+void sha256_transform(SHA256_CTX *ctx, const BYTE data[]);
+
+#endif /* _SHA256_H_INCLUDE */
-- 
2.3.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 2/4] added missing file commands (attributes, deletion)
  2015-03-31  8:34 [Qemu-devel] [PATCH 0/4] qga added functionality itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 1/4] added qga hash file command (win/linux) itamar.tal4
@ 2015-03-31  8:34 ` itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 3/4] added qga system uptime and hostname commands itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 4/4] added qga processes and connections enumeration commands (win/linux) itamar.tal4
  3 siblings, 0 replies; 5+ messages in thread
From: itamar.tal4 @ 2015-03-31  8:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: ori, ariel, mdroth, pavel, Itamar Tal

From: Itamar Tal <itamar@guardicore.com>

This patch add support for retrieving file attributes and file deletion by
file name, to get a more complete file functionality over the guest agent.

---
 qga/commands-posix.c |  23 +++++++++
 qga/commands-win32.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
 qga/commands.c       |   8 +++
 qga/qapi-schema.json |  42 ++++++++++++++++
 4 files changed, 212 insertions(+)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index ba8de62..028d533 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -7,6 +7,9 @@
  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
  *  Michal Privoznik  <mprivozn@redhat.com>
  *
+ * Changes (itamar@guardicore.com):
+ * - file attributes, removal, hashes
+ *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
@@ -2456,3 +2459,23 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
 #endif
     ga_command_state_add(cs, guest_file_init, NULL);
 }
+
+GuestFileAttributes *qmp_guest_file_attributes(const char *path, Error **errp)
+{
+    GuestFileAttributes *file_stat = g_malloc0(sizeof(GuestFileAttributes));
+    struct stat file_os_stat;
+
+    if (stat(path, &file_os_stat)) {
+        error_setg(errp, "Failed to get file attributes for '%s' (error %d)",
+                   path, errno);
+        return NULL;
+    }
+
+    file_stat->mode = file_os_stat.st_mode;
+    file_stat->size = file_os_stat.st_size;
+    file_stat->access_time = file_os_stat.st_atime;
+    file_stat->modification_time = file_os_stat.st_mtime;
+    file_stat->creation_time = 0; /* not all Linux FS store file BoD */
+
+    return file_stat;
+}
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 3ef0549..aeb49c5 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -7,6 +7,9 @@
  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
  *  Gal Hammer        <ghammer@redhat.com>
  *
+ * Changes (itamar@guardicore.com):
+ * - file attributes, removal, hashes
+ *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
@@ -742,3 +745,139 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
     }
     ga_command_state_add(cs, guest_file_init, NULL);
 }
+
+/* The CRT of Windows has a number of flaws wrt. its stat() implementation:
+   - time stamps are restricted to second resolution
+   - file modification times suffer from forth-and-back conversions between
+     UTC and local time
+   Therefore, we implement our own stat, based on the Win32 API directly.
+*/
+
+/* Seconds between 1.1.1601 and 1.1.1970 */
+static __int64 secs_between_epochs = 11644473600;
+
+static void
+FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out)
+{
+    /* XXX endianness. Shouldn't matter, as all Windows implementations are
+    little-endian */
+    /* Cannot simply cast and dereference in_ptr,
+       since it might not be aligned properly */
+    __int64 in;
+    memcpy(&in, in_ptr, sizeof(in));
+    *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100
+                                            nsec. */
+    *time_out = (time_t)((in / 10000000) - secs_between_epochs);
+}
+
+static int
+attributes_to_mode(DWORD attr)
+{
+    int m = 0;
+    if (0 != (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+        m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */
+    } else {
+        m |= _S_IFREG;
+    }
+    if (0 != (attr & FILE_ATTRIBUTE_READONLY)) {
+        m |= 0444;
+    } else {
+        m |= 0666;
+    }
+    return m;
+}
+
+static int
+attribute_data_to_stat(WIN32_FILE_ATTRIBUTE_DATA *info,
+                       GuestFileAttributes *result)
+{
+    int nsec = 0;
+
+    memset(result, 0, sizeof(*result));
+    result->mode = attributes_to_mode(info->dwFileAttributes);
+    result->size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow;
+    FILE_TIME_to_time_t_nsec(&info->ftCreationTime,
+                             (time_t *)&result->creation_time, &nsec);
+    FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime,
+                             (time_t *)&result->modification_time, &nsec);
+    FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime,
+                             (time_t *)&result->access_time, &nsec);
+
+    return 0;
+}
+
+static BOOL
+attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
+{
+    HANDLE hFindFile;
+    WIN32_FIND_DATAA FileData;
+    hFindFile = FindFirstFileA(pszFile, &FileData);
+    if (hFindFile == INVALID_HANDLE_VALUE) {
+        return FALSE;
+    }
+    (void)FindClose(hFindFile);
+    pfad->dwFileAttributes = FileData.dwFileAttributes;
+    pfad->ftCreationTime   = FileData.ftCreationTime;
+    pfad->ftLastAccessTime = FileData.ftLastAccessTime;
+    pfad->ftLastWriteTime  = FileData.ftLastWriteTime;
+    pfad->nFileSizeHigh    = FileData.nFileSizeHigh;
+    pfad->nFileSizeLow     = FileData.nFileSizeLow;
+    return TRUE;
+}
+
+/* based upon Python implementation of windows file stat() */
+GuestFileAttributes *qmp_guest_file_attributes(const char *path, Error **errp)
+{
+    WIN32_FILE_ATTRIBUTE_DATA info;
+    int code;
+    char *dot = NULL;
+    GuestFileAttributes *result = NULL;
+
+    if (!GetFileAttributesExA(path, GetFileExInfoStandard, &info)) {
+        if (GetLastError() != ERROR_SHARING_VIOLATION) {
+            error_setg(errp, "Failed querying '%s' for attributes (error %d)",
+                       path, (int)GetLastError());
+            /* Protocol violation: we explicitly clear errno, instead of
+               setting it to a POSIX error. Callers should use GetLastError. */
+            errno = 0;
+            return NULL;
+        } else {
+            /* Could not get attributes on open file. Fall back to
+               reading the directory. */
+            if (!attributes_from_dir(path, &info)) {
+                error_setg(errp, "Error querying '%s' attributes (error %d)",
+                           path, (int)GetLastError());
+                /* Very strange. This should not fail now */
+                errno = 0;
+                return NULL;
+            }
+        }
+    }
+
+    result = g_malloc(sizeof(GuestFileAttributes));
+    if (NULL == result) {
+        error_setg(errp, "No memory for attributes result for '%s' (error %d)",
+                   path, errno);
+        return NULL;
+    }
+
+    code = attribute_data_to_stat(&info, result);
+    if (code != 0) {
+        g_free(result);
+        error_setg(errp, "Error converting attributes result '%s' (code %d)",
+                   path, code);
+        return NULL;
+    }
+    /* Set S_IFEXEC if it is an .exe, .bat, ... */
+    dot = strrchr(path, '.');
+    if (dot) {
+        if (stricmp(dot, ".bat") == 0 ||
+            stricmp(dot, ".cmd") == 0 ||
+            stricmp(dot, ".exe") == 0 ||
+            stricmp(dot, ".com") == 0) {
+            result->mode |= 0111;
+        }
+    }
+    return result;
+}
+
diff --git a/qga/commands.c b/qga/commands.c
index f9378f4..64404d6 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -113,3 +113,11 @@ char *qmp_guest_file_hash(const char *path, Error **errp)
 
     return g_strdup((char *)sha256_hexdigest);
 }
+
+void qmp_guest_file_remove(const char *path, Error **errp)
+{
+    if (unlink(path)) {
+        error_setg(errp, "Error deleting file '%s' (error %d)", path, errno);
+        errno = 0;
+    }
+}
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 68b420d..cc670b2 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -904,3 +904,45 @@
 { 'command': 'guest-file-hash',
   'data': { 'path': 'str' },
   'returns': 'str' }
+
+##
+# @GuestFileAttributes
+#
+# @mode: file access permissions mode
+# @size: file size in bytes
+# @access-time: file last access time
+# @modification-time: file last modification time
+# @creation-time: file creation time (when possible)
+#
+# Since: 2.4
+##
+{ 'type': 'GuestFileAttributes',
+  'data': {'mode': 'int', 'size': 'uint64', 'access-time': 'int',
+           'modification-time': 'int', 'creation-time': 'int'
+          }}
+
+##
+# @guest-file-attributes:
+#
+# Get file attributes for a file in the guest's operating system
+# for a given file path
+#
+# Returns: file attributes structure (GuestFileAttributes type)
+#
+# Since 2.4
+##
+{ 'command': 'guest-file-attributes',
+  'data': { 'path': 'str' },
+  'returns': 'GuestFileAttributes'}
+
+##
+# @guest-file-remove:
+#
+# Remove a file in the guest's operating system for a given file path
+#
+# Returns:
+#
+# Since 2.4
+##
+{ 'command': 'guest-file-remove',
+  'data': { 'path': 'str' }}
-- 
2.3.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 3/4] added qga system uptime and hostname commands
  2015-03-31  8:34 [Qemu-devel] [PATCH 0/4] qga added functionality itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 1/4] added qga hash file command (win/linux) itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 2/4] added missing file commands (attributes, deletion) itamar.tal4
@ 2015-03-31  8:34 ` itamar.tal4
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 4/4] added qga processes and connections enumeration commands (win/linux) itamar.tal4
  3 siblings, 0 replies; 5+ messages in thread
From: itamar.tal4 @ 2015-03-31  8:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: ori, ariel, mdroth, pavel, Itamar Tal

From: Itamar Tal <itamar@guardicore.com>

This patch add more missing commands to the qga (both Windows and Linux):
- retrieving system uptime in seconds
- retrieving system hostname

---
 qga/commands-posix.c   | 13 +++++++++++++
 qga/commands-win32.c   | 22 ++++++++++++++++++++++
 qga/commands.c         | 18 ++++++++++++++++++
 qga/guest-agent-core.h |  2 ++
 qga/main.c             |  5 +++++
 qga/qapi-schema.json   | 25 +++++++++++++++++++++++++
 6 files changed, 85 insertions(+)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 028d533..38b639c 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -17,6 +17,7 @@
 #include <glib.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#include <sys/sysinfo.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #include <errno.h>
@@ -2479,3 +2480,15 @@ GuestFileAttributes *qmp_guest_file_attributes(const char *path, Error **errp)
 
     return file_stat;
 }
+
+uint32_t qmp_guest_uptime(Error **errp)
+{
+    struct sysinfo sys_info;
+    if (sysinfo(&sys_info)) {
+        error_setg(errp, "Failed reading system info");
+    }
+
+    return sys_info.uptime;
+}
+
+
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index aeb49c5..6987f4e 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -385,6 +385,21 @@ static void guest_file_init(void)
     QTAILQ_INIT(&guest_file_state.filehandles);
 }
 
+int ga_win_commands_init(void)
+{
+    WSADATA wsa_data = {0};
+
+    if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) {
+        g_critical("failed to initialize WSA engine");
+        goto error;
+    }
+
+    return 1;
+
+error:
+    return 0;
+}
+
 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
 {
     error_set(errp, QERR_UNSUPPORTED);
@@ -881,3 +896,10 @@ GuestFileAttributes *qmp_guest_file_attributes(const char *path, Error **errp)
     return result;
 }
 
+uint32_t qmp_guest_uptime(Error **errp)
+{
+    uint32_t uptime_milli = GetTickCount();
+    return uptime_milli / 1000;
+}
+
+
diff --git a/qga/commands.c b/qga/commands.c
index 64404d6..3acc95c 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -121,3 +121,21 @@ void qmp_guest_file_remove(const char *path, Error **errp)
         errno = 0;
     }
 }
+
+char *qmp_guest_get_hostname(Error **errp)
+{
+    char hostname[64];
+
+    if (gethostname(hostname, 64)) {
+#ifdef _WIN32
+        error_setg(errp, "Error getting hostname (error %d)",
+                   (int)WSAGetLastError());
+#else
+        error_setg(errp, "Error getting hostname (error %d)", errno);
+        errno = 0;
+#endif
+        return NULL;
+    }
+
+    return g_strdup(hostname);
+}
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
index b496c47..49cbb19 100644
--- a/qga/guest-agent-core.h
+++ b/qga/guest-agent-core.h
@@ -44,6 +44,8 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp);
 
 #ifndef _WIN32
 void reopen_fd_to_null(int fd);
+#else
+int ga_win_commands_init(void);
 #endif
 
 #endif /* _GUEST_AGENT_CORE_H_ */
diff --git a/qga/main.c b/qga/main.c
index 9939a2b..8365349 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1163,6 +1163,11 @@ int main(int argc, char **argv)
         g_critical("failed to register signal handlers");
         goto out_bad;
     }
+#else
+    if (!ga_win_commands_init()) {
+        g_critical("failed initializing commands module");
+        goto out_bad;
+    }
 #endif
 
     s->main_loop = g_main_loop_new(NULL, false);
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index cc670b2..61f8a5a 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -946,3 +946,28 @@
 ##
 { 'command': 'guest-file-remove',
   'data': { 'path': 'str' }}
+
+##
+# @guest-get-hostname:
+#
+# Get the hostname of the guest's operating system
+#
+# Returns: hostname string.
+#
+# Since 2.4
+##
+{ 'command': 'guest-get-hostname',
+  'returns': 'str' }
+
+##
+# @guest-uptime:
+#
+# Get the time in seconds since the guest machine operating system was started
+#
+# Returns: uptime in seconds
+#
+# Since 2.4
+##
+{ 'command': 'guest-uptime',
+  'returns': 'uint32' }
+
-- 
2.3.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 4/4] added qga processes and connections enumeration commands (win/linux)
  2015-03-31  8:34 [Qemu-devel] [PATCH 0/4] qga added functionality itamar.tal4
                   ` (2 preceding siblings ...)
  2015-03-31  8:34 ` [Qemu-devel] [PATCH 3/4] added qga system uptime and hostname commands itamar.tal4
@ 2015-03-31  8:34 ` itamar.tal4
  3 siblings, 0 replies; 5+ messages in thread
From: itamar.tal4 @ 2015-03-31  8:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: ori, ariel, mdroth, pavel, Itamar Tal

From: Itamar Tal <itamar@guardicore.com>

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 (itamar@guardicore.com):
  * - 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 (itamar@guardicore.com):
  * - 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

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-03-31  8:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-31  8:34 [Qemu-devel] [PATCH 0/4] qga added functionality itamar.tal4
2015-03-31  8:34 ` [Qemu-devel] [PATCH 1/4] added qga hash file command (win/linux) itamar.tal4
2015-03-31  8:34 ` [Qemu-devel] [PATCH 2/4] added missing file commands (attributes, deletion) itamar.tal4
2015-03-31  8:34 ` [Qemu-devel] [PATCH 3/4] added qga system uptime and hostname commands itamar.tal4
2015-03-31  8:34 ` [Qemu-devel] [PATCH 4/4] added qga processes and connections enumeration commands (win/linux) itamar.tal4

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).