CLEANUP: Replace weak RNGs with arc4random, make NOSPOOF unconditional
authorRemco Rijnders <remmy@serenity-irc.net>
Sat, 7 Mar 2026 17:17:36 +0000 (12:17 -0500)
committerRemco Rijnders <remmy@serenity-irc.net>
Sat, 7 Mar 2026 17:17:36 +0000 (12:17 -0500)
Replace srand/rand (NOSPOOF seeds) and srand48/lrand48 (DNS query IDs)
with arc4random(), which is cryptographically strong and needs no seeding.

Simplify NOSPOOF anti-spoof challenge: replace the MD5-based construction
(which depended on predictable seeds) with a direct arc4random() call.
Remove NOSPOOF_SEED01/NOSPOOF_SEED02 globals and MD5 dependency.

Make NOSPOOF unconditional — every modern IRC client handles PING-on-connect.
Remove all #ifdef NOSPOOF conditionals across the codebase.

Fix operator precedence bug in res.c where & 0xffff only applied to the
lrand48() result instead of the whole expression.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
include/config.h
include/h.h
include/struct.h
src/ircd.c
src/parse.c
src/res.c
src/s_debug.c
src/s_user.c

index c185042eaa3a38c3accc0753ebc22840290f00e1..70286972da2ae75a5fea0d6ac0bbfde66ad2565c 100644 (file)
@@ -95,7 +95,7 @@
  
 #define MALLOC_FLAGS_EXTRA ""
 
-#undef NOSPOOF
+#define NOSPOOF
        
 
 /* KLINE_ADDRESS
index 6c942ec44c01890e06ab4c47c75f0ace79ae0cef..283029b34aaab4957f561ec90101d0da2f77f28b 100644 (file)
@@ -32,13 +32,6 @@ extern       int     bootopt;
 /* Prototype added to force errors -- Barubary */
 extern time_t  check_pings(time_t now, int check_kills);
 
-/* moved here to allow the server to generate new seeds on startup
-       InnerFIRE       */
-
-#ifdef NOSPOOF
-extern uint32_t NOSPOOF_SEED01, NOSPOOF_SEED02 ;
-#endif /*  NOSPOOF*/
-
 #define BREPORT_DO_DNS "NOTICE AUTH :*** Looking up your hostname...\r\n"
 #define BREPORT_FIN_DNS "NOTICE AUTH :*** Found your hostname\r\n"
 #define BREPORT_FIN_DNSC "NOTICE AUTH :*** Found your hostname (cached)\r\n"
index 700cf061151766486e68d6eed2a836c3c21db5fd..4621aff364f4e674f3b9fdef5b568d9fc0d49b00 100644 (file)
@@ -253,11 +253,7 @@ typedef struct  Zdata   aZdata;
 #define GotProtoctl(x)         ((x)->flags & FLAGS_PROTOCTL)
 #define IsBlocked(x)           ((x)->flags & FLAGS_BLOCKED)
 #define GotCapab(x)             ((x)->flags & FLAGS_GOTCAPAB)
-#ifdef NOSPOOF
 #define        IsNotSpoof(x)           ((x)->nospoof == 0)
-#else
-#define IsNotSpoof(x)           (1)
-#endif
 
 #ifdef SEEUSERSTATS
 #define SetStatsF(x)           ((x)->umodes |= UMODE_STATS)
