1 /* This is a more significant example of a tool which can grab the
2 * DHCP address from some types of virtual machine. Since there are
3 * so many possible ways to do this, without clarity on which is the
4 * best way, I don't want to make this into an official virt tool.
6 * For more information, see:
8 * https://rwmj.wordpress.com/2010/10/26/tip-find-the-ip-address-of-a-virtual-machine/
9 * https://rwmj.wordpress.com/2011/03/30/tip-another-way-to-get-the-ip-address-of-a-virtual-machine/
22 static int compare_keys_len (const void *p1, const void *p2);
23 static size_t count_strings (char *const *argv);
24 static void free_strings (char **argv);
25 static void mount_disks (guestfs_h *g, char *root);
26 static void print_dhcp_address (guestfs_h *g, char *root);
27 static void print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile);
28 static void print_dhcp_address_windows (guestfs_h *g, char *root);
31 main (int argc, char *argv[])
39 "Usage: virt-dhcp-address disk.img [disk.img [...]]\n"
40 "Note that all disks must come from a single virtual machine.\n");
44 g = guestfs_create ();
46 perror ("failed to create libguestfs handle");
50 for (i = 1; i < (size_t) argc; ++i) {
51 /* Attach the disk image(s) read-only to libguestfs. */
52 if (guestfs_add_drive_opts (g, argv[i],
53 /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
54 GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
55 -1) /* this marks end of optional arguments */
60 /* Run the libguestfs back-end. */
61 if (guestfs_launch (g) == -1)
64 /* Ask libguestfs to inspect for operating systems. */
65 roots = guestfs_inspect_os (g);
68 if (roots[0] == NULL) {
69 fprintf (stderr, "virt-dhcp-address: no operating systems found\n");
72 if (count_strings (roots) > 1) {
73 fprintf (stderr, "virt-dhcp-address: multi-boot operating system\n");
79 /* Mount up the guest's disks. */
80 mount_disks (g, root);
82 /* Print DHCP address. */
83 print_dhcp_address (g, root);
85 /* Close handle and exit. */
93 mount_disks (guestfs_h *g, char *root)
98 /* Mount up the disks, like guestfish -i.
100 * Sort keys by length, shortest first, so that we end up
101 * mounting the filesystems in the correct order.
103 mountpoints = guestfs_inspect_get_mountpoints (g, root);
104 if (mountpoints == NULL)
107 qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
110 for (i = 0; mountpoints[i] != NULL; i += 2) {
111 /* Ignore failures from this call, since bogus entries can
112 * appear in the guest's /etc/fstab.
114 guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
117 free_strings (mountpoints);
121 print_dhcp_address (guestfs_h *g, char *root)
123 char *guest_type, *guest_distro;
125 /* Depending on the guest type, try to get the DHCP address. */
126 guest_type = guestfs_inspect_get_type (g, root);
128 if (strcmp (guest_type, "linux") == 0) {
129 guest_distro = guestfs_inspect_get_distro (g, root);
131 if (strcmp (guest_distro, "fedora") == 0 ||
132 strcmp (guest_distro, "rhel") == 0 ||
133 strcmp (guest_distro, "redhat-based") == 0) {
134 print_dhcp_address_linux (g, root, "/var/log/messages");
136 else if (strcmp (guest_distro, "debian") == 0 ||
137 strcmp (guest_distro, "ubuntu") == 0) {
138 print_dhcp_address_linux (g, root, "/var/log/syslog");
141 fprintf (stderr, "virt-dhcp-address: don't know how to get DHCP address from '%s'\n",
148 else if (strcmp (guest_type, "windows") == 0) {
149 print_dhcp_address_windows (g, root);
152 fprintf (stderr, "virt-dhcp-address: don't know how to get DHCP address from '%s'\n",
160 /* Look for dhclient messages in logfile.
163 print_dhcp_address_linux (guestfs_h *g, char *root, const char *logfile)
168 lines = guestfs_egrep (g, "dhclient.*: bound to ", logfile);
172 len = count_strings (lines);
174 fprintf (stderr, "virt-dhcp-address: cannot find DHCP address for this guest.\n");
178 /* Only want the last message. */
179 p = strstr (lines[len-1], "bound to ");
182 len = strcspn (p, " ");
187 free_strings (lines);
190 /* Download the Windows SYSTEM hive and find DHCP configuration in there. */
192 print_dhcp_address_windows (guestfs_h *g, char *root_fs)
195 char tmpfile[] = "/tmp/systemXXXXXX";
198 hive_node_h root, node, *nodes;
204 /* Locate the SYSTEM hive case-sensitive path. */
206 guestfs_case_sensitive_path (g, "/windows/system32/config/system");
208 fprintf (stderr, "virt-dhcp-address: HKLM\\System not found in this guest.");
212 fd = mkstemp (tmpfile);
218 /* Download the SYSTEM hive. */
219 if (guestfs_download (g, system_path, tmpfile) == -1)
224 controlset = guestfs_inspect_get_windows_current_control_set (g, root_fs);
225 if (controlset == NULL)
228 /* Open the hive to parse it. */
229 h = hivex_open (tmpfile, 0);
236 perror ("hivex_open");
240 root = hivex_root (h);
242 perror ("hivex_root");
246 /* Get ControlSetXXX\Services\Tcpip\Parameters\Interfaces. */
247 const char *path[] = { controlset, "Services", "Tcpip", "Parameters",
251 for (i = 0; node != 0 && i < sizeof path / sizeof path[0]; ++i)
252 node = hivex_node_get_child (h, node, path[i]);
256 perror ("hivex_node_get_child");
258 fprintf (stderr, "virt-dhcp-address: HKLM\\System\\%s\\Services\\Tcpip\\Parameters\\Interfaces not found.", controlset);
262 /* Look for a node under here which has a "DhcpIPAddress" entry in it. */
263 nodes = hivex_node_children (h, node);
265 perror ("hivex_node_children");
270 for (i = 0; value == 0 && nodes[i] != 0; ++i) {
272 value = hivex_node_get_value (h, nodes[i], "DhcpIPAddress");
273 if (value == 0 && errno != 0) {
274 perror ("hivex_node_get_value");
280 fprintf (stderr, "virt-dhcp-address: cannot find DHCP address for this guest.\n");
284 /* Get the string and use hivex's auto-conversion to convert it to UTF-8
287 p = hivex_value_string (h, value);
289 perror ("hivex_value_string");
295 /* Close the hive handle. */
302 compare_keys_len (const void *p1, const void *p2)
304 const char *key1 = * (char * const *) p1;
305 const char *key2 = * (char * const *) p2;
306 return strlen (key1) - strlen (key2);
310 count_strings (char *const *argv)
314 for (c = 0; argv[c]; ++c)
320 free_strings (char **argv)
324 for (i = 0; argv[i]; ++i)