Commit Diff


commit - dc89e42ef5a60dda96707d2520fad998bf9ac74f
commit + 35e2dcff88e29617db0e5af1d016ab76a31ab677
blob - 9a8ddf6fdcefa96674200764876b7e7895cd2b74
blob + 39c5730bd4a76da18380af3f44562c806b1e005e
--- doc/Protocol.txt
+++ doc/Protocol.txt
@@ -225,6 +225,7 @@ new server link", <serverflag> "M"), even if it doesn'
 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)
 
blob - 54c01291cba646adc99e2499b59f8ac6be565ed1
blob + 2114f84ddbc8bcf6a6761db022524b880c6a1d85
--- src/ngircd/client.c
+++ src/ngircd/client.c
@@ -671,7 +671,6 @@ Client_OrigUser(CLIENT *Client) {
 
 #endif
 
-
 /**
  * Return the hostname of a client.
  * @param Client Pointer to client structure
@@ -682,8 +681,19 @@ Client_Hostname(CLIENT *Client)
 {
 	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.
@@ -698,33 +708,61 @@ Client_Hostname(CLIENT *Client)
 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);
+	/* Use an already saved cloaked hostname, if there is one */
+	if (Client->cloaked[0])
+		return Client->cloaked;
 
-	/* Do simple mapping to the server ID? */
-	if (!*Conf_CloakHostModeX)
-		return Client_ID(Client->introducer);
+	Client_UpdateCloakedHostname(Client, NULL, NULL);
+	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));
-
-	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 )
blob - 82b69019e2d071ad0a29fa0564b2d7e6f78d879e
blob + ebbd06cba05b0239fd5f42d6c4e8ce4fee706a79
--- src/ngircd/client.h
+++ src/ngircd/client.h
@@ -48,6 +48,7 @@ typedef struct _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 */
@@ -107,6 +108,7 @@ GLOBAL char *Client_User PARAMS(( CLIENT *Client ));
 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 ));
@@ -166,7 +168,11 @@ GLOBAL void Client_Reject PARAMS((CLIENT *Client, cons
 				  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));
 #endif
blob - 5cef8333792cf612f4a4d7f0ca6803bf3796c25b
blob + 308a7157ac4bad8c969391fe30a32b5be7a04cb6
--- src/ngircd/irc-metadata.c
+++ src/ngircd/irc-metadata.c
@@ -66,7 +66,7 @@ IRC_METADATA(CLIENT *Client, REQUEST *Req)
 					  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 */
@@ -76,9 +76,23 @@ IRC_METADATA(CLIENT *Client, REQUEST *Req)
 		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);
@@ -88,6 +102,7 @@ IRC_METADATA(CLIENT *Client, REQUEST *Req)
 		    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;
blob - ec12e282e1f0b14d83a30cd05fc24e5d38da62a0
blob + 32219975f5ea23a389fcc368551104e331226155
--- src/ngircd/irc-mode.c
+++ src/ngircd/irc-mode.c
@@ -35,8 +35,6 @@
 #include "exp.h"
 #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));
@@ -368,9 +366,17 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Ori
 						  "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));
@@ -381,27 +387,6 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Ori
 } /* 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)
 {
blob - f48cc2147f470124cf120e0d9c063c23ce0ac8dc
blob + 9b8240bdca0227f7e9862d4fb6d5e0646d36ce7a
--- src/ngircd/numeric.c
+++ src/ngircd/numeric.c
@@ -179,24 +179,40 @@ Announce_User(CLIENT * Client, CLIENT * User)
 				     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 */