/** Get connection class name for a configuration item. * @param[in] aconf Configuration item to check. * @return Name of connection class associated with \a aconf. */ char* get_conf_class(const struct ConfItem* aconf) { if ((aconf) && (aconf->conn_class)) return (ConfClass(aconf)); Debug((DEBUG_DEBUG, "No Class For %s", (aconf) ? aconf->name : "*No Conf*")); return NULL; }
/* ** try_connections ** ** Scan through configuration and try new connections. ** Returns the calendar time when the next call to this ** function should be made latest. (No harm done if this ** is called earlier or later...) */ static time_t try_connections(time_t currenttime) { Reg aConfItem *aconf; Reg aClient *cptr; aConfItem **pconf; int confrq; time_t next = 0; aClass *cltmp; aConfItem *con_conf = NULL; int allheld = 1; #ifdef DISABLE_DOUBLE_CONNECTS int i; #endif if ((bootopt & BOOT_STANDALONE)) return 0; Debug((DEBUG_NOTICE,"Connection check at : %s", myctime(currenttime))); for (aconf = conf; aconf; aconf = aconf->next ) { /* not a C-line */ if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER))) continue; /* not a candidate for AC */ if (aconf->port <= 0) continue; cltmp = Class(aconf); /* not a candidate for AC */ if (MaxLinks(cltmp) == 0) continue; /* minimize next to lowest hold time of all AC-able C-lines */ if (next > aconf->hold || next == 0) next = aconf->hold; /* skip conf if the use of it is on hold until future. */ if (aconf->hold > currenttime) continue; /* at least one candidate not held for future, good */ allheld = 0; /* see if another link in this conf is allowed */ if (Links(cltmp) >= MaxLinks(cltmp)) continue; /* next possible check after connfreq secs for this C-line */ confrq = get_con_freq(cltmp); aconf->hold = currenttime + confrq; /* is this server already connected? */ cptr = find_name(aconf->name, (aClient *)NULL); if (!cptr) cptr = find_mask(aconf->name, (aClient *)NULL); /* matching client already exists, no AC to it */ if (cptr) continue; /* no such server, check D-lines */ if (find_denied(aconf->name, Class(cltmp))) continue; #ifdef DISABLE_DOUBLE_CONNECTS /* Much better would be traversing only unknown ** connections, but this requires another global ** variable, adding and removing from there in ** proper places etc. Some day. --B. */ for (i = highest_fd; i >= 0; i--) { if (!(cptr = local[i]) || cptr->status > STAT_UNKNOWN) { continue; } /* an unknown traveller we have */ if ( #ifndef INET6 cptr->ip.s_addr == aconf->ipnum.s_addr #else !memcmp(cptr->ip.s6_addr, aconf->ipnum.s6_addr, 16) #endif ) { /* IP the same. Coincidence? Maybe. ** Do not cause havoc with double connect. */ break; } cptr = NULL; } if (cptr) { sendto_flag(SCH_SERVER, "AC to %s postponed", aconf->name); continue; } #endif /* we have a candidate! */ /* choose the best. */ if (!con_conf || (con_conf->pref > aconf->pref && aconf->pref >= 0) || (con_conf->pref == -1 && Class(cltmp) > ConfClass(con_conf))) { con_conf = aconf; } /* above is my doubt: if we always choose best connection ** and it always fails connecting, we may never try another, ** even "worse"; what shall we do? --Beeth */ } if (con_conf) { if (con_conf->next) /* are we already last? */ { for (pconf = &conf; (aconf = *pconf); pconf = &(aconf->next)) /* put the current one at the end and * make sure we try all connections */ if (aconf == con_conf) *pconf = aconf->next; (*pconf = con_conf)->next = 0; } /* "Penalty" for being the best, so in next call of * try_connections() other servers have chance. --B. */ con_conf->hold += get_con_freq(Class(con_conf)); if (!iconf.aconnect) { sendto_flag(SCH_NOTICE, "Connection to %s deferred. Autoconnect " "administratively disabled", con_conf->name); } else if (connect_server(con_conf, (aClient *)NULL, (struct hostent *)NULL) == 0) { sendto_flag(SCH_NOTICE, "Connection to %s[%s] activated.", con_conf->name, con_conf->host); } } else if (allheld == 0) /* disable AC only when some C: got checked */ { /* No suitable conf for AC was found, so why bother checking ** again? If some server quits, it'd get reenabled --B. */ next = 0; } Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next))); return (next); }
/** Interpret \a client as a client specifier and show which Client * block(s) match that client. * * The client specifier may contain an IP address, hostname, listener * port, or a combination of those separated by commas. IP addresses * and hostnamese may be preceded by "username@"; the last given * username will be used for the match. * * @param[in] client Client specifier. * @return Matching Client block structure. */ struct ConfItem *conf_debug_iline(const char *client) { struct irc_in_addr address; struct ConfItem *aconf; struct DenyConf *deny; char *sep; unsigned short listener; char username[USERLEN+1], hostname[HOSTLEN+1], realname[REALLEN+1]; /* Initialize variables. */ listener = 0; memset(&address, 0, sizeof(address)); memset(&username, 0, sizeof(username)); memset(&hostname, 0, sizeof(hostname)); memset(&realname, 0, sizeof(realname)); /* Parse client specifier. */ while (*client) { struct irc_in_addr tmpaddr; long tmp; /* Try to parse as listener port number first. */ tmp = strtol(client, &sep, 10); if (tmp && (*sep == '\0' || *sep == ',')) { listener = tmp; client = sep + (*sep != '\0'); continue; } /* Maybe username@ before an IP address or hostname? */ tmp = strcspn(client, ",@"); if (client[tmp] == '@') { if (tmp > USERLEN) tmp = USERLEN; ircd_strncpy(username, client, tmp); /* and fall through */ client += tmp + 1; } /* Looks like an IP address? */ tmp = ircd_aton(&tmpaddr, client); if (tmp && (client[tmp] == '\0' || client[tmp] == ',')) { memcpy(&address, &tmpaddr, sizeof(address)); client += tmp + (client[tmp] != '\0'); continue; } /* Realname? */ if (client[0] == '$' && client[1] == 'R') { client += 2; for (tmp = 0; *client != '\0' && *client != ',' && tmp < REALLEN; ++client, ++tmp) { if (*client == '\\') realname[tmp] = *++client; else realname[tmp] = *client; } continue; } /* Else must be a hostname. */ tmp = strcspn(client, ","); if (tmp > HOSTLEN) tmp = HOSTLEN; ircd_strncpy(hostname, client, tmp); client += tmp + (client[tmp] != '\0'); } /* Walk configuration to find matching Client block. */ for (aconf = GlobalConfList; aconf; aconf = aconf->next) { if (aconf->status != CONF_CLIENT) continue; if (aconf->address.port && aconf->address.port != listener) { fprintf(stdout, "Listener port mismatch: %u != %u\n", aconf->address.port, listener); continue; } if (aconf->username && match(aconf->username, username)) { fprintf(stdout, "Username mismatch: %s != %s\n", aconf->username, username); continue; } if (aconf->host && match(aconf->host, hostname)) { fprintf(stdout, "Hostname mismatch: %s != %s\n", aconf->host, hostname); continue; } if ((aconf->addrbits >= 0) && !ipmask_check(&address, &aconf->address.addr, aconf->addrbits)) { fprintf(stdout, "IP address mismatch: %s != %s\n", aconf->name, ircd_ntoa(&address)); continue; } fprintf(stdout, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n", (aconf->username ? aconf->username : "******"), (aconf->host ? aconf->host : "(null)"), (aconf->name ? aconf->name : "(null)"), ConfClass(aconf), aconf->maximum, (aconf->passwd ? aconf->passwd : "(null)")); break; } /* If no authorization, say so and exit. */ if (!aconf) { fprintf(stdout, "No authorization found.\n"); return NULL; } /* Look for a Kill block with the user's name on it. */ for (deny = denyConfList; deny; deny = deny->next) { if (deny->usermask && match(deny->usermask, username)) continue; if (deny->realmask && match(deny->realmask, realname)) continue; if (deny->bits > 0) { if (!ipmask_check(&address, &deny->address, deny->bits)) continue; } else if (deny->hostmask && match(deny->hostmask, hostname)) continue; /* Looks like a match; report it. */ fprintf(stdout, "Denied! usermask=%s realmask=\"%s\" hostmask=%s (bits=%u)\n", deny->usermask ? deny->usermask : "(null)", deny->realmask ? deny->realmask : "(null)", deny->hostmask ? deny->hostmask : "(null)", deny->bits); } return aconf; }