ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/server.c
Revision: 6722
Committed: Tue Nov 3 19:44:24 2015 UTC (8 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 29167 byte(s)
Log Message:
- server.c:try_connections(): remove outdated comment

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2015 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file s_serv.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
32 #include "list.h"
33 #include "client.h"
34 #include "event.h"
35 #include "hash.h"
36 #include "irc_string.h"
37 #include "ircd.h"
38 #include "ircd_defs.h"
39 #include "s_bsd.h"
40 #include "numeric.h"
41 #include "packet.h"
42 #include "conf.h"
43 #include "server.h"
44 #include "log.h"
45 #include "user.h"
46 #include "send.h"
47 #include "memory.h"
48 #include "channel.h"
49 #include "parse.h"
50
51
52 dlink_list flatten_links;
53 static dlink_list server_capabilities_list;
54 static void serv_connect_callback(fde_t *, int, void *);
55
56
57 /*
58 * write_links_file
59 *
60 * inputs - void pointer which is not used
61 * output - NONE
62 * side effects - called from an event, write out list of linked servers
63 * but in no particular order.
64 */
65 void
66 write_links_file(void *unused)
67 {
68 FILE *file = NULL;
69 dlink_node *node = NULL, *node_next = NULL;
70 char buff[IRCD_BUFSIZE] = "";
71
72 if (EmptyString(ConfigServerHide.flatten_links_file))
73 return;
74
75 if ((file = fopen(ConfigServerHide.flatten_links_file, "w")) == NULL)
76 {
77 ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", ConfigServerHide.flatten_links_file,
78 strerror(errno));
79 return;
80 }
81
82 DLINK_FOREACH_SAFE(node, node_next, flatten_links.head)
83 {
84 dlinkDelete(node, &flatten_links);
85 MyFree(node->data);
86 free_dlink_node(node);
87 }
88
89 DLINK_FOREACH(node, global_server_list.head)
90 {
91 const struct Client *target_p = node->data;
92
93 /*
94 * Skip hidden servers, aswell as ourselves, since we already send
95 * ourselves in /links
96 */
97 if (IsHidden(target_p) || IsMe(target_p))
98 continue;
99
100 if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
101 continue;
102
103 /*
104 * Attempt to format the file in such a way it follows the usual links output
105 * ie "servername uplink :hops info"
106 * Mostly for aesthetic reasons - makes it look pretty in mIRC ;)
107 * - madmax
108 */
109 snprintf(buff, sizeof(buff), "%s %s :1 %s", target_p->name,
110 me.name, target_p->info);
111 dlinkAddTail(xstrdup(buff), make_dlink_node(), &flatten_links);
112 snprintf(buff, sizeof(buff), "%s %s :1 %s\n", target_p->name,
113 me.name, target_p->info);
114
115 fputs(buff, file);
116 }
117
118 fclose(file);
119 }
120
121 void
122 read_links_file(void)
123 {
124 FILE *file = NULL;
125 char *p = NULL;
126 char buff[IRCD_BUFSIZE] = "";
127
128 if (EmptyString(ConfigServerHide.flatten_links_file))
129 return;
130
131 if ((file = fopen(ConfigServerHide.flatten_links_file, "r")) == NULL)
132 {
133 ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", ConfigServerHide.flatten_links_file,
134 strerror(errno));
135 return;
136 }
137
138 while (fgets(buff, sizeof(buff), file))
139 {
140 if ((p = strchr(buff, '\n')))
141 *p = '\0';
142
143 dlinkAddTail(xstrdup(buff), make_dlink_node(), &flatten_links);
144 }
145
146 fclose(file);
147 }
148
149 /* hunt_server()
150 * Do the basic thing in delivering the message (command)
151 * across the relays to the specific server (server) for
152 * actions.
153 *
154 * Note: The command is a format string and *MUST* be
155 * of prefixed style (e.g. ":%s COMMAND %s ...").
156 * Command can have only max 8 parameters.
157 *
158 * server parv[server] is the parameter identifying the
159 * target server.
160 *
161 * *WARNING*
162 * parv[server] is replaced with the pointer to the
163 * real servername from the matched client (I'm lazy
164 * now --msa).
165 *
166 * returns: (see #defines)
167 */
168 int
169 hunt_server(struct Client *source_p, const char *command,
170 const int server, const int parc, char *parv[])
171 {
172 struct Client *target_p = NULL;
173 dlink_node *node = NULL;
174
175 /* Assume it's me, if no server */
176 if (parc <= server || EmptyString(parv[server]))
177 return HUNTED_ISME;
178
179 if ((target_p = find_person(source_p, parv[server])) == NULL)
180 target_p = hash_find_server(parv[server]);
181
182 /*
183 * These are to pickup matches that would cause the following
184 * message to go in the wrong direction while doing quick fast
185 * non-matching lookups.
186 */
187 if (target_p)
188 if (target_p->from == source_p->from && !MyConnect(target_p))
189 target_p = NULL;
190
191 if (!target_p && has_wildcards(parv[server]))
192 {
193 DLINK_FOREACH(node, global_server_list.head)
194 {
195 struct Client *tmp = node->data;
196
197 assert(IsMe(tmp) || IsServer(tmp));
198 if (!match(parv[server], tmp->name))
199 {
200 if (tmp->from == source_p->from && !MyConnect(tmp))
201 continue;
202
203 target_p = node->data;
204 break;
205 }
206 }
207
208 if (!target_p)
209 {
210 DLINK_FOREACH(node, global_client_list.head)
211 {
212 struct Client *tmp = node->data;
213
214 assert(IsMe(tmp) || IsServer(tmp) || IsClient(tmp));
215 if (!match(parv[server], tmp->name))
216 {
217 if (tmp->from == source_p->from && !MyConnect(tmp))
218 continue;
219
220 target_p = node->data;
221 break;
222 }
223 }
224 }
225 }
226
227 if (target_p)
228 {
229 assert(IsMe(target_p) || IsServer(target_p) || IsClient(target_p));
230 if (IsMe(target_p) || MyClient(target_p))
231 return HUNTED_ISME;
232
233 parv[server] = target_p->id;
234 sendto_one(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;
238 }
239
240 sendto_one_numeric(source_p, &me, ERR_NOSUCHSERVER, parv[server]);
241 return HUNTED_NOSUCH;
242 }
243
244 /* try_connections()
245 *
246 * inputs - void pointer which is not used
247 * output - NONE
248 * side effects -
249 * scan through configuration and try new connections.
250 * Returns the calendar time when the next call to this
251 * function should be made latest. (No harm done if this
252 * is called earlier or later...)
253 */
254 void
255 try_connections(void *unused)
256 {
257 dlink_node *node = NULL;
258
259 if (GlobalSetOptions.autoconn == 0)
260 return;
261
262 DLINK_FOREACH(node, server_items.head)
263 {
264 struct MaskItem *conf = node->data;
265
266 assert(conf->type == CONF_SERVER);
267
268 /* Also when already connecting! (update holdtimes) --SRB */
269 if (!conf->port || !IsConfAllowAutoConn(conf))
270 continue;
271
272 /*
273 * Skip this entry if the use of it is still on hold until
274 * future. Otherwise handle this entry (and set it on hold
275 * until next time). Will reset only hold times, if already
276 * made one successfull connection... [this algorithm is
277 * a bit fuzzy... -- msa >;) ]
278 */
279 if (conf->until > CurrentTime)
280 continue;
281
282 assert(conf->class);
283
284 conf->until = CurrentTime + conf->class->con_freq;
285
286 /*
287 * Found a CONNECT config with port specified, scan clients
288 * and see if this server is already connected?
289 */
290 if (hash_find_server(conf->name))
291 continue;
292
293 if (conf->class->ref_count < conf->class->max_total)
294 {
295 /* Move this entry to the end of the list, if not already last */
296 if (node->next)
297 {
298 dlinkDelete(node, &server_items);
299 dlinkAddTail(conf, &conf->node, &server_items);
300 }
301
302 if (find_servconn_in_progress(conf->name))
303 return;
304
305 /*
306 * We used to only print this if serv_connect() actually
307 * succeeded, but since comm_tcp_connect() can call the callback
308 * immediately if there is an error, we were getting error messages
309 * in the wrong order. SO, we just print out the activated line,
310 * and let serv_connect() / serv_connect_callback() print an
311 * error afterwards if it fails.
312 * -- adrian
313 */
314 if (ConfigServerHide.hide_server_ips)
315 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
316 "Connection to %s activated.",
317 conf->name);
318 else
319 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
320 "Connection to %s[%s] activated.",
321 conf->name, conf->host);
322
323 serv_connect(conf, NULL);
324 /* We connect only one at time... */
325 return;
326 }
327 }
328 }
329
330 int
331 valid_servname(const char *name)
332 {
333 unsigned int dots = 0;
334 const char *p = name;
335
336 for (; *p; ++p)
337 {
338 if (!IsServChar(*p))
339 return 0;
340
341 if (*p == '.')
342 ++dots;
343 }
344
345 return dots && (p - name) <= HOSTLEN;
346 }
347
348 int
349 check_server(const char *name, struct Client *client_p)
350 {
351 dlink_node *node = NULL;
352 struct MaskItem *conf = NULL;
353 struct MaskItem *server_conf = NULL;
354 int error = -1;
355
356 assert(client_p);
357
358 /* Loop through looking for all possible connect items that might work */
359 DLINK_FOREACH(node, server_items.head)
360 {
361 conf = node->data;
362
363 if (match(name, conf->name))
364 continue;
365
366 error = -3;
367
368 /* XXX: Fix me for IPv6 */
369 /* XXX sockhost is the IPv4 ip as a string */
370 if (!match(conf->host, client_p->host) ||
371 !match(conf->host, client_p->sockhost))
372 {
373 error = -2;
374
375 if (!match_conf_password(client_p->connection->password, conf))
376 return -2;
377
378 if (!EmptyString(conf->certfp))
379 if (EmptyString(client_p->certfp) || strcasecmp(client_p->certfp, conf->certfp))
380 return -4;
381
382 server_conf = conf;
383 }
384 }
385
386 if (server_conf == NULL)
387 return error;
388
389 attach_conf(client_p, server_conf);
390
391 switch (server_conf->aftype)
392 {
393 case AF_INET6:
394 {
395 const struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&server_conf->addr;
396
397 if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
398 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
399 break;
400 }
401 case AF_INET:
402 {
403 const struct sockaddr_in *v4 = (struct sockaddr_in *)&server_conf->addr;
404
405 if (v4->sin_addr.s_addr == INADDR_NONE)
406 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
407 break;
408 }
409 }
410
411 return 0;
412 }
413
414 /* add_capability()
415 *
416 * inputs - string name of CAPAB
417 * - int flag of capability
418 * output - NONE
419 * side effects - Adds given capability name and bit mask to
420 * current supported capabilities. This allows
421 * modules to dynamically add or subtract their capability.
422 */
423 void
424 add_capability(const char *name, unsigned int flag)
425 {
426 struct Capability *cap = MyCalloc(sizeof(*cap));
427
428 cap->name = xstrdup(name);
429 cap->cap = flag;
430 dlinkAdd(cap, &cap->node, &server_capabilities_list);
431 }
432
433 /* delete_capability()
434 *
435 * inputs - string name of CAPAB
436 * output - NONE
437 * side effects - delete given capability from ones known.
438 */
439 void
440 delete_capability(const char *name)
441 {
442 dlink_node *node = NULL, *node_next = NULL;
443
444 DLINK_FOREACH_SAFE(node, node_next, server_capabilities_list.head)
445 {
446 struct Capability *cap = node->data;
447
448 if (!irccmp(cap->name, name))
449 {
450 dlinkDelete(node, &server_capabilities_list);
451 MyFree(cap->name);
452 MyFree(cap);
453 }
454 }
455 }
456
457 /*
458 * find_capability()
459 *
460 * inputs - string name of capab to find
461 * output - 0 if not found CAPAB otherwise
462 * side effects - none
463 */
464 unsigned int
465 find_capability(const char *name)
466 {
467 const dlink_node *node = NULL;
468
469 DLINK_FOREACH(node, server_capabilities_list.head)
470 {
471 const struct Capability *cap = node->data;
472
473 if (!irccmp(cap->name, name))
474 return cap->cap;
475 }
476
477 return 0;
478 }
479
480 /* send_capabilities()
481 *
482 * inputs - Client pointer to send to
483 * - int flag of capabilities that this server can send
484 * output - NONE
485 * side effects - send the CAPAB line to a server -orabidoo
486 *
487 */
488 void
489 send_capabilities(struct Client *client_p)
490 {
491 char buf[IRCD_BUFSIZE] = "";
492 const dlink_node *node = NULL;
493
494 DLINK_FOREACH(node, server_capabilities_list.head)
495 {
496 const struct Capability *cap = node->data;
497
498 strlcat(buf, cap->name, sizeof(buf));
499
500 if (node->next)
501 strlcat(buf, " ", sizeof(buf));
502 }
503
504 sendto_one(client_p, "CAPAB :%s", buf);
505 }
506
507 /*
508 * show_capabilities - show current server capabilities
509 *
510 * inputs - pointer to a struct Client
511 * output - pointer to static string
512 * side effects - build up string representing capabilities of server listed
513 */
514 const char *
515 show_capabilities(const struct Client *target_p)
516 {
517 static char msgbuf[IRCD_BUFSIZE] = "";
518 const dlink_node *node = NULL;
519
520 strlcpy(msgbuf, "TS", sizeof(msgbuf));
521
522 DLINK_FOREACH(node, server_capabilities_list.head)
523 {
524 const struct Capability *cap = node->data;
525
526 if (!IsCapable(target_p, cap->cap))
527 continue;
528
529 strlcat(msgbuf, " ", sizeof(msgbuf));
530 strlcat(msgbuf, cap->name, sizeof(msgbuf));
531 }
532
533 return msgbuf;
534 }
535
536 /* make_server()
537 *
538 * inputs - pointer to client struct
539 * output - pointer to struct Server
540 * side effects - add's an Server information block to a client
541 * if it was not previously allocated.
542 */
543 struct Server *
544 make_server(struct Client *client_p)
545 {
546 if (client_p->serv == NULL)
547 client_p->serv = MyCalloc(sizeof(struct Server));
548
549 return client_p->serv;
550 }
551
552 /* New server connection code
553 * Based upon the stuff floating about in s_bsd.c
554 * -- adrian
555 */
556
557 /* serv_connect() - initiate a server connection
558 *
559 * inputs - pointer to conf
560 * - pointer to client doing the connect
561 * output -
562 * side effects -
563 *
564 * This code initiates a connection to a server. It first checks to make
565 * sure the given server exists. If this is the case, it creates a socket,
566 * creates a client, saves the socket information in the client, and
567 * initiates a connection to the server through comm_connect_tcp(). The
568 * completion of this goes through serv_completed_connection().
569 *
570 * We return 1 if the connection is attempted, since we don't know whether
571 * it suceeded or not, and 0 if it fails in here somewhere.
572 */
573 int
574 serv_connect(struct MaskItem *conf, struct Client *by)
575 {
576 struct Client *client_p = NULL;
577 char buf[HOSTIPLEN + 1] = "";
578
579 /* conversion structs */
580 struct sockaddr_in *v4;
581
582 /* Make sure conf is useful */
583 assert(conf);
584
585 getnameinfo((const struct sockaddr *)&conf->addr, conf->addr.ss_len,
586 buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
587 ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", conf->name, conf->host,
588 buf);
589
590 /* Still processing a DNS lookup? -> exit */
591 if (conf->dns_pending)
592 {
593 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
594 "Error connecting to %s: DNS lookup for connect{} in progress.",
595 conf->name);
596 return 0;
597 }
598
599 if (conf->dns_failed)
600 {
601 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
602 "Error connecting to %s: DNS lookup for connect{} failed.",
603 conf->name);
604 return 0;
605 }
606
607 /* Make sure this server isn't already connected
608 * Note: conf should ALWAYS be a valid C: line
609 */
610 if ((client_p = hash_find_server(conf->name)))
611 {
612 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
613 "Server %s already present from %s",
614 conf->name, get_client_name(client_p, SHOW_IP));
615 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
616 "Server %s already present from %s",
617 conf->name, get_client_name(client_p, MASK_IP));
618 if (by && IsClient(by) && !MyClient(by))
619 sendto_one_notice(by, &me, ":Server %s already present from %s",
620 conf->name, get_client_name(client_p, MASK_IP));
621 return 0;
622 }
623
624 /* Create a local client */
625 client_p = make_client(NULL);
626
627 /* Copy in the server, hostname, fd */
628 strlcpy(client_p->name, conf->name, sizeof(client_p->name));
629 strlcpy(client_p->host, conf->host, sizeof(client_p->host));
630
631 /* We already converted the ip once, so lets use it - stu */
632 strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
633
634 /* create a socket for the server connection */
635 if (comm_open(&client_p->connection->fd, conf->addr.ss.ss_family, SOCK_STREAM, 0, NULL) < 0)
636 {
637 /* Eek, failure to create the socket */
638 report_error(L_ALL, "opening stream socket to %s: %s", conf->name, errno);
639
640 SetDead(client_p);
641 exit_client(client_p, "Connection failed");
642 return 0;
643 }
644
645 /* servernames are always guaranteed under HOSTLEN chars */
646 fd_note(&client_p->connection->fd, "Server: %s", client_p->name);
647
648 /* Attach config entries to client here rather than in
649 * serv_connect_callback(). This to avoid null pointer references.
650 */
651 if (!attach_connect_block(client_p, conf->name, conf->host))
652 {
653 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
654 "Host %s is not enabled for connecting: no connect {} block",
655 conf->name);
656 if (by && IsClient(by) && !MyClient(by))
657 sendto_one_notice(by, &me, ":Connect to host %s failed: no connect {} block", client_p->name);
658
659 SetDead(client_p);
660 exit_client(client_p, "Connection failed");
661 return 0;
662 }
663
664 /* at this point we have a connection in progress and C/N lines
665 * attached to the client, the socket info should be saved in the
666 * client and it should either be resolved or have a valid address.
667 *
668 * The socket has been connected or connect is in progress.
669 */
670 make_server(client_p);
671
672 if (by && IsClient(by))
673 strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
674 else
675 strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
676
677 SetConnecting(client_p);
678 client_p->connection->aftype = conf->aftype;
679
680 /* Now, initiate the connection */
681 /* XXX assume that a non 0 type means a specific bind address
682 * for this connect.
683 */
684 switch (conf->aftype)
685 {
686 case AF_INET:
687 v4 = (struct sockaddr_in*)&conf->bind;
688 if (v4->sin_addr.s_addr)
689 {
690 struct irc_ssaddr ipn;
691 memset(&ipn, 0, sizeof(struct irc_ssaddr));
692 ipn.ss.ss_family = AF_INET;
693 ipn.ss_port = 0;
694 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
695 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
696 (struct sockaddr *)&ipn, ipn.ss_len,
697 serv_connect_callback, client_p, conf->aftype,
698 CONNECTTIMEOUT);
699 }
700 else if (ConfigServerInfo.specific_ipv4_vhost)
701 {
702 struct irc_ssaddr ipn;
703 memset(&ipn, 0, sizeof(struct irc_ssaddr));
704 ipn.ss.ss_family = AF_INET;
705 ipn.ss_port = 0;
706 memcpy(&ipn, &ConfigServerInfo.ip, sizeof(struct irc_ssaddr));
707 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
708 (struct sockaddr *)&ipn, ipn.ss_len,
709 serv_connect_callback, client_p, conf->aftype,
710 CONNECTTIMEOUT);
711 }
712 else
713 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
714 NULL, 0, serv_connect_callback, client_p, conf->aftype,
715 CONNECTTIMEOUT);
716 break;
717 case AF_INET6:
718 {
719 struct irc_ssaddr ipn;
720 struct sockaddr_in6 *v6;
721 struct sockaddr_in6 *v6conf;
722
723 memset(&ipn, 0, sizeof(struct irc_ssaddr));
724 v6conf = (struct sockaddr_in6 *)&conf->bind;
725 v6 = (struct sockaddr_in6 *)&ipn;
726
727 if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr, sizeof(struct in6_addr)))
728 {
729 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
730 ipn.ss.ss_family = AF_INET6;
731 ipn.ss_port = 0;
732 comm_connect_tcp(&client_p->connection->fd,
733 conf->host, conf->port,
734 (struct sockaddr *)&ipn, ipn.ss_len,
735 serv_connect_callback, client_p,
736 conf->aftype, CONNECTTIMEOUT);
737 }
738 else if (ConfigServerInfo.specific_ipv6_vhost)
739 {
740 memcpy(&ipn, &ConfigServerInfo.ip6, sizeof(struct irc_ssaddr));
741 ipn.ss.ss_family = AF_INET6;
742 ipn.ss_port = 0;
743 comm_connect_tcp(&client_p->connection->fd,
744 conf->host, conf->port,
745 (struct sockaddr *)&ipn, ipn.ss_len,
746 serv_connect_callback, client_p,
747 conf->aftype, CONNECTTIMEOUT);
748 }
749 else
750 comm_connect_tcp(&client_p->connection->fd,
751 conf->host, conf->port,
752 NULL, 0, serv_connect_callback, client_p,
753 conf->aftype, CONNECTTIMEOUT);
754 }
755 }
756
757 return 1;
758 }
759
760 #ifdef HAVE_LIBCRYPTO
761 static void
762 finish_ssl_server_handshake(struct Client *client_p)
763 {
764 struct MaskItem *conf = NULL;
765
766 conf = find_conf_name(&client_p->connection->confs,
767 client_p->name, CONF_SERVER);
768 if (conf == NULL)
769 {
770 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
771 "Lost connect{} block for %s", get_client_name(client_p, SHOW_IP));
772 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
773 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
774
775 exit_client(client_p, "Lost connect{} block");
776 return;
777 }
778
779 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
780
781 send_capabilities(client_p);
782
783 sendto_one(client_p, "SERVER %s 1 :%s%s",
784 me.name, ConfigServerHide.hidden ? "(H) " : "",
785 me.info);
786
787 /*
788 * If we've been marked dead because a send failed, just exit
789 * here now and save everyone the trouble of us ever existing.
790 */
791 if (IsDead(client_p))
792 {
793 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
794 "%s went dead during handshake", get_client_name(client_p, SHOW_IP));
795 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
796 "%s went dead during handshake", get_client_name(client_p, MASK_IP));
797 return;
798 }
799
800 /* don't move to serv_list yet -- we haven't sent a burst! */
801 /* If we get here, we're ok, so lets start reading some data */
802 comm_setselect(&client_p->connection->fd, COMM_SELECT_READ, read_packet, client_p, 0);
803 }
804
805 static void
806 ssl_server_handshake(fde_t *fd, void *data)
807 {
808 struct Client *client_p = data;
809 X509 *cert = NULL;
810 int ret = 0;
811
812 if ((ret = SSL_connect(client_p->connection->fd.ssl)) <= 0)
813 {
814 if ((CurrentTime - client_p->connection->firsttime) > CONNECTTIMEOUT)
815 {
816 exit_client(client_p, "Timeout during SSL handshake");
817 return;
818 }
819
820 switch (SSL_get_error(client_p->connection->fd.ssl, ret))
821 {
822 case SSL_ERROR_WANT_WRITE:
823 comm_setselect(&client_p->connection->fd, COMM_SELECT_WRITE,
824 ssl_server_handshake, client_p, CONNECTTIMEOUT);
825 return;
826 case SSL_ERROR_WANT_READ:
827 comm_setselect(&client_p->connection->fd, COMM_SELECT_READ,
828 ssl_server_handshake, client_p, CONNECTTIMEOUT);
829 return;
830 default:
831 {
832 const char *sslerr = ERR_error_string(ERR_get_error(), NULL);
833 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
834 "Error connecting to %s: %s", client_p->name,
835 sslerr ? sslerr : "unknown SSL error");
836 exit_client(client_p, "Error during SSL handshake");
837 return;
838 }
839 }
840 }
841
842 comm_settimeout(&client_p->connection->fd, 0, NULL, NULL);
843
844 if ((cert = SSL_get_peer_certificate(client_p->connection->fd.ssl)))
845 {
846 int res = SSL_get_verify_result(client_p->connection->fd.ssl);
847 char buf[EVP_MAX_MD_SIZE * 2 + 1] = "";
848 unsigned char md[EVP_MAX_MD_SIZE] = "";
849
850 if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
851 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
852 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
853 {
854 unsigned int n = 0;
855
856 if (X509_digest(cert, ConfigServerInfo.message_digest_algorithm, md, &n))
857 {
858 binary_to_hex(md, buf, n);
859 client_p->certfp = xstrdup(buf);
860 }
861 }
862 else
863 ilog(LOG_TYPE_IRCD, "Server %s!%s@%s gave bad SSL client certificate: %d",
864 client_p->name, client_p->username, client_p->host, res);
865 X509_free(cert);
866 }
867
868 finish_ssl_server_handshake(client_p);
869 }
870
871 static void
872 ssl_connect_init(struct Client *client_p, const struct MaskItem *conf, fde_t *fd)
873 {
874 if ((client_p->connection->fd.ssl = SSL_new(ConfigServerInfo.client_ctx)) == NULL)
875 {
876 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
877 ERR_error_string(ERR_get_error(), NULL));
878 SetDead(client_p);
879 exit_client(client_p, "SSL_new failed");
880 return;
881 }
882
883 SSL_set_fd(fd->ssl, fd->fd);
884
885 if (!EmptyString(conf->cipher_list))
886 SSL_set_cipher_list(client_p->connection->fd.ssl, conf->cipher_list);
887
888 ssl_server_handshake(NULL, client_p);
889 }
890 #endif
891
892 /* serv_connect_callback() - complete a server connection.
893 *
894 * This routine is called after the server connection attempt has
895 * completed. If unsucessful, an error is sent to ops and the client
896 * is closed. If sucessful, it goes through the initialisation/check
897 * procedures, the capabilities are sent, and the socket is then
898 * marked for reading.
899 */
900 static void
901 serv_connect_callback(fde_t *fd, int status, void *data)
902 {
903 struct Client *const client_p = data;
904 const struct MaskItem *conf = NULL;
905
906 /* First, make sure it's a real client! */
907 assert(client_p);
908 assert(&client_p->connection->fd == fd);
909
910 /* Next, for backward purposes, record the ip of the server */
911 memcpy(&client_p->connection->ip, &fd->connect.hostaddr,
912 sizeof(struct irc_ssaddr));
913
914 /* Check the status */
915 if (status != COMM_OK)
916 {
917 /* We have an error, so report it and quit */
918 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
919 "Error connecting to %s: %s",
920 get_client_name(client_p, SHOW_IP), comm_errstr(status));
921 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
922 "Error connecting to %s: %s",
923 get_client_name(client_p, MASK_IP), comm_errstr(status));
924
925 /*
926 * If a fd goes bad, call dead_link() the socket is no
927 * longer valid for reading or writing.
928 */
929 dead_link_on_write(client_p, 0);
930 return;
931 }
932
933 /* COMM_OK, so continue the connection procedure */
934 /* Get the C/N lines */
935 conf = find_conf_name(&client_p->connection->confs,
936 client_p->name, CONF_SERVER);
937 if (conf == NULL)
938 {
939 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
940 "Lost connect{} block for %s", get_client_name(client_p, SHOW_IP));
941 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
942 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
943
944 exit_client(client_p, "Lost connect{} block");
945 return;
946 }
947
948 /* Next, send the initial handshake */
949 SetHandshake(client_p);
950
951 #ifdef HAVE_LIBCRYPTO
952 if (IsConfSSL(conf))
953 {
954 ssl_connect_init(client_p, conf, fd);
955 return;
956 }
957 #endif
958
959 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
960
961 send_capabilities(client_p);
962
963 sendto_one(client_p, "SERVER %s 1 :%s%s", me.name,
964 ConfigServerHide.hidden ? "(H) " : "", me.info);
965
966 /*
967 * If we've been marked dead because a send failed, just exit
968 * here now and save everyone the trouble of us ever existing.
969 */
970 if (IsDead(client_p))
971 {
972 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
973 "%s went dead during handshake", get_client_name(client_p, SHOW_IP));
974 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
975 "%s went dead during handshake", get_client_name(client_p, MASK_IP));
976 return;
977 }
978
979 /* don't move to serv_list yet -- we haven't sent a burst! */
980 /* If we get here, we're ok, so lets start reading some data */
981 comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
982 }
983
984 struct Client *
985 find_servconn_in_progress(const char *name)
986 {
987 dlink_node *ptr;
988 struct Client *cptr;
989
990 DLINK_FOREACH(ptr, unknown_list.head)
991 {
992 cptr = ptr->data;
993
994 if (cptr && cptr->name[0])
995 if (!match(name, cptr->name))
996 return cptr;
997 }
998
999 return NULL;
1000 }

Properties

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