ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/server.c
Revision: 3303
Committed: Sun Apr 13 11:19:36 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/s_serv.c
File size: 29892 byte(s)
Log Message:
- s_serv.c, m_server.c: moved all netburst related code to m_server.c

File Contents

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

Properties

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