/** * iteratively call find_gen() & find_kill */ void calc_genkill() { struct block *b = first_block; int i; while(b) { find_gen(b); b = b->next; } b = first_block; while(b) { find_kill(b); b = b->next; } }
static time_t check_pings(time_t currenttime) { #ifdef TIMEDKLINES static time_t lkill = 0; #endif Reg aClient *cptr; Reg int kflag = 0; aClient *bysptr = NULL; int ping = 0, i; time_t oldest = 0, timeout; char *reason = NULL; for (i = highest_fd; i >= 0; i--) { if (!(cptr = local[i]) || IsListener(cptr)) continue; #ifdef TIMEDKLINES kflag = 0; reason = NULL; /* ** Once per TIMEDKLINES seconds. ** (1 minute is minimum resolution in K-line field) */ if ((currenttime - lkill > TIMEDKLINES) && IsPerson(cptr) && !IsKlineExempt(cptr)) { kflag = find_kill(cptr, 1, &reason); } #endif ping = IsRegistered(cptr) ? cptr->ping : ACCEPTTIMEOUT; Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d a %d", cptr->name, cptr->status, ping, kflag, currenttime - cptr->lasttime)); /* * Ok, so goto's are ugly and can be avoided here but this code * is already indented enough so I think its justified. -avalon */ if (!kflag && IsRegistered(cptr) && (ping >= currenttime - cptr->lasttime)) goto ping_timeout; /* * If the server hasnt talked to us in 2*ping seconds * and it has a ping time, then close its connection. * If the client is a user and a KILL line was found * to be active, close this connection too. */ if (kflag || ((currenttime - cptr->lasttime) >= (2 * ping) && (cptr->flags & FLAGS_PINGSENT)) || (!IsRegistered(cptr) && (currenttime - cptr->firsttime) >= ping)) { if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr) || DoingXAuth(cptr))) { if (cptr->authfd >= 0) { (void)close(cptr->authfd); cptr->authfd = -1; cptr->count = 0; *cptr->buffer = '\0'; } Debug((DEBUG_NOTICE, "%s/%c%s timeout %s", (DoingDNS(cptr)) ? "DNS" : "dns", (DoingXAuth(cptr)) ? "X" : "x", (DoingAuth(cptr)) ? "AUTH" : "auth", get_client_name(cptr,TRUE))); del_queries((char *)cptr); ClearAuth(cptr); #if defined(USE_IAUTH) if (DoingDNS(cptr) || DoingXAuth(cptr)) { if (DoingDNS(cptr) && (iauth_options & XOPT_EXTWAIT)) { /* iauth wants more time */ sendto_iauth("%d d", cptr->fd); ClearDNS(cptr); cptr->lasttime = currenttime; continue; } if (DoingXAuth(cptr) && (iauth_options & XOPT_NOTIMEOUT)) { cptr->exitc = EXITC_AUTHTOUT; sendto_iauth("%d T", cptr->fd); exit_client(cptr, cptr, &me, "Authentication Timeout"); continue; } sendto_iauth("%d T", cptr->fd); SetDoneXAuth(cptr); } #endif ClearDNS(cptr); ClearXAuth(cptr); ClearWXAuth(cptr); cptr->firsttime = currenttime; cptr->lasttime = currenttime; continue; } if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) { if (cptr->serv && cptr->serv->byuid[0]) { bysptr = find_uid(cptr->serv->byuid, NULL); } /* we are interested only in *remote* opers */ if (bysptr && !MyConnect(bysptr)) { sendto_one(bysptr, ":%s NOTICE %s :" "No response from %s, closing" " link", ME, bysptr->name, get_client_name(cptr, FALSE)); } sendto_flag(SCH_NOTICE, "No response from %s closing link", get_client_name(cptr, FALSE)); } /* * this is used for KILL lines with time restrictions * on them - send a message to the user being killed * first. */ if (kflag && IsPerson(cptr)) { char buf[100]; sendto_flag(SCH_NOTICE, "Kill line active for %s", get_client_name(cptr, FALSE)); cptr->exitc = EXITC_KLINE; if (!BadPtr(reason)) sprintf(buf, "Kill line active: %.80s", reason); (void)exit_client(cptr, cptr, &me, (reason) ? buf : "Kill line active"); } else { cptr->exitc = EXITC_PING; (void)exit_client(cptr, cptr, &me, "Ping timeout"); } continue; } else if (IsRegistered(cptr) && (cptr->flags & FLAGS_PINGSENT) == 0) { /* * if we havent PINGed the connection and we havent * heard from it in a while, PING it to make sure * it is still alive. */ cptr->flags |= FLAGS_PINGSENT; /* not nice but does the job */ cptr->lasttime = currenttime - ping; sendto_one(cptr, "PING :%s", me.name); } ping_timeout: timeout = cptr->lasttime + ping; while (timeout <= currenttime) timeout += ping; if (timeout < oldest || !oldest) oldest = timeout; } #ifdef TIMEDKLINES if (currenttime - lkill > 60) lkill = currenttime; #endif if (!oldest || oldest < currenttime) oldest = currenttime + PINGFREQUENCY; if (oldest < currenttime + 30) oldest += 30; Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d", myctime(oldest), ping, oldest, currenttime)); return (oldest); }
/* Checks all clients against KILL lines. (And remove them, if found.) ** Only MAXDELAYEDKILLS at a time or all, if not defined. ** Returns 1, if still work to do, 0 if finished. */ static int delayed_kills(time_t currenttime) { static time_t dk_rehashed = 0; /* time of last rehash we're processing */ static int dk_lastfd; /* fd we last checked */ static int dk_checked; /* # clients we checked */ static int dk_killed; /* # clients we killed */ Reg aClient *cptr; Reg int i, j; if (dk_rehashed == 0) { dk_rehashed = currenttime; dk_checked = 0; dk_killed = 0; dk_lastfd = highest_fd; } #ifdef MAXDELAYEDKILLS /* checking only this many clients each time */ j = dk_lastfd - MAXDELAYEDKILLS + 1; if (j < 0) #endif j = 0; for (i = dk_lastfd; i >= j; i--) { int kflag = 0; char *reason = NULL; if (!(cptr = local[i]) || !IsPerson(cptr)) { /* for K:lines we're interested only in local, ** fully registered clients */ if (j > 0) j--; continue; } dk_checked++; kflag = find_kill(cptr, 0, &reason); /* If the client is a user and a KILL line was found ** to be active, close this connection. */ if (kflag == -1) { char buf[100]; dk_killed++; sendto_flag(SCH_NOTICE, "Kill line active for %s", get_client_name(cptr, FALSE)); cptr->exitc = EXITC_KLINE; if (!BadPtr(reason)) sprintf(buf, "Kill line active: %.80s", reason); (void)exit_client(cptr, cptr, &me, (reason) ? buf : "Kill line active"); } } dk_lastfd = i; /* from which fd to start next time */ Debug((DEBUG_DEBUG, "DelayedKills killed %d and counting...", dk_killed)); if (dk_lastfd < 0) { sendto_flag(SCH_NOTICE, "DelayedKills checked %d killed %d " "in %d sec", dk_checked, dk_killed, currenttime - dk_rehashed); dk_rehashed = 0; if (rehashed == 2) { /* there was rehash queued, start again */ return 1; } return 0; } return rehashed; }
static time_t check_pings(time_t currenttime) { aClient *cptr; aConfItem *aconf = (aConfItem *) NULL; int killflag, zkillflag, ping = 0, i; time_t oldest = 0; /* timeout removed, see EXPLANATION below */ char *reason, *ktype, fbuf[512]; char *errtxt = "No response from %s, closing link"; for (i = 0; i <= highest_fd; i++) { if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr)) continue; /* Note: No need to notify opers here. It's * already done when "FLAGS_DEADSOCKET" is set. */ if (cptr->flags & FLAGS_DEADSOCKET) { (void) exit_client(cptr, cptr, &me, (cptr->flags & FLAGS_SENDQEX) ? "SendQ exceeded" : "Dead socket"); i--; continue; } killflag = NO; zkillflag = NO; if (rehashed) { if (zline_in_progress) { if (IsPerson(cptr)) { if ((aconf = find_zkill(cptr))) zkillflag = YES; } } else { if(IsPerson(cptr)) { if((aconf = find_kill(cptr))) killflag = YES; } } } /* Added a bit of code here to differentiate * between K and Z-lines. -ThemBones */ if (zkillflag || killflag) { ktype = zkillflag ? "Z-lined" : ((aconf->status == CONF_KILL) ? "K-lined" : "Autokilled"); if (killflag) { sendto_ops("%s active for %s", (aconf->status == CONF_KILL) ? "K-line" : "Autokill", get_client_name(cptr, FALSE)); reason = aconf->passwd ? aconf->passwd : ktype; } else { /* its a Z line */ sendto_ops("Z-line active for %s", get_client_name(cptr, FALSE)); reason = aconf->passwd ? aconf->passwd : "Z-lined"; } sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, ktype); ircsprintf(fbuf, "%s: %s", ktype, reason); (void) exit_client(cptr, cptr, &me, fbuf); i--; /* subtract out this fd so we check it again.. */ continue; } if (IsRegistered(cptr)) ping = cptr->pingval; else ping = CONNECTTIMEOUT; /* * Ok, so goto's are ugly and can be avoided here but this code * is already indented enough so I think its justified. -avalon * * justified by what? laziness? <g> * If the client pingtime is fine (ie, not larger than the client ping) * skip over all the checks below. - lucas */ if (ping < (currenttime - cptr->lasttime)) { /* * If the server hasnt talked to us in 2*ping seconds and it has * a ping time, then close its connection. If the client is a * user and a KILL line was found to be active, close this * connection too. */ if (((cptr->flags & FLAGS_PINGSENT) && ((currenttime - cptr->lasttime) >= (2 * ping))) || ((!IsRegistered(cptr) && (currenttime - cptr->since) >= ping))) { if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr))) { if (cptr->authfd >= 0) { (void) close(cptr->authfd); cptr->authfd = -1; cptr->count = 0; *cptr->buffer = '\0'; } #ifdef SHOW_HEADERS if (DoingDNS(cptr)) ssl_send(cptr, REPORT_FAIL_DNS, R_fail_dns, 0); if (DoingAuth(cptr)) ssl_send(cptr, REPORT_FAIL_ID, R_fail_id, 0); #endif Debug((DEBUG_NOTICE, "DNS/AUTH timeout %s", get_client_name(cptr, TRUE))); del_queries((char *) cptr); ClearAuth(cptr); ClearDNS(cptr); SetAccess(cptr); cptr->since = currenttime; continue; } if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) { ircsprintf(fbuf, "from %s: %s", me.name, errtxt); sendto_gnotice(fbuf, get_client_name(cptr, HIDEME)); ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, errtxt); sendto_serv_butone(cptr, fbuf, get_client_name(cptr, HIDEME)); } (void) exit_client(cptr, cptr, &me, "Ping timeout"); i--; /* subtract out this fd so we check it again.. */ continue; } /* don't send pings during a burst, as we send them already. */ else if (!(cptr->flags & (FLAGS_PINGSENT|FLAGS_BURST))) { /* * if we havent PINGed the connection and we havent heard from * it in a while, PING it to make sure it is still alive. */ cptr->flags |= FLAGS_PINGSENT; /* * not nice but does the job */ cptr->lasttime = currenttime - ping; sendto_one(cptr, "PING :%s", me.name); } } /* see EXPLANATION below * * timeout = cptr->lasttime + ping; * while (timeout <= currenttime) * timeout += ping; * if (timeout < oldest || !oldest) * oldest = timeout; */ /* * Check UNKNOWN connections - if they have been in this state * for > 100s, close them. */ if (IsUnknown(cptr)) if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0) (void) exit_client(cptr, cptr, &me, "Connection Timed Out"); } rehashed = 0; zline_in_progress = 0; /* EXPLANATION * on a server with a large volume of clients, at any given point * there may be a client which needs to be pinged the next second, * or even right away (a second may have passed while running * check_pings). Preserving CPU time is more important than * pinging clients out at exact times, IMO. Therefore, I am going to make * check_pings always return currenttime + 9. This means that it may take * a user up to 9 seconds more than pingfreq to timeout. Oh well. * Plus, the number is 9 to 'stagger' our check_pings calls out over * time, to avoid doing it and the other tasks ircd does at the same time * all the time (which are usually done on intervals of 5 seconds or so). * - lucas * * if (!oldest || oldest < currenttime) * oldest = currenttime + PINGFREQUENCY; */ oldest = currenttime + 9; Debug((DEBUG_NOTICE, "Next check_ping() call at: %s, %d %d %d", myctime(oldest), ping, oldest, currenttime)); return oldest; }
/* * check_klines * inputs - NONE * output - NONE * side effects - Check all connections for a pending kline against the * client, exit the client if a kline matches. */ void check_klines(void) { struct Client *client_p; /* current local client_p being examined */ struct ConfItem *aconf = (struct ConfItem *)NULL; char *reason; /* pointer to reason string */ dlink_node *ptr, *next_ptr; for (ptr = lclient_list.head; ptr; ptr = next_ptr) { next_ptr = ptr->next; client_p = ptr->data; if (IsMe(client_p)) continue; /* if there is a returned struct ConfItem then kill it */ if ((aconf = find_dline(&client_p->localClient->ip, client_p->localClient->aftype))) { if (aconf->status & CONF_EXEMPTDLINE) continue; sendto_realops_flags(FLAGS_ALL, L_ALL,"DLINE active for %s", get_client_name(client_p, HIDE_IP)); if (ConfigFileEntry.kline_with_connection_closed && ConfigFileEntry.kline_with_reason) { reason = "Connection closed"; if(IsPerson(client_p)) sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP), me.name, client_p->name, aconf->passwd ? aconf->passwd : "D-lined"); else sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined"); } else { if(ConfigFileEntry.kline_with_connection_closed) reason = "Connection closed"; else if(ConfigFileEntry.kline_with_reason && aconf->passwd) reason = aconf->passwd; else reason = "D-lined"; if(IsPerson(client_p)) sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP), me.name, client_p->name, reason); else sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined"); } (void)exit_client(client_p, client_p, &me, reason); continue; /* and go examine next fd/client_p */ } if (IsPerson(client_p)) { if (ConfigFileEntry.glines && (aconf = find_gkill(client_p, client_p->username))) { if (IsExemptKline(client_p)) { sendto_realops_flags(FLAGS_ALL, L_ALL, "GLINE over-ruled for %s, client is kline_exempt", get_client_name(client_p, HIDE_IP)); continue; } if (IsExemptGline(client_p)) { sendto_realops_flags(FLAGS_ALL, L_ALL, "GLINE over-ruled for %s, client is gline_exempt", get_client_name(client_p, HIDE_IP)); continue; } sendto_realops_flags(FLAGS_ALL, L_ALL, "GLINE active for %s", get_client_name(client_p, HIDE_IP)); if(ConfigFileEntry.kline_with_connection_closed && ConfigFileEntry.kline_with_reason) { reason = "Connection closed"; sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP), me.name, client_p->name, aconf->passwd ? aconf->passwd : "G-lined"); } else { if(ConfigFileEntry.kline_with_connection_closed) reason = "Connection closed"; else if(ConfigFileEntry.kline_with_reason && aconf->passwd) reason = aconf->passwd; else reason = "G-lined"; sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP), me.name, client_p->name, reason); } (void)exit_client(client_p, client_p, &me, reason); /* and go examine next fd/client_p */ continue; } else if((aconf = find_kill(client_p))) { /* if there is a returned struct ConfItem.. then kill it */ if (IsExemptKline(client_p)) { sendto_realops_flags(FLAGS_ALL, L_ALL, "KLINE over-ruled for %s, client is kline_exempt", get_client_name(client_p, HIDE_IP)); continue; } sendto_realops_flags(FLAGS_ALL, L_ALL, "KLINE active for %s", get_client_name(client_p, HIDE_IP)); if(ConfigFileEntry.kline_with_connection_closed && ConfigFileEntry.kline_with_reason) { reason = "Connection closed"; sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP), me.name, client_p->name, aconf->passwd ? aconf->passwd : "K-lined"); } else { if(ConfigFileEntry.kline_with_connection_closed) reason = "Connection closed"; else if(ConfigFileEntry.kline_with_reason && aconf->passwd) reason = aconf->passwd; else reason = "K-lined"; sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP), me.name, client_p->name, reason); } (void)exit_client(client_p, client_p, &me, reason); continue; } } } /* also check the unknowns list for new dlines */ for (ptr = unknown_list.head; ptr; ptr = next_ptr) { next_ptr = ptr->next; client_p = ptr->data; if((aconf = find_dline(&client_p->localClient->ip, client_p->localClient->aftype))) { if(aconf->status & CONF_EXEMPTDLINE) continue; sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined"); exit_client(client_p, client_p, &me, "D-lined"); } } }
static time_t check_pings(time_t currenttime) { register aClient *cptr; /* current local cptr being examined */ aConfItem *aconf = (aConfItem *)NULL; int ping = 0; /* ping time value from client */ int i; /* used to index through fd/cptr's */ time_t oldest = 0; /* next ping time */ time_t timeout; /* found necessary ping time */ char *reason; /* pointer to reason string */ int die_index=0; /* index into list */ char ping_time_out_buffer[64]; /* blech that should be a define */ /* of dying clients */ dying_clients[0] = (aClient *)NULL; /* mark first one empty */ /* * I re-wrote the way klines are handled. Instead of rescanning * the local[] array and calling exit_client() right away, I * mark the client thats dying by placing a pointer to its aClient * into dying_clients[]. When I have examined all in local[], * I then examine the dying_clients[] for aClient's to exit. * This saves the rescan on k-lines, also greatly simplifies the code, * * Jan 28, 1998 * -Dianora */ for (i = 0; i <= highest_fd; i++) { if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr)) continue; /* and go examine next fd/cptr */ /* ** Note: No need to notify opers here. It's ** already done when "FLAGS_DEADSOCKET" is set. */ if (cptr->flags & FLAGS_DEADSOCKET) { /* N.B. EVERY single time dying_clients[] is set * it must be followed by an immediate continue, * to prevent this cptr from being marked again for exit. * If you don't, you could cause exit_client() to be called twice * for the same cptr. i.e. bad news * -Dianora */ dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = ((cptr->flags & FLAGS_SENDQEX) ? "SendQ exceeded" : "Dead socket"); dying_clients[die_index] = (aClient *)NULL; continue; /* and go examine next fd/cptr */ } if (rehashed) { if(dline_in_progress) { if(IsPerson(cptr)) { if( (aconf = find_dkill(cptr)) ) /* if there is a returned aConfItem then kill it */ { sendto_ops("D-line active for %s", get_client_name(cptr, FALSE)); dying_clients[die_index] = cptr; #ifdef KLINE_WITH_REASON reason = aconf->passwd ? aconf->passwd : "D-lined"; dying_clients_reason[die_index++] = reason; #else dying_clients_reason[die_index++] = "D-lined"; #endif dying_clients[die_index] = (aClient *)NULL; sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, reason); continue; /* and go examine next fd/cptr */ } } } else { if(IsPerson(cptr)) { #ifdef GLINES if( (aconf = find_gkill(cptr)) ) { sendto_ops("G-line active for %s", get_client_name(cptr, FALSE)); dying_clients[die_index] = cptr; #ifdef KLINE_WITH_REASON reason = aconf->passwd ? aconf->passwd : "G-lined"; dying_clients_reason[die_index++] = reason; #else dying_clients_reason[die_index++] = "G-lined"; #endif dying_clients[die_index] = (aClient *)NULL; sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, reason); continue; /* and go examine next fd/cptr */ } else #endif if((aconf = find_kill(cptr))) /* if there is a returned aConfItem.. then kill it */ { sendto_ops("K-line active for %s", get_client_name(cptr, FALSE)); dying_clients[die_index] = cptr; #ifdef KLINE_WITH_REASON #ifdef K_COMMENT_ONLY reason = aconf->passwd ? aconf->passwd : "K-lined"; #else reason = (BadPtr(aconf->passwd) || !is_comment(aconf->passwd)) ? "K-lined" : aconf->passwd; #endif dying_clients_reason[die_index++] = reason; #else dying_clients_reason[die_index++] = "K-lined"; #endif dying_clients[die_index] = (aClient *)NULL; sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, reason); continue; /* and go examine next fd/cptr */ } } } } #ifdef IDLE_CHECK if (IsPerson(cptr)) { if( !IsElined(cptr) && ((timeofday - cptr->user->last) > idle_time)) { aConfItem *aconf; dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "idle exceeder"; dying_clients[die_index] = (aClient *)NULL; aconf = make_conf(); aconf->status = CONF_KILL; DupString(aconf->host, cptr->user->host); DupString(aconf->passwd, "idle exceeder" ); DupString(aconf->name, cptr->user->username); aconf->port = 0; aconf->hold = timeofday + 60; add_temp_kline(aconf); sendto_ops("Idle exceeder %s temp k-lining", get_client_name(cptr,FALSE)); continue; /* and go examine next fd/cptr */ } } #endif #ifdef REJECT_HOLD if (IsRejectHeld(cptr)) { if( timeofday > (cptr->firsttime + REJECT_HOLD_TIME) ) { dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "reject held client"; dying_clients[die_index] = (aClient *)NULL; continue; /* and go examine next fd/cptr */ } } #endif #if defined(R_LINES) && defined(R_LINES_OFTEN) /* * this is used for KILL lines with time restrictions * on them - send a message to the user being killed * first. * *** Moved up above -taner *** * * Moved here, no more rflag -Dianora */ if (IsPerson(cptr) && find_restrict(cptr)) { sendto_ops("Restricting %s, closing link.", get_client_name(cptr,FALSE)); dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "you have been R-lined"; dying_clients[die_index] = (aClient *)NULL; continue; /* and go examine next fd/cptr */ } #endif if (!IsRegistered(cptr)) ping = CONNECTTIMEOUT; else ping = get_client_ping(cptr); /* * Ok, so goto's are ugly and can be avoided here but this code * is already indented enough so I think its justified. -avalon */ /* if (!rflag && (ping >= currenttime - cptr->lasttime)) goto ping_timeout; */ /* * *sigh* I think not -Dianora */ if (ping < (currenttime - cptr->lasttime)) { /* * If the server hasnt talked to us in 2*ping seconds * and it has a ping time, then close its connection. * If the client is a user and a KILL line was found * to be active, close this connection too. */ if (((currenttime - cptr->lasttime) >= (2 * ping) && (cptr->flags & FLAGS_PINGSENT)) || ((!IsRegistered(cptr) && (currenttime - cptr->since) >= ping))) { if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr))) { if (cptr->authfd >= 0) { (void)close(cptr->authfd); cptr->authfd = -1; cptr->count = 0; *cptr->buffer = '\0'; } #ifdef SHOW_HEADERS if (DoingDNS(cptr)) send(cptr->fd, REPORT_FAIL_DNS, R_fail_dns, 0); else send(cptr->fd, REPORT_FAIL_ID, R_fail_id, 0); #endif Debug((DEBUG_NOTICE,"DNS/AUTH timeout %s", get_client_name(cptr,TRUE))); del_queries((char *)cptr); ClearAuth(cptr); ClearDNS(cptr); SetAccess(cptr); cptr->since = currenttime; continue; } if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) { sendto_ops("No response from %s, closing link", get_client_name(cptr, FALSE)); } /* * this is used for KILL lines with time restrictions * on them - send a messgae to the user being killed * first. * *** Moved up above -taner *** */ cptr->flags2 |= FLAGS2_PING_TIMEOUT; dying_clients[die_index++] = cptr; /* the reason is taken care of at exit time */ /* dying_clients_reason[die_index++] = "Ping timeout"; */ dying_clients[die_index] = (aClient *)NULL; /* * need to start loop over because the close can * affect the ordering of the local[] array.- avalon * ** Not if you do it right - Dianora */ continue; } else if ((cptr->flags & FLAGS_PINGSENT) == 0) { /* * if we havent PINGed the connection and we havent * heard from it in a while, PING it to make sure * it is still alive. */ cptr->flags |= FLAGS_PINGSENT; /* not nice but does the job */ cptr->lasttime = currenttime - ping; sendto_one(cptr, "PING :%s", me.name); } } /* ping_timeout: */ timeout = cptr->lasttime + ping; while (timeout <= currenttime) timeout += ping; if (timeout < oldest || !oldest) oldest = timeout; /* * Check UNKNOWN connections - if they have been in this state * for > 100s, close them. */ if (IsUnknown(cptr)) { if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0) { dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "Connection Timed Out"; dying_clients[die_index] = (aClient *)NULL; continue; } } } /* Now exit clients marked for exit above. * it doesn't matter if local[] gets re-arranged now * * -Dianora */ for(die_index = 0; (cptr = dying_clients[die_index]); die_index++) { if(cptr->flags2 & FLAGS2_PING_TIMEOUT) { (void)ircsprintf(ping_time_out_buffer, "Ping timeout: %d seconds", currenttime - cptr->lasttime); (void)exit_client(cptr, cptr, &me, ping_time_out_buffer ); } else (void)exit_client(cptr, cptr, &me, dying_clients_reason[die_index]); } rehashed = 0; dline_in_progress = 0; if (!oldest || oldest < currenttime) oldest = currenttime + PINGFREQUENCY; Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d", myctime(oldest), ping, oldest, currenttime)); return (oldest); }
/* * m_notice - generic message handler */ int m_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char* name; char* server; int ret = 0; int i; int j; int fd = 0; int count; char *clean; char* vector[MAXTARGETS]; char* temp; /* added by Vadtec 02/25/2008 */ char* parv_temp; /* added by Vadtec 02/26/2008 */ int found_g = 0; /* added by Vadtec 02/26/2008 */ int sent = 0; /* added by Vadtec 03/13/2008 */ struct Client* acptr; /* added by Vadtec 02/26/2008 */ struct Channel* chptr; /* added by Vadtec 02/27/2008 */ int isdcc = 0; assert(0 != cptr); assert(cptr == sptr); ClrFlag(sptr, FLAG_TS8); if (parc < 2 || EmptyString(parv[1])) return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE); if (parc < 3 || EmptyString(parv[parc - 1])) return send_reply(sptr, ERR_NOTEXTTOSEND); if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) { parv[1]++; /* Get rid of '@' */ return m_wallchops(cptr, sptr, parc, parv); } count = unique_name_vector(parv[1], ',', vector, MAXTARGETS); /* Check here to make sure that the client is ours so we dont respond to NOTICES from other server's users. - Vadtec 02/25/2008 */ /* Also, check to make sure that the notice is actually destined for the *server* and not another user. That way we don't process some user saying "what version do you use" to another user via notice. - Vadtec 03/13/2008 */ if (feature_bool(FEAT_CTCP_VERSIONING) && MyConnect(sptr) && !strcmp(parv[1], cli_name(&me))) { /* Added by Vadtec 02/25/2008. This is so that we can do version checking (and banning) of connecting clients. Rules: Only one really. CTCP VERSION is not part of the RFC and therefore clients are not required to respond to a request for their version. NOTE: If we are lucky enough to have _GNU_SOURCE, we will use it over the standard strstr because its case insensetive. This should help against clients that like to send lower case CTCPs from slipping through as easily with only one function call. */ for (fd = HighestFd; fd >= 0 && !sent; --fd) { /* Added the "sent" check here so that if we have already sent the notice we don't needlessly loop through *all* the users - Vadtec 03/13/2008 */ if ((acptr = LocalClientArray[fd])) { if (!cli_user(acptr)) continue; #ifdef _GNU_SOURCE if ((temp = strcasestr(parv[2], "\x01VERSION"))) { /* added \x01 to the string so that it will *only* respond to CTCP version replies. Seems redundant, but we dont want the users doing /notice <server> version (and getting away with it) - Vadtec 03/13/2008 */ temp = strchrnul(parv[2], ' '); /* Moved this here to take advantage of strchrnul - added by Vadtec 03/13/2008 */ #else if ((temp = strstr(parv[2], "\x01VERSION")) || (temp = strstr(parv[2], "\x01version"))) { /* See above comment about \x01 - Vadtec */ temp = strchr(parv[2], ' '); /* Moved this here to take advantage of strchrnul - added by Vadtec 03/13/2008 */ if (temp == 0) temp = parv[2] + strlen(parv[2]); /* This does the same thing as strchrnul - Vadtec */ #endif parv_temp = parv[2]; j = 0; while (j <= (temp - parv[2])) { parv_temp++; j++; } clean = normalizeBuffer(parv_temp); doCleanBuffer((char *) clean); ircd_strncpy(cli_version(sptr), normalizeBuffer(clean), VERSIONLEN); sendcmdto_serv_butone(&me, CMD_MARK, cptr, "%s %s :%s", cli_name(sptr), MARK_CVERSION, cli_version(sptr)); /* Moved here to solve duplicate MARK's if any of the CTCP_* conditions were false 05/13/2009 */ sent = 1; if (feature_bool(FEAT_CTCP_VERSIONING_CHAN)) { sprintf(temp, "%s has version \002%s\002", cli_name(sptr), cli_version(sptr)); /* Announce to channel. */ if ((chptr = FindChannel(feature_str(FEAT_CTCP_VERSIONING_CHANNAME)))) { if (feature_bool(FEAT_CTCP_VERSIONING_USEMSG)) sendcmdto_channel_butone(&me, CMD_PRIVATE, chptr, cptr, SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, temp); else sendcmdto_channel_butone(&me, CMD_NOTICE, chptr, cptr, SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, temp); /* Removed sent=1 from here because it caused the MARK above to be sent more then once if any of the conditions leading here are false 05/13/2009 */ } } if (feature_bool(FEAT_CTCP_VERSIONING_KILL)) { if ((found_g = find_kill(acptr))) { sendto_opmask_butone(0, found_g == -2 ? SNO_GLINE : SNO_OPERKILL, found_g == -2 ? "G-line active for %s%s" : "K-line active for %s%s", IsUnknown(sptr) ? "Unregistered Client ":"", get_client_name(sptr, SHOW_IP)); return exit_client_msg(cptr, acptr, &me, "Banned Client: %s", cli_version(acptr)); } } else return 0; } } } } for (i = 0; i < count; ++i) { name = vector[i]; if (IsChannelPrefix(*name)) { ret = find_fline(cptr, sptr, parv[parc-1], WFFLAG_CHANNOTICE, name); if (ret != 0) { if (ret == 2) return CPTR_KILLED; else return 0; } } else { #ifdef _GNU_SOURCE if ((temp = strcasestr(parv[2], "\001DCC"))) { temp = strchrnul(parv[2], ' '); #else if ((temp = strstr(parv[2], "\001DCC")) || (temp = strstr(parv[2], "\001dcc"))) { temp = strchr(parv[2], ' '); #endif isdcc = 1; ret = find_fline(cptr, sptr, parv[parc-1], WFFLAG_DCC, name); if (ret != 0) { if (ret == 2) return CPTR_KILLED; else return 0; } } if (!isdcc) { ret = find_fline(cptr, sptr, parv[parc-1], WFFLAG_NOTICE, name); if (ret != 0) { if (ret == 2) return CPTR_KILLED; else return 0; } } } } i = 0; for (i = 0; i < count; ++i) { name = vector[i]; /* * channel msg? */ if (IsChannelPrefix(*name)) { relay_channel_notice(sptr, name, parv[parc - 1], count); } /* * we have to check for the '@' at least once no matter what we do * handle it first so we don't have to do it twice */ else if ((server = strchr(name, '@'))) relay_directed_notice(sptr, name, server, parv[parc - 1]); else relay_private_notice(sptr, name, parv[parc - 1]); } return 0; } /* * ms_notice - server message handler */ int ms_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char* name; char* server; ClrFlag(sptr, FLAG_TS8); if (parc < 3) { /* * we can't deliver it, sending an error back is pointless */ return protocol_violation(sptr,"Not enough params for NOTICE"); } name = parv[1]; /* * channel msg? */ if (IsChannelPrefix(*name)) { server_relay_channel_notice(sptr, name, parv[parc - 1]); } /* * coming from another server, we have to check this here */ else if ('$' == *name && IsOper(sptr)) { server_relay_masked_notice(sptr, name, parv[parc - 1]); } else if ((server = strchr(name, '@'))) { /* * XXX - can't get away with not doing everything * relay_directed_notice has to do */ relay_directed_notice(sptr, name, server, parv[parc - 1]); } else { server_relay_private_notice(sptr, name, parv[parc - 1]); } return 0; } /* * mo_notice - oper message handler */ int mo_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char* name; char* server; int i; int count; char* vector[MAXTARGETS]; assert(0 != cptr); assert(cptr == sptr); ClrFlag(sptr, FLAG_TS8); if (parc < 2 || EmptyString(parv[1])) return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE); if (parc < 3 || EmptyString(parv[parc - 1])) return send_reply(sptr, ERR_NOTEXTTOSEND); if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) { parv[1]++; /* Get rid of '@' */ return m_wallchops(cptr, sptr, parc, parv); } count = unique_name_vector(parv[1], ',', vector, MAXTARGETS); for (i = 0; i < count; ++i) { name = vector[i]; /* * channel msg? */ if (IsChannelPrefix(*name)) relay_channel_notice(sptr, name, parv[parc - 1], count); else if (*name == '$') relay_masked_notice(sptr, name, parv[parc - 1]); else if ((server = strchr(name, '@'))) relay_directed_notice(sptr, name, server, parv[parc - 1]); else relay_private_notice(sptr, name, parv[parc - 1]); } return 0; }
/** Reload the configuration file. * @param cptr Client that requested rehash (if a signal, &me). * @param sig Type of rehash (0 = oper-requested, 1 = signal, 2 = * oper-requested but do not restart resolver) * @return CPTR_KILLED if any client was K/G-lined because of the * rehash; otherwise 0. */ int rehash(struct Client *cptr, int sig) { struct ConfItem** tmp = &GlobalConfList; struct ConfItem* tmp2; struct Client* acptr; int i; int ret = 0; int found_g = 0; if (1 == sig) sendto_opmask_butone(0, SNO_OLDSNO, "Got signal SIGHUP, reloading ircd conf. file"); while ((tmp2 = *tmp)) { if (tmp2->clients) { /* * Configuration entry is still in use by some * local clients, cannot delete it--mark it so * that it will be deleted when the last client * exits... */ if (CONF_CLIENT == (tmp2->status & CONF_CLIENT)) tmp = &tmp2->next; else { *tmp = tmp2->next; tmp2->next = 0; } tmp2->status |= CONF_ILLEGAL; } else { *tmp = tmp2->next; free_conf(tmp2); } } conf_erase_crule_list(); conf_erase_deny_list(); conf_erase_webirc_list(); conf_erase_shost_list(); conf_erase_except_list(); motd_clear(); /* * delete the juped nicks list */ clearNickJupes(); clear_quarantines(); class_mark_delete(); mark_listeners_closing(); auth_mark_closing(); close_mappings(); read_configuration_file(); if (sig != 2) restart_resolver(); log_reopen(); /* reopen log files */ auth_close_unused(); close_listeners(); class_delete_marked(); /* unless it fails */ /* * Flush out deleted I and P lines although still in use. */ for (tmp = &GlobalConfList; (tmp2 = *tmp);) { if (CONF_ILLEGAL == (tmp2->status & CONF_ILLEGAL)) { *tmp = tmp2->next; tmp2->next = NULL; if (!tmp2->clients) free_conf(tmp2); } else tmp = &tmp2->next; } for (i = 0; i <= HighestFd; i++) { if ((acptr = LocalClientArray[i])) { assert(!IsMe(acptr)); if (IsServer(acptr)) det_confs_butmask(acptr, ~(CONF_UWORLD | CONF_ILLEGAL)); /* Because admin's are getting so uppity about people managing to * get past K/G's etc, we'll "fix" the bug by actually explaining * whats going on. */ if ((found_g = find_kill(acptr))) { sendto_opmask_butone(0, found_g > -1 ? SNO_GLINE : SNO_OPERKILL, found_g == -2 ? "G-line active for %s%s" : (found_g == -3 ? "Z-line active for %s%s" : "K-line active for %s%s"), IsUnknown(acptr) ? "Unregistered Client ":"", get_client_name(acptr, SHOW_IP)); if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" : (found_g == -3 ? "Z-lined" : "K-lined")) == CPTR_KILLED) ret = CPTR_KILLED; } } } attach_conf_uworld(&me); geoip_init(); auth_send_event("rehash", NULL); return ret; }