Index: doc/example.conf
===================================================================
RCS file: /home/coder-com/cvs/ircu2.10/doc/example.conf,v
retrieving revision 1.15.2.5
diff -b -u -d -r1.15.2.5 example.conf
--- doc/example.conf	2002/05/17 16:42:18	1.15.2.5
+++ doc/example.conf	2002/07/17 22:17:54
@@ -365,6 +365,30 @@
 # Y:10:90:0:100:160000
 
 
+# [S:lines]
+# Opers may wish to hide their IP mask and hostname, even if they are on
+# a bnc. This can prevent the risk of opers or their providers getting
+# dos'd or whatever the case may be.
+#
+# When a client connects, his or her IP is compared to the incoming_IP in 
+# each of the S:lines in the conf. If it finds an exact match (NOT a mask 
+# match, but a simple comparison), it will substitute the client's ip with 
+# modified_IP and the client's real hostname with modified_hostname (as 
+# shown below).
+#
+# Syntax:
+# S:<incoming_IP>:<modified_IP>:<modifed_hostname>
+#
+# Example:
+# S:193.178.138.13:192.168.128.1:undernet.org
+#
+# If a user connects to the server with the IP 193.178.138.13, it is
+# automatically changed to 192.168.128.1 and the user's host is set to
+# undernet.org.
+#
+# If no modified_IP is provided, only the host is modified.
+
+
 # [P:lines]
 # When your server gets more full, you will notice delays when trying to
 # connect to your server's primary listening port. It is possible via the
Index: include/client.h
===================================================================
RCS file: /home/coder-com/cvs/ircu2.10/include/client.h,v
retrieving revision 1.23.2.4
diff -b -u -d -r1.23.2.4 client.h
--- include/client.h	2002/07/17 21:07:01	1.23.2.4
+++ include/client.h	2002/07/17 22:17:56
@@ -370,6 +370,7 @@
 #define FLAGS_DOID      0x00040000      /* I-lines say must use ident return */
 #define FLAGS_NONL      0x00080000      /* No \n in buffer */
 #define FLAGS_TS8       0x00100000      /* Why do you want to know? */
+#define FLAGS_SLINE     0x00200000      /* User is S-lined */
 #define FLAGS_MAP       0x00800000      /* Show server on the map */
 #define FLAGS_JUNCTION  0x01000000      /* Junction causing the net.burst */
 #define FLAGS_DEAF      0x02000000      /* Makes user deaf */
@@ -414,6 +415,7 @@
 #define IsAccount(x)            (cli_flags(x) & FLAGS_ACCOUNT)
 #define IsHiddenHost(x)		(cli_flags(x) & FLAGS_HIDDENHOST)
 #define HasHiddenHost(x)	(IsAccount(x) && IsHiddenHost(x))
+#define HasSLine(x)             (cli_flags(x) & FLAGS_SLINE)
 
 #define IsPrivileged(x)         (IsAnOper(x) || IsServer(x))
 
@@ -436,6 +438,7 @@
 #define SetService(x)           (cli_flags(x) |= FLAGS_SERVICE)
 #define SetAccount(x)           (cli_flags(x) |= FLAGS_ACCOUNT)
 #define SetHiddenHost(x)	(cli_flags(x) |= FLAGS_HIDDENHOST)
+#define SetSLined(x)            (cli_flags(x) |= FLAGS_SLINE)
 
 #define ClearAccess(x)          (cli_flags(x) &= ~FLAGS_CHKACCESS)
 #define ClearBurst(x)           (cli_flags(x) &= ~FLAGS_BURST)
Index: include/s_conf.h
===================================================================
RCS file: /home/coder-com/cvs/ircu2.10/include/s_conf.h,v
retrieving revision 1.15.2.1
diff -b -u -d -r1.15.2.1 s_conf.h
--- include/s_conf.h	2002/05/17 16:42:19	1.15.2.1
+++ include/s_conf.h	2002/07/17 22:17:57
@@ -33,6 +33,7 @@
 
 #define CONF_ILLEGAL            0x80000000
 #define CONF_MATCH              0x40000000
+#define CONF_SPOOF              0x20000000
 #define CONF_CLIENT             0x0002
 #define CONF_SERVER             0x0004
 #define CONF_LOCOP              0x0010
Index: ircd/s_auth.c
===================================================================
RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_auth.c,v
retrieving revision 1.21.2.5
diff -b -u -d -r1.21.2.5 s_auth.c
--- ircd/s_auth.c	2002/07/10 16:22:47	1.21.2.5
+++ ircd/s_auth.c	2002/07/17 22:17:59
@@ -46,6 +46,7 @@
 #include "querycmds.h"
 #include "res.h"
 #include "s_bsd.h"
+#include "s_conf.h"
 #include "s_debug.h"
 #include "s_misc.h"
 #include "send.h"
@@ -82,6 +83,7 @@
   { "NOTICE AUTH :*** No ident response\r\n",              36 },
   { "NOTICE AUTH :*** Your forward and reverse DNS do not match, " \
     "ignoring hostname.\r\n",                              80 },
