Logo Search packages:      
Sourcecode: rageircd version File versions  Download package

s_serv.c

/*
 * RageIRCd: an advanced Internet Relay Chat daemon (ircd).
 * (C) 2000-2005 the RageIRCd Development Team, all rights reserved.
 *
 * This software is free, licensed under the General Public License.
 * Please refer to doc/LICENSE and doc/README for further details.
 *
 * $Id: s_serv.c,v 1.148.2.8 2005/07/09 00:39:21 amcwilliam Exp $
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "patchlevel.h"
#include "ssl.h"
#include "zlink.h"
#include "memory.h"
#include "xmode.h"
#include "user_ban.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <utmp.h>
#include "h.h"
#if defined(HAVE_STRING_H)
#include <string.h>
#else
#include <strings.h>
#endif
#if defined(AIX) || defined(SVR3)
#include <time.h>
#endif

Capability cap_table[] = {
      /* CAP_FLAG,      TOKEN,            link, synch, PrettyToken */
      { CAP_BURST,      "BURST",    0, 0, NULL },
      { CAP_UNCONN,     "UNCONNECT",      0, 0, NULL },
      { CAP_SUPER,      NULL,       1, 0, "U-Lined" },
#ifdef USE_ZLIB
      { CAP_ZIP,  "ZIP",            1, 0, "OutputZipped" },
#endif
#ifdef USE_OPENSSL
      { CAP_DKEY, "DKEY",           1, 0, "Encrypted" },
#endif
      { CAP_SSJ3, "SSJ3",           0, 1, NULL },
      { CAP_SN2,  "SN2",            0, 1, NULL },
      { CAP_VHOST,      "VHOST",    0, 1, NULL },
      { CAP_SUID, "SUID",           1, 0, "Identities" },
      { CAP_TOK1, "TOK1",           1, 0, "Tokenised" },
      { CAP_NOQUIT,     "NOQUIT",   0, 0, NULL },
      { CAP_TSMODE,     "TSMODE",   0, 0, NULL },
      { CAP_NBURST,     "NBURST",   0, 0, NULL },
      { 0, NULL, 0, 0, NULL }
};

char *make_capab_list(unsigned int capabs, int pretty, int type)
{
      static char cbuf[512];
      int cidx = 0;
      Capability *c;

      cbuf[cidx] = '\0';
      for (c = cap_table; c->flag; c++) {
            if (!(capabs & c->flag) || (type < 0 && !c->link_state) || (type > 0 && !c->synch_state)) {
                  continue;
            }
            if (pretty && (c->pretty_token != NULL)) {
                  ADD_STRING(c->pretty_token, cbuf, cidx);
            }
            else if (c->token != NULL) {
                  ADD_STRING(c->token, cbuf, cidx);
            }
      }
      return cbuf;
}

void try_connections(void *setup)
{
      dlink_node *node;
      ConfigItem_link *linkp;
      aClient *cptr;
      
      if (setup) {
            if (GeneralConfig.auto_connect_freq < 1) {
                  return;
            }
            
            add_event("try_connections", try_connections, NULL,
                  GeneralConfig.auto_connect_freq, 1);
      }     

      Debug((DEBUG_DEBUG, "Connection check at: %s", myctime(timeofday)));

      DLINK_FOREACH_DATA(conf_link_list.head, node, linkp, ConfigItem_link) {
            if (!(linkp->flags & LINK_AUTOCONNECT) || (linkp->next_connect > timeofday)) {
                  continue;
            }

            linkp->next_connect = (timeofday + GeneralConfig.auto_connect_freq);

            if ((cptr = find_server(linkp->servername, NULL)) != NULL) {
                  continue;
            }
            if (linkp->class->clients > linkp->class->max_clients) {
                  continue;
            }
            if (serv_connect(linkp, NULL)) {
                  send_gnotice("Connection to %s[%s].%d activated.", linkp->servername,
                        linkp->host, linkp->port);
            }
      }
      
      Debug((DEBUG_DEBUG, "Next connection check at: %s",
            myctime(timeofday + GeneralConfig.auto_connect_freq)));
}

