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