diff -uNrd ircd-ratbox-1.4-2/doc/example.conf ircd-ratbox-1.4-2+ipmask/doc/example.conf
--- ircd-ratbox-1.4-2/doc/example.conf	Wed Apr  7 13:37:42 2004
+++ ircd-ratbox-1.4-2+ipmask/doc/example.conf	Sun May  9 17:28:16 2004
@@ -239,6 +239,8 @@
 	 * no_tilde      (old - flag)	| don't prefix ~ to username if no ident
 	 * need_ident    (old + flag)	| require ident for user in this class
 	 * restricted			| prevent user from sending mode changes
+     * mask					| mask the users hostname
+	 * mask_notice			| give a notice when masking this host
 	 */
 	flags = kline_exempt, exceed_limit;
 	
@@ -264,7 +266,7 @@
 	user = "*@*";
 	class = "users";
 	
-	flags = restricted, need_ident;
+	flags = restricted, need_ident, mask, mask_notice;
 };
 
 /* operator {}: defines ircd operators. (OLD O:)
diff -uNrd ircd-ratbox-1.4-2/include/client.h ircd-ratbox-1.4-2+ipmask/include/client.h
--- ircd-ratbox-1.4-2/include/client.h	Wed Mar 24 17:30:45 2004
+++ ircd-ratbox-1.4-2+ipmask/include/client.h	Sun May  9 17:28:16 2004
@@ -145,6 +145,7 @@
 	 * considered a read-only field after the client has registered.
 	 */
 	char host[HOSTLEN + 1];	/* client's hostname */
+	char rhost[HOSTLEN + 1];
 	/*
 	 * client->info for unix clients will normally contain the info from the 
 	 * gcos field in /etc/passwd but anything can go here.
@@ -378,6 +379,8 @@
 #define UMODE_ADMIN        0x40000	/* Admin on server */
 #define UMODE_HIDDENOPER   0x80000	/* Oper hidden from stats p */
 
+#define UMODE_IPMASK	   0x100000
+
 #define UMODE_ALL	   UMODE_SERVNOTICE
 
 
@@ -417,7 +420,7 @@
                          OPER_HIDDENOPER)
 
 #define SEND_UMODES  (UMODE_INVISIBLE | UMODE_OPER | UMODE_WALLOP | \
-                      UMODE_ADMIN)
+                      UMODE_ADMIN | UMODE_IPMASK)
 #define ALL_UMODES   (SEND_UMODES | UMODE_SERVNOTICE | UMODE_CCONN | \
                       UMODE_REJ | UMODE_SKILL | UMODE_FULL | UMODE_SPY | \
                       UMODE_NCHANGE | UMODE_OPERWALL | UMODE_DEBUG | \
@@ -499,6 +502,8 @@
 
 #define SetGotId(x)             ((x)->flags |= FLAGS_GOTID)
 #define IsGotId(x)              (((x)->flags & FLAGS_GOTID) != 0)
+
+#define IsMasked(x)				((x)->umodes & UMODE_IPMASK)
 
 /*
  * flags2 macros.
diff -uNrd ircd-ratbox-1.4-2/include/numeric.h ircd-ratbox-1.4-2+ipmask/include/numeric.h
--- ircd-ratbox-1.4-2/include/numeric.h	Mon Apr  5 12:22:46 2004
+++ ircd-ratbox-1.4-2+ipmask/include/numeric.h	Sun May  9 17:28:16 2004
@@ -183,12 +183,15 @@
 #define RPL_ENDOFBANLIST     368
 /* rpl_endofwhowas above (369) */
 
+#define RPL_WHOWASREALHOST   370
 #define RPL_INFO             371
 #define RPL_MOTD             372
 #define RPL_INFOSTART        373
 #define RPL_ENDOFINFO        374
 #define RPL_MOTDSTART        375
 #define RPL_ENDOFMOTD        376
+
+#define RPL_WHOISHOST        378 /* -Jeremy */
 
 #define RPL_YOUREOPER        381
 #define RPL_REHASHING        382
diff -uNrd ircd-ratbox-1.4-2/include/s_conf.h ircd-ratbox-1.4-2+ipmask/include/s_conf.h
--- ircd-ratbox-1.4-2/include/s_conf.h	Wed Apr  7 13:37:45 2004
+++ ircd-ratbox-1.4-2+ipmask/include/s_conf.h	Sun May  9 17:28:16 2004
@@ -140,6 +140,9 @@
 #define CONF_FLAGS_CRYPTLINK            0x00400000
 #define CONF_FLAGS_VHOSTED		0x00800000
 #define CONF_FLAGS_TB			0x01000000
+
+#define CONF_FLAGS_IPMASK		0x02000000
+#define CONF_FLAGS_MASK_NOTICE	0x04000000
 /* Macros for struct ConfItem */
 
 #define IsLimitIp(x)            ((x)->flags & CONF_FLAGS_LIMIT_IP)
@@ -162,6 +165,8 @@
 #define IsConfCryptLink(x)      ((x)->flags & CONF_FLAGS_CRYPTLINK)
 #define IsConfVhosted(x)	((x)->flags & CONF_FLAGS_VHOSTED)
 #define IsConfTburst(x)		((x)->flags & CONF_FLAGS_TB)
+#define IsConfDoMaskIp(x)		((x)->flags & CONF_FLAGS_IPMASK)
+#define IsConfMaskNotice(x)		((x)->flags & CONF_FLAGS_MASK_NOTICE)
 
 /* flag definitions for opers now in client.h */
 
diff -uNrd ircd-ratbox-1.4-2/include/s_serv.h ircd-ratbox-1.4-2+ipmask/include/s_serv.h
--- ircd-ratbox-1.4-2/include/s_serv.h	Sun Apr 11 19:08:13 2004
+++ ircd-ratbox-1.4-2+ipmask/include/s_serv.h	Sun May  9 17:29:56 2004
@@ -72,12 +72,13 @@
 #define CAP_UNKLN       0x00100000	/* supports remote unkline */
 #define CAP_CLUSTER	0x00200000	/* supports clustering */
 #define CAP_ENCAP	0x00400000
