Fix missing XML hostnames when --unique is used (#3409)

When using the --unique flag, duplicate IPs are skipped to avoid redundant scanning. However, if a user provided multiple aliases for the same IP (e.g. '127.0.0.1 localhost'), the aliases were silently discarded when skipped, resulting in missing '<hostname type="user">' tags in the XML output.
This commit resolves the issue by extending the Target class to support storing multiple aliases. During host generation (HostGroupState::get_next_host), if a named host is skipped due to the --unique flag, its name is now looked up in the current hostbatch and appended to the existing Target's aliases. Finally, output.cc was updated to iterate over and print all collected aliases.
This commit is contained in:
I-am-Krish 2026-08-24 17:22:34 +05:30
parent 271cabb86a
commit 5d8a4cc56b
5 changed files with 41 additions and 0 deletions

View file

@ -356,6 +356,16 @@ void Target::setTargetName(const char *name) {
}
}
void Target::addTargetNameAlias(const char *name) {
if (name)
target_aliases.push_back(std::string(name));
}
const std::vector<std::string> &Target::getTargetNameAliases() const {
return target_aliases;
}
/* Generates a printable string consisting of the host's IP
address and hostname (if available). Eg "www.insecure.org
(64.71.184.53)" or "fe80::202:e3ff:fe14:1102". The name is

View file

@ -184,6 +184,11 @@ class Target {
order
*/
void setTargetName(const char *name);
/* Add an additional user-supplied name that resolved to the same IP as this
target (recorded when --unique suppresses duplicate scanning). */
void addTargetNameAlias(const char *name);
/* Returns the list of additional user-supplied names for this target. */
const std::vector<std::string> &getTargetNameAliases() const;
/* If the host is directly connected on a network, set and retrieve
that information here. directlyConnected() will abort if it hasn't
@ -262,6 +267,8 @@ class Target {
struct timeout_info to;
char *hostname; // Null if unable to resolve or unset
char * targetname; // The name of the target host given on the command line if it is a named host
std::vector<std::string> target_aliases; /* Additional user-supplied names that resolved to this
same IP, collected when --unique suppresses duplicate scanning. */
struct probespec traceroute_probespec;
std::list <TracerouteHop> traceroute_hops;

View file

@ -1281,6 +1281,14 @@ static void write_xml_initial_hostinfo(const Target *currenths,
xml_close_empty_tag();
xml_newline();
}
/* Print additional names collected when --unique suppressed duplicate scanning. */
for (const std::string &alias : currenths->getTargetNameAliases()) {
xml_open_start_tag("hostname");
xml_attribute("name", "%s", alias.c_str());
xml_attribute("type", "user");
xml_close_empty_tag();
xml_newline();
}
if (*currenths->HostName()) {
xml_open_start_tag("hostname");
xml_attribute("name", "%s", currenths->HostName());

View file

@ -467,6 +467,21 @@ bool HostGroupState::get_next_host(struct sockaddr_storage *ss, size_t *sslen, s
current_group.reject_last_host();
break;
}
/* This IP is already in the exclude list (a --unique duplicate).
At this point *ss holds the excluded IP. If it came from a named
host, attach that name as an alias on the existing Target in the
current batch so it appears in XML output. */
if (o.unique && current_group.get_namedhost()) {
const char *skipped_name = current_group.get_resolved_name();
if (skipped_name) {
for (int i = 0; i < current_batch_sz; i++) {
if (sockaddr_storage_cmp(hostbatch[i]->TargetSockAddr(), ss) == 0) {
hostbatch[i]->addTargetNameAlias(skipped_name);
break;
}
}
}
}
} while (true);
return true;

View file

@ -66,6 +66,7 @@
#include "TargetGroup.h"
#include <list>
#include <string>
#include <nbase.h>
class Target;