2 # Parent 3303f23758b0f0bc35a9d786a027aba155488e62
4 diff -r 3303f23758b0 include/check.h
5 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6 +++ b/include/check.h Wed Jul 17 21:38:16 2013 +0100
9 + * IRC - Internet Relay Chat, ircd/check.h
10 + * Copyright (C) 1990 University of Oulu, Computing Center
12 + * This program is free software; you can redistribute it and/or modify
13 + * it under the terms of the GNU General Public License as published by
14 + * the Free Software Foundation; either version 1, or (at your option)
15 + * any later version.
17 + * This program is distributed in the hope that it will be useful,
18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 + * GNU General Public License for more details.
22 + * You should have received a copy of the GNU General Public License
23 + * along with this program; if not, write to the Free Software
24 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 + * - ASUKA ---------------------------------------------------------------------
29 + * These are the declarations of the CHECK functions for Asuka.
30 + * Some of this code is from previous QuakeNet ircds, and some of it is my own.
31 + * The old code was written by Durzel (durzel@quakenet.org).
33 + * qoreQ (qoreQ@quakenet.org) - 08/14/2002
34 + * -----------------------------------------------------------------------------
37 +#ifndef INCLUDED_check_h
38 +#define INCLUDED_check_h
40 +#define HEADERLINE "--------------------------------------------------------------------"
41 +#define COLOR_OFF '\017'
43 +/* IP is IPv4, or IPv4 over IPv6 (2002::/16 range) */
44 +#define has_ipv4_addr(x) (irc_in_addr_is_ipv4(x) || (x)->in6_16[0] == htons(0x2002))
45 +/* Return IP in IPv4 notation, also when IP is IPv4 over IPv6 */
46 +#define get_ipv4_addr(x) (irc_in_addr_is_ipv4(x) ? \
47 + (ntohs((x)->in6_16[6]) << 16) | ntohs((x)->in6_16[7]) : \
48 + (ntohs((x)->in6_16[1]) << 16) | ntohs((x)->in6_16[2]))
50 +extern void checkChannel(struct Client *sptr, struct Channel *chptr);
51 +extern void checkUsers(struct Client *sptr, struct Channel *chptr, int flags);
52 +extern void checkClient(struct Client *sptr, struct Client *acptr);
53 +extern void checkServer(struct Client *sptr, struct Client *acptr);
54 +extern signed int checkHostmask(struct Client *sptr, char *hoststr, int flags);
56 +#endif /* INCLUDED_check_h */
57 diff -r 3303f23758b0 include/client.h
58 --- a/include/client.h Wed Jul 17 21:30:44 2013 +0100
59 +++ b/include/client.h Wed Jul 17 21:38:16 2013 +0100
61 #define HIDE_IP 0 /**< Do not show IP address in get_client_name() */
62 #define SHOW_IP 1 /**< Show ident and IP address in get_client_name() */
64 +/** Number of bits unique per user under IPv6, used for clone checks */
65 +#define IPV6USERBITS 64
67 extern const char* get_client_name(const struct Client* sptr, int showip);
68 extern const char* client_get_default_umode(const struct Client* sptr);
69 extern int client_get_ping(const struct Client* local_client);
70 diff -r 3303f23758b0 include/handlers.h
71 --- a/include/handlers.h Wed Jul 17 21:30:44 2013 +0100
72 +++ b/include/handlers.h Wed Jul 17 21:38:16 2013 +0100
75 extern int m_admin(struct Client*, struct Client*, int, char*[]);
76 extern int m_away(struct Client*, struct Client*, int, char*[]);
79 + * - ASUKA ---------------------------------------------------------------------
80 + * Add the command for CHECK.
81 + * This was adapted from Lain for use in Asuka.
82 + * Original code by Durzel (durzel@quakenet.org).
84 + * qoreQ (qoreQ@quakenet.org) - 08/30/2002
85 + * -----------------------------------------------------------------------------
88 +extern int m_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]);
90 extern int m_cap(struct Client*, struct Client*, int, char*[]);
91 extern int m_cnotice(struct Client*, struct Client*, int, char*[]);
92 extern int m_cprivmsg(struct Client*, struct Client*, int, char*[]);
93 diff -r 3303f23758b0 include/ircd_features.h
94 --- a/include/ircd_features.h Wed Jul 17 21:30:44 2013 +0100
95 +++ b/include/ircd_features.h Wed Jul 17 21:38:16 2013 +0100
97 FEAT_ANNOUNCE_INVITES,
99 /* features that affect all operators */
100 + FEAT_EXTENDED_CHECKCMD,
101 FEAT_CONFIG_OPERCMDS,
104 diff -r 3303f23758b0 include/msg.h
105 --- a/include/msg.h Wed Jul 17 21:30:44 2013 +0100
106 +++ b/include/msg.h Wed Jul 17 21:38:16 2013 +0100
108 #define TOK_SERVSET "SERVSET"
109 #define CMD_SERVSET MSG_SERVSET, TOK_SERVSET
111 +#define MSG_CHECK "CHECK"
112 +#define TOK_CHECK "CC"
113 +#define CMD_CHECK MSG_CHECK, TOK_CHECK
115 #define MSG_REHASH "REHASH" /* REHA */
116 #define TOK_REHASH "REHASH"
117 #define CMD_REHASH MSG_REHASH, TOK_REHASH
118 diff -r 3303f23758b0 include/s_user.h
119 --- a/include/s_user.h Wed Jul 17 21:30:44 2013 +0100
120 +++ b/include/s_user.h Wed Jul 17 21:38:16 2013 +0100
122 #define ALLOWMODES_ANY 0 /**< Allow any user mode */
123 #define ALLOWMODES_DEFAULT 1 /**< Only allow the subset of modes that are legit defaults */
125 +/* return sets for umode_str() */
126 +#define UMODE_ALL_PARAMS 0 /**< return the user modes and all parameters */
127 +#define UMODE_ALL_PARAMS_BUT_OPERID 1 /**< return the user modes and all parameters except OperID */
128 +#define UMODE_AND_ACCOUNT 2 /**< return the user modes and account parameter */
129 +#define UMODE_AND_ACCOUNT_SHORT 3 /**< return the user modes and account (but no account timestamp, ID or flags) */
131 /** Formatter function for send_user_info().
132 * @param who Client being displayed.
133 * @param sptr Client requesting information.
134 diff -r 3303f23758b0 ircd/IPcheck.c
135 --- a/ircd/IPcheck.c Wed Jul 17 21:30:44 2013 +0100
136 +++ b/ircd/IPcheck.c Wed Jul 17 21:38:16 2013 +0100
138 ip_registry_canonicalize(&canon, ip);
139 entry = hashTable[ip_registry_hash(&canon)];
140 for ( ; entry; entry = entry->next) {
141 - int bits = (canon.in6_16[0] == htons(0x2002)) ? 48 : 64;
142 + int bits = (canon.in6_16[0] == htons(0x2002)) ? 48 : IPV6USERBITS;
143 if (ipmask_check(&canon, &entry->addr, bits))
146 diff -r 3303f23758b0 ircd/Makefile.in
147 --- a/ircd/Makefile.in Wed Jul 17 21:30:44 2013 +0100
148 +++ b/ircd/Makefile.in Wed Jul 17 21:38:16 2013 +0100
157 diff -r 3303f23758b0 ircd/ircd_features.c
158 --- a/ircd/ircd_features.c Wed Jul 17 21:30:44 2013 +0100
159 +++ b/ircd/ircd_features.c Wed Jul 17 21:38:16 2013 +0100
161 F_B(ANNOUNCE_INVITES, 0, 0, 0),
163 /* features that affect all operators */
164 + F_B(EXTENDED_CHECKCMD, 0, 0, 0),
165 F_B(CONFIG_OPERCMDS, 0, 0, 0),
166 F_B(SETHOST, 0, 0, 0),
167 F_B(SETHOST_USER, 0, 0, 0),
168 diff -r 3303f23758b0 ircd/m_check.c
169 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
170 +++ b/ircd/m_check.c Wed Jul 17 21:38:16 2013 +0100
173 + * IRC - Internet Relay Chat, ircd/m_check.c
174 + * Copyright (C) 1990 Jarkko Oikarinen and
175 + * University of Oulu, Computing Center
177 + * See file AUTHORS in IRC package for additional names of
180 + * This program is free software; you can redistribute it and/or modify
181 + * it under the terms of the GNU General Public License as published by
182 + * the Free Software Foundation; either version 1, or (at your option)
183 + * any later version.
185 + * This program is distributed in the hope that it will be useful,
186 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
187 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
188 + * GNU General Public License for more details.
190 + * You should have received a copy of the GNU General Public License
191 + * along with this program; if not, write to the Free Software
192 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
195 +#include "channel.h"
200 +#include "IPcheck.h"
202 +#include "ircd_alloc.h"
203 +#include "ircd_defs.h"
204 +#include "ircd_features.h"
205 +#include "ircd_reply.h"
206 +#include "ircd_string.h"
207 +#include "ircd_snprintf.h"
208 +#include "ircd_osdep.h"
210 +#include "listener.h"
213 +#include "numeric.h"
214 +#include "numnicks.h"
215 +#include "querycmds.h"
218 +#include "s_debug.h"
223 +#define CHECK_CHECKCHAN 0x01 /* -c */
224 +#define CHECK_SHOWUSERS 0x02 /* ! -u */
225 +#define CHECK_OPSONLY 0x04 /* -o */
226 +#define CHECK_SHOWIPS 0x08 /* -i */
227 +#define CHECK_CIDRMASK 0x10 /* automatically detected when performing a hostmask /CHECK */
228 +#define CHECK_OPLEVELS 0x20 /* -l */
229 +#define CHECK_CLONES 0x40 /* -C */
230 +#define CHECK_SHOWSERVER 0x80 /* -s */
231 +#define CHECK_SHOWHOSTIP 0x100 /* -I */
232 +#define CHECK_SHOWMORE 0x200 /* -e */
235 + * - ASUKA ---------------------------------------------------------------------
236 + * This is the implimentation of the CHECK function for Asuka.
237 + * Some of this code is from previous QuakeNet ircds, but most of it is mine..
238 + * The old code was written by Durzel (durzel@quakenet.org).
240 + * qoreQ (qoreQ@quakenet.org) - 08/14/2002
241 + * -----------------------------------------------------------------------------
245 + * Syntax: CHECK <channel|nick|server|hostmask> [-flags]
247 + * Where valid flags are:
248 + * -c: Show channels when checking a hostmask.
249 + * -e: show more inform when checking a mask.
250 + * -i: Show IPs instead of hostnames when displaying results.
251 + * -l: Show oplevels when checking a channel.
252 + * -o: Only show channel operators when checking a channel.
253 + * -s: show server user is on when checking a channel (or on a mask when combined with -e).
254 + * -u: Hide users when checking a channel.
255 + * -C: Perform clone count when checking a channel.
256 + * -I: show hostnames and IPs when checking a channel.
258 + * <hostmask> can be of the form host, user@host, nick!user@host,
259 + * with host being host.domain.cc, 127.0.0.1 or 127.0.0.0/24.
260 + * Wildcards are supported.
263 +int m_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
264 + struct Channel *chptr;
265 + struct Client *acptr;
266 + int flags = CHECK_SHOWUSERS, i;
269 + send_reply(sptr, ERR_NEEDMOREPARAMS, "CHECK");
274 + (parc==3 && parv[2][0] != '-')) {
276 + if (hunt_server_cmd(sptr, CMD_CHECK, cptr, 0, parc==4 ? "%C %s %s" : "%C %s", 1, parc, parv) != HUNTED_ISME)
281 + /* This checks to see if any flags have been supplied */
282 + if ((parc >= 3) && (parv[2][0] == '-')) {
283 + for (i = 0; parv[2][i]; i++) {
284 + switch (parv[2][i]) {
286 + flags |= CHECK_CHECKCHAN;
290 + flags |= CHECK_OPSONLY; /* fall through */
292 + flags &= ~(CHECK_SHOWUSERS);
296 + flags |= CHECK_SHOWIPS;
299 + flags |= CHECK_OPLEVELS;
302 + flags |= CHECK_CLONES;
305 + flags |= CHECK_SHOWSERVER;
308 + flags |= CHECK_SHOWHOSTIP;
311 + flags |= CHECK_SHOWMORE;
314 + /* might want to raise some sort of error here? */
320 + if (IsChannelName(parv[1])) { /* channel */
321 + if ((chptr = FindChannel(parv[1]))) {
322 + checkChannel(sptr, chptr);
323 + checkUsers(sptr, chptr, flags);
326 + send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
328 + else if ((acptr = FindClient(parv[1])) && !(FindServer(parv[1]))) { /* client and not a server */
329 + if (!IsRegistered(acptr)) {
330 + send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
334 + checkClient(sptr, acptr);
336 + else if ((acptr = FindServer(parv[1]))) { /* server */
337 + checkServer(sptr, acptr);
339 + else if (checkHostmask(sptr, parv[1], flags) > 0) /* hostmask */
341 + else /* no match */
342 + send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
349 +/* return number of clients from same IP on the channel */
350 +static int checkClones(struct Channel *chptr, struct Client *cptr) {
351 + int clones = 0, count = 0;
352 + struct Membership *lp;
353 + struct Client *acptr;
355 + for (lp = chptr->members; lp; lp = lp->next_member) {
357 + if (are_ips_clones(&cli_ip(cptr),&cli_ip(acptr))) {
362 + /* Optimise only if we will actually save CPU time */
364 + for (lp = chptr->members; lp; lp = lp->next_member) {
366 + if (are_ips_clones(&cli_ip(cptr),&cli_ip(acptr))) {
367 + cli_marker(acptr) = clones;
369 + if (clones == count) {
380 +/* compare IPs from clients and return 1 when they are clones
382 + * IPv4 and IPv6 IPs, but IPv4 over IPv6 etc cases
383 + * IPv6 IPs from the same /64 block
385 +int are_ips_clones(const struct irc_in_addr *ip1, const struct irc_in_addr *ip2) {
386 + int ipv4ip1 = has_ipv4_addr(ip1);
388 + /* are both ip addresses ipv4 or ipv6? if not, no clones */
389 + if (ipv4ip1 != has_ipv4_addr(ip2)) return 0;
391 + if (ipv4ip1) /* check ipv4 */
392 + return (get_ipv4_addr(ip1) == get_ipv4_addr(ip2)) ? 1 : 0;
395 + return ipmask_check(ip1, ip2, IPV6USERBITS) ? 1 : 0;
399 +void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) {
400 + struct Membership *lp;
402 + struct Client *acptr;
404 + char outbuf[BUFSIZE], outbuf2[BUFSIZE], ustat[64];
405 + int cntr = 0, opcntr = 0, vcntr = 0, clones = 0, bans = 0, authed = 0, delayedjoin = 0;
406 + char *zombie, *showlevel;
408 + if (flags & CHECK_SHOWUSERS) {
409 + send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice)");
412 + if (flags & CHECK_CLONES) {
413 + for (lp = chptr->members; lp; lp = lp->next_member) {
414 + cli_marker(lp->user) = 0;
418 + for (lp = chptr->members; lp; lp = lp->next_member) {
419 + int opped = 0, c = 0;
422 + zombie = IsZombie(lp) ? "!" : "";
423 + showlevel = (flags & CHECK_OPLEVELS) ? " " : "";
425 + if (flags & CHECK_CLONES) {
426 + if (!cli_marker(acptr)) {
427 + c = checkClones(chptr, acptr);
429 + c = cli_marker(acptr);
437 + if (IsChanOp(lp)) {
438 + if (flags & CHECK_OPLEVELS) {
440 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%3hu@", c, zombie, OpLevel(lp));
442 + ircd_snprintf(0, ustat, sizeof(ustat), "%s%3hu@", zombie, OpLevel(lp));
446 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s@", c, zombie);
448 + ircd_snprintf(0, ustat, sizeof(ustat), "%s@", zombie);
454 + else if (HasVoice(lp)) {
456 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%s+", c, showlevel, zombie);
458 + ircd_snprintf(0, ustat, sizeof(ustat), "%s%s+", showlevel, zombie);
462 + else if (IsDelayedJoin(lp)) {
464 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%s<", c, showlevel, zombie);
466 + ircd_snprintf(0, ustat, sizeof(ustat), "%s%s<", showlevel, zombie);
472 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%s", c, showlevel, zombie);
474 + ircd_snprintf(0, ustat, sizeof(ustat), " %s%s", showlevel, zombie);
478 + if ((c = IsAccount(acptr))) {
482 + if ((flags & CHECK_SHOWUSERS) || ((flags & CHECK_OPSONLY) && opped)) {
483 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF);
484 + if (flags & CHECK_SHOWHOSTIP) {
485 + ircd_snprintf(0, outbuf2, sizeof(outbuf2), " [%s]", ircd_ntoa(&(cli_ip(acptr))));
487 + send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, cli_user(acptr)->realusername,
488 + ((flags & CHECK_SHOWIPS) ? ircd_ntoa(&(cli_ip(acptr))) : cli_user(acptr)->realhost), (flags & CHECK_SHOWHOSTIP) ? outbuf2 : "", (flags & CHECK_SHOWSERVER) ? cli_name(cli_user(acptr)->server) : outbuf,
489 + (c ? cli_user(acptr)->account : ""));
495 + send_reply(sptr, RPL_DATASTR, " ");
497 + if (flags & CHECK_CLONES) {
498 + ircd_snprintf(0, outbuf, sizeof(outbuf),
499 + "Total users:: %d (%d ops, %d voiced, %d clones, %d authed, %d hidden)",
500 + cntr, opcntr, vcntr, clones, authed, delayedjoin);
502 + for (lp = chptr->members; lp; lp = lp->next_member) {
503 + cli_marker(lp->user) = 0;
506 + ircd_snprintf(0, outbuf, sizeof(outbuf),
507 + "Total users:: %d (%d ops, %d voiced, %d authed, %d hidden)",
508 + cntr, opcntr, vcntr, authed, delayedjoin);
511 + send_reply(sptr, RPL_DATASTR, outbuf);
512 + send_reply(sptr, RPL_DATASTR, " ");
514 + /* Do not display bans if ! flags & CHECK_SHOWUSERS */
515 + if (flags & CHECK_SHOWUSERS) {
516 + send_reply(sptr, RPL_DATASTR, "Bans on channel::");
518 + for (ban = chptr->banlist; ban; ban = ban->next) {
519 + ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s - Set by %s, on %s (%Tu)",
520 + ++bans, ban->banstr, ban->who, myctime(ban->when), ban->when);
521 + send_reply(sptr, RPL_DATASTR, outbuf);
525 + send_reply(sptr, RPL_DATASTR, "<none>");
528 + send_reply(sptr, RPL_ENDOFCHECK, " ");
531 +void checkChannel(struct Client *sptr, struct Channel *chptr) {
532 + char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
535 + send_reply(sptr, RPL_DATASTR, " ");
536 + send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname);
537 + send_reply(sptr, RPL_DATASTR, " ");
539 + /* Creation Time */
540 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Creation time:: %s (%Tu)", myctime(chptr->creationtime), chptr->creationtime);
541 + send_reply(sptr, RPL_DATASTR, outbuf);
544 + if (strlen(chptr->topic) <= 0)
545 + send_reply(sptr, RPL_DATASTR, " Topic:: <none>");
547 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Topic:: %s", chptr->topic);
548 + send_reply(sptr, RPL_DATASTR, outbuf);
551 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Set by:: %s", chptr->topic_nick);
552 + send_reply(sptr, RPL_DATASTR, outbuf);
554 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Set at:: %s (%Tu)", myctime(chptr->topic_time), chptr->topic_time);
555 + send_reply(sptr, RPL_DATASTR, outbuf);
558 + /* Channel Modes */
560 + strcpy(outbuf, "Channel mode(s):: ");
565 + channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr, NULL);
567 + if(modebuf[1] == '\0')
568 + strcat(outbuf, "<none>");
569 + else if(*parabuf) {
570 + strcat(outbuf, modebuf);
571 + strcat(outbuf, " ");
572 + strcat(outbuf, parabuf);
575 + strcat(outbuf, modebuf);
577 + send_reply(sptr, RPL_DATASTR, outbuf);
579 + /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
582 +void checkClient(struct Client *sptr, struct Client *acptr) {
583 + struct Channel *chptr;
584 + struct Membership *lp;
585 + struct irc_sockaddr sin;
586 + char outbuf[BUFSIZE];
590 + send_reply(sptr, RPL_DATASTR, " ");
591 + send_reply(sptr, RPL_CHKHEAD, "user", cli_name(acptr));
592 + send_reply(sptr, RPL_DATASTR, " ");
594 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", cli_name(acptr), NumNick(acptr));
595 + send_reply(sptr, RPL_DATASTR, outbuf);
597 + if (MyUser(acptr)) {
598 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s (%Tu)", myctime(acptr->cli_firsttime), acptr->cli_firsttime);
599 + send_reply(sptr, RPL_DATASTR, outbuf);
602 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
603 + send_reply(sptr, RPL_DATASTR, outbuf);
605 + ircd_snprintf(0, outbuf, sizeof(outbuf), " User/Hostmask:: %s@%s [%s] (Clients: %hu)", cli_user(acptr)->username, cli_user(acptr)->host,
606 + ircd_ntoa(&(cli_ip(acptr))), IPcheck_nr(acptr));
607 + send_reply(sptr, RPL_DATASTR, outbuf);
609 + if (IsSetHost(acptr) || HasHiddenHost(acptr)) {
610 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", cli_user(acptr)->realusername, cli_user(acptr)->realhost);
611 + send_reply(sptr, RPL_DATASTR, outbuf);
614 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF);
615 + send_reply(sptr, RPL_DATASTR, outbuf);
617 + if( IsService(cli_user(acptr)->server)) {
618 + if (IsChannelService(acptr))
619 + send_reply(sptr, RPL_DATASTR, " Status:: Network Service");
620 + else if (IsAnOper(acptr))
621 + send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator (service) (ID: %s)", cli_user(acptr)->opername ? cli_user(acptr)->opername : "<unknown>");
623 + send_reply(sptr, RPL_DATASTR, " Status:: Client (service)");
624 + } else if (IsAnOper(acptr)) {
625 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Status:: IRC Operator (ID: %s)", cli_user(acptr)->opername ? cli_user(acptr)->opername : "<unknown>");
626 + send_reply(sptr, RPL_DATASTR, outbuf);
628 + send_reply(sptr, RPL_DATASTR, " Status:: Client");
630 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s (Hops: %d)", cli_name(cli_user(acptr)->server), cli_hopcount(acptr));
631 + send_reply(sptr, RPL_DATASTR, outbuf);
633 + /* +s (SERV_NOTICE) is not relayed to us from remote servers,
634 + * so we cannot tell if a remote client has that mode set.
635 + * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG
636 + * (and breaks if the user is +r) so we won't do that either.
639 + /* show the usermodes and account info (but not OperID and sethost) */
640 + umodes = umode_str(acptr, UMODE_AND_ACCOUNT);
641 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Usermode(s):: %s%s", *umodes ? "+" : "<none>", umodes);
642 + send_reply(sptr, RPL_DATASTR, outbuf);
644 + if (cli_user(acptr)->joined == 0)
645 + send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>");
646 + else if (cli_user(acptr)->joined > 50) {
648 + /* NB. As a sanity check, we DO NOT show the individual channels the
649 + * client is on if it is on > 50 channels. This is to prevent the ircd
650 + * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
651 + * an Oper would want to see every single channel 'x' client is on anyway if
652 + * they are on *that* many).
655 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", cli_user(acptr)->joined);
656 + send_reply(sptr, RPL_DATASTR, outbuf);
659 + char chntext[BUFSIZE];
660 + int len = strlen(" Channel(s):: ");
661 + int mlen = strlen(me.cli_name) + len + strlen(cli_name(sptr));
664 + strcpy(chntext, " Channel(s):: ");
665 + for (lp = cli_user(acptr)->channel; lp; lp = lp->next_channel) {
666 + chptr = lp->channel;
667 + if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
668 + send_reply(sptr, RPL_DATASTR, chntext);
670 + strcpy(chntext, " Channel(s):: ");
671 + len = strlen(chntext);
674 + *(chntext + len++) = '-';
675 + if (!PubChannel(chptr))
676 + *(chntext + len++) = '*';
678 + *(chntext + len++) = '!';
680 + *(chntext + len++) = '@';
681 + else if (HasVoice(lp))
682 + *(chntext + len++) = '+';
683 + else if (IsDelayedJoin(lp))
684 + *(chntext + len++) = '<';
686 + *(chntext + len) = '\0';
688 + strcpy(chntext + len, chptr->chname);
689 + len += strlen(chptr->chname);
690 + strcat(chntext + len, " ");
694 + if (chntext[0] != '\0')
695 + send_reply(sptr, RPL_DATASTR, chntext);
698 + if (MyUser(acptr)) {
699 + nowr = CurrentTime - cli_user(acptr)->last;
700 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Idle for:: %d days, %02ld:%02ld:%02ld",
701 + nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
702 + send_reply(sptr, RPL_DATASTR, outbuf);
705 + /* Away message (if applicable) */
706 + if (cli_user(acptr)->away) {
707 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Away message:: %s", cli_user(acptr)->away);
708 + send_reply(sptr, RPL_DATASTR, outbuf);
711 + /* If local user.. */
712 + if (MyUser(acptr)) {
713 + os_get_peername(con_fd(cli_connect(sptr)), &sin);
715 + send_reply(sptr, RPL_DATASTR, " ");
716 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Ports:: %d -> %d (client -> server)",
717 + sin.port, cli_listener(acptr)->addr.port);
718 + send_reply(sptr, RPL_DATASTR, outbuf);
719 + if (feature_bool(FEAT_EXTENDED_CHECKCMD)) {
720 + /* Note: sendq = receiveq for a client (it makes sense really) */
721 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Data sent:: %lu.%0.3u Kb (%u protocol messages)",
722 + (unsigned long)cli_receiveB(acptr) / 1024, (unsigned long)cli_receiveB(acptr) % 1024, cli_receiveM(acptr));
723 + send_reply(sptr, RPL_DATASTR, outbuf);
724 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Data received:: %lu.%0.3lu Kb (%u protocol messages)",
725 + (unsigned long)cli_sendB(acptr) / 1024, (unsigned long)cli_sendB(acptr) % 1024, cli_sendM(acptr));
726 + send_reply(sptr, RPL_DATASTR, outbuf);
727 + ircd_snprintf(0, outbuf, sizeof(outbuf), " receiveQ size:: %d bytes (max. %d bytes)",
728 + DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD));
729 + send_reply(sptr, RPL_DATASTR, outbuf);
730 + ircd_snprintf(0, outbuf, sizeof(outbuf), " sendQ size:: %d bytes (max. %d bytes)",
731 + DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr));
732 + send_reply(sptr, RPL_DATASTR, outbuf);
736 + /* Send 'END OF CHECK' message */
737 + send_reply(sptr, RPL_ENDOFCHECK, " ");
740 +void checkServer(struct Client *sptr, struct Client *acptr) {
741 + char outbuf[BUFSIZE];
744 + send_reply(sptr, RPL_DATASTR, " ");
745 + send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name);
746 + send_reply(sptr, RPL_DATASTR, " ");
748 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected at:: %s (%Tu)", myctime(acptr->cli_serv->timestamp), acptr->cli_serv->timestamp);
749 + send_reply(sptr, RPL_DATASTR, outbuf);
751 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Server name:: %s", acptr->cli_name);
752 + send_reply(sptr, RPL_DATASTR, outbuf);
754 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx));
755 + send_reply(sptr, RPL_DATASTR, outbuf);
757 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Users:: %d / %d", (acptr == &me) ? UserStats.local_clients : cli_serv(acptr)->clients,
758 + base64toint(cli_serv(acptr)->nn_capacity));
759 + send_reply(sptr, RPL_DATASTR, outbuf);
761 + if (IsBurst(acptr))
762 + send_reply(sptr, RPL_DATASTR, " Status:: Bursting");
763 + else if (IsBurstAck(acptr))
764 + send_reply(sptr, RPL_DATASTR, " Status:: Awaiting EOB Ack");
765 + else if (IsService(acptr))
766 + send_reply(sptr, RPL_DATASTR, " Status:: Network Service");
767 + else if (IsHub(acptr))
768 + send_reply(sptr, RPL_DATASTR, " Status:: Network Hub");
770 + if (feature_bool(FEAT_EXTENDED_CHECKCMD)) {
772 + struct DLink* slink = NULL;
774 + send_reply(sptr, RPL_DATASTR, " ");
775 + send_reply(sptr, RPL_DATASTR, "Downlinks::");
776 + for (slink = cli_serv(acptr)->down; slink; slink = slink->next) {
777 + ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc,
778 + IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" : IsService(slink->value.cptr) ? "=" : IsHub(slink->value.cptr) ? "+" : " ",
779 + cli_name(slink->value.cptr));
780 + send_reply(sptr, RPL_DATASTR, outbuf);
784 + send_reply(sptr, RPL_DATASTR, "<none>");
787 + /* Send 'END OF CHECK' message */
788 + send_reply(sptr, RPL_ENDOFCHECK, " ");
791 +signed int checkHostmask(struct Client *sptr, char *orighoststr, int flags) {
792 + struct Client *acptr;
793 + struct Channel *chptr;
794 + struct Membership *lp;
795 + int count = 0, found = 0;
796 + char outbuf[BUFSIZE];
797 + char targhost[NICKLEN + USERLEN + HOSTLEN + 3], curhost[NICKLEN + USERLEN + HOSTLEN + 3];
798 + char hoststr[NICKLEN + USERLEN + HOSTLEN + 3];
799 + char nickm[NICKLEN + 1], userm[USERLEN + 1], hostm[HOSTLEN + 1];
802 + struct irc_in_addr cidr_check;
803 + unsigned char cidr_check_bits;
805 + ircd_strncpy(hoststr, orighoststr, NICKLEN + USERLEN + HOSTLEN + 3);
810 + if (!strchr(hoststr, '!') && !strchr(hoststr, '@'))
811 + ircd_strncpy(hostm,hoststr,HOSTLEN);
813 + if ((p = strchr(hoststr, '@'))) {
815 + if (*p) ircd_strncpy(hostm,p, HOSTLEN);
818 + /* Get the nick!user mask */
819 + if ((p = strchr(hoststr, '!'))) {
821 + if (*p) ircd_strncpy(userm,p,USERLEN);
822 + if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN);
824 + else if (*hoststr) {
825 + /* Durz: We should only do the following *IF* the hoststr has not already been
826 + * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do
827 + * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com
829 + ircd_strncpy(userm,hoststr,USERLEN);
833 + if (ipmask_parse(hostm, &cidr_check, &cidr_check_bits) != 0) {
834 + flags |= CHECK_CIDRMASK;
837 + /* Copy formatted string into "targhost" buffer */
838 + ircd_snprintf(0, targhost, sizeof(targhost), "%s!%s@%s", nickm, userm, hostm);
840 + targhost[sizeof(targhost) - 1] = '\0';
842 + /* Note: we have to exclude the last client struct as it is not a real client
843 + * structure, and therefore any attempt to access elements in it would cause
847 + for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
848 + /* Dont process if acptr is a unregistered client, a server or a ping */
849 + if (!IsRegistered(acptr) || IsServer(acptr))
852 + if (IsMe(acptr)) /* Always the last acptr record */
855 + if(count >= 500) { /* sanity stuff */
856 + ircd_snprintf(0, outbuf, sizeof(outbuf), "More than %d results, truncating...", count);
857 + send_reply(sptr, RPL_DATASTR, outbuf);
861 + /* Copy host info into buffer */
863 + ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", cli_name(acptr), cli_user(acptr)->realusername, cli_user(acptr)->realhost);
865 + if (flags & CHECK_CIDRMASK) {
866 + if (ipmask_check(&cli_ip(acptr), &cidr_check, cidr_check_bits) && !match(nickm, acptr->cli_name)
867 + && (!match(userm, cli_user(acptr)->realusername) || !match(userm, cli_user(acptr)->username)))
871 + if(match((const char*)targhost,(const char*)curhost) == 0)
875 + ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, cli_user(acptr)->username, cli_user(acptr)->host);
877 + if(match((const char*)targhost,(const char*)curhost) == 0)
883 + found = 0; /* reset that so it doesn't get crazy go nuts */
885 + /* Show header if we've found at least 1 record */
887 + /* Output header */
888 + send_reply(sptr, RPL_DATASTR, " ");
889 + send_reply(sptr, RPL_CHKHEAD, "host", targhost);
891 + send_reply(sptr, RPL_DATASTR, " ");
892 + if (flags & CHECK_SHOWMORE)
893 + ircd_snprintf(0, outbuf, sizeof(outbuf), "No. %s nick user@host [IP] (usermodes) :realname", (flags & CHECK_CLONES) ? "[clients]" : "");
895 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s %-*s%-*s%s", "No.", (NICKLEN + 2), "Nick",
896 + (USERLEN + 2), "User", "Host");
897 + send_reply(sptr, RPL_DATASTR, outbuf);
900 + if (flags & CHECK_SHOWMORE) {
901 + /* show more information */
902 + umodes = umode_str(acptr, UMODE_AND_ACCOUNT_SHORT);
903 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d ", (count+1));
904 + if (flags & CHECK_CLONES)
905 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s[%+3hu] ", outbuf, IPcheck_nr(acptr));
906 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%s %s@%s [%s] (%s%s) :%s", outbuf,
908 + cli_user(acptr)->realusername, cli_user(acptr)->realhost,
909 + ircd_ntoa(&(cli_ip(acptr))),
910 + *umodes ? "+" : "<none>", umodes,
911 + (flags & CHECK_SHOWSERVER) ? cli_name(cli_user(acptr)->server) : cli_info(acptr));
913 + /* default output */
914 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d %-*s%-*s%s", (count+1), (NICKLEN + 2),
915 + acptr->cli_name, (USERLEN + 2), cli_user(acptr)->realusername,
916 + (flags & CHECK_SHOWIPS) ? ircd_ntoa(&(cli_ip(acptr))) : cli_user(acptr)->realhost);
918 + send_reply(sptr, RPL_DATASTR, outbuf);
920 + /* Show channel output (if applicable) - the 50 channel limit sanity check
921 + * is specifically to prevent coredumping when someone lamely tries to /check
922 + * Q or some other channel service...
924 + if (flags & CHECK_CHECKCHAN) {
925 + if (cli_user(acptr)->joined > 0 && cli_user(acptr)->joined <= 50) {
926 + char chntext[BUFSIZE];
927 + int len = strlen(" on channels: ");
928 + int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
931 + strcpy(chntext, " on channels: ");
932 + for (lp = cli_user(acptr)->channel; lp; lp = lp->next_channel) {
933 + chptr = lp->channel;
934 + if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
935 + send_reply(sptr, RPL_DATASTR, chntext);
937 + strcpy(chntext, " on channels: ");
938 + len = strlen(chntext);
941 + *(chntext + len++) = '-';
942 + if (!PubChannel(chptr))
943 + *(chntext + len++) = '*';
945 + *(chntext + len++) = '!';
947 + *(chntext + len++) = '@';
948 + else if (HasVoice(lp))
949 + *(chntext + len++) = '+';
950 + else if (IsDelayedJoin(lp))
951 + *(chntext + len++) = '<';
953 + *(chntext + len) = '\0';
955 + strcpy(chntext + len, chptr->chname);
956 + len += strlen(chptr->chname);
957 + strcat(chntext + len, " ");
960 + if (chntext[0] != '\0')
961 + send_reply(sptr, RPL_DATASTR, chntext);
963 + send_reply(sptr, RPL_DATASTR, " ");
971 + send_reply(sptr, RPL_DATASTR, " ");
973 + ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count);
974 + send_reply(sptr, RPL_DATASTR, outbuf);
976 + send_reply(sptr, RPL_ENDOFCHECK, " ");
981 diff -r 3303f23758b0 ircd/parse.c
982 --- a/ircd/parse.c Wed Jul 17 21:30:44 2013 +0100
983 +++ b/ircd/parse.c Wed Jul 17 21:38:16 2013 +0100
985 { m_cap, m_cap, m_ignore, m_cap, m_ignore }
990 + * - ASUKA ---------------------------------------------------------------------
991 + * Add the command for CHECK.
992 + * This was adapted from Lain for use in Asuka.
993 + * Original code by Durzel (durzel@quakenet.org).
995 + * qoreQ (qoreQ@quakenet.org) - 08/14/2002
996 + * -----------------------------------------------------------------------------
1001 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
1002 + { m_unregistered, m_not_oper, m_check, m_check, m_ignore }
1005 /* This command is an alias for QUIT during the unregistered part of
1006 * of the server. This is because someone jumping via a broken web
1007 * proxy will send a 'POST' as their first command - which we will
1008 diff -r 3303f23758b0 ircd/s_err.c
1009 --- a/ircd/s_err.c Wed Jul 17 21:30:44 2013 +0100
1010 +++ b/ircd/s_err.c Wed Jul 17 21:38:16 2013 +0100
1011 @@ -602,19 +602,19 @@
1013 { RPL_FEATURE, 0, "284" },
1016 + { RPL_NEWHOSTIS, "%s: %s host %s - [%s@%s]" },
1019 + { RPL_CHKHEAD, ":Information for %s %s", "286" },
1022 + { RPL_CHANUSER, ": %s%s (%s@%s) %s (%s) %s", "287" },
1029 + { RPL_DATASTR, ":%s", "290" },
1032 + { RPL_ENDOFCHECK, ":%s", "291" },
1038 { ERR_TOOMANYTARGETS, "%s :Duplicate recipients. No message delivered", "407" },
1041 + { ERR_SEARCHNOMATCH, ":%s %s No matching record(s) found", "408" },
1043 { ERR_NOORIGIN, ":No origin specified", "409" },
1045 diff -r 3303f23758b0 ircd/s_user.c
1046 --- a/ircd/s_user.c Wed Jul 17 21:30:44 2013 +0100
1047 +++ b/ircd/s_user.c Wed Jul 17 21:38:16 2013 +0100
1048 @@ -1485,7 +1485,8 @@
1049 m--; /* Step back over the '\0' */
1052 - if (IsSetHost(cptr)) {
1053 + /* sethost parameter is wanted */
1054 + if (type != UMODE_AND_ACCOUNT && IsSetHost(cptr)) {
1056 ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
1057 cli_user(cptr)->host);