The following <key> names are defined:
- "host": the hostname of a client (can't be empty)
+ - "cloakhost": the cloaked hostname of a client
- "info": info text ("real name") of a client
- "user": the user name of a client (can't be empty)
#endif
-
/**
* Return the hostname of a client.
* @param Client Pointer to client structure
{
assert (Client != NULL);
return Client->host;
-} /* Client_Hostname */
+}
+/**
+ * Return the cloaked hostname of a client, if set.
+ * @param Client Pointer to the client structure.
+ * @return Pointer to the cloaked hostname or NULL if not set.
+ */
+GLOBAL char *
+Client_HostnameCloaked(CLIENT *Client)
+{
+ assert(Client != NULL);
+ return Client->cloaked;
+}
/**
* Get (potentially cloaked) hostname of a client to display it to other users.
GLOBAL char *
Client_HostnameDisplayed(CLIENT *Client)
{
- static char Cloak_Buffer[CLIENT_HOST_LEN];
-
assert(Client != NULL);
/* Client isn't cloaked at all, return real hostname: */
if (!Client_HasMode(Client, 'x'))
return Client_Hostname(Client);
- /* Client has received METADATA command, so it got the eventually
- * cloaked hostname set correctly and this server doesn't need
- * to cloak it on its own: */
- if (strchr(Client_Flags(Client), 'M'))
- return Client_Hostname(Client);
-
- /* Do simple mapping to the server ID? */
- if (!*Conf_CloakHostModeX)
- return Client_ID(Client->introducer);
+ /* Use an already saved cloaked hostname, if there is one */
+ if (Client->cloaked[0])
+ return Client->cloaked;
- strlcpy(Cloak_Buffer, Client->host, CLIENT_HOST_LEN);
- strlcat(Cloak_Buffer, Conf_CloakHostSalt, CLIENT_HOST_LEN);
-
- snprintf(Cloak_Buffer, CLIENT_HOST_LEN, Conf_CloakHostModeX,
- Hash(Cloak_Buffer));
+ Client_UpdateCloakedHostname(Client, NULL, NULL);
+ return Client->cloaked;
+}
- return Cloak_Buffer;
-} /* Client_HostnameCloaked */
+/**
+ * Update (and generate, if necessary) the cloaked hostname of a client.
+ *
+ * The newly set cloaked hostname is announced in the network using METADATA
+ * commands to peers that support this feature.
+ *
+ * @param Client The client of which the cloaked hostname should be updated.
+ * @param Origin The originator of the hostname change, or NULL if this server.
+ * @param Hostname The new cloaked hostname, or NULL if it should be generated.
+ */
+GLOBAL void
+Client_UpdateCloakedHostname(CLIENT *Client, CLIENT *Origin,
+ const char *Hostname)
+{
+ static char Cloak_Buffer[CLIENT_HOST_LEN];
+ assert(Client != NULL);
+ if (!Origin)
+ Origin = Client_ThisServer();
+
+ if (!Hostname) {
+ /* Generate new cloaked hostname */
+ if (*Conf_CloakHostModeX) {
+ strlcpy(Cloak_Buffer, Client->host, CLIENT_HOST_LEN);
+ strlcat(Cloak_Buffer, Conf_CloakHostSalt,
+ CLIENT_HOST_LEN);
+ snprintf(Client->cloaked, sizeof(Client->cloaked),
+ Conf_CloakHostModeX, Hash(Cloak_Buffer));
+ } else
+ strlcpy(Client->cloaked, Client_ID(Client->introducer),
+ sizeof(Client->cloaked));
+ } else
+ strlcpy(Client->cloaked, Hostname, sizeof(Client->cloaked));
+ LogDebug("Cloaked hostname of \"%s\" updated to \"%s\"",
+ Client_ID(Client), Client->cloaked);
+
+ /* Inform other servers in the network */
+ IRC_WriteStrServersPrefixFlag(Client_NextHop(Origin), Origin, 'M',
+ "METADATA %s cloakhost :%s",
+ Client_ID(Client), Client->cloaked);
+}
GLOBAL char *
Client_Modes( CLIENT *Client )
struct _CLIENT *introducer; /* ID of the servers which the client is connected to */
struct _CLIENT *topserver; /* toplevel servers (only valid if client is a server) */
char host[CLIENT_HOST_LEN]; /* hostname of the client */
+ char cloaked[CLIENT_HOST_LEN]; /* cloaked hostname of the client */
char user[CLIENT_USER_LEN]; /* user name ("login") */
#if defined(PAM) && defined(IDENTAUTH)
char orig_user[CLIENT_USER_LEN];/* user name supplied by USER command */
GLOBAL char *Client_OrigUser PARAMS(( CLIENT *Client ));
#endif
GLOBAL char *Client_Hostname PARAMS(( CLIENT *Client ));
+GLOBAL char *Client_HostnameCloaked PARAMS((CLIENT *Client));
GLOBAL char *Client_HostnameDisplayed PARAMS(( CLIENT *Client ));
GLOBAL char *Client_Modes PARAMS(( CLIENT *Client ));
GLOBAL char *Client_Flags PARAMS(( CLIENT *Client ));
bool InformClient));
GLOBAL void Client_Introduce PARAMS((CLIENT *From, CLIENT *Client, int Type));
+GLOBAL void Client_UpdateCloakedHostname PARAMS((CLIENT *Client,
+ CLIENT *Originator,
+ const char *hostname));
+
#ifdef DEBUG
GLOBAL void Client_DebugDump PARAMS((void));
Client_ID(Client), Req->argv[0]);
LogDebug("Got \"METADATA\" command from \"%s\" for client \"%s\": \"%s=%s\".",
- Client_ID(Client), Client_ID(target),
+ Client_ID(prefix), Client_ID(target),
Req->argv[1], Req->argv[2]);
/* Mark client: it has receiveda a METADATA command */
Client_SetFlags(target, new_flags);
}
- if (*Req->argv[2] && strcasecmp(Req->argv[1], "host") == 0)
+ if (strcasecmp(Req->argv[1], "cloakhost") == 0) {
+ Client_UpdateCloakedHostname(target, prefix, Req->argv[2]);
+ if (Client_Conn(target) > NONE && Client_HasMode(target, 'x'))
+ IRC_WriteStrClientPrefix(target, prefix,
+ RPL_HOSTHIDDEN_MSG, Client_ID(target),
+ Client_HostnameDisplayed(target));
+ /* The Client_UpdateCloakedHostname() function already
+ * forwarded the METADATA command, don't do it twice: */
+ return CONNECTED;
+ }
+ else if (*Req->argv[2] && strcasecmp(Req->argv[1], "host") == 0) {
Client_SetHostname(target, Req->argv[2]);
- else if (strcasecmp(Req->argv[1], "info") == 0)
+ if (Client_Conn(target) > NONE && !Client_HasMode(target, 'x'))
+ IRC_WriteStrClientPrefix(target, prefix,
+ RPL_HOSTHIDDEN_MSG, Client_ID(target),
+ Client_HostnameDisplayed(target));
+ } else if (strcasecmp(Req->argv[1], "info") == 0)
Client_SetInfo(target, Req->argv[2]);
else if (*Req->argv[2] && strcasecmp(Req->argv[1], "user") == 0)
Client_SetUser(target, Req->argv[2], true);
Client_ID(Client), Client_ID(target),
Req->argv[1], Req->argv[2]);
+ /* Forward the METADATA command to peers that support it: */
IRC_WriteStrServersPrefixFlag(Client, prefix, 'M', "METADATA %s %s :%s",
Client_ID(target), Req->argv[1], Req->argv[2]);
return CONNECTED;
#include "irc-mode.h"
-static void Announce_Client_Hostname PARAMS((CLIENT *Origin, CLIENT *Client));
-
static bool Client_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
CLIENT *Target));
static bool Channel_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
"MODE %s :%s",
Client_ID(Target),
the_modes);
- if (send_RPL_HOSTHIDDEN_MSG)
- Announce_Client_Hostname(Origin, Client);
}
+
+ if (send_RPL_HOSTHIDDEN_MSG && Client_Conn(Target) > NONE) {
+ /* A new (cloaked) hostname must be annoucned */
+ IRC_WriteStrClientPrefix(Target, Origin,
+ RPL_HOSTHIDDEN_MSG,
+ Client_ID(Target),
+ Client_HostnameDisplayed(Target));
+
+ }
+
LogDebug("%s \"%s\": Mode change, now \"%s\".",
Client_TypeText(Target), Client_Mask(Target),
Client_Modes(Target));
} /* Client_Mode */
-/**
- * Announce changed client hostname in the network.
- *
- * @param Client The client of which the hostname changed.
- */
-static void
-Announce_Client_Hostname(CLIENT *Origin, CLIENT *Client)
-{
- assert(Client != NULL);
-
- /* Inform the client itself */
- IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG, Client_ID(Client),
- Client_HostnameDisplayed(Client));
-
- /* Inform other servers in the network */
- IRC_WriteStrServersPrefixFlag(Origin, Client_ThisServer(), 'M',
- "METADATA %s host :%s", Client_ID(Client),
- Client_HostnameDisplayed(Client));
-}
-
-
static bool
Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
{
Client_ID(User), Client_ID(User),
modes);
}
- return CONNECTED;
} else {
/* RFC 2813 mode: one combined NICK or SERVICE command */
if (Client_Type(User) == CLIENT_SERVICE
- && strchr(Client_Flags(Client), 'S'))
- return IRC_WriteStrClient(Client,
- "SERVICE %s %d * +%s %d :%s", Client_Mask(User),
- Client_MyToken(Client_Introducer(User)),
- Client_Modes(User), Client_Hops(User) + 1,
- Client_Info(User));
- else
- return IRC_WriteStrClient(Client,
- "NICK %s %d %s %s %d +%s :%s",
- Client_ID(User), Client_Hops(User) + 1,
- Client_User(User), Client_Hostname(User),
- Client_MyToken(Client_Introducer(User)),
- Client_Modes(User), Client_Info(User));
+ && strchr(Client_Flags(Client), 'S')) {
+ if (!IRC_WriteStrClient(Client,
+ "SERVICE %s %d * +%s %d :%s",
+ Client_Mask(User),
+ Client_MyToken(Client_Introducer(User)),
+ Client_Modes(User), Client_Hops(User) + 1,
+ Client_Info(User)))
+ return DISCONNECTED;
+ } else {
+ if (!IRC_WriteStrClient(Client,
+ "NICK %s %d %s %s %d +%s :%s",
+ Client_ID(User), Client_Hops(User) + 1,
+ Client_User(User), Client_Hostname(User),
+ Client_MyToken(Client_Introducer(User)),
+ Client_Modes(User), Client_Info(User)))
+ return DISCONNECTED;
+ }
}
+
+ if (strchr(Client_Flags(Client), 'M')) {
+ /* Synchronize metadata */
+ if (Client_HostnameCloaked(User)) {
+ if (!IRC_WriteStrClient(Client,
+ "METADATA %s cloakhost :%s",
+ Client_ID(User),
+ Client_HostnameCloaked(User)))
+ return DISCONNECTED;
+ }
+ }
+
+ return CONNECTED;
} /* Announce_User */