#define HOOK_NICK_MODEOPER 307 /* Argument is void*[2] (nick, modes) */
#define HOOK_NICK_KILL 308 /* Argument is void*[2] (nick, reason) */
#define HOOK_NICK_MASKPRIVMSG 309 /* Argument is void*[3] (nick, target, message) ** NICK COULD BE NULL ** */
+#define HOOK_NICK_MOVENODE 310 /* Argument is void*[2] (nick, oldnode) */
#define HOOK_CHANNEL_BURST 400 /* Argument is channel pointer */
#define HOOK_CHANNEL_CREATE 401 /* Argument is void*[2] (channel, nick) */
return buf;
}
+/*
+ * setipnodebits:
+ * Moves the nick to a different ipnode.
+ */
+void setipnodebits(nick *np, int bits) {
+ struct irc_in_addr ipaddress;
+ patricia_node_t *oldnode;
+ void *harg[2];
+
+ if(np->ipnode->prefix->bitlen == bits)
+ return;
+
+ memcpy(&ipaddress, &np->p_nodeaddr, sizeof(ipaddress));
+ node_decrement_usercount(np->ipnode);
+ oldnode = np->ipnode;
+ np->ipnode = refnode(iptree, &ipaddress, bits);
+ node_increment_usercount(np->ipnode);
+
+ harg[0] = np;
+ harg[1] = oldnode;
+ triggerhook(HOOK_NICK_MOVENODE, harg);
+
+ derefnode(iptree, oldnode);
+}
+
#if 0
/*
return getnickbynumeric(numerictolong(numericstr,5));
}
+
#endif
} nick;
#define p_ipaddr ipaddress
+#define p_nodeaddr ipnode->prefix->sin
#define NICKHASHSIZE 60000
#define HOSTHASHSIZE 40000
void releasenickext(int index);
char *visiblehostmask(nick *np, char *buf);
char *visibleuserhost(nick *np, char *buf);
+void setipnodebits(nick *np, int bits);
/* nickhandlers.c functions */
int handlenickmsg(void *source, int cargc, char **cargv);
registerhook(HOOK_NICK_NEWNICK, &pn_hook_newuser);
registerhook(HOOK_NICK_LOSTNICK, &pn_hook_lostuser);
+ registerhook(HOOK_NICK_MOVENODE, &pn_hook_movenodeuser);
registercontrolhelpcmd("nodeuserlist", NO_OPER, 1, &pn_cmd_nodeuserlist, "Usage: nodeuserlist <ipv4|ipv6|cidr4|cidr6>\nLists all users on a given IP address or CIDR range.");
}
deregisterhook(HOOK_NICK_NEWNICK, &pn_hook_newuser);
deregisterhook(HOOK_NICK_LOSTNICK, &pn_hook_lostuser);
+ deregisterhook(HOOK_NICK_MOVENODE, &pn_hook_movenodeuser);
deregistercontrolcmd("nodeuserlist", &pn_cmd_nodeuserlist);
}
deletenickfromnode(np->ipnode, np);
}
+void pn_hook_nodemoveuser(int hook, void *arg) {
+ nick *np = ((void **)arg)[0];
+ patricia_node_t *oldnode = ((void **)arg)[1];
+
+ deletenickfromnode(oldnode, np);
+ addnicktonode(np->ipnode, np);
+}
+
int pn_cmd_nodeuserlist(void *source, int cargc, char **cargv) {
nick *np=(nick *)source;
struct irc_in_addr sin;
void pn_hook_newuser(int hook, void *arg);
void pn_hook_lostuser(int hook, void *arg);
+void pn_hook_movenodeuser(int hook, void *arg);
void addnicktonode(patricia_node_t *node, nick *nick);
void deletenickfromnode(patricia_node_t *node, nick *nick);
th->users = NULL;
th->count = 0;
+ th->maxpernode = 0;
+ th->nodebits = 128;
+
th->parent = NULL;
th->children = NULL;
nick *np, *nnp;
for(np=superset->users;np;np=nnp) {
nnp = nextbytrust(np);
- if((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip) {
+ if((irc_in_addr_v4_to_int(&np->p_nodeaddr) & th->mask) == th->ip) {
trusts_lostnick(np, 1);
trusts_newnick(np, 1);
}
for(i=0;i<NICKHASHSIZE;i++)
for(np=nicktable[i];np;np=np->next)
- if(!gettrusthost(np) && ((irc_in_addr_v4_to_int(&np->p_ipaddr) & th->mask) == th->ip))
+ if(!gettrusthost(np) && ((irc_in_addr_v4_to_int(&np->p_nodeaddr) & th->mask) == th->ip))
trusts_newnick(np, 1);
}
}
} else {
setnextbytrust(sender, th->users);
th->users = sender;
+ setipnodebits(sender, th->nodebits);
}
arg[0] = sender;
if(oformat) {
snprintf(buf, sizeof(buf), "#%u,%s,%u,%u,%jd", th->group->id, trusts_cidr2str(th->ip, th->mask), th->count, th->maxusage, (intmax_t)th->lastseen);
} else {
- snprintf(buf, sizeof(buf), "%u,%s,%u,%u,%jd,%jd", th->group->id, trusts_cidr2str(th->ip, th->mask), th->id, th->maxusage, (intmax_t)th->lastseen, (intmax_t)th->created);
+ snprintf(buf, sizeof(buf), "%u,%s,%u,%u,%jd,%jd,%u,%u", th->group->id, trusts_cidr2str(th->ip, th->mask), th->id, th->maxusage, (intmax_t)th->lastseen, (intmax_t)th->created, th->maxpernode, th->nodebits);
}
return buf;
int parseth(char *line, trusthost *th, unsigned int *tgid, int oformat) {
unsigned long lastseen, created;
+ int maxpernode, nodebits;
char *ip, xbuf[1024], *id;
/* #id,213.230.192.128/26,20,23,1222732944
return 0;
created = time(NULL);
} else {
- if(sscanf(line, "%u,%u,%lu,%lu", &th->id, &th->maxusage, &lastseen, &created) != 4)
+ if(sscanf(line, "%u,%u,%lu,%lu,%d,%d", &th->id, &th->maxusage, &lastseen, &created, &maxpernode, &nodebits) != 6)
return 0;
}
th->lastseen = (time_t)lastseen;
th->created = (time_t)created;
+ th->maxpernode = maxpernode;
+ th->nodebits = nodebits;
return 1;
}
typedef struct trusthost {
unsigned int id;
-
uint32_t ip, mask;
unsigned int maxusage;
time_t created;
unsigned int count;
+ int maxpernode;
+ int nodebits;
+
struct trusthost *parent, *children;
unsigned int marker;
static void outputtree(nick *np, unsigned int marker, trustgroup *originalgroup, trusthost *th, int depth) {
char *cidrstr, *prespacebuf, *postspacebuf, parentbuf[512];
+ int mask;
if(th->marker != marker)
return;
snprintf(parentbuf, sizeof(parentbuf), "%-10d %s", th->group->id, th->group->name->content);
}
- controlreply(np, "%s%s%s %-10d %-10d %-21s%s", prespacebuf, cidrstr, postspacebuf, th->count, th->maxusage, (th->count>0)?"(now)":((th->lastseen>0)?trusts_timetostr(th->lastseen):"(never)"), trusts_timetostr(th->created), parentbuf);
+ /*if (!ipv6) */
+ mask = th->nodebits - 96;
+
+ controlreply(np, "%s%s%s %-10d %-10d %-21s %-15d /%-14d%s", prespacebuf, cidrstr, postspacebuf, th->count, th->maxusage, (th->count>0)?"(now)":((th->lastseen>0)?trusts_timetostr(th->lastseen):"(never)"), th->maxpernode, mask, parentbuf);
for(th=th->children;th;th=th->nextbychild)
outputtree(np, marker, originalgroup, th, depth + 1);
controlreply(sender, "Max usage : %d", tg->maxusage);
controlreply(sender, "Last max reset : %s", tg->lastmaxusereset?trusts_timetostr(tg->lastmaxusereset):"(never)");
- controlreply(sender, "Host Current Max Last seen Created Group ID Group name");
+ controlreply(sender, "Host Current Max Last seen Max per Node Node Mask Group ID Group name");
marker = nextthmarker();
array_init(&parents, sizeof(trusthost *));
);
/* I'd like multiple keys here but that's not gonna happen on a cross-database platform :( */
- trustsdb->createtable(trustsdb, NULL, NULL, "CREATE TABLE ? (id INT PRIMARY KEY, groupid INT, host VARCHAR(?), maxusage INT, created INT, lastseen INT)", "Td", hosts, TRUSTHOSTLEN);
+ trustsdb->createtable(trustsdb, NULL, NULL, "CREATE TABLE ? (id INT PRIMARY KEY, groupid INT, host VARCHAR(?), maxusage INT, created INT, lastseen INT, maxpernode INT, nodebits INT)", "Td", hosts, TRUSTHOSTLEN);
trustsdb->createtable(trustsdb, NULL, NULL,
"CREATE TABLE ? (id INT PRIMARY KEY, groupid INT, groupname VARCHAR(?), ts INT, username VARCHAR(?), message VARCHAR(?))",
return;
}
- if(result->fields != 6) {
+ if(result->fields != 8) {
Error("trusts", ERR_ERROR, "Wrong number of fields in hosts table.");
loaderror = 1;
th.maxusage = strtoul(result->get(result, 3), NULL, 10);
th.created = (time_t)strtoul(result->get(result, 4), NULL, 10);
th.lastseen = (time_t)strtoul(result->get(result, 5), NULL, 10);
+ th.maxpernode = strtol(result->get(result, 6), NULL, 10);
+ th.nodebits = strtol(result->get(result, 7), NULL, 10);
if(!th_add(&th))
Error("trusts", ERR_WARNING, "Error adding host to trust %d: %s", groupid, host);
void trustsdb_insertth(char *table, trusthost *th, unsigned int groupid) {
trustsdb->squery(trustsdb,
- "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen) VALUES (?, ?, ?, ?, ?, ?)",
- "Tuusuut", table, th->id, groupid, trusts_cidr2str(th->ip, th->mask), th->maxusage, th->created, th->lastseen
+ "INSERT INTO ? (id, groupid, host, maxusage, created, lastseen, maxpernode, nodebits) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
+ "Tuusuutuu", table, th->id, groupid, trusts_cidr2str(th->ip, th->mask), th->maxusage, th->created, th->lastseen, th->maxpernode, th->nodebits
);
}
if(moving)
return;
- if(!th) {
+ if(!th)
+ return;
+
+ if(th->maxpernode > np->ipnode->usercount) {
if(np->ipnode->usercount > 5)
- controlwall(NO_OPER, NL_TRUSTS, "Hard connection limit exceeded on IP: %s (untrusted) %d connected, 5 max.", IPtostr(np->p_ipaddr), np->ipnode->usercount);
+ controlwall(NO_OPER, NL_TRUSTS, "Hard connection limit exceeded on IP: %s (group: %s) %d connected, %d max.", IPtostr(np->p_ipaddr), tg->name->content, np->ipnode->usercount, th->maxpernode);
return;
}