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

Comparing ircd-hybrid/trunk/src/server.c (file contents):
Revision 6159 by michael, Thu Jun 18 09:36:14 2015 UTC vs.
Revision 9213 by michael, Sat Jan 25 23:20:08 2020 UTC

# Line 1 | Line 1
1   /*
2   *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (c) 1997-2015 ircd-hybrid development team
4 > *  Copyright (c) 1997-2020 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 19 | Line 19
19   *  USA
20   */
21  
22 < /*! \file s_serv.c
22 > /*! \file server.c
23   * \brief Server related functions.
24   * \version $Id$
25   */
26  
27   #include "stdinc.h"
28 – #ifdef HAVE_LIBCRYPTO
29 – #include <openssl/rsa.h>
30 – #include "rsa.h"
31 – #endif
28   #include "list.h"
29   #include "client.h"
30   #include "event.h"
# Line 37 | Line 33
33   #include "ircd.h"
34   #include "ircd_defs.h"
35   #include "s_bsd.h"
40 – #include "numeric.h"
36   #include "packet.h"
37   #include "conf.h"
38   #include "server.h"
39 + #include "server_capab.h"
40   #include "log.h"
45 – #include "user.h"
41   #include "send.h"
42   #include "memory.h"
48 – #include "channel.h"
43   #include "parse.h"
44  
51 – #define MIN_CONN_FREQ 300
45  
46   dlink_list flatten_links;
47 < static dlink_list server_capabilities_list;
55 < static void serv_connect_callback(fde_t *, int, void *);
47 > static void server_connect_callback(fde_t *, int, void *);
48  
49  
50   /*
# Line 66 | Line 58 | static void serv_connect_callback(fde_t
58   void
59   write_links_file(void *unused)
60   {
61 <  FILE *file = NULL;
62 <  dlink_node *node = NULL, *node_next = NULL;
71 <  char buff[IRCD_BUFSIZE] = "";
61 >  char buf[IRCD_BUFSIZE];
62 >  dlink_node *node, *node_next;
63  
64 <  if ((file = fopen(LIPATH, "w")) == NULL)
64 >  if (EmptyString(ConfigServerHide.flatten_links_file))
65      return;
66  
67 +  FILE *file = fopen(ConfigServerHide.flatten_links_file, "w");
68 +  if (file == NULL)
69 +  {
70 +    ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", ConfigServerHide.flatten_links_file,
71 +         strerror(errno));
72 +    return;
73 +  }
74 +
75    DLINK_FOREACH_SAFE(node, node_next, flatten_links.head)
76    {
77      dlinkDelete(node, &flatten_links);
78 <    MyFree(node->data);
78 >    xfree(node->data);
79      free_dlink_node(node);
80    }
81  
# Line 100 | Line 99 | write_links_file(void *unused)
99       * Mostly for aesthetic reasons - makes it look pretty in mIRC ;)
100       * - madmax
101       */
102 <    snprintf(buff, sizeof(buff), "%s %s :1 %s",   target_p->name,
103 <             me.name, target_p->info);
105 <    dlinkAddTail(xstrdup(buff), make_dlink_node(), &flatten_links);
106 <    snprintf(buff, sizeof(buff), "%s %s :1 %s\n", target_p->name,
107 <             me.name, target_p->info);
102 >    snprintf(buf, sizeof(buf), "%s %s :1 %s", target_p->name, me.name, target_p->info);
103 >    dlinkAddTail(xstrdup(buf), make_dlink_node(), &flatten_links);
104  
105 <    fputs(buff, file);
105 >    strlcat(buf, "\n", sizeof(buf));
106 >    fputs(buf, file);
107    }
108  
109    fclose(file);
# Line 115 | Line 112 | write_links_file(void *unused)
112   void
113   read_links_file(void)
114   {
115 <  FILE *file = NULL;
119 <  char *p = NULL;
120 <  char buff[IRCD_BUFSIZE] = "";
115 >  char buf[IRCD_BUFSIZE];
116  
117 <  if ((file = fopen(LIPATH, "r")) == NULL)
117 >  if (EmptyString(ConfigServerHide.flatten_links_file))
118      return;
119  
120 <  while (fgets(buff, sizeof(buff), file))
120 >  FILE *file = fopen(ConfigServerHide.flatten_links_file, "r");
121 >  if (file == NULL)
122    {
123 <    if ((p = strchr(buff, '\n')))
123 >    ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", ConfigServerHide.flatten_links_file,
124 >         strerror(errno));
125 >    return;
126 >  }
127 >
128 >  while (fgets(buf, sizeof(buf), file))
129 >  {
130 >    char *p = strchr(buf, '\n');
131 >    if (p)
132        *p = '\0';
133  
134 <    dlinkAddTail(xstrdup(buff), make_dlink_node(), &flatten_links);
134 >    dlinkAddTail(xstrdup(buf), make_dlink_node(), &flatten_links);
135    }
136  
137    fclose(file);
138   }
139  
140 < /* hunt_server()
140 > /* server_hunt()
141   *      Do the basic thing in delivering the message (command)
142   *      across the relays to the specific server (server) for
143   *      actions.
# Line 152 | Line 156 | read_links_file(void)
156   *
157   *      returns: (see #defines)
158   */
159 < int
160 < hunt_server(struct Client *source_p, const char *command,
159 > const struct server_hunt *
160 > server_hunt(struct Client *source_p, const char *command,
161              const int server, const int parc, char *parv[])
162   {
163 <  struct Client *target_p = NULL;
164 <  dlink_node *node = NULL;
163 >  static struct server_hunt hunt;
164 >  struct server_hunt *const h = &hunt;
165 >  dlink_node *node;
166  
167    /* Assume it's me, if no server */
168    if (parc <= server || EmptyString(parv[server]))
169 <    return HUNTED_ISME;
169 >  {
170 >    h->target_p = &me;
171 >    h->ret = HUNTED_ISME;
172 >    return h;
173 >  }
174  
175 <  if ((target_p = find_person(source_p, parv[server])) == NULL)
176 <    target_p = hash_find_server(parv[server]);
175 >  h->target_p = find_person(source_p, parv[server]);
176 >  if (h->target_p == NULL)
177 >    h->target_p = hash_find_server(parv[server]);
178  
179    /*
180     * These are to pickup matches that would cause the following
181     * message to go in the wrong direction while doing quick fast
182     * non-matching lookups.
183     */
184 <  if (target_p)
185 <    if (target_p->from == source_p->from && !MyConnect(target_p))
186 <      target_p = NULL;
184 >  if (h->target_p)
185 >    if (h->target_p->from == source_p->from && !MyConnect(h->target_p))
186 >      h->target_p = NULL;
187  
188 <  if (!target_p && has_wildcards(parv[server]))
188 >  if (h->target_p == NULL && has_wildcards(parv[server]))
189    {
190      DLINK_FOREACH(node, global_server_list.head)
191      {
192        struct Client *tmp = node->data;
193  
194        assert(IsMe(tmp) || IsServer(tmp));
195 <      if (!match(parv[server], tmp->name))
195 >      if (match(parv[server], tmp->name) == 0)
196        {
197          if (tmp->from == source_p->from && !MyConnect(tmp))
198            continue;
199  
200 <        target_p = node->data;
200 >        h->target_p = tmp;
201          break;
202        }
203      }
204  
205 <    if (!target_p)
205 >    if (h->target_p == NULL)
206      {
207        DLINK_FOREACH(node, global_client_list.head)
208        {
209          struct Client *tmp = node->data;
210  
211 <        assert(IsMe(tmp) || IsServer(tmp) || IsClient(tmp));
212 <        if (!match(parv[server], tmp->name))
211 >        assert(IsClient(tmp));
212 >        if (match(parv[server], tmp->name) == 0)
213          {
214            if (tmp->from == source_p->from && !MyConnect(tmp))
215              continue;
216  
217 <          target_p = node->data;
217 >          h->target_p = tmp;
218            break;
219          }
220        }
221      }
222    }
223  
224 <  if (target_p)
224 >  if (h->target_p)
225    {
226 <    assert(IsMe(target_p) || IsServer(target_p) || IsClient(target_p));
227 <    if (IsMe(target_p) || MyClient(target_p))
228 <      return HUNTED_ISME;
226 >    assert(IsMe(h->target_p) || IsServer(h->target_p) || IsClient(h->target_p));
227 >    if (IsMe(h->target_p) || MyClient(h->target_p))
228 >    {
229 >      h->ret = HUNTED_ISME;
230 >      return h;
231 >    }
232  
233 <    parv[server] = target_p->id;
234 <    sendto_one(target_p, command, source_p->id,
233 >    parv[server] = h->target_p->id;
234 >    sendto_one(h->target_p, command, source_p->id,
235                 parv[1], parv[2], parv[3], parv[4],
236                 parv[5], parv[6], parv[7], parv[8]);
237 <    return HUNTED_PASS;
237 >    h->ret = HUNTED_PASS;
238 >    return h;
239    }
240  
241    sendto_one_numeric(source_p, &me, ERR_NOSUCHSERVER, parv[server]);
242 <  return HUNTED_NOSUCH;
242 >  h->ret = HUNTED_NOSUCH;
243 >  return h;
244   }
245  
246   /* try_connections()
# Line 241 | Line 256 | hunt_server(struct Client *source_p, con
256   void
257   try_connections(void *unused)
258   {
259 <  dlink_node *node = NULL;
245 <  int confrq = 0;
259 >  dlink_node *node;
260  
261 <  /* TODO: change this to set active flag to 0 when added to event! --Habeeb */
248 <  if (GlobalSetOptions.autoconn == 0)
261 >  if (GlobalSetOptions.autoconn == false)
262      return;
263  
264 <  DLINK_FOREACH(node, server_items.head)
264 >  DLINK_FOREACH(node, connect_items.head)
265    {
266      struct MaskItem *conf = node->data;
267  
268      assert(conf->type == CONF_SERVER);
269 +    assert(conf->class);
270  
271 <    /* Also when already connecting! (update holdtimes) --SRB
272 <     */
259 <    if (!conf->port || !IsConfAllowAutoConn(conf))
271 >    /* Also when already connecting! (update holdtimes) --SRB */
272 >    if (conf->port == 0 || !IsConfAllowAutoConn(conf))
273        continue;
274  
275 <
276 <    /* Skip this entry if the use of it is still on hold until
275 >    /*
276 >     * Skip this entry if the use of it is still on hold until
277       * future. Otherwise handle this entry (and set it on hold
278       * until next time). Will reset only hold times, if already
279       * made one successfull connection... [this algorithm is
280       * a bit fuzzy... -- msa >;) ]
281       */
282 <    if (conf->until > CurrentTime)
282 >    if (conf->until > event_base->time.sec_monotonic)
283        continue;
284  
285 <    assert(conf->class);
273 <
274 <    confrq = conf->class->con_freq;
275 <    if (confrq < MIN_CONN_FREQ)
276 <      confrq = MIN_CONN_FREQ;
277 <
278 <    conf->until = CurrentTime + confrq;
285 >    conf->until = event_base->time.sec_monotonic + conf->class->con_freq;
286  
287      /*
288       * Found a CONNECT config with port specified, scan clients
# Line 286 | Line 293 | try_connections(void *unused)
293  
294      if (conf->class->ref_count < conf->class->max_total)
295      {
296 <      /* Go to the end of the list, if not already last */
296 >      /* Move this entry to the end of the list, if not already last */
297        if (node->next)
298        {
299 <        dlinkDelete(node, &server_items);
300 <        dlinkAddTail(conf, &conf->node, &server_items);
299 >        dlinkDelete(node, &connect_items);
300 >        dlinkAddTail(conf, &conf->node, &connect_items);
301        }
302  
303        if (find_servconn_in_progress(conf->name))
304          return;
305  
306        /*
307 <       * We used to only print this if serv_connect() actually
307 >       * We used to only print this if server_connect() actually
308         * succeeded, but since comm_tcp_connect() can call the callback
309         * immediately if there is an error, we were getting error messages
310         * in the wrong order. SO, we just print out the activated line,
311 <       * and let serv_connect() / serv_connect_callback() print an
311 >       * and let server_connect() / server_connect_callback() print an
312         * error afterwards if it fails.
313         *   -- adrian
314         */
315        if (ConfigServerHide.hide_server_ips)
316 <        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
316 >        sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
317                               "Connection to %s activated.",
318                               conf->name);
319        else
320 <        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
320 >        sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
321                               "Connection to %s[%s] activated.",
322                               conf->name, conf->host);
323  
324 <      serv_connect(conf, NULL);
324 >      server_connect(conf, NULL);
325        /* We connect only one at time... */
326        return;
327      }
328    }
329   }
330  
331 < int
332 < valid_servname(const char *name)
331 > bool
332 > server_valid_name(const char *name)
333   {
334    unsigned int dots = 0;
335    const char *p = name;
# Line 330 | Line 337 | valid_servname(const char *name)
337    for (; *p; ++p)
338    {
339      if (!IsServChar(*p))
340 <      return 0;
340 >      return false;
341  
342      if (*p == '.')
343        ++dots;
# Line 339 | Line 346 | valid_servname(const char *name)
346    return dots && (p - name) <= HOSTLEN;
347   }
348  
349 < int
343 < check_server(const char *name, struct Client *client_p)
344 < {
345 <  dlink_node *node = NULL;
346 <  struct MaskItem *conf        = NULL;
347 <  struct MaskItem *server_conf = NULL;
348 <  int error = -1;
349 <
350 <  assert(client_p);
351 <
352 <  /* loop through looking for all possible connect items that might work */
353 <  DLINK_FOREACH(node, server_items.head)
354 <  {
355 <    conf = node->data;
356 <
357 <    if (match(name, conf->name))
358 <      continue;
359 <
360 <    error = -3;
361 <
362 <    /* XXX: Fix me for IPv6                    */
363 <    /* XXX sockhost is the IPv4 ip as a string */
364 <    if (!match(conf->host, client_p->host) ||
365 <        !match(conf->host, client_p->sockhost))
366 <    {
367 <      error = -2;
368 <
369 <      if (!match_conf_password(client_p->connection->password, conf))
370 <        return -2;
371 <
372 <      if (!EmptyString(conf->certfp))
373 <        if (EmptyString(client_p->certfp) || strcasecmp(client_p->certfp, conf->certfp))
374 <          return -4;
375 <
376 <      server_conf = conf;
377 <    }
378 <  }
379 <
380 <  if (server_conf == NULL)
381 <    return error;
382 <
383 <  attach_conf(client_p, server_conf);
384 <
385 <
386 <  if (server_conf)
387 <  {
388 <    struct sockaddr_in *v4;
389 <    struct sockaddr_in6 *v6;
390 <
391 <    switch (server_conf->aftype)
392 <    {
393 <      case AF_INET6:
394 <        v6 = (struct sockaddr_in6 *)&server_conf->addr;
395 <
396 <        if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
397 <          memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
398 <        break;
399 <      case AF_INET:
400 <        v4 = (struct sockaddr_in *)&server_conf->addr;
401 <
402 <        if (v4->sin_addr.s_addr == INADDR_NONE)
403 <          memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
404 <        break;
405 <    }
406 <  }
407 <
408 <  return 0;
409 < }
410 <
411 < /* add_capability()
412 < *
413 < * inputs       - string name of CAPAB
414 < *              - int flag of capability
415 < * output       - NONE
416 < * side effects - Adds given capability name and bit mask to
417 < *                current supported capabilities. This allows
418 < *                modules to dynamically add or subtract their capability.
419 < */
420 < void
421 < add_capability(const char *name, unsigned int flag)
422 < {
423 <  struct Capability *cap = MyCalloc(sizeof(*cap));
424 <
425 <  cap->name = xstrdup(name);
426 <  cap->cap = flag;
427 <  dlinkAdd(cap, &cap->node, &server_capabilities_list);
428 < }
429 <
430 < /* delete_capability()
431 < *
432 < * inputs       - string name of CAPAB
433 < * output       - NONE
434 < * side effects - delete given capability from ones known.
435 < */
436 < void
437 < delete_capability(const char *name)
438 < {
439 <  dlink_node *node = NULL, *node_next = NULL;
440 <
441 <  DLINK_FOREACH_SAFE(node, node_next, server_capabilities_list.head)
442 <  {
443 <    struct Capability *cap = node->data;
444 <
445 <    if (!irccmp(cap->name, name))
446 <    {
447 <      dlinkDelete(node, &server_capabilities_list);
448 <      MyFree(cap->name);
449 <      MyFree(cap);
450 <    }
451 <  }
452 < }
453 <
454 < /*
455 < * find_capability()
456 < *
457 < * inputs       - string name of capab to find
458 < * output       - 0 if not found CAPAB otherwise
459 < * side effects - none
460 < */
461 < unsigned int
462 < find_capability(const char *name)
463 < {
464 <  const dlink_node *node = NULL;
465 <
466 <  DLINK_FOREACH(node, server_capabilities_list.head)
467 <  {
468 <    const struct Capability *cap = node->data;
469 <
470 <    if (!irccmp(cap->name, name))
471 <      return cap->cap;
472 <  }
473 <
474 <  return 0;
475 < }
476 <
477 < /* send_capabilities()
478 < *
479 < * inputs       - Client pointer to send to
480 < *              - int flag of capabilities that this server can send
481 < * output       - NONE
482 < * side effects - send the CAPAB line to a server  -orabidoo
483 < *
484 < */
485 < void
486 < send_capabilities(struct Client *client_p)
487 < {
488 <  char buf[IRCD_BUFSIZE] = "";
489 <  const dlink_node *node = NULL;
490 <
491 <  DLINK_FOREACH(node, server_capabilities_list.head)
492 <  {
493 <    const struct Capability *cap = node->data;
494 <
495 <    strlcat(buf, cap->name, sizeof(buf));
496 <
497 <    if (node->next)
498 <      strlcat(buf, " ", sizeof(buf));
499 <  }
500 <
501 <  sendto_one(client_p, "CAPAB :%s", buf);
502 < }
503 <
504 < /*
505 < * show_capabilities - show current server capabilities
506 < *
507 < * inputs       - pointer to a struct Client
508 < * output       - pointer to static string
509 < * side effects - build up string representing capabilities of server listed
510 < */
511 < const char *
512 < show_capabilities(const struct Client *target_p)
513 < {
514 <  static char msgbuf[IRCD_BUFSIZE] = "";
515 <  const dlink_node *node = NULL;
516 <
517 <  strlcpy(msgbuf, "TS", sizeof(msgbuf));
518 <
519 <  DLINK_FOREACH(node, server_capabilities_list.head)
520 <  {
521 <    const struct Capability *cap = node->data;
522 <
523 <    if (!IsCapable(target_p, cap->cap))
524 <      continue;
525 <
526 <    strlcat(msgbuf,       " ", sizeof(msgbuf));
527 <    strlcat(msgbuf, cap->name, sizeof(msgbuf));
528 <  }
529 <
530 <  return msgbuf;
531 < }
532 <
533 < /* make_server()
349 > /* server_make()
350   *
351   * inputs       - pointer to client struct
352   * output       - pointer to struct Server
# Line 538 | Line 354 | show_capabilities(const struct Client *t
354   *                if it was not previously allocated.
355   */
356   struct Server *
357 < make_server(struct Client *client_p)
357 > server_make(struct Client *client_p)
358   {
359    if (client_p->serv == NULL)
360 <    client_p->serv = MyCalloc(sizeof(struct Server));
360 >    client_p->serv = xcalloc(sizeof(*client_p->serv));
361  
362    return client_p->serv;
363   }
364  
365 < /* New server connection code
550 < * Based upon the stuff floating about in s_bsd.c
551 < *   -- adrian
552 < */
553 <
554 < /* serv_connect() - initiate a server connection
365 > /* server_connect() - initiate a server connection
366   *
367   * inputs       - pointer to conf
368   *              - pointer to client doing the connect
# Line 567 | Line 378 | make_server(struct Client *client_p)
378   * We return 1 if the connection is attempted, since we don't know whether
379   * it suceeded or not, and 0 if it fails in here somewhere.
380   */
381 < int
382 < serv_connect(struct MaskItem *conf, struct Client *by)
381 > bool
382 > server_connect(struct MaskItem *conf, struct Client *by)
383   {
384 <  struct Client *client_p = NULL;
574 <  char buf[HOSTIPLEN + 1] = "";
575 <
576 <  /* conversion structs */
577 <  struct sockaddr_in *v4;
384 >  char buf[HOSTIPLEN + 1];
385  
386    /* Make sure conf is useful */
387    assert(conf);
388 <
389 <  getnameinfo((const struct sockaddr *)&conf->addr, conf->addr.ss_len,
583 <              buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
584 <  ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", conf->name, conf->host,
585 <       buf);
388 >  assert(conf->type == CONF_SERVER);
389 >  assert(hash_find_server(conf->name) == NULL);  /* This should have been checked by the caller */
390  
391    /* Still processing a DNS lookup? -> exit */
392 <  if (conf->dns_pending)
392 >  if (conf->dns_pending == true)
393    {
394 <    sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
394 >    sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
395                           "Error connecting to %s: DNS lookup for connect{} in progress.",
396                           conf->name);
397 <    return 0;
397 >    return false;
398    }
399  
400 <  if (conf->dns_failed)
400 >  if (conf->dns_failed == true)
401    {
402 <    sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
402 >    sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
403                           "Error connecting to %s: DNS lookup for connect{} failed.",
404                           conf->name);
405 <    return 0;
405 >    return false;
406    }
407  
408 <  /* Make sure this server isn't already connected
409 <   * Note: conf should ALWAYS be a valid C: line
410 <   */
411 <  if ((client_p = hash_find_server(conf->name)))
408 >  getnameinfo((const struct sockaddr *)conf->addr, conf->addr->ss_len,
409 >              buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
410 >  ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", conf->name, conf->host, buf);
411 >
412 >  /* Create a socket for the server connection */
413 >  int fd = comm_socket(conf->addr->ss.ss_family, SOCK_STREAM, 0);
414 >  if (fd == -1)
415    {
416 <    sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
417 <                         "Server %s already present from %s",
418 <                         conf->name, get_client_name(client_p, SHOW_IP));
612 <    sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
613 <                         "Server %s already present from %s",
614 <                         conf->name, get_client_name(client_p, MASK_IP));
615 <    if (by && IsClient(by) && !MyClient(by))
616 <      sendto_one_notice(by, &me, ":Server %s already present from %s",
617 <                        conf->name, get_client_name(client_p, MASK_IP));
618 <    return 0;
416 >    /* Eek, failure to create the socket */
417 >    report_error(L_ALL, "opening stream socket to %s: %s", conf->name, errno);
418 >    return false;
419    }
420  
421    /* Create a local client */
422 <  client_p = make_client(NULL);
422 >  struct Client *client_p = client_make(NULL);
423  
424    /* Copy in the server, hostname, fd */
425    strlcpy(client_p->name, conf->name, sizeof(client_p->name));
# Line 628 | Line 428 | serv_connect(struct MaskItem *conf, stru
428    /* We already converted the ip once, so lets use it - stu */
429    strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
430  
431 <  /* create a socket for the server connection */
432 <  if (comm_open(&client_p->connection->fd, conf->addr.ss.ss_family, SOCK_STREAM, 0, NULL) < 0)
633 <  {
634 <    /* Eek, failure to create the socket */
635 <    report_error(L_ALL, "opening stream socket to %s: %s", conf->name, errno);
636 <
637 <    SetDead(client_p);
638 <    exit_client(client_p, "Connection failed");
639 <    return 0;
640 <  }
431 >  client_p->ip = *conf->addr;
432 >  client_p->connection->fd = fd_open(fd, true, NULL);
433  
434 <  /* servernames are always guaranteed under HOSTLEN chars */
435 <  fd_note(&client_p->connection->fd, "Server: %s", conf->name);
434 >  /* Server names are always guaranteed under HOSTLEN chars */
435 >  fd_note(client_p->connection->fd, "Server: %s", client_p->name);
436  
437 <  /* Attach config entries to client here rather than in
438 <   * serv_connect_callback(). This to avoid null pointer references.
437 >  /*
438 >   * Attach config entries to client here rather than in server_connect_callback().
439 >   * This to avoid null pointer references.
440     */
441 <  if (!attach_connect_block(client_p, conf->name, conf->host))
649 <  {
650 <    sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
651 <                         "Host %s is not enabled for connecting: no connect {} block",
652 <                         conf->name);
653 <    if (by && IsClient(by) && !MyClient(by))
654 <      sendto_one_notice(by, &me, ":Connect to host %s failed: no connect {} block", client_p->name);
441 >  conf_attach(client_p, conf);
442  
443 <    SetDead(client_p);
657 <    exit_client(client_p, "Connection failed");
658 <    return 0;
659 <  }
660 <
661 <  /* at this point we have a connection in progress and C/N lines
662 <   * attached to the client, the socket info should be saved in the
663 <   * client and it should either be resolved or have a valid address.
664 <   *
665 <   * The socket has been connected or connect is in progress.
666 <   */
667 <  make_server(client_p);
443 >  server_make(client_p);
444  
445    if (by && IsClient(by))
446      strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
# Line 672 | Line 448 | serv_connect(struct MaskItem *conf, stru
448      strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
449  
450    SetConnecting(client_p);
675 –  client_p->connection->aftype = conf->aftype;
451  
452    /* Now, initiate the connection */
453 <  /* XXX assume that a non 0 type means a specific bind address
454 <   * for this connect.
680 <   */
681 <  switch (conf->aftype)
682 <  {
683 <    case AF_INET:
684 <      v4 = (struct sockaddr_in*)&conf->bind;
685 <      if (v4->sin_addr.s_addr)
686 <      {
687 <        struct irc_ssaddr ipn;
688 <        memset(&ipn, 0, sizeof(struct irc_ssaddr));
689 <        ipn.ss.ss_family = AF_INET;
690 <        ipn.ss_port = 0;
691 <        memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
692 <        comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
693 <                         (struct sockaddr *)&ipn, ipn.ss_len,
694 <                         serv_connect_callback, client_p, conf->aftype,
695 <                         CONNECTTIMEOUT);
696 <      }
697 <      else if (ConfigServerInfo.specific_ipv4_vhost)
698 <      {
699 <        struct irc_ssaddr ipn;
700 <        memset(&ipn, 0, sizeof(struct irc_ssaddr));
701 <        ipn.ss.ss_family = AF_INET;
702 <        ipn.ss_port = 0;
703 <        memcpy(&ipn, &ConfigServerInfo.ip, sizeof(struct irc_ssaddr));
704 <        comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
705 <                         (struct sockaddr *)&ipn, ipn.ss_len,
706 <                         serv_connect_callback, client_p, conf->aftype,
707 <                         CONNECTTIMEOUT);
708 <      }
709 <      else
710 <        comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
711 <                         NULL, 0, serv_connect_callback, client_p, conf->aftype,
712 <                         CONNECTTIMEOUT);
713 <      break;
714 <    case AF_INET6:
715 <      {
716 <        struct irc_ssaddr ipn;
717 <        struct sockaddr_in6 *v6;
718 <        struct sockaddr_in6 *v6conf;
719 <
720 <        memset(&ipn, 0, sizeof(struct irc_ssaddr));
721 <        v6conf = (struct sockaddr_in6 *)&conf->bind;
722 <        v6 = (struct sockaddr_in6 *)&ipn;
453 >  comm_connect_tcp(client_p->connection->fd, conf->addr, conf->port, conf->bind,
454 >                   server_connect_callback, client_p, conf->timeout);
455  
456 <        if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr, sizeof(struct in6_addr)))
457 <        {
458 <          memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
459 <          ipn.ss.ss_family = AF_INET6;
460 <          ipn.ss_port = 0;
461 <          comm_connect_tcp(&client_p->connection->fd,
462 <                           conf->host, conf->port,
463 <                           (struct sockaddr *)&ipn, ipn.ss_len,
732 <                           serv_connect_callback, client_p,
733 <                           conf->aftype, CONNECTTIMEOUT);
734 <        }
735 <        else if (ConfigServerInfo.specific_ipv6_vhost)
736 <        {
737 <          memcpy(&ipn, &ConfigServerInfo.ip6, sizeof(struct irc_ssaddr));
738 <          ipn.ss.ss_family = AF_INET6;
739 <          ipn.ss_port = 0;
740 <          comm_connect_tcp(&client_p->connection->fd,
741 <                           conf->host, conf->port,
742 <                           (struct sockaddr *)&ipn, ipn.ss_len,
743 <                           serv_connect_callback, client_p,
744 <                           conf->aftype, CONNECTTIMEOUT);
745 <        }
746 <        else
747 <          comm_connect_tcp(&client_p->connection->fd,
748 <                           conf->host, conf->port,
749 <                           NULL, 0, serv_connect_callback, client_p,
750 <                           conf->aftype, CONNECTTIMEOUT);
751 <      }
752 <  }
753 <
754 <  return 1;
456 >  /*
457 >   * At this point we have a connection in progress and a connect {} block
458 >   * attached to the client, the socket info should be saved in the client
459 >   * and it should either be resolved or have a valid address.
460 >   *
461 >   * The socket has been connected or connect is in progress.
462 >   */
463 >  return true;
464   }
465  
757 – #ifdef HAVE_LIBCRYPTO
466   static void
467 < finish_ssl_server_handshake(struct Client *client_p)
467 > server_finish_tls_handshake(struct Client *client_p)
468   {
469 <  struct MaskItem *conf = NULL;
470 <
763 <  conf = find_conf_name(&client_p->connection->confs,
764 <                        client_p->name, CONF_SERVER);
469 >  const struct MaskItem *conf = find_conf_name(&client_p->connection->confs,
470 >                                                client_p->name, CONF_SERVER);
471    if (conf == NULL)
472    {
473 <    sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
474 <                         "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
475 <    sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
476 <                         "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
473 >    sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
474 >                         "Lost connect{} block for %s", client_get_name(client_p, SHOW_IP));
475 >    sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
476 >                         "Lost connect{} block for %s", client_get_name(client_p, MASK_IP));
477  
478      exit_client(client_p, "Lost connect{} block");
479      return;
480    }
481  
482 <  sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
482 >  /* Next, send the initial handshake */
483 >  SetHandshake(client_p);
484 >
485 >  sendto_one(client_p, "PASS %s TS %u %s", conf->spasswd, TS_CURRENT, me.id);
486  
487 <  send_capabilities(client_p);
487 >  sendto_one(client_p, "CAPAB :%s", capab_get(NULL));
488  
489    sendto_one(client_p, "SERVER %s 1 :%s%s",
490               me.name, ConfigServerHide.hidden ? "(H) " : "",
491               me.info);
492  
784 –  /* If we've been marked dead because a send failed, just exit
785 –   * here now and save everyone the trouble of us ever existing.
786 –   */
787 –  if (IsDead(client_p))
788 –  {
789 –      sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
790 –                           "%s[%s] went dead during handshake",
791 –                           client_p->name,
792 –                           client_p->host);
793 –      sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
794 –                           "%s went dead during handshake", client_p->name);
795 –      return;
796 –  }
797 –
798 –  /* don't move to serv_list yet -- we haven't sent a burst! */
493    /* If we get here, we're ok, so lets start reading some data */
494 <  comm_setselect(&client_p->connection->fd, COMM_SELECT_READ, read_packet, client_p, 0);
494 >  read_packet(client_p->connection->fd, client_p);
495   }
496  
497   static void
498 < ssl_server_handshake(fde_t *fd, void *data)
498 > server_tls_handshake(fde_t *F, void *data)
499   {
500    struct Client *client_p = data;
501 <  X509 *cert = NULL;
502 <  int ret = 0;
501 >  const char *sslerr = NULL;
502 >
503 >  assert(client_p);
504 >  assert(client_p->connection);
505 >  assert(client_p->connection->fd);
506 >  assert(client_p->connection->fd == F);
507  
508 <  if ((ret = SSL_connect(client_p->connection->fd.ssl)) <= 0)
508 >  tls_handshake_status_t ret = tls_handshake(&F->tls, TLS_ROLE_CLIENT, &sslerr);
509 >  if (ret != TLS_HANDSHAKE_DONE)
510    {
511 <    if ((CurrentTime - client_p->connection->firsttime) > CONNECTTIMEOUT)
511 >    if ((event_base->time.sec_monotonic - client_p->connection->created_monotonic) > TLS_HANDSHAKE_TIMEOUT)
512      {
513 <      exit_client(client_p, "Timeout during SSL handshake");
513 >      exit_client(client_p, "Timeout during TLS handshake");
514        return;
515      }
516  
517 <    switch (SSL_get_error(client_p->connection->fd.ssl, ret))
517 >    switch (ret)
518      {
519 <      case SSL_ERROR_WANT_WRITE:
520 <        comm_setselect(&client_p->connection->fd, COMM_SELECT_WRITE,
521 <                       ssl_server_handshake, client_p, CONNECTTIMEOUT);
519 >      case TLS_HANDSHAKE_WANT_WRITE:
520 >        comm_setselect(F, COMM_SELECT_WRITE,
521 >                       server_tls_handshake, client_p, TLS_HANDSHAKE_TIMEOUT);
522          return;
523 <      case SSL_ERROR_WANT_READ:
524 <        comm_setselect(&client_p->connection->fd, COMM_SELECT_READ,
525 <                       ssl_server_handshake, client_p, CONNECTTIMEOUT);
523 >      case TLS_HANDSHAKE_WANT_READ:
524 >        comm_setselect(F, COMM_SELECT_READ,
525 >                       server_tls_handshake, client_p, TLS_HANDSHAKE_TIMEOUT);
526          return;
527        default:
528        {
529 <        const char *sslerr = ERR_error_string(ERR_get_error(), NULL);
831 <        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
529 >        sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
530                               "Error connecting to %s: %s", client_p->name,
531 <                             sslerr ? sslerr : "unknown SSL error");
532 <        exit_client(client_p, "Error during SSL handshake");
531 >                             sslerr ? sslerr : "unknown TLS error");
532 >        exit_client(client_p, "Error during TLS handshake");
533          return;
534        }
535      }
536    }
537  
538 <  comm_settimeout(&client_p->connection->fd, 0, NULL, NULL);
841 <
842 <  if ((cert = SSL_get_peer_certificate(client_p->connection->fd.ssl)))
843 <  {
844 <    int res = SSL_get_verify_result(client_p->connection->fd.ssl);
845 <    char buf[EVP_MAX_MD_SIZE * 2 + 1] = "";
846 <    unsigned char md[EVP_MAX_MD_SIZE] = "";
847 <
848 <    if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
849 <        res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
850 <        res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
851 <    {
852 <      unsigned int n = 0;
538 >  comm_settimeout(F, 0, NULL, NULL);
539  
540 <      if (X509_digest(cert, ConfigServerInfo.message_digest_algorithm, md, &n))
541 <      {
542 <        binary_to_hex(md, buf, n);
857 <        client_p->certfp = xstrdup(buf);
858 <      }
859 <    }
860 <    else
861 <      ilog(LOG_TYPE_IRCD, "Server %s!%s@%s gave bad SSL client certificate: %d",
862 <           client_p->name, client_p->username, client_p->host, res);
863 <    X509_free(cert);
864 <  }
540 >  if (tls_verify_cert(&F->tls, ConfigServerInfo.message_digest_algorithm, &client_p->certfp) == false)
541 >    ilog(LOG_TYPE_IRCD, "Server %s gave bad TLS client certificate",
542 >         client_get_name(client_p, MASK_IP));
543  
544 <  finish_ssl_server_handshake(client_p);
544 >  server_finish_tls_handshake(client_p);
545   }
546  
547   static void
548 < ssl_connect_init(struct Client *client_p, struct MaskItem *conf, fde_t *fd)
548 > server_tls_connect_init(struct Client *client_p, const struct MaskItem *conf, fde_t *F)
549   {
550 <  if ((client_p->connection->fd.ssl = SSL_new(ConfigServerInfo.client_ctx)) == NULL)
550 >  assert(client_p);
551 >  assert(client_p->connection);
552 >  assert(client_p->connection->fd);
553 >  assert(client_p->connection->fd == F);
554 >
555 >  if (tls_new(&F->tls, F->fd, TLS_ROLE_CLIENT) == false)
556    {
874 –    ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
875 –         ERR_error_string(ERR_get_error(), NULL));
557      SetDead(client_p);
558 <    exit_client(client_p, "SSL_new failed");
558 >    exit_client(client_p, "TLS context initialization failed");
559      return;
560    }
561  
881 –  SSL_set_fd(fd->ssl, fd->fd);
882 –
562    if (!EmptyString(conf->cipher_list))
563 <    SSL_set_cipher_list(client_p->connection->fd.ssl, conf->cipher_list);
563 >    tls_set_ciphers(&F->tls, conf->cipher_list);
564  
565 <  ssl_server_handshake(NULL, client_p);
565 >  server_tls_handshake(F, client_p);
566   }
888 – #endif
567  
568 < /* serv_connect_callback() - complete a server connection.
568 > /* server_connect_callback() - complete a server connection.
569   *
570   * This routine is called after the server connection attempt has
571   * completed. If unsucessful, an error is sent to ops and the client
# Line 896 | Line 574 | ssl_connect_init(struct Client *client_p
574   * marked for reading.
575   */
576   static void
577 < serv_connect_callback(fde_t *fd, int status, void *data)
577 > server_connect_callback(fde_t *F, int status, void *data)
578   {
579 <  struct Client *client_p = data;
902 <  struct MaskItem *conf = NULL;
579 >  struct Client *const client_p = data;
580  
581    /* First, make sure it's a real client! */
582    assert(client_p);
583 <  assert(&client_p->connection->fd == fd);
584 <
585 <  /* Next, for backward purposes, record the ip of the server */
909 <  memcpy(&client_p->connection->ip, &fd->connect.hostaddr,
910 <         sizeof(struct irc_ssaddr));
583 >  assert(client_p->connection);
584 >  assert(client_p->connection->fd);
585 >  assert(client_p->connection->fd == F);
586  
587    /* Check the status */
588    if (status != COMM_OK)
589    {
590 <    /* We have an error, so report it and quit
591 <     * Admins get to see any IP, mere opers don't *sigh*
590 >    /* We have an error, so report it and quit */
591 >    sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
592 >                         "Error connecting to %s: %s",
593 >                         client_get_name(client_p, SHOW_IP), comm_errstr(status));
594 >    sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
595 >                         "Error connecting to %s: %s",
596 >                         client_get_name(client_p, MASK_IP), comm_errstr(status));
597 >
598 >    /*
599 >     * If a fd goes bad, call dead_link() the socket is no
600 >     * longer valid for reading or writing.
601       */
602 <     if (ConfigServerHide.hide_server_ips)
603 <       sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
920 <                            "Error connecting to %s: %s",
921 <                            client_p->name, comm_errstr(status));
922 <     else
923 <       sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
924 <                            "Error connecting to %s[%s]: %s", client_p->name,
925 <                            client_p->host, comm_errstr(status));
926 <
927 <     sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
928 <                          "Error connecting to %s: %s",
929 <                          client_p->name, comm_errstr(status));
930 <
931 <     /* If a fd goes bad, call dead_link() the socket is no
932 <      * longer valid for reading or writing.
933 <      */
934 <     dead_link_on_write(client_p, 0);
935 <     return;
602 >    dead_link_on_write(client_p, 0);
603 >    return;
604    }
605  
606    /* COMM_OK, so continue the connection procedure */
607 <  /* Get the C/N lines */
608 <  conf = find_conf_name(&client_p->connection->confs,
609 <                        client_p->name, CONF_SERVER);
607 >  /* Get the connect {} block */
608 >  const struct MaskItem *conf = find_conf_name(&client_p->connection->confs,
609 >                                                client_p->name, CONF_SERVER);
610    if (conf == NULL)
611    {
612 <    sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
613 <                         "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
614 <    sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
615 <                         "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
612 >    sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
613 >                         "Lost connect{} block for %s", client_get_name(client_p, SHOW_IP));
614 >    sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
615 >                         "Lost connect{} block for %s", client_get_name(client_p, MASK_IP));
616  
617      exit_client(client_p, "Lost connect{} block");
618      return;
619    }
620  
621 <  /* Next, send the initial handshake */
954 <  SetHandshake(client_p);
955 <
956 < #ifdef HAVE_LIBCRYPTO
957 <  if (IsConfSSL(conf))
621 >  if (IsConfTLS(conf))
622    {
623 <    ssl_connect_init(client_p, conf, fd);
623 >    server_tls_connect_init(client_p, conf, F);
624      return;
625    }
962 – #endif
626  
627 <  sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
627 >  /* Next, send the initial handshake */
628 >  SetHandshake(client_p);
629 >
630 >  sendto_one(client_p, "PASS %s TS %u %s", conf->spasswd, TS_CURRENT, me.id);
631  
632 <  send_capabilities(client_p);
632 >  sendto_one(client_p, "CAPAB :%s", capab_get(NULL));
633  
634    sendto_one(client_p, "SERVER %s 1 :%s%s", me.name,
635               ConfigServerHide.hidden ? "(H) " : "", me.info);
636  
971 –  /* If we've been marked dead because a send failed, just exit
972 –   * here now and save everyone the trouble of us ever existing.
973 –   */
974 –  if (IsDead(client_p))
975 –  {
976 –      sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
977 –                           "%s[%s] went dead during handshake",
978 –                           client_p->name,
979 –                           client_p->host);
980 –      sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
981 –                           "%s went dead during handshake", client_p->name);
982 –      return;
983 –  }
984 –
985 –  /* don't move to serv_list yet -- we haven't sent a burst! */
637    /* If we get here, we're ok, so lets start reading some data */
638 <  comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
638 >  read_packet(client_p->connection->fd, client_p);
639   }
640  
641   struct Client *
642   find_servconn_in_progress(const char *name)
643   {
644    dlink_node *ptr;
994 –  struct Client *cptr;
645  
646    DLINK_FOREACH(ptr, unknown_list.head)
647    {
648 <    cptr = ptr->data;
648 >    struct Client *cptr = ptr->data;
649  
650 <    if (cptr && cptr->name[0])
651 <      if (!match(name, cptr->name))
650 >    if (cptr->name[0])
651 >      if (!irccmp(name, cptr->name))
652          return cptr;
653    }
654  
655    return NULL;
656   }
1007 –
1008 – void
1009 – generate_sid(void)
1010 – {
1011 –  unsigned int sid = 0;
1012 –  const char *p;
1013 –
1014 –  for (p = me.name; *p; ++p)
1015 –    sid = 5 * sid + *p;
1016 –  for (p = me.info; *p; ++p)
1017 –    sid = 5 * sid + *p;
1018 –
1019 –  snprintf(me.id, IRC_MAXSID + 1, "%03d", sid % 1000);
1020 – }

Comparing ircd-hybrid/trunk/src/server.c (property svn:keywords):
Revision 6159 by michael, Thu Jun 18 09:36:14 2015 UTC vs.
Revision 9213 by michael, Sat Jan 25 23:20:08 2020 UTC

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

Diff Legend

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