+#define CAP_IPMASK      0x00800000
 
 #define CAP_MASK        (CAP_QS  | CAP_EX   | CAP_CHW  | \
                          CAP_IE  | CAP_KLN  | \
                          CAP_GLN | CAP_CLUSTER | CAP_ENCAP | \
                          CAP_ZIP  | CAP_ENC | \
-                         CAP_KNOCK  | CAP_UNKLN)
+                         CAP_KNOCK  | CAP_UNKLN | CAP_IPMASK)
 
 #ifdef HAVE_LIBZ
 #define CAP_ZIP_SUPPORTED       CAP_ZIP
diff -uNrd ircd-ratbox-1.4-2/include/s_user.h ircd-ratbox-1.4-2+ipmask/include/s_user.h
--- ircd-ratbox-1.4-2/include/s_user.h	Sun Mar 28 04:45:14 2004
+++ ircd-ratbox-1.4-2+ipmask/include/s_user.h	Sun May  9 17:28:16 2004
@@ -44,7 +44,7 @@
 extern int do_local_user(char *, struct Client *, struct Client *, char *, char *, char *, char *);
 
 extern int do_remote_user(char *, struct Client *, struct Client *,
-			  char *, char *, char *, char *);
+			  char *, char *, char *, char *, char *);
 
 extern int user_modes_from_c_to_bitmask[];
 extern void show_isupport(struct Client *);
diff -uNrd ircd-ratbox-1.4-2/include/supported.h ircd-ratbox-1.4-2+ipmask/include/supported.h
--- ircd-ratbox-1.4-2/include/supported.h	Wed Apr 21 08:07:13 2004
+++ ircd-ratbox-1.4-2+ipmask/include/supported.h	Sun May  9 17:28:57 2004
@@ -65,7 +65,8 @@
 		  " ETRACE" \
 		  " WALLCHOPS" \
 		  " SAFELIST" \
-		  " ELIST=U"
+		  " ELIST=U" \
+                  " IPMASK"
 
 #define FEATURES2VALUES ConfigServerHide.disable_local_channels ? "#" : "#&", \
                         ConfigChannel.use_except ? "e" : "", \
diff -uNrd ircd-ratbox-1.4-2/include/whowas.h ircd-ratbox-1.4-2+ipmask/include/whowas.h
--- ircd-ratbox-1.4-2/include/whowas.h	Mon Mar 15 11:19:45 2004
+++ ircd-ratbox-1.4-2+ipmask/include/whowas.h	Sun May  9 17:28:16 2004
@@ -51,6 +51,7 @@
 	char name[NICKLEN];
 	char username[USERLEN + 1];
 	char hostname[HOSTLEN + 1];
+	char rhostname[HOSTLEN + 1];
 	const char *servername;
 	char realname[REALLEN + 1];
 	time_t logoff;
diff -uNrd ircd-ratbox-1.4-2/modules/Makefile.in ircd-ratbox-1.4-2+ipmask/modules/Makefile.in
--- ircd-ratbox-1.4-2/modules/Makefile.in	Sun Apr 11 19:08:15 2004
+++ ircd-ratbox-1.4-2+ipmask/modules/Makefile.in	Sun May  9 17:28:16 2004
@@ -86,6 +86,7 @@
   m_set.c \
   m_stats.c \
   m_svinfo.c \
+  m_svs.c \
   m_tb.c \
   m_testline.c \
   m_testmask.c \
diff -uNrd ircd-ratbox-1.4-2/modules/core/m_nick.c ircd-ratbox-1.4-2+ipmask/modules/core/m_nick.c
--- ircd-ratbox-1.4-2/modules/core/m_nick.c	Wed Mar 24 17:30:52 2004
+++ ircd-ratbox-1.4-2+ipmask/modules/core/m_nick.c	Sun May  9 17:28:16 2004
@@ -277,7 +277,7 @@
 	}
 
 	/* parc == 3 on nickchange, parc == 9 on new nick */
-	if((IsClient(source_p) && (parc != 3)) || (IsServer(source_p) && (parc != 9)))
+	if((IsClient(source_p) && (parc != 3)) || (IsServer(source_p) && ((parc != 9) && (parc != 10))))
 	{
 		char tbuf[BUFSIZE] = { 0 };
 		int j;
@@ -302,23 +302,30 @@
 	/* fix the length of the nick */
 	strlcpy(nick, parv[1], sizeof(nick));
 
-	if(check_clean_nick(client_p, source_p, nick, parv[1], 
-			    (parc == 9 ? parv[7] : (char *)source_p->user->server)))
-		return;
+    if ((parc == 9) || (parc == 10))
+	{
+		if (check_clean_nick(client_p, source_p, nick, parv[1], parv[7]))
+			return;
+	}
+	else
+	{
+		if (check_clean_nick(client_p, source_p, nick, parv[1], (char *)source_p->user->server))
+			return;
+	}
 
-	if(parc == 9)
+	if(parc == 9 || parc == 10)
 	{
 		if(check_clean_user(client_p, nick, parv[5], parv[7]) ||
 		   check_clean_host(client_p, nick, parv[6], parv[7]))
 			return;
 
 		/* check the length of the clients gecos */
-		if(strlen(parv[8]) > REALLEN)
+		if(strlen(parv[(parc > 9)? 9 : 8]) > REALLEN)
 		{
 			sendto_realops_flags(UMODE_ALL, L_ALL,
 					     "Long realname from server %s for %s", parv[7],
 					     parv[1]);
-			parv[8][REALLEN] = '\0';
+			parv[(parc > 9)? 9 : 8][REALLEN] = '\0';
 		}
 
 		if(IsServer(source_p))
@@ -591,7 +598,8 @@
 			}
 
 			return do_remote_user(nick, client_p, source_p, parv[5], parv[6],
-					      parv[7], parv[8]);
+					      parv[7], (parc > 9)? parv[8] : NULL,
+						parv[(parc > 9)? 9 : 8]);
 		}
 	}
 	else if(source_p->name[0])
