Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/VibeDevelopers/Comet.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659/* * ircd-ratbox: A slightly useful ircd. * m_server.c: Introduces a server. * * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 2002-2005 ircd-ratbox development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */
#include "stdinc.h"#include "client.h" /* client struct */#include "hash.h" /* add_to_client_hash */#include "match.h"#include "ircd.h" /* me */#include "numeric.h" /* ERR_xxx */#include "s_conf.h" /* struct ConfItem */#include "s_newconf.h"#include "logger.h" /* log level defines */#include "s_serv.h" /* server_estab, check_server */#include "s_stats.h" /* ServerStats */#include "scache.h"#include "send.h" /* sendto_one */#include "msg.h"#include "parse.h"#include "modules.h"
static const char server_desc[] = "Provides the TS6 commands to introduce a new server to the network";
static void mr_server(struct MsgBuf *, struct Client *, struct Client *, int, const char **);static void ms_server(struct MsgBuf *, struct Client *, struct Client *, int, const char **);static void ms_sid(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
static bool bogus_host(const char *host);static void set_server_gecos(struct Client *, const char *);
struct Message server_msgtab = { "SERVER", 0, 0, 0, 0, {{mr_server, 4}, mg_reg, mg_ignore, {ms_server, 4}, mg_ignore, mg_reg}};struct Message sid_msgtab = { "SID", 0, 0, 0, 0, {mg_ignore, mg_reg, mg_ignore, {ms_sid, 5}, mg_ignore, mg_reg}};
mapi_clist_av1 server_clist[] = { &server_msgtab, &sid_msgtab, NULL };
DECLARE_MODULE_AV2(server, NULL, NULL, server_clist, NULL, NULL, NULL, NULL, server_desc);
/* * mr_server - SERVER message handler * parv[1] = servername * parv[2] = serverinfo/hopcount * parv[3] = serverinfo */static voidmr_server(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ char info[REALLEN + 1]; const char *name; struct Client *target_p; int hop; unsigned int required_mask; const char *missing; int ret;
name = parv[1]; hop = atoi(parv[2]); rb_strlcpy(info, parv[3], sizeof(info));
if (IsHandshake(client_p) && irccmp(client_p->name, name)) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Server %s has unexpected name %s", client_p->name, name); ilog(L_SERVER, "Server %s has unexpected name %s", log_client_name(client_p, SHOW_IP), name); exit_client(client_p, client_p, client_p, "Server name mismatch"); return; }
/* * Reject a direct nonTS server connection if we're TS_ONLY -orabidoo */ if(!DoesTS(client_p)) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Link %s dropped, non-TS server", client_p->name); exit_client(client_p, client_p, client_p, "Non-TS server"); return; }
if(bogus_host(name)) { exit_client(client_p, client_p, client_p, "Bogus server name"); return; }
/* Now we just have to call check_server and everything should be * check for us... -A1kmm. */ ret = check_server(name, client_p); switch (ret) { case 0: /* success */ break; case -1: if(ConfigFileEntry.warn_no_nline) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unauthorised server connection attempt from %s: " "No entry for servername %s", "[@255.255.255.255]", name);
ilog(L_SERVER, "Access denied, no connect block for server %s%s", EmptyString(client_p->name) ? name : "", log_client_name(client_p, SHOW_IP)); }
exit_client(client_p, client_p, client_p, "Invalid servername."); return; /* NOT REACHED */ break;
case -2: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unauthorised server connection attempt from %s: " "Bad credentials for server %s", "[@255.255.255.255]", name);
ilog(L_SERVER, "Access denied, invalid credentials for server %s%s", EmptyString(client_p->name) ? name : "", log_client_name(client_p, SHOW_IP));
exit_client(client_p, client_p, client_p, "Invalid credentials."); return; /* NOT REACHED */ break;
case -3: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unauthorised server connection attempt from %s: " "Invalid host for server %s", "[@255.255.255.255]", name);
ilog(L_SERVER, "Access denied, invalid host for server %s%s", EmptyString(client_p->name) ? name : "", log_client_name(client_p, SHOW_IP));
exit_client(client_p, client_p, client_p, "Invalid host."); return; /* NOT REACHED */ break;
/* servername is > HOSTLEN */ case -4: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Invalid servername %s from %s", name, "[@255.255.255.255]"); ilog(L_SERVER, "Access denied, invalid servername from %s", log_client_name(client_p, SHOW_IP));
exit_client(client_p, client_p, client_p, "Invalid servername."); return; /* NOT REACHED */ break; case -5: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Connection from servername %s requires SSL/TLS but is plaintext", name); ilog(L_SERVER, "Access denied, requires SSL/TLS but is plaintext from %s", log_client_name(client_p, SHOW_IP));
exit_client(client_p, client_p, client_p, "Access denied, requires SSL/TLS but is plaintext"); return; case -6: if (client_p->certfp) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Connection from servername %s has invalid certificate fingerprint %s", name, client_p->certfp); ilog(L_SERVER, "Access denied, invalid certificate fingerprint %s from %s", client_p->certfp, log_client_name(client_p, SHOW_IP)); exit_client(client_p, client_p, client_p, "Invalid fingerprint."); } else { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Connection from servername %s failed certificate validation", name); ilog(L_SERVER, "Access denied; certificate validation failed for certificate from %s", log_client_name(client_p, SHOW_IP)); exit_client(client_p, client_p, client_p, "Invalid certificate."); }
return; case -7: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Connection from servername %s rejected, no more connections allowed in class", name); ilog(L_SERVER, "Access denied, no more connections allowed in class for %s", log_client_name(client_p, SHOW_IP));
exit_client(client_p, client_p, client_p, "Access denied, no more connections allowed in class"); return; default: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Connection from servername %s rejected, unknown error %d", name, ret); ilog(L_SERVER, "Access denied, unknown error %d for server %s%s", ret, EmptyString(client_p->name) ? name : "", log_client_name(client_p, SHOW_IP));
exit_client(client_p, client_p, client_p, "Unknown error."); return; }
/* require TS6 for direct links */ if (!IsServerCapable(client_p, CAP_TS6)) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Link %s dropped, TS6 protocol is required", name); exit_client(client_p, client_p, client_p, "Incompatible TS version"); return; }
/* check to ensure any "required" caps are set. --nenolod */ required_mask = capability_index_get_required(serv_capindex); if (!IsServerCapable(client_p, required_mask)) { missing = capability_index_list(serv_capindex, required_mask & ~client_p->localClient->server_caps); sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Link %s dropped, required CAPABs [%s] are missing", name, missing); ilog(L_SERVER, "Link %s%s dropped, required CAPABs [%s] are missing", EmptyString(client_p->name) ? name : "", log_client_name(client_p, SHOW_IP), missing); /* Do not use '[' in the below message because it would cause * it to be considered potentially unsafe (might disclose IP * addresses) */ sendto_one(client_p, "ERROR :Missing required CAPABs (%s)", missing); exit_client(client_p, client_p, client_p, "Missing required CAPABs");
return; }
if((target_p = find_server(NULL, name))) { /* * This link is trying feed me a server that I already have * access through another path -- multiple paths not accepted * currently, kill this link immediately!! * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon * * Definitely don't do that here. This is from an unregistered * connect - A1kmm. */ if (target_p->servptr->flags & FLAGS_SERVICE) { /* Assume any servers introduced by services * are jupes. * -- jilles */ sendto_one(client_p, "ERROR :Server juped."); } else { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Attempt to re-introduce server %s from %s", name, "[@255.255.255.255]"); ilog(L_SERVER, "Attempt to re-introduce server %s from %s", name, log_client_name(client_p, SHOW_IP));
sendto_one(client_p, "ERROR :Server already exists."); } exit_client(client_p, client_p, client_p, "Server Exists"); return; }
if (client_p->preClient && !EmptyString(client_p->preClient->id)) { if ((target_p = find_id(client_p->preClient->id)) != NULL) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Attempt to re-introduce SID %s from %s%s (already in use by %s)", client_p->preClient->id, EmptyString(client_p->name) ? name : "", client_p->name, target_p->name); ilog(L_SERVER, "Attempt to re-introduce SID %s from %s%s (already in use by %s)", client_p->preClient->id, EmptyString(client_p->name) ? name : "", log_client_name(client_p, SHOW_IP), target_p->name);
sendto_one(client_p, "ERROR :SID already exists."); exit_client(client_p, client_p, client_p, "SID Exists"); return; } else { rb_strlcpy(client_p->id, client_p->preClient->id, sizeof(client_p->id)); } }
/* * if we are connecting (Handshake), we already have the name from the * C:line in client_p->name */
rb_strlcpy(client_p->name, name, sizeof(client_p->name)); set_server_gecos(client_p, info); client_p->hopcount = hop; server_estab(client_p);}
/* * ms_server - SERVER message handler * parv[1] = servername * parv[2] = serverinfo/hopcount * parv[3] = serverinfo */static voidms_server(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ char info[REALLEN + 1]; /* same size as in s_misc.c */ const char *name; struct Client *target_p; hook_data_client hdata; int hop; char squitreason[160];
name = parv[1]; hop = atoi(parv[2]); rb_strlcpy(info, parv[3], sizeof(info));
if(find_server(NULL, name)) { /* * This link is trying feed me a server that I already have * access through another path -- multiple paths not accepted * currently, kill this link immediately!! * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon * * I think that we should exit the link itself, not the introducer, * and we should always exit the most recently received(i.e. the * one we are receiving this SERVER for. -A1kmm * * You *cant* do this, if you link somewhere, it bursts you a server * that already exists, then sends you a client burst, you squit the * server, but you keep getting the burst of clients on a server that * doesnt exist, although ircd can handle it, its not a realistic * solution.. --fl_ */ ilog(L_SERVER, "Link %s cancelled, server %s already exists", client_p->name, name);
snprintf(squitreason, sizeof squitreason, "Server %s already exists", name); exit_client(client_p, client_p, &me, squitreason); return; }
/* * User nicks never have '.' in them and server names * must always have '.' in them. */ if(strchr(name, '.') == NULL) { /* * Server trying to use the same name as a person. Would * cause a fair bit of confusion. Enough to make it hellish * for a while and servers to send stuff to the wrong place. */ sendto_one(client_p, "ERROR :Nickname %s already exists!", name); sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Link %s cancelled: Server/nick collision on %s", client_p->name, name); ilog(L_SERVER, "Link %s cancelled: Server/nick collision on %s", client_p->name, name);
exit_client(client_p, client_p, client_p, "Nick as Server"); return; }
/* * Server is informing about a new server behind * this link. Create REMOTE server structure, * add it to list and propagate word to my other * server links... */
if(strlen(name) > HOSTLEN) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Link %s introduced server with invalid servername %s", client_p->name, name); ilog(L_SERVER, "Link %s introduced server with invalid servername %s", client_p->name, name);
exit_client(NULL, client_p, &me, "Invalid servername introduced."); return; }
target_p = make_client(client_p); make_server(target_p); target_p->hopcount = hop;
rb_strlcpy(target_p->name, name, sizeof(target_p->name));
set_server_gecos(target_p, info);
target_p->servptr = source_p;
SetServer(target_p);
rb_dlinkAddTail(target_p, &target_p->node, &global_client_list); rb_dlinkAddTailAlloc(target_p, &global_serv_list); add_to_client_hash(target_p->name, target_p); rb_dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->servers);
target_p->serv->nameinfo = scache_connect(target_p->name, target_p->info, IsHidden(target_p));
sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s SERVER %s %d :%s%s", source_p->name, target_p->name, target_p->hopcount + 1, IsHidden(target_p) ? "(H) " : "", target_p->info);
sendto_realops_snomask(SNO_EXTERNAL, L_ALL, "Server %s being introduced by %s", target_p->name, source_p->name);
/* quick, dirty EOB. you know you love it. */ sendto_one(target_p, ":%s PING %s %s", get_id(&me, target_p), me.name, target_p->name);
hdata.client = source_p; hdata.target = target_p; call_hook(h_server_introduced, &hdata);}
static voidms_sid(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ struct Client *target_p; hook_data_client hdata; char squitreason[160];
/* collision on the name? */ if(find_server(NULL, parv[1]) != NULL) { ilog(L_SERVER, "Link %s cancelled, server %s already exists", client_p->name, parv[1]);
snprintf(squitreason, sizeof squitreason, "Server %s already exists", parv[1]); exit_client(NULL, client_p, &me, squitreason); return; }
/* collision on the SID? */ if((target_p = find_id(parv[3])) != NULL) { sendto_wallops_flags(UMODE_WALLOP, &me, "Link %s cancelled, SID %s for server %s already in use by %s", client_p->name, parv[3], parv[1], target_p->name); sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s WALLOPS :Link %s cancelled, SID %s for server %s already in use by %s", me.id, client_p->name, parv[3], parv[1], target_p->name); ilog(L_SERVER, "Link %s cancelled, SID %s for server %s already in use by %s", client_p->name, parv[3], parv[1], target_p->name);
snprintf(squitreason, sizeof squitreason, "SID %s for %s already in use by %s", parv[3], parv[1], target_p->name); exit_client(NULL, client_p, &me, squitreason); return; }
if(bogus_host(parv[1]) || strlen(parv[1]) > HOSTLEN) { sendto_one(client_p, "ERROR :Invalid servername"); sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Link %s cancelled, servername %s invalid", client_p->name, parv[1]); ilog(L_SERVER, "Link %s cancelled, servername %s invalid", client_p->name, parv[1]);
exit_client(NULL, client_p, &me, "Bogus server name"); return; }
if(!IsDigit(parv[3][0]) || !IsIdChar(parv[3][1]) || !IsIdChar(parv[3][2]) || parv[3][3] != '\0') { sendto_one(client_p, "ERROR :Invalid SID"); sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Link %s cancelled, SID %s invalid", client_p->name, parv[3]); ilog(L_SERVER, "Link %s cancelled, SID %s invalid", client_p->name, parv[3]);
exit_client(NULL, client_p, &me, "Bogus SID"); return; }
/* ok, alls good */ target_p = make_client(client_p); make_server(target_p);
rb_strlcpy(target_p->name, parv[1], sizeof(target_p->name)); target_p->hopcount = atoi(parv[2]); rb_strlcpy(target_p->id, parv[3], sizeof(target_p->id)); set_server_gecos(target_p, parv[4]);
target_p->servptr = source_p; SetServer(target_p);
rb_dlinkAddTail(target_p, &target_p->node, &global_client_list); rb_dlinkAddTailAlloc(target_p, &global_serv_list); add_to_client_hash(target_p->name, target_p); add_to_id_hash(target_p->id, target_p); rb_dlinkAdd(target_p, &target_p->lnode, &target_p->servptr->serv->servers);
target_p->serv->nameinfo = scache_connect(target_p->name, target_p->info, IsHidden(target_p));
sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s SID %s %d %s :%s%s", source_p->id, target_p->name, target_p->hopcount + 1, target_p->id, IsHidden(target_p) ? "(H) " : "", target_p->info);
sendto_realops_snomask(SNO_EXTERNAL, L_ALL, "Server %s being introduced by %s", target_p->name, source_p->name);
/* quick, dirty EOB. you know you love it. */ sendto_one(target_p, ":%s PING %s %s", get_id(&me, target_p), me.name, get_id(target_p, target_p));
hdata.client = source_p; hdata.target = target_p; call_hook(h_server_introduced, &hdata);}
/* set_server_gecos() * * input - pointer to client * output - none * side effects - servers gecos field is set */static voidset_server_gecos(struct Client *client_p, const char *info){ /* check the info for [IP] */ if(info[0]) { char *p; char *s;
s = LOCAL_COPY(info);
/* we should only check the first word for an ip */ if((p = strchr(s, ' '))) *p = '\0';
/* check for a ] which would symbolise an [IP] */ if(strchr(s, ']')) { /* set s to after the first space */ if(p) s = ++p; else s = NULL; } /* no ], put the space back */ else if(p) *p = ' ';
/* p may have been set to a trailing space, so check s exists and that * it isnt \0 */ if(s && (*s != '\0')) { /* a space? if not (H) could be the last part of info.. */ if((p = strchr(s, ' '))) *p = '\0';
/* check for (H) which is a hidden server */ if(!strcmp(s, "(H)")) { SetHidden(client_p);
/* if there was no space.. theres nothing to set info to */ if(p) s = ++p; else s = NULL; } else if(p) *p = ' ';
/* if there was a trailing space, s could point to \0, so check */ if(s && (*s != '\0')) { rb_strlcpy(client_p->info, s, sizeof(client_p->info)); return; } } }
rb_strlcpy(client_p->info, "(Unknown Location)", sizeof(client_p->info));}
/* * bogus_host * * inputs - hostname * output - true if a bogus hostname input, false if its valid * side effects - none */static boolbogus_host(const char *host){ bool bogus_server = false; const char *s; int dots = 0;
for(s = host; *s; s++) { if(!IsServChar(*s)) { bogus_server = true; break; } if('.' == *s) ++dots; }
if(!dots || bogus_server) return true;
return false;}