Allow TOPIC from off-channel services. Preserve user's visibility in
authorMichael Poole <mdpoole@troilus.org>
Thu, 16 Dec 2004 04:37:14 +0000 (04:37 +0000)
committerMichael Poole <mdpoole@troilus.org>
Thu, 16 Dec 2004 04:37:14 +0000 (04:37 +0000)
a +D channel when logging in.  Canonicalize IP addresses in IPcheck so
6to4 users are counted the same as IPv4 users from the same IPs.  Do
the same trick for 6to4 users when sending their NICKs to a non-IPv6
server.

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1276 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
ircd/IPcheck.c
ircd/m_topic.c
ircd/numnicks.c
ircd/s_user.c

index 6c3fcc7e7a036a8faa268a14dcfd0576616a63c9..b366d8bf121d4a50c62df7588f1a53c75e0fc0c7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2004-12-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/m_topic.c (do_settopic): Allow +k services to set topics on
+       channels they are not joined.
+
+2004-12-15  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/IPcheck.c (IPTargetEntry): Make count unsigned to squash
+       warning.
+       (ip_registry_canonicalize): New function to convert an IP address
+       into a canonical form for clone checks.
+       (ip_registry_hash): Update to reflect canonical form.
+       (ip_registry_find): Use ip_registry_canonicalize().
+       (ip_registry_check_local, ip_registry_check_remote): Likewise.
+
+       * ircd/numnicks.c (iptobase64): Map 6to4 addresses to IPv4 when
+       sending them to a non-IPv6 server.
+
+2004-02-17  Michael Poole <mdpoole@troilus.org>
+
+       * ircd/s_user.c (hide_hostmask): Preserve user's visibility in a
+       +D channel when they hide their hostmask.
+
 2004-12-15  Michael Poole <dmpoole@troilus.org>
 
        * doc/example.conf: Remove the example Server blocks since they
index 49a448aca3819171090adc9a0a61bad9a7537deb..4c1521f2e9d92f20f52e07b58fd6b5e9368f6624 100644 (file)
@@ -41,7 +41,7 @@
 
 /** Stores free target information for a particular user. */
 struct IPTargetEntry {
-  int           count; /**< Number of free targets targets. */
+  unsigned int  count; /**< Number of free targets targets. */
   unsigned char targets[MAXTARGETS]; /**< Array of recent targets. */
 };
 
@@ -76,24 +76,34 @@ static struct IPRegistryEntry* freeList;
 /** Periodic timer to look for too-old registry entries. */
 static struct Timer expireTimer;
 
+/** Convert IP addresses to canonical form for comparison.  IPv4
+ * addresses are translated into 6to4 form; IPv6 addresses are left
+ * alone.
+ * @param[out] out Receives canonical format for address.
+ * @param[in] in IP address to canonicalize.
+ */
+static void ip_registry_canonicalize(struct irc_in_addr *out, const struct irc_in_addr *in)
+{
+    if (irc_in_addr_is_ipv4(in)) {
+        out->in6_16[0] = htons(0x2002);
+        out->in6_16[1] = in->in6_16[6];
+        out->in6_16[2] = in->in6_16[7];
+        out->in6_16[3] = out->in6_16[4] = out->in6_16[5] = 0;
+        out->in6_16[6] = out->in6_16[7] = 0;
+    } else
+        memcpy(out, in, sizeof(*out));
+}
+
 /** Calculate hash value for an IP address.
- * If this looks like an IPv6 address, only consider the first 64 bits
- * of the address. Otherwise, only consider the final 32 bits.
- * @param[in] ip Address to hash.
+ * @param[in] ip Address to hash; must be in canonical form.
  * @return Hash value for address.
  */
 static unsigned int ip_registry_hash(const struct irc_in_addr *ip)
 {
   unsigned int res;
-
-  if (ip->in6_16[0] || ip->in6_16[1] || ip->in6_16[2] || ip->in6_16[3] || ip->in6_16[4]) {
-      /* Only use the first 64 bits of address, since the last 64 bits
-       * tend to be under user control. */
-      res = ip->in6_16[0] ^ ip->in6_16[1] ^ ip->in6_16[2] ^ ip->in6_16[3];
-  } else {
-      /* Looks like an IPv4 address. */
-      res = ip->in6_16[6] ^ ip->in6_16[7];
-  }
+  /* Only use the first 64 bits of address, since the last 64 bits
+   * tend to be under user control. */
+  res = ip->in6_16[0] ^ ip->in6_16[1] ^ ip->in6_16[2] ^ ip->in6_16[3];
   return res & (IP_REGISTRY_TABLE_SIZE - 1);
 }
 
