]> jfr.im git - irc/quakenet/newserv.git/blob - patricianick/patricianick.c
IPv6 support for trusts.
[irc/quakenet/newserv.git] / patricianick / patricianick.c
1 /* patricianick.c */
2
3 #include "patricianick.h"
4 #include "../irc/irc_config.h"
5 #include "../lib/irc_string.h"
6 #include "../core/error.h"
7 #include "../core/nsmalloc.h"
8 #include "../control/control.h"
9 #include "../core/schedule.h"
10 #include "../lib/version.h"
11
12 #include <stdio.h>
13 #include <string.h>
14
15 #define ALLOCUNIT 100
16
17 MODULE_VERSION("")
18
19 patricianick_t *freepatricianicks;
20 int pnode_ext;
21 int pnick_ext;
22
23 int pn_cmd_nodeuserlist(void *source, int cargc, char **cargv);
24
25 void _init() {
26 nick *np, *nnp;
27 int i;
28
29 pnode_ext = registernodeext("patricianick");
30 if (pnode_ext == -1) {
31 Error("patricianick", ERR_FATAL, "Could not register a required node extension");
32 return;
33 }
34
35 pnick_ext = registernickext("patricianick");
36 if (pnick_ext == -1) {
37 Error("patricianick", ERR_FATAL, "Could not register a required nick extension");
38 return;
39 }
40
41 for (i=0;i<NICKHASHSIZE;i++)
42 for (np=nicktable[i];np;np=nnp) {
43 nnp=np->next;
44 addnicktonode(np->ipnode, np);
45 }
46
47 registerhook(HOOK_NICK_NEWNICK, &pn_hook_newuser);
48 registerhook(HOOK_NICK_LOSTNICK, &pn_hook_lostuser);
49 registerhook(HOOK_NICK_MOVENODE, &pn_hook_nodemoveuser);
50
51 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.");
52 }
53
54 void _fini() {
55 nsfreeall(POOL_PATRICIANICK);
56
57 if (pnode_ext != -1) {
58 releasenodeext(pnode_ext);
59 }
60
61 if (pnick_ext != -1) {
62 releasenickext(pnick_ext);
63 }
64
65 deregisterhook(HOOK_NICK_NEWNICK, &pn_hook_newuser);
66 deregisterhook(HOOK_NICK_LOSTNICK, &pn_hook_lostuser);
67 deregisterhook(HOOK_NICK_MOVENODE, &pn_hook_nodemoveuser);
68
69 deregistercontrolcmd("nodeuserlist", &pn_cmd_nodeuserlist);
70 }
71
72 patricianick_t *getpatricianick() {
73 int i;
74 patricianick_t *pnp;
75
76 if (freepatricianicks==NULL) {
77 freepatricianicks=(patricianick_t *)nsmalloc(POOL_PATRICIANICK, ALLOCUNIT*sizeof(patricianick_t));
78 for(i=0;i<ALLOCUNIT-1;i++) {
79 freepatricianicks[i].identhash[0]=(nick *)&(freepatricianicks[i+1]);
80 }
81 freepatricianicks[ALLOCUNIT-1].identhash[0]=NULL;
82 }
83
84 pnp=freepatricianicks;
85 freepatricianicks=(patricianick_t *)pnp->identhash[0];
86
87 memset(pnp, 0, sizeof(patricianick_t));
88 return pnp;
89 }
90
91 void addnicktonode(patricia_node_t *node, nick *np) {
92 unsigned long hash;
93
94 patricia_ref_prefix(node->prefix);
95
96 if (!(node->exts[pnode_ext])) {
97 node->exts[pnode_ext] = getpatricianick();
98 }
99
100 hash = pn_getidenthash(np->ident);
101 np->exts[pnick_ext] = ((patricianick_t *)node->exts[pnode_ext])->identhash[hash];
102 ((patricianick_t *)node->exts[pnode_ext])->identhash[hash] = np;
103 }
104
105 void deletenickfromnode(patricia_node_t *node, nick *np) {
106 nick **tnp;
107 int found, i;
108
109 found = 0;
110
111 for (tnp = &(((patricianick_t *)node->exts[pnode_ext])->identhash[pn_getidenthash(np->ident)]); *tnp; tnp = (nick **)(&((*tnp)->exts[pnick_ext]))) {
112 if (*tnp == np) {
113 *tnp = np->exts[pnick_ext];
114 found = 1;
115 break;
116 }
117 }
118
119 if (!found) {
120 Error("patricianick", ERR_ERROR, "Could not remove %s!%s from %s", np->nick, np->ident, IPtostr(node->prefix->sin));
121 return;
122 }
123
124 for (i = 0; i < PATRICIANICK_HASHSIZE; i++) {
125 if (((patricianick_t *)node->exts[pnode_ext])->identhash[i]) {
126 return;
127 }
128 }
129
130 freepatricianick(node->exts[pnode_ext]);
131 node->exts[pnode_ext]= NULL;
132 }
133
134 void freepatricianick(patricianick_t *pnp) {
135 pnp->identhash[0]=(nick *)freepatricianicks;
136 freepatricianicks=pnp;
137 }
138
139 void pn_hook_newuser(int hook, void *arg) {
140 nick *np = (nick *)arg;
141
142 addnicktonode(np->ipnode, np);
143 }
144
145 void pn_hook_lostuser(int hook, void *arg) {
146 nick *np = (nick *)arg;
147
148 deletenickfromnode(np->ipnode, np);
149 }
150
151 void pn_hook_nodemoveuser(int hook, void *arg) {
152 nick *np = ((void **)arg)[0];
153 patricia_node_t *oldnode = ((void **)arg)[1];
154
155 deletenickfromnode(oldnode, np);
156 addnicktonode(np->ipnode, np);
157 }
158
159 int pn_cmd_nodeuserlist(void *source, int cargc, char **cargv) {
160 nick *np=(nick *)source;
161 struct irc_in_addr sin;
162 unsigned char bits;
163 unsigned int count, i;
164 patricia_node_t *head, *node;
165 patricianick_t *pnp;
166 nick *npp;
167
168 if (cargc < 1) {
169 return CMD_USAGE;
170 }
171
172 if (ipmask_parse(cargv[0], &sin, &bits) == 0) {
173 controlreply(np, "Invalid mask.");
174 return CMD_ERROR;
175 }
176
177 head = refnode(iptree, &sin, bits);
178 count = 0;
179
180 PATRICIA_WALK(head, node)
181 {
182 pnp = node->exts[pnode_ext];
183 if (pnp) {
184 if (count < PATRICIANICK_MAXRESULTS) {
185 for (i = 0; i < PATRICIANICK_HASHSIZE; i++) {
186 for (npp = pnp->identhash[i]; npp; npp=npp->exts[pnick_ext]) {
187 controlreply(np, "%s!%s@%s%s%s (%s)", npp->nick, npp->ident, npp->host->name->content, IsAccount(npp) ? "/" : "", npp->authname, IPtostr(node->prefix->sin));
188 }
189 }
190
191 count += node->usercount;
192
193 if (count >= PATRICIANICK_MAXRESULTS) {
194 controlreply(np, "Too many results, output truncated");
195 }
196 } else {
197 count += node->usercount;
198 }
199 }
200 }
201 PATRICIA_WALK_END;
202 derefnode(iptree, head);
203
204 controlreply(np, "Total users on %s: %d", cargv[0], count);
205 return CMD_OK;
206 }