2 * IRC - Internet Relay Chat, ircd/ircd.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 #include <sys/resource.h>
47 #include <netinet/in.h>
48 #include <arpa/nameser.h>
51 #include <sys/socket.h> /* Needed for AF_INET on some OS */
75 extern void init_counters(void);
77 aClient me; /* That's me */
78 aClient *client = &me; /* Pointer to beginning of Client list */
79 time_t TSoffset = 0; /* Global variable; Offset of timestamps to
83 unsigned short int portnum = 0; /* Server port number, listening this */
84 char *configfile = CPATH; /* Server configuration file */
85 int debuglevel = -1; /* Server debug level */
86 unsigned int bootopt = 0; /* Server boot option flags */
87 char *debugmode = ""; /* -"- -"- -"- */
90 static char *dpath = DPATH;
92 time_t nextconnect = 1; /* time for next try_connections call */
93 time_t nextping = 1; /* same as above for check_pings() */
94 time_t nextdnscheck = 0; /* next time to poll dns to force timeouts */
95 time_t nextexpire = 1; /* next expire run on the dns cache */
97 time_t now; /* Updated every time we leave select(),
98 and used everywhere else */
103 RETSIGTYPE s_monitor(HANDLER_ARG(int UNUSED(sig)))
107 struct sigaction act;
113 act.sa_handler = s_rehash;
115 sigemptyset(&act.sa_mask);
116 sigaddset(&act.sa_mask, SIGUSR1);
117 sigaction(SIGUSR1, &act, NULL);
119 signal(SIGUSR1, s_monitor);
125 RETSIGTYPE s_die(HANDLER_ARG(int UNUSED(sig)))
128 syslog(LOG_CRIT, "Server Killed By SIGTERM");
130 flush_connections(me.fd);
134 static RETSIGTYPE s_rehash(HANDLER_ARG(int UNUSED(sig)))
137 struct sigaction act;
141 act.sa_handler = s_rehash;
143 sigemptyset(&act.sa_mask);
144 sigaddset(&act.sa_mask, SIGHUP);
145 sigaction(SIGHUP, &act, NULL);
147 signal(SIGHUP, s_rehash); /* sysV -argv */
152 void restart(char *mesg)
154 void restart(char *UNUSED(mesg))
158 syslog(LOG_WARNING, "Restarting Server because: %s", mesg);
163 RETSIGTYPE s_restart(HANDLER_ARG(int UNUSED(sig)))
168 void server_reboot(void)
172 sendto_ops("Aieeeee!!! Restarting server...");
173 Debug((DEBUG_NOTICE, "Restarting server..."));
174 flush_connections(me.fd);
176 * fd 0 must be 'preserved' if either the -d or -i options have
177 * been passed to us before restarting.
182 for (i = 3; i < MAXCONNECTIONS; i++)
184 if (!(bootopt & (BOOT_TTY | BOOT_DEBUG)))
187 if ((bootopt & BOOT_CONSOLE) || isatty(0))
189 if (!(bootopt & BOOT_INETD))
190 execv(SPATH, myargv);
192 /* Have to reopen since it has been closed above */
194 openlog(myargv[0], LOG_PID | LOG_NDELAY, LOG_FACILITY);
195 syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", SPATH, myargv[0]);
198 Debug((DEBUG_FATAL, "Couldn't restart server \"%s\": %s",
199 SPATH, strerror(errno)));
206 * Scan through configuration and try new connections.
208 * Returns the calendar time when the next call to this
209 * function should be made latest. (No harm done if this
210 * is called earlier or later...)
212 static time_t try_connections(void)
214 Reg1 aConfItem *aconf;
217 int connecting, confrq;
220 aConfItem *cconf, *con_conf = NULL;
221 unsigned int con_class = 0;
224 Debug((DEBUG_NOTICE, "Connection check at : %s", myctime(now)));
225 for (aconf = conf; aconf; aconf = aconf->next)
227 /* Also when already connecting! (update holdtimes) --SRB */
228 if (!(aconf->status & CONF_CONNECT_SERVER) || aconf->port == 0)
230 cltmp = aconf->confClass;
232 * Skip this entry if the use of it is still on hold until
233 * future. Otherwise handle this entry (and set it on hold
234 * until next time). Will reset only hold times, if already
235 * made one successfull connection... [this algorithm is
236 * a bit fuzzy... -- msa >;) ]
239 if ((aconf->hold > now))
241 if ((next > aconf->hold) || (next == 0))
246 confrq = get_con_freq(cltmp);
247 aconf->hold = now + confrq;
249 * Found a CONNECT config with port specified, scan clients
250 * and see if this server is already connected?
252 cptr = FindServer(aconf->name);
254 if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
255 (!connecting || (ConClass(cltmp) > con_class)))
257 /* Check connect rules to see if we're allowed to try */
258 for (cconf = conf; cconf; cconf = cconf->next)
259 if ((cconf->status & CONF_CRULE) &&
260 (match(cconf->host, aconf->name) == 0))
261 if (crule_eval(cconf->passwd))
265 con_class = ConClass(cltmp);
267 /* We connect only one at time... */
271 if ((next > aconf->hold) || (next == 0))
276 if (con_conf->next) /* are we already last? */
278 /* Put the current one at the end and make sure we try all connections */
279 for (pconf = &conf; (aconf = *pconf); pconf = &(aconf->next))
280 if (aconf == con_conf)
281 *pconf = aconf->next;
282 (*pconf = con_conf)->next = 0;
284 if (connect_server(con_conf, (aClient *)NULL, (struct hostent *)NULL) == 0)
285 sendto_ops("Connection to %s[%s] activated.",
286 con_conf->name, con_conf->host);
288 Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next)));
292 static time_t check_pings(void)
295 int ping = 0, i, rflag = 0;
296 time_t oldest = 0, timeout;
298 for (i = 0; i <= highest_fd; i++)
300 if (!(cptr = loc_clients[i]) || IsMe(cptr) || IsLog(cptr) || IsPing(cptr))
304 * Note: No need to notify opers here.
305 * It's already done when "FLAGS_DEADSOCKET" is set.
309 exit_client(cptr, cptr, &me, LastDeadComment(cptr));
313 #if defined(R_LINES) && defined(R_LINES_OFTEN)
314 rflag = IsUser(cptr) ? find_restrict(cptr) : 0;
316 ping = IsRegistered(cptr) ? get_client_ping(cptr) : CONNECTTIMEOUT;
317 Debug((DEBUG_DEBUG, "c(%s)=%d p %d r %d a %d",
318 cptr->name, cptr->status, ping, rflag, (int)(now - cptr->lasttime)));
320 * Ok, so goto's are ugly and can be avoided here but this code
321 * is already indented enough so I think its justified. -avalon
323 if (!rflag && IsRegistered(cptr) && (ping >= now - cptr->lasttime))
326 * If the server hasnt talked to us in 2*ping seconds
327 * and it has a ping time, then close its connection.
328 * If the client is a user and a KILL line was found
329 * to be active, close this connection too.
332 ((now - cptr->lasttime) >= (2 * ping) &&
333 (cptr->flags & FLAGS_PINGSENT)) ||
334 (!IsRegistered(cptr) && !IsHandshake(cptr) &&
335 (now - cptr->firsttime) >= ping))
337 if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr)))
339 Debug((DEBUG_NOTICE, "%s/%s timeout %s", DoingDNS(cptr) ? "DNS" : "",
340 DoingAuth(cptr) ? "AUTH" : "", get_client_name(cptr, TRUE)));
341 if (cptr->authfd >= 0)
346 *cptr->buffer = '\0';
348 del_queries((char *)cptr);
352 cptr->firsttime = now;
353 cptr->lasttime = now;
356 if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
358 sendto_ops("No response from %s, closing link",
359 get_client_name(cptr, FALSE));
360 exit_client(cptr, cptr, &me, "Ping timeout");
364 * This is used for KILL lines with time restrictions
365 * on them - send a messgae to the user being killed first.
367 #if defined(R_LINES) && defined(R_LINES_OFTEN)
368 else if (IsUser(cptr) && rflag)
370 sendto_ops("Restricting %s, closing link.",
371 get_client_name(cptr, FALSE));
372 exit_client(cptr, cptr, &me, "R-lined");
377 if (!IsRegistered(cptr) && *cptr->name && *cptr->user->username)
380 ":%s %d %s :Your client may not be compatible with this server.",
381 me.name, ERR_BADPING, cptr->name);
383 ":%s %d %s :Compatible clients are available at "
384 "ftp://ftp.undernet.org/pub/irc/clients",
385 me.name, ERR_BADPING, cptr->name);
387 exit_client_msg(cptr, cptr, &me, "Ping timeout for %s",
388 get_client_name(cptr, FALSE));
392 else if (IsRegistered(cptr) && (cptr->flags & FLAGS_PINGSENT) == 0)
395 * If we havent PINGed the connection and we havent
396 * heard from it in a while, PING it to make sure
399 cptr->flags |= FLAGS_PINGSENT;
400 /* not nice but does the job */
401 cptr->lasttime = now - ping;
403 sendto_one(cptr, "PING :%s", me.name);
405 sendto_one(cptr, ":%s PING :%s", me.name, me.name);
408 timeout = cptr->lasttime + ping;
409 while (timeout <= now)
411 if (timeout < oldest || !oldest)
414 if (!oldest || oldest < now)
415 oldest = now + PINGFREQUENCY;
417 "Next check_ping() call at: %s, %d " TIME_T_FMT " " TIME_T_FMT,
418 myctime(oldest), ping, oldest, now));
426 * This is called when the commandline is not acceptable.
427 * Give error message and exit without starting anything.
429 static int bad_command(void)
431 printf("Usage: ircd %s[-h servername] [-p portnumber] [-x loglevel] [-t]\n",
432 #ifdef CMDLINE_CONFIG
438 printf("Server not started\n\n");
442 static void setup_signals(void)
445 struct sigaction act;
447 act.sa_handler = SIG_IGN;
449 sigemptyset(&act.sa_mask);
450 sigaddset(&act.sa_mask, SIGPIPE);
451 sigaddset(&act.sa_mask, SIGALRM);
453 sigaddset(&act.sa_mask, SIGWINCH);
454 sigaction(SIGWINCH, &act, NULL);
456 sigaction(SIGPIPE, &act, NULL);
457 act.sa_handler = dummy;
458 sigaction(SIGALRM, &act, NULL);
459 act.sa_handler = s_rehash;
460 sigemptyset(&act.sa_mask);
461 sigaddset(&act.sa_mask, SIGHUP);
462 sigaction(SIGHUP, &act, NULL);
463 act.sa_handler = s_restart;
464 sigaddset(&act.sa_mask, SIGINT);
465 sigaction(SIGINT, &act, NULL);
466 act.sa_handler = s_die;
467 sigaddset(&act.sa_mask, SIGTERM);
468 sigaction(SIGTERM, &act, NULL);
471 #ifndef HAVE_RELIABLE_SIGNALS
472 signal(SIGPIPE, dummy);
474 signal(SIGWINCH, dummy);
478 signal(SIGWINCH, SIG_IGN);
480 signal(SIGPIPE, SIG_IGN);
482 signal(SIGALRM, dummy);
483 signal(SIGHUP, s_rehash);
484 signal(SIGTERM, s_die);
485 signal(SIGINT, s_restart);
488 #ifdef HAVE_RESTARTABLE_SYSCALLS
490 * At least on Apollo sr10.1 it seems continuing system calls
491 * after signal is the default. The following 'siginterrupt'
492 * should change that default to interrupting calls.
494 siginterrupt(SIGALRM, 1);
501 * If the -t option is not given on the command line when the server is
502 * started, all debugging output is sent to the file set by LPATH in config.h
503 * Here we just open that file and make sure it is opened to fd 2 so that
504 * any fprintf's to stderr also goto the logfile. If the debuglevel is not
505 * set from the command line by -x, use /dev/null as the dummy logfile as long
506 * as DEBUGMODE has been defined, else dont waste the fd.
508 static void open_debugfile(void)
516 cptr = make_client(NULL, STAT_LOG);
518 cptr->port = debuglevel;
521 loc_clients[2] = cptr;
522 strcpy(cptr->sockhost, me.sockhost);
524 printf("isatty = %d ttyname = %#x\n", isatty(2), (unsigned int)ttyname(2));
525 if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
527 if ((fd = creat(LOGFILE, 0600)) < 0)
528 if ((fd = open("/dev/null", O_WRONLY)) < 0)
535 strncpy(cptr->name, LOGFILE, sizeof(cptr->name));
536 cptr->name[sizeof(cptr->name) - 1] = 0;
538 else if (isatty(2) && ttyname(2))
540 strncpy(cptr->name, ttyname(2), sizeof(cptr->name));
541 cptr->name[sizeof(cptr->name) - 1] = 0;
544 strcpy(cptr->name, "FD2-Pipe");
545 Debug((DEBUG_FATAL, "Debug: File <%s> Level: %u at %s",
546 cptr->name, cptr->port, myctime(now)));
549 loc_clients[2] = NULL;
554 int have_server_port;
556 int main(int argc, char *argv[])
558 unsigned short int portarg = 0;
562 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE)
563 struct rlimit corelim;
570 monstartup(0, etext);
572 signal(SIGUSR1, s_monitor);
578 fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", DPATH, strerror(errno));
584 fprintf(stderr, "Fail: Cannot chroot(%s): %s\n", DPATH, strerror(errno));
588 #endif /*CHROOTDIR */
591 umask(077); /* better safe than sorry --SRB */
592 memset(&me, 0, sizeof(me));
593 memset(&vserv, 0, sizeof(vserv));
594 vserv.sin_family = AF_INET;
595 vserv.sin_addr.s_addr = htonl(INADDR_ANY);
596 memset(&cserv, 0, sizeof(cserv));
597 cserv.sin_addr.s_addr = htonl(INADDR_ANY);
598 cserv.sin_family = AF_INET;
603 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE)
604 if (getrlimit(RLIMIT_CORE, &corelim))
606 fprintf(stderr, "Read of rlimit core size failed: %s\n", strerror(errno));
607 corelim.rlim_max = RLIM_INFINITY; /* Try to recover */
609 corelim.rlim_cur = corelim.rlim_max;
610 if (setrlimit(RLIMIT_CORE, &corelim))
611 fprintf(stderr, "Setting rlimit core size failed: %s\n", strerror(errno));
615 * All command line parameters have the syntax "-fstring"
616 * or "-f string" (e.g. the space is optional). String may
617 * be empty. Flag characters cannot be concatenated (like
618 * "-fxyz"), it would conflict with the form "-fstring".
620 while (--argc > 0 && (*++argv)[0] == '-')
622 char *p = argv[0] + 1;
625 if (flag == '\0' || *p == '\0')
627 if (argc > 1 && argv[1][0] != '-')
639 bootopt |= BOOT_AUTODIE;
642 bootopt |= BOOT_CONSOLE;
645 bootopt |= BOOT_QUICK;
652 #ifdef CMDLINE_CONFIG
660 strncpy(me.name, p, sizeof(me.name));
661 me.name[sizeof(me.name) - 1] = 0;
664 bootopt |= BOOT_INETD | BOOT_AUTODIE;
667 if ((portarg = atoi(p)) > 0)
676 printf("ircd %s\n", version);
681 if (!(hep = gethostbyname(p)))
683 fprintf(stderr, "%s: Error resolving \"%s\" (h_errno == %d).\n",
684 argv[-1], p, h_errno);
687 if (hep->h_addrtype == AF_INET && hep->h_addr_list[0] &&
688 !hep->h_addr_list[1])
691 memcpy(&vserv.sin_addr, hep->h_addr_list[0], sizeof(struct in_addr));
692 memcpy(&cserv.sin_addr, hep->h_addr_list[0], sizeof(struct in_addr));
693 /* Test if we can bind to this address */
694 fd = socket(AF_INET, SOCK_STREAM, 0);
695 if (bind(fd, (struct sockaddr *)&vserv, sizeof(vserv)) == 0)
701 fprintf(stderr, "%s:\tError binding to interface \"%s\".\n"
702 " \tUse `ifconfig -a' to check your interfaces.\n", argv[-1], p);
709 debuglevel = atoi(p);
710 debugmode = *p ? p : "0";
711 bootopt |= BOOT_DEBUG;
714 fprintf(stderr, "%s: DEBUGMODE must be defined for -x y\n", myargv[0]);
725 fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", dpath, strerror(errno));
730 if ((uid != euid) && !euid)
733 "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
738 #if !defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID))
743 setuid((uid_t) euid);
747 if ((int)getuid() == 0)
749 #if defined(IRC_UID) && defined(IRC_GID)
751 /* run as a specified user */
752 fprintf(stderr, "WARNING: running ircd with uid = %d\n", IRC_UID);
753 fprintf(stderr, " changing to gid %d.\n", IRC_GID);
757 /* check for setuid root as usual */
759 "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
763 #endif /*CHROOTDIR/UID/GID */
766 return bad_command(); /* This should exit out */
776 if (access(path, X_OK) == 0)
780 if (access(path, R_OK) == 0)
784 if (access(path, R_OK) == 0)
788 if (access(path, R_OK) == 0)
795 if (access(path, W_OK) == 0)
804 fprintf(stderr, "Check on %cPATH (%s) failed: %s\n",
805 c, path, strerror(errno));
807 "Please create file and/or rerun `make config' and recompile to correct this.\n");
810 "Keep in mind that all paths are relative to CHROOTDIR.\n");
827 me.flags = FLAGS_LISTEN;
828 if ((bootopt & BOOT_INETD))
831 loc_clients[0] = &me;
832 me.flags = FLAGS_LISTEN;
838 openlog(myargv[0], LOG_PID | LOG_NDELAY, LOG_FACILITY);
840 if (initconf(bootopt) == -1)
842 Debug((DEBUG_FATAL, "Failed in reading configuration file %s", configfile));
843 printf("Couldn't open configuration file %s\n", configfile);
846 if (!(bootopt & BOOT_INETD))
848 Debug((DEBUG_ERROR, "Port = %u", portnum));
849 if (!have_server_port && inetport(&me, "*", "", portnum))
852 else if (inetport(&me, "*", "*", 0))
856 rmotd = read_motd(RPATH);
857 motd = read_motd(MPATH);
859 get_my_name(&me, me.sockhost, sizeof(me.sockhost) - 1);
869 /* Abuse own link timestamp as start timestamp: */
870 me.serv->timestamp = TStime();
871 me.serv->prot = atoi(MAJOR_PROTOCOL);
873 me.serv->down = NULL;
875 SetYXXCapacity(&me, MAXCLIENTS);
877 me.lasttime = me.since = me.firsttime = now;
885 Debug((DEBUG_NOTICE, "Server ready..."));
887 syslog(LOG_NOTICE, "Server Ready");
893 * We only want to connect if a connection is due,
894 * not every time through. Note, if there are no
895 * active C lines, this call to Tryconnections is
896 * made once only; it will return 0. - avalon
898 if (nextconnect && now >= nextconnect)
899 nextconnect = try_connections();
901 * DNS checks. One to timeout queries, one for cache expiries.
903 if (now >= nextdnscheck)
904 nextdnscheck = timeout_query_list();
905 if (now >= nextexpire)
906 nextexpire = expire_cache();
908 * Take the smaller of the two 'timed' event times as
909 * the time of next event (stops us being late :) - avalon
910 * WARNING - nextconnect can return 0!
913 delay = MIN(nextping, nextconnect);
916 delay = MIN(nextdnscheck, delay);
917 delay = MIN(nextexpire, delay);
920 * Adjust delay to something reasonable [ad hoc values]
921 * (one might think something more clever here... --msa)
922 * We don't really need to check that often and as long
923 * as we don't delay too long, everything should be ok.
924 * waiting too long can cause things to timeout...
925 * i.e. PINGS -> a disconnection :(
931 delay = MIN(delay, TIMESEC);
934 Debug((DEBUG_DEBUG, "Got message(s)"));
937 * ...perhaps should not do these loops every time,
938 * but only if there is some chance of something
939 * happening (but, note that conf->hold times may
940 * be changed elsewhere--so precomputed next event
941 * time might be too far away... (similarly with
945 nextping = check_pings();