diff -uNrd ircd-ratbox-1.4-2/modules/m_svs.c ircd-ratbox-1.4-2+ipmask/modules/m_svs.c
--- ircd-ratbox-1.4-2/modules/m_svs.c	Wed Dec 31 17:00:00 1969
+++ ircd-ratbox-1.4-2+ipmask/modules/m_svs.c	Sun May  9 17:28:16 2004
@@ -0,0 +1,243 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/example_module.c
+ *   Copyright (C) 2001 Hybrid Development Team
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id: m_svs.c,v 1.6 2003/11/05 18:29:47 jeremy Exp $
+ */
+
+/* List of ircd includes from ../include/ */
+#include "stdinc.h"
+#include "handlers.h"
+#include "client.h"
+#include "common.h"     /* FALSE bleah */
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "fdlist.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+
+#include "s_user.h"  /* send_umode_out() */
+#include "channel_mode.h" /* MODE_ADD & MOD_DEL */
+#include "hash.h"
+
+static void ms_svshost(struct Client *client_p, struct Client *source_p,
+                    int parc, char *parv[]);
+static void mo_svshost(struct Client *client_p, struct Client *source_p,
+                    int parc, char *parv[]);
+
+static void remove_host(struct Client *, char *);
+static void change_host(struct Client *, char *, char *);
+
+/* CHGHOST/SVSHOST/SETHOST */
+struct Message svshost_msgtab = {
+  "SVSHOST", 0, 0, 0, 0, MFLG_SLOW, 0,
+  {m_ignore, m_ignore, ms_svshost, m_ignore}
+};
+struct Message chghost_msgtab = {
+  "CHGHOST", 0, 0, 2, 3, MFLG_SLOW, 0,
+  {m_ignore, m_not_oper, m_ignore, mo_svshost}
+};
+struct Message sethost_msgtab = {
+  "SETHOST", 0, 0, 2, 3, MFLG_SLOW, 0,
+  {m_ignore, m_not_oper, m_ignore, mo_svshost}
+};
+
+#ifndef STATIC_MODULES
+/* Here we tell it what to do when the module is loaded */
+void
+_modinit(void)
+{
+  /* This will add the commands in test_msgtab (which is above) */
+  /* SVSHOST/CHGHOST/SETHOST */
+  mod_add_cmd(&svshost_msgtab);
+  mod_add_cmd(&chghost_msgtab);
+  mod_add_cmd(&sethost_msgtab);
+}
+
+/* here we tell it what to do when the module is unloaded */
+void
+_moddeinit(void)
+{
+  /* This will remove the commands in test_msgtab (which is above) */
+  /* SVSHOST/CHGHOST/SETHOST */
+  mod_del_cmd(&svshost_msgtab);
+  mod_del_cmd(&chghost_msgtab);
+  mod_del_cmd(&sethost_msgtab);
+}
+
+/* When we last modified the file (shown in /modlist), this is usually:
+ */
+const char *_version = "$Revision: 1.6 $";
+#endif
+
+/*
+ * mo_svshost
+ *      parv[0] = sender prefix
+ *      parv[1] = target nickname
+ *      parv[2] = new hostname
+ */
+static void mo_svshost(struct Client *client_p, struct Client *source_p,
+                   int parc, char *parv[])
+{
+  struct Client *target_p;
+  char *nick, hostname[HOSTLEN+1];
+  int remove = 0;
+
+  nick = parv[1];
+
+  if(parc > 2)
+    strlcpy(hostname, parv[2], HOSTLEN);
+
+  if(!isalpha(nick[0]))
+    if(nick[0] == '-')
+      remove = 1;
+
+  if(remove > 0)
+    {
+      nick++;
+      remove_host(source_p, nick);
+    }
+  else
+    {
+      if (parc != 3)
+        {
+          sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "CHGHOST");
+          return;
+        }
+      change_host(source_p, nick, (hostname)? hostname : NULL);
+    }
+
+  return;
+}
+
+static void remove_host(struct Client *source_p, char *nick)
+{
+  struct Client *target_p;
+
+  if ((target_p = find_client(nick)) == NULL)
+    {
+      sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, target_p->name);
+      return;
+    }
+
+  strcpy(target_p->host, target_p->rhost);
+
+  sendto_one(source_p, "Reset %s's Host", target_p->name);
+  return;
+}
+
+static void change_host(struct Client *source_p, char *nick, char *host)
+{
+  struct Client *target_p;
+  char oldhost[HOSTLEN+1];
+  int setflags;
+
+  if ((target_p = find_client(nick)) == NULL)
+    {
+      sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, nick);
+      return;
+    }
+
+  /* check at this point for a valid hostname, and if its null
+     which it shouldn't be at this point */
+  if (!valid_hostname(host) || (host == NULL) || (strlen(host) > HOSTLEN))
+    {
+      sendto_one(source_p, "%s :Invalid Hostname", host);
+      return;
+    }
+
+  if(!strchr(host, '.') && !strchr(host, ':'))
+    {
+      sendto_one(source_p, "Hostname's must contain one . or :");
+      return;
+    }
+
+  /* Preserve the old hostname until we are finished */
+  strcpy(oldhost, target_p->host);
+
+  /* Prevent any unnecessary bursts */
+  if(!strcmp(oldhost, host))
+    {
+      sendto_one(source_p, "%s :Hostname Identical", host);
+      return;
+    }
+
+  if(MyClient(target_p) && IsMasked(target_p))
+    {
+      setflags = target_p->umodes;
+      target_p->umodes &= ~UMODE_IPMASK;
+      send_umode_out(target_p, target_p, setflags);
+    }
+
+  strcpy(target_p->host, host);
+  sendto_realops_flags(UMODE_ALL, L_ALL, "CHGHOST was used on %s (%s -> %s)", nick, oldhost, host);
+  ilog(L_NOTICE, "%s changed %s's hostname (%s -> %s)", source_p->name, nick, oldhost, host);
+  sendto_server(NULL, NULL, CAP_IPMASK, NOCAPS, ":%s SVSHOST %s %s %s", source_p->name, target_p->name, oldhost, host);
+
+  sendto_one(source_p, "Changed %s's Host (%s -> %s)", nick, oldhost, host);
+  return;
+}
+
+/*
+ * ms_svshost
+ *      parv[0] = sender prefix
+ *      parv[1] = target nickname
+ *      parv[2] = new hostname
+ */
+static void ms_svshost(struct Client *client_p, struct Client *source_p,
+                   int parc, char *parv[])
+{
+  struct Client *target_p;
+  char *nick;
+  int setflags;
+  nick = parv[1];
+
+  if (parc != 4)
+    return;
+
+  sendto_server(client_p, NULL, CAP_IPMASK, NOCAPS, ":%s SVSHOST %s %s %s", parv[0], parv[1], parv[2], parv[3]);
+
+  target_p = find_client(nick);  
+  strcpy(target_p->host, parv[3]);
+
+  if(!IsServer(client_p))
+    {
+      sendto_realops_flags(UMODE_ALL, L_ALL, "CHGHOST was used on %s (%s -> %s)", nick, parv[2], parv[3]);
+      ilog(L_NOTICE, "%s changed %s's hostname (%s -> %s)", parv[0], nick, parv[2], parv[3]);
+    }
+  else
+    {
+      /* Changing the host on a masked user?
+         if so pull +X */
+      if(MyClient(target_p) && IsMasked(target_p))
+        {
+          setflags = target_p->umodes;
+          target_p->umodes &= ~UMODE_IPMASK;
+          send_umode_out(target_p, target_p, setflags);
+        }
+      ilog(L_NOTICE, "Caught SVSHOST from server [%s], Possibly a change of UMODE_ISMASK", parv[0]);
+    }
+
+  return;
+}
diff -uNrd ircd-ratbox-1.4-2/modules/m_whois.c ircd-ratbox-1.4-2+ipmask/modules/m_whois.c
--- ircd-ratbox-1.4-2/modules/m_whois.c	Sun Apr  4 05:44:55 2004
+++ ircd-ratbox-1.4-2+ipmask/modules/m_whois.c	Sun May  9 17:28:16 2004
@@ -303,6 +303,9 @@
 		   target_p->username, target_p->host, target_p->info);
 	server_name = (char *) target_p->user->server;
 
