📄 m_server.c
字号:
/* * IRC - Internet Relay Chat, src/modules/out.c * (C) 2004 The UnrealIRCd Team * * See file AUTHORS in IRC package for additional names of * the programmers. * * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "config.h"#include "struct.h"#include "common.h"#include "sys.h"#include "numeric.h"#include "msg.h"#include "proto.h"#include "channel.h"#include <time.h>#include <sys/stat.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef _WIN32#include <io.h>#endif#include <fcntl.h>#include "h.h"#ifdef STRIPBADWORDS#include "badwords.h"#endif#include "version.h"void send_channel_modes(aClient *cptr, aChannel *chptr);void send_channel_modes_sjoin(aClient *cptr, aChannel *chptr);void send_channel_modes_sjoin3(aClient *cptr, aChannel *chptr);DLLFUNC int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[]);static char buf[BUFSIZE];#define MSG_SERVER "SERVER" #define TOK_SERVER "'" ModuleHeader MOD_HEADER(m_server) = { "m_server", "$Id: m_server.c,v 1.1.6.8 2006/12/22 21:10:33 syzop Exp $", "command /server", "3.2-b8-1", NULL };DLLFUNC int MOD_INIT(m_server)(ModuleInfo *modinfo){ add_CommandX(MSG_SERVER, TOK_SERVER, m_server, MAXPARA, M_UNREGISTERED|M_SERVER); MARK_AS_OFFICIAL_MODULE(modinfo); return MOD_SUCCESS;}DLLFUNC int MOD_LOAD(m_server)(int module_load){ return MOD_SUCCESS;}DLLFUNC int MOD_UNLOAD(m_server)(int module_unload){ if (del_Command(MSG_SERVER, TOK_SERVER, m_server) < 0) { sendto_realops("Failed to delete commands when unloading %s", MOD_HEADER(m_server).name); } return MOD_SUCCESS;}int m_server_synch(aClient *cptr, long numeric, ConfigItem_link *conf);/*** m_server** parv[0] = sender prefix** parv[1] = servername** parv[2] = hopcount** parv[3] = numeric** parv[4] = serverinfo**** on old protocols, serverinfo is parv[3], and numeric is left out**** Recode 2001 by Stskeeps*/DLLFUNC CMD_FUNC(m_server){ char *servername = NULL; /* Pointer for servername */ /* char *password = NULL; */ char *ch = NULL; /* */ char *inpath = get_client_name(cptr, TRUE); aClient *acptr = NULL, *ocptr = NULL; ConfigItem_ban *bconf; int hop = 0, numeric = 0; char info[REALLEN + 61]; ConfigItem_link *aconf = NULL; ConfigItem_deny_link *deny; char *flags = NULL, *protocol = NULL, *inf = NULL, *num = NULL; /* Ignore it */ if (IsPerson(sptr)) { sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); sendto_one(cptr, ":%s %s %s :*** Sorry, but your IRC program doesn't appear to support changing servers.", me.name, IsWebTV(cptr) ? "PRIVMSG" : "NOTICE", cptr->name); sptr->since += 7; return 0; } /* * We do some parameter checks now. We want atleast upto serverinfo now */ if (parc < 4 || (!*parv[3])) { sendto_one(sptr, "ERROR :Not enough SERVER parameters"); return exit_client(cptr, sptr, &me, "Not enough parameters"); } if (IsUnknown(cptr) && (cptr->listener->umodes & LISTENER_CLIENTSONLY)) { return exit_client(cptr, sptr, &me, "This port is for clients only"); } /* Now, let us take a look at the parameters we got * Passes here: * Check for bogus server name */ servername = parv[1]; /* Cut off if too big */ if (strlen(servername) > HOSTLEN) servername[HOSTLEN] = '\0'; /* Check if bogus, like spaces and ~'s */ for (ch = servername; *ch; ch++) if (*ch <= ' ' || *ch > '~') break; if (*ch || !index(servername, '.')) { sendto_one(sptr, "ERROR :Bogus server name (%s)", servername); sendto_snomask (SNO_JUNK, "WARNING: Bogus server name (%s) from %s (maybe just a fishy client)", servername, get_client_name(cptr, TRUE)); return exit_client(cptr, sptr, &me, "Bogus server name"); } if ((IsUnknown(cptr) || IsHandshake(cptr)) && !cptr->passwd) { sendto_one(sptr, "ERROR :Missing password"); return exit_client(cptr, sptr, &me, "Missing password"); } /* * Now, we can take a look at it all */ if (IsUnknown(cptr) || IsHandshake(cptr)) { char xerrmsg[256]; ConfigItem_link *link; strcpy(xerrmsg, "No matching link configuration"); /* First check if the server is in the list */ if (!servername) { strcpy(xerrmsg, "Null servername"); goto errlink; } if (cptr->serv && cptr->serv->conf) { /* We already know what block we are dealing with (outgoing connect!) */ link = cptr->serv->conf; } else { /* Hunt the linkblock down ;) */ for(link = conf_link; link; link = (ConfigItem_link *) link->next) if (!match(link->servername, servername)) break; } if (!link) { snprintf(xerrmsg, 256, "No link block named '%s'", servername); goto errlink; } if (link->username && match(link->username, cptr->username)) { snprintf(xerrmsg, 256, "Username '%s' didn't match '%s'", cptr->username, link->username); /* I assume nobody will have 2 link blocks with the same servername * and different username. -- Syzop */ goto errlink; } /* For now, we don't check based on DNS, it is slow, and IPs are better. * We also skip checking if link::options::nohostcheck is set. */ if (link->options & CONNECT_NOHOSTCHECK) { aconf = link; goto nohostcheck; } aconf = Find_link(cptr->username, cptr->sockhost, cptr->sockhost, servername); #ifdef INET6 /* * We first try match on uncompressed form ::ffff:192.168.1.5 thing included */ if (!aconf) aconf = Find_link(cptr->username, cptr->sockhost, Inet_ia2pNB(&cptr->ip, 0), servername); /* * Then on compressed */ if (!aconf) aconf = Find_link(cptr->username, cptr->sockhost, Inet_ia2pNB(&cptr->ip, 1), servername);#endif if (!aconf) { snprintf(xerrmsg, 256, "Server is in link block but IP/host didn't match");errlink: /* Send the "simple" error msg to the server */ sendto_one(cptr, "ERROR :Link denied (No matching link configuration) %s", inpath); /* And send the "verbose" error msg only to local failops */ sendto_locfailops ("Link denied for %s(%s@%s) (%s) %s", servername, cptr->username, cptr->sockhost, xerrmsg, inpath); return exit_client(cptr, sptr, &me, "Link denied (No matching link configuration)"); }nohostcheck: /* Now for checking passwords */ if (Auth_Check(cptr, aconf->recvauth, cptr->passwd) == -1) { sendto_one(cptr, "ERROR :Link denied (Authentication failed) %s", inpath); sendto_locfailops ("Link denied (Authentication failed [Bad password?]) %s", inpath); return exit_client(cptr, sptr, &me, "Link denied (Authentication failed)"); } /* * Third phase, we check that the server does not exist * already */ if ((acptr = find_server(servername, NULL))) { /* Found. Bad. Quit. */ acptr = acptr->from; ocptr = (cptr->firsttime > acptr->firsttime) ? acptr : cptr; acptr = (cptr->firsttime > acptr->firsttime) ? cptr : acptr; sendto_one(acptr, "ERROR :Server %s already exists from %s", servername, (ocptr->from ? ocptr->from->name : "<nobody>")); sendto_realops ("Link %s cancelled, server %s already exists from %s", get_client_name(acptr, TRUE), servername, (ocptr->from ? ocptr->from->name : "<nobody>")); return exit_client(acptr, acptr, acptr, "Server Exists"); } if ((bconf = Find_ban(NULL, servername, CONF_BAN_SERVER))) { sendto_realops ("Cancelling link %s, banned server", get_client_name(cptr, TRUE)); sendto_one(cptr, "ERROR :Banned server (%s)", bconf->reason ? bconf->reason : "no reason"); return exit_client(cptr, cptr, &me, "Banned server"); } if (aconf->class->clients + 1 > aconf->class->maxclients) { sendto_realops ("Cancelling link %s, full class", get_client_name(cptr, TRUE)); return exit_client(cptr, cptr, &me, "Full class"); } /* OK, let us check in the data now now */ hop = TS2ts(parv[2]); numeric = (parc > 4) ? TS2ts(parv[3]) : 0; if ((numeric < 0) || (numeric > 255)) { sendto_realops ("Cancelling link %s, invalid numeric", get_client_name(cptr, TRUE)); return exit_client(cptr, cptr, &me, "Invalid numeric"); } strncpyzt(info, parv[parc - 1], REALLEN + 61); strncpyzt(cptr->name, servername, sizeof(cptr->name)); cptr->hopcount = hop; /* Add ban server stuff */ if (SupportVL(cptr)) { /* we also have a fail safe incase they say they are sending * VL stuff and don't -- codemastr */ ConfigItem_deny_version *vlines; inf = NULL; protocol = NULL; flags = NULL; num = NULL; protocol = (char *)strtok((char *)info, "-"); if (protocol) flags = (char *)strtok((char *)NULL, "-"); if (flags) num = (char *)strtok((char *)NULL, " "); if (num) inf = (char *)strtok((char *)NULL, ""); if (inf) { strncpyzt(cptr->info, inf[0] ? inf : me.name, sizeof(cptr->info)); for (vlines = conf_deny_version; vlines; vlines = (ConfigItem_deny_version *) vlines->next) { if (!match(vlines->mask, cptr->name)) break; } if (vlines) { char *proto = vlines->version; char *vflags = vlines->flags; int version, result = 0, i; protocol++; version = atoi(protocol); switch (*proto) { case '<': proto++; if (version < atoi(proto)) result = 1; break; case '>': proto++; if (version > atoi(proto)) result = 1; break; case '=': proto++; if (version == atoi(proto)) result = 1; break; case '!': proto++; if (version != atoi(proto)) result = 1; break; default: if (version == atoi(proto)) result = 1; break; } if (version == 0 || *proto == '*') result = 0; if (result) return exit_client(cptr, cptr, cptr, "Denied by V:line"); for (i = 0; vflags[i]; i++) { if (vflags[i] == '!') { i++; if (strchr(flags, vflags[i])) { result = 1; break; } } else if (!strchr(flags, vflags[i])) { result = 1; break; } } if (*vflags == '*' || !strcmp(flags, "0")) result = 0; if (result) return exit_client(cptr, cptr, cptr, "Denied by V:line"); } } else strncpyzt(cptr->info, info[0] ? info : me.name, sizeof(cptr->info)); } else strncpyzt(cptr->info, info[0] ? info : me.name, sizeof(cptr->info)); /* Numerics .. */ numeric = num ? atol(num) : numeric; if (numeric) { if ((numeric < 0) || (numeric > 254)) { sendto_locfailops("Link %s denied, numeric '%d' out of range (should be 0-254)", inpath, numeric); return exit_client(cptr, cptr, cptr, "Numeric out of range (0-254)"); } if (numeric_collides(numeric)) { sendto_locfailops("Link %s denied, colliding server numeric", inpath); return exit_client(cptr, cptr, cptr, "Colliding server numeric (choose another)"); } } for (deny = conf_deny_link; deny; deny = (ConfigItem_deny_link *) deny->next) { if (deny->flag.type == CRULE_ALL && !match(deny->mask, servername) && crule_eval(deny->rule)) { sendto_ops("Refused connection from %s.", get_client_host(cptr)); return exit_client(cptr, cptr, cptr, "Disallowed by connection rule"); } } if (aconf->options & CONNECT_QUARANTINE) cptr->flags |= FLAGS_QUARANTINE; /* Start synch now */ if (m_server_synch(cptr, numeric, aconf) == FLUSH_BUFFER) return FLUSH_BUFFER; } else { return m_server_remote(cptr, sptr, parc, parv); } return 0;}CMD_FUNC(m_server_remote){ aClient *acptr, *ocptr, *bcptr; ConfigItem_link *aconf; ConfigItem_ban *bconf; int hop; char info[REALLEN + 61]; long numeric = 0; char *servername = parv[1]; int i; if ((acptr = find_server(servername, NULL))) { /* Found. Bad. Quit. */ acptr = acptr->from; ocptr = (cptr->firsttime > acptr->firsttime) ? acptr : cptr; acptr = (cptr->firsttime > acptr->firsttime) ? cptr : acptr; sendto_one(acptr, "ERROR :Server %s already exists from %s", servername, (ocptr->from ? ocptr->from->name : "<nobody>")); sendto_realops ("Link %s cancelled, server %s already exists from %s", get_client_name(acptr, TRUE), servername, (ocptr->from ? ocptr->from->name : "<nobody>")); if (acptr == cptr) { return exit_client(acptr, acptr, acptr, "Server Exists"); } else { /* AFAIK this can cause crashes if this happends remotely because * we will still receive msgs for some time because of lag. * Two possible solutions: unlink the directly connected server (cptr) * and/or fix all those commands which blindly trust server input. -- Syzop */ exit_client(acptr, acptr, acptr, "Server Exists"); return 0; } } if ((bconf = Find_ban(NULL, servername, CONF_BAN_SERVER))) { sendto_realops ("Cancelling link %s, banned server %s", get_client_name(cptr, TRUE), servername); sendto_one(cptr, "ERROR :Banned server (%s)", bconf->reason ? bconf->reason : "no reason"); return exit_client(cptr, cptr, &me, "Brought in banned server"); } /* OK, let us check in the data now now */ hop = TS2ts(parv[2]); numeric = (parc > 4) ? TS2ts(parv[3]) : 0; if ((numeric < 0) || (numeric > 255)) { sendto_realops ("Cancelling link %s, invalid numeric at server %s", get_client_name(cptr, TRUE), servername); sendto_one(cptr, "ERROR :Invalid numeric (%s)", servername); return exit_client(cptr, cptr, &me, "Invalid remote numeric"); } strncpyzt(info, parv[parc - 1], REALLEN + 61); if (!cptr->serv->conf) { sendto_realops("Lost conf for %s!!, dropping link", cptr->name); return exit_client(cptr, cptr, cptr, "Lost configuration"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -