chanfix
-------
-Keeps track of channel ops and can be used to re-op opless channels.
+Keeps track of channel ops and can be used to re-op opless channels. However,
+since its chanfixing commands require oper, it should be paired with the request
+module, which provides REQUESTOP for users and uses chanfix internally.
chanserv
--------
This is QuakeNet's channel service (Q). In order to load this module you will
need also need to load the pqsql module.
+Configuration:
+
+[chanserv]
+nick=Q
+user=TheQBot
+host=some.host
+realname=ChannelService
+account=Q
+secret=
+ticketsecret=
+createaccountsecret=
+
+secret can be an arbitrary string, at most 128 characters long. If not set, Q
+will generate a random one and not write it to the configuration.
+
+ticketsecret can be an arbitrary string, at most 256 characters long and must
+be set for ticket auth to work. Note that you must implement ticket auth
+yourself if you wish to use it.
+
+createaccountsecret must be a hex string of exact 128 characters (i.e. 64 bytes
+of hex-encoded data).
+
pqsql
-----
port=5432
username=gunnar
password=changeme
+#database=newserv
dbapi2
------
Configuration:
[lua]
+#botnick=U
+#scriptsuffix=.lua
scriptdir=./luascripts
script=labspace
Implements event-based nicksearch queries.
+nterfacer
+---------
+
+Implements a protocol that allows external services to communicate with this
+newserv instance.
+
+You will need to implement your own client if you wish to use this.
+
+Configuration:
+
+[nterfacer]
+#debug=0
+# listening port
+#port=2438
+# Each individual permit/allowed client must have a hostname and password
+hostname=127.0.0.1
+password=changeme
+
miscreply
---------
Does on-connect proxy scans and glines open proxies.
+Configuration:
+
+[proxyscan]
+# listen port
+port=9999
+# bind IP
+ip=127.0.0.1
+maxscans=200
+rescaninterval=3600
+nick=P
+user=proxyscan
+host=some.host
+realname=Proxyscan
+
request
-------
#sserver=spamscan.quakenet.org
#qnick=Q
#qserver=cserve.quakenet.org
+#auth=R
+#authid=1780711
+# Auth to S
+#user=R
+#password=bla
serverlist
----------
Implements the serverlist command which shows various information about
connected servers (including their network latency).
+Configuration:
+
+[serverlist]
+q_server=CServe.quakenet.org
+s_server=services2.uk.quakenet.org
+service_re=^services\d*\..*$
+hub_re=^hub\d*\..*$
+not_client_re=^(testserv\d*\.).*$
+
settime
-------
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.
+ticketauth
+----------
+
+Provides ticketauth, a way to authenticate to noperserv using a one-time
+ticket. It works similar to the ticket auth in chanserv.
+
+If you want to use ticketauth, you'll need to implement a method to issue
+tickets using the shared secret yourself.
+
+Configuration:
+
+[ticketauth]
+sharedsecret=
+
+sharedsecret is an arbitrary string of at most 512 characters.
+
trojanscan
----------
Used to find and gline drones on the network.
+Note that this module uses MySQL exclusively and in a blocking manner, so that
+a hanging connection to the MySQL database can and will block all network I/O.
+For this reason, you will probably want a newserv instance dedicated to running
+trojanscan if you wish to run it.
+
+Configuration:
+
+[trojanscan]
+nick=T
+ident=trojanscan
+hostname=trojanscan.quakenet.org
+realname=Trojanscan v2.73
+authname=T
+# MySQL credentials
+dbhost=localhost
+dbport=3306
+dbuser=moo
+dbpass=changeme
+db=moo
+maxchans=750
+cycletime=16000
+parttime=2600
+maxusers=20
+minchansize=150
+
trusts
------
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
+https://hg.quakenet.org/iauthd/ to enforce connection limits using IAuth rather
than g:lines.
whowas, whowas_channels
The whowas_channels module optionally keeps track of which channels users
were on.
+Configuration:
+
+[whowas]
+maxentries=1000
+
xsb
---
#define CLEANUP_INACTIVE_DAYS 30 /* disable channels where nothing happened for this many days */
#define CLEANUP_DELETE_DAYS 5 /* delete data for channels that have been disabled for this many days */
+#define A4STATS_DB_TOLOWER(x) "translate(lower(" x "), E'[]\\\\~', '{}|^')"
+#define A4STATS_DB_EQ_NOCASE(x, y) A4STATS_DB_TOLOWER(x) " = " A4STATS_DB_TOLOWER(y)
+
MODULE_VERSION("");
DBAPIConn *a4statsdb;
channel = lua_tostring(ps, 1);
hour = lua_tonumber(ps, 2);
- snprintf(query, sizeof(query), "UPDATE ? SET h%d = h%d + 1 WHERE name = ?", hour, hour);
+ snprintf(query, sizeof(query), "UPDATE ? SET h%d = h%d + 1 WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), hour, hour);
a4statsdb->squery(a4statsdb, query, "Ts", "channels", channel);
LUA_RETURN(ps, LUA_FAIL);
a4statsdb->squery(a4statsdb, "INSERT INTO ? (name, timestamp) VALUES (?, ?)", "Tst", "channels", lua_tostring(ps, 1), time(NULL));
- a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 1, deleted = 0 WHERE name = ?", "Ts", "channels", lua_tostring(ps, 1));
+ a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 1, deleted = 0 WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "Ts", "channels", lua_tostring(ps, 1));
LUA_RETURN(ps, LUA_OK);
}
if (!lua_isstring(ps, 1))
LUA_RETURN(ps, LUA_FAIL);
- a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 0, deleted = ? WHERE name = ?", "Tts", "channels", time(NULL), lua_tostring(ps, 1));
+ a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 0, deleted = ? WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "Tts", "channels", time(NULL), lua_tostring(ps, 1));
LUA_RETURN(ps, LUA_OK);
}
channel = lua_tostring(ps, 1);
privacy = lua_tonumber(ps, 2);
- a4statsdb->squery(a4statsdb, "UPDATE ? SET privacy = ? WHERE name = ?", "TUs", "channels", privacy, channel);
+ a4statsdb->squery(a4statsdb, "UPDATE ? SET privacy = ? WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "TUs", "channels", privacy, channel);
LUA_RETURN(ps, LUA_OK);
}
raw=
nickwatch=
patrol=
-regexgline=pcre mysql
+regexgline=pcre dbapi
facepalm=
a4stats=lua
rbl=
next if ($sym eq "_init");
next if ($sym eq "_fini");
next if ($sym eq "_version");
+ next if ($sym eq "__bss_start");
+ next if ($sym eq "_end");
if ($type eq "U") {
push @{$reqsyms{$modname}}, $sym;
helpmod_reply(sender, returntype, "Cannot issue a ticket: User %s is considered improper and not worthy of a ticket", argv[1]);
return;
}
- if (huser_get_level(husr) > H_PEON)
+ if (huser_get_level(husr) > H_FRIEND)
{
helpmod_reply(sender, returntype, "Cannot issue a ticket: User %s does not require a ticket", argv[1]);
return;
unsigned int opt=1;
if ((fd=socket(AF_INET,SOCK_STREAM,0))==-1) {
- Error("proxyscan",ERR_ERROR,"Unable to open listening socket (%d).",errno);
+ Error("nickrate",ERR_ERROR,"Unable to open listening socket (%d).",errno);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt, sizeof(opt))!=0) {
close(fd);
- Error("proxyscan",ERR_ERROR,"Unable to set SO_REUSEADDR on listen socket.");
+ Error("nickrate",ERR_ERROR,"Unable to set SO_REUSEADDR on listen socket.");
return -1;
}
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) {
close(fd);
- Error("proxyscan",ERR_ERROR,"Unable to bind listen socket (%d).",errno);
+ Error("nickrate",ERR_ERROR,"Unable to bind listen socket (%d).",errno);
return -1;
}
if (ioctl(fd, FIONBIO, &opt)!=0) {
close(fd);
- Error("proxyscan",ERR_ERROR,"Unable to set listen socket non-blocking.");
+ Error("nickrate",ERR_ERROR,"Unable to set listen socket non-blocking.");
return -1;
}
size_t esclen;
esclen = dbescapestring(xbuf, (char *)data, len);
- sbaddstr(&b, "E'");
+ sbaddchar(&b, '\'');
sbaddstrlen(&b, xbuf, esclen);
sbaddchar(&b, '\'');
static void sphook_newserver(int hook, void *arg);
static void sphook_lostserver(int hook, void *arg);
-static void sp_addsplit(const char *name, time_t ts, flag_t flags);
void _init(void) {
registerhook(HOOK_SERVER_NEWSERVER, &sphook_newserver);
}
}
-static void sp_addsplit(const char *name, time_t ts, flag_t type) {
+void sp_addsplit(const char *name, time_t ts, flag_t type) {
int slot;
splitserver *srv;
void sp_deletesplit(const char *name);
int sp_countsplitservers(flag_t orflags);
-/* I don't see why these are exported... */
+/* I don't see why this is exported... */
/*
int sp_issplitserver(const char *name);
-void sp_addsplit(const char *name, time_t ts);
*/
+void sp_addsplit(const char *name, time_t ts, flag_t type);
#endif /* __SPLITLIST_H */
/* oper commands for the splitlist */
+#include <errno.h>
+#include <string.h>
+
#include "../lib/irc_string.h"
#include "../irc/irc.h"
+#include "../irc/irc_config.h"
#include "../splitlist/splitlist.h"
#include "../serverlist/serverlist.h"
#include "../control/control.h"
#include "../lib/version.h"
+#include "../lib/flags.h"
MODULE_VERSION("");
int spcmd_splitlist(void *source, int cargc, char **cargv);
int spcmd_splitdel(void *source, int cargc, char **cargv);
+int spcmd_splitadd(void *source, int cargc, char **cargv);
void _init(void) {
registercontrolhelpcmd("splitlist", NO_STAFF, 0, &spcmd_splitlist, "Usage: splitlist\nLists servers currently split from the network.");
registercontrolcmd("splitdel", 10, 1, &spcmd_splitdel);
+ registercontrolhelpcmd("splitadd", 10, 3, &spcmd_splitadd,
+ "Usage: splitadd <servername> [+flags] [split time as unix timestamp]\n"
+ " Adds a server as split from the network.\n"
+ " Flags:\n"
+ " +c: Client server\n"
+ " +h: Hub server\n"
+ " +s: Service\n"
+ " +Q: Q/CServe\n"
+ " +S: S/spamscan\n"
+ " +X: Other critical service\n"
+ " If no flags are given, an attempt to figure them out based on name\n"
+ " will be made, but it's likely not a good one.");
}
void _fini(void) {
deregistercontrolcmd("splitlist", &spcmd_splitlist);
deregistercontrolcmd("splitdel", &spcmd_splitdel);
+ deregistercontrolcmd("splitadd", &spcmd_splitadd);
}
/* todo: add RELINK status */
return CMD_OK;
}
+
+static int doessplitalreadyexist(const char *servername) {
+ splitserver srv;
+ unsigned int i;
+
+ for (i = 0; i < splitlist.cursi; i++) {
+ srv = ((splitserver*)splitlist.content)[i];
+
+ if (!strcasecmp(srv.name->content, servername))
+ return 1;
+ }
+
+ return 0;
+}
+
+int spcmd_splitadd(void *source, int cargc, char **cargv) {
+ nick *np = (nick*)source;
+ unsigned long long num;
+ char *end;
+ flag_t servertype = 0;
+ char *servername;
+ size_t servernamelen;
+ time_t splittime;
+ server fake;
+
+ if (cargc < 1) {
+ controlreply(np, "Usage: splitadd <servername> [+flags] [split time as unix timestamp]");
+ return CMD_ERROR;
+ }
+
+ servername = cargv[0];
+ servernamelen = strlen(servername);
+
+ if (findserver(servername) != -1) {
+ controlreply(np, "Server %s is linked right now, refusing to add split.",
+ servername);
+ return CMD_ERROR;
+ }
+
+ if (doessplitalreadyexist(servername)) {
+ controlreply(np, "There is a split for %s already.", servername);
+ return CMD_ERROR;
+ }
+
+ if (servernamelen > SERVERLEN) {
+ controlreply(np, "Server name %s is too long (max: %d characters)",
+ servername, SERVERLEN);
+ return CMD_ERROR;
+ }
+
+ /* Handle flags */
+ if (cargc > 1) {
+ if (setflags(&servertype, (flag_t)-1, cargv[1], servertypeflags,
+ REJECT_UNKNOWN) != REJECT_NONE) {
+ controlreply(np, "Flag string %s contained invalid flags.", cargv[1]);
+ return CMD_ERROR;
+ }
+ } else {
+ /* Set up a fake server for getservertype. */
+ memset(&fake, 0, sizeof(fake));
+
+ fake.name = getsstring(servername, servernamelen);
+ servertype = getservertype(&fake);
+ freesstring(fake.name);
+ }
+
+ /* Handle timestamp */
+ if (cargc < 3) {
+ splittime = getnettime();
+ } else {
+ errno = 0;
+ num = strtoull(cargv[2], &end, 10);
+ if (errno == ERANGE) {
+ controlreply(np, "%s is out of range for a timestamp.", cargv[2]);
+ return CMD_ERROR;
+ }
+
+ /* Truncation may happen here.
+ * However, there's no way to get the max time_t value, so we'll just try to
+ * find out after the fact.
+ */
+ splittime = (time_t)num;
+
+ if ((unsigned long long)splittime < num) {
+ controlreply(np, "Tried to use %llu as split time value, but it's too "
+ "large for the system to handle", num);
+ return CMD_ERROR;
+ }
+ }
+
+ sp_addsplit(servername, splittime, servertype);
+ controlreply(np, "Added split for %s (%s ago) with flags %s.",
+ servername, longtoduration(getnettime() - splittime, 1),
+ printflags(servertype, servertypeflags));
+
+ return CMD_OK;
+}
controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPADD'ed '%s'", controlid(sender), tg->name->content);
trustlog(tg, sender->authname, "Created trust group '%s' (ID #%d): howmany=%d, enforceident=%d, maxperident=%d, "
"createdby=%s, contact=%s, comment=%s",
- tg->name->content, howmany, tg->id, enforceident, maxperident, createdby, contact, comment);
+ tg->name->content, tg->id, howmany, enforceident, maxperident, createdby, contact, comment);
return CMD_OK;
}