+  if((IsOper(source_p)) || (source_p == target_p))
+    sendto_one(source_p, form_str(RPL_WHOISHOST), me.name, source_p->name, target_p->name, target_p->rhost);
+
 	cur_len = mlen = ircsprintf(buf, form_str(RPL_WHOISCHANNELS), me.name, source_p->name, target_p->name);
 	t = buf + mlen;
 
diff -uNrd ircd-ratbox-1.4-2/modules/m_whowas.c ircd-ratbox-1.4-2+ipmask/modules/m_whowas.c
--- ircd-ratbox-1.4-2/modules/m_whowas.c	Mon Mar 15 11:19:50 2004
+++ ircd-ratbox-1.4-2+ipmask/modules/m_whowas.c	Sun May  9 17:28:16 2004
@@ -154,6 +154,10 @@
 				sendto_one(source_p, form_str(RPL_WHOISSERVER),
 					   me.name, parv[0], temp->name,
 					   temp->servername, myctime(temp->logoff));
+
+          if(IsOper(source_p))
+            sendto_one(source_p, form_str(RPL_WHOWASREALHOST), me.name, parv[0], temp->name, temp->hostname, temp->rhostname);
+
 			cur++;
 			found++;
 		}
diff -uNrd ircd-ratbox-1.4-2/src/Makefile.in ircd-ratbox-1.4-2+ipmask/src/Makefile.in
--- ircd-ratbox-1.4-2/src/Makefile.in	Wed Mar 24 17:30:54 2004
+++ ircd-ratbox-1.4-2+ipmask/src/Makefile.in	Sun May  9 17:40:47 2004
@@ -69,6 +69,8 @@
   hash.c                        \
   hook.c                        \
   hostmask.c                    \
+  hostmasking.c			\
+  ipmask.c			\
   irc_string.c                  \
   ircd.c                        \
   ircd_signal.c                 \
diff -uNrd ircd-ratbox-1.4-2/src/channel.c ircd-ratbox-1.4-2+ipmask/src/channel.c
--- ircd-ratbox-1.4-2/src/channel.c	Mon Apr 26 10:47:43 2004
+++ ircd-ratbox-1.4-2+ipmask/src/channel.c	Sun May  9 17:38:26 2004
@@ -57,7 +57,7 @@
 static BlockHeap *member_heap;
 
 static void send_mode_list(struct Client *client_p, char *chname, dlink_list * top, char flag);
-static int check_banned(struct Channel *chptr, struct Client *who, char *s, char *s2);
+static int check_banned(struct Channel *chptr, struct Client *who, char *s, char *s2, char *s3);
 
 static char buf[BUFSIZE];
 static char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
@@ -652,14 +652,16 @@
 {
 	char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
 	char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
+	char src_rhost[NICKLEN + USERLEN + HOSTLEN + 6];
 
 	if(!IsPerson(who))
 		return (0);
 
 	ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
 	ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->localClient->sockhost);
+	ircsprintf(src_rhost, "%s!%s@%s", who->name, who->username, who->rhost);
 
-	return (check_banned(chptr, who, src_host, src_iphost));
+	return (check_banned(chptr, who, src_host, src_iphost, src_rhost));
 }
 
 /*
@@ -678,7 +680,7 @@
  * +e code from orabidoo
  */
 static int
-check_banned(struct Channel *chptr, struct Client *who, char *s, char *s2)
+check_banned(struct Channel *chptr, struct Client *who, char *s, char *s2, char *s3)
 {
 	dlink_node *ban;
 	dlink_node *except;
@@ -689,7 +691,8 @@
 	{
 		actualBan = ban->data;
 		if(match(actualBan->banstr, s) ||
-		   match(actualBan->banstr, s2) || match_cidr(actualBan->banstr, s2))
+		   match(actualBan->banstr, s2) || match_cidr(actualBan->banstr, s2) ||
+                   match(actualBan->banstr, s3))
 			break;
 		else
 			actualBan = NULL;
@@ -702,7 +705,8 @@
 			actualExcept = except->data;
 
 			if(match(actualExcept->banstr, s) ||
-			   match(actualExcept->banstr, s2) || match_cidr(actualExcept->banstr, s2))
+			   match(actualExcept->banstr, s2) || match_cidr(actualExcept->banstr, s2) ||
+                           match(actualExcept->banstr, s3))
 			{
 				return CHFL_EXCEPTION;
 			}
