+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
/** 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. */
};
/** 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);
}
*/
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;
}
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;
}
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);
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;
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;
}