/* Same as in s_user.c for introduce_client */
#define nick_maskedhost(x) (HasMode((x), UMODE_MASKED) ? (x)->user->maskedhost : "*")
#define nick_id(x) (HasSUID((x)) ? (x)->id.string : (x)->user->server)

static void sendnick_TS(aClient *sptr, aClient *acptr)
{
      char umode_buf[16];

      if (!IsPerson(acptr)) {
            return;
      }

      *umode_buf = '\0';
      send_umode(NULL, acptr, 0, SEND_UMODES, umode_buf);
      
      if (*umode_buf == '\0') {
            *umode_buf = '+';
            *(umode_buf + 1) = '\0';
      }
      
      if (CapSN2(sptr)) {
            if (CapID(sptr)) {
                  sendto_one_client_nopostfix(sptr, NULL, &CMD_SNICK,
                        "%s %B %d %s %s %B %s %s %B %s :%s",
                        acptr->name, acptr->tsinfo, acptr->hopcount + 1, acptr->username,
                        acptr->host, acptr->ip.s_addr, nick_maskedhost(acptr), nick_id(acptr),
                        acptr->user->servicestamp, umode_buf, acptr->info);
            }
            else {
                  sendto_one_client_nopostfix(sptr, NULL, &CMD_SNICK,
                        "%s %ld %d %s %s %lu %s %s %lu %s :%s",
                        acptr->name, acptr->tsinfo, acptr->hopcount + 1, acptr->username,
                        acptr->host, htonl(acptr->ip.s_addr), nick_maskedhost(acptr),
                        acptr->user->server, acptr->user->servicestamp, umode_buf, acptr->info);
            }
      }
      else {
            if (CapID(sptr)) {
                  sendto_one_client_nopostfix(sptr, NULL, &CMD_NICK,
                        "%s %d %B %s %s %s %s %B %B :%s", acptr->name, acptr->hopcount + 1,
                        acptr->tsinfo, umode_buf, acptr->username, acptr->host, nick_id(acptr),
                        acptr->user->servicestamp, acptr->ip.s_addr, acptr->info);
            }
            else {
                  sendto_one_client_nopostfix(sptr, NULL, &CMD_NICK,
                        "%s %d %ld %s %s %s %s %lu %lu :%s", acptr->name, acptr->hopcount + 1,
                        acptr->tsinfo, umode_buf, acptr->username, acptr->host,
                        acptr->user->server, acptr->user->servicestamp, htonl(acptr->ip.s_addr),
                        acptr->info);
            }

            /* Synch masked host too */
            if (CapVHOST(sptr) && HasMode(acptr, UMODE_MASKED)) {
                  sendto_one_client_nopostfix(sptr, NULL, &CMD_VHOST, "%s %s",
                        use_id(acptr, sptr), acptr->user->maskedhost);
            }
      }
}