@@ -728,15 +732,17 @@
 	dlink_node *ptr;
 	struct Ban *invex = NULL;
 	char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
+	char src_rhost[NICKLEN + USERLEN + HOSTLEN + 6];
 	char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
 
 	s_assert(source_p->localClient != NULL);
 
 	ircsprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
+	ircsprintf(src_rhost, "%s!%s@%s", source_p->name, source_p->username, source_p->rhost);
 	ircsprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username,
 		   source_p->localClient->sockhost);
 
-	if((check_banned(chptr, source_p, src_host, src_iphost)) == CHFL_BAN)
+	if((check_banned(chptr, source_p, src_host, src_iphost, src_rhost)) == CHFL_BAN)
 		return (ERR_BANNEDFROMCHAN);
 
 	if(chptr->mode.mode & MODE_INVITEONLY)
diff -uNrd ircd-ratbox-1.4-2/src/client.c ircd-ratbox-1.4-2+ipmask/src/client.c
--- ircd-ratbox-1.4-2/src/client.c	Wed Mar 24 17:30:54 2004
+++ ircd-ratbox-1.4-2+ipmask/src/client.c	Sun May  9 17:28:16 2004
@@ -1541,7 +1541,7 @@
 		if(IsPerson(source_p))
 			sendto_realops_flags(UMODE_CCONN, L_ALL,
 					     "Client exiting: %s (%s@%s) [%s] [%s]",
-					     source_p->name, source_p->username, source_p->host,
+					     source_p->name, source_p->username, source_p->rhost,
 					     comment,
 #ifdef HIDE_SPOOF_IPS
 					     IsIPSpoof(source_p) ? "255.255.255.255" :
diff -uNrd ircd-ratbox-1.4-2/src/hostmask.c ircd-ratbox-1.4-2+ipmask/src/hostmask.c
--- ircd-ratbox-1.4-2/src/hostmask.c	Tue Mar 23 10:35:54 2004
+++ ircd-ratbox-1.4-2+ipmask/src/hostmask.c	Sun May  9 17:28:16 2004
@@ -454,6 +454,9 @@
 	aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
 				     CONF_KILL, client_p->localClient->aftype, client_p->username);
 
+	if (!aconf)
+		aconf = find_conf_by_address(client_p->rhost, &client_p->localClient->ip, CONF_KILL, client_p->localClient->aftype, client_p->username);
+
 	return aconf;
 }
 
@@ -470,6 +473,9 @@
 
 	aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
 				     CONF_GLINE, client_p->localClient->aftype, client_p->username);
+
+	if (!aconf)
+		aconf = find_conf_by_address(client_p->rhost, &client_p->localClient->ip, CONF_GLINE, client_p->localClient->aftype, client_p->username);
 
 	return aconf;
 }
