]> jfr.im git - solanum.git/blame - modules/m_trace.c
Add ACCOUNTEXTBAN ISUPPORT token
[solanum.git] / modules / m_trace.c
CommitLineData
212380e3
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_trace.c: Traces a path to a client/server.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
212380e3
AC
23 */
24
25#include "stdinc.h"
26#include "class.h"
27#include "hook.h"
28#include "client.h"
29#include "hash.h"
212380e3 30#include "hash.h"
4562c604 31#include "match.h"
212380e3
AC
32#include "ircd.h"
33#include "numeric.h"
212380e3
AC
34#include "s_serv.h"
35#include "s_conf.h"
36#include "s_newconf.h"
37#include "send.h"
38#include "msg.h"
39#include "parse.h"
40#include "modules.h"
41
be9c3979
AW
42static const char trace_desc[] =
43 "Provides the TRACE command to trace the route to a client or server";
212380e3 44
3c7d6fcc 45static void m_trace(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
eeabf33a 46
212380e3
AC
47static void trace_spy(struct Client *, struct Client *);
48
49struct Message trace_msgtab = {
7baa37a9 50 "TRACE", 0, 0, 0, 0,
212380e3
AC
51 {mg_unreg, {m_trace, 0}, {m_trace, 0}, mg_ignore, mg_ignore, {m_trace, 0}}
52};
53
54int doing_trace_hook;
01fb744c 55int doing_trace_show_idle_hook;
212380e3
AC
56
57mapi_clist_av1 trace_clist[] = { &trace_msgtab, NULL };
58mapi_hlist_av1 trace_hlist[] = {
59 { "doing_trace", &doing_trace_hook },
01fb744c 60 { "doing_trace_show_idle", &doing_trace_show_idle_hook },
212380e3
AC
61 { NULL, NULL }
62};
be9c3979 63DECLARE_MODULE_AV2(trace, NULL, NULL, trace_clist, trace_hlist, NULL, NULL, NULL, trace_desc);
212380e3
AC
64
65static void count_downlinks(struct Client *server_p, int *pservcount, int *pusercount);
a4da8e48 66static int report_this_status(struct Client *source_p, struct Client *target_p);
212380e3 67
a3afc27a
VY
68static const char *empty_sockhost = "255.255.255.255";
69
212380e3
AC
70/*
71 * m_trace
212380e3
AC
72 * parv[1] = servername
73 */
3c7d6fcc 74static void
428ca87b 75m_trace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
76{
77 struct Client *target_p = NULL;
78 struct Class *cltmp;
79 const char *tname;
3c7d6fcc
EM
80 bool doall = false, wilds, dow;
81 int cnt = 0;
5b96d9a6 82 rb_dlink_node *ptr;
212380e3
AC
83
84 if(parc > 1)
85 {
86 tname = parv[1];
87
88 if(parc > 2)
89 {
90 if(hunt_server(client_p, source_p, ":%s TRACE %s :%s", 2, parc, parv) !=
91 HUNTED_ISME)
3c7d6fcc 92 return;
212380e3
AC
93 }
94 }
95 else
96 tname = me.name;
97
98 /* if we have 3 parameters, then the command is directed at us. So
99 * we shouldnt be forwarding it anywhere.
100 */
101 if(parc < 3)
102 {
103 switch (hunt_server(client_p, source_p, ":%s TRACE :%s", 1, parc, parv))
104 {
105 case HUNTED_PASS: /* note: gets here only if parv[1] exists */
106 {
107 struct Client *ac2ptr;
108
109 if(MyClient(source_p))
110 ac2ptr = find_named_client(tname);
111 else
112 ac2ptr = find_client(tname);
113
114 if(ac2ptr == NULL)
115 {
2fb07961 116 RB_DLINK_FOREACH(ptr, global_serv_list.head)
212380e3
AC
117 {
118 ac2ptr = ptr->data;
119
4d7a1ee5 120 if(match(tname, ac2ptr->name))
212380e3
AC
121 break;
122 else
123 ac2ptr = NULL;
124 }
125 }
126
127 /* giving this out with flattened links defeats the
128 * object --fl
129 */
d4f7eb4c 130 if(IsOperGeneral(source_p) || IsExemptShide(source_p) ||
212380e3 131 !ConfigServerHide.flatten_links)
55abcbb2 132 sendto_one_numeric(source_p, RPL_TRACELINK,
212380e3 133 form_str(RPL_TRACELINK),
55abcbb2 134 ircd_version,
212380e3
AC
135 ac2ptr ? ac2ptr->name : tname,
136 ac2ptr ? ac2ptr->from->name : "EEK!");
137
3c7d6fcc 138 return;
212380e3
AC
139 }
140
141 case HUNTED_ISME:
142 break;
143
144 default:
3c7d6fcc 145 return;
212380e3
AC
146 }
147 }
148
149 if(match(tname, me.name))
150 {
3c7d6fcc 151 doall = true;
212380e3
AC
152 }
153 /* if theyre tracing our SID, we need to move tname to our name so
154 * we dont give the sid in ENDOFTRACE
155 */
156 else if(!MyClient(source_p) && !strcmp(tname, me.id))
157 {
3c7d6fcc 158 doall = true;
212380e3
AC
159 tname = me.name;
160 }
161
162 wilds = strchr(tname, '*') || strchr(tname, '?');
163 dow = wilds || doall;
164
165 /* specific trace */
3c7d6fcc 166 if(!dow)
212380e3
AC
167 {
168 if(MyClient(source_p) || parc > 2)
169 target_p = find_named_person(tname);
170 else
171 target_p = find_person(tname);
172
173 /* tname could be pointing to an ID at this point, so reset
174 * it to target_p->name if we have a target --fl
175 */
176 if(target_p != NULL)
177 {
a4da8e48 178 report_this_status(source_p, target_p);
212380e3
AC
179 tname = target_p->name;
180 }
181
182 trace_spy(source_p, target_p);
183
55abcbb2 184 sendto_one_numeric(source_p, RPL_ENDOFTRACE,
212380e3 185 form_str(RPL_ENDOFTRACE), tname);
3c7d6fcc 186 return;
212380e3
AC
187 }
188
189 trace_spy(source_p, NULL);
190
55abcbb2 191 /* give non-opers a limited trace output of themselves (if local),
212380e3
AC
192 * opers and servers (if no shide) --fl
193 */
194 if(!IsOper(source_p))
195 {
196 if(MyClient(source_p))
197 {
198 if(doall || (wilds && match(tname, source_p->name)))
a4da8e48 199 report_this_status(source_p, source_p);
212380e3
AC
200 }
201
5b96d9a6 202 RB_DLINK_FOREACH(ptr, local_oper_list.head)
212380e3
AC
203 {
204 target_p = ptr->data;
205
206 if(!doall && wilds && (match(tname, target_p->name) == 0))
207 continue;
208
1123eefc
EK
209 if(!SeesOper(target_p, source_p))
210 continue;
211
a4da8e48 212 report_this_status(source_p, target_p);
212380e3
AC
213 }
214
215 if (IsExemptShide(source_p) || !ConfigServerHide.flatten_links)
216 {
5b96d9a6 217 RB_DLINK_FOREACH(ptr, serv_list.head)
212380e3
AC
218 {
219 target_p = ptr->data;
220
221 if(!doall && wilds && !match(tname, target_p->name))
222 continue;
223
a4da8e48 224 report_this_status(source_p, target_p);
212380e3
AC
225 }
226 }
227
55abcbb2 228 sendto_one_numeric(source_p, RPL_ENDOFTRACE,
212380e3 229 form_str(RPL_ENDOFTRACE), tname);
3c7d6fcc 230 return;
212380e3
AC
231 }
232
233 /* source_p is opered */
234
235 /* report all direct connections */
5b96d9a6 236 RB_DLINK_FOREACH(ptr, lclient_list.head)
212380e3
AC
237 {
238 target_p = ptr->data;
239
240 /* dont show invisible users to remote opers */
1123eefc 241 if(IsInvisible(target_p) && dow && !MyConnect(source_p) && !SeesOper(target_p, source_p))
212380e3
AC
242 continue;
243
244 if(!doall && wilds && !match(tname, target_p->name))
245 continue;
246
abee738b 247 /* remote opers may not see invisible normal users */
1123eefc 248 if(dow && !MyConnect(source_p) && !SeesOper(target_p, source_p) &&
abee738b
JT
249 IsInvisible(target_p))
250 continue;
251
a4da8e48 252 cnt = report_this_status(source_p, target_p);
212380e3
AC
253 }
254
5b96d9a6 255 RB_DLINK_FOREACH(ptr, serv_list.head)
212380e3
AC
256 {
257 target_p = ptr->data;
258
259 if(!doall && wilds && !match(tname, target_p->name))
260 continue;
261
a4da8e48 262 cnt = report_this_status(source_p, target_p);
212380e3
AC
263 }
264
265 if(MyConnect(source_p))
266 {
5b96d9a6 267 RB_DLINK_FOREACH(ptr, unknown_list.head)
212380e3
AC
268 {
269 target_p = ptr->data;
270
271 if(!doall && wilds && !match(tname, target_p->name))
272 continue;
273
a4da8e48 274 cnt = report_this_status(source_p, target_p);
212380e3
AC
275 }
276 }
277
278 if(!cnt)
279 {
280 sendto_one_numeric(source_p, ERR_NOSUCHSERVER, form_str(ERR_NOSUCHSERVER),
281 tname);
282
283 /* let the user have some idea that its at the end of the
284 * trace
285 */
55abcbb2 286 sendto_one_numeric(source_p, RPL_ENDOFTRACE,
212380e3 287 form_str(RPL_ENDOFTRACE), tname);
3c7d6fcc 288 return;
212380e3
AC
289 }
290
291 if(doall)
292 {
5b96d9a6 293 RB_DLINK_FOREACH(ptr, class_list.head)
212380e3
AC
294 {
295 cltmp = ptr->data;
296
297 if(CurrUsers(cltmp) > 0)
298 sendto_one_numeric(source_p, RPL_TRACECLASS,
55abcbb2 299 form_str(RPL_TRACECLASS),
212380e3
AC
300 ClassName(cltmp), CurrUsers(cltmp));
301 }
302 }
303
304 sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), tname);
212380e3
AC
305}
306
307/*
308 * count_downlinks
309 *
310 * inputs - pointer to server to count
311 * - pointers to server and user count
312 * output - NONE
313 * side effects - server and user counts are added to given values
314 */
315static void
316count_downlinks(struct Client *server_p, int *pservcount, int *pusercount)
317{
5b96d9a6 318 rb_dlink_node *ptr;
212380e3
AC
319
320 (*pservcount)++;
5b96d9a6
AC
321 *pusercount += rb_dlink_list_length(&server_p->serv->users);
322 RB_DLINK_FOREACH(ptr, server_p->serv->servers.head)
212380e3
AC
323 {
324 count_downlinks(ptr->data, pservcount, pusercount);
325 }
326}
327
328/*
329 * report_this_status
330 *
331 * inputs - pointer to client to report to
332 * - pointer to client to report about
333 * output - counter of number of hits
334 * side effects - NONE
335 */
336static int
a4da8e48 337report_this_status(struct Client *source_p, struct Client *target_p)
212380e3
AC
338{
339 const char *name;
340 const char *class_name;
341 char ip[HOSTIPLEN];
342 int cnt = 0;
343
344 /* sanity check - should never happen */
345 if(!MyConnect(target_p))
346 return 0;
347
caa4d9d2 348 rb_inet_ntop_sock((struct sockaddr *)&target_p->localClient->ip, ip, sizeof(ip));
212380e3
AC
349 class_name = get_client_class(target_p);
350
351 if(IsAnyServer(target_p))
b3ebc7ab 352 name = target_p->name;
212380e3
AC
353 else
354 name = get_client_name(target_p, HIDE_IP);
355
356 switch (target_p->status)
357 {
358 case STAT_CONNECTING:
359 sendto_one_numeric(source_p, RPL_TRACECONNECTING,
360 form_str(RPL_TRACECONNECTING),
361 class_name, name);
362 cnt++;
363 break;
364
365 case STAT_HANDSHAKE:
366 sendto_one_numeric(source_p, RPL_TRACEHANDSHAKE,
367 form_str(RPL_TRACEHANDSHAKE),
368 class_name, name);
369 cnt++;
370 break;
371
372 case STAT_ME:
373 break;
374
375 case STAT_UNKNOWN:
376 /* added time -Taner */
377 sendto_one_numeric(source_p, RPL_TRACEUNKNOWN,
378 form_str(RPL_TRACEUNKNOWN),
379 class_name, name, ip,
77910830 380 (unsigned long)(rb_current_time() - target_p->localClient->firsttime));
212380e3
AC
381 cnt++;
382 break;
383
384 case STAT_CLIENT:
a672fbb7 385 {
01fb744c
DS
386 /* fire the doing_trace_show_idle hook to allow modules to tell us whether to show the idle time */
387 hook_data_client_approval hdata_showidle;
388
389 hdata_showidle.client = source_p;
390 hdata_showidle.target = target_p;
391 hdata_showidle.approved = WHOIS_IDLE_SHOW;
392
393 call_hook(doing_trace_show_idle_hook, &hdata_showidle);
394
6f7b36d5 395 sendto_one_numeric(source_p,
1123eefc
EK
396 SeesOper(target_p, source_p) ? RPL_TRACEOPERATOR : RPL_TRACEUSER,
397 SeesOper(target_p, source_p) ? form_str(RPL_TRACEOPERATOR) : form_str(RPL_TRACEUSER),
a672fbb7
JT
398 class_name, name,
399 show_ip(source_p, target_p) ? ip : empty_sockhost,
01fb744c
DS
400 hdata_showidle.approved ? (unsigned long)(rb_current_time() - target_p->localClient->lasttime) : 0,
401 hdata_showidle.approved ? (unsigned long)(rb_current_time() - target_p->localClient->last) : 0);
a672fbb7
JT
402
403 cnt++;
404 }
a4da8e48 405 break;
212380e3
AC
406
407 case STAT_SERVER:
408 {
409 int usercount = 0;
410 int servcount = 0;
411
412 count_downlinks(target_p, &servcount, &usercount);
413
414 sendto_one_numeric(source_p, RPL_TRACESERVER, form_str(RPL_TRACESERVER),
415 class_name, servcount, usercount, name,
416 *(target_p->serv->by) ? target_p->serv->by : "*", "*",
0cce01d3
JT
417 me.name,
418 (unsigned long)(rb_current_time() - target_p->localClient->lasttime));
212380e3
AC
419 cnt++;
420
421 }
422 break;
423
424 default: /* ...we actually shouldn't come here... --msa */
55abcbb2 425 sendto_one_numeric(source_p, RPL_TRACENEWTYPE,
0cce01d3 426 form_str(RPL_TRACENEWTYPE), name);
212380e3
AC
427 cnt++;
428 break;
429 }
430
431 return (cnt);
432}
433
434/* trace_spy()
435 *
436 * input - pointer to client
437 * output - none
438 * side effects - hook event doing_trace is called
439 */
440static void
441trace_spy(struct Client *source_p, struct Client *target_p)
442{
443 hook_data_client hdata;
444
445 hdata.client = source_p;
446 hdata.target = target_p;
447
448 call_hook(doing_trace_hook, &hdata);
449}