ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/client.c
(Generate patch)

Comparing ircd-hybrid/trunk/src/client.c (file contents):
Revision 1667 by michael, Sun Nov 18 21:54:30 2012 UTC vs.
Revision 8399 by michael, Sun Mar 18 14:43:15 2018 UTC

# Line 1 | Line 1
1   /*
2 < *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 < *  client.c: Controls clients.
2 > *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (C) 2002 by the past and present ircd coders, and others.
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
# Line 16 | Line 15
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 > *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19   *  USA
20 < *
21 < *  $Id$
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"
28 #include "channel_mode.h"
30   #include "event.h"
30 #include "fdlist.h"
31   #include "hash.h"
32   #include "irc_string.h"
33   #include "ircd.h"
34 #include "s_gline.h"
34   #include "numeric.h"
35 < #include "packet.h"
37 < #include "s_auth.h"
35 > #include "auth.h"
36   #include "s_bsd.h"
37   #include "conf.h"
38 + #include "conf_gecos.h"
39   #include "log.h"
40 < #include "s_misc.h"
41 < #include "s_serv.h"
40 > #include "misc.h"
41 > #include "server.h"
42   #include "send.h"
43   #include "whowas.h"
44 < #include "s_user.h"
46 < #include "dbuf.h"
44 > #include "user.h"
45   #include "memory.h"
48 #include "mempool.h"
46   #include "hostmask.h"
47   #include "listener.h"
51 #include "irc_res.h"
48   #include "userhost.h"
49   #include "watch.h"
50 + #include "rng_mt.h"
51 + #include "parse.h"
52 + #include "ipcache.h"
53  
55 dlink_list listing_client_list = { NULL, NULL, 0 };
56 /* Pointer to beginning of Client list */
57 dlink_list global_client_list = {NULL, NULL, 0};
58 /* unknown/client pointer lists */
59 dlink_list unknown_list = {NULL, NULL, 0};
60 dlink_list local_client_list = {NULL, NULL, 0};
61 dlink_list serv_list = {NULL, NULL, 0};
62 dlink_list global_serv_list = {NULL, NULL, 0};
63 dlink_list oper_list = {NULL, NULL, 0};
64
65 static EVH check_pings;
66
67 static mp_pool_t *client_pool  = NULL;
68 static mp_pool_t *lclient_pool = NULL;
54  
55 < static dlink_list dead_list  = { NULL, NULL, 0};
56 < static dlink_list abort_list = { NULL, NULL, 0};
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  
75 static void check_pings_list(dlink_list *);
76 static void check_unknowns_list(void);
77 static void ban_them(struct Client *, struct MaskItem *);
78
79
80 /* init_client()
81 *
82 * inputs       - NONE
83 * output       - NONE
84 * side effects - initialize client free memory
85 */
86 void
87 init_client(void)
88 {
89  /* start off the check ping event ..  -- adrian
90   * Every 30 seconds is plenty -- db
91   */
92  client_pool = mp_pool_new(sizeof(struct Client), MP_CHUNK_SIZE_CLIENT);
93  lclient_pool = mp_pool_new(sizeof(struct LocalUser), MP_CHUNK_SIZE_LCLIENT);
94  eventAdd("check_pings", check_pings, NULL, 5);
95 }
66  
67   /*
68   * make_client - create a new Client struct and set it to initial state.
# Line 110 | Line 80 | init_client(void)
80   *                      'from'). ('from' is a local client!!).
81   */
82   struct Client *
83 < make_client(struct Client *from)
83 > client_make(struct Client *from)
84   {
85 <  struct Client *client_p = mp_pool_get(client_pool);
85 >  struct Client *const client_p = xcalloc(sizeof(*client_p));
86  
87 <  memset(client_p, 0, sizeof(*client_p));
88 <
89 <  if (from == NULL)
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->localClient               = mp_pool_get(lclient_pool);
93 <
94 <    memset(client_p->localClient, 0, sizeof(*client_p->localClient));
95 <
96 <    client_p->localClient->since        = CurrentTime;
127 <    client_p->localClient->lasttime     = CurrentTime;
128 <    client_p->localClient->firsttime    = CurrentTime;
129 <    client_p->localClient->registration = REG_INIT;
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->localClient->lclient_node, &unknown_list);
99 >    dlinkAdd(client_p, &client_p->connection->lclient_node, &unknown_list);
100    }
134  else
135    client_p->from = from; /* 'from' of local client is self! */
101  
102    client_p->idhnext = client_p;
103 <  client_p->hnext  = client_p;
104 <  client_p->status = STAT_UNKNOWN;
103 >  client_p->hnext = client_p;
104 >  SetUnknown(client_p);
105    strcpy(client_p->username, "unknown");
106 <  strcpy(client_p->svid, "0");
106 >  strcpy(client_p->account, "*");
107  
108    return client_p;
109   }
110  
111   /*
112 < * free_client
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 < free_client(struct Client *client_p)
119 > client_free(struct Client *client_p)
120   {
121 <  assert(client_p != NULL);
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 <  assert(client_p->channel.head == NULL);
125 >
126 >  assert(client_p->node.data == NULL);
127 >  assert(client_p->node.prev == NULL);
128 >  assert(client_p->node.next == NULL);
129 >
130 >  assert(client_p->lnode.data == NULL);
131 >  assert(client_p->lnode.prev == NULL);
132 >  assert(client_p->lnode.next == NULL);
133 >
134 >  assert(dlink_list_length(&client_p->whowas_list) == 0);
135 >  assert(client_p->whowas_list.head == NULL);
136 >  assert(client_p->whowas_list.tail == NULL);
137 >
138    assert(dlink_list_length(&client_p->channel) == 0);
139 <  assert(dlink_list_length(&client_p->whowas) == 0);
140 <  assert(!IsServer(client_p) || (IsServer(client_p) && client_p->serv));
139 >  assert(client_p->channel.head == NULL);
140 >  assert(client_p->channel.tail == NULL);
141 >
142 >  assert(dlink_list_length(&client_p->svstags) == 0);
143 >  assert(client_p->svstags.head == NULL);
144 >  assert(client_p->svstags.tail == NULL);
145  
146 <  MyFree(client_p->serv);
146 >
147 >  xfree(client_p->serv);
148 >  xfree(client_p->certfp);
149  
150    if (MyConnect(client_p))
151    {
152 <    assert(client_p->localClient->invited.head == NULL);
153 <    assert(dlink_list_length(&client_p->localClient->invited) == 0);
154 <    assert(dlink_list_length(&client_p->localClient->watches) == 0);
155 <    assert(IsClosing(client_p) && IsDead(client_p));
152 >    assert(client_p->connection->lclient_node.data == NULL);
153 >    assert(client_p->connection->lclient_node.prev == NULL);
154 >    assert(client_p->connection->lclient_node.next == NULL);
155 >
156 >    assert(client_p->connection->list_task == NULL);
157 >    assert(client_p->connection->auth == NULL);
158 >
159 >    assert(dlink_list_length(&client_p->connection->acceptlist) == 0);
160 >    assert(client_p->connection->acceptlist.head == NULL);
161 >    assert(client_p->connection->acceptlist.tail == NULL);
162 >
163 >
164 >    assert(dlink_list_length(&client_p->connection->watches) == 0);
165 >    assert(client_p->connection->watches.head == NULL);
166 >    assert(client_p->connection->watches.tail == NULL);
167 >
168 >    assert(dlink_list_length(&client_p->connection->confs) == 0);
169 >    assert(client_p->connection->confs.head == NULL);
170 >    assert(client_p->connection->confs.tail == NULL);
171 >
172 >    assert(dlink_list_length(&client_p->connection->invited) == 0);
173 >    assert(client_p->connection->invited.head == NULL);
174 >    assert(client_p->connection->invited.tail == NULL);
175  
176 <    MyFree(client_p->localClient->response);
177 <    MyFree(client_p->localClient->auth_oper);
176 >    assert(client_p->connection->fd == NULL);
177 >
178 >    assert(HasFlag(client_p, FLAGS_CLOSING) && IsDead(client_p));
179  
180      /*
181 <     * clean up extra sockets from P-lines which have been discarded.
181 >     * Clean up extra sockets from listen {} blocks which have been discarded.
182       */
183 <    if (client_p->localClient->listener)
183 >    if (client_p->connection->listener)
184      {
185 <      assert(0 < client_p->localClient->listener->ref_count);
186 <      if (0 == --client_p->localClient->listener->ref_count &&
184 <          !client_p->localClient->listener->active)
185 <        free_listener(client_p->localClient->listener);
185 >      listener_release(client_p->connection->listener);
186 >      client_p->connection->listener = NULL;
187      }
188  
189 <    dbuf_clear(&client_p->localClient->buf_recvq);
190 <    dbuf_clear(&client_p->localClient->buf_sendq);
189 >    dbuf_clear(&client_p->connection->buf_recvq);
190 >    dbuf_clear(&client_p->connection->buf_sendq);
191  
192 <    mp_pool_release(client_p->localClient);
192 >    xfree(client_p->connection);
193 >    client_p->connection = NULL;
194    }
195  
196 <  mp_pool_release(client_p);
196 >  xfree(client_p);
197   }
198  
199 < /*
200 < * check_pings - go through the local client list and check activity
201 < * kill off stuff that should die
202 < *
203 < * inputs       - NOT USED (from event)
204 < * output       - next time_t when check_pings() should be called again
205 < * side effects -
204 < *
205 < *
206 < * A PING can be sent to clients as necessary.
207 < *
208 < * Client/Server ping outs are handled.
209 < */
199 > static void
200 > svstag_free(struct ServicesTag *svstag, dlink_list *list)
201 > {
202 >  dlinkDelete(&svstag->node, list);
203 >  xfree(svstag->tag);
204 >  xfree(svstag);
205 > }
206  
207 < /*
208 < * Addon from adrian. We used to call this after nextping seconds,
209 < * however I've changed it to run once a second. This is only for
210 < * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
215 < * run once a second makes life a lot easier - when a new client connects
216 < * and they need a ping in 4 seconds, if nextping was set to 20 seconds
217 < * we end up waiting 20 seconds. This is stupid. :-)
218 < * I will optimise (hah!) check_pings() once I've finished working on
219 < * tidying up other network IO evilnesses.
220 < *     -- adrian
221 < */
207 > void
208 > client_detach_svstag(dlink_list *list, unsigned int numeric)
209 > {
210 >  dlink_node *node, *node_next;
211  
212 < static void
213 < check_pings(void *notused)
214 < {              
215 <  check_pings_list(&local_client_list);
216 <  check_pings_list(&serv_list);
217 <  check_unknowns_list();
212 >  DLINK_FOREACH_SAFE(node, node_next, list->head)
213 >  {
214 >    struct ServicesTag *svstag = node->data;
215 >
216 >    if (svstag->numeric == numeric)
217 >      svstag_free(svstag, list);
218 >  }
219 > }
220 >
221 > void
222 > client_attach_svstag(dlink_list *list, unsigned int numeric,
223 >                     const char *umodes, const char *tag)
224 > {
225 >  const struct user_modes *tab = NULL;
226 >
227 >  if (numeric >= ERR_LAST_ERR_MSG || *umodes != '+')
228 >    return;
229 >
230 >  struct ServicesTag *svstag = xcalloc(sizeof(*svstag));
231 >  svstag->numeric = numeric;
232 >  svstag->tag = xstrdup(tag);
233 >
234 >  for (const char *m = umodes + 1; *m; ++m)
235 >    if ((tab = umode_map[(unsigned char)*m]))
236 >      svstag->umodes |= tab->flag;
237 >
238 >  if (numeric != RPL_WHOISOPERATOR)
239 >    dlinkAddTail(svstag, &svstag->node, list);
240 >  else
241 >    dlinkAdd(svstag, &svstag->node, list);
242 > }
243 >
244 > void
245 > client_clear_svstags(dlink_list *list)
246 > {
247 >  while (list->head)
248 >    svstag_free(list->head->data, list);
249   }
250  
251   /* check_pings_list()
252   *
253   * inputs       - pointer to list to check
254   * output       - NONE
255 < * side effects -
255 > * side effects -
256   */
257   static void
258   check_pings_list(dlink_list *list)
259   {
260 <  char scratch[32];        /* way too generous but... */
261 <  int ping = 0;      /* ping time value from client */
262 <  dlink_node *ptr = NULL, *next_ptr = NULL;
260 >  char buf[32] = "";  /* 32 = sizeof("Ping timeout: 999999999 seconds") */
261 >  unsigned int ping = 0;      /* ping time value from client */
262 >  dlink_node *node = NULL, *node_next = NULL;
263  
264 <  DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
264 >  DLINK_FOREACH_SAFE(node, node_next, list->head)
265    {
266 <    struct Client *client_p = ptr->data;
266 >    struct Client *client_p = node->data;
267  
248    /*
249    ** Note: No need to notify opers here. It's
250    ** already done when "FLAGS_DEADSOCKET" is set.
251    */
268      if (IsDead(client_p))
269 <    {
254 <      /* Ignore it, its been exited already */
255 <      continue;
256 <    }
269 >      continue;  /* Ignore it, its been exited already */
270  
271 <    if (!IsRegistered(client_p))
272 <      ping = CONNECTTIMEOUT;
271 >    if (IsClient(client_p) || IsServer(client_p))
272 >      ping = get_client_ping(&client_p->connection->confs);
273      else
274 <      ping = get_client_ping(&client_p->localClient->confs);
274 >      ping = CONNECTTIMEOUT;
275  
276 <    if (ping < CurrentTime - client_p->localClient->lasttime)
276 >    if (ping < CurrentTime - client_p->connection->lasttime)
277      {
278 <      if (!IsPingSent(client_p))
278 >      if (!HasFlag(client_p, FLAGS_PINGSENT))
279        {
280 <        /*
281 <         * if we havent PINGed the connection and we havent
282 <         * heard from it in a while, PING it to make sure
283 <         * it is still alive.
284 <         */
285 <        SetPingSent(client_p);
286 <        client_p->localClient->lasttime = CurrentTime - ping;
287 <        sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
280 >        /*
281 >         * If we haven't PINGed the connection and we haven't
282 >         * heard from it in a while, PING it to make sure
283 >         * it is still alive.
284 >         */
285 >        AddFlag(client_p, FLAGS_PINGSENT);
286 >        client_p->connection->lasttime = CurrentTime - ping;
287 >        sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
288        }
289        else
290        {
291 <        if (CurrentTime - client_p->localClient->lasttime >= 2 * ping)
291 >        if (CurrentTime - client_p->connection->lasttime >= 2 * ping)
292          {
293            /*
294             * If the client/server hasn't talked to us in 2*ping seconds
295             * and it has a ping time, then close its connection.
296             */
297            if (IsServer(client_p) || IsHandshake(client_p))
298 <          {
299 <            sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
300 <                                 "No response from %s, closing link",
301 <                                 get_client_name(client_p, HIDE_IP));
302 <            sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
303 <                                 "No response from %s, closing link",
304 <                                 get_client_name(client_p, MASK_IP));
305 <            ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
306 <                 get_client_name(client_p, HIDE_IP));
307 <          }
308 <
309 <          snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds",
310 <                   (int)(CurrentTime - client_p->localClient->lasttime));
311 <          exit_client(client_p, &me, scratch);
298 >          {
299 >            sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
300 >                                 "No response from %s, closing link",
301 >                                 client_get_name(client_p, SHOW_IP));
302 >            sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
303 >                                 "No response from %s, closing link",
304 >                                 client_get_name(client_p, MASK_IP));
305 >            ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
306 >                 client_get_name(client_p, SHOW_IP));
307 >          }
308 >
309 >          snprintf(buf, sizeof(buf), "Ping timeout: %ji seconds",
310 >                   (CurrentTime - client_p->connection->lasttime));
311 >          exit_client(client_p, buf);
312          }
313        }
314      }
# Line 311 | Line 324 | check_pings_list(dlink_list *list)
324   static void
325   check_unknowns_list(void)
326   {
327 <  dlink_node *ptr, *next_ptr;
327 >  dlink_node *node = NULL, *node_next = NULL;
328  
329 <  DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
329 >  DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
330    {
331 <    struct Client *client_p = ptr->data;
331 >    struct Client *client_p = node->data;
332  
333      /*
334       * Check UNKNOWN connections - if they have been in this state
335       * for > 30s, close them.
336       */
337 <    if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30)
338 <      exit_client(client_p, &me, "Registration timed out");
337 >    if (HasFlag(client_p, FLAGS_FINISHED_AUTH) && (CurrentTime - client_p->connection->firsttime) > 30)
338 >      exit_client(client_p, "Registration timed out");
339    }
340   }
341  
342 + /*
343 + * check_pings - go through the local client list and check activity
344 + * kill off stuff that should die
345 + *
346 + * inputs       - NOT USED (from event)
347 + * side effects -
348 + *
349 + *
350 + * A PING can be sent to clients as necessary.
351 + *
352 + * Client/Server ping outs are handled.
353 + */
354 +
355 + /*
356 + * Addon from adrian. We used to call this after nextping seconds,
357 + * however I've changed it to run once a second. This is only for
358 + * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
359 + * run once a second makes life a lot easier - when a new client connects
360 + * and they need a ping in 4 seconds, if nextping was set to 20 seconds
361 + * we end up waiting 20 seconds. This is stupid. :-)
362 + * I will optimise (hah!) check_pings() once I've finished working on
363 + * tidying up other network IO evilnesses.
364 + *     -- adrian
365 + */
366 +
367 + static void
368 + check_pings(void *unused)
369 + {
370 +  check_pings_list(&local_client_list);
371 +  check_pings_list(&local_server_list);
372 +  check_unknowns_list();
373 + }
374 +
375   /* check_conf_klines()
376   *
377   * inputs       - NONE
# Line 333 | Line 379 | check_unknowns_list(void)
379   * side effects - Check all connections for a pending kline against the
380   *                client, exit the client if a kline matches.
381   */
382 < void
382 > void
383   check_conf_klines(void)
384 < {              
385 <  struct Client *client_p = NULL;       /* current local client_p being examined */
386 <  struct MaskItem *conf = NULL;
341 <  dlink_node *ptr, *next_ptr;
384 > {
385 >  dlink_node *node = NULL, *node_next = NULL;
386 >  const void *ptr;
387  
388 <  DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
388 >  DLINK_FOREACH_SAFE(node, node_next, local_client_list.head)
389    {
390 <    client_p = ptr->data;
390 >    struct Client *client_p = node->data;
391  
392 <    /* If a client is already being exited
393 <     */
349 <    if (IsDead(client_p) || !IsClient(client_p))
392 >    /* If a client is already being exited */
393 >    if (IsDead(client_p))
394        continue;
395  
396 <    if ((conf = find_dline_conf(&client_p->localClient->ip,
397 <                                  client_p->localClient->aftype)) != NULL)
396 >    if ((ptr = find_conf_by_address(NULL, &client_p->connection->ip, CONF_DLINE,
397 >                                    client_p->connection->aftype, NULL, NULL, 1)))
398      {
399 <      if (conf->type == CONF_EXEMPT)
400 <        continue;
401 <
358 <      ban_them(client_p, conf);
359 <      continue; /* and go examine next fd/client_p */
399 >      const struct MaskItem *conf = ptr;
400 >      conf_try_ban(client_p, CLIENT_BAN_DLINE, conf->reason);
401 >      continue;  /* and go examine next Client */
402      }
403  
404 <    if (ConfigFileEntry.glines && (conf = find_gline(client_p)))
404 >    if ((ptr = find_conf_by_address(client_p->host, &client_p->connection->ip,
405 >                                    CONF_KLINE, client_p->connection->aftype,
406 >                                    client_p->username, NULL, 1)))
407      {
408 <      if (IsExemptKline(client_p) ||
409 <          IsExemptGline(client_p))
410 <      {
367 <        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
368 <                             "GLINE over-ruled for %s, client is %sline_exempt",
369 <                             get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
370 <        continue;
371 <      }
372 <
373 <      ban_them(client_p, conf);
374 <      /* and go examine next fd/client_p */    
375 <      continue;
376 <    }
377 <
378 <    if ((conf = find_kill(client_p)) != NULL)
379 <    {
380 <      if (IsExemptKline(client_p))
381 <      {
382 <        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
383 <                             "KLINE over-ruled for %s, client is kline_exempt",
384 <                             get_client_name(client_p, HIDE_IP));
385 <        continue;
386 <      }
387 <
388 <      ban_them(client_p, conf);
389 <      continue;
408 >      const struct MaskItem *conf = ptr;
409 >      conf_try_ban(client_p, CLIENT_BAN_KLINE, conf->reason);
410 >      continue;  /* and go examine next Client */
411      }
412  
413 <    if ((conf = find_matching_name_conf(CONF_XLINE,  client_p->info,
393 <                                        NULL, NULL, 0)) != NULL ||
394 <        (conf = find_matching_name_conf(CONF_RXLINE, client_p->info,
395 <                                        NULL, NULL, 0)) != NULL)
413 >    if ((ptr = gecos_find(client_p->info, match)))
414      {
415 <      ban_them(client_p, conf);
416 <      continue;
415 >      const struct GecosItem *conf = ptr;
416 >      conf_try_ban(client_p, CLIENT_BAN_XLINE, conf->reason);
417 >      continue;  /* and go examine next Client */
418      }
419    }
420  
421 <  /* also check the unknowns list for new dlines */
422 <  DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
421 >  /* Also check the unknowns list for new dlines */
422 >  DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
423    {
424 <    client_p = ptr->data;
424 >    struct Client *client_p = node->data;
425  
426 <    if ((conf = find_dline_conf(&client_p->localClient->ip,
427 <                                 client_p->localClient->aftype)))
426 >    if ((ptr = find_conf_by_address(NULL, &client_p->connection->ip, CONF_DLINE,
427 >                                    client_p->connection->aftype, NULL, NULL, 1)))
428      {
429 <      if (conf->type == CONF_EXEMPT)
430 <        continue;
431 <
413 <      exit_client(client_p, &me, "D-lined");
429 >      const struct MaskItem *conf = ptr;
430 >      conf_try_ban(client_p, CLIENT_BAN_DLINE, conf->reason);
431 >      continue;  /* and go examine next Client */
432      }
433    }
434   }
435  
436   /*
437 < * ban_them
437 > * conf_try_ban
438   *
439   * inputs       - pointer to client to ban
440   *              - pointer to MaskItem
441   * output       - NONE
442   * side effects - given client_p is banned
443   */
444 < static void
445 < ban_them(struct Client *client_p, struct MaskItem *conf)
444 > void
445 > conf_try_ban(struct Client *client_p, int type, const char *reason)
446   {
447 <  const char *user_reason = NULL;       /* What is sent to user */
448 <  const char *type_string = NULL;
449 <  const char dline_string[] = "D-line";
450 <  const char kline_string[] = "K-line";
451 <  const char gline_string[] = "G-line";
452 <  const char xline_string[] = "X-line";
453 <
454 <  switch (conf->type)
455 <  {
456 <    case CONF_RKLINE:
457 <    case CONF_KLINE:
458 <      type_string = kline_string;
459 <      break;
460 <    case CONF_DLINE:
443 <      type_string = dline_string;
447 >  char ban_type = '?';
448 >
449 >  switch (type)
450 >  {
451 >    case CLIENT_BAN_KLINE:
452 >      if (HasFlag(client_p, FLAGS_EXEMPTKLINE))
453 >      {
454 >        sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
455 >                             "KLINE over-ruled for %s, client is kline_exempt",
456 >                             client_get_name(client_p, HIDE_IP));
457 >        return;
458 >      }
459 >
460 >      ban_type = 'K';
461        break;
462 <    case CONF_GLINE:
463 <      type_string = gline_string;
462 >    case CLIENT_BAN_DLINE:
463 >      if (find_conf_by_address(NULL, &client_p->connection->ip, CONF_EXEMPT,
464 >                               client_p->connection->aftype, NULL, NULL, 1))
465 >        return;
466 >      ban_type = 'D';
467        break;
468 <    case CONF_RXLINE:
469 <    case CONF_XLINE:
470 <      type_string = xline_string;
471 <      ++conf->count;
468 >    case CLIENT_BAN_XLINE:
469 >      if (HasFlag(client_p, FLAGS_EXEMPTXLINE))
470 >      {
471 >        sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
472 >                             "XLINE over-ruled for %s, client is xline_exempt",
473 >                             client_get_name(client_p, HIDE_IP));
474 >        return;
475 >      }
476 >
477 >      ban_type = 'X';
478        break;
479      default:
480        assert(0);
481        break;
482    }
483  
484 <  user_reason = conf->reason ? conf->reason : type_string;
485 <
460 <  sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s active for %s",
461 <                       type_string, get_client_name(client_p, HIDE_IP));
484 >  sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "%c-line active for %s",
485 >                       ban_type, client_get_name(client_p, HIDE_IP));
486  
487    if (IsClient(client_p))
488 <    sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
465 <               me.name, client_p->name, user_reason);
488 >    sendto_one_numeric(client_p, &me, ERR_YOUREBANNEDCREEP, reason);
489  
490 <  exit_client(client_p, &me, user_reason);
468 < }
469 <
470 < /* update_client_exit_stats()
471 < *
472 < * input        - pointer to client
473 < * output       - NONE
474 < * side effects -
475 < */
476 < static void
477 < update_client_exit_stats(struct Client *client_p)
478 < {
479 <  if (IsClient(client_p))
480 <  {
481 <    assert(Count.total > 0);
482 <    --Count.total;
483 <    if (HasUMode(client_p, UMODE_OPER))
484 <      --Count.oper;
485 <    if (HasUMode(client_p, UMODE_INVISIBLE))
486 <      --Count.invisi;
487 <  }
488 <  else if (IsServer(client_p))
489 <    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
490 <                         "Server %s split from %s",
491 <                         client_p->name, client_p->servptr->name);
492 <
493 <  if (splitchecking && !splitmode)
494 <    check_splitmode(NULL);
490 >  exit_client(client_p, reason);
491   }
492  
493   /* find_person()
# Line 501 | Line 497 | update_client_exit_stats(struct Client *
497   * side effects - find person by (nick)name
498   */
499   struct Client *
500 < find_person(const struct Client *client_p, const char *name)
500 > find_person(const struct Client *source_p, const char *name)
501   {
502 <  struct Client *c2ptr = NULL;
502 >  struct Client *target_p = NULL;
503  
504    if (IsDigit(*name))
505    {
506 <    if ((c2ptr = hash_find_id(name)) != NULL)
507 <    {
512 <      /* invisible users shall not be found by UID guessing */
513 <      if (HasUMode(c2ptr, UMODE_INVISIBLE))
514 <        if (!IsServer(client_p) && !HasFlag(client_p, FLAGS_SERVICE))
515 <          c2ptr = NULL;
516 <    }
506 >    if (IsServer(source_p->from))
507 >      target_p = hash_find_id(name);
508    }
509    else
510 <    c2ptr = hash_find_client(name);
510 >    target_p = hash_find_client(name);
511  
512 <  return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : NULL);
512 >  return (target_p && IsClient(target_p)) ? target_p : NULL;
513   }
514  
515   /*
516 < * find_chasing - find the client structure for a nick name (user)
517 < *      using history mechanism if necessary. If the client is not found,
518 < *      an error message (NO SUCH NICK) is generated. If the client was found
528 < *      through the history, chasing will be 1 and otherwise 0.
516 > * find_chasing - find the client structure for a nick name (name)
517 > *      using history mechanism if necessary. If the client is not found,
518 > *      an error message (NO SUCH NICK) is generated.
519   */
520   struct Client *
521 < find_chasing(struct Client *client_p, struct Client *source_p, const char *user, int *chasing)
521 > find_chasing(struct Client *source_p, const char *name)
522   {
523 <  struct Client *who = find_person(client_p, user);
534 <
535 <  if (chasing)
536 <    *chasing = 0;
523 >  struct Client *target_p = find_person(source_p, name);
524  
525 <  if (who)
526 <    return who;
525 >  if (target_p)
526 >    return target_p;
527  
528 <  if (IsDigit(*user))
542 <    return NULL;
543 <
544 <  if ((who = get_history(user,
545 <                        (time_t)ConfigFileEntry.kill_chase_time_limit))
546 <                         == NULL)
547 <  {
548 <    sendto_one(source_p, form_str(ERR_NOSUCHNICK),
549 <               me.name, source_p->name, user);
528 >  if (IsDigit(*name))
529      return NULL;
551  }
530  
531 <  if (chasing)
532 <    *chasing = 1;
531 >  target_p = whowas_get_history(name, ConfigGeneral.kill_chase_time_limit);
532 >  if (!target_p)
533 >    sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, name);
534  
535 <  return who;
535 >  return target_p;
536   }
537  
538   /*
539 < * get_client_name -  Return the name of the client
539 > * client_get_name -  Return the name of the client
540   *    for various tracking and
541   *      admin purposes. The main purpose of this function is to
542   *      return the "socket host" name of the client, if that
# Line 565 | Line 544 | find_chasing(struct Client *client_p, st
544   *        But, this can be used to any client structure.
545   *
546   * NOTE 1:
547 < *        Watch out the allocation of "nbuf", if either source_p->name
547 > *        Watch out the allocation of "buf", if either source_p->name
548   *        or source_p->sockhost gets changed into pointers instead of
549   *        directly allocated within the structure...
550   *
551   * NOTE 2:
552   *        Function return either a pointer to the structure (source_p) or
553 < *        to internal buffer (nbuf). *NEVER* use the returned pointer
553 > *        to internal buffer (buf). *NEVER* use the returned pointer
554   *        to modify what it points!!!
555   */
556   const char *
557 < get_client_name(const struct Client *client, enum addr_mask_type type)
557 > client_get_name(const struct Client *client_p, enum addr_mask_type type)
558   {
559 <  static char nbuf[HOSTLEN * 2 + USERLEN + 5];
559 >  static char buf[HOSTLEN * 2 + USERLEN + 4];  /* +4 for [,@,],\0 */
560  
561 <  assert(client != NULL);
561 >  if (!MyConnect(client_p))
562 >    return client_p->name;
563  
564 <  if (!MyConnect(client))
585 <    return client->name;
586 <
587 <  if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
564 >  if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
565    {
566 <    if (!irccmp(client->name, client->host))
567 <      return client->name;
566 >    if (!irccmp(client_p->name, client_p->host))
567 >      return client_p->name;
568      else if (ConfigServerHide.hide_server_ips)
569        type = MASK_IP;
570    }
571  
595  if (ConfigFileEntry.hide_spoof_ips)
596    if (type == SHOW_IP && IsIPSpoof(client))
597      type = MASK_IP;
598
572    /* And finally, let's get the host information, ip or name */
573    switch (type)
574    {
575      case SHOW_IP:
576 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
577 <               client->name,
578 <               client->username, client->sockhost);
576 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
577 >               client_p->name,
578 >               client_p->username, client_p->sockhost);
579        break;
580      case MASK_IP:
581 <      if (client->localClient->aftype == AF_INET)
582 <        snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
583 <                 client->name, client->username);
581 >      if (client_p->connection->aftype == AF_INET)
582 >        snprintf(buf, sizeof(buf), "%s[%s@255.255.255.255]",
583 >                 client_p->name, client_p->username);
584        else
585 <        snprintf(nbuf, sizeof(nbuf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
586 <                 client->name, client->username);
585 >        snprintf(buf, sizeof(buf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
586 >                 client_p->name, client_p->username);
587        break;
588 <    default:
589 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
590 <               client->name,
591 <               client->username, client->host);
588 >    default:  /* HIDE_IP */
589 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
590 >               client_p->name,
591 >               client_p->username, client_p->host);
592    }
593  
594 <  return nbuf;
594 >  return buf;
595   }
596  
597   void
598   free_exited_clients(void)
599   {
600 <  dlink_node *ptr = NULL, *next = NULL;
601 <  
602 <  DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
600 >  dlink_node *node, *node_next;
601 >
602 >  DLINK_FOREACH_SAFE(node, node_next, dead_list.head)
603    {
604 <    free_client(ptr->data);
605 <    dlinkDelete(ptr, &dead_list);
606 <    free_dlink_node(ptr);
604 >    client_free(node->data);
605 >    dlinkDelete(node, &dead_list);
606 >    free_dlink_node(node);
607    }
608   }
609  
610   /*
611 + * client_close_connection
612 + *        Close the physical connection. This function must make
613 + *        MyConnect(client_p) == FALSE, and set client_p->from == NULL.
614 + */
615 + static void
616 + client_close_connection(struct Client *client_p)
617 + {
618 +  assert(client_p);
619 +
620 +  if (!IsDead(client_p))
621 +  {
622 +    /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
623 +    /* there is still a chance that we might send data to this socket
624 +     * even if it is marked as blocked (COMM_SELECT_READ handler is called
625 +     * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
626 +     */
627 +    DelFlag(client_p, FLAGS_BLOCKED);
628 +    send_queued_write(client_p);
629 +  }
630 +
631 +  if (IsClient(client_p))
632 +  {
633 +    ++ServerStats.is_cl;
634 +    ServerStats.is_cbs += client_p->connection->send.bytes;
635 +    ServerStats.is_cbr += client_p->connection->recv.bytes;
636 +    ServerStats.is_cti += CurrentTime - client_p->connection->firsttime;
637 +  }
638 +  else if (IsServer(client_p))
639 +  {
640 +    dlink_node *node = NULL;
641 +
642 +    ++ServerStats.is_sv;
643 +    ServerStats.is_sbs += client_p->connection->send.bytes;
644 +    ServerStats.is_sbr += client_p->connection->recv.bytes;
645 +    ServerStats.is_sti += CurrentTime - client_p->connection->firsttime;
646 +
647 +    DLINK_FOREACH(node, connect_items.head)
648 +    {
649 +      struct MaskItem *conf = node->data;
650 +
651 +      if (irccmp(conf->name, client_p->name))
652 +        continue;
653 +
654 +      /*
655 +       * Reset next-connect cycle of all connect{} blocks that match
656 +       * this servername.
657 +       */
658 +      conf->until = CurrentTime + conf->class->con_freq;
659 +    }
660 +  }
661 +  else
662 +    ++ServerStats.is_ni;
663 +
664 +  if (tls_isusing(&client_p->connection->fd->ssl))
665 +    tls_shutdown(&client_p->connection->fd->ssl);
666 +
667 +  if (client_p->connection->fd)
668 +  {
669 +    fd_close(client_p->connection->fd);
670 +    client_p->connection->fd = NULL;
671 +  }
672 +
673 +  dbuf_clear(&client_p->connection->buf_sendq);
674 +  dbuf_clear(&client_p->connection->buf_recvq);
675 +
676 +  xfree(client_p->connection->password);
677 +  client_p->connection->password = NULL;
678 +
679 +  conf_detach(client_p, CONF_CLIENT | CONF_OPER | CONF_SERVER);
680 + }
681 +
682 + /*
683   * Exit one client, local or remote. Assuming all dependents have
684   * been already removed, and socket closed for local client.
685   *
686   * The only messages generated are QUITs on channels.
687   */
688   static void
689 < exit_one_client(struct Client *source_p, const char *quitmsg)
689 > exit_one_client(struct Client *source_p, const char *comment)
690   {
691 <  dlink_node *lp = NULL, *next_lp = NULL;
691 >  dlink_node *node, *node_next;
692  
693    assert(!IsMe(source_p));
694 +  assert(source_p != &me);
695  
696    if (IsClient(source_p))
697    {
698 <    if (source_p->servptr->serv != NULL)
699 <      dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
698 >    if (HasUMode(source_p, UMODE_OPER))
699 >      --Count.oper;
700 >    if (HasUMode(source_p, UMODE_INVISIBLE))
701 >      --Count.invisi;
702 >
703 >    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
704 >    dlinkDelete(&source_p->node, &global_client_list);
705  
706      /*
707       * If a person is on a channel, send a QUIT notice
# Line 658 | Line 709 | exit_one_client(struct Client *source_p,
709       * that the client can show the "**signoff" message).
710       * (Note: The notice is to the local clients *only*)
711       */
712 <    sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s",
712 >    sendto_common_channels_local(source_p, 0, 0, 0, ":%s!%s@%s QUIT :%s",
713                                   source_p->name, source_p->username,
714 <                                 source_p->host, quitmsg);
664 <    DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
665 <      remove_user_from_channel(lp->data);
714 >                                 source_p->host, comment);
715  
716 <    add_history(source_p, 0);
717 <    off_history(source_p);
716 >    DLINK_FOREACH_SAFE(node, node_next, source_p->channel.head)
717 >      remove_user_from_channel(node->data);
718  
719 <    watch_check_hash(source_p, RPL_LOGOFF);
719 >    client_clear_svstags(&source_p->svstags);
720  
721 <    if (MyConnect(source_p))
722 <    {
674 <      /* Clean up invitefield */
675 <      DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head)
676 <        del_invite(lp->data, source_p);
721 >    whowas_add_history(source_p, 0);
722 >    whowas_off_history(source_p);
723  
724 <      del_all_accepts(source_p);
679 <    }
724 >    watch_check_hash(source_p, RPL_LOGOFF);
725    }
726    else if (IsServer(source_p))
727    {
728 <    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
728 >    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
729 >                         "Server %s split from %s",
730 >                         source_p->name, source_p->servptr->name);
731  
732 <    if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
733 <      free_dlink_node(lp);
732 >    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
733 >    dlinkDelete(&source_p->node, &global_server_list);
734    }
735  
736    /* Remove source_p from the client lists */
737 <  if (HasID(source_p))
737 >  if (source_p->id[0])
738      hash_del_id(source_p);
739 +
740    if (source_p->name[0])
741      hash_del_client(source_p);
742  
743 <  if (IsUserHostIp(source_p))
744 <    delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
697 <
698 <  /* remove from global client list
699 <   * NOTE: source_p->node.next cannot be NULL if the client is added
700 <   *       to global_client_list (there is always &me at its end)
701 <   */
702 <  if (source_p != NULL && source_p->node.next != NULL)
703 <    dlinkDelete(&source_p->node, &global_client_list);
704 <
705 <  update_client_exit_stats(source_p);
743 >  if (HasFlag(source_p, FLAGS_USERHOST))
744 >    userhost_del(source_p->sockhost, !MyConnect(source_p));
745  
746    /* Check to see if the client isn't already on the dead list */
747    assert(dlinkFind(&dead_list, source_p) == NULL);
# Line 712 | Line 751 | exit_one_client(struct Client *source_p,
751    dlinkAdd(source_p, make_dlink_node(), &dead_list);
752   }
753  
754 < /* Recursively send QUITs and SQUITs for source_p and all its dependent clients
716 < * and servers to those servers that need them.  A server needs the client
717 < * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
718 < * isn't getting the SQUIT because of @#(*&@)# hostmasking.  With TS4, once
719 < * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
720 < * on that one -orabidoo
721 < *
722 < * This is now called on each local server -adx
723 < */
724 < static void
725 < recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
726 <                   struct Client *from, struct Client *to, const char *comment,
727 <                   const char *splitstr)
728 < {
729 <  dlink_node *ptr, *next;
730 <  struct Client *target_p;
731 <
732 <  assert(to != source_p);  /* should be already removed from serv_list */
733 <
734 <  /* If this server can handle quit storm (QS) removal
735 <   * of dependents, just send the SQUIT
736 <   */
737 <  if (!IsCapable(to, CAP_QS))
738 <    DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
739 <    {
740 <      target_p = ptr->data;
741 <      sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
742 <    }
743 <
744 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
745 <    recurse_send_quits(original_source_p, ptr->data, from, to,
746 <                       comment, splitstr);
747 <
748 <  if ((source_p == original_source_p && to != from) ||
749 <                  !IsCapable(to, CAP_QS))
750 <  {
751 <    /* don't use a prefix here - we have to be 100% sure the message
752 <     * will be accepted without Unknown prefix etc.. */
753 <    sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment);
754 <  }
755 < }
756 <
757 < /*
754 > /*
755   * Remove all clients that depend on source_p; assumes all (S)QUITs have
756 < * already been sent.  we make sure to exit a server's dependent clients
757 < * and servers before the server itself; exit_one_client takes care of
756 > * already been sent.  we make sure to exit a server's dependent clients
757 > * and servers before the server itself; exit_one_client takes care of
758   * actually removing things off llists.   tweaked from +CSr31  -orabidoo
759   */
760   static void
761 < recurse_remove_clients(struct Client *source_p, const char *quitmsg)
761 > recurse_remove_clients(struct Client *source_p, const char *comment)
762   {
763 <  dlink_node *ptr, *next;
763 >  dlink_node *node, *node_next;
764  
765 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
766 <    exit_one_client(ptr->data, quitmsg);
765 >  DLINK_FOREACH_SAFE(node, node_next, source_p->serv->client_list.head)
766 >    exit_one_client(node->data, comment);
767  
768 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
768 >  DLINK_FOREACH_SAFE(node, node_next, source_p->serv->server_list.head)
769    {
770 <    recurse_remove_clients(ptr->data, quitmsg);
771 <    exit_one_client(ptr->data, quitmsg);
770 >    recurse_remove_clients(node->data, comment);
771 >    exit_one_client(node->data, comment);
772    }
773   }
774  
775   /*
779 ** Remove *everything* that depends on source_p, from all lists, and sending
780 ** all necessary QUITs and SQUITs.  source_p itself is still on the lists,
781 ** and its SQUITs have been sent except for the upstream one  -orabidoo
782 */
783 static void
784 remove_dependents(struct Client *source_p, struct Client *from,
785                  const char *comment, const char *splitstr)
786 {
787  dlink_node *ptr = NULL;
788
789  DLINK_FOREACH(ptr, serv_list.head)
790    recurse_send_quits(source_p, source_p, from, ptr->data,
791                       comment, splitstr);
792
793  recurse_remove_clients(source_p, splitstr);
794 }
795
796 /*
776   * exit_client - exit a client of any type. Generally, you can use
777   * this on any struct Client, regardless of its state.
778   *
779   * Note, you shouldn't exit remote _users_ without first doing
780   * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
781 + *
782   * However, it is perfectly correct to call exit_client to force a _server_
783   * quit (either local or remote one).
784   *
785 + *
786   * inputs:       - a client pointer that is going to be exited
806 *               - for servers, the second argument is a pointer to who
807 *                 is firing the server. This side won't get any generated
808 *                 messages. NEVER NULL!
787   * output:       none
788   * side effects: the client is delinked from all lists, disconnected,
789   *               and the rest of IRC network is notified of the exit.
790   *               Client memory is scheduled to be freed
791   */
792   void
793 < exit_client(struct Client *source_p, struct Client *from, const char *comment)
793 > exit_client(struct Client *source_p, const char *comment)
794   {
795 <  dlink_node *m = NULL;
795 >  assert(!IsMe(source_p));
796 >  assert(source_p != &me);
797  
798    if (MyConnect(source_p))
799    {
800 <    /* DO NOT REMOVE. exit_client can be called twice after a failed
801 <     * read/write.
800 >    /*
801 >     * DO NOT REMOVE. exit_client can be called twice after a failed read/write.
802       */
803 <    if (IsClosing(source_p))
803 >    if (HasFlag(source_p, FLAGS_CLOSING))
804        return;
805  
806 <    SetClosing(source_p);
806 >    AddFlag(source_p, FLAGS_CLOSING);
807  
808 <    if (IsIpHash(source_p))
830 <      remove_one_ip(&source_p->localClient->ip);
831 <
832 <    if (source_p->localClient->auth)
808 >    if (HasFlag(source_p, FLAGS_IPHASH))
809      {
810 <      delete_auth(source_p->localClient->auth);
811 <      source_p->localClient->auth = NULL;
810 >      DelFlag(source_p, FLAGS_IPHASH);
811 >      ipcache_remove_address(&source_p->connection->ip);
812      }
813  
814 <    /*
839 <     * This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
840 <     * STAT_HANDSHAKE or STAT_UNKNOWN
841 <     * all of which are lumped together into unknown_list
842 <     *
843 <     * In all above cases IsRegistered() will not be true.
844 <     */
845 <    if (!IsRegistered(source_p))
814 >    if (source_p->connection->auth)
815      {
816 <      assert(dlinkFind(&unknown_list, source_p));
817 <
849 <      dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
816 >      auth_delete(source_p->connection->auth);
817 >      source_p->connection->auth = NULL;
818      }
819 <    else if (IsClient(source_p))
819 >
820 >    if (IsClient(source_p))
821      {
822 <      time_t on_for = CurrentTime - source_p->localClient->firsttime;
854 <      assert(Count.local > 0);
855 <      Count.local--;
822 >      dlink_node *node;
823  
824        if (HasUMode(source_p, UMODE_OPER))
825 <        if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
826 <          free_dlink_node(m);
825 >        if ((node = dlinkFindDelete(&oper_list, source_p)))
826 >          free_dlink_node(node);
827  
828        assert(dlinkFind(&local_client_list, source_p));
829 <      dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
829 >      dlinkDelete(&source_p->connection->lclient_node, &local_client_list);
830  
831 <      if (source_p->localClient->list_task != NULL)
832 <        free_list_task(source_p->localClient->list_task, source_p);
831 >      if (source_p->connection->list_task)
832 >        free_list_task(source_p);
833  
834 +      clear_invite_list(&source_p->connection->invited);
835 +      del_all_accepts(source_p);
836        watch_del_watch_list(source_p);
837 +
838        sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
839                             "Client exiting: %s (%s@%s) [%s] [%s]",
840 <                           source_p->name, source_p->username, source_p->host, comment,
841 <                           ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
842 <                           "255.255.255.255" : source_p->sockhost);
843 <      sendto_realops_flags(UMODE_CCONN_FULL, L_ALL, SEND_NOTICE,
844 <                           "CLIEXIT: %s %s %s %s 0 %s",
845 <                           source_p->name,
876 <                           source_p->username,
877 <                           source_p->host,
878 <                           ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
879 <                           "255.255.255.255" : source_p->sockhost,
880 <                           comment);
881 <      ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
882 <           myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
883 <           (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60),
840 >                           source_p->name, source_p->username, source_p->realhost,
841 >                           source_p->sockhost, comment);
842 >
843 >      ilog(LOG_TYPE_USER, "%s (%ju): %s!%s@%s %s %s %ju/%ju :%s",
844 >           date_ctime(source_p->connection->firsttime),
845 >           CurrentTime - source_p->connection->firsttime,
846             source_p->name, source_p->username, source_p->host,
847 <           source_p->localClient->send.bytes>>10,
848 <           source_p->localClient->recv.bytes>>10);
847 >           source_p->sockhost, source_p->account,
848 >           source_p->connection->send.bytes >> 10,
849 >           source_p->connection->recv.bytes >> 10, source_p->info);
850      }
851      else if (IsServer(source_p))
852      {
853 <      assert(Count.myserver > 0);
854 <      --Count.myserver;
855 <
856 <      assert(dlinkFind(&serv_list, source_p));
857 <      dlinkDelete(&source_p->localClient->lclient_node, &serv_list);
858 <      unset_chcap_usage_counts(source_p);
853 >      assert(dlinkFind(&local_server_list, source_p));
854 >      dlinkDelete(&source_p->connection->lclient_node, &local_server_list);
855 >    }
856 >    else
857 >    {
858 >      assert(dlinkFind(&unknown_list, source_p));
859 >      dlinkDelete(&source_p->connection->lclient_node, &unknown_list);
860      }
861  
862      if (!IsDead(source_p))
863      {
864        if (IsServer(source_p))
865        {
866 <        /* for them, we are exiting the network */
867 <        sendto_one(source_p, ":%s SQUIT %s :%s",
868 <                   ID_or_name(from, source_p), me.name, comment);
866 >        if (!HasFlag(source_p, FLAGS_SQUIT))
867 >        {
868 >          /* for them, we are exiting the network */
869 >          sendto_one(source_p, ":%s SQUIT %s :%s",
870 >                     me.id, me.id, comment);
871 >        }
872        }
873  
874        sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
875                   source_p->host, comment);
876      }
877  
878 <    /*
912 <    ** Currently only server connections can have
913 <    ** depending remote clients here, but it does no
914 <    ** harm to check for all local clients. In
915 <    ** future some other clients than servers might
916 <    ** have remotes too...
917 <    **
918 <    ** Close the Client connection first and mark it
919 <    ** so that no messages are attempted to send to it.
920 <    ** Remember it makes source_p->from == NULL.
921 <    */
922 <    close_connection(source_p);
878 >    client_close_connection(source_p);
879    }
880 +  else if (IsClient(source_p) && HasFlag(source_p->servptr, FLAGS_EOB))
881 +    sendto_realops_flags(UMODE_FARCONNECT, L_ALL, SEND_NOTICE,
882 +                         "Client exiting at %s: %s (%s@%s) [%s] [%s]",
883 +                         source_p->servptr->name, source_p->name,
884 +                         source_p->username, source_p->realhost, source_p->sockhost, comment);
885  
886    if (IsServer(source_p))
887    {
888 <    char splitstr[HOSTLEN + HOSTLEN + 2];
888 >    char splitstr[HOSTLEN + HOSTLEN + 2] = "";
889  
890 <    /* This shouldn't ever happen */
891 <    assert(source_p->serv != NULL && source_p->servptr != NULL);
890 >    assert(source_p->serv);
891 >    assert(source_p->servptr);
892  
893      if (ConfigServerHide.hide_servers)
894        /*
895 <       * Set netsplit message to "*.net *.split" to still show
895 >       * Set netsplit message to "*.net *.split" to still show
896         * that its a split, but hide the servers splitting
897         */
898 <      strcpy(splitstr, "*.net *.split");
898 >      strlcpy(splitstr, "*.net *.split", sizeof(splitstr));
899      else
900        snprintf(splitstr, sizeof(splitstr), "%s %s",
901                 source_p->servptr->name, source_p->name);
902  
903 <    remove_dependents(source_p, from->from, comment, splitstr);
903 >    /* Send SQUIT for source_p in every direction. source_p is already off of local_server_list here */
904 >    if (!HasFlag(source_p, FLAGS_SQUIT))
905 >      sendto_server(NULL, 0, 0, "SQUIT %s :%s", source_p->id, comment);
906 >
907 >    /* Now exit the clients internally */
908 >    recurse_remove_clients(source_p, splitstr);
909  
910 <    if (source_p->servptr == &me)
910 >    if (MyConnect(source_p))
911      {
912 <      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
913 <                           "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
914 <                           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
915 <                           source_p->localClient->send.bytes >> 10,
916 <                           source_p->localClient->recv.bytes >> 10);
917 <      ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
918 <           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
919 <           source_p->localClient->send.bytes >> 10,
920 <           source_p->localClient->recv.bytes >> 10);
912 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
913 >                           "%s was connected for %s. %ju/%ju sendK/recvK.",
914 >                           source_p->name, time_dissect(CurrentTime - source_p->connection->firsttime),
915 >                           source_p->connection->send.bytes >> 10,
916 >                           source_p->connection->recv.bytes >> 10);
917 >      ilog(LOG_TYPE_IRCD, "%s was connected for %s. %ju/%ju sendK/recvK.",
918 >           source_p->name, time_dissect(CurrentTime - source_p->connection->firsttime),
919 >           source_p->connection->send.bytes >> 10,
920 >           source_p->connection->recv.bytes >> 10);
921      }
922    }
923    else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
924 <  {
959 <    sendto_server(from->from, CAP_TS6, NOCAPS,
960 <                  ":%s QUIT :%s", ID(source_p), comment);
961 <    sendto_server(from->from, NOCAPS, CAP_TS6,
962 <                  ":%s QUIT :%s", source_p->name, comment);
963 <  }
924 >    sendto_server(source_p->from, 0, 0, ":%s QUIT :%s", source_p->id, comment);
925  
926    /* The client *better* be off all of the lists */
927    assert(dlinkFind(&unknown_list, source_p) == NULL);
928    assert(dlinkFind(&local_client_list, source_p) == NULL);
929 <  assert(dlinkFind(&serv_list, source_p) == NULL);
929 >  assert(dlinkFind(&local_server_list, source_p) == NULL);
930    assert(dlinkFind(&oper_list, source_p) == NULL);
931 +  assert(dlinkFind(&listing_client_list, source_p) == NULL);
932  
933    exit_one_client(source_p, comment);
934   }
# Line 978 | Line 940 | exit_client(struct Client *source_p, str
940   void
941   dead_link_on_write(struct Client *client_p, int ierrno)
942   {
943 <  dlink_node *ptr;
943 >  dlink_node *node;
944  
945    if (IsDefunct(client_p))
946      return;
947  
948 <  dbuf_clear(&client_p->localClient->buf_recvq);
949 <  dbuf_clear(&client_p->localClient->buf_sendq);
948 >  dbuf_clear(&client_p->connection->buf_recvq);
949 >  dbuf_clear(&client_p->connection->buf_sendq);
950  
951    assert(dlinkFind(&abort_list, client_p) == NULL);
952 <  ptr = make_dlink_node();
952 >  node = make_dlink_node();
953    /* don't let exit_aborted_clients() finish yet */
954 <  dlinkAddTail(client_p, ptr, &abort_list);
954 >  dlinkAddTail(client_p, node, &abort_list);
955  
956    if (eac_next == NULL)
957 <    eac_next = ptr;
957 >    eac_next = node;
958  
959    SetDead(client_p); /* You are dead my friend */
960   }
# Line 1004 | Line 966 | dead_link_on_write(struct Client *client
966   void
967   dead_link_on_read(struct Client *client_p, int error)
968   {
969 <  char errmsg[255];
969 >  char errmsg[IRCD_BUFSIZE];
970    int current_error;
971  
972    if (IsDefunct(client_p))
973      return;
974  
975 <  dbuf_clear(&client_p->localClient->buf_recvq);
976 <  dbuf_clear(&client_p->localClient->buf_sendq);
975 >  dbuf_clear(&client_p->connection->buf_recvq);
976 >  dbuf_clear(&client_p->connection->buf_sendq);
977  
978 <  current_error = get_sockerr(client_p->localClient->fd.fd);
978 >  current_error = get_sockerr(client_p->connection->fd->fd);
979  
980    if (IsServer(client_p) || IsHandshake(client_p))
981    {
1020    int connected = CurrentTime - client_p->localClient->firsttime;
1021      
982      if (error == 0)
983      {
984 <      /* Admins get the real IP */
985 <      sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
986 <                           "Server %s closed the connection",
987 <                           get_client_name(client_p, SHOW_IP));
988 <
989 <      /* Opers get a masked IP */
1030 <      sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
1031 <                           "Server %s closed the connection",
1032 <                           get_client_name(client_p, MASK_IP));
1033 <
984 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
985 >                           "Server %s closed the connection",
986 >                           client_get_name(client_p, SHOW_IP));
987 >      sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
988 >                           "Server %s closed the connection",
989 >                           client_get_name(client_p, MASK_IP));
990        ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
991 <           get_client_name(client_p, SHOW_IP));
991 >           client_get_name(client_p, SHOW_IP));
992      }
993      else
994      {
995 <      report_error(L_ADMIN, "Lost connection to %s: %s",
996 <                   get_client_name(client_p, SHOW_IP), current_error);
997 <      report_error(L_OPER, "Lost connection to %s: %s",
998 <                   get_client_name(client_p, MASK_IP), current_error);
995 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
996 >                           "Lost connection to %s: %s",
997 >                           client_get_name(client_p, SHOW_IP), strerror(current_error));
998 >      sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
999 >                           "Lost connection to %s: %s",
1000 >                           client_get_name(client_p, MASK_IP), strerror(current_error));
1001 >      ilog(LOG_TYPE_IRCD, "Lost connection to %s: %s",
1002 >           client_get_name(client_p, SHOW_IP), strerror(current_error));
1003      }
1004  
1005 <    sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
1006 <                         "%s had been connected for %d day%s, %2d:%02d:%02d",
1007 <                         client_p->name, connected/86400,
1048 <                         (connected/86400 == 1) ? "" : "s",
1049 <                         (connected % 86400) / 3600, (connected % 3600) / 60,
1050 <                         connected % 60);
1005 >    sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
1006 >                         "%s was connected for %s",
1007 >                         client_p->name, time_dissect(CurrentTime - client_p->connection->firsttime));
1008    }
1009  
1010    if (error == 0)
# Line 1057 | Line 1014 | dead_link_on_read(struct Client *client_
1014      snprintf(errmsg, sizeof(errmsg), "Read error: %s",
1015               strerror(current_error));
1016  
1017 <  exit_client(client_p, &me, errmsg);
1017 >  exit_client(client_p, errmsg);
1018   }
1019  
1020   void
# Line 1072 | Line 1029 | exit_aborted_clients(void)
1029      target_p = ptr->data;
1030      eac_next = ptr->next;
1031  
1032 +    dlinkDelete(ptr, &abort_list);
1033 +    free_dlink_node(ptr);
1034 +
1035      if (target_p == NULL)
1036      {
1037 <      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
1037 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
1038                             "Warning: null client on abort_list!");
1079      dlinkDelete(ptr, &abort_list);
1080      free_dlink_node(ptr);
1039        continue;
1040      }
1041  
1042 <    dlinkDelete(ptr, &abort_list);
1085 <
1086 <    if (IsSendQExceeded(target_p))
1042 >    if (HasFlag(target_p, FLAGS_SENDQEX))
1043        notice = "Max SendQ exceeded";
1044      else
1045        notice = "Write error: connection closed";
1046  
1047 <    exit_client(target_p, &me, notice);  
1092 <    free_dlink_node(ptr);
1047 >    exit_client(target_p, notice);
1048    }
1049   }
1050  
# Line 1106 | Line 1061 | exit_aborted_clients(void)
1061   void
1062   del_accept(struct split_nuh_item *accept_p, struct Client *client_p)
1063   {
1064 <  dlinkDelete(&accept_p->node, &client_p->localClient->acceptlist);
1064 >  dlinkDelete(&accept_p->node, &client_p->connection->acceptlist);
1065  
1066 <  MyFree(accept_p->nickptr);
1067 <  MyFree(accept_p->userptr);
1068 <  MyFree(accept_p->hostptr);
1069 <  MyFree(accept_p);
1066 >  xfree(accept_p->nickptr);
1067 >  xfree(accept_p->userptr);
1068 >  xfree(accept_p->hostptr);
1069 >  xfree(accept_p);
1070   }
1071  
1072   struct split_nuh_item *
1073   find_accept(const char *nick, const char *user,
1074 <            const char *host, struct Client *client_p, int do_match)
1074 >            const char *host, struct Client *client_p,
1075 >            int (*cmpfunc)(const char *, const char *))
1076   {
1077 <  dlink_node *ptr = NULL;
1122 <  /* XXX We wouldn't need that if match() would return 0 on match */
1123 <  int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
1077 >  dlink_node *node;
1078  
1079 <  DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head)
1079 >  DLINK_FOREACH(node, client_p->connection->acceptlist.head)
1080    {
1081 <    struct split_nuh_item *accept_p = ptr->data;
1081 >    struct split_nuh_item *accept_p = node->data;
1082  
1083      if (!cmpfunc(accept_p->nickptr, nick) &&
1084          !cmpfunc(accept_p->userptr, user) &&
# Line 1146 | Line 1100 | int
1100   accept_message(struct Client *source,
1101                 struct Client *target)
1102   {
1103 <  dlink_node *ptr = NULL;
1103 >  dlink_node *node;
1104 >
1105 >  if (HasFlag(source, FLAGS_SERVICE) ||
1106 >      (HasUMode(source, UMODE_OPER) && ConfigGeneral.opers_bypass_callerid))
1107 >    return 1;
1108  
1109    if (source == target || find_accept(source->name, source->username,
1110 <                                      source->host, target, 1))
1110 >                                      source->host, target, match))
1111      return 1;
1112  
1113 <  if (HasUMode(target, UMODE_SOFTCALLERID))
1114 <    DLINK_FOREACH(ptr, target->channel.head)
1115 <      if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
1113 >  if (!HasUMode(target, UMODE_CALLERID) && HasUMode(target, UMODE_SOFTCALLERID))
1114 >    DLINK_FOREACH(node, target->channel.head)
1115 >      if (IsMember(source, ((struct Membership *)node->data)->chptr))
1116          return 1;
1117  
1118    return 0;
# Line 1169 | Line 1127 | accept_message(struct Client *source,
1127   void
1128   del_all_accepts(struct Client *client_p)
1129   {
1130 <  dlink_node *ptr = NULL, *next_ptr = NULL;
1130 >  dlink_node *node, *node_next;
1131 >
1132 >  DLINK_FOREACH_SAFE(node, node_next, client_p->connection->acceptlist.head)
1133 >    del_accept(node->data, client_p);
1134 > }
1135 >
1136 > unsigned int
1137 > client_get_idle_time(const struct Client *source_p,
1138 >                     const struct Client *target_p)
1139 > {
1140 >  unsigned int idle = 0;
1141 >  const struct ClassItem *const class = get_class_ptr(&target_p->connection->confs);
1142 >
1143 >  if (!(class->flags & CLASS_FLAGS_FAKE_IDLE) || target_p == source_p)
1144 >    return CurrentTime - target_p->connection->last_privmsg;
1145 >
1146 >  if (HasUMode(source_p, UMODE_OPER) &&
1147 >      !(class->flags & CLASS_FLAGS_HIDE_IDLE_FROM_OPERS))
1148 >    return CurrentTime - target_p->connection->last_privmsg;
1149 >
1150 >  const unsigned int min_idle = class->min_idle;
1151 >  const unsigned int max_idle = class->max_idle;
1152 >
1153 >  if (min_idle == max_idle)
1154 >    return min_idle;
1155 >
1156 >  if (class->flags & CLASS_FLAGS_RANDOM_IDLE)
1157 >    idle = genrand_int32();
1158 >  else
1159 >    idle = CurrentTime - target_p->connection->last_privmsg;
1160 >
1161 >  if (max_idle)
1162 >    idle %= max_idle;
1163 >  else
1164 >    idle = 0;
1165 >
1166 >  if (idle < min_idle)
1167 >    idle = min_idle + (idle % (max_idle - min_idle));
1168 >
1169 >  return idle;
1170 > }
1171 >
1172 > /* client_init()
1173 > *
1174 > * inputs       - NONE
1175 > * output       - NONE
1176 > * side effects - initialize client free memory
1177 > */
1178 > void
1179 > client_init(void)
1180 > {
1181 >  static struct event event_ping =
1182 >  {
1183 >    .name = "check_pings",
1184 >    .handler = check_pings,
1185 >    .when = 5
1186 >  };
1187  
1188 <  DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
1175 <    del_accept(ptr->data, client_p);
1188 >  event_add(&event_ping, NULL);
1189   }

Comparing ircd-hybrid/trunk/src/client.c (property svn:keywords):
Revision 1667 by michael, Sun Nov 18 21:54:30 2012 UTC vs.
Revision 8399 by michael, Sun Mar 18 14:43:15 2018 UTC

# Line 1 | Line 1
1 < Id Revision
1 > Id

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)