diff -uNrd ircd-ratbox-1.4-2/src/hostmasking.c ircd-ratbox-1.4-2+ipmask/src/hostmasking.c
--- ircd-ratbox-1.4-2/src/hostmasking.c	Wed Dec 31 17:00:00 1969
+++ ircd-ratbox-1.4-2+ipmask/src/hostmasking.c	Sun May  9 17:35:04 2004
@@ -0,0 +1,229 @@
+/*
+ *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *  hostmasking.c: IP Masking routines.
+ *
+ *  Obtained from Greg (Siracide) <sharpen@wanadoo.fr>
+ *  Modified by J. Johnston
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *  USA
+ *
+ *  $Id: ipmask.c,v 1.2 2003/10/20 06:30:42 ircd Exp $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "s_user.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "fdlist.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "listener.h"
+#include "motd.h"
+#include "ircd_handler.h"
+#include "msg.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "s_stats.h"
+#include "scache.h"
+#include "send.h"
+#include "supported.h"
+#include "whowas.h"
+#include "memory.h"
+#include "packet.h"
+
+/* Hidden host code below */
+
+#define KEY 23857
+#define KEY2 38447
+#define KEY3 64709
+
+int str2arr (char **, char *, char *);
+
+static unsigned long crc32_tab[] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+unsigned long
+crc32 (const unsigned char *s, unsigned int len)
+{
+  unsigned int i;
+  unsigned long crc32val;
+
+  crc32val = 0;
+  for (i = 0; i < len; i++)
+    {
+      crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+    }
+  return crc32val;
+}
+
+int
+str2arr (char **pparv, char *string, char *delim)
+{
+  char *tok;
+  int pparc = 0;
+
+  tok = (char *) strtok (string, delim);
+  while (tok != NULL)
+    {
+      pparv[pparc++] = tok;
+      tok = (char *) strtok (NULL, delim);
+    }
+
+  return pparc;
+}
+
+/* Regular user host */
+void
+make_virthost (char *curr, char *host, char *new)
+{
+  static char mask[HOSTLEN + 1];
+  char *parv[HOSTLEN + 1], *parv2[HOSTLEN + 1], s[HOSTLEN + 1],
+    s2[HOSTLEN + 2];
+  int parc = 0, parc2 = 0, len = 0;
+  unsigned long hash[8];
+
+
+  /* Paranoia. curr & host are pointers */
+  strncpy (s, curr, HOSTLEN);
+  strncpy (s2, host, HOSTLEN);
+
+  parc = str2arr (parv, s, ".");
+  parc2 = str2arr (parv2, s2, ".");
+
+  if (parc2 < 2)
+	return;
+
+  if ((curr == NULL) || (host == NULL))
+	return;
+
+  /* crc32 and hashing using our 3 keys */
+  hash[0] = ((crc32 (parv[3], strlen (parv[3])) + KEY2) ^ KEY) ^ KEY3;
+  hash[1] = ((crc32 (parv[2], strlen (parv[2])) + KEY2) ^ KEY) ^ KEY3;
+
+
+  /* Why make life easy on crackers? Bitshifting */
+  hash[0] <<= 2;
+  hash[0] >>= 2;
+
+  hash[1] <<= 2;
+  hash[1] >>= 2;
+
+  /* Check if host could be IPv4 */
+  if (parc2 == 4)
+    {
+      len = strlen (parv2[3]);
+      /* Check if its an IPv4 for sure */
+      if (strchr ("0123456789", parv2[3][len - 1]))
+	{
+	  hash[2] = ((crc32 (parv[1], strlen (parv[1])) + KEY2) ^ KEY) ^ KEY3;
+	  hash[3] = ((crc32 (parv[0], strlen (parv[0])) + KEY2) ^ KEY) ^ KEY3;
+
+	  hash[2] <<= 2;
+	  hash[2] >>= 2;
+
+	  hash[3] <<= 2;
+	  hash[3] >>= 2;
+
+          ircsprintf (mask, "%s-%lu.%s",
+                   ServerInfo.network_name, hash[3], "IP");
+	}
+      else
+	{
+	  ircsprintf (mask, "%s-%lu.%s.%s",
+		   ServerInfo.network_name, hash[0], parv2[parc2 - 2], parv2[parc2 - 1]);
+	}
+    }
+  else
+    {
+      if (parc2 >= 4) /* There are isp's like *.isp.co.uk etc out there */
+	{
+	  ircsprintf (mask, "%s-%lu.%s.%s",
+		   ServerInfo.network_name, hash[0], parv2[parc2 - 2], parv2[parc2 - 1]);
+	}
+      else
+	{
+	  ircsprintf (mask, "%s-%lu.%s.%s",
+		   ServerInfo.network_name, hash[0], parv2[parc2 - 2], parv2[parc2 - 1]);
+	}
+    }
+  strncpy (new, mask, HOSTLEN);
+  return;
+}
diff -uNrd ircd-ratbox-1.4-2/src/ipmask.c ircd-ratbox-1.4-2+ipmask/src/ipmask.c
--- ircd-ratbox-1.4-2/src/ipmask.c	Wed Dec 31 17:00:00 1969
+++ ircd-ratbox-1.4-2+ipmask/src/ipmask.c	Sun May  9 17:35:49 2004
@@ -0,0 +1,68 @@
+/*
+ *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
+ *  FreeWorld-ircd:
+ *  ipmask.c: IP Masking routines.
+ *
+ *  Copyright (C) 2002 by the past and present ircd coders, and others.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *  USA
+ *
+ *  $Id: ipmask.c,v 1.2 2003/10/20 06:30:42 ircd Exp $
+ */
+
+#include "stdinc.h"
+#include "tools.h"
+#include "s_user.h"
+#include "channel.h"
+#include "channel_mode.h"
+#include "class.h"
+#include "client.h"
+#include "common.h"
+#include "fdlist.h"
+#include "hash.h"
+#include "irc_string.h"
+#include "sprintf_irc.h"
+#include "ircd.h"
+#include "listener.h"
+#include "motd.h"
+#include "ircd_handler.h"
+#include "msg.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "s_stats.h"
+#include "scache.h"
+#include "send.h"
+#include "supported.h"
+#include "whowas.h"
+#include "memory.h"
+#include "packet.h"
+
+char *ret_maskip(struct Client *client_p)
+{
+        static char rmask[HOSTLEN];
+
+        rmask[0] = '\0';
+
+	make_virthost (client_p->localClient->sockhost, client_p->host, rmask);
+
+	if (rmask[0] != '\0')
+		return rmask;
+	else
+		return client_p->rhost;
+}
diff -uNrd ircd-ratbox-1.4-2/src/messages.tab ircd-ratbox-1.4-2+ipmask/src/messages.tab
--- ircd-ratbox-1.4-2/src/messages.tab	Mon Apr  5 12:22:56 2004
+++ ircd-ratbox-1.4-2+ipmask/src/messages.tab	Sun May  9 17:28:16 2004
@@ -24,7 +24,7 @@
 /* 001  RPL_WELCOME, */ ":%s 001 %s :Welcome to the %s Internet Relay Chat Network %s",
 /* 002  RPL_YOURHOST,*/ ":%s 002 %s :Your host is %s, running version %s",
 /* 003  RPL_CREATED, */ ":%s 003 %s :This server was created %s",
-/* 004  RPL_MYINFO, */ ":%s 004 %s %s %s oiwszcerkfydnxbauglZ biklmnopstveI bkloveI",
+/* 004  RPL_MYINFO, */ ":%s 004 %s %s %s oiwszcerkfydnxbauglZX biklmnopstveI bkloveI",
 /* 005  RPL_ISUPPORT, */ ":%s 005 %s %s :are supported by this server",
 /* 006 */       NULL,
 /* 007 */       NULL,
@@ -394,7 +394,7 @@
 /* 367 RPL_BANLIST, */          ":%s 367 %s %s %s %s %lu",
 /* 368 RPL_ENDOFBANLIST, */     ":%s 368 %s %s :End of Channel Ban List",
 /* 369 RPL_ENDOFWHOWAS, */      ":%s 369 %s %s :End of WHOWAS",
-/* 370 */       NULL,
+/* 370 RPL_WHOWASREALHOST, */   ":%s 370 %s :%s was connected from *@%s [%s]", 
 /* 371 RPL_INFO, */             ":%s 371 %s :%s",
 /* 372 RPL_MOTD, */             ":%s 372 %s :- %s",
 /* 373 RPL_INFOSTART, */        ":%s 373 %s :Server INFO",
@@ -402,7 +402,7 @@
 /* 375 RPL_MOTDSTART, */        ":%s 375 %s :- %s Message of the Day - ",
 /* 376 RPL_ENDOFMOTD, */        ":%s 376 %s :End of /MOTD command.",
 /* 377 */       NULL,