int do_server_estab(aClient *cptr)
{
      char *inpath, *cap_list;
      aClient *acptr;
      aChannel *chptr;
      unsigned long link_capabs;

      ASSERT(cptr != NULL);
      ASSERT(cptr->localClient != NULL);

      inpath = get_client_name(cptr, HIDE_IP);

      Debug((DEBUG_DEBUG, "Beginning server synch: %s", inpath));

      SetServer(cptr);
      Count.server++;
      Count.myserver++;

#ifdef USE_ZLIB
      if (CapZIP(cptr) && WantZIP(cptr)) {
            sendto_one_client_nopostfix(cptr, NULL, &CMD_SVINFO, "ZIP");
            SetOutputZIP(cptr);
            cptr->serv->zip_out = zip_create_output_session();
      }
#endif

#ifdef INCREASE_SOCK_BUFS
      increase_sock_bufs(cptr->localClient->fd, 1);
#endif

      dlink_del_nofree(&lunknown_list, NULL, &cptr->localClient->self);
      dlink_add_node(&lserver_list, &cptr->localClient->self, cptr);
      Count.unknown--;

      attach_class(cptr);

      if ((acptr = find_server(cptr->name, NULL)) != NULL) {
            aClient *bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr : acptr->from;
            char *b_inpath = get_client_name(bcptr, HIDE_IP);

            sendto_one_client_nopostfix(bcptr, NULL, &CMD_ERROR, ":Server %s already exists", cptr->name);
            if (bcptr == cptr) {
                  send_gnotice("Link %s cancelled, server %s already exists (final phase)",
                        b_inpath, cptr->name);
                  sendto_serv_msg_butone(bcptr, &me, &CMD_GNOTICE, ":Link %s cancelled, "
                        "server %s already exists (final phase)", b_inpath, cptr->name);
                  return exit_client(bcptr, bcptr, &me, "Server Exists (final phase)");
            }

            send_gnotice("Link %s cancelled, server %s reintroduced by %s (final phase)",
                  b_inpath, cptr->name, inpath);
            sendto_serv_msg_butone(bcptr, &me, &CMD_GNOTICE, ":Link %s cancelled, server %s "
                  "reintroduced by %s (final phase)", b_inpath, cptr->name, inpath);
            return exit_client(bcptr, bcptr, &me, "Server Exists (final phase)");
      }

      if (is_id(cptr->id.string)) {
            char b64id[IDLEN + 1];

            strcpy(b64id, cptr->id.string);

            if (!add_base64_serv(cptr, b64id)) {
                  char *name = "<UNKNOWN>";

                  if ((acptr = find_serv_by_base64_id(b64id, NULL)) != NULL) {
                        name = acptr->name;
                  }

                  send_gnotice("Link %s cancelled, identity collision with %s (final phase)",
                        inpath, name);
                  sendto_serv_msg_butone(cptr, &me, &CMD_GNOTICE, ":Link %s cancelled, "
                        "identity collision with %s (final phase)", inpath, name);
                  return exit_client(cptr, cptr, &me, "Identity collision (final phase)");
            }
      }

      if (find_super(cptr->name)) {
            Count.mysuper++;
            SetULine(cptr);
      }

      link_capabs = cptr->localClient->capabs;
      
      if (!OutputZIP(cptr)) {
            link_capabs &= ~CAP_ZIP;
      }
      if (!InputRC4(cptr) || !OutputRC4(cptr)) {
            link_capabs &= ~CAP_DKEY;
      }
      
      if (IsULine(cptr)) {
            link_capabs |= CAP_SUPER;
      }

      cap_list = get_link_cap(link_capabs);
      send_gnotice("Link with %s established (capabilities: %s)", inpath,
            !BadPtr(cap_list) ? cap_list : "none");
      sendto_serv_msg_butone(NULL, &me, &CMD_GNOTICE, ":Link with %s established "
            "(capabilities: %s)", inpath, !BadPtr(cap_list) ? cap_list : NULL);
      ircdlog(LOG_SERVER, "link with %s established (%s)", get_client_name(cptr, FALSE),
            cap_list);

      add_to_client_hash_table(cptr->name, cptr);
      find_or_add(cptr->name);

      if (HasSUID(cptr)) {
            sendto_serv_capab_msg_butone(cptr, &me, NO_CAPS, ID_CAPS, &CMD_SERVER,
                  "%s 2 :%s", cptr->name, cptr->info);
            sendto_serv_capab_msg_butone(cptr, &me, ID_CAPS, NO_CAPS, &CMD_SERVER,
                  "%s 2 %s :%s", cptr->name, cptr->id.string, cptr->info);
      }
      else {
            sendto_serv_msg_butone(cptr, &me, &CMD_SERVER, "%s 2 :%s", cptr->name, cptr->info);
      }

      for (acptr = &me; acptr; acptr = acptr->prev) {
            if (acptr->from == cptr || !IsServer(acptr)) {
                  continue;
            }

            if (!CapID(cptr) || (CapID(cptr) && (!HasSUID(acptr->uplink)
              || (HasSUID(acptr->uplink) && !HasSUID(acptr))))) {
                  sendto_one_client_nopostfix(cptr, acptr->uplink, &CMD_SERVER, "%s %d :%s",
                        acptr->name, acptr->hopcount + 1, acptr->info);
            }
            else {
                  sendto_one_client_nopostfix(cptr, acptr->uplink, &CMD_SERVER, "%s %d %s :%s",
                        acptr->name, acptr->hopcount + 1, acptr->id.string, acptr->info);
            }
            
            /* We must notify the new server (cptr) that this server (acptr) is
             * already fully synchronised to my data.
             */
             if (CapNBURST(cptr) && GotNBurst(acptr)) {
                  ASSERT(CapNBURST(acptr)); /* if !NBURST, GotNBurst impossible... */
                  sendto_one_client_nopostfix(cptr, acptr, &CMD_NBURST, "");
             }
      }

      send_simbans(cptr, SBAN_NICK|BAN_NETWORK);
      send_simbans(cptr, SBAN_CHAN|BAN_NETWORK);
      send_simbans(cptr, SBAN_GCOS|BAN_NETWORK);

      /* This is our SOB (Start of Burst) */
      if (CapBURST(cptr)) {
            sendto_one_client_nopostfix(cptr, NULL, &CMD_BURST, "");
      }

      {
            chanMember *cm;
            static char nickissent = 1;

            synch_chan_modes(cptr, NULL);

            nickissent = 3 - nickissent;
            for (chptr = channel; chptr != NULL; chptr = chptr->nextch) {
                  for (cm = chptr->members; cm != NULL; cm = cm->nextuser) {
                        acptr = cm->cptr;
                        if (!IsPerson(acptr)) {
                              continue;
                        }
                        if (acptr->user->nicksent != nickissent) {
                              acptr->user->nicksent = nickissent;
                              if (acptr->from != cptr) {
                                    sendnick_TS(cptr, acptr);
                              }
                        }
                  }
                  synch_chan_modes(cptr, chptr);
            }
            for (acptr = &me; acptr != NULL; acptr = acptr->prev) {
                  if (!IsPerson(acptr)) {
                        continue;
                  }
                  if (acptr->user->nicksent != nickissent) {
                        acptr->user->nicksent = nickissent;
                        if (acptr->from != cptr) {
                              sendnick_TS(cptr, acptr);
                        }
                  }
            }
      }

#ifdef USE_ZLIB
      if (OutputZIP(cptr)) {
            unsigned long in_b, out_b;
            double ratio;

            zip_out_get_stats(cptr->serv->zip_out, &in_b, &out_b, &ratio);
            if (in_b) {
                  send_gnotice("Connect burst to %s: %lu bytes normal, %lu compressed (%3.2f%%)",
                        inpath, in_b, out_b, ratio);
                  sendto_serv_msg_butone(cptr, &me, &CMD_GNOTICE, ":Connect burst to %s: %lu "
                        "bytes normal, %lu compressed (%3.2f%%)", inpath, in_b, out_b, ratio);
            }
      }
#endif

      SetPingSent(cptr);
      SetUserBurst(cptr);
      SetTopicBurst(cptr);
      
      if (CapBURST(cptr)) {
            SetSentSOB(cptr);
      }

      sendto_one_client_nopostfix(cptr, &me, &CMD_PING, ":%s", me.name);
      
      /* Issue a Network Burst (fully synched to MY data) */
      if (CapNBURST(cptr)) {
            sendto_one_client_nopostfix(cptr, &me, &CMD_NBURST, "");
      }
      
      return 0;
}

