ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/server.c
Revision: 1514
Committed: Sun Aug 26 09:11:17 2012 UTC (13 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/s_serv.c
File size: 45225 byte(s)
Log Message:
- Removed two outdated/invalid XXX tags

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

Properties

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