-/* 378 */       NULL,
+/* 378 RPL_WHOISHOST */         ":%s 378 %s :%s is connected from *@%s",
 /* 379 */       NULL,
 /* 380 */       NULL,
 /* 381 RPL_YOUREOPER, */        ":%s 381 %s :You have entered... the Vanity Zone!.",
diff -uNrd ircd-ratbox-1.4-2/src/newconf.c ircd-ratbox-1.4-2+ipmask/src/newconf.c
--- ircd-ratbox-1.4-2/src/newconf.c	Wed Apr  7 13:37:50 2004
+++ ircd-ratbox-1.4-2+ipmask/src/newconf.c	Sun May  9 17:28:16 2004
@@ -112,6 +112,8 @@
 	{"restricted", CONF_FLAGS_RESTRICTED},
 	{"need_ident", CONF_FLAGS_NEED_IDENTD},
 	{"have_ident", CONF_FLAGS_NEED_IDENTD},
+	{"mask", CONF_FLAGS_IPMASK},
+	{"mask_notice", CONF_FLAGS_MASK_NOTICE},
 	{NULL}
 };
 
@@ -1412,6 +1414,28 @@
 	DupString(yy_achead->className, data);
 }
 
+static void
+conf_set_auth_mask(void *data)
+{
+	int yesno = *(unsigned int *) data;
+
+	if (yesno)
+		yy_achead->flags |= CONF_FLAGS_IPMASK;
+	else
+		yy_achead->flags &= ~CONF_FLAGS_IPMASK;
+}
+
+static void
+conf_set_auth_mask_notice (void *data)
+{
+	int yesno = *(unsigned int *) data;
+
+	if (yesno)
+		yy_achead->flags |= CONF_FLAGS_MASK_NOTICE;
+	else
+		yy_achead->flags &= ~CONF_FLAGS_MASK_NOTICE;
+}
+
 static int
 conf_begin_resv(struct TopConf *tc)
 {
@@ -3066,6 +3090,8 @@
 	add_conf_item("auth", "flood_exempt", CF_YESNO, conf_set_auth_flood_exempt);
 	add_conf_item("auth", "redirserv", CF_QSTRING, conf_set_auth_redir_serv);
 	add_conf_item("auth", "redirport", CF_INT, conf_set_auth_redir_port);
+	add_conf_item("auth", "mask", CF_YESNO, conf_set_auth_mask);
+	add_conf_item("auth", "mask_notice", CF_YESNO, conf_set_auth_mask_notice);
 	add_conf_item("auth", "flags", CF_STRING | CF_FLIST, conf_set_auth_flags);
 
 	add_top_conf("resv", conf_begin_resv, conf_end_resv);
diff -uNrd ircd-ratbox-1.4-2/src/s_conf.c ircd-ratbox-1.4-2+ipmask/src/s_conf.c
--- ircd-ratbox-1.4-2/src/s_conf.c	Thu Apr 22 11:42:06 2004
+++ ircd-ratbox-1.4-2+ipmask/src/s_conf.c	Sun May  9 17:28:16 2004
@@ -56,6 +56,7 @@
 #include "patricia.h"
 #include "reject.h"
 
+char *ret_maskip(struct Client *);
 
 struct config_server_hide ConfigServerHide;
 
@@ -534,6 +535,16 @@
 			SetNeedId(client_p);
 		if(IsConfRestricted(aconf))
 			SetRestricted(client_p);
+
+
+		strlcpy (client_p->rhost, client_p->host, sizeof(client_p->rhost));
+		if(IsConfDoMaskIp(aconf))
+		{
+			strcpy (client_p->host, ret_maskip(client_p));
+			client_p->umodes |= UMODE_IPMASK;
+			if(IsConfMaskNotice(aconf))
+				sendto_realops_flags (UMODE_ALL, L_ALL, "%s masking: %s as %s", client_p->name, client_p->rhost, client_p->host);
+		}
 
 		/* Thanks for spoof idea amm */
 		if(IsConfDoSpoofIp(aconf))
diff -uNrd ircd-ratbox-1.4-2/src/s_serv.c ircd-ratbox-1.4-2+ipmask/src/s_serv.c
--- ircd-ratbox-1.4-2/src/s_serv.c	Sun Apr 11 19:08:18 2004
+++ ircd-ratbox-1.4-2+ipmask/src/s_serv.c	Sun May  9 17:28:16 2004
@@ -95,6 +95,7 @@
 	{ "UNKLN",	CAP_UNKLN },
 	{ "CLUSTER",	CAP_CLUSTER },
 	{ "ENCAP",	CAP_ENCAP },
+	{ "IPMASK", CAP_IPMASK },
 	{ 0, 		0 }
 };
 
@@ -790,13 +791,15 @@
 		ubuf[1] = '\0';
 	}
 
