]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_trace.c
2 * IRC - Internet Relay Chat, ircd/m_trace.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
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 1, or (at your option)
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., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * $Id: m_trace.c,v 1.13 2005/08/26 03:23:23 entrope Exp $
27 * m_functions execute protocol messages on this server:
29 * cptr is always NON-NULL, pointing to a *LOCAL* client
30 * structure (with an open socket connected!). This
31 * identifies the physical socket where the message
32 * originated (or which caused the m_function to be
33 * executed--some m_functions may call others...).
35 * sptr is the source of the message, defined by the
36 * prefix part of the message if present. If not
37 * or prefix not found, then sptr==cptr.
39 * (!IsServer(cptr)) => (cptr == sptr), because
40 * prefixes are taken *only* from servers...
43 * (sptr == cptr) => the message didn't
46 * (sptr != cptr && IsServer(sptr) means
47 * the prefix specified servername. (?)
49 * (sptr != cptr && !IsServer(sptr) means
50 * that message originated from a remote
55 * (!IsServer(sptr)) means that, sptr can safely
56 * taken as defining the target structure of the
57 * message in this server.
59 * *Always* true (if 'parse' and others are working correct):
61 * 1) sptr->from == cptr (note: cptr->from == cptr)
63 * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64 * *cannot* be a local connection, unless it's
65 * actually cptr!). [MyConnect(x) should probably
66 * be defined as (x == x->from) --msa ]
68 * parc number of variable parameter strings (if zero,
69 * parv is allowed to be NULL)
71 * parv a NULL terminated list of parameter pointers,
73 * parv[0], sender (prefix string), if not present
74 * this points to an empty string.
75 * parv[1]...parv[parc-1]
76 * pointers to additional parameters
77 * parv[parc] == NULL, *always*
79 * note: it is guaranteed that parv[0]..parv[parc-1] are all
88 #include "ircd_features.h"
90 #include "ircd_reply.h"
91 #include "ircd_string.h"
102 /* #include <assert.h> -- Now using assert in ircd_log.h */
105 void do_trace(struct Client
*cptr
, struct Client
*sptr
, int parc
, char *parv
[])
108 struct Client
*acptr
;
109 struct Client
*acptr2
;
110 const struct ConnectionClass
* cl
;
113 int link_s
[MAXCONNECTIONS
];
114 int link_u
[MAXCONNECTIONS
];
119 if (parc
< 2 || BadPtr(parv
[1]))
121 /* just "TRACE" without parameters. Must be from local client */
124 tname
= cli_name(&me
);
127 else if (parc
< 3 || BadPtr(parv
[2]))
129 /* No target specified. Make one before propagating. */
132 if ((acptr
= find_match_server(parv
[1])) ||
133 ((acptr
= FindClient(parv
[1])) && !MyUser(acptr
)))
136 parv
[2] = cli_name(cli_user(acptr
)->server
);
138 parv
[2] = cli_name(acptr
);
141 if ((i
= hunt_server_cmd(sptr
, CMD_TRACE
, cptr
, IsServer(acptr
),
142 "%s :%C", 2, parc
, parv
)) == HUNTED_NOSUCH
)
148 /* Got "TRACE <tname> :<target>" */
150 if (MyUser(sptr
) || Protocol(cptr
) < 10)
151 acptr
= find_match_server(parv
[2]);
153 acptr
= FindNServer(parv
[2]);
154 if ((i
= hunt_server_cmd(sptr
, CMD_TRACE
, cptr
, 0, "%s :%C", 2, parc
,
155 parv
)) == HUNTED_NOSUCH
)
160 if (i
== HUNTED_PASS
) {
162 acptr
= next_client(GlobalClientList
, tname
);
164 acptr
= cli_from(acptr
);
165 send_reply(sptr
, RPL_TRACELINK
,
166 version
, debugmode
, tname
,
167 acptr
? cli_name(cli_from(acptr
)) : "<No_match>");
171 doall
= (parv
[1] && (parc
> 1)) ? !match(tname
, cli_name(&me
)) : 1;
172 wilds
= !parv
[1] || strchr(tname
, '*') || strchr(tname
, '?');
173 dow
= wilds
|| doall
;
175 /* Don't give (long) remote listings to lusers */
176 if (dow
&& !MyConnect(sptr
) && !IsAnOper(sptr
)) {
177 send_reply(sptr
, RPL_TRACEEND
);
181 for (i
= 0; i
< MAXCONNECTIONS
; i
++)
182 link_s
[i
] = 0, link_u
[i
] = 0;
185 for (acptr
= GlobalClientList
; acptr
; acptr
= cli_next(acptr
)) {
187 link_u
[cli_fd(cli_from(acptr
))]++;
188 else if (IsServer(acptr
))
189 link_s
[cli_fd(cli_from(acptr
))]++;
193 /* report all direct connections */
195 for (i
= 0; i
<= HighestFd
; i
++) {
196 const char *conClass
;
198 if (!(acptr
= LocalClientArray
[i
])) /* Local Connection? */
200 if (IsInvisible(acptr
) && dow
&& !(MyConnect(sptr
) && IsOper(sptr
)) &&
201 !IsAnOper(acptr
) && (acptr
!= sptr
))
203 if (!doall
&& wilds
&& match(tname
, cli_name(acptr
)))
205 if (!dow
&& 0 != ircd_strcmp(tname
, cli_name(acptr
)))
208 conClass
= get_client_class(acptr
);
210 switch (cli_status(acptr
)) {
211 case STAT_CONNECTING
:
212 send_reply(sptr
, RPL_TRACECONNECTING
, conClass
, cli_name(acptr
));
216 send_reply(sptr
, RPL_TRACEHANDSHAKE
, conClass
, cli_name(acptr
));
222 case STAT_UNKNOWN_USER
:
223 send_reply(sptr
, RPL_TRACEUNKNOWN
, conClass
,
224 get_client_name(acptr
, HIDE_IP
));
227 case STAT_UNKNOWN_SERVER
:
228 send_reply(sptr
, RPL_TRACEUNKNOWN
, conClass
, "Unknown Server");
232 /* Only opers see users if there is a wildcard
233 but anyone can see all the opers. */
234 if ((IsAnOper(sptr
) && (MyUser(sptr
) ||
235 !(dow
&& IsInvisible(acptr
)))) || !dow
|| IsAnOper(acptr
)) {
237 send_reply(sptr
, RPL_TRACEOPERATOR
, conClass
,
238 get_client_name(acptr
, SHOW_IP
),
239 CurrentTime
- cli_lasttime(acptr
));
241 send_reply(sptr
, RPL_TRACEUSER
, conClass
,
242 get_client_name(acptr
, SHOW_IP
),
243 CurrentTime
- cli_lasttime(acptr
));
248 * Connection is a server
250 * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
252 * class Class the server is in
253 * nS Number of servers reached via this link
254 * nC Number of clients reached via this link
255 * name Name of the server linked
256 * ConnBy Who established this link
257 * last Seconds since we got something from this link
258 * age Seconds this link has been alive
260 * Additional comments etc...... -Cym-<cym@acrux.net>
264 if (cli_serv(acptr
)->user
) {
265 if (!cli_serv(acptr
)->by
[0]
266 || !(acptr2
= findNUser(cli_serv(acptr
)->by
))
267 || (cli_user(acptr2
) != cli_serv(acptr
)->user
))
269 send_reply(sptr
, RPL_TRACESERVER
, conClass
, link_s
[i
],
270 link_u
[i
], cli_name(acptr
),
271 acptr2
? cli_name(acptr2
) : "*",
272 cli_serv(acptr
)->user
->username
,
273 cli_serv(acptr
)->user
->host
,
274 CurrentTime
- cli_lasttime(acptr
),
275 CurrentTime
- cli_serv(acptr
)->timestamp
);
277 send_reply(sptr
, RPL_TRACESERVER
, conClass
, link_s
[i
],
278 link_u
[i
], cli_name(acptr
),
279 (*(cli_serv(acptr
))->by
) ? cli_serv(acptr
)->by
: "*", "*",
280 cli_name(&me
), CurrentTime
- cli_lasttime(acptr
),
281 CurrentTime
- cli_serv(acptr
)->timestamp
);
284 default: /* We actually shouldn't come here, -msa */
285 send_reply(sptr
, RPL_TRACENEWTYPE
, get_client_name(acptr
, HIDE_IP
));
291 * Add these lines to summarize the above which can get rather long
292 * and messy when done remotely - Avalon
294 if (IsAnOper(sptr
) && doall
) {
295 for (cl
= get_class_list(); cl
; cl
= cl
->next
) {
297 send_reply(sptr
, RPL_TRACECLASS
, ConClass(cl
), Links(cl
) - 1);
300 send_reply(sptr
, RPL_TRACEEND
);
304 * m_trace - generic message handler
306 * parv[0] = sender prefix
307 * parv[1] = nick or servername
308 * parv[2] = 'target' servername
310 int m_trace(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
312 if (feature_bool(FEAT_HIS_TRACE
))
313 return send_reply(cptr
, ERR_NOPRIVILEGES
);
314 do_trace(cptr
, sptr
, parc
, parv
);
319 * ms_trace - server message handler
321 * parv[0] = sender prefix
322 * parv[1] = nick or servername
323 * parv[2] = 'target' servername
325 int ms_trace(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
327 do_trace(cptr
, sptr
, parc
, parv
);
332 * mo_trace - oper message handler
334 * parv[0] = sender prefix
335 * parv[1] = nick or servername
336 * parv[2] = 'target' servername
338 int mo_trace(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
340 if (feature_bool(FEAT_HIS_TRACE
) && !IsAnOper(sptr
))
341 return send_reply(cptr
, ERR_NOPRIVILEGES
);
342 do_trace(cptr
, sptr
, parc
, parv
);