]> arthur.barton.de Git - ngircd-alex.git/commitdiff
Rework cloaked hostname handling, implement "METADATA cloakhost"
authorAlexander Barton <alex@barton.de>
Sat, 24 Nov 2012 15:15:35 +0000 (16:15 +0100)
committerAlexander Barton <alex@barton.de>
Sat, 24 Nov 2012 15:15:35 +0000 (16:15 +0100)
Now ngIRCd uses two fields internally, one to store the "real" hostname
and one to save the "cloaked" hostname. And both fields can be set
independently using the "METADATA host" and "METADATA cloakhost" commands.

This allows "foreign servers" (aka "IRC services") to alter the real and
cloaked hostnames of clients without problems, even when the user itself
issues additional "MODE +x" and "MODE -x" commands.

doc/Protocol.txt
src/ngircd/client.c
src/ngircd/client.h
src/ngircd/irc-metadata.c
src/ngircd/irc-mode.c
src/ngircd/numeric.c

index 9a8ddf6fdcefa96674200764876b7e7895cd2b74..39c5730bd4a76da18380af3f44562c806b1e005e 100644 (file)
@@ -225,6 +225,7 @@ new server link", <serverflag> "M"), even if it doesn't support the given
 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)
 
index 54c01291cba646adc99e2499b59f8ac6be565ed1..2114f84ddbc8bcf6a6761db022524b880c6a1d85 100644 (file)
@@ -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);
-
-       /* 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 )
index 82b69019e2d071ad0a29fa0564b2d7e6f78d879e..ebbd06cba05b0239fd5f42d6c4e8ce4fee706a79 100644 (file)
@@ -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));
index 5cef8333792cf612f4a4d7f0ca6803bf3796c25b..308a7157ac4bad8c969391fe30a32b5be7a04cb6 100644 (file)
@@ -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;
index ec12e282e1f0b14d83a30cd05fc24e5d38da62a0..32219975f5ea23a389fcc368551104e331226155 100644 (file)
@@ -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)
 {
index f48cc2147f470124cf120e0d9c063c23ce0ac8dc..9b8240bdca0227f7e9862d4fb6d5e0646d36ce7a 100644 (file)
@@ -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 */