-		sendto_one(client_p, "NICK %s %d %lu %s %s %s %s :%s",
+		sendto_one(client_p, "NICK %s %d %lu %s %s %s %s %s :%s",
 			   target_p->name,
 			   target_p->hopcount + 1,
 			   (unsigned long) target_p->tsinfo,
 			   ubuf,
 			   target_p->username, target_p->host,
-			   target_p->user->server, target_p->info);
+			   target_p->user->server,
+			   IsCapable (client_p, CAP_IPMASK)? target_p->rhost : "", target_p->info);
+
 }
 
 /*
diff -uNrd ircd-ratbox-1.4-2/src/s_user.c ircd-ratbox-1.4-2+ipmask/src/s_user.c
--- ircd-ratbox-1.4-2/src/s_user.c	Fri Apr  2 08:51:02 2004
+++ ircd-ratbox-1.4-2+ipmask/src/s_user.c	Sun May  9 17:28:16 2004
@@ -54,11 +54,13 @@
 #include "memory.h"
 #include "packet.h"
 #include "reject.h"
+#include "hostmask.h"
 
 static void report_and_set_user_flags(struct Client *, struct ConfItem *);
 static int check_X_line(struct Client *client_p, struct Client *source_p);
 void user_welcome(struct Client *source_p);
 int oper_up(struct Client *source_p, struct ConfItem *aconf);
+char *ret_maskip(struct Client *);
 
 extern char *crypt();
 
@@ -88,6 +90,7 @@
 	{UMODE_UNAUTH, 'u'},
 	{UMODE_WALLOP, 'w'},
 	{UMODE_EXTERNAL, 'x'},
+    {UMODE_IPMASK, 'X'},
 	{UMODE_SPY, 'y'},
 	{UMODE_OPERWALL, 'z'},
 	{UMODE_OPERSPY, 'Z'},
@@ -462,7 +465,7 @@
 		 ipaddr, HOSTIPLEN);
 	sendto_realops_flags(UMODE_CCONN, L_ALL,
 			     "Client connecting: %s (%s@%s) [%s] {%s} [%s]",
-			     nick, source_p->username, source_p->host,
+			     nick, source_p->username, source_p->rhost,
 #ifdef HIDE_SPOOF_IPS
 			     IsIPSpoof(source_p) ? "255.255.255.255" :
 #endif
@@ -608,13 +611,21 @@
 		ubuf[1] = '\0';
 	}
 
-	sendto_server(client_p, NULL, NOCAPS, NOCAPS,
+	sendto_server(client_p, NULL, NOCAPS, CAP_IPMASK,
 		      "NICK %s %d %lu %s %s %s %s :%s",
 		      nick, source_p->hopcount + 1, 
 		      (unsigned long) source_p->tsinfo, ubuf, 
 		      source_p->username, source_p->host, user->server,
 		      source_p->info);
 
+    sendto_server(client_p, NULL, CAP_IPMASK, NOCAPS,
+              "NICK %s %d %lu %s %s %s %s %s :%s",
+              nick, source_p->hopcount + 1,
+              (unsigned long) source_p->tsinfo, ubuf,
+              source_p->username, source_p->host, user->server,
+			  source_p->rhost,
+              source_p->info);
+
 	return 0;
 }
 
@@ -841,7 +852,7 @@
  */
 int
 do_remote_user(char *nick, struct Client *client_p, struct Client *source_p,
-	       char *username, char *host, char *server, char *realname)
+	       char *username, char *host, char *server, char *rhost, char *realname)
 {
 	unsigned int oflags;
 	struct User *user;
@@ -862,6 +873,11 @@
 	strlcpy(source_p->host, host, sizeof(source_p->host));
 	strlcpy(source_p->info, realname, sizeof(source_p->info));
 
+	if(rhost)
+		strlcpy(source_p->rhost, rhost, sizeof(source_p->rhost));
+	else
+		strlcpy(source_p->rhost, "unavailable", sizeof(source_p->rhost));
+
 	return register_remote_user(client_p, source_p, source_p->name, username);
 }
 
@@ -882,7 +898,8 @@
 	struct Client *target_p;
 	int what, setflags;
 	int badflag = NO;	/* Only send one bad flag notice */
-	char buf[BUFSIZE];
+	char buf[BUFSIZE], oldhost[HOSTLEN];
+	struct ConfItem* aconf;
 
 	what = MODE_ADD;
 
@@ -984,6 +1001,47 @@
 					}
 				}
 				break;
+
+				case 'X':
+				if (MyClient(source_p))
+				{
+					aconf = find_address_conf (source_p->rhost, source_p->username, &source_p->localClient->ip, source_p->localClient->aftype);
+
+					strcpy (oldhost, source_p->host);
+
+					if(what == MODE_ADD)
+					{
+						if(IsConfDoSpoofIp(aconf))
+						{
+							source_p->umodes &= ~UMODE_IPMASK;
+							break;
+						}
+
+						if(IsMasked(source_p))
+						{
+							if(!strcmp(ret_maskip(source_p), source_p->host))
+								break;
+
+							source_p->umodes |= UMODE_IPMASK;
+							strcpy(source_p->host, ret_maskip(source_p));
+						}
+
+						source_p->umodes |= UMODE_IPMASK;
+						strcpy(source_p->host, ret_maskip(source_p));
+					}
+
+					if(what == MODE_DEL)
+					{
+						if(!IsMasked(source_p))
+							break;
+
+						source_p->umodes &= ~UMODE_IPMASK;
+						strcpy(source_p->host, source_p->rhost);
+					}
+
+					sendto_server (NULL, NULL, CAP_IPMASK, NOCAPS, ":%s SVSHOST %s %s %s", me.name, source_p->name, oldhost, source_p->host);
+			}
+			break;
 
 			case 'p':
 				if (MyConnect(source_p))
diff -uNrd ircd-ratbox-1.4-2/src/version.c.SH ircd-ratbox-1.4-2+ipmask/src/version.c.SH
--- ircd-ratbox-1.4-2/src/version.c.SH	Sun Jul  6 08:01:03 2003
+++ ircd-ratbox-1.4-2+ipmask/src/version.c.SH	Sun May  9 17:39:51 2004
@@ -52,10 +52,12 @@
 #include "patchlevel.h"
 #include "serno.h"
 
+#define PATCHVER PATCHLEVEL "+ipmask-1.4-crc"
+
 const char *generation = "$generation";
 const char *creation = "$creation";
 const char *platform = "$uname";
-const char *ircd_version = PATCHLEVEL;
+const char *ircd_version = PATCHVER;
 const char *serno = SERIALNUM;
 
 const char *infotext[] =
diff -uNrd ircd-ratbox-1.4-2/src/whowas.c ircd-ratbox-1.4-2+ipmask/src/whowas.c
--- ircd-ratbox-1.4-2/src/whowas.c	Mon Mar 15 11:19:57 2004
+++ ircd-ratbox-1.4-2+ipmask/src/whowas.c	Sun May  9 17:28:16 2004
@@ -88,6 +88,7 @@
 	strlcpy(who->name, client_p->name, sizeof(who->name));
 	strcpy(who->username, client_p->username);
 	strcpy(who->hostname, client_p->host);
+	strcpy(who->rhostname, client_p->rhost);
 	strcpy(who->realname, client_p->info);
 
 	who->servername = client_p->user->server;
