Remove spy hooks.
[seven.git] / modules / m_trace.c
blob0edf7b0bbaa425851fa23cf821a1b46180651699
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_trace.c: Traces a path to a client/server.
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
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.
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.
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
24 * $Id: m_trace.c 147 2006-11-13 12:35:45Z spb $
27 #include "stdinc.h"
28 #include "class.h"
29 #include "hook.h"
30 #include "client.h"
31 #include "hash.h"
32 #include "common.h"
33 #include "hash.h"
34 #include "irc_string.h"
35 #include "ircd.h"
36 #include "numeric.h"
37 #include "commio.h"
38 #include "s_serv.h"
39 #include "s_conf.h"
40 #include "s_newconf.h"
41 #include "send.h"
42 #include "msg.h"
43 #include "parse.h"
44 #include "modules.h"
46 static int m_trace(struct Client *, struct Client *, int, const char **);
48 struct Message trace_msgtab = {
49 "TRACE", 0, 0, 0, MFLG_SLOW,
50 {mg_unreg, {m_trace, 0}, {m_trace, 0}, mg_ignore, mg_ignore, {m_trace, 0}}
53 int doing_trace_hook;
55 mapi_clist_av1 trace_clist[] = { &trace_msgtab, NULL };
56 mapi_hlist_av1 trace_hlist[] = {
57 { "doing_trace", &doing_trace_hook },
58 { NULL, NULL }
60 DECLARE_MODULE_AV1(trace, NULL, NULL, trace_clist, trace_hlist, NULL, "$Revision: 147 $");
62 static void count_downlinks(struct Client *server_p, int *pservcount, int *pusercount);
63 static int report_this_status(struct Client *source_p, struct Client *target_p, int dow);
66 * m_trace
67 * parv[0] = sender prefix
68 * parv[1] = servername
70 static int
71 m_trace(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
73 struct Client *target_p = NULL;
74 struct Class *cltmp;
75 const char *tname;
76 int doall = 0;
77 int cnt = 0, wilds, dow;
78 dlink_node *ptr;
80 if(parc > 1)
82 tname = parv[1];
84 if(parc > 2)
86 if(hunt_server(client_p, source_p, ":%s TRACE %s :%s", 2, parc, parv) !=
87 HUNTED_ISME)
88 return 0;
91 else
92 tname = me.name;
94 /* if we have 3 parameters, then the command is directed at us. So
95 * we shouldnt be forwarding it anywhere.
97 if(parc < 3)
99 switch (hunt_server(client_p, source_p, ":%s TRACE :%s", 1, parc, parv))
101 case HUNTED_PASS: /* note: gets here only if parv[1] exists */
103 struct Client *ac2ptr;
105 if(MyClient(source_p))
106 ac2ptr = find_named_client(tname);
107 else
108 ac2ptr = find_client(tname);
110 if(ac2ptr == NULL)
112 DLINK_FOREACH(ptr, global_client_list.head)
114 ac2ptr = ptr->data;
116 if(match(tname, ac2ptr->name) || match(ac2ptr->name, tname))
117 break;
118 else
119 ac2ptr = NULL;
123 /* giving this out with flattened links defeats the
124 * object --fl
126 if(IsOperRouting(source_p) || IsExemptShide(source_p) ||
127 !ConfigServerHide.flatten_links)
128 sendto_one_numeric(source_p, RPL_TRACELINK,
129 form_str(RPL_TRACELINK),
130 ircd_version,
131 ac2ptr ? ac2ptr->name : tname,
132 ac2ptr ? ac2ptr->from->name : "EEK!");
134 return 0;
137 case HUNTED_ISME:
138 break;
140 default:
141 return 0;
145 if(match(tname, me.name))
147 doall = 1;
149 /* if theyre tracing our SID, we need to move tname to our name so
150 * we dont give the sid in ENDOFTRACE
152 else if(!MyClient(source_p) && !strcmp(tname, me.id))
154 doall = 1;
155 tname = me.name;
158 wilds = strchr(tname, '*') || strchr(tname, '?');
159 dow = wilds || doall;
161 /* specific trace */
162 if(dow == 0)
164 if(MyClient(source_p) || parc > 2)
165 target_p = find_named_person(tname);
166 else
167 target_p = find_person(tname);
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
172 if(target_p != NULL)
174 report_this_status(source_p, target_p, 0);
175 tname = target_p->name;
178 sendto_one_numeric(source_p, RPL_ENDOFTRACE,
179 form_str(RPL_ENDOFTRACE), tname);
180 return 0;
183 /* give non-opers a limited trace output of themselves (if local),
184 * opers and servers (if no shide) --fl
186 if(!IsOperRouting(source_p))
188 if(MyClient(source_p))
190 if(doall || (wilds && match(tname, source_p->name)))
191 report_this_status(source_p, source_p, 0);
194 DLINK_FOREACH(ptr, local_oper_list.head)
196 target_p = ptr->data;
198 if(!doall && wilds && (match(tname, target_p->name) == 0))
199 continue;
201 report_this_status(source_p, target_p, 0);
204 if (IsExemptShide(source_p) || !ConfigServerHide.flatten_links)
206 DLINK_FOREACH(ptr, serv_list.head)
208 target_p = ptr->data;
210 if(!doall && wilds && !match(tname, target_p->name))
211 continue;
213 report_this_status(source_p, target_p, 0);
217 sendto_one_numeric(source_p, RPL_ENDOFTRACE,
218 form_str(RPL_ENDOFTRACE), tname);
219 return 0;
222 /* source_p is opered */
224 /* report all direct connections */
225 DLINK_FOREACH(ptr, lclient_list.head)
227 target_p = ptr->data;
229 /* dont show invisible users to remote opers */
230 if(IsInvisible(target_p) && dow && !MyConnect(source_p) && !IsOper(target_p))
231 continue;
233 if(!doall && wilds && !match(tname, target_p->name))
234 continue;
236 cnt = report_this_status(source_p, target_p, dow);
239 DLINK_FOREACH(ptr, serv_list.head)
241 target_p = ptr->data;
243 if(!doall && wilds && !match(tname, target_p->name))
244 continue;
246 cnt = report_this_status(source_p, target_p, dow);
249 if(MyConnect(source_p))
251 DLINK_FOREACH(ptr, unknown_list.head)
253 target_p = ptr->data;
255 if(!doall && wilds && !match(tname, target_p->name))
256 continue;
258 cnt = report_this_status(source_p, target_p, dow);
262 if(!cnt)
264 sendto_one_numeric(source_p, ERR_NOSUCHSERVER, form_str(ERR_NOSUCHSERVER),
265 tname);
267 /* let the user have some idea that its at the end of the
268 * trace
270 sendto_one_numeric(source_p, RPL_ENDOFTRACE,
271 form_str(RPL_ENDOFTRACE), tname);
272 return 0;
275 if(doall)
277 DLINK_FOREACH(ptr, class_list.head)
279 cltmp = ptr->data;
281 if(CurrUsers(cltmp) > 0)
282 sendto_one_numeric(source_p, RPL_TRACECLASS,
283 form_str(RPL_TRACECLASS),
284 ClassName(cltmp), CurrUsers(cltmp));
288 sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), tname);
290 return 0;
294 * count_downlinks
296 * inputs - pointer to server to count
297 * - pointers to server and user count
298 * output - NONE
299 * side effects - server and user counts are added to given values
301 static void
302 count_downlinks(struct Client *server_p, int *pservcount, int *pusercount)
304 dlink_node *ptr;
306 (*pservcount)++;
307 *pusercount += dlink_list_length(&server_p->serv->users);
308 DLINK_FOREACH(ptr, server_p->serv->servers.head)
310 count_downlinks(ptr->data, pservcount, pusercount);
315 * report_this_status
317 * inputs - pointer to client to report to
318 * - pointer to client to report about
319 * output - counter of number of hits
320 * side effects - NONE
322 static int
323 report_this_status(struct Client *source_p, struct Client *target_p,
324 int dow)
326 const char *name;
327 const char *class_name;
328 char ip[HOSTIPLEN];
329 int cnt = 0;
331 /* sanity check - should never happen */
332 if(!MyConnect(target_p))
333 return 0;
335 inetntop_sock((struct sockaddr *)&target_p->localClient->ip, ip, sizeof(ip));
336 class_name = get_client_class(target_p);
338 if(IsAnyServer(target_p))
339 name = get_server_name(target_p, HIDE_IP);
340 else
341 name = get_client_name(target_p, HIDE_IP);
343 switch (target_p->status)
345 case STAT_CONNECTING:
346 sendto_one_numeric(source_p, RPL_TRACECONNECTING,
347 form_str(RPL_TRACECONNECTING),
348 class_name, name);
349 cnt++;
350 break;
352 case STAT_HANDSHAKE:
353 sendto_one_numeric(source_p, RPL_TRACEHANDSHAKE,
354 form_str(RPL_TRACEHANDSHAKE),
355 class_name, name);
356 cnt++;
357 break;
359 case STAT_ME:
360 break;
362 case STAT_UNKNOWN:
363 /* added time -Taner */
364 sendto_one_numeric(source_p, RPL_TRACEUNKNOWN,
365 form_str(RPL_TRACEUNKNOWN),
366 class_name, name, ip,
367 CurrentTime - target_p->localClient->firsttime);
368 cnt++;
369 break;
371 case STAT_CLIENT:
372 /* Only opers see users if there is a wildcard
373 * but anyone can see all the opers.
375 if((IsOper(source_p) &&
376 (MyClient(source_p) || !(dow && IsInvisible(target_p))))
377 || !dow || IsOper(target_p) || (source_p == target_p))
379 if(IsOper(target_p))
380 sendto_one_numeric(source_p, RPL_TRACEOPERATOR,
381 form_str(RPL_TRACEOPERATOR),
382 class_name, name,
383 show_ip(source_p, target_p) ? ip : "255.255.255.255",
384 CurrentTime - target_p->localClient->lasttime,
385 CurrentTime - target_p->localClient->last);
387 else
388 sendto_one_numeric(source_p, RPL_TRACEUSER,
389 form_str(RPL_TRACEUSER),
390 class_name, name,
391 show_ip(source_p, target_p) ? ip : "255.255.255.255",
392 CurrentTime - target_p->localClient->lasttime,
393 CurrentTime - target_p->localClient->last);
394 cnt++;
396 break;
398 case STAT_SERVER:
400 int usercount = 0;
401 int servcount = 0;
403 count_downlinks(target_p, &servcount, &usercount);
405 sendto_one_numeric(source_p, RPL_TRACESERVER, form_str(RPL_TRACESERVER),
406 class_name, servcount, usercount, name,
407 *(target_p->serv->by) ? target_p->serv->by : "*", "*",
408 me.name, CurrentTime - target_p->localClient->lasttime);
409 cnt++;
412 break;
414 default: /* ...we actually shouldn't come here... --msa */
415 sendto_one_numeric(source_p, RPL_TRACENEWTYPE,
416 form_str(RPL_TRACENEWTYPE),
417 me.name, source_p->name, name);
418 cnt++;
419 break;
422 return (cnt);