diff --git a/doc/Protocol.txt b/doc/Protocol.txt index 9a8ddf6f..39c5730b 100644 --- a/doc/Protocol.txt +++ b/doc/Protocol.txt @@ -225,6 +225,7 @@ new server link", "M"), even if it doesn't support the given The following 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) diff --git a/src/ngircd/client.c b/src/ngircd/client.c index 54c01291..2114f84d 100644 --- a/src/ngircd/client.c +++ b/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); +/** + * 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]; - snprintf(Cloak_Buffer, CLIENT_HOST_LEN, Conf_CloakHostModeX, - Hash(Cloak_Buffer)); + assert(Client != NULL); + if (!Origin) + Origin = Client_ThisServer(); - return Cloak_Buffer; -} /* Client_HostnameCloaked */ + 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 ) diff --git a/src/ngircd/client.h b/src/ngircd/client.h index 82b69019..ebbd06cb 100644 --- a/src/ngircd/client.h +++ b/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,6 +168,10 @@ GLOBAL void Client_Reject PARAMS((CLIENT *Client, const char *Reason, 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)); diff --git a/src/ngircd/irc-metadata.c b/src/ngircd/irc-metadata.c index 5cef8333..308a7157 100644 --- a/src/ngircd/irc-metadata.c +++ b/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; diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index ec12e282..32219975 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -36,8 +36,6 @@ #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, @@ -368,9 +366,17 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ) "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 *Origin, CLIENT *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) { diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c index f48cc214..9b8240bd 100644 --- a/src/ngircd/numeric.c +++ b/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 */