ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/client.c
Revision: 8593
Committed: Sun Oct 21 18:11:04 2018 UTC (5 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 33572 byte(s)
Log Message:
- ipcache: rewrite to use patricia

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2018 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file client.c
23 * \brief Controls clients.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "client_svstag.h"
31 #include "event.h"
32 #include "hash.h"
33 #include "irc_string.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "auth.h"
37 #include "s_bsd.h"
38 #include "conf.h"
39 #include "conf_gecos.h"
40 #include "log.h"
41 #include "misc.h"
42 #include "server.h"
43 #include "send.h"
44 #include "whowas.h"
45 #include "user.h"
46 #include "memory.h"
47 #include "hostmask.h"
48 #include "listener.h"
49 #include "watch.h"
50 #include "rng_mt.h"
51 #include "parse.h"
52 #include "ipcache.h"
53
54
55 dlink_list listing_client_list;
56 dlink_list unknown_list;
57 dlink_list local_client_list;
58 dlink_list local_server_list;
59 dlink_list global_client_list;
60 dlink_list global_server_list;
61 dlink_list oper_list;
62
63 static dlink_list dead_list, abort_list;
64 static dlink_node *eac_next; /* next aborted client to exit */
65
66
67 /*
68 * client_make - create a new Client struct and set it to initial state.
69 *
70 * from == NULL, create local client (a client connected
71 * to a socket).
72 * WARNING: This leaves the client in a dangerous
73 * state where fd == -1, dead flag is not set and
74 * the client is on the unknown_list; therefore,
75 * the first thing to do after calling make_client(NULL)
76 * is setting fd to something reasonable. -adx
77 *
78 * from, create remote client (behind a socket
79 * associated with the client defined by
80 * 'from'). ('from' is a local client!!).
81 */
82 struct Client *
83 client_make(struct Client *from)
84 {
85 struct Client *client_p = xcalloc(sizeof(*client_p));
86
87 if (from)
88 client_p->from = from;
89 else
90 {
91 client_p->from = client_p; /* 'from' of local client is self! */
92 client_p->connection = xcalloc(sizeof(*client_p->connection));
93 client_p->connection->since = CurrentTime;
94 client_p->connection->lasttime = CurrentTime;
95 client_p->connection->firsttime = CurrentTime;
96 client_p->connection->registration = REG_INIT;
97
98 /* as good a place as any... */
99 dlinkAdd(client_p, &client_p->connection->lclient_node, &unknown_list);
100 }
101
102 client_p->idhnext = client_p;
103 client_p->hnext = client_p;
104 SetUnknown(client_p);
105 strcpy(client_p->username, "unknown");
106 strcpy(client_p->account, "*");
107
108 return client_p;
109 }
110
111 /*
112 * client_free
113 *
114 * inputs - pointer to client
115 * output - NONE
116 * side effects - client pointed to has its memory freed
117 */
118 static void
119 client_free(struct Client *client_p)
120 {
121 assert(!IsMe(client_p));
122 assert(client_p != &me);
123 assert(client_p->hnext == client_p);
124 assert(client_p->idhnext == client_p);
125
126 assert(client_p->node.prev == NULL);
127 assert(client_p->node.next == NULL);
128
129 assert(client_p->lnode.prev == NULL);
130 assert(client_p->lnode.next == NULL);
131
132 assert(dlink_list_length(&client_p->whowas_list) == 0);
133 assert(client_p->whowas_list.head == NULL);
134 assert(client_p->whowas_list.tail == NULL);
135
136 assert(dlink_list_length(&client_p->channel) == 0);
137 assert(client_p->channel.head == NULL);
138 assert(client_p->channel.tail == NULL);
139
140 assert(dlink_list_length(&client_p->svstags) == 0);
141 assert(client_p->svstags.head == NULL);
142 assert(client_p->svstags.tail == NULL);
143
144
145 xfree(client_p->serv);
146 xfree(client_p->certfp);
147
148 if (MyConnect(client_p))
149 {
150 assert(client_p->connection->lclient_node.prev == NULL);
151 assert(client_p->connection->lclient_node.next == NULL);
152
153 assert(client_p->connection->list_task == NULL);
154 assert(client_p->connection->auth == NULL);
155
156 assert(dlink_list_length(&client_p->connection->acceptlist) == 0);
157 assert(client_p->connection->acceptlist.head == NULL);
158 assert(client_p->connection->acceptlist.tail == NULL);
159
160
161 assert(dlink_list_length(&client_p->connection->watches) == 0);
162 assert(client_p->connection->watches.head == NULL);
163 assert(client_p->connection->watches.tail == NULL);
164
165 assert(dlink_list_length(&client_p->connection->confs) == 0);
166 assert(client_p->connection->confs.head == NULL);
167 assert(client_p->connection->confs.tail == NULL);
168
169 assert(dlink_list_length(&client_p->connection->invited) == 0);
170 assert(client_p->connection->invited.head == NULL);
171 assert(client_p->connection->invited.tail == NULL);
172
173 assert(client_p->connection->fd == NULL);
174
175 assert(HasFlag(client_p, FLAGS_CLOSING) && IsDead(client_p));
176
177 /*
178 * Clean up extra sockets from listen {} blocks which have been discarded.
179 */
180 if (client_p->connection->listener)
181 {
182 listener_release(client_p->connection->listener);
183 client_p->connection->listener = NULL;
184 }
185
186 dbuf_clear(&client_p->connection->buf_recvq);
187 dbuf_clear(&client_p->connection->buf_sendq);
188
189 xfree(client_p->connection);
190 client_p->connection = NULL;
191 }
192
193 xfree(client_p);
194 }
195
196 /* check_pings_list()
197 *
198 * inputs - pointer to list to check
199 * output - NONE
200 * side effects -
201 */
202 static void
203 check_pings_list(dlink_list *list)
204 {
205 char buf[32] = ""; /* 32 = sizeof("Ping timeout: 999999999 seconds") */
206 unsigned int ping = 0; /* ping time value from client */
207 dlink_node *node, *node_next;
208
209 DLINK_FOREACH_SAFE(node, node_next, list->head)
210 {
211 struct Client *client_p = node->data;
212
213 if (IsDead(client_p))
214 continue; /* Ignore it, it's been exited already */
215
216 if (IsClient(client_p) || IsServer(client_p))
217 ping = get_client_ping(&client_p->connection->confs);
218 else
219 ping = CONNECTTIMEOUT;
220
221 if (ping < CurrentTime - client_p->connection->lasttime)
222 {
223 if (!HasFlag(client_p, FLAGS_PINGSENT))
224 {
225 /*
226 * If we haven't PINGed the connection and we haven't
227 * heard from it in a while, PING it to make sure
228 * it is still alive.
229 */
230 AddFlag(client_p, FLAGS_PINGSENT);
231 client_p->connection->lasttime = CurrentTime - ping;
232 sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
233 }
234 else
235 {
236 if (CurrentTime - client_p->connection->lasttime >= 2 * ping)
237 {
238 /*
239 * If the client/server hasn't talked to us in 2*ping seconds
240 * and it has a ping time, then close its connection.
241 */
242 if (IsServer(client_p) || IsHandshake(client_p))
243 {
244 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
245 "No response from %s, closing link",
246 client_get_name(client_p, SHOW_IP));
247 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
248 "No response from %s, closing link",
249 client_get_name(client_p, MASK_IP));
250 ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
251 client_get_name(client_p, SHOW_IP));
252 }
253
254 snprintf(buf, sizeof(buf), "Ping timeout: %ji seconds",
255 (CurrentTime - client_p->connection->lasttime));
256 exit_client(client_p, buf);
257 }
258 }
259 }
260 }
261 }
262
263 /* check_unknowns_list()
264 *
265 * inputs - pointer to list of unknown clients
266 * output - NONE
267 * side effects - unknown clients get marked for termination after n seconds
268 */
269 static void
270 check_unknowns_list(void)
271 {
272 dlink_node *node, *node_next;
273
274 DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
275 {
276 struct Client *client_p = node->data;
277
278 /*
279 * Check UNKNOWN connections - if they have been in this state
280 * for > 30s, close them.
281 */
282 if (HasFlag(client_p, FLAGS_FINISHED_AUTH) && (CurrentTime - client_p->connection->firsttime) > 30)
283 exit_client(client_p, "Registration timed out");
284 }
285 }
286
287 /*
288 * check_pings - go through the local client list and check activity
289 * kill off stuff that should die
290 *
291 * inputs - NOT USED (from event)
292 * side effects -
293 *
294 *
295 * A PING can be sent to clients as necessary.
296 *
297 * Client/Server ping outs are handled.
298 */
299
300 /*
301 * Addon from adrian. We used to call this after nextping seconds,
302 * however I've changed it to run once a second. This is only for
303 * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
304 * run once a second makes life a lot easier - when a new client connects
305 * and they need a ping in 4 seconds, if nextping was set to 20 seconds
306 * we end up waiting 20 seconds. This is stupid. :-)
307 * I will optimise (hah!) check_pings() once I've finished working on
308 * tidying up other network IO evilnesses.
309 * -- adrian
310 */
311
312 static void
313 check_pings(void *unused)
314 {
315 check_pings_list(&local_client_list);
316 check_pings_list(&local_server_list);
317 check_unknowns_list();
318 }
319
320 /* check_conf_klines()
321 *
322 * inputs - NONE
323 * output - NONE
324 * side effects - Check all connections for a pending kline against the
325 * client, exit the client if a kline matches.
326 */
327 void
328 check_conf_klines(void)
329 {
330 dlink_node *node = NULL, *node_next = NULL;
331 const void *ptr;
332
333 DLINK_FOREACH_SAFE(node, node_next, local_client_list.head)
334 {
335 struct Client *client_p = node->data;
336
337 /* If a client is already being exited */
338 if (IsDead(client_p))
339 continue;
340
341 if ((ptr = find_conf_by_address(NULL, &client_p->ip, CONF_DLINE,
342 client_p->ip.ss.ss_family, NULL, NULL, 1)))
343 {
344 const struct MaskItem *conf = ptr;
345 conf_try_ban(client_p, CLIENT_BAN_DLINE, conf->reason);
346 continue; /* and go examine next Client */
347 }
348
349 if ((ptr = find_conf_by_address(client_p->host, &client_p->ip,
350 CONF_KLINE, client_p->ip.ss.ss_family,
351 client_p->username, NULL, 1)))
352 {
353 const struct MaskItem *conf = ptr;
354 conf_try_ban(client_p, CLIENT_BAN_KLINE, conf->reason);
355 continue; /* and go examine next Client */
356 }
357
358 if ((ptr = gecos_find(client_p->info, match)))
359 {
360 const struct GecosItem *conf = ptr;
361 conf_try_ban(client_p, CLIENT_BAN_XLINE, conf->reason);
362 continue; /* and go examine next Client */
363 }
364 }
365
366 /* Also check the unknowns list for new dlines */
367 DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
368 {
369 struct Client *client_p = node->data;
370
371 if ((ptr = find_conf_by_address(NULL, &client_p->ip, CONF_DLINE,
372 client_p->ip.ss.ss_family, NULL, NULL, 1)))
373 {
374 const struct MaskItem *conf = ptr;
375 conf_try_ban(client_p, CLIENT_BAN_DLINE, conf->reason);
376 continue; /* and go examine next Client */
377 }
378 }
379 }
380
381 /*
382 * conf_try_ban
383 *
384 * inputs - pointer to client to ban
385 * - pointer to MaskItem
386 * output - NONE
387 * side effects - given client_p is banned
388 */
389 void
390 conf_try_ban(struct Client *client_p, int type, const char *reason)
391 {
392 char ban_type = '?';
393
394 switch (type)
395 {
396 case CLIENT_BAN_KLINE:
397 if (HasFlag(client_p, FLAGS_EXEMPTKLINE))
398 {
399 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
400 "KLINE over-ruled for %s, client is kline_exempt",
401 client_get_name(client_p, HIDE_IP));
402 return;
403 }
404
405 ban_type = 'K';
406 break;
407 case CLIENT_BAN_DLINE:
408 if (find_conf_by_address(NULL, &client_p->ip, CONF_EXEMPT,
409 client_p->ip.ss.ss_family, NULL, NULL, 1))
410 return;
411 ban_type = 'D';
412 break;
413 case CLIENT_BAN_XLINE:
414 if (HasFlag(client_p, FLAGS_EXEMPTXLINE))
415 {
416 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
417 "XLINE over-ruled for %s, client is xline_exempt",
418 client_get_name(client_p, HIDE_IP));
419 return;
420 }
421
422 ban_type = 'X';
423 break;
424 default:
425 assert(0);
426 break;
427 }
428
429 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "%c-line active for %s",
430 ban_type, client_get_name(client_p, HIDE_IP));
431
432 if (IsClient(client_p))
433 sendto_one_numeric(client_p, &me, ERR_YOUREBANNEDCREEP, reason);
434
435 exit_client(client_p, reason);
436 }
437
438 /* find_person()
439 *
440 * inputs - pointer to name
441 * output - return client pointer
442 * side effects - find person by (nick)name
443 */
444 struct Client *
445 find_person(const struct Client *source_p, const char *name)
446 {
447 struct Client *target_p = NULL;
448
449 if (IsDigit(*name))
450 {
451 if (IsServer(source_p->from))
452 target_p = hash_find_id(name);
453 }
454 else
455 target_p = hash_find_client(name);
456
457 return (target_p && IsClient(target_p)) ? target_p : NULL;
458 }
459
460 /*
461 * find_chasing - find the client structure for a nick name (name)
462 * using history mechanism if necessary. If the client is not found,
463 * an error message (NO SUCH NICK) is generated.
464 */
465 struct Client *
466 find_chasing(struct Client *source_p, const char *name)
467 {
468 struct Client *target_p = find_person(source_p, name);
469
470 if (target_p)
471 return target_p;
472
473 if (IsDigit(*name))
474 return NULL;
475
476 target_p = whowas_get_history(name, ConfigGeneral.kill_chase_time_limit);
477 if (target_p == NULL)
478 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, name);
479
480 return target_p;
481 }
482
483 /*
484 * client_get_name - Return the name of the client
485 * for various tracking and
486 * admin purposes. The main purpose of this function is to
487 * return the "socket host" name of the client, if that
488 * differs from the advertised name (other than case).
489 * But, this can be used to any client structure.
490 *
491 * NOTE 1:
492 * Watch out the allocation of "buf", if either source_p->name
493 * or source_p->sockhost gets changed into pointers instead of
494 * directly allocated within the structure...
495 *
496 * NOTE 2:
497 * Function return either a pointer to the structure (source_p) or
498 * to internal buffer (buf). *NEVER* use the returned pointer
499 * to modify what it points!!!
500 */
501 const char *
502 client_get_name(const struct Client *client_p, enum addr_mask_type type)
503 {
504 static char buf[HOSTLEN * 2 + USERLEN + 4]; /* +4 for [,@,],\0 */
505
506 if (!MyConnect(client_p))
507 return client_p->name;
508
509 if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
510 {
511 if (irccmp(client_p->name, client_p->host) == 0)
512 return client_p->name;
513 else if (ConfigServerHide.hide_server_ips)
514 type = MASK_IP;
515 }
516
517 /* And finally, let's get the host information, ip or name */
518 switch (type)
519 {
520 case SHOW_IP:
521 snprintf(buf, sizeof(buf), "%s[%s@%s]",
522 client_p->name,
523 client_p->username, client_p->sockhost);
524 break;
525 case MASK_IP:
526 if (client_p->ip.ss.ss_family == AF_INET)
527 snprintf(buf, sizeof(buf), "%s[%s@255.255.255.255]",
528 client_p->name, client_p->username);
529 else
530 snprintf(buf, sizeof(buf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
531 client_p->name, client_p->username);
532 break;
533 default: /* HIDE_IP */
534 snprintf(buf, sizeof(buf), "%s[%s@%s]",
535 client_p->name,
536 client_p->username, client_p->host);
537 }
538
539 return buf;
540 }
541
542 void
543 free_exited_clients(void)
544 {
545 dlink_node *node, *node_next;
546
547 DLINK_FOREACH_SAFE(node, node_next, dead_list.head)
548 {
549 client_free(node->data);
550 dlinkDelete(node, &dead_list);
551 free_dlink_node(node);
552 }
553 }
554
555 /*
556 * client_close_connection
557 * Close the physical connection. This function must make
558 * MyConnect(client_p) == FALSE, and set client_p->from == NULL.
559 */
560 static void
561 client_close_connection(struct Client *client_p)
562 {
563 assert(client_p);
564
565 if (!IsDead(client_p))
566 {
567 /* Attempt to flush any pending dbufs. Evil, but .. -- adrian */
568 /*
569 * There is still a chance that we might send data to this socket
570 * even if it is marked as blocked (COMM_SELECT_READ handler is called
571 * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
572 */
573 DelFlag(client_p, FLAGS_BLOCKED);
574 send_queued_write(client_p);
575 }
576
577 if (IsClient(client_p))
578 {
579 ++ServerStats.is_cl;
580 ServerStats.is_cbs += client_p->connection->send.bytes;
581 ServerStats.is_cbr += client_p->connection->recv.bytes;
582 ServerStats.is_cti += CurrentTime - client_p->connection->firsttime;
583 }
584 else if (IsServer(client_p))
585 {
586 dlink_node *node;
587
588 ++ServerStats.is_sv;
589 ServerStats.is_sbs += client_p->connection->send.bytes;
590 ServerStats.is_sbr += client_p->connection->recv.bytes;
591 ServerStats.is_sti += CurrentTime - client_p->connection->firsttime;
592
593 DLINK_FOREACH(node, connect_items.head)
594 {
595 struct MaskItem *conf = node->data;
596
597 if (irccmp(conf->name, client_p->name))
598 continue;
599
600 /*
601 * Reset next-connect cycle of all connect{} blocks that match
602 * this servername.
603 */
604 conf->until = CurrentTime + conf->class->con_freq;
605 }
606 }
607 else
608 ++ServerStats.is_ni;
609
610 if (tls_isusing(&client_p->connection->fd->ssl))
611 tls_shutdown(&client_p->connection->fd->ssl);
612
613 if (client_p->connection->fd)
614 {
615 fd_close(client_p->connection->fd);
616 client_p->connection->fd = NULL;
617 }
618
619 dbuf_clear(&client_p->connection->buf_sendq);
620 dbuf_clear(&client_p->connection->buf_recvq);
621
622 xfree(client_p->connection->password);
623 client_p->connection->password = NULL;
624
625 conf_detach(client_p, CONF_CLIENT | CONF_OPER | CONF_SERVER);
626 }
627
628 /*
629 * Exit one client, local or remote. Assuming all dependents have
630 * been already removed, and socket closed for local client.
631 *
632 * The only messages generated are QUITs on channels.
633 */
634 static void
635 exit_one_client(struct Client *source_p, const char *comment)
636 {
637 dlink_node *node, *node_next;
638
639 assert(!IsMe(source_p));
640 assert(source_p != &me);
641
642 if (IsClient(source_p))
643 {
644 if (HasUMode(source_p, UMODE_OPER))
645 --Count.oper;
646 if (HasUMode(source_p, UMODE_INVISIBLE))
647 --Count.invisi;
648
649 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
650 dlinkDelete(&source_p->node, &global_client_list);
651
652 /*
653 * If a person is on a channel, send a QUIT notice
654 * to every client (person) on the same channel (so
655 * that the client can show the "**signoff" message).
656 * (Note: The notice is to the local clients *only*)
657 */
658 sendto_common_channels_local(source_p, 0, 0, 0, ":%s!%s@%s QUIT :%s",
659 source_p->name, source_p->username,
660 source_p->host, comment);
661
662 DLINK_FOREACH_SAFE(node, node_next, source_p->channel.head)
663 remove_user_from_channel(node->data);
664
665 svstag_clear_list(&source_p->svstags);
666
667 whowas_add_history(source_p, 0);
668 whowas_off_history(source_p);
669
670 watch_check_hash(source_p, RPL_LOGOFF);
671 }
672 else if (IsServer(source_p))
673 {
674 sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
675 "Server %s split from %s",
676 source_p->name, source_p->servptr->name);
677
678 dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
679 dlinkDelete(&source_p->node, &global_server_list);
680 }
681
682 /* Remove source_p from the client lists */
683 if (source_p->id[0])
684 hash_del_id(source_p);
685
686 if (source_p->name[0])
687 hash_del_client(source_p);
688
689 if (HasFlag(source_p, FLAGS_IPHASH))
690 {
691 DelFlag(source_p, FLAGS_IPHASH);
692 ipcache_record_remove(&source_p->ip, MyConnect(source_p));
693 }
694
695 /* Check to see if the client isn't already on the dead list */
696 assert(dlinkFind(&dead_list, source_p) == NULL);
697
698 /* Add to dead client dlist */
699 SetDead(source_p);
700 dlinkAdd(source_p, make_dlink_node(), &dead_list);
701 }
702
703 /*
704 * Remove all clients that depend on source_p; assumes all (S)QUITs have
705 * already been sent. we make sure to exit a server's dependent clients
706 * and servers before the server itself; exit_one_client takes care of
707 * actually removing things off llists. tweaked from +CSr31 -orabidoo
708 */
709 static void
710 recurse_remove_clients(struct Client *source_p, const char *comment)
711 {
712 dlink_node *node, *node_next;
713
714 DLINK_FOREACH_SAFE(node, node_next, source_p->serv->client_list.head)
715 exit_one_client(node->data, comment);
716
717 DLINK_FOREACH_SAFE(node, node_next, source_p->serv->server_list.head)
718 {
719 recurse_remove_clients(node->data, comment);
720 exit_one_client(node->data, comment);
721 }
722 }
723
724 /*
725 * exit_client - exit a client of any type. Generally, you can use
726 * this on any struct Client, regardless of its state.
727 *
728 * Note, you shouldn't exit remote _users_ without first doing
729 * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
730 *
731 * However, it is perfectly correct to call exit_client to force a _server_
732 * quit (either local or remote one).
733 *
734 *
735 * inputs: - a client pointer that is going to be exited
736 * output: none
737 * side effects: the client is delinked from all lists, disconnected,
738 * and the rest of IRC network is notified of the exit.
739 * Client memory is scheduled to be freed
740 */
741 void
742 exit_client(struct Client *source_p, const char *comment)
743 {
744 assert(!IsMe(source_p));
745 assert(source_p != &me);
746
747 if (MyConnect(source_p))
748 {
749 /*
750 * DO NOT REMOVE. exit_client can be called twice after a failed read/write.
751 */
752 if (HasFlag(source_p, FLAGS_CLOSING))
753 return;
754
755 AddFlag(source_p, FLAGS_CLOSING);
756
757 if (source_p->connection->auth)
758 {
759 auth_delete(source_p->connection->auth);
760 source_p->connection->auth = NULL;
761 }
762
763 if (IsClient(source_p))
764 {
765 dlink_node *node;
766
767 if (HasUMode(source_p, UMODE_OPER))
768 if ((node = dlinkFindDelete(&oper_list, source_p)))
769 free_dlink_node(node);
770
771 assert(dlinkFind(&local_client_list, source_p));
772 dlinkDelete(&source_p->connection->lclient_node, &local_client_list);
773
774 if (source_p->connection->list_task)
775 free_list_task(source_p);
776
777 clear_invite_list(&source_p->connection->invited);
778 del_all_accepts(source_p);
779 watch_del_watch_list(source_p);
780
781 sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
782 "Client exiting: %s (%s@%s) [%s] [%s]",
783 source_p->name, source_p->username, source_p->realhost,
784 source_p->sockhost, comment);
785
786 ilog(LOG_TYPE_USER, "%s (%ju): %s!%s@%s %s %s %ju/%ju :%s",
787 date_ctime(source_p->connection->firsttime),
788 CurrentTime - source_p->connection->firsttime,
789 source_p->name, source_p->username, source_p->host,
790 source_p->sockhost, source_p->account,
791 source_p->connection->send.bytes >> 10,
792 source_p->connection->recv.bytes >> 10, source_p->info);
793 }
794 else if (IsServer(source_p))
795 {
796 assert(dlinkFind(&local_server_list, source_p));
797 dlinkDelete(&source_p->connection->lclient_node, &local_server_list);
798 }
799 else
800 {
801 assert(dlinkFind(&unknown_list, source_p));
802 dlinkDelete(&source_p->connection->lclient_node, &unknown_list);
803 }
804
805 if (!IsDead(source_p))
806 {
807 if (IsServer(source_p))
808 {
809 if (!HasFlag(source_p, FLAGS_SQUIT))
810 {
811 /* For them, we are exiting the network */
812 sendto_one(source_p, ":%s SQUIT %s :%s",
813 me.id, me.id, comment);
814 }
815 }
816
817 sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
818 source_p->host, comment);
819 }
820
821 client_close_connection(source_p);
822 }
823 else if (IsClient(source_p) && HasFlag(source_p->servptr, FLAGS_EOB))
824 sendto_realops_flags(UMODE_FARCONNECT, L_ALL, SEND_NOTICE,
825 "Client exiting at %s: %s (%s@%s) [%s] [%s]",
826 source_p->servptr->name, source_p->name,
827 source_p->username, source_p->realhost, source_p->sockhost, comment);
828
829 if (IsServer(source_p))
830 {
831 char splitstr[HOSTLEN + HOSTLEN + 2] = "";
832
833 assert(source_p->serv);
834 assert(source_p->servptr);
835
836 if (ConfigServerHide.hide_servers)
837 /*
838 * Set netsplit message to "*.net *.split" to still show that it's a split,
839 * but hide the servers splitting.
840 */
841 strlcpy(splitstr, "*.net *.split", sizeof(splitstr));
842 else
843 snprintf(splitstr, sizeof(splitstr), "%s %s",
844 source_p->servptr->name, source_p->name);
845
846 /* Send SQUIT for source_p in every direction. source_p is already off of local_server_list here */
847 if (!HasFlag(source_p, FLAGS_SQUIT))
848 sendto_server(NULL, 0, 0, "SQUIT %s :%s", source_p->id, comment);
849
850 /* Now exit the clients internally */
851 recurse_remove_clients(source_p, splitstr);
852
853 if (MyConnect(source_p))
854 {
855 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
856 "%s was connected for %s. %ju/%ju sendK/recvK.",
857 source_p->name, time_dissect(CurrentTime - source_p->connection->firsttime),
858 source_p->connection->send.bytes >> 10,
859 source_p->connection->recv.bytes >> 10);
860 ilog(LOG_TYPE_IRCD, "%s was connected for %s. %ju/%ju sendK/recvK.",
861 source_p->name, time_dissect(CurrentTime - source_p->connection->firsttime),
862 source_p->connection->send.bytes >> 10,
863 source_p->connection->recv.bytes >> 10);
864 }
865 }
866 else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
867 sendto_server(source_p->from, 0, 0, ":%s QUIT :%s", source_p->id, comment);
868
869 /* The client *better* be off all of the lists */
870 assert(dlinkFind(&unknown_list, source_p) == NULL);
871 assert(dlinkFind(&local_client_list, source_p) == NULL);
872 assert(dlinkFind(&local_server_list, source_p) == NULL);
873 assert(dlinkFind(&oper_list, source_p) == NULL);
874 assert(dlinkFind(&listing_client_list, source_p) == NULL);
875
876 exit_one_client(source_p, comment);
877 }
878
879 /*
880 * dead_link_on_write - report a write error if not already dead,
881 * mark it as dead then exit it
882 */
883 void
884 dead_link_on_write(struct Client *client_p, int ierrno)
885 {
886 dlink_node *node;
887
888 if (IsDefunct(client_p))
889 return;
890
891 dbuf_clear(&client_p->connection->buf_recvq);
892 dbuf_clear(&client_p->connection->buf_sendq);
893
894 assert(dlinkFind(&abort_list, client_p) == NULL);
895 node = make_dlink_node();
896 /* don't let exit_aborted_clients() finish yet */
897 dlinkAddTail(client_p, node, &abort_list);
898
899 if (eac_next == NULL)
900 eac_next = node;
901
902 SetDead(client_p); /* You are dead my friend */
903 }
904
905 /*
906 * dead_link_on_read - report a read error if not already dead,
907 * mark it as dead then exit it
908 */
909 void
910 dead_link_on_read(struct Client *client_p, int error)
911 {
912 char errmsg[IRCD_BUFSIZE];
913 int current_error;
914
915 if (IsDefunct(client_p))
916 return;
917
918 dbuf_clear(&client_p->connection->buf_recvq);
919 dbuf_clear(&client_p->connection->buf_sendq);
920
921 current_error = comm_get_sockerr(client_p->connection->fd->fd);
922
923 if (IsServer(client_p) || IsHandshake(client_p))
924 {
925 if (error == 0)
926 {
927 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
928 "Server %s closed the connection",
929 client_get_name(client_p, SHOW_IP));
930 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
931 "Server %s closed the connection",
932 client_get_name(client_p, MASK_IP));
933 ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
934 client_get_name(client_p, SHOW_IP));
935 }
936 else
937 {
938 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
939 "Lost connection to %s: %s",
940 client_get_name(client_p, SHOW_IP), strerror(current_error));
941 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
942 "Lost connection to %s: %s",
943 client_get_name(client_p, MASK_IP), strerror(current_error));
944 ilog(LOG_TYPE_IRCD, "Lost connection to %s: %s",
945 client_get_name(client_p, SHOW_IP), strerror(current_error));
946 }
947
948 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
949 "%s was connected for %s",
950 client_p->name, time_dissect(CurrentTime - client_p->connection->firsttime));
951 }
952
953 if (error == 0)
954 strlcpy(errmsg, "Remote host closed the connection",
955 sizeof(errmsg));
956 else
957 snprintf(errmsg, sizeof(errmsg), "Read error: %s",
958 strerror(current_error));
959
960 exit_client(client_p, errmsg);
961 }
962
963 void
964 exit_aborted_clients(void)
965 {
966 dlink_node *ptr;
967 struct Client *target_p;
968 const char *notice;
969
970 DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head)
971 {
972 target_p = ptr->data;
973 eac_next = ptr->next;
974
975 dlinkDelete(ptr, &abort_list);
976 free_dlink_node(ptr);
977
978 if (target_p == NULL)
979 {
980 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
981 "Warning: null client on abort_list!");
982 continue;
983 }
984
985 if (HasFlag(target_p, FLAGS_SENDQEX))
986 notice = "Max SendQ exceeded";
987 else
988 notice = "Write error: connection closed";
989
990 exit_client(target_p, notice);
991 }
992 }
993
994 /*
995 * accept processing, this adds a form of "caller ID" to ircd
996 *
997 * If a client puts themselves into "caller ID only" mode,
998 * only clients that match a client pointer they have put on
999 * the accept list will be allowed to message them.
1000 *
1001 * Diane Bruce, "Dianora" db@db.net
1002 */
1003
1004 void
1005 del_accept(struct split_nuh_item *accept_p, struct Client *client_p)
1006 {
1007 dlinkDelete(&accept_p->node, &client_p->connection->acceptlist);
1008
1009 xfree(accept_p->nickptr);
1010 xfree(accept_p->userptr);
1011 xfree(accept_p->hostptr);
1012 xfree(accept_p);
1013 }
1014
1015 struct split_nuh_item *
1016 find_accept(const char *nick, const char *user,
1017 const char *host, struct Client *client_p,
1018 int (*compare)(const char *, const char *))
1019 {
1020 dlink_node *node;
1021
1022 DLINK_FOREACH(node, client_p->connection->acceptlist.head)
1023 {
1024 struct split_nuh_item *accept_p = node->data;
1025
1026 if (compare(accept_p->nickptr, nick) == 0 &&
1027 compare(accept_p->userptr, user) == 0 &&
1028 compare(accept_p->hostptr, host) == 0)
1029 return accept_p;
1030 }
1031
1032 return NULL;
1033 }
1034
1035 /* accept_message()
1036 *
1037 * inputs - pointer to source client
1038 * - pointer to target client
1039 * output - 1 if accept this message 0 if not
1040 * side effects - See if source is on target's allow list
1041 */
1042 int
1043 accept_message(struct Client *source,
1044 struct Client *target)
1045 {
1046 dlink_node *node;
1047
1048 if (HasFlag(source, FLAGS_SERVICE) ||
1049 (HasUMode(source, UMODE_OPER) && ConfigGeneral.opers_bypass_callerid))
1050 return 1;
1051
1052 if (source == target || find_accept(source->name, source->username,
1053 source->host, target, match))
1054 return 1;
1055
1056 if (!HasUMode(target, UMODE_CALLERID) && HasUMode(target, UMODE_SOFTCALLERID))
1057 DLINK_FOREACH(node, target->channel.head)
1058 if (IsMember(source, ((struct Membership *)node->data)->chptr))
1059 return 1;
1060
1061 return 0;
1062 }
1063
1064 /* del_all_accepts()
1065 *
1066 * inputs - pointer to exiting client
1067 * output - NONE
1068 * side effects - Walk through given clients acceptlist and remove all entries
1069 */
1070 void
1071 del_all_accepts(struct Client *client_p)
1072 {
1073 dlink_node *node, *node_next;
1074
1075 DLINK_FOREACH_SAFE(node, node_next, client_p->connection->acceptlist.head)
1076 del_accept(node->data, client_p);
1077 }
1078
1079 unsigned int
1080 client_get_idle_time(const struct Client *source_p,
1081 const struct Client *target_p)
1082 {
1083 unsigned int idle = 0;
1084 const struct ClassItem *const class = class_get_ptr(&target_p->connection->confs);
1085
1086 if (!(class->flags & CLASS_FLAGS_FAKE_IDLE) || target_p == source_p)
1087 return CurrentTime - target_p->connection->last_privmsg;
1088
1089 if (HasUMode(source_p, UMODE_OPER) &&
1090 !(class->flags & CLASS_FLAGS_HIDE_IDLE_FROM_OPERS))
1091 return CurrentTime - target_p->connection->last_privmsg;
1092
1093 const unsigned int min_idle = class->min_idle;
1094 const unsigned int max_idle = class->max_idle;
1095
1096 if (min_idle == max_idle)
1097 return min_idle;
1098
1099 if (class->flags & CLASS_FLAGS_RANDOM_IDLE)
1100 idle = genrand_int32();
1101 else
1102 idle = CurrentTime - target_p->connection->last_privmsg;
1103
1104 if (max_idle)
1105 idle %= max_idle;
1106 else
1107 idle = 0;
1108
1109 if (idle < min_idle)
1110 idle = min_idle + (idle % (max_idle - min_idle));
1111
1112 return idle;
1113 }
1114
1115 /* client_init()
1116 *
1117 * inputs - NONE
1118 * output - NONE
1119 * side effects - initialize client free memory
1120 */
1121 void
1122 client_init(void)
1123 {
1124 static struct event event_ping =
1125 {
1126 .name = "check_pings",
1127 .handler = check_pings,
1128 .when = 5
1129 };
1130
1131 event_add(&event_ping, NULL);
1132 }

Properties

Name Value
svn:eol-style native
svn:keywords Id