ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/server.c
Revision: 6633
Committed: Sat Oct 24 15:15:33 2015 UTC (9 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 29246 byte(s)
Log Message:
- Use client->name when updating the fd's associated name record with fd_note()

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 /* TODO: change this to set active flag to 0 when added to event! --Habeeb */
260 if (GlobalSetOptions.autoconn == 0)
261 return;
262
263 DLINK_FOREACH(node, server_items.head)
264 {
265 struct MaskItem *conf = node->data;
266
267 assert(conf->type == CONF_SERVER);
268
269 /* Also when already connecting! (update holdtimes) --SRB
270 */
271 if (!conf->port || !IsConfAllowAutoConn(conf))
272 continue;
273
274
275 /* Skip this entry if the use of it is still on hold until
276 * future. Otherwise handle this entry (and set it on hold
277 * until next time). Will reset only hold times, if already
278 * made one successfull connection... [this algorithm is
279 * a bit fuzzy... -- msa >;) ]
280 */
281 if (conf->until > CurrentTime)
282 continue;
283
284 assert(conf->class);
285
286 conf->until = CurrentTime + conf->class->con_freq;
287
288 /*
289 * Found a CONNECT config with port specified, scan clients
290 * and see if this server is already connected?
291 */
292 if (hash_find_server(conf->name))
293 continue;
294
295 if (conf->class->ref_count < conf->class->max_total)
296 {
297 /* Move this entry to the end of the list, if not already last */
298 if (node->next)
299 {
300 dlinkDelete(node, &server_items);
301 dlinkAddTail(conf, &conf->node, &server_items);
302 }
303
304 if (find_servconn_in_progress(conf->name))
305 return;
306
307 /*
308 * We used to only print this if serv_connect() actually
309 * succeeded, but since comm_tcp_connect() can call the callback
310 * immediately if there is an error, we were getting error messages
311 * in the wrong order. SO, we just print out the activated line,
312 * and let serv_connect() / serv_connect_callback() print an
313 * error afterwards if it fails.
314 * -- adrian
315 */
316 if (ConfigServerHide.hide_server_ips)
317 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
318 "Connection to %s activated.",
319 conf->name);
320 else
321 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
322 "Connection to %s[%s] activated.",
323 conf->name, conf->host);
324
325 serv_connect(conf, NULL);
326 /* We connect only one at time... */
327 return;
328 }
329 }
330 }
331
332 int
333 valid_servname(const char *name)
334 {
335 unsigned int dots = 0;
336 const char *p = name;
337
338 for (; *p; ++p)
339 {
340 if (!IsServChar(*p))
341 return 0;
342
343 if (*p == '.')
344 ++dots;
345 }
346
347 return dots && (p - name) <= HOSTLEN;
348 }
349
350 int
351 check_server(const char *name, struct Client *client_p)
352 {
353 dlink_node *node = NULL;
354 struct MaskItem *conf = NULL;
355 struct MaskItem *server_conf = NULL;
356 int error = -1;
357
358 assert(client_p);
359
360 /* Loop through looking for all possible connect items that might work */
361 DLINK_FOREACH(node, server_items.head)
362 {
363 conf = node->data;
364
365 if (match(name, conf->name))
366 continue;
367
368 error = -3;
369
370 /* XXX: Fix me for IPv6 */
371 /* XXX sockhost is the IPv4 ip as a string */
372 if (!match(conf->host, client_p->host) ||
373 !match(conf->host, client_p->sockhost))
374 {
375 error = -2;
376
377 if (!match_conf_password(client_p->connection->password, conf))
378 return -2;
379
380 if (!EmptyString(conf->certfp))
381 if (EmptyString(client_p->certfp) || strcasecmp(client_p->certfp, conf->certfp))
382 return -4;
383
384 server_conf = conf;
385 }
386 }
387
388 if (server_conf == NULL)
389 return error;
390
391 attach_conf(client_p, server_conf);
392
393 switch (server_conf->aftype)
394 {
395 case AF_INET6:
396 {
397 const struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&server_conf->addr;
398
399 if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
400 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
401 break;
402 }
403 case AF_INET:
404 {
405 const struct sockaddr_in *v4 = (struct sockaddr_in *)&server_conf->addr;
406
407 if (v4->sin_addr.s_addr == INADDR_NONE)
408 memcpy(&server_conf->addr, &client_p->connection->ip, sizeof(struct irc_ssaddr));
409 break;
410 }
411 }
412
413 return 0;
414 }
415
416 /* add_capability()
417 *
418 * inputs - string name of CAPAB
419 * - int flag of capability
420 * output - NONE
421 * side effects - Adds given capability name and bit mask to
422 * current supported capabilities. This allows
423 * modules to dynamically add or subtract their capability.
424 */
425 void
426 add_capability(const char *name, unsigned int flag)
427 {
428 struct Capability *cap = MyCalloc(sizeof(*cap));
429
430 cap->name = xstrdup(name);
431 cap->cap = flag;
432 dlinkAdd(cap, &cap->node, &server_capabilities_list);
433 }
434
435 /* delete_capability()
436 *
437 * inputs - string name of CAPAB
438 * output - NONE
439 * side effects - delete given capability from ones known.
440 */
441 void
442 delete_capability(const char *name)
443 {
444 dlink_node *node = NULL, *node_next = NULL;
445
446 DLINK_FOREACH_SAFE(node, node_next, server_capabilities_list.head)
447 {
448 struct Capability *cap = node->data;
449
450 if (!irccmp(cap->name, name))
451 {
452 dlinkDelete(node, &server_capabilities_list);
453 MyFree(cap->name);
454 MyFree(cap);
455 }
456 }
457 }
458
459 /*
460 * find_capability()
461 *
462 * inputs - string name of capab to find
463 * output - 0 if not found CAPAB otherwise
464 * side effects - none
465 */
466 unsigned int
467 find_capability(const char *name)
468 {
469 const dlink_node *node = NULL;
470
471 DLINK_FOREACH(node, server_capabilities_list.head)
472 {
473 const struct Capability *cap = node->data;
474
475 if (!irccmp(cap->name, name))
476 return cap->cap;
477 }
478
479 return 0;
480 }
481
482 /* send_capabilities()
483 *
484 * inputs - Client pointer to send to
485 * - int flag of capabilities that this server can send
486 * output - NONE
487 * side effects - send the CAPAB line to a server -orabidoo
488 *
489 */
490 void
491 send_capabilities(struct Client *client_p)
492 {
493 char buf[IRCD_BUFSIZE] = "";
494 const dlink_node *node = NULL;
495
496 DLINK_FOREACH(node, server_capabilities_list.head)
497 {
498 const struct Capability *cap = node->data;
499
500 strlcat(buf, cap->name, sizeof(buf));
501
502 if (node->next)
503 strlcat(buf, " ", sizeof(buf));
504 }
505
506 sendto_one(client_p, "CAPAB :%s", buf);
507 }
508
509 /*
510 * show_capabilities - show current server capabilities
511 *
512 * inputs - pointer to a struct Client
513 * output - pointer to static string
514 * side effects - build up string representing capabilities of server listed
515 */
516 const char *
517 show_capabilities(const struct Client *target_p)
518 {
519 static char msgbuf[IRCD_BUFSIZE] = "";
520 const dlink_node *node = NULL;
521
522 strlcpy(msgbuf, "TS", sizeof(msgbuf));
523
524 DLINK_FOREACH(node, server_capabilities_list.head)
525 {
526 const struct Capability *cap = node->data;
527
528 if (!IsCapable(target_p, cap->cap))
529 continue;
530
531 strlcat(msgbuf, " ", sizeof(msgbuf));
532 strlcat(msgbuf, cap->name, sizeof(msgbuf));
533 }
534
535 return msgbuf;
536 }
537
538 /* make_server()
539 *
540 * inputs - pointer to client struct
541 * output - pointer to struct Server
542 * side effects - add's an Server information block to a client
543 * if it was not previously allocated.
544 */
545 struct Server *
546 make_server(struct Client *client_p)
547 {
548 if (client_p->serv == NULL)
549 client_p->serv = MyCalloc(sizeof(struct Server));
550
551 return client_p->serv;
552 }
553
554 /* New server connection code
555 * Based upon the stuff floating about in s_bsd.c
556 * -- adrian
557 */
558
559 /* serv_connect() - initiate a server connection
560 *
561 * inputs - pointer to conf
562 * - pointer to client doing the connect
563 * output -
564 * side effects -
565 *
566 * This code initiates a connection to a server. It first checks to make
567 * sure the given server exists. If this is the case, it creates a socket,
568 * creates a client, saves the socket information in the client, and
569 * initiates a connection to the server through comm_connect_tcp(). The
570 * completion of this goes through serv_completed_connection().
571 *
572 * We return 1 if the connection is attempted, since we don't know whether
573 * it suceeded or not, and 0 if it fails in here somewhere.
574 */
575 int
576 serv_connect(struct MaskItem *conf, struct Client *by)
577 {
578 struct Client *client_p = NULL;
579 char buf[HOSTIPLEN + 1] = "";
580
581 /* conversion structs */
582 struct sockaddr_in *v4;
583
584 /* Make sure conf is useful */
585 assert(conf);
586
587 getnameinfo((const struct sockaddr *)&conf->addr, conf->addr.ss_len,
588 buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
589 ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", conf->name, conf->host,
590 buf);
591
592 /* Still processing a DNS lookup? -> exit */
593 if (conf->dns_pending)
594 {
595 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
596 "Error connecting to %s: DNS lookup for connect{} in progress.",
597 conf->name);
598 return 0;
599 }
600
601 if (conf->dns_failed)
602 {
603 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
604 "Error connecting to %s: DNS lookup for connect{} failed.",
605 conf->name);
606 return 0;
607 }
608
609 /* Make sure this server isn't already connected
610 * Note: conf should ALWAYS be a valid C: line
611 */
612 if ((client_p = hash_find_server(conf->name)))
613 {
614 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
615 "Server %s already present from %s",
616 conf->name, get_client_name(client_p, SHOW_IP));
617 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
618 "Server %s already present from %s",
619 conf->name, get_client_name(client_p, MASK_IP));
620 if (by && IsClient(by) && !MyClient(by))
621 sendto_one_notice(by, &me, ":Server %s already present from %s",
622 conf->name, get_client_name(client_p, MASK_IP));
623 return 0;
624 }
625
626 /* Create a local client */
627 client_p = make_client(NULL);
628
629 /* Copy in the server, hostname, fd */
630 strlcpy(client_p->name, conf->name, sizeof(client_p->name));
631 strlcpy(client_p->host, conf->host, sizeof(client_p->host));
632
633 /* We already converted the ip once, so lets use it - stu */
634 strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
635
636 /* create a socket for the server connection */
637 if (comm_open(&client_p->connection->fd, conf->addr.ss.ss_family, SOCK_STREAM, 0, NULL) < 0)
638 {
639 /* Eek, failure to create the socket */
640 report_error(L_ALL, "opening stream socket to %s: %s", conf->name, errno);
641
642 SetDead(client_p);
643 exit_client(client_p, "Connection failed");
644 return 0;
645 }
646
647 /* servernames are always guaranteed under HOSTLEN chars */
648 fd_note(&client_p->connection->fd, "Server: %s", client_p->name);
649
650 /* Attach config entries to client here rather than in
651 * serv_connect_callback(). This to avoid null pointer references.
652 */
653 if (!attach_connect_block(client_p, conf->name, conf->host))
654 {
655 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
656 "Host %s is not enabled for connecting: no connect {} block",
657 conf->name);
658 if (by && IsClient(by) && !MyClient(by))
659 sendto_one_notice(by, &me, ":Connect to host %s failed: no connect {} block", client_p->name);
660
661 SetDead(client_p);
662 exit_client(client_p, "Connection failed");
663 return 0;
664 }
665
666 /* at this point we have a connection in progress and C/N lines
667 * attached to the client, the socket info should be saved in the
668 * client and it should either be resolved or have a valid address.
669 *
670 * The socket has been connected or connect is in progress.
671 */
672 make_server(client_p);
673
674 if (by && IsClient(by))
675 strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
676 else
677 strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
678
679 SetConnecting(client_p);
680 client_p->connection->aftype = conf->aftype;
681
682 /* Now, initiate the connection */
683 /* XXX assume that a non 0 type means a specific bind address
684 * for this connect.
685 */
686 switch (conf->aftype)
687 {
688 case AF_INET:
689 v4 = (struct sockaddr_in*)&conf->bind;
690 if (v4->sin_addr.s_addr)
691 {
692 struct irc_ssaddr ipn;
693 memset(&ipn, 0, sizeof(struct irc_ssaddr));
694 ipn.ss.ss_family = AF_INET;
695 ipn.ss_port = 0;
696 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
697 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
698 (struct sockaddr *)&ipn, ipn.ss_len,
699 serv_connect_callback, client_p, conf->aftype,
700 CONNECTTIMEOUT);
701 }
702 else if (ConfigServerInfo.specific_ipv4_vhost)
703 {
704 struct irc_ssaddr ipn;
705 memset(&ipn, 0, sizeof(struct irc_ssaddr));
706 ipn.ss.ss_family = AF_INET;
707 ipn.ss_port = 0;
708 memcpy(&ipn, &ConfigServerInfo.ip, sizeof(struct irc_ssaddr));
709 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
710 (struct sockaddr *)&ipn, ipn.ss_len,
711 serv_connect_callback, client_p, conf->aftype,
712 CONNECTTIMEOUT);
713 }
714 else
715 comm_connect_tcp(&client_p->connection->fd, conf->host, conf->port,
716 NULL, 0, serv_connect_callback, client_p, conf->aftype,
717 CONNECTTIMEOUT);
718 break;
719 case AF_INET6:
720 {
721 struct irc_ssaddr ipn;
722 struct sockaddr_in6 *v6;
723 struct sockaddr_in6 *v6conf;
724
725 memset(&ipn, 0, sizeof(struct irc_ssaddr));
726 v6conf = (struct sockaddr_in6 *)&conf->bind;
727 v6 = (struct sockaddr_in6 *)&ipn;
728
729 if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr, sizeof(struct in6_addr)))
730 {
731 memcpy(&ipn, &conf->bind, sizeof(struct irc_ssaddr));
732 ipn.ss.ss_family = AF_INET6;
733 ipn.ss_port = 0;
734 comm_connect_tcp(&client_p->connection->fd,
735 conf->host, conf->port,
736 (struct sockaddr *)&ipn, ipn.ss_len,
737 serv_connect_callback, client_p,
738 conf->aftype, CONNECTTIMEOUT);
739 }
740 else if (ConfigServerInfo.specific_ipv6_vhost)
741 {
742 memcpy(&ipn, &ConfigServerInfo.ip6, sizeof(struct irc_ssaddr));
743 ipn.ss.ss_family = AF_INET6;
744 ipn.ss_port = 0;
745 comm_connect_tcp(&client_p->connection->fd,
746 conf->host, conf->port,
747 (struct sockaddr *)&ipn, ipn.ss_len,
748 serv_connect_callback, client_p,
749 conf->aftype, CONNECTTIMEOUT);
750 }
751 else
752 comm_connect_tcp(&client_p->connection->fd,
753 conf->host, conf->port,
754 NULL, 0, serv_connect_callback, client_p,
755 conf->aftype, CONNECTTIMEOUT);
756 }
757 }
758
759 return 1;
760 }
761
762 #ifdef HAVE_LIBCRYPTO
763 static void
764 finish_ssl_server_handshake(struct Client *client_p)
765 {
766 struct MaskItem *conf = NULL;
767
768 conf = find_conf_name(&client_p->connection->confs,
769 client_p->name, CONF_SERVER);
770 if (conf == NULL)
771 {
772 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
773 "Lost connect{} block for %s", get_client_name(client_p, SHOW_IP));
774 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
775 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
776
777 exit_client(client_p, "Lost connect{} block");
778 return;
779 }
780
781 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
782
783 send_capabilities(client_p);
784
785 sendto_one(client_p, "SERVER %s 1 :%s%s",
786 me.name, ConfigServerHide.hidden ? "(H) " : "",
787 me.info);
788
789 /*
790 * If we've been marked dead because a send failed, just exit
791 * here now and save everyone the trouble of us ever existing.
792 */
793 if (IsDead(client_p))
794 {
795 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
796 "%s went dead during handshake", get_client_name(client_p, SHOW_IP));
797 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
798 "%s went dead during handshake", get_client_name(client_p, MASK_IP));
799 return;
800 }
801
802 /* don't move to serv_list yet -- we haven't sent a burst! */
803 /* If we get here, we're ok, so lets start reading some data */
804 comm_setselect(&client_p->connection->fd, COMM_SELECT_READ, read_packet, client_p, 0);
805 }
806
807 static void
808 ssl_server_handshake(fde_t *fd, void *data)
809 {
810 struct Client *client_p = data;
811 X509 *cert = NULL;
812 int ret = 0;
813
814 if ((ret = SSL_connect(client_p->connection->fd.ssl)) <= 0)
815 {
816 if ((CurrentTime - client_p->connection->firsttime) > CONNECTTIMEOUT)
817 {
818 exit_client(client_p, "Timeout during SSL handshake");
819 return;
820 }
821
822 switch (SSL_get_error(client_p->connection->fd.ssl, ret))
823 {
824 case SSL_ERROR_WANT_WRITE:
825 comm_setselect(&client_p->connection->fd, COMM_SELECT_WRITE,
826 ssl_server_handshake, client_p, CONNECTTIMEOUT);
827 return;
828 case SSL_ERROR_WANT_READ:
829 comm_setselect(&client_p->connection->fd, COMM_SELECT_READ,
830 ssl_server_handshake, client_p, CONNECTTIMEOUT);
831 return;
832 default:
833 {
834 const char *sslerr = ERR_error_string(ERR_get_error(), NULL);
835 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
836 "Error connecting to %s: %s", client_p->name,
837 sslerr ? sslerr : "unknown SSL error");
838 exit_client(client_p, "Error during SSL handshake");
839 return;
840 }
841 }
842 }
843
844 comm_settimeout(&client_p->connection->fd, 0, NULL, NULL);
845
846 if ((cert = SSL_get_peer_certificate(client_p->connection->fd.ssl)))
847 {
848 int res = SSL_get_verify_result(client_p->connection->fd.ssl);
849 char buf[EVP_MAX_MD_SIZE * 2 + 1] = "";
850 unsigned char md[EVP_MAX_MD_SIZE] = "";
851
852 if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
853 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
854 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
855 {
856 unsigned int n = 0;
857
858 if (X509_digest(cert, ConfigServerInfo.message_digest_algorithm, md, &n))
859 {
860 binary_to_hex(md, buf, n);
861 client_p->certfp = xstrdup(buf);
862 }
863 }
864 else
865 ilog(LOG_TYPE_IRCD, "Server %s!%s@%s gave bad SSL client certificate: %d",
866 client_p->name, client_p->username, client_p->host, res);
867 X509_free(cert);
868 }
869
870 finish_ssl_server_handshake(client_p);
871 }
872
873 static void
874 ssl_connect_init(struct Client *client_p, const struct MaskItem *conf, fde_t *fd)
875 {
876 if ((client_p->connection->fd.ssl = SSL_new(ConfigServerInfo.client_ctx)) == NULL)
877 {
878 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
879 ERR_error_string(ERR_get_error(), NULL));
880 SetDead(client_p);
881 exit_client(client_p, "SSL_new failed");
882 return;
883 }
884
885 SSL_set_fd(fd->ssl, fd->fd);
886
887 if (!EmptyString(conf->cipher_list))
888 SSL_set_cipher_list(client_p->connection->fd.ssl, conf->cipher_list);
889
890 ssl_server_handshake(NULL, client_p);
891 }
892 #endif
893
894 /* serv_connect_callback() - complete a server connection.
895 *
896 * This routine is called after the server connection attempt has
897 * completed. If unsucessful, an error is sent to ops and the client
898 * is closed. If sucessful, it goes through the initialisation/check
899 * procedures, the capabilities are sent, and the socket is then
900 * marked for reading.
901 */
902 static void
903 serv_connect_callback(fde_t *fd, int status, void *data)
904 {
905 struct Client *const client_p = data;
906 const struct MaskItem *conf = NULL;
907
908 /* First, make sure it's a real client! */
909 assert(client_p);
910 assert(&client_p->connection->fd == fd);
911
912 /* Next, for backward purposes, record the ip of the server */
913 memcpy(&client_p->connection->ip, &fd->connect.hostaddr,
914 sizeof(struct irc_ssaddr));
915
916 /* Check the status */
917 if (status != COMM_OK)
918 {
919 /* We have an error, so report it and quit */
920 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
921 "Error connecting to %s: %s",
922 get_client_name(client_p, SHOW_IP), comm_errstr(status));
923 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
924 "Error connecting to %s: %s",
925 get_client_name(client_p, MASK_IP), comm_errstr(status));
926
927 /*
928 * If a fd goes bad, call dead_link() the socket is no
929 * longer valid for reading or writing.
930 */
931 dead_link_on_write(client_p, 0);
932 return;
933 }
934
935 /* COMM_OK, so continue the connection procedure */
936 /* Get the C/N lines */
937 conf = find_conf_name(&client_p->connection->confs,
938 client_p->name, CONF_SERVER);
939 if (conf == NULL)
940 {
941 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
942 "Lost connect{} block for %s", get_client_name(client_p, SHOW_IP));
943 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
944 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
945
946 exit_client(client_p, "Lost connect{} block");
947 return;
948 }
949
950 /* Next, send the initial handshake */
951 SetHandshake(client_p);
952
953 #ifdef HAVE_LIBCRYPTO
954 if (IsConfSSL(conf))
955 {
956 ssl_connect_init(client_p, conf, fd);
957 return;
958 }
959 #endif
960
961 sendto_one(client_p, "PASS %s TS %d %s", conf->spasswd, TS_CURRENT, me.id);
962
963 send_capabilities(client_p);
964
965 sendto_one(client_p, "SERVER %s 1 :%s%s", me.name,
966 ConfigServerHide.hidden ? "(H) " : "", me.info);
967
968 /*
969 * If we've been marked dead because a send failed, just exit
970 * here now and save everyone the trouble of us ever existing.
971 */
972 if (IsDead(client_p))
973 {
974 sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
975 "%s went dead during handshake", get_client_name(client_p, SHOW_IP));
976 sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
977 "%s went dead during handshake", get_client_name(client_p, MASK_IP));
978 return;
979 }
980
981 /* don't move to serv_list yet -- we haven't sent a burst! */
982 /* If we get here, we're ok, so lets start reading some data */
983 comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
984 }
985
986 struct Client *
987 find_servconn_in_progress(const char *name)
988 {
989 dlink_node *ptr;
990 struct Client *cptr;
991
992 DLINK_FOREACH(ptr, unknown_list.head)
993 {
994 cptr = ptr->data;
995
996 if (cptr && cptr->name[0])
997 if (!match(name, cptr->name))
998 return cptr;
999 }
1000
1001 return NULL;
1002 }

Properties

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