@@ -639,9 +635,7 @@ struct Client       {
        short   lastsq;         /* # of 2k blocks when sendqueued called last*/
        dbuf    sendQ;          /* Outgoing message queue--if socket full */
        dbuf    recvQ;          /* Hold for data incoming yet to be parsed */
-#ifdef NOSPOOF
        uint32_t        nospoof;        /* Anti-spoofing random number */
-#endif
        long    oflag;          /* Operator access flags -Cabal95 */
        long    proto;          /* ProtoCtl options */
        long    sendM;          /* Statistics: protocol messages send */
index 432b0ae37730afd793013337fbd9d276e5f4d6a6..33fd9fdc9e0a86c698c32596915573ecbb737476 100644 (file)
 char *malloc_options = "h" MALLOC_FLAGS_EXTRA;
 #endif
 
-#ifdef NOSPOOF
-uint32_t NOSPOOF_SEED01, NOSPOOF_SEED02;
-#endif /* NOSPOOF */
-
 int global_count, max_global_count;
 time_t now;
 int synchmode;
@@ -663,13 +659,6 @@ int main (argc, argv)
     R_fin_id = strlen (REPORT_FIN_ID);
     R_fail_id = strlen (REPORT_FAIL_ID);
 
-#ifdef NOSPOOF
-    srand (time (NULL));
-
-    NOSPOOF_SEED01 = rand () % 2147483647;
-    NOSPOOF_SEED02 = rand () % 2147483647;
-#endif /* NOSPOOF */
-
     check_class ();
     if (bootopt & BOOT_OPER) {
        aClient *tmp = add_connection (&me, 0);
index e9d4985f6bb3c961827d8f78185652a5852fb3bb..548fcdcb5d13982fd795ea825c66d1c1a353c63a 100644 (file)
@@ -339,9 +339,7 @@ int parse (aClient *cptr, char *buffer, char *bufend, struct Message *mptr)
          (mptr->func != m_pass) && (mptr->func != m_quit) &&
          (mptr->func != m_protoctl) && (mptr->func != m_error) &&
          (mptr->func != m_admin) && (mptr->func != m_version)
-#ifdef NOSPOOF
          && (mptr->func != m_notice)
-#endif
         ))) {
        sendto_one (from, ":%s %d %s :You have not registered",
                    me.name, ERR_NOTREGISTERED, ch);
index ed46dc98ac5b90e10c31a073698075a4a3192572..5f83e55ba5b75f349867bee48df0b69b43da0ef7 100644 (file)
--- a/src/res.c
+++ b/src/res.c
@@ -81,7 +81,6 @@ int init_resolver (op)
 {
     int ret = 0;
 
-    srand48 (time (NULL));
     if (op & RES_INITLIST) {
        bzero ((char *) &reinfo, sizeof (reinfo));
        first = last = NULL;
@@ -410,7 +409,7 @@ static int query_name (char *name, int class, int type, ResRQ *rptr)
     }
     hptr = (HEADER *) buf;
     do {
-       hptr->id = htons (ntohs (hptr->id) + k + lrand48 () & 0xffff);
+       hptr->id = htons ((ntohs (hptr->id) + k + arc4random ()) & 0xffff);
        k++;
     }
     while (find_id (ntohs (hptr->id)));
index 45ad583c5798a4efc26abf872d256ca8a3a23f17..a6d69ea5dde1d6837f021496090da95f4c4845d2 100644 (file)
@@ -47,9 +47,7 @@ char serveropts[] = {
 #ifdef CRYPT_OPER_PASSWORD
     'p',
 #endif
-#ifdef NOSPOOF
     'n',
-#endif
 #ifdef USE_SYSLOG
     'Y',
 #endif
index d480fb354e6584ca4c6c3bcac23886c34cc7932c..86d638c13e80a342b953cf06baeca43c8efb611b 100644 (file)
@@ -45,11 +45,6 @@ static char buf[BUFSIZE], buf2[BUFSIZE];
 int ZLineExists (char *);
 #endif
 
-#ifdef NOSPOOF
-/* From md5.c */
-void MD5Init (uint32_t[]);
-void MD5Transform (uint32_t[], uint32_t[]);
-#endif
 
 /*
    ** m_functions execute protocol messages on this server:
@@ -866,10 +861,6 @@ int m_nick (cptr, sptr, parc, parv)
     time_t lastnick = (time_t) 0;
     int differ = 1;
 
-#ifdef NOSPOOF
-    uint32_t md5data[16];
-    static uint32_t md5hash[4];
-#endif
 
     /*
      * If the user didn't specify a nickname, complain
@@ -1226,55 +1217,7 @@ int m_nick (cptr, sptr, parc, parv)
                            parv[0], nick, sptr->lastnick);
     }
     else if (!sptr->name[0]) {
-#ifdef NOSPOOF
-       /*
-        * Client setting NICK the first time.
-        *
-        * Generate a random string for them to pong with.
-        *
-        * The first two are server specific.  The intent is to randomize
-        * things well.
-        *
-        * We use lots of junk here, but only "low cost" things.
-        */
-       md5data[0] = NOSPOOF_SEED01;
-       md5data[1] = NOSPOOF_SEED02;
-       md5data[2] = time (NULL);
-       md5data[3] = me.sendM;
-       md5data[4] = me.receiveM;
-       md5data[5] = 0;
-       md5data[6] = getpid ();
-       md5data[7] = sptr->ip.s_addr;
-       md5data[8] = sptr->fd;
-       md5data[9] = 0;
-       md5data[10] = 0;
-       md5data[11] = 0;
-       md5data[12] = md5hash[0]; /* previous runs... */
-       md5data[13] = md5hash[1];
-       md5data[14] = md5hash[2];
-       md5data[15] = md5hash[3];
-
-       /*
-        * initialize the md5 buffer to known values
-        */
-       MD5Init (md5hash);
-
-       /*
-        * transform the above information into gibberish
-        */
-       MD5Transform (md5hash, md5data);
-
-       /*
-        * Never release any internal state of our generator.  Instead,
-        * use two parts of the returned hash and xor them to hide
-        * both values.
-        */
-       sptr->nospoof = (md5hash[0] ^ md5hash[1]);
-
-       /*
-        * If on the odd chance it comes out zero, make it something
-        * non-zero.
-        */
+       sptr->nospoof = arc4random ();
        if (sptr->nospoof == 0)
            sptr->nospoof = 0xdeadbeef;
        sendto_one (sptr, ":%s NOTICE %s :*** If you are having problems"
@@ -1282,7 +1225,6 @@ int m_nick (cptr, sptr, parc, parv)
                    " type /notice %X nospoof now.",
                    me.name, nick, sptr->nospoof, sptr->nospoof);
        sendto_one (sptr, "PING :%X", sptr->nospoof);
-#endif /* NOSPOOF */
 
 #ifdef CONTACT_EMAIL
        sendto_one (sptr, ":%s NOTICE %s :*** If you need assistance with a"
@@ -1376,20 +1318,12 @@ static int m_message (cptr, sptr, parc, parv, notice)
        NULL
     };
 
-/* This is related to the test for unregistered users in 
- * parse.c. Unless NOSPOOF is defined, there is no need to
- * test this here since m_notice and m_message are disallowed.
- *  -Studded
- */
-
-#ifdef NOSPOOF
     if (notice) {
        if (check_registered (sptr))
            return 0;
     }
     else if (check_registered_user (sptr))
        return 0;
-#endif
 
     sptr->flags &= ~FLAGS_TS8;
 
@@ -1781,19 +1715,15 @@ int m_notice (cptr, sptr, parc, parv)
     if ((cptr->name[0]) && !IsNotSpoof (cptr)) {
        if (BadPtr (parv[1]))
            return 0;
-#ifdef NOSPOOF
        if (strtoul (parv[1], NULL, 16) != cptr->nospoof)
            goto temp;
        sptr->nospoof = 0;
-#endif
        if (sptr->user && sptr->name[0])
            return register_user (cptr, sptr, sptr->name,
                                  sptr->user->username);
        return 0;
     }
-#ifdef NOSPOOF
   temp:
-#endif
     return m_message (cptr, sptr, parc, parv, 1);
     return 0;
 }
@@ -2746,7 +2676,6 @@ int m_ping (cptr, sptr, parc, parv)
     return 0;
 }
 
-#ifdef NOSPOOF
 /*
    ** m_nospoof - allows clients to respond to no spoofing patch
    **   parv[0] = prefix
@@ -2786,7 +2715,6 @@ int m_nospoof (cptr, sptr, parc, parv)
                cptr->nospoof, me.name, cptr->name, (char) 1, (char) 1);
     return 0;
 }
-#endif /* NOSPOOF */
 
 /*
    ** m_pong
@@ -2802,10 +2730,8 @@ int m_pong (cptr, sptr, parc, parv)
     aClient *acptr;
     char *origin, *destination;
 
-#ifdef NOSPOOF
     if (!IsRegistered (cptr))
        return m_nospoof (cptr, sptr, parc, parv);
-#endif
 
     if (parc < 2 || *parv[1] == '\0') {
        sendto_one (sptr, err_str (ERR_NOORIGIN), me.name, parv[0]);