+  { "NOTICE AUTH :*** Using S-line privilege\r\n",         41 },
   { "NOTICE AUTH :*** Invalid hostname\r\n",               35 }
 };
 
@@ -94,6 +96,7 @@
   REPORT_FIN_ID,
   REPORT_FAIL_ID,
   REPORT_IP_MISMATCH,
+  REPORT_USING_SLINE,
   REPORT_INVAL_DNS
 } ReportType;
 
@@ -597,6 +600,13 @@
   struct AuthRequest* auth = 0;
 
   assert(0 != client);
+
+  if (conf_check_slines(client)) {
+    sendheader(client, REPORT_USING_SLINE);
+    SetSLined(client);
+    release_auth_client(client);
+    return;
+  }
 
   auth = make_auth_request(client);
   assert(0 != auth);
Index: ircd/s_conf.c
===================================================================
RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_conf.c,v
retrieving revision 1.44.2.3
diff -b -u -d -r1.44.2.3 s_conf.c
--- ircd/s_conf.c	2002/05/17 16:42:19	1.44.2.3
+++ ircd/s_conf.c	2002/07/17 22:18:03
@@ -1158,6 +1158,10 @@
       conf_add_quarantine(field_vector, field_count);
       aconf->status = CONF_ILLEGAL;
       break;
+    case 'S':
+    case 's':
+      aconf->status = CONF_SPOOF;
+      break;
     case 'T':                /* print out different motd's */
     case 't':                /* based on hostmask - CONF_TLINES */
       motd_add(field_vector[1], field_vector[2]);
@@ -1260,6 +1264,9 @@
     if ((aconf->status == CONF_UWORLD) && (aconf->passwd) && (*aconf->passwd))
       addNickJupes(aconf->passwd);
 
+    if (aconf->status & CONF_SPOOF)
+      lookup_confhost(aconf);
+
     collapse(aconf->host);
     collapse(aconf->name);
     Debug((DEBUG_NOTICE,
@@ -1625,6 +1632,70 @@
     c_conf->ipnum.s_addr = cli_ip(cptr).s_addr;
 
   Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", cli_name(cptr), cli_sockhost(cptr)));
+  return 0;
+}
+
+/*
+ * conf_check_slines()
+ *
+ * Check S lines for the specified client, passed in cptr struct.
+ * If the client's IP is S-lined, process the substitution here.
+ * 1. cptr->cli_ip                    (cli_ip(cptr))
+ * 2. cptr->cli_connect->con_sock_ip  (cli_sock_ip(cptr))
+ * 3. cptr->cli_connect->sockhost     (cli_sockhost(cptr))
+ *
+ * If no substitued IP are specified, only change sockhost.
+ *
+ * Precondition
+ *  cptr != NULL
+ *
+ * Returns
+ *  0 = No S-line found
+ *  1 = S-line found and substitution done.
+ *
+ * -mbuna 9/2001
+ *
+ */
+
+int
+conf_check_slines(struct Client *cptr)
+{
+  struct ConfItem* aconf;
+  struct in_addr iptemp;
+  char* hostonly;
+
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+    if (aconf->status != CONF_SPOOF)
+      continue;
+    if ((aconf->dns_pending)
+      || (INADDR_NONE == aconf->ipnum.s_addr)
+      || EmptyString(aconf->name))
+      continue;
+
+    if (cli_ip(cptr).s_addr == aconf->ipnum.s_addr) {
+
+                               /* Ignore user part if u@h. */
+      if ((hostonly = strchr(aconf->name, '@')))
+        hostonly++;
+      else
+        hostonly = aconf->name;
+
+      if(!*hostonly)
+        continue;
+
+      if (!EmptyString(aconf->passwd)) {
+        iptemp.s_addr = inet_addr(aconf->passwd);
+        if (INADDR_NONE == iptemp.s_addr)
+          continue;
+        cli_ip(cptr).s_addr = iptemp.s_addr;
+      }
+
+                               /* Perform a luxurious ircd_ntoa for sanity. */
+      ircd_strncpy(cli_sock_ip(cptr), ircd_ntoa((const char*) &cli_ip(cptr)), SOCKIPLEN);
+      ircd_strncpy(cli_sockhost(cptr), hostonly, HOSTLEN);
+      return 1;
+    }
+  }
   return 0;
 }
 
Index: ircd/s_user.c
===================================================================
RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_user.c,v
retrieving revision 1.52.2.10
diff -b -u -d -r1.52.2.10 s_user.c
--- ircd/s_user.c	2002/07/17 21:07:01	1.52.2.10
+++ ircd/s_user.c	2002/07/17 22:18:05
@@ -453,7 +453,8 @@
 
     clean_user_id(user->username,
         (cli_flags(sptr) & FLAGS_GOTID) ? cli_username(sptr) : username,
-        (cli_flags(sptr) & FLAGS_DOID) && !(cli_flags(sptr) & FLAGS_GOTID));
+        (cli_flags(sptr) & FLAGS_DOID) && !(cli_flags(sptr) & FLAGS_GOTID)
+        && !(HasSLine(sptr))); /* No tilde for S-lined users. */
 
     if ((user->username[0] == '\0')
         || ((user->username[0] == '~') && (user->username[1] == '\000')))
