Anope IRC Services  Version 1.8
servers.c
Go to the documentation of this file.
1 /* Routines to maintain a list of connected servers
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  *
11  *
12  */
13 
14 #include "services.h"
15 
16 Server *servlist = NULL;
17 Server *me_server = NULL; /* This are we */
18 Server *serv_uplink = NULL; /* This is our uplink */
20 char *uplink;
21 char *TS6UPLINK;
22 char *TS6SID;
23 
24 /* For first_server / next_server */
26 
28  {"NOQUIT", CAPAB_NOQUIT},
29  {"TSMODE", CAPAB_TSMODE},
30  {"UNCONNECT", CAPAB_UNCONNECT},
31  {"NICKIP", CAPAB_NICKIP},
32  {"SSJOIN", CAPAB_NSJOIN},
33  {"ZIP", CAPAB_ZIP},
34  {"BURST", CAPAB_BURST},
35  {"TS5", CAPAB_TS5},
36  {"TS3", CAPAB_TS3},
37  {"DKEY", CAPAB_DKEY},
38  {"PT4", CAPAB_PT4},
39  {"SCS", CAPAB_SCS},
40  {"QS", CAPAB_QS},
41  {"UID", CAPAB_UID},
42  {"KNOCK", CAPAB_KNOCK},
43  {"CLIENT", CAPAB_CLIENT},
44  {"IPV6", CAPAB_IPV6},
45  {"SSJ5", CAPAB_SSJ5},
46  {"SN2", CAPAB_SN2},
47  {"TOK1", CAPAB_TOKEN},
48  {"TOKEN", CAPAB_TOKEN},
49  {"VHOST", CAPAB_VHOST},
50  {"SSJ3", CAPAB_SSJ3},
51  {"SJB64", CAPAB_SJB64},
52  {"CHANMODES", CAPAB_CHANMODE},
53  {"NICKCHARS", CAPAB_NICKCHARS},
54  {NULL, 0}
55 };
56 
57 /*************************************************************************/
58 
64 Server *first_server(int flags)
65 {
66  server_cur = servlist;
67  if (flags > -1) {
68  while (server_cur && (server_cur->flags != flags))
69  server_cur = next_server(flags);
70  }
71  return server_cur;
72 }
73 
74 /*************************************************************************/
75 
81 Server *next_server(int flags)
82 {
83  if (!server_cur)
84  return NULL;
85 
86  do {
87  if (server_cur->links) {
88  server_cur = server_cur->links;
89  } else if (server_cur->next) {
90  server_cur = server_cur->next;
91  } else {
92  do {
93  server_cur = server_cur->uplink;
94  if (server_cur && server_cur->next) {
95  server_cur = server_cur->next;
96  break;
97  }
98  } while (server_cur);
99  }
100  } while (server_cur && ((flags > -1) && (server_cur->flags != flags)));
101 
102  return server_cur;
103 }
104 
105 /*************************************************************************/
106 
119 Server *new_server(Server * uplink, const char *name, const char *desc,
120  uint16 flags, char *suid)
121 {
122  Server *serv;
123 
124  if (debug)
125  alog("debug: Creating %s(%s) uplinked to %s", name, suid ? suid : "",
126  uplink ? uplink->name : "No uplink");
127 
128  serv = scalloc(sizeof(Server), 1);
129  if (!name)
130  name = "";
131  serv->name = sstrdup(name);
132  serv->desc = sstrdup(desc);
133  serv->flags = flags;
134  serv->uplink = uplink;
135  if (suid) {
136  serv->suid = sstrdup(suid);
137  } else {
138  serv->suid = NULL;
139  }
140  if (ircd->sync)
141  serv->sync = SSYNC_IN_PROGRESS;
142  else
143  serv->sync = SSYNC_UNKNOWN;
144  serv->links = NULL;
145  serv->prev = NULL;
146 
147  if (!uplink) {
148  serv->hops = 0;
149  serv->next = servlist;
150  if (servlist)
151  servlist->prev = serv;
152  servlist = serv;
153  } else {
154  serv->hops = uplink->hops + 1;
155  serv->next = uplink->links;
156  if (uplink->links)
157  uplink->links->prev = serv;
158  uplink->links = serv;
159  }
160  /* Check if this is our uplink server */
161  if ((uplink == me_server) && !(flags & SERVER_JUPED)) {
162  serv_uplink = serv;
163  serv->flags |= SERVER_ISUPLINK;
164  }
165 
166  /* Write the StartGlobal (to non-juped servers) */
167  if (GlobalOnCycle && GlobalOnCycleUP && !(flags & SERVER_JUPED))
169 
170  return serv;
171 }
172 
173 /*************************************************************************/
174 
185 static void delete_server(Server * serv, const char *quitreason)
186 {
187  Server *s, *snext;
188  User *u, *unext;
189  NickAlias *na;
190 
191  if (!serv) {
192  if (debug)
193  alog("debug: delete_server() called with NULL arg!");
194  return;
195  }
196 
197  if (debug)
198  alog("debug: Deleting %s(%s) uplinked to %s(%s)", serv->name,
199  serv->suid ? serv->suid : "", serv->uplink ? serv->uplink->name : "???",
200  serv->uplink ? serv->uplink->suid : "");
201 
202  if (ircdcap->noquit || ircdcap->qs) {
203  if ((uplink_capab & ircdcap->noquit)
204  || (uplink_capab & ircdcap->qs)) {
205  u = firstuser();
206  while (u) {
207  unext = nextuser();
208  if (u->server == serv) {
209  if ((na = u->na) && !(na->status & NS_VERBOTEN)
210  && (!(na->nc->flags & NI_SUSPENDED))
211  && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
212  na->last_seen = time(NULL);
213  if (na->last_quit)
214  free(na->last_quit);
215  na->last_quit =
216  (quitreason ? sstrdup(quitreason) : NULL);
217  }
218  if (LimitSessions && !is_ulined(u->server->name)) {
219  del_session(u->host);
220  }
221  delete_user(u);
222  }
223  u = unext;
224  }
225  if (debug)
226  alog("debug: delete_server() cleared all users");
227  }
228  }
229 
230  s = serv->links;
231  while (s) {
232  snext = s->next;
233  delete_server(s, quitreason);
234  s = snext;
235  }
236 
237  if (debug)
238  alog("debug: delete_server() cleared all servers");
239 
240  free(serv->name);
241  free(serv->desc);
242  if (serv->prev)
243  serv->prev->next = serv->next;
244  if (serv->next)
245  serv->next->prev = serv->prev;
246  if (serv->uplink && serv->uplink->links == serv)
247  serv->uplink->links = serv->next;
248 
249  if (debug)
250  alog("debug: delete_server() completed");
251 }
252 
253 /*************************************************************************/
254 
261 Server *findserver(Server * s, const char *name)
262 {
263  Server *sl;
264 
265  if (!name || !*name) {
266  return NULL;
267  }
268 
269  if (debug >= 3) {
270  alog("debug: findserver(%p)", name);
271  }
272  while (s && (stricmp(s->name, name) != 0)) {
273  if (s->links) {
274  sl = findserver(s->links, name);
275  if (sl) {
276  s = sl;
277  } else {
278  s = s->next;
279  }
280  } else {
281  s = s->next;
282  }
283  }
284  if (debug >= 3) {
285  alog("debug: findserver(%s) -> %p", name, (void *) s);
286  }
287  return s;
288 }
289 
290 /*************************************************************************/
291 
298 Server *findserver_uid(Server * s, const char *name)
299 {
300  Server *sl;
301 
302  if (!name || !*name) {
303  return NULL;
304  }
305 
306  if (debug >= 3) {
307  alog("debug: findserver_uid(%p)", name);
308  }
309  while (s && s->suid && (stricmp(s->suid, name) != 0)) {
310  if (s->links) {
311  sl = findserver_uid(s->links, name);
312  if (sl) {
313  s = sl;
314  } else {
315  s = s->next;
316  }
317  } else {
318  s = s->next;
319  }
320  }
321  if (debug >= 3) {
322  alog("debug: findserver_uid(%s) -> %p", name, (void *) s);
323  }
324  return s;
325 }
326 
327 /*************************************************************************/
328 
335 int anope_check_sync(const char *name)
336 {
337  Server *s;
338  s = findserver(servlist, name);
339 
340  if (!s)
341  return 0;
342 
343  if (is_sync(s))
344  return 1;
345  else
346  return -1;
347 }
348 
349 /*************************************************************************/
350 
360 void do_server(const char *source, char *servername, char *hops,
361  char *descript, char *numeric)
362 {
363  Server *s;
364 
365  if (debug) {
366  if (!*source) {
367  alog("debug: Server introduced (%s)", servername);
368  } else {
369  alog("debug: Server introduced (%s) from %s", servername,
370  source);
371  }
372  }
373  if (source[0] == '\0')
374  s = me_server;
375  else if (UseTS6 && ircd->ts6) {
376  s = findserver_uid(servlist, source);
377  if (!s)
378  s = findserver(servlist, source);
379  } else
380  s = findserver(servlist, source);
381 
382  if (!s)
383  fatal("FATAL ERROR: Received new server from nonexistant uplink.");
384 
385  new_server(s, servername, descript, 0, numeric);
386  send_event(EVENT_SERVER_CONNECT, 1, servername);
387 }
388 
389 /*************************************************************************/
390 
398 void do_squit(const char *source, int ac, char **av)
399 {
400  char buf[BUFSIZE];
401  Server *s;
402 
403  if (UseTS6 && ircd->ts6) {
404  s = findserver_uid(servlist, av[0]);
405  if (!s) {
406  s = findserver(servlist, av[0]);
407  }
408  } else {
409  s = findserver(servlist, av[0]);
410  }
411  if (!s) {
412  alog("SQUIT for nonexistent server (%s)!!", av[0]);
413  return;
414  }
416 
417  /* If this is a juped server, send a nice global to inform the online
418  * opers that we received it.
419  */
420  if (s->flags & SERVER_JUPED) {
421  snprintf(buf, BUFSIZE, "Received SQUIT for juped server %s",
422  s->name);
424  }
425 
426  snprintf(buf, sizeof(buf), "%s %s", s->name,
427  (s->uplink ? s->uplink->name : ""));
428 
429  if (ircdcap->unconnect) {
430  if ((s->uplink == me_server)
431  && (uplink_capab & ircdcap->unconnect)) {
432  if (debug) {
433  alog("debug: Sending UNCONNECT SQUIT for %s", s->name);
434  }
435  /* need to fix */
436  anope_cmd_squit(s->name, buf);
437  }
438  }
439 
440  delete_server(s, buf);
441 }
442 
443 /*************************************************************************/
444 
451 void capab_parse(int ac, char **av)
452 {
453  int i;
454  int j;
455  char *s, *tmp;
456 
457  char *temp;
458 
459  for (i = 0; i < ac; i++) {
460  temp = av[i];
461 
462  s = myStrGetToken(temp, '=', 0);
463  tmp = myStrGetTokenRemainder(temp, '=', 1);
464 
465  if (!s)
466  continue;
467 
468  for (j = 0; capab_info[j].token; j++) {
469  if (stricmp(s, capab_info[j].token) == 0)
470  uplink_capab |= capab_info[j].flag;
471  /* Special cases */
472  if ((stricmp(s, "NICKIP") == 0) && !ircd->nickip)
473  ircd->nickip = 1;
474  if ((stricmp(s, "CHANMODES") == 0) && tmp)
475  ircd->chanmodes = sstrdup(tmp);
476  if ((stricmp(s, "NICKCHARS") == 0) && tmp)
477  ircd->nickchars = sstrdup(tmp);
478  }
479 
480  if (s)
481  free(s);
482  if (tmp)
483  free(tmp);
484  }
485 }
486 
487 /*************************************************************************/
488 
495 int is_ulined(char *server)
496 {
497  int j;
498 
499  for (j = 0; j < NumUlines; j++) {
500  if (stricmp(Ulines[j], server) == 0) {
501  return 1;
502  }
503  }
504 
505  return 0;
506 }
507 
508 /*************************************************************************/
509 
516 int is_sync(Server * server)
517 {
518  if ((server->sync == SSYNC_DONE) || (server->sync == SSYNC_UNKNOWN))
519  return 1;
520  return 0;
521 }
522 
523 /*************************************************************************/
524 
525 /* Finish the syncing process for this server and (optionally) for all
526  * it's leaves as well
527  * @param serv Server to finish syncing
528  * @param sync_links Should all leaves be synced as well? (1: yes, 0: no)
529  * @return void
530  */
531 void finish_sync(Server * serv, int sync_links)
532 {
533  Server *s;
534 
535  if (!serv || is_sync(serv))
536  return;
537 
538  /* Mark each server as in sync */
539  s = serv;
540  do {
541  if (!is_sync(s)) {
542  if (debug)
543  alog("debug: Finishing sync for server %s", s->name);
544 
545  s->sync = SSYNC_DONE;
546  }
547 
548  if (!sync_links)
549  break;
550 
551  if (s->links) {
552  s = s->links;
553  } else if (s->next) {
554  s = s->next;
555  } else {
556  do {
557  s = s->uplink;
558  if (s == serv)
559  s = NULL;
560  if (s == me_server)
561  s = NULL;
562  } while (s && !(s->next));
563  if (s)
564  s = s->next;
565  }
566  } while (s);
567 
568  /* Do some general stuff which should only be done once */
570  alog("Server %s is done syncing", serv->name);
571 }
572 
573 /*******************************************************************/
574 
575 /* TS6 UID generator common code.
576  *
577  * Derived from atheme-services, uid.c (hg 2954:116d46894b4c).
578  * -nenolod
579  */
580 static int ts6_uid_initted = 0;
581 static char ts6_new_uid[10]; /* allow for \0 */
582 static unsigned int ts6_uid_index = 9; /* last slot in uid buf */
583 
584 void ts6_uid_init(void)
585 {
586  /* check just in case... you can never be too safe. */
587  if (TS6SID != NULL) {
588  snprintf(ts6_new_uid, 10, "%sAAAAAA", TS6SID);
589  ts6_uid_initted = 1;
590  } else {
591  alog("warning: no TS6SID specified, disabling TS6 support.");
592  UseTS6 = 0;
593 
594  return;
595  }
596 }
597 
598 void ts6_uid_increment(unsigned int slot)
599 {
600  if (slot != strlen(TS6SID)) {
601  if (ts6_new_uid[slot] == 'Z')
602  ts6_new_uid[slot] = '0';
603  else if (ts6_new_uid[slot] == '9') {
604  ts6_new_uid[slot] = 'A';
605  ts6_uid_increment(slot - 1);
606  } else
607  ts6_new_uid[slot]++;
608  } else {
609  if (ts6_new_uid[slot] == 'Z')
610  for (slot = 3; slot < 9; slot++)
611  ts6_new_uid[slot] = 'A';
612  else
613  ts6_new_uid[slot]++;
614  }
615 }
616 
617 char *ts6_uid_retrieve(void)
618 {
619  if (ts6_uid_initted != 1)
620  ts6_uid_init();
621 
623 
624  return ts6_new_uid;
625 }
626 
627 /* EOF */
E void E void E void notice_server(char *source, Server *s, char *fmt,...) FORMAT(printf
uint32 qs
Definition: services.h:392
int is_sync(Server *server)
Definition: servers.c:516
#define CAPAB_TS3
Definition: services.h:1373
#define EVENT_SERVER_SQUIT
Definition: events.h:56
E User * nextuser(void)
Definition: users.c:364
E void delete_user(User *user)
Definition: users.c:195
char * chanmodes
Definition: services.h:355
#define CAPAB_UID
Definition: services.h:1381
#define SERVER_ISUPLINK
Definition: services.h:867
E IRCDCAPAB * ircdcap
Definition: extern.h:40
char * nickchars
Definition: services.h:369
int nickip
Definition: services.h:340
CapabInfo capab_info[]
Definition: servers.c:27
#define CAPAB_SSJ5
Definition: services.h:1385
E int snprintf(char *buf, size_t size, const char *fmt,...)
Definition: compat.c:37
#define CAPAB_NICKCHARS
Definition: services.h:1396
#define NI_SUSPENDED
Definition: services.h:1308
E IRCDVar * ircd
Definition: extern.h:39
#define CAPAB_DKEY
Definition: services.h:1375
#define CAPAB_NOQUIT
Definition: services.h:1366
char * last_quit
Definition: services.h:527
E void send_event(const char *name, int argc,...)
Definition: events.c:37
int is_ulined(char *server)
Definition: servers.c:495
#define CAPAB_VHOST
Definition: services.h:1387
char * uplink
Definition: servers.c:20
Server * serv_uplink
Definition: servers.c:18
uint32 unconnect
Definition: services.h:382
E int stricmp(const char *s1, const char *s2)
Definition: compat.c:58
E int GlobalOnCycle
Definition: extern.h:430
E char * myStrGetTokenRemainder(const char *str, const char dilim, int token_number)
Definition: misc.c:720
#define NS_RECOGNIZED
Definition: services.h:1276
#define NS_VERBOTEN
Definition: services.h:1273
E void del_session(const char *host)
Definition: sessions.c:265
uint32 noquit
Definition: services.h:380
char * host
Definition: services.h:878
E char * GlobalOnCycleUP
Definition: extern.h:433
#define CAPAB_NICKIP
Definition: services.h:1369
E void restore_unsynced_topics(void)
Definition: channels.c:2075
#define CAPAB_TOKEN
Definition: services.h:1388
Server * links
Definition: services.h:861
char * TS6UPLINK
Definition: servers.c:21
#define CAPAB_SN2
Definition: services.h:1386
Server * next_server(int flags)
Definition: servers.c:81
char * desc
Definition: services.h:856
uint32 flag
Definition: services.h:1363
E char * sstrdup(const char *s)
Definition: memory.c:105
NickCore * nc
Definition: services.h:533
E void * scalloc(long elsize, long els)
Definition: memory.c:55
int anope_check_sync(const char *name)
Definition: servers.c:335
E void E void E void fatal(const char *fmt,...) FORMAT(printf
E char * s_OperServ
Definition: extern.h:289
Server * next
Definition: services.h:852
SyncState sync
Definition: services.h:859
void ts6_uid_increment(unsigned int slot)
Definition: servers.c:598
Server * me_server
Definition: servers.c:17
uint16 status
Definition: services.h:532
#define CAPAB_TSMODE
Definition: services.h:1367
E int NumUlines
Definition: extern.h:515
char * token
Definition: services.h:1362
char * TS6SID
Definition: servers.c:22
E char ** Ulines
Definition: extern.h:514
char * name
Definition: services.h:854
#define CAPAB_QS
Definition: services.h:1378
uint16 flags
Definition: services.h:857
Server * prev
Definition: services.h:852
Server * server
Definition: services.h:884
u_int32_t uint32
Definition: db-merger.c:123
E void alog(const char *fmt,...) FORMAT(printf
uint32 uplink_capab
Definition: servers.c:19
static void delete_server(Server *serv, const char *quitreason)
Definition: servers.c:185
E int UseTS6
Definition: extern.h:364
#define CAPAB_UNCONNECT
Definition: services.h:1368
#define CAPAB_CHANMODE
Definition: services.h:1394
#define CAPAB_SSJ3
Definition: services.h:1389
E User * firstuser(void)
Definition: users.c:352
#define CAPAB_NSJOIN
Definition: services.h:1370
E void anope_cmd_squit(char *servname, char *message)
Definition: ircd.c:529
#define CAPAB_CLIENT
Definition: services.h:1383
E int debug
Definition: extern.h:775
#define CAPAB_SJB64
Definition: services.h:1395
Server * findserver(Server *s, const char *name)
Definition: servers.c:261
int sync
Definition: services.h:370
uint16 hops
Definition: services.h:855
#define CAPAB_BURST
Definition: services.h:1372
#define CAPAB_PT4
Definition: services.h:1380
char * ts6_uid_retrieve(void)
Definition: servers.c:617
static unsigned int ts6_uid_index
Definition: servers.c:582
static char ts6_new_uid[10]
Definition: servers.c:581
Server * uplink
Definition: services.h:862
void do_squit(const char *source, int ac, char **av)
Definition: servers.c:398
void do_server(const char *source, char *servername, char *hops, char *descript, char *numeric)
Definition: servers.c:360
E int LimitSessions
Definition: extern.h:503
Server * first_server(int flags)
Definition: servers.c:64
Server * servlist
Definition: servers.c:16
#define SERVER_JUPED
Definition: services.h:866
void ts6_uid_init(void)
Definition: servers.c:584
static int ts6_uid_initted
Definition: servers.c:580
E char * myStrGetToken(const char *str, const char dilim, int token_number)
Definition: misc.c:654
#define NS_IDENTIFIED
Definition: services.h:1275
#define CAPAB_TS5
Definition: services.h:1374
void finish_sync(Server *serv, int sync_links)
Definition: servers.c:531
uint32 flags
Definition: services.h:548
void capab_parse(int ac, char **av)
Definition: servers.c:451
#define CAPAB_SCS
Definition: services.h:1379
Server * new_server(Server *uplink, const char *name, const char *desc, uint16 flags, char *suid)
Definition: servers.c:119
int ts6
Definition: services.h:366
char * suid
Definition: services.h:858
time_t last_seen
Definition: services.h:531
static Server * server_cur
Definition: servers.c:25
#define CAPAB_IPV6
Definition: services.h:1384
#define EVENT_SERVER_CONNECT
Definition: events.h:57
#define CAPAB_ZIP
Definition: services.h:1371
#define BUFSIZE
Definition: config.h:47
E char * s_GlobalNoticer
Definition: extern.h:290
NickAlias * na
Definition: services.h:892
Server * findserver_uid(Server *s, const char *name)
Definition: servers.c:298
E void anope_cmd_global(char *source, const char *fmt,...)
Definition: ircd.c:506
u_int16_t uint16
Definition: db-merger.c:121
#define CAPAB_KNOCK
Definition: services.h:1382