]> jfr.im git - irc/quakenet/newserv.git/blob - banevade/banevade.c
045d1096abd7842e4417ff111eb35c856c779da5
[irc/quakenet/newserv.git] / banevade / banevade.c
1 #include <stdio.h>
2 #include "../irc/irc.h"
3 #include "../lib/version.h"
4 #include "../lib/irc_string.h"
5 #include "../channel/channel.h"
6 #include "../bans/bans.h"
7 #include "../control/control.h"
8 #include "../localuser/localuser.h"
9 #include "../localuser/localuserchannel.h"
10
11 #define BANEVADE_SPAM
12
13 MODULE_VERSION("")
14
15 int ircdbanned(nick *n, channel *c);
16
17 static chanban *nickbanned2(nick *np, channel *cp, int visibleonly) {
18 chanban *cbp;
19
20 for (cbp=cp->bans;cbp;cbp=cbp->next) {
21 if (nickmatchban(np,cbp,visibleonly))
22 return cbp;
23 }
24
25 return NULL;
26 }
27
28 void be_onjoin(int hooknum, void *arg) {
29 void **arglist = (void **)arg;
30 channel *c = ((channel *)arglist[0]);
31 nick *np = arglist[1];
32
33 /* Verify both are valid */
34 if(!c || !np)
35 return;
36
37 /* Services, opers and extended opers can bypass bans */
38 if (IsService(np) || IsOper(np) || IsXOper(np) || NickOnServiceServer(np))
39 return;
40
41 int ircd_banned = ircdbanned(np, c);
42 chanban *ns_banned = nickbanned2(np, c, 0);
43
44 #ifdef BANEVADE_SPAM
45 Error("banevade", ERR_INFO, "Ban status ircd_banned=%d newserv_banned=%s", ircd_banned, (ns_banned ? "here" : "(null)"));
46 #endif
47
48 /* If we're not considered banned as per the ircd code,
49 but banned according to newserv - trigger the hook */
50 if(!ircd_banned && ns_banned) {
51 /* We kinda dont need this hook anymore - but we'll trigger it anyway for future scripts/modules */
52 triggerhook(HOOK_CHANNEL_JOIN_BYPASS_BAN, arg);
53
54 channel *cp = findchannel("#qnet.banevade");
55 if(cp)
56 controlchanmsg(cp, "banevade: bad user in %s: %s!%s@%s vs. %s", c->index->name->content, np->nick, np->ident, np->host->name->content, bantostring(ns_banned));
57
58 if(IsAccount(np)) {
59 /* Reset host to [cc].HIS_HIDDENHOST */
60 char host[HOSTLEN+1] = "";
61 snprintf(host, sizeof(host), "%s.%s", np->authname, HIS_HIDDENHOST);
62
63 /* I didnt find a function for this, so we're doing it R A W */
64 irc_send("%s SH %s %s %s", mynumeric->content, longtonumeric(np->numeric, 5), np->ident, host);
65
66 /* Also remove them from the channel they're not supposed to be in */
67 /* We're gonna go with the generic default-Q-kick-reason since we don't know the real reason for the kick */
68 localkickuser(NULL, c, np, "Banned.");
69 } else {
70 /* Honest to god, this should never happen since the IRCD is in a state where it
71 * checks EITHER the sethost or the authname. So people shouldn't be able to avoid bans
72 * unauthed. But we still need to handle it, incase shit hits the fan. */
73
74 /* User has a spoofed host but isn't authed, most likely a s:line (for some reason I want to write an s:line). Send them flying. */
75 /* We're not gonna kill the user because they'll most likely just reconnect and rejoin, causing a buttload of spam. */
76 /* So just trigger an extra line of spam into qnet.banevade so we'll investigate manually! */
77 //killuser(NULL, np, "Please don't avoid bans on QuakeNet");
78
79 /* Also send an additional spam line to the amazing OGs in qnet.banevade */
80 if(cp) controlchanmsg(cp, "banevade: user %s appears to be un-authed, this might be a s:line!", np->nick);
81 }
82 }
83
84 }
85 void _init() {
86 registerhook(HOOK_CHANNEL_JOIN, &be_onjoin);
87 registerhook(HOOK_CHANNEL_CREATE, &be_onjoin);
88 }
89
90 void _fini() {
91 deregisterhook(HOOK_CHANNEL_JOIN, &be_onjoin);
92 deregisterhook(HOOK_CHANNEL_CREATE, &be_onjoin);
93 }
94
95 /* This code is based on snircd 1.3.4a, which has the bug where authed users with +h
96 could bypass *!*@[account].users.quakenet.org bans.
97 It has been somewhat rewritten to fit the NewServ ban flags and structure
98 */
99
100 /* The ircd checks 4 things:
101 *
102 * The clients nick!username (where username is current, original usernames are not checked)
103 * The clients real ip towards IP bans
104 * The real host (if client is using a cloaked host)
105 * The current host of the client
106 *
107 * This causes the bug that [account].HIS_HIDDENHOST is never checked towards the banlist
108 * if they have +h set.
109 * We need to replicate that check in this code
110 */
111
112 #ifdef BANEVADE_SPAM
113 #define IFNULLELSE(x, y) (x ? y : "(null)")
114 #endif
115
116 int ircdbanned(nick *n, channel *c) {
117 char *nick = n->nick;
118 char *ident = n->ident;
119 char tmphost[HOSTLEN + 1];
120 char *sr;
121 chanban *cb = NULL;
122
123 /* Here is the bug in the ircd.
124 * In a perfect world we'd have one more variable to save both sethost and authhost
125 */
126 if (!IsAccount(n))
127 sr = NULL;
128 else if (IsSetHost(n))
129 sr = n->sethost->content;
130 else {
131 snprintf(tmphost, sizeof(tmphost), "%s.%s", n->authname, HIS_HIDDENHOST);
132 sr = tmphost;
133 }
134
135 #ifdef BANEVADE_SPAM
136 Error("banevade", ERR_INFO, "---------------------------");
137 Error("banevade", ERR_INFO, "User %s has joined %s.", nick, c->index->name->content);
138 Error("banevade", ERR_INFO, "We will be checking the following:");
139 Error("banevade", ERR_INFO, " nick=%s ident=%s iphost=%s sr=%s host=%s", nick, ident, IPtostr(n->ipaddress), IFNULLELSE(sr, sr), n->host->name->content);
140 #endif
141
142 /* Walk through ban list. */
143 for (cb = c->bans; cb; cb = cb->next) {
144 #ifdef BANEVADE_SPAM
145 Error("banevade", ERR_INFO, "Ban for: %s!%s@%s", IFNULLELSE(cb->nick, cb->nick->content), IFNULLELSE(cb->user, cb->user->content), IFNULLELSE(cb->host, cb->host->content));
146 #endif
147
148 /* Compare nick and user portion of ban. */
149 /* ircd code:
150 banlist->banstr[banlist->nu_len] = '\0';
151 res = match(banlist->banstr, nu);
152 banlist->banstr[banlist->nu_len] = '@';
153 */
154
155 /* Our code - since we don't save nick!user in our ban structure - we need to check it using other tools!
156 * I've only used match2strings, I've not used the flags for CHANBAN_NICKEXACT etc.
157 * The only issue I could think of is the lack of irc_compare for {[]} etc.
158 * But the ircd uses match, so I went with this to be somewhat 1:1 close to it.
159 * Give me a poke if you want this to be more like nickbanned() with those checks.
160 */
161 if(cb->nick) {
162 if(!match2strings(cb->nick->content, nick)) {
163 #ifdef BANEVADE_SPAM
164 Error("banevade", ERR_INFO, " nick is present but not matching");
165 #endif
166 continue;
167 }
168 }
169 if(cb->user) {
170 if(!match2strings(cb->user->content, ident)) {
171 #ifdef BANEVADE_SPAM
172 Error("banevade", ERR_INFO, " user is present but not matching");
173 #endif
174 continue;
175 }
176 }
177
178 /* Compare host portion of ban. */
179 /* ircd code:
180 if (!((cb->flags & BAN_IPMASK)
181 && ipmask_check(&cli_ip(cptr), &cb->address, cb->addrbits))
182 && match(hostmask, cli_user(cptr)->host)
183 && !(sr && !match(hostmask, sr)))
184 continue;
185 */
186 if(cb->host) {
187 if(
188 /* Check current host */
189 !match2strings(cb->host->content, n->host->name->content)
190 /* Check IP if ip-ban */
191 && !((cb->flags & CHANBAN_IP) && ipmask_check(&(n->ipnode->prefix->sin), &(cb->ipaddr), cb->prefixlen))
192 /* Check our real host (if +h/+x) */
193 && !(sr && match2strings(cb->host->content, sr))
194 ) {
195 #ifdef BANEVADE_SPAM
196 Error("banevade", ERR_INFO, " host is present but not matching.");
197 #endif
198 continue;
199 }
200 }
201
202 /* If we got this far, everything that exists in the ban matches! */
203 #ifdef BANEVADE_SPAM
204 Error("banevade", ERR_INFO, " -- Ban appears to hit the user.");
205 #endif
206 return 1;
207 }
208
209 return 0;
210 }