int send_lusers(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
      static long last_time = 0;
      static int s_count = 0, c_count = 0, u_count = 0, i_count = 0;
      static int o_count = 0, my_client = 0, my_server = 0, my_super = 0;
      static int ch_count = 0;
      int forced = (HasMode(sptr, UMODE_OPER) && parc > 3);
      aClient *acptr;
      aChannel *chptr;

      my_server = Count.myserver;
      my_super = Count.mysuper;
      my_client = Count.local;
      i_count = Count.invisi;
      u_count = Count.unknown;
      c_count = Count.total - Count.invisi;
      s_count = Count.server;
      o_count = Count.oper;
      ch_count = Count.chan;

      if (forced || last_time + LUSERS_CACHE_TIME > timeofday) {
            last_time = timeofday;
            s_count = c_count = u_count = i_count = o_count = my_client = my_server = my_super = 0;

            for (acptr = client; acptr; acptr = acptr->next) {
                  switch (acptr->status) {
                        case STAT_SERVER:
                              if (MyConnect(acptr)) {
                                    my_server++;
                                    if (IsULine(acptr)) {
                                          my_super++;
                                    }
                              }
                        case STAT_ME:
                              s_count++;
                              break;
                        case STAT_CLIENT:
                              if (HasMode(acptr, UMODE_OPER)) {
                                    o_count++;
                              }
                              if (MyConnect(acptr)) {
                                    if (GeneralConfig.show_invisible_lusers
                                      || (!GeneralConfig.show_invisible_lusers
                                      && HasMode(acptr, UMODE_INVISIBLE)
                                      && HasMode(sptr, UMODE_OPER))) {
                                          my_client++;
                                    }
                              }
                              if (!HasMode(acptr, UMODE_INVISIBLE)) {
                                    c_count++;
                              }
                              else {
                                    i_count++;
                              }
                              break;
                        default:
                              u_count++;
                              break;
                  }
            }
            for (chptr = channel; chptr != NULL; chptr = chptr->nextch) {
                  ch_count++;
            }
            if (!forced) {
                  if (my_server != Count.myserver) {
                        sendto_realops_lev(DEBUG_LEV, "Local server count off by %d",
                              Count.myserver - my_server);
                        Count.myserver = my_server;
                  }
                  if (my_super != Count.mysuper) {
                        sendto_realops_lev(DEBUG_LEV, "Local super server count off by %d",
                              Count.mysuper - my_super);
                        Count.mysuper = my_super;
                  }
                  if (my_client != Count.local) {
                        sendto_realops_lev(DEBUG_LEV, "Local client count off by %d",
                              Count.local - my_client);
                        Count.local = my_client;
                  }
                  if (s_count != Count.server) {
                        sendto_realops_lev(DEBUG_LEV, "Server count off by %d",
                              Count.server - s_count);
                        Count.server = s_count;
                  }
                  if (i_count != Count.invisi) {
                        sendto_realops_lev(DEBUG_LEV, "Invisible client count off by %d",
                              Count.invisi - i_count);
                        Count.invisi = i_count;
                  }
                  if (c_count + i_count != Count.total) {
                        sendto_realops_lev(DEBUG_LEV, "Total client count off by %d",
                              Count.total - (c_count + i_count));
                        Count.total = c_count + i_count;
                  }
                  if (o_count != Count.oper) {
                        sendto_realops_lev(DEBUG_LEV, "Oper count off by %d",
                              Count.oper - o_count);
                        Count.oper = o_count;
                  }
                  if (ch_count != Count.chan) {
                        sendto_realops_lev(DEBUG_LEV, "Chan count off by %d",
                              Count.chan - ch_count);
                        Count.chan = ch_count;
                  }
                  Count.unknown = u_count;
            }
      }

      if (GeneralConfig.show_invisible_lusers || (!GeneralConfig.show_invisible_lusers
        && HasMode(sptr, UMODE_OPER) && (i_count > 0))) {
            send_me_numeric(sptr, RPL_LUSERCLIENT, c_count, i_count, s_count);
      }
      else {
            send_me_numeric_buf(sptr, ":There are %d users on %d servers", RPL_LUSERCLIENT,
                  c_count, s_count);
      }
      if (o_count > 0) {
            send_me_numeric(sptr, RPL_LUSEROP, o_count);
      }
      if (u_count > 0) {
            send_me_numeric(sptr, RPL_LUSERUNKNOWN, u_count);
      }
      if (ch_count > 0) {
            send_me_numeric(sptr, RPL_LUSERCHANNELS, ch_count);
      }
      send_me_numeric(sptr, RPL_LUSERME, my_client,
            (GeneralConfig.hide_super_servers && !HasMode(sptr, UMODE_OPER)) ? my_server - my_super : my_server);

      send_me_numeric(sptr, RPL_LOCALUSERS, Count.local, Count.max_loc);
      send_me_numeric(sptr, RPL_GLOBALUSERS, Count.total, Count.max_tot);
      send_me_numeric(sptr, RPL_STATSCONN, Internal.max_con_count, Internal.max_cli_count, Count.cli_restart);

      if (my_client > Internal.max_cli_count) {
            Internal.max_cli_count = my_client;
      }
      if (my_client + my_server > Internal.max_con_count) {
            Internal.max_con_count = my_client + my_server;
      }
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index