ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/server.c
Revision: 3450
Committed: Thu May 1 19:14:55 2014 UTC (12 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 29767 byte(s)
Log Message:
- server.c:hunt_server(): save extra has_wildcards() call everytime hunt_server()
  finds a client/server in the hash tables.

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

Properties

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