2 * charybdis: an advanced ircd.
3 * client.c: Controls clients.
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 * Copyright (C) 2007 William Pitcock
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 * $Id: client.c 3514 2007-06-06 16:25:21Z nenolod $
36 #include "irc_string.h"
37 #include "sprintf_irc.h"
45 #include "s_newconf.h"
61 #include "blacklist.h"
64 #include "irc_dictionary.h"
66 #define DEBUG_EXITED_CLIENTS
68 static void check_pings_list(dlink_list
* list
);
69 static void check_unknowns_list(dlink_list
* list
);
70 static void free_exited_clients(void *unused
);
71 static void exit_aborted_clients(void *unused
);
73 static int exit_remote_client(struct Client
*, struct Client
*, struct Client
*,const char *);
74 static int exit_remote_server(struct Client
*, struct Client
*, struct Client
*,const char *);
75 static int exit_local_client(struct Client
*, struct Client
*, struct Client
*,const char *);
76 static int exit_unknown_client(struct Client
*, struct Client
*, struct Client
*,const char *);
77 static int exit_local_server(struct Client
*, struct Client
*, struct Client
*,const char *);
78 static int qs_server(struct Client
*, struct Client
*, struct Client
*, const char *comment
);
80 static EVH check_pings
;
82 extern BlockHeap
*client_heap
;
83 extern BlockHeap
*lclient_heap
;
84 extern BlockHeap
*pclient_heap
;
86 extern char current_uid
[IDLEN
];
96 #ifdef DEBUG_EXITED_CLIENTS
97 static dlink_list dead_remote_list
;
103 struct Client
*client
;
104 char notice
[REASONLEN
];
107 static dlink_list abort_list
;
115 * side effects - initialize client free memory
121 * start off the check ping event .. -- adrian
122 * Every 30 seconds is plenty -- db
124 client_heap
= BlockHeapCreate(sizeof(struct Client
), CLIENT_HEAP_SIZE
);
125 lclient_heap
= BlockHeapCreate(sizeof(struct LocalUser
), LCLIENT_HEAP_SIZE
);
126 pclient_heap
= BlockHeapCreate(sizeof(struct PreClient
), PCLIENT_HEAP_SIZE
);
127 eventAddIsh("check_pings", check_pings
, NULL
, 30);
128 eventAddIsh("free_exited_clients", &free_exited_clients
, NULL
, 4);
129 eventAddIsh("exit_aborted_clients", exit_aborted_clients
, NULL
, 1);
134 * make_client - create a new Client struct and set it to initial state.
136 * from == NULL, create local client (a client connected
139 * from, create remote client (behind a socket
140 * associated with the client defined by
141 * 'from'). ('from' is a local client!!).
144 make_client(struct Client
*from
)
146 struct Client
*client_p
= NULL
;
147 struct LocalUser
*localClient
;
149 client_p
= BlockHeapAlloc(client_heap
);
153 client_p
->from
= client_p
; /* 'from' of local client is self! */
155 localClient
= (struct LocalUser
*) BlockHeapAlloc(lclient_heap
);
156 SetMyConnect(client_p
);
157 client_p
->localClient
= localClient
;
159 client_p
->localClient
->lasttime
= client_p
->localClient
->firsttime
= CurrentTime
;
161 client_p
->localClient
->fd
= -1;
162 client_p
->localClient
->ctrlfd
= -1;
164 client_p
->preClient
= (struct PreClient
*) BlockHeapAlloc(pclient_heap
);
166 /* as good a place as any... */
167 dlinkAdd(client_p
, &client_p
->localClient
->tnode
, &unknown_list
);
170 { /* from is not NULL */
171 client_p
->localClient
= NULL
;
172 client_p
->preClient
= NULL
;
173 client_p
->from
= from
; /* 'from' of local client is self! */
176 SetUnknown(client_p
);
177 strcpy(client_p
->username
, "unknown");
183 free_pre_client(struct Client
*client_p
)
185 struct Blacklist
*blptr
;
187 s_assert(NULL
!= client_p
);
189 if(client_p
->preClient
== NULL
)
192 blptr
= client_p
->preClient
->dnsbl_listed
;
194 unref_blacklist(blptr
);
195 abort_blacklist_queries(client_p
);
196 BlockHeapFree(pclient_heap
, client_p
->preClient
);
197 client_p
->preClient
= NULL
;
201 free_local_client(struct Client
*client_p
)
203 s_assert(NULL
!= client_p
);
204 s_assert(&me
!= client_p
);
206 if(client_p
->localClient
== NULL
)
210 * clean up extra sockets from P-lines which have been discarded.
212 if(client_p
->localClient
->listener
)
214 s_assert(0 < client_p
->localClient
->listener
->ref_count
);
215 if(0 == --client_p
->localClient
->listener
->ref_count
216 && !client_p
->localClient
->listener
->active
)
217 free_listener(client_p
->localClient
->listener
);
218 client_p
->localClient
->listener
= 0;
221 if(client_p
->localClient
->fd
>= 0)
222 comm_close(client_p
->localClient
->fd
);
224 if(client_p
->localClient
->passwd
)
226 memset(client_p
->localClient
->passwd
, 0,
227 strlen(client_p
->localClient
->passwd
));
228 MyFree(client_p
->localClient
->passwd
);
231 MyFree(client_p
->localClient
->challenge
);
232 MyFree(client_p
->localClient
->fullcaps
);
233 MyFree(client_p
->localClient
->opername
);
234 MyFree(client_p
->localClient
->mangledhost
);
236 BlockHeapFree(lclient_heap
, client_p
->localClient
);
237 client_p
->localClient
= NULL
;
241 free_client(struct Client
*client_p
)
243 s_assert(NULL
!= client_p
);
244 s_assert(&me
!= client_p
);
245 free_local_client(client_p
);
246 free_pre_client(client_p
);
247 BlockHeapFree(client_heap
, client_p
);
251 * check_pings - go through the local client list and check activity
252 * kill off stuff that should die
254 * inputs - NOT USED (from event)
255 * output - next time_t when check_pings() should be called again
259 * A PING can be sent to clients as necessary.
261 * Client/Server ping outs are handled.
265 * Addon from adrian. We used to call this after nextping seconds,
266 * however I've changed it to run once a second. This is only for
267 * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
268 * run once a second makes life a lot easier - when a new client connects
269 * and they need a ping in 4 seconds, if nextping was set to 20 seconds
270 * we end up waiting 20 seconds. This is stupid. :-)
271 * I will optimise (hah!) check_pings() once I've finished working on
272 * tidying up other network IO evilnesses.
277 check_pings(void *notused
)
279 check_pings_list(&lclient_list
);
280 check_pings_list(&serv_list
);
281 check_unknowns_list(&unknown_list
);
287 * inputs - pointer to list to check
292 check_pings_list(dlink_list
* list
)
294 char scratch
[32]; /* way too generous but... */
295 struct Client
*client_p
; /* current local client_p being examined */
296 int ping
= 0; /* ping time value from client */
297 dlink_node
*ptr
, *next_ptr
;
299 DLINK_FOREACH_SAFE(ptr
, next_ptr
, list
->head
)
301 client_p
= ptr
->data
;
304 ** Note: No need to notify opers here. It's
305 ** already done when "FLAGS_DEADSOCKET" is set.
307 if(!MyConnect(client_p
) || IsDead(client_p
))
310 if(IsPerson(client_p
))
312 if(!IsExemptKline(client_p
) &&
313 GlobalSetOptions
.idletime
&&
315 !IsIdlelined(client_p
) &&
316 ((CurrentTime
- client_p
->localClient
->last
) > GlobalSetOptions
.idletime
))
318 struct ConfItem
*aconf
;
321 aconf
->status
= CONF_KILL
;
323 DupString(aconf
->host
, client_p
->host
);
324 DupString(aconf
->passwd
, "idle exceeder");
325 DupString(aconf
->user
, client_p
->username
);
327 aconf
->hold
= CurrentTime
+ 60;
328 add_temp_kline(aconf
);
329 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
330 "Idle time limit exceeded for %s - temp k-lining",
331 get_client_name(client_p
, HIDE_IP
));
333 exit_client(client_p
, client_p
, &me
, aconf
->passwd
);
338 if(!IsRegistered(client_p
))
339 ping
= ConfigFileEntry
.connect_timeout
;
341 ping
= get_client_ping(client_p
);
343 if(ping
< (CurrentTime
- client_p
->localClient
->lasttime
))
346 * If the client/server hasnt talked to us in 2*ping seconds
347 * and it has a ping time, then close its connection.
349 if(((CurrentTime
- client_p
->localClient
->lasttime
) >= (2 * ping
)
350 && (client_p
->flags
& FLAGS_PINGSENT
)))
352 if(IsAnyServer(client_p
))
354 sendto_realops_snomask(SNO_GENERAL
, is_remote_connect(client_p
) && !IsServer(client_p
) ? L_NETWIDE
: L_ALL
,
355 "No response from %s, closing link",
356 get_server_name(client_p
, HIDE_IP
));
358 "No response from %s, closing link",
359 log_client_name(client_p
, HIDE_IP
));
361 (void) ircsnprintf(scratch
, sizeof(scratch
),
362 "Ping timeout: %d seconds",
363 (int) (CurrentTime
- client_p
->localClient
->lasttime
));
365 exit_client(client_p
, client_p
, &me
, scratch
);
368 else if((client_p
->flags
& FLAGS_PINGSENT
) == 0)
371 * if we havent PINGed the connection and we havent
372 * heard from it in a while, PING it to make sure
375 client_p
->flags
|= FLAGS_PINGSENT
;
376 /* not nice but does the job */
377 client_p
->localClient
->lasttime
= CurrentTime
- ping
;
378 sendto_one(client_p
, "PING :%s", me
.name
);
387 * check_unknowns_list
389 * inputs - pointer to list of unknown clients
391 * side effects - unknown clients get marked for termination after n seconds
394 check_unknowns_list(dlink_list
* list
)
396 dlink_node
*ptr
, *next_ptr
;
397 struct Client
*client_p
;
399 DLINK_FOREACH_SAFE(ptr
, next_ptr
, list
->head
)
401 client_p
= ptr
->data
;
403 if(IsDead(client_p
) || IsClosing(client_p
))
407 * Check UNKNOWN connections - if they have been in this state
408 * for > 30s, close them.
411 if((CurrentTime
- client_p
->localClient
->firsttime
) > 30)
412 exit_client(client_p
, client_p
, &me
, "Connection timed out");
417 notify_banned_client(struct Client
*client_p
, struct ConfItem
*aconf
, int ban
)
419 static const char conn_closed
[] = "Connection closed";
420 static const char d_lined
[] = "D-lined";
421 static const char k_lined
[] = "K-lined";
422 static const char g_lined
[] = "G-lined";
423 const char *reason
= NULL
;
424 const char *exit_reason
= conn_closed
;
426 if(ConfigFileEntry
.kline_with_reason
&& !EmptyString(aconf
->passwd
))
428 reason
= aconf
->passwd
;
429 exit_reason
= aconf
->passwd
;
433 switch (aconf
->status
)
447 if(ban
== D_LINED
&& !IsPerson(client_p
))
448 sendto_one(client_p
, "NOTICE DLINE :*** You have been D-lined");
450 sendto_one(client_p
, form_str(ERR_YOUREBANNEDCREEP
),
451 me
.name
, client_p
->name
, reason
);
453 exit_client(client_p
, client_p
, &me
,
454 EmptyString(ConfigFileEntry
.kline_reason
) ? exit_reason
:
455 ConfigFileEntry
.kline_reason
);
462 * side effects - Check all connections for a pending k/d/gline against the
463 * client, exit the client if found.
466 check_banned_lines(void)
468 struct Client
*client_p
; /* current local client_p being examined */
469 struct ConfItem
*aconf
= NULL
;
470 dlink_node
*ptr
, *next_ptr
;
472 DLINK_FOREACH_SAFE(ptr
, next_ptr
, lclient_list
.head
)
474 client_p
= ptr
->data
;
479 /* if there is a returned struct ConfItem then kill it */
480 if((aconf
= find_dline((struct sockaddr
*)&client_p
->localClient
->ip
, client_p
->localClient
->ip
.ss_family
)))
482 if(aconf
->status
& CONF_EXEMPTDLINE
)
485 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
486 "DLINE active for %s",
487 get_client_name(client_p
, HIDE_IP
));
489 notify_banned_client(client_p
, aconf
, D_LINED
);
490 continue; /* and go examine next fd/client_p */
493 if(!IsPerson(client_p
))
496 if((aconf
= find_kline(client_p
)) != NULL
)
498 if(IsExemptKline(client_p
))
500 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
501 "KLINE over-ruled for %s, client is kline_exempt [%s@%s]",
502 get_client_name(client_p
, HIDE_IP
),
503 aconf
->user
, aconf
->host
);
507 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
508 "KLINE active for %s",
509 get_client_name(client_p
, HIDE_IP
));
510 notify_banned_client(client_p
, aconf
, K_LINED
);
513 else if((aconf
= find_gline(client_p
)) != NULL
)
515 if(IsExemptKline(client_p
))
517 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
518 "GLINE over-ruled for %s, client is kline_exempt [%s@%s]",
519 get_client_name(client_p
, HIDE_IP
),
520 aconf
->user
, aconf
->host
);
524 if(IsExemptGline(client_p
))
526 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
527 "GLINE over-ruled for %s, client is gline_exempt [%s@%s]",
528 get_client_name(client_p
, HIDE_IP
),
529 aconf
->user
, aconf
->host
);
533 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
534 "GLINE active for %s",
535 get_client_name(client_p
, HIDE_IP
));
537 notify_banned_client(client_p
, aconf
, G_LINED
);
540 else if((aconf
= find_xline(client_p
->info
, 1)) != NULL
)
542 if(IsExemptKline(client_p
))
544 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
545 "XLINE over-ruled for %s, client is kline_exempt [%s]",
546 get_client_name(client_p
, HIDE_IP
),
551 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "XLINE active for %s",
552 get_client_name(client_p
, HIDE_IP
));
554 (void) exit_client(client_p
, client_p
, &me
, "Bad user info");
559 /* also check the unknowns list for new dlines */
560 DLINK_FOREACH_SAFE(ptr
, next_ptr
, unknown_list
.head
)
562 client_p
= ptr
->data
;
564 if((aconf
= find_dline((struct sockaddr
*)&client_p
->localClient
->ip
,client_p
->localClient
->ip
.ss_family
)))
566 if(aconf
->status
& CONF_EXEMPTDLINE
)
569 notify_banned_client(client_p
, aconf
, D_LINED
);
575 /* check_klines_event()
579 * side effects - check_klines() is called, kline_queued unset
582 check_klines_event(void *unused
)
592 * side effects - all clients will be checked for klines
597 struct Client
*client_p
;
598 struct ConfItem
*aconf
;
600 dlink_node
*next_ptr
;
602 DLINK_FOREACH_SAFE(ptr
, next_ptr
, lclient_list
.head
)
604 client_p
= ptr
->data
;
606 if(IsMe(client_p
) || !IsPerson(client_p
))
609 if((aconf
= find_kline(client_p
)) != NULL
)
611 if(IsExemptKline(client_p
))
613 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
614 "KLINE over-ruled for %s, client is kline_exempt",
615 get_client_name(client_p
, HIDE_IP
));
619 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
620 "KLINE active for %s",
621 get_client_name(client_p
, HIDE_IP
));
623 notify_banned_client(client_p
, aconf
, K_LINED
);
633 * side effects - all clients will be checked for glines
638 struct Client
*client_p
;
639 struct ConfItem
*aconf
;
641 dlink_node
*next_ptr
;
643 DLINK_FOREACH_SAFE(ptr
, next_ptr
, lclient_list
.head
)
645 client_p
= ptr
->data
;
647 if(IsMe(client_p
) || !IsPerson(client_p
))
650 if((aconf
= find_gline(client_p
)) != NULL
)
652 if(IsExemptKline(client_p
))
654 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
655 "GLINE over-ruled for %s, client is kline_exempt",
656 get_client_name(client_p
, HIDE_IP
));
660 if(IsExemptGline(client_p
))
662 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
663 "GLINE over-ruled for %s, client is gline_exempt",
664 get_client_name(client_p
, HIDE_IP
));
668 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
669 "GLINE active for %s",
670 get_client_name(client_p
, HIDE_IP
));
672 notify_banned_client(client_p
, aconf
, K_LINED
);
682 * side effects - all clients will be checked for dlines
687 struct Client
*client_p
;
688 struct ConfItem
*aconf
;
690 dlink_node
*next_ptr
;
692 DLINK_FOREACH_SAFE(ptr
, next_ptr
, lclient_list
.head
)
694 client_p
= ptr
->data
;
699 if((aconf
= find_dline((struct sockaddr
*)&client_p
->localClient
->ip
,client_p
->localClient
->ip
.ss_family
)) != NULL
)
701 if(aconf
->status
& CONF_EXEMPTDLINE
)
704 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
705 "DLINE active for %s",
706 get_client_name(client_p
, HIDE_IP
));
708 notify_banned_client(client_p
, aconf
, D_LINED
);
713 /* dlines need to be checked against unknowns too */
714 DLINK_FOREACH_SAFE(ptr
, next_ptr
, unknown_list
.head
)
716 client_p
= ptr
->data
;
718 if((aconf
= find_dline((struct sockaddr
*)&client_p
->localClient
->ip
,client_p
->localClient
->ip
.ss_family
)) != NULL
)
720 if(aconf
->status
& CONF_EXEMPTDLINE
)
723 notify_banned_client(client_p
, aconf
, D_LINED
);
732 * side effects - all clients will be checked for xlines
737 struct Client
*client_p
;
738 struct ConfItem
*aconf
;
740 dlink_node
*next_ptr
;
742 DLINK_FOREACH_SAFE(ptr
, next_ptr
, lclient_list
.head
)
744 client_p
= ptr
->data
;
746 if(IsMe(client_p
) || !IsPerson(client_p
))
749 if((aconf
= find_xline(client_p
->info
, 1)) != NULL
)
751 if(IsExemptKline(client_p
))
753 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
754 "XLINE over-ruled for %s, client is kline_exempt",
755 get_client_name(client_p
, HIDE_IP
));
759 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "XLINE active for %s",
760 get_client_name(client_p
, HIDE_IP
));
762 (void) exit_client(client_p
, client_p
, &me
, "Bad user info");
769 * update_client_exit_stats
771 * input - pointer to client
776 update_client_exit_stats(struct Client
*client_p
)
778 if(IsServer(client_p
))
780 sendto_realops_snomask(SNO_EXTERNAL
, L_ALL
,
781 "Server %s split from %s",
782 client_p
->name
, client_p
->servptr
->name
);
783 if(HasSentEob(client_p
))
786 else if(IsClient(client_p
))
791 if(IsInvisible(client_p
))
795 if(splitchecking
&& !splitmode
)
796 check_splitmode(NULL
);
800 * release_client_state
802 * input - pointer to client to release
807 release_client_state(struct Client
*client_p
)
809 if(client_p
->user
!= NULL
)
811 free_user(client_p
->user
, client_p
); /* try this here */
815 if(client_p
->serv
->user
!= NULL
)
816 free_user(client_p
->serv
->user
, client_p
);
817 if(client_p
->serv
->fullcaps
)
818 MyFree(client_p
->serv
->fullcaps
);
819 MyFree(client_p
->serv
);
824 * remove_client_from_list
825 * inputs - point to client to remove
827 * side effects - taken the code from ExitOneClient() for this
828 * and placed it here. - avalon
831 remove_client_from_list(struct Client
*client_p
)
833 s_assert(NULL
!= client_p
);
838 /* A client made with make_client()
839 * is on the unknown_list until removed.
840 * If it =does= happen to exit before its removed from that list
841 * and its =not= on the global_client_list, it will core here.
842 * short circuit that case now -db
844 if(client_p
->node
.prev
== NULL
&& client_p
->node
.next
== NULL
)
847 dlinkDelete(&client_p
->node
, &global_client_list
);
849 update_client_exit_stats(client_p
);
854 * find_person - find person by (nick)name.
855 * inputs - pointer to name
856 * output - return client pointer
860 find_person(const char *name
)
862 struct Client
*c2ptr
;
864 c2ptr
= find_client(name
);
866 if(c2ptr
&& IsPerson(c2ptr
))
872 find_named_person(const char *name
)
874 struct Client
*c2ptr
;
876 c2ptr
= find_named_client(name
);
878 if(c2ptr
&& IsPerson(c2ptr
))
885 * find_chasing - find the client structure for a nick name (user)
886 * using history mechanism if necessary. If the client is not found,
887 * an error message (NO SUCH NICK) is generated. If the client was found
888 * through the history, chasing will be 1 and otherwise 0.
891 find_chasing(struct Client
*source_p
, const char *user
, int *chasing
)
895 if(MyClient(source_p
))
896 who
= find_named_person(user
);
898 who
= find_person(user
);
903 if(who
|| IsDigit(*user
))
906 if(!(who
= get_history(user
, (long) KILLCHASETIMELIMIT
)))
908 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
909 form_str(ERR_NOSUCHNICK
), user
);
918 * get_client_name - Return the name of the client
919 * for various tracking and
920 * admin purposes. The main purpose of this function is to
921 * return the "socket host" name of the client, if that
922 * differs from the advertised name (other than case).
923 * But, this can be used to any client structure.
926 * Watch out the allocation of "nbuf", if either source_p->name
927 * or source_p->sockhost gets changed into pointers instead of
928 * directly allocated within the structure...
931 * Function return either a pointer to the structure (source_p) or
932 * to internal buffer (nbuf). *NEVER* use the returned pointer
933 * to modify what it points!!!
937 get_client_name(struct Client
*client
, int showip
)
939 static char nbuf
[HOSTLEN
* 2 + USERLEN
+ 5];
941 s_assert(NULL
!= client
);
945 if(MyConnect(client
))
947 if(!irccmp(client
->name
, client
->host
))
950 if(ConfigFileEntry
.hide_spoof_ips
&&
951 showip
== SHOW_IP
&& IsIPSpoof(client
))
953 #ifdef HIDE_SERVERS_IPS
954 if(IsAnyServer(client
))
958 /* And finally, let's get the host information, ip or name */
962 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@%s]",
963 client
->name
, client
->username
,
967 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@255.255.255.255]",
968 client
->name
, client
->username
);
971 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@%s]",
972 client
->name
, client
->username
, client
->host
);
977 /* As pointed out by Adel Mezibra
978 * Neph|l|m@EFnet. Was missing a return here.
984 get_server_name(struct Client
*target_p
, int showip
)
986 static char nbuf
[HOSTLEN
* 2 + USERLEN
+ 5];
991 if(!MyConnect(target_p
) || !irccmp(target_p
->name
, target_p
->host
))
992 return target_p
->name
;
994 #ifdef HIDE_SERVERS_IPS
995 if(EmptyString(target_p
->name
))
997 ircsnprintf(nbuf
, sizeof(nbuf
), "[%s@255.255.255.255]",
1002 return target_p
->name
;
1008 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@%s]",
1009 target_p
->name
, target_p
->username
,
1010 target_p
->sockhost
);
1014 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@255.255.255.255]",
1015 target_p
->name
, target_p
->username
);
1018 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@%s]",
1019 target_p
->name
, target_p
->username
,
1026 /* log_client_name()
1028 * This version is the same as get_client_name, but doesnt contain the
1029 * code that will hide IPs always. This should be used for logfiles.
1032 log_client_name(struct Client
*target_p
, int showip
)
1034 static char nbuf
[HOSTLEN
* 2 + USERLEN
+ 5];
1036 if(target_p
== NULL
)
1039 if(MyConnect(target_p
))
1041 if(irccmp(target_p
->name
, target_p
->host
) == 0)
1042 return target_p
->name
;
1047 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@%s]", target_p
->name
,
1048 target_p
->username
, target_p
->sockhost
);
1052 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@255.255.255.255]",
1053 target_p
->name
, target_p
->username
);
1056 ircsnprintf(nbuf
, sizeof(nbuf
), "%s[%s@%s]", target_p
->name
,
1057 target_p
->username
, target_p
->host
);
1063 return target_p
->name
;
1066 /* is_remote_connect - Returns whether a server was /connect'ed by a remote
1067 * oper (send notices netwide) */
1069 is_remote_connect(struct Client
*client_p
)
1071 struct Client
*oper
;
1073 if (client_p
->serv
== NULL
)
1075 oper
= find_named_person(client_p
->serv
->by
);
1076 return oper
!= NULL
&& IsOper(oper
) && !MyConnect(oper
);
1080 free_exited_clients(void *unused
)
1082 dlink_node
*ptr
, *next
;
1083 struct Client
*target_p
;
1085 DLINK_FOREACH_SAFE(ptr
, next
, dead_list
.head
)
1087 target_p
= ptr
->data
;
1089 #ifdef DEBUG_EXITED_CLIENTS
1091 struct abort_client
*abt
;
1095 DLINK_FOREACH(aptr
, abort_list
.head
)
1098 if(abt
->client
== target_p
)
1101 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1102 "On abort_list: %s stat: %u flags: %u/%u handler: %c",
1103 target_p
->name
, (unsigned int) target_p
->status
,
1104 target_p
->flags
, target_p
->flags2
, target_p
->handler
);
1105 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1106 "Please report this to the charybdis developers!");
1113 dlinkDestroy(ptr
, &dead_list
);
1119 if(ptr
->data
== NULL
)
1121 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1122 "Warning: null client on dead_list!");
1123 dlinkDestroy(ptr
, &dead_list
);
1126 release_client_state(target_p
);
1127 free_client(target_p
);
1128 dlinkDestroy(ptr
, &dead_list
);
1131 #ifdef DEBUG_EXITED_CLIENTS
1132 DLINK_FOREACH_SAFE(ptr
, next
, dead_remote_list
.head
)
1134 target_p
= ptr
->data
;
1136 if(ptr
->data
== NULL
)
1138 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1139 "Warning: null client on dead_list!");
1140 dlinkDestroy(ptr
, &dead_list
);
1143 release_client_state(target_p
);
1144 free_client(target_p
);
1145 dlinkDestroy(ptr
, &dead_remote_list
);
1152 ** Recursively send QUITs and SQUITs for source_p and all its dependent clients
1153 ** and servers to those servers that need them. A server needs the client
1154 ** QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
1155 ** isn't getting the SQUIT because of @#(*&@)# hostmasking. With TS4, once
1156 ** a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
1157 ** on that one -orabidoo
1160 recurse_send_quits(struct Client
*client_p
, struct Client
*source_p
,
1161 struct Client
*to
, const char *comment1
,
1162 const char *comment
)
1164 struct Client
*target_p
;
1165 dlink_node
*ptr
, *ptr_next
;
1166 /* If this server can handle quit storm (QS) removal
1167 * of dependents, just send the SQUIT
1170 if(IsCapable(to
, CAP_QS
))
1172 sendto_one(to
, "SQUIT %s :%s",
1173 get_id(source_p
, to
), comment
);
1177 DLINK_FOREACH_SAFE(ptr
, ptr_next
, source_p
->serv
->users
.head
)
1179 target_p
= ptr
->data
;
1180 sendto_one(to
, ":%s QUIT :%s", target_p
->name
, comment1
);
1182 DLINK_FOREACH_SAFE(ptr
, ptr_next
, source_p
->serv
->servers
.head
)
1184 target_p
= ptr
->data
;
1185 recurse_send_quits(client_p
, target_p
, to
, comment1
, comment
);
1187 sendto_one(to
, "SQUIT %s :%s", source_p
->name
, comment
);
1192 ** Remove all clients that depend on source_p; assumes all (S)QUITs have
1193 ** already been sent. we make sure to exit a server's dependent clients
1194 ** and servers before the server itself; exit_one_client takes care of
1195 ** actually removing things off llists. tweaked from +CSr31 -orabidoo
1198 * added sanity test code.... source_p->serv might be NULL...
1201 recurse_remove_clients(struct Client
*source_p
, const char *comment
)
1203 struct Client
*target_p
;
1204 dlink_node
*ptr
, *ptr_next
;
1209 if(source_p
->serv
== NULL
) /* oooops. uh this is actually a major bug */
1212 /* this is very ugly, but it saves cpu :P */
1213 if(ConfigFileEntry
.nick_delay
> 0)
1215 DLINK_FOREACH_SAFE(ptr
, ptr_next
, source_p
->serv
->users
.head
)
1217 target_p
= ptr
->data
;
1218 target_p
->flags
|= FLAGS_KILLED
;
1219 add_nd_entry(target_p
->name
);
1221 if(!IsDead(target_p
) && !IsClosing(target_p
))
1222 exit_remote_client(NULL
, target_p
, &me
, comment
);
1227 DLINK_FOREACH_SAFE(ptr
, ptr_next
, source_p
->serv
->users
.head
)
1229 target_p
= ptr
->data
;
1230 target_p
->flags
|= FLAGS_KILLED
;
1232 if(!IsDead(target_p
) && !IsClosing(target_p
))
1233 exit_remote_client(NULL
, target_p
, &me
, comment
);
1237 DLINK_FOREACH_SAFE(ptr
, ptr_next
, source_p
->serv
->servers
.head
)
1239 target_p
= ptr
->data
;
1240 recurse_remove_clients(target_p
, comment
);
1241 qs_server(NULL
, target_p
, &me
, comment
);
1246 ** Remove *everything* that depends on source_p, from all lists, and sending
1247 ** all necessary QUITs and SQUITs. source_p itself is still on the lists,
1248 ** and its SQUITs have been sent except for the upstream one -orabidoo
1251 remove_dependents(struct Client
*client_p
,
1252 struct Client
*source_p
,
1253 struct Client
*from
, const char *comment
, const char *comment1
)
1256 dlink_node
*ptr
, *next
;
1258 DLINK_FOREACH_SAFE(ptr
, next
, serv_list
.head
)
1262 if(IsMe(to
) || to
== source_p
->from
||
1263 (to
== client_p
&& IsCapable(to
, CAP_QS
)))
1266 recurse_send_quits(client_p
, source_p
, to
, comment1
, comment
);
1269 recurse_remove_clients(source_p
, comment1
);
1273 exit_aborted_clients(void *unused
)
1275 struct abort_client
*abt
;
1276 dlink_node
*ptr
, *next
;
1277 DLINK_FOREACH_SAFE(ptr
, next
, abort_list
.head
)
1281 #ifdef DEBUG_EXITED_CLIENTS
1283 if(dlinkFind(abt
->client
, &dead_list
))
1286 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1287 "On dead_list: %s stat: %u flags: %u/%u handler: %c",
1288 abt
->client
->name
, (unsigned int) abt
->client
->status
,
1289 abt
->client
->flags
, abt
->client
->flags2
, abt
->client
->handler
);
1290 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1291 "Please report this to the charybdis developers!");
1297 s_assert(*((unsigned long*)abt
->client
) != 0xdeadbeef); /* This is lame but its a debug thing */
1298 dlinkDelete(ptr
, &abort_list
);
1300 if(IsAnyServer(abt
->client
))
1301 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1302 "Closing link to %s: %s",
1303 get_server_name(abt
->client
, HIDE_IP
), abt
->notice
);
1305 /* its no longer on abort list - we *must* remove
1306 * FLAGS_CLOSING otherwise exit_client() will not run --fl
1308 abt
->client
->flags
&= ~FLAGS_CLOSING
;
1309 exit_client(abt
->client
, abt
->client
, &me
, abt
->notice
);
1316 * dead_link - Adds client to a list of clients that need an exit_client()
1320 dead_link(struct Client
*client_p
)
1322 struct abort_client
*abt
;
1324 s_assert(!IsMe(client_p
));
1325 if(IsDead(client_p
) || IsClosing(client_p
) || IsMe(client_p
))
1328 abt
= (struct abort_client
*) MyMalloc(sizeof(struct abort_client
));
1330 if(client_p
->flags
& FLAGS_SENDQEX
)
1331 strlcpy(abt
->notice
, "Max SendQ exceeded", sizeof(abt
->notice
));
1333 ircsnprintf(abt
->notice
, sizeof(abt
->notice
), "Write error: %s", strerror(errno
));
1335 abt
->client
= client_p
;
1336 SetIOError(client_p
);
1338 SetClosing(client_p
);
1339 dlinkAdd(abt
, &abt
->node
, &abort_list
);
1343 /* This does the remove of the user from channels..local or remote */
1345 exit_generic_client(struct Client
*client_p
, struct Client
*source_p
, struct Client
*from
,
1346 const char *comment
)
1348 dlink_node
*ptr
, *next_ptr
;
1350 if(IsOper(source_p
))
1351 dlinkFindDestroy(source_p
, &oper_list
);
1353 sendto_common_channels_local(source_p
, ":%s!%s@%s QUIT :%s",
1355 source_p
->username
, source_p
->host
, comment
);
1357 remove_user_from_channels(source_p
);
1359 /* Should not be in any channels now */
1360 s_assert(source_p
->user
->channel
.head
== NULL
);
1362 /* Clean up invitefield */
1363 DLINK_FOREACH_SAFE(ptr
, next_ptr
, source_p
->user
->invited
.head
)
1365 del_invite(ptr
->data
, source_p
);
1368 /* Clean up allow lists */
1369 del_all_accepts(source_p
);
1371 add_history(source_p
, 0);
1372 off_history(source_p
);
1374 monitor_signoff(source_p
);
1376 if(has_id(source_p
))
1377 del_from_id_hash(source_p
->id
, source_p
);
1379 del_from_hostname_hash(source_p
->orighost
, source_p
);
1380 del_from_client_hash(source_p
->name
, source_p
);
1381 remove_client_from_list(source_p
);
1385 * Assumes IsPerson(source_p) && !MyConnect(source_p)
1389 exit_remote_client(struct Client
*client_p
, struct Client
*source_p
, struct Client
*from
,
1390 const char *comment
)
1392 exit_generic_client(client_p
, source_p
, from
, comment
);
1394 if(source_p
->servptr
&& source_p
->servptr
->serv
)
1396 dlinkDelete(&source_p
->lnode
, &source_p
->servptr
->serv
->users
);
1399 if((source_p
->flags
& FLAGS_KILLED
) == 0)
1401 sendto_server(client_p
, NULL
, CAP_TS6
, NOCAPS
,
1402 ":%s QUIT :%s", use_id(source_p
), comment
);
1403 sendto_server(client_p
, NULL
, NOCAPS
, CAP_TS6
,
1404 ":%s QUIT :%s", source_p
->name
, comment
);
1408 #ifdef DEBUG_EXITED_CLIENTS
1409 dlinkAddAlloc(source_p
, &dead_remote_list
);
1411 dlinkAddAlloc(source_p
, &dead_list
);
1413 return(CLIENT_EXITED
);
1417 * This assumes IsUnknown(source_p) == TRUE and MyConnect(source_p) == TRUE
1421 exit_unknown_client(struct Client
*client_p
, struct Client
*source_p
, struct Client
*from
,
1422 const char *comment
)
1424 delete_auth_queries(source_p
);
1425 client_flush_input(source_p
);
1426 del_unknown_ip(source_p
);
1427 dlinkDelete(&source_p
->localClient
->tnode
, &unknown_list
);
1429 if(!IsIOError(source_p
))
1430 sendto_one(source_p
, "ERROR :Closing Link: %s (%s)",
1431 source_p
->user
!= NULL
? source_p
->host
: "127.0.0.1",
1434 close_connection(source_p
);
1436 if(has_id(source_p
))
1437 del_from_id_hash(source_p
->id
, source_p
);
1439 del_from_hostname_hash(source_p
->host
, source_p
);
1440 del_from_client_hash(source_p
->name
, source_p
);
1441 remove_client_from_list(source_p
);
1443 dlinkAddAlloc(source_p
, &dead_list
);
1445 /* Note that we don't need to add unknowns to the dead_list */
1446 return(CLIENT_EXITED
);
1450 exit_remote_server(struct Client
*client_p
, struct Client
*source_p
, struct Client
*from
,
1451 const char *comment
)
1453 static char comment1
[(HOSTLEN
*2)+2];
1454 static char newcomment
[BUFSIZE
];
1455 struct Client
*target_p
;
1457 if(ConfigServerHide
.flatten_links
)
1458 strcpy(comment1
, "*.net *.split");
1461 strcpy(comment1
, source_p
->servptr
->name
);
1462 strcat(comment1
, " ");
1463 strcat(comment1
, source_p
->name
);
1466 ircsnprintf(newcomment
, sizeof(newcomment
), "by %s: %s",
1467 from
->name
, comment
);
1469 if(source_p
->serv
!= NULL
)
1470 remove_dependents(client_p
, source_p
, from
, IsPerson(from
) ? newcomment
: comment
, comment1
);
1472 if(source_p
->servptr
&& source_p
->servptr
->serv
)
1473 dlinkDelete(&source_p
->lnode
, &source_p
->servptr
->serv
->servers
);
1477 dlinkFindDestroy(source_p
, &global_serv_list
);
1478 target_p
= source_p
->from
;
1480 if(target_p
!= NULL
&& IsServer(target_p
) && target_p
!= client_p
&&
1481 !IsMe(target_p
) && (source_p
->flags
& FLAGS_KILLED
) == 0)
1483 sendto_one(target_p
, ":%s SQUIT %s :%s",
1484 get_id(from
, target_p
), get_id(source_p
, target_p
),
1488 if(has_id(source_p
))
1489 del_from_id_hash(source_p
->id
, source_p
);
1491 del_from_client_hash(source_p
->name
, source_p
);
1492 remove_client_from_list(source_p
);
1493 scache_split(source_p
->serv
->nameinfo
);
1496 #ifdef DEBUG_EXITED_CLIENTS
1497 dlinkAddAlloc(source_p
, &dead_remote_list
);
1499 dlinkAddAlloc(source_p
, &dead_list
);
1505 qs_server(struct Client
*client_p
, struct Client
*source_p
, struct Client
*from
,
1506 const char *comment
)
1508 struct Client
*target_p
;
1510 if(source_p
->servptr
&& source_p
->servptr
->serv
)
1511 dlinkDelete(&source_p
->lnode
, &source_p
->servptr
->serv
->servers
);
1515 dlinkFindDestroy(source_p
, &global_serv_list
);
1516 target_p
= source_p
->from
;
1518 if(has_id(source_p
))
1519 del_from_id_hash(source_p
->id
, source_p
);
1521 del_from_client_hash(source_p
->name
, source_p
);
1522 remove_client_from_list(source_p
);
1525 dlinkAddAlloc(source_p
, &dead_list
);
1530 exit_local_server(struct Client
*client_p
, struct Client
*source_p
, struct Client
*from
,
1531 const char *comment
)
1533 static char comment1
[(HOSTLEN
*2)+2];
1534 static char newcomment
[BUFSIZE
];
1535 unsigned int sendk
, recvk
;
1537 dlinkDelete(&source_p
->localClient
->tnode
, &serv_list
);
1538 dlinkFindDestroy(source_p
, &global_serv_list
);
1540 unset_chcap_usage_counts(source_p
);
1541 sendk
= source_p
->localClient
->sendK
;
1542 recvk
= source_p
->localClient
->receiveK
;
1544 /* Always show source here, so the server notices show
1545 * which side initiated the split -- jilles
1547 ircsnprintf(newcomment
, sizeof(newcomment
), "by %s: %s",
1548 from
== source_p
? me
.name
: from
->name
, comment
);
1549 if (!IsIOError(source_p
))
1550 sendto_one(source_p
, "SQUIT %s :%s", use_id(source_p
),
1552 if(client_p
!= NULL
&& source_p
!= client_p
&& !IsIOError(source_p
))
1554 sendto_one(source_p
, "ERROR :Closing Link: 127.0.0.1 %s (%s)",
1555 source_p
->name
, comment
);
1558 if(source_p
->servptr
&& source_p
->servptr
->serv
)
1559 dlinkDelete(&source_p
->lnode
, &source_p
->servptr
->serv
->servers
);
1564 close_connection(source_p
);
1566 if(ConfigServerHide
.flatten_links
)
1567 strcpy(comment1
, "*.net *.split");
1570 strcpy(comment1
, source_p
->servptr
->name
);
1571 strcat(comment1
, " ");
1572 strcat(comment1
, source_p
->name
);
1575 if(source_p
->serv
!= NULL
)
1576 remove_dependents(client_p
, source_p
, from
, IsPerson(from
) ? newcomment
: comment
, comment1
);
1578 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "%s was connected"
1579 " for %ld seconds. %d/%d sendK/recvK.",
1580 source_p
->name
, CurrentTime
- source_p
->localClient
->firsttime
, sendk
, recvk
);
1582 ilog(L_SERVER
, "%s was connected for %ld seconds. %d/%d sendK/recvK.",
1583 source_p
->name
, CurrentTime
- source_p
->localClient
->firsttime
, sendk
, recvk
);
1585 if(has_id(source_p
))
1586 del_from_id_hash(source_p
->id
, source_p
);
1588 del_from_client_hash(source_p
->name
, source_p
);
1589 remove_client_from_list(source_p
);
1590 scache_split(source_p
->serv
->nameinfo
);
1593 dlinkAddAlloc(source_p
, &dead_list
);
1599 * This assumes IsPerson(source_p) == TRUE && MyConnect(source_p) == TRUE
1603 exit_local_client(struct Client
*client_p
, struct Client
*source_p
, struct Client
*from
,
1604 const char *comment
)
1606 unsigned long on_for
;
1608 exit_generic_client(client_p
, source_p
, from
, comment
);
1609 clear_monitor(source_p
);
1611 s_assert(IsPerson(source_p
));
1612 client_flush_input(source_p
);
1613 dlinkDelete(&source_p
->localClient
->tnode
, &lclient_list
);
1614 dlinkDelete(&source_p
->lnode
, &me
.serv
->users
);
1616 if(IsOper(source_p
))
1617 dlinkFindDestroy(source_p
, &local_oper_list
);
1619 sendto_realops_snomask(SNO_CCONN
, L_ALL
,
1620 "Client exiting: %s (%s@%s) [%s] [%s]",
1622 source_p
->username
, source_p
->host
, comment
,
1623 show_ip(NULL
, source_p
) ? source_p
->sockhost
: "255.255.255.255");
1625 sendto_realops_snomask(SNO_CCONNEXT
, L_ALL
,
1626 "CLIEXIT %s %s %s %s 0 %s",
1627 source_p
->name
, source_p
->username
, source_p
->host
,
1628 show_ip(NULL
, source_p
) ? source_p
->sockhost
: "255.255.255.255",
1631 on_for
= CurrentTime
- source_p
->localClient
->firsttime
;
1633 ilog(L_USER
, "%s (%3lu:%02lu:%02lu): %s!%s@%s %d/%d",
1634 myctime(CurrentTime
), on_for
/ 3600,
1635 (on_for
% 3600) / 60, on_for
% 60,
1636 source_p
->name
, source_p
->username
, source_p
->host
,
1637 source_p
->localClient
->sendK
, source_p
->localClient
->receiveK
);
1639 sendto_one(source_p
, "ERROR :Closing Link: %s (%s)", source_p
->host
, comment
);
1640 close_connection(source_p
);
1642 if((source_p
->flags
& FLAGS_KILLED
) == 0)
1644 sendto_server(client_p
, NULL
, CAP_TS6
, NOCAPS
,
1645 ":%s QUIT :%s", use_id(source_p
), comment
);
1646 sendto_server(client_p
, NULL
, NOCAPS
, CAP_TS6
,
1647 ":%s QUIT :%s", source_p
->name
, comment
);
1651 dlinkAddAlloc(source_p
, &dead_list
);
1652 return(CLIENT_EXITED
);
1657 ** exit_client - This is old "m_bye". Name changed, because this is not a
1658 ** protocol function, but a general server utility function.
1660 ** This function exits a client of *any* type (user, server, etc)
1661 ** from this server. Also, this generates all necessary prototol
1662 ** messages that this exit may cause.
1664 ** 1) If the client is a local client, then this implicitly
1665 ** exits all other clients depending on this connection (e.g.
1666 ** remote clients having 'from'-field that points to this.
1668 ** 2) If the client is a remote client, then only this is exited.
1670 ** For convenience, this function returns a suitable value for
1671 ** m_function return value:
1673 ** CLIENT_EXITED if (client_p == source_p)
1674 ** 0 if (client_p != source_p)
1677 exit_client(struct Client
*client_p
, /* The local client originating the
1678 * exit or NULL, if this exit is
1679 * generated by this server for
1681 * This will not get any of the
1682 * generated messages. */
1683 struct Client
*source_p
, /* Client exiting */
1684 struct Client
*from
, /* Client firing off this Exit,
1686 const char *comment
/* Reason for the exit */
1689 hook_data_client_exit hdata
;
1690 if(IsClosing(source_p
))
1693 /* note, this HAS to be here, when we exit a client we attempt to
1694 * send them data, if this generates a write error we must *not* add
1695 * them to the abort list --fl
1697 SetClosing(source_p
);
1699 hdata
.local_link
= client_p
;
1700 hdata
.target
= source_p
;
1702 hdata
.comment
= comment
;
1703 call_hook(h_client_exit
, &hdata
);
1705 if(MyConnect(source_p
))
1707 /* Local clients of various types */
1708 if(IsPerson(source_p
))
1709 return exit_local_client(client_p
, source_p
, from
, comment
);
1710 else if(IsServer(source_p
))
1711 return exit_local_server(client_p
, source_p
, from
, comment
);
1712 /* IsUnknown || IsConnecting || IsHandShake */
1713 else if(!IsReject(source_p
))
1714 return exit_unknown_client(client_p
, source_p
, from
, comment
);
1719 if(IsPerson(source_p
))
1720 return exit_remote_client(client_p
, source_p
, from
, comment
);
1721 else if(IsServer(source_p
))
1722 return exit_remote_server(client_p
, source_p
, from
, comment
);
1729 * Count up local client memory
1732 /* XXX one common Client list now */
1734 count_local_client_memory(size_t * count
, size_t * local_client_memory_used
)
1737 BlockHeapUsage(lclient_heap
, count
, NULL
, &lusage
);
1738 *local_client_memory_used
= lusage
+ (*count
* (sizeof(MemBlock
) + sizeof(struct Client
)));
1742 * Count up remote client memory
1745 count_remote_client_memory(size_t * count
, size_t * remote_client_memory_used
)
1747 size_t lcount
, rcount
;
1748 BlockHeapUsage(lclient_heap
, &lcount
, NULL
, NULL
);
1749 BlockHeapUsage(client_heap
, &rcount
, NULL
, NULL
);
1750 *count
= rcount
- lcount
;
1751 *remote_client_memory_used
= *count
* (sizeof(MemBlock
) + sizeof(struct Client
));
1756 * accept processing, this adds a form of "caller ID" to ircd
1758 * If a client puts themselves into "caller ID only" mode,
1759 * only clients that match a client pointer they have put on
1760 * the accept list will be allowed to message them.
1762 * [ source.on_allow_list ] -> [ target1 ] -> [ target2 ]
1764 * [target.allow_list] -> [ source1 ] -> [source2 ]
1766 * i.e. a target will have a link list of source pointers it will allow
1767 * each source client then has a back pointer pointing back
1768 * to the client that has it on its accept list.
1769 * This allows for exit_one_client to remove these now bogus entries
1770 * from any client having an accept on them.
1775 * inputs - pointer to exiting client
1777 * side effects - Walk through given clients allow_list and on_allow_list
1778 * remove all references to this client
1781 del_all_accepts(struct Client
*client_p
)
1784 dlink_node
*next_ptr
;
1785 struct Client
*target_p
;
1787 if(MyClient(client_p
) && client_p
->localClient
->allow_list
.head
)
1789 /* clear this clients accept list, and remove them from
1790 * everyones on_accept_list
1792 DLINK_FOREACH_SAFE(ptr
, next_ptr
, client_p
->localClient
->allow_list
.head
)
1794 target_p
= ptr
->data
;
1795 dlinkFindDestroy(client_p
, &target_p
->on_allow_list
);
1796 dlinkDestroy(ptr
, &client_p
->localClient
->allow_list
);
1800 /* remove this client from everyones accept list */
1801 DLINK_FOREACH_SAFE(ptr
, next_ptr
, client_p
->on_allow_list
.head
)
1803 target_p
= ptr
->data
;
1804 dlinkFindDestroy(client_p
, &target_p
->localClient
->allow_list
);
1805 dlinkDestroy(ptr
, &client_p
->on_allow_list
);
1810 * show_ip() - asks if the true IP shoudl be shown when source is
1811 * askin for info about target
1813 * Inputs - source_p who is asking
1814 * - target_p who do we want the info on
1815 * Output - returns 1 if clear IP can be showed, otherwise 0
1816 * Side Effects - none
1820 show_ip(struct Client
*source_p
, struct Client
*target_p
)
1822 if(IsAnyServer(target_p
))
1824 #ifndef HIDE_SERVERS_IPS
1825 if(source_p
== NULL
|| IsOper(source_p
))
1830 else if(IsIPSpoof(target_p
))
1832 /* source == NULL indicates message is being sent
1835 if(!ConfigFileEntry
.hide_spoof_ips
&&
1836 (source_p
== NULL
|| MyOper(source_p
)))
1840 else if(IsDynSpoof(target_p
) && (source_p
!= NULL
&& !IsOper(source_p
)))
1847 show_ip_conf(struct ConfItem
*aconf
, struct Client
*source_p
)
1849 if(IsConfDoSpoofIp(aconf
))
1851 if(!ConfigFileEntry
.hide_spoof_ips
&& MyOper(source_p
))
1866 * side effects - Creates a block heap for struct Users
1869 static BlockHeap
*user_heap
;
1873 user_heap
= BlockHeapCreate(sizeof(struct User
), USER_HEAP_SIZE
);
1881 * inputs - pointer to client struct
1882 * output - pointer to struct User
1883 * side effects - add's an User information block to a client
1884 * if it was not previously allocated.
1887 make_user(struct Client
*client_p
)
1891 user
= client_p
->user
;
1894 user
= (struct User
*) BlockHeapAlloc(user_heap
);
1896 client_p
->user
= user
;
1904 * inputs - pointer to client struct
1905 * output - pointer to server_t
1906 * side effects - add's an Server information block to a client
1907 * if it was not previously allocated.
1910 make_server(struct Client
*client_p
)
1912 server_t
*serv
= client_p
->serv
;
1916 serv
= (server_t
*) MyMalloc(sizeof(server_t
));
1917 client_p
->serv
= serv
;
1919 return client_p
->serv
;
1925 * inputs - pointer to user struct
1926 * - pointer to client struct
1928 * side effects - Decrease user reference count by one and release block,
1929 * if count reaches 0
1932 free_user(struct User
*user
, struct Client
*client_p
)
1934 if(--user
->refcnt
<= 0)
1937 MyFree((char *) user
->away
);
1941 if(user
->refcnt
< 0 || user
->invited
.head
|| user
->channel
.head
)
1943 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1944 "* %#lx user (%s!%s@%s) %#lx %#lx %#lx %lu %d *",
1945 (unsigned long) client_p
,
1946 client_p
? client_p
->
1950 (unsigned long) user
,
1951 (unsigned long) user
->invited
.head
,
1952 (unsigned long) user
->channel
.head
,
1953 dlink_list_length(&user
->channel
),
1955 s_assert(!user
->refcnt
);
1956 s_assert(!user
->invited
.head
);
1957 s_assert(!user
->channel
.head
);
1960 BlockHeapFree(user_heap
, user
);
1969 for(i
= 0; i
< 3; i
++)
1970 current_uid
[i
] = me
.id
[i
];
1972 for(i
= 3; i
< 9; i
++)
1973 current_uid
[i
] = 'A';
1975 current_uid
[9] = '\0';
1984 for(i
= 8; i
> 3; i
--)
1986 if(current_uid
[i
] == 'Z')
1988 current_uid
[i
] = '0';
1991 else if(current_uid
[i
] != '9')
1997 current_uid
[i
] = 'A';
2000 /* if this next if() triggers, we're fucked. */
2001 if(current_uid
[3] == 'Z')
2003 current_uid
[i
] = 'A';
2014 * Close the physical connection. This function must make
2015 * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
2018 close_connection(struct Client
*client_p
)
2020 s_assert(client_p
!= NULL
);
2021 if(client_p
== NULL
)
2024 s_assert(MyConnect(client_p
));
2025 if(!MyConnect(client_p
))
2028 if(IsServer(client_p
))
2030 struct server_conf
*server_p
;
2032 ServerStats
->is_sv
++;
2033 ServerStats
->is_sbs
+= client_p
->localClient
->sendB
;
2034 ServerStats
->is_sbr
+= client_p
->localClient
->receiveB
;
2035 ServerStats
->is_sks
+= client_p
->localClient
->sendK
;
2036 ServerStats
->is_skr
+= client_p
->localClient
->receiveK
;
2037 ServerStats
->is_sti
+= CurrentTime
- client_p
->localClient
->firsttime
;
2038 if(ServerStats
->is_sbs
> 2047)
2040 ServerStats
->is_sks
+= (ServerStats
->is_sbs
>> 10);
2041 ServerStats
->is_sbs
&= 0x3ff;
2043 if(ServerStats
->is_sbr
> 2047)
2045 ServerStats
->is_skr
+= (ServerStats
->is_sbr
>> 10);
2046 ServerStats
->is_sbr
&= 0x3ff;
2050 * If the connection has been up for a long amount of time, schedule
2051 * a 'quick' reconnect, else reset the next-connect cycle.
2053 if((server_p
= find_server_conf(client_p
->name
)) != NULL
)
2056 * Reschedule a faster reconnect, if this was a automatically
2057 * connected configuration entry. (Note that if we have had
2058 * a rehash in between, the status has been changed to
2059 * CONF_ILLEGAL). But only do this if it was a "good" link.
2061 server_p
->hold
= time(NULL
);
2063 (server_p
->hold
- client_p
->localClient
->lasttime
>
2064 HANGONGOODLINK
) ? HANGONRETRYDELAY
: ConFreq(server_p
->class);
2068 else if(IsClient(client_p
))
2070 ServerStats
->is_cl
++;
2071 ServerStats
->is_cbs
+= client_p
->localClient
->sendB
;
2072 ServerStats
->is_cbr
+= client_p
->localClient
->receiveB
;
2073 ServerStats
->is_cks
+= client_p
->localClient
->sendK
;
2074 ServerStats
->is_ckr
+= client_p
->localClient
->receiveK
;
2075 ServerStats
->is_cti
+= CurrentTime
- client_p
->localClient
->firsttime
;
2076 if(ServerStats
->is_cbs
> 2047)
2078 ServerStats
->is_cks
+= (ServerStats
->is_cbs
>> 10);
2079 ServerStats
->is_cbs
&= 0x3ff;
2081 if(ServerStats
->is_cbr
> 2047)
2083 ServerStats
->is_ckr
+= (ServerStats
->is_cbr
>> 10);
2084 ServerStats
->is_cbr
&= 0x3ff;
2088 ServerStats
->is_ni
++;
2090 if(-1 < client_p
->localClient
->fd
)
2092 /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
2093 if(!IsIOError(client_p
))
2094 send_queued_write(client_p
->localClient
->fd
, client_p
);
2096 comm_close(client_p
->localClient
->fd
);
2097 client_p
->localClient
->fd
= -1;
2100 if(-1 < client_p
->localClient
->ctrlfd
)
2102 comm_close(client_p
->localClient
->ctrlfd
);
2103 client_p
->localClient
->ctrlfd
= -1;
2106 linebuf_donebuf(&client_p
->localClient
->buf_sendq
);
2107 linebuf_donebuf(&client_p
->localClient
->buf_recvq
);
2108 detach_conf(client_p
);
2110 /* XXX shouldnt really be done here. */
2111 detach_server_conf(client_p
);
2113 client_p
->from
= NULL
; /* ...this should catch them! >:) --msa */
2114 ClearMyConnect(client_p
);
2115 SetIOError(client_p
);
2121 error_exit_client(struct Client
*client_p
, int error
)
2124 * ...hmm, with non-blocking sockets we might get
2125 * here from quite valid reasons, although.. why
2126 * would select report "data available" when there
2127 * wasn't... so, this must be an error anyway... --msa
2128 * actually, EOF occurs when read() returns 0 and
2129 * in due course, select() returns that fd as ready
2130 * for reading even though it ends up being an EOF. -avalon
2133 int current_error
= comm_get_sockerr(client_p
->localClient
->fd
);
2135 SetIOError(client_p
);
2137 if(IsServer(client_p
) || IsHandshake(client_p
))
2139 int connected
= CurrentTime
- client_p
->localClient
->firsttime
;
2143 sendto_realops_snomask(SNO_GENERAL
, is_remote_connect(client_p
) && !IsServer(client_p
) ? L_NETWIDE
: L_ALL
,
2144 "Server %s closed the connection",
2145 get_server_name(client_p
, SHOW_IP
));
2147 ilog(L_SERVER
, "Server %s closed the connection",
2148 log_client_name(client_p
, SHOW_IP
));
2152 sendto_realops_snomask(SNO_GENERAL
, is_remote_connect(client_p
) && !IsServer(client_p
) ? L_NETWIDE
: L_ALL
,
2153 "Lost connection to %s: %s",
2154 client_p
->name
, strerror(current_error
));
2155 ilog(L_SERVER
, "Lost connection to %s: %s",
2156 log_client_name(client_p
, SHOW_IP
), strerror(current_error
));
2159 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
2160 "%s had been connected for %d day%s, %2d:%02d:%02d",
2161 client_p
->name
, connected
/ 86400,
2162 (connected
/ 86400 == 1) ? "" : "s",
2163 (connected
% 86400) / 3600,
2164 (connected
% 3600) / 60, connected
% 60);
2168 strlcpy(errmsg
, "Remote host closed the connection", sizeof(errmsg
));
2170 ircsnprintf(errmsg
, sizeof(errmsg
), "Read error: %s", strerror(current_error
));
2172 exit_client(client_p
, client_p
, &me
, errmsg
);