@@ -105,9 +115,12 @@ static unsigned int ip_registry_hash(const struct irc_in_addr *ip)
  */
 static struct IPRegistryEntry* ip_registry_find(const struct irc_in_addr *ip)
 {
-  struct IPRegistryEntry* entry = hashTable[ip_registry_hash(ip)];
+  struct irc_in_addr canon;
+  struct IPRegistryEntry* entry;
+  ip_registry_canonicalize(&canon, ip);
+  entry = hashTable[ip_registry_hash(&canon)];
   for ( ; entry; entry = entry->next) {
-    int bits = (ip->in6_16[0] || ip->in6_16[1] || ip->in6_16[2] || ip->in6_16[3] || ip->in6_16[4]) ? 64 : 128;
+    int bits = (ip->in6_16[0] == ntohs(0x2002)) ? 48 : 64;
     if (ipmask_check(ip, &entry->addr, bits))
       break;
   }
@@ -260,7 +273,7 @@ int ip_registry_check_local(const struct irc_in_addr *addr, time_t* next_target_
 
   if (0 == entry) {
     entry       = ip_registry_new_entry();
-    memcpy(&entry->addr, addr, sizeof(entry->addr));
+    ip_registry_canonicalize(&entry->addr, addr);
     ip_registry_add(entry);
     return 1;
   }
@@ -321,7 +334,7 @@ int ip_registry_check_remote(struct Client* cptr, int is_burst)
   SetIPChecked(cptr);
   if (0 == entry) {
     entry = ip_registry_new_entry();
-    memcpy(&entry->addr, &cli_ip(cptr), sizeof(entry->addr));
+    ip_registry_canonicalize(&entry->addr, &cli_ip(cptr));
     if (is_burst)
       entry->attempts = 0;
     ip_registry_add(entry);
index d0c674c757d4a62cdd693818f855eb241bb122e1..d646907596e24728d845deeca8325d1769d4e319 100644 (file)
 static void do_settopic(struct Client *sptr, struct Client *cptr, 
                        struct Channel *chptr, char *topic, time_t ts)
 {
-   struct Membership *member;
    struct Client *from;
    int newtopic;
 
@@ -108,14 +107,18 @@ static void do_settopic(struct Client *sptr, struct Client *cptr,
        from = &me;
    else
        from = sptr;
-   member = find_channel_member(sptr, chptr);
-   /* if +t and not @'d, return an error and ignore the topic */
-   if ((chptr->mode.mode & MODE_TOPICLIMIT) != 0 && (!member || !IsChanOp(member)))
+   if (IsChannelService(sptr))
    {
+       /* allow off-channel services to set the topic of any channel */
+   }
+   else if ((chptr->mode.mode & MODE_TOPICLIMIT) != 0 && is_chan_op(sptr, chptr))
+   {
+      /* if +t and not @'d, return an error and ignore the topic */
       send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
       return;
    }
-   if (!client_can_send_to_channel(sptr, chptr, 1) && !IsChannelService(sptr)) {
+   else if (!client_can_send_to_channel(sptr, chptr, 1))
+   {
       send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
       return;
    }
index 1e41917375fa2a9bffb6e13f1c35288a0bd98a22..143cec5a019d53dcedc6b1285a3abcffccc7a725 100644 (file)
@@ -444,10 +444,13 @@ const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int c
 {
   if (irc_in_addr_is_ipv4(addr)) {
     assert(count >= 6);
-    inttobase64(buf, (htons(addr->in6_16[6]) << 16) | htons(addr->in6_16[7]), 6);
+    inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6);
   } else if (!v6_ok) {
     assert(count >= 6);
-    strcpy(buf, "AAAAAA");
+    if (addr[0] == htons(0x2002))
+        inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6);
+    else
+        strcpy(buf, "AAAAAA");
   } else {
     unsigned int max_start, max_zeros, curr_zeros, zero, ii;
     char *output = buf;
index 958bb90244f042a3fdc3c36a5045c92ca7d7b340..5a7afd6ce89221d9f3968de592d8db71687182b5 100644 (file)
@@ -1162,12 +1162,8 @@ hide_hostmask(struct Client *cptr, unsigned int flag)
   {
     if (IsZombie(chan))
       continue;
-    /* For a user with no modes in a join-delayed channel, do not show
-     * the rejoin. */
-    if (!IsChanOp(chan) && !HasVoice(chan)
-        && (chan->channel->mode.mode & MODE_DELJOINS))
-      SetDelayedJoin(chan);
-    else
+    /* Send a JOIN unless the user's join has been delayed. */
+    if (!IsDelayedJoin(chan))
       sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
                                          "%H", chan->channel);
     if (IsChanOp(chan) && HasVoice(chan))