4
mirror of git://git.acid.vegas/unrealircd.git synced 2024-11-14 03:56:46 +00:00

Updated to 6.0.3

This commit is contained in:
Dionysus 2022-04-03 11:09:29 -04:00
parent 4e71d6fead
commit 252e8547f4
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
80 changed files with 2669 additions and 1361 deletions

1
.gitignore vendored
View File

@ -9,7 +9,6 @@ extras/c-ares*
config.status
extras/ircdcron/ircd.cron
extras/ircdcron/ircdchk
src/modules/snomasks/Makefile
src/modules/chanmodes/Makefile
src/modules/extbans/Makefile
src/modules/usermodes/Makefile

32
Config
View File

@ -18,7 +18,24 @@
# some bits edited by baafie on March 17 2004, every change marked.
# Remove trailing slash in paths (if any)
FIX_PATHNAMES () {
BASEPATH="${BASEPATH%/}"
BINDIR="${BINDIR%/}"
DATADIR="${DATADIR%/}"
CONFDIR="${CONFDIR%/}"
MODULESDIR="${MODULESDIR%/}"
LOGDIR="${LOGDIR%/}"
CACHEDIR="${CACHEDIR%/}"
DOCDIR="${DOCDIR%/}"
TMPDIR="${TMPDIR%/}"
PRIVATELIBDIR="${PRIVATELIBDIR%/}"
SSLDIR="${SSLDIR%/}"
CURLDIR="${CURLDIR%/}"
}
# Create and run the ./configure command with the appropriate
# options based on the users settings.
RUN_CONFIGURE () {
ARG=" "
@ -72,6 +89,7 @@ fi
ARG="$ARG--with-bindir=$BINDIR "
ARG="$ARG--with-datadir=$DATADIR "
ARG="$ARG--with-pidfile=$DATADIR/unrealircd.pid "
ARG="$ARG--with-controlfile=$DATADIR/unrealircd.ctl "
ARG="$ARG--with-confdir=$CONFDIR "
ARG="$ARG--with-modulesdir=$MODULESDIR "
ARG="$ARG--with-logdir=$LOGDIR "
@ -292,6 +310,7 @@ while [ $# -ge 1 ] ; do
if [ -f "config.settings" ] ; then
. ./config.settings
fi
FIX_PATHNAMES
RUN_CONFIGURE
cd "$UNREALCWD"
exit 0
@ -356,7 +375,7 @@ echo "We will now ask you a number of questions. You can just press ENTER to acc
echo ""
# This needs to be updated each release so auto-upgrading works for settings, modules, etc!!:
UNREALRELEASES="unrealircd-6.0.1 unrealircd-6.0.0 unrealircd-6.0.0-rc2 unrealircd-6.0.0-rc1 unrealircd-6.0.0-beta4 unrealircd-6.0.0-beta3 unrealircd-6.0.0-beta2 unrealircd-6.0.0-beta1 unrealircd-5.2.3 unrealircd-5.2.2 unrealircd-5.2.1.1 unrealircd-5.2.1 unrealircd-5.2.1-rc1 unrealircd-5.2.0.2 unrealircd-5.2.0.1 unrealircd-5.2.0 unrealircd-5.2.0-rc1 unrealircd-5.0.9.1 unrealircd-5.0.9 unrealircd-5.0.9-rc1 unrealircd-5.0.8 unrealircd-5.0.8-rc1 unrealircd-5.0.7 unrealircd-5.0.7-rc1 unrealircd-5.0.6"
UNREALRELEASES="unrealircd-6.0.2 unrealircd-6.0.1.1 unrealircd-6.0.1 unrealircd-6.0.0 unrealircd-6.0.0-rc2 unrealircd-6.0.0-rc1 unrealircd-6.0.0-beta4 unrealircd-6.0.0-beta3 unrealircd-6.0.0-beta2 unrealircd-6.0.0-beta1 unrealircd-5.2.3 unrealircd-5.2.2 unrealircd-5.2.1.1 unrealircd-5.2.1 unrealircd-5.2.1-rc1 unrealircd-5.2.0.2 unrealircd-5.2.0.1 unrealircd-5.2.0 unrealircd-5.2.0-rc1 unrealircd-5.0.9.1 unrealircd-5.0.9 unrealircd-5.0.9-rc1 unrealircd-5.0.8 unrealircd-5.0.8-rc1 unrealircd-5.0.7 unrealircd-5.0.7-rc1 unrealircd-5.0.6"
if [ -f "config.settings" ]; then
. ./config.settings
else
@ -701,11 +720,12 @@ while [ -z "$TEST" ] ; do
TEST="$GEOIP"
echo ""
echo "GeoIP is a feature that allows converting an IP address to a location (country)"
echo "You have three options in UnrealIRCd:"
echo " classic: This is the DEFAULT geoip engine that should work on all systems"
echo "libmaxminddb: This uses the libmaxminddb library. If you want to use it then"
echo "Possible build options:"
echo " classic: This is the DEFAULT geoip engine. It should work on all systems"
echo " and receives automatic updates."
echo "libmaxminddb: This uses the libmaxminddb library. If you want to use this, then"
echo " you need to install the libmaxminddb library on your system first"
echo " none: Don't built with any geoip feature"
echo " none: Don't build with any geoip library (geoip-csv is still built)"
echo "Choose one of: classic, libmaxminddb, none"
echo $n "[$TEST] -> $c"
read cc
@ -814,6 +834,8 @@ if [ -z "$EXTRAPARA" ]; then
EXTRAPARA="$TEST"
fi
FIX_PATHNAMES
rm -f config.settings
cat > config.settings << __EOF__
#

View File

@ -179,13 +179,13 @@ depend:
install: all
$(INSTALL) -m 0700 -d $(DESTDIR)@BINDIR@
$(INSTALL) -m 0700 src/ircd $(DESTDIR)@BINDIR@/unrealircd
$(INSTALL) -m 0700 src/unrealircdctl $(DESTDIR)@BINDIR@/unrealircdctl
$(INSTALL) -m 0700 extras/unrealircd-upgrade-script $(DESTDIR)@BINDIR@/unrealircd-upgrade-script
$(INSTALL) -m 0700 -d $(DESTDIR)@DOCDIR@
$(INSTALL) -m 0600 doc/Authors doc/coding-guidelines doc/tao.of.irc doc/KEYS doc/RELEASE-NOTES.md $(DESTDIR)@DOCDIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@CONFDIR@
$(INSTALL) -m 0600 doc/conf/*.conf $(DESTDIR)@CONFDIR@
$(INSTALL) -m 0600 doc/conf/*.motd $(DESTDIR)@CONFDIR@
$(INSTALL) -m 0600 doc/conf/modules.sources.list $(DESTDIR)@CONFDIR@ ; \
$(INSTALL) -m 0700 unrealircd $(DESTDIR)@SCRIPTDIR@
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@
@rm -f $(DESTDIR)@MODULESDIR@/*.so 1>/dev/null 2>&1

View File

@ -165,8 +165,7 @@ CFLAGS=$(DBGCFLAG) $(STDOPTIONS) /FS /MP1 /c /Fosrc/
CFLAGSST=$(DBGCFLAGST) $(STDOPTIONS) /FS /MP1 /c /Fosrc/
LFLAGS=kernel32.lib user32.lib gdi32.lib shell32.lib ws2_32.lib advapi32.lib \
dbghelp.lib oldnames.lib comctl32.lib comdlg32.lib $(STDLIBS) \
/def:UnrealIRCd.def /implib:UnrealIRCd.lib \
/nologo $(DBGLFLAG) /out:UnrealIRCd.exe
/nologo $(DBGLFLAG)
MODCFLAGS=$(MODDBGCFLAG) $(STDOPTIONS) /D DYNAMIC_LINKING /D MODULE_COMPILE
MODLFLAGS=/link /def:src/modules/module.def UnrealIRCd.lib ws2_32.lib $(STDLIBS)
@ -174,10 +173,10 @@ INCLUDES=./include/struct.h ./include/config.h ./include/sys.h \
./include/common.h ./include/version.h ./include/h.h ./include/numeric.h \
./include/msg.h ./include/setup.h ./include/dynconf.h
EXP_OBJ_FILES=src/channel.obj src/send.obj src/socket.obj \
src/conf.obj src/conf_preprocessor.obj \
EXP_OBJ_FILES=src/ircd_vars.obj src/channel.obj src/send.obj src/socket.obj \
src/conf.obj src/proc_io_server.obj src/conf_preprocessor.obj \
src/fdlist.obj src/dbuf.obj \
src/hash.obj src/parse.obj src/ircd.obj \
src/hash.obj src/parse.obj \
src/whowas.obj \
src/misc.obj src/match.obj src/crule.obj \
src/debug.obj src/support.obj src/list.obj \
@ -194,7 +193,7 @@ EXP_OBJ_FILES=src/channel.obj src/send.obj src/socket.obj \
src/utf8.obj src/log.obj $(CURLOBJ)
OBJ_FILES=$(EXP_OBJ_FILES) src/gui.obj src/service.obj src/windebug.obj src/rtf.obj \
src/editor.obj src/win.obj
src/editor.obj src/win.obj src/ircd.obj src/proc_io_client.obj
DLL_FILES=\
src/modules/account-notify.dll \
@ -411,7 +410,7 @@ DLL_FILES=\
src/modules/whox.dll
ALL: CONF UNREALSVC.EXE UnrealIRCd.exe MODULES
ALL: CONF unrealircdctl.exe UNREALSVC.EXE UnrealIRCd.exe MODULES
CLEAN:
-@del /Q /S *.dll *.exe *.obj *.pdb *.res *.lib *.exp *.ilk src\version.c >NUL
@ -424,21 +423,27 @@ CONF:
$(CC) src/windows/config.c
-@config.exe
UnrealIRCd.exe: $(OBJ_FILES) src/windows/win.res
$(LINK) $(LFLAGS) $(OBJ_FILES) src/windows/win.res /MAP
UnrealIRCd.exe: $(OBJ_FILES) src/ircd.obj src/windows/win.res
$(LINK) $(LFLAGS) /out:UnrealIRCd.exe /def:UnrealIRCd.def /implib:UnrealIRCd.lib $(OBJ_FILES) src/windows/win.res /MAP
-@erase src\windows\win.res
$(MT) -manifest src\windows\UnrealIRCd.exe.manifest -outputresource:UnrealIRCd.exe;1
!IFNDEF DEBUGEXTRA
@echo Standard version built
!ELSE
@echo Extra-Debug version built ...
!ENDIF
unrealircdctl.exe: $(OBJ_FILES) src/unrealircdctl.obj src/proc_io_client.obj
$(LINK) $(LFLAGS) /SUBSYSTEM:CONSOLE /out:unrealircdctl.exe $(OBJ_FILES) src/unrealircdctl.obj
$(MT) -manifest src\windows\unrealircdctl.exe.manifest -outputresource:unrealircdctl.exe;1
# alternative option -- FIXME: REMOVE / CHOOSE
#unrealircdctl.exe: $(OBJ_FILES) src/unrealircdctl.obj src/proc_io_client.obj src/windows/unrealircdctl.res
# $(LINK) $(LFLAGS) /out:unrealircdctl.exe $(OBJ_FILES) src/unrealircdctl.obj src/windows/unrealircdctl.res
#Source files
src/version.obj: src/version.c
$(CC) $(CFLAGS) src/version.c
src/ircd_vars.obj: src/ircd_vars.c $(INCLUDES)
$(CC) $(CFLAGS) src/ircd_vars.c
src/parse.obj: src/parse.c $(INCLUDES)
$(CC) $(CFLAGS) src/parse.c
@ -485,6 +490,12 @@ src/dns.obj: src/dns.c $(INCLUDES)
src/conf.obj: src/conf.c $(INCLUDES)
$(CC) $(CFLAGS) src/conf.c
src/proc_io_server.obj: src/proc_io_server.c $(INCLUDES)
$(CC) $(CFLAGS) src/proc_io_server.c
src/proc_io_client.obj: src/proc_io_client.c $(INCLUDES)
$(CC) $(CFLAGS) src/proc_io_client.c
src/conf_preprocessor.obj: src/conf_preprocessor.c $(INCLUDES)
$(CC) $(CFLAGS) src/conf_preprocessor.c
@ -540,6 +551,9 @@ src/win.obj: src/windows/win.c $(INCLUDES)
src/unrealsvc.obj: src/windows/unrealsvc.c $(INCLUDES)
$(CC) $(CFLAGSST) src/windows/unrealsvc.c
src/unrealircdctl.obj: src/unrealircdctl.c $(INCLUDES)
$(CC) $(CFLAGS) src/unrealircdctl.c
src/modules.obj: src/modules.c $(INCLUDES)
$(CC) $(CFLAGS) src/modules.c
@ -623,6 +637,10 @@ src/windows/unrealsvc.res: src/windows/unrealsvc.rc
$(RC) /l 0x409 /fosrc/windows/unrealsvc.res /i ./include /i ./src \
/d NDEBUG src/windows/unrealsvc.rc
src/windows/unrealircdctl.res: src/windows/unrealircdctl.rc
$(RC) /l 0x409 /fosrc/windows/unrealircdctl.res /i ./include /i ./src \
/d NDEBUG src/windows/unrealircdctl.rc
################# Modules #################
CUSTOMMODULE: src/modules/third/$(MODULEFILE).c

51
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for unrealircd 6.0.1.1.
# Generated by GNU Autoconf 2.69 for unrealircd 6.0.3.
#
# Report bugs to <https://bugs.unrealircd.org/>.
#
@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unrealircd'
PACKAGE_TARNAME='unrealircd'
PACKAGE_VERSION='6.0.1.1'
PACKAGE_STRING='unrealircd 6.0.1.1'
PACKAGE_VERSION='6.0.3'
PACKAGE_STRING='unrealircd 6.0.3'
PACKAGE_BUGREPORT='https://bugs.unrealircd.org/'
PACKAGE_URL='https://unrealircd.org/'
@ -659,6 +659,7 @@ PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
LDFLAGS_PRIVATELIBS
CONTROLFILE
PIDFILE
DOCDIR
PERMDATADIR
@ -752,6 +753,7 @@ with_tmpdir
with_datadir
with_docdir
with_pidfile
with_controlfile
with_privatelibdir
with_maxconnections
with_no_operoverride
@ -1345,7 +1347,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures unrealircd 6.0.1.1 to adapt to many kinds of systems.
\`configure' configures unrealircd 6.0.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1411,7 +1413,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unrealircd 6.0.1.1:";;
short | recursive ) echo "Configuration of unrealircd 6.0.3:";;
esac
cat <<\_ACEOF
@ -1460,6 +1462,7 @@ Optional Packages:
--with-datadir=path Specify the directory where permanent data is stored
--with-docdir=path Specify the directory where documentation is stored
--with-pidfile=path Specify the path of the pid file
--with-controlfile=path Specify the path of the control socket
--with-privatelibdir=path
Specify the directory where private libraries are
stored. Disable when building a package for a distro
@ -1586,7 +1589,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unrealircd configure 6.0.1.1
unrealircd configure 6.0.3
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1955,7 +1958,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by unrealircd $as_me 6.0.1.1, which was
It was created by unrealircd $as_me 6.0.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2363,7 +2366,7 @@ _ACEOF
# Minor version number (e.g.: Z in X.Y.Z)
UNREAL_VERSION_MINOR="1"
UNREAL_VERSION_MINOR="3"
cat >>confdefs.h <<_ACEOF
#define UNREAL_VERSION_MINOR $UNREAL_VERSION_MINOR
@ -2373,7 +2376,7 @@ _ACEOF
# The version suffix such as a beta marker or release candidate
# marker. (e.g.: -rcX for unrealircd-3.2.9-rcX). This macro is a
# string instead of an integer because it contains arbitrary data.
UNREAL_VERSION_SUFFIX=".1"
UNREAL_VERSION_SUFFIX=""
cat >>confdefs.h <<_ACEOF
#define UNREAL_VERSION_SUFFIX "$UNREAL_VERSION_SUFFIX"
@ -6548,6 +6551,25 @@ fi
# Check whether --with-controlfile was given.
if test "${with_controlfile+set}" = set; then :
withval=$with_controlfile;
cat >>confdefs.h <<_ACEOF
#define CONTROLFILE "$withval"
_ACEOF
CONTROLFILE="$withval"
else
cat >>confdefs.h <<_ACEOF
#define CONTROLFILE "$HOME/unrealircd/data/unrealircd.ctl"
_ACEOF
CONTROLFILE="$HOME/unrealircd/data/unrealircd.ctl"
fi
# Check whether --with-privatelibdir was given.
if test "${with_privatelibdir+set}" = set; then :
withval=$with_privatelibdir;
@ -6589,6 +6611,7 @@ fi
# Check whether --with-maxconnections was given.
if test "${with_maxconnections+set}" = set; then :
withval=$with_maxconnections; ac_fd=$withval
@ -7438,7 +7461,7 @@ fi
if test "$has_system_pcre2" = "no"; then :
pcre2_version="10.36"
pcre2_version="10.39"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: extracting PCRE2 regex library" >&5
$as_echo "extracting PCRE2 regex library" >&6; }
cur_dir=`pwd`
@ -7455,7 +7478,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: configuring PCRE2 regex library" >&5
$as_echo "configuring PCRE2 regex library" >&6; }
cd pcre2-$pcre2_version
./configure --enable-jit --enable-shared --disable-unicode --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
./configure --enable-jit --enable-shared --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: compiling PCRE2 regex library" >&5
$as_echo "compiling PCRE2 regex library" >&6; }
$ac_cv_prog_MAKER || exit 1
@ -7798,7 +7821,7 @@ fi
if test "$has_system_cares" = "no"; then :
cares_version="1.17.2"
cares_version="1.18.1"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: extracting c-ares resolver library" >&5
$as_echo "extracting c-ares resolver library" >&6; }
cur_dir=`pwd`
@ -9391,7 +9414,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by unrealircd $as_me 6.0.1.1, which was
This file was extended by unrealircd $as_me 6.0.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -9454,7 +9477,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
unrealircd config.status 6.0.1.1
unrealircd config.status 6.0.3
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -7,7 +7,7 @@ dnl src/windows/unrealinst.iss
dnl doc/Config.header
dnl src/version.c.SH
AC_INIT([unrealircd], [6.0.1.1], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
AC_INIT([unrealircd], [6.0.3], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
AC_CONFIG_SRCDIR([src/ircd.c])
AC_CONFIG_HEADER([include/setup.h])
AC_CONFIG_AUX_DIR([autoconf])
@ -34,13 +34,13 @@ UNREAL_VERSION_MAJOR=["0"]
AC_DEFINE_UNQUOTED([UNREAL_VERSION_MAJOR], [$UNREAL_VERSION_MAJOR], [Major version number (e.g.: Y for X.Y.Z)])
# Minor version number (e.g.: Z in X.Y.Z)
UNREAL_VERSION_MINOR=["1"]
UNREAL_VERSION_MINOR=["3"]
AC_DEFINE_UNQUOTED([UNREAL_VERSION_MINOR], [$UNREAL_VERSION_MINOR], [Minor version number (e.g.: Z for X.Y.Z)])
# The version suffix such as a beta marker or release candidate
# marker. (e.g.: -rcX for unrealircd-3.2.9-rcX). This macro is a
# string instead of an integer because it contains arbitrary data.
UNREAL_VERSION_SUFFIX=[".1"]
UNREAL_VERSION_SUFFIX=[""]
AC_DEFINE_UNQUOTED([UNREAL_VERSION_SUFFIX], ["$UNREAL_VERSION_SUFFIX"], [Version suffix such as a beta marker or release candidate marker. (e.g.: -rcX for unrealircd-3.2.9-rcX)])
AC_PATH_PROG(RM,rm)
@ -484,6 +484,12 @@ AC_ARG_WITH(pidfile, [AS_HELP_STRING([--with-pidfile=path],[Specify the path of
[AC_DEFINE_UNQUOTED([PIDFILE], ["$HOME/unrealircd/data/unrealircd.pid"], [Define the path of the pid file])
PIDFILE="$HOME/unrealircd/data/unrealircd.pid"])
AC_ARG_WITH(controlfile, [AS_HELP_STRING([--with-controlfile=path],[Specify the path of the control socket])],
[AC_DEFINE_UNQUOTED([CONTROLFILE], ["$withval"], [Define the path of the control socket])
CONTROLFILE="$withval"],
[AC_DEFINE_UNQUOTED([CONTROLFILE], ["$HOME/unrealircd/data/unrealircd.ctl"], [Define the path of the control socket])
CONTROLFILE="$HOME/unrealircd/data/unrealircd.ctl"])
dnl Ensure that this “feature” can be disabled as it makes it harder to package unrealircd.
dnl Users have always been able to specify “./configure LDFLAGS=-Wl,-rpath,/path/to/blah”—binki
AC_ARG_WITH(privatelibdir, [AS_HELP_STRING([--with-privatelibdir=path],[Specify the directory where private libraries are stored. Disable when building a package for a distro])],
@ -514,6 +520,7 @@ dnl well, Because DATADIR conflicts with the Windows SDK header files.. amazing.
AC_SUBST(PERMDATADIR)
AC_SUBST(DOCDIR)
AC_SUBST(PIDFILE)
AC_SUBST(CONTROLFILE)
AC_SUBST(LDFLAGS_PRIVATELIBS)
AC_ARG_WITH(maxconnections, [AS_HELP_STRING([--with-maxconnections=size], [Specify the max file descriptors to use])],
@ -576,7 +583,7 @@ AS_IF([test "x$PRIVATELIBDIR" != "x"], [rm -f "$PRIVATELIBDIR/"libpcre2*])],[has
AS_IF([test "$has_system_pcre2" = "no"], [
dnl REMEMBER TO CHANGE WITH A NEW PCRE2 RELEASE!
pcre2_version="10.36"
pcre2_version="10.39"
AC_MSG_RESULT(extracting PCRE2 regex library)
cur_dir=`pwd`
cd extras
@ -593,7 +600,7 @@ else
fi
AC_MSG_RESULT(configuring PCRE2 regex library)
cd pcre2-$pcre2_version
./configure --enable-jit --enable-shared --disable-unicode --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
./configure --enable-jit --enable-shared --prefix=$cur_dir/extras/pcre2 --libdir=$PRIVATELIBDIR || exit 1
AC_MSG_RESULT(compiling PCRE2 regex library)
$ac_cv_prog_MAKER || exit 1
AC_MSG_RESULT(installing PCRE2 regex library)
@ -716,7 +723,7 @@ AS_IF([test "$has_system_cares" = "no"], [
dnl REMEMBER TO CHANGE WITH A NEW C-ARES RELEASE!
dnl NOTE: when changing this here, ALSO change it in extras/curlinstall
dnl and in the comment in this file around line 400!
cares_version="1.17.2"
cares_version="1.18.1"
AC_MSG_RESULT(extracting c-ares resolver library)
cur_dir=`pwd`
cd extras

View File

@ -7,7 +7,7 @@
\___/|_| |_|_| \___|\__,_|_|\___/\_| \_| \____/\__,_|
Configuration Program
for UnrealIRCd 6.0.1.1
for UnrealIRCd 6.0.3
This program will help you to compile your IRC server, and ask you
questions regarding the compile-time settings of it during the process.

View File

@ -1,8 +1,139 @@
UnrealIRCd 6.0.3
=================
A number of serious issues were discovered in UnrealIRCd 6. Among these is
an issue which will likely crash the IRCd sooner or later if you /REHASH
with any active clients connected.
We suggest everyone who is running UnrealIRCd 6 to upgrade to 6.0.3.
If you are already running UnrealIRCd 6 then read below. Otherwise, jump
straight to the [summary about UnrealIRCd 6](#Summary) to learn more
about UnrealIRCd 6.
Fixes:
* Crash in `WATCH` if the IRCd has been rehashed at least once. After doing
a `REHASH` with active clients it will likely corrupt memory. It may take
several days until after the rehash for the crash to occur, or even
weeks/months on smaller networks (accidental triggering, that is).
* A `REHASH` with certain remote includes setups could cause a crash or
other weird and confusing problems such as complaining about unable
to open an ipv6-database or missing snomask configuration.
This only affected some people with remote includes, not all.
* Potential out-of-bounds write in sending code. In practice it seems
harmless on most servers but this cannot be 100% guaranteed.
* Unlikely triggered log message would log uninitialized stack data to the
log file or send it to ircops.
* Channel ops could not remove halfops from a user (`-h`).
* After using the `RESTART` command (not recommended) the new IRCd was
often no longer writing to log files.
* Fix compile problem if you choose to use cURL remote includes but don't
have cURL on the system and ask UnrealIRCd to compile cURL.
Enhancements:
* The default text log format on disk changed. It now includes the server
name where the event was generated. Without this, it was sometimes
difficult to trace problems, since previously it sometimes looked like
there was a problem on your server when it was actually another server
on the network.
* Old log format: `[DATE TIME] subsystem.EVENT_ID loglevel: ........`
* New log format: `[DATE TIME] servername subsystem.EVENT_ID loglevel: ........`
Changes:
* Any MOTD lines added by services via
[`SVSMOTD`](https://www.unrealircd.org/docs/MOTD_and_Rules#SVSMOTD)
are now shown at the end of the MOTD-on-connect (unless using a shortmotd).
Previously the lines were only shown if you manually ran the `MOTD` command.
Developers and protocol:
* `LIST C<xx` now means: filter on channels that are created less
than `xx` minutes ago. This is the opposite of what we had earlier.
`LIST T<xx` is now supported as well (topic changed in last xx minutes),
it was already advertised in ELIST but support was not enabled previously.
UnrealIRCd 6.0.2
-----------------
UnrealIRCd 6.0.2 comes with several nice feature enhancements along with
some fixes. It also includes a fix for a crash bug that can be triggered
by ordinary users.
Fixes:
* Fix crash that can be triggered by regular users if you have any `deny dcc`
blocks in the config or any spamfilters with the `d` (DCC) target.
NOTE: You don't *have* to upgrade to 6.0.2 to fix this, you can also
hot-patch this issue without restart, see the news announcement.
* Windows: fix crash with IPv6 clients (local or remote) due to GeoIP lookup
* Fix infinite hang on "Loading IRCd configuration" if DNS is not working.
For example if the 1st DNS server in `/etc/resolv.conf` is down or refusing
requests.
* Some `MODE` server-to-server commands were missing a timestamp at the end,
even though this is mandatory for modes coming from a server.
* The [channeldb](https://www.unrealircd.org/docs/Set_block#set::channeldb)
module now converts letter extbans to named extbans (eg `~a` to `~account`).
Previously it did not, which caused letter extbans to appear in the banlist.
Later on, when linking servers, this would cause duplicate entries to appear
as well, with both the old and new format. The extbans were still effective
though, so this is mostly a visual +b/+e/+I list issue.
* Some [Extended Server Bans](https://www.unrealircd.org/docs/Extended_server_bans)
were not working correctly for WEBIRC proxies. In particular, a server ban
or exempt (ELINE) on `~country:XX` was only checked against the WEBIRC proxy.
Enhancements:
* Support for [logging to a channel](https://www.unrealircd.org/docs/Log_block#Logging_to_a_channel).
Similar to snomasks but then for channels.
* Command line interface changes:
* The [CLI tool](https://www.unrealircd.org/docs/Command_Line_Interface) now
communicates to the running UnrealIRCd process via a UNIX socket to
send commands and retrieve output.
* The command `./unrealircd rehash` will now show the rehash output,
including warnings and errors, and return a proper exit code.
* The same for `./unrealircd reloadtls`
* New command `./unrealircd status` to show if UnrealIRCd is running, the
version, channel and user count, ..
* The command `./unrealircd genlinkblock` is now
[documented](https://www.unrealircd.org/docs/Linking_servers_(genlinkblock))
and is referred to from the
[Linking servers tutorial](https://www.unrealircd.org/docs/Tutorial:_Linking_servers).
* On Windows in the `C:\Program Files\UnrealIRCd 6\bin` directory there is
now an `unrealircdctl.exe` that can be used to do similar things to what
you can do on *NIX. Supported operations are: `rehash`, `reloadtls`,
`mkpasswd`, `gencloak` and `spkifp`.
* New option [set::server-notice-show-event](https://www.unrealircd.org/docs/Set_block#set::server-notice-show-event)
which can be set to `no` to hide the event information (eg `connect.LOCAL_CLIENT_CONNECT`)
in server notices. This can be overridden per-oper in the
[Oper block](https://www.unrealircd.org/docs/Oper_block) via oper::server-notice-show-event.
* Support for IRC over UNIX sockets (on the same machine), if you specify a
file in the [listen block](https://www.unrealircd.org/docs/Listen_block)
instead of an ip/port. This probably won't be used much, but the option is
there. Users will show up with a host of `localhost` and IP `127.0.0.1` to
keep things simple.
* The `MAP` command now shows percentages of users
* Add `WHO` option to search clients by time connected (eg. `WHO <300 t` to
search for less than 300 seconds)
* Rate limiting of `MODE nick -x` and `-t` via new `vhost-flood` option in
[set::anti-flood block](https://www.unrealircd.org/docs/Anti-flood_settings).
Changes:
* Update Russian `help.ru.conf`.
Developers and protocol:
* People packaging UnrealIRCd (eg. to an .rpm/.deb):
* Be sure to pass the new `--with-controlfile` configure option
* There is now an `unrealircdctl` tool that the `unrealircd` shell script
uses, it is expected to be in `bindir`.
* `SVSMODE #chan -b nick` will now correctly remove extbans that prevent `nick`
from joining. This fixes a bug where it would remove too much (for `~time`)
or not remove extbans (most other extbans, eg `~account`).
`SVSMODE #chan -b` has also been fixed accordingly (remove all bans
preventing joins).
Note that all these commands do not remove bans that do not affect joins,
such as `~quiet` or `~text`.
* For module coders: setting the `EXTBOPT_CHSVSMODE` flag in `extban.options`
is no longer useful, the flag is ignored. We now decide based on
`BANCHK_JOIN` being in `extban.is_banned_events` if the ban should be
removed or not upon SVS(2)MODE -b.
UnrealIRCd 6.0.1.1
===================
If you are already running UnrealIRCd 6 then read below on the
changes between 6.0.0 and 6.0.1(.1). Otherwise, jump straight to the
[summary about UnrealIRCd 6](#Summary) to learn more about UnrealIRCd 6.
-------------------
Fixes:
* In 6.0.1.1: extended bans were not properly synced between U5 and U6.
@ -89,6 +220,8 @@ Enhancements
* Colors are enabled by default in snomask server notices, these can be disabled via
[set::server-notice-colors](https://www.unrealircd.org/docs/Set_block#set::server-notice-colors)
and also in [oper::server-notice-colors](https://www.unrealircd.org/docs/Oper_block)
* Support for [logging to a channel](https://www.unrealircd.org/docs/Log_block#Logging_to_a_channel).
Similar to snomasks but then for channels. *Requires UnrealIRCd 6.0.2 or later*
* Almost all channel modes are modularized
* Only the three list modes (+b/+e/+I) are still in the core
* The five [level modes](https://www.unrealircd.org/docs/Channel_Modes#Access_levels)

View File

@ -1 +0,0 @@
https://modules.unrealircd.org/modules.list

View File

@ -1,228 +1,50 @@
/* Server bans snomask - 'b' */
log {
source {
!debug;
blacklist;
chgcmds;
connect.LOCAL_CLIENT_CONNECT;
connect.LOCAL_CLIENT_DISCONNECT;
connect.REMOTE_CLIENT_CONNECT;
connect.REMOTE_CLIENT_DISCONNECT;
dcc;
flood;
kill;
link;
nick.QLINE_NICK_LOCAL_ATTEMPT;
nick.QLINE_NICK_REMOTE;
nomatch;
oper;
operoverride;
sacmds;
tkl.BAN_REALNAME;
tkl.RMTKL_COMMAND;
tkl.SPAMFILTER_MATCH;
tkl.TKL_ADD;
tkl.TKL_DEL;
tkl.TKL_ADD_TEMPSHUN;
tkl.TKL_DEL_TEMPSHUN;
tkl.TKL_EXPIRE;
tkl.RMTKL_COMMAND;
}
destination {
snomask b;
}
}
/* Blacklist snomask: 'B' */
log {
source {
blacklist;
}
destination {
snomask B;
}
}
/* Local client connects snomask - 'c' */
log {
source {
connect.LOCAL_CLIENT_CONNECT;
connect.LOCAL_CLIENT_DISCONNECT;
}
destination {
snomask c;
}
}
/* Remote client connects snomask - 'C' */
log {
source {
connect.REMOTE_CLIENT_CONNECT;
connect.REMOTE_CLIENT_DISCONNECT;
}
destination {
snomask C;
}
}
/* DCC rejections snomask - 'd' */
log {
source {
dcc;
}
destination {
snomask d;
}
}
/* Debug snomask (not recommended) - 'D' */
log {
source {
debug;
}
destination {
snomask D;
}
}
/* Floods snomask - 'f' */
log {
source {
flood;
}
destination {
snomask f;
}
}
/* Join, parts, kicks - 'j' */
log {
source {
// TODO: these don't exist yet..
join.LOCAL_CLIENT_JOIN;
join.REMOTE_CLIENT_JOIN;
part.LOCAL_CLIENT_PART;
part.REMOTE_CLIENT_PART;
kick.LOCAL_CLIENT_KICK;
kick.REMOTE_CLIENT_KICK;
}
destination {
snomask j;
}
}
/* Kill snomask */
log {
source {
kill;
}
destination {
snomask k;
}
}
/* Local nick changes snomask - 'n' */
log {
source {
nick.LOCAL_NICK_CHANGE;
}
destination {
snomask n;
}
}
/* Remote nick changes snomask - 'N' */
log {
source {
nick.REMOTE_NICK_CHANGE;
}
destination {
snomask N;
}
}
/* Deny nick (QLINE) rejections snomask - 'q' */
log {
source {
nick.QLINE_NICK_LOCAL_ATTEMPT;
nick.QLINE_NICK_REMOTE;
}
destination {
snomask q;
}
}
/* Spamfilter hits snomask - 'S' */
log {
source {
tkl.SPAMFILTER_MATCH;
}
destination {
snomask S;
}
}
/* IRCOp overriding in channels (OperOverride) - 'o' */
log {
source {
operoverride;
}
destination {
snomask o;
}
}
/* IRCOp changing user properties or forcing users to do things - 'O' */
log {
source {
chgcmds;
sacmds;
}
destination {
snomask O;
}
}
/* VHOST usage - 'v' */
log {
source {
vhost;
}
destination {
snomask v;
}
destination { snomask o; }
}
/* Snomask s (server notices) - the "catch all" snomask for all other things */
log {
source {
link;
oper;
!debug;
nomatch;
}
destination {
snomask s;
}
}
/* These log sources are sent to all servers (globally).
* These are generally two categories:
* 1) Things that affect the network as a whole, eg linking
* 2) Things that otherwise cannot be logged by a remote server
* that may interest ircops. Eg: a spamfilter match,
* since that would otherwise not be propagated.
*/
log {
source {
/* All link messages affect the network so
* these should be global. Except for the
* link connecting... and timeout while
* connecting.. messages, which can be noisy.
*/
flood;
link;
!link.LINK_CONNECTING;
!link.LINK_CONNECT_TIMEOUT;
!link.SERVER_LINKED_REMOTE;
!link.SERVER_LINKED;
/* All oper up/downs */
oper;
/* Flood messages, important to keep an eye on, network-wide */
flood;
/* TEMPSHUN: these are otherwise missing for snomask 'b' */
samode.SAMODE_COMMAND;
tkl.TKL_ADD_TEMPSHUN;
tkl.TKL_DEL_TEMPSHUN;
/* Spamfilter matches: needed for snomask 'S' */
tkl.SPAMFILTER_MATCH;
/* Critical issue: */
tls.TLS_CERT_EXPIRING;
/* SAMODE: needed for snomask 'o' */
samode.SAMODE_COMMAND;
/* Never any debug messages */
!debug;
}
destination {
remote;
}
}
destination { remote; }
}

View File

@ -3,5 +3,6 @@ include "https://USERNAME:PASSWORD@HOSTNAME:PORT/except.conf";
include "https://USERNAME:PASSWORD@HOSTNAME:PORT/ircd.conf";
include "https://USERNAME:PASSWORD@HOSTNAME:PORT/modules.conf";
include "https://USERNAME:PASSWORD@HOSTNAME:PORT/opers.conf";
include "https://USERNAME:PASSWORD@HOSTNAME:PORT/snomasks.conf";
include "https://USERNAME:PASSWORD@HOSTNAME:PORT/spamfilter.conf";
me { name "example.supernets.org"; info "SuperNETS IRC Network"; sid XXX; }

View File

@ -17,11 +17,6 @@ class servers { pingfreq 120; maxclients 10; sendq 1M; connfreq 30; }
allow { mask *; class clients; maxperip 2; global-maxperip 2; }
allow { mask 127.0.0.1; class clients; maxperip 10; global-maxperip 10; }
#require authentication {
# mask *@*;
# reason "8,4 E N T E R T H E V O I D ";
#}
listen { ip *; port 6667; options { clientsonly; } }
listen { ip *; port 6697; options { clientsonly; tls; } }
listen { ip *; port REDACTED; options { serversonly; tls; } }
@ -45,13 +40,13 @@ link irc.supernets.org {
log {
source { error; fatal; warn; }
destination { file "ircd.log" { maxsize 10M; } }
destination { file "ircd.log" { maxsize 5M; } }
}
log {
source { all; }
destination { channel "#REDACTED" }
}
#log {
# source { all; }
# destination { channel "#REDACTED" }
#}
tld { mask *@*; motd remote.motd; rules remote.motd; options { remote; } }
@ -95,7 +90,7 @@ set {
gline-address "enterthevoid@supernets.org";
modes-on-connect "+iIpTx";
modes-on-oper "+Hq";
snomask-on-oper "+bBcCfksSoO";
snomask-on-oper "+o";
modes-on-join "+ns";
level-on-join "op";
restrict-usermodes "ips";
@ -127,7 +122,7 @@ set {
"REDACTED";
"REDACTED";
}
hiddenhost-prefix "SUPER";
cloak-prefix "SUPER";
plaintext-policy {
user warn;
oper deny;
@ -139,8 +134,8 @@ set {
user warn;
oper deny;
server deny;
user-message "4WARNING: You are using an outdated SSL/TLS protocol or cipher";
oper-message "Network operators must be using an up-to-date SSL/TLS protocol & cipher";
user-message "4WARNING: You are using an outdated TLS protocol or cipher";
oper-message "Network operators must be using an up-to-date TLS protocol & cipher";
}
anti-flood {
everyone {
@ -209,9 +204,10 @@ set {
ban-reason "8,4 E N T E R T H E V O I D ";
}
connthrottle {
known-users { minimum-reputation-score 25; sasl-bypass yes; }
new-users { local-throttle 20:60; global-throttle 30:60; }
disabled-when { reputation-gathering 1w; start-delay 3m; }
known-users { minimum-reputation-score 100; sasl-bypass yes; }
new-users { local-throttle 20:60; global-throttle 30:60; }
disabled-when { reputation-gathering 1w; start-delay 3m; }
reason "8,4 E N T E R T H E V O I D ";
}
history {
channel {
@ -224,24 +220,24 @@ set {
}
hide-idle-time { policy always; }
whois-details {
basic { everyone full; }
modes { everyone none; self full; oper full; }
realhost { everyone none; self full; oper full; }
registered-nick { everyone full; }
channels { everyone limited; self full; oper full; }
server { everyone full; }
away { everyone full; }
oper { everyone limited; self full; oper full; }
secure { everyone limited; self full; oper full; }
bot { everyone full; }
services { everyone full; }
reputation { everyone none; self none; oper full; }
geo { everyone none; self none; oper full; }
certfp { everyone full; }
shunned { everyone none; self none; oper full; }
account { everyone full; }
away { everyone full; }
basic { everyone full; }
bot { everyone full; }
certfp { everyone full; }
channels { everyone none; self full; oper full; }
geo { everyone none; }
idle { everyone none; }
modes { everyone none; self full; oper full; }
oper { everyone limited; self full; oper full; }
realhost { everyone none; self full; oper full; }
registered-nick { everyone full; }
reputation { everyone full; }
secure { everyone limited; self full; oper full; }
server { everyone full; }
services { everyone full; }
shunned { everyone none; self none; oper full; }
swhois { everyone full; }
idle { everyone limited; self full; oper full; }
}
}
@ -254,5 +250,5 @@ hideserver {
security-group known-users {
identified yes;
reputation-score 25;
reputation-score 100;
}

View File

@ -8,7 +8,7 @@
# in case it misbehaves
#
set +ex
timeout --kill-after=5 600 extras/build-tests/nix/run-tests
timeout --kill-after=5 900 extras/build-tests/nix/run-tests
EX="$?"
killall -9 valgrind valgrind.bin memcheck memcheck-amd64-linux memcheck-x86-linux ircd unrealircd val 1>/dev/null 2>&1
exit $EX

View File

@ -36,11 +36,11 @@ rem Now the actual build
rem - First this, otherwise JOM will fail
IF NOT EXIST src\version.c nmake -f Makefile.windows CONF
rem - Then build most of UnrealIRCd.exe etc
call extras\build-tests\windows\compilecmd\%SHORTNAME%.bat UNREALSVC.EXE UnrealIRCd.exe
call extras\build-tests\windows\compilecmd\%SHORTNAME%.bat UNREALSVC.EXE UnrealIRCd.exe unrealircdctl.exe
rem - It will fail due to missing symbolfile, which we create here..
nmake -f makefile.windows SYMBOLFILE
rem - Then we finalize building UnrealIRCd.exe: should be no error
call extras\build-tests\windows\compilecmd\%SHORTNAME%.bat UNREALSVC.EXE UnrealIRCd.exe
call extras\build-tests\windows\compilecmd\%SHORTNAME%.bat UNREALSVC.EXE UnrealIRCd.exe unrealircdctl.exe
if %ERRORLEVEL% NEQ 0 EXIT /B 1
rem - Build all the modules (DLL files): should be no error
call extras\build-tests\windows\compilecmd\%SHORTNAME%.bat MODULES

Binary file not shown.

View File

@ -2,10 +2,8 @@
URL="https://www.unrealircd.org/files/curl-latest.tar.gz"
OUTF="curl-latest.tar.gz"
OUTD="curl-latest"
ARESPATH="`pwd`/extras/c-ares"
UNREALDIR="`pwd`"
CARESVERSION="1.17.2"
LIBDIR="$1"
PRIVATELIBDIR="$1"
if [ "x$1" = "x" ]; then
echo "You should (no longer) run this program directly."
@ -73,26 +71,9 @@ else
n="-n"
fi
if [ ! -d "$ARESPATH/lib" ]; then
echo "c-ares has not been build yet, let's do that now..."
cd ../extras/
tar xzf c-ares.tar.gz || exit 1
cd c-ares-$CARESVERSION || exit 1
./configure --prefix=$ARESPATH || exit 1
(make && make install) || exit 1
cd ../../tmp/
echo "c-ares built."
echo ""
fi
# We assume curl has been packaged in a way it will extract to "$OUTD"/
cd "$OUTD" || exit 1
echo "Building and installing libcurl"
CPPFLAGS="-I$ARESPATH/include" ./configure --prefix=$UNREALDIR/extras/curl --libdir=$LIBDIR --enable-shared \
--enable-ares=$ARESPATH --with-openssl
cp -R $ARESPATH/lib ares
./configure --prefix=$UNREALDIR/extras/curl --libdir=$PRIVATELIBDIR --enable-shared --with-openssl
make && make install
#cp $ARESPATH/lib/libcares.a $HOME/curl/lib
# that isn't needed anymore as the lib is already in unreal...

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "UnrealIRCd"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 6.0.1.1
PROJECT_NUMBER = 6.0.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

Binary file not shown.

View File

@ -170,6 +170,7 @@ struct Configuration {
char *stats_server;
char *sasl_server;
int server_notice_colors;
int server_notice_show_event;
};
extern MODVAR Configuration iConf;

View File

@ -28,6 +28,34 @@
#include "setup.h"
#include "fdlist.h"
extern int dorehash, dorestart, doreloadcert;
#ifndef _WIN32
extern char **myargv;
#else
extern LPCSTR cmdLine;
#endif
/* Externals */
extern MODVAR char *buildid;
extern MODVAR char backupbuf[8192];
extern EVENT(unrealdns_removeoldrecords);
extern EVENT(unrealdb_expire_secret_cache);
extern void init_glines(void);
extern void tkl_init(void);
extern void process_clients(void);
extern void unrealdb_test(void);
extern void ignore_this_signal();
extern void s_rehash();
extern void s_reloadcert();
extern void s_restart();
extern void s_die();
#ifndef _WIN32
// nix specific
extern char unreallogo[];
#else
// windows specific
extern SERVICE_STATUS_HANDLE IRCDStatusHandle;
extern SERVICE_STATUS IRCDStatus;
#endif
extern MODVAR char *extraflags;
extern MODVAR int tainted;
extern MODVAR Member *freemember;
@ -117,7 +145,7 @@ extern void ipport_seperate(const char *string, char **ip, char **port);
extern ConfigItem_class *find_class(const char *name);
extern ConfigItem_oper *find_oper(const char *name);
extern ConfigItem_operclass *find_operclass(const char *name);
extern ConfigItem_listen *find_listen(const char *ipmask, int port, int ipv6);
extern ConfigItem_listen *find_listen(const char *ipmask, int port, SocketType socket_type);
extern ConfigItem_sni *find_sni(const char *name);
extern ConfigItem_ulines *find_uline(const char *host);
extern ConfigItem_tld *find_tld(Client *cptr);
@ -153,6 +181,7 @@ extern MODVAR struct list_head lclient_list;
extern MODVAR struct list_head server_list;
extern MODVAR struct list_head oper_list;
extern MODVAR struct list_head unknown_list;
extern MODVAR struct list_head control_list;
extern MODVAR struct list_head global_server_list;
extern MODVAR struct list_head dead_list;
extern RealCommand *find_command(const char *cmd, int flags);
@ -489,6 +518,7 @@ extern int channel_canjoin(Client *client, const char *name);
extern char *collapse(char *pattern);
extern void dcc_sync(Client *client);
extern void request_rehash(Client *client);
extern int rehash_internal(Client *client);
extern void s_die();
extern int match_simple(const char *mask, const char *name);
extern int match_esc(const char *mask, const char *name);
@ -507,7 +537,7 @@ extern void rehash_motdrules();
extern void read_motd(const char *filename, MOTDFile *motd); /* s_serv.c */
extern void send_proto(Client *, ConfigItem_link *);
extern void unload_all_modules(void);
extern void set_sock_opts(int fd, Client *cptr, int ipv6);
extern void set_sock_opts(int fd, Client *cptr, SocketType socket_type);
extern void stripcrlf(char *line);
extern int strnatcmp(char const *a, char const *b);
extern int strnatcasecmp(char const *a, char const *b);
@ -663,7 +693,6 @@ extern int spamfilter_getconftargets(const char *s);
extern void remove_all_snomasks(Client *client);
extern void remove_oper_modes(Client *client);
extern char *spamfilter_inttostring_long(int v);
extern MODVAR char backupbuf[];
extern int is_invited(Client *client, Channel *channel);
extern void channel_modes(Client *client, char *mbuf, char *pbuf, size_t mbuf_size, size_t pbuf_size, Channel *channel, int hide_local_modes);
extern int op_can_override(const char *acl, Client *client,Channel *channel,void* extra);
@ -859,6 +888,7 @@ extern const char *cmdname_by_spamftarget(int target);
extern void unrealdns_delreq_bycptr(Client *cptr);
extern void unrealdns_gethostbyname_link(const char *name, ConfigItem_link *conf, int ipv4_only);
extern void unrealdns_delasyncconnects(void);
extern EVENT(unrealdns_timeout);
extern int is_autojoin_chan(const char *chname);
extern void unreal_free_hostent(struct hostent *he);
extern struct hostent *unreal_create_hostent(const char *name, const char *ip);
@ -915,10 +945,14 @@ extern void report_crash(void);
extern void modulemanager(int argc, char *argv[]);
extern int inet_pton4(const char *src, unsigned char *dst);
extern int inet_pton6(const char *src, unsigned char *dst);
extern int unreal_bind(int fd, const char *ip, int port, int ipv6);
extern int unreal_bind(int fd, const char *ip, int port, SocketType socket_type);
extern int unreal_connect(int fd, const char *ip, int port, int ipv6);
extern int is_valid_ip(const char *str);
extern int ipv6_capable(void);
extern int unix_sockets_capable(void);
#ifdef _WIN32
extern void init_winsock(void);
#endif
extern MODVAR Client *remote_rehash_client;
extern MODVAR int debugfd;
extern void convert_to_absolute_path(char **path, const char *reldir);
@ -929,7 +963,7 @@ extern Cmode_t get_extmode_bitbychar(char m);
extern long find_user_mode(char mode);
extern void start_listeners(void);
extern void buildvarstring(const char *inbuf, char *outbuf, size_t len, const char *name[], const char *value[]);
extern void reinit_tls(void);
extern int reinit_tls(void);
extern CMD_FUNC(cmd_error);
extern CMD_FUNC(cmd_dns);
extern CMD_FUNC(cmd_info);
@ -1135,6 +1169,8 @@ extern void flood_limit_exceeded_log(Client *client, const char *floodname);
/* logging */
extern int config_test_log(ConfigFile *conf, ConfigEntry *ce);
extern int config_run_log(ConfigFile *conf, ConfigEntry *ce);
extern const char *log_level_terminal_color(LogLevel loglevel);
#define TERMINAL_COLOR_RESET "\033[0m"
extern LogType log_type_stringtoval(const char *str);
extern const char *log_type_valtostring(LogType v);
#ifdef DEBUGMODE
@ -1208,3 +1244,8 @@ extern void make_umodestr(void);
extern void initwhowas(void);
extern void uid_init(void);
extern const char *uid_get(void);
/* proc i/o */
extern void add_proc_io_server(void);
extern void procio_post_rehash(int failure);
/* end of proc i/o */
extern int minimum_msec_since_last_run(struct timeval *tv_old, long minimum);

View File

@ -394,7 +394,7 @@ typedef enum ExtbanType {
#define EXTBANTABLESZ 32
typedef enum ExtbanOptions {
EXTBOPT_CHSVSMODE=0x1, /**< SVSMODE -b/-e/-I will clear this ban */
EXTBOPT_CHSVSMODE=0x1, /**< SVSMODE -b/-e/-I will clear this ban (UNUSED as of 6.0.1+) */
EXTBOPT_ACTMODIFIER=0x2, /**< Action modifier (not a matcher). These are extended bans like ~q/~n/~j. */
EXTBOPT_NOSTACKCHILD=0x4, /**< Disallow prefixing with another extban. Eg disallow ~n:~T:censor:xyz */
EXTBOPT_INVEX=0x8, /**< Available for use with +I too */
@ -1151,12 +1151,14 @@ extern void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, l
#define HOOKTYPE_POST_LOCAL_NICKCHANGE 106
/** See hooktype_post_remote_nickchange() */
#define HOOKTYPE_POST_REMOTE_NICKCHANGE 107
/** See hooktype_userhost_changed() */
#define HOOKTYPE_USERHOST_CHANGED 108
/** See hooktype_realname_changed() */
#define HOOKTYPE_REALNAME_CHANGED 109
/** See hooktype_userhost_change() */
#define HOOKTYPE_USERHOST_CHANGE 108
/** See hooktype_realname_change() */
#define HOOKTYPE_REALNAME_CHANGE 109
/** See hooktype_can_set_topic() */
#define HOOKTYPE_CAN_SET_TOPIC 110
/** See hooktype_ip_change() */
#define HOOKTYPE_IP_CHANGE 111
/* Adding a new hook here?
* 1) Add the #define HOOKTYPE_.... with a new number
* 2) Add a hook prototype (see below)
@ -2127,14 +2129,22 @@ int hooktype_post_remote_nickchange(Client *client, MessageTag *mtags, const cha
* @param oldhost Old hostname of the client
* @return The return value is ignored (use return 0)
*/
int hooktype_realname_changed(Client *client, const char *oldinfo);
int hooktype_userhost_change(Client *client, const char *olduser, const char *oldhost);
/** Called when user realname has changed.
* @param client The client whose realname has changed
* @param oldinfo Old realname of the client
* @return The return value is ignored (use return 0)
*/
int hooktype_userhost_changed(Client *client, const char *olduser, const char *oldhost);
int hooktype_realname_change(Client *client, const char *oldinfo);
/** Called when changing IP (eg due to PROXY/WEBIRC/etc).
* @param client The client whose IP has changed
* @param oldip Old IP of the client
* @return The return value is ignored (use return 0)
*/
int hooktype_ip_change(Client *client, const char *oldip);
/** @} */
#ifdef GCC_TYPECHECKING
@ -2247,8 +2257,9 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
((hooktype == HOOKTYPE_IS_INVITED) && !ValidateHook(hooktype_is_invited, func)) || \
((hooktype == HOOKTYPE_POST_LOCAL_NICKCHANGE) && !ValidateHook(hooktype_post_local_nickchange, func)) || \
((hooktype == HOOKTYPE_POST_REMOTE_NICKCHANGE) && !ValidateHook(hooktype_post_remote_nickchange, func)) || \
((hooktype == HOOKTYPE_USERHOST_CHANGED) && !ValidateHook(hooktype_userhost_changed, func)) || \
((hooktype == HOOKTYPE_REALNAME_CHANGED) && !ValidateHook(hooktype_realname_changed, func)) )\
((hooktype == HOOKTYPE_USERHOST_CHANGE) && !ValidateHook(hooktype_userhost_change, func)) || \
((hooktype == HOOKTYPE_REALNAME_CHANGE) && !ValidateHook(hooktype_realname_change, func)) || \
((hooktype == HOOKTYPE_IP_CHANGE) && !ValidateHook(hooktype_ip_change, func)) ) \
_hook_error_incompatible();
#endif /* GCC_TYPECHECKING */

View File

@ -37,6 +37,8 @@
#define RPL_REDIR 10
#define RPL_MAPUSERS 18
#define RPL_REMOTEISUPPORT 105
/*
@ -349,10 +351,11 @@
#define STR_RPL_CREATED /* 003 */ ":This server was created %s"
#define STR_RPL_MYINFO /* 004 */ "%s %s %s %s"
#define STR_RPL_ISUPPORT /* 005 */ "%s :are supported by this server"
#define STR_RPL_MAP /* 006 */ ":%s%-*s(%ld) %s"
#define STR_RPL_MAP /* 006 */ ":%s%s %s | Users: %*ld (%*.2f%%)%s"
#define STR_RPL_MAPEND /* 007 */ ":End of /MAP"
#define STR_RPL_SNOMASK /* 008 */ "+%s :Server notice mask"
#define STR_RPL_REDIR /* 010 */ "%s %d :Please use this Server/Port instead"
#define STR_RPL_MAPUSERS /* 018 */ ":%d server%s and %d user%s, average %.2f users per server"
#define STR_RPL_REMOTEISUPPORT /* 105 */ "%s :are supported by this server"
#define STR_RPL_TRACELINK /* 200 */ "Link %s%s %s %s"
#define STR_RPL_TRACECONNECTING /* 201 */ "Attempt %s %s"

View File

@ -12,6 +12,9 @@
/* Define the location of the configuration files */
#undef CONFDIR
/* Define the path of the control socket */
#undef CONTROLFILE
/* Define the location of permanent data files */
#undef DATADIR

View File

@ -263,12 +263,18 @@ typedef struct Log Log;
struct Log {
Log *prev, *next;
LogSource *sources;
int type;
char destination[CHANNELLEN+1];
int show_event;
/* for destination::file */
char *file;
char *filefmt;
long maxsize;
int type;
int logfd;
/* for destination::channel */
int color;
int json_message_tag;
int oper_only;
};
/** This is used for deciding the <index> in logs[<index>] and temp_logs[<index>] */
@ -317,6 +323,7 @@ typedef enum LogDestination { LOG_DEST_SNOMASK=0, LOG_DEST_OPER=1, LOG_DEST_REMO
* @{
*/
typedef enum ClientStatus {
CLIENT_STATUS_CONTROL = -8, /**< Client is on the control channel */
CLIENT_STATUS_LOG = -7, /**< Client is a log file */
CLIENT_STATUS_TLS_STARTTLS_HANDSHAKE = -8, /**< Client is doing a STARTTLS handshake */
CLIENT_STATUS_CONNECTING = -6, /**< Client is an outgoing connect */
@ -339,6 +346,7 @@ typedef enum ClientStatus {
/** Client is not fully registered yet. May become a user or a server, we don't know yet. */
#define IsUnknown(x) (((x)->status == CLIENT_STATUS_UNKNOWN) || ((x)->status == CLIENT_STATUS_TLS_STARTTLS_HANDSHAKE))
#define IsServer(x) ((x)->status == CLIENT_STATUS_SERVER) /**< Is a server that has completed the connection handshake */
#define IsControl(x) ((x)->status == CLIENT_STATUS_CONTROL) /**< Is on the control channel (not on IRC) */
#define IsLog(x) ((x)->status == CLIENT_STATUS_LOG) /**< Is a log file, not a user or server */
#define IsStartTLSHandshake(x) ((x)->status == CLIENT_STATUS_TLS_STARTTLS_HANDSHAKE) /**< Currently doing a STARTTLS handshake */
#define IsTLSAcceptHandshake(x) ((x)->status == CLIENT_STATUS_TLS_ACCEPT_HANDSHAKE) /**< Currently doing a TLS handshake - incoming */
@ -355,6 +363,8 @@ typedef enum ClientStatus {
#define SetServer(x) ((x)->status = CLIENT_STATUS_SERVER)
#define SetUser(x) ((x)->status = CLIENT_STATUS_USER)
#define SetLog(x) ((x)->status = CLIENT_STATUS_LOG)
#define SetControl(x) ((x)->status = CLIENT_STATUS_CONTROL)
#define SetUser(x) ((x)->status = CLIENT_STATUS_USER)
/** @} */
@ -366,7 +376,7 @@ typedef enum ClientStatus {
#define CLIENT_FLAG_DEAD 0x00000002 /**< Client is dead: already quit/exited and removed from all lists -- Remaining part will soon be freed in main loop */
#define CLIENT_FLAG_DEADSOCKET 0x00000004 /**< Local socket is dead but otherwise the client still exists fully -- Will soon exit in main loop */
#define CLIENT_FLAG_KILLED 0x00000008 /**< Prevents "QUIT" from being sent for this */
#define CLIENT_FLAG_IPV6 0x00000010 /**< Connection is using IPv6 */
#define CLIENT_FLAG_MONITOR_REHASH 0x00000010 /**< Client is monitoring rehash output */
#define CLIENT_FLAG_OUTGOING 0x00000020 /**< Outgoing connection (do not touch cptr->listener->clients) */
#define CLIENT_FLAG_CLOSING 0x00000040 /**< Set when closing to suppress errors */
#define CLIENT_FLAG_LISTEN 0x00000080 /**< Used to mark clients which we listen() on */
@ -464,8 +474,8 @@ typedef enum ClientStatus {
#define IsDNSLookup(x) ((x)->flags & CLIENT_FLAG_DNSLOOKUP)
#define IsEAuth(x) ((x)->flags & CLIENT_FLAG_EAUTH)
#define IsIdentSuccess(x) ((x)->flags & CLIENT_FLAG_IDENTSUCCESS)
#define IsIPV6(x) ((x)->flags & CLIENT_FLAG_IPV6)
#define IsKilled(x) ((x)->flags & CLIENT_FLAG_KILLED)
#define IsMonitorRehash(x) ((x)->flags & CLIENT_FLAG_MONITOR_REHASH)
#define IsListening(x) ((x)->flags & CLIENT_FLAG_LISTEN)
#define IsLocalhost(x) ((x)->flags & CLIENT_FLAG_LOCALHOST)
#define IsMap(x) ((x)->flags & CLIENT_FLAG_MAP)
@ -496,8 +506,8 @@ typedef enum ClientStatus {
#define SetDNSLookup(x) do { (x)->flags |= CLIENT_FLAG_DNSLOOKUP; } while(0)
#define SetEAuth(x) do { (x)->flags |= CLIENT_FLAG_EAUTH; } while(0)
#define SetIdentSuccess(x) do { (x)->flags |= CLIENT_FLAG_IDENTSUCCESS; } while(0)
#define SetIPV6(x) do { (x)->flags |= CLIENT_FLAG_IPV6; } while(0)
#define SetKilled(x) do { (x)->flags |= CLIENT_FLAG_KILLED; } while(0)
#define SetMonitorRehash(x) do { (x)->flags |= CLIENT_FLAG_MONITOR_REHASH; } while(0)
#define SetListening(x) do { (x)->flags |= CLIENT_FLAG_LISTEN; } while(0)
#define SetLocalhost(x) do { (x)->flags |= CLIENT_FLAG_LOCALHOST; } while(0)
#define SetMap(x) do { (x)->flags |= CLIENT_FLAG_MAP; } while(0)
@ -526,8 +536,8 @@ typedef enum ClientStatus {
#define ClearDNSLookup(x) do { (x)->flags &= ~CLIENT_FLAG_DNSLOOKUP; } while(0)
#define ClearEAuth(x) do { (x)->flags &= ~CLIENT_FLAG_EAUTH; } while(0)
#define ClearIdentSuccess(x) do { (x)->flags &= ~CLIENT_FLAG_IDENTSUCCESS; } while(0)
#define ClearIPV6(x) do { (x)->flags &= ~CLIENT_FLAG_IPV6; } while(0)
#define ClearKilled(x) do { (x)->flags &= ~CLIENT_FLAG_KILLED; } while(0)
#define ClearMonitorRehash(x) do { (x)->flags &= ~CLIENT_FLAG_MONITOR_REHASH; } while(0)
#define ClearListening(x) do { (x)->flags &= ~CLIENT_FLAG_LISTEN; } while(0)
#define ClearLocalhost(x) do { (x)->flags &= ~CLIENT_FLAG_LOCALHOST; } while(0)
#define ClearMap(x) do { (x)->flags &= ~CLIENT_FLAG_MAP; } while(0)
@ -546,6 +556,9 @@ typedef enum ClientStatus {
#define ClearULine(x) do { (x)->flags &= ~CLIENT_FLAG_ULINE; } while(0)
#define ClearVirus(x) do { (x)->flags &= ~CLIENT_FLAG_VIRUS; } while(0)
#define ClearIdentLookupSent(x) do { (x)->flags &= ~CLIENT_FLAG_IDENTLOOKUPSENT; } while(0)
#define IsIPV6(x) ((x)->local->socket_type == SOCKET_TYPE_IPV6)
#define IsUnixSocket(x) ((x)->local->socket_type == SOCKET_TYPE_UNIX)
#define SetIPV6(x) do { (x)->local->socket_type = SOCKET_TYPE_IPV6; } while(0)
/** @} */
@ -779,11 +792,11 @@ struct LoopStruct {
unsigned do_bancheck : 1; /* perform *line bancheck? */
unsigned do_bancheck_spamf_user : 1; /* perform 'user' spamfilter bancheck */
unsigned do_bancheck_spamf_away : 1; /* perform 'away' spamfilter bancheck */
unsigned rehashing : 1;
unsigned terminating : 1;
unsigned config_load_failed : 1;
unsigned rehash_download_busy : 1; /* don't return "all downloads complete", needed for race condition */
unsigned tainted : 1;
int rehashing;
Client *rehash_save_client;
void (*boot_function)();
};
@ -851,6 +864,8 @@ struct SWhois {
#define CMD_VIRUS 0x0080
/** Command requires IRCOp privileges */
#define CMD_OPER 0x0200
/** Command is for control channel only (unrealircd.ctl socket) */
#define CMD_CONTROL 0x0400
/** Command function - used by all command handlers.
* This is used in the code like <pre>CMD_FUNC(cmd_yourcmd)</pre> as a function definition.
@ -1212,6 +1227,7 @@ extern void unload_all_unused_moddata(void);
#define LISTENER_TLS 0x000010
#define LISTENER_BOUND 0x000020
#define LISTENER_DEFER_ACCEPT 0x000040
#define LISTENER_CONTROL 0x000080 /**< Control channel */
#define IsServersOnlyListener(x) ((x) && ((x)->options & LISTENER_SERVERSONLY))
@ -1240,6 +1256,7 @@ typedef enum FloodOption {
FLD_KNOCK = 4, /**< knock-flood */
FLD_CONVERSATIONS = 5, /**< max-concurrent-conversations */
FLD_LAG_PENALTY = 6, /**< lag-penalty / lag-penalty-bytes */
FLD_VHOST = 7, /**< vhost-flood */
} FloodOption;
#define MAXFLOODOPTIONS 10
@ -1251,6 +1268,11 @@ struct TrafficStats {
long long bytes_received; /* Received bytes */
};
/** Socket type (IPv4, IPv6, UNIX) */
typedef enum {
SOCKET_TYPE_IPV4=0, SOCKET_TYPE_IPV6=1, SOCKET_TYPE_UNIX=2
} SocketType;
/** This shows the Client struct (any client), the User struct (a user), Server (a server) that are commonly accessed both in the core and by 3rd party coders.
* @defgroup CommonStructs Common structs
* @{
@ -1288,6 +1310,7 @@ struct Client {
*/
struct LocalClient {
int fd; /**< File descriptor, can be <0 if socket has been closed already. */
SocketType socket_type; /**< Type of socket: IPv4, IPV6, UNIX */
SSL *ssl; /**< OpenSSL/LibreSSL struct for TLS connection */
time_t fake_lag; /**< Time when user will next be allowed to send something (actually fake_lag<currenttime+10) */
int fake_lag_msec; /**< Used for calculating 'fake_lag' penalty (modulo) */
@ -1606,6 +1629,7 @@ struct ConfigItem_oper {
char *vhost;
int maxlogins;
int server_notice_colors;
int server_notice_show_event;
};
/** The TLS options that are used in set::tls and otherblocks::tls-options.
@ -1666,11 +1690,12 @@ struct ConfigItem_tld {
struct ConfigItem_listen {
ConfigItem_listen *prev, *next;
ConfigFlag flag;
SocketType socket_type;
char *file;
char *ip;
int port;
int options, clients;
int fd;
int ipv6;
SSL_CTX *ssl_ctx;
TLSOptions *tls_options;
int websocket_options; /* should be in module, but lazy */

View File

@ -58,10 +58,12 @@
#ifndef _WIN32
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <afunix.h>
#endif
#ifndef _WIN32

View File

@ -54,7 +54,7 @@
* Can be useful if the above 3 versionids are insufficient for you (eg: you want to support CVS).
* This is updated automatically on the CVS server every Monday. so don't touch it.
*/
#define UNREAL_VERSION_TIME 202148
#define UNREAL_VERSION_TIME 202204
#define UNREAL_VERSION ((UNREAL_VERSION_GENERATION << 24) + (UNREAL_VERSION_MAJOR << 16) + (UNREAL_VERSION_MINOR << 8))
#define UnrealProtocol 6000

View File

@ -33,6 +33,7 @@
#define CACHEDIR "cache"
#define TMPDIR "tmp"
#define PIDFILE PERMDATADIR"/unrealircd.pid"
#define CONTROLFILE PERMDATADIR"/unrealircd.ctl"
#define NO_U_TYPES
#define NEED_U_INT32_T
#define strcasecmp _stricmp
@ -61,10 +62,10 @@
#define UNREAL_VERSION_MAJOR 0
/* Minor version number (e.g.: 1 for Unreal3.2.1) */
#define UNREAL_VERSION_MINOR 1
#define UNREAL_VERSION_MINOR 3
/* Version suffix such as a beta marker or release candidate marker. (e.g.:
-rcX for unrealircd-3.2.9-rcX) */
#define UNREAL_VERSION_SUFFIX ".1"
#define UNREAL_VERSION_SUFFIX ""
#endif

View File

@ -21,10 +21,10 @@
CC = "==== DO NOT RUN MAKE FROM THIS DIRECTORY ===="
OBJS=dns.o auth.o channel.o crule.o dbuf.o \
fdlist.o hash.o ircd.o ircsprintf.o list.o \
OBJS=ircd_vars.o dns.o auth.o channel.o crule.o dbuf.o \
fdlist.o hash.o ircsprintf.o list.o \
match.o modules.o parse.o mempool.o operclass.o \
conf_preprocessor.o conf.o debug.o dispatch.o \
conf_preprocessor.o conf.o proc_io_server.o debug.o dispatch.o \
misc.o serv.o aliases.o socket.o \
tls.o user.o scache.o send.o support.o \
version.o whowas.o random.o api-usermode.o api-channelmode.o \
@ -62,22 +62,22 @@ all: build
build:
# Force build of 'ircd', before we start building any modules:
$(MAKE) ircd
$(MAKE) ircd unrealircdctl
$(MAKE) mods
custommodule:
+cd modules/third; $(MAKE) MODULEFILE=$(MODULEFILE) 'EXLIBS=$(EXLIBS)' custommodule
ircd: $(OBJS)
$(CC) $(CFLAGS) $(BINCFLAGS) $(CRYPTOLIB) -o ircd $(OBJS) $(LDFLAGS) $(BINLDFLAGS) $(IRCDLIBS) $(CRYPTOLIB)
ircd: $(OBJS) ircd.o
$(CC) $(CFLAGS) $(BINCFLAGS) $(CRYPTOLIB) -o ircd ircd.o $(OBJS) $(LDFLAGS) $(BINLDFLAGS) $(IRCDLIBS) $(CRYPTOLIB)
unrealircdctl: $(OBJS) unrealircdctl.o proc_io_client.o
$(CC) $(CFLAGS) $(BINCFLAGS) $(CRYPTOLIB) -o unrealircdctl unrealircdctl.o proc_io_client.o $(OBJS) $(LDFLAGS) $(BINLDFLAGS) $(IRCDLIBS) $(CRYPTOLIB)
mods:
@if [ ! -r include ] ; then \
ln -s ../include include; \
fi
@if [ ! -r modules ] ; then \
echo "You havent done cvs update -P -d"; \
fi
+cd modules; $(MAKE) all
version.c: version.c.SH

View File

@ -89,7 +89,7 @@ static Command *CommandAddInternal(Module *module, const char *cmd, CmdFunc func
Command *command = NULL;
RealCommand *c;
if (find_command_simple(cmd))
if ((c = find_command(cmd, flags)) && (c->flags == flags))
{
if (module)
module->errorcode = MODERR_EXISTS;
@ -253,15 +253,26 @@ static RealCommand *add_Command_backend(const char *cmd)
RealCommand *find_command(const char *cmd, int flags)
{
RealCommand *p;
for (p = CommandHash[toupper(*cmd)]; p; p = p->next) {
if ((flags & CMD_UNREGISTERED) && !(p->flags & CMD_UNREGISTERED))
continue;
if ((flags & CMD_SHUN) && !(p->flags & CMD_SHUN))
continue;
if ((flags & CMD_VIRUS) && !(p->flags & CMD_VIRUS))
continue;
if ((flags & CMD_ALIAS) && !(p->flags & CMD_ALIAS))
continue;
for (p = CommandHash[toupper(*cmd)]; p; p = p->next)
{
if (flags & CMD_CONTROL)
{
if (!(p->flags & CMD_CONTROL))
continue;
} else
{
if ((flags & CMD_UNREGISTERED) && !(p->flags & CMD_UNREGISTERED))
continue;
if ((flags & CMD_SHUN) && !(p->flags & CMD_SHUN))
continue;
if ((flags & CMD_VIRUS) && !(p->flags & CMD_VIRUS))
continue;
if ((flags & CMD_ALIAS) && !(p->flags & CMD_ALIAS))
continue;
if (p->flags & CMD_CONTROL)
continue; /* important to also filter it this way ;) */
}
if (!strcasecmp(p->cmd, cmd))
return p;
}

View File

@ -27,9 +27,6 @@ ID_Copyright("(C) Carsten Munk 2001");
MODVAR Event *events = NULL;
extern EVENT(unrealdns_removeoldrecords);
extern EVENT(unrealdb_expire_secret_cache);
/** Add an event, a function that will run at regular intervals.
* @param module Module that this event belongs to
* @param name Name of the event
@ -211,18 +208,3 @@ void DoEvents(void)
CleanupEvents();
}
void SetupEvents(void)
{
/* Start events */
EventAdd(NULL, "tunefile", save_tunefile, NULL, 300*1000, 0);
EventAdd(NULL, "garbage", garbage_collect, NULL, GARBAGE_COLLECT_EVERY*1000, 0);
EventAdd(NULL, "loop", loop_event, NULL, 1000, 0);
EventAdd(NULL, "unrealdns_removeoldrecords", unrealdns_removeoldrecords, NULL, 15000, 0);
EventAdd(NULL, "check_pings", check_pings, NULL, 1000, 0);
EventAdd(NULL, "check_deadsockets", check_deadsockets, NULL, 1000, 0);
EventAdd(NULL, "handshake_timeout", handshake_timeout, NULL, 1000, 0);
EventAdd(NULL, "tls_check_expiry", tls_check_expiry, NULL, (86400/2)*1000, 0);
EventAdd(NULL, "unrealdb_expire_secret_cache", unrealdb_expire_secret_cache, NULL, 61000, 0);
EventAdd(NULL, "throttling_check_expire", throttling_check_expire, NULL, 1000, 0);
}

View File

@ -199,8 +199,8 @@ void free_tls_options(TLSOptions *tlsoptions);
* Config parser (IRCd)
*/
int config_read_file(const char *filename, const char *display_name);
void config_rehash();
int config_run_blocks();
void config_rehash(void);
int config_run_blocks(void);
int config_test_blocks();
/*
@ -464,10 +464,15 @@ int config_parse_flood_generic(const char *str, Configuration *conf, char *block
long config_checkval(const char *orig, unsigned short flags)
{
char *value = raw_strdup(orig);
char *value;
char *text;
long ret = 0;
/* Handle empty strings early, since we use +1 later in the code etc. */
if (BadPtr(orig))
return 0;
value = raw_strdup(orig);
if (flags == CFG_YESNO) {
for (text = value; *text; text++) {
if (!isalnum(*text))
@ -1586,7 +1591,7 @@ ConfigCommand *config_binary_search(const char *cmd) {
return NULL;
}
void free_iConf(Configuration *i)
void free_iConf(Configuration *i)
{
FloodSettings *f, *f_next;
@ -1645,6 +1650,7 @@ void config_setdefaultsettings(Configuration *i)
safe_strdup(i->oper_snomask, OPER_SNOMASKS);
i->server_notice_colors = 1;
i->server_notice_show_event = 1;
i->ident_read_timeout = 7;
i->ident_connect_timeout = 3;
i->ban_version_tkl_time = 86400; /* 1d */
@ -1694,6 +1700,7 @@ void config_setdefaultsettings(Configuration *i)
/* - known-users */
config_parse_flood_generic("3:60", i, "known-users", FLD_NICK); /* NICK flood protection: max 3 per 60s */
config_parse_flood_generic("3:90", i, "known-users", FLD_JOIN); /* JOIN flood protection: max 3 per 90s */
config_parse_flood_generic("3:90", i, "known-users", FLD_VHOST); /* MODE -x flood protection: max 3 per 90s */
config_parse_flood_generic("4:120", i, "known-users", FLD_AWAY); /* AWAY flood protection: max 4 per 120s */
config_parse_flood_generic("4:60", i, "known-users", FLD_INVITE); /* INVITE flood protection: max 4 per 60s */
config_parse_flood_generic("4:120", i, "known-users", FLD_KNOCK); /* KNOCK protection: max 4 per 120s */
@ -1702,6 +1709,7 @@ void config_setdefaultsettings(Configuration *i)
/* - unknown-users */
config_parse_flood_generic("2:60", i, "unknown-users", FLD_NICK); /* NICK flood protection: max 2 per 60s */
config_parse_flood_generic("2:90", i, "unknown-users", FLD_JOIN); /* JOIN flood protection: max 2 per 90s */
config_parse_flood_generic("2:90", i, "unknown-users", FLD_VHOST); /* MODE -x flood protection: max 2 per 90s */
config_parse_flood_generic("4:120", i, "unknown-users", FLD_AWAY); /* AWAY flood protection: max 4 per 120s */
config_parse_flood_generic("2:60", i, "unknown-users", FLD_INVITE); /* INVITE flood protection: max 2 per 60s */
config_parse_flood_generic("2:120", i, "unknown-users", FLD_KNOCK); /* KNOCK protection: max 2 per 120s */
@ -2411,7 +2419,8 @@ void config_rehash()
}
for (listen_ptr = conf_listen; listen_ptr; listen_ptr = listen_ptr->next)
{
listen_ptr->flag.temporary = 1;
if (!(listen_ptr->options & LISTENER_CONTROL))
listen_ptr->flag.temporary = 1;
}
for (tld_ptr = conf_tld; tld_ptr; tld_ptr = (ConfigItem_tld *) next)
{
@ -2642,152 +2651,87 @@ void config_switchover(void)
log_blocks_switchover();
}
int config_run_blocks()
/** Priority of config blocks during CONFIG_TEST stage */
static const char *config_test_priority_blocks[] =
{
"me",
"secret",
"log", /* "log" needs to be before "set" in CONFIG_TEST */
"set",
"class",
};
/** Priority of config blocks during CONFIG_RUN stage */
static const char *config_run_priority_blocks[] =
{
"me",
"secret",
"set",
"log", /* "log" needs to be after "set" in CONFIG_RUN */
"class",
};
int config_test_blocks()
{
ConfigEntry *ce;
ConfigFile *cfptr;
ConfigCommand *cc;
int errors = 0;
int i;
Hook *h;
ConfigItem_allow *allow;
/* Stage 1: set block first */
for (cfptr = conf; cfptr; cfptr = cfptr->next)
invalid_snomasks_encountered = 0;
/* Stage 1: first the priority blocks, in the order as specified
* in config_test_priority_blocks[]
*/
for (i=0; i < ARRAY_SIZEOF(config_test_priority_blocks); i++)
{
if (config_verbose > 1)
config_status("Running %s", cfptr->filename);
for (ce = cfptr->items; ce; ce = ce->next)
const char *config_block = config_test_priority_blocks[i];
cc = config_binary_search(config_block);
if (!cc)
abort(); /* internal fuckup */
for (cfptr = conf; cfptr; cfptr = cfptr->next)
{
if (!strcmp(ce->name, "set"))
if (config_verbose > 1)
config_status("Running %s", cfptr->filename);
for (ce = cfptr->items; ce; ce = ce->next)
{
if (_conf_set(cfptr, ce) < 0)
errors++;
}
}
}
/* Stage 2: now class blocks */
for (cfptr = conf; cfptr; cfptr = cfptr->next)
{
if (config_verbose > 1)
config_status("Running %s", cfptr->filename);
for (ce = cfptr->items; ce; ce = ce->next)
{
if (!strcmp(ce->name, "class"))
{
if (_conf_class(cfptr, ce) < 0)
errors++;
}
}
}
/* Stage 3: now all the rest */
for (cfptr = conf; cfptr; cfptr = cfptr->next)
{
if (config_verbose > 1)
config_status("Running %s", cfptr->filename);
for (ce = cfptr->items; ce; ce = ce->next)
{
/* These are already processed above (set, class)
* or via config_test_blocks() (secret).
*/
if (!strcmp(ce->name, "set") ||
!strcmp(ce->name, "class") ||
!strcmp(ce->name, "secret"))
{
continue;
}
if ((cc = config_binary_search(ce->name))) {
if ((cc->conffunc) && (cc->conffunc(cfptr, ce) < 0))
errors++;
}
else
{
int value;
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
if (!strcmp(ce->name, config_block))
{
value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN);
if (value == 1)
break;
int n = cc->testfunc(cfptr, ce);
errors += n;
if (!strcmp(config_block, "secret") && (n == 0))
{
/* Yeah special case: secret { } blocks we run
* immediately here.
*/
_conf_secret(cfptr, ce);
}
}
}
}
}
close_unbound_listeners();
listen_cleanup();
close_unbound_listeners();
loop.do_bancheck = 1;
config_switchover();
update_throttling_timer_settings();
/* initialize conf_files with defaults if the block isn't set: */
if (!conf_files)
_conf_files(NULL, NULL);
if (errors > 0)
{
config_error("%i fatal errors encountered", errors);
}
return (errors > 0 ? -1 : 1);
}
int config_test_blocks()
{
ConfigEntry *ce;
ConfigFile *cfptr;
ConfigCommand *cc;
int errors = 0;
Hook *h;
invalid_snomasks_encountered = 0;
/* First, all the log { } blocks everywhere */
/* Stage 2: now all the other config blocks */
for (cfptr = conf; cfptr; cfptr = cfptr->next)
{
if (config_verbose > 1)
config_status("Testing %s", cfptr->filename);
/* First test and run the log { } blocks */
config_status("Running %s", cfptr->filename);
for (ce = cfptr->items; ce; ce = ce->next)
{
if (!strcmp(ce->name, "log"))
errors += config_test_log(cfptr, ce);
}
}
for (cfptr = conf; cfptr; cfptr = cfptr->next)
{
if (config_verbose > 1)
config_status("Testing %s", cfptr->filename);
/* First test and run the secret { } blocks */
for (ce = cfptr->items; ce; ce = ce->next)
{
if (!strcmp(ce->name, "secret"))
char skip = 0;
for (i=0; i < ARRAY_SIZEOF(config_test_priority_blocks); i++)
{
int n = _test_secret(cfptr, ce);
errors += n;
if (n == 0)
_conf_secret(cfptr, ce);
if (!strcmp(ce->name, config_test_priority_blocks[i]))
{
skip = 1;
break;
}
}
}
/* First test the set { } block */
for (ce = cfptr->items; ce; ce = ce->next)
{
if (!strcmp(ce->name, "set"))
errors += _test_set(cfptr, ce);
}
/* Now test all the rest */
for (ce = cfptr->items; ce; ce = ce->next)
{
/* These are already processed, so skip them here.. */
if (!strcmp(ce->name, "secret") ||
!strcmp(ce->name, "set") ||
!strcmp(ce->name, "log"))
{
if (skip)
continue;
}
if ((cc = config_binary_search(ce->name))) {
if (cc->testfunc)
errors += (cc->testfunc(cfptr, ce));
@ -2841,7 +2785,9 @@ int config_test_blocks()
}
}
}
errors += config_post_test();
if (errors > 0)
{
config_error("%i errors encountered", errors);
@ -2856,6 +2802,96 @@ int config_test_blocks()
return (errors > 0 ? -1 : 1);
}
int config_run_blocks(void)
{
ConfigEntry *ce;
ConfigFile *cfptr;
ConfigCommand *cc;
int errors = 0;
int i;
Hook *h;
ConfigItem_allow *allow;
/* Stage 1: first the priority blocks, in the order as specified
* in config_run_priority_blocks[]
*/
for (i=0; i < ARRAY_SIZEOF(config_run_priority_blocks); i++)
{
const char *config_block = config_run_priority_blocks[i];
cc = config_binary_search(config_block);
if (!cc)
abort(); /* internal fuckup */
if (!strcmp(config_block, "secret"))
continue; /* yeah special case, we already processed the run part in test for these */
for (cfptr = conf; cfptr; cfptr = cfptr->next)
{
if (config_verbose > 1)
config_status("Running %s", cfptr->filename);
for (ce = cfptr->items; ce; ce = ce->next)
{
if (!strcmp(ce->name, config_block))
{
if (cc->conffunc(cfptr, ce) < 0)
errors++;
}
}
}
}
/* Stage 2: now all the other config blocks */
for (cfptr = conf; cfptr; cfptr = cfptr->next)
{
if (config_verbose > 1)
config_status("Running %s", cfptr->filename);
for (ce = cfptr->items; ce; ce = ce->next)
{
char skip = 0;
for (i=0; i < ARRAY_SIZEOF(config_run_priority_blocks); i++)
{
if (!strcmp(ce->name, config_run_priority_blocks[i]))
{
skip = 1;
break;
}
}
if (skip)
continue;
if ((cc = config_binary_search(ce->name))) {
if ((cc->conffunc) && (cc->conffunc(cfptr, ce) < 0))
errors++;
}
else
{
int value;
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
{
value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN);
if (value == 1)
break;
}
}
}
}
close_unbound_listeners();
listen_cleanup();
close_unbound_listeners();
loop.do_bancheck = 1;
config_switchover();
update_throttling_timer_settings();
/* initialize conf_files with defaults if the block isn't set: */
if (!conf_files)
_conf_files(NULL, NULL);
if (errors > 0)
{
config_error("%i fatal errors encountered", errors);
}
return (errors > 0 ? -1 : 1);
}
/*
* Service functions
*/
@ -2935,7 +2971,7 @@ int count_oper_sessions(const char *name)
return count;
}
ConfigItem_listen *find_listen(const char *ipmask, int port, int ipv6)
ConfigItem_listen *find_listen(const char *ipmask, int port, SocketType socket_type)
{
ConfigItem_listen *e;
@ -2943,8 +2979,19 @@ ConfigItem_listen *find_listen(const char *ipmask, int port, int ipv6)
return NULL;
for (e = conf_listen; e; e = e->next)
if ((e->ipv6 == ipv6) && (e->port == port) && !strcmp(e->ip, ipmask))
return e;
{
if (e->socket_type != socket_type)
continue;
if (e->socket_type == SOCKET_TYPE_UNIX)
{
if (!strcmp(e->file, ipmask))
return e;
} else
{
if ((e->socket_type == socket_type) && (e->port == port) && !strcmp(e->ip, ipmask))
return e;
}
}
return NULL;
}
@ -3889,7 +3936,9 @@ int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
oper = safe_alloc(sizeof(ConfigItem_oper));
safe_strdup(oper->name, ce->value);
oper->server_notice_colors = tempiConf.server_notice_colors; /* default */
/* Inherit some defaults: */
oper->server_notice_colors = tempiConf.server_notice_colors;
oper->server_notice_show_event = tempiConf.server_notice_show_event;
for (cep = ce->items; cep; cep = cep->next)
{
@ -3937,6 +3986,10 @@ int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
{
oper->server_notice_colors = config_checkval(cep->value, CFG_YESNO);
}
else if (!strcmp(cep->name, "server-notice-show-event"))
{
oper->server_notice_show_event = config_checkval(cep->value, CFG_YESNO);
}
else if (!strcmp(cep->name, "modes"))
{
oper->modes = set_usermode(cep->value);
@ -4069,6 +4122,9 @@ int _test_oper(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cep->name, "server-notice-colors"))
{
}
else if (!strcmp(cep->name, "server-notice-show-event"))
{
}
/* oper::modes */
else if (!strcmp(cep->name, "modes"))
{
@ -4777,6 +4833,7 @@ int _conf_listen(ConfigFile *conf, ConfigEntry *ce)
ConfigEntry *cepp;
ConfigEntry *tlsconfig = NULL;
ConfigItem_listen *listen = NULL;
char *file = NULL;
char *ip = NULL;
int start=0, end=0, port, isnew;
int tmpflags =0;
@ -4784,6 +4841,10 @@ int _conf_listen(ConfigFile *conf, ConfigEntry *ce)
for (cep = ce->items; cep; cep = cep->next)
{
if (!strcmp(cep->name, "file"))
{
file = cep->value;
} else
if (!strcmp(cep->name, "ip"))
{
ip = cep->value;
@ -4825,18 +4886,44 @@ int _conf_listen(ConfigFile *conf, ConfigEntry *ce)
}
}
}
/* UNIX domain socket code */
if (file)
{
if (!(listen = find_listen(file, 0, SOCKET_TYPE_UNIX)))
{
listen = safe_alloc(sizeof(ConfigItem_listen));
safe_strdup(listen->file, file);
listen->socket_type = SOCKET_TYPE_UNIX;
listen->fd = -1;
isnew = 1;
} else {
isnew = 0;
}
if (listen->options & LISTENER_BOUND)
tmpflags |= LISTENER_BOUND;
listen->options = tmpflags;
if (isnew)
AddListItem(listen, conf_listen);
listen->flag.temporary = 0;
return 1;
}
for (port = start; port <= end; port++)
{
/* First deal with IPv4 */
if (!strchr(ip, ':'))
{
if (!(listen = find_listen(ip, port, 0)))
if (!(listen = find_listen(ip, port, SOCKET_TYPE_IPV4)))
{
listen = safe_alloc(sizeof(ConfigItem_listen));
safe_strdup(listen->ip, ip);
listen->port = port;
listen->fd = -1;
listen->ipv6 = 0;
listen->socket_type = SOCKET_TYPE_IPV4;
isnew = 1;
} else
isnew = 0;
@ -4915,13 +5002,13 @@ int _conf_listen(ConfigFile *conf, ConfigEntry *ce)
{
if (strchr(ip, ':') || (*ip == '*'))
{
if (!(listen = find_listen(ip, port, 1)))
if (!(listen = find_listen(ip, port, SOCKET_TYPE_IPV6)))
{
listen = safe_alloc(sizeof(ConfigItem_listen));
safe_strdup(listen->ip, ip);
listen->port = port;
listen->fd = -1;
listen->ipv6 = 1;
listen->socket_type = SOCKET_TYPE_IPV6;
isnew = 1;
} else
isnew = 0;
@ -5002,7 +5089,8 @@ int _test_listen(ConfigFile *conf, ConfigEntry *ce)
ConfigEntry *cep;
ConfigEntry *cepp;
int errors = 0;
char has_ip = 0, has_port = 0, has_options = 0, port_6667 = 0;
char has_file = 0, has_ip = 0, has_port = 0, has_options = 0, port_6667 = 0;
char *file = NULL;
char *ip = NULL;
Hook *h;
@ -5117,6 +5205,11 @@ int _test_listen(ConfigFile *conf, ConfigEntry *ce)
}
continue; /* always */
} else
if (!strcmp(cep->name, "file"))
{
has_file = 1;
file = cep->value;
} else
if (!strcmp(cep->name, "ip"))
{
has_ip = 1;
@ -5189,18 +5282,32 @@ int _test_listen(ConfigFile *conf, ConfigEntry *ce)
}
}
if (!has_ip)
if (has_file)
{
config_error("%s:%d: listen block requires an listen::ip",
ce->file->filename, ce->line_number);
errors++;
}
if (has_ip || has_port)
{
config_error("%s:%d: listen block should either have a 'file' (for *NIX domain socket), "
"OR have an 'ip' and 'port' (for IPv4/IPv6). You cannot combine both in one listen block.",
ce->file->filename, ce->line_number);
errors++;
} else {
// TODO: check if file can be created fresh etc.
}
} else
{
if (!has_ip)
{
config_error("%s:%d: listen block requires an listen::ip",
ce->file->filename, ce->line_number);
errors++;
}
if (!has_port)
{
config_error("%s:%d: listen block requires an listen::port",
ce->file->filename, ce->line_number);
errors++;
if (!has_port)
{
config_error("%s:%d: listen block requires an listen::port",
ce->file->filename, ce->line_number);
errors++;
}
}
if (port_6667)
@ -7167,6 +7274,9 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cep->name, "server-notice-colors")) {
tempiConf.server_notice_colors = config_checkval(cep->value, CFG_YESNO);
}
else if (!strcmp(cep->name, "server-notice-show-event")) {
tempiConf.server_notice_show_event = config_checkval(cep->value, CFG_YESNO);
}
else if (!strcmp(cep->name, "level-on-join")) {
const char *res = channellevel_to_string(cep->value); /* 'halfop', etc */
if (!res)
@ -7380,6 +7490,10 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
{
config_parse_flood_generic(ceppp->value, &tempiConf, cepp->name, FLD_NICK);
}
else if (!strcmp(ceppp->name, "vhost-flood"))
{
config_parse_flood_generic(ceppp->value, &tempiConf, cepp->name, FLD_VHOST);
}
else if (!strcmp(ceppp->name, "join-flood"))
{
config_parse_flood_generic(ceppp->value, &tempiConf, cepp->name, FLD_JOIN);
@ -7847,6 +7961,9 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cep->name, "server-notice-colors")) {
CheckNull(cep);
}
else if (!strcmp(cep->name, "server-notice-show-event")) {
CheckNull(cep);
}
else if (!strcmp(cep->name, "level-on-join")) {
CheckNull(cep);
CheckDuplicate(cep, level_on_join, "level-on-join");
@ -8340,6 +8457,19 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
errors++;
}
}
else if (!strcmp(ceppp->name, "vhost-flood"))
{
int cnt, period;
CheckNull(ceppp);
if (!config_parse_flood(ceppp->value, &cnt, &period) ||
(cnt < 1) || (cnt > 255) || (period < 5))
{
config_error("%s:%i: set::anti-flood::vhost-flood error. Syntax is '<count>:<period>' (eg 5:60), "
"count should be 1-255, period should be greater than 4",
ceppp->file->filename, ceppp->line_number);
errors++;
}
}
else if (!strcmp(ceppp->name, "join-flood"))
{
int cnt, period;
@ -9191,14 +9321,22 @@ void start_listeners(void)
log_data_string("listen_ip", listener->ip),
log_data_integer("listen_port", listener->port));
} else {
if (listener->ipv6)
snprintf(boundmsg_ipv6+strlen(boundmsg_ipv6), sizeof(boundmsg_ipv6)-strlen(boundmsg_ipv6),
"%s:%d%s, ", listener->ip, listener->port,
listener->options & LISTENER_TLS ? "(TLS)" : "");
else
snprintf(boundmsg_ipv4+strlen(boundmsg_ipv4), sizeof(boundmsg_ipv4)-strlen(boundmsg_ipv4),
"%s:%d%s, ", listener->ip, listener->port,
listener->options & LISTENER_TLS ? "(TLS)" : "");
switch (listener->socket_type)
{
case SOCKET_TYPE_IPV4:
snprintf(boundmsg_ipv4+strlen(boundmsg_ipv4), sizeof(boundmsg_ipv4)-strlen(boundmsg_ipv4),
"%s:%d%s, ", listener->ip, listener->port,
listener->options & LISTENER_TLS ? "(TLS)" : "");
break;
case SOCKET_TYPE_IPV6:
snprintf(boundmsg_ipv6+strlen(boundmsg_ipv6), sizeof(boundmsg_ipv6)-strlen(boundmsg_ipv6),
"%s:%d%s, ", listener->ip, listener->port,
listener->options & LISTENER_TLS ? "(TLS)" : "");
break;
// TODO: show unix domain sockets ;)
default:
break;
}
}
}
}
@ -9268,6 +9406,7 @@ void config_run(void)
{
extcmodes_check_for_changes();
start_listeners();
add_proc_io_server();
free_all_config_resources();
}
@ -10499,13 +10638,6 @@ void resource_download_complete(const char *url, const char *file, const char *e
safe_strdup(wce->ce->value, rs->file); // now information of url is lost, hm!!
}
}
/* If rehashing, check if we are done.
* If booting (not rehashing), this is done from the
* startup loop where it also checks is_config_read_finished().
*/
if (loop.rehashing && is_config_read_finished())
rehash_internal(loop.rehash_save_client);
}
/** Request to REHASH the configuration file.
@ -10540,13 +10672,16 @@ void request_rehash(Client *client)
int rehash_internal(Client *client)
{
int failure;
/* Log it here if it is by a signal */
if (client == NULL)
unreal_log(ULOG_INFO, "config", "CONFIG_RELOAD", client, "Rehashing server configuration file [./unrealircd rehash]");
loop.rehashing = 1; /* double checking.. */
loop.rehashing = 2; /* now doing the actual rehash */
if (config_test() == 0)
failure = config_test();
if (failure == 0)
config_run();
/* TODO: uh.. are we supposed to do all this for a failed rehash too? maybe some but not all? */
reread_motdsandrules();
@ -10557,8 +10692,11 @@ int rehash_internal(Client *client)
// unload_all_unused_moddata(); -- this will crash
umodes_check_for_changes();
charsys_check_for_changes();
/* Clear everything now that we are done */
loop.rehashing = 0;
remote_rehash_client = NULL;
procio_post_rehash(failure);
return 1;
}

View File

@ -649,6 +649,13 @@ int crashreport_send(char *fname)
if ((n < 0) || strncmp(buf, "HTTP/1.1 100", 12))
{
printf("Error transmitting bug report (stage II, n=%d)\n", n);
if (!strncmp(buf, "HTTP/1.1 403", 12))
{
printf("Your crash report was rejected automatically.\n"
"This normally means your UnrealIRCd version is too old and unsupported.\n"
"Chances are that your crash issue is already fixed in a later release.\n"
"Check https://www.unrealircd.org/ for latest releases!\n");
}
return 0;
}

View File

@ -58,6 +58,7 @@ static void dbuf_free(dbufbuf *ptr)
void dbuf_queue_init(dbuf *dyn)
{
memset(dyn, 0, sizeof(dbuf));
INIT_LIST_HEAD(&dyn->dbuf_list);
}

View File

@ -113,7 +113,7 @@ static int unrealdns_sock_create_cb(ares_socket_t fd, int type, void *data)
return ARES_SUCCESS;
}
static EVENT(unrealdns_timeout)
EVENT(unrealdns_timeout)
{
ares_process_fd(resolver_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}

View File

@ -25,209 +25,10 @@
char *malloc_options = "h" MALLOC_FLAGS_EXTRA;
#endif
#ifndef _WIN32
extern char unreallogo[];
#endif
int SVSNOOP = 0;
extern MODVAR char *buildid;
time_t timeofday = 0;
struct timeval timeofday_tv;
int tainted = 0;
LoopStruct loop;
#ifndef _WIN32
uid_t irc_uid = 0;
gid_t irc_gid = 0;
#endif
MODVAR IRCCounts irccounts;
MODVAR Client me; /* That's me */
MODVAR char *me_hash;
extern char backupbuf[8192];
#ifdef _WIN32
extern SERVICE_STATUS_HANDLE IRCDStatusHandle;
extern SERVICE_STATUS IRCDStatus;
#endif
MODVAR unsigned char conf_debuglevel = 0;
/* Forward declarations */
void server_reboot(const char *);
void restart(const char *);
static void open_debugfile(), setup_signals();
extern void init_glines(void);
extern void tkl_init(void);
extern void process_clients(void);
extern void unrealdb_test(void);
#ifndef _WIN32
MODVAR char **myargv;
#else
LPCSTR cmdLine;
#endif
char *configfile = NULL; /* Server configuration file */
int debuglevel = 0; /* Server debug level */
int bootopt = 0; /* Server boot option flags */
char *debugmode = ""; /* -"- -"- -"- */
char *sbrk0; /* initial sbrk(0) */
static int dorehash = 0, dorestart = 0, doreloadcert = 0;
MODVAR int booted = FALSE;
void s_die()
{
#ifdef _WIN32
Client *client;
if (!IsService)
{
loop.terminating = 1;
unload_all_modules();
list_for_each_entry(client, &lclient_list, lclient_node)
(void) send_queued(client);
exit(-1);
}
else {
SERVICE_STATUS status;
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
SC_HANDLE hService = OpenService(hSCManager, "UnrealIRCd", SERVICE_STOP);
ControlService(hService, SERVICE_CONTROL_STOP, &status);
}
#else
loop.terminating = 1;
unload_all_modules();
unlink(conf_files ? conf_files->pid_file : IRCD_PIDFILE);
exit(0);
#endif
}
#ifndef _WIN32
static void s_rehash()
{
struct sigaction act;
dorehash = 1;
act.sa_handler = s_rehash;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGHUP);
(void)sigaction(SIGHUP, &act, NULL);
}
static void s_reloadcert()
{
struct sigaction act;
doreloadcert = 1;
act.sa_handler = s_reloadcert;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGUSR1);
(void)sigaction(SIGUSR1, &act, NULL);
}
#endif // #ifndef _WIN32
void restart(const char *mesg)
{
server_reboot(mesg);
}
void s_restart()
{
dorestart = 1;
#if 0
static int restarting = 0;
if (restarting == 0) {
/*
* Send (or attempt to) a dying scream to oper if present
*/
restarting = 1;
server_reboot("SIGINT");
}
#endif
}
#ifndef _WIN32
/** Signal handler for signals which we ignore,
* like SIGPIPE ("Broken pipe") and SIGWINCH (terminal window changed) etc.
*/
void ignore_this_signal()
{
struct sigaction act;
act.sa_handler = ignore_this_signal;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGALRM);
(void)sigaddset(&act.sa_mask, SIGPIPE);
(void)sigaction(SIGALRM, &act, (struct sigaction *)NULL);
(void)sigaction(SIGPIPE, &act, (struct sigaction *)NULL);
#ifdef SIGWINCH
(void)sigaddset(&act.sa_mask, SIGWINCH);
(void)sigaction(SIGWINCH, &act, (struct sigaction *)NULL);
#endif
}
#endif /* #ifndef _WIN32 */
void server_reboot(const char *mesg)
{
int i;
Client *client;
unreal_log(ULOG_INFO, "main", "UNREALIRCD_RESTARTING", NULL,
"Restarting server: $reason",
log_data_string("reason", mesg));
list_for_each_entry(client, &lclient_list, lclient_node)
(void) send_queued(client);
/*
* ** fd 0 must be 'preserved' if either the -d or -i options have
* ** been passed to us before restarting.
*/
#ifdef HAVE_SYSLOG
(void)closelog();
#endif
#ifndef _WIN32
for (i = 3; i < MAXCONNECTIONS; i++)
(void)close(i);
if (!(bootopt & (BOOT_TTY | BOOT_DEBUG)))
(void)close(2);
(void)close(1);
(void)close(0);
(void)execv(MYNAME, myargv);
#else
close_connections();
if (!IsService)
{
CleanUp();
WinExec(cmdLine, SW_SHOWDEFAULT);
}
#endif
unload_all_modules();
#ifdef _WIN32
if (IsService)
{
SERVICE_STATUS status;
PROCESS_INFORMATION pi;
STARTUPINFO si;
char fname[MAX_PATH];
memset(&status, 0, sizeof(status));
memset(&si, 0, sizeof(si));
IRCDStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(IRCDStatusHandle, &IRCDStatus);
GetModuleFileName(GetModuleHandle(NULL), fname, MAX_PATH);
CreateProcess(fname, "restartsvc", NULL, NULL, FALSE,
0, NULL, NULL, &si, &pi);
IRCDStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(IRCDStatusHandle, &IRCDStatus);
ExitProcess(0);
}
else
#endif
exit(-1);
}
MODVAR char *areason;
EVENT(loop_event)
{
@ -557,58 +358,6 @@ void fix_timers(void)
}
#ifndef _WIN32
/* Generate 3 cloak keys and print to console */
static void generate_cloakkeys()
{
#define GENERATE_CLOAKKEY_LEN 80 /* Length of cloak keys to generate. */
char keyBuf[GENERATE_CLOAKKEY_LEN + 1];
int keyNum;
int charIndex;
short has_upper;
short has_lower;
short has_num;
fprintf(stderr, "Here are 3 random cloak keys that you can copy-paste to your configuration file:\n\n");
fprintf(stderr, "set {\n\tcloak-keys {\n");
for (keyNum = 0; keyNum < 3; ++keyNum)
{
has_upper = 0;
has_lower = 0;
has_num = 0;
for (charIndex = 0; charIndex < sizeof(keyBuf)-1; ++charIndex)
{
switch (getrandom8() % 3)
{
case 0: /* Uppercase. */
keyBuf[charIndex] = (char)('A' + (getrandom8() % ('Z' - 'A')));
has_upper = 1;
break;
case 1: /* Lowercase. */
keyBuf[charIndex] = (char)('a' + (getrandom8() % ('z' - 'a')));
has_lower = 1;
break;
case 2: /* Digit. */
keyBuf[charIndex] = (char)('0' + (getrandom8() % ('9' - '0')));
has_num = 1;
break;
}
}
keyBuf[sizeof(keyBuf)-1] = '\0';
if (has_upper && has_lower && has_num)
fprintf(stderr, "\t\t\"%s\";\n", keyBuf);
else
/* Try again. For this reason, keyNum must be signed. */
keyNum--;
}
fprintf(stderr, "\t}\n}\n\n");
}
#endif
/* MY tdiff... because 'double' sucks.
* This should work until 2038, and very likely after that as well
* because 'long' should be 64 bit on all systems by then... -- Syzop
@ -677,30 +426,19 @@ void detect_timeshift_and_warn(void)
oldtimeofday = timeofday;
}
/** Check if at least 'minimum' seconds passed by since last run.
* @param tv_old Pointer to a timeval struct to keep track of things.
* @param minimum The time specified in milliseconds (eg: 1000 for 1 second)
* @returns When 'minimum' msec passed 1 is returned and the time is reset, otherwise 0 is returned.
*/
int minimum_msec_since_last_run(struct timeval *tv_old, long minimum)
void SetupEvents(void)
{
long v;
if (tv_old->tv_sec == 0)
{
/* First call ever */
tv_old->tv_sec = timeofday_tv.tv_sec;
tv_old->tv_usec = timeofday_tv.tv_usec;
return 0;
}
v = ((timeofday_tv.tv_sec - tv_old->tv_sec) * 1000) + ((timeofday_tv.tv_usec - tv_old->tv_usec)/1000);
if (v >= minimum)
{
tv_old->tv_sec = timeofday_tv.tv_sec;
tv_old->tv_usec = timeofday_tv.tv_usec;
return 1;
}
return 0;
/* Start events */
EventAdd(NULL, "tunefile", save_tunefile, NULL, 300*1000, 0);
EventAdd(NULL, "garbage", garbage_collect, NULL, GARBAGE_COLLECT_EVERY*1000, 0);
EventAdd(NULL, "loop", loop_event, NULL, 1000, 0);
EventAdd(NULL, "unrealdns_removeoldrecords", unrealdns_removeoldrecords, NULL, 15000, 0);
EventAdd(NULL, "check_pings", check_pings, NULL, 1000, 0);
EventAdd(NULL, "check_deadsockets", check_deadsockets, NULL, 1000, 0);
EventAdd(NULL, "handshake_timeout", handshake_timeout, NULL, 1000, 0);
EventAdd(NULL, "tls_check_expiry", tls_check_expiry, NULL, (86400/2)*1000, 0);
EventAdd(NULL, "unrealdb_expire_secret_cache", unrealdb_expire_secret_cache, NULL, 61000, 0);
EventAdd(NULL, "throttling_check_expire", throttling_check_expire, NULL, 1000, 0);
}
/** The main function. This will call SocketLoop() once the server is ready. */
@ -710,10 +448,7 @@ int main(int argc, char *argv[])
int InitUnrealIRCd(int argc, char *argv[])
#endif
{
#ifdef _WIN32
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
#else
#ifndef _WIN32
uid_t uid, euid;
gid_t gid, egid;
#endif
@ -755,7 +490,6 @@ int InitUnrealIRCd(int argc, char *argv[])
SetErrorMode(SEM_FAILCRITICALERRORS);
#endif
#if !defined(_WIN32) && !defined(_AMIGA)
sbrk0 = (char *)sbrk((size_t)0);
uid = getuid();
euid = geteuid();
gid = getgid();
@ -784,7 +518,7 @@ int InitUnrealIRCd(int argc, char *argv[])
#ifndef _WIN32
(void)umask(077); /* better safe than sorry --SRB */
#else
WSAStartup(wVersionRequested, &wsaData);
init_winsock();
#endif
setup_signals();
@ -840,43 +574,6 @@ int InitUnrealIRCd(int argc, char *argv[])
safe_strdup(configfile, p);
convert_to_absolute_path(&configfile, CONFDIR);
break;
#ifndef _WIN32
case 'P':{
short type;
const char *result;
srandom(TStime());
type = Auth_FindType(NULL, p);
if (type == -1)
{
type = AUTHTYPE_ARGON2;
} else {
p = *++argv;
argc--;
}
if (BadPtr(p))
{
#ifndef _WIN32
p = getpass("Enter password to hash: ");
#else
printf("ERROR: You should specify a password to hash");
exit(1);
#endif
}
if ((type == AUTHTYPE_UNIXCRYPT) && (strlen(p) > 8))
{
/* Hmmm.. is this warning really still true (and always) ?? */
printf("WARNING: Password truncated to 8 characters due to 'crypt' algorithm. "
"You are suggested to use the 'argon2' algorithm instead.");
p[8] = '\0';
}
if (!(result = Auth_Hash(type, p))) {
printf("Failed to generate password. Deprecated method? Try 'argon2' instead.\n");
exit(0);
}
printf("Encrypted password is: %s\n", result);
exit(0);
}
#endif
#if 0
case 'S':
charsys_dump_table(p ? p : "*");
@ -921,11 +618,6 @@ int InitUnrealIRCd(int argc, char *argv[])
}
# endif
exit(0);
#endif
#ifndef _WIN32
case 'k':
generate_cloakkeys();
exit(0);
#endif
case 'K':
{
@ -1032,7 +724,6 @@ int InitUnrealIRCd(int argc, char *argv[])
initstats();
if (!loop.config_test)
DeleteTempModules();
booted = FALSE;
#if !defined(_WIN32) && !defined(_AMIGA) && !defined(OSXTIGER) && DEFAULT_PERMISSIONS != 0
/* Hack to stop people from being able to read the config file */
(void)chmod(CPATH, DEFAULT_PERMISSIONS);
@ -1056,11 +747,11 @@ int InitUnrealIRCd(int argc, char *argv[])
gettimeofday(&timeofday_tv, NULL);
timeofday = timeofday_tv.tv_sec;
url_socket_timeout(NULL);
unrealdns_timeout(NULL);
fd_select(500);
}
if (config_test() < 0)
exit(-1);
booted = TRUE;
load_tunefile();
make_umodestr();
SetListening(&me);
@ -1223,6 +914,9 @@ void SocketLoop(void *dummy)
reinit_tls();
doreloadcert = 0;
}
/* If rehashing, check if we are done. */
if (loop.rehashing && is_config_read_finished())
rehash_internal(loop.rehash_save_client);
}
}

31
src/ircd_vars.c Normal file
View File

@ -0,0 +1,31 @@
/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/ircd_vars.c
* (c) 2021- Bram Matthys and The UnrealIRCd team
* License: GPLv2
*/
#include "unrealircd.h"
/** @file
* @brief UnrealIRCd global variables of the IRCd
*/
int SVSNOOP = 0;
time_t timeofday = 0;
struct timeval timeofday_tv;
int tainted = 0;
LoopStruct loop;
MODVAR IRCCounts irccounts;
MODVAR Client me; /* That's me */
MODVAR char *me_hash;
char *configfile = NULL; /* Server configuration file */
int debuglevel = 0; /* Server debug level */
int bootopt = 0; /* Server boot option flags */
char *debugmode = ""; /* -"- -"- -"- */
int dorehash = 0; /**< Rehash server on next socket loop */
int dorestart = 0; /**< Restart server on next socket loop */
int doreloadcert = 0; /**< Reload TLS certificate on next socket loop */
#ifndef _WIN32
char **myargv;
#else
LPCSTR cmdLine;
#endif

View File

@ -44,6 +44,7 @@ MODVAR int numclients = 0;
// TODO: Document whether servers are included or excluded in these lists...
MODVAR struct list_head unknown_list; /**< Local clients in handshake (may become a user or server later) */
MODVAR struct list_head control_list; /**< Local "control channel" clients */
MODVAR struct list_head lclient_list; /**< Local clients (users only, right?) */
MODVAR struct list_head client_list; /**< All clients - local and remote (not in handshake) */
MODVAR struct list_head server_list; /**< Locally connected servers */
@ -71,6 +72,7 @@ void initlists(void)
INIT_LIST_HEAD(&server_list);
INIT_LIST_HEAD(&oper_list);
INIT_LIST_HEAD(&unknown_list);
INIT_LIST_HEAD(&control_list);
INIT_LIST_HEAD(&global_server_list);
INIT_LIST_HEAD(&dead_list);

241
src/log.c
View File

@ -28,7 +28,7 @@
#include "unrealircd.h"
// TODO: Make configurable at compile time (runtime won't do, as we haven't read the config file)
#define show_event_id_console 0
#define show_event_console 0
/* Variables */
Log *logs[NUM_LOG_DESTINATIONS] = { NULL, NULL, NULL, NULL, NULL };
@ -186,7 +186,7 @@ int config_test_log(ConfigFile *conf, ConfigEntry *block)
/* TODO: Validate the sources lightly for formatting issues */
any_sources = 1;
}
}
} else
if (!strcmp(ce->name, "destination"))
{
for (cep = ce->items; cep; cep = cep->next)
@ -225,6 +225,22 @@ int config_test_log(ConfigFile *conf, ConfigEntry *block)
cep->file->filename, cep->line_number, cep->value);
errors++;
}
for (cepp = cep->items; cepp; cepp = cepp->next)
{
if (!strcmp(cepp->name, "color"))
;
else if (!strcmp(cepp->name, "show-event"))
;
else if (!strcmp(cepp->name, "json-message-tag"))
;
else if (!strcmp(cepp->name, "oper-only"))
;
else
{
config_error_unknown(cepp->file->filename, cepp->line_number, "log::destination::channel", cepp->name);
errors++;
}
}
} else
if (!strcmp(cep->name, "file"))
{
@ -308,6 +324,10 @@ int config_test_log(ConfigFile *conf, ConfigEntry *block)
continue;
}
}
} else
{
config_error_unknown(ce->file->filename, ce->line_number, "log", ce->name);
errors++;
}
}
@ -393,6 +413,23 @@ int config_run_log(ConfigFile *conf, ConfigEntry *block)
strlcpy(log->destination, cep->value, sizeof(log->destination)); /* destination is the channel */
log->sources = sources;
AddListItem(log, temp_logs[LOG_DEST_CHANNEL]);
/* set defaults */
log->color = tempiConf.server_notice_colors;
log->show_event = tempiConf.server_notice_show_event;
log->json_message_tag = 1;
log->oper_only = 1;
/* now parse options (if any) */
for (cepp = cep->items; cepp; cepp = cepp->next)
{
if (!strcmp(cepp->name, "color"))
log->color = config_checkval(cepp->value, CFG_YESNO);
else if (!strcmp(cepp->name, "show-event"))
log->show_event = config_checkval(cepp->value, CFG_YESNO);
else if (!strcmp(cepp->name, "json-message-tag"))
log->json_message_tag = config_checkval(cepp->value, CFG_YESNO);
else if (!strcmp(cepp->name, "oper-only"))
log->oper_only = config_checkval(cepp->value, CFG_YESNO);
}
} else
if (!strcmp(cep->name, "remote"))
{
@ -499,6 +536,10 @@ void json_expand_client(json_t *j, const char *key, Client *client, int detail)
/* same for ip, is there for all (well, some services pseudo-users may not have one) */
json_object_set_new(child, "ip", json_string_unreal(client->ip));
if (client->local && client->local->listener)
json_object_set_new(child, "server_port", json_integer(client->local->listener->port));
if (client->local && client->local->port)
json_object_set_new(child, "client_port", json_integer(client->local->port));
/* client.details is always available: it is nick!user@host, nick@host, server@host
* server@ip, or just server.
@ -963,7 +1004,6 @@ static NameValue log_colors_terminal[] = {
{ ULOG_ERROR, "\033[91m" },
{ ULOG_FATAL, "\033[95m" },
};
#define TERMINAL_COLOR_RESET "\033[0m"
const char *log_level_irc_color(LogLevel loglevel)
{
@ -1151,7 +1191,7 @@ literal:
}
/** Do the actual writing to log files */
void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized)
void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized, Client *from_server)
{
static int last_log_file_warning = 0;
Log *l;
@ -1171,14 +1211,14 @@ void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *ev
for (m = msg; m; m = m->next)
{
#ifdef _WIN32
if (show_event_id_console)
if (show_event_console)
win_log("* %s.%s%s [%s] %s\n", subsystem, event_id, m->next?"+":"", log_level_valtostring(loglevel), m->line);
else
win_log("* [%s] %s\n", log_level_valtostring(loglevel), m->line);
#else
if (terminal_supports_color())
{
if (show_event_id_console)
if (show_event_console)
{
fprintf(stderr, "%s%s.%s%s %s[%s]%s %s\n",
log_level_terminal_color(ULOG_INVALID), subsystem, event_id, TERMINAL_COLOR_RESET,
@ -1190,7 +1230,7 @@ void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *ev
m->line);
}
} else {
if (show_event_id_console)
if (show_event_console)
fprintf(stderr, "%s.%s%s [%s] %s\n", subsystem, event_id, m->next?"+":"", log_level_valtostring(loglevel), m->line);
else
fprintf(stderr, "[%s] %s\n", log_level_valtostring(loglevel), m->line);
@ -1303,13 +1343,9 @@ void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *ev
for (m = msg; m; m = m->next)
{
char text_buf[8192];
snprintf(text_buf, sizeof(text_buf), "%s.%s%s %s: %s\n", subsystem, event_id, m->next?"+":"", log_level_valtostring(loglevel), m->line);
// FIXME: don't write in 2 stages, waste of slow system calls
if (write(l->logfd, timebuf, strlen(timebuf)) < 0)
{
/* Let's ignore any write errors for this one. Next write() will catch it... */
;
}
snprintf(text_buf, sizeof(text_buf), "%s%s %s.%s%s %s: %s\n",
timebuf, from_server->name,
subsystem, event_id, m->next?"+":"", log_level_valtostring(loglevel), m->line);
n = write(l->logfd, text_buf, strlen(text_buf));
if (n < strlen(text_buf))
{
@ -1423,13 +1459,66 @@ const char *log_to_snomask(LogLevel loglevel, const char *subsystem, const char
#define COLOR_NONE "\xf"
#define COLOR_DARKGREY "\00314"
/** Do the actual writing to log files */
/** Generic sendto function for logging to IRC. Used for notices to IRCOps and also for sending to individual users on channels */
void sendto_log(Client *client, const char *msgtype, const char *destination, int show_colors, int show_event,
LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized, Client *from_server)
{
MultiLine *m;
for (m = msg; m; m = m->next)
{
MessageTag *mtags = NULL;
new_message(from_server, NULL, &mtags);
/* Add JSON data, but only if it is the first message (m == msg) */
if (json_serialized && (m == msg))
{
MessageTag *json_mtag = safe_alloc(sizeof(MessageTag));
safe_strdup(json_mtag->name, "unrealircd.org/json-log");
safe_strdup(json_mtag->value, json_serialized);
AddListItem(json_mtag, mtags);
}
if (show_colors)
{
if (show_event)
{
sendto_one(client, mtags, ":%s %s %s :%s%s.%s%s%s %s[%s]%s %s",
from_server->name, msgtype, destination,
COLOR_DARKGREY, subsystem, event_id, m->next?"+":"", COLOR_NONE,
log_level_irc_color(loglevel), log_level_valtostring(loglevel), COLOR_NONE,
m->line);
} else {
sendto_one(client, mtags, ":%s %s %s :%s[%s]%s %s",
from_server->name, msgtype, destination,
log_level_irc_color(loglevel), log_level_valtostring(loglevel), COLOR_NONE,
m->line);
}
} else {
if (show_event)
{
sendto_one(client, mtags, ":%s %s %s :%s.%s%s [%s] %s",
from_server->name, msgtype, destination,
subsystem, event_id, m->next?"+":"",
log_level_valtostring(loglevel),
m->line);
} else {
sendto_one(client, mtags, ":%s %s %s :[%s] %s",
from_server->name, msgtype, destination,
log_level_valtostring(loglevel),
m->line);
}
}
safe_free_message_tags(mtags);
}
}
/** Send server notices to IRCOps */
void do_unreal_log_opers(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized, Client *from_server)
{
Client *client;
const char *snomask_destinations, *p;
MessageTag *mtags = NULL, *mtags_loop;
MultiLine *m;
/* If not fully booted then we don't have a logging to snomask mapping so can't do much.. */
if (!loop.booted)
@ -1443,20 +1532,13 @@ void do_unreal_log_opers(LogLevel loglevel, const char *subsystem, const char *e
if (!snomask_destinations)
return;
/* Prepare message tag for those who have CAP unrealircd.org/json-log */
if (json_serialized)
{
mtags = safe_alloc(sizeof(MessageTag));
safe_strdup(mtags->name, "unrealircd.org/json-log");
safe_strdup(mtags->value, json_serialized);
}
/* To specific snomasks... */
list_for_each_entry(client, &oper_list, special_node)
{
const char *operlogin;
ConfigItem_oper *oper;
int colors = iConf.server_notice_colors;
int show_colors = iConf.server_notice_colors;
int show_event = iConf.server_notice_show_event;
if (snomask_destinations)
{
@ -1477,30 +1559,56 @@ void do_unreal_log_opers(LogLevel loglevel, const char *subsystem, const char *e
operlogin = get_operlogin(client);
if (operlogin && (oper = find_oper(operlogin)))
colors = oper->server_notice_colors;
mtags_loop = mtags;
for (m = msg; m; m = m->next)
{
if (colors)
{
sendto_one(client, mtags_loop, ":%s NOTICE %s :%s%s.%s%s%s %s[%s]%s %s",
from_server->name, client->name,
COLOR_DARKGREY, subsystem, event_id, m->next?"+":"", COLOR_NONE,
log_level_irc_color(loglevel), log_level_valtostring(loglevel), COLOR_NONE,
m->line);
} else {
sendto_one(client, mtags_loop, ":%s NOTICE %s :%s.%s%s [%s] %s",
from_server->name, client->name,
subsystem, event_id, m->next?"+":"",
log_level_valtostring(loglevel),
m->line);
}
mtags_loop = NULL; /* this way we only send the JSON in the first msg */
show_colors = oper->server_notice_colors;
show_event = oper->server_notice_show_event;
}
sendto_log(client, "NOTICE", client->name, show_colors, show_event, loglevel, subsystem, event_id, msg, json_serialized, from_server);
}
}
/** Send server notices to channels */
void do_unreal_log_channels(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized, Client *from_server)
{
Log *l;
Member *m;
Client *client;
/* If not fully booted then we don't have a logging to snomask mapping so can't do much.. */
if (!loop.booted)
return;
/* Never send these */
if (!strcmp(subsystem, "rawtraffic"))
return;
for (l = logs[LOG_DEST_CHANNEL]; l; l = l->next)
{
const char *operlogin;
ConfigItem_oper *oper;
Channel *channel;
if (!log_sources_match(l->sources, loglevel, subsystem, event_id, 0))
continue;
channel = find_channel(l->destination);
if (!channel)
continue;
for (m = channel->members; m; m = m->next)
{
Client *client = m->client;
if (!MyUser(client))
continue;
if (l->oper_only && !IsOper(client))
continue;
sendto_log(client, "PRIVMSG", channel->name, l->color, l->show_event,
loglevel, subsystem, event_id, msg,
l->json_message_tag ? json_serialized : NULL,
from_server);
}
}
safe_free_message_tags(mtags);
}
void do_unreal_log_remote(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized)
@ -1522,6 +1630,25 @@ void do_unreal_log_remote(LogLevel loglevel, const char *subsystem, const char *
do_unreal_log_remote_deliver(loglevel, subsystem, event_id, msg, json_serialized);
}
/** Send server notices to control channel */
void do_unreal_log_control(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized, Client *from_server)
{
Client *client;
MultiLine *m;
if (!loop.booted)
return;
/* Never send these */
if (!strcmp(subsystem, "rawtraffic"))
return;
list_for_each_entry(client, &control_list, lclient_node)
if (IsMonitorRehash(client))
for (m = msg; m; m = m->next)
sendto_one(client, NULL, "REPLY [%s] %s", log_level_valtostring(loglevel), m->line);
}
void do_unreal_log_free_args(va_list vl)
{
LogData *d;
@ -1693,17 +1820,24 @@ void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char
/* Convert the message buffer to MultiLine */
mmsg = line2multiline(msgbuf);
/* Now call the disk loggers */
do_unreal_log_disk(loglevel, subsystem, event_id, mmsg, json_serialized);
/* And the ircops stuff */
/* Parse the "from server" info, if any */
t = json_object_get(j_details, "from_server_name");
if (t && (str = json_get_value(t)))
from_server = find_server(str, NULL);
if (from_server == NULL)
from_server = &me;
/* Now call all the loggers: */
do_unreal_log_disk(loglevel, subsystem, event_id, mmsg, json_serialized, from_server);
if ((loop.rehashing == 2) || !strcmp(subsystem, "config"))
do_unreal_log_control(loglevel, subsystem, event_id, mmsg, json_serialized, from_server);
do_unreal_log_opers(loglevel, subsystem, event_id, mmsg, json_serialized, from_server);
do_unreal_log_channels(loglevel, subsystem, event_id, mmsg, json_serialized, from_server);
do_unreal_log_remote(loglevel, subsystem, event_id, mmsg, json_serialized);
// NOTE: code duplication further down!
@ -1723,10 +1857,11 @@ void do_unreal_log_internal_from_remote(LogLevel loglevel, const char *subsystem
unreal_log_recursion_trap = 1;
/* Call the disk loggers */
do_unreal_log_disk(loglevel, subsystem, event_id, msg, json_serialized);
do_unreal_log_disk(loglevel, subsystem, event_id, msg, json_serialized, from_server);
/* And the ircops stuff */
/* And to IRC */
do_unreal_log_opers(loglevel, subsystem, event_id, msg, json_serialized, from_server);
do_unreal_log_channels(loglevel, subsystem, event_id, msg, json_serialized, from_server);
unreal_log_recursion_trap = 0;
}

View File

@ -623,8 +623,8 @@ void exit_client_ex(Client *client, Client *origin, MessageTag *recv_mtags, cons
if (client->local->fd >= 0 && !IsConnecting(client))
{
sendto_one(client, NULL, "ERROR :Closing Link: %s (%s)",
get_client_name(client, FALSE), comment);
if (!IsControl(client))
sendto_one(client, NULL, "ERROR :Closing Link: %s (%s)", get_client_name(client, FALSE), comment);
}
close_connection(client);
}
@ -2369,3 +2369,173 @@ void addlettertodynamicstringsorted(char **str, char letter)
safe_free_raw(*str);
*str = newbuf;
}
void s_die()
{
#ifdef _WIN32
Client *client;
if (!IsService)
{
loop.terminating = 1;
unload_all_modules();
list_for_each_entry(client, &lclient_list, lclient_node)
(void) send_queued(client);
exit(-1);
}
else {
SERVICE_STATUS status;
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
SC_HANDLE hService = OpenService(hSCManager, "UnrealIRCd", SERVICE_STOP);
ControlService(hService, SERVICE_CONTROL_STOP, &status);
}
#else
loop.terminating = 1;
unload_all_modules();
unlink(conf_files ? conf_files->pid_file : IRCD_PIDFILE);
exit(0);
#endif
}
#ifndef _WIN32
void s_rehash()
{
struct sigaction act;
dorehash = 1;
act.sa_handler = s_rehash;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGHUP);
(void)sigaction(SIGHUP, &act, NULL);
}
void s_reloadcert()
{
struct sigaction act;
doreloadcert = 1;
act.sa_handler = s_reloadcert;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGUSR1);
(void)sigaction(SIGUSR1, &act, NULL);
}
#endif // #ifndef _WIN32
void restart(const char *mesg)
{
server_reboot(mesg);
}
void s_restart()
{
dorestart = 1;
}
#ifndef _WIN32
/** Signal handler for signals which we ignore,
* like SIGPIPE ("Broken pipe") and SIGWINCH (terminal window changed) etc.
*/
void ignore_this_signal()
{
struct sigaction act;
act.sa_handler = ignore_this_signal;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGALRM);
(void)sigaddset(&act.sa_mask, SIGPIPE);
(void)sigaction(SIGALRM, &act, (struct sigaction *)NULL);
(void)sigaction(SIGPIPE, &act, (struct sigaction *)NULL);
#ifdef SIGWINCH
(void)sigaddset(&act.sa_mask, SIGWINCH);
(void)sigaction(SIGWINCH, &act, (struct sigaction *)NULL);
#endif
}
#endif /* #ifndef _WIN32 */
void server_reboot(const char *mesg)
{
int i;
Client *client;
unreal_log(ULOG_INFO, "main", "UNREALIRCD_RESTARTING", NULL,
"Restarting server: $reason",
log_data_string("reason", mesg));
list_for_each_entry(client, &lclient_list, lclient_node)
(void) send_queued(client);
/*
* ** fd 0 must be 'preserved' if either the -d or -i options have
* ** been passed to us before restarting.
*/
#ifdef HAVE_SYSLOG
(void)closelog();
#endif
#ifndef _WIN32
for (i = 3; i < MAXCONNECTIONS; i++)
(void)close(i);
if (!(bootopt & (BOOT_TTY | BOOT_DEBUG)))
(void)close(2);
(void)close(1);
(void)close(0);
close_std_descriptors();
(void)execv(MYNAME, myargv);
#else
close_connections();
if (!IsService)
{
CleanUp();
WinExec(cmdLine, SW_SHOWDEFAULT);
}
#endif
unload_all_modules();
#ifdef _WIN32
if (IsService)
{
SERVICE_STATUS status;
PROCESS_INFORMATION pi;
STARTUPINFO si;
char fname[MAX_PATH];
memset(&status, 0, sizeof(status));
memset(&si, 0, sizeof(si));
IRCDStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(IRCDStatusHandle, &IRCDStatus);
GetModuleFileName(GetModuleHandle(NULL), fname, MAX_PATH);
CreateProcess(fname, "restartsvc", NULL, NULL, FALSE,
0, NULL, NULL, &si, &pi);
IRCDStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(IRCDStatusHandle, &IRCDStatus);
ExitProcess(0);
}
else
#endif
exit(-1);
}
/** Check if at least 'minimum' seconds passed by since last run.
* @param tv_old Pointer to a timeval struct to keep track of things.
* @param minimum The time specified in milliseconds (eg: 1000 for 1 second)
* @returns When 'minimum' msec passed 1 is returned and the time is reset, otherwise 0 is returned.
*/
int minimum_msec_since_last_run(struct timeval *tv_old, long minimum)
{
long v;
if (tv_old->tv_sec == 0)
{
/* First call ever */
tv_old->tv_sec = timeofday_tv.tv_sec;
tv_old->tv_usec = timeofday_tv.tv_usec;
return 0;
}
v = ((timeofday_tv.tv_sec - tv_old->tv_sec) * 1000) + ((timeofday_tv.tv_usec - tv_old->tv_usec)/1000);
if (v >= minimum)
{
tv_old->tv_sec = timeofday_tv.tv_sec;
tv_old->tv_usec = timeofday_tv.tv_usec;
return 1;
}
return 0;
}

View File

@ -99,6 +99,7 @@ void blacklist_free_conf(void);
void delete_blacklist_block(Blacklist *e);
void blacklist_md_free(ModData *md);
int blacklist_handshake(Client *client);
int blacklist_ip_change(Client *client, const char *oldip);
int blacklist_quit(Client *client, MessageTag *mtags, const char *comment);
int blacklist_preconnect(Client *client);
void blacklist_resolver_callback(void *arg, int status, int timeouts, struct hostent *he);
@ -146,6 +147,7 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, blacklist_config_run);
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, blacklist_handshake);
HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, 0, blacklist_ip_change);
HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, blacklist_preconnect);
HookAdd(modinfo->handle, HOOKTYPE_REHASH, 0, blacklist_rehash);
HookAdd(modinfo->handle, HOOKTYPE_REHASH_COMPLETE, 0, blacklist_rehash_complete);
@ -553,6 +555,12 @@ int blacklist_handshake(Client *client)
return 0;
}
int blacklist_ip_change(Client *client, const char *oldip)
{
blacklist_start_check(client);
return 0;
}
int blacklist_start_check(Client *client)
{
Blacklist *bl;

View File

@ -73,9 +73,9 @@ int cmode_halfop_is_ok(Client *client, Channel *channel, char mode, const char *
/* User may always remove their own modes */
return EX_ALLOW;
}
if ((what == MODE_ADD) && check_channel_access(client, channel, "hoaq"))
if (check_channel_access(client, channel, "oaq"))
{
/* Permitted for +hoaq */
/* Permitted for +oaq */
return EX_ALLOW;
}
if (type == EXCHK_ACCESS_ERR)

View File

@ -384,10 +384,24 @@ int read_listmode(UnrealDB *db, Ban **lst)
for (i = 0; i < total; i++)
{
const char *str;
e = safe_alloc(sizeof(Ban));
R_SAFE(unrealdb_read_str(db, &e->banstr));
R_SAFE(unrealdb_read_str(db, &e->who));
R_SAFE(unrealdb_read_int64(db, &when));
str = clean_ban_mask(e->banstr, MODE_ADD, &me, 0);
if (str == NULL)
{
/* Skip this item */
config_warn("[channeldb] listmode skipped (no longer valid?): %s", e->banstr);
safe_free(e->banstr);
safe_free(e->who);
safe_free(e);
continue;
}
safe_strdup(e->banstr, str);
/* Add to list */
e->when = when;
e->next = *lst;
*lst = e;

View File

@ -219,7 +219,7 @@ void _userhost_changed(Client *client)
}
}
RunHook(HOOKTYPE_USERHOST_CHANGED, client, remember_user, remember_host);
RunHook(HOOKTYPE_USERHOST_CHANGE, client, remember_user, remember_host);
if (MyUser(client))
{

View File

@ -25,7 +25,7 @@
ModuleHeader MOD_HEADER
= {
"dccdeny",
"5.0",
"6.0.2",
"command /dccdeny",
"UnrealIRCd Team",
"unrealircd-6",
@ -525,11 +525,8 @@ int dccdeny_can_send_to_channel(Client *client, Channel *channel, Membership *lp
const char *filename = get_dcc_filename(*msg);
if (filename && !can_dcc(client, channel->name, NULL, filename, &err))
{
if (!IsDead(client) && (sendtype != SEND_TYPE_NOTICE))
{
strlcpy(errbuf, err, sizeof(errbuf));
*errmsg = errbuf;
}
strlcpy(errbuf, err, sizeof(errbuf));
*errmsg = errbuf;
return HOOK_DENY;
}
}
@ -649,7 +646,11 @@ static int can_dcc(Client *client, const char *target, Client *targetcli, const
}
if (match_spamfilter(client, filename, SPAMF_DCC, "PRIVMSG", target, 0, NULL))
{
/* Dirty hack, yeah spamfilter already sent the error message :( */
*errmsg = "";
return 0;
}
if ((fl = dcc_isforbidden(client, filename)))
{

View File

@ -43,7 +43,7 @@ MOD_INIT()
req.conv_param = extban_realname_conv_param;
req.is_banned = extban_realname_is_banned;
req.is_banned_events = BANCHK_ALL|BANCHK_TKL;
req.options = EXTBOPT_CHSVSMODE|EXTBOPT_INVEX|EXTBOPT_TKL;
req.options = EXTBOPT_INVEX|EXTBOPT_TKL;
if (!ExtbanAdd(modinfo->handle, req))
{
config_error("could not register extended ban type");

View File

@ -78,7 +78,6 @@ MOD_INIT()
extban.letter = 't';
extban.name = "time";
extban.options |= EXTBOPT_ACTMODIFIER; /* not really, but ours shouldn't be stacked from group 1 */
extban.options |= EXTBOPT_CHSVSMODE; /* so "SVSMODE -nick" will unset affected ~t extbans */
extban.options |= EXTBOPT_INVEX; /* also permit timed invite-only exceptions (+I) */
extban.conv_param = timedban_extban_conv_param;
extban.is_ok = timedban_extban_is_ok;

View File

@ -26,8 +26,8 @@ long CAP_EXTENDED_MONITOR = 0L;
int extended_monitor_away(Client *client, MessageTag *mtags, const char *reason, int already_as_away);
int extended_monitor_account_login(Client *client, MessageTag *mtags);
int extended_monitor_userhost_changed(Client *client, const char *olduser, const char *oldhost);
int extended_monitor_realname_changed(Client *client, const char *oldinfo);
int extended_monitor_userhost_change(Client *client, const char *olduser, const char *oldhost);
int extended_monitor_realname_change(Client *client, const char *oldinfo);
int extended_monitor_notification(Client *client, Watch *watch, Link *lp, int event);
ModuleHeader MOD_HEADER
@ -59,8 +59,8 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_AWAY, 0, extended_monitor_away);
HookAdd(modinfo->handle, HOOKTYPE_ACCOUNT_LOGIN, 0, extended_monitor_account_login);
HookAdd(modinfo->handle, HOOKTYPE_USERHOST_CHANGED, 0, extended_monitor_userhost_changed);
HookAdd(modinfo->handle, HOOKTYPE_REALNAME_CHANGED, 0, extended_monitor_realname_changed);
HookAdd(modinfo->handle, HOOKTYPE_USERHOST_CHANGE, 0, extended_monitor_userhost_change);
HookAdd(modinfo->handle, HOOKTYPE_REALNAME_CHANGE, 0, extended_monitor_realname_change);
return MOD_SUCCESS;
}
@ -95,13 +95,13 @@ int extended_monitor_account_login(Client *client, MessageTag *mtags)
return 0;
}
int extended_monitor_userhost_changed(Client *client, const char *olduser, const char *oldhost)
int extended_monitor_userhost_change(Client *client, const char *olduser, const char *oldhost)
{
watch_check(client, WATCH_EVENT_USERHOST, extended_monitor_notification);
return 0;
}
int extended_monitor_realname_changed(Client *client, const char *oldinfo)
int extended_monitor_realname_change(Client *client, const char *oldinfo)
{
watch_check(client, WATCH_EVENT_REALNAME, extended_monitor_notification);
return 0;

View File

@ -25,6 +25,7 @@ void geoip_base_free(ModData *m);
const char *geoip_base_serialize(ModData *m);
void geoip_base_unserialize(const char *str, ModData *m);
int geoip_base_handshake(Client *client);
int geoip_base_ip_change(Client *client, const char *oldip);
int geoip_base_whois(Client *client, Client *target, NameValuePrioList **list);
int geoip_connect_extinfo(Client *client, NameValuePrioList **list);
int geoip_base_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
@ -119,10 +120,10 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, geoip_base_configrun);
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, geoip_base_handshake);
HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, 0, geoip_base_ip_change);
HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, geoip_base_handshake);
HookAdd(modinfo->handle, HOOKTYPE_CONNECT_EXTINFO, 1, geoip_connect_extinfo); /* (prio: near-first) */
HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0,geoip_base_handshake); /* in case the IP changed in registration phase (WEBIRC, HTTP Forwarded) */
HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CONNECT, 0, geoip_base_handshake); /* remote user */
HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, geoip_base_whois);
CommandAdd(modinfo->handle, "GEOIP", cmd_geoip, MAXPARA, CMD_USER);
@ -167,6 +168,12 @@ int geoip_base_handshake(Client *client)
return 0;
}
int geoip_base_ip_change(Client *client, const char *oldip)
{
geoip_base_handshake(client);
return 0;
}
void geoip_base_free(ModData *m)
{
if (m->ptr)
@ -229,12 +236,13 @@ void geoip_base_unserialize(const char *str, ModData *m)
m->ptr = res;
}
EVENT(geoip_base_set_existing_users_evt){
EVENT(geoip_base_set_existing_users_evt)
{
Client *client;
list_for_each_entry(client, &client_list, client_node){
if (!IsUser(client))
continue;
geoip_base_handshake(client);
list_for_each_entry(client, &client_list, client_node)
{
if (MyUser(client))
geoip_base_handshake(client);
}
}

View File

@ -43,6 +43,22 @@ static ModuleInfo *MyModInfo;
#define MyMod MyModInfo->handle
#define SAVE_MODINFO MyModInfo = modinfo;
static int lmax = 0;
static int umax = 0;
static int dcount(int n)
{
int cnt = 0;
while (n != 0)
{
n = n/10;
cnt++;
}
return cnt;
}
ModuleHeader MOD_HEADER
= {
"hideserver",
@ -230,8 +246,24 @@ static void dump_map(Client *client, Client *server, char *mask, int prompt_leng
sendnumeric(client, RPL_MAPMORE, prompt, length, server->name);
else
{
sendnumeric(client, RPL_MAP, prompt,
length, server->name, server->server->users, IsOper(client) ? server->id : "");
char tbuf[256];
char sid[10];
int len = length - strlen(server->name) + 1;
if (len < 0)
len = 0;
if (len > 255)
len = 255;
tbuf[len--] = '\0';
while (len >= 0)
tbuf[len--] = '-';
if (IsOper(client))
snprintf(sid, sizeof(sid), " [%s]", server->id);
sendnumeric(client, RPL_MAP, prompt, server->name, tbuf, umax,
server->server->users, (double)(lmax < 10) ? 4 : (lmax == 100) ? 6 : 5,
(server->server->users * 100.0 / irccounts.clients),
IsOper(client) ? sid : "");
cnt = 0;
}
@ -279,12 +311,25 @@ static void dump_map(Client *client, Client *server, char *mask, int prompt_leng
void dump_flat_map(Client *client, Client *server, int length)
{
char buf[4];
char tbuf[256];
Client *acptr;
int cnt = 0, hide_ulines;
int cnt = 0, len = 0, hide_ulines;
hide_ulines = (HIDE_ULINES && !ValidatePermissionsForPath("server:info:map:ulines",client,NULL,NULL,NULL)) ? 1 : 0;
sendnumeric(client, RPL_MAP, "", length, server->name, server->server->users, "");
len = length - strlen(server->name) + 3;
if (len < 0)
len = 0;
if (len > 255)
len = 255;
tbuf[len--] = '\0';
while (len >= 0)
tbuf[len--] = '-';
sendnumeric(client, RPL_MAP, "", server->name, tbuf, umax, server->server->users,
(lmax < 10) ? 4 : (lmax == 100) ? 6 : 5,
(server->server->users * 100.0 / irccounts.clients), "");
list_for_each_entry(acptr, &global_server_list, client_node)
{
@ -304,7 +349,20 @@ void dump_flat_map(Client *client, Client *server, int length)
break;
if (--cnt == 0)
*buf = '`';
sendnumeric(client, RPL_MAP, buf, length-2, acptr->name, acptr->server->users, "");
len = length - strlen(acptr->name) + 1;
if (len < 0)
len = 0;
if (len > 255)
len = 255;
tbuf[len--] = '\0';
while (len >= 0)
tbuf[len--] = '-';
sendnumeric(client, RPL_MAP, buf, acptr->name, tbuf, umax, acptr->server->users,
(lmax < 10) ? 4 : (lmax == 100) ? 6 : 5,
(acptr->server->users * 100.0 / irccounts.clients), "");
}
}
@ -318,6 +376,10 @@ CMD_OVERRIDE_FUNC(override_map)
{
Client *acptr;
int longest = strlen(me.name);
float avg_users = 0.0;
umax = 0;
lmax = 0;
if (parc < 2)
parv[1] = "*";
@ -339,10 +401,16 @@ CMD_OVERRIDE_FUNC(override_map)
list_for_each_entry(acptr, &global_server_list, client_node)
{
int perc = 0;
if (FindHiddenServer(acptr->name))
break;
perc = (acptr->server->users * 100 / irccounts.clients);
if ((strlen(acptr->name) + acptr->hopcount * 2) > longest)
longest = strlen(acptr->name) + acptr->hopcount * 2;
if (lmax < perc)
lmax = perc;
if (umax < dcount(acptr->server->users))
umax = dcount(acptr->server->users);
}
if (longest > 60)
@ -354,6 +422,9 @@ CMD_OVERRIDE_FUNC(override_map)
else
dump_map(client, &me, "*", 0, longest);
avg_users = irccounts.clients * 1.0 / irccounts.servers;
sendnumeric(client, RPL_MAPUSERS, irccounts.servers, (irccounts.servers > 1 ? "s" : ""), irccounts.clients,
(irccounts.clients > 1 ? "s" : ""), avg_users);
sendnumeric(client, RPL_MAPEND);
}

View File

@ -196,7 +196,7 @@ int lr_post_command(Client *from, MessageTag *mtags, const char *buf)
*/
int more_tags = currentcmd.firstbuf[0] == '@';
currentcmd.client = NULL; /* prevent lr_packet from interfering */
snprintf(packet, sizeof(packet),
snprintf(packet, sizeof(packet)-3,
"@label=%s%s%s\r\n",
currentcmd.label,
more_tags ? ";" : " ",

View File

@ -31,7 +31,7 @@ ModuleHeader MOD_HEADER
= {
"list",
"5.0",
"command /list",
"command /LIST",
"UnrealIRCd Team",
"unrealircd-6",
};
@ -136,8 +136,8 @@ CMD_FUNC(cmd_list)
"use, and what channels LIST will return when you use them.",
">number List channels with more than <number> people.",
"<number List channels with less than <number> people.",
"C>number List channels created between now and <number> minutes ago.",
"C<number List channels created earlier than <number> minutes ago.",
"C>number List channels created more than <number> minutes ago.",
"C<number List channels created less than <number> minutes ago.",
"T>number List channels whose topics are older than <number> minutes",
" (Ie, they have not changed in the last <number> minutes.",
"T<number List channels whose topics are not older than <number> minutes.",
@ -199,56 +199,52 @@ CMD_FUNC(cmd_list)
}
switch (*name)
{
case '<':
usermax = atoi(name + 1) - 1;
doall = 1;
break;
case '>':
usermin = atoi(name + 1) + 1;
doall = 1;
break;
case 'C':
case 'c': /* Channel time -- creation time? */
++name;
switch (*name++)
{
case '<':
chantimemax = currenttime - 60 * atoi(name);
doall = 1;
break;
case '>':
chantimemin = currenttime - 60 * atoi(name);
doall = 1;
break;
default:
sendnumeric(client, ERR_LISTSYNTAX);
error = 1;
}
break;
#ifdef LIST_USE_T
case 'T':
case 't':
++name;
switch (*name++)
{
case '<':
topictimemax =
currenttime - 60 * atoi(name);
doall = 1;
break;
case '>':
topictimemin =
currenttime - 60 * atoi(name);
doall = 1;
break;
default:
sendnumeric(client, ERR_LISTSYNTAX,
"Bad list syntax, type /list ?");
error = 1;
}
break;
#endif
default: /* A channel, possibly with wildcards.
case '<':
usermax = atoi(name + 1) - 1;
doall = 1;
break;
case '>':
usermin = atoi(name + 1) + 1;
doall = 1;
break;
case 'C':
case 'c': /* Channel time -- creation time? */
++name;
switch (*name++)
{
case '<':
chantimemin = currenttime - 60 * atoi(name);
doall = 1;
break;
case '>':
chantimemax = currenttime - 60 * atoi(name);
doall = 1;
break;
default:
sendnumeric(client, ERR_LISTSYNTAX);
error = 1;
}
break;
case 'T':
case 't':
++name;
switch (*name++)
{
case '<':
topictimemin = currenttime - 60 * atoi(name);
doall = 1;
break;
case '>':
topictimemax = currenttime - 60 * atoi(name);
doall = 1;
break;
default:
sendnumeric(client, ERR_LISTSYNTAX);
error = 1;
}
break;
default:
/* A channel, possibly with wildcards.
* Thought for the future: Consider turning wildcard
* processing on the fly.
* new syntax: !channelmask will tell ircd to ignore
@ -259,35 +255,38 @@ CMD_FUNC(cmd_list)
* channel even if any of the !channelmask masks
* matches it.
*/
if (*name == '!')
{
doall = 1;
add_name_list(nolist, name + 1);
}
else if (strchr(name, '*') || strchr(name, '?'))
{
doall = 1;
add_name_list(yeslist, name);
}
else /* Just a normal channel */
{
channel = find_channel(name);
if (channel && (ShowChannel(client, channel) || ValidatePermissionsForPath("channel:see:list:secret",client,NULL,channel,NULL))) {
modebuf[0] = '[';
channel_modes(client, modebuf+1, parabuf, sizeof(modebuf)-1, sizeof(parabuf), channel, 0);
if (modebuf[2] == '\0')
modebuf[0] = '\0';
else
strlcat(modebuf, "]", sizeof modebuf);
sendnumeric(client, RPL_LIST,
name, channel->users,
modebuf,
(channel->topic ? channel->topic :
""));
}
}
} /* switch */
} /* while */
if (*name == '!')
{
/* Negative matching by name */
doall = 1;
add_name_list(nolist, name + 1);
}
else if (strchr(name, '*') || strchr(name, '?'))
{
/* Channel with wildcards */
doall = 1;
add_name_list(yeslist, name);
}
else
{
/* A specific channel name without wildcards */
channel = find_channel(name);
if (channel && (ShowChannel(client, channel) || ValidatePermissionsForPath("channel:see:list:secret",client,NULL,channel,NULL)))
{
modebuf[0] = '[';
channel_modes(client, modebuf+1, parabuf, sizeof(modebuf)-1, sizeof(parabuf), channel, 0);
if (modebuf[2] == '\0')
modebuf[0] = '\0';
else
strlcat(modebuf, "]", sizeof modebuf);
sendnumeric(client, RPL_LIST, name, channel->users, modebuf,
channel->topic ? channel->topic : "");
}
}
} /* switch */
} /* for */
if (doall)
{
@ -335,7 +334,7 @@ int send_list(Client *client)
* choice of numsend. -Rak
*/
/* Begin of /list? then send official channels. */
/* Begin of /LIST? then send official channels first. */
if ((lopt->starthash == 0) && conf_offchans)
{
ConfigItem_offchans *x;
@ -343,18 +342,15 @@ int send_list(Client *client)
{
if (find_channel(x->name))
continue; /* exists, >0 users.. will be sent later */
sendnumeric(client, RPL_LIST, x->name,
0,
"",
x->topic ? x->topic : "");
sendnumeric(client, RPL_LIST, x->name, 0, "",
x->topic ? x->topic : "");
}
}
for (hashnum = lopt->starthash; hashnum < CHAN_HASH_TABLE_SIZE; hashnum++)
{
if (numsend > 0)
for (channel = hash_get_chan_bucket(hashnum);
channel; channel = channel->hnextch)
for (channel = hash_get_chan_bucket(hashnum); channel; channel = channel->hnextch)
{
if (SecretChannel(channel)
&& !IsMember(client, channel)
@ -373,15 +369,13 @@ int send_list(Client *client)
if ((!lopt->showall))
{
/* User count must be in range */
if ((channel->users < lopt->usermin) ||
((lopt->usermax >= 0) && (channel->users >
lopt->usermax)))
if ((channel->users < lopt->usermin) ||
((lopt->usermax >= 0) && (channel->users > lopt->usermax)))
continue;
/* Creation time must be in range */
if ((channel->creationtime && (channel->creationtime <
lopt->chantimemin)) || (channel->creationtime >
lopt->chantimemax))
if ((channel->creationtime && (channel->creationtime < lopt->chantimemin)) ||
(channel->creationtime > lopt->chantimemax))
continue;
/* Topic time must be in range */
@ -432,7 +426,7 @@ int send_list(Client *client)
return 0;
}
/*
/*
* We've exceeded the limit on the number of channels to send back
* at once.
*/

View File

@ -26,6 +26,22 @@ CMD_FUNC(cmd_map);
#define MSG_MAP "MAP"
static int lmax = 0;
static int umax = 0;
static int dcount(int n)
{
int cnt = 0;
while (n != 0)
{
n = n/10;
cnt++;
}
return cnt;
}
ModuleHeader MOD_HEADER
= {
"map",
@ -70,8 +86,24 @@ static void dump_map(Client *client, Client *server, char *mask, int prompt_leng
sendnumeric(client, RPL_MAPMORE, prompt, length, server->name);
else
{
sendnumeric(client, RPL_MAP, prompt,
length, server->name, server->server->users, IsOper(client) ? server->id : "");
char tbuf[256];
char sid[10];
int len = length - strlen(server->name) + 1;
if (len < 0)
len = 0;
if (len > 255)
len = 255;
tbuf[len--] = '\0';
while (len >= 0)
tbuf[len--] = '-';
if (IsOper(client))
snprintf(sid, sizeof(sid), " [%s]", server->id);
sendnumeric(client, RPL_MAP, prompt, server->name, tbuf, umax,
server->server->users, (double)(lmax < 10) ? 4 : (lmax == 100) ? 6 : 5,
(server->server->users * 100.0 / irccounts.clients),
IsOper(client) ? sid : "");
cnt = 0;
}
@ -115,12 +147,25 @@ static void dump_map(Client *client, Client *server, char *mask, int prompt_leng
void dump_flat_map(Client *client, Client *server, int length)
{
char buf[4];
char tbuf[256];
Client *acptr;
int cnt = 0, hide_ulines;
int cnt = 0, len = 0, hide_ulines;
hide_ulines = (HIDE_ULINES && !ValidatePermissionsForPath("server:info:map:ulines",client,NULL,NULL,NULL)) ? 1 : 0;
sendnumeric(client, RPL_MAP, "", length, server->name, server->server->users, "");
len = length - strlen(server->name) + 3;
if (len < 0)
len = 0;
if (len > 255)
len = 255;
tbuf[len--] = '\0';
while (len >= 0)
tbuf[len--] = '-';
sendnumeric(client, RPL_MAP, "", server->name, tbuf, umax, server->server->users,
(lmax < 10) ? 4 : (lmax == 100) ? 6 : 5,
(server->server->users * 100.0 / irccounts.clients), "");
list_for_each_entry(acptr, &global_server_list, client_node)
{
@ -136,7 +181,20 @@ void dump_flat_map(Client *client, Client *server, int length)
continue;
if (--cnt == 0)
*buf = '`';
sendnumeric(client, RPL_MAP, buf, length-2, acptr->name, acptr->server->users, "");
len = length - strlen(acptr->name) + 1;
if (len < 0)
len = 0;
if (len > 255)
len = 255;
tbuf[len--] = '\0';
while (len >= 0)
tbuf[len--] = '-';
sendnumeric(client, RPL_MAP, buf, acptr->name, tbuf, umax, acptr->server->users,
(lmax < 10) ? 4 : (lmax == 100) ? 6 : 5,
(acptr->server->users * 100.0 / irccounts.clients), "");
}
}
@ -150,14 +208,23 @@ CMD_FUNC(cmd_map)
{
Client *acptr;
int longest = strlen(me.name);
float avg_users;
umax = 0;
lmax = 0;
if (parc < 2)
parv[1] = "*";
list_for_each_entry(acptr, &global_server_list, client_node)
{
int perc = (acptr->server->users * 100 / irccounts.clients);
if ((strlen(acptr->name) + acptr->hopcount * 2) > longest)
longest = strlen(acptr->name) + acptr->hopcount * 2;
if (lmax < perc)
lmax = perc;
if (umax < dcount(acptr->server->users))
umax = dcount(acptr->server->users);
}
if (longest > 60)
@ -169,5 +236,8 @@ CMD_FUNC(cmd_map)
else
dump_map(client, &me, "*", 0, longest);
avg_users = irccounts.clients * 1.0 / irccounts.servers;
sendnumeric(client, RPL_MAPUSERS, irccounts.servers, (irccounts.servers > 1 ? "s" : ""), irccounts.clients,
(irccounts.clients > 1 ? "s" : ""), avg_users);
sendnumeric(client, RPL_MAPEND);
}

View File

@ -37,7 +37,7 @@ long CAP_MESSAGE_TAGS = 0; /**< Looked up at MOD_LOAD, may stay 0 if message-tag
ModuleHeader MOD_HEADER
= {
"message", /* Name of module */
"5.0", /* Version */
"6.0.2", /* Version */
"private message and notice", /* Short description of module */
"UnrealIRCd Team",
"unrealircd-6",
@ -318,7 +318,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, const char *p
*/
if (IsDead(client))
return;
if (!IsDead(client) && (sendtype != SEND_TYPE_NOTICE) && errmsg)
if (!IsDead(client) && (sendtype != SEND_TYPE_NOTICE) && !BadPtr(errmsg))
sendnumeric(client, ERR_CANNOTSENDTOCHAN, channel->name, errmsg, p2);
continue; /* skip delivery to this target */
}
@ -423,7 +423,7 @@ void cmd_message(Client *client, MessageTag *recv_mtags, int parc, const char *p
/* Message is discarded */
if (IsDead(client))
return;
if ((sendtype != SEND_TYPE_NOTICE) && errmsg)
if ((sendtype != SEND_TYPE_NOTICE) && !BadPtr(errmsg))
sendnumeric(client, ERR_CANTSENDTOUSER, target->name, errmsg);
} else
{

View File

@ -370,28 +370,19 @@ void _do_mode(Channel *channel, Client *client, MessageTag *recv_mtags, int parc
":%s MODE %s %s %s",
client->name, channel->name, modebuf, parabuf);
if (IsServer(client) && sendts != -1)
if (IsServer(client) || IsMe(client))
{
sendto_server(client, 0, 0, mtags,
":%s MODE %s %s %s %lld",
client->id, channel->name,
modebuf, parabuf,
(long long)sendts);
} else
if (samode && IsMe(client))
{
/* SAMODE is a special case: always send a TS of 0 (omitting TS==desync) */
sendto_server(client, 0, 0, mtags,
":%s MODE %s %s %s 0",
client->id, channel->name,
modebuf, parabuf);
(sendts != -1) ? (long long)sendts : 0LL);
} else
{
sendto_server(client, 0, 0, mtags,
":%s MODE %s %s %s",
client->id, channel->name,
modebuf, parabuf);
/* tell them it's not a timestamp, in case the last param is a number. */
}
if (MyConnect(client))
@ -1159,6 +1150,22 @@ CMD_FUNC(_cmd_umode)
goto def;
case 't':
case 'x':
/* set::anti-flood::vhost-flood */
if (MyUser(client))
{
if ((what == MODE_DEL) && !ValidatePermissionsForPath("immune:vhost-flood",client,NULL,NULL,NULL) &&
flood_limit_exceeded(client, FLD_VHOST))
{
/* Throttle... */
if (!modex_err)
{
sendnotice(client, "*** Setting -%c too fast. Please try again later.", *m);
modex_err = 1;
}
break;
}
}
switch (UHOST_ALLOWED)
{
case UHALLOW_ALWAYS:

View File

@ -141,6 +141,7 @@ CMD_FUNC(reputationunperm);
int reputation_whois(Client *client, Client *target, NameValuePrioList **list);
int reputation_set_on_connect(Client *client);
int reputation_pre_lconnect(Client *client);
int reputation_ip_change(Client *client, const char *oldip);
int reputation_connect_extinfo(Client *client, NameValuePrioList **list);
int reputation_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
int reputation_config_run(ConfigFile *cf, ConfigEntry *ce, int type);
@ -192,6 +193,7 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, reputation_config_run);
HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, reputation_whois);
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, reputation_set_on_connect);
HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, 0, reputation_ip_change);
HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 2000000000, reputation_pre_lconnect); /* (prio: last) */
HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CONNECT, -1000000000, reputation_set_on_connect); /* (prio: near-first) */
HookAdd(modinfo->handle, HOOKTYPE_CONNECT_EXTINFO, 0, reputation_connect_extinfo); /* (prio: near-first) */
@ -804,6 +806,12 @@ int reputation_set_on_connect(Client *client)
return 0;
}
int reputation_ip_change(Client *client, const char *oldip)
{
reputation_lookup_score_and_set(client);
return 0;
}
int reputation_pre_lconnect(Client *client)
{
/* User will likely be accepted. Inform other servers about the score

View File

@ -170,9 +170,9 @@ CMD_FUNC(cmd_sapart)
if (comment)
{
snprintf(commentx, sizeof(commentx), "SAPart: %s", comment);
//sendnotice(target, "*** You were forced to part %s (%s)", request, commentx);
sendnotice(target, "*** You were forced to part %s (%s)", request, commentx);
} else {
//sendnotice(target, "*** You were forced to part %s", request);
sendnotice(target, "*** You were forced to part %s", request);
}
parv[0] = target->name; // nick

View File

@ -158,5 +158,5 @@ CMD_FUNC(cmd_setname)
}
free_message_tags(mtags);
RunHook(HOOKTYPE_REALNAME_CHANGED, client, oldinfo);
RunHook(HOOKTYPE_REALNAME_CHANGE, client, oldinfo);
}

View File

@ -520,17 +520,17 @@ int stats_command(Client *client, const char *para)
int stats_oper(Client *client, const char *para)
{
ConfigItem_oper *oper_p;
ConfigItem_oper *o;
ConfigItem_mask *m;
for (oper_p = conf_oper; oper_p; oper_p = oper_p->next)
for (o = conf_oper; o; o = o->next)
{
for (m = oper_p->mask; m; m = m->next)
for (m = o->mask; m; m = m->next)
{
sendnumeric(client, RPL_STATSOLINE,
'O', m->mask, oper_p->name,
"-",
oper_p->class->name? oper_p->class->name : "");
sendnumeric(client, RPL_STATSOLINE,
'O', m->mask, o->name,
o->operclass ? o->operclass: "",
o->class->name ? o->class->name : "");
}
}
return 0;
@ -540,11 +540,20 @@ static char *stats_port_helper(ConfigItem_listen *listener)
{
static char buf[256];
ircsnprintf(buf, sizeof(buf), "%s%s%s%s",
ircsnprintf(buf, sizeof(buf), "%s%s%s",
(listener->options & LISTENER_CLIENTSONLY)? "clientsonly ": "",
(listener->options & LISTENER_SERVERSONLY)? "serversonly ": "",
(listener->options & LISTENER_TLS)? "tls ": "",
!(listener->options & LISTENER_TLS)? "plaintext ": "");
(listener->options & LISTENER_DEFER_ACCEPT)? "defer-accept ": "");
/* And one of these.. */
if (listener->options & LISTENER_CONTROL)
strlcat(buf, "control ", sizeof(buf));
else if (listener->socket_type == SOCKET_TYPE_UNIX)
;
else if (listener->options & LISTENER_TLS)
strlcat(buf, "tls ", sizeof(buf));
else
strlcat(buf, "plaintext ", sizeof(buf));
return buf;
}
@ -558,13 +567,22 @@ int stats_port(Client *client, const char *para)
continue;
if ((listener->options & LISTENER_SERVERSONLY) && !ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL))
continue;
sendnotice(client, "*** Listener on %s:%i (%s): has %i client(s), options: %s %s",
listener->ip,
listener->port,
listener->ipv6 ? "IPv6" : "IPv4",
listener->clients,
stats_port_helper(listener),
listener->flag.temporary ? "[TEMPORARY]" : "");
if (listener->socket_type == SOCKET_TYPE_UNIX)
{
sendnotice(client, "*** Listener on %s (UNIX): has %i client(s), options: %s %s",
listener->file,
listener->clients,
stats_port_helper(listener),
listener->flag.temporary ? "[TEMPORARY]" : "");
} else {
sendnotice(client, "*** Listener on %s:%i (%s): has %i client(s), options: %s %s",
listener->ip,
listener->port,
listener->socket_type == SOCKET_TYPE_IPV6 ? "IPv6" : "IPv4",
listener->clients,
stats_port_helper(listener),
listener->flag.temporary ? "[TEMPORARY]" : "");
}
}
return 0;
}

View File

@ -136,7 +136,7 @@ void unban_user(Client *client, Channel *channel, Client *acptr, char chmode)
}
else if (chmode != 'I' && *ban->banstr == '~' && (extban = findmod_by_bantype(ban->banstr, &nextbanstr)))
{
if ((extban->options & EXTBOPT_CHSVSMODE) && (extban->is_banned_events & b->ban_check_types))
if (extban->is_banned_events & b->ban_check_types)
{
b->banstr = nextbanstr;
if (extban->is_banned(b))
@ -176,7 +176,7 @@ void clear_bans(Client *client, Channel *channel, char chmode)
bnext = ban->next;
if (chmode != 'I' && (*ban->banstr == '~') && (extban = findmod_by_bantype(ban->banstr, NULL)))
{
if (!(extban->options & EXTBOPT_CHSVSMODE))
if (!(extban->is_banned_events & BANCHK_JOIN))
continue;
}
add_send_mode_param(channel, client, '-', chmode, ban->banstr);
@ -298,7 +298,7 @@ void channel_svsmode(Client *client, int parc, const char *parv[])
sendto_channel(channel, client, client, 0, 0, SEND_LOCAL, mtags,
":%s MODE %s %s %s",
client->name, channel->name, modebuf, parabuf);
sendto_server(NULL, 0, 0, mtags, ":%s MODE %s %s %s", client->id, channel->name, modebuf, parabuf);
sendto_server(NULL, 0, 0, mtags, ":%s MODE %s %s %s%s", client->id, channel->name, modebuf, parabuf, IsServer(client)?" 0":"");
/* Activate this hook just like cmd_mode.c */
RunHook(HOOKTYPE_REMOTE_CHANMODE, client, channel, mtags, modebuf, parabuf, 0, 0, &destroy_channel);
@ -615,7 +615,7 @@ void add_send_mode_param(Channel *channel, Client *from, char what, char mode, c
sendto_channel(channel, from, from, 0, 0, SEND_LOCAL, mtags,
":%s MODE %s %s %s",
from->name, channel->name, modebuf, parabuf);
sendto_server(NULL, 0, 0, mtags, ":%s MODE %s %s %s", from->id, channel->name, modebuf, parabuf);
sendto_server(NULL, 0, 0, mtags, ":%s MODE %s %s %s%s", from->id, channel->name, modebuf, parabuf, IsServer(from)?" 0":"");
free_message_tags(mtags);
send = 0;
*parabuf = 0;

View File

@ -41,6 +41,7 @@ int tkl_config_test_except(ConfigFile *, ConfigEntry *, int, int *);
int tkl_config_run_except(ConfigFile *, ConfigEntry *, int);
int tkl_config_test_set(ConfigFile *, ConfigEntry *, int, int *);
int tkl_config_run_set(ConfigFile *, ConfigEntry *, int);
int tkl_ip_change(Client *client, const char *oldip);
CMD_FUNC(cmd_gline);
CMD_FUNC(cmd_shun);
CMD_FUNC(cmd_tempshun);
@ -213,6 +214,7 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_ban);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_except);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_set);
HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, 2000000000, tkl_ip_change);
CommandAdd(modinfo->handle, "GLINE", cmd_gline, 3, CMD_OPER);
CommandAdd(modinfo->handle, "SHUN", cmd_shun, 3, CMD_OPER);
CommandAdd(modinfo->handle, "TEMPSHUN", cmd_tempshun, 2, CMD_OPER);
@ -952,6 +954,12 @@ char *spamfilter_id(TKL *tk)
return buf;
}
int tkl_ip_change(Client *client, const char *oldip)
{
check_banned(client, 0);
return 0;
}
/** GLINE - Global kline.
** Syntax: /gline [+|-]u@h mask time :reason
**
@ -4772,23 +4780,15 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
if (ret)
{
/* We have a match! */
char destinationbuf[48];
if (destination) {
destinationbuf[0] = ' ';
strlcpy(destinationbuf+1, destination, sizeof(destinationbuf)-1); /* cut it off */
} else
destinationbuf[0] = '\0';
/* Hold on.. perhaps it's on the exceptions list... */
/* We have a match! But.. perhaps it's on the exceptions list? */
if (!winner_tkl && destination && target_is_spamexcept(destination))
return 0; /* No problem! */
unreal_log(ULOG_INFO, "tkl", "SPAMFILTER_MATCH", client,
"[Spamfilter] $client.details matches filter '$tkl': [cmd: $command$destination: '$str'] [reason: $tkl.reason] [action: $tkl.ban_action]",
"[Spamfilter] $client.details matches filter '$tkl': [cmd: $command$_space$destination: '$str'] [reason: $tkl.reason] [action: $tkl.ban_action]",
log_data_tkl("tkl", tkl),
log_data_string("command", cmd),
log_data_string("_space", destination ? " " : ""),
log_data_string("destination", destination ? destination : ""),
log_data_string("str", str));

View File

@ -29,9 +29,9 @@
ModDataInfo *watchCounterMD;
ModDataInfo *watchListMD;
static Watch *watchTable[WATCH_HASH_TABLE_SIZE];
static int watch_initialized = 0;
static char siphashkey_watch[SIPHASH_KEY_LENGTH];
static Watch **watchTable = NULL;
static char *siphashkey_watch = NULL;
void dummy_free(ModData *md);
void watch_free(ModData *md);
@ -47,8 +47,8 @@ uint64_t hash_watch_nick_name(const char *name);
ModuleHeader MOD_HEADER
= {
"watch-backend",
"5.0",
"backend for /watch",
"6.0.3",
"backend for /WATCH",
"UnrealIRCd Team",
"unrealircd-6",
};
@ -65,20 +65,28 @@ MOD_TEST()
return MOD_SUCCESS;
}
void watch_generic_free(ModData *m)
{
safe_free(m->ptr);
}
MOD_INIT()
{
ModDataInfo mreq;
MARK_AS_OFFICIAL_MODULE(modinfo);
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM_RELOADABLE, 1); /* or do a complex memory freeing algorithm instead */
if (!watch_initialized)
LoadPersistentPointer(modinfo, siphashkey_watch, watch_generic_free);
if (siphashkey_watch == NULL)
{
memset(watchTable, 0, sizeof(watchTable));
siphashkey_watch = safe_alloc(SIPHASH_KEY_LENGTH);
siphash_generate_key(siphashkey_watch);
watch_initialized = 1;
}
LoadPersistentPointer(modinfo, watchTable, watch_generic_free);
if (watchTable == NULL)
watchTable = safe_alloc(sizeof(Watch) * WATCH_HASH_TABLE_SIZE);
memset(&mreq, 0 , sizeof(mreq));
mreq.type = MODDATATYPE_LOCAL_CLIENT;
mreq.name = "watchCount",
@ -113,6 +121,8 @@ MOD_LOAD()
MOD_UNLOAD()
{
SavePersistentPointer(modinfo, siphashkey_watch);
SavePersistentPointer(modinfo, watchTable);
return MOD_SUCCESS;
}
@ -151,13 +161,13 @@ int _watch_add(char *nick, Client *client, int flags)
hashv = hash_watch_nick_name(nick);
/* Find the right nick (header) in the bucket, or NULL... */
if ((watch = (Watch *)watchTable[hashv]))
if ((watch = watchTable[hashv]))
while (watch && mycmp(watch->nick, nick))
watch = watch->hnext;
/* If found NULL (no header for this nick), make one... */
if (!watch) {
watch = (Watch *)safe_alloc(sizeof(Watch)+strlen(nick));
watch = safe_alloc(sizeof(Watch)+strlen(nick));
watch->lasttime = timeofday;
strcpy(watch->nick, nick);
@ -203,7 +213,7 @@ int _watch_check(Client *client, int event, int (*watch_notify)(Client *client,
hashv = hash_watch_nick_name(client->name);
/* Find the right header in this bucket */
if ((watch = (Watch *)watchTable[hashv]))
if ((watch = watchTable[hashv]))
while (watch && mycmp(watch->nick, client->name))
watch = watch->hnext;
if (!watch)
@ -231,7 +241,7 @@ Watch *_watch_get(char *nick)
hashv = hash_watch_nick_name(nick);
if ((watch = (Watch *)watchTable[hashv]))
if ((watch = watchTable[hashv]))
while (watch && mycmp(watch->nick, nick))
watch = watch->hnext;

View File

@ -336,6 +336,7 @@ ConfigItem_webirc *find_webirc(Client *client, const char *password, WEBIRCType
/* Does the CGI:IRC host spoofing work */
void dowebirc(Client *client, const char *ip, const char *host, const char *options)
{
char oldip[64];
char scratch[64];
if (IsWEBIRC(client))
@ -357,6 +358,7 @@ void dowebirc(Client *client, const char *ip, const char *host, const char *opti
}
/* STEP 2: Update GetIP() */
strlcpy(oldip, client->ip, sizeof(oldip));
safe_strdup(client->ip, ip);
/* STEP 3: Update client->local->hostp */
@ -397,15 +399,7 @@ void dowebirc(Client *client, const char *ip, const char *host, const char *opti
}
}
/* blacklist_start_check() */
if (RCallbacks[CALLBACKTYPE_BLACKLIST_CHECK] != NULL)
RCallbacks[CALLBACKTYPE_BLACKLIST_CHECK]->func.intfunc(client);
/* Check (g)zlines right now; these are normally checked upon accept(),
* but since we know the IP only now after PASS/WEBIRC, we have to check
* here again...
*/
check_banned(client, 0);
RunHook(HOOKTYPE_IP_CHANGE, client, oldip);
}
/* WEBIRC <pass> "cgiirc" <hostname> <ip> [:option1 [option2...]]*/

View File

@ -686,6 +686,9 @@ int websocket_handshake_valid(Client *client)
}
if (WSU(client)->forwarded)
{
struct HTTPForwardedHeader *forwarded;
char oldip[64];
/* check for source ip */
if (BadPtr(client->local->listener->websocket_forward) || !websocket_ip_compare(client->local->listener->websocket_forward, client->ip))
{
@ -694,7 +697,6 @@ int websocket_handshake_valid(Client *client)
return 0;
}
/* parse the header */
struct HTTPForwardedHeader *forwarded;
forwarded = websocket_parse_forwarded_header(WSU(client)->forwarded);
/* check header values */
if (!is_valid_ip(forwarded->ip))
@ -705,6 +707,7 @@ int websocket_handshake_valid(Client *client)
}
/* store data */
WSU(client)->secure = forwarded->secure;
strlcpy(oldip, client->ip, sizeof(oldip));
safe_strdup(client->ip, forwarded->ip);
/* Update client->local->hostp */
strlcpy(client->local->sockhost, forwarded->ip, sizeof(client->local->sockhost)); /* in case dns lookup fails or is disabled */
@ -733,15 +736,7 @@ int websocket_handshake_valid(Client *client)
/* Race condition detected, DNS has been done, continue with auth */
}
}
/* blacklist_start_check() */
if (RCallbacks[CALLBACKTYPE_BLACKLIST_CHECK] != NULL)
RCallbacks[CALLBACKTYPE_BLACKLIST_CHECK]->func.intfunc(client);
/* Check (g)zlines right now; these are normally checked upon accept(),
* but since we know the IP only now after PASS/WEBIRC, we have to check
* here again...
*/
check_banned(client, 0);
RunHook(HOOKTYPE_IP_CHANGE, client, oldip);
}
return 1;
}

View File

@ -46,6 +46,7 @@ ModuleHeader MOD_HEADER
#define WMATCH_ACCOUNT 0x0040
#define WMATCH_IP 0x0080
#define WMATCH_MODES 0x0100
#define WMATCH_CONTIME 0x0200
#define RPL_WHOSPCRPL 354
@ -69,6 +70,8 @@ struct who_format
const char *querytype;
int show_realhost;
int show_ip;
time_t contimemin;
time_t contimemax;
};
/* Global variables */
@ -229,6 +232,7 @@ CMD_FUNC(cmd_whox)
case 's': fmt.matchsel |= WMATCH_SERVER; continue;
case 'a': fmt.matchsel |= WMATCH_ACCOUNT; continue;
case 'm': fmt.matchsel |= WMATCH_MODES; continue;
case 't': fmt.matchsel |= WMATCH_CONTIME; continue;
case 'R':
if (IsOper(client))
fmt.show_realhost = 1;
@ -336,6 +340,28 @@ CMD_FUNC(cmd_whox)
}
}
/* match connect time */
if (fmt.matchsel & WMATCH_CONTIME)
{
char *s = mask;
time_t currenttime = TStime();
fmt.contimemin = 0;
fmt.contimemax = 0;
switch (*s)
{
case '<':
if (*s++)
fmt.contimemin = currenttime - config_checkval(s, CFG_TIME);
break;
case '>':
if (*s++)
fmt.contimemax = currenttime - config_checkval(s, CFG_TIME);
break;
}
}
/* '/who #some_channel' */
if (IsChannelName(mask))
{
@ -449,6 +475,16 @@ static int do_match(Client *client, Client *acptr, char *mask, struct who_format
}
}
/* match connect time */
if (IsMatch(fmt, WMATCH_CONTIME) && MyConnect(acptr) && (fmt->contimemin || fmt->contimemax))
{
if (fmt->contimemin && (acptr->local->creationtime > fmt->contimemin))
return 1;
if (fmt->contimemax && (acptr->local->creationtime < fmt->contimemax))
return 1;
}
return 0;
}

View File

@ -104,7 +104,9 @@ void parse_client_queued(Client *client)
return; /* we delay processing of data until identd has replied */
if (!IsUser(client) && !IsServer(client) && (iConf.handshake_delay > 0) &&
!IsNoHandshakeDelay(client) && (TStime() - client->local->creationtime < iConf.handshake_delay))
!IsNoHandshakeDelay(client) &&
!IsControl(client) &&
(TStime() - client->local->creationtime < iConf.handshake_delay))
{
return; /* we delay processing of data until set::handshake-delay is reached */
}
@ -368,6 +370,8 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_
flags |= CMD_VIRUS;
if (IsOper(from))
flags |= CMD_OPER;
if (IsControl(from))
flags |= CMD_CONTROL;
cmptr = find_command(ch, flags);
if (!cmptr || !(cmptr->flags & CMD_NOLAG))
{
@ -376,6 +380,12 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_
}
if (!cmptr)
{
if (IsControl(from))
{
sendto_one(from, NULL, "ERROR UNKNOWN_COMMAND: %s", ch);
sendto_one(from, NULL, "END 1");
return;
}
/* Don't send error messages in response to NOTICEs
* in pre-connection state.
*/

199
src/proc_io_client.c Normal file
View File

@ -0,0 +1,199 @@
/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/proc_io_client.c
* (c) 2022- Bram Matthys and The UnrealIRCd team
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file
* @brief Inter-process I/O
*/
#include "unrealircd.h"
int procio_client_connect(const char *file)
{
int fd;
struct sockaddr_un addr;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
{
#ifdef _WIN32
fprintf(stderr, "Your Windows version does not support UNIX sockets, "
"so cannot communicate to UnrealIRCd.\n"
"Windows 10 version 1803 (April 2018) or later is needed.\n");
#else
fprintf(stderr, "Cannot communicate to UnrealIRCd: %s\n"
"Perhaps your operating system does not support UNIX Sockets?\n",
strerror(ERRNO));
#endif
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strlcpy(addr.sun_path, file, sizeof(addr.sun_path));
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
fprintf(stderr, "Could not connect to '%s': %s\n",
CONTROLFILE, strerror(errno));
fprintf(stderr, "The IRC server does not appear to be running.\n");
close(fd);
return -1;
}
return fd;
}
int procio_send(int fd, const char *command)
{
char buf[512];
int n;
snprintf(buf, sizeof(buf), "%s\r\n", command);
n = strlen(buf);
if (send(fd, buf, n, 0) != n)
return 0;
return 1;
}
const char *recolor_logs(const char *str)
{
static char retbuf[2048];
char buf[2048], *p;
const char *color = NULL;
strlcpy(buf, str, sizeof(buf));
p = strchr(buf, ' ');
if ((*str != '[') || !p)
return str;
*p++ = '\0';
if (!strcmp(buf, "[debug]"))
color = log_level_terminal_color(ULOG_DEBUG);
else if (!strcmp(buf, "[info]"))
color = log_level_terminal_color(ULOG_INFO);
else if (!strcmp(buf, "[warning]"))
color = log_level_terminal_color(ULOG_WARNING);
else if (!strcmp(buf, "[error]"))
color = log_level_terminal_color(ULOG_ERROR);
else if (!strcmp(buf, "[fatal]"))
color = log_level_terminal_color(ULOG_FATAL);
else
color = log_level_terminal_color(ULOG_INVALID);
snprintf(retbuf, sizeof(retbuf), "%s%s%s %s",
color, buf, TERMINAL_COLOR_RESET, p);
return retbuf;
}
const char *recolor_split(const char *str)
{
static char retbuf[2048];
char buf[2048], *p;
const char *color = NULL;
strlcpy(buf, str, sizeof(buf));
p = strchr(buf, ' ');
if (!p)
return str;
*p++ = '\0';
snprintf(retbuf, sizeof(retbuf), "%s%s %s%s%s",
"\033[92m", buf,
"\033[93m", p,
TERMINAL_COLOR_RESET);
return retbuf;
}
int procio_client(const char *command, int auto_color_logs)
{
int fd;
char buf[READBUFSIZE];
int n;
dbuf queue;
if (auto_color_logs && !terminal_supports_color())
auto_color_logs = 0;
fd = procio_client_connect(CONTROLFILE);
if (fd < 0)
return -1;
/* Expect the welcome message */
memset(buf, 0, sizeof(buf));
n = recv(fd, buf, sizeof(buf), 0);
if ((n < 0) || strncmp(buf, "READY", 4))
{
fprintf(stderr, "Error while communicating to IRCd via '%s': %s\n"
"Maybe the IRC server is not running?\n",
CONTROLFILE, strerror(errno));
close(fd);
return -1;
}
if (!procio_send(fd, command))
{
fprintf(stderr, "Error while sending command to IRCd via '%s'. Strange!\n",
CONTROLFILE);
close(fd);
return -1;
}
*buf = '\0';
dbuf_queue_init(&queue);
while(1)
{
n = recv(fd, buf, sizeof(buf)-1, 0);
if (n <= 0)
break;
buf[n] = '\0'; /* terminate the string */
dbuf_put(&queue, buf, n);
/* And try to read all complete lines: */
do
{
n = dbuf_getmsg(&queue, buf);
if (n > 0)
{
if (!strncmp(buf, "REPLY ", 6))
{
char *reply = buf+6;
if (auto_color_logs == 0)
printf("%s\n", reply);
else if (auto_color_logs == 1)
printf("%s\n", recolor_logs(reply));
else
printf("%s\n", recolor_split(reply));
} else
if (!strncmp(buf, "END ", 4))
{
int exitcode = atoi(buf+4);
close(fd);
return exitcode;
}
}
} while(n > 0);
}
/* IRCd hung up without saying goodbye, possibly problematic,
* or at least we cannot determine, so exit with status 66.
*/
close(fd);
return 66;
}

170
src/proc_io_server.c Normal file
View File

@ -0,0 +1,170 @@
/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/proc_io_server.c
* (c) 2022- Bram Matthys and The UnrealIRCd team
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file
* @brief Inter-process I/O
*/
#include "unrealircd.h"
#include <ares.h>
CMD_FUNC(procio_status);
CMD_FUNC(procio_modules);
CMD_FUNC(procio_rehash);
CMD_FUNC(procio_exit);
CMD_FUNC(procio_help);
/** Create the unrealircd.ctl socket (server-side) */
void add_proc_io_server(void)
{
ConfigItem_listen *listener;
#ifdef _WIN32
/* Ignore silently on Windows versions older than W10 build 17061 */
if (!unix_sockets_capable())
return;
#endif
listener = safe_alloc(sizeof(ConfigItem_listen));
safe_strdup(listener->file, CONTROLFILE);
listener->socket_type = SOCKET_TYPE_UNIX;
listener->options = LISTENER_CONTROL;
listener->fd = -1;
AddListItem(listener, conf_listen);
if (add_listener(listener) == -1)
exit(-1);
CommandAdd(NULL, "STATUS", procio_status, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "MODULES", procio_modules, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "REHASH", procio_rehash, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "EXIT", procio_exit, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "HELP", procio_help, MAXPARA, CMD_CONTROL);
}
/** Start of "control channel" client handshake - this is minimal
* @param client The client
*/
void start_of_control_client_handshake(Client *client)
{
sendto_one(client, NULL, "READY %s %s", me.name, version);
fd_setselect(client->local->fd, FD_SELECT_READ, read_packet, client);
}
CMD_FUNC(procio_status)
{
sendto_one(client, NULL, "REPLY servername %s", me.name);
sendto_one(client, NULL, "REPLY unrealircd_version %s", version);
sendto_one(client, NULL, "REPLY libssl_version %s", SSLeay_version(SSLEAY_VERSION));
sendto_one(client, NULL, "REPLY libsodium_version %s", sodium_version_string());
#ifdef USE_LIBCURL
sendto_one(client, NULL, "REPLY libcurl_version %s", curl_version());
#endif
sendto_one(client, NULL, "REPLY libcares_version %s", ares_version(NULL));
sendto_one(client, NULL, "REPLY libpcre2_version %s", pcre2_version());
sendto_one(client, NULL, "REPLY global_clients %ld", (long)irccounts.clients);
sendto_one(client, NULL, "REPLY local_clients %ld", (long)irccounts.me_clients);
sendto_one(client, NULL, "REPLY operators %ld", (long)irccounts.operators);
sendto_one(client, NULL, "REPLY servers %ld", (long)irccounts.servers);
sendto_one(client, NULL, "REPLY channels %ld", (long)irccounts.channels);
sendto_one(client, NULL, "END 0");
}
extern MODVAR Module *Modules;
CMD_FUNC(procio_modules)
{
char tmp[1024];
Module *m;
for (m = Modules; m; m = m->next)
{
tmp[0] = '\0';
if (m->flags & MODFLAG_DELAYED)
strlcat(tmp, "[Unloading] ", sizeof(tmp));
if (m->options & MOD_OPT_PERM_RELOADABLE)
strlcat(tmp, "[PERM-BUT-RELOADABLE] ", sizeof(tmp));
if (m->options & MOD_OPT_PERM)
strlcat(tmp, "[PERM] ", sizeof(tmp));
if (!(m->options & MOD_OPT_OFFICIAL))
strlcat(tmp, "[3RD] ", sizeof(tmp));
sendto_one(client, NULL, "REPLY %s %s - %s - by %s %s",
m->header->name,
m->header->version,
m->header->description,
m->header->author,
tmp);
}
sendto_one(client, NULL, "END 0");
}
CMD_FUNC(procio_rehash)
{
if (loop.rehashing)
{
sendto_one(client, NULL, "REPLY ERROR: A rehash is already in progress");
sendto_one(client, NULL, "END 1");
return;
}
if (parv[1] && !strcmp(parv[1], "-tls"))
{
int ret;
SetMonitorRehash(client);
unreal_log(ULOG_INFO, "config", "CONFIG_RELOAD_TLS", NULL, "Reloading all TLS related data (./unrealircd reloadtls)");
ret = reinit_tls();
sendto_one(client, NULL, "END %d", ret == 0 ? -1 : 0);
ClearMonitorRehash(client);
} else {
SetMonitorRehash(client);
request_rehash(client);
/* completion will go via procio_post_rehash() */
}
}
CMD_FUNC(procio_exit)
{
sendto_one(client, NULL, "END 0");
exit_client(client, NULL, "");
}
CMD_FUNC(procio_help)
{
sendto_one(client, NULL, "REPLY Commands available:");
sendto_one(client, NULL, "REPLY EXIT");
sendto_one(client, NULL, "REPLY HELP");
sendto_one(client, NULL, "REPLY REHASH");
sendto_one(client, NULL, "REPLY STATUS");
sendto_one(client, NULL, "REPLY MODULES");
sendto_one(client, NULL, "END 0");
}
/** Called upon REHASH completion (with or without failure) */
void procio_post_rehash(int failure)
{
Client *client;
list_for_each_entry(client, &control_list, lclient_node)
{
if (IsMonitorRehash(client))
{
sendto_one(client, NULL, "END %d", failure);
ClearMonitorRehash(client);
}
}
}

View File

@ -218,7 +218,7 @@ void vsendto_one(Client *to, MessageTag *mtags, const char *pattern, va_list vl)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
ircvsnprintf(sendbuf, sizeof(sendbuf), pattern, vl);
ircvsnprintf(sendbuf, sizeof(sendbuf)-3, pattern, vl);
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
@ -229,7 +229,7 @@ void vsendto_one(Client *to, MessageTag *mtags, const char *pattern, va_list vl)
sendbufto_one(to, sendbuf, 0);
} else {
/* Message tags need to be prepended */
snprintf(sendbuf2, sizeof(sendbuf2), "@%s %s", mtags_str, sendbuf);
snprintf(sendbuf2, sizeof(sendbuf2)-3, "@%s %s", mtags_str, sendbuf);
sendbufto_one(to, sendbuf2, 0);
}
}
@ -339,10 +339,10 @@ void sendbufto_one(Client *to, char *msg, unsigned int quick)
if (IsMe(to))
{
char tmp_msg[500], *p;
char tmp_msg[500];
p = strchr(msg, '\r');
if (p) *p = '\0';
strlcpy(tmp_msg, msg, sizeof(tmp_msg));
stripcrlf(tmp_msg);
unreal_log(ULOG_WARNING, "send", "SENDBUFTO_ONE_ME_MESSAGE", to,
"Trying to send data to myself: $buf",
log_data_string("buf", tmp_msg));
@ -395,7 +395,10 @@ void sendbufto_one(Client *to, char *msg, unsigned int quick)
* a bad idea, CPU-wise. So now we just mark the client indicating
* that there is data to send.
*/
mark_data_to_send(to);
if (IsControl(to))
send_queued(to); /* send this one ASAP */
else
mark_data_to_send(to);
}
/** A single function to send data to a channel.

View File

@ -716,62 +716,77 @@ CMD_FUNC(cmd_restart)
/** Send short message of the day to the client */
void short_motd(Client *client)
{
ConfigItem_tld *tld;
MOTDFile *themotd;
MOTDLine *motdline;
struct tm *tm;
char is_short;
ConfigItem_tld *tld;
MOTDFile *themotd;
MOTDLine *motdline;
struct tm *tm;
char is_short;
tm = NULL;
is_short = 1;
tm = NULL;
is_short = 1;
tld = find_tld(client);
tld = find_tld(client);
/*
/*
* Try different sources of short MOTDs, falling back to the
* long MOTD.
*/
themotd = &smotd;
if (tld && tld->smotd.lines)
themotd = &tld->smotd;
*/
themotd = &smotd;
if (tld && tld->smotd.lines)
themotd = &tld->smotd;
/* try long MOTDs */
if (!themotd->lines)
{
is_short = 0;
if (tld && tld->motd.lines)
themotd = &tld->motd;
else
themotd = &motd;
}
/* try long MOTDs */
if (!themotd->lines)
{
is_short = 0;
if (tld && tld->motd.lines)
themotd = &tld->motd;
else
themotd = &motd;
}
if (!themotd->lines)
{
sendnumeric(client, ERR_NOMOTD);
return;
}
if (themotd->last_modified.tm_year)
{
tm = &themotd->last_modified; /* for readability */
sendnumeric(client, RPL_MOTDSTART, me.name);
sendnumericfmt(client, RPL_MOTD, ":- %d/%d/%d %d:%02d", tm->tm_mday, tm->tm_mon + 1,
1900 + tm->tm_year, tm->tm_hour, tm->tm_min);
}
if (is_short)
{
sendnumeric(client, RPL_MOTD, "This is the short MOTD. To view the complete MOTD type /motd");
sendnumeric(client, RPL_MOTD, "");
}
if (!themotd->lines)
{
sendnumeric(client, ERR_NOMOTD);
return;
}
if (themotd->last_modified.tm_year)
{
tm = &themotd->last_modified; /* for readability */
sendnumeric(client, RPL_MOTDSTART, me.name);
sendnumericfmt(client, RPL_MOTD, ":- %d/%d/%d %d:%02d", tm->tm_mday, tm->tm_mon + 1,
1900 + tm->tm_year, tm->tm_hour, tm->tm_min);
}
if (is_short)
{
sendnumeric(client, RPL_MOTD, "This is the short MOTD. To view the complete MOTD type /motd");
sendnumeric(client, RPL_MOTD, "");
}
motdline = NULL;
if (themotd)
motdline = themotd->lines;
while (motdline)
{
sendnumeric(client, RPL_MOTD, motdline->line);
motdline = motdline->next;
}
sendnumeric(client, RPL_ENDOFMOTD);
motdline = NULL;
if (themotd)
motdline = themotd->lines;
while (motdline)
{
sendnumeric(client, RPL_MOTD, motdline->line);
motdline = motdline->next;
}
if (!is_short)
{
/* If the admin does not use a short MOTD then we append the SVSMOTD here...
* If we did show a short motd then we don't append SVSMOTD,
* since they want to keep it short.
*/
motdline = svsmotd.lines;
while (motdline)
{
sendnumeric(client, RPL_MOTD, motdline->line);
motdline = motdline->next;
}
}
sendnumeric(client, RPL_ENDOFMOTD);
}
/** Read motd-like file, used for rules/motd/botmotd/opermotd/etc.

View File

@ -32,7 +32,7 @@ int OpenFiles = 0; /* GLOBAL - number of files currently open */
int readcalls = 0;
void completed_connection(int, int, void *);
void set_sock_opts(int, Client *, int);
void set_sock_opts(int, Client *, SocketType);
void set_ipv6_opts(int);
void close_listener(ConfigItem_listen *listener);
static char readbuf[BUFSIZE];
@ -41,6 +41,7 @@ extern char *version;
MODVAR time_t last_allinuse = 0;
void start_of_normal_client_handshake(Client *client);
extern void start_of_control_client_handshake(Client *client);
void proceed_normal_client_handshake(Client *client, struct hostent *he);
/** Close all connections - only used when we terminate the server (eg: /DIE or SIGTERM) */
@ -72,6 +73,15 @@ void close_connections(void)
}
}
list_for_each_entry(client, &control_list, lclient_node)
{
if (client->local->fd >= 0)
{
fd_close(client->local->fd);
client->local->fd = -2;
}
}
close_unbound_listeners();
OpenFiles = 0;
@ -101,10 +111,17 @@ static void listener_accept(int listener_fd, int revents, void *data)
* Of course the underlying cause of this issue should be investigated, as this
* is very much a workaround.
*/
unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR", NULL, "Cannot accept incoming connection on IP \"$listen_ip\" port $listen_port: $socket_error",
log_data_socket_error(listener->fd),
log_data_string("listen_ip", listener->ip),
log_data_integer("listen_port", listener->port));
if (listener->file)
{
unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR", NULL, "Cannot accept incoming connection on file $file: $socket_error",
log_data_socket_error(listener->fd),
log_data_string("file", listener->file));
} else {
unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR", NULL, "Cannot accept incoming connection on IP \"$listen_ip\" port $listen_port: $socket_error",
log_data_socket_error(listener->fd),
log_data_string("listen_ip", listener->ip),
log_data_integer("listen_port", listener->port));
}
close_listener(listener);
start_listeners();
}
@ -113,45 +130,67 @@ static void listener_accept(int listener_fd, int revents, void *data)
ircstats.is_ac++;
set_sock_opts(cli_fd, NULL, listener->ipv6);
set_sock_opts(cli_fd, NULL, listener->socket_type);
if ((++OpenFiles >= maxclients) || (cli_fd >= maxclients))
/* Allow connections to the control socket, even if maxclients is reached */
if (listener->options & LISTENER_CONTROL)
{
ircstats.is_ref++;
if (last_allinuse < TStime() - 15)
/* ... but not unlimited ;) */
if ((++OpenFiles >= maxclients+(CLIENTS_RESERVE/2)) || (cli_fd >= maxclients+(CLIENTS_RESERVE/2)))
{
unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR_MAXCLIENTS", NULL, "Cannot accept incoming connection on IP \"$listen_ip\" port $listen_port: All connections in use",
log_data_string("listen_ip", listener->ip),
log_data_integer("listen_port", listener->port));
last_allinuse = TStime();
ircstats.is_ref++;
if (last_allinuse < TStime() - 15)
{
unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR_MAXCLIENTS", NULL, "Cannot accept incoming connection on file $file: All connections in use",
log_data_string("file", listener->file));
last_allinuse = TStime();
}
fd_close(cli_fd);
--OpenFiles;
return;
}
} else
{
if ((++OpenFiles >= maxclients) || (cli_fd >= maxclients))
{
ircstats.is_ref++;
if (last_allinuse < TStime() - 15)
{
if (listener->file)
{
unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR_MAXCLIENTS", NULL, "Cannot accept incoming connection on file $file: All connections in use",
log_data_string("file", listener->file));
} else {
unreal_log(ULOG_FATAL, "listen", "ACCEPT_ERROR_MAXCLIENTS", NULL, "Cannot accept incoming connection on IP \"$listen_ip\" port $listen_port: All connections in use",
log_data_string("listen_ip", listener->ip),
log_data_integer("listen_port", listener->port));
}
last_allinuse = TStime();
}
(void)send(cli_fd, "ERROR :All connections in use\r\n", 31, 0);
(void)send(cli_fd, "ERROR :All connections in use\r\n", 31, 0);
fd_close(cli_fd);
--OpenFiles;
return;
fd_close(cli_fd);
--OpenFiles;
return;
}
}
/* add_connection() may fail. we just don't care. */
add_connection(listener, cli_fd);
}
/** Create a listener port.
* @param listener The listen { } block configuration
* @param ip IP address to bind on
* @param port Port to bind on
* @param ipv6 IPv6 (1) or IPv4 (0)
* @returns 0 on success and <0 on error. Yeah, confusing.
*/
int unreal_listen(ConfigItem_listen *listener, char *ip, int port, int ipv6)
int unreal_listen_inet(ConfigItem_listen *listener)
{
const char *ip = listener->ip;
int port = listener->port;
if (BadPtr(ip))
ip = "*";
if (*ip == '*')
{
if (ipv6)
if (listener->socket_type == SOCKET_TYPE_IPV6)
ip = "::";
else
ip = "0.0.0.0";
@ -160,11 +199,11 @@ int unreal_listen(ConfigItem_listen *listener, char *ip, int port, int ipv6)
/* At first, open a new socket */
if (listener->fd >= 0)
abort(); /* Socket already exists but we are asked to create and listen on one. Bad! */
if (port == 0)
abort(); /* Impossible as well, right? */
listener->fd = fd_socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0, "Listener socket");
listener->fd = fd_socket(listener->socket_type == SOCKET_TYPE_IPV6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0, "Listener socket");
if (listener->fd < 0)
{
unreal_log(ULOG_FATAL, "listen", "LISTEN_SOCKET_ERROR", NULL,
@ -187,9 +226,9 @@ int unreal_listen(ConfigItem_listen *listener, char *ip, int port, int ipv6)
return -1;
}
set_sock_opts(listener->fd, NULL, ipv6);
set_sock_opts(listener->fd, NULL, listener->socket_type);
if (!unreal_bind(listener->fd, ip, port, ipv6))
if (!unreal_bind(listener->fd, ip, port, listener->socket_type))
{
unreal_log(ULOG_FATAL, "listen", "LISTEN_BIND_ERROR", NULL,
"Could not listen on IP \"$listen_ip\" on port $listen_port: $socket_error",
@ -240,23 +279,95 @@ int unreal_listen(ConfigItem_listen *listener, char *ip, int port, int ipv6)
return 0;
}
/** Activate a listen { } block */
int add_listener(ConfigItem_listen *conf)
int unreal_listen_unix(ConfigItem_listen *listener)
{
if (unreal_listen(conf, conf->ip, conf->port, conf->ipv6))
if (listener->socket_type != SOCKET_TYPE_UNIX)
abort(); /* "impossible" */
/* At first, open a new socket */
if (listener->fd >= 0)
abort(); /* Socket already exists but we are asked to create and listen on one. Bad! */
listener->fd = fd_socket(AF_UNIX, SOCK_STREAM, 0, "Listener socket (UNIX)");
if (listener->fd < 0)
{
/* Error is already handled upstream */
conf->fd = -2;
unreal_log(ULOG_FATAL, "listen", "LISTEN_SOCKET_ERROR", NULL,
"Could not create UNIX domain socket for $file: $socket_error",
log_data_socket_error(-1),
log_data_string("file", listener->file));
return -1;
}
if (conf->fd >= 0)
if (++OpenFiles >= maxclients)
{
conf->options |= LISTENER_BOUND;
unreal_log(ULOG_FATAL, "listen", "LISTEN_ERROR_MAXCLIENTS", NULL,
"Could not create UNIX domain socket for $file: all connections in use",
log_data_string("file", listener->file));
fd_close(listener->fd);
listener->fd = -1;
--OpenFiles;
return -1;
}
set_sock_opts(listener->fd, NULL, listener->socket_type);
if (!unreal_bind(listener->fd, listener->file, 0, SOCKET_TYPE_UNIX))
{
unreal_log(ULOG_FATAL, "listen", "LISTEN_BIND_ERROR", NULL,
"Could not listen on UNIX domain socket $file: $socket_error",
log_data_socket_error(listener->fd),
log_data_string("file", listener->file));
fd_close(listener->fd);
listener->fd = -1;
--OpenFiles;
return -1;
}
if (listen(listener->fd, LISTEN_SIZE) < 0)
{
unreal_log(ULOG_FATAL, "listen", "LISTEN_LISTEN_ERROR", NULL,
"Could not listen on UNIX domain socket $file: $socket_error",
log_data_socket_error(listener->fd),
log_data_string("file", listener->file));
fd_close(listener->fd);
listener->fd = -1;
--OpenFiles;
return -1;
}
fd_setselect(listener->fd, FD_SELECT_READ, listener_accept, listener);
return 0;
}
/** Create a listener port.
* @param listener The listen { } block configuration
* @returns 0 on success and <0 on error. Yeah, confusing.
*/
int unreal_listen(ConfigItem_listen *listener)
{
if ((listener->socket_type == SOCKET_TYPE_IPV4) || (listener->socket_type == SOCKET_TYPE_IPV6))
return unreal_listen_inet(listener);
return unreal_listen_unix(listener);
}
/** Activate a listen { } block */
int add_listener(ConfigItem_listen *listener)
{
if (unreal_listen(listener))
{
/* Error is already handled upstream */
listener->fd = -2;
}
if (listener->fd >= 0)
{
listener->options |= LISTENER_BOUND;
return 1;
}
else
{
conf->fd = -1;
listener->fd = -1;
return -1;
}
}
@ -433,7 +544,7 @@ void consider_ident_lookup(Client *client)
char buf[BUFSIZE];
/* If ident checking is disabled or it's an outgoing connect, then no ident check */
if ((IDENT_CHECK == 0) || (client->server && IsHandshake(client)))
if ((IDENT_CHECK == 0) || (client->server && IsHandshake(client)) || IsUnixSocket(client))
{
ClearIdentLookupSent(client);
ClearIdentLookup(client);
@ -560,37 +671,38 @@ void set_socket_buffers(int fd, int rcvbuf, int sndbuf)
}
/** Set the appropriate socket options */
void set_sock_opts(int fd, Client *client, int ipv6)
void set_sock_opts(int fd, Client *client, SocketType socket_type)
{
int opt;
if (ipv6)
if (socket_type == SOCKET_TYPE_IPV6)
set_ipv6_opts(fd);
#ifdef SO_REUSEADDR
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)) < 0)
if ((socket_type == SOCKET_TYPE_IPV4) || (socket_type == SOCKET_TYPE_IPV6))
{
unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client,
"Could not setsockopt(SO_REUSEADDR): $socket_error",
log_data_socket_error(-1));
}
#ifdef SO_REUSEADDR
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)) < 0)
{
unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client,
"Could not setsockopt(SO_REUSEADDR): $socket_error",
log_data_socket_error(-1));
}
#endif
#if defined(SO_USELOOPBACK) && !defined(_WIN32)
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK, (void *)&opt, sizeof(opt)) < 0)
{
unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client,
"Could not setsockopt(SO_USELOOPBACK): $socket_error",
log_data_socket_error(-1));
}
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK, (void *)&opt, sizeof(opt)) < 0)
{
unreal_log(ULOG_WARNING, "socket", "SOCKET_ERROR_SETSOCKOPTS", client,
"Could not setsockopt(SO_USELOOPBACK): $socket_error",
log_data_socket_error(-1));
}
#endif
/* Previously we also called set_socket_buffers() to set some
* specific buffer limits. This is no longer needed on modern OS's.
* Setting it explicitly actually slows things down.
*/
}
/* The following code applies to all socket types: IPv4, IPv6, UNIX domain sockets */
/* Set to non blocking: */
#if !defined(_WIN32)
@ -641,7 +753,7 @@ int is_loopback_ip(char *ip)
for (e = conf_listen; e; e = e->next)
{
if ((e->options & LISTENER_BOUND) && !strcmp(ip, e->ip))
if ((e->options & LISTENER_BOUND) && e->ip && !strcmp(ip, e->ip))
return 1;
}
return 0;
@ -718,15 +830,15 @@ Client *add_connection(ConfigItem_listen *listener, int fd)
Client *client;
const char *ip;
int port = 0;
client = make_client(NULL, &me);
client->local->socket_type = listener->socket_type;
/* If listener is IPv6 then mark client (client) as IPv6 */
if (listener->ipv6)
SetIPV6(client);
if (listener->socket_type == SOCKET_TYPE_UNIX)
ip = "127.0.0.1";
else
ip = getpeerip(client, fd, &port);
ip = getpeerip(client, fd, &port);
if (!ip)
{
/* On Linux 2.4 and FreeBSD the socket may just have been disconnected
@ -762,29 +874,38 @@ refuse_client:
SetLocalhost(client);
}
/* Check set::max-unknown-connections-per-ip */
if (check_too_many_unknown_connections(client))
if (!(listener->options & LISTENER_CONTROL))
{
ircsnprintf(zlinebuf, sizeof(zlinebuf),
"ERROR :Closing Link: [%s] (Too many unknown connections from your IP)\r\n",
client->ip);
(void)send(fd, zlinebuf, strlen(zlinebuf), 0);
goto refuse_client;
}
/* Check set::max-unknown-connections-per-ip */
if (check_too_many_unknown_connections(client))
{
ircsnprintf(zlinebuf, sizeof(zlinebuf),
"ERROR :Closing Link: [%s] (Too many unknown connections from your IP)\r\n",
client->ip);
(void)send(fd, zlinebuf, strlen(zlinebuf), 0);
goto refuse_client;
}
/* Check (G)Z-Lines and set::anti-flood::connect-flood */
if (check_banned(client, NO_EXIT_CLIENT))
goto refuse_client;
/* Check (G)Z-Lines and set::anti-flood::connect-flood */
if (check_banned(client, NO_EXIT_CLIENT))
goto refuse_client;
}
client->local->listener = listener;
if (client->local->listener != NULL)
client->local->listener->clients++;
add_client_to_list(client);
irccounts.unknown++;
client->status = CLIENT_STATUS_UNKNOWN;
list_add(&client->lclient_node, &unknown_list);
if (!(listener->options & LISTENER_CONTROL))
{
/* IRC: unknown connection */
irccounts.unknown++;
client->status = CLIENT_STATUS_UNKNOWN;
list_add(&client->lclient_node, &unknown_list);
} else {
client->status = CLIENT_STATUS_CONTROL;
list_add(&client->lclient_node, &control_list);
}
if ((listener->options & LISTENER_TLS) && ctx_server)
{
@ -809,7 +930,9 @@ refuse_client:
goto refuse_client;
}
}
}
} else
if (listener->options & LISTENER_CONTROL)
start_of_control_client_handshake(client);
else
start_of_normal_client_handshake(client);
return client;
@ -828,7 +951,7 @@ void start_of_normal_client_handshake(Client *client)
RunHook(HOOKTYPE_HANDSHAKE, client);
if (!DONT_RESOLVE)
if (!DONT_RESOLVE && !IsUnixSocket(client))
{
if (should_show_connect_info(client))
sendto_one(client, NULL, ":%s %s", me.name, REPORT_DO_DNS);
@ -1027,6 +1150,20 @@ void process_clients(void)
}
}
} while(&client->lclient_node != &unknown_list);
do {
list_for_each_entry(client, &control_list, lclient_node)
{
if ((client->local->fd >= 0) && DBufLength(&client->local->recvQ) && !IsDead(client))
{
parse_client_queued(client);
if (IsDead(client))
break;
}
}
} while(&client->lclient_node != &control_list);
}
/** Check if 'ip' is a valid IP address, and if so what type.
@ -1038,16 +1175,16 @@ void process_clients(void)
int is_valid_ip(const char *ip)
{
char scratch[64];
if (BadPtr(ip))
return 0;
if (inet_pton(AF_INET, ip, scratch) == 1)
return 4; /* IPv4 */
if (inet_pton(AF_INET6, ip, scratch) == 1)
return 6; /* IPv6 */
return 0; /* not an IP address */
}
@ -1060,11 +1197,21 @@ int ipv6_capable(void)
int s = socket(AF_INET6, SOCK_STREAM, 0);
if (s < 0)
return 0; /* NO ipv6 */
CLOSE_SOCK(s);
return 1; /* YES */
}
/** Return 1 if UNIX sockets of type SOCK_STREAM are supported, and 0 otherwise */
int unix_sockets_capable(void)
{
int fd = fd_socket(AF_UNIX, SOCK_STREAM, 0, "Testing UNIX socket");
if (fd < 0)
return 0;
fd_close(fd);
return 1;
}
/** Attempt to deliver data to a client.
* This function is only called from send_queued() and will deal
* with sending to the TLS or plaintext connection.
@ -1156,7 +1303,7 @@ int deliver_it(Client *client, char *str, int len, int *want_read)
int unreal_connect(int fd, const char *ip, int port, int ipv6)
{
int n;
if (ipv6)
{
struct sockaddr_in6 server;
@ -1182,25 +1329,17 @@ int unreal_connect(int fd, const char *ip, int port, int ipv6)
{
return 0; /* FATAL ERROR */
}
return 1; /* SUCCESS (probably still in progress) */
}
/** Bind to an IP/port (port may be 0 for auto).
* @returns 0 on failure, other on success.
*/
int unreal_bind(int fd, const char *ip, int port, int ipv6)
int unreal_bind(int fd, const char *ip, int port, SocketType socket_type)
{
if (ipv6)
if (socket_type == SOCKET_TYPE_IPV4)
{
struct sockaddr_in6 server;
memset(&server, 0, sizeof(server));
server.sin6_family = AF_INET6;
server.sin6_port = htons(port);
if (inet_pton(AF_INET6, ip, &server.sin6_addr.s6_addr) != 1)
return 0;
return !bind(fd, (struct sockaddr *)&server, sizeof(server));
} else {
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
@ -1209,4 +1348,43 @@ int unreal_bind(int fd, const char *ip, int port, int ipv6)
return 0;
return !bind(fd, (struct sockaddr *)&server, sizeof(server));
}
else if (socket_type == SOCKET_TYPE_IPV6)
{
struct sockaddr_in6 server;
memset(&server, 0, sizeof(server));
server.sin6_family = AF_INET6;
server.sin6_port = htons(port);
if (inet_pton(AF_INET6, ip, &server.sin6_addr.s6_addr) != 1)
return 0;
return !bind(fd, (struct sockaddr *)&server, sizeof(server));
} else
{
struct sockaddr_un server;
mode_t saved_umask;
int ret;
unlink(ip); /* (ignore errors) */
memset(&server, 0, sizeof(server));
server.sun_family = AF_UNIX;
strlcpy(server.sun_path, ip, sizeof(server.sun_path));
saved_umask = umask(077); // TODO: make this configurable
ret = !bind(fd, (struct sockaddr *)&server, sizeof(server));
umask(saved_umask);
return ret;
}
}
#ifdef _WIN32
void init_winsock(void)
{
WSADATA WSAData;
if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
{
MessageBox(NULL, "Unable to initialize WinSock", "UnrealIRCD Initalization Error", MB_OK);
fprintf(stderr, "Unable to initialize WinSock\n");
exit(1);
}
}
#endif

View File

@ -512,7 +512,7 @@ int init_tls(void)
/** Reinitialize TLS server and client contexts - after REHASH -tls
*/
void reinit_tls(void)
int reinit_tls(void)
{
SSL_CTX *tmp;
ConfigItem_listen *listen;
@ -524,7 +524,7 @@ void reinit_tls(void)
{
unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
"TLS Reload failed. See previous errors.");
return;
return 0;
}
if (ctx_server)
SSL_CTX_free(ctx_server);
@ -535,7 +535,7 @@ void reinit_tls(void)
{
unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
"TLS Reload failed at client context. See previous errors.");
return;
return 0;
}
if (ctx_client)
SSL_CTX_free(ctx_client);
@ -551,7 +551,7 @@ void reinit_tls(void)
{
unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
"TLS Reload failed at listen::tls-options. See previous errors.");
return;
return 0;
}
if (listen->ssl_ctx)
SSL_CTX_free(listen->ssl_ctx);
@ -569,7 +569,7 @@ void reinit_tls(void)
{
unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
"TLS Reload failed at sni::tls-options. See previous errors.");
return;
return 0;
}
if (sni->ssl_ctx)
SSL_CTX_free(sni->ssl_ctx);
@ -588,13 +588,15 @@ void reinit_tls(void)
unreal_log(ULOG_ERROR, "config", "TLS_RELOAD_FAILED", NULL,
"TLS Reload failed at link $servername due to outgoing::tls-options. See previous errors.",
log_data_string("servername", link->servername));
return;
return 0;
}
if (link->ssl_ctx)
SSL_CTX_free(link->ssl_ctx);
link->ssl_ctx = tmp; /* activate */
}
}
return 1;
}
/** Set SSL connection as nonblocking */

266
src/unrealircdctl.c Normal file
View File

@ -0,0 +1,266 @@
/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/unrealircdctl
* (c) 2022- Bram Matthys and The UnrealIRCd team
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file
* @brief UnrealIRCd Control
*/
#include "unrealircd.h"
#ifdef _WIN32
#define UNREALCMD "unrealircdctl"
#else
#define UNREALCMD "./unrealircd"
#endif
extern int procio_client(const char *command, int auto_color_logs);
void unrealircdctl_usage(const char *program_name)
{
printf("Usage: %s <option>\n"
"Where <option> is one of:\n"
"rehash - Rehash the server (reread configuration files)\n"
"reloadtls - Reload the SSL/TLS certificates\n"
"status - Show current status of server\n"
"module-status - Show currently loaded modules\n"
"mkpasswd - Hash a password\n"
"gencloak - Display 3 random cloak keys\n"
"spkifp - Display SPKI Fingerprint\n"
"\n", program_name);
exit(-1);
}
void unrealircdctl_rehash(void)
{
if (procio_client("REHASH", 1) == 0)
{
printf("Rehashed succesfully.\n");
exit(0);
}
printf("Rehash failed.\n");
exit(1);
}
void unrealircdctl_reloadtls(void)
{
if (procio_client("REHASH -tls", 1) == 0)
{
printf("Reloading of TLS certificates successful.\n");
exit(0);
}
printf("Reloading TLS certificates failed.\n");
exit(1);
}
void unrealircdctl_status(void)
{
if (procio_client("STATUS", 2) == 0)
{
printf("UnrealIRCd is up and running.\n");
exit(0);
}
printf("UnrealIRCd status report failed.\n");
exit(1);
}
void unrealircdctl_module_status(void)
{
if (procio_client("MODULES", 2) == 0)
exit(0);
printf("Could not retrieve complete module list.\n");
exit(1);
}
void unrealircdctl_mkpasswd(int argc, char *argv[])
{
AuthenticationType type;
const char *result;
char *p = argv[2];
type = Auth_FindType(NULL, p);
if (type == -1)
{
type = AUTHTYPE_ARGON2;
} else {
p = argv[3];
}
if (BadPtr(p))
{
#ifndef _WIN32
p = getpass("Enter password to hash: ");
#else
printf("ERROR: You should specify a password to hash");
exit(1);
#endif
}
if ((type == AUTHTYPE_UNIXCRYPT) && (strlen(p) > 8))
{
/* Hmmm.. is this warning really still true (and always) ?? */
printf("WARNING: Password truncated to 8 characters due to 'crypt' algorithm. "
"You are suggested to use the 'argon2' algorithm instead.");
p[8] = '\0';
}
if (!(result = Auth_Hash(type, p))) {
printf("Failed to generate password. Deprecated method? Try 'argon2' instead.\n");
exit(0);
}
printf("Encrypted password is: %s\n", result);
exit(0);
}
void unrealircdctl_gencloak(int argc, char *argv[])
{
#define GENERATE_CLOAKKEY_LEN 80 /* Length of cloak keys to generate. */
char keyBuf[GENERATE_CLOAKKEY_LEN + 1];
int keyNum;
int charIndex;
short has_upper;
short has_lower;
short has_num;
printf("Here are 3 random cloak keys that you can copy-paste to your configuration file:\n\n");
printf("set {\n\tcloak-keys {\n");
for (keyNum = 0; keyNum < 3; ++keyNum)
{
has_upper = 0;
has_lower = 0;
has_num = 0;
for (charIndex = 0; charIndex < sizeof(keyBuf)-1; ++charIndex)
{
switch (getrandom8() % 3)
{
case 0: /* Uppercase. */
keyBuf[charIndex] = (char)('A' + (getrandom8() % ('Z' - 'A')));
has_upper = 1;
break;
case 1: /* Lowercase. */
keyBuf[charIndex] = (char)('a' + (getrandom8() % ('z' - 'a')));
has_lower = 1;
break;
case 2: /* Digit. */
keyBuf[charIndex] = (char)('0' + (getrandom8() % ('9' - '0')));
has_num = 1;
break;
}
}
keyBuf[sizeof(keyBuf)-1] = '\0';
if (has_upper && has_lower && has_num)
printf("\t\t\"%s\";\n", keyBuf);
else
/* Try again. For this reason, keyNum must be signed. */
keyNum--;
}
printf("\t}\n}\n\n");
exit(0);
}
void unrealircdctl_spkifp(int argc, char *argv[])
{
char *file = argv[2];
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
SSL *ssl;
X509 *cert;
const char *spkifp;
if (!ctx)
{
printf("Internal failure while initializing SSL/TLS library context\n");
exit(1);
}
if (!file)
{
printf("NOTE: This script uses the default certificate location (any set::tls settings\n"
"are ignored). If this is not what you want then specify a certificate\n"
"explicitly like this: %s spkifp conf/tls/example.pem\n\n", UNREALCMD);
safe_strdup(file, "tls/server.cert.pem");
convert_to_absolute_path(&file, CONFDIR);
}
if (!file_exists(file))
{
printf("Could not open certificate: %s\n"
"You can specify a certificate like this: %s spkifp conf/tls/example.pem\n",
UNREALCMD, file);
exit(1);
}
if (SSL_CTX_use_certificate_chain_file(ctx, file) <= 0)
{
printf("Could not read certificate '%s'\n", file);
exit(1);
}
ssl = SSL_new(ctx);
if (!ssl)
{
printf("Something went wrong when generating the SPKI fingerprint.\n");
exit(1);
}
cert = SSL_get_certificate(ssl);
spkifp = spki_fingerprint_ex(cert);
printf("The SPKI fingerprint for certificate '%s' is:\n"
"%s\n"
"\n"
"You normally add this password on the other side of the link as:\n"
"password \"%s\" { spkifp; };\n"
"\n",
file, spkifp, spkifp);
exit(0);
}
int main(int argc, char *argv[])
{
#ifdef _WIN32
chdir(".."); /* go up one level from "bin" */
init_winsock();
#endif
dbuf_init();
init_random();
early_init_tls();
if (argc == 1)
unrealircdctl_usage(argv[0]);
if (!strcmp(argv[1], "rehash"))
unrealircdctl_rehash();
else if (!strcmp(argv[1], "reloadtls"))
unrealircdctl_reloadtls();
else if (!strcmp(argv[1], "status"))
unrealircdctl_status();
else if (!strcmp(argv[1], "module-status"))
unrealircdctl_module_status();
else if (!strcmp(argv[1], "mkpasswd"))
unrealircdctl_mkpasswd(argc, argv);
else if (!strcmp(argv[1], "gencloak"))
unrealircdctl_gencloak(argc, argv);
else if (!strcmp(argv[1], "spkifp") || !strcmp(argv[1], "spki"))
unrealircdctl_spkifp(argc, argv);
else
unrealircdctl_usage(argv[0]);
exit(0);
}

View File

@ -1083,6 +1083,7 @@ MODVAR const char *floodoption_names[] = {
"knock-flood",
"max-concurrent-conversations",
"lag-penalty",
"vhost-flood",
NULL
};

View File

@ -7,7 +7,7 @@ echo "Extracting src/version.c..."
if [ -d ../.git ]; then
SUFFIX="-$(git rev-parse --short HEAD)"
fi
id="6.0.1.1$SUFFIX"
id="6.0.3$SUFFIX"
echo "$id"
if test -r version.c

View File

@ -3,7 +3,7 @@
<assemblyIdentity
processorArchitecture="amd64"
name="UnrealIRCd.UnrealIRCd.6"
version="6.0.1.0"
version="6.0.3.0"
type="win32"
/>
<description>Internet Relay Chat Daemon</description>
@ -12,7 +12,7 @@
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.1.0"
version="6.0.0.0"
processorArchitecture="amd64"
publicKeyToken="6595b64144ccf1df"
language="*"

View File

@ -188,7 +188,6 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
MSG msg;
unsigned char *s;
HWND hWnd;
WSADATA WSAData;
HICON hIcon;
SC_HANDLE hService, hSCManager;
SERVICE_TABLE_ENTRY DispatchTable[] =
@ -250,12 +249,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
if (!LoadLibrary("riched20.dll"))
LoadLibrary("riched32.dll");
InitDebug();
if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
{
MessageBox(NULL, "Unable to initialize WinSock", "UnrealIRCD Initalization Error", MB_OK);
return FALSE;
}
init_winsock();
hInst = hInstance;
MainDlgBackground = CreateSolidBrush(RGB(75, 134, 238)); /* Background of main dialog */

View File

@ -90,7 +90,6 @@ VOID WINAPI IRCDCtrlHandler(DWORD opcode)
*/
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
WSADATA WSAData;
DWORD error = 0;
char path[MAX_PATH], *folder;
@ -121,13 +120,7 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
GetOSName(OSName);
InitDebug();
/* Initialize Winsocks */
if ((error = WSAStartup(MAKEWORD(1, 1), &WSAData)) != 0)
{
SetServiceStop(error);
return;
}
init_winsock();
/* Initialize the IRCd */
if ((error = InitUnrealIRCd(dwArgc, lpszArgv)) != 1)

View File

@ -6,7 +6,7 @@
[Setup]
AppName=UnrealIRCd 6
AppVerName=UnrealIRCd 6.0.1.1
AppVerName=UnrealIRCd 6.0.3
AppPublisher=UnrealIRCd Team
AppPublisherURL=https://www.unrealircd.org
AppSupportURL=https://www.unrealircd.org
@ -45,6 +45,7 @@ Name: "fixperm"; Description: "Make UnrealIRCd folder writable by current user";
; UnrealIRCd binaries
Source: "UnrealIRCd.exe"; DestDir: "{app}\bin"; Flags: ignoreversion signonce
Source: "UnrealIRCd.pdb"; DestDir: "{app}\bin"; Flags: ignoreversion
Source: "unrealircdctl.exe"; DestDir: "{app}\bin"; Flags: ignoreversion signonce
Source: "unrealsvc.exe"; DestDir: "{app}\bin"; Flags: ignoreversion signonce
; TLS certificate generation helpers

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
processorArchitecture="amd64"
name="UnrealIRCd.UnrealIRCd.6"
version="6.0.1.0"
type="win32"
/>
<description>UnrealIRCd - Control utility</description>
</assembly>

View File

@ -2,6 +2,7 @@
PID_FILE="@PIDFILE@"
PID_BACKUP="@PIDFILE@.bak"
UNREALIRCDCTL="@BINDIR@/unrealircdctl"
# When built with --with-asan, ASan does not dump core by default because
# older gcc/clang might dump a 16TB core file. We explicitly enable it here.
@ -87,16 +88,13 @@ elif [ "$1" = "stop" ] ; then
kill -9 `cat $PID_FILE` 1>/dev/null 2>&1
fi
elif [ "$1" = "rehash" ] ; then
echo "Rehashing UnrealIRCd"
if [ ! -r $PID_FILE ] ; then
echo "ERROR: UnrealIRCd is not running"
exit 1
fi
kill -1 `cat $PID_FILE`
if [ "$?" != 0 ]; then
echo "ERROR: UnrealIRCd is not running"
exit 1
fi
$UNREALIRCDCTL $*
elif [ "$1" = "status" ] ; then
$UNREALIRCDCTL $*
elif [ "$1" = "module-status" ] ; then
$UNREALIRCDCTL $*
elif [ "$1" = "reloadtls" ] ; then
$UNREALIRCDCTL $*
elif [ "$1" = "restart" ] ; then
echo "Restarting UnrealIRCd"
$0 stop
@ -117,23 +115,12 @@ elif [ "$1" = "configtest" ] ; then
elif [ "$1" = "module" ] ; then
shift
@BINDIR@/unrealircd -m $*
elif [ "$1" = "reloadtls" ] ; then
echo "Reloading SSL/TLS certificates"
if [ ! -r $PID_FILE ] ; then
echo "ERROR: UnrealIRCd is not running"
exit 1
fi
kill -USR1 `cat $PID_FILE`
if [ "$?" != 0 ]; then
echo "ERROR: UnrealIRCd is not running"
exit 1
fi
elif [ "$1" = "mkpasswd" ] ; then
@BINDIR@/unrealircd -P $2 $3
$UNREALIRCDCTL $*
elif [ "$1" = "version" ] ; then
@BINDIR@/unrealircd -v
elif [ "$1" = "gencloak" ] ; then
@BINDIR@/unrealircd -k
$UNREALIRCDCTL $*
elif [ "$1" = "backtrace" ] ; then
cd @TMPDIR@
@ -224,34 +211,7 @@ __EOF__
echo ""
echo "Thanks!"
elif [ "$1" = "spki" -o "$1" = "spkifp" ] ; then
CERT="@CONFDIR@/tls/server.cert.pem"
if [ "$2" != "" ]; then
CERT="$2"
else
echo "NOTE: This script uses the default certificate location (any set::tls settings"
echo "are ignored). If this is not what you want then specify a certificate"
echo "explicitly like this: ./unrealircd spkifp conf/tls/example.pem"
echo ""
fi
if [ ! -f "$CERT" ]; then
echo "Could not open certificate: $CERT"
echo "You can specify a certificate like this: ./unrealircd spkifp conf/tls/example.pem"
exit 1
fi
openssl x509 -noout -in "$CERT" -pubkey | openssl asn1parse -noout -inform pem -out @TMPDIR@/tmp.public.key
HASH="`openssl dgst -sha256 -binary @TMPDIR@/tmp.public.key | openssl enc -base64`"
rm -f @TMPDIR@/tmp.public.key
if [ "$HASH" = "" ]; then
echo "Sorry, something went wrong when generating the SPKI fingerprint."
echo "Is the 'openssl' tool properly installed?"
exit 1
fi
echo "The SPKI fingerprint for certificate $CERT is:"
echo "$HASH"
echo ""
echo "You normally add this password on the other side of the link as:"
echo "password \"$HASH\" { spkifp; };"
echo ""
$UNREALIRCDCTL $*
elif [ "$1" = "hot-patch" -o "$1" = "cold-patch" ] ; then
if [ ! -d "@BUILDDIR@" ]; then
echo "UnrealIRCd source not found. Sorry, it is not possible to patch."
@ -282,6 +242,11 @@ elif [ "$1" = "hot-patch" -o "$1" = "cold-patch" ] ; then
exit 1
fi
if ! patch --dry-run -p1 -N <patch 1>/dev/null 2>&1; then
echo "Patch failed to apply (no files changed)"
exit 1
fi
if ! patch -p1 <patch; then
echo "Patch failed to apply"
exit 1
@ -291,11 +256,18 @@ elif [ "$1" = "hot-patch" -o "$1" = "cold-patch" ] ; then
make || gmake || exit 1
make install || gmake install || exit 1
cd -
cd @SCRIPTDIR@
if [ "$1" = "hot-patch" ]; then
echo "Patch applied successfully and installed. Rehashing your IRCd..."
./unrealircd rehash
echo "Done! All should be good now."
if ./unrealircd rehash; then
echo "Patch installed and server rehashed correctly. All should be good now!"
else
echo "Patching the source code and recompiling succeeded,"
echo "however rehashing the current UnrealIRCd process FAILED"
echo "so it is NOT running the patched code yet."
echo "IMPORTANT: Check error output above!"
exit 1
fi
else
echo "Patch applied successfully. You must now restart your IRC server."
fi
@ -316,6 +288,8 @@ else
echo "unrealircd rehash Reload the configuration file"
echo "unrealircd reloadtls Reload the SSL/TLS certificates"
echo "unrealircd restart Restart the IRC Server (stop+start)"
echo "unrealircd status Show current status of the IRC Server"
echo "unrealircd module-status Show all currently loaded modules"
echo "unrealircd upgrade Upgrade UnrealIRCd to the latest version"
echo "unrealircd upgrade-conf Upgrade the configuration file from UnrealIRCd"
echo " 3.2.x/4.x to 5.x format"