ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/server.c
Revision: 1308
Committed: Sat Mar 24 13:37:05 2012 UTC (13 years, 5 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/s_serv.c
File size: 47095 byte(s)
Log Message:
- ssl_server_handshake(): better error reporting

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * s_serv.c: Server related functions.
4 *
5 * Copyright (C) 2005 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #ifdef HAVE_LIBCRYPTO
27 #include <openssl/rsa.h>
28 #include "rsa.h"
29 #endif
30 #include "list.h"
31 #include "channel.h"
32 #include "channel_mode.h"
33 #include "client.h"
34 #include "dbuf.h"
35 #include "event.h"
36 #include "fdlist.h"
37 #include "hash.h"
38 #include "irc_string.h"
39 #include "sprintf_irc.h"
40 #include "ircd.h"
41 #include "ircd_defs.h"
42 #include "s_bsd.h"
43 #include "numeric.h"
44 #include "packet.h"
45 #include "irc_res.h"
46 #include "s_conf.h"
47 #include "s_serv.h"
48 #include "s_log.h"
49 #include "s_misc.h"
50 #include "s_user.h"
51 #include "send.h"
52 #include "memory.h"
53 #include "channel.h" /* chcap_usage_counts stuff...*/
54 #include "parse.h"
55
56 #define MIN_CONN_FREQ 300
57
58 static dlink_list cap_list = { NULL, NULL, 0 };
59 static void server_burst(struct Client *);
60 static void burst_all(struct Client *);
61 static void send_tb(struct Client *client_p, struct Channel *chptr);
62
63 static CNCB serv_connect_callback;
64
65 static void start_io(struct Client *);
66 static void burst_members(struct Client *, struct Channel *);
67
68 /*
69 * write_links_file
70 *
71 * inputs - void pointer which is not used
72 * output - NONE
73 * side effects - called from an event, write out list of linked servers
74 * but in no particular order.
75 */
76 void
77 write_links_file(void* notused)
78 {
79 MessageFileLine *next_mptr = 0;
80 MessageFileLine *mptr = 0;
81 MessageFileLine *currentMessageLine = 0;
82 MessageFileLine *newMessageLine = 0;
83 MessageFile *MessageFileptr;
84 const char *p;
85 FBFILE *file;
86 char buff[512];
87 dlink_node *ptr;
88
89 MessageFileptr = &ConfigFileEntry.linksfile;
90
91 if ((file = fbopen(MessageFileptr->fileName, "w")) == NULL)
92 return;
93
94 for (mptr = MessageFileptr->contentsOfFile; mptr; mptr = next_mptr)
95 {
96 next_mptr = mptr->next;
97 MyFree(mptr);
98 }
99
100 MessageFileptr->contentsOfFile = NULL;
101 currentMessageLine = NULL;
102
103 DLINK_FOREACH(ptr, global_serv_list.head)
104 {
105 size_t nbytes = 0;
106 struct Client *target_p = ptr->data;
107
108 /* skip ourselves, we send ourselves in /links */
109 if (IsMe(target_p))
110 continue;
111
112 /* skip hidden servers */
113 if (IsHidden(target_p) && !ConfigServerHide.disable_hidden)
114 continue;
115
116 if (target_p->info[0])
117 p = target_p->info;
118 else
119 p = "(Unknown Location)";
120
121 newMessageLine = MyMalloc(sizeof(MessageFileLine));
122
123 /* Attempt to format the file in such a way it follows the usual links output
124 * ie "servername uplink :hops info"
125 * Mostly for aesthetic reasons - makes it look pretty in mIRC ;)
126 * - madmax
127 */
128
129 /*
130 * For now, check this ircsprintf wont overflow - it shouldnt on a
131 * default config but it is configurable..
132 * This should be changed to an snprintf at some point, but I'm wanting to
133 * know if this is a cause of a bug - cryogen
134 */
135 assert(strlen(target_p->name) + strlen(me.name) + 6 + strlen(p) <=
136 MESSAGELINELEN);
137 ircsprintf(newMessageLine->line, "%s %s :1 %s",
138 target_p->name, me.name, p);
139 newMessageLine->next = NULL;
140
141 if (MessageFileptr->contentsOfFile)
142 {
143 if (currentMessageLine)
144 currentMessageLine->next = newMessageLine;
145 currentMessageLine = newMessageLine;
146 }
147 else
148 {
149 MessageFileptr->contentsOfFile = newMessageLine;
150 currentMessageLine = newMessageLine;
151 }
152
153 nbytes = ircsprintf(buff, "%s %s :1 %s\n", target_p->name, me.name, p);
154 fbputs(buff, file, nbytes);
155 }
156
157 fbclose(file);
158 }
159
160 /* hunt_server()
161 * Do the basic thing in delivering the message (command)
162 * across the relays to the specific server (server) for
163 * actions.
164 *
165 * Note: The command is a format string and *MUST* be
166 * of prefixed style (e.g. ":%s COMMAND %s ...").
167 * Command can have only max 8 parameters.
168 *
169 * server parv[server] is the parameter identifying the
170 * target server.
171 *
172 * *WARNING*
173 * parv[server] is replaced with the pointer to the
174 * real servername from the matched client (I'm lazy
175 * now --msa).
176 *
177 * returns: (see #defines)
178 */
179 int
180 hunt_server(struct Client *client_p, struct Client *source_p, const char *command,
181 int server, int parc, char *parv[])
182 {
183 struct Client *target_p = NULL;
184 struct Client *target_tmp = NULL;
185 dlink_node *ptr;
186 int wilds;
187
188 /* Assume it's me, if no server
189 */
190 if (parc <= server || EmptyString(parv[server]) ||
191 match(me.name, parv[server]) ||
192 match(parv[server], me.name) ||
193 !strcmp(parv[server], me.id))
194 return(HUNTED_ISME);
195
196 /* These are to pickup matches that would cause the following
197 * message to go in the wrong direction while doing quick fast
198 * non-matching lookups.
199 */
200 if (MyClient(source_p))
201 target_p = hash_find_client(parv[server]);
202 else
203 target_p = find_person(client_p, parv[server]);
204
205 if (target_p)
206 if (target_p->from == source_p->from && !MyConnect(target_p))
207 target_p = NULL;
208
209 if (target_p == NULL && (target_p = hash_find_server(parv[server])))
210 if (target_p->from == source_p->from && !MyConnect(target_p))
211 target_p = NULL;
212
213 collapse(parv[server]);
214 wilds = (strchr(parv[server], '?') || strchr(parv[server], '*'));
215
216 /* Again, if there are no wild cards involved in the server
217 * name, use the hash lookup
218 */
219 if (target_p == NULL)
220 {
221 if (!wilds)
222 {
223 if (!(target_p = hash_find_server(parv[server])))
224 {
225 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
226 me.name, source_p->name, parv[server]);
227 return(HUNTED_NOSUCH);
228 }
229 }
230 else
231 {
232 DLINK_FOREACH(ptr, global_client_list.head)
233 {
234 target_tmp = ptr->data;
235
236 if (match(parv[server], target_tmp->name))
237 {
238 if (target_tmp->from == source_p->from && !MyConnect(target_tmp))
239 continue;
240 target_p = ptr->data;
241
242 if (IsRegistered(target_p) && (target_p != client_p))
243 break;
244 }
245 }
246 }
247 }
248
249 if (target_p != NULL)
250 {
251 if(!IsRegistered(target_p))
252 {
253 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
254 me.name, source_p->name, parv[server]);
255 return HUNTED_NOSUCH;
256 }
257
258 if (IsMe(target_p) || MyClient(target_p))
259 return HUNTED_ISME;
260
261 if (!match(target_p->name, parv[server]))
262 parv[server] = target_p->name;
263
264 /* This is a little kludgy but should work... */
265 if (IsClient(source_p) &&
266 ((MyConnect(target_p) && IsCapable(target_p, CAP_TS6)) ||
267 (!MyConnect(target_p) && IsCapable(target_p->from, CAP_TS6))))
268 parv[0] = ID(source_p);
269
270 sendto_one(target_p, command, parv[0],
271 parv[1], parv[2], parv[3], parv[4],
272 parv[5], parv[6], parv[7], parv[8]);
273 return(HUNTED_PASS);
274 }
275
276 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
277 me.name, source_p->name, parv[server]);
278 return(HUNTED_NOSUCH);
279 }
280
281 /* try_connections()
282 *
283 * inputs - void pointer which is not used
284 * output - NONE
285 * side effects -
286 * scan through configuration and try new connections.
287 * Returns the calendar time when the next call to this
288 * function should be made latest. (No harm done if this
289 * is called earlier or later...)
290 */
291 void
292 try_connections(void *unused)
293 {
294 dlink_node *ptr;
295 struct ConfItem *conf;
296 struct AccessItem *aconf;
297 struct ClassItem *cltmp;
298 int confrq;
299
300 /* TODO: change this to set active flag to 0 when added to event! --Habeeb */
301 if (GlobalSetOptions.autoconn == 0)
302 return;
303
304 DLINK_FOREACH(ptr, server_items.head)
305 {
306 conf = ptr->data;
307 aconf = map_to_conf(conf);
308
309 /* Also when already connecting! (update holdtimes) --SRB
310 */
311 if (!(aconf->status & CONF_SERVER) || !aconf->port ||
312 !(IsConfAllowAutoConn(aconf)))
313 continue;
314
315 cltmp = map_to_conf(aconf->class_ptr);
316
317 /* Skip this entry if the use of it is still on hold until
318 * future. Otherwise handle this entry (and set it on hold
319 * until next time). Will reset only hold times, if already
320 * made one successfull connection... [this algorithm is
321 * a bit fuzzy... -- msa >;) ]
322 */
323 if (aconf->hold > CurrentTime)
324 continue;
325
326 if (cltmp == NULL)
327 confrq = DEFAULT_CONNECTFREQUENCY;
328 else
329 {
330 confrq = ConFreq(cltmp);
331 if (confrq < MIN_CONN_FREQ )
332 confrq = MIN_CONN_FREQ;
333 }
334
335 aconf->hold = CurrentTime + confrq;
336
337 /* Found a CONNECT config with port specified, scan clients
338 * and see if this server is already connected?
339 */
340 if (hash_find_server(conf->name) != NULL)
341 continue;
342
343 if (CurrUserCount(cltmp) < MaxTotal(cltmp))
344 {
345 /* Go to the end of the list, if not already last */
346 if (ptr->next != NULL)
347 {
348 dlinkDelete(ptr, &server_items);
349 dlinkAddTail(conf, &conf->node, &server_items);
350 }
351
352 if (find_servconn_in_progress(conf->name))
353 return;
354
355 /* We used to only print this if serv_connect() actually
356 * succeeded, but since comm_tcp_connect() can call the callback
357 * immediately if there is an error, we were getting error messages
358 * in the wrong order. SO, we just print out the activated line,
359 * and let serv_connect() / serv_connect_callback() print an
360 * error afterwards if it fails.
361 * -- adrian
362 */
363 if (ConfigServerHide.hide_server_ips)
364 sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s activated.",
365 conf->name);
366 else
367 sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s[%s] activated.",
368 conf->name, aconf->host);
369
370 serv_connect(aconf, NULL);
371 /* We connect only one at time... */
372 return;
373 }
374 }
375 }
376
377 int
378 valid_servname(const char *name)
379 {
380 unsigned int length = 0;
381 unsigned int dots = 0;
382 const char *p = name;
383
384 for (; *p; ++p)
385 {
386 if (!IsServChar(*p))
387 return 0;
388
389 ++length;
390
391 if (*p == '.')
392 ++dots;
393 }
394
395 return dots != 0 && length <= HOSTLEN;
396 }
397
398 int
399 check_server(const char *name, struct Client *client_p)
400 {
401 dlink_node *ptr;
402 struct ConfItem *conf = NULL;
403 struct ConfItem *server_conf = NULL;
404 struct AccessItem *server_aconf = NULL;
405 struct AccessItem *aconf = NULL;
406 int error = -1;
407
408 assert(client_p != NULL);
409
410 if (client_p == NULL)
411 return(error);
412
413 if (strlen(name) > HOSTLEN)
414 return(-4);
415
416 /* loop through looking for all possible connect items that might work */
417 DLINK_FOREACH(ptr, server_items.head)
418 {
419 conf = ptr->data;
420 aconf = map_to_conf(conf);
421
422 if (!match(name, conf->name))
423 continue;
424
425 error = -3;
426
427 /* XXX: Fix me for IPv6 */
428 /* XXX sockhost is the IPv4 ip as a string */
429 if (match(aconf->host, client_p->host) ||
430 match(aconf->host, client_p->sockhost))
431 {
432 error = -2;
433 {
434 /* A NULL password is as good as a bad one */
435 if (EmptyString(client_p->localClient->passwd))
436 return(-2);
437
438 /* code in s_conf.c should not have allowed this to be NULL */
439 if (aconf->passwd == NULL)
440 return(-2);
441
442 if (IsConfEncrypted(aconf))
443 {
444 if (strcmp(aconf->passwd,
445 (const char *)crypt(client_p->localClient->passwd,
446 aconf->passwd)) == 0)
447 server_conf = conf;
448 }
449 else
450 {
451 if (strcmp(aconf->passwd, client_p->localClient->passwd) == 0)
452 server_conf = conf;
453 }
454 }
455 }
456 }
457
458 if (server_conf == NULL)
459 return(error);
460
461 attach_conf(client_p, server_conf);
462
463 /* Now find all leaf or hub config items for this server */
464 DLINK_FOREACH(ptr, hub_items.head)
465 {
466 conf = ptr->data;
467
468 if (!match(name, conf->name))
469 continue;
470 attach_conf(client_p, conf);
471 }
472
473 DLINK_FOREACH(ptr, leaf_items.head)
474 {
475 conf = ptr->data;
476
477 if (!match(name, conf->name))
478 continue;
479 attach_conf(client_p, conf);
480 }
481
482 server_aconf = map_to_conf(server_conf);
483
484 if (!IsConfTopicBurst(server_aconf))
485 {
486 ClearCap(client_p, CAP_TB);
487 ClearCap(client_p, CAP_TBURST);
488 }
489
490 if (aconf != NULL)
491 {
492 struct sockaddr_in *v4;
493 #ifdef IPV6
494 struct sockaddr_in6 *v6;
495 #endif
496 switch (aconf->aftype)
497 {
498 #ifdef IPV6
499 case AF_INET6:
500 v6 = (struct sockaddr_in6 *)&aconf->ipnum;
501
502 if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr))
503 memcpy(&aconf->ipnum, &client_p->localClient->ip, sizeof(struct irc_ssaddr));
504 break;
505 #endif
506 case AF_INET:
507 v4 = (struct sockaddr_in *)&aconf->ipnum;
508
509 if (v4->sin_addr.s_addr == INADDR_NONE)
510 memcpy(&aconf->ipnum, &client_p->localClient->ip, sizeof(struct irc_ssaddr));
511 break;
512 }
513 }
514
515 return(0);
516 }
517
518 /* add_capability()
519 *
520 * inputs - string name of CAPAB
521 * - int flag of capability
522 * output - NONE
523 * side effects - Adds given capability name and bit mask to
524 * current supported capabilities. This allows
525 * modules to dynamically add or subtract their capability.
526 */
527 void
528 add_capability(const char *capab_name, int cap_flag, int add_to_default)
529 {
530 struct Capability *cap = MyMalloc(sizeof(*cap));
531
532 DupString(cap->name, capab_name);
533 cap->cap = cap_flag;
534 dlinkAdd(cap, &cap->node, &cap_list);
535
536 if (add_to_default)
537 default_server_capabs |= cap_flag;
538 }
539
540 /* delete_capability()
541 *
542 * inputs - string name of CAPAB
543 * output - NONE
544 * side effects - delete given capability from ones known.
545 */
546 int
547 delete_capability(const char *capab_name)
548 {
549 dlink_node *ptr;
550 dlink_node *next_ptr;
551 struct Capability *cap;
552
553 DLINK_FOREACH_SAFE(ptr, next_ptr, cap_list.head)
554 {
555 cap = ptr->data;
556
557 if (cap->cap != 0)
558 {
559 if (irccmp(cap->name, capab_name) == 0)
560 {
561 default_server_capabs &= ~(cap->cap);
562 dlinkDelete(ptr, &cap_list);
563 MyFree(cap->name);
564 cap->name = NULL;
565 MyFree(cap);
566 }
567 }
568 }
569
570 return 0;
571 }
572
573 /*
574 * find_capability()
575 *
576 * inputs - string name of capab to find
577 * output - 0 if not found CAPAB otherwise
578 * side effects - none
579 */
580 int
581 find_capability(const char *capab)
582 {
583 const dlink_node *ptr = NULL;
584
585 DLINK_FOREACH(ptr, cap_list.head)
586 {
587 const struct Capability *cap = ptr->data;
588
589 if (cap->cap && !irccmp(cap->name, capab))
590 return cap->cap;
591 }
592
593 return 0;
594 }
595
596 /* send_capabilities()
597 *
598 * inputs - Client pointer to send to
599 * - Pointer to AccessItem (for crypt)
600 * - int flag of capabilities that this server can send
601 * output - NONE
602 * side effects - send the CAPAB line to a server -orabidoo
603 *
604 */
605 void
606 send_capabilities(struct Client *client_p, struct AccessItem *aconf,
607 int cap_can_send)
608 {
609 struct Capability *cap=NULL;
610 char msgbuf[IRCD_BUFSIZE];
611 char *t;
612 int tl;
613 dlink_node *ptr;
614
615 t = msgbuf;
616
617 DLINK_FOREACH(ptr, cap_list.head)
618 {
619 cap = ptr->data;
620
621 if (cap->cap & (cap_can_send|default_server_capabs))
622 {
623 tl = ircsprintf(t, "%s ", cap->name);
624 t += tl;
625 }
626 }
627
628 *(t - 1) = '\0';
629 sendto_one(client_p, "CAPAB :%s", msgbuf);
630 }
631
632 /* sendnick_TS()
633 *
634 * inputs - client (server) to send nick towards
635 * - client to send nick for
636 * output - NONE
637 * side effects - NICK message is sent towards given client_p
638 */
639 void
640 sendnick_TS(struct Client *client_p, struct Client *target_p)
641 {
642 static char ubuf[12];
643
644 if (!IsClient(target_p))
645 return;
646
647 send_umode(NULL, target_p, 0, SEND_UMODES, ubuf);
648
649 if (ubuf[0] == '\0')
650 {
651 ubuf[0] = '+';
652 ubuf[1] = '\0';
653 }
654
655 /* XXX Both of these need to have a :me.name or :mySID!?!?! */
656 if (IsCapable(client_p, CAP_SVS))
657 {
658 if (HasID(target_p) && IsCapable(client_p, CAP_TS6))
659 sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s %lu :%s",
660 target_p->servptr->id,
661 target_p->name, target_p->hopcount + 1,
662 (unsigned long) target_p->tsinfo,
663 ubuf, target_p->username, target_p->host,
664 (MyClient(target_p) && IsIPSpoof(target_p)) ?
665 "0" : target_p->sockhost, target_p->id,
666 (unsigned long)target_p->servicestamp, target_p->info);
667 else
668 sendto_one(client_p, "NICK %s %d %lu %s %s %s %s %lu :%s",
669 target_p->name, target_p->hopcount + 1,
670 (unsigned long) target_p->tsinfo,
671 ubuf, target_p->username, target_p->host,
672 target_p->servptr->name, (unsigned long)target_p->servicestamp,
673 target_p->info);
674 }
675 else
676 {
677 if (HasID(target_p) && IsCapable(client_p, CAP_TS6))
678 sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s :%s",
679 target_p->servptr->id,
680 target_p->name, target_p->hopcount + 1,
681 (unsigned long) target_p->tsinfo,
682 ubuf, target_p->username, target_p->host,
683 (MyClient(target_p) && IsIPSpoof(target_p)) ?
684 "0" : target_p->sockhost, target_p->id, target_p->info);
685 else
686 sendto_one(client_p, "NICK %s %d %lu %s %s %s %s :%s",
687 target_p->name, target_p->hopcount + 1,
688 (unsigned long) target_p->tsinfo,
689 ubuf, target_p->username, target_p->host,
690 target_p->servptr->name, target_p->info);
691 }
692
693 if (IsConfAwayBurst((struct AccessItem *)map_to_conf(client_p->serv->sconf)))
694 if (!EmptyString(target_p->away))
695 sendto_one(client_p, ":%s AWAY :%s", target_p->name,
696 target_p->away);
697
698 }
699
700 /*
701 * show_capabilities - show current server capabilities
702 *
703 * inputs - pointer to a struct Client
704 * output - pointer to static string
705 * side effects - build up string representing capabilities of server listed
706 */
707 const char *
708 show_capabilities(struct Client *target_p)
709 {
710 static char msgbuf[IRCD_BUFSIZE];
711 char *t = msgbuf;
712 dlink_node *ptr;
713
714 t += ircsprintf(msgbuf, "TS ");
715
716 DLINK_FOREACH(ptr, cap_list.head)
717 {
718 const struct Capability *cap = ptr->data;
719
720 if (IsCapable(target_p, cap->cap))
721 t += ircsprintf(t, "%s ", cap->name);
722 }
723
724 *(t - 1) = '\0';
725 return msgbuf;
726 }
727
728 /* make_server()
729 *
730 * inputs - pointer to client struct
731 * output - pointer to struct Server
732 * side effects - add's an Server information block to a client
733 * if it was not previously allocated.
734 */
735 struct Server *
736 make_server(struct Client *client_p)
737 {
738 if (client_p->serv == NULL)
739 client_p->serv = MyMalloc(sizeof(struct Server));
740
741 return client_p->serv;
742 }
743
744 /* server_estab()
745 *
746 * inputs - pointer to a struct Client
747 * output -
748 * side effects -
749 */
750 void
751 server_estab(struct Client *client_p)
752 {
753 struct Client *target_p;
754 struct ConfItem *conf;
755 struct AccessItem *aconf=NULL;
756 char *host;
757 const char *inpath;
758 static char inpath_ip[HOSTLEN * 2 + USERLEN + 6];
759 dlink_node *ptr;
760 #ifdef HAVE_LIBCRYPTO
761 const COMP_METHOD *compression = NULL, *expansion = NULL;
762 #endif
763
764 assert(client_p != NULL);
765
766 strlcpy(inpath_ip, get_client_name(client_p, SHOW_IP), sizeof(inpath_ip));
767
768 inpath = get_client_name(client_p, MASK_IP); /* "refresh" inpath with host */
769 host = client_p->name;
770
771 if ((conf = find_conf_name(&client_p->localClient->confs, host, SERVER_TYPE))
772 == NULL)
773 {
774 /* This shouldn't happen, better tell the ops... -A1kmm */
775 sendto_realops_flags(UMODE_ALL, L_ALL, "Warning: Lost connect{} block "
776 "for server %s(this shouldn't happen)!", host);
777 exit_client(client_p, &me, "Lost connect{} block!");
778 return;
779 }
780
781 MyFree(client_p->localClient->passwd);
782 client_p->localClient->passwd = NULL;
783
784 /* Its got identd, since its a server */
785 SetGotId(client_p);
786
787 /* If there is something in the serv_list, it might be this
788 * connecting server..
789 */
790 if (!ServerInfo.hub && serv_list.head)
791 {
792 if (client_p != serv_list.head->data || serv_list.head->next)
793 {
794 ++ServerStats.is_ref;
795 sendto_one(client_p, "ERROR :I'm a leaf not a hub");
796 exit_client(client_p, &me, "I'm a leaf");
797 return;
798 }
799 }
800
801 aconf = map_to_conf(conf);
802
803 if (IsUnknown(client_p))
804 {
805 /* jdc -- 1. Use EmptyString(), not [0] index reference.
806 * 2. Check aconf->spasswd, not aconf->passwd.
807 */
808 if (!EmptyString(aconf->spasswd))
809 sendto_one(client_p, "PASS %s TS %d %s",
810 aconf->spasswd, TS_CURRENT, me.id);
811
812 /* Pass my info to the new server
813 *
814 * Pass on ZIP if supported
815 * Pass on TB if supported.
816 * - Dianora
817 */
818
819 send_capabilities(client_p, aconf,
820 (IsConfTopicBurst(aconf) ? CAP_TBURST|CAP_TB : 0));
821
822 sendto_one(client_p, "SERVER %s 1 :%s%s",
823 me.name, ConfigServerHide.hidden ? "(H) " : "", me.info);
824 }
825
826 sendto_one(client_p, "SVINFO %d %d 0 :%lu", TS_CURRENT, TS_MIN,
827 (unsigned long)CurrentTime);
828
829 /* assumption here is if they passed the correct TS version, they also passed an SID */
830 if (IsCapable(client_p, CAP_TS6))
831 hash_add_id(client_p);
832
833 /* XXX Does this ever happen? I don't think so -db */
834 detach_conf(client_p, OPER_TYPE);
835
836 /* *WARNING*
837 ** In the following code in place of plain server's
838 ** name we send what is returned by get_client_name
839 ** which may add the "sockhost" after the name. It's
840 ** *very* *important* that there is a SPACE between
841 ** the name and sockhost (if present). The receiving
842 ** server will start the information field from this
843 ** first blank and thus puts the sockhost into info.
844 ** ...a bit tricky, but you have been warned, besides
845 ** code is more neat this way... --msa
846 */
847 client_p->servptr = &me;
848
849 if (IsClosing(client_p))
850 return;
851
852 SetServer(client_p);
853
854 /* Update the capability combination usage counts. -A1kmm */
855 set_chcap_usage_counts(client_p);
856
857 /* Some day, all these lists will be consolidated *sigh* */
858 dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list);
859
860 assert(dlinkFind(&unknown_list, client_p));
861
862 dlink_move_node(&client_p->localClient->lclient_node,
863 &unknown_list, &serv_list);
864
865 Count.myserver++;
866
867 dlinkAdd(client_p, make_dlink_node(), &global_serv_list);
868 hash_add_client(client_p);
869
870 /* doesnt duplicate client_p->serv if allocated this struct already */
871 make_server(client_p);
872
873 /* fixing eob timings.. -gnp */
874 client_p->localClient->firsttime = CurrentTime;
875
876 if (find_matching_name_conf(SERVICE_TYPE, client_p->name, NULL, NULL, 0))
877 AddFlag(client_p, FLAGS_SERVICE);
878
879 /* Show the real host/IP to admins */
880 #ifdef HAVE_LIBCRYPTO
881 if (client_p->localClient->fd.ssl)
882 {
883 compression = SSL_get_current_compression(client_p->localClient->fd.ssl);
884 expansion = SSL_get_current_expansion(client_p->localClient->fd.ssl);
885
886 sendto_realops_flags(UMODE_ALL, L_ADMIN,
887 "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
888 inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl),
889 compression ? SSL_COMP_get_name(compression) : "NONE",
890 expansion ? SSL_COMP_get_name(expansion) : "NONE",
891 show_capabilities(client_p));
892 /* Now show the masked hostname/IP to opers */
893 sendto_realops_flags(UMODE_ALL, L_OPER,
894 "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
895 inpath, ssl_get_cipher(client_p->localClient->fd.ssl),
896 compression ? SSL_COMP_get_name(compression) : "NONE",
897 expansion ? SSL_COMP_get_name(expansion) : "NONE",
898 show_capabilities(client_p));
899 ilog(LOG_TYPE_IRCD, "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)",
900 inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl),
901 compression ? SSL_COMP_get_name(compression) : "NONE",
902 expansion ? SSL_COMP_get_name(expansion) : "NONE",
903 show_capabilities(client_p));
904 }
905 else
906 #endif
907 {
908 sendto_realops_flags(UMODE_ALL, L_ADMIN,
909 "Link with %s established: (Capabilities: %s)",
910 inpath_ip,show_capabilities(client_p));
911 /* Now show the masked hostname/IP to opers */
912 sendto_realops_flags(UMODE_ALL, L_OPER,
913 "Link with %s established: (Capabilities: %s)",
914 inpath,show_capabilities(client_p));
915 ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)",
916 inpath_ip, show_capabilities(client_p));
917 }
918
919 client_p->serv->sconf = conf;
920
921 fd_note(&client_p->localClient->fd, "Server: %s", client_p->name);
922
923 /* Old sendto_serv_but_one() call removed because we now
924 ** need to send different names to different servers
925 ** (domain name matching) Send new server to other servers.
926 */
927 DLINK_FOREACH(ptr, serv_list.head)
928 {
929 target_p = ptr->data;
930
931 if (target_p == client_p)
932 continue;
933
934 if (IsCapable(target_p, CAP_TS6) && HasID(client_p))
935 sendto_one(target_p, ":%s SID %s 2 %s :%s%s",
936 me.id, client_p->name, client_p->id,
937 IsHidden(client_p) ? "(H) " : "",
938 client_p->info);
939 else
940 sendto_one(target_p,":%s SERVER %s 2 :%s%s",
941 me.name, client_p->name,
942 IsHidden(client_p) ? "(H) " : "",
943 client_p->info);
944 }
945
946 /* Pass on my client information to the new server
947 **
948 ** First, pass only servers (idea is that if the link gets
949 ** cancelled beacause the server was already there,
950 ** there are no NICK's to be cancelled...). Of course,
951 ** if cancellation occurs, all this info is sent anyway,
952 ** and I guess the link dies when a read is attempted...? --msa
953 **
954 ** Note: Link cancellation to occur at this point means
955 ** that at least two servers from my fragment are building
956 ** up connection this other fragment at the same time, it's
957 ** a race condition, not the normal way of operation...
958 **
959 ** ALSO NOTE: using the get_client_name for server names--
960 ** see previous *WARNING*!!! (Also, original inpath
961 ** is destroyed...)
962 */
963
964 DLINK_FOREACH_PREV(ptr, global_serv_list.tail)
965 {
966 target_p = ptr->data;
967
968 /* target_p->from == target_p for target_p == client_p */
969 if (IsMe(target_p) || target_p->from == client_p)
970 continue;
971
972 if (IsCapable(client_p, CAP_TS6))
973 {
974 if (HasID(target_p))
975 sendto_one(client_p, ":%s SID %s %d %s :%s%s",
976 ID(target_p->servptr), target_p->name, target_p->hopcount+1,
977 target_p->id, IsHidden(target_p) ? "(H) " : "",
978 target_p->info);
979 else /* introducing non-ts6 server */
980 sendto_one(client_p, ":%s SERVER %s %d :%s%s",
981 ID(target_p->servptr), target_p->name, target_p->hopcount+1,
982 IsHidden(target_p) ? "(H) " : "", target_p->info);
983 }
984 else
985 sendto_one(client_p, ":%s SERVER %s %d :%s%s",
986 target_p->servptr->name, target_p->name, target_p->hopcount+1,
987 IsHidden(target_p) ? "(H) " : "", target_p->info);
988 }
989
990 server_burst(client_p);
991 }
992
993 /* server_burst()
994 *
995 * inputs - struct Client pointer server
996 * -
997 * output - none
998 * side effects - send a server burst
999 * bugs - still too long
1000 */
1001 static void
1002 server_burst(struct Client *client_p)
1003 {
1004 /* Send it in the shortened format with the TS, if
1005 ** it's a TS server; walk the list of channels, sending
1006 ** all the nicks that haven't been sent yet for each
1007 ** channel, then send the channel itself -- it's less
1008 ** obvious than sending all nicks first, but on the
1009 ** receiving side memory will be allocated more nicely
1010 ** saving a few seconds in the handling of a split
1011 ** -orabidoo
1012 */
1013
1014 burst_all(client_p);
1015
1016 /* EOB stuff is now in burst_all */
1017 /* Always send a PING after connect burst is done */
1018 sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
1019 }
1020
1021 /* burst_all()
1022 *
1023 * inputs - pointer to server to send burst to
1024 * output - NONE
1025 * side effects - complete burst of channels/nicks is sent to client_p
1026 */
1027 static void
1028 burst_all(struct Client *client_p)
1029 {
1030 dlink_node *ptr = NULL;
1031
1032 DLINK_FOREACH(ptr, global_channel_list.head)
1033 {
1034 struct Channel *chptr = ptr->data;
1035
1036 if (dlink_list_length(&chptr->members) != 0)
1037 {
1038 burst_members(client_p, chptr);
1039 send_channel_modes(client_p, chptr);
1040
1041 if (IsCapable(client_p, CAP_TBURST) ||
1042 IsCapable(client_p, CAP_TB))
1043 send_tb(client_p, chptr);
1044 }
1045 }
1046
1047 /* also send out those that are not on any channel
1048 */
1049 DLINK_FOREACH(ptr, global_client_list.head)
1050 {
1051 struct Client *target_p = ptr->data;
1052
1053 if (!HasFlag(target_p, FLAGS_BURSTED) && target_p->from != client_p)
1054 sendnick_TS(client_p, target_p);
1055
1056 DelFlag(target_p, FLAGS_BURSTED);
1057 }
1058
1059 /* We send the time we started the burst, and let the remote host determine an EOB time,
1060 ** as otherwise we end up sending a EOB of 0 Sending here means it gets sent last -- fl
1061 */
1062 /* Its simpler to just send EOB and use the time its been connected.. --fl_ */
1063 if (IsCapable(client_p, CAP_EOB))
1064 sendto_one(client_p, ":%s EOB", ID_or_name(&me, client_p));
1065 }
1066
1067 /*
1068 * send_tb
1069 *
1070 * inputs - pointer to Client
1071 * - pointer to channel
1072 * output - NONE
1073 * side effects - Called on a server burst when
1074 * server is CAP_TB|CAP_TBURST capable
1075 */
1076 static void
1077 send_tb(struct Client *client_p, struct Channel *chptr)
1078 {
1079 /*
1080 * We may also send an empty topic here, but only if topic_time isn't 0,
1081 * i.e. if we had a topic that got unset. This is required for syncing
1082 * topics properly.
1083 *
1084 * Imagine the following scenario: Our downlink introduces a channel
1085 * to us with a TS that is equal to ours, but the channel topic on
1086 * their side got unset while the servers were in splitmode, which means
1087 * their 'topic' is newer. They simply wanted to unset it, so we have to
1088 * deal with it in a more sophisticated fashion instead of just resetting
1089 * it to their old topic they had before. Read m_tburst.c:ms_tburst
1090 * for further information -Michael
1091 */
1092 if (chptr->topic_time != 0)
1093 {
1094 if (IsCapable(client_p, CAP_TBURST))
1095 sendto_one(client_p, ":%s TBURST %lu %s %lu %s :%s",
1096 me.name, (unsigned long)chptr->channelts, chptr->chname,
1097 (unsigned long)chptr->topic_time,
1098 chptr->topic_info,
1099 chptr->topic);
1100 else if (IsCapable(client_p, CAP_TB))
1101 {
1102 if (ConfigChannel.burst_topicwho)
1103 {
1104 sendto_one(client_p, ":%s TB %s %lu %s :%s",
1105 me.name, chptr->chname,
1106 (unsigned long)chptr->topic_time,
1107 chptr->topic_info, chptr->topic);
1108 }
1109 else
1110 {
1111 sendto_one(client_p, ":%s TB %s %lu :%s",
1112 me.name, chptr->chname,
1113 (unsigned long)chptr->topic_time,
1114 chptr->topic);
1115 }
1116 }
1117 }
1118 }
1119
1120 /* burst_members()
1121 *
1122 * inputs - pointer to server to send members to
1123 * - dlink_list pointer to membership list to send
1124 * output - NONE
1125 * side effects -
1126 */
1127 static void
1128 burst_members(struct Client *client_p, struct Channel *chptr)
1129 {
1130 struct Client *target_p;
1131 struct Membership *ms;
1132 dlink_node *ptr;
1133
1134 DLINK_FOREACH(ptr, chptr->members.head)
1135 {
1136 ms = ptr->data;
1137 target_p = ms->client_p;
1138
1139 if (!HasFlag(target_p, FLAGS_BURSTED))
1140 {
1141 AddFlag(target_p, FLAGS_BURSTED);
1142
1143 if (target_p->from != client_p)
1144 sendnick_TS(client_p, target_p);
1145 }
1146 }
1147 }
1148
1149 /* New server connection code
1150 * Based upon the stuff floating about in s_bsd.c
1151 * -- adrian
1152 */
1153
1154 /* serv_connect() - initiate a server connection
1155 *
1156 * inputs - pointer to conf
1157 * - pointer to client doing the connect
1158 * output -
1159 * side effects -
1160 *
1161 * This code initiates a connection to a server. It first checks to make
1162 * sure the given server exists. If this is the case, it creates a socket,
1163 * creates a client, saves the socket information in the client, and
1164 * initiates a connection to the server through comm_connect_tcp(). The
1165 * completion of this goes through serv_completed_connection().
1166 *
1167 * We return 1 if the connection is attempted, since we don't know whether
1168 * it suceeded or not, and 0 if it fails in here somewhere.
1169 */
1170 int
1171 serv_connect(struct AccessItem *aconf, struct Client *by)
1172 {
1173 struct ConfItem *conf;
1174 struct Client *client_p;
1175 char buf[HOSTIPLEN];
1176
1177 /* conversion structs */
1178 struct sockaddr_in *v4;
1179 /* Make sure aconf is useful */
1180 assert(aconf != NULL);
1181
1182 if(aconf == NULL)
1183 return (0);
1184
1185 /* XXX should be passing struct ConfItem in the first place */
1186 conf = unmap_conf_item(aconf);
1187
1188 /* log */
1189 getnameinfo((struct sockaddr *)&aconf->ipnum, aconf->ipnum.ss_len,
1190 buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
1191 ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", aconf->user, aconf->host,
1192 buf);
1193
1194 /* Still processing a DNS lookup? -> exit */
1195 if (aconf->dns_pending)
1196 {
1197 sendto_realops_flags(UMODE_ALL, L_ALL,
1198 "Error connecting to %s: DNS lookup for connect{} in progress.",
1199 conf->name);
1200 return (0);
1201 }
1202
1203 if (aconf->dns_failed)
1204 {
1205 sendto_realops_flags(UMODE_ALL, L_ALL,
1206 "Error connecting to %s: DNS lookup for connect{} failed.",
1207 conf->name);
1208 return (0);
1209 }
1210
1211 /* Make sure this server isn't already connected
1212 * Note: aconf should ALWAYS be a valid C: line
1213 */
1214 if ((client_p = hash_find_server(conf->name)) != NULL)
1215 {
1216 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1217 "Server %s already present from %s",
1218 conf->name, get_client_name(client_p, SHOW_IP));
1219 sendto_realops_flags(UMODE_ALL, L_OPER,
1220 "Server %s already present from %s",
1221 conf->name, get_client_name(client_p, MASK_IP));
1222 if (by && IsClient(by) && !MyClient(by))
1223 sendto_one(by, ":%s NOTICE %s :Server %s already present from %s",
1224 me.name, by->name, conf->name,
1225 get_client_name(client_p, MASK_IP));
1226 return (0);
1227 }
1228
1229 /* Create a local client */
1230 client_p = make_client(NULL);
1231
1232 /* Copy in the server, hostname, fd */
1233 strlcpy(client_p->name, conf->name, sizeof(client_p->name));
1234 strlcpy(client_p->host, aconf->host, sizeof(client_p->host));
1235
1236 /* We already converted the ip once, so lets use it - stu */
1237 strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
1238
1239 /* create a socket for the server connection */
1240 if (comm_open(&client_p->localClient->fd, aconf->ipnum.ss.ss_family,
1241 SOCK_STREAM, 0, NULL) < 0)
1242 {
1243 /* Eek, failure to create the socket */
1244 report_error(L_ALL,
1245 "opening stream socket to %s: %s", conf->name, errno);
1246 SetDead(client_p);
1247 exit_client(client_p, &me, "Connection failed");
1248 return (0);
1249 }
1250
1251 /* servernames are always guaranteed under HOSTLEN chars */
1252 fd_note(&client_p->localClient->fd, "Server: %s", conf->name);
1253
1254 /* Attach config entries to client here rather than in
1255 * serv_connect_callback(). This to avoid null pointer references.
1256 */
1257 if (!attach_connect_block(client_p, conf->name, aconf->host))
1258 {
1259 sendto_realops_flags(UMODE_ALL, L_ALL,
1260 "Host %s is not enabled for connecting:no C/N-line",
1261 conf->name);
1262 if (by && IsClient(by) && !MyClient(by))
1263 sendto_one(by, ":%s NOTICE %s :Connect to host %s failed.",
1264 me.name, by->name, client_p->name);
1265 SetDead(client_p);
1266 exit_client(client_p, client_p, "Connection failed");
1267 return (0);
1268 }
1269
1270 /* at this point we have a connection in progress and C/N lines
1271 * attached to the client, the socket info should be saved in the
1272 * client and it should either be resolved or have a valid address.
1273 *
1274 * The socket has been connected or connect is in progress.
1275 */
1276 make_server(client_p);
1277
1278 if (by && IsClient(by))
1279 strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
1280 else
1281 strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by));
1282
1283 SetConnecting(client_p);
1284 dlinkAdd(client_p, &client_p->node, &global_client_list);
1285 /* from def_fam */
1286 client_p->localClient->aftype = aconf->aftype;
1287
1288 /* Now, initiate the connection */
1289 /* XXX assume that a non 0 type means a specific bind address
1290 * for this connect.
1291 */
1292 switch (aconf->aftype)
1293 {
1294 case AF_INET:
1295 v4 = (struct sockaddr_in*)&aconf->my_ipnum;
1296 if (v4->sin_addr.s_addr != 0)
1297 {
1298 struct irc_ssaddr ipn;
1299 memset(&ipn, 0, sizeof(struct irc_ssaddr));
1300 ipn.ss.ss_family = AF_INET;
1301 ipn.ss_port = 0;
1302 memcpy(&ipn, &aconf->my_ipnum, sizeof(struct irc_ssaddr));
1303 comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port,
1304 (struct sockaddr *)&ipn, ipn.ss_len,
1305 serv_connect_callback, client_p, aconf->aftype,
1306 CONNECTTIMEOUT);
1307 }
1308 else if (ServerInfo.specific_ipv4_vhost)
1309 {
1310 struct irc_ssaddr ipn;
1311 memset(&ipn, 0, sizeof(struct irc_ssaddr));
1312 ipn.ss.ss_family = AF_INET;
1313 ipn.ss_port = 0;
1314 memcpy(&ipn, &ServerInfo.ip, sizeof(struct irc_ssaddr));
1315 comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port,
1316 (struct sockaddr *)&ipn, ipn.ss_len,
1317 serv_connect_callback, client_p, aconf->aftype,
1318 CONNECTTIMEOUT);
1319 }
1320 else
1321 comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port,
1322 NULL, 0, serv_connect_callback, client_p, aconf->aftype,
1323 CONNECTTIMEOUT);
1324 break;
1325 #ifdef IPV6
1326 case AF_INET6:
1327 {
1328 struct irc_ssaddr ipn;
1329 struct sockaddr_in6 *v6;
1330 struct sockaddr_in6 *v6conf;
1331
1332 memset(&ipn, 0, sizeof(struct irc_ssaddr));
1333 v6conf = (struct sockaddr_in6 *)&aconf->my_ipnum;
1334 v6 = (struct sockaddr_in6 *)&ipn;
1335
1336 if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr,
1337 sizeof(struct in6_addr)) != 0)
1338 {
1339 memcpy(&ipn, &aconf->my_ipnum, sizeof(struct irc_ssaddr));
1340 ipn.ss.ss_family = AF_INET6;
1341 ipn.ss_port = 0;
1342 comm_connect_tcp(&client_p->localClient->fd,
1343 aconf->host, aconf->port,
1344 (struct sockaddr *)&ipn, ipn.ss_len,
1345 serv_connect_callback, client_p,
1346 aconf->aftype, CONNECTTIMEOUT);
1347 }
1348 else if (ServerInfo.specific_ipv6_vhost)
1349 {
1350 memcpy(&ipn, &ServerInfo.ip6, sizeof(struct irc_ssaddr));
1351 ipn.ss.ss_family = AF_INET6;
1352 ipn.ss_port = 0;
1353 comm_connect_tcp(&client_p->localClient->fd,
1354 aconf->host, aconf->port,
1355 (struct sockaddr *)&ipn, ipn.ss_len,
1356 serv_connect_callback, client_p,
1357 aconf->aftype, CONNECTTIMEOUT);
1358 }
1359 else
1360 comm_connect_tcp(&client_p->localClient->fd,
1361 aconf->host, aconf->port,
1362 NULL, 0, serv_connect_callback, client_p,
1363 aconf->aftype, CONNECTTIMEOUT);
1364 }
1365 #endif
1366 }
1367 return (1);
1368 }
1369
1370 #ifdef HAVE_LIBCRYPTO
1371 static void
1372 finish_ssl_server_handshake(struct Client *client_p)
1373 {
1374 struct ConfItem *conf=NULL;
1375 struct AccessItem *aconf=NULL;
1376
1377 conf = find_conf_name(&client_p->localClient->confs,
1378 client_p->name, SERVER_TYPE);
1379 if (conf == NULL)
1380 {
1381 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1382 "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
1383 sendto_realops_flags(UMODE_ALL, L_OPER,
1384 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
1385
1386 exit_client(client_p, &me, "Lost connect{} block");
1387 return;
1388 }
1389
1390 aconf = map_to_conf(conf);
1391
1392 /* jdc -- Check and send spasswd, not passwd. */
1393 if (!EmptyString(aconf->spasswd))
1394 sendto_one(client_p, "PASS %s TS %d %s",
1395 aconf->spasswd, TS_CURRENT, me.id);
1396
1397 send_capabilities(client_p, aconf,
1398 (IsConfTopicBurst(aconf) ? CAP_TBURST|CAP_TB : 0));
1399
1400 sendto_one(client_p, "SERVER %s 1 :%s%s",
1401 me.name, ConfigServerHide.hidden ? "(H) " : "",
1402 me.info);
1403
1404 /* If we've been marked dead because a send failed, just exit
1405 * here now and save everyone the trouble of us ever existing.
1406 */
1407 if (IsDead(client_p))
1408 {
1409 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1410 "%s[%s] went dead during handshake",
1411 client_p->name,
1412 client_p->host);
1413 sendto_realops_flags(UMODE_ALL, L_OPER,
1414 "%s went dead during handshake", client_p->name);
1415 return;
1416 }
1417
1418 /* don't move to serv_list yet -- we haven't sent a burst! */
1419 /* If we get here, we're ok, so lets start reading some data */
1420 comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ, read_packet, client_p, 0);
1421 }
1422
1423 static void
1424 ssl_server_handshake(fde_t *fd, struct Client *client_p)
1425 {
1426 int ret;
1427 int err;
1428
1429 ret = SSL_connect(client_p->localClient->fd.ssl);
1430
1431 if (ret <= 0)
1432 {
1433 switch ((err = SSL_get_error(client_p->localClient->fd.ssl, ret)))
1434 {
1435 case SSL_ERROR_WANT_WRITE:
1436 comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE,
1437 (PF *)ssl_server_handshake, client_p, 0);
1438 return;
1439 case SSL_ERROR_WANT_READ:
1440 comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ,
1441 (PF *)ssl_server_handshake, client_p, 0);
1442 return;
1443 default:
1444 {
1445 const char *sslerr = ERR_error_string(ERR_get_error(), NULL);
1446 sendto_realops_flags(UMODE_ALL, L_ALL,
1447 "Error connecting to %s: %s", client_p->name,
1448 sslerr ? sslerr : "unknown SSL error");
1449 exit_client(client_p, client_p, "Error during SSL handshake");
1450 return;
1451 }
1452 }
1453 }
1454
1455 finish_ssl_server_handshake(client_p);
1456 }
1457
1458 static void
1459 ssl_connect_init(struct Client *client_p, struct AccessItem *aconf, fde_t *fd)
1460 {
1461 if ((client_p->localClient->fd.ssl = SSL_new(ServerInfo.client_ctx)) == NULL)
1462 {
1463 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
1464 ERR_error_string(ERR_get_error(), NULL));
1465 SetDead(client_p);
1466 exit_client(client_p, client_p, "SSL_new failed");
1467 return;
1468 }
1469
1470 SSL_set_fd(fd->ssl, fd->fd);
1471
1472 if (!EmptyString(aconf->cipher_list))
1473 SSL_set_cipher_list(client_p->localClient->fd.ssl, aconf->cipher_list);
1474
1475 ssl_server_handshake(NULL, client_p);
1476 }
1477 #endif
1478
1479 /* serv_connect_callback() - complete a server connection.
1480 *
1481 * This routine is called after the server connection attempt has
1482 * completed. If unsucessful, an error is sent to ops and the client
1483 * is closed. If sucessful, it goes through the initialisation/check
1484 * procedures, the capabilities are sent, and the socket is then
1485 * marked for reading.
1486 */
1487 static void
1488 serv_connect_callback(fde_t *fd, int status, void *data)
1489 {
1490 struct Client *client_p = data;
1491 struct ConfItem *conf=NULL;
1492 struct AccessItem *aconf=NULL;
1493
1494 /* First, make sure its a real client! */
1495 assert(client_p != NULL);
1496 assert(&client_p->localClient->fd == fd);
1497
1498 /* Next, for backward purposes, record the ip of the server */
1499 memcpy(&client_p->localClient->ip, &fd->connect.hostaddr,
1500 sizeof(struct irc_ssaddr));
1501 /* Check the status */
1502 if (status != COMM_OK)
1503 {
1504 /* We have an error, so report it and quit
1505 * Admins get to see any IP, mere opers don't *sigh*
1506 */
1507 if (ConfigServerHide.hide_server_ips)
1508 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1509 "Error connecting to %s: %s",
1510 client_p->name, comm_errstr(status));
1511 else
1512 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1513 "Error connecting to %s[%s]: %s", client_p->name,
1514 client_p->host, comm_errstr(status));
1515
1516 sendto_realops_flags(UMODE_ALL, L_OPER,
1517 "Error connecting to %s: %s",
1518 client_p->name, comm_errstr(status));
1519
1520 /* If a fd goes bad, call dead_link() the socket is no
1521 * longer valid for reading or writing.
1522 */
1523 dead_link_on_write(client_p, 0);
1524 return;
1525 }
1526
1527 /* COMM_OK, so continue the connection procedure */
1528 /* Get the C/N lines */
1529 conf = find_conf_name(&client_p->localClient->confs,
1530 client_p->name, SERVER_TYPE);
1531 if (conf == NULL)
1532 {
1533 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1534 "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP));
1535 sendto_realops_flags(UMODE_ALL, L_OPER,
1536 "Lost connect{} block for %s", get_client_name(client_p, MASK_IP));
1537
1538 exit_client(client_p, &me, "Lost connect{} block");
1539 return;
1540 }
1541
1542 aconf = map_to_conf(conf);
1543 /* Next, send the initial handshake */
1544 SetHandshake(client_p);
1545
1546 #ifdef HAVE_LIBCRYPTO
1547 if (IsConfSSL(aconf))
1548 {
1549 ssl_connect_init(client_p, aconf, fd);
1550 return;
1551 }
1552 #endif
1553
1554 /* jdc -- Check and send spasswd, not passwd. */
1555 if (!EmptyString(aconf->spasswd))
1556 sendto_one(client_p, "PASS %s TS %d %s",
1557 aconf->spasswd, TS_CURRENT, me.id);
1558
1559 send_capabilities(client_p, aconf,
1560 (IsConfTopicBurst(aconf) ? CAP_TBURST|CAP_TB : 0));
1561
1562 sendto_one(client_p, "SERVER %s 1 :%s%s",
1563 me.name, ConfigServerHide.hidden ? "(H) " : "",
1564 me.info);
1565
1566 /* If we've been marked dead because a send failed, just exit
1567 * here now and save everyone the trouble of us ever existing.
1568 */
1569 if (IsDead(client_p))
1570 {
1571 sendto_realops_flags(UMODE_ALL, L_ADMIN,
1572 "%s[%s] went dead during handshake",
1573 client_p->name,
1574 client_p->host);
1575 sendto_realops_flags(UMODE_ALL, L_OPER,
1576 "%s went dead during handshake", client_p->name);
1577 return;
1578 }
1579
1580 /* don't move to serv_list yet -- we haven't sent a burst! */
1581 /* If we get here, we're ok, so lets start reading some data */
1582 comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
1583 }
1584
1585 struct Client *
1586 find_servconn_in_progress(const char *name)
1587 {
1588 dlink_node *ptr;
1589 struct Client *cptr;
1590
1591 DLINK_FOREACH(ptr, unknown_list.head)
1592 {
1593 cptr = ptr->data;
1594
1595 if (cptr && cptr->name[0])
1596 if (match(name, cptr->name))
1597 return cptr;
1598 }
1599
1600 return NULL;
1601 }

Properties

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