--- /dev/null
+newserv Modules
+~~~~~~~~~~~~~~
+
+This is a brief overview of the newserv modules.
+
+core
+~~~
+
+This is not actually a module. Instead, this is the code of the "newserv" binary
+which provides minimal support for loading modules.
+
+authext, bans, chanindex, channel, irc, nick, server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These modules provide basic support for accounts, channels, nicks and server
+connections. Virtually all other modules depend on at least some of these
+modules.
+
+localuser
+~~~~~~~~
+
+Implements functionality for creating local users that are "connected" to the
+newserv instance.
+
+control
+~~~~~~
+
+Spawns the control user for your newserv instance. The control user provides
+an IRC-based interface for newserv commands, e.g. to manage loaded modules
+and modify user accounts.
+
+Other modules can register their own commands.
+
+You can create a user on your control instance using /msg N hello (where N is
+the nick of your control instance). You need to be opered in order to use this
+command.
+
+Once you have an account you should have a look at /msg N showcommands for a
+list of available commands.
+
+Configuration:
+
+[control]
+nick=N3
+
+auth
+~~~
+
+Supports sending AC tokens. You should only use this module if you don't have
+some other form of authentication service on your network (such as Q). This
+module lets opers use arbitrary account names and IDs.
+
+chanfix
+~~~~~~
+
+Keeps track of channel ops and can be used to re-op opless channels.
+
+chanserv
+~~~~~~~
+
+This is QuakeNet's channel service (Q). In order to load this module you will
+need also need to load the pqsql module.
+
+pqsql
+~~~~
+
+Provides support for PostgreSQL database queries.
+
+Configuration:
+
+[pqsql]
+host=127.0.0.1
+port=5432
+username=gunnar
+password=changeme
+
+dbapi2
+~~~~~
+
+Implements database functionality used by some other modules. In addition to
+loading the dbapi2 module you will also need to load one of the database
+provider modules: sqlite-dbapi2 or pqsql-dbapi2
+
+fakeusers
+~~~~~~~~
+
+Provides a way to spawn fake users.
+
+glines
+~~~~~
+
+Implements gline commands and general gline functionality that is used by other
+modules.
+
+helpmod2
+~~~~~~~
+
+This is QuakeNet's G service. It is primarily used on official support channels.
+
+invalidbans
+~~~~~~~~~~
+
+This module automatically removes invalid IPv6 bans as these can desync channel
+modes on snircd 1.3.4a.
+
+jupe
+~~~
+
+Provides commands to set, list and remove jupes.
+
+lua
+~~
+
+Provides support for Lua scripts. For an example of a fairly complex script
+have a look at the labspace repository at http://hg.quakenet.org/lua-labspace/
+
+Configuration:
+
+[lua]
+scriptdir=./luascripts
+script=labspace
+
+Note: You will need to create the script directory in your newserv
+installation directory (e.g. "luascripts" in this example) and symlink the
+lua/lib directory into it.
+
+newsearch
+~~~~~~~~
+
+Provides functionality to search for nicks and channels based on certain
+criteria.
+
+miscreply
+~~~~~~~~
+
+Implements rping and various other status query commands.
+
+proxyscan
+~~~~~~~~
+
+Does on-connect proxy scans and glines open proxies.
+
+request
+~~~~~~
+
+This is QuakeNet's channel service request bot (R). Some of the module
+parameters are not configurable - instead you will have to modify the
+request/request.h header file and recompile the module.
+
+serverlist
+~~~~~~~~~
+
+Implements the serverlist command which shows various information about
+connected servers (including their network latency).
+
+settime
+~~~~~~
+
+Provides commands to set the network time.
+
+splitlist
+~~~~~~~~
+
+Keeps track of servers that were lost during a netsplit. This module is used
+by chanfix to determine when it shouldn't re-op users.
+
+trojanscan
+~~~~~~~~~
+
+Used to find and gline drones on the network.
+
+trusts
+~~~~~
+
+Implements connection limits. Supports the TRUST protocol which is used
+by quakenet-iauthd to determine whether to allow users on the network.
+
+You will need to load the trusts_master module on one of your newserv
+instances. All other instances should load the trusts_slave module in order
+to receive replication updates from the trusts master:
+
+[trusts]
+master=1
+#masterserver=trusts.services.netsplit.net # Only used if master=0
+
+In most cases you will also want to load the trusts_management module on
+your trusts master. This module provides commands to add, modify and delete
+trusts.
+
+If you want to enforce connection limits on your network you can use the
+trusts_policy module:
+
+[trusts_policy]
+enforcepolicy_irc=1
+enforcepolicy_auth=0
+trustport=5776
+server=gnb.netsplit.net,changeme
+server=test.gnb.netsplit.net,changeme
+
+You can use the QuakeNet IAuth daemon available at
+http://hg.quakenet.org/iauthd/ to enforce connection limits using IAuth rather
+than g:lines.
+
+whowas
+~~~~~
+
+Keeps track of historical user records. Used by the glines module to chase
+nicks and by newsearch.
+
+xsb
+~~
+
+Provides replication capabilities. Used by the trusts modules to sync
+trusts between newserv instances.
+
+Configuration:
+
+[xsb]
+servicemask=*.services.netsplit.net
int cfext;
int cfnext;
-int cffailedinit;
+
+static int cffailedinit;
/* user accessible commands */
int cfcmd_debug(void *source, int cargc, char **cargv);
if (cfext < 0 || cfnext < 0) {
Error("chanfix", ERR_ERROR, "Couldn't register channel and/or nick extension");
cffailedinit = 1;
- } else {
- schedulerecurring(time(NULL), 0, CFSAMPLEINTERVAL, &cfsched_dosample, NULL);
- schedulerecurring(time(NULL), 0, CFEXPIREINTERVAL, &cfsched_doexpire, NULL);
- schedulerecurring(time(NULL), 0, CFAUTOSAVEINTERVAL, &cfsched_dosave, NULL);
+ return;
+ }
- registercontrolhelpcmd("cfdebug", NO_DEVELOPER, 1, &cfcmd_debug, "Display Debug Information on chanfix data for channel");
- registercontrolhelpcmd("cfhistogram", NO_DEVELOPER, 1, &cfcmd_debughistogram, "Display Debug Histogram of chanfix data for channel");
+ schedulerecurring(time(NULL), 0, CFSAMPLEINTERVAL, &cfsched_dosample, NULL);
+ schedulerecurring(time(NULL), 0, CFEXPIREINTERVAL, &cfsched_doexpire, NULL);
+ schedulerecurring(time(NULL), 0, CFAUTOSAVEINTERVAL, &cfsched_dosave, NULL);
+
+ registercontrolhelpcmd("cfdebug", NO_DEVELOPER, 1, &cfcmd_debug, "Display Debug Information on chanfix data for channel");
+ registercontrolhelpcmd("cfhistogram", NO_DEVELOPER, 1, &cfcmd_debughistogram, "Display Debug Histogram of chanfix data for channel");
#if CFDEBUG
- registercontrolhelpcmd("cfsample", NO_DEVELOPER, 1, &cfcmd_debugsample, "DEBUG Command - must not be loaded on live instances");
- registercontrolhelpcmd("cfexpire", NO_DEVELOPER, 1, &cfcmd_debugexpire, "DEBUG Command - must not be loaded on live instances");
+ registercontrolhelpcmd("cfsample", NO_DEVELOPER, 1, &cfcmd_debugsample, "DEBUG Command - must not be loaded on live instances");
+ registercontrolhelpcmd("cfexpire", NO_DEVELOPER, 1, &cfcmd_debugexpire, "DEBUG Command - must not be loaded on live instances");
#endif
- registercontrolhelpcmd("chanopstat", NO_OPER, 1, &cfcmd_chanopstat, "Shows chanop statistics for a given channel");
- registercontrolhelpcmd("chanoplist", NO_OPER, 1, &cfcmd_chanoplist, "Shows lists of known chanops, including scores");
+ registercontrolhelpcmd("chanopstat", NO_OPER, 1, &cfcmd_chanopstat, "Shows chanop statistics for a given channel");
+ registercontrolhelpcmd("chanoplist", NO_OPER, 1, &cfcmd_chanoplist, "Shows lists of known chanops, including scores");
- registercontrolhelpcmd("chanfix", NO_OPER, 1, &cfcmd_chanfix, "Perform a chanfix on a channel to op known users only");
- registercontrolhelpcmd("showregs", NO_OPER, 1, &cfcmd_showregs, "Show regular ops known on a channel (including services)");
+ registercontrolhelpcmd("chanfix", NO_OPER, 1, &cfcmd_chanfix, "Perform a chanfix on a channel to op known users only");
+ registercontrolhelpcmd("showregs", NO_OPER, 1, &cfcmd_showregs, "Show regular ops known on a channel (including services)");
#if CFDEBUG
- /* should we disable this in the 'final' build? */
- /* registercontrolcmd("requestop", 0, 2, &cfcmd_requestop); */
+ /* should we disable this in the 'final' build? */
+ /* registercontrolcmd("requestop", 0, 2, &cfcmd_requestop); */
#endif
- registercontrolhelpcmd("cfsave", NO_DEVELOPER, 0, &cfcmd_save, "Force save of chanfix data");
- registercontrolhelpcmd("cfload", NO_DEVELOPER, 0, &cfcmd_load, "Force load of chanfix data");
+ registercontrolhelpcmd("cfsave", NO_DEVELOPER, 0, &cfcmd_save, "Force save of chanfix data");
+ registercontrolhelpcmd("cfload", NO_DEVELOPER, 0, &cfcmd_load, "Force load of chanfix data");
#if CFAUTOFIX
- registerhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
- registerhook(HOOK_CHANNEL_PART, &cfhook_autofix);
- registerhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
- registerhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
+ registerhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
+ registerhook(HOOK_CHANNEL_PART, &cfhook_autofix);
+ registerhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
+ registerhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
#endif
- registerhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
- registerhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
+ registerhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
+ registerhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
- cf_loadchanfix();
+ cf_loadchanfix();
- cffailedinit = 0;
- }
+ cffailedinit = 0;
}
void _fini() {
- if (cffailedinit == 0) {
- deleteschedule(NULL, &cfsched_dosample, NULL);
- deleteschedule(NULL, &cfsched_doexpire, NULL);
- deleteschedule(NULL, &cfsched_dosave, NULL);
+ if (cffailedinit == 0)
+ return;
- cf_storechanfix();
+ deleteschedule(NULL, &cfsched_dosample, NULL);
+ deleteschedule(NULL, &cfsched_doexpire, NULL);
+ deleteschedule(NULL, &cfsched_dosave, NULL);
- cf_free();
+ cf_storechanfix();
+
+ cf_free();
- deregistercontrolcmd("cfdebug", &cfcmd_debug);
- deregistercontrolcmd("cfhistogram", &cfcmd_debughistogram);
+ deregistercontrolcmd("cfdebug", &cfcmd_debug);
+ deregistercontrolcmd("cfhistogram", &cfcmd_debughistogram);
#if CFDEBUG
- deregistercontrolcmd("cfsample", &cfcmd_debugsample);
- deregistercontrolcmd("cfexpire", &cfcmd_debugexpire);
+ deregistercontrolcmd("cfsample", &cfcmd_debugsample);
+ deregistercontrolcmd("cfexpire", &cfcmd_debugexpire);
#endif
- deregistercontrolcmd("chanopstat", &cfcmd_chanopstat);
- deregistercontrolcmd("chanoplist", &cfcmd_chanoplist);
- deregistercontrolcmd("chanfix", &cfcmd_chanfix);
- deregistercontrolcmd("showregs", &cfcmd_showregs);
+ deregistercontrolcmd("chanopstat", &cfcmd_chanopstat);
+ deregistercontrolcmd("chanoplist", &cfcmd_chanoplist);
+ deregistercontrolcmd("chanfix", &cfcmd_chanfix);
+ deregistercontrolcmd("showregs", &cfcmd_showregs);
#if CFDEBUG
-// deregistercontrolcmd("requestop", &cfcmd_requestop);
+// deregistercontrolcmd("requestop", &cfcmd_requestop);
#endif
- deregistercontrolcmd("cfsave", &cfcmd_save);
- deregistercontrolcmd("cfload", &cfcmd_load);
+ deregistercontrolcmd("cfsave", &cfcmd_save);
+ deregistercontrolcmd("cfload", &cfcmd_load);
#if CFAUTOFIX
- deregisterhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
- deregisterhook(HOOK_CHANNEL_PART, &cfhook_autofix);
- deregisterhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
- deregisterhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
+ deregisterhook(HOOK_CHANNEL_DEOPPED, &cfhook_autofix);
+ deregisterhook(HOOK_CHANNEL_PART, &cfhook_autofix);
+ deregisterhook(HOOK_CHANNEL_KICK, &cfhook_autofix);
+ deregisterhook(HOOK_CHANNEL_JOIN, &cfhook_autofix);
#endif
- deregisterhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
- deregisterhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
- }
+ deregisterhook(HOOK_CORE_STATSREQUEST, &cfhook_statsreport);
+ deregisterhook(HOOK_NICK_ACCOUNT, &cfhook_auth);
- if (cfext >= 0) {
+ if (cfext >= 0)
releasechanext(cfext);
- }
- if (cfnext >= 0) {
+ if (cfnext >= 0)
releasenickext(cfnext);
- }
}
int cfcmd_debug(void *source, int cargc, char **cargv) {
regop *ro;
int i;
- if (cargc < 1) {
- controlreply(np, "Syntax: cfdebug <#channel>");
-
- return CMD_ERROR;
- }
+ if (cargc < 1)
+ return CMD_USAGE;
cip = findchanindex(cargv[0]);
controlreply(np, "No such channel.");
return CMD_ERROR;
- } else
- controlreply(np, "Found channel %s. Retrieving chanfix information...", cargv[0]);
+ }
+
+ controlreply(np, "Found channel %s. Retrieving chanfix information...", cargv[0]);
cf = cip->exts[cfext];
controlreply(np, "No chanfix information for %s", cargv[0]);
return CMD_ERROR;
- } else
- controlreply(np, "Found chanfix information. Dumping...");
+ }
+
+ controlreply(np, "Found chanfix information. Dumping...");
for (i=0;i<cf->regops.cursi;i++) {
ro = ((regop**)cf->regops.content)[i];
qsort(cf->regops.content, cf->regops.cursi, sizeof(regop*), cmpregop);
- for (i = 0; i < min(max, cf->regops.cursi); i++) {
+ for (i = 0; i < min(max, cf->regops.cursi); i++)
list[i] = ((regop**)cf->regops.content)[i];
- }
return i;
}
int i, a, count;
int *scores;
- if (cargc < 1) {
- controlreply(np, "Syntax: chanopstat <#channel>");
-
- return CMD_ERROR;
- }
+ if (cargc < 1)
+ return CMD_USAGE;
cp = findchannel(cargv[0]);
count = cf_getsortedregops(cf, 10, rolist);
controlreply(np, "Scores of \"best ops\" on %s are:", cargv[0]);
- for (i=0;i<count;i++) {
+ for (i=0;i<count;i++)
controlreply(np, " %d", rolist[i]->score);
- }
/* current ops */
scores = (int*)malloc(sizeof(int) * cp->users->hashsize);
char date[50];
unsigned long *hand;
- if (cargc < 1) {
- controlreply(np, "Syntax: chanoplist <#channel>");
-
- return CMD_ERROR;
- }
+ if (cargc < 1)
+ return CMD_USAGE;
cip = findchanindex(cargv[0]);
channel *cp;
int ret;
- if (cargc < 1) {
- controlreply(np, "Syntax: chanfix <#channel>");
-
- return CMD_ERROR;
- }
+ if (cargc < 1)
+ return CMD_USAGE;
cp = findchannel(cargv[0]);
int i, count, ops;
regop *rolist[50];
- if (cargc < 1) {
- controlreply(np, "Syntax: showregs <#channel>");
-
- return CMD_ERROR;
- }
+ if (cargc < 1)
+ return CMD_USAGE;
cp = findchannel(cargv[0]);
unsigned long *hand;
modechanges changes;
- if (cargc < 1) {
- controlreply(np, "Syntax: requestop <#channel> [nick]");
-
- return CMD_ERROR;
- }
+ if (cargc < 1)
+ return CMD_USAGE;
cp = findchannel(cargv[0]);
}
void cfsched_dosample(void *arg) {
- int i,a,now,cfscore,cfnewro,cfuhost,diff;
+ int i,a,now,cfscore,cfnewro,diff;
channel *cp;
chanindex *cip;
nick *np;
regop *ro, *roh;
struct timeval start;
struct timeval end;
- char buf[USERLEN+1+HOSTLEN+1];
now = getnettime();
- cfuhost = cfscore = cfnewro = 0;
+ cfscore = cfnewro = 0;
if (sp_countsplitservers(SERVERTYPEFLAG_USER_STATE) > CFMAXSPLITSERVERS)
return;
if ((cp->users->content[a] != nouser) && (cp->users->content[a] & CUMODE_OP)) {
np = getnickbynumeric(cp->users->content[a]);
- if (np)
+ if (!np)
continue;
#if !CFDEBUG
/* lastopped == now if the user has clones, we obviously
* don't want to give them points in this case */
- if (ro && ro->lastopped != now) {
- if (ro->type != CFHOST || !cf_hasauthedcloneonchan(np, cp)) {
- ro->score++;
- cfscore++;
- }
-
- /* merge any matching CFHOST records */
- if (roh && roh->type == CFHOST && ro->type == CFACCOUNT) {
- /* hmm */
- ro->score += roh->score;
-
- cf_deleteregop(cip, roh);
- }
-
- /* store the user's account/host if we have to */
- if (ro->uh == NULL && ro->score >= CFMINSCOREUH) {
- if (ro->type == CFACCOUNT)
- ro->uh = getsstring(np->authname, ACCOUNTLEN);
- else {
- snprintf(buf, sizeof(buf), "%s@%s", np->ident, np->host->name->content);
- roh->uh = getsstring(buf, USERLEN+1+HOSTLEN);
- }
-
- cfuhost++;
- }
-
- ro->lastopped = now;
+ if (!ro || ro->lastopped == now)
+ continue;
+
+ if (ro->type != CFHOST || !cf_hasauthedcloneonchan(np, cp)) {
+ ro->score++;
+ cfscore++;
}
+
+ /* merge any matching CFHOST records */
+ if (roh && roh->type == CFHOST && ro->type == CFACCOUNT) {
+ /* hmm */
+ ro->score += roh->score;
+
+ cf_deleteregop(cip, roh);
+ }
+
+ ro->lastopped = now;
}
}
}
(start.tv_sec * 1000 + start.tv_usec / 1000);
sendmessagetochannel(mynick, cp, "sampled chanfix scores, assigned %d new"
- " points, %d new regops, %d user@hosts added, deltaT: %dms", cfscore,
- cfnewro, cfuhost, diff);
+ " points, %d new regops, deltaT: %dms", cfscore,
+ cfnewro, diff);
}
}
chanindex *cip;
chanindex *ncip;
chanfix *cf;
- int i,a,cfscore,cfregop,cffreeuh,diff;
+ int i,a,cfscore,cfregop,diff;
regop **rolist;
regop *ro;
struct timeval start;
struct timeval end;
time_t currenttime;
- cffreeuh = cfscore = cfregop = 0;
+ cfscore = cfregop = 0;
gettimeofday(&start, NULL);
currenttime=getnettime();
cfscore++;
}
- if ((ro->score < CFMINSCOREUH) && ro->uh) {
- freesstring(ro->uh);
- ro->uh = NULL;
-
- cffreeuh++;
- }
-
if (ro->score == 0 || ro->lastopped < (currenttime - CFREMEMBEROPS)) {
cf_deleteregop(cip, ro);
cfregop++;
(start.tv_sec * 1000 + start.tv_usec / 1000);
sendmessagetochannel(mynick, cp, "expired chanfix scores, purged %d points,"
- " scrapped %6d regops, %d user@hosts freed, deltaT: %dms", cfscore,
- cfregop, cffreeuh, diff);
+ " scrapped %6d regops, deltaT: %dms", cfscore,
+ cfregop, diff);
}
}
chanfix *cf = cip->exts[cfext];
int slot, type;
regop **rolist;
+ char buf[USERLEN+1+HOSTLEN+1];
if (cf == NULL) {
cf = (chanfix*)malloc(sizeof(chanfix));
rolist[slot] = (regop*)malloc(sizeof(regop));
- if (IsAccount(np))
+ if (IsAccount(np)) {
type = CFACCOUNT;
- else
+ rolist[slot]->uh = getsstring(np->authname, ACCOUNTLEN);
+ } else {
type = CFHOST;
+ snprintf(buf, sizeof(buf), "%s@%s", np->ident, np->host->name->content);
+ rolist[slot]->uh = getsstring(buf, USERLEN+1+HOSTLEN);
+ }
+
rolist[slot]->type = type;
rolist[slot]->hash = cf_gethash(np, type);
- rolist[slot]->uh = NULL;
rolist[slot]->lastopped = 0;
rolist[slot]->score = 0;
rolist[slot]->hash = hash;
rolist[slot]->lastopped = lastopped;
rolist[slot]->score = score;
-
- if (count >= 6)
- rolist[slot]->uh = getsstring(host, USERLEN+1+HOSTLEN);
- else
- rolist[slot]->uh = NULL;
+ rolist[slot]->uh = getsstring(host, USERLEN+1+HOSTLEN);
return 1;
}