void checkServer(struct Client *sptr, struct Client *acptr) { char outbuf[BUFSIZE]; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected at:: %s (%Tu)", myctime(acptr->cli_serv->timestamp), acptr->cli_serv->timestamp); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Server name:: %s", acptr->cli_name); send_reply(sptr, RPL_DATASTR, outbuf); if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Users:: %d / %d", (acptr == &me) ? UserStats.local_clients : cli_serv(acptr)->clients, base64toint(cli_serv(acptr)->nn_capacity)); send_reply(sptr, RPL_DATASTR, outbuf); if (IsBurst(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Bursting"); else if (IsBurstAck(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Awaiting EOB Ack"); else if (IsService(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Network Service"); else if (IsHub(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Network Hub"); ircd_snprintf(0, outbuf, sizeof(outbuf), " Class:: %s", get_client_class(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (feature_bool(FEAT_CHECK_EXTENDED)) { int dlinkc = 0; struct DLink* slink = NULL; send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_DATASTR, "Downlinks::"); for (slink = cli_serv(acptr)->down; slink; slink = slink->next) { ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc, IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" : IsService(slink->value.cptr) ? "=" : IsHub(slink->value.cptr) ? "+" : " ", cli_name(slink->value.cptr)); send_reply(sptr, RPL_DATASTR, outbuf); } if (!dlinkc) send_reply(sptr, RPL_DATASTR, "<none>"); } /* Send 'END OF CHECK' message */ send_reply(sptr, RPL_ENDOFCHECK, " "); }
int verify_sslclifp(struct Client* cptr, struct ConfItem* aconf) { if (!(aconf->sslfp)) return 1; if (!cli_sslclifp(cptr)) return 0; if (ircd_strcmp(aconf->sslfp, cli_sslclifp(cptr)) != 0) return 0; return 1; }
/* * ms_mark - server message handler */ int ms_mark(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr; if (!IsServer(sptr)) return protocol_violation(sptr, "MARK from non-server %s", cli_name(sptr)); if (!strcmp(parv[2], MARK_WEBIRC)) { if(parc < 4) return protocol_violation(sptr, "MARK webirc received too few parameters (%u)", parc); if ((acptr = FindUser(parv[1]))) { ircd_strncpy(cli_webirc(acptr), parv[3], BUFSIZE); sendcmdto_serv_butone(sptr, CMD_MARK, cptr, "%s %s :%s", cli_name(acptr), MARK_WEBIRC, parv[3]); } } else if (!strcmp(parv[2], MARK_GEOIP)) { if(parc < 5) return protocol_violation(sptr, "MARK geoip received too few parameters (%u)", parc); if ((acptr = FindUser(parv[1]))) { geoip_apply_mark(acptr, parv[3], parv[4], (parc > 5 ? parv[5] : NULL)); if (parc > 5) sendcmdto_serv_butone(sptr, CMD_MARK, cptr, "%s %s %s %s :%s", cli_name(acptr), MARK_GEOIP, parv[3], parv[4], parv[5]); else sendcmdto_serv_butone(sptr, CMD_MARK, cptr, "%s %s %s %s", cli_name(acptr), MARK_GEOIP, parv[3], parv[4]); } } else if (!strcmp(parv[2], MARK_CVERSION)) { if(parc < 4) return protocol_violation(sptr, "MARK client version received too few parameters (%u)", parc); if ((acptr = FindUser(parv[1]))) { ircd_strncpy(cli_version(acptr), parv[3], VERSIONLEN); sendcmdto_serv_butone(sptr, CMD_MARK, cptr, "%s %s :%s", cli_name(acptr), MARK_CVERSION, parv[3]); } } else if (!strcmp(parv[2], MARK_SSLCLIFP)) { if(parc < 4) return protocol_violation(sptr, "MARK SSL client certificate fingerprint received too few parameters (%u)", parc); if ((acptr = FindUser(parv[1]))) { ircd_strncpy(cli_sslclifp(acptr), parv[3], BUFSIZE); sendcmdto_serv_butone(sptr, CMD_MARK, cptr, "%s %s :%s", cli_name(acptr), MARK_SSLCLIFP, parv[3]); } } else if (!strcmp(parv[2], MARK_KILL)) { if(parc < 4) return protocol_violation(sptr, "MARK kill received too few parameters (%u)", parc); if ((acptr = FindUser(parv[1]))) { ircd_strncpy(cli_killmark(acptr), parv[3], BUFSIZE); sendcmdto_serv_butone(sptr, CMD_MARK, cptr, "%s %s :%s", cli_name(acptr), MARK_KILL, parv[3]); } } else if (!strcmp(parv[2], MARK_MARK) || !strcmp(parv[2], MARK_DNSBL_DATA)) { if(parc < 4) return protocol_violation(sptr, "MARK MARK (tag) received too few parameters (%u)", parc); if ((acptr = FindUser(parv[1]))) { add_mark(acptr, parv[3]); SetMarked(acptr); sendcmdto_serv_butone(sptr, CMD_MARK, cptr, "%s %s :%s", cli_name(acptr), MARK_MARK, parv[3]); } } return 0; }
void checkClient(struct Client *sptr, struct Client *acptr) { struct Channel *chptr; struct Membership *lp; char outbuf[BUFSIZE]; char *privs; time_t nowr; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s", myctime(acptr->cli_firsttime)); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " User/Hostmask:: %s@%s (%s)", acptr->cli_user->username, acptr->cli_user->host, ircd_ntoa((const char*) &(cli_ip(acptr)))); send_reply(sptr, RPL_DATASTR, outbuf); if (((feature_int(FEAT_HOST_HIDING_STYLE) == 1) ? HasHiddenHost(acptr) : IsHiddenHost(acptr)) || IsSetHost(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", acptr->cli_user->realusername, acptr->cli_user->realhost); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF); send_reply(sptr, RPL_DATASTR, outbuf); if (IsService(cli_user(acptr)->server)) { if (acptr) send_reply(sptr, RPL_DATASTR, " Status:: Network Service"); else if (IsAdmin(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator (service)"); else if (IsAnOper(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator (service)"); else send_reply(sptr, RPL_DATASTR, " Status:: Client (service)"); } else if (IsAdmin(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Administrator"); } else if (IsAnOper(acptr)) { send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator"); } else { send_reply(sptr, RPL_DATASTR, " Status:: Client"); } if (MyUser(acptr)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Class:: %s", get_client_class(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } privs = client_print_privs(acptr); if (strlen(privs) > 1) client_check_privs(acptr, sptr); ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s", cli_name(acptr->cli_user->server)); send_reply(sptr, RPL_DATASTR, outbuf); if (cli_version(acptr)) { if (strlen(cli_version(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " CTCP Version:: %s", cli_version(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_user(acptr) && !EmptyString(cli_user(acptr)->swhois)) { ircd_snprintf(0, outbuf, sizeof(outbuf), " SWHOIS:: %s", cli_user(acptr)->swhois); send_reply(sptr, RPL_DATASTR, outbuf); } if (cli_webirc(acptr)) { if (strlen(cli_webirc(acptr)) > 0) { ircd_snprintf(0, outbuf, sizeof(outbuf), " WebIRC:: %s", cli_webirc(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } if (MyUser(acptr)) get_eflags(sptr, acptr); /* +s (SERV_NOTICE) is not relayed to us from remote servers, * so we cannot tell if a remote client has that mode set. * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG * (and breaks if the user is +r) so we won't do that either. */ if (strlen(umode_str(acptr)) < 1) strcpy(outbuf, " Umode(s):: <none>"); else ircd_snprintf(0, outbuf, sizeof(outbuf), " Umode(s):: +%s", umode_str(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (acptr->cli_user->joined == 0) send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>"); else if (acptr->cli_user->joined > 50) { /* NB. As a sanity check, we DO NOT show the individual channels the * client is on if it is on > 50 channels. This is to prevent the ircd * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine * an Oper would want to see every single channel 'x' client is on anyway if * they are on *that* many). */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", acptr->cli_user->joined); send_reply(sptr, RPL_DATASTR, outbuf); } else { char chntext[BUFSIZE]; int len = strlen(" Channel(s):: "); int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) { chptr = lp->channel; if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) { send_reply(sptr, RPL_DATASTR, chntext); *chntext = '\0'; strcpy(chntext, " Channel(s):: "); len = strlen(chntext); } if (IsDeaf(acptr)) *(chntext + len++) = '-'; if (is_chan_op(acptr, chptr)) *(chntext + len++) = '@'; if (is_half_op(acptr, chptr)) *(chntext + len++) = '%'; if (IsOper(sptr) && !ShowChannel(sptr,chptr)) *(chntext + len++) = '*'; if (IsZombie(lp)) *(chntext + len++) = '!'; if (len) *(chntext + len) = '\0'; strcpy(chntext + len, chptr->chname); len += strlen(chptr->chname); strcat(chntext + len, " "); len++; } if (chntext[0] != '\0') send_reply(sptr, RPL_DATASTR, chntext); } /* If client processing command ISN'T target (or a registered * Network Service), show idle time since the last time we * parsed something. */ if (MyUser(acptr) && !(IsService(acptr) == -1) && !(strCasediff(acptr->cli_name, sptr->cli_name) == 0)) { nowr = CurrentTime - acptr->cli_user->last; ircd_snprintf(0, outbuf, sizeof(outbuf), " Idle for:: %d days, %02ld:%02ld:%02ld", nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60); send_reply(sptr, RPL_DATASTR, outbuf); } /* Away message (if applicable) */ if (acptr->cli_user->away) { ircd_snprintf(0, outbuf, sizeof(outbuf), " Away message:: %s", acptr->cli_user->away); send_reply(sptr, RPL_DATASTR, outbuf); } /* If local user.. */ if (MyUser(acptr)) { send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Ports:: %d -> %d (client -> server)", cli_port(acptr), cli_listener(acptr)->port); send_reply(sptr, RPL_DATASTR, outbuf); if (feature_bool(FEAT_CHECK_EXTENDED)) { /* Note: sendq = receiveq for a client (it makes sense really) */ ircd_snprintf(0, outbuf, sizeof(outbuf), " Data sent:: %u.%0.3u Kb (%u protocol messages)", cli_receiveK(acptr), cli_receiveB(acptr), cli_receiveM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Data received:: %u.%0.3u Kb (%u protocol messages)", cli_sendK(acptr), cli_sendB(acptr), cli_sendM(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " receiveQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " sendQ size:: %d bytes (max. %d bytes)", DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } } /* Send 'END OF CHECK' message */ send_reply(sptr, RPL_ENDOFCHECK, " "); }
void add_connection(struct Listener* listener, int fd, void *ssl) { #else void add_connection(struct Listener* listener, int fd) { #endif struct irc_sockaddr addr; struct Client *new_client; time_t next_target = 0; #if defined(USE_SSL) char *sslfp; #endif const char* const throttle_message = "ERROR :Your host is trying to (re)connect too fast -- throttled\r\n"; /* 12345678901234567890123456789012345679012345678901234567890123456 */ const char* const register_message = "ERROR :Unable to complete your registration\r\n"; assert(0 != listener); /* * Removed preliminary access check. Full check is performed in m_server and * m_user instead. Also connection time out help to get rid of unwanted * connections. */ if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) { ++ServerStats->is_ref; #if defined(USE_SSL) ssl_murder(ssl, fd, NULL); #else close(fd); #endif return; } /* * Disable IP (*not* TCP) options. In particular, this makes it impossible * to use source routing to connect to the server. If we didn't do this * (and if intermediate networks didn't drop source-routed packets), an * attacker could successfully IP spoof us...and even return the anti-spoof * ping, because the options would cause the packet to be routed back to * the spoofer's machine. When we disable the IP options, we delete the * source route, and the normal routing takes over. */ os_disable_options(fd); if (listener_server(listener)) { new_client = make_client(0, STAT_UNKNOWN_SERVER); } else { /* * Add this local client to the IPcheck registry. * * If they're throttled, murder them, but tell them why first. */ if (!IPcheck_local_connect(&addr.addr, &next_target)) { ++ServerStats->is_ref; #if defined(USE_SSL) ssl_murder(ssl, fd, throttle_message); #else write(fd, throttle_message, strlen(throttle_message)); close(fd); #endif return; } new_client = make_client(0, STAT_UNKNOWN_USER); SetIPChecked(new_client); } /* * Copy ascii address to 'sockhost' just in case. Then we have something * valid to put into error messages... */ ircd_ntoa_r(cli_sock_ip(new_client), &addr.addr); strcpy(cli_sockhost(new_client), cli_sock_ip(new_client)); memcpy(&cli_ip(new_client), &addr.addr, sizeof(cli_ip(new_client))); if (next_target) cli_nexttarget(new_client) = next_target; cli_fd(new_client) = fd; if (!socket_add(&(cli_socket(new_client)), client_sock_callback, (void*) cli_connect(new_client), SS_CONNECTED, 0, fd)) { ++ServerStats->is_ref; #if defined(USE_SSL) ssl_murder(ssl, fd, register_message); #else write(fd, register_message, strlen(register_message)); close(fd); #endif cli_fd(new_client) = -1; return; } #if defined(USE_SSL) if (ssl) { cli_socket(new_client).s_ssl = ssl; sslfp = ssl_get_fingerprint(ssl); if (sslfp) ircd_strncpy(cli_sslclifp(new_client), sslfp, BUFSIZE+1); } #endif cli_freeflag(new_client) |= FREEFLAG_SOCKET; cli_listener(new_client) = listener; ++listener->ref_count; Count_newunknown(UserStats); /* if we've made it this far we can put the client on the auth query pile */ start_auth(new_client); } /** Determines whether to tell the events engine we're interested in * writable events. * @param cptr Client for which to decide this. */ void update_write(struct Client* cptr) { /* If there are messages that need to be sent along, or if the client * is in the middle of a /list, then we need to tell the engine that * we're interested in writable events--otherwise, we need to drop * that interest. */ socket_events(&(cli_socket(cptr)), ((MsgQLength(&cli_sendQ(cptr)) || cli_listing(cptr)) ? SOCK_ACTION_ADD : SOCK_ACTION_DEL) | SOCK_EVENT_WRITABLE); }
/** Attempt to send a sequence of bytes to the connection. * As a side effect, updates \a cptr's FLAG_BLOCKED setting * and sendB/sendK fields. * @param cptr Client that should receive data. * @param buf Message buffer to send to client. * @return Negative on connection-fatal error; otherwise * number of bytes sent. */ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) { unsigned int bytes_written = 0; unsigned int bytes_count = 0; assert(0 != cptr); #if defined(USE_SSL) switch (client_sendv(cptr, buf, &bytes_count, &bytes_written)) { #else switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) { #endif case IO_SUCCESS: ClrFlag(cptr, FLAG_BLOCKED); cli_sendB(cptr) += bytes_written; cli_sendB(&me) += bytes_written; /* A partial write implies that future writes will block. */ if (bytes_written < bytes_count) SetFlag(cptr, FLAG_BLOCKED); break; case IO_BLOCKED: SetFlag(cptr, FLAG_BLOCKED); break; case IO_FAILURE: cli_error(cptr) = errno; SetFlag(cptr, FLAG_DEADSOCKET); break; } return bytes_written; } /** Complete non-blocking connect()-sequence. Check access and * terminate connection, if trouble detected. * @param cptr Client to which we have connected, with all ConfItem structs attached. * @return Zero on failure (caller should exit_client()), non-zero on success. */ static int completed_connection(struct Client* cptr) { struct ConfItem *aconf; time_t newts; struct Client *acptr; int i; #if defined(USE_SSL) char *sslfp; int r; #endif assert(0 != cptr); /* * get the socket status from the fd first to check if * connection actually succeeded */ if ((cli_error(cptr) = os_get_sockerr(cli_fd(cptr)))) { const char* msg = strerror(cli_error(cptr)); if (!msg) msg = "Unknown error"; sendto_opmask(0, SNO_OLDSNO, "Connection failed to %s: %s", cli_name(cptr), msg); return 0; } if (!(aconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER))) { sendto_opmask(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr)); return 0; } #if defined(USE_SSL) if (aconf->flags & CONF_SSL) { r = ssl_connect(&(cli_socket(cptr))); if (r == -1) { sendto_opmask(0, SNO_OLDSNO, "Connection failed to %s: SSL error", cli_name(cptr)); return 0; } else if (r == 0) return 1; sslfp = ssl_get_fingerprint(cli_socket(cptr).s_ssl); if (sslfp) ircd_strncpy(cli_sslclifp(cptr), sslfp, BUFSIZE+1); SetSSL(cptr); } #endif if (s_state(&(cli_socket(cptr))) == SS_CONNECTING) socket_state(&(cli_socket(cptr)), SS_CONNECTED); if (!EmptyString(aconf->passwd)) sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd); /* * Create a unique timestamp */ newts = TStime(); for (i = HighestFd; i > -1; --i) { if ((acptr = LocalClientArray[i]) && (IsServer(acptr) || IsHandshake(acptr))) { if (cli_serv(acptr)->timestamp >= newts) newts = cli_serv(acptr)->timestamp + 1; } } assert(0 != cli_serv(cptr)); cli_serv(cptr)->timestamp = newts; SetHandshake(cptr); /* * Make us timeout after twice the timeout for DNS look ups */ cli_lasttime(cptr) = CurrentTime; ClearPingSent(cptr); /* TODO: NEGOCIACION envia_config_req(cptr); */ sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6 :%s", cli_name(&me), cli_serv(&me)->timestamp, newts, MAJOR_PROTOCOL, NumServCap(&me), feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me)); #if defined(DDB) ddb_burst(cptr); #endif return (IsDead(cptr)) ? 0 : 1; } /** Close the physical connection. Side effects: MyConnect(cptr) * becomes false and cptr->from becomes NULL. * @param cptr Client to disconnect. */ void close_connection(struct Client *cptr) { struct ConfItem* aconf; if (IsServer(cptr)) { ServerStats->is_sv++; ServerStats->is_sbs += cli_sendB(cptr); ServerStats->is_sbr += cli_receiveB(cptr); ServerStats->is_sti += CurrentTime - cli_firsttime(cptr); /* * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) { /* * Reschedule a faster reconnect, if this was a automatically * connected configuration entry. (Note that if we have had * a rehash in between, the status has been changed to * CONF_ILLEGAL). But only do this if it was a "good" link. */ aconf->hold = CurrentTime; aconf->hold += ((aconf->hold - cli_since(cptr) > feature_int(FEAT_HANGONGOODLINK)) ? feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf)); /* if (nextconnect > aconf->hold) */ /* nextconnect = aconf->hold; */ } } else if (IsUser(cptr)) { ServerStats->is_cl++; ServerStats->is_cbs += cli_sendB(cptr); ServerStats->is_cbr += cli_receiveB(cptr); ServerStats->is_cti += CurrentTime - cli_firsttime(cptr); } else ServerStats->is_ni++; #if defined(USE_ZLIB) /* * Siempre es una conexion nuestra */ if (cli_connect(cptr)->zlib_negociation & ZLIB_IN) { inflateEnd(cli_connect(cptr)->comp_in); MyFree(cli_connect(cptr)->comp_in); } if (cli_connect(cptr)->zlib_negociation & ZLIB_OUT) { deflateEnd(cli_connect(cptr)->comp_out); MyFree(cli_connect(cptr)->comp_out); } #endif if (-1 < cli_fd(cptr)) { flush_connections(cptr); LocalClientArray[cli_fd(cptr)] = 0; close(cli_fd(cptr)); socket_del(&(cli_socket(cptr))); /* queue a socket delete */ cli_fd(cptr) = -1; cli_freeflag(cptr) &= ~FREEFLAG_SOCKET; } SetFlag(cptr, FLAG_DEADSOCKET); MsgQClear(&(cli_sendQ(cptr))); client_drop_sendq(cli_connect(cptr)); DBufClear(&(cli_recvQ(cptr))); memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr))); set_snomask(cptr, 0, SNO_SET); det_confs_butmask(cptr, 0); if (cli_listener(cptr)) { release_listener(cli_listener(cptr)); cli_listener(cptr) = 0; } for ( ; HighestFd > 0; --HighestFd) { if (LocalClientArray[HighestFd]) break; } } /** Close all unregistered connections. * @param source Oper who requested the close. * @return Number of closed connections. */ int net_close_unregistered_connections(struct Client* source) { int i; struct Client* cptr; int count = 0; assert(0 != source); for (i = HighestFd; i > 0; --i) { if ((cptr = LocalClientArray[i]) && !IsRegistered(cptr)) { send_reply(source, RPL_CLOSING, get_client_name(source, HIDE_IP)); exit_client(source, cptr, &me, "Oper Closing"); ++count; } } return count; }