mirror of
git://git.acid.vegas/unrealircd.git
synced 2024-11-27 02:16:39 +00:00
Updated to 6.1.0
This commit is contained in:
parent
66d0369626
commit
d53bf1d1c0
29
Config
29
Config
@ -280,7 +280,7 @@ OPEROVERRIDEVERIFY=""
|
||||
GENCERTIFICATE="1"
|
||||
EXTRAPARA=""
|
||||
SANITIZER=""
|
||||
GEOIP="none"
|
||||
GEOIP="classic"
|
||||
if [ "`eval echo -n 'a'`" = "-n a" ] ; then
|
||||
c="\c"
|
||||
else
|
||||
@ -364,7 +364,7 @@ fi
|
||||
clear
|
||||
|
||||
if [ -f "doc/Config.header" -a -z "$NOINTRO" ] ; then
|
||||
more doc/Config.header
|
||||
cat doc/Config.header
|
||||
echo ""
|
||||
echo $n "[Press Enter to continue]"
|
||||
read cc
|
||||
@ -375,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.4.1 unrealircd-6.0.4 unrealircd-6.0.4-rc2 unrealircd-6.0.4-rc1 unrealircd-6.0.3 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"
|
||||
UNREALRELEASES="unrealircd-6.1.0-rc2 unrealircd-6.1.0-rc1 unrealircd-6.0.7 unrealircd-6.0.6 unrealircd-6.0.5 unrealircd-6.0.5-rc2 unrealircd-6.0.5-rc1 unrealircd-6.0.4.2 unrealircd-6.0.4.1 unrealircd-6.0.4 unrealircd-6.0.4-rc2 unrealircd-6.0.4-rc1 unrealircd-6.0.3 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
|
||||
@ -527,6 +527,29 @@ else
|
||||
SSLDIR=`eval echo $cc` # modified
|
||||
fi
|
||||
|
||||
if [ "$SSLDIR" != "" -a "$SSLDIR" != "/usr" ]; then
|
||||
echo ""
|
||||
echo "You answered previous question manually. Just note that if the library is not"
|
||||
echo "in your default library path then UnrealIRCd may fail to start with an error"
|
||||
echo "that it cannot find certain .so files (libraries). In that case you would have"
|
||||
echo "to either set the LD_LIBARY_PATH environment variable, or you could update the"
|
||||
echo "Makefile to link with -Wl,-rpath,$SSLDIR or similar."
|
||||
echo ""
|
||||
if [ "$SSLDIR" = "/usr/local" ]; then
|
||||
echo "**** CAUTION ****"
|
||||
echo "You have chosen to use OpenSSL from /usr/local. Just be aware that if you"
|
||||
echo "use the LD_LIBRARY_PATH or -Wl,-rpath,$SSLDIR from above,"
|
||||
echo "that you are diverting OTHER libraries to that path as well."
|
||||
echo "It's not only loading OpenSSL from /usr/local but also potentially other"
|
||||
echo "libraries like PCRE2, Jansson, or any of the other libraries that"
|
||||
echo "UnrealIRCd uses (including dependencies about 40 libs in total!)"
|
||||
echo "All that can result in weird issues and crashes!"
|
||||
echo ""
|
||||
fi
|
||||
echo "Press enter to continue with the rest of the questions, or CTRL+C to abort."
|
||||
read cc
|
||||
fi
|
||||
|
||||
TEST=""
|
||||
while [ -z "$TEST" ] ; do
|
||||
if [ "$REMOTEINC" = "1" ] ; then
|
||||
|
@ -199,6 +199,9 @@ install: all
|
||||
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@/extbans
|
||||
@rm -f $(DESTDIR)@MODULESDIR@/extbans/*.so 1>/dev/null 2>&1
|
||||
$(INSTALL) -m 0700 src/modules/extbans/*.so $(DESTDIR)@MODULESDIR@/extbans
|
||||
$(INSTALL) -m 0700 -d $(DESTDIR)@MODULESDIR@/rpc
|
||||
@rm -f $(DESTDIR)@MODULESDIR@/rpc/*.so 1>/dev/null 2>&1
|
||||
$(INSTALL) -m 0700 src/modules/rpc/*.so $(DESTDIR)@MODULESDIR@/rpc
|
||||
@#If the conf/ssl directory exists then rename it here to conf/tls
|
||||
@#and add a symlink for backwards compatibility (so that f.e. certbot
|
||||
@#doesn't randomly fail after an upgrade to U5).
|
||||
|
@ -184,13 +184,13 @@ EXP_OBJ_FILES=src/ircd_vars.obj src/channel.obj src/send.obj src/socket.obj \
|
||||
src/version.obj src/ircsprintf.obj \
|
||||
src/scache.obj src/dns.obj src/modules.obj \
|
||||
src/aliases.obj src/api-event.obj src/api-usermode.obj src/auth.obj src/tls.obj \
|
||||
src/random.obj src/api-channelmode.obj src/api-moddata.obj src/mempool.obj \
|
||||
src/random.obj src/api-channelmode.obj src/api-moddata.obj src/api-rpc.obj src/mempool.obj \
|
||||
src/dispatch.obj src/api-isupport.obj src/api-command.obj \
|
||||
src/api-clicap.obj src/api-messagetag.obj src/api-history-backend.obj \
|
||||
src/api-extban.obj src/api-efunctions.obj src/crypt_blowfish.obj \
|
||||
src/operclass.obj src/crashreport.obj src/unrealdb.obj \
|
||||
src/openssl_hostname_validation.obj \
|
||||
src/utf8.obj src/log.obj $(CURLOBJ)
|
||||
src/utf8.obj src/json.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/ircd.obj src/proc_io_client.obj
|
||||
@ -253,6 +253,7 @@ DLL_FILES=\
|
||||
src/modules/clienttagdeny.dll \
|
||||
src/modules/close.dll \
|
||||
src/modules/connect.dll \
|
||||
src/modules/connect-flood.dll \
|
||||
src/modules/connthrottle.dll \
|
||||
src/modules/creationtime.dll \
|
||||
src/modules/cycle.dll \
|
||||
@ -265,6 +266,7 @@ DLL_FILES=\
|
||||
src/modules/extbans/country.dll \
|
||||
src/modules/extbans/inchannel.dll \
|
||||
src/modules/extbans/join.dll \
|
||||
src/modules/extbans/flood.dll \
|
||||
src/modules/extbans/msgbypass.dll \
|
||||
src/modules/extbans/nickchange.dll \
|
||||
src/modules/extbans/operclass.dll \
|
||||
@ -305,6 +307,7 @@ DLL_FILES=\
|
||||
src/modules/locops.dll \
|
||||
src/modules/lusers.dll \
|
||||
src/modules/map.dll \
|
||||
src/modules/max-unknown-connections-per-ip.dll \
|
||||
src/modules/md.dll \
|
||||
src/modules/message.dll \
|
||||
src/modules/message-ids.dll \
|
||||
@ -329,11 +332,23 @@ DLL_FILES=\
|
||||
src/modules/plaintext-policy.dll \
|
||||
src/modules/protoctl.dll \
|
||||
src/modules/quit.dll \
|
||||
src/modules/real-quit-reason.dll \
|
||||
src/modules/reply-tag.dll \
|
||||
src/modules/reputation.dll \
|
||||
src/modules/require-module.dll \
|
||||
src/modules/restrict-commands.dll \
|
||||
src/modules/rmtkl.dll \
|
||||
src/modules/rpc/channel.dll \
|
||||
src/modules/rpc/log.dll \
|
||||
src/modules/rpc/name_ban.dll \
|
||||
src/modules/rpc/rpc.dll \
|
||||
src/modules/rpc/stats.dll \
|
||||
src/modules/rpc/server.dll \
|
||||
src/modules/rpc/server_ban.dll \
|
||||
src/modules/rpc/server_ban_exception.dll \
|
||||
src/modules/rpc/spamfilter.dll \
|
||||
src/modules/rpc/whowas.dll \
|
||||
src/modules/rpc/user.dll \
|
||||
src/modules/rules.dll \
|
||||
src/modules/sajoin.dll \
|
||||
src/modules/samode.dll \
|
||||
@ -353,12 +368,15 @@ DLL_FILES=\
|
||||
src/modules/slog.dll \
|
||||
src/modules/sqline.dll \
|
||||
src/modules/squit.dll \
|
||||
src/modules/sreply.dll \
|
||||
src/modules/staff.dll \
|
||||
src/modules/standard-replies.dll \
|
||||
src/modules/starttls.dll \
|
||||
src/modules/stats.dll \
|
||||
src/modules/sts.dll \
|
||||
src/modules/svsjoin.dll \
|
||||
src/modules/svskill.dll \
|
||||
src/modules/svslogin.dll \
|
||||
src/modules/svslusers.dll \
|
||||
src/modules/svsmode.dll \
|
||||
src/modules/svsmotd.dll \
|
||||
@ -376,6 +394,7 @@ DLL_FILES=\
|
||||
src/modules/time.dll \
|
||||
src/modules/tkl.dll \
|
||||
src/modules/tkldb.dll \
|
||||
src/modules/tline.dll \
|
||||
src/modules/tls_antidos.dll \
|
||||
src/modules/tls_cipher.dll \
|
||||
src/modules/topic.dll \
|
||||
@ -407,10 +426,13 @@ DLL_FILES=\
|
||||
src/modules/watch.dll \
|
||||
src/modules/webirc.dll \
|
||||
src/modules/webredir.dll \
|
||||
src/modules/webserver.dll \
|
||||
src/modules/websocket.dll \
|
||||
src/modules/websocket_common.dll \
|
||||
src/modules/whois.dll \
|
||||
src/modules/who_old.dll \
|
||||
src/modules/whowas.dll \
|
||||
src/modules/whowasdb.dll \
|
||||
src/modules/whox.dll
|
||||
|
||||
|
||||
@ -582,6 +604,9 @@ src/api-channelmode.obj: src/api-channelmode.c $(INCLUDES)
|
||||
src/api-moddata.obj: src/api-moddata.c $(INCLUDES)
|
||||
$(CC) $(CFLAGS) src/api-moddata.c
|
||||
|
||||
src/api-rpc.obj: src/api-rpc.c $(INCLUDES)
|
||||
$(CC) $(CFLAGS) src/api-rpc.c
|
||||
|
||||
src/mempool.obj: src/mempool.c $(INCLUDES)
|
||||
$(CC) $(CFLAGS) src/mempool.c
|
||||
|
||||
@ -633,6 +658,9 @@ src/utf8.obj: src/utf8.c $(INCLUDES) ./include/dbuf.h
|
||||
src/openssl_hostname_validation.obj: src/openssl_hostname_validation.c $(INCLUDES) ./include/dbuf.h
|
||||
$(CC) $(CFLAGS) src/openssl_hostname_validation.c
|
||||
|
||||
src/json.obj: src/json.c $(INCLUDES) ./include/dbuf.h
|
||||
$(CC) $(CFLAGS) src/json.c
|
||||
|
||||
src/log.obj: src/log.c $(INCLUDES) ./include/dbuf.h
|
||||
$(CC) $(CFLAGS) src/log.c
|
||||
|
||||
@ -832,6 +860,9 @@ src/modules/close.dll: src/modules/close.c $(INCLUDES)
|
||||
src/modules/connect.dll: src/modules/connect.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/connect.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/connect.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/connect-flood.dll: src/modules/connect-flood.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/connect-flood.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/connect-flood.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/connthrottle.dll: src/modules/connthrottle.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/connthrottle.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/connthrottle.pdb $(MODLFLAGS)
|
||||
|
||||
@ -868,6 +899,9 @@ src/modules/extbans/inchannel.dll: src/modules/extbans/inchannel.c $(INCLUDES)
|
||||
src/modules/extbans/join.dll: src/modules/extbans/join.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/extbans/join.c /Fesrc/modules/extbans/ /Fosrc/modules/extbans/ /Fdsrc/modules/extbans/join.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/extbans/flood.dll: src/modules/extbans/flood.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/extbans/flood.c /Fesrc/modules/extbans/ /Fosrc/modules/extbans/ /Fdsrc/modules/extbans/flood.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/extbans/msgbypass.dll: src/modules/extbans/msgbypass.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/extbans/msgbypass.c /Fesrc/modules/extbans/ /Fosrc/modules/extbans/ /Fdsrc/modules/extbans/msgbypass.pdb $(MODLFLAGS)
|
||||
|
||||
@ -991,6 +1025,9 @@ src/modules/lusers.dll: src/modules/lusers.c $(INCLUDES)
|
||||
src/modules/map.dll: src/modules/map.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/map.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/map.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/max-unknown-connections-per-ip.dll: src/modules/max-unknown-connections-per-ip.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/max-unknown-connections-per-ip.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/max-unknown-connections-per-ip.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/md.dll: src/modules/md.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/md.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/md.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1063,6 +1100,9 @@ src/modules/protoctl.dll: src/modules/protoctl.c $(INCLUDES)
|
||||
src/modules/quit.dll: src/modules/quit.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/quit.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/quit.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/real-quit-reason.dll: src/modules/real-quit-reason.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/real-quit-reason.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/real-quit-reason.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/reply-tag.dll: src/modules/reply-tag.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/reply-tag.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/reply-tag.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1078,6 +1118,39 @@ src/modules/restrict-commands.dll: src/modules/restrict-commands.c $(INCLUDES)
|
||||
src/modules/rmtkl.dll: src/modules/rmtkl.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rmtkl.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/rmtkl.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/channel.dll: src/modules/rpc/channel.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/channel.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/channel.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/log.dll: src/modules/rpc/log.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/log.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/log.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/name_ban.dll: src/modules/rpc/name_ban.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/name_ban.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/name_ban.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/rpc.dll: src/modules/rpc/rpc.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/rpc.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/rpc.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/stats.dll: src/modules/rpc/stats.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/stats.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/stats.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/server.dll: src/modules/rpc/server.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/server.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/server.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/server_ban.dll: src/modules/rpc/server_ban.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/server_ban.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/server_ban.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/server_ban_exception.dll: src/modules/rpc/server_ban_exception.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/server_ban_exception.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/server_ban_exception.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/spamfilter.dll: src/modules/rpc/spamfilter.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/spamfilter.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/spamfilter.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/user.dll: src/modules/rpc/user.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/user.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/user.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rpc/whowas.dll: src/modules/rpc/whowas.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rpc/whowas.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/whowas.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/rules.dll: src/modules/rules.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/rules.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/rules.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1135,9 +1208,15 @@ src/modules/sqline.dll: src/modules/sqline.c $(INCLUDES)
|
||||
src/modules/squit.dll: src/modules/squit.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/squit.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/squit.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/sreply.dll: src/modules/sreply.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/sreply.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/sreply.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/staff.dll: src/modules/staff.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/staff.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/staff.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/standard-replies.dll: src/modules/standard-replies.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/standard-replies.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/standard-replies.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/starttls.dll: src/modules/starttls.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/starttls.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/starttls.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1153,6 +1232,9 @@ src/modules/svsjoin.dll: src/modules/svsjoin.c $(INCLUDES)
|
||||
src/modules/svskill.dll: src/modules/svskill.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/svskill.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/svskill.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/svslogin.dll: src/modules/svslogin.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/svslogin.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/svslogin.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/svslusers.dll: src/modules/svslusers.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/svslusers.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/svslusers.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1204,6 +1286,9 @@ src/modules/tkl.dll: src/modules/tkl.c $(INCLUDES)
|
||||
src/modules/tkldb.dll: src/modules/tkldb.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/tkldb.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/tkldb.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/tline.dll: src/modules/tline.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/tline.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/tline.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/tls_antidos.dll: src/modules/tls_antidos.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/tls_antidos.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/tls_antidos.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1297,9 +1382,15 @@ src/modules/webirc.dll: src/modules/webirc.c $(INCLUDES)
|
||||
src/modules/webredir.dll: src/modules/webredir.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/webredir.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/webredir.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/webserver.dll: src/modules/webserver.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/webserver.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/webserver.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/websocket.dll: src/modules/websocket.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/websocket.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/websocket.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/websocket_common.dll: src/modules/websocket_common.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/websocket_common.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/websocket_common.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/whois.dll: src/modules/whois.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/whois.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/whois.pdb $(MODLFLAGS)
|
||||
|
||||
@ -1309,6 +1400,9 @@ src/modules/who_old.dll: src/modules/who_old.c $(INCLUDES)
|
||||
src/modules/whowas.dll: src/modules/whowas.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/whowas.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/whowas.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/whowasdb.dll: src/modules/whowasdb.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/whowasdb.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/whowasdb.pdb $(MODLFLAGS)
|
||||
|
||||
src/modules/whox.dll: src/modules/whox.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/whox.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/whox.pdb $(MODLFLAGS)
|
||||
|
||||
|
45
README.md
45
README.md
@ -11,55 +11,18 @@ online documentation.
|
||||
|
||||
## Versions
|
||||
* UnrealIRCd 6 is the *stable* series since December 2021. All new features go in there.
|
||||
* UnrealIRCd 5 is the *oldstable* series. It will receive bug fixes until
|
||||
July 1, 2022 plus another 12 months of security fixes.
|
||||
* UnrealIRCd 5 is the *oldstable* series. It is End Of Life. Only security bugs will
|
||||
be fixed until June 30, 2023, after which all support will stop.
|
||||
* For full details of release scheduling and EOL dates, see
|
||||
[UnrealIRCd releases](https://www.unrealircd.org/docs/UnrealIRCd_releases) on the wiki
|
||||
|
||||
## How to get started
|
||||
### Use the wiki!
|
||||
**IMPORTANT:** We recommend you follow our installation guide on the wiki instead of the
|
||||
steps in this README. The wiki has more detailed information and is more easy to navigate.
|
||||
Follow the installation guide on the wiki. See:
|
||||
* [Installing from source for *NIX](https://www.unrealircd.org/docs/Installing_from_source)
|
||||
* [Installating instructions for Windows](https://www.unrealircd.org/docs/Installing_(Windows))
|
||||
|
||||
Please consult the online documentation at https://www.unrealircd.org/docs/ when setting up the IRCd!
|
||||
|
||||
### Step 1: Installation
|
||||
#### Windows
|
||||
Simply download the UnrealIRCd Windows version from www.unrealircd.org
|
||||
|
||||
Alternatively you can compile UnrealIRCd for Windows yourself. However this is not straightforward and thus not recommended.
|
||||
|
||||
#### *BSD/Linux/macOS
|
||||
Do the following steps under a separate account for running UnrealIRCd,
|
||||
[do NOT compile or run as root](https://www.unrealircd.org/docs/Do_not_run_as_root).
|
||||
|
||||
### Step 1: Compile the IRCd
|
||||
|
||||
* Run `./Config`
|
||||
* Run `make`
|
||||
* Run `make install`
|
||||
* Now change to the directory where you installed UnrealIRCd, e.g. `cd /home/xxxx/unrealircd`
|
||||
|
||||
### Step 2: Configuration
|
||||
Configuration files are stored in the `conf/` folder by default (eg: `/home/xxxx/unrealircd/conf`)
|
||||
|
||||
#### Create a configuration file
|
||||
If you are new, then you need to create your own configuration file:
|
||||
Copy `conf/examples/example.conf` to `conf/` and call it `unrealircd.conf`.
|
||||
Then open it in an editor and carefully modify it using the documentation and FAQ as a guide (see below).
|
||||
|
||||
### Step 3: Booting
|
||||
|
||||
#### Linux/*BSD/macOS
|
||||
Run `./unrealircd start` in the directory where you installed UnrealIRCd.
|
||||
|
||||
#### Windows
|
||||
Start -> All Programs -> UnrealIRCd -> UnrealIRCd
|
||||
|
||||
## Documentation & FAQ
|
||||
You can find the **documentation** online at: https://www.unrealircd.org/docs/
|
||||
You can find all **documentation** online at: https://www.unrealircd.org/docs/
|
||||
|
||||
We also have a good **FAQ**: https://www.unrealircd.org/docs/FAQ
|
||||
|
||||
|
@ -97,7 +97,7 @@ AC_DEFUN([CHECK_LIBCURL],
|
||||
with the system-installed libcURL, this is a bad idea which may result in error
|
||||
messages looking like:
|
||||
|
||||
\`\`[error] unrealircd.conf:9: include: error downloading '(http://example.net/ex.conf)': Could not resolve host: example.net (Successful completion)''
|
||||
error downloading ... Could not resolve host: example.net (Successful completion)
|
||||
|
||||
Or UnrealIRCd might even crash.
|
||||
|
||||
@ -321,6 +321,26 @@ else
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([CHECK_X509_check_host],
|
||||
[
|
||||
AC_MSG_CHECKING([for X509_check_host in SSL library])
|
||||
AC_LANG_PUSH(C)
|
||||
SAVE_LIBS="$LIBS"
|
||||
LIBS="$LIBS $CRYPTOLIB"
|
||||
AC_TRY_LINK([#include <openssl/x509v3.h>],
|
||||
[X509_check_host(NULL, NULL, 0, 0, NULL);],
|
||||
has_function=1,
|
||||
has_function=0)
|
||||
LIBS="$SAVE_LIBS"
|
||||
AC_LANG_POP(C)
|
||||
if test $has_function = 1; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAS_X509_check_host], [], [Define if ssl library has X509_check_host])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl For geoip-api-c
|
||||
AC_DEFUN([CHECK_GEOIP_CLASSIC],
|
||||
[
|
||||
@ -366,6 +386,7 @@ AC_DEFUN([CHECK_GEOIP_CLASSIC],
|
||||
AC_MSG_RESULT(compiling GeoIP Classic library)
|
||||
$ac_cv_prog_MAKER || exit 1
|
||||
AC_MSG_RESULT(installing GeoIP Classic library)
|
||||
rm -f "$PRIVATELIBDIR/"libGeoIP.so*
|
||||
$ac_cv_prog_MAKER install || exit 1
|
||||
dnl Try pkg-config first...
|
||||
AS_IF([test -n "$ac_cv_path_PKGCONFIG"],
|
||||
|
45
configure.ac
45
configure.ac
@ -7,7 +7,7 @@ dnl src/windows/unrealinst.iss
|
||||
dnl doc/Config.header
|
||||
dnl src/version.c.SH
|
||||
|
||||
AC_INIT([unrealircd], [6.0.4.2], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
|
||||
AC_INIT([unrealircd], [6.1.0], [https://bugs.unrealircd.org/], [], [https://unrealircd.org/])
|
||||
AC_CONFIG_SRCDIR([src/ircd.c])
|
||||
AC_CONFIG_HEADER([include/setup.h])
|
||||
AC_CONFIG_AUX_DIR([autoconf])
|
||||
@ -30,17 +30,17 @@ UNREAL_VERSION_GENERATION=["6"]
|
||||
AC_DEFINE_UNQUOTED([UNREAL_VERSION_GENERATION], [$UNREAL_VERSION_GENERATION], [Generation version number (e.g.: X for X.Y.Z)])
|
||||
|
||||
# Major version number (e.g.: Y in X.Y.Z)
|
||||
UNREAL_VERSION_MAJOR=["0"]
|
||||
UNREAL_VERSION_MAJOR=["1"]
|
||||
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=["4"]
|
||||
UNREAL_VERSION_MINOR=["0"]
|
||||
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=[".2"]
|
||||
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)
|
||||
@ -257,6 +257,9 @@ check_cc_flag([-Wsign-compare], [CFLAGS="$CFLAGS -Wno-sign-compare"])
|
||||
dnl Don't warn about empty body, we use this, eg via Debug(()) or in if's.
|
||||
check_cc_flag([-Wempty-body], [CFLAGS="$CFLAGS -Wno-empty-body"])
|
||||
|
||||
dnl This warns about all our hook calls - RunHook() and others
|
||||
check_cc_flag([-Wdeprecated-non-prototype], [CFLAGS="$CFLAGS -Wno-deprecated-non-prototype"])
|
||||
|
||||
dnl Yeah this old clang version is a bit problematic
|
||||
dnl (ships in Ubuntu 16.04 for example)
|
||||
dnl -Wtautological-compare has false positives
|
||||
@ -326,7 +329,7 @@ fi
|
||||
])
|
||||
AC_CACHE_CHECK(if your system prepends an underscore on symbols,ac_cv_underscore,[
|
||||
cat >uscore.c << __EOF__
|
||||
int main() {
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
__EOF__
|
||||
@ -354,7 +357,8 @@ AC_CACHE_CHECK([if your system has IPv6 support], [ac_cv_ip6], [
|
||||
AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
int main() {
|
||||
#include <stdlib.h>
|
||||
int main(void) {
|
||||
int s = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
exit(0); /* We only check if the code compiles, that's enough. We can deal with missing runtime IPv6 */
|
||||
}
|
||||
@ -405,6 +409,7 @@ AC_CHECK_FUNCS([setproctitle],
|
||||
|
||||
AC_CHECK_FUNCS(explicit_bzero,AC_DEFINE([HAVE_EXPLICIT_BZERO], [], [Define if you have explicit_bzero]))
|
||||
AC_CHECK_FUNCS(syslog,AC_DEFINE([HAVE_SYSLOG], [], [Define if you have syslog]))
|
||||
AC_CHECK_FUNCS(strnlen,AC_DEFINE([HAVE_STRNLEN], [], [Define if you have strnlen]))
|
||||
AC_SUBST(CRYPTOLIB)
|
||||
AC_SUBST(MODULEFLAGS)
|
||||
AC_SUBST(DYNAMIC_LDFLAGS)
|
||||
@ -547,6 +552,7 @@ CHECK_SSL_CTX_SET_MIN_PROTO_VERSION
|
||||
CHECK_SSL_CTX_SET_SECURITY_LEVEL
|
||||
CHECK_ASN1_TIME_diff
|
||||
CHECK_X509_get0_notAfter
|
||||
CHECK_X509_check_host
|
||||
AC_ARG_ENABLE(dynamic-linking, [AS_HELP_STRING([--disable-dynamic-linking], [Make the IRCd statically link with shared objects rather than dynamically (noone knows if disabling dynamic linking actually does anything or not)])],
|
||||
[enable_dynamic_linking=$enableval], [enable_dynamic_linking="yes"])
|
||||
AS_IF([test $enable_dynamic_linking = "yes"],
|
||||
@ -580,12 +586,12 @@ export PATH_SEPARATOR
|
||||
dnl Use system pcre2 when available, unless --without-system-pcre2.
|
||||
has_system_pcre2="no"
|
||||
AS_IF([test "x$with_system_pcre2" = "xyes"],[
|
||||
PKG_CHECK_MODULES([PCRE2], libpcre2-8 >= 10.00,[has_system_pcre2=yes
|
||||
PKG_CHECK_MODULES([PCRE2], libpcre2-8 >= 10.36,[has_system_pcre2=yes
|
||||
AS_IF([test "x$PRIVATELIBDIR" != "x"], [rm -f "$PRIVATELIBDIR/"libpcre2*])],[has_system_pcre2=no])])
|
||||
|
||||
AS_IF([test "$has_system_pcre2" = "no"], [
|
||||
dnl REMEMBER TO CHANGE WITH A NEW PCRE2 RELEASE!
|
||||
pcre2_version="10.39"
|
||||
pcre2_version="10.42"
|
||||
AC_MSG_RESULT(extracting PCRE2 regex library)
|
||||
cur_dir=`pwd`
|
||||
cd extras
|
||||
@ -606,6 +612,7 @@ cd pcre2-$pcre2_version
|
||||
AC_MSG_RESULT(compiling PCRE2 regex library)
|
||||
$ac_cv_prog_MAKER || exit 1
|
||||
AC_MSG_RESULT(installing PCRE2 regex library)
|
||||
rm -f "$PRIVATELIBDIR/"libpcre2*
|
||||
$ac_cv_prog_MAKER install || exit 1
|
||||
PCRE2_CFLAGS="-I$cur_dir/extras/pcre2/include"
|
||||
AC_SUBST(PCRE2_CFLAGS)
|
||||
@ -631,7 +638,7 @@ AS_IF([test "x$PRIVATELIBDIR" != "x"], [rm -f "$PRIVATELIBDIR/"libargon2*])],[ha
|
||||
|
||||
AS_IF([test "$has_system_argon2" = "no"],[
|
||||
dnl REMEMBER TO CHANGE WITH A NEW ARGON2 RELEASE!
|
||||
argon2_version="20181209"
|
||||
argon2_version="20190702"
|
||||
AC_MSG_RESULT(extracting Argon2 library)
|
||||
cur_dir=`pwd`
|
||||
cd extras
|
||||
@ -639,12 +646,12 @@ dnl remove old argon2 directory to force a recompile...
|
||||
dnl and remove its installation prefix just to clean things up.
|
||||
rm -rf argon2-$argon2_version argon2
|
||||
if test "x$ac_cv_path_GUNZIP" = "x" ; then
|
||||
tar xfz argon2-$argon2_version.tar.gz
|
||||
tar xfz argon2.tar.gz
|
||||
else
|
||||
cp argon2-$argon2_version.tar.gz argon2-$argon2_version.tar.gz.bak
|
||||
gunzip -f argon2-$argon2_version.tar.gz
|
||||
cp argon2-$argon2_version.tar.gz.bak argon2-$argon2_version.tar.gz
|
||||
tar xf argon2-$argon2_version.tar
|
||||
cp argon2.tar.gz argon2.tar.gz.bak
|
||||
gunzip -f argon2.tar.gz
|
||||
cp argon2.tar.gz.bak argon2.tar.gz
|
||||
tar xf argon2.tar
|
||||
fi
|
||||
AC_MSG_RESULT(compiling Argon2 library)
|
||||
cd argon2-$argon2_version
|
||||
@ -699,6 +706,7 @@ CFLAGS="$save_cflags"
|
||||
AC_MSG_RESULT(compiling sodium resolver library)
|
||||
$ac_cv_prog_MAKER || exit 1
|
||||
AC_MSG_RESULT(installing sodium resolver library)
|
||||
rm -f "$PRIVATELIBDIR/"libsodium*
|
||||
$ac_cv_prog_MAKER install || exit 1
|
||||
SODIUM_CFLAGS="-I$cur_dir/extras/sodium/include"
|
||||
AC_SUBST(SODIUM_CFLAGS)
|
||||
@ -725,7 +733,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.18.1"
|
||||
cares_version="1.19.0"
|
||||
AC_MSG_RESULT(extracting c-ares resolver library)
|
||||
cur_dir=`pwd`
|
||||
cd extras
|
||||
@ -749,6 +757,7 @@ CFLAGS="$save_cflags"
|
||||
AC_MSG_RESULT(compiling c-ares resolver library)
|
||||
$ac_cv_prog_MAKER || exit 1
|
||||
AC_MSG_RESULT(installing c-ares resolver library)
|
||||
rm -f "$PRIVATELIBDIR/"libcares*
|
||||
$ac_cv_prog_MAKER install || exit 1
|
||||
CARES_CFLAGS="-I$cur_dir/extras/c-ares/include"
|
||||
AC_SUBST(CARES_CFLAGS)
|
||||
@ -799,7 +808,7 @@ AS_IF([test "x$PRIVATELIBDIR" != "x"], [rm -f "$PRIVATELIBDIR/"libjansson*])],[h
|
||||
|
||||
AS_IF([test "$has_system_jansson" = "no"],[
|
||||
dnl REMEMBER TO CHANGE WITH A NEW JANSSON RELEASE!
|
||||
jansson_version="2.13.1"
|
||||
jansson_version="2.14"
|
||||
AC_MSG_RESULT(extracting jansson library)
|
||||
cur_dir=`pwd`
|
||||
cd extras
|
||||
@ -819,11 +828,12 @@ cd jansson-$jansson_version
|
||||
save_cflags="$CFLAGS"
|
||||
CFLAGS="$orig_cflags"
|
||||
export CFLAGS
|
||||
./configure --prefix=$cur_dir/extras/jansson --libdir=$PRIVATELIBDIR --enable-shared --disable-static --enable-opt || exit 1
|
||||
./configure --prefix=$cur_dir/extras/jansson --libdir=$PRIVATELIBDIR --enable-shared --disable-static || exit 1
|
||||
CFLAGS="$save_cflags"
|
||||
AC_MSG_RESULT(compiling jansson resolver library)
|
||||
$ac_cv_prog_MAKER || exit 1
|
||||
AC_MSG_RESULT(installing jansson resolver library)
|
||||
rm -f "$PRIVATELIBDIR/"libjansson*
|
||||
$ac_cv_prog_MAKER install || exit 1
|
||||
JANSSON_CFLAGS="-I$cur_dir/extras/jansson/include"
|
||||
AC_SUBST(JANSSON_CFLAGS)
|
||||
@ -873,6 +883,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/modules/chanmodes/Makefile
|
||||
src/modules/usermodes/Makefile
|
||||
src/modules/extbans/Makefile
|
||||
src/modules/rpc/Makefile
|
||||
src/modules/third/Makefile
|
||||
extras/unrealircd-upgrade-script
|
||||
unrealircd])
|
||||
|
@ -7,7 +7,7 @@
|
||||
\___/|_| |_|_| \___|\__,_|_|\___/\_| \_| \____/\__,_|
|
||||
|
||||
Configuration Program
|
||||
for UnrealIRCd 6.0.4.2
|
||||
for UnrealIRCd 6.1.0
|
||||
|
||||
This program will help you to compile your IRC server, and ask you
|
||||
questions regarding the compile-time settings of it during the process.
|
||||
|
@ -1,19 +1,451 @@
|
||||
UnrealIRCd 6.0.4.2
|
||||
===================
|
||||
Another small update to 6.0.4.x:
|
||||
UnrealIRCd 6.1.0
|
||||
=================
|
||||
This is UnrealIRCd 6.1.0 stable. It is the direct successor to 6.0.7, there
|
||||
will be no 6.0.8.
|
||||
|
||||
* Fix crash when linking. This requires a certain sequence of events: first
|
||||
This release contains several channel mode `+f` enhancements and introduces a
|
||||
new channel mode `+F` which works with flood profiles like `+F normal` and
|
||||
`+F strict`. It is much easier for users than the scary looking mode +f.
|
||||
|
||||
UnrealIRCd 6.1.0 also contains lots of JSON-RPC improvements, which is used
|
||||
by the [UnrealIRCd admin panel](https://www.unrealircd.org/docs/UnrealIRCd_webpanel).
|
||||
Live streaming of logs has been added and the webpanel now communicates to
|
||||
UnrealIRCd which web user issued a command (eg: who issued a kill, who
|
||||
changed a channel mode, ..).
|
||||
|
||||
Other improvements are whowasdb (persistent WHOWAS history) and a new guide
|
||||
on running a Tor Onion service. The release also fixes a crash bug related
|
||||
to remote includes and fixes multiple memory leaks.
|
||||
|
||||
See the full release notes below. As usual on *NIX you can upgrade easily
|
||||
with the command: `./unrealircd upgrade`
|
||||
|
||||
### Enhancements:
|
||||
* Channel flood protection improvements:
|
||||
* New [channel mode `+F`](https://www.unrealircd.org/docs/Channel_anti-flood_settings)
|
||||
(uppercase F). This allows the user to choose a "flood profile",
|
||||
which (behind the scenes) translates to something similar to an `+f` mode.
|
||||
This so end-users can simply choose an `+F` profile without having to learn
|
||||
the complex channel mode `+f`.
|
||||
* For example `+F normal` effectively results in
|
||||
`[7c#C15,30j#R10,10k#K15,40m#M10,8n#N15]:15`
|
||||
* Multiple profiles are available and changing them is possible,
|
||||
see [the documentation](https://www.unrealircd.org/docs/Channel_anti-flood_settings).
|
||||
* Any settings in mode `+f` will override the ones of the `+F` profile.
|
||||
To see the effective flood settings, use `MODE #channel F`.
|
||||
* You can optionally set a default profile via
|
||||
[set::anti-flood::channel::default-profile](https://www.unrealircd.org/docs/Channel_anti-flood_settings#Default_profile).
|
||||
This profile is used if the channel is `-F`. If the user does not
|
||||
want channel flood protection then they have to use an explicit `+F off`.
|
||||
* When channel mode `+f` or `+F` detect that a flood is caused by >75% of
|
||||
["unknown-users"](https://www.unrealircd.org/docs/Security-group_block),
|
||||
the server will now set a temporary ban on `~security-group:unknown-users`.
|
||||
It will still set `+i` and other modes if the flood keeps on going
|
||||
(eg. is caused by known-users).
|
||||
* Forced nick changes (eg. by NickServ) are no longer counted in nick flood
|
||||
for channel mode `+f`/`+F`.
|
||||
* When a server splits on the network, we now temporarily disable +f/+F
|
||||
join-flood protection for 75 seconds
|
||||
([set::anti-flood::channel::split-delay](https://www.unrealircd.org/docs/Channel_anti-flood_settings#config)).
|
||||
This because a server splitting could mean that server has network problems
|
||||
or has died (or restarted), in which case the clients would typically
|
||||
reconnect to the remaining other servers, triggering an +f/+F join-flood and
|
||||
channels ending up being `+i` and such. That is not good because we want
|
||||
+f/+F to be as effortless as possible, with as little false positives as
|
||||
possible.
|
||||
* If your network has 5+ servers and the user load is spread evenly among
|
||||
them, then you could disable this feature by setting the amount of seconds
|
||||
to `0`. This because in such a scenario only 1/5th (20%) of the users
|
||||
would reconnect and hopefully don't trigger +f/+F join floods.
|
||||
* All these features only work properly if all servers are on 6.1.0-rc1 or later.
|
||||
* New module `whowasdb` (persistent `WHOWAS` history): this saves the WHOWAS
|
||||
history on disk periodically and when we terminate, so next server boot
|
||||
still has the WHOWAS history. This module is currently not loaded by default.
|
||||
* New option [listen::spoof-ip](https://www.unrealircd.org/docs/Listen_block#spoof-ip),
|
||||
only valid when using UNIX domain sockets (so listen::file).
|
||||
This way you can override the IP address that users come online with when
|
||||
they use the socket (default was and still is `127.0.0.1`).
|
||||
* Add a new guide [Running Tor Onion service with UnrealIRCd](https://www.unrealircd.org/docs/Running_Tor_Onion_service_with_UnrealIRCd)
|
||||
which uses the new listen::spoof-ip and optionally requires a services account.
|
||||
* [JSON-RPC](https://www.unrealircd.org/docs/JSON-RPC):
|
||||
* Logging of JSON-RPC requests (eg. via snomask `+R`) has been improved,
|
||||
it now shows:
|
||||
* The issuer, such as the user logged in to the admin panel (if known)
|
||||
* The parameters of the request
|
||||
* The JSON-RPC calls
|
||||
[`channel.list`](https://www.unrealircd.org/docs/JSON-RPC:Channel#channel.list),
|
||||
[`channel.get`](https://www.unrealircd.org/docs/JSON-RPC:Channel#channel.get),
|
||||
[`user.list`](https://www.unrealircd.org/docs/JSON-RPC:User#user.list) and
|
||||
[`user.get`](https://www.unrealircd.org/docs/JSON-RPC:User#user.get)
|
||||
now support an optional argument `object_detail_level` which specifies how detailed
|
||||
the [Channel](https://www.unrealircd.org/docs/JSON-RPC:Channel#Structure_of_a_channel)
|
||||
and [User](https://www.unrealircd.org/docs/JSON-RPC:User#Structure_of_a_client_object)
|
||||
response object will be. Especially useful if you don't need all the
|
||||
details in the list calls.
|
||||
* New JSON-RPC methods
|
||||
[`log.subscribe`](https://www.unrealircd.org/docs/JSON-RPC:Log#log.subscribe) and
|
||||
[`log.unsubscribe`](https://www.unrealircd.org/docs/JSON-RPC:Log#log.unsubscribe)
|
||||
to allow real-time streaming of
|
||||
[JSON log events](https://www.unrealircd.org/docs/JSON_logging).
|
||||
* New JSON-RPC method
|
||||
[`rpc.set_issuer`](https://www.unrealircd.org/docs/JSON-RPC:Rpc#rpc.set_issuer)
|
||||
to indiciate who is actually issuing the requests. The admin panel uses this
|
||||
to communicate who is logged in to the panel so this info can be used in logging.
|
||||
* New JSON-RPC methods
|
||||
[`rpc.add_timer`](https://www.unrealircd.org/docs/JSON-RPC:Rpc#rpc.add_timer) and
|
||||
[`rpc.del_timer`](https://www.unrealircd.org/docs/JSON-RPC:Rpc#rpc.del_timer)
|
||||
so you can schedule JSON-RPC calls, like stats.get, to be executed every xyz msec.
|
||||
* New JSON-RPC method
|
||||
[`whowas.get`](https://www.unrealircd.org/docs/JSON-RPC:Whowas#whowas.get)
|
||||
to fetch WHOWAS history.
|
||||
* Low ASCII is no longer filtered out in strings in JSON-RPC, only in JSON logging.
|
||||
* A new message tag `unrealircd.org/issued-by` which is IRCOp-only (and
|
||||
used intra-server) to communicate who actually issued a command.
|
||||
See [docs](https://www.unrealircd.org/issued-by).
|
||||
|
||||
### Changes:
|
||||
* The RPC modules are enabled by default now. This so remote RPC works
|
||||
from other IRC servers for calls like `modules.list`. The default
|
||||
configuration does NOT enable the webserver nor does it cause
|
||||
listening on any socket for RPC, for that you need to follow the
|
||||
[JSON-RPC](https://www.unrealircd.org/docs/JSON-RPC) instructions.
|
||||
* The [blacklist-module](https://www.unrealircd.org/docs/Blacklist-module_directive)
|
||||
directive now accepts wildcards, eg `blacklist-module rpc/*;`
|
||||
* The setting set::modef-boot-delay has been moved to
|
||||
[set::anti-flood::channel::boot-delay](https://www.unrealircd.org/docs/Channel_anti-flood_settings#config).
|
||||
* We now only exempt `127.0.0.1` and `::1` from banning by default
|
||||
(hardcoded in the source). Previously we exempted whole `127.*` but
|
||||
that gets in the way if you want to allow Tor with a
|
||||
[require authentication](https://www.unrealircd.org/docs/Require_authentication_block)
|
||||
block or soft-ban. Now you can just tell Tor to bind to `127.0.0.2`
|
||||
so its not affected by the default exemption.
|
||||
|
||||
### Fixes:
|
||||
* Crash if there is a parse error in an included file and there are
|
||||
other remote included files still being downloaded.
|
||||
* Memory leak in WHOWAS
|
||||
* Memory leak when connecting to a TLS server fails
|
||||
* Workaround a bug in some websocket implementations where the WSOP_PONG
|
||||
frame is unmasked (now permitted).
|
||||
|
||||
### Developers and protocol:
|
||||
* The `cmode.free_param` definition changed. It now has an extra argument
|
||||
`int soft` and for return value you will normally `return 0` here.
|
||||
You can `return 1` if you resist freeing, which is rare and only used by
|
||||
`+F` with set::anti-flood::channel::default-profile.
|
||||
* New `cmode.flood_type_action` which can be used to indicate a channel mode
|
||||
can be used from +f/+F as an action. You need to specify for which
|
||||
flood type your mode is, eg `cmode.flood_type_action = 'j';` for joinflood.
|
||||
* JSON-RPC supports
|
||||
[UNIX domain sockets](https://www.unrealircd.org/docs/JSON-RPC:Technical_documentation#UNIX_domain_socket)
|
||||
for making RPC calls. If this is used, we now split on `\n` (newline)
|
||||
so multiple parallel requests can be handled properly.
|
||||
* Message tag `unrealircd.org/issued-by`, sent to IRCOps only.
|
||||
See [docs](https://www.unrealircd.org/issued-by).
|
||||
|
||||
UnrealIRCd 6.0.7
|
||||
-----------------
|
||||
|
||||
UnrealIRCd 6.0.7 makes WHOWAS show more information to IRCOps and adds an
|
||||
experimental spamfilter feature. It also contains other enhancements and
|
||||
quite a number of bug fixes. One notable change is that on linking of anope
|
||||
or atheme, every server will now check if they have ulines { } for that
|
||||
services server, since it's a common mistake to forget this, leading to
|
||||
desyncs or other weird problems.
|
||||
|
||||
### Enhancements:
|
||||
* [Spamfilter](https://www.unrealircd.org/docs/Spamfilter) can now be made UTF8-aware:
|
||||
* This is experimental, to enable: `set { spamfilter { utf8 yes; } }`
|
||||
* Case insensitive matches will then work better. For example, for extended
|
||||
Latin, a spamfilter on `ę` then also matches `Ę`.
|
||||
* Other PCRE2 features such as [\p](https://www.pcre.org/current/doc/html/pcre2syntax.html#SEC5)
|
||||
can then be used. For example the regex `\p{Arabic}` would block all Arabic script.
|
||||
See also this [full list of scripts](https://www.pcre.org/current/doc/html/pcre2syntax.html#SEC7).
|
||||
Please use this new tool with care. Blocking an entire language or script
|
||||
is quite a drastic measure.
|
||||
* As a consequence of this we require PCRE2 10.36 or newer. If your system
|
||||
PCRE2 is older, then the UnrealIRCd-shipped-library version will be compiled
|
||||
and `./Config` may take a little longer than usual.
|
||||
* `WHOWAS` now shows IP address and account information to IRCOps
|
||||
* Allow services to send a couple of protocol messages in the
|
||||
unregistered / SASL stage. These are: `CHGHOST`, `CHGIDENT`
|
||||
and `SREPLY`
|
||||
* This allows services to set the vhost on a user during SASL,
|
||||
so the user receives the vhost straight from the start, before
|
||||
all the auto-joining/re-rejoining of channels.
|
||||
* Future anope/atheme/etc services will presumably support this.
|
||||
* [WebSocket](https://www.unrealircd.org/docs/WebSocket_support) status is
|
||||
now synced over the network and an extra default
|
||||
[security group](https://www.unrealircd.org/docs/Security-group_block)
|
||||
`websocket-users` has been added. Similarly there is now
|
||||
security-group::websocket and security-group::exclude-websocket item.
|
||||
Same for [mask items](https://www.unrealircd.org/docs/Mask_item) such
|
||||
as in [set::restrict-commands::command::except](https://www.unrealircd.org/docs/Restrict_commands).
|
||||
* Support for IRCv3 [Standard Replies](https://ircv3.net/specs/extensions/standard-replies).
|
||||
Right now nothing fancy yet, other than us sending `ACCOUNT_REQUIRED_TO_CONNECT`
|
||||
from the authprompt module when a user is
|
||||
[soft-banned](https://www.unrealircd.org/docs/Soft_ban).
|
||||
* Add support for sending IRCv3 Standard Replies intra-server, eg
|
||||
from services (`SREPLY` server-to-server command)
|
||||
* Support `NO_COLOR` environment variable, as per [no-color.org](https://no-color.org).
|
||||
|
||||
### Changes:
|
||||
* We now verify that all servers have
|
||||
[ulines { }](https://www.unrealircd.org/docs/Ulines_block) for Anope and
|
||||
Atheme servers and reject the link if this is not the case.
|
||||
* The `FLOOD_BLOCKED` log message now shows the target of the flood
|
||||
for `target-flood-user` and `target-flood-channel`.
|
||||
* When an IRCOp sets `+H` to hide ircop status, only the swhois items that
|
||||
were added through oper will be hidden (and not the ones added by eg. vhost).
|
||||
Previously all were hidden.
|
||||
* Update shipped libraries: c-ares to 1.19.0, Jansson to 2.14, PCRE2 to 10.42,
|
||||
and on Windows LibreSSL to 3.6.2 and cURL to 8.0.1.
|
||||
|
||||
### Fixes:
|
||||
* Crash if a third party module is loaded which allows very large message tags
|
||||
(e.g. has no length check)
|
||||
* Crash if an IRCOp uses
|
||||
[`unrealircd.org/json-log`](https://www.unrealircd.org/docs/JSON_logging#Enabling_on_IRC)
|
||||
on IRC and during `REHASH` some module sends log output during MOD_INIT
|
||||
(eg. with some 3rd party modules)
|
||||
* Crash when parsing [deny link block](https://www.unrealircd.org/docs/Deny_link_block)
|
||||
* The [Module manager](https://www.unrealircd.org/docs/Module_manager)
|
||||
now works on FreeBSD and similar.
|
||||
* In `LUSERS` the "unknown connection(s)" count was wrong. This was just a
|
||||
harmless counting error with no other effects.
|
||||
* Silence warnings on Clang 15+ (eg. Ubuntu 23.04)
|
||||
* Don't download `GeoIP.dat` if you have
|
||||
[`blacklist-module geoip_classic;`](https://www.unrealircd.org/docs/Blacklist-module_directive)
|
||||
* Channel mode `+S` stripping too much on incorrect color codes.
|
||||
* Make [`@if module-loaded()`](https://www.unrealircd.org/docs/Defines_and_conditional_config)
|
||||
work correctly for modules that are about to be unloaded during REHASH.
|
||||
* Some missing notices if remotely REHASHing a server, and one duplicate line.
|
||||
* Check invalid host setting in oper::vhost, just like we already have in vhost::vhost.
|
||||
|
||||
UnrealIRCd 6.0.6
|
||||
-----------------
|
||||
|
||||
The main objective of this release is to enhance the new JSON-RPC functionality.
|
||||
In 6.0.5 we made a start and in 6.0.6 it is expanded a lot, plus some important
|
||||
bugs were fixed in it. Thanks everyone who has been testing the functionality!
|
||||
|
||||
The new [UnrealIRCd Administration Webpanel](https://github.com/unrealircd/unrealircd-webpanel/)
|
||||
(which uses JSON-RPC) is very much usable now. It allows admins to view the
|
||||
users/channels/servers lists, view detailed information on users and channels,
|
||||
manage server bans and spamfilters, all from the browser.
|
||||
|
||||
Both the JSON-RPC API and the webpanel are work in progress. They will improve
|
||||
and expand with more features over time.
|
||||
|
||||
If you are already using UnrealIRCd 6.0.5 and you are NOT interested in
|
||||
JSON-RPC or the webpanel then there is NO reason to upgrade to 6.0.6.
|
||||
|
||||
As usual, on *NIX you can easily upgrade with `./unrealircd upgrade`
|
||||
|
||||
### Enhancements:
|
||||
* The [JSON-RPC](https://www.unrealircd.org/docs/JSON-RPC) API for
|
||||
UnrealIRCd has been expanded a lot. From 12 API methods to 42:
|
||||
`stats.get`, `rpc.info`, `user.part`,
|
||||
`user.join`, `user.quit`, `user.kill`,
|
||||
`user.set_oper`, `user.set_snomask`, `user.set_mode`,
|
||||
`user.set_vhost`, `user.set_realname`,
|
||||
`user.set_username`, `user.set_nick`, `user.get`,
|
||||
`user.list`, `server.module_list`, `server.disconnect`,
|
||||
`server.connect`, `server.rehash`, `server.get`,
|
||||
`server.list`, `channel.kick`, `channel.set_topic`,
|
||||
`channel.set_mode`, `channel.get`, `channel.list`,
|
||||
`server_ban.add`, `server_ban.del`, `server_ban.get`,
|
||||
`server_ban.list`, `server_ban_exception.add`,
|
||||
`server_ban_exception.del`, `server_ban_exception.get`,
|
||||
`server_ban_exception.list`, `name_ban.add`,
|
||||
`name_ban.del`, `name_ban.get`, `name_ban.list`,
|
||||
`spamfilter.add`, `spamfilter.del`, `spamfilter.get`,
|
||||
`spamfilter.list`.
|
||||
* Server admins can read the [JSON-RPC](https://www.unrealircd.org/docs/JSON-RPC)
|
||||
documentation on how to get started. For developers, see the
|
||||
[Technical documentation](https://www.unrealircd.org/docs/JSON-RPC:Technical_documentation)
|
||||
for all info on the different RPC calls and the protocol.
|
||||
* Some functionality requires all servers to be on 6.0.6 or later.
|
||||
* Some functionality requires all servers to include
|
||||
`rpc.modules.default.conf` instead of only the single server that
|
||||
the webpanel interfaces with through JSON-RPC.
|
||||
When all servers have that file included then the API call
|
||||
`server.module_list` can work for remote servers, and the API call
|
||||
`server.rehash` for remote servers can return the actual rehash result
|
||||
and a full log of the rehash process. It is not used for any other
|
||||
API call at the moment, but in the future more API calls may need this
|
||||
functionality because it allows us to do things that are otherwise impossible
|
||||
or very hard.
|
||||
* Known issue: logging of RPC actions needs to be improved. For some API calls,
|
||||
like adding of server bans and spamfilters, this already works, but in
|
||||
other API calls it is not clearly logged yet "who did what".
|
||||
|
||||
### Changes:
|
||||
* Previously some server protocol commands could only be used by
|
||||
services, commands such as `SVSJOIN` and `SVSPART`. We now allow SVS*
|
||||
command to be used by any servers, so the JSON-RPC API can use them.
|
||||
There's a new option
|
||||
[set::limit-svscmds](https://www.unrealircd.org/docs/Set_block#set::limit-svscmds)
|
||||
so one can revert back to the original situation, if needed.
|
||||
* All JSON-RPC calls that don't change anything, such as `user.list`
|
||||
are now logged in the `rpc.debug` facility. Any call that changes
|
||||
anything like `user.join` or `spamfilter.add` is logged via `rpc.info`.
|
||||
This because JSON-RPC calls can be quite noisy and logging the
|
||||
read-only calls is generally not so interesting.
|
||||
|
||||
### Fixes:
|
||||
* When using JSON-RPC with UnrealIRCd 6.0.5 it would often crash
|
||||
* Fix parsing services version (anope) in `EAUTH`.
|
||||
|
||||
### Developers and protocol:
|
||||
* A new `RRPC` server to server command to handle RPC-over-IRC.
|
||||
This way the JSON-RPC user, like the admin panel, can interface with
|
||||
a remote server. If you are writing an RPC handler, then the remote
|
||||
RPC request does not look much different than a local one, so you
|
||||
can just process it as usual. See the code for `server.rehash` or
|
||||
`server.module_list` for an example (src/modules/rpc/server.c).
|
||||
|
||||
UnrealIRCd 6.0.5
|
||||
-----------------
|
||||
|
||||
This release adds experimental JSON-RPC support, a new TLINE command, the
|
||||
`./unrealircd restart` command has been improved to check for config errors,
|
||||
logging to files has been improved and there are several other enhancements.
|
||||
|
||||
There are also two important changes: 1) servers that use websockets now also
|
||||
need to load the "webserver" module (so you may need to edit your config
|
||||
file). 2) we now require TLSv1.2 or higher and a modern cipher for IRC clients.
|
||||
This should be no problem for clients using any reasonably new SSL/TLS library
|
||||
(from 2014 or later).
|
||||
|
||||
I would also like to take this opportunity to say that we are
|
||||
[looking for webdevs to create an UnrealIRCd admin panel](https://forums.unrealircd.org/viewtopic.php?t=9257).
|
||||
The previous attempt at this failed so we are looking for new people.
|
||||
|
||||
See the full release notes below for all changes in more detail.
|
||||
|
||||
As usual, on *NIX you can easily upgrade with `./unrealircd upgrade`
|
||||
|
||||
### Enhancements:
|
||||
* Internally the websocket module has been split up into 3 modules:
|
||||
`websocket_common`, `webserver` and `websocket`. The `websocket_common` one
|
||||
is loaded by default via modules.default.conf, the other two are not.
|
||||
**Important:** if you use websockets then you need to load two modules now (instead of only one):
|
||||
```
|
||||
loadmodule "websocket";
|
||||
loadmodule "webserver";
|
||||
```
|
||||
* [JSON-RPC](https://www.unrealircd.org/docs/JSON-RPC) API for UnrealIRCd.
|
||||
This is work in progress.
|
||||
* New `TLINE` command to test *LINEs. This can be especially useful for
|
||||
checking how many people match an [extended server ban](https://www.unrealircd.org/docs/Extended_server_bans)
|
||||
such as `TLINE ~C:NL`
|
||||
* The `./unrealircd start` command will now refuse to start if UnrealIRCd
|
||||
is already running.
|
||||
* The `./unrealircd restart` command will validate the configuration file
|
||||
(it will call `./unrealircd configtest`). If there is a configuration
|
||||
error then the restart will not go through and the current UnrealIRCd
|
||||
process is kept running.
|
||||
* When an IRCOp is outside the channel and does `MODE #channel` they will
|
||||
now get to see the mode parameters too. This depends on the `channel:see:mode:remote`
|
||||
[operclass permission](https://www.unrealircd.org/docs/Operclass_permissions)
|
||||
which all IRCOps have by default if you use the default operclasses.
|
||||
* [Logging to a file](https://www.unrealircd.org/docs/Log_block) now creates
|
||||
a directory structure if needed.
|
||||
* You could already use:
|
||||
```
|
||||
log { source { !debug; all; } destination { file "ircd.%Y-%m-%d.log"; } }
|
||||
```
|
||||
* But now you can also use:
|
||||
```
|
||||
log { source { !debug; all; } destination { file "%Y-%m-%d/ircd.log"; } }
|
||||
```
|
||||
This is especially useful if you output to multiple log files and then
|
||||
want them grouped by date in a directory.
|
||||
* Add additional variables in
|
||||
[blacklist::reason](https://www.unrealircd.org/docs/Blacklist_block):
|
||||
* `$blacklist`: name of the blacklist block
|
||||
* `$dnsname`: the blacklist::dns::name
|
||||
* `$dnsreply`: the DNS reply code
|
||||
* Resolved technical issue so opers can `REHASH` from
|
||||
[Websocket connections](https://www.unrealircd.org/docs/WebSocket_support).
|
||||
* In the [TLD block](https://www.unrealircd.org/docs/Tld_block) the use
|
||||
of `tld::motd` and `tld::rules` is now optional.
|
||||
* Log which oper actually initiated a server link request (`CONNECT`)
|
||||
|
||||
### Changes:
|
||||
* SSL/TLS: By default we now require TLSv1.2 or later and a modern cipher
|
||||
with forward secrecy. Otherwise the connection is refused.
|
||||
* Since UnrealIRCd 4.2.2 (March 2019) users see an on-connect notice with
|
||||
a warning when they use an outdated TLS protocol or cipher that does not
|
||||
meet these requirements.
|
||||
* This move also reflects the phase out of versions below TLSv1.2 which
|
||||
happened in browsers in 2020/2021.
|
||||
* In practice on the client-side this requires at least:
|
||||
* OpenSSL 1.0.1 (released in 2012)
|
||||
* GnuTLS 3.2.6 (2013)
|
||||
* Android 4.4.2 (2013)
|
||||
* Or presumably any other SSL/TLS library that is not 9+ years old
|
||||
* If you want to revert back to the previous less secure settings, then
|
||||
look under ''Previous less secure setting'' in
|
||||
[TLS Ciphers and protocols](https://www.unrealircd.org/docs/TLS_Ciphers_and_protocols).
|
||||
* The code for handling
|
||||
[`set::anti-flood::everyone::connect-flood`](https://www.unrealircd.org/docs/Anti-flood_settings#connect-flood)
|
||||
is now in its own module `connect-flood`. This module is loaded by default,
|
||||
no changes needed in your configuration file.
|
||||
* Similarly,
|
||||
[`set:max-unknown-connections-per-ip`](https://www.unrealircd.org/docs/Set_block#set::max-unknown-connections-per-ip)
|
||||
is now handled by the new module `max-unknown-connections-per-ip`. This module is loaded
|
||||
by default as well, no changes needed in your configuration file.
|
||||
* Upgrade shipped PCRE2 to 10.41, curl-ca-bundle to 2022-10-11,
|
||||
on Windows LibreSSL to 3.6.1 and cURL to 7.86.0.
|
||||
* After people do a major upgrade on their Linux distro, UnrealIRCd may
|
||||
no longer start due to an `error while loading shared libraries`.
|
||||
We now print a more helpful message and link to the new
|
||||
[FAQ entry](https://www.unrealircd.org/docs/FAQ#shared-library-error)
|
||||
about it.
|
||||
* When timing out on the [authprompt](https://www.unrealircd.org/docs/Set_block#set::authentication-prompt)
|
||||
module, the error (quit message) is now the original (ban) reason for the
|
||||
prompt, instead of the generic `Registration timeout`.
|
||||
|
||||
### Fixes:
|
||||
* Crash when linking. This requires a certain sequence of events: first
|
||||
a server is linked in successfully, then we need to REHASH, and then a new
|
||||
link attempt has to come in with the same server name (for example because
|
||||
there is a network issue and the old link has not timed out yet).
|
||||
If all that happens, then an UnreaIRCd 6 server may crash, but not always.
|
||||
* Warning message about moddata creationtime when linking.
|
||||
* [Snomask `+j`](https://www.unrealircd.org/docs/Snomasks) was not showing
|
||||
remote joins, even though it did show remote parts and kicks.
|
||||
* Leak of 1 file descriptor per /REHASH (the control socket).
|
||||
* Ban letters showing up twice in 005 EXTBAN=
|
||||
* Setting [set::authentication-prompt::enabled](https://www.unrealircd.org/docs/Set_block#set::authentication-prompt)
|
||||
to `no` was ignored. The default is still `yes`.
|
||||
|
||||
### Developers and protocol:
|
||||
* Add `CALL_CMD_FUNC(cmd_func_name)` for calling commands in the same
|
||||
module, see [this commit](https://github.com/unrealircd/unrealircd/commit/dc55c3ec9f19e5ed284e5a786f646d0e6bb60ef9).
|
||||
Benefit of this is that it will keep working if we ever change command paramters.
|
||||
* Add `CALL_NEXT_COMMAND_OVERRIDE()` which can be used instead of
|
||||
`CallCommandOverride()`, see also [this commit](https://github.com/unrealircd/unrealircd/commit/4e5598b6cf0986095f757f31a2540b03e4d235dc).
|
||||
This too, will keep working if we ever change command parameters.
|
||||
* During loading and rehash we now set `loop.config_status` to one of
|
||||
`CONFIG_STATUS_*` so modules (and core) can see at what step we are
|
||||
during configuration file and module processing.
|
||||
* New RPC API. See the `src/modules/rpc/` directory for examples.
|
||||
* New function `get_nvplist(NameValuePrioList *list, const char *name)`
|
||||
|
||||
UnrealIRCd 6.0.4.2
|
||||
-------------------
|
||||
Another small update to 6.0.4.x:
|
||||
|
||||
* Two IRCv3 specifications were ratified which we already supported as drafts:
|
||||
* Change CAP `draft/extended-monitor` to `extended-monitor`
|
||||
* Add message-tag `bot` next to existing (for now) `draft/bot`
|
||||
* Update Turkish translations
|
||||
|
||||
UnrealIRCd 6.0.4.1
|
||||
===================
|
||||
-------------------
|
||||
This is a small update to 6.0.4. It fixes the following issues that were
|
||||
present in all 6.0.x versions:
|
||||
|
||||
@ -27,12 +459,11 @@ present in all 6.0.x versions:
|
||||
(limit) and other restrictions and would have to resort back to using
|
||||
MODE or SAMODE. Only +b and +i could be bypassed via INVITE OperOverride.
|
||||
|
||||
(This cherry picks commit 0e6fc07bd9000ecc463577892cf2195a670de4be and
|
||||
commit 0d139c6e7c268e31ca8a4c9fc5cb7bfeb4f56831 from 6.0.5-git)
|
||||
|
||||
UnrealIRCd 6.0.4
|
||||
-----------------
|
||||
This release comes with lots of features and enhancements. In particular,
|
||||
security groups and mask items now allow you to write cleaner and more
|
||||
flexible configuration files. There are also JSON logging enhancements and
|
||||
several bug fixes. Thanks a lot to everyone who tested the release candidates!
|
||||
|
||||
If you are already running UnrealIRCd 6 then read below. Otherwise, jump
|
||||
straight to the [summary about UnrealIRCd 6](#Summary) to learn more
|
||||
@ -148,8 +579,8 @@ about UnrealIRCd 6.
|
||||
### Changes:
|
||||
* Clarified that UnrealIRCd is licensed as "GPLv2 or later"
|
||||
* Fix use of variables in
|
||||
[`set::reject-message](https://www.unrealircd.org/docs/Set_block#set::reject-message)
|
||||
and in [`blacklist::reason](https://www.unrealircd.org/docs/Blacklist_block):
|
||||
[`set::reject-message`](https://www.unrealircd.org/docs/Set_block#set::reject-message)
|
||||
and in [`blacklist::reason`](https://www.unrealircd.org/docs/Blacklist_block):
|
||||
previously short forms of variables were (unintentionally) expanded
|
||||
as well, such as `$serv` for `$server`. This is no longer supported, you need
|
||||
to use the correct full variable names.
|
||||
|
@ -164,6 +164,7 @@ loadmodule "usermodes/servicebot"; /* +S */
|
||||
loadmodule "extbans/account"; /* +b ~account */
|
||||
loadmodule "extbans/certfp"; /* +b ~certfp */
|
||||
#loadmodule "extbans/country"; /* +b ~country */
|
||||
loadmodule "extbans/flood"; /* +e ~flood */
|
||||
loadmodule "extbans/inchannel"; /* +b ~channel */
|
||||
loadmodule "extbans/join"; /* +b ~join */
|
||||
loadmodule "extbans/msgbypass"; /* +e ~msgbypass */
|
||||
@ -194,9 +195,23 @@ loadmodule "monitor";
|
||||
loadmodule "plaintext-policy";
|
||||
loadmodule "reply-tag";
|
||||
loadmodule "server-time";
|
||||
loadmodule "standard-replies";
|
||||
loadmodule "sts";
|
||||
loadmodule "typing-indicator";
|
||||
|
||||
// RPC
|
||||
loadmodule "rpc/rpc";
|
||||
loadmodule "rpc/stats";
|
||||
loadmodule "rpc/user";
|
||||
loadmodule "rpc/server";
|
||||
loadmodule "rpc/channel";
|
||||
loadmodule "rpc/server_ban";
|
||||
loadmodule "rpc/server_ban_exception";
|
||||
loadmodule "rpc/name_ban";
|
||||
loadmodule "rpc/spamfilter";
|
||||
loadmodule "rpc/log";
|
||||
loadmodule "rpc/whowas";
|
||||
|
||||
// Other
|
||||
loadmodule "antimixedutf8";
|
||||
#loadmodule "authprompt";
|
||||
@ -228,3 +243,4 @@ loadmodule "watch-backend";
|
||||
#loadmodule "webirc";
|
||||
#loadmodule "webserver";
|
||||
#loadmodule "websocket";
|
||||
loadmodule "websocket_common";
|
@ -16,6 +16,7 @@ log {
|
||||
nomatch;
|
||||
oper;
|
||||
operoverride;
|
||||
rpc;
|
||||
sacmds;
|
||||
tkl.BAN_REALNAME;
|
||||
tkl.RMTKL_COMMAND;
|
||||
|
@ -146,6 +146,16 @@ set {
|
||||
oper-message "Network operators must be using an up-to-date TLS protocol & cipher";
|
||||
}
|
||||
anti-flood {
|
||||
channel {
|
||||
profile very-strict { flood-mode "[7c#C15,10j#R10,10k#K15,30m#M10,10n#N15]:15"; }
|
||||
profile strict { flood-mode "[7c#C15,15j#R10,10k#K15,40m#M10,10n#N15]:15"; }
|
||||
profile normal { flood-mode "[7c#C15,30j#R10,10k#K15,40m#M10,10n#N15]:15"; }
|
||||
profile relaxed { flood-mode "[7c#C15,45j#R10,10k#K15,60m#M10,10n#N15]:15"; }
|
||||
profile very-relaxed { flood-mode "[7c#C15,60j#R10,10k#K15,90m#M10,10n#N15]:15"; }
|
||||
default-profile normal;
|
||||
boot-delay 75;
|
||||
split-delay 75;
|
||||
}
|
||||
everyone {
|
||||
connect-flood 3:300;
|
||||
handshake-data-flood {
|
||||
|
@ -18,14 +18,14 @@ by this server"
|
||||
Currently UnrealIRCd supports several tokens that are included in numeric 005. A list of
|
||||
all tokens, their respective value and a brief description are listed below.
|
||||
|
||||
Unreal attempts to follow the proposed ISupport standard as much as possible. Unreal only
|
||||
ignores the standard in one regard, the TARGMAX token. This token is believed to be
|
||||
UnrealIRCd attempts to follow the proposed ISupport standard as much as possible. UnrealIRCd
|
||||
only ignores the standard in one regard, the TARGMAX token. This token is believed to be
|
||||
impractical and technically impossible to correctly implement due to existing limitations
|
||||
in the standard. Therefore, this token is not currently supported.
|
||||
|
||||
Unreal does additionally provide a few tokens which are not specified in the standard, these
|
||||
UnrealIRCd does additionally provide a few tokens which are not specified in the standard, these
|
||||
include: HCN, AWAYLEN, WATCH, SILENCE, EXTBAN, ELIST, CMDS, NAMESX, UHNAMES, and WATCHOPTS.
|
||||
Unreal also maintains a few legacy tokens such as MAXCHANNELS and WALLCHOPS to ensure
|
||||
UnrealIRCd also maintains a few legacy tokens such as MAXCHANNELS and WALLCHOPS to ensure
|
||||
compatibility until the ISupport standard is more widely accepted by clients.
|
||||
|
||||
Token Value Default Value Description
|
||||
|
Binary file not shown.
BIN
extras/argon2.tar.gz
Normal file
BIN
extras/argon2.tar.gz
Normal file
Binary file not shown.
@ -48,8 +48,8 @@ fi
|
||||
$MAKE
|
||||
yes ''|$MAKE pem
|
||||
$MAKE || exit 1
|
||||
./unrealircd module install third/dumpcmds
|
||||
$MAKE install || exit 1
|
||||
./unrealircd module install third/dumpcmds || exit 1
|
||||
|
||||
set +x
|
||||
echo ""
|
||||
|
@ -6,7 +6,7 @@ rem But nowadays we use JOM for parallel builds:
|
||||
jom /j32 -f makefile.windows ^
|
||||
LIBRESSL_INC_DIR="c:\projects\unrealircd-6-libs\libressl\include" ^
|
||||
LIBRESSL_LIB_DIR="c:\projects\unrealircd-6-libs\libressl\lib" ^
|
||||
SSLLIB="crypto-47.lib ssl-50.lib" ^
|
||||
SSLLIB="crypto-50.lib ssl-53.lib" ^
|
||||
USE_REMOTEINC=1 ^
|
||||
LIBCURL_INC_DIR="c:\projects\unrealircd-6-libs\curl\include" ^
|
||||
LIBCURL_LIB_DIR="c:\projects\unrealircd-6-libs\curl\builds\libcurl-vc-x64-release-dll-ssl-dll-cares-dll-ipv6-obj-lib" ^
|
||||
|
Binary file not shown.
@ -76,4 +76,6 @@ cd "$OUTD" || exit 1
|
||||
|
||||
echo "Building and installing libcurl"
|
||||
./configure --prefix=$UNREALDIR/extras/curl --libdir=$PRIVATELIBDIR --enable-shared --with-openssl
|
||||
make && make install
|
||||
make || exit 1
|
||||
rm -f "$PRIVATELIBDIR/"libcurl*
|
||||
make install || exit 1
|
||||
|
@ -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.4.2
|
||||
PROJECT_NUMBER = 6.1.0
|
||||
|
||||
# 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.
Binary file not shown.
@ -1,12 +1,10 @@
|
||||
Target: 127.0.0.1:5901
|
||||
|
||||
prio ciphersuite protocols pfs curves
|
||||
1 ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
2 ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
3 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
4 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
5 ECDHE-ECDSA-AES256-SHA TLSv1,TLSv1.1,TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
6 ECDHE-ECDSA-AES128-SHA TLSv1,TLSv1.1,TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
prio ciphersuite protocols pfs curves
|
||||
1 ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
2 ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
3 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
4 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
|
||||
Certificate: untrusted, 384 bits, ecdsa-with-SHA256 signature
|
||||
TLS ticket lifetime hint: None
|
||||
@ -20,8 +18,8 @@ TLS Tolerance: yes
|
||||
|
||||
Intolerance to:
|
||||
SSL 3.254 : absent
|
||||
TLS 1.0 : absent
|
||||
TLS 1.1 : absent
|
||||
TLS 1.0 : PRESENT
|
||||
TLS 1.1 : PRESENT
|
||||
TLS 1.2 : absent
|
||||
TLS 1.3 : absent
|
||||
TLS 1.4 : absent
|
||||
|
@ -1,27 +0,0 @@
|
||||
Target: 127.0.0.1:5901
|
||||
|
||||
prio ciphersuite protocols pfs curves
|
||||
1 ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 ECDH,P-256,256bits prime256v1
|
||||
2 ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 ECDH,P-256,256bits prime256v1
|
||||
3 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 ECDH,P-256,256bits prime256v1
|
||||
4 ECDHE-ECDSA-AES256-SHA TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits prime256v1
|
||||
5 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 ECDH,P-256,256bits prime256v1
|
||||
6 ECDHE-ECDSA-AES128-SHA TLSv1,TLSv1.1,TLSv1.2 ECDH,P-256,256bits prime256v1
|
||||
|
||||
Certificate: untrusted, 384 bits, ecdsa-with-SHA256 signature
|
||||
TLS ticket lifetime hint: None
|
||||
NPN protocols: None
|
||||
OCSP stapling: not supported
|
||||
Cipher ordering: server
|
||||
Curves ordering: server - fallback: no
|
||||
Server supports secure renegotiation
|
||||
Server supported compression methods: NONE
|
||||
TLS Tolerance: yes
|
||||
|
||||
Intolerance to:
|
||||
SSL 3.254 : absent
|
||||
TLS 1.0 : absent
|
||||
TLS 1.1 : absent
|
||||
TLS 1.2 : absent
|
||||
TLS 1.3 : absent
|
||||
TLS 1.4 : absent
|
@ -1,27 +0,0 @@
|
||||
Target: 127.0.0.1:5901
|
||||
|
||||
prio ciphersuite protocols pfs curves
|
||||
1 ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
2 ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
3 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
4 ECDHE-ECDSA-AES256-SHA TLSv1,TLSv1.1,TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
5 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
6 ECDHE-ECDSA-AES128-SHA TLSv1,TLSv1.1,TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
|
||||
Certificate: untrusted, 384 bits, ecdsa-with-SHA256 signature
|
||||
TLS ticket lifetime hint: None
|
||||
NPN protocols: None
|
||||
OCSP stapling: not supported
|
||||
Cipher ordering: server
|
||||
Curves ordering: server - fallback: no
|
||||
Server supports secure renegotiation
|
||||
Server supported compression methods: NONE
|
||||
TLS Tolerance: yes
|
||||
|
||||
Intolerance to:
|
||||
SSL 3.254 : absent
|
||||
TLS 1.0 : absent
|
||||
TLS 1.1 : absent
|
||||
TLS 1.2 : absent
|
||||
TLS 1.3 : absent
|
||||
TLS 1.4 : absent
|
@ -1,27 +0,0 @@
|
||||
Target: 127.0.0.1:5901
|
||||
|
||||
prio ciphersuite protocols pfs curves
|
||||
1 ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
2 ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
3 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
4 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
5 ECDHE-ECDSA-AES256-SHA TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
6 ECDHE-ECDSA-AES128-SHA TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1
|
||||
|
||||
Certificate: untrusted, 384 bits, ecdsa-with-SHA256 signature
|
||||
TLS ticket lifetime hint: None
|
||||
NPN protocols: None
|
||||
OCSP stapling: not supported
|
||||
Cipher ordering: server
|
||||
Curves ordering: server - fallback: no
|
||||
Server supports secure renegotiation
|
||||
Server supported compression methods: NONE
|
||||
TLS Tolerance: yes
|
||||
|
||||
Intolerance to:
|
||||
SSL 3.254 : absent
|
||||
TLS 1.0 : PRESENT
|
||||
TLS 1.1 : PRESENT
|
||||
TLS 1.2 : absent
|
||||
TLS 1.3 : absent
|
||||
TLS 1.4 : absent
|
@ -96,6 +96,7 @@ extern int myncmp(const char *, const char *, int);
|
||||
#endif
|
||||
|
||||
extern char *strtoken(char **, char *, char *);
|
||||
extern char *strtoken_noskip(char **, char *, char *);
|
||||
|
||||
extern MODVAR int global_count, max_global_count;
|
||||
#ifdef _WIN32
|
||||
@ -167,7 +168,7 @@ extern MODVAR unsigned char char_atribs[];
|
||||
* you are doing.
|
||||
*/
|
||||
|
||||
/* IRCu/Hybrid/Unreal way now :) -Stskeeps */
|
||||
/* IRCu/Hybrid/unrealircd way now :) -Stskeeps */
|
||||
|
||||
#define EXPAR1 extchmstr[0]
|
||||
#define EXPAR2 extchmstr[1]
|
||||
|
@ -275,12 +275,12 @@
|
||||
/* Default TLS cipherlist (except for TLS1.3, see further down).
|
||||
* This can be changed via set::ssl::options::ciphers in the config file.
|
||||
*/
|
||||
#define UNREALIRCD_DEFAULT_CIPHERS "TLS13-CHACHA20-POLY1305-SHA256 TLS13-AES-256-GCM-SHA384 TLS13-AES-128-GCM-SHA256 EECDH+CHACHA20 EECDH+AESGCM EECDH+AES AES256-GCM-SHA384 AES128-GCM-SHA256 AES256-SHA256 AES128-SHA256 AES256-SHA AES128-SHA"
|
||||
#define UNREALIRCD_DEFAULT_CIPHERS "EECDH+CHACHA20 EECDH+AESGCM EECDH+AES+SHA384 EECDH+AES+SHA256"
|
||||
|
||||
/* Default TLS 1.3 ciphersuites.
|
||||
* This can be changed via set::ssl::options::ciphersuites in the config file.
|
||||
*/
|
||||
#define UNREALIRCD_DEFAULT_CIPHERSUITES "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256"
|
||||
#define UNREALIRCD_DEFAULT_CIPHERSUITES "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256"
|
||||
|
||||
/* Default TLS curves for ECDH(E)
|
||||
* This can be changed via set::ssl::options::ecdh-curve in the config file.
|
||||
|
@ -95,6 +95,7 @@ void dbuf_delete(dbuf *, size_t);
|
||||
#define DBufClear(dyn) dbuf_delete((dyn),DBufLength(dyn))
|
||||
|
||||
extern int dbuf_getmsg(dbuf *, char *);
|
||||
extern int dbuf_get(dbuf *dyn, char **buf);
|
||||
extern void dbuf_queue_init(dbuf *dyn);
|
||||
extern void dbuf_init(void);
|
||||
|
||||
|
@ -53,6 +53,8 @@ typedef enum BanTarget { BAN_TARGET_IP=1, BAN_TARGET_USERIP=2, BAN_TARGET_HOST=3
|
||||
|
||||
typedef enum HideIdleTimePolicy { HIDE_IDLE_TIME_NEVER=1, HIDE_IDLE_TIME_ALWAYS=2, HIDE_IDLE_TIME_USERMODE=3, HIDE_IDLE_TIME_OPER_USERMODE=4 } HideIdleTimePolicy;
|
||||
|
||||
typedef enum LimitSVSCMDS { LIMIT_SVSCMDS_SERVERS=0, LIMIT_SVSCMDS_ULINES=1 } LimitSVSCMDS;
|
||||
|
||||
/** The set { } block configuration */
|
||||
typedef struct Configuration Configuration;
|
||||
struct Configuration {
|
||||
@ -128,6 +130,7 @@ struct Configuration {
|
||||
long spamfilter_detectslow_warn;
|
||||
long spamfilter_detectslow_fatal;
|
||||
int spamfilter_stop_on_first_match;
|
||||
int spamfilter_utf8;
|
||||
int maxbans;
|
||||
int maxbanlength;
|
||||
int watch_away_notification;
|
||||
@ -171,6 +174,7 @@ struct Configuration {
|
||||
char *sasl_server;
|
||||
int server_notice_colors;
|
||||
int server_notice_show_event;
|
||||
LimitSVSCMDS limit_svscmds;
|
||||
};
|
||||
|
||||
extern MODVAR Configuration iConf;
|
||||
|
@ -35,7 +35,7 @@ extern int fd_fileopen(const char *path, unsigned int flags);
|
||||
#define FD_SELECT_WRITE 0x2
|
||||
|
||||
extern void fd_setselect(int fd, int flags, IOCallbackFunc iocb, void *data);
|
||||
extern void fd_select(time_t delay); /* backend-specific */
|
||||
extern void fd_select(int delay); /* backend-specific */
|
||||
extern void fd_refresh(int fd); /* backend-specific */
|
||||
extern void fd_fork(); /* backend-specific */
|
||||
|
||||
|
141
include/h.h
141
include/h.h
@ -105,7 +105,6 @@ extern MODVAR ConfigItem_link *conf_link;
|
||||
extern MODVAR ConfigItem_sni *conf_sni;
|
||||
extern MODVAR ConfigItem_ban *conf_ban;
|
||||
extern MODVAR ConfigItem_deny_channel *conf_deny_channel;
|
||||
extern MODVAR ConfigItem_deny_link *conf_deny_link;
|
||||
extern MODVAR ConfigItem_allow_channel *conf_allow_channel;
|
||||
extern MODVAR ConfigItem_deny_version *conf_deny_version;
|
||||
extern MODVAR ConfigItem_alias *conf_alias;
|
||||
@ -148,7 +147,7 @@ extern ConfigItem_listen *find_listen(const char *ipmask, int port, SocketType s
|
||||
extern ConfigItem_sni *find_sni(const char *name);
|
||||
extern ConfigItem_ulines *find_uline(const char *host);
|
||||
extern ConfigItem_tld *find_tld(Client *cptr);
|
||||
extern ConfigItem_link *find_link(const char *servername, Client *acptr);
|
||||
extern ConfigItem_link *find_link(const char *servername);
|
||||
extern ConfigItem_ban *find_ban(Client *, const char *host, short type);
|
||||
extern ConfigItem_ban *find_banEx(Client *,const char *host, short type, short type2);
|
||||
extern ConfigItem_vhost *find_vhost(const char *name);
|
||||
@ -183,6 +182,7 @@ 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 MODVAR struct list_head rpc_remote_list;
|
||||
extern RealCommand *find_command(const char *cmd, int flags);
|
||||
extern RealCommand *find_command_simple(const char *cmd);
|
||||
extern Membership *find_membership_link(Membership *lp, Channel *ptr);
|
||||
@ -226,12 +226,15 @@ extern const char *extban_conv_param_nuh_or_extban(BanContext *b, Extban *extban
|
||||
extern const char *extban_conv_param_nuh(BanContext *b, Extban *extban);
|
||||
extern Ban *is_banned(Client *, Channel *, int, const char **, const char **);
|
||||
extern Ban *is_banned_with_nick(Client *, Channel *, int, const char *, const char **, const char **);
|
||||
extern int ban_exists(Ban *lst, const char *str);
|
||||
extern int ban_exists_ignore_time(Ban *lst, const char *str);
|
||||
|
||||
extern Client *find_client(const char *, Client *);
|
||||
extern Client *find_name(const char *, Client *);
|
||||
extern Client *find_nickserv(const char *, Client *);
|
||||
extern Client *find_user(const char *, Client *);
|
||||
extern Client *find_server(const char *, Client *);
|
||||
extern Client *find_server_by_uid(const char *uid);
|
||||
extern Client *find_service(const char *, Client *);
|
||||
#define find_server_quick(x) find_server(x, NULL)
|
||||
extern char *find_or_add(char *);
|
||||
@ -283,6 +286,7 @@ extern void sendto_channel(Channel *channel, Client *from, Client *skip,
|
||||
extern void sendto_local_common_channels(Client *user, Client *skip,
|
||||
long clicap, MessageTag *mtags,
|
||||
FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,5,6)));
|
||||
extern void quit_sendto_local_common_channels(Client *user, MessageTag *mtags, const char *reason);
|
||||
extern void sendto_match_servs(Channel *, Client *, FORMAT_STRING(const char *), ...) __attribute__((format(printf,3,4)));
|
||||
extern void sendto_match_butone(Client *, Client *, const char *, int, MessageTag *,
|
||||
FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,6,7)));
|
||||
@ -312,8 +316,33 @@ extern void sendnotice(Client *to, FORMAT_STRING(const char *pattern), ...) __at
|
||||
* @endcode
|
||||
* @ingroup SendFunctions
|
||||
*/
|
||||
#define sendnumeric(to, numeric, ...) sendnumericfmt(to, numeric, STR_ ## numeric, ##__VA_ARGS__)
|
||||
extern void sendnumericfmt(Client *to, int numeric, FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,3,4)));
|
||||
#define sendnumeric(to, numeric, ...) sendtaggednumericfmt(to, NULL, numeric, STR_ ## numeric, ##__VA_ARGS__)
|
||||
|
||||
/** Send numeric message to a client - format to user specific needs.
|
||||
* This will ignore the numeric definition of src/numeric.c and always send ":me.name numeric clientname "
|
||||
* followed by the pattern and format string you choose.
|
||||
* @param to The recipient
|
||||
* @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c
|
||||
* @param pattern The format string / pattern to use.
|
||||
* @param ... Format string parameters.
|
||||
* @note Don't forget to add a colon if you need it (eg `:%%s`), this is a common mistake.
|
||||
*/
|
||||
#define sendnumericfmt(to, numeric, ...) sendtaggednumericfmt(to, NULL, numeric, __VA_ARGS__)
|
||||
|
||||
/** Send numeric message to a client - format to user specific needs.
|
||||
* This will ignore the numeric definition of src/numeric.c and always send ":me.name numeric clientname "
|
||||
* followed by the pattern and format string you choose.
|
||||
* @param to The recipient
|
||||
* @param mtags NULL, or NULL-terminated array of message tags
|
||||
* @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c
|
||||
* @param pattern The format string / pattern to use.
|
||||
* @param ... Format string parameters.
|
||||
* @note Don't forget to add a colon if you need it (eg `:%%s`), this is a common mistake.
|
||||
*/
|
||||
#define sendtaggednumeric(to, mtags, numeric, ...) sendtaggednumericfmt(to, mtags, numeric, STR_ ## numeric, ##__VA_ARGS__)
|
||||
|
||||
extern void sendtaggednumericfmt(Client *to, MessageTag *mtags, int numeric, FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,4,5)));
|
||||
|
||||
extern void sendtxtnumeric(Client *to, FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,2,3)));
|
||||
/** Build numeric message so it is ready to be sent to a client - rarely used, normally you use sendnumeric() instead.
|
||||
* This function is normally only used in eg CAN_KICK and CAN_SET_TOPIC, where
|
||||
@ -408,7 +437,13 @@ extern uint64_t siphash_raw(const char *in, size_t len, const char *k);
|
||||
extern uint64_t siphash_nocase(const char *in, const char *k);
|
||||
extern void siphash_generate_key(char *k);
|
||||
extern void init_hash(void);
|
||||
uint64_t hash_whowas_name(const char *name);
|
||||
extern void add_whowas_to_clist(WhoWas **, WhoWas *);
|
||||
extern void del_whowas_from_clist(WhoWas **, WhoWas *);
|
||||
extern void add_whowas_to_list(WhoWas **, WhoWas *);
|
||||
extern void del_whowas_from_list(WhoWas **, WhoWas *);
|
||||
extern uint64_t hash_whowas_name(const char *name);
|
||||
extern void create_whowas_entry(Client *client, WhoWas *e, WhoWasEvent event);
|
||||
extern void free_whowas_fields(WhoWas *e);
|
||||
extern int add_to_client_hash_table(const char *, Client *);
|
||||
extern int del_from_client_hash_table(const char *, Client *);
|
||||
extern int add_to_id_hash_table(const char *, Client *);
|
||||
@ -454,6 +489,9 @@ extern MODVAR long SNO_SNOTICE;
|
||||
extern MODVAR long SNO_SPAMF;
|
||||
extern MODVAR long SNO_OPER;
|
||||
|
||||
#ifndef HAVE_STRNLEN
|
||||
extern size_t strnlen(const char *s, size_t maxlen);
|
||||
#endif
|
||||
#ifndef HAVE_STRLCPY
|
||||
extern size_t strlcpy(char *dst, const char *src, size_t size);
|
||||
#endif
|
||||
@ -489,11 +527,11 @@ extern MODVAR RealCommand *CommandHash[256];
|
||||
extern void init_CommandHash(void);
|
||||
|
||||
/* CRULE */
|
||||
char *crule_parse(char *);
|
||||
int crule_test(char *);
|
||||
char *crule_errstring(int);
|
||||
int crule_eval(char *);
|
||||
void crule_free(char **);
|
||||
extern struct CRuleNode* crule_parse(const char*);
|
||||
extern void crule_free(struct CRuleNode**);
|
||||
extern int crule_eval(struct CRuleNode* rule);
|
||||
extern int crule_test(const char *rule);
|
||||
extern const char *crule_errstring(int errcode);
|
||||
|
||||
/*
|
||||
* Close all local socket connections, invalidate client fd's
|
||||
@ -664,11 +702,16 @@ extern void IRCToRTF(unsigned char *buffer, unsigned char *string);
|
||||
#endif
|
||||
extern void verify_opercount(Client *, const char *);
|
||||
extern int valid_host(const char *host, int strict);
|
||||
extern int valid_username(const char *username);
|
||||
extern int valid_vhost(const char *userhost);
|
||||
extern int count_oper_sessions(const char *);
|
||||
extern char *unreal_mktemp(const char *dir, const char *suffix);
|
||||
extern char *unreal_getpathname(const char *filepath, char *path);
|
||||
extern const char *unreal_getfilename(const char *path);
|
||||
extern const char *unreal_getmodfilename(const char *path);
|
||||
extern int unreal_create_directory_structure_for_file(const char *fname, mode_t mode);
|
||||
extern int unreal_create_directory_structure(const char *dname, mode_t mode);
|
||||
extern int unreal_mkdir(const char *pathname, mode_t mode);
|
||||
extern int unreal_copyfile(const char *src, const char *dest);
|
||||
extern int unreal_copyfileex(const char *src, const char *dest, int tryhardlink);
|
||||
extern time_t unreal_getfilemodtime(const char *filename);
|
||||
@ -704,8 +747,8 @@ extern int add_banid(Client *, Channel *, const char *);
|
||||
extern int add_exbanid(Client *cptr, Channel *channel, const char *banid);
|
||||
extern int sub1_from_channel(Channel *);
|
||||
extern MODVAR CoreChannelModeTable corechannelmodetable[];
|
||||
extern char *unreal_encodespace(char *s);
|
||||
extern char *unreal_decodespace(char *s);
|
||||
extern char *unreal_encodespace(const char *s);
|
||||
extern char *unreal_decodespace(const char *s);
|
||||
extern MODVAR Link *helpign;
|
||||
extern void reread_motdsandrules();
|
||||
extern MODVAR int SVSNOOP;
|
||||
@ -739,12 +782,14 @@ extern MODVAR int (*can_join)(Client *client, Channel *channel, const char *key,
|
||||
extern MODVAR void (*do_mode)(Channel *channel, Client *client, MessageTag *mtags, int parc, const char *parv[], time_t sendts, int samode);
|
||||
extern MODVAR MultiLineMode *(*set_mode)(Channel *channel, Client *cptr, int parc, const char *parv[], u_int *pcount,
|
||||
char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]);
|
||||
extern MODVAR void (*set_channel_mode)(Channel *channel, char *modes, char *parameters);
|
||||
extern MODVAR void (*set_channel_mode)(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters);
|
||||
extern MODVAR void (*set_channel_topic)(Client *client, Channel *channel, MessageTag *recv_mtags, const char *topic, const char *set_by, time_t set_at);
|
||||
extern MODVAR void (*cmd_umode)(Client *, MessageTag *, int, const char **);
|
||||
extern MODVAR int (*register_user)(Client *client);
|
||||
extern MODVAR int (*tkl_hash)(unsigned int c);
|
||||
extern MODVAR char (*tkl_typetochar)(int type);
|
||||
extern MODVAR int (*tkl_chartotype)(char c);
|
||||
extern MODVAR char (*tkl_configtypetochar)(const char *name);
|
||||
extern MODVAR const char *(*tkl_type_string)(TKL *tk);
|
||||
extern MODVAR const char *(*tkl_type_config_string)(TKL *tk);
|
||||
extern MODVAR TKL *(*tkl_add_serverban)(int type, const char *usermask, const char *hostmask, const char *reason, const char *setby,
|
||||
@ -798,7 +843,6 @@ extern MODVAR void (*send_moddata_client)(Client *srv, Client *acptr);
|
||||
extern MODVAR void (*send_moddata_channel)(Client *srv, Channel *channel);
|
||||
extern MODVAR void (*send_moddata_members)(Client *srv);
|
||||
extern MODVAR void (*broadcast_moddata_client)(Client *acptr);
|
||||
extern MODVAR int (*check_banned)(Client *cptr, int exitflags);
|
||||
extern MODVAR void (*introduce_user)(Client *to, Client *acptr);
|
||||
extern MODVAR int (*check_deny_version)(Client *cptr, const char *software, int protocol, const char *flags);
|
||||
extern MODVAR int (*match_user)(const char *rmask, Client *acptr, int options);
|
||||
@ -810,6 +854,7 @@ extern MODVAR int (*do_remote_nick_name)(char *nick);
|
||||
extern MODVAR const char *(*charsys_get_current_languages)(void);
|
||||
extern MODVAR void (*broadcast_sinfo)(Client *acptr, Client *to, Client *except);
|
||||
extern MODVAR void (*connect_server)(ConfigItem_link *aconf, Client *by, struct hostent *hp);
|
||||
extern MODVAR int (*is_services_but_not_ulined)(Client *client);
|
||||
extern MODVAR void (*parse_message_tags)(Client *cptr, char **str, MessageTag **mtag_list);
|
||||
extern MODVAR const char *(*mtags_to_string)(MessageTag *m, Client *acptr);
|
||||
extern MODVAR int (*can_send_to_channel)(Client *cptr, Channel *channel, const char **msgtext, const char **errmsg, int notice);
|
||||
@ -818,6 +863,9 @@ extern MODVAR void (*broadcast_md_globalvar_cmd)(Client *except, Client *sender,
|
||||
extern MODVAR int (*tkl_ip_hash)(const char *ip);
|
||||
extern MODVAR int (*tkl_ip_hash_type)(int type);
|
||||
extern MODVAR int (*find_tkl_exception)(int ban_type, Client *cptr);
|
||||
extern MODVAR int (*server_ban_parse_mask)(Client *client, int add, char type, const char *str, char **usermask_out, char **hostmask_out, int *soft, const char **error);
|
||||
extern MODVAR int (*server_ban_exception_parse_mask)(Client *client, int add, const char *bantypes, const char *str, char **usermask_out, char **hostmask_out, int *soft, const char **error);
|
||||
extern MODVAR void (*tkl_added)(Client *client, TKL *tkl);
|
||||
extern MODVAR int (*del_silence)(Client *client, const char *mask);
|
||||
extern MODVAR int (*add_silence)(Client *client, const char *mask, int senderr);
|
||||
extern MODVAR int (*is_silenced)(Client *client, Client *acptr);
|
||||
@ -836,6 +884,22 @@ extern MODVAR char *(*get_chmodes_for_user)(Client *client, const char *flags);
|
||||
extern MODVAR WhoisConfigDetails (*whois_get_policy)(Client *client, Client *target, const char *name);
|
||||
extern MODVAR int (*make_oper)(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost);
|
||||
extern MODVAR int (*unreal_match_iplist)(Client *client, NameList *l);
|
||||
extern MODVAR void (*webserver_send_response)(Client *client, int status, char *msg);
|
||||
extern MODVAR void (*webserver_close_client)(Client *client);
|
||||
extern MODVAR int (*webserver_handle_body)(Client *client, WebRequest *web, const char *readbuf, int length);
|
||||
extern MODVAR void (*rpc_response)(Client *client, json_t *request, json_t *result);
|
||||
extern MODVAR void (*rpc_error)(Client *client, json_t *request, JsonRpcError error_code, const char *error_message);
|
||||
extern MODVAR void (*rpc_error_fmt)(Client *client, json_t *request, JsonRpcError error_code, FORMAT_STRING(const char *fmt), ...) __attribute__((format(printf,4,5)));
|
||||
extern MODVAR void (*rpc_send_request_to_remote)(Client *source, Client *target, json_t *request);
|
||||
extern MODVAR void (*rpc_send_response_to_remote)(Client *source, Client *target, json_t *request);
|
||||
extern MODVAR int (*rrpc_supported_simple)(Client *target, char **problem_server);
|
||||
extern MODVAR int (*rrpc_supported)(Client *target, const char *module, const char *minimum_version, char **problem_server);
|
||||
extern MODVAR int (*websocket_handle_websocket)(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len));
|
||||
extern MODVAR int (*websocket_create_packet)(int opcode, char **buf, int *len);
|
||||
extern MODVAR int (*websocket_create_packet_ex)(int opcode, char **buf, int *len, char *sendbuf, size_t sendbufsize);
|
||||
extern MODVAR int (*websocket_create_packet_simple)(int opcode, const char **buf, int *len);
|
||||
extern MODVAR const char *(*check_deny_link)(ConfigItem_link *link, int auto_connect);
|
||||
extern MODVAR void (*mtag_add_issued_by)(MessageTag **mtags, Client *client, MessageTag *recv_mtags);
|
||||
/* /Efuncs */
|
||||
|
||||
/* TLS functions */
|
||||
@ -872,6 +936,21 @@ extern int del_silence_default_handler(Client *client, const char *mask);
|
||||
extern int is_silenced_default_handler(Client *client, Client *acptr);
|
||||
extern void do_unreal_log_remote_deliver_default_handler(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized);
|
||||
extern int make_oper_default_handler(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost);
|
||||
extern void webserver_send_response_default_handler(Client *client, int status, char *msg);
|
||||
extern void webserver_close_client_default_handler(Client *client);
|
||||
extern int webserver_handle_body_default_handler(Client *client, WebRequest *web, const char *readbuf, int length);
|
||||
extern void rpc_response_default_handler(Client *client, json_t *request, json_t *result);
|
||||
extern void rpc_error_default_handler(Client *client, json_t *request, JsonRpcError error_code, const char *error_message);
|
||||
extern void rpc_error_fmt_default_handler(Client *client, json_t *request, JsonRpcError error_code, const char *fmt, ...);
|
||||
extern void rpc_send_request_to_remote_default_handler(Client *source, Client *target, json_t *request);
|
||||
extern void rpc_send_response_to_remote_default_handler(Client *source, Client *target, json_t *response);
|
||||
extern int rrpc_supported_simple_default_handler(Client *target, char **problem_server);
|
||||
extern int rrpc_supported_default_handler(Client *target, const char *module, const char *minimum_version, char **problem_server);
|
||||
extern int websocket_handle_websocket_default_handler(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len));
|
||||
extern int websocket_create_packet_default_handler(int opcode, char **buf, int *len);
|
||||
extern int websocket_create_packet_ex_default_handler(int opcode, char **buf, int *len, char *sendbuf, size_t sendbufsize);
|
||||
extern int websocket_create_packet_simple_default_handler(int opcode, const char **buf, int *len);
|
||||
extern void mtag_add_issued_by_default_handler(MessageTag **mtags, Client *client, MessageTag *recv_mtags);
|
||||
/* End of default handlers for efunctions */
|
||||
|
||||
extern MODVAR MOTDFile opermotd, svsmotd, motd, botmotd, smotd, rules;
|
||||
@ -880,6 +959,7 @@ extern int add_listmode(Ban **list, Client *cptr, Channel *channel, const char *
|
||||
extern int add_listmode_ex(Ban **list, Client *cptr, Channel *channel, const char *banid, const char *setby, time_t seton);
|
||||
extern int del_listmode(Ban **list, Channel *channel, const char *banid);
|
||||
extern int Halfop_mode(long mode);
|
||||
extern const char *convert_regular_ban(char *mask, char *buf, size_t buflen);
|
||||
extern const char *clean_ban_mask(const char *, int, Client *, int);
|
||||
extern int find_invex(Channel *channel, Client *client);
|
||||
extern void DoMD5(char *mdout, const char *src, unsigned long n);
|
||||
@ -955,6 +1035,7 @@ extern int unix_sockets_capable(void);
|
||||
extern void init_winsock(void);
|
||||
#endif
|
||||
extern MODVAR Client *remote_rehash_client;
|
||||
extern MODVAR json_t *json_rehash_log;
|
||||
extern MODVAR int debugfd;
|
||||
extern void convert_to_absolute_path(char **path, const char *reldir);
|
||||
extern int has_user_mode(Client *acptr, char mode);
|
||||
@ -994,7 +1075,7 @@ extern int verify_certificate(SSL *ssl, const char *hostname, char **errstr);
|
||||
extern const char *certificate_name(SSL *ssl);
|
||||
extern void start_of_normal_client_handshake(Client *acptr);
|
||||
extern void clicap_pre_rehash(void);
|
||||
extern void clicap_post_rehash(void);
|
||||
extern void clicap_check_for_changes(void);
|
||||
extern void unload_all_unused_mtag_handlers(void);
|
||||
extern void send_cap_notify(int add, const char *token);
|
||||
extern void sendbufto_one(Client *to, char *msg, unsigned int quick);
|
||||
@ -1002,6 +1083,7 @@ extern MODVAR int current_serial;
|
||||
extern const char *spki_fingerprint(Client *acptr);
|
||||
extern const char *spki_fingerprint_ex(X509 *x509_cert);
|
||||
extern int is_module_loaded(const char *name);
|
||||
extern int is_blacklisted_module(const char *name);
|
||||
extern void close_std_descriptors(void);
|
||||
extern void banned_client(Client *acptr, const char *bantype, const char *reason, int global, int noexit);
|
||||
extern char *mystpcpy(char *dst, const char *src);
|
||||
@ -1093,6 +1175,7 @@ extern int hide_idle_time(Client *client, Client *target);
|
||||
extern void lost_server_link(Client *serv, const char *tls_error_string);
|
||||
extern const char *sendtype_to_cmd(SendType sendtype);
|
||||
extern MODVAR MessageTagHandler *mtaghandlers;
|
||||
extern MODVAR RPCHandler *rpchandlers;
|
||||
#define nv_find_by_name(stru, name) do_nv_find_by_name(stru, name, ARRAY_SIZEOF((stru)))
|
||||
extern long do_nv_find_by_name(NameValue *table, const char *cmd, int numelements);
|
||||
#define nv_find_by_value(stru, value) do_nv_find_by_value(stru, value, ARRAY_SIZEOF((stru)))
|
||||
@ -1111,6 +1194,7 @@ extern void add_fmt_nvplist(NameValuePrioList **lst, int priority, const char *n
|
||||
#define add_nvplist_numeric(lst, priority, name, to, numeric, ...) add_nvplist_numeric_fmt(lst, priority, name, to, numeric, STR_ ## numeric, ##__VA_ARGS__)
|
||||
extern void add_nvplist_numeric_fmt(NameValuePrioList **lst, int priority, const char *name, Client *to, int numeric, FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,6,7)));
|
||||
extern NameValuePrioList *find_nvplist(NameValuePrioList *list, const char *name);
|
||||
extern const char *get_nvplist(NameValuePrioList *list, const char *name);
|
||||
extern void free_nvplist(NameValuePrioList *lst);
|
||||
extern void unreal_add_name_values(NameValuePrioList **n, const char *name, ConfigEntry *ce);
|
||||
extern const char *namevalue(NameValuePrioList *n);
|
||||
@ -1127,7 +1211,21 @@ extern void skip_whitespace(char **p);
|
||||
extern void read_until(char **p, char *stopchars);
|
||||
extern int is_ip_valid(const char *ip);
|
||||
extern int is_file_readable(const char *file, const char *dir);
|
||||
json_t *json_string_unreal(const char *s);
|
||||
/* json.c */
|
||||
extern int log_json_filter;
|
||||
extern json_t *json_string_unreal(const char *s);
|
||||
extern const char *json_object_get_string(json_t *j, const char *name);
|
||||
extern int json_object_get_integer(json_t *j, const char *name, int default_value);
|
||||
extern int json_object_get_boolean(json_t *j, const char *name, int default_value);
|
||||
extern json_t *json_timestamp(time_t v);
|
||||
extern const char *timestamp_iso8601_now(void);
|
||||
extern const char *timestamp_iso8601(time_t v);
|
||||
extern const char *json_get_value(json_t *t);
|
||||
extern void json_expand_client(json_t *j, const char *key, Client *client, int detail);
|
||||
extern void json_expand_client_security_groups(json_t *parent, Client *client);
|
||||
extern void json_expand_channel(json_t *j, const char *key, Channel *channel, int detail);
|
||||
extern void json_expand_tkl(json_t *j, const char *key, TKL *tkl, int detail);
|
||||
/* end of json.c */
|
||||
/* securitygroup.c start */
|
||||
extern MODVAR SecurityGroup *securitygroups;
|
||||
extern void unreal_delete_masks(ConfigItem_mask *m);
|
||||
@ -1202,7 +1300,7 @@ extern const char *log_type_valtostring(LogType v);
|
||||
#endif
|
||||
extern void do_unreal_log(LogLevel loglevel, const char *subsystem, const char *event_id, Client *client, const char *msg, ...) __attribute__((format(printf,5,0)));
|
||||
extern void do_unreal_log_raw(LogLevel loglevel, const char *subsystem, const char *event_id, Client *client, const char *msg, ...);
|
||||
extern void do_unreal_log_internal_from_remote(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized, Client *from_server);
|
||||
extern void do_unreal_log_internal_from_remote(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, json_t *json, const char *json_serialized, Client *from_server);
|
||||
extern LogData *log_data_string(const char *key, const char *str);
|
||||
extern LogData *log_data_char(const char *key, const char c);
|
||||
extern LogData *log_data_integer(const char *key, int64_t integer);
|
||||
@ -1219,11 +1317,15 @@ extern int log_tests(void);
|
||||
extern void config_pre_run_log(void);
|
||||
extern void log_blocks_switchover(void);
|
||||
extern void postconf_defaults_log_block(void);
|
||||
extern int valid_loglevel(int v);
|
||||
extern LogLevel log_level_stringtoval(const char *str);
|
||||
extern const char *log_level_valtostring(LogLevel loglevel);
|
||||
extern LogLevel log_level_stringtoval(const char *str);
|
||||
extern int valid_event_id(const char *s);
|
||||
extern int valid_subsystem(const char *s);
|
||||
extern LogSource *add_log_source(const char *str);
|
||||
extern void free_log_sources(LogSource *l);
|
||||
extern int log_sources_match(LogSource *logsource, LogLevel loglevel, const char *subsystem, const char *event_id, int matched_already);
|
||||
extern const char *timestamp_iso8601_now(void);
|
||||
extern const char *timestamp_iso8601(time_t v);
|
||||
extern int is_valid_snomask(char c);
|
||||
@ -1244,11 +1346,13 @@ extern const char *displayurl(const char *url);
|
||||
extern char *url_getfilename(const char *url);
|
||||
extern void download_file_async(const char *url, time_t cachetime, vFP callback, void *callback_data, char *original_url, int maxredirects);
|
||||
extern void url_init(void);
|
||||
extern void url_cancel_handle_by_callback_data(void *ptr);
|
||||
extern EVENT(url_socket_timeout);
|
||||
/* end of url stuff */
|
||||
extern char *collapse(char *pattern);
|
||||
extern void clear_scache_hash_table(void);
|
||||
extern void sendto_one(Client *, MessageTag *mtags, FORMAT_STRING(const char *), ...) __attribute__((format(printf,3,4)));
|
||||
extern void mark_data_to_send(Client *to);
|
||||
extern EVENT(garbage_collect);
|
||||
extern EVENT(loop_event);
|
||||
extern EVENT(check_pings);
|
||||
@ -1270,5 +1374,8 @@ 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);
|
||||
extern long get_connected_time(Client *client);
|
||||
extern time_t get_creationtime(Client *client);
|
||||
extern const char *StripControlCodes(const char *text);
|
||||
extern const char *StripControlCodesEx(const char *text, char *output, size_t outputlen, int strip_flags);
|
||||
extern MODVAR Module *Modules;
|
||||
extern const char *command_issued_by_rpc(MessageTag *mtags);
|
||||
|
@ -22,7 +22,7 @@
|
||||
#define MODULES_H
|
||||
#include "types.h"
|
||||
#define MAXCUSTOMHOOKS 30
|
||||
#define MAXHOOKTYPES 150
|
||||
#define MAXHOOKTYPES 200
|
||||
#define MAXCALLBACKS 30
|
||||
#define MAXEFUNCTIONS 128
|
||||
#if defined(_WIN32)
|
||||
@ -107,6 +107,7 @@ typedef enum ModuleObjectType {
|
||||
MOBJ_CLICAP = 16,
|
||||
MOBJ_MTAG = 17,
|
||||
MOBJ_HISTORY_BACKEND = 18,
|
||||
MOBJ_RPC = 19,
|
||||
} ModuleObjectType;
|
||||
|
||||
typedef struct Umode Umode;
|
||||
@ -284,10 +285,13 @@ struct Cmode {
|
||||
|
||||
/** Free and remove parameter from list.
|
||||
* This function pointer is NULL (unused) for modes without parameters.
|
||||
* @param parastruct The parameter struct
|
||||
* @param parastruct The parameter struct
|
||||
* @param soft This is set to 1 if you may 'resist freeing'
|
||||
* (used by floodprot module to have active F profile even if -F).
|
||||
* @returns Normally return 0, must return 1 if it 'resisted' freeing.
|
||||
* @note In most cases you will just call safe_free() on 'list'
|
||||
*/
|
||||
void (*free_param)(void *parastruct);
|
||||
int (*free_param)(void *parastruct, int soft);
|
||||
|
||||
/** duplicate a struct and return a pointer to duplicate.
|
||||
* This function pointer is NULL (unused) for modes without parameters.
|
||||
@ -317,6 +321,11 @@ struct Cmode {
|
||||
/** Unsetting also eats/requires a parameter. Unusual, but possible. */
|
||||
char unset_with_param;
|
||||
|
||||
/** Is this mode available for chanmode +f, and if so for which flood type?
|
||||
* eg 'j' for join flood.
|
||||
*/
|
||||
char flood_type_action;
|
||||
|
||||
/** Is this mode being unloaded?
|
||||
* This is set to 1 if the chanmode module providing this mode is unloaded
|
||||
* and we are waiting to see if in our new round of loads a "new" chanmode
|
||||
@ -324,7 +333,7 @@ struct Cmode {
|
||||
* should never be 0 outside an internal rehash.
|
||||
*/
|
||||
char unloaded;
|
||||
|
||||
|
||||
/** Slot number - Can be used instead of GETPARAMSLOT() */
|
||||
int param_slot;
|
||||
|
||||
@ -346,11 +355,12 @@ typedef struct {
|
||||
void * (*put_param)(void *, const char *);
|
||||
const char * (*get_param)(void *);
|
||||
const char * (*conv_param)(const char *, Client *, Channel *);
|
||||
void (*free_param)(void *);
|
||||
int (*free_param)(void *, int);
|
||||
void * (*dup_struct)(void *);
|
||||
int (*sjoin_check)(Channel *, void *, void *);
|
||||
char local;
|
||||
char unset_with_param;
|
||||
char flood_type_action;
|
||||
} CmodeInfo;
|
||||
|
||||
/** Get a slot number for a param - eg GETPARAMSLOT('k') */
|
||||
@ -433,7 +443,7 @@ struct Extban {
|
||||
|
||||
int (*is_ok)(BanContext *b);
|
||||
|
||||
/** Convert input parameter to output [optional].
|
||||
/** Convert input parameter to output.
|
||||
* like with normal bans '+b blah' gets '+b blah!*@*', and it allows
|
||||
* you to limit the length of the ban too.
|
||||
* return value: pointer to output string (temp. storage)
|
||||
@ -604,6 +614,49 @@ typedef struct {
|
||||
int (*history_destroy)(const char *object);
|
||||
} HistoryBackendInfo;
|
||||
|
||||
/** @defgroup RPCAPI RPC API
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** No special flags set */
|
||||
#define RPC_HANDLER_FLAGS_NONE 0x0
|
||||
#define RPC_HANDLER_FLAGS_UNFILTERED 0x1 /**< Don't filter input (don't reject strings bigger than 510 in length or containing \r or \n) */
|
||||
|
||||
/** RPC Tag Handler */
|
||||
typedef struct RPCHandler RPCHandler;
|
||||
struct RPCHandler {
|
||||
RPCHandler *prev, *next;
|
||||
char *method; /**< Name of the method handler, eg "client.get" */
|
||||
int flags; /**< A flag of RPC_HANDLER_FLAG_* */
|
||||
LogLevel loglevel; /**< Log level to use for this call: for example ULOG_DEBUG for .list calls, leave 0 for default */
|
||||
void (*call)(Client *, json_t *request, json_t *params); /**< RPC call: use RPC_CALL_FUNC() ! */
|
||||
Module *owner; /**< Module introducing this. */
|
||||
char unloaded; /**< Internal flag to indicate module is being unloaded */
|
||||
};
|
||||
|
||||
/** The struct used to register a RPC handler.
|
||||
* For documentation, see the RPCHandler struct.
|
||||
*/
|
||||
typedef struct {
|
||||
char *method;
|
||||
int flags;
|
||||
LogLevel loglevel;
|
||||
void (*call)(Client *, json_t *request, json_t *params);
|
||||
} RPCHandlerInfo;
|
||||
|
||||
/** RPC function - used by all RPC call functions.
|
||||
* This is used in the code like <pre>RPC_CALL_FUNC(rpc_call_xyz)</pre> as a function definition.
|
||||
* It allows the UnrealIRCd devs to add or change parameters to the function without
|
||||
* (necessarily) breaking your code.
|
||||
* @param client The client issueing the request
|
||||
* @param request The full JSON-RPC request
|
||||
* @param params Parameters of the JSON-RPC call
|
||||
* @note You are expected to call rpc_response() or rpc_error() on the request.
|
||||
*/
|
||||
#define RPC_CALL_FUNC(x) void (x) (Client *client, json_t *request, json_t *params)
|
||||
|
||||
/** @} */
|
||||
|
||||
struct Hook {
|
||||
Hook *prev, *next;
|
||||
int priority;
|
||||
@ -688,6 +741,7 @@ typedef struct ModuleObject {
|
||||
ClientCapability *clicap;
|
||||
MessageTagHandler *mtag;
|
||||
HistoryBackend *history_backend;
|
||||
RPCHandler *rpc;
|
||||
} object;
|
||||
} ModuleObject;
|
||||
|
||||
@ -735,9 +789,15 @@ struct Module
|
||||
#define MOD_OPT_OFFICIAL 0x0002 /* Official module, do not set "tainted" */
|
||||
#define MOD_OPT_PERM_RELOADABLE 0x0004 /* Module is semi-permanent: it can be re-loaded but not un-loaded */
|
||||
#define MOD_OPT_GLOBAL 0x0008 /* Module is required to be loaded globally (i.e. across the entire network) */
|
||||
#define MOD_OPT_UNLOAD_PRIORITY 0x1000 /* Module wants a higher or lower unload priority */
|
||||
#define MOD_OPT_PRIORITY 0x1000 /* Module wants a higher or lower priority for unloading, init, load, etc */
|
||||
#define MOD_OPT_UNLOAD_PRIORITY 0x1000 /* Alias for MOD_OPT_PRIORITY */
|
||||
#define MOD_Dep(name, container,module) {#name, (vFP *) &container, module}
|
||||
|
||||
/** Websocket module should init 'first' because it handles sockets */
|
||||
#define WEBSOCKET_MODULE_PRIORITY_INIT -1000000000
|
||||
/** Websocket module should unload 'last' because it handles sockets */
|
||||
#define WEBSOCKET_MODULE_PRIORITY_UNLOAD 1000000000
|
||||
|
||||
/** Event structs */
|
||||
struct Event {
|
||||
Event *prev; /**< Previous event (linked list) */
|
||||
@ -825,6 +885,10 @@ extern HistoryBackend *HistoryBackendFind(const char *name);
|
||||
extern HistoryBackend *HistoryBackendAdd(Module *module, HistoryBackendInfo *mreq);
|
||||
extern void HistoryBackendDel(HistoryBackend *m);
|
||||
|
||||
extern RPCHandler *RPCHandlerFind(const char *method);
|
||||
extern RPCHandler *RPCHandlerAdd(Module *module, RPCHandlerInfo *mreq);
|
||||
extern void RPCHandlerDel(RPCHandler *m);
|
||||
|
||||
#ifndef GCC_TYPECHECKING
|
||||
#define HookAdd(module, hooktype, priority, func) HookAddMain(module, hooktype, priority, func, NULL, NULL, NULL)
|
||||
#define HookAddVoid(module, hooktype, priority, func) HookAddMain(module, hooktype, priority, NULL, func, NULL, NULL)
|
||||
@ -909,6 +973,11 @@ extern int CommandExists(const char *name);
|
||||
extern CommandOverride *CommandOverrideAdd(Module *module, const char *name, int priority, OverrideCmdFunc func);
|
||||
extern void CommandOverrideDel(CommandOverride *ovr);
|
||||
extern void CallCommandOverride(CommandOverride *ovr, Client *client, MessageTag *mtags, int parc, const char *parv[]);
|
||||
/** Call next command override function - easy way to do it.
|
||||
* This way you don't have to call CallCommandOverride() with the right arguments.
|
||||
* Which is nice because command (override) arguments may change in future UnrealIRCd versions.
|
||||
*/
|
||||
#define CALL_NEXT_COMMAND_OVERRIDE() CallCommandOverride(ovr, client, recv_mtags, parc, parv)
|
||||
|
||||
extern void moddata_free_client(Client *acptr);
|
||||
extern void moddata_free_local_client(Client *acptr);
|
||||
@ -937,6 +1006,11 @@ extern int LoadPersistentLongX(ModuleInfo *modinfo, const char *varshortname, lo
|
||||
extern void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, long var);
|
||||
#define SavePersistentLong(modinfo, var) SavePersistentLongX(modinfo, #var, var)
|
||||
|
||||
extern int LoadPersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long *var);
|
||||
#define LoadPersistentLongLong(modinfo, var) LoadPersistentLongLongX(modinfo, #var, &var)
|
||||
extern void SavePersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long var);
|
||||
#define SavePersistentLongLong(modinfo, var) SavePersistentLongLongX(modinfo, #var, var)
|
||||
|
||||
/** Hooks trigger on "events", such as a new user connecting or joining a channel,
|
||||
* see https://www.unrealircd.org/docs/Dev:Hook_API for background info.
|
||||
* You are suggested to use CTRL+F on this page to search for any useful hook,
|
||||
@ -1170,6 +1244,12 @@ extern void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, l
|
||||
#define HOOKTYPE_JSON_EXPAND_CLIENT_SERVER 114
|
||||
/** See hooktype_json_expand_channel() */
|
||||
#define HOOKTYPE_JSON_EXPAND_CHANNEL 115
|
||||
/** See hooktype_accept() */
|
||||
#define HOOKTYPE_ACCEPT 116
|
||||
/** See hooktype_pre_local_handshake_timeout */
|
||||
#define HOOKTYPE_PRE_LOCAL_HANDSHAKE_TIMEOUT 117
|
||||
/** See hooktype_rehash_log */
|
||||
#define HOOKTYPE_REHASH_LOG 118
|
||||
|
||||
/* Adding a new hook here?
|
||||
* 1) Add the #define HOOKTYPE_.... with a new number
|
||||
@ -1759,11 +1839,12 @@ int hooktype_tkl_del(Client *client, TKL *tkl);
|
||||
* @param subsystem Subsystem (eg "operoverride")
|
||||
* @param event_id Event ID (eg "SAJOIN_COMMAND")
|
||||
* @param msg Message(s) in text form
|
||||
* @param json_serialized The associated JSON text
|
||||
* @param json The JSON log entry
|
||||
* @param json_serialized The serialized JSON log entry (as a string)
|
||||
* @param timebuf The [xxxx] time buffer, for convenience
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_log(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized, const char *timebuf);
|
||||
int hooktype_log(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, json_t *json, const char *json_serialized, const char *timebuf);
|
||||
|
||||
/** Called when a local user matches a spamfilter (function prototype for HOOKTYPE_LOCAL_SPAMFILTER).
|
||||
* @param client The client
|
||||
@ -1821,6 +1902,18 @@ int hooktype_packet(Client *from, Client *to, Client *intended_to, char **msg, i
|
||||
*/
|
||||
int hooktype_handshake(Client *client);
|
||||
|
||||
/** Called very early when a client connects (function prototype for HOOKTYPE_ACCEPT).
|
||||
* Module coders: have a look at hooktype_handshake() instead of this one!
|
||||
* HOOKTYPE_ACCEPT is called even before HOOKTYPE_HANDSHAKE, as soon as the socket
|
||||
* is connected and during the client is being set up, before the SSL/TLS handshake.
|
||||
* It is only used for connection flood detection and checking (G)Z-lines.
|
||||
* Note that this connection is also called for *NIX domain socket connections,
|
||||
* HTTP(S) requests, and so on.
|
||||
* @param client The client
|
||||
* @return One of HOOK_*. Use HOOK_DENY to reject the client.
|
||||
*/
|
||||
int hooktype_accept(Client *client);
|
||||
|
||||
/** Called when a client structure is freed (function prototype for HOOKTYPE_FREE_CLIENT).
|
||||
* @param client The client
|
||||
* @note Normally you use hooktype_local_quit(), hooktype_remote_quit() and hooktype_unkuser_quit() for this.
|
||||
@ -2200,6 +2293,24 @@ int hooktype_json_expand_client_server(Client *client, int detail, json_t *j, js
|
||||
*/
|
||||
int hooktype_json_expand_channel(Channel *channel, int detail, json_t *j);
|
||||
|
||||
/** Called when a local user is about to be disconnected due to a registration timeout,
|
||||
* allows changing the disconnect reason (function prototype for HOOKTYPE_PRE_LOCAL_HANDSHAKE_TIMEOUT).
|
||||
* This is used by the authprompt module.
|
||||
* @param client The client
|
||||
* @param comment The quit/disconnect reason (can be changed by you)
|
||||
* @retval HOOK_CONTINUE Continue as normal
|
||||
* @retval HOOK_ALLOW Do not exit the user due to a handshake timeout
|
||||
*/
|
||||
int hooktype_pre_local_handshake_timeout(Client *client, const char **comment);
|
||||
|
||||
/** Called when a REHASH completed (either succesfully or with a failure).
|
||||
* This gives the full rehash log. Used by the JSON-RPC interface.
|
||||
* @param failure Set to 1 if the rehash failed, otherwise 0.
|
||||
* @param t The JSON object containing the rehash log and other information.
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_rehash_log(int failure, json_t *rehash_log);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef GCC_TYPECHECKING
|
||||
@ -2318,7 +2429,9 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CLIENT) && !ValidateHook(hooktype_json_expand_client, func)) || \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CLIENT_USER) && !ValidateHook(hooktype_json_expand_client_user, func)) || \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CLIENT_SERVER) && !ValidateHook(hooktype_json_expand_client_server, func)) || \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CHANNEL) && !ValidateHook(hooktype_json_expand_channel, func)) ) \
|
||||
((hooktype == HOOKTYPE_JSON_EXPAND_CHANNEL) && !ValidateHook(hooktype_json_expand_channel, func)) || \
|
||||
((hooktype == HOOKTYPE_PRE_LOCAL_HANDSHAKE_TIMEOUT) && !ValidateHook(hooktype_pre_local_handshake_timeout, func)) || \
|
||||
((hooktype == HOOKTYPE_REHASH_LOG) && !ValidateHook(hooktype_rehash_log, func)) ) \
|
||||
_hook_error_incompatible();
|
||||
#endif /* GCC_TYPECHECKING */
|
||||
|
||||
@ -2350,6 +2463,7 @@ enum EfunctionType {
|
||||
EFUNC_DO_MODE,
|
||||
EFUNC_SET_MODE,
|
||||
EFUNC_SET_CHANNEL_MODE,
|
||||
EFUNC_SET_CHANNEL_TOPIC,
|
||||
EFUNC_CMD_UMODE,
|
||||
EFUNC_REGISTER_USER,
|
||||
EFUNC_TKL_HASH,
|
||||
@ -2382,7 +2496,6 @@ enum EfunctionType {
|
||||
EFUNC_BROADCAST_MD_CHANNEL,
|
||||
EFUNC_BROADCAST_MD_MEMBER,
|
||||
EFUNC_BROADCAST_MD_MEMBERSHIP,
|
||||
EFUNC_CHECK_BANNED,
|
||||
EFUNC_INTRODUCE_USER,
|
||||
EFUNC_CHECK_DENY_VERSION,
|
||||
EFUNC_BROADCAST_MD_CLIENT_CMD,
|
||||
@ -2404,9 +2517,11 @@ enum EfunctionType {
|
||||
EFUNC_CHARSYS_GET_CURRENT_LANGUAGES,
|
||||
EFUNC_BROADCAST_SINFO,
|
||||
EFUNC_CONNECT_SERVER,
|
||||
EFUNC_IS_SERVICES_BUT_NOT_ULINED,
|
||||
EFUNC_PARSE_MESSAGE_TAGS,
|
||||
EFUNC_MTAGS_TO_STRING,
|
||||
EFUNC_TKL_CHARTOTYPE,
|
||||
EFUNC_TKL_CONFIGTYPETOCHAR,
|
||||
EFUNC_TKL_TYPE_STRING,
|
||||
EFUNC_TKL_TYPE_CONFIG_STRING,
|
||||
EFUNC_CAN_SEND_TO_CHANNEL,
|
||||
@ -2426,6 +2541,9 @@ enum EfunctionType {
|
||||
EFUNC_FIND_TKL_NAMEBAN,
|
||||
EFUNC_FIND_TKL_SPAMFILTER,
|
||||
EFUNC_FIND_TKL_EXCEPTION,
|
||||
EFUNC_SERVER_BAN_PARSE_MASK,
|
||||
EFUNC_SERVER_BAN_EXCEPTION_PARSE_MASK,
|
||||
EFUNC_TKL_ADDED,
|
||||
EFUNC_ADD_SILENCE,
|
||||
EFUNC_DEL_SILENCE,
|
||||
EFUNC_IS_SILENCED,
|
||||
@ -2444,6 +2562,22 @@ enum EfunctionType {
|
||||
EFUNC_WHOIS_GET_POLICY,
|
||||
EFUNC_MAKE_OPER,
|
||||
EFUNC_UNREAL_MATCH_IPLIST,
|
||||
EFUNC_WEBSERVER_SEND_RESPONSE,
|
||||
EFUNC_WEBSERVER_CLOSE_CLIENT,
|
||||
EFUNC_WEBSERVER_HANDLE_BODY,
|
||||
EFUNC_RPC_RESPONSE,
|
||||
EFUNC_RPC_ERROR,
|
||||
EFUNC_RPC_ERROR_FMT,
|
||||
EFUNC_RPC_SEND_REQUEST_TO_REMOTE,
|
||||
EFUNC_RPC_SEND_RESPONSE_TO_REMOTE,
|
||||
EFUNC_RRPC_SUPPORTED,
|
||||
EFUNC_RRPC_SUPPORTED_SIMPLE,
|
||||
EFUNC_WEBSOCKET_HANDLE_WEBSOCKET,
|
||||
EFUNC_WEBSOCKET_CREATE_PACKET,
|
||||
EFUNC_WEBSOCKET_CREATE_PACKET_EX,
|
||||
EFUNC_WEBSOCKET_CREATE_PACKET_SIMPLE,
|
||||
EFUNC_CHECK_DENY_LINK,
|
||||
EFUNC_MTAG_GENERATE_ISSUED_BY_IRC,
|
||||
};
|
||||
|
||||
/* Module flags */
|
||||
|
@ -59,6 +59,7 @@
|
||||
#define ERR_NORECIPIENT 411
|
||||
#define ERR_NOTEXTTOSEND 412
|
||||
#define ERR_TOOMANYMATCHES 416
|
||||
#define ERR_INPUTTOOLONG 417
|
||||
|
||||
#define ERR_UNKNOWNCOMMAND 421
|
||||
#define ERR_NOMOTD 422
|
||||
@ -482,6 +483,7 @@
|
||||
#define STR_ERR_NORECIPIENT /* 411 */ ":No recipient given (%s)"
|
||||
#define STR_ERR_NOTEXTTOSEND /* 412 */ ":No text to send"
|
||||
#define STR_ERR_TOOMANYMATCHES /* 416 */ "%s :%s"
|
||||
#define STR_ERR_INPUTTOOLONG /* 417 */ ":Input line was too long"
|
||||
#define STR_ERR_UNKNOWNCOMMAND /* 421 */ "%s :Unknown command"
|
||||
#define STR_ERR_NOMOTD /* 422 */ ":MOTD File is missing"
|
||||
#define STR_ERR_NOADMININFO /* 423 */ "%s :No administrative info available"
|
||||
|
@ -43,6 +43,9 @@
|
||||
/* Define if ssl library has SSL_CTX_set_security_level */
|
||||
#undef HAS_SSL_CTX_SET_SECURITY_LEVEL
|
||||
|
||||
/* Define if ssl library has X509_check_host */
|
||||
#undef HAS_X509_check_host
|
||||
|
||||
/* Define if ssl library has X509_get0_notAfter */
|
||||
#undef HAS_X509_get0_notAfter
|
||||
|
||||
@ -76,9 +79,6 @@
|
||||
/* Define to 1 if you have the `kqueue' function. */
|
||||
#undef HAVE_KQUEUE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `poll' function. */
|
||||
#undef HAVE_POLL
|
||||
|
||||
@ -100,6 +100,9 @@
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
@ -121,6 +124,9 @@
|
||||
/* Define to 1 if you have the `strlncpy' function. */
|
||||
#undef HAVE_STRLNCPY
|
||||
|
||||
/* Define to 1 if you have the `strnlen' function. */
|
||||
#undef HAVE_STRNLEN
|
||||
|
||||
/* Define to 1 if you have the `syslog' function. */
|
||||
#undef HAVE_SYSLOG
|
||||
|
||||
@ -201,7 +207,9 @@
|
||||
tofail) */
|
||||
#undef STATIC_LINKING
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define if you have the <sys/syslog.h> header file. */
|
||||
|
283
include/struct.h
283
include/struct.h
@ -39,6 +39,9 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/ripemd.h>
|
||||
#ifdef HAS_X509_check_host
|
||||
#include <openssl/x509v3.h>
|
||||
#endif
|
||||
#include <jansson.h>
|
||||
#include "common.h"
|
||||
#include "sys.h"
|
||||
@ -104,7 +107,6 @@ typedef struct ConfigItem_vhost ConfigItem_vhost;
|
||||
typedef struct ConfigItem_link ConfigItem_link;
|
||||
typedef struct ConfigItem_ban ConfigItem_ban;
|
||||
typedef struct ConfigItem_deny_dcc ConfigItem_deny_dcc;
|
||||
typedef struct ConfigItem_deny_link ConfigItem_deny_link;
|
||||
typedef struct ConfigItem_deny_channel ConfigItem_deny_channel;
|
||||
typedef struct ConfigItem_deny_version ConfigItem_deny_version;
|
||||
typedef struct ConfigItem_alias ConfigItem_alias;
|
||||
@ -128,6 +130,7 @@ typedef struct LocalClient LocalClient;
|
||||
typedef struct Channel Channel;
|
||||
typedef struct User User;
|
||||
typedef struct Server Server;
|
||||
typedef struct RPCClient RPCClient;
|
||||
typedef struct Link Link;
|
||||
typedef struct Ban Ban;
|
||||
typedef struct Mode Mode;
|
||||
@ -179,7 +182,9 @@ typedef OperPermission (*OperClassEntryEvalCallback)(OperClassACLEntryVar* varia
|
||||
#define KEYLEN 23
|
||||
#define LINKLEN 32
|
||||
#define BUFSIZE 512 /* WARNING: *DONT* CHANGE THIS!!!! */
|
||||
#define READBUFSIZE 8192 /* for the read buffer */
|
||||
#define MAXTAGSIZE 8192 /**< Maximum length of message tags (4K user + 4K server) */
|
||||
#define MAXLINELENGTH (MAXTAGSIZE+BUFSIZE) /**< Maximum length of a line on IRC: 4k client tags + 4k server tags + 512 bytes (IRCv3) */
|
||||
#define READBUFSIZE MAXLINELENGTH /* for the read buffer */
|
||||
#define MAXRECIPIENTS 20
|
||||
#define MAXSILELENGTH NICKLEN+USERLEN+HOSTLEN+10
|
||||
#define IDLEN 12
|
||||
@ -323,9 +328,10 @@ 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_RPC = -10, /**< RPC Client (either local or remote) */
|
||||
CLIENT_STATUS_CONTROL = -9, /**< Client is on the control channel */
|
||||
CLIENT_STATUS_LOG = -8, /**< Client is a log file */
|
||||
CLIENT_STATUS_TLS_STARTTLS_HANDSHAKE = -7, /**< Client is doing a STARTTLS handshake */
|
||||
CLIENT_STATUS_CONNECTING = -6, /**< Client is an outgoing connect */
|
||||
CLIENT_STATUS_TLS_CONNECT_HANDSHAKE = -5, /**< Client is doing an TLS handshake - outgoing connection */
|
||||
CLIENT_STATUS_TLS_ACCEPT_HANDSHAKE = -4, /**< Client is doing an TLS handshake - incoming connection */
|
||||
@ -346,7 +352,8 @@ 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 IsControl(x) ((x)->status == CLIENT_STATUS_CONTROL) /**< Is on the control channel (not an IRC client) */
|
||||
#define IsRPC(x) ((x)->status == CLIENT_STATUS_RPC) /**< Is doing RPC (not an IRC client) */
|
||||
#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 */
|
||||
@ -364,6 +371,7 @@ typedef enum ClientStatus {
|
||||
#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 SetRPC(x) ((x)->status = CLIENT_STATUS_RPC)
|
||||
#define SetUser(x) ((x)->status = CLIENT_STATUS_USER)
|
||||
|
||||
/** @} */
|
||||
@ -403,6 +411,7 @@ typedef enum ClientStatus {
|
||||
#define CLIENT_FLAG_PINGWARN 0x10000000 /**< Server ping warning (remote server slow with responding to PINGs) */
|
||||
#define CLIENT_FLAG_NOHANDSHAKEDELAY 0x20000000 /**< No handshake delay */
|
||||
#define CLIENT_FLAG_SERVER_DISCONNECT_LOGGED 0x40000000 /**< Server disconnect message is (already) logged */
|
||||
#define CLIENT_FLAG_ASYNC_RPC 0x80000000 /**< Asynchronous remote RPC request - special case for rehash etc. */
|
||||
|
||||
/** @} */
|
||||
|
||||
@ -493,8 +502,10 @@ typedef enum ClientStatus {
|
||||
#define IsTLS(x) ((x)->flags & CLIENT_FLAG_TLS)
|
||||
#define IsSecure(x) ((x)->flags & CLIENT_FLAG_TLS)
|
||||
#define IsULine(x) ((x)->flags & CLIENT_FLAG_ULINE)
|
||||
#define IsSvsCmdOk(x) (((x)->flags & CLIENT_FLAG_ULINE) || ((iConf.limit_svscmds == LIMIT_SVSCMDS_SERVERS) && (IsServer((x)) || IsMe((x)))))
|
||||
#define IsVirus(x) ((x)->flags & CLIENT_FLAG_VIRUS)
|
||||
#define IsIdentLookupSent(x) ((x)->flags & CLIENT_FLAG_IDENTLOOKUPSENT)
|
||||
#define IsAsyncRPC(x) ((x)->flags & CLIENT_FLAG_ASYNC_RPC)
|
||||
#define SetIdentLookup(x) do { (x)->flags |= CLIENT_FLAG_IDENTLOOKUP; } while(0)
|
||||
#define SetClosing(x) do { (x)->flags |= CLIENT_FLAG_CLOSING; } while(0)
|
||||
#define SetDCCBlock(x) do { (x)->flags |= CLIENT_FLAG_DCCBLOCK; } while(0)
|
||||
@ -526,6 +537,7 @@ typedef enum ClientStatus {
|
||||
#define SetULine(x) do { (x)->flags |= CLIENT_FLAG_ULINE; } while(0)
|
||||
#define SetVirus(x) do { (x)->flags |= CLIENT_FLAG_VIRUS; } while(0)
|
||||
#define SetIdentLookupSent(x) do { (x)->flags |= CLIENT_FLAG_IDENTLOOKUPSENT; } while(0)
|
||||
#define SetAsyncRPC(x) do { (x)->flags |= CLIENT_FLAG_ASYNC_RPC; } while(0)
|
||||
#define ClearIdentLookup(x) do { (x)->flags &= ~CLIENT_FLAG_IDENTLOOKUP; } while(0)
|
||||
#define ClearClosing(x) do { (x)->flags &= ~CLIENT_FLAG_CLOSING; } while(0)
|
||||
#define ClearDCCBlock(x) do { (x)->flags &= ~CLIENT_FLAG_DCCBLOCK; } while(0)
|
||||
@ -556,12 +568,13 @@ 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 ClearAsyncRPC(x) do { (x)->flags &= ~CLIENT_FLAG_ASYNC_RPC; } 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)
|
||||
#define SetUnixSocket(x) do { (x)->local->socket_type = SOCKET_TYPE_UNIX; } while(0)
|
||||
/** @} */
|
||||
|
||||
|
||||
/* Others that access client structs: */
|
||||
#define IsNotSpoof(x) ((x)->local->nospoof == 0)
|
||||
@ -788,6 +801,20 @@ struct MOTDLine {
|
||||
struct MOTDLine *next;
|
||||
};
|
||||
|
||||
/** Current status of configuration in memory (what stage are we in..) */
|
||||
typedef enum ConfigStatus {
|
||||
CONFIG_STATUS_NONE = 0, /**< Config files have not been parsed yet */
|
||||
CONFIG_STATUS_TEST = 1, /**< Currently running MOD_TEST() */
|
||||
CONFIG_STATUS_POSTTEST = 2, /**< Currently running post_config_test hooks */
|
||||
CONFIG_STATUS_PRE_INIT = 3, /**< In-between */
|
||||
CONFIG_STATUS_INIT = 4, /**< Currently running MOD_INIT() */
|
||||
CONFIG_STATUS_RUN_CONFIG = 5, /**< Currently running CONFIG_RUN hooks */
|
||||
CONFIG_STATUS_LOAD = 6, /**< Currently running MOD_LOAD() */
|
||||
CONFIG_STATUS_POSTLOAD = 7, /**< Doing post-load stuff like activating listeners */
|
||||
CONFIG_STATUS_COMPLETE = 8, /**< Load or rehash complete */
|
||||
CONFIG_STATUS_ROLLBACK = 99, /**< Configuration failed, rolling back changes */
|
||||
} ConfigStatus;
|
||||
|
||||
struct LoopStruct {
|
||||
unsigned do_garbage_collect : 1;
|
||||
unsigned config_test : 1;
|
||||
@ -801,6 +828,7 @@ struct LoopStruct {
|
||||
unsigned rehash_download_busy : 1; /* don't return "all downloads complete", needed for race condition */
|
||||
unsigned tainted : 1;
|
||||
int rehashing;
|
||||
ConfigStatus config_status;
|
||||
Client *rehash_save_client;
|
||||
void (*boot_function)();
|
||||
};
|
||||
@ -826,10 +854,15 @@ typedef struct Whowas {
|
||||
char *username;
|
||||
char *hostname;
|
||||
char *virthost;
|
||||
char *ip;
|
||||
char *servername;
|
||||
char *realname;
|
||||
char *account;
|
||||
long umodes;
|
||||
time_t logoff;
|
||||
time_t logon;
|
||||
time_t logoff;
|
||||
time_t connected_since;
|
||||
WhoWasEvent event;
|
||||
struct Client *online; /* Pointer to new nickname for chasing or NULL */
|
||||
struct Whowas *next; /* for hash table... */
|
||||
struct Whowas *prev; /* for hash table... */
|
||||
@ -873,8 +906,9 @@ struct SWhois {
|
||||
|
||||
/** Command function - used by all command handlers.
|
||||
* This is used in the code like <pre>CMD_FUNC(cmd_yourcmd)</pre> as a function definition.
|
||||
* @param cptr The client direction pointer.
|
||||
* @param client The source client pointer (you usually need this one).
|
||||
* It allows UnrealIRCd devs to change the parameters in the function without
|
||||
* (necessarily) breaking your code.
|
||||
* @param client The client
|
||||
* @param recv_mtags Received message tags for this command.
|
||||
* @param parc Parameter count *plus* 1.
|
||||
* @param parv Parameter values.
|
||||
@ -885,6 +919,15 @@ struct SWhois {
|
||||
* E.g. parv[3] in the above example is out of bounds.
|
||||
*/
|
||||
#define CMD_FUNC(x) void (x) (Client *client, MessageTag *recv_mtags, int parc, const char *parv[])
|
||||
|
||||
/** Call a command function - can be useful if you are calling another command function in your own module.
|
||||
* For example in cmd_nick() we call cmd_nick_local() for local functions,
|
||||
* and then we can just use CALL_CMD_FUNC(cmd_nick_local); and don't have
|
||||
* to bother with passing the right command arguments. Which is nice because
|
||||
* command arguments may change in future UnrealIRCd versions.
|
||||
*/
|
||||
#define CALL_CMD_FUNC(x) (x)(client, recv_mtags, parc, parv)
|
||||
|
||||
/** @} */
|
||||
|
||||
/** Command override function - used by all command override handlers.
|
||||
@ -1226,13 +1269,15 @@ extern ModDataInfo *ModDataAdd(Module *module, ModDataInfo req);
|
||||
extern void ModDataDel(ModDataInfo *md);
|
||||
extern void unload_all_unused_moddata(void);
|
||||
|
||||
#define LISTENER_NORMAL 0x000001
|
||||
#define LISTENER_CLIENTSONLY 0x000002
|
||||
#define LISTENER_SERVERSONLY 0x000004
|
||||
#define LISTENER_TLS 0x000010
|
||||
#define LISTENER_BOUND 0x000020
|
||||
#define LISTENER_DEFER_ACCEPT 0x000040
|
||||
#define LISTENER_CONTROL 0x000080 /**< Control channel */
|
||||
#define LISTENER_NORMAL 0x000001
|
||||
#define LISTENER_CLIENTSONLY 0x000002
|
||||
#define LISTENER_SERVERSONLY 0x000004
|
||||
#define LISTENER_TLS 0x000010
|
||||
#define LISTENER_BOUND 0x000020
|
||||
#define LISTENER_DEFER_ACCEPT 0x000040
|
||||
#define LISTENER_CONTROL 0x000080 /**< Control channel */
|
||||
#define LISTENER_NO_CHECK_CONNECT_FLOOD 0x000100 /**< Don't check for connect-flood and max-unknown-connections-per-ip (eg for RPC) */
|
||||
#define LISTENER_NO_CHECK_ZLINED 0x000200 /**< Don't check for zlines */
|
||||
|
||||
#define IsServersOnlyListener(x) ((x) && ((x)->options & LISTENER_SERVERSONLY))
|
||||
|
||||
@ -1292,11 +1337,12 @@ struct Client {
|
||||
LocalClient *local; /**< Additional information regarding locally connected clients */
|
||||
User *user; /**< Additional information, if this client is a user */
|
||||
Server *server; /**< Additional information, if this is a server */
|
||||
RPCClient *rpc; /**< RPC Client, or NULL */
|
||||
ClientStatus status; /**< Client status, one of CLIENT_STATUS_* */
|
||||
struct list_head client_hash; /**< For name hash table (clientTable) */
|
||||
char name[HOSTLEN + 1]; /**< Unique name of the client: nickname for users, hostname for servers */
|
||||
time_t lastnick; /**< Timestamp on nick */
|
||||
long flags; /**< Client flags (one or more of CLIENT_FLAG_*) */
|
||||
uint64_t flags; /**< Client flags (one or more of CLIENT_FLAG_*) */
|
||||
long umodes; /**< Client usermodes (if user) */
|
||||
Client *direction; /**< Direction from which this client originated.
|
||||
This always points to a directly connected server or &me.
|
||||
@ -1349,6 +1395,7 @@ struct LocalClient {
|
||||
char sockhost[HOSTLEN + 1]; /**< Hostname from the socket */
|
||||
u_short port; /**< Remote TCP port of client */
|
||||
FloodCounter flood[MAXFLOODOPTIONS];
|
||||
RPCClient *rpc; /**< RPC Client, or NULL */
|
||||
};
|
||||
|
||||
/** User information (persons, not servers), you use client->user to access these (see also @link Client @endlink).
|
||||
@ -1393,6 +1440,15 @@ struct Server {
|
||||
|
||||
/** @} */
|
||||
|
||||
typedef struct RPCClient RPCClient;
|
||||
/** RPC Client information */
|
||||
struct RPCClient {
|
||||
char *rpc_user; /**< Name of the rpc-user block after authentication, NULL during pre-auth */
|
||||
char *issuer; /**< Optional name of the issuer, set by rpc.set_issuer(), eg logged in user on admin panel, can be NULL */
|
||||
json_t *rehash_request; /**< If a REHASH (request) is currently running, otherwise NULL */
|
||||
LogSource *log_sources; /**< Subscribed to which log sources */
|
||||
};
|
||||
|
||||
struct MessageTag {
|
||||
MessageTag *prev, *next;
|
||||
char *name;
|
||||
@ -1409,7 +1465,8 @@ typedef enum PreprocessorItem {
|
||||
|
||||
typedef enum PreprocessorPhase {
|
||||
PREPROCESSOR_PHASE_INITIAL = 1,
|
||||
PREPROCESSOR_PHASE_MODULE = 2
|
||||
PREPROCESSOR_PHASE_SECONDARY = 2,
|
||||
PREPROCESSOR_PHASE_MODULE = 3
|
||||
} PreprocessorPhase;
|
||||
|
||||
typedef enum AuthenticationType {
|
||||
@ -1437,6 +1494,30 @@ struct AuthConfig {
|
||||
#define crypt DES_crypt
|
||||
#endif
|
||||
|
||||
/* CRULE stuff */
|
||||
|
||||
#define CRULE_ALL 0
|
||||
#define CRULE_AUTO 1
|
||||
|
||||
/* some constants and shared data types */
|
||||
#define CR_MAXARGLEN 80 /**< Maximum arg length (must be > HOSTLEN) */
|
||||
#define CR_MAXARGS 3 /**< Maximum number of args for a rule */
|
||||
|
||||
/** Evaluation function for a connection rule. */
|
||||
typedef int (*crule_funcptr) (int, void **);
|
||||
|
||||
/** CRULE - Node in a connection rule tree. */
|
||||
struct CRuleNode {
|
||||
crule_funcptr funcptr; /**< Evaluation function for this node. */
|
||||
int numargs; /**< Number of arguments. */
|
||||
void *arg[CR_MAXARGS]; /**< Array of arguments. For operators, each arg
|
||||
is a tree element; for functions, each arg is
|
||||
a string. */
|
||||
};
|
||||
typedef struct CRuleNode CRuleNode;
|
||||
typedef struct CRuleNode* CRuleNodePtr;
|
||||
|
||||
|
||||
/*
|
||||
* conf2 stuff -stskeeps
|
||||
*/
|
||||
@ -1514,9 +1595,6 @@ struct ConfigFlag_tld
|
||||
#define CONF_BAN_TYPE_AKILL 1
|
||||
#define CONF_BAN_TYPE_TEMPORARY 2
|
||||
|
||||
#define CRULE_ALL 0
|
||||
#define CRULE_AUTO 1
|
||||
|
||||
struct ConfigItem {
|
||||
ConfigItem *prev, *next;
|
||||
ConfigFlag flag;
|
||||
@ -1693,19 +1771,93 @@ struct ConfigItem_tld {
|
||||
u_short options;
|
||||
};
|
||||
|
||||
#define WEB_OPT_ENABLE 0x1
|
||||
|
||||
typedef enum HttpMethod {
|
||||
HTTP_METHOD_NONE = 0, /**< No valid HTTP request (yet) */
|
||||
HTTP_METHOD_HEAD = 1, /**< HEAD request */
|
||||
HTTP_METHOD_GET = 2, /**< GET request */
|
||||
HTTP_METHOD_PUT = 3, /**< PUT request */
|
||||
HTTP_METHOD_POST = 4, /**< POST request */
|
||||
} HttpMethod;
|
||||
|
||||
typedef enum TransferEncoding {
|
||||
TRANSFER_ENCODING_NONE=0,
|
||||
TRANSFER_ENCODING_CHUNKED=1
|
||||
} TransferEncoding;
|
||||
|
||||
typedef struct WebRequest WebRequest;
|
||||
struct WebRequest {
|
||||
HttpMethod method; /**< GET/PUT/POST */
|
||||
char *uri; /**< Requested resource, eg "/api" */
|
||||
NameValuePrioList *headers; /**< HTTP request headers */
|
||||
int num_headers; /**< Number of HTTP request headers (also used for sorting the list) */
|
||||
char request_header_parsed; /**< Done parsing? */
|
||||
char *lefttoparse; /**< Leftover buffer to parse */
|
||||
int lefttoparselen; /**< Length of lefttoparse buffer */
|
||||
int pending_close; /**< Set to 1 when connection should be closed as soon as all data is sent (sendq==0) */
|
||||
char *request_buffer; /**< Buffer for POST data */
|
||||
int request_buffer_size; /**< Size of buffer for POST data */
|
||||
int request_body_complete; /**< POST data has all been read */
|
||||
long long content_length; /**< "Content-Length" as sent by the client */
|
||||
long long chunk_remaining;
|
||||
TransferEncoding transfer_encoding;
|
||||
long long config_max_request_buffer_size; /**< CONFIG: Maximum request length allowed */
|
||||
};
|
||||
|
||||
typedef struct WebServer WebServer;
|
||||
struct WebServer {
|
||||
int (*handle_request)(Client *client, WebRequest *web);
|
||||
int (*handle_body)(Client *client, WebRequest *web, const char *buf, int length);
|
||||
};
|
||||
|
||||
typedef enum WebSocketType {
|
||||
WEBSOCKET_TYPE_BINARY = 1,
|
||||
WEBSOCKET_TYPE_TEXT = 2
|
||||
} WebSocketType;
|
||||
|
||||
typedef struct WebSocketUser WebSocketUser;
|
||||
struct WebSocketUser {
|
||||
char get; /**< GET initiated */
|
||||
char handshake_completed; /**< Handshake completed, use websocket frames */
|
||||
char *handshake_key; /**< Handshake key (used during handshake) */
|
||||
char *lefttoparse; /**< Leftover buffer to parse */
|
||||
int lefttoparselen; /**< Length of lefttoparse buffer */
|
||||
WebSocketType type; /**< WEBSOCKET_TYPE_BINARY or WEBSOCKET_TYPE_TEXT */
|
||||
char *sec_websocket_protocol; /**< Only valid during parsing of the request, after that it is NULL again */
|
||||
char *forwarded; /**< Unparsed `Forwarded:` header, RFC 7239 */
|
||||
int secure; /**< If there is a Forwarded header, this indicates if the remote connection is secure */
|
||||
};
|
||||
|
||||
#define WEBSOCKET_MAGIC_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" /* see RFC6455 */
|
||||
|
||||
/* Websocket operations: */
|
||||
#define WSOP_CONTINUATION 0x00
|
||||
#define WSOP_TEXT 0x01
|
||||
#define WSOP_BINARY 0x02
|
||||
#define WSOP_CLOSE 0x08
|
||||
#define WSOP_PING 0x09
|
||||
#define WSOP_PONG 0x0a
|
||||
|
||||
struct ConfigItem_listen {
|
||||
ConfigItem_listen *prev, *next;
|
||||
ConfigFlag flag;
|
||||
SocketType socket_type;
|
||||
char *file;
|
||||
char *ip;
|
||||
int port;
|
||||
int options, clients;
|
||||
int fd;
|
||||
SSL_CTX *ssl_ctx;
|
||||
TLSOptions *tls_options;
|
||||
int websocket_options; /* should be in module, but lazy */
|
||||
char *websocket_forward;
|
||||
SocketType socket_type; /**< Socket type, eg. SOCKET_TYPE_IPV4 or SOCKET_TYPE_UNIX */
|
||||
char *file; /**< If the listener is a file, the full pathname */
|
||||
char *ip; /**< IP bind address (if IP listener) */
|
||||
int port; /**< Port to listen on (if IP listener) */
|
||||
int mode; /**< Mode permissions (if file aka unix socket listener) */
|
||||
int options; /**< e.g. LISTENER_BOUND if active */
|
||||
int clients; /**< Clients connected to this socket / listener */
|
||||
int fd; /**< File descriptor (if open), or -1 (if not open yet) */
|
||||
char *spoof_ip; /**< listen::spoof-ip (only for listen::file, if you want to override 127.0.0.1) */
|
||||
SSL_CTX *ssl_ctx; /**< SSL/TLS context */
|
||||
TLSOptions *tls_options; /**< SSL/TLS options */
|
||||
WebServer *webserver; /**< For the webserver module */
|
||||
void (*start_handshake)(Client *client); /**< Function to call on accept() */
|
||||
int websocket_options; /**< Websocket options (for the websocket module) */
|
||||
int rpc_options; /**< For the RPC module */
|
||||
char *websocket_forward; /**< For websocket module too */
|
||||
};
|
||||
|
||||
struct ConfigItem_sni {
|
||||
@ -1768,13 +1920,6 @@ struct ConfigItem_deny_dcc {
|
||||
char *filename, *reason;
|
||||
};
|
||||
|
||||
struct ConfigItem_deny_link {
|
||||
ConfigItem_deny_link *prev, *next;
|
||||
ConfigFlag_except flag;
|
||||
ConfigItem_mask *mask;
|
||||
char *rule, *prettyrule;
|
||||
};
|
||||
|
||||
struct ConfigItem_deny_version {
|
||||
ConfigItem_deny_version *prev, *next;
|
||||
ConfigFlag flag;
|
||||
@ -1873,6 +2018,7 @@ struct SecurityGroup {
|
||||
int reputation_score;
|
||||
long connect_time;
|
||||
int webirc;
|
||||
int websocket;
|
||||
int tls;
|
||||
NameList *ip;
|
||||
ConfigItem_mask *mask;
|
||||
@ -1883,6 +2029,7 @@ struct SecurityGroup {
|
||||
int exclude_reputation_score;
|
||||
long exclude_connect_time;
|
||||
int exclude_webirc;
|
||||
int exclude_websocket;
|
||||
int exclude_tls;
|
||||
NameList *exclude_ip;
|
||||
ConfigItem_mask *exclude_mask;
|
||||
@ -2270,6 +2417,62 @@ typedef enum WhoisConfigDetails {
|
||||
#define UNRL_STRIP_LOW_ASCII 0x1 /**< Strip all ASCII < 32 (control codes) */
|
||||
#define UNRL_STRIP_KEEP_LF 0x2 /**< Do not strip LF (line feed, \n) */
|
||||
|
||||
/** JSON-RPC API Errors, according to jsonrpc.org spec */
|
||||
typedef enum JsonRpcError {
|
||||
// Official JSON-RPC error codes:
|
||||
JSON_RPC_ERROR_PARSE_ERROR = -32700, /**< JSON parse error (fatal) */
|
||||
JSON_RPC_ERROR_INVALID_REQUEST = -32600, /**< Invalid JSON-RPC Request */
|
||||
JSON_RPC_ERROR_METHOD_NOT_FOUND = -32601, /**< Method not found */
|
||||
JSON_RPC_ERROR_INVALID_PARAMS = -32602, /**< Method parameters invalid */
|
||||
JSON_RPC_ERROR_INTERNAL_ERROR = -32603, /**< Internal server error */
|
||||
// UnrealIRCd JSON-RPC server specific error codes:
|
||||
JSON_RPC_ERROR_API_CALL_DENIED = -32000, /**< The api user does not have enough permissions to do this call */
|
||||
JSON_RPC_ERROR_SERVER_GONE = -32001, /**< The request was forwarded to a remote server, but this server went gone while processing the request */
|
||||
JSON_RPC_ERROR_TIMEOUT = -32002, /**< The request was forwarded to a remote server, but the request/response timed out (15 seconds) */
|
||||
JSON_RPC_ERROR_REMOTE_SERVER_NO_RPC = -32003, /**< The request was going to be forwarded to a remote server, but the remote server does not support JSON-RPC */
|
||||
// UnrealIRCd specific application error codes:
|
||||
JSON_RPC_ERROR_NOT_FOUND = -1000, /**< Target not found (no such nick / channel / ..) */
|
||||
JSON_RPC_ERROR_ALREADY_EXISTS = -1001, /**< Resource already exists by that name (eg on nickchange request, a gline, etc) */
|
||||
JSON_RPC_ERROR_INVALID_NAME = -1002, /**< Name is not permitted (eg: nick, channel, ..) */
|
||||
JSON_RPC_ERROR_USERNOTINCHANNEL = -1003, /**< The user is not in the channel */
|
||||
JSON_RPC_ERROR_TOO_MANY_ENTRIES = -1004, /**< Too many entries (eg: banlist, ..) */
|
||||
JSON_RPC_ERROR_DENIED = -1005, /**< Permission denied for user (unrelated to api user permissions) */
|
||||
} JsonRpcError;
|
||||
|
||||
/** Require a parameter in an RPC command */
|
||||
#define REQUIRE_PARAM_STRING(name, varname) do { \
|
||||
varname = json_object_get_string(params, name); \
|
||||
if (!varname) \
|
||||
{ \
|
||||
rpc_error_fmt(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: '%s'", name); \
|
||||
return; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define REQUIRE_PARAM_INTEGER(name, varname) do { \
|
||||
json_t *t = json_object_get(params, name); \
|
||||
if (!t || !json_is_integer(t)) \
|
||||
{ \
|
||||
rpc_error_fmt(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: '%s'", name); \
|
||||
return; \
|
||||
} \
|
||||
varname = json_integer_value(t); \
|
||||
} while(0)
|
||||
|
||||
#define REQUIRE_PARAM_BOOLEAN(name, varname) do { \
|
||||
json_t *vvv = json_object_get(params, name); \
|
||||
if (!v || !json_is_boolean(v)) \
|
||||
{ \
|
||||
rpc_error_fmt(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: '%s'", name); \
|
||||
return; \
|
||||
} \
|
||||
varname = json_is_true(v) ? 1 : 0; \
|
||||
} while(0)
|
||||
|
||||
#define OPTIONAL_PARAM_STRING(name, varname) varname = json_object_get_string(params, name)
|
||||
#define OPTIONAL_PARAM_INTEGER(name, varname, def) varname = json_object_get_integer(params, name, def)
|
||||
#define OPTIONAL_PARAM_BOOLEAN(name, varname, def) varname = json_object_get_boolean(params, name, def)
|
||||
|
||||
#endif /* __struct_include__ */
|
||||
|
||||
#include "dynconf.h"
|
||||
|
@ -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 202204
|
||||
#define UNREAL_VERSION_TIME 202313
|
||||
|
||||
#define UNREAL_VERSION ((UNREAL_VERSION_GENERATION << 24) + (UNREAL_VERSION_MAJOR << 16) + (UNREAL_VERSION_MINOR << 8))
|
||||
#define UnrealProtocol 6000
|
||||
|
@ -35,6 +35,15 @@
|
||||
#ifndef __whowas_include__
|
||||
#define __whowas_include__
|
||||
|
||||
/* NOTE: Don't reorder values of these, as they are used in whowasdb */
|
||||
typedef enum WhoWasEvent {
|
||||
WHOWAS_EVENT_QUIT=0,
|
||||
WHOWAS_EVENT_NICK_CHANGE=1,
|
||||
WHOWAS_EVENT_SERVER_TERMINATING=2
|
||||
} WhoWasEvent;
|
||||
#define WHOWAS_LOWEST_EVENT 0
|
||||
#define WHOWAS_HIGHEST_EVENT 2
|
||||
|
||||
/*
|
||||
** add_history
|
||||
** Add the currently defined name of the client to history.
|
||||
@ -42,7 +51,7 @@
|
||||
** Client must be a fully registered user (specifically,
|
||||
** the user structure must have been allocated).
|
||||
*/
|
||||
void add_history(Client *, int);
|
||||
void add_history(Client *, int, WhoWasEvent);
|
||||
|
||||
/*
|
||||
** off_history
|
||||
|
@ -39,6 +39,7 @@
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#define HAVE_EXPLICIT_BZERO
|
||||
#define HAVE_STRNLEN
|
||||
#define explicit_bzero(a,b) SecureZeroMemory(a,b)
|
||||
|
||||
/* mode_t: Needed in s_conf.c for the third argument of open(3p).
|
||||
@ -59,13 +60,13 @@
|
||||
#define UNREAL_VERSION_GENERATION 6
|
||||
|
||||
/* Major version number (e.g.: 2 for Unreal3.2*) */
|
||||
#define UNREAL_VERSION_MAJOR 0
|
||||
#define UNREAL_VERSION_MAJOR 1
|
||||
|
||||
/* Minor version number (e.g.: 1 for Unreal3.2.1) */
|
||||
#define UNREAL_VERSION_MINOR 4
|
||||
#define UNREAL_VERSION_MINOR 0
|
||||
|
||||
/* Version suffix such as a beta marker or release candidate marker. (e.g.:
|
||||
-rcX for unrealircd-3.2.9-rcX) */
|
||||
#define UNREAL_VERSION_SUFFIX ".2"
|
||||
#define UNREAL_VERSION_SUFFIX ""
|
||||
|
||||
#endif
|
||||
|
@ -30,9 +30,9 @@ OBJS=ircd_vars.o dns.o auth.o channel.o crule.o dbuf.o \
|
||||
version.o whowas.o random.o api-usermode.o api-channelmode.o \
|
||||
api-moddata.o api-extban.o api-isupport.o api-command.o \
|
||||
api-clicap.o api-messagetag.o api-history-backend.o api-efunctions.o \
|
||||
api-event.o \
|
||||
api-event.o api-rpc.o \
|
||||
crypt_blowfish.o unrealdb.o crashreport.o modulemanager.o \
|
||||
utf8.o log.o \
|
||||
utf8.o json.o log.o \
|
||||
openssl_hostname_validation.o $(URL)
|
||||
|
||||
SRC=$(OBJS:%.o=%.c)
|
||||
|
@ -423,6 +423,7 @@ Cmode *CmodeAdd(Module *module, CmodeInfo req, Cmode_t *mode)
|
||||
cm->sjoin_check = req.sjoin_check;
|
||||
cm->local = req.local;
|
||||
cm->unset_with_param = req.unset_with_param;
|
||||
cm->flood_type_action = req.flood_type_action;
|
||||
cm->owner = module;
|
||||
cm->unloaded = 0;
|
||||
|
||||
@ -534,7 +535,7 @@ static void unload_extcmode_commit(Cmode *cmode)
|
||||
}
|
||||
free_message_tags(mtags);
|
||||
|
||||
cmode->free_param(GETPARASTRUCT(channel, cmode->letter));
|
||||
cmode->free_param(GETPARASTRUCT(channel, cmode->letter), 0);
|
||||
channel->mode.mode &= ~cmode->mode;
|
||||
}
|
||||
}
|
||||
@ -627,8 +628,9 @@ void cm_putparameter(Channel *channel, char mode, const char *str)
|
||||
*/
|
||||
void cm_freeparameter(Channel *channel, char mode)
|
||||
{
|
||||
GETPARAMHANDLERBYLETTER(mode)->free_param(GETPARASTRUCT(channel, mode));
|
||||
GETPARASTRUCT(channel, mode) = NULL;
|
||||
int n = GETPARAMHANDLERBYLETTER(mode)->free_param(GETPARASTRUCT(channel, mode), 1);
|
||||
if (n == 0)
|
||||
GETPARASTRUCT(channel, mode) = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -713,7 +715,7 @@ void extcmode_free_paramlist(void **ar)
|
||||
handler = GETPARAMHANDLERBYSLOT(i);
|
||||
if (!handler)
|
||||
continue; /* nothing here... */
|
||||
handler->free_param(ar[handler->param_slot]);
|
||||
handler->free_param(ar[handler->param_slot], 0);
|
||||
ar[handler->param_slot] = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,20 @@
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
#define ADVERTISEONLYCAPS 16
|
||||
/* Advertise only caps are not counted anywhere, this only provides space in rehash temporary storage arrays.
|
||||
* If exceeded, the caps just won't be stored and will be re-added safely. --k4be
|
||||
*/
|
||||
|
||||
#define MAXCLICAPS ((int)(sizeof(long)*8 - 1 + ADVERTISEONLYCAPS)) /* how many cap bits will fit in `long`? */
|
||||
static char *old_caps[MAXCLICAPS]; /**< List of old CAP names - used for /rehash */
|
||||
int old_caps_proto[MAXCLICAPS]; /**< List of old CAP protocol values - used for /rehash */
|
||||
|
||||
MODVAR ClientCapability *clicaps = NULL; /* List of client capabilities */
|
||||
|
||||
void clicap_init(void)
|
||||
{
|
||||
memset(&old_caps, 0, sizeof(old_caps));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,7 +221,7 @@ void unload_clicap_commit(ClientCapability *clicap)
|
||||
log_data_string("token", clicap->name));
|
||||
|
||||
/* NOTE: Stripping the CAP from local clients is done
|
||||
* in clicap_post_rehash(), so not here.
|
||||
* in clicap_check_for_changes(), so not here.
|
||||
*/
|
||||
|
||||
/* A message tag handler may depend on us, remove it */
|
||||
@ -266,24 +276,19 @@ void unload_all_unused_caps(void)
|
||||
}
|
||||
}
|
||||
|
||||
#define ADVERTISEONLYCAPS 16
|
||||
/* Advertise only caps are not counted anywhere, this only provides space in rehash temporary storage arrays.
|
||||
* If exceeded, the caps just won't be stored and will be re-added safely. --k4be
|
||||
*/
|
||||
|
||||
#define MAXCLICAPS ((int)(sizeof(long)*8 - 1 + ADVERTISEONLYCAPS)) /* how many cap bits will fit in `long`? */
|
||||
static char *old_caps[MAXCLICAPS]; /**< List of old CAP names - used for /rehash */
|
||||
int old_caps_proto[MAXCLICAPS]; /**< List of old CAP protocol values - used for /rehash */
|
||||
|
||||
/** Called before REHASH. This saves the list of cap names and protocol values */
|
||||
void clicap_pre_rehash(void)
|
||||
{
|
||||
ClientCapability *clicap;
|
||||
int i = 0;
|
||||
|
||||
memset(&old_caps, 0, sizeof(old_caps));
|
||||
for (i=0; i < MAXCLICAPS; i++)
|
||||
{
|
||||
safe_free(old_caps[i]);
|
||||
old_caps_proto[i] = 0;
|
||||
}
|
||||
|
||||
for (clicap = clicaps; clicap; clicap = clicap->next)
|
||||
for (i=0, clicap = clicaps; clicap; clicap = clicap->next)
|
||||
{
|
||||
if (i == MAXCLICAPS)
|
||||
{
|
||||
@ -321,7 +326,7 @@ void clear_cap_for_users(long cap)
|
||||
* 2. Sending any CAP DEL
|
||||
* 3. Sending any CAP NEW
|
||||
*/
|
||||
void clicap_post_rehash(void)
|
||||
void clicap_check_for_changes(void)
|
||||
{
|
||||
ClientCapability *clicap;
|
||||
char *name;
|
||||
|
@ -40,12 +40,14 @@ int (*can_join)(Client *client, Channel *channel, const char *key, char **errmsg
|
||||
void (*do_mode)(Channel *channel, Client *client, MessageTag *mtags, int parc, const char *parv[], time_t sendts, int samode);
|
||||
MultiLineMode *(*set_mode)(Channel *channel, Client *client, int parc, const char *parv[], u_int *pcount,
|
||||
char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]);
|
||||
void (*set_channel_mode)(Channel *channel, char *modes, char *parameters);
|
||||
void (*set_channel_mode)(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters);
|
||||
void (*set_channel_topic)(Client *client, Channel *channel, MessageTag *recv_mtags, const char *topic, const char *set_by, time_t set_at);
|
||||
void (*cmd_umode)(Client *client, MessageTag *mtags, int parc, const char *parv[]);
|
||||
int (*register_user)(Client *client);
|
||||
int (*tkl_hash)(unsigned int c);
|
||||
char (*tkl_typetochar)(int type);
|
||||
int (*tkl_chartotype)(char c);
|
||||
char (*tkl_configtypetochar)(const char *name);
|
||||
const char *(*tkl_type_string)(TKL *tk);
|
||||
const char *(*tkl_type_config_string)(TKL *tk);
|
||||
char *(*tkl_uhost)(TKL *tkl, char *buf, size_t buflen, int options);
|
||||
@ -84,7 +86,6 @@ void (*broadcast_md_client)(ModDataInfo *mdi, Client *client, ModData *md);
|
||||
void (*broadcast_md_channel)(ModDataInfo *mdi, Channel *channel, ModData *md);
|
||||
void (*broadcast_md_member)(ModDataInfo *mdi, Channel *channel, Member *m, ModData *md);
|
||||
void (*broadcast_md_membership)(ModDataInfo *mdi, Client *client, Membership *m, ModData *md);
|
||||
int (*check_banned)(Client *client, int exitflags);
|
||||
int (*check_deny_version)(Client *client, const char *software, int protocol, const char *flags);
|
||||
void (*broadcast_md_client_cmd)(Client *except, Client *sender, Client *acptr, const char *varname, const char *value);
|
||||
void (*broadcast_md_channel_cmd)(Client *except, Client *sender, Channel *channel, const char *varname, const char *value);
|
||||
@ -105,6 +106,7 @@ int (*do_remote_nick_name)(char *nick);
|
||||
const char *(*charsys_get_current_languages)(void);
|
||||
void (*broadcast_sinfo)(Client *client, Client *to, Client *except);
|
||||
void (*connect_server)(ConfigItem_link *aconf, Client *by, struct hostent *hp);
|
||||
int (*is_services_but_not_ulined)(Client *client);
|
||||
void (*parse_message_tags)(Client *client, char **str, MessageTag **mtag_list);
|
||||
const char *(*mtags_to_string)(MessageTag *m, Client *client);
|
||||
int (*can_send_to_channel)(Client *client, Channel *channel, const char **msgtext, const char **errmsg, int notice);
|
||||
@ -120,6 +122,9 @@ TKL *(*find_tkl_banexception)(int type, const char *usermask, const char *hostma
|
||||
TKL *(*find_tkl_nameban)(int type, const char *name, int hold);
|
||||
TKL *(*find_tkl_spamfilter)(int type, const char *match_string, unsigned short action, unsigned short target);
|
||||
int (*find_tkl_exception)(int ban_type, Client *client);
|
||||
int (*server_ban_parse_mask)(Client *client, int add, char type, const char *str, char **usermask_out, char **hostmask_out, int *soft, const char **error);
|
||||
int (*server_ban_exception_parse_mask)(Client *client, int add, const char *bantypes, const char *str, char **usermask_out, char **hostmask_out, int *soft, const char **error);
|
||||
void (*tkl_added)(Client *client, TKL *tkl);
|
||||
int (*is_silenced)(Client *client, Client *acptr);
|
||||
int (*del_silence)(Client *client, const char *mask);
|
||||
int (*add_silence)(Client *client, const char *mask, int senderr);
|
||||
@ -137,6 +142,22 @@ char *(*get_chmodes_for_user)(Client *client, const char *flags);
|
||||
WhoisConfigDetails (*whois_get_policy)(Client *client, Client *target, const char *name);
|
||||
int (*make_oper)(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost);
|
||||
int (*unreal_match_iplist)(Client *client, NameList *l);
|
||||
void (*webserver_send_response)(Client *client, int status, char *msg);
|
||||
void (*webserver_close_client)(Client *client);
|
||||
int (*webserver_handle_body)(Client *client, WebRequest *web, const char *readbuf, int length);
|
||||
void (*rpc_response)(Client *client, json_t *request, json_t *result);
|
||||
void (*rpc_error)(Client *client, json_t *request, JsonRpcError error_code, const char *error_message);
|
||||
void (*rpc_error_fmt)(Client *client, json_t *request, JsonRpcError error_code, const char *fmt, ...);
|
||||
void (*rpc_send_request_to_remote)(Client *source, Client *target, json_t *request);
|
||||
void (*rpc_send_response_to_remote)(Client *source, Client *target, json_t *response);
|
||||
int (*rrpc_supported_simple)(Client *target, char **problem_server);
|
||||
int (*rrpc_supported)(Client *target, const char *module, const char *minimum_version, char **problem_server);
|
||||
int (*websocket_handle_websocket)(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len));
|
||||
int (*websocket_create_packet)(int opcode, char **buf, int *len);
|
||||
int (*websocket_create_packet_ex)(int opcode, char **buf, int *len, char *sendbuf, size_t sendbufsize);
|
||||
int (*websocket_create_packet_simple)(int opcode, const char **buf, int *len);
|
||||
const char *(*check_deny_link)(ConfigItem_link *link, int auto_connect);
|
||||
void (*mtag_add_issued_by)(MessageTag **mtags, Client *client, MessageTag *recv_mtags);
|
||||
|
||||
Efunction *EfunctionAddMain(Module *module, EfunctionType eftype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*stringfunc)(), const char *(*conststringfunc)())
|
||||
{
|
||||
@ -320,6 +341,7 @@ void efunctions_init(void)
|
||||
efunc_init_function(EFUNC_DO_MODE, do_mode, NULL);
|
||||
efunc_init_function(EFUNC_SET_MODE, set_mode, NULL);
|
||||
efunc_init_function(EFUNC_SET_CHANNEL_MODE, set_channel_mode, NULL);
|
||||
efunc_init_function(EFUNC_SET_CHANNEL_TOPIC, set_channel_topic, NULL);
|
||||
efunc_init_function(EFUNC_CMD_UMODE, cmd_umode, NULL);
|
||||
efunc_init_function(EFUNC_REGISTER_USER, register_user, NULL);
|
||||
efunc_init_function(EFUNC_TKL_HASH, tkl_hash, NULL);
|
||||
@ -349,7 +371,6 @@ void efunctions_init(void)
|
||||
efunc_init_function(EFUNC_BROADCAST_MD_CHANNEL, broadcast_md_channel, NULL);
|
||||
efunc_init_function(EFUNC_BROADCAST_MD_MEMBER, broadcast_md_member, NULL);
|
||||
efunc_init_function(EFUNC_BROADCAST_MD_MEMBERSHIP, broadcast_md_membership, NULL);
|
||||
efunc_init_function(EFUNC_CHECK_BANNED, check_banned, NULL);
|
||||
efunc_init_function(EFUNC_INTRODUCE_USER, introduce_user, NULL);
|
||||
efunc_init_function(EFUNC_CHECK_DENY_VERSION, check_deny_version, NULL);
|
||||
efunc_init_function(EFUNC_BROADCAST_MD_CLIENT_CMD, broadcast_md_client_cmd, NULL);
|
||||
@ -371,9 +392,11 @@ void efunctions_init(void)
|
||||
efunc_init_function(EFUNC_CHARSYS_GET_CURRENT_LANGUAGES, charsys_get_current_languages, NULL);
|
||||
efunc_init_function(EFUNC_BROADCAST_SINFO, broadcast_sinfo, NULL);
|
||||
efunc_init_function(EFUNC_CONNECT_SERVER, connect_server, NULL);
|
||||
efunc_init_function(EFUNC_IS_SERVICES_BUT_NOT_ULINED, is_services_but_not_ulined, NULL);
|
||||
efunc_init_function(EFUNC_PARSE_MESSAGE_TAGS, parse_message_tags, &parse_message_tags_default_handler);
|
||||
efunc_init_function(EFUNC_MTAGS_TO_STRING, mtags_to_string, &mtags_to_string_default_handler);
|
||||
efunc_init_function(EFUNC_TKL_CHARTOTYPE, tkl_chartotype, NULL);
|
||||
efunc_init_function(EFUNC_TKL_CONFIGTYPETOCHAR, tkl_configtypetochar, NULL);
|
||||
efunc_init_function(EFUNC_TKL_TYPE_STRING, tkl_type_string, NULL);
|
||||
efunc_init_function(EFUNC_TKL_TYPE_CONFIG_STRING, tkl_type_config_string, NULL);
|
||||
efunc_init_function(EFUNC_CAN_SEND_TO_CHANNEL, can_send_to_channel, NULL);
|
||||
@ -391,6 +414,9 @@ void efunctions_init(void)
|
||||
efunc_init_function(EFUNC_FIND_TKL_NAMEBAN, find_tkl_nameban, NULL);
|
||||
efunc_init_function(EFUNC_FIND_TKL_SPAMFILTER, find_tkl_spamfilter, NULL);
|
||||
efunc_init_function(EFUNC_FIND_TKL_EXCEPTION, find_tkl_exception, NULL);
|
||||
efunc_init_function(EFUNC_SERVER_BAN_PARSE_MASK, server_ban_parse_mask, NULL);
|
||||
efunc_init_function(EFUNC_SERVER_BAN_EXCEPTION_PARSE_MASK, server_ban_exception_parse_mask, NULL);
|
||||
efunc_init_function(EFUNC_TKL_ADDED, tkl_added, NULL);
|
||||
efunc_init_function(EFUNC_ADD_SILENCE, add_silence, add_silence_default_handler);
|
||||
efunc_init_function(EFUNC_DEL_SILENCE, del_silence, del_silence_default_handler);
|
||||
efunc_init_function(EFUNC_IS_SILENCED, is_silenced, is_silenced_default_handler);
|
||||
@ -409,4 +435,20 @@ void efunctions_init(void)
|
||||
efunc_init_function(EFUNC_WHOIS_GET_POLICY, whois_get_policy, NULL);
|
||||
efunc_init_function(EFUNC_MAKE_OPER, make_oper, make_oper_default_handler);
|
||||
efunc_init_function(EFUNC_UNREAL_MATCH_IPLIST, unreal_match_iplist, NULL);
|
||||
efunc_init_function(EFUNC_WEBSERVER_SEND_RESPONSE, webserver_send_response, webserver_send_response_default_handler);
|
||||
efunc_init_function(EFUNC_WEBSERVER_CLOSE_CLIENT, webserver_close_client, webserver_close_client_default_handler);
|
||||
efunc_init_function(EFUNC_WEBSERVER_HANDLE_BODY, webserver_handle_body, webserver_handle_body_default_handler);
|
||||
efunc_init_function(EFUNC_RPC_RESPONSE, rpc_response, rpc_response_default_handler);
|
||||
efunc_init_function(EFUNC_RPC_ERROR, rpc_error, rpc_error_default_handler);
|
||||
efunc_init_function(EFUNC_RPC_ERROR_FMT, rpc_error_fmt, rpc_error_fmt_default_handler);
|
||||
efunc_init_function(EFUNC_RPC_SEND_REQUEST_TO_REMOTE, rpc_send_request_to_remote, rpc_send_request_to_remote_default_handler);
|
||||
efunc_init_function(EFUNC_RPC_SEND_RESPONSE_TO_REMOTE, rpc_send_response_to_remote, rpc_send_response_to_remote_default_handler);
|
||||
efunc_init_function(EFUNC_RRPC_SUPPORTED, rrpc_supported, rrpc_supported_default_handler);
|
||||
efunc_init_function(EFUNC_RRPC_SUPPORTED_SIMPLE, rrpc_supported_simple, rrpc_supported_simple_default_handler);
|
||||
efunc_init_function(EFUNC_WEBSOCKET_HANDLE_WEBSOCKET, websocket_handle_websocket, websocket_handle_websocket_default_handler);
|
||||
efunc_init_function(EFUNC_WEBSOCKET_CREATE_PACKET, websocket_create_packet, websocket_create_packet_default_handler);
|
||||
efunc_init_function(EFUNC_WEBSOCKET_CREATE_PACKET_EX, websocket_create_packet_ex, websocket_create_packet_ex_default_handler);
|
||||
efunc_init_function(EFUNC_WEBSOCKET_CREATE_PACKET_SIMPLE, websocket_create_packet_simple, websocket_create_packet_simple_default_handler);
|
||||
efunc_init_function(EFUNC_CHECK_DENY_LINK, check_deny_link, NULL);
|
||||
efunc_init_function(EFUNC_MTAG_GENERATE_ISSUED_BY_IRC, mtag_add_issued_by, mtag_add_issued_by_default_handler);
|
||||
}
|
||||
|
@ -80,8 +80,10 @@ int is_valid_extban_name(const char *p)
|
||||
{
|
||||
if (!*p)
|
||||
return 0; /* empty name */
|
||||
if (strlen(p) > 32)
|
||||
return 0; /* too long */
|
||||
for (; *p; p++)
|
||||
if (!isalnum(*p) && !strchr("_-", *p))
|
||||
if (!islower(*p) && !isdigit(*p) && !strchr("_-", *p))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -169,6 +171,15 @@ Extban *ExtbanAdd(Module *module, ExtbanInfo req)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!req.conv_param)
|
||||
{
|
||||
module->errorcode = MODERR_INVALID;
|
||||
unreal_log(ULOG_ERROR, "module", "EXTBANADD_API_ERROR", NULL,
|
||||
"ExtbanAdd(): conv_param event missing. Module: $module_name",
|
||||
log_data_string("module_name", module->header->name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (e=extbans; e; e = e->next)
|
||||
{
|
||||
if (e->letter == req.letter)
|
||||
@ -188,6 +199,7 @@ Extban *ExtbanAdd(Module *module, ExtbanInfo req)
|
||||
*/
|
||||
e->preregistered = 0;
|
||||
existing = 1;
|
||||
break;
|
||||
} else
|
||||
if (module->flags == MODFLAG_NONE)
|
||||
{
|
||||
@ -360,33 +372,12 @@ int extban_is_ok_nuh_extban(BanContext *b)
|
||||
*/
|
||||
const char *extban_conv_param_nuh(BanContext *b, Extban *extban)
|
||||
{
|
||||
char *cp, *user, *host, *mask, *ret = NULL;
|
||||
static char retbuf[USERLEN + NICKLEN + HOSTLEN + 32];
|
||||
char tmpbuf[USERLEN + NICKLEN + HOSTLEN + 32];
|
||||
static char retbuf[USERLEN + NICKLEN + HOSTLEN + 32];
|
||||
|
||||
/* Work on a copy */
|
||||
strlcpy(tmpbuf, b->banstr, sizeof(retbuf));
|
||||
mask = tmpbuf;
|
||||
|
||||
if (!*mask)
|
||||
return NULL; /* empty extban */
|
||||
if ((*mask == '~') && !strchr(mask, '@'))
|
||||
return NULL; /* not a user@host ban, too confusing. */
|
||||
if ((user = strchr((cp = mask), '!')))
|
||||
*user++ = '\0';
|
||||
if ((host = strrchr(user ? user : cp, '@')))
|
||||
{
|
||||
*host++ = '\0';
|
||||
if (!user)
|
||||
ret = make_nick_user_host(NULL, trim_str(cp,USERLEN), trim_str(host,HOSTLEN));
|
||||
}
|
||||
else if (!user && strchr(cp, '.'))
|
||||
ret = make_nick_user_host(NULL, NULL, trim_str(cp,HOSTLEN));
|
||||
if (!ret)
|
||||
ret = make_nick_user_host(trim_str(cp,NICKLEN), trim_str(user,USERLEN), trim_str(host,HOSTLEN));
|
||||
|
||||
strlcpy(retbuf, ret, sizeof(retbuf));
|
||||
return retbuf;
|
||||
return convert_regular_ban(tmpbuf, retbuf, sizeof(retbuf));
|
||||
}
|
||||
|
||||
/** conv_param to deal with stacked extbans.
|
||||
@ -440,25 +431,11 @@ const char *extban_conv_param_nuh_or_extban(BanContext *b, Extban *self_extban)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (extban->conv_param)
|
||||
{
|
||||
//BanContext *b = safe_alloc(sizeof(BanContext));
|
||||
//b->banstr = mask; <-- this is redundant right? we can use existing 'b' context??
|
||||
extban_recursion++;
|
||||
ret = extban->conv_param(b, extban);
|
||||
extban_recursion--;
|
||||
ret = prefix_with_extban(ret, b, extban, retbuf, sizeof(retbuf));
|
||||
//safe_free(b);
|
||||
return ret;
|
||||
}
|
||||
/* I honestly don't know what the deal is with the 80 char cap in clean_ban_mask is about. So I'm leaving it out here. -- aquanight */
|
||||
/* I don't know why it's 80, but I like a limit anyway. A ban of 500 characters can never be good... -- Syzop */
|
||||
if (strlen(b->banstr) > 80)
|
||||
{
|
||||
strlcpy(retbuf, b->banstr, 128);
|
||||
return retbuf;
|
||||
}
|
||||
return b->banstr;
|
||||
extban_recursion++;
|
||||
ret = extban->conv_param(b, extban);
|
||||
extban_recursion--;
|
||||
ret = prefix_with_extban(ret, b, extban, retbuf, sizeof(retbuf));
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *prefix_with_extban(const char *remainder, BanContext *b, Extban *extban, char *buf, size_t buflen)
|
||||
|
150
src/api-rpc.c
Normal file
150
src/api-rpc.c
Normal file
@ -0,0 +1,150 @@
|
||||
/************************************************************************
|
||||
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/api-rpc.c
|
||||
* (c) 2022- Bram Matthys and The UnrealIRCd Team
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief RPC API
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
/** This is the RPC API used for web requests.
|
||||
* For an overview of available RPC's (not the API)
|
||||
* see https://www.unrealircd.org/docs/RPC
|
||||
* @defgroup RPCAPI RPC API
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** List of RPC handlers */
|
||||
MODVAR RPCHandler *rpchandlers = NULL;
|
||||
|
||||
/* Forward declarations */
|
||||
static void unload_rpc_handler_commit(RPCHandler *m);
|
||||
|
||||
/** Adds a new RPC handler.
|
||||
* @param module The module which owns this RPC handler.
|
||||
* @param mreq The details of the request such as the method name, callback, etc.
|
||||
* @return Returns the handle to the RPC handler if successful, otherwise NULL.
|
||||
* The module's error code contains specific information about the
|
||||
* error.
|
||||
*/
|
||||
RPCHandler *RPCHandlerAdd(Module *module, RPCHandlerInfo *mreq)
|
||||
{
|
||||
RPCHandler *m;
|
||||
ModuleObject *mobj;
|
||||
|
||||
/* Some consistency checks to avoid a headache for module devs later on: */
|
||||
if (!mreq->method || !mreq->call)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "module", "RPCHANDLERADD_API_ERROR", NULL,
|
||||
"RPCHandlerAdd() from module $module_name: "
|
||||
"Missing required fields.",
|
||||
log_data_string("module_name", module->header->name));
|
||||
abort();
|
||||
}
|
||||
|
||||
m = RPCHandlerFind(mreq->method);
|
||||
if (m)
|
||||
{
|
||||
if (m->unloaded)
|
||||
{
|
||||
m->unloaded = 0;
|
||||
} else {
|
||||
if (module)
|
||||
module->errorcode = MODERR_EXISTS;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* New RPC handler */
|
||||
m = safe_alloc(sizeof(RPCHandler));
|
||||
safe_strdup(m->method, mreq->method);
|
||||
AddListItem(m, rpchandlers);
|
||||
}
|
||||
/* Add or update the following fields: */
|
||||
m->owner = module;
|
||||
m->flags = mreq->flags;
|
||||
m->loglevel = mreq->loglevel;
|
||||
if (!valid_loglevel(m->loglevel))
|
||||
m->loglevel = ULOG_INFO;
|
||||
m->call = mreq->call;
|
||||
|
||||
/* Add module object */
|
||||
mobj = safe_alloc(sizeof(ModuleObject));
|
||||
mobj->type = MOBJ_RPC;
|
||||
mobj->object.rpc = m;
|
||||
AddListItem(mobj, module->objects);
|
||||
module->errorcode = MODERR_NOERROR;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Returns the RPC handler for the given method name.
|
||||
* @param method The method to search for.
|
||||
* @return Returns the handle to the RPC handler,
|
||||
* or NULL if not found.
|
||||
*/
|
||||
RPCHandler *RPCHandlerFind(const char *method)
|
||||
{
|
||||
RPCHandler *m;
|
||||
|
||||
for (m = rpchandlers; m; m = m->next)
|
||||
{
|
||||
if (!strcasecmp(method, m->method))
|
||||
return m;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Remove the specified RPC handler - modules should not call this.
|
||||
* This is done automatically for modules on unload, so is only called internally.
|
||||
* @param m The PRC handler to remove.
|
||||
*/
|
||||
void RPCHandlerDel(RPCHandler *m)
|
||||
{
|
||||
if (m->owner)
|
||||
{
|
||||
ModuleObject *mobj;
|
||||
for (mobj = m->owner->objects; mobj; mobj = mobj->next) {
|
||||
if (mobj->type == MOBJ_RPC && mobj->object.rpc == m)
|
||||
{
|
||||
DelListItem(mobj, m->owner->objects);
|
||||
safe_free(mobj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m->owner = NULL;
|
||||
}
|
||||
|
||||
if (loop.rehashing)
|
||||
m->unloaded = 1;
|
||||
else
|
||||
unload_rpc_handler_commit(m);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
static void unload_rpc_handler_commit(RPCHandler *m)
|
||||
{
|
||||
/* This is an unusual operation, I think we should log it. */
|
||||
unreal_log(ULOG_INFO, "module", "UNLOAD_RPC_HANDLER", NULL,
|
||||
"Unloading RPC handler for '$method'",
|
||||
log_data_string("method", m->method));
|
||||
|
||||
/* Destroy the object */
|
||||
DelListItem(m, rpchandlers);
|
||||
safe_free(m->method);
|
||||
safe_free(m);
|
||||
}
|
||||
|
||||
void unload_all_unused_rpc_handlers(void)
|
||||
{
|
||||
RPCHandler *m, *m_next;
|
||||
|
||||
for (m = rpchandlers; m; m = m_next)
|
||||
{
|
||||
m_next = m->next;
|
||||
if (m->unloaded)
|
||||
unload_rpc_handler_commit(m);
|
||||
}
|
||||
}
|
135
src/channel.c
135
src/channel.c
@ -473,6 +473,46 @@ Ban *is_banned_with_nick(Client *client, Channel *channel, int type, const char
|
||||
return ban;
|
||||
}
|
||||
|
||||
/** Checks if a ban already exists */
|
||||
int ban_exists(Ban *lst, const char *str)
|
||||
{
|
||||
for (; lst; lst = lst->next)
|
||||
if (!mycmp(lst->banstr, str))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Checks if a ban already exists - special version.
|
||||
* This ignores the "~time:xx:" suffixes in the banlist.
|
||||
* So it will return 1 if a ban is there for ~time:5:blah!*@*
|
||||
* and you call ban_exists_ignore_time(channel->banlist, "blah!*@*")
|
||||
*/
|
||||
int ban_exists_ignore_time(Ban *lst, const char *str)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
for (; lst; lst = lst->next)
|
||||
{
|
||||
if (!strncmp(lst->banstr, "~time:", 6))
|
||||
{
|
||||
/* Special treatment for ~time:xx: */
|
||||
p = strchr(lst->banstr+6, ':');
|
||||
if (p)
|
||||
{
|
||||
p++;
|
||||
if (!mycmp(p, str))
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
/* The simple version */
|
||||
if (!mycmp(lst->banstr, str))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Add user to the channel.
|
||||
* This adds both the Member struct to the channel->members linked list
|
||||
* and also the Membership struct to the client->user->channel linked list.
|
||||
@ -614,34 +654,24 @@ Cmode_t get_extmode_bitbychar(char m)
|
||||
*/
|
||||
void channel_modes(Client *client, char *mbuf, char *pbuf, size_t mbuf_size, size_t pbuf_size, Channel *channel, int hide_local_modes)
|
||||
{
|
||||
int ismember = 0;
|
||||
int show_mode_parameters = 0;
|
||||
Cmode *cm;
|
||||
|
||||
if (!mbuf_size || !pbuf_size)
|
||||
return;
|
||||
|
||||
if (!client || IsMember(client, channel) || IsServer(client) || IsMe(client) || IsULine(client))
|
||||
ismember = 1;
|
||||
if (!client || IsMember(client, channel) || IsServer(client) || IsMe(client) || IsULine(client) ||
|
||||
ValidatePermissionsForPath("channel:see:mode:remote",client,NULL,channel,NULL))
|
||||
{
|
||||
show_mode_parameters = 1;
|
||||
}
|
||||
|
||||
*pbuf = '\0';
|
||||
strlcpy(mbuf, "+", mbuf_size);
|
||||
|
||||
/* Paramless first */
|
||||
for (cm=channelmodes; cm; cm = cm->next)
|
||||
{
|
||||
if (cm->letter &&
|
||||
!cm->paracount &&
|
||||
!(hide_local_modes && cm->local) &&
|
||||
(channel->mode.mode & cm->mode))
|
||||
{
|
||||
strlcat_letter(mbuf, cm->letter, mbuf_size);
|
||||
}
|
||||
}
|
||||
|
||||
for (cm=channelmodes; cm; cm = cm->next)
|
||||
{
|
||||
if (cm->letter &&
|
||||
cm->paracount &&
|
||||
!(hide_local_modes && cm->local) &&
|
||||
(channel->mode.mode & cm->mode))
|
||||
{
|
||||
@ -650,7 +680,7 @@ void channel_modes(Client *client, char *mbuf, char *pbuf, size_t mbuf_size, siz
|
||||
if (mbuf_size)
|
||||
strlcat_letter(mbuf, flag, mbuf_size);
|
||||
|
||||
if (ismember)
|
||||
if (cm->paracount && show_mode_parameters)
|
||||
{
|
||||
strlcat(pbuf, cm_getparameter(channel, flag), pbuf_size);
|
||||
strlcat(pbuf, " ", pbuf_size);
|
||||
@ -704,6 +734,59 @@ char *trim_str(char *str, int len)
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Convert regular ban (non-extban) if needed.
|
||||
* This does things like:
|
||||
* nick!user@host -> nick!user@host (usually no change)
|
||||
* nickkkkkkkkkkkkkkkkkkkkkkkkkk!user@host -> nickkkkkkk*!user@host (dealing with NICKLEN restrictions and such).
|
||||
* user@host -> *!user@host
|
||||
* 1.2.3.4 -> *!*@1.2.3.4 (converting IP to a proper mask)
|
||||
* @param mask Incoming mask (this will be touched/fragged!)
|
||||
* @param buf Output buffer
|
||||
* @param buflen Length of the output buffer, eg sizeof(buf)
|
||||
* @retval The sanitized mask, or NULL if it should be rejected fully.
|
||||
* @note Since 'mask' will be fragged, you most likely wish to pass a copy of it rather than the original.
|
||||
*/
|
||||
const char *convert_regular_ban(char *mask, char *buf, size_t buflen)
|
||||
{
|
||||
static char namebuf[USERLEN + HOSTLEN + 6];
|
||||
char *user, *host;
|
||||
|
||||
if (!*mask)
|
||||
return NULL; /* empty extban */
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
buf = namebuf;
|
||||
buflen = sizeof(namebuf);
|
||||
}
|
||||
|
||||
if ((*mask == '~') && !strchr(mask, '@'))
|
||||
{
|
||||
/* has a '~', which makes it look like an extban,
|
||||
* but is not a user@host ban, too confusing.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((user = strchr(mask, '!')))
|
||||
*user++ = '\0';
|
||||
|
||||
if ((host = strrchr(user ? user : mask, '@')))
|
||||
{
|
||||
*host++ = '\0';
|
||||
if (!user)
|
||||
return make_nick_user_host_r(buf, buflen, NULL, trim_str(mask,USERLEN), trim_str(host,HOSTLEN));
|
||||
}
|
||||
else if (!user && (strchr(mask, '.') || strchr(mask, ':')))
|
||||
{
|
||||
/* 1.2.3.4 -> *!*@1.2.3.4 (and the same for IPv6) */
|
||||
return make_nick_user_host_r(buf, buflen, NULL, NULL, trim_str(mask,HOSTLEN));
|
||||
}
|
||||
|
||||
/* regular nick!user@host with the auto-trimming feature */
|
||||
return make_nick_user_host_r(buf, buflen, trim_str(mask,NICKLEN), trim_str(user,USERLEN), trim_str(host,HOSTLEN));
|
||||
}
|
||||
|
||||
/** Make a proper ban mask.
|
||||
* This takes user input (eg: "nick") and converts it to a mask suitable
|
||||
* in the +beI lists (eg: "nick!*@*"). It also deals with extended bans,
|
||||
@ -719,8 +802,6 @@ char *trim_str(char *str, int len)
|
||||
const char *clean_ban_mask(const char *mask_in, int what, Client *client, int conv_options)
|
||||
{
|
||||
char *cp, *x;
|
||||
char *user;
|
||||
char *host;
|
||||
static char mask[512];
|
||||
|
||||
/* Strip any ':' at beginning since that would cause a desync */
|
||||
@ -798,21 +879,7 @@ const char *clean_ban_mask(const char *mask_in, int what, Client *client, int co
|
||||
return mask;
|
||||
}
|
||||
|
||||
if ((*mask == '~') && !strchr(mask, '@'))
|
||||
return NULL; /* not an extended ban and not a ~user@host ban either. */
|
||||
|
||||
if ((user = strchr((cp = mask), '!')))
|
||||
*user++ = '\0';
|
||||
if ((host = strrchr(user ? user : cp, '@')))
|
||||
{
|
||||
*host++ = '\0';
|
||||
|
||||
if (!user)
|
||||
return make_nick_user_host(NULL, trim_str(cp,USERLEN), trim_str(host,HOSTLEN));
|
||||
}
|
||||
else if (!user && strchr(cp, '.'))
|
||||
return make_nick_user_host(NULL, NULL, trim_str(cp,HOSTLEN));
|
||||
return make_nick_user_host(trim_str(cp,NICKLEN), trim_str(user,USERLEN), trim_str(host,HOSTLEN));
|
||||
return convert_regular_ban(mask, NULL, 0);
|
||||
}
|
||||
|
||||
/** Check if 'client' matches an invite exception (+I) on 'channel' */
|
||||
|
759
src/conf.c
759
src/conf.c
File diff suppressed because it is too large
Load Diff
@ -348,7 +348,17 @@ int preprocessor_resolve_if(ConditionalConfig *cc, PreprocessorPhase phase)
|
||||
if (cc->condition == IF_MODULE)
|
||||
{
|
||||
if (phase == PREPROCESSOR_PHASE_INITIAL)
|
||||
return 1; /* we cannot handle @if module-loaded() yet.. */
|
||||
{
|
||||
/* We cannot handle @if module-loaded() yet.. */
|
||||
return 1;
|
||||
}
|
||||
if (phase == PREPROCESSOR_PHASE_SECONDARY)
|
||||
{
|
||||
/* We can only handle blacklisted modules at this point, so: */
|
||||
if (is_blacklisted_module(cc->name))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (is_module_loaded(cc->name))
|
||||
{
|
||||
result = 1;
|
||||
|
1230
src/crule.c
1230
src/crule.c
File diff suppressed because it is too large
Load Diff
29
src/dbuf.c
29
src/dbuf.c
@ -189,3 +189,32 @@ int dbuf_getmsg(dbuf *dyn, char *buf)
|
||||
dbuf_delete(dyn, line_bytes + empty_bytes);
|
||||
return MIN(line_bytes, READBUFSIZE - 2);
|
||||
}
|
||||
|
||||
/*
|
||||
** dbuf_get
|
||||
**
|
||||
** Get the entire dbuf buffer as a newly allocated string. There is NO CR/LF processing.
|
||||
*/
|
||||
int dbuf_get(dbuf *dyn, char **buf)
|
||||
{
|
||||
dbufbuf *block;
|
||||
char *d;
|
||||
int bytes = 0;
|
||||
|
||||
/* First calculate the room needed... */
|
||||
list_for_each_entry2(block, dbufbuf, &dyn->dbuf_list, dbuf_node)
|
||||
bytes += block->size;
|
||||
|
||||
d = *buf = safe_alloc(bytes + 1);
|
||||
|
||||
list_for_each_entry2(block, dbufbuf, &dyn->dbuf_list, dbuf_node)
|
||||
{
|
||||
memcpy(d, block->data, block->size);
|
||||
d += block->size;
|
||||
}
|
||||
*d = '\0'; /* zero terminate */
|
||||
|
||||
/* Remove what is now unnecessary */
|
||||
dbuf_delete(dyn, bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ void fd_debug(fd_set *f, int highest, char *name)
|
||||
}
|
||||
}
|
||||
}
|
||||
void fd_select(time_t delay)
|
||||
void fd_select(int delay)
|
||||
{
|
||||
struct timeval to;
|
||||
int num, fd;
|
||||
@ -360,7 +360,7 @@ void fd_refresh(int fd)
|
||||
}
|
||||
}
|
||||
|
||||
void fd_select(time_t delay)
|
||||
void fd_select(int delay)
|
||||
{
|
||||
struct timespec ts;
|
||||
int num, p, revents, fd;
|
||||
@ -469,7 +469,7 @@ void fd_refresh(int fd)
|
||||
fde->backend_flags = pflags;
|
||||
}
|
||||
|
||||
void fd_select(time_t delay)
|
||||
void fd_select(int delay)
|
||||
{
|
||||
int num, p, revents, fd;
|
||||
struct epoll_event *epfd;
|
||||
@ -605,7 +605,7 @@ void fd_refresh(int fd)
|
||||
fde->backend_flags = pflags;
|
||||
}
|
||||
|
||||
void fd_select(time_t delay)
|
||||
void fd_select(int delay)
|
||||
{
|
||||
int num, p, revents, fd;
|
||||
struct pollfd *pfd;
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
/* new FD management code, based on mowgli.eventloop from atheme, hammered into Unreal by
|
||||
/* new FD management code, based on mowgli.eventloop from atheme, hammered into UnrealIRCd by
|
||||
* me, nenolod.
|
||||
*/
|
||||
FDEntry fd_table[MAXCONNECTIONS + 1];
|
||||
|
20
src/hash.c
20
src/hash.c
@ -320,7 +320,7 @@ int add_to_client_hash_table(const char *name, Client *client)
|
||||
/*
|
||||
* If you see this, you have probably found your way to why changing the
|
||||
* base version made the IRCd become weird. This has been the case in all
|
||||
* Unreal versions since 3.0. I'm sick of people ripping the IRCd off and
|
||||
* UnrealIRCd versions since 3.0. I'm sick of people ripping the IRCd off and
|
||||
* just slapping on some random <theirnet> BASE_VERSION while not changing
|
||||
* a single bit of code. YOU DID NOT WRITE ALL OF THIS THEREFORE YOU DO NOT
|
||||
* DESERVE TO BE ABLE TO DO THAT. If you found this however, I'm OK with you
|
||||
@ -720,3 +720,21 @@ int throttle_can_connect(Client *client)
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/** Find a server by the SID-part of a UID.
|
||||
* Eg you pass "001ABCDEFG" and it would look up server "001".
|
||||
*
|
||||
* @param uid The UID, eg 001ABCDEFG
|
||||
* @returns Server where the UID would be hosted on, or NULL
|
||||
* if no such server is linked.
|
||||
*/
|
||||
Client *find_server_by_uid(const char *uid)
|
||||
{
|
||||
char sid[SIDLEN+1];
|
||||
|
||||
if (!isdigit(*uid))
|
||||
return NULL; /* not a UID/SID */
|
||||
|
||||
strlcpy(sid, uid, sizeof(sid));
|
||||
return hash_find_id(sid, NULL);
|
||||
}
|
||||
|
30
src/ircd.c
30
src/ircd.c
@ -121,12 +121,32 @@ EVENT(handshake_timeout)
|
||||
|
||||
list_for_each_entry_safe(client, next, &unknown_list, lclient_node)
|
||||
{
|
||||
if (client->local->creationtime && ((TStime() - client->local->creationtime) > iConf.handshake_timeout))
|
||||
if (client->local->creationtime &&
|
||||
((TStime() - client->local->creationtime) > iConf.handshake_timeout) &&
|
||||
!(client->local->listener && (client->local->listener->socket_type == SOCKET_TYPE_UNIX)))
|
||||
{
|
||||
Hook *h;
|
||||
int n = HOOK_CONTINUE;
|
||||
const char *quitreason = "Registration Timeout";
|
||||
char reasonbuf[512];
|
||||
|
||||
if (client->server && *client->server->by)
|
||||
continue; /* handled by server module */
|
||||
|
||||
exit_client(client, NULL, "Registration Timeout");
|
||||
for (h = Hooks[HOOKTYPE_PRE_LOCAL_HANDSHAKE_TIMEOUT]; h; h = h->next)
|
||||
{
|
||||
n = (*(h->func.intfunc))(client, &quitreason);
|
||||
if (n == HOOK_ALLOW)
|
||||
break;
|
||||
}
|
||||
if (n == HOOK_ALLOW)
|
||||
continue; /* Do not exit the client due to registration timeout */
|
||||
|
||||
/* Work on a copy here, since the 'quitreason' may point to
|
||||
* some kind of buffer that gets freed in the exit code.
|
||||
*/
|
||||
strlcpy(reasonbuf, quitreason ? quitreason : "Registration Timeout", sizeof(reasonbuf));
|
||||
exit_client(client, NULL, reasonbuf);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -712,6 +732,9 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
#endif
|
||||
fprintf(stderr, "* c-ares %s\n", ares_version(NULL));
|
||||
fprintf(stderr, "* %s\n", pcre2_version());
|
||||
#endif
|
||||
#if JANSSON_VERSION_HEX >= 0x020D00
|
||||
fprintf(stderr, "* jansson %s\n", jansson_version_str());
|
||||
#endif
|
||||
check_user_limit();
|
||||
#ifndef _WIN32
|
||||
@ -730,6 +753,7 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
#endif
|
||||
init_dynconf();
|
||||
init_sys();
|
||||
clicap_init();
|
||||
/*
|
||||
* Add default class
|
||||
*/
|
||||
@ -760,7 +784,6 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
make_server(&me);
|
||||
umodes_check_for_changes();
|
||||
charsys_check_for_changes();
|
||||
clicap_init();
|
||||
if (!find_command_simple("PRIVMSG"))
|
||||
{
|
||||
config_error("Someone forgot to load modules with proper commands in them. READ THE DOCUMENTATION");
|
||||
@ -854,6 +877,7 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
PS_STRINGS->ps_argvstr = me.name;
|
||||
#endif
|
||||
module_loadall();
|
||||
loop.config_status = CONFIG_STATUS_COMPLETE;
|
||||
|
||||
#ifndef _WIN32
|
||||
SocketLoop(NULL);
|
||||
|
580
src/json.c
Normal file
580
src/json.c
Normal file
@ -0,0 +1,580 @@
|
||||
/************************************************************************
|
||||
* UnralIRCd JSON functions, src/json.c
|
||||
* (C) 2021-.. Bram Matthys (Syzop) and the UnrealIRCd Team
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
/** @file
|
||||
* @brief JSON functions - used for logging and RPC.
|
||||
*/
|
||||
|
||||
/** Are we currently in the logging code? */
|
||||
int log_json_filter = 0;
|
||||
|
||||
/** Calculate expansion of a JSON string thanks to double escaping.
|
||||
* orig => JSON => IRC
|
||||
* " => \" => \\"
|
||||
* \ => \\ => \\\\
|
||||
*/
|
||||
int json_dump_string_length(const char *s)
|
||||
{
|
||||
int len = 0;
|
||||
for (; *s; s++)
|
||||
{
|
||||
if (*s == '\\')
|
||||
len += 4;
|
||||
else if (*s == '"')
|
||||
len += 3;
|
||||
else
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Convert a regular string value to a JSON string.
|
||||
* In UnrealIRCd, this must be used instead of json_string()
|
||||
* as we may use non-UTF8 sequences. Also, this takes care
|
||||
* of using json_null() if the string was NULL, which is
|
||||
* usually what we want as well.
|
||||
* @param s Input string
|
||||
* @returns a json string value or json null value.
|
||||
*/
|
||||
json_t *json_string_unreal(const char *s)
|
||||
{
|
||||
char buf1[512], buf2[512];
|
||||
char *verified_s;
|
||||
const char *stripped;
|
||||
|
||||
if (s == NULL)
|
||||
return json_null();
|
||||
|
||||
if (log_json_filter)
|
||||
{
|
||||
stripped = StripControlCodesEx(s, buf1, sizeof(buf1), UNRL_STRIP_LOW_ASCII|UNRL_STRIP_KEEP_LF);
|
||||
verified_s = unrl_utf8_make_valid(buf1, buf2, sizeof(buf2), 0);
|
||||
} else {
|
||||
verified_s = unrl_utf8_make_valid(s, buf2, sizeof(buf2), 0);
|
||||
}
|
||||
|
||||
return json_string(verified_s);
|
||||
}
|
||||
|
||||
const char *json_object_get_string(json_t *j, const char *name)
|
||||
{
|
||||
json_t *v = json_object_get(j, name);
|
||||
return v ? json_string_value(v) : NULL;
|
||||
}
|
||||
|
||||
/** Get integer value of a JSON object.
|
||||
* @param j The JSON object that should contain a 'name' item
|
||||
* @param name The item to search for
|
||||
* @param default_value The value to return when the JSON object 'name' is not found
|
||||
* or not an integer.
|
||||
* @returns The integer value, or default_value if the object does not exist or is not an integer.
|
||||
*/
|
||||
int json_object_get_integer(json_t *j, const char *name, int default_value)
|
||||
{
|
||||
json_t *v = json_object_get(j, name);
|
||||
if (!v || !json_is_integer(v))
|
||||
return default_value;
|
||||
return json_integer_value(v);
|
||||
}
|
||||
|
||||
int json_object_get_boolean(json_t *j, const char *name, int default_value)
|
||||
{
|
||||
json_t *v = json_object_get(j, name);
|
||||
if (!v)
|
||||
return default_value;
|
||||
if (json_is_true(v))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define json_string __BAD___DO__NOT__USE__JSON__STRING__PLZ
|
||||
|
||||
const char *json_get_value(json_t *t)
|
||||
{
|
||||
static char buf[32];
|
||||
|
||||
if (json_is_string(t))
|
||||
return json_string_value(t);
|
||||
|
||||
if (json_is_integer(t))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%lld", (long long)json_integer_value(t));
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (json_is_boolean(t))
|
||||
{
|
||||
if (json_is_true(t))
|
||||
return "true";
|
||||
return "false";
|
||||
}
|
||||
|
||||
if (json_is_array(t))
|
||||
return "<array>";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
json_t *json_timestamp(time_t v)
|
||||
{
|
||||
const char *ts = timestamp_iso8601(v);
|
||||
if (ts)
|
||||
return json_string_unreal(ts);
|
||||
return json_null();
|
||||
}
|
||||
|
||||
const char *timestamp_iso8601_now(void)
|
||||
{
|
||||
struct timeval t;
|
||||
struct tm *tm;
|
||||
time_t sec;
|
||||
static char buf[64];
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
sec = t.tv_sec;
|
||||
tm = gmtime(&sec);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec,
|
||||
(int)(t.tv_usec / 1000));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *timestamp_iso8601(time_t v)
|
||||
{
|
||||
struct tm *tm;
|
||||
static char buf[64];
|
||||
|
||||
if (v == 0)
|
||||
return NULL;
|
||||
|
||||
tm = gmtime(&v);
|
||||
|
||||
if (tm == NULL)
|
||||
return NULL;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec,
|
||||
0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void json_expand_client_security_groups(json_t *parent, Client *client)
|
||||
{
|
||||
SecurityGroup *s;
|
||||
json_t *child = json_array();
|
||||
json_object_set_new(parent, "security-groups", child);
|
||||
|
||||
/* We put known-users or unknown-users at the beginning.
|
||||
* The latter is special and doesn't actually exist
|
||||
* in the linked list, hence the special code here,
|
||||
* and again later in the for loop to skip it.
|
||||
*/
|
||||
if (user_allowed_by_security_group_name(client, "known-users"))
|
||||
json_array_append_new(child, json_string_unreal("known-users"));
|
||||
else
|
||||
json_array_append_new(child, json_string_unreal("unknown-users"));
|
||||
|
||||
for (s = securitygroups; s; s = s->next)
|
||||
if (strcmp(s->name, "known-users") && user_allowed_by_security_group(client, s))
|
||||
json_array_append_new(child, json_string_unreal(s->name));
|
||||
}
|
||||
|
||||
/* detail=0: only name, id
|
||||
* detail=1: only name, id, hostname, ip, details, geoip
|
||||
* detail=2: everything, except 'channels'
|
||||
* detail=3: everything, with 'channels' being a max 384 character string (meant for JSON logging only)
|
||||
* detail=4: everything, with 'channels' object (full).
|
||||
*/
|
||||
void json_expand_client(json_t *j, const char *key, Client *client, int detail)
|
||||
{
|
||||
char buf[BUFSIZE+1];
|
||||
json_t *child;
|
||||
json_t *user = NULL;
|
||||
time_t ts;
|
||||
|
||||
if (key)
|
||||
{
|
||||
child = json_object();
|
||||
json_object_set_new(j, key, child);
|
||||
} else {
|
||||
child = j;
|
||||
}
|
||||
|
||||
/* First the information that is available for ALL client types: */
|
||||
json_object_set_new(child, "name", json_string_unreal(client->name));
|
||||
json_object_set_new(child, "id", json_string_unreal(client->id));
|
||||
|
||||
if (detail == 0)
|
||||
return;
|
||||
|
||||
/* hostname is available for all, it just depends a bit on whether it is DNS or IP */
|
||||
if (client->user && *client->user->realhost)
|
||||
json_object_set_new(child, "hostname", json_string_unreal(client->user->realhost));
|
||||
else if (client->local && *client->local->sockhost)
|
||||
json_object_set_new(child, "hostname", json_string_unreal(client->local->sockhost));
|
||||
else
|
||||
json_object_set_new(child, "hostname", json_string_unreal(GetIP(client)));
|
||||
|
||||
/* 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));
|
||||
/* client.details is always available: it is nick!user@host, nick@host, server@host
|
||||
* server@ip, or just server.
|
||||
*/
|
||||
if (client->user)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s!%s@%s", client->name, client->user->username, client->user->realhost);
|
||||
json_object_set_new(child, "details", json_string_unreal(buf));
|
||||
} else if (client->ip) {
|
||||
if (*client->name)
|
||||
snprintf(buf, sizeof(buf), "%s@%s", client->name, client->ip);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "[%s]", client->ip);
|
||||
json_object_set_new(child, "details", json_string_unreal(buf));
|
||||
} else {
|
||||
json_object_set_new(child, "details", json_string_unreal(client->name));
|
||||
}
|
||||
|
||||
if (detail < 2)
|
||||
{
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT, client, detail, child);
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
if ((ts = get_creationtime(client)))
|
||||
json_object_set_new(child, "connected_since", json_timestamp(ts));
|
||||
if (client->local && client->local->idle_since)
|
||||
json_object_set_new(child, "idle_since", json_timestamp(client->local->idle_since));
|
||||
|
||||
if (client->user)
|
||||
{
|
||||
char buf[512];
|
||||
const char *str;
|
||||
/* client.user */
|
||||
user = json_object();
|
||||
json_object_set_new(child, "user", user);
|
||||
|
||||
json_object_set_new(user, "username", json_string_unreal(client->user->username));
|
||||
if (!BadPtr(client->info))
|
||||
json_object_set_new(user, "realname", json_string_unreal(client->info));
|
||||
if (has_user_mode(client, 'x') && client->user->virthost && strcmp(client->user->virthost, client->user->realhost))
|
||||
json_object_set_new(user, "vhost", json_string_unreal(client->user->virthost));
|
||||
if (*client->user->cloakedhost)
|
||||
json_object_set_new(user, "cloakedhost", json_string_unreal(client->user->cloakedhost));
|
||||
if (client->uplink)
|
||||
json_object_set_new(user, "servername", json_string_unreal(client->uplink->name));
|
||||
if (IsLoggedIn(client))
|
||||
json_object_set_new(user, "account", json_string_unreal(client->user->account));
|
||||
json_object_set_new(user, "reputation", json_integer(GetReputation(client)));
|
||||
json_expand_client_security_groups(user, client);
|
||||
|
||||
/* user modes and snomasks */
|
||||
get_usermode_string_r(client, buf, sizeof(buf));
|
||||
json_object_set_new(user, "modes", json_string_unreal(buf+1));
|
||||
if (client->user->snomask)
|
||||
json_object_set_new(user, "snomasks", json_string_unreal(client->user->snomask));
|
||||
|
||||
/* if oper then we can possibly expand a bit more */
|
||||
str = get_operlogin(client);
|
||||
if (str)
|
||||
json_object_set_new(user, "operlogin", json_string_unreal(str));
|
||||
str = get_operclass(client);
|
||||
if (str)
|
||||
json_object_set_new(user, "operclass", json_string_unreal(str));
|
||||
/* For detail>2 we will include the channels.
|
||||
* Even if the user is on 0 channels we include "channels":[]
|
||||
* so it is clear that the user is on 0 channels and it is
|
||||
* not because of low detail level that channels are skipped.
|
||||
*/
|
||||
if (detail > 2)
|
||||
{
|
||||
Membership *m;
|
||||
int cnt = 0;
|
||||
int len = 0;
|
||||
json_t *channels = json_array();
|
||||
json_object_set_new(user, "channels", channels);
|
||||
|
||||
if (detail == 3)
|
||||
{
|
||||
/* Short format, mainly for JSON logging */
|
||||
for (m = client->user->channel; m; m = m->next)
|
||||
{
|
||||
len += json_dump_string_length(m->channel->name);
|
||||
if (len > 384)
|
||||
{
|
||||
/* Truncated */
|
||||
json_array_append_new(channels, json_string_unreal("..."));
|
||||
break;
|
||||
}
|
||||
json_array_append_new(channels, json_string_unreal(m->channel->name));
|
||||
}
|
||||
} else {
|
||||
/* Long format for JSON-RPC */
|
||||
for (m = client->user->channel; m; m = m->next)
|
||||
{
|
||||
json_t *e = json_object();
|
||||
json_object_set_new(e, "name", json_string_unreal(m->channel->name));
|
||||
if (*m->member_modes)
|
||||
json_object_set_new(e, "level", json_string_unreal(m->member_modes));
|
||||
json_array_append_new(channels, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT_USER, client, detail, child, user);
|
||||
} else
|
||||
if (IsMe(client))
|
||||
{
|
||||
json_t *server = json_object();
|
||||
json_t *features;
|
||||
|
||||
/* client.server */
|
||||
json_object_set_new(child, "server", server);
|
||||
|
||||
if (!BadPtr(client->info))
|
||||
json_object_set_new(server, "info", json_string_unreal(client->info));
|
||||
json_object_set_new(server, "num_users", json_integer(client->server->users));
|
||||
json_object_set_new(server, "boot_time", json_timestamp(client->server->boottime));
|
||||
|
||||
/* client.server.features */
|
||||
features = json_object();
|
||||
json_object_set_new(server, "features", features);
|
||||
if (!BadPtr(client->server->features.software))
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "UnrealIRCd-%s", buildid);
|
||||
json_object_set_new(features, "software", json_string_unreal(buf));
|
||||
}
|
||||
json_object_set_new(features, "protocol", json_integer(UnrealProtocol));
|
||||
if (!BadPtr(client->server->features.usermodes))
|
||||
json_object_set_new(features, "usermodes", json_string_unreal(umodestring));
|
||||
|
||||
/* client.server.features.chanmodes (array) */
|
||||
{
|
||||
int i;
|
||||
char buf[512];
|
||||
json_t *chanmodes = json_array();
|
||||
json_object_set_new(features, "chanmodes", chanmodes);
|
||||
/* first one is special - wait.. is this still the case? lol. */
|
||||
snprintf(buf, sizeof(buf), "%s%s", CHPAR1, EXPAR1);
|
||||
json_array_append_new(chanmodes, json_string_unreal(buf));
|
||||
for (i=1; i < 4; i++)
|
||||
json_array_append_new(chanmodes, json_string_unreal(extchmstr[i]));
|
||||
}
|
||||
if (!BadPtr(client->server->features.nickchars))
|
||||
json_object_set_new(features, "nick_character_sets", json_string_unreal(charsys_get_current_languages()));
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT_SERVER, client, detail, child, server);
|
||||
} else
|
||||
if (IsServer(client) && client->server)
|
||||
{
|
||||
/* client.server */
|
||||
|
||||
/* Whenever a server is expanded, which is rare,
|
||||
* we should probably expand as much as info as possible:
|
||||
*/
|
||||
json_t *server = json_object();
|
||||
json_t *features;
|
||||
|
||||
/* client.server */
|
||||
json_object_set_new(child, "server", server);
|
||||
if (!BadPtr(client->info))
|
||||
json_object_set_new(server, "info", json_string_unreal(client->info));
|
||||
if (client->uplink)
|
||||
json_object_set_new(server, "uplink", json_string_unreal(client->uplink->name));
|
||||
json_object_set_new(server, "num_users", json_integer(client->server->users));
|
||||
json_object_set_new(server, "boot_time", json_timestamp(client->server->boottime));
|
||||
json_object_set_new(server, "synced", json_boolean(client->server->flags.synced));
|
||||
json_object_set_new(server, "ulined", json_boolean(IsULine(client)));
|
||||
|
||||
/* client.server.features */
|
||||
features = json_object();
|
||||
json_object_set_new(server, "features", features);
|
||||
if (!BadPtr(client->server->features.software))
|
||||
json_object_set_new(features, "software", json_string_unreal(client->server->features.software));
|
||||
json_object_set_new(features, "protocol", json_integer(client->server->features.protocol));
|
||||
if (!BadPtr(client->server->features.usermodes))
|
||||
json_object_set_new(features, "usermodes", json_string_unreal(client->server->features.usermodes));
|
||||
if (!BadPtr(client->server->features.chanmodes[0]))
|
||||
{
|
||||
/* client.server.features.chanmodes (array) */
|
||||
int i;
|
||||
json_t *chanmodes = json_array();
|
||||
json_object_set_new(features, "chanmodes", chanmodes);
|
||||
for (i=0; i < 4; i++)
|
||||
json_array_append_new(chanmodes, json_string_unreal(client->server->features.chanmodes[i]));
|
||||
}
|
||||
if (!BadPtr(client->server->features.nickchars))
|
||||
json_object_set_new(features, "nick_character_sets", json_string_unreal(client->server->features.nickchars));
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT_SERVER, client, detail, child, server);
|
||||
}
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT, client, detail, child);
|
||||
}
|
||||
|
||||
void json_expand_channel_ban(json_t *child, const char *banlist_name, Ban *banlist)
|
||||
{
|
||||
Ban *ban;
|
||||
json_t *list, *e;
|
||||
|
||||
list = json_array();
|
||||
json_object_set_new(child, banlist_name, list);
|
||||
for (ban = banlist; ban; ban = ban->next)
|
||||
{
|
||||
e = json_object();
|
||||
json_array_append_new(list, e);
|
||||
json_object_set_new(e, "name", json_string_unreal(ban->banstr));
|
||||
json_object_set_new(e, "set_by", json_string_unreal(ban->who));
|
||||
json_object_set_new(e, "set_at", json_timestamp(ban->when));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* detail=1 adds bans, ban_exemptions and invite_exceptions
|
||||
* detail=2 adds members
|
||||
* detail=3+ makes the members more detailed
|
||||
*/
|
||||
void json_expand_channel(json_t *j, const char *key, Channel *channel, int detail)
|
||||
{
|
||||
char mode1[512], mode2[512], modes[512];
|
||||
json_t *child;
|
||||
|
||||
if (key)
|
||||
{
|
||||
child = json_object();
|
||||
json_object_set_new(j, key, child);
|
||||
} else {
|
||||
child = j;
|
||||
}
|
||||
|
||||
json_object_set_new(child, "name", json_string_unreal(channel->name));
|
||||
if (detail == 0)
|
||||
return;
|
||||
|
||||
json_object_set_new(child, "creation_time", json_timestamp(channel->creationtime));
|
||||
json_object_set_new(child, "num_users", json_integer(channel->users));
|
||||
if (channel->topic)
|
||||
{
|
||||
json_object_set_new(child, "topic", json_string_unreal(channel->topic));
|
||||
json_object_set_new(child, "topic_set_by", json_string_unreal(channel->topic_nick));
|
||||
json_object_set_new(child, "topic_set_at", json_timestamp(channel->topic_time));
|
||||
}
|
||||
|
||||
/* Add "mode" too */
|
||||
channel_modes(NULL, mode1, mode2, sizeof(mode1), sizeof(mode2), channel, 0);
|
||||
if (*mode2)
|
||||
{
|
||||
snprintf(modes, sizeof(modes), "%s %s", mode1+1, mode2);
|
||||
json_object_set_new(child, "modes", json_string_unreal(modes));
|
||||
} else {
|
||||
json_object_set_new(child, "modes", json_string_unreal(mode1+1));
|
||||
}
|
||||
|
||||
if (detail > 1)
|
||||
{
|
||||
json_expand_channel_ban(child, "bans", channel->banlist);
|
||||
json_expand_channel_ban(child, "ban_exemptions", channel->exlist);
|
||||
json_expand_channel_ban(child, "invite_exceptions", channel->invexlist);
|
||||
}
|
||||
|
||||
if (detail >= 3)
|
||||
{
|
||||
Member *u;
|
||||
json_t *list = json_array();
|
||||
json_object_set_new(child, "members", list);
|
||||
|
||||
for (u = channel->members; u; u = u->next)
|
||||
{
|
||||
json_t *e = json_object();
|
||||
if (*u->member_modes)
|
||||
json_object_set_new(e, "level", json_string_unreal(u->member_modes));
|
||||
json_expand_client(e, NULL, u->client, detail-3);
|
||||
json_array_append_new(list, e);
|
||||
}
|
||||
}
|
||||
|
||||
// Possibly later: If detail is set to 1 then expand more...
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CHANNEL, channel, detail, child);
|
||||
}
|
||||
|
||||
void json_expand_tkl(json_t *root, const char *key, TKL *tkl, int detail)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
json_t *j;
|
||||
|
||||
if (key)
|
||||
{
|
||||
j = json_object();
|
||||
json_object_set_new(root, key, j);
|
||||
} else {
|
||||
j = root;
|
||||
}
|
||||
|
||||
json_object_set_new(j, "type", json_string_unreal(tkl_type_config_string(tkl))); // Eg 'kline'
|
||||
json_object_set_new(j, "type_string", json_string_unreal(tkl_type_string(tkl))); // Eg 'Soft K-Line'
|
||||
json_object_set_new(j, "set_by", json_string_unreal(tkl->set_by));
|
||||
json_object_set_new(j, "set_at", json_timestamp(tkl->set_at));
|
||||
json_object_set_new(j, "expire_at", json_timestamp(tkl->expire_at));
|
||||
*buf = '\0';
|
||||
short_date(tkl->set_at, buf);
|
||||
strlcat(buf, " GMT", sizeof(buf));
|
||||
json_object_set_new(j, "set_at_string", json_string_unreal(buf));
|
||||
if (tkl->expire_at <= 0)
|
||||
{
|
||||
json_object_set_new(j, "expire_at_string", json_string_unreal("Never"));
|
||||
json_object_set_new(j, "duration_string", json_string_unreal("permanent"));
|
||||
} else {
|
||||
*buf = '\0';
|
||||
short_date(tkl->expire_at, buf);
|
||||
strlcat(buf, " GMT", sizeof(buf));
|
||||
json_object_set_new(j, "expire_at_string", json_string_unreal(buf));
|
||||
json_object_set_new(j, "duration_string", json_string_unreal(pretty_time_val_r(buf, sizeof(buf), tkl->expire_at - tkl->set_at)));
|
||||
}
|
||||
json_object_set_new(j, "set_at_delta", json_integer(TStime() - tkl->set_at));
|
||||
if (tkl->flags & TKL_FLAG_CONFIG)
|
||||
json_object_set_new(j, "set_in_config", json_boolean(1));
|
||||
if (TKLIsServerBan(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl_uhost(tkl, buf, sizeof(buf), 0)));
|
||||
json_object_set_new(j, "reason", json_string_unreal(tkl->ptr.serverban->reason));
|
||||
} else
|
||||
if (TKLIsNameBan(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl->ptr.nameban->name));
|
||||
json_object_set_new(j, "reason", json_string_unreal(tkl->ptr.nameban->reason));
|
||||
} else
|
||||
if (TKLIsBanException(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl_uhost(tkl, buf, sizeof(buf), 0)));
|
||||
json_object_set_new(j, "reason", json_string_unreal(tkl->ptr.banexception->reason));
|
||||
json_object_set_new(j, "exception_types", json_string_unreal(tkl->ptr.banexception->bantypes));
|
||||
} else
|
||||
if (TKLIsSpamfilter(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl->ptr.spamfilter->match->str));
|
||||
json_object_set_new(j, "match_type", json_string_unreal(unreal_match_method_valtostr(tkl->ptr.spamfilter->match->type)));
|
||||
json_object_set_new(j, "ban_action", json_string_unreal(banact_valtostring(tkl->ptr.spamfilter->action)));
|
||||
json_object_set_new(j, "ban_duration", json_integer(tkl->ptr.spamfilter->tkl_duration));
|
||||
json_object_set_new(j, "ban_duration_string", json_string_unreal(pretty_time_val_r(buf, sizeof(buf), tkl->ptr.spamfilter->tkl_duration)));
|
||||
json_object_set_new(j, "spamfilter_targets", json_string_unreal(spamfilter_target_inttostring(tkl->ptr.spamfilter->target)));
|
||||
json_object_set_new(j, "reason", json_string_unreal(unreal_decodespace(tkl->ptr.spamfilter->tkl_reason)));
|
||||
}
|
||||
}
|
49
src/list.c
49
src/list.c
@ -51,6 +51,7 @@ MODVAR struct list_head server_list; /**< Locally connected servers */
|
||||
MODVAR struct list_head oper_list; /**< Locally connected IRC Operators */
|
||||
MODVAR struct list_head global_server_list; /**< All servers (local and remote) */
|
||||
MODVAR struct list_head dead_list; /**< All dead clients (local and remote) that will soon be freed in the main loop */
|
||||
MODVAR struct list_head rpc_remote_list; /**< All remote RPC clients (very specific use-case) */
|
||||
|
||||
static mp_pool_t *client_pool = NULL;
|
||||
static mp_pool_t *local_client_pool = NULL;
|
||||
@ -75,6 +76,7 @@ void initlists(void)
|
||||
INIT_LIST_HEAD(&control_list);
|
||||
INIT_LIST_HEAD(&global_server_list);
|
||||
INIT_LIST_HEAD(&dead_list);
|
||||
INIT_LIST_HEAD(&rpc_remote_list);
|
||||
|
||||
client_pool = mp_pool_new(sizeof(Client), 512 * 1024);
|
||||
local_client_pool = mp_pool_new(sizeof(LocalClient), 512 * 1024);
|
||||
@ -145,6 +147,19 @@ Client *make_client(Client *from, Client *servr)
|
||||
return client;
|
||||
}
|
||||
|
||||
/** Free the client->rpc struct.
|
||||
* NOTE: if you want to fully free the entire client, call free_client()
|
||||
*/
|
||||
void free_client_rpc(Client *client)
|
||||
{
|
||||
safe_free(client->rpc->rpc_user);
|
||||
safe_free(client->rpc->issuer);
|
||||
if (client->rpc->rehash_request)
|
||||
json_decref(client->rpc->rehash_request);
|
||||
free_log_sources(client->rpc->log_sources);
|
||||
safe_free(client->rpc);
|
||||
}
|
||||
|
||||
void free_client(Client *client)
|
||||
{
|
||||
if (!list_empty(&client->client_node))
|
||||
@ -160,6 +175,19 @@ void free_client(Client *client)
|
||||
RunHook(HOOKTYPE_FREE_CLIENT, client);
|
||||
if (client->local)
|
||||
{
|
||||
if (client->local->listener)
|
||||
{
|
||||
if (client->local->listener && !IsOutgoing(client))
|
||||
{
|
||||
ConfigItem_listen *listener = client->local->listener;
|
||||
listener->clients--;
|
||||
if (listener->flag.temporary && (listener->clients == 0))
|
||||
{
|
||||
/* Call listen cleanup */
|
||||
listen_cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
safe_free(client->local->passwd);
|
||||
safe_free(client->local->error_str);
|
||||
if (client->local->hostp)
|
||||
@ -176,7 +204,10 @@ void free_client(Client *client)
|
||||
del_from_id_hash_table(client->id, client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (client->rpc)
|
||||
free_client_rpc(client);
|
||||
|
||||
safe_free(client->ip);
|
||||
|
||||
mp_pool_release(client);
|
||||
@ -207,8 +238,12 @@ User *make_user(Client *client)
|
||||
} else {
|
||||
*user->realhost = '\0';
|
||||
}
|
||||
user->virthost = NULL;
|
||||
client->user = user;
|
||||
client->user = user;
|
||||
/* These may change later (eg when using hostname instead of IP),
|
||||
* but we now set it early.
|
||||
*/
|
||||
make_cloakedhost(client, client->user->realhost, client->user->cloakedhost, sizeof(client->user->cloakedhost));
|
||||
safe_strdup(client->user->virthost, client->user->cloakedhost);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
@ -309,7 +344,7 @@ void remove_client_from_list(Client *client)
|
||||
|
||||
if (IsUser(client)) /* Only persons can have been added before */
|
||||
{
|
||||
add_history(client, 0);
|
||||
add_history(client, 0, WHOWAS_EVENT_QUIT);
|
||||
off_history(client); /* Remove all pointers to client */
|
||||
}
|
||||
|
||||
@ -590,6 +625,12 @@ NameValuePrioList *find_nvplist(NameValuePrioList *list, const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *get_nvplist(NameValuePrioList *list, const char *name)
|
||||
{
|
||||
NameValuePrioList *e = find_nvplist(list, name);
|
||||
return e ? e->value : NULL;
|
||||
}
|
||||
|
||||
void add_fmt_nvplist(NameValuePrioList **lst, int priority, const char *name, FORMAT_STRING(const char *format), ...)
|
||||
{
|
||||
char value[512];
|
||||
|
491
src/log.c
491
src/log.c
@ -30,6 +30,8 @@
|
||||
// TODO: Make configurable at compile time (runtime won't do, as we haven't read the config file)
|
||||
#define show_event_console 0
|
||||
|
||||
#define MAXLOGLENGTH 16384 /**< Maximum length of a log entry (which may be multiple lines) */
|
||||
|
||||
/* Variables */
|
||||
Log *logs[NUM_LOG_DESTINATIONS] = { NULL, NULL, NULL, NULL, NULL };
|
||||
Log *temp_logs[NUM_LOG_DESTINATIONS] = { NULL, NULL, NULL, NULL, NULL };
|
||||
@ -43,59 +45,6 @@ int log_sources_match(LogSource *logsource, LogLevel loglevel, const char *subsy
|
||||
void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char *event_id, Client *client, int expand_msg, const char *msg, va_list vl);
|
||||
void log_blocks_switchover(void);
|
||||
|
||||
/** Calculate expansion of a JSON string thanks to double escaping.
|
||||
* orig => JSON => IRC
|
||||
* " => \" => \\"
|
||||
* \ => \\ => \\\\
|
||||
*/
|
||||
int json_dump_string_length(const char *s)
|
||||
{
|
||||
int len = 0;
|
||||
for (; *s; s++)
|
||||
{
|
||||
if (*s == '\\')
|
||||
len += 4;
|
||||
else if (*s == '"')
|
||||
len += 3;
|
||||
else
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Convert a regular string value to a JSON string.
|
||||
* In UnrealIRCd, this must be used instead of json_string()
|
||||
* as we may use non-UTF8 sequences. Also, this takes care
|
||||
* of using json_null() if the string was NULL, which is
|
||||
* usually what we want as well.
|
||||
* @param s Input string
|
||||
* @returns a json string value or json null value.
|
||||
*/
|
||||
json_t *json_string_unreal(const char *s)
|
||||
{
|
||||
char buf1[512], buf2[512];
|
||||
char *verified_s;
|
||||
const char *stripped;
|
||||
|
||||
if (s == NULL)
|
||||
return json_null();
|
||||
|
||||
stripped = StripControlCodesEx(s, buf1, sizeof(buf1), UNRL_STRIP_LOW_ASCII|UNRL_STRIP_KEEP_LF);
|
||||
verified_s = unrl_utf8_make_valid(buf1, buf2, sizeof(buf2), 0);
|
||||
|
||||
return json_string(verified_s);
|
||||
}
|
||||
|
||||
#define json_string __BAD___DO__NOT__USE__JSON__STRING__PLZ
|
||||
|
||||
json_t *json_timestamp(time_t v)
|
||||
{
|
||||
const char *ts = timestamp_iso8601(v);
|
||||
if (ts)
|
||||
return json_string_unreal(ts);
|
||||
return json_null();
|
||||
}
|
||||
|
||||
LogType log_type_stringtoval(const char *str)
|
||||
{
|
||||
if (!strcmp(str, "json"))
|
||||
@ -118,6 +67,18 @@ const char *log_type_valtostring(LogType v)
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks if 'v' is a valid loglevel */
|
||||
int valid_loglevel(int v)
|
||||
{
|
||||
if ((v == ULOG_DEBUG) || (v == ULOG_INFO) ||
|
||||
(v == ULOG_WARNING) || (v == ULOG_ERROR) ||
|
||||
(v == ULOG_FATAL))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***** CONFIGURATION ******/
|
||||
|
||||
LogSource *add_log_source(const char *str)
|
||||
@ -511,273 +472,6 @@ int config_run_log(ConfigFile *conf, ConfigEntry *block)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***** RUNTIME *****/
|
||||
|
||||
void json_expand_client_security_groups(json_t *parent, Client *client)
|
||||
{
|
||||
SecurityGroup *s;
|
||||
json_t *child = json_array();
|
||||
json_object_set_new(parent, "security-groups", child);
|
||||
|
||||
/* We put known-users or unknown-users at the beginning.
|
||||
* The latter is special and doesn't actually exist
|
||||
* in the linked list, hence the special code here,
|
||||
* and again later in the for loop to skip it.
|
||||
*/
|
||||
if (user_allowed_by_security_group_name(client, "known-users"))
|
||||
json_array_append_new(child, json_string_unreal("known-users"));
|
||||
else
|
||||
json_array_append_new(child, json_string_unreal("unknown-users"));
|
||||
|
||||
for (s = securitygroups; s; s = s->next)
|
||||
if (strcmp(s->name, "known-users") && user_allowed_by_security_group(client, s))
|
||||
json_array_append_new(child, json_string_unreal(s->name));
|
||||
}
|
||||
|
||||
void json_expand_client(json_t *j, const char *key, Client *client, int detail)
|
||||
{
|
||||
char buf[BUFSIZE+1];
|
||||
json_t *child = json_object();
|
||||
json_t *user = NULL;
|
||||
json_object_set_new(j, key, child);
|
||||
|
||||
/* First the information that is available for ALL client types: */
|
||||
|
||||
json_object_set_new(child, "name", json_string_unreal(client->name));
|
||||
json_object_set_new(child, "id", json_string_unreal(client->id));
|
||||
|
||||
/* hostname is available for all, it just depends a bit on whether it is DNS or IP */
|
||||
if (client->user && *client->user->realhost)
|
||||
json_object_set_new(child, "hostname", json_string_unreal(client->user->realhost));
|
||||
else if (client->local && *client->local->sockhost)
|
||||
json_object_set_new(child, "hostname", json_string_unreal(client->local->sockhost));
|
||||
else
|
||||
json_object_set_new(child, "hostname", json_string_unreal(GetIP(client)));
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
if (client->user)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s!%s@%s", client->name, client->user->username, client->user->realhost);
|
||||
json_object_set_new(child, "details", json_string_unreal(buf));
|
||||
} else if (client->ip) {
|
||||
if (*client->name)
|
||||
snprintf(buf, sizeof(buf), "%s@%s", client->name, client->ip);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "[%s]", client->ip);
|
||||
json_object_set_new(child, "details", json_string_unreal(buf));
|
||||
} else {
|
||||
json_object_set_new(child, "details", json_string_unreal(client->name));
|
||||
}
|
||||
|
||||
if (client->local && client->local->creationtime)
|
||||
json_object_set_new(child, "connected_since", json_timestamp(client->local->creationtime));
|
||||
|
||||
if (client->local && client->local->idle_since)
|
||||
json_object_set_new(child, "idle_since", json_timestamp(client->local->idle_since));
|
||||
|
||||
if (client->user)
|
||||
{
|
||||
char buf[512];
|
||||
const char *str;
|
||||
/* client.user */
|
||||
user = json_object();
|
||||
json_object_set_new(child, "user", user);
|
||||
|
||||
json_object_set_new(user, "username", json_string_unreal(client->user->username));
|
||||
if (!BadPtr(client->info))
|
||||
json_object_set_new(user, "realname", json_string_unreal(client->info));
|
||||
if (has_user_mode(client, 'x') && client->user->virthost && strcmp(client->user->virthost, client->user->realhost))
|
||||
json_object_set_new(user, "vhost", json_string_unreal(client->user->virthost));
|
||||
if (*client->user->cloakedhost)
|
||||
json_object_set_new(user, "cloakedhost", json_string_unreal(client->user->cloakedhost));
|
||||
if (client->uplink)
|
||||
json_object_set_new(user, "servername", json_string_unreal(client->uplink->name));
|
||||
if (IsLoggedIn(client))
|
||||
json_object_set_new(user, "account", json_string_unreal(client->user->account));
|
||||
json_object_set_new(user, "reputation", json_integer(GetReputation(client)));
|
||||
json_expand_client_security_groups(user, client);
|
||||
|
||||
/* user modes and snomasks */
|
||||
get_usermode_string_r(client, buf, sizeof(buf));
|
||||
json_object_set_new(user, "modes", json_string_unreal(buf+1));
|
||||
if (client->user->snomask)
|
||||
json_object_set_new(user, "snomasks", json_string_unreal(client->user->snomask));
|
||||
|
||||
/* if oper then we can possibly expand a bit more */
|
||||
str = get_operlogin(client);
|
||||
if (str)
|
||||
json_object_set_new(user, "operlogin", json_string_unreal(str));
|
||||
str = get_operclass(client);
|
||||
if (str)
|
||||
json_object_set_new(user, "operclass", json_string_unreal(str));
|
||||
if (client->user->channel)
|
||||
{
|
||||
Membership *m;
|
||||
int cnt = 0;
|
||||
int len = 0;
|
||||
json_t *channels = json_array();
|
||||
json_object_set_new(user, "channels", channels);
|
||||
for (m = client->user->channel; m; m = m->next)
|
||||
{
|
||||
len += json_dump_string_length(m->channel->name);
|
||||
if (len > 384)
|
||||
{
|
||||
/* Truncated */
|
||||
json_array_append_new(channels, json_string_unreal("..."));
|
||||
break;
|
||||
}
|
||||
json_array_append_new(channels, json_string_unreal(m->channel->name));
|
||||
}
|
||||
}
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT_USER, client, detail, child, user);
|
||||
} else
|
||||
if (IsMe(client))
|
||||
{
|
||||
json_t *server = json_object();
|
||||
json_t *features;
|
||||
|
||||
/* client.server */
|
||||
json_object_set_new(child, "server", server);
|
||||
|
||||
if (!BadPtr(client->info))
|
||||
json_object_set_new(server, "info", json_string_unreal(client->info));
|
||||
json_object_set_new(server, "num_users", json_integer(client->server->users));
|
||||
json_object_set_new(server, "boot_time", json_timestamp(client->server->boottime));
|
||||
} else
|
||||
if (IsServer(client) && client->server)
|
||||
{
|
||||
/* client.server */
|
||||
|
||||
/* Whenever a server is expanded, which is rare,
|
||||
* we should probably expand as much as info as possible:
|
||||
*/
|
||||
json_t *server = json_object();
|
||||
json_t *features;
|
||||
|
||||
/* client.server */
|
||||
json_object_set_new(child, "server", server);
|
||||
if (!BadPtr(client->info))
|
||||
json_object_set_new(server, "info", json_string_unreal(client->info));
|
||||
if (client->uplink)
|
||||
json_object_set_new(server, "uplink", json_string_unreal(client->uplink->name));
|
||||
json_object_set_new(server, "num_users", json_integer(client->server->users));
|
||||
json_object_set_new(server, "boot_time", json_timestamp(client->server->boottime));
|
||||
json_object_set_new(server, "synced", json_boolean(client->server->flags.synced));
|
||||
|
||||
/* client.server.features */
|
||||
features = json_object();
|
||||
json_object_set_new(server, "features", features);
|
||||
if (!BadPtr(client->server->features.software))
|
||||
json_object_set_new(features, "software", json_string_unreal(client->server->features.software));
|
||||
json_object_set_new(features, "protocol", json_integer(client->server->features.protocol));
|
||||
if (!BadPtr(client->server->features.usermodes))
|
||||
json_object_set_new(features, "usermodes", json_string_unreal(client->server->features.usermodes));
|
||||
if (!BadPtr(client->server->features.chanmodes[0]))
|
||||
{
|
||||
/* client.server.features.chanmodes (array) */
|
||||
int i;
|
||||
json_t *chanmodes = json_array();
|
||||
json_object_set_new(features, "chanmodes", chanmodes);
|
||||
for (i=0; i < 4; i++)
|
||||
json_array_append_new(chanmodes, json_string_unreal(client->server->features.chanmodes[i]));
|
||||
}
|
||||
if (!BadPtr(client->server->features.nickchars))
|
||||
json_object_set_new(features, "nick_character_sets", json_string_unreal(client->server->features.nickchars));
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT_SERVER, client, detail, child, server);
|
||||
}
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CLIENT, client, detail, child);
|
||||
}
|
||||
|
||||
void json_expand_channel(json_t *j, const char *key, Channel *channel, int detail)
|
||||
{
|
||||
char mode1[512], mode2[512], modes[512];
|
||||
|
||||
json_t *child = json_object();
|
||||
json_object_set_new(j, key, child);
|
||||
json_object_set_new(child, "name", json_string_unreal(channel->name));
|
||||
json_object_set_new(child, "creation_time", json_timestamp(channel->creationtime));
|
||||
json_object_set_new(child, "num_users", json_integer(channel->users));
|
||||
if (channel->topic)
|
||||
{
|
||||
json_object_set_new(child, "topic", json_string_unreal(channel->topic));
|
||||
json_object_set_new(child, "topic_set_by", json_string_unreal(channel->topic_nick));
|
||||
json_object_set_new(child, "topic_set_at", json_timestamp(channel->topic_time));
|
||||
}
|
||||
|
||||
/* Add "mode" too */
|
||||
channel_modes(NULL, mode1, mode2, sizeof(mode1), sizeof(mode2), channel, 0);
|
||||
if (*mode2)
|
||||
{
|
||||
snprintf(modes, sizeof(modes), "%s %s", mode1+1, mode2);
|
||||
json_object_set_new(child, "modes", json_string_unreal(modes));
|
||||
} else {
|
||||
json_object_set_new(child, "modes", json_string_unreal(mode1+1));
|
||||
}
|
||||
|
||||
// Possibly later: If detail is set to 1 then expand more...
|
||||
RunHook(HOOKTYPE_JSON_EXPAND_CHANNEL, channel, detail, child);
|
||||
}
|
||||
|
||||
const char *timestamp_iso8601_now(void)
|
||||
{
|
||||
struct timeval t;
|
||||
struct tm *tm;
|
||||
time_t sec;
|
||||
static char buf[64];
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
sec = t.tv_sec;
|
||||
tm = gmtime(&sec);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec,
|
||||
(int)(t.tv_usec / 1000));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *timestamp_iso8601(time_t v)
|
||||
{
|
||||
struct tm *tm;
|
||||
static char buf[64];
|
||||
|
||||
if (v == 0)
|
||||
return NULL;
|
||||
|
||||
tm = gmtime(&v);
|
||||
|
||||
if (tm == NULL)
|
||||
return NULL;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec,
|
||||
0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
LogData *log_data_string(const char *key, const char *str)
|
||||
{
|
||||
LogData *d = safe_alloc(sizeof(LogData));
|
||||
@ -963,51 +657,7 @@ LogData *log_data_tkl(const char *key, TKL *tkl)
|
||||
safe_strdup(d->key, key);
|
||||
d->value.object = j = json_object();
|
||||
|
||||
json_object_set_new(j, "type", json_string_unreal(tkl_type_config_string(tkl))); // Eg 'kline'
|
||||
json_object_set_new(j, "type_string", json_string_unreal(tkl_type_string(tkl))); // Eg 'Soft K-Line'
|
||||
json_object_set_new(j, "set_by", json_string_unreal(tkl->set_by));
|
||||
json_object_set_new(j, "set_at", json_timestamp(tkl->set_at));
|
||||
json_object_set_new(j, "expire_at", json_timestamp(tkl->expire_at));
|
||||
*buf = '\0';
|
||||
short_date(tkl->set_at, buf);
|
||||
strlcat(buf, " GMT", sizeof(buf));
|
||||
json_object_set_new(j, "set_at_string", json_string_unreal(buf));
|
||||
if (tkl->expire_at <= 0)
|
||||
{
|
||||
json_object_set_new(j, "expire_at_string", json_string_unreal("Never"));
|
||||
json_object_set_new(j, "duration_string", json_string_unreal("permanent"));
|
||||
} else {
|
||||
*buf = '\0';
|
||||
short_date(tkl->expire_at, buf);
|
||||
strlcat(buf, " GMT", sizeof(buf));
|
||||
json_object_set_new(j, "expire_at_string", json_string_unreal(buf));
|
||||
json_object_set_new(j, "duration_string", json_string_unreal(pretty_time_val_r(buf, sizeof(buf), tkl->expire_at - tkl->set_at)));
|
||||
}
|
||||
json_object_set_new(j, "set_at_delta", json_integer(TStime() - tkl->set_at));
|
||||
if (TKLIsServerBan(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl_uhost(tkl, buf, sizeof(buf), 0)));
|
||||
json_object_set_new(j, "reason", json_string_unreal(tkl->ptr.serverban->reason));
|
||||
} else
|
||||
if (TKLIsNameBan(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl->ptr.nameban->name));
|
||||
json_object_set_new(j, "reason", json_string_unreal(tkl->ptr.nameban->reason));
|
||||
} else
|
||||
if (TKLIsBanException(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl_uhost(tkl, buf, sizeof(buf), 0)));
|
||||
json_object_set_new(j, "reason", json_string_unreal(tkl->ptr.banexception->reason));
|
||||
json_object_set_new(j, "exception_types", json_string_unreal(tkl->ptr.banexception->bantypes));
|
||||
} else
|
||||
if (TKLIsSpamfilter(tkl))
|
||||
{
|
||||
json_object_set_new(j, "name", json_string_unreal(tkl->ptr.spamfilter->match->str));
|
||||
json_object_set_new(j, "match_type", json_string_unreal(unreal_match_method_valtostr(tkl->ptr.spamfilter->match->type)));
|
||||
json_object_set_new(j, "ban_action", json_string_unreal(banact_valtostring(tkl->ptr.spamfilter->action)));
|
||||
json_object_set_new(j, "spamfilter_targets", json_string_unreal(spamfilter_target_inttostring(tkl->ptr.spamfilter->target)));
|
||||
json_object_set_new(j, "reason", json_string_unreal(unreal_decodespace(tkl->ptr.spamfilter->tkl_reason)));
|
||||
}
|
||||
json_expand_tkl(j, NULL, tkl, 1);
|
||||
|
||||
return d;
|
||||
}
|
||||
@ -1111,22 +761,6 @@ int valid_subsystem(const char *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *json_get_value(json_t *t)
|
||||
{
|
||||
static char buf[32];
|
||||
|
||||
if (json_is_string(t))
|
||||
return json_string_value(t);
|
||||
|
||||
if (json_is_integer(t))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%lld", (long long)json_integer_value(t));
|
||||
return buf;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: if in the function below we keep adding auto expanshion shit,
|
||||
// like we currently have $client automatically expanding to $client.name
|
||||
// and $socket_error to $socket_error.error_string,
|
||||
@ -1246,9 +880,9 @@ 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, Client *from_server)
|
||||
void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, json_t *json, const char *json_serialized, Client *from_server)
|
||||
{
|
||||
static int last_log_file_warning = 0;
|
||||
static time_t last_log_file_warning = 0;
|
||||
Log *l;
|
||||
char timebuf[128];
|
||||
struct stat fstats;
|
||||
@ -1259,7 +893,7 @@ void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *ev
|
||||
|
||||
snprintf(timebuf, sizeof(timebuf), "[%s] ", myctime(TStime()));
|
||||
|
||||
RunHook(HOOKTYPE_LOG, loglevel, subsystem, event_id, msg, json_serialized, timebuf);
|
||||
RunHook(HOOKTYPE_LOG, loglevel, subsystem, event_id, msg, json, json_serialized, timebuf);
|
||||
|
||||
if (!loop.forked && (loglevel > ULOG_DEBUG))
|
||||
{
|
||||
@ -1366,17 +1000,27 @@ void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *ev
|
||||
l->logfd = fd_fileopen(l->file, O_CREAT|O_APPEND|O_WRONLY);
|
||||
if (l->logfd == -1)
|
||||
{
|
||||
if (!loop.booted)
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
config_status("WARNING: Unable to write to '%s': %s", l->file, strerror(errno));
|
||||
} else {
|
||||
if (last_log_file_warning + 300 < TStime())
|
||||
{
|
||||
config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", l->file, strerror(errno));
|
||||
last_log_file_warning = TStime();
|
||||
}
|
||||
/* Create directory structure and retry */
|
||||
unreal_create_directory_structure_for_file(l->file, 0777);
|
||||
l->logfd = fd_fileopen(l->file, O_CREAT|O_APPEND|O_WRONLY);
|
||||
}
|
||||
if (l->logfd == -1)
|
||||
{
|
||||
/* Still failed! */
|
||||
if (!loop.booted)
|
||||
{
|
||||
config_status("WARNING: Unable to write to '%s': %s", l->file, strerror(errno));
|
||||
} else {
|
||||
if (last_log_file_warning + 300 < TStime())
|
||||
{
|
||||
config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", l->file, strerror(errno));
|
||||
last_log_file_warning = TStime();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1397,7 +1041,7 @@ void do_unreal_log_disk(LogLevel loglevel, const char *subsystem, const char *ev
|
||||
{
|
||||
for (m = msg; m; m = m->next)
|
||||
{
|
||||
char text_buf[8192];
|
||||
static char text_buf[MAXLOGLENGTH];
|
||||
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);
|
||||
@ -1686,7 +1330,7 @@ void do_unreal_log_remote(LogLevel loglevel, const char *subsystem, const char *
|
||||
}
|
||||
|
||||
/** 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)
|
||||
void do_unreal_log_control(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, json_t *j, const char *json_serialized, Client *from_server)
|
||||
{
|
||||
Client *client;
|
||||
MultiLine *m;
|
||||
@ -1699,9 +1343,16 @@ void do_unreal_log_control(LogLevel loglevel, const char *subsystem, const char
|
||||
return;
|
||||
|
||||
list_for_each_entry(client, &control_list, lclient_node)
|
||||
if (IsMonitorRehash(client))
|
||||
if (IsMonitorRehash(client) && IsControl(client))
|
||||
for (m = msg; m; m = m->next)
|
||||
sendto_one(client, NULL, "REPLY [%s] %s", log_level_valtostring(loglevel), m->line);
|
||||
|
||||
if (json_rehash_log)
|
||||
{
|
||||
json_t *log = json_object_get(json_rehash_log, "log");
|
||||
if (log)
|
||||
json_array_append(log, j); // not xxx_new, right?
|
||||
}
|
||||
}
|
||||
|
||||
void do_unreal_log_free_args(va_list vl)
|
||||
@ -1777,11 +1428,14 @@ void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char
|
||||
json_t *j = NULL;
|
||||
json_t *j_details = NULL;
|
||||
json_t *t;
|
||||
char msgbuf[8192];
|
||||
char msgbuf[MAXLOGLENGTH];
|
||||
const char *loglevel_string = log_level_valtostring(loglevel);
|
||||
MultiLine *mmsg;
|
||||
Client *from_server = NULL;
|
||||
|
||||
/* Set flag so json_string_unreal() uses more strict filter */
|
||||
log_json_filter = 1;
|
||||
|
||||
if (loglevel_string == NULL)
|
||||
{
|
||||
do_unreal_log_norecursioncheck(ULOG_ERROR, "log", "BUG_LOG_LOGLEVEL", NULL,
|
||||
@ -1826,7 +1480,7 @@ void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char
|
||||
* details later on.
|
||||
*/
|
||||
if (client)
|
||||
json_expand_client(j_details, "client", client, 0);
|
||||
json_expand_client(j_details, "client", client, 3);
|
||||
/* Additional details (if any) */
|
||||
while ((d = va_arg(vl, LogData *)))
|
||||
{
|
||||
@ -1842,10 +1496,10 @@ void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char
|
||||
json_object_set_new(j_details, d->key, json_null());
|
||||
break;
|
||||
case LOG_FIELD_CLIENT:
|
||||
json_expand_client(j_details, d->key, d->value.client, 0);
|
||||
json_expand_client(j_details, d->key, d->value.client, 3);
|
||||
break;
|
||||
case LOG_FIELD_CHANNEL:
|
||||
json_expand_channel(j_details, d->key, d->value.channel, 0);
|
||||
json_expand_channel(j_details, d->key, d->value.channel, 1);
|
||||
break;
|
||||
case LOG_FIELD_OBJECT:
|
||||
json_object_set_new(j_details, d->key, d->value.object);
|
||||
@ -1884,10 +1538,10 @@ void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char
|
||||
|
||||
/* Now call all the loggers: */
|
||||
|
||||
do_unreal_log_disk(loglevel, subsystem, event_id, mmsg, json_serialized, from_server);
|
||||
do_unreal_log_disk(loglevel, subsystem, event_id, mmsg, j, 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_control(loglevel, subsystem, event_id, mmsg, j, json_serialized, from_server);
|
||||
|
||||
do_unreal_log_opers(loglevel, subsystem, event_id, mmsg, json_serialized, from_server);
|
||||
|
||||
@ -1897,27 +1551,52 @@ void do_unreal_log_internal(LogLevel loglevel, const char *subsystem, const char
|
||||
|
||||
// NOTE: code duplication further down!
|
||||
|
||||
/* This one should only be in do_unreal_log_internal()
|
||||
* and never in do_unreal_log_internal_from_remote()
|
||||
*/
|
||||
if (remote_rehash_client &&
|
||||
((!strcmp(event_id, "CONFIG_ERROR_GENERIC") ||
|
||||
!strcmp(event_id, "CONFIG_WARNING_GENERIC") ||
|
||||
!strcmp(event_id, "CONFIG_INFO_GENERIC"))
|
||||
||
|
||||
(loop.config_status >= CONFIG_STATUS_TEST)) &&
|
||||
strcmp(subsystem, "rawtraffic"))
|
||||
{
|
||||
sendto_log(remote_rehash_client, "NOTICE", remote_rehash_client->name,
|
||||
iConf.server_notice_colors, iConf.server_notice_show_event,
|
||||
loglevel, subsystem, event_id, mmsg, json_serialized, from_server);
|
||||
}
|
||||
|
||||
/* Free everything */
|
||||
safe_free(json_serialized);
|
||||
safe_free_multiline(mmsg);
|
||||
json_decref(j_details);
|
||||
json_decref(j);
|
||||
|
||||
/* Turn off flag again */
|
||||
log_json_filter = 0;
|
||||
}
|
||||
|
||||
void do_unreal_log_internal_from_remote(LogLevel loglevel, const char *subsystem, const char *event_id,
|
||||
MultiLine *msg, const char *json_serialized, Client *from_server)
|
||||
MultiLine *msg, json_t *json, const char *json_serialized, Client *from_server)
|
||||
{
|
||||
if (unreal_log_recursion_trap)
|
||||
return;
|
||||
unreal_log_recursion_trap = 1;
|
||||
|
||||
/* Set flag so json_string_unreal() uses more strict filter */
|
||||
log_json_filter = 1;
|
||||
|
||||
/* Call the disk loggers */
|
||||
do_unreal_log_disk(loglevel, subsystem, event_id, msg, json_serialized, from_server);
|
||||
do_unreal_log_disk(loglevel, subsystem, event_id, msg, json, json_serialized, from_server);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Turn off flag again */
|
||||
log_json_filter = 0;
|
||||
|
||||
unreal_log_recursion_trap = 0;
|
||||
}
|
||||
|
||||
@ -1943,7 +1622,7 @@ void free_log_block(Log *l)
|
||||
|
||||
int log_tests(void)
|
||||
{
|
||||
if (snomask_num_destinations <= 1)
|
||||
if (snomask_num_destinations == 0)
|
||||
{
|
||||
unreal_log(ULOG_ERROR, "config", "LOG_SNOMASK_BLOCK_MISSING", NULL,
|
||||
"Missing snomask logging configuration:\n"
|
||||
@ -1951,7 +1630,6 @@ int log_tests(void)
|
||||
"include \"snomasks.default.conf\";");
|
||||
return 0;
|
||||
}
|
||||
snomask_num_destinations = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -2000,6 +1678,7 @@ void postconf_defaults_log_block(void)
|
||||
void log_pre_rehash(void)
|
||||
{
|
||||
*snomasks_in_use_testing = '\0';
|
||||
snomask_num_destinations = 0;
|
||||
}
|
||||
|
||||
/* Called after CONFIG_TEST right before CONFIG_RUN */
|
||||
|
@ -134,7 +134,7 @@
|
||||
</button>
|
||||
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fya-YD-1uu">
|
||||
<rect key="frame" x="132" y="88" width="274" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Automatically start Unreal Agent on login" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="VUc-0Q-Rwf">
|
||||
<buttonCell key="cell" type="check" title="Automatically start UnrealIRCd Agent on login" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="VUc-0Q-Rwf">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
|
@ -405,7 +405,10 @@ Match *unreal_create_match(MatchType type, const char *str, char **error)
|
||||
int options = 0;
|
||||
char buf2[512];
|
||||
|
||||
options = PCRE2_CASELESS|PCRE2_NEVER_UTF|PCRE2_NEVER_UCP;
|
||||
if (iConf.spamfilter_utf8)
|
||||
options = PCRE2_CASELESS|PCRE2_MATCH_INVALID_UTF;
|
||||
else
|
||||
options = PCRE2_CASELESS|PCRE2_NEVER_UTF|PCRE2_NEVER_UCP;
|
||||
|
||||
m->ext.pcre2_expr = pcre2_compile(str, PCRE2_ZERO_TERMINATED, options, &errorcode, &erroroffset, NULL);
|
||||
if (m->ext.pcre2_expr == NULL)
|
||||
|
194
src/misc.c
194
src/misc.c
@ -471,7 +471,10 @@ static void exit_one_client(Client *client, MessageTag *mtags_i, const char *com
|
||||
RunHook(HOOKTYPE_REMOTE_QUIT, client, mtags_i, comment);
|
||||
|
||||
new_message_special(client, mtags_i, &mtags_o, ":%s QUIT", client->name);
|
||||
sendto_local_common_channels(client, NULL, 0, mtags_o, ":%s QUIT :%s", client->name, comment);
|
||||
if (find_mtag(mtags_o, "unrealircd.org/real-quit-reason"))
|
||||
quit_sendto_local_common_channels(client, mtags_o, comment);
|
||||
else
|
||||
sendto_local_common_channels(client, NULL, 0, mtags_o, ":%s QUIT :%s", client->name, comment);
|
||||
free_message_tags(mtags_o);
|
||||
|
||||
while ((mp = client->user->channel))
|
||||
@ -594,17 +597,6 @@ void exit_client_ex(Client *client, Client *origin, MessageTag *recv_mtags, cons
|
||||
}
|
||||
}
|
||||
free_pending_net(client);
|
||||
if (client->local->listener)
|
||||
if (client->local->listener && !IsOutgoing(client))
|
||||
{
|
||||
listen_conf = client->local->listener;
|
||||
listen_conf->clients--;
|
||||
if (listen_conf->flag.temporary && (listen_conf->clients == 0))
|
||||
{
|
||||
/* Call listen cleanup */
|
||||
listen_cleanup();
|
||||
}
|
||||
}
|
||||
SetClosing(client);
|
||||
if (IsUser(client))
|
||||
{
|
||||
@ -623,7 +615,7 @@ void exit_client_ex(Client *client, Client *origin, MessageTag *recv_mtags, cons
|
||||
|
||||
if (client->local->fd >= 0 && !IsConnecting(client))
|
||||
{
|
||||
if (!IsControl(client))
|
||||
if (!IsControl(client) && !IsRPC(client))
|
||||
sendto_one(client, NULL, "ERROR :Closing Link: %s (%s)", get_client_name(client, FALSE), comment);
|
||||
}
|
||||
close_connection(client);
|
||||
@ -648,6 +640,7 @@ void exit_client_ex(Client *client, Client *origin, MessageTag *recv_mtags, cons
|
||||
if (IsServer(client))
|
||||
{
|
||||
char splitstr[HOSTLEN + HOSTLEN + 2];
|
||||
Client *acptr, *next;
|
||||
|
||||
assert(client->server != NULL && client->uplink != NULL);
|
||||
|
||||
@ -658,6 +651,11 @@ void exit_client_ex(Client *client, Client *origin, MessageTag *recv_mtags, cons
|
||||
|
||||
remove_dependents(client, origin, recv_mtags, comment, splitstr);
|
||||
|
||||
/* Special case for remote async RPC, server.rehash in particular.. */
|
||||
list_for_each_entry_safe(acptr, next, &rpc_remote_list, client_node)
|
||||
if (!strncmp(client->id, acptr->id, SIDLEN))
|
||||
free_client(acptr);
|
||||
|
||||
RunHook(HOOKTYPE_SERVER_QUIT, client, recv_mtags);
|
||||
}
|
||||
else if (IsUser(client) && !IsKilled(client))
|
||||
@ -733,6 +731,54 @@ int valid_host(const char *host, int strict)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Check if the specified ident / user name does not contain forbidden characters.
|
||||
* @param username The username / ident to check
|
||||
* @returns 1 if valid, 0 if not.
|
||||
*/
|
||||
int valid_username(const char *username)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
if (strlen(username) > USERLEN)
|
||||
return 0; /* Too long */
|
||||
|
||||
for (s = username; *s; s++)
|
||||
{
|
||||
if ((*s == '~') && (s == username))
|
||||
continue;
|
||||
if (!isallowed(*s))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Check validity of a vhost which can be both in 'host' or 'user@host' format.
|
||||
* This will call valid_username() and valid_host(xxx, 0) accordingly.
|
||||
* @param userhost the "host" or "user@host"
|
||||
* @returns 1 if valid, 0 if not.
|
||||
*/
|
||||
int valid_vhost(const char *userhost)
|
||||
{
|
||||
char uhost[512], *p;
|
||||
const char *host = userhost;
|
||||
|
||||
strlcpy(uhost, userhost, sizeof(uhost));
|
||||
|
||||
if ((p = strchr(uhost, '@')))
|
||||
{
|
||||
*p++ = '\0';
|
||||
if (!valid_username(uhost))
|
||||
return 0;
|
||||
host = p;
|
||||
}
|
||||
|
||||
if (!valid_host(host, 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*|| BAN ACTION ROUTINES FOLLOW ||*/
|
||||
|
||||
/** Converts a banaction string (eg: "kill") to an integer value (eg: BAN_ACT_KILL) */
|
||||
@ -832,9 +878,10 @@ char *spamfilter_target_inttostring(int v)
|
||||
/** Replace underscores back to the space character.
|
||||
* This is used for the spamfilter reason.
|
||||
*/
|
||||
char *unreal_decodespace(char *s)
|
||||
char *unreal_decodespace(const char *s)
|
||||
{
|
||||
static char buf[512], *i, *o;
|
||||
const char *i;
|
||||
static char buf[512], *o;
|
||||
|
||||
for (i = s, o = buf; (*i) && (o < buf+510); i++)
|
||||
if (*i == '_')
|
||||
@ -855,9 +902,10 @@ char *unreal_decodespace(char *s)
|
||||
/** Replace spaces to underscore characters.
|
||||
* This is used for the spamfilter reason.
|
||||
*/
|
||||
char *unreal_encodespace(char *s)
|
||||
char *unreal_encodespace(const char *s)
|
||||
{
|
||||
static char buf[512], *i, *o;
|
||||
const char *i;
|
||||
static char buf[512], *o;
|
||||
|
||||
if (!s)
|
||||
return NULL; /* NULL in = NULL out */
|
||||
@ -1113,9 +1161,10 @@ void banned_client(Client *client, const char *bantype, const char *reason, int
|
||||
char buf[512];
|
||||
char *fmt = global ? iConf.reject_message_gline : iConf.reject_message_kline;
|
||||
const char *vars[6], *values[6];
|
||||
MessageTag *mtags = NULL;
|
||||
|
||||
if (!MyConnect(client))
|
||||
abort(); /* hmm... or be more flexible? */
|
||||
abort();
|
||||
|
||||
/* This was: "You are not welcome on this %s. %s: %s. %s" but is now dynamic: */
|
||||
vars[0] = "bantype";
|
||||
@ -1154,18 +1203,28 @@ void banned_client(Client *client, const char *bantype, const char *reason, int
|
||||
|
||||
/* The final message in the ERROR is shorter. */
|
||||
if (HIDE_BAN_REASON && IsRegistered(client))
|
||||
snprintf(buf, sizeof(buf), "Banned (%s)", bantype);
|
||||
else
|
||||
{
|
||||
/* Hide the ban reason, but put the real reason in unrealircd.org/real-quit-reason */
|
||||
MessageTag *m = safe_alloc(sizeof(MessageTag));
|
||||
safe_strdup(m->name, "unrealircd.org/real-quit-reason");
|
||||
snprintf(buf, sizeof(buf), "Banned (%s): %s", bantype, reason);
|
||||
safe_strdup(m->value, buf);
|
||||
AddListItem(m, mtags);
|
||||
/* And the quit reason for anyone else, goes here.. */
|
||||
snprintf(buf, sizeof(buf), "Banned (%s)", bantype);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Banned (%s): %s", bantype, reason);
|
||||
}
|
||||
|
||||
if (noexit != NO_EXIT_CLIENT)
|
||||
{
|
||||
exit_client(client, NULL, buf);
|
||||
exit_client(client, mtags, buf);
|
||||
} else {
|
||||
/* Special handling for direct Z-line code */
|
||||
send_raw_direct(client, "ERROR :Closing Link: [%s] (%s)",
|
||||
client->ip, buf);
|
||||
}
|
||||
safe_free_message_tags(mtags);
|
||||
}
|
||||
|
||||
/** Our stpcpy implementation - discouraged due to lack of bounds checking */
|
||||
@ -1395,6 +1454,77 @@ int make_oper_default_handler(Client *client, const char *operblock_name, const
|
||||
return 0;
|
||||
}
|
||||
|
||||
void webserver_send_response_default_handler(Client *client, int status, char *msg)
|
||||
{
|
||||
}
|
||||
|
||||
void webserver_close_client_default_handler(Client *client)
|
||||
{
|
||||
}
|
||||
|
||||
int webserver_handle_body_default_handler(Client *client, WebRequest *web, const char *readbuf, int length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rpc_response_default_handler(Client *client, json_t *request, json_t *result)
|
||||
{
|
||||
}
|
||||
|
||||
void rpc_error_default_handler(Client *client, json_t *request, JsonRpcError error_code, const char *error_message)
|
||||
{
|
||||
}
|
||||
|
||||
void rpc_error_fmt_default_handler(Client *client, json_t *request, JsonRpcError error_code, const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void rpc_send_request_to_remote_default_handler(Client *source, Client *target, json_t *request)
|
||||
{
|
||||
}
|
||||
|
||||
void rpc_send_response_to_remote_default_handler(Client *source, Client *target, json_t *response)
|
||||
{
|
||||
}
|
||||
|
||||
int rrpc_supported_simple_default_handler(Client *target, char **problem_server)
|
||||
{
|
||||
if (problem_server)
|
||||
*problem_server = me.name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rrpc_supported_default_handler(Client *target, const char *module, const char *minimum_version, char **problem_server)
|
||||
{
|
||||
if (problem_server)
|
||||
*problem_server = me.name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int websocket_handle_websocket_default_handler(Client *client, WebRequest *web, const char *readbuf2, int length2, int callback(Client *client, char *buf, int len))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int websocket_create_packet_default_handler(int opcode, char **buf, int *len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int websocket_create_packet_ex_default_handler(int opcode, char **buf, int *len, char *sendbuf, size_t sendbufsize)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int websocket_create_packet_simple_default_handler(int opcode, const char **buf, int *len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void mtag_add_issued_by_default_handler(MessageTag **mtags, Client *client, MessageTag *recv_mtags)
|
||||
{
|
||||
}
|
||||
|
||||
/** my_timegm: mktime()-like function which will use GMT/UTC.
|
||||
* Strangely enough there is no standard function for this.
|
||||
* On some *NIX OS's timegm() may be available, sometimes only
|
||||
@ -2068,7 +2198,12 @@ int terminal_supports_color(void)
|
||||
#ifndef _WIN32
|
||||
char *s;
|
||||
|
||||
/* Yeah we check all of stdin, stdout, stderr, because
|
||||
/* Support NO_COLOR as per https://no-color.org */
|
||||
s = getenv("NO_COLOR");
|
||||
if (s != NULL && s[0] != '\0')
|
||||
return 0;
|
||||
|
||||
/* Yeah we check all of stdin, stdout, stderr, because one
|
||||
* or more may be redirected (bin/unrealircd >log 2>&1),
|
||||
* and then we want to say no to color support.
|
||||
*/
|
||||
@ -2424,6 +2559,7 @@ void server_reboot(const char *mesg)
|
||||
WinExec(cmdLine, SW_SHOWDEFAULT);
|
||||
}
|
||||
#endif
|
||||
loop.terminating = 1;
|
||||
unload_all_modules();
|
||||
#ifdef _WIN32
|
||||
if (IsService)
|
||||
@ -2504,11 +2640,15 @@ const char *StripControlCodesEx(const char *text, char *output, size_t outputlen
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
if ( col && ((isdigit(*text) && nc < 2) || (*text == ',' && nc < 3)))
|
||||
if ((col && isdigit(*text) && nc < 2) ||
|
||||
((col == 1) && (*text == ',') && isdigit(text[1]) && (nc > 0) && (nc < 3)))
|
||||
{
|
||||
nc++;
|
||||
if (*text == ',')
|
||||
{
|
||||
nc = 0;
|
||||
col++;
|
||||
}
|
||||
}
|
||||
/* Syntax for RGB is ^DHHHHHH where H is a hex digit.
|
||||
* If < 6 hex digits are specified, the code is displayed
|
||||
@ -2611,3 +2751,11 @@ const char *StripControlCodes(const char *text)
|
||||
|
||||
return StripControlCodesEx(text, new_str, sizeof(new_str), 0);
|
||||
}
|
||||
|
||||
const char *command_issued_by_rpc(MessageTag *mtags)
|
||||
{
|
||||
MessageTag *m = find_mtag(mtags, "unrealircd.org/issued-by");
|
||||
if (m && m->value && !strncmp(m->value, "RPC:", 4))
|
||||
return m->value;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1173,7 +1173,7 @@ int mm_compile(ManagedModule *m, char *tmpfile, int test)
|
||||
return 0;
|
||||
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"cd \"%s\"; make custommodule MODULEFILE=\"%s\"",
|
||||
"cd \"%s\"; $MAKE custommodule MODULEFILE=\"%s\"",
|
||||
BUILDDIR,
|
||||
filename_strip_suffix(basename, ".c")
|
||||
);
|
||||
@ -1312,7 +1312,7 @@ void mm_make_install(void)
|
||||
if (no_make_install)
|
||||
return;
|
||||
printf("Running 'make install'...\n");
|
||||
snprintf(cmd, sizeof(cmd), "cd \"%s\"; make install 1>/dev/null 2>&1", BUILDDIR);
|
||||
snprintf(cmd, sizeof(cmd), "cd \"%s\"; $MAKE install 1>/dev/null 2>&1", BUILDDIR);
|
||||
n = system(cmd);
|
||||
}
|
||||
|
||||
@ -1652,6 +1652,46 @@ void mm_parse_c_file(int argc, char *args[])
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int mm_detect_make_is_gmake(void)
|
||||
{
|
||||
FILE *fd;
|
||||
char buf[512], *s;
|
||||
|
||||
fd = popen("$MAKE --version 2>&1", "r");
|
||||
if (fd)
|
||||
{
|
||||
*buf = '\0';
|
||||
s = fgets(buf, sizeof(buf), fd);
|
||||
pclose(fd);
|
||||
if (s && strstr(s, "GNU Make"))
|
||||
return 1; /* Good! We are done. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mm_detect_make(void)
|
||||
{
|
||||
FILE *fd;
|
||||
char *s;
|
||||
char buf[512];
|
||||
|
||||
/* Get or set $MAKE */
|
||||
s = getenv("MAKE");
|
||||
if (!s)
|
||||
setenv("MAKE", "make", 1);
|
||||
|
||||
if (mm_detect_make_is_gmake())
|
||||
return;
|
||||
|
||||
/* Try again with MAKE=gmake */
|
||||
setenv("MAKE", "gmake", 1);
|
||||
if (mm_detect_make_is_gmake())
|
||||
return;
|
||||
|
||||
fprintf(stderr, "ERROR: GNU Make is not found as 'make' or 'gmake'\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void mm_self_test(void)
|
||||
{
|
||||
char name[512];
|
||||
@ -1672,6 +1712,7 @@ void mm_self_test(void)
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
mm_detect_make();
|
||||
}
|
||||
|
||||
void modulemanager(int argc, char *args[])
|
||||
|
@ -430,18 +430,19 @@ const char *Module_Create(const char *path_)
|
||||
if (Mod_Handle)
|
||||
*Mod_Handle = mod;
|
||||
irc_dlsym(Mod, "Mod_Test", Mod_Test);
|
||||
/* add module here, so ModuleSetOptions() w/MOD_OPT_PRIORITY is available in Mod_Test() */
|
||||
AddListItemPrio(mod, Modules, 0);
|
||||
if (Mod_Test)
|
||||
{
|
||||
if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS) {
|
||||
ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i",
|
||||
ret);
|
||||
if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS)
|
||||
{
|
||||
ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i", ret);
|
||||
/* We EXPECT the module to have cleaned up its mess */
|
||||
Module_free(mod);
|
||||
return (errorbuf);
|
||||
}
|
||||
}
|
||||
mod->flags = MODFLAG_TESTING;
|
||||
AddListItemPrio(mod, Modules, 0);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
@ -560,6 +561,9 @@ void FreeModObj(ModuleObject *obj, Module *m)
|
||||
else if (obj->type == MOBJ_HISTORY_BACKEND) {
|
||||
HistoryBackendDel(obj->object.history_backend);
|
||||
}
|
||||
else if (obj->type == MOBJ_RPC) {
|
||||
RPCHandlerDel(obj->object.rpc);
|
||||
}
|
||||
else
|
||||
{
|
||||
unreal_log(ULOG_FATAL, "module", "FREEMODOBJ_UNKNOWN_TYPE", NULL,
|
||||
@ -731,6 +735,8 @@ void module_loadall(void)
|
||||
iFP fp;
|
||||
Module *mi, *next;
|
||||
|
||||
loop.config_status = CONFIG_STATUS_LOAD;
|
||||
|
||||
/* Run through all modules and check for module load */
|
||||
for (mi = Modules; mi; mi = next)
|
||||
{
|
||||
@ -1216,7 +1222,7 @@ void ModuleSetOptions(Module *module, unsigned int options, int action)
|
||||
{
|
||||
unsigned int oldopts = module->options;
|
||||
|
||||
if (options == MOD_OPT_UNLOAD_PRIORITY)
|
||||
if (options == MOD_OPT_PRIORITY)
|
||||
{
|
||||
DelListItem(module, Modules);
|
||||
AddListItemPrio(module, Modules, action);
|
||||
@ -1335,6 +1341,16 @@ int is_module_loaded(const char *name)
|
||||
if (mi->flags & MODFLAG_DELAYED)
|
||||
continue; /* unloading (delayed) */
|
||||
|
||||
/* During config_posttest ignore modules that are loaded,
|
||||
* since we only care about the 'future' state.
|
||||
*/
|
||||
if ((loop.config_status < CONFIG_STATUS_LOAD) &&
|
||||
(loop.config_status >= CONFIG_STATUS_POSTTEST) &&
|
||||
(mi->flags == MODFLAG_LOADED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcasecmp(mi->relpath, name))
|
||||
return 1;
|
||||
}
|
||||
@ -1444,6 +1460,38 @@ void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, long var
|
||||
moddata_local_variable(m).l = var;
|
||||
}
|
||||
|
||||
int LoadPersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long *var)
|
||||
{
|
||||
ModDataInfo *m;
|
||||
const char *fullname = mod_var_name(modinfo, varshortname);
|
||||
|
||||
m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
|
||||
if (m)
|
||||
{
|
||||
*var = moddata_local_variable(m).ll;
|
||||
return 1;
|
||||
} else {
|
||||
ModDataInfo mreq;
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.type = MODDATATYPE_LOCAL_VARIABLE;
|
||||
mreq.name = strdup(fullname);
|
||||
mreq.free = NULL;
|
||||
m = ModDataAdd(modinfo->handle, mreq);
|
||||
moddata_local_variable(m).ll = 0;
|
||||
safe_free(mreq.name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SavePersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long var)
|
||||
{
|
||||
ModDataInfo *m;
|
||||
const char *fullname = mod_var_name(modinfo, varshortname);
|
||||
|
||||
m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
|
||||
moddata_local_variable(m).ll = var;
|
||||
}
|
||||
|
||||
extern int module_has_moddata(Module *mod);
|
||||
extern int module_has_extcmode_param_mode(Module *mod);
|
||||
|
||||
|
@ -39,10 +39,10 @@ MODULES= \
|
||||
sethost.so chghost.so chgident.so setname.so \
|
||||
setident.so sdesc.so svsmode.so swhois.so\
|
||||
svsmotd.so svsnline.so who_old.so whox.so mkpasswd.so \
|
||||
away.so svsnoop.so svsnick.so svso.so \
|
||||
away.so svsnoop.so svsnick.so svso.so svslogin.so \
|
||||
chgname.so kill.so \
|
||||
lag.so message.so oper.so pingpong.so \
|
||||
quit.so sendumode.so sqline.so \
|
||||
quit.so sendumode.so sqline.so sreply.so \
|
||||
tsctl.so unsqline.so whois.so \
|
||||
tkl.so vhost.so cycle.so svsjoin.so svspart.so \
|
||||
svswatch.so svssilence.so sendsno.so svssno.so \
|
||||
@ -59,13 +59,14 @@ MODULES= \
|
||||
botmotd.so lusers.so names.so svsnolag.so addmotd.so \
|
||||
svslusers.so starttls.so webredir.so cap.so \
|
||||
sasl.so md.so certfp.so \
|
||||
tls_antidos.so webirc.so websocket.so \
|
||||
tls_antidos.so connect-flood.so max-unknown-connections-per-ip.so \
|
||||
webirc.so webserver.so websocket_common.so websocket.so \
|
||||
blacklist.so jointhrottle.so \
|
||||
antirandom.so hideserver.so jumpserver.so \
|
||||
ircops.so staff.so nocodes.so \
|
||||
charsys.so antimixedutf8.so authprompt.so sinfo.so \
|
||||
reputation.so connthrottle.so history_backend_mem.so \
|
||||
history_backend_null.so tkldb.so channeldb.so \
|
||||
history_backend_null.so tkldb.so channeldb.so whowasdb.so \
|
||||
restrict-commands.so rmtkl.so require-module.so \
|
||||
account-notify.so \
|
||||
message-tags.so batch.so \
|
||||
@ -79,7 +80,9 @@ MODULES= \
|
||||
monitor.so slog.so tls_cipher.so operinfo.so creationtime.so \
|
||||
unreal_server_compat.so \
|
||||
extended-monitor.so geoip_csv.so \
|
||||
geoip_base.so extjwt.so \
|
||||
geoip_base.so extjwt.so tline.so \
|
||||
standard-replies.so issued-by-tag.so \
|
||||
real-quit-reason.so \
|
||||
$(GEOIP_CLASSIC_OBJECTS) $(GEOIP_MAXMIND_OBJECTS)
|
||||
|
||||
MODULEFLAGS=@MODULEFLAGS@
|
||||
@ -94,6 +97,7 @@ build: $(MODULES)
|
||||
cd chanmodes; $(MAKE) all
|
||||
cd usermodes; $(MAKE) all
|
||||
cd extbans; $(MAKE) all
|
||||
cd rpc; $(MAKE) all
|
||||
cd third; $(MAKE) all
|
||||
|
||||
clean:
|
||||
@ -101,6 +105,7 @@ clean:
|
||||
cd chanmodes; $(MAKE) clean
|
||||
cd usermodes; $(MAKE) clean
|
||||
cd extbans; $(MAKE) clean
|
||||
cd rpc; $(MAKE) clean
|
||||
cd third; $(MAKE) clean
|
||||
|
||||
# Generic *.so rule:
|
||||
|
@ -205,7 +205,7 @@ CMD_OVERRIDE_FUNC(override_msg)
|
||||
/* Short circuit for: remote clients, insufficient parameters,
|
||||
* antimixedutf8::except.
|
||||
*/
|
||||
CallCommandOverride(ovr, client, recv_mtags, parc, parv);
|
||||
CALL_NEXT_COMMAND_OVERRIDE();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ CMD_OVERRIDE_FUNC(override_msg)
|
||||
}
|
||||
}
|
||||
|
||||
CallCommandOverride(ovr, client, recv_mtags, parc, parv);
|
||||
CALL_NEXT_COMMAND_OVERRIDE();
|
||||
}
|
||||
|
||||
/*** rest is module and config stuff ****/
|
||||
|
@ -40,6 +40,7 @@ struct {
|
||||
typedef struct APUser APUser;
|
||||
struct APUser {
|
||||
char *authmsg;
|
||||
char *reason;
|
||||
};
|
||||
|
||||
/* Global variables */
|
||||
@ -55,6 +56,7 @@ int authprompt_sasl_continuation(Client *client, const char *buf);
|
||||
int authprompt_sasl_result(Client *client, int success);
|
||||
int authprompt_place_host_ban(Client *client, int action, const char *reason, long duration);
|
||||
int authprompt_find_tkline_match(Client *client, TKL *tk);
|
||||
int authprompt_pre_local_handshake_timeout(Client *client, const char **comment);
|
||||
int authprompt_pre_connect(Client *client);
|
||||
CMD_FUNC(cmd_auth);
|
||||
void authprompt_md_free(ModData *md);
|
||||
@ -93,6 +95,7 @@ MOD_INIT()
|
||||
HookAdd(modinfo->handle, HOOKTYPE_SASL_RESULT, 0, authprompt_sasl_result);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_PLACE_HOST_BAN, 0, authprompt_place_host_ban);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_FIND_TKLINE_MATCH, 0, authprompt_find_tkline_match);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_HANDSHAKE_TIMEOUT, 0, authprompt_pre_local_handshake_timeout);
|
||||
/* For HOOKTYPE_PRE_LOCAL_CONNECT we want a low priority, so we are called last.
|
||||
* This gives hooks like the one from the blacklist module (pending softban)
|
||||
* a chance to be handled first.
|
||||
@ -118,7 +121,7 @@ static void init_config(void)
|
||||
{
|
||||
/* This sets some default values */
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.enabled = 0;
|
||||
cfg.enabled = 1;
|
||||
}
|
||||
|
||||
static void config_postdefaults(void)
|
||||
@ -229,6 +232,7 @@ void authprompt_md_free(ModData *md)
|
||||
if (se)
|
||||
{
|
||||
safe_free(se->authmsg);
|
||||
safe_free(se->reason);
|
||||
safe_free(se);
|
||||
md->ptr = se = NULL;
|
||||
}
|
||||
@ -294,6 +298,7 @@ void send_first_auth(Client *client)
|
||||
Client *sasl_server;
|
||||
char *addr = BadPtr(client->ip) ? "0" : client->ip;
|
||||
const char *certfp = moddata_client_get(client, "certfp");
|
||||
|
||||
sasl_server = find_client(SASL_SERVER, NULL);
|
||||
if (!sasl_server)
|
||||
{
|
||||
@ -301,6 +306,10 @@ void send_first_auth(Client *client)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make them a user, needed for CHGHOST etc that we may receive */
|
||||
if (!client->user)
|
||||
make_user(client);
|
||||
|
||||
sendto_one(sasl_server, NULL, ":%s SASL %s %s H %s %s",
|
||||
me.id, SASL_SERVER, client->id, addr, addr);
|
||||
|
||||
@ -364,15 +373,26 @@ CMD_FUNC(cmd_auth)
|
||||
send_first_auth(client);
|
||||
}
|
||||
|
||||
void authprompt_tag_as_auth_required(Client *client)
|
||||
void authprompt_tag_as_auth_required(Client *client, const char *reason)
|
||||
{
|
||||
/* Allocate, and therefore indicate, that we are going to handle SASL for this user */
|
||||
if (!SEUSER(client))
|
||||
SetAPUser(client, safe_alloc(sizeof(APUser)));
|
||||
safe_strdup(SEUSER(client)->reason, reason);
|
||||
}
|
||||
|
||||
void authprompt_send_auth_required_message(Client *client)
|
||||
{
|
||||
/* Send the standard-reply ACCOUNT_REQUIRED_TO_CONNECT if the client supports receiving it */
|
||||
if (HasCapability(client, "standard-replies"))
|
||||
{
|
||||
const char *reason = SEUSER(client) && SEUSER(client)->reason ? SEUSER(client)->reason : NULL;
|
||||
if (reason)
|
||||
sendto_one(client, NULL, "FAIL * ACCOUNT_REQUIRED_TO_CONNECT :An account is required to connect: %s", reason);
|
||||
else
|
||||
sendto_one(client, NULL, "FAIL * ACCOUNT_REQUIRED_TO_CONNECT :An account is required to connect");
|
||||
}
|
||||
|
||||
/* Display set::authentication-prompt::message */
|
||||
sendnotice_multiline(client, cfg.message);
|
||||
}
|
||||
@ -383,14 +403,10 @@ int authprompt_place_host_ban(Client *client, int action, const char *reason, lo
|
||||
/* If it's a soft-xx action and the user is not logged in
|
||||
* and the user is not yet online, then we will handle this user.
|
||||
*/
|
||||
if (IsSoftBanAction(action) && !IsLoggedIn(client) && !IsUser(client))
|
||||
if (IsSoftBanAction(action) && !IsLoggedIn(client) && !IsUser(client) && cfg.enabled)
|
||||
{
|
||||
/* Send ban reason */
|
||||
if (reason)
|
||||
sendnotice(client, "%s", reason);
|
||||
|
||||
/* And tag the user */
|
||||
authprompt_tag_as_auth_required(client);
|
||||
authprompt_tag_as_auth_required(client, reason);
|
||||
authprompt_send_auth_required_message(client);
|
||||
return 1; /* pretend user is killed */
|
||||
}
|
||||
@ -403,17 +419,14 @@ int authprompt_find_tkline_match(Client *client, TKL *tkl)
|
||||
/* If it's a soft-xx action and the user is not logged in
|
||||
* and the user is not yet online, then we will handle this user.
|
||||
*/
|
||||
if (TKLIsServerBan(tkl) &&
|
||||
if (cfg.enabled &&
|
||||
TKLIsServerBan(tkl) &&
|
||||
(tkl->ptr.serverban->subtype & TKL_SUBTYPE_SOFT) &&
|
||||
!IsLoggedIn(client) &&
|
||||
!IsUser(client))
|
||||
{
|
||||
/* Send ban reason */
|
||||
if (tkl->ptr.serverban->reason)
|
||||
sendnotice(client, "%s", tkl->ptr.serverban->reason);
|
||||
|
||||
/* And tag the user */
|
||||
authprompt_tag_as_auth_required(client);
|
||||
authprompt_tag_as_auth_required(client, tkl->ptr.serverban->reason);
|
||||
authprompt_send_auth_required_message(client);
|
||||
return 1; /* pretend user is killed */
|
||||
}
|
||||
@ -423,7 +436,7 @@ int authprompt_find_tkline_match(Client *client, TKL *tkl)
|
||||
int authprompt_pre_connect(Client *client)
|
||||
{
|
||||
/* If the user is tagged as auth required and not logged in, then.. */
|
||||
if (SEUSER(client) && !IsLoggedIn(client))
|
||||
if (SEUSER(client) && !IsLoggedIn(client) && cfg.enabled)
|
||||
{
|
||||
authprompt_send_auth_required_message(client);
|
||||
return HOOK_DENY; /* do not process register_user() */
|
||||
@ -478,3 +491,17 @@ int authprompt_sasl_result(Client *client, int success)
|
||||
|
||||
return 1; /* inhibit success/failure message */
|
||||
}
|
||||
|
||||
/** Override the default "Registration timeout" quit reason */
|
||||
int authprompt_pre_local_handshake_timeout(Client *client, const char **comment)
|
||||
{
|
||||
if (SEUSER(client))
|
||||
{
|
||||
if (SEUSER(client)->reason)
|
||||
*comment = SEUSER(client)->reason;
|
||||
else
|
||||
*comment = "Account required to connect";
|
||||
}
|
||||
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
@ -765,8 +765,8 @@ int blacklist_action(Client *client, char *opernotice, BanAction ban_action, cha
|
||||
|
||||
void blacklist_hit(Client *client, Blacklist *bl, int reply)
|
||||
{
|
||||
char opernotice[512], banbuf[512];
|
||||
const char *name[4], *value[4];
|
||||
char opernotice[512], banbuf[512], reply_num[5];
|
||||
const char *name[6], *value[6];
|
||||
BLUser *blu = BLUSER(client);
|
||||
|
||||
if (find_tkline_match(client, 1))
|
||||
@ -779,12 +779,21 @@ void blacklist_hit(Client *client, Blacklist *bl, int reply)
|
||||
snprintf(opernotice, sizeof(opernotice), "[Blacklist] IP %s matches blacklist %s (%s/reply=%d)",
|
||||
GetIP(client), bl->name, bl->backend->dns->name, reply);
|
||||
|
||||
snprintf(reply_num, sizeof(reply_num), "%d", reply);
|
||||
|
||||
name[0] = "ip";
|
||||
value[0] = GetIP(client);
|
||||
name[1] = "server";
|
||||
value[1] = me.name;
|
||||
name[2] = NULL;
|
||||
value[2] = NULL;
|
||||
name[2] = "blacklist";
|
||||
value[2] = bl->name;
|
||||
name[3] = "dnsname";
|
||||
value[3] = bl->backend->dns->name;
|
||||
name[4] = "dnsreply";
|
||||
value[4] = reply_num;
|
||||
name[5] = NULL;
|
||||
value[5] = NULL;
|
||||
/* when adding more, be sure to update the array elements number in the definition of const char *name[] and value[] */
|
||||
|
||||
buildvarstring(bl->reason, banbuf, sizeof(banbuf), name, value);
|
||||
|
||||
|
@ -67,11 +67,9 @@ CMD_FUNC(cmd_botmotd)
|
||||
return;
|
||||
|
||||
tld = find_tld(client);
|
||||
|
||||
motdline = NULL;
|
||||
if (tld)
|
||||
if (tld && tld->botmotd.lines)
|
||||
motdline = tld->botmotd.lines;
|
||||
if (!motdline)
|
||||
else
|
||||
motdline = botmotd.lines;
|
||||
|
||||
if (!motdline)
|
||||
|
@ -27,7 +27,7 @@ void certfp_unserialize(const char *str, ModData *m);
|
||||
int certfp_handshake(Client *client);
|
||||
int certfp_connect(Client *client);
|
||||
int certfp_whois(Client *client, Client *target, NameValuePrioList **list);
|
||||
int certfp_log(Client *client, int detail, json_t *j);
|
||||
int certfp_json_expand_client(Client *client, int detail, json_t *j);
|
||||
|
||||
ModDataInfo *certfp_md; /* Module Data structure which we acquire */
|
||||
|
||||
@ -52,7 +52,7 @@ MOD_INIT()
|
||||
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, certfp_handshake);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, certfp_handshake);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, certfp_whois);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, certfp_log);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, certfp_json_expand_client);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
@ -161,11 +161,14 @@ void certfp_unserialize(const char *str, ModData *m)
|
||||
safe_strdup(m->str, str);
|
||||
}
|
||||
|
||||
int certfp_log(Client *client, int detail, json_t *j)
|
||||
int certfp_json_expand_client(Client *client, int detail, json_t *j)
|
||||
{
|
||||
json_t *tls;
|
||||
const char *str;
|
||||
|
||||
if (detail < 2)
|
||||
return 0;
|
||||
|
||||
str = moddata_client_get(client, "certfp");
|
||||
if (!str)
|
||||
return 0;
|
||||
|
@ -264,7 +264,7 @@ int delayjoin_is_ok(Client *client, Channel *channel, char mode, const char *par
|
||||
|
||||
int visible_in_channel(Client *client, Channel *channel)
|
||||
{
|
||||
return channel_is_delayed(channel) && moded_user_invisible(client, channel);
|
||||
return (channel_is_delayed(channel) || channel_is_post_delayed(channel)) && moded_user_invisible(client, channel);
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,7 +50,7 @@ int history_chanmode_is_ok(Client *client, Channel *channel, char mode, const ch
|
||||
void *history_chanmode_put_param(void *r_in, const char *param);
|
||||
const char *history_chanmode_get_param(void *r_in);
|
||||
const char *history_chanmode_conv_param(const char *param, Client *client, Channel *channel);
|
||||
void history_chanmode_free_param(void *r);
|
||||
int history_chanmode_free_param(void *r, int soft);
|
||||
void *history_chanmode_dup_struct(void *r_in);
|
||||
int history_chanmode_sjoin_check(Channel *channel, void *ourx, void *theirx);
|
||||
int history_channel_destroy(Channel *channel, int *should_destroy);
|
||||
@ -576,9 +576,10 @@ const char *history_chanmode_get_param(void *h_in)
|
||||
}
|
||||
|
||||
/** Free channel mode */
|
||||
void history_chanmode_free_param(void *r)
|
||||
int history_chanmode_free_param(void *r, int soft)
|
||||
{
|
||||
safe_free(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Duplicate the channel mode +H settings */
|
||||
@ -731,7 +732,7 @@ CMD_OVERRIDE_FUNC(override_mode)
|
||||
had_r = 1;
|
||||
}
|
||||
}
|
||||
CallCommandOverride(ovr, client, recv_mtags, parc, parv);
|
||||
CALL_NEXT_COMMAND_OVERRIDE();
|
||||
|
||||
/* If..
|
||||
* - channel was +r
|
||||
|
@ -45,7 +45,7 @@ int cmode_key_is_ok(Client *client, Channel *channel, char mode, const char *par
|
||||
void *cmode_key_put_param(void *r_in, const char *param);
|
||||
const char *cmode_key_get_param(void *r_in);
|
||||
const char *cmode_key_conv_param(const char *param_in, Client *client, Channel *channel);
|
||||
void cmode_key_free_param(void *r);
|
||||
int cmode_key_free_param(void *r, int soft);
|
||||
void *cmode_key_dup_struct(void *r_in);
|
||||
int cmode_key_sjoin_check(Channel *channel, void *ourx, void *theirx);
|
||||
int is_valid_key(const char *key);
|
||||
@ -162,9 +162,10 @@ const char *cmode_key_conv_param(const char *param, Client *client, Channel *cha
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
void cmode_key_free_param(void *r)
|
||||
int cmode_key_free_param(void *r, int soft)
|
||||
{
|
||||
safe_free(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *cmode_key_dup_struct(void *r_in)
|
||||
|
@ -48,7 +48,7 @@ int cmode_limit_is_ok(Client *client, Channel *channel, char mode, const char *p
|
||||
void *cmode_limit_put_param(void *r_in, const char *param);
|
||||
const char *cmode_limit_get_param(void *r_in);
|
||||
const char *cmode_limit_conv_param(const char *param_in, Client *client, Channel *channel);
|
||||
void cmode_limit_free_param(void *r);
|
||||
int cmode_limit_free_param(void *r, int soft);
|
||||
void *cmode_limit_dup_struct(void *r_in);
|
||||
int cmode_limit_sjoin_check(Channel *channel, void *ourx, void *theirx);
|
||||
int transform_channel_limit(const char *param);
|
||||
@ -159,9 +159,10 @@ const char *cmode_limit_conv_param(const char *param, Client *client, Channel *c
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
void cmode_limit_free_param(void *r)
|
||||
int cmode_limit_free_param(void *r, int soft)
|
||||
{
|
||||
safe_free(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *cmode_limit_dup_struct(void *r_in)
|
||||
|
@ -49,7 +49,7 @@ int cmodeL_is_ok(Client *client, Channel *channel, char mode, const char *para,
|
||||
void *cmodeL_put_param(void *r_in, const char *param);
|
||||
const char *cmodeL_get_param(void *r_in);
|
||||
const char *cmodeL_conv_param(const char *param_in, Client *client, Channel *channel);
|
||||
void cmodeL_free_param(void *r);
|
||||
int cmodeL_free_param(void *r, int soft);
|
||||
void *cmodeL_dup_struct(void *r_in);
|
||||
int cmodeL_sjoin_check(Channel *channel, void *ourx, void *theirx);
|
||||
|
||||
@ -178,9 +178,10 @@ const char *cmodeL_conv_param(const char *param, Client *client, Channel *channe
|
||||
return param;
|
||||
}
|
||||
|
||||
void cmodeL_free_param(void *r)
|
||||
int cmodeL_free_param(void *r, int soft)
|
||||
{
|
||||
safe_free(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *cmodeL_dup_struct(void *r_in)
|
||||
|
@ -93,7 +93,7 @@ MOD_INIT()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
/* We must unload early, when all channel modes and such are still in place: */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -99999999);
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -99999999);
|
||||
|
||||
LoadPersistentLong(modinfo, channeldb_next_event);
|
||||
|
||||
@ -359,14 +359,6 @@ int write_channel_entry(UnrealDB *db, const char *tmpfname, Channel *channel)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ban_exists(Ban *lst, Ban *e)
|
||||
{
|
||||
for (; lst; lst = lst->next)
|
||||
if (!mycmp(lst->banstr, e->banstr))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define R_SAFE(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
@ -409,7 +401,7 @@ int read_listmode(UnrealDB *db, Ban **lst)
|
||||
}
|
||||
safe_strdup(e->banstr, str);
|
||||
|
||||
if (ban_exists(*lst, e))
|
||||
if (ban_exists(*lst, e->banstr))
|
||||
{
|
||||
/* Free again - duplicate item */
|
||||
safe_free(e->banstr);
|
||||
@ -545,7 +537,7 @@ int read_channeldb(void)
|
||||
safe_strdup(channel->topic_nick, topic_nick);
|
||||
channel->topic_time = topic_time;
|
||||
safe_strdup(channel->mode_lock, mode_lock);
|
||||
set_channel_mode(channel, modes1, modes2);
|
||||
set_channel_mode(channel, NULL, modes1, modes2);
|
||||
R_SAFE(read_listmode(db, &channel->banlist));
|
||||
R_SAFE(read_listmode(db, &channel->exlist));
|
||||
R_SAFE(read_listmode(db, &channel->invexlist));
|
||||
|
@ -210,6 +210,18 @@ void chathistory_targets(Client *client, HistoryFilter *filter, int limit)
|
||||
sendto_one(client, NULL, ":%s BATCH -%s", me.name, batch);
|
||||
}
|
||||
|
||||
void send_empty_batch(Client *client, const char *target)
|
||||
{
|
||||
char batch[BATCHLEN+1];
|
||||
|
||||
if (HasCapability(client, "batch"))
|
||||
{
|
||||
generate_batch_id(batch);
|
||||
sendto_one(client, NULL, ":%s BATCH +%s chathistory %s", me.name, batch, target);
|
||||
sendto_one(client, NULL, ":%s BATCH -%s", me.name, batch);
|
||||
}
|
||||
}
|
||||
|
||||
CMD_FUNC(cmd_chathistory)
|
||||
{
|
||||
HistoryFilter *filter = NULL;
|
||||
@ -261,6 +273,13 @@ CMD_FUNC(cmd_chathistory)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* We don't support retrieving chathistory for PM's. Send empty response/batch, similar to channels without +H. */
|
||||
if (parv[2][0] != '#')
|
||||
{
|
||||
send_empty_batch(client, parv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
channel = find_channel(parv[2]);
|
||||
if (!channel)
|
||||
{
|
||||
@ -279,14 +298,7 @@ CMD_FUNC(cmd_chathistory)
|
||||
/* Channel is not +H? Send empty response/batch (as per IRCv3 discussion) */
|
||||
if (!has_channel_mode(channel, 'H'))
|
||||
{
|
||||
if (HasCapability(client, "batch"))
|
||||
{
|
||||
char batch[BATCHLEN+1];
|
||||
|
||||
generate_batch_id(batch);
|
||||
sendto_one(client, NULL, ":%s BATCH +%s chathistory %s", me.name, batch, channel->name);
|
||||
sendto_one(client, NULL, ":%s BATCH -%s", me.name, batch);
|
||||
}
|
||||
send_empty_batch(client, channel->name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,21 @@ CMD_FUNC(cmd_chghost)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(target = find_user(parv[1], NULL)))
|
||||
target = find_client(parv[1], NULL);
|
||||
if (!MyUser(client) && !target && (target = find_server_by_uid(parv[1])))
|
||||
{
|
||||
/* CHGHOST for a UID that is not online.
|
||||
* Let's assume it may not YET be online and forward the message to
|
||||
* the remote server and stop processing ourselves.
|
||||
* That server will then handle pre-registered processing of the
|
||||
* CHGHOST and later communicate the host when the user actually
|
||||
* comes online in the UID message.
|
||||
*/
|
||||
sendto_one(target, recv_mtags, ":%s CHGHOST %s %s", client->id, parv[1], parv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target || !target->user)
|
||||
{
|
||||
sendnumeric(client, ERR_NOSUCHNICK, parv[1]);
|
||||
return;
|
||||
@ -328,17 +342,31 @@ CMD_FUNC(cmd_chghost)
|
||||
|
||||
if (!IsULine(client))
|
||||
{
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGHOST_COMMAND", client,
|
||||
"CHGHOST: $client changed the virtual hostname of $target.details to be $new_hostname",
|
||||
log_data_string("change_type", "hostname"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_hostname", parv[2]));
|
||||
const char *issuer = command_issued_by_rpc(recv_mtags);
|
||||
if (issuer)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGHOST_COMMAND", client,
|
||||
"CHGHOST: $issuer changed the virtual hostname of $target.details to be $new_hostname",
|
||||
log_data_string("issuer", issuer),
|
||||
log_data_string("change_type", "hostname"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_hostname", parv[2]));
|
||||
} else {
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGHOST_COMMAND", client,
|
||||
"CHGHOST: $client changed the virtual hostname of $target.details to be $new_hostname",
|
||||
log_data_string("change_type", "hostname"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_hostname", parv[2]));
|
||||
}
|
||||
}
|
||||
|
||||
target->umodes |= UMODE_HIDE;
|
||||
target->umodes |= UMODE_SETHOST;
|
||||
sendto_server(client, 0, 0, NULL, ":%s CHGHOST %s %s", client->id, target->id, parv[2]);
|
||||
|
||||
/* Send to other servers too, unless the client is still in the registration phase (SASL) */
|
||||
if (IsUser(target))
|
||||
sendto_server(client, 0, 0, recv_mtags, ":%s CHGHOST %s %s", client->id, target->id, parv[2]);
|
||||
|
||||
safe_strdup(target->user->virthost, parv[2]);
|
||||
|
||||
userhost_changed(target);
|
||||
}
|
||||
|
@ -85,24 +85,27 @@ CMD_FUNC(cmd_chgident)
|
||||
return;
|
||||
}
|
||||
|
||||
/* illegal?! */
|
||||
for (s = parv[2]; *s; s++)
|
||||
{
|
||||
if ((*s == '~') && (s == parv[2]))
|
||||
continue;
|
||||
if (!isallowed(*s))
|
||||
{
|
||||
legalident = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (legalident == 0)
|
||||
if (!valid_username(parv[2]))
|
||||
{
|
||||
sendnotice(client, "*** /ChgIdent Error: A ident may contain a-z, A-Z, 0-9, '-' & '.' - Please only use them");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(target = find_user(parv[1], NULL)))
|
||||
target = find_client(parv[1], NULL);
|
||||
if (!MyUser(client) && !target && (target = find_server_by_uid(parv[1])))
|
||||
{
|
||||
/* CHGIDENT for a UID that is not online.
|
||||
* Let's assume it may not YET be online and forward the message to
|
||||
* the remote server and stop processing ourselves.
|
||||
* That server will then handle pre-registered processing of the
|
||||
* CHGIDENT and later communicate the host when the user actually
|
||||
* comes online in the UID message.
|
||||
*/
|
||||
sendto_one(target, recv_mtags, ":%s CHGIDENT %s %s", client->id, parv[1], parv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target || !target->user)
|
||||
{
|
||||
sendnumeric(client, ERR_NOSUCHNICK, parv[1]);
|
||||
return;
|
||||
@ -134,16 +137,28 @@ CMD_FUNC(cmd_chgident)
|
||||
}
|
||||
if (!IsULine(client))
|
||||
{
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGIDENT_COMMAND", client,
|
||||
"CHGIDENT: $client changed the username of $target.details to be $new_username",
|
||||
log_data_string("change_type", "username"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_username", parv[2]));
|
||||
const char *issuer = command_issued_by_rpc(recv_mtags);
|
||||
if (issuer)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGIDENT_COMMAND", client,
|
||||
"CHGIDENT: $issuer changed the username of $target.details to be $new_username",
|
||||
log_data_string("issuer", issuer),
|
||||
log_data_string("change_type", "username"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_username", parv[2]));
|
||||
} else {
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGIDENT_COMMAND", client,
|
||||
"CHGIDENT: $client changed the username of $target.details to be $new_username",
|
||||
log_data_string("change_type", "username"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_username", parv[2]));
|
||||
}
|
||||
}
|
||||
|
||||
sendto_server(client, 0, 0, NULL, ":%s CHGIDENT %s %s",
|
||||
client->id, target->id, parv[2]);
|
||||
ircsnprintf(target->user->username, sizeof(target->user->username), "%s", parv[2]);
|
||||
/* Send to other servers too, unless the client is still in the registration phase (SASL) */
|
||||
if (IsUser(target))
|
||||
sendto_server(client, 0, 0, recv_mtags, ":%s CHGIDENT %s %s", client->id, target->id, parv[2]);
|
||||
|
||||
ircsnprintf(target->user->username, sizeof(target->user->username), "%s", parv[2]);
|
||||
userhost_changed(target);
|
||||
}
|
||||
|
@ -97,11 +97,22 @@ CMD_FUNC(cmd_chgname)
|
||||
/* Let's log this first */
|
||||
if (!IsULine(client))
|
||||
{
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGNAME_COMMAND", client,
|
||||
"CHGNAME: $client changed the realname of $target.details to be $new_realname",
|
||||
log_data_string("change_type", "realname"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_realname", parv[2]));
|
||||
const char *issuer = command_issued_by_rpc(recv_mtags);
|
||||
if (issuer)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGNAME_COMMAND", client,
|
||||
"CHGNAME: $issuer changed the realname of $target.details to be $new_realname",
|
||||
log_data_string("issuer", issuer),
|
||||
log_data_string("change_type", "realname"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_realname", parv[2]));
|
||||
} else {
|
||||
unreal_log(ULOG_INFO, "chgcmds", "CHGNAME_COMMAND", client,
|
||||
"CHGNAME: $client changed the realname of $target.details to be $new_realname",
|
||||
log_data_string("change_type", "realname"),
|
||||
log_data_client("target", target),
|
||||
log_data_string("new_realname", parv[2]));
|
||||
}
|
||||
}
|
||||
|
||||
/* set the realname to make ban checking work */
|
||||
@ -118,6 +129,6 @@ CMD_FUNC(cmd_chgname)
|
||||
}
|
||||
}
|
||||
|
||||
sendto_server(client, 0, 0, NULL, ":%s CHGNAME %s :%s",
|
||||
sendto_server(client, 0, 0, recv_mtags, ":%s CHGNAME %s :%s",
|
||||
client->id, target->name, parv[2]);
|
||||
}
|
||||
|
89
src/modules/connect-flood.c
Normal file
89
src/modules/connect-flood.c
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Connection throttling (set::anti-flood::connect-flood)
|
||||
* (C) Copyright 2022- Bram Matthys and the UnrealIRCd team.
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"connect-flood",
|
||||
"6.0.0",
|
||||
"set::anti-flood::connect-flood",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
int connect_flood_accept(Client *client);
|
||||
int connect_flood_ip_change(Client *client, const char *oldip);
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
HookAdd(modinfo->handle, HOOKTYPE_ACCEPT, -3000, connect_flood_accept);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, -3000, connect_flood_ip_change);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
int connect_flood_throttle(Client *client, int exitflags)
|
||||
{
|
||||
int val;
|
||||
char zlinebuf[512];
|
||||
|
||||
if (!(val = throttle_can_connect(client)))
|
||||
{
|
||||
if (exitflags & NO_EXIT_CLIENT)
|
||||
{
|
||||
ircsnprintf(zlinebuf, sizeof(zlinebuf),
|
||||
"ERROR :Closing Link: [%s] (Throttled: Reconnecting too fast) - "
|
||||
"Email %s for more information.\r\n",
|
||||
client->ip, KLINE_ADDRESS);
|
||||
(void)send(client->local->fd, zlinebuf, strlen(zlinebuf), 0);
|
||||
return HOOK_DENY;
|
||||
} else {
|
||||
ircsnprintf(zlinebuf, sizeof(zlinebuf),
|
||||
"Throttled: Reconnecting too fast - "
|
||||
"Email %s for more information.",
|
||||
KLINE_ADDRESS);
|
||||
/* WAS: exit_client(client, NULL, zlinebuf);
|
||||
* Can't use exit_client() here because HOOKTYPE_IP_CHANGE call
|
||||
* may be too deep. Eg: read_packet -> webserver_packet_in ->
|
||||
* webserver_handle_request_header -> webserver_handle_request ->
|
||||
* RunHook().... and then returning without touching anything
|
||||
* after an exit_client() would not be feasible.
|
||||
*/
|
||||
dead_socket(client, zlinebuf);
|
||||
return HOOK_DENY;
|
||||
}
|
||||
}
|
||||
else if (val == 1)
|
||||
add_throttling_bucket(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connect_flood_accept(Client *client)
|
||||
{
|
||||
if (client->local->listener->options & LISTENER_NO_CHECK_CONNECT_FLOOD)
|
||||
return 0;
|
||||
return connect_flood_throttle(client, NO_EXIT_CLIENT);
|
||||
}
|
||||
|
||||
int connect_flood_ip_change(Client *client, const char *oldip)
|
||||
{
|
||||
return connect_flood_throttle(client, 0);
|
||||
}
|
@ -62,8 +62,8 @@ CMD_FUNC(cmd_connect)
|
||||
{
|
||||
int retval;
|
||||
ConfigItem_link *aconf;
|
||||
ConfigItem_deny_link *deny;
|
||||
Client *server;
|
||||
const char *str;
|
||||
|
||||
if (!IsServer(client) && MyConnect(client) && !ValidatePermissionsForPath("route:global",client,NULL,NULL,NULL) && parc > 3)
|
||||
{ /* Only allow LocOps to make */
|
||||
@ -92,12 +92,7 @@ CMD_FUNC(cmd_connect)
|
||||
return;
|
||||
}
|
||||
|
||||
for (aconf = conf_link; aconf; aconf = aconf->next)
|
||||
if (match_simple(parv[1], aconf->servername))
|
||||
break;
|
||||
|
||||
/* Checked first servernames, then try hostnames. */
|
||||
|
||||
aconf = find_link(parv[1]);
|
||||
if (!aconf)
|
||||
{
|
||||
sendnotice(client,
|
||||
@ -114,25 +109,15 @@ CMD_FUNC(cmd_connect)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Evaluate deny link */
|
||||
for (deny = conf_deny_link; deny; deny = deny->next)
|
||||
if ((str = check_deny_link(aconf, 0)))
|
||||
{
|
||||
if (deny->flag.type == CRULE_ALL && unreal_mask_match_string(aconf->servername, deny->mask)
|
||||
&& crule_eval(deny->rule))
|
||||
{
|
||||
sendnotice(client, "*** Connect: Disallowed by connection rule");
|
||||
return;
|
||||
}
|
||||
sendnotice(client, "*** Connect: Disallowed by connection rule: %s", str);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Notify all operators about remote connect requests */
|
||||
if (!MyUser(client))
|
||||
{
|
||||
sendto_server(NULL, 0, 0, NULL,
|
||||
":%s SENDUMODE o :Remote CONNECT %s %s from %s",
|
||||
me.id, parv[1], parv[2] ? parv[2] : "",
|
||||
get_client_name(client, FALSE));
|
||||
}
|
||||
unreal_log(ULOG_INFO, "link", "LINK_REQUEST", client,
|
||||
"CONNECT: Link to $link_block requested by $client",
|
||||
log_data_link_block(aconf));
|
||||
|
||||
connect_server(aconf, client, NULL);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"creationtime",
|
||||
"6.0",
|
||||
"6.1",
|
||||
"Store and retrieve creation time of clients",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
@ -38,6 +38,7 @@ MOD_INIT()
|
||||
mreq.free = creationtime_free;
|
||||
mreq.serialize = creationtime_serialize;
|
||||
mreq.unserialize = creationtime_unserialize;
|
||||
mreq.self_write = 1;
|
||||
mreq.sync = MODDATA_SYNC_EARLY;
|
||||
mreq.type = MODDATATYPE_CLIENT;
|
||||
creationtime_md = ModDataAdd(modinfo->handle, mreq);
|
||||
|
@ -26,7 +26,7 @@ ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"echo-message",
|
||||
"5.0",
|
||||
"Batch CAP",
|
||||
"echo-message CAP",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
@ -35,7 +35,7 @@ R_MODULES= \
|
||||
join.so quiet.so nickchange.so inchannel.so realname.so \
|
||||
account.so operclass.so certfp.so textban.so msgbypass.so \
|
||||
timedban.so partmsg.so securitygroup.so \
|
||||
country.so
|
||||
country.so flood.so
|
||||
|
||||
MODULES=$(R_MODULES)
|
||||
MODULEFLAGS=@MODULEFLAGS@
|
||||
|
@ -66,6 +66,8 @@ MOD_INIT()
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
ISupportAdd(modinfo->handle, "ACCOUNTEXTBAN", "account,a");
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
@ -100,15 +102,15 @@ const char *extban_account_conv_param(BanContext *b, Extban *extban)
|
||||
int extban_account_is_banned(BanContext *b)
|
||||
{
|
||||
/* ~a:0 is special and matches all unauthenticated users */
|
||||
if (!strcmp(b->banstr, "0") && !IsLoggedIn(b->client))
|
||||
return 1;
|
||||
if (!strcmp(b->banstr, "0"))
|
||||
return IsLoggedIn(b->client) ? 0 : 1;
|
||||
|
||||
/* ~a:* matches all authenticated users
|
||||
* (Yes this special code is needed because account
|
||||
* is 0 or * for unauthenticated users)
|
||||
*/
|
||||
if (!strcmp(b->banstr, "*") && IsLoggedIn(b->client))
|
||||
return 1;
|
||||
if (!strcmp(b->banstr, "*"))
|
||||
return IsLoggedIn(b->client) ? 1 : 0;
|
||||
|
||||
if (b->client->user && match_simple(b->banstr, b->client->user->account))
|
||||
return 1;
|
||||
|
187
src/modules/extbans/flood.c
Normal file
187
src/modules/extbans/flood.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Extended ban to exempt from +f/+F checking.
|
||||
* Eg: +e ~flood:*:~account:TrustedBot
|
||||
* (C) Copyright 2023-.. Bram Matthys (Syzop) and the UnrealIRCd team
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "unrealircd.h"
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"extbans/flood",
|
||||
"1.0",
|
||||
"Extban ~flood - exempt from +f/+F checks",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/** Maximum length of the ~flood ban exemption */
|
||||
#define MAX_FLOODBAN_LENGTH 128
|
||||
|
||||
/* Forward declarations */
|
||||
int extban_flood_is_banned(BanContext *b);
|
||||
int flood_extban_is_ok(BanContext *b);
|
||||
const char *flood_extban_conv_param(BanContext *b, Extban *extban);
|
||||
|
||||
/** Called upon module init */
|
||||
MOD_INIT()
|
||||
{
|
||||
ExtbanInfo req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.letter = 'F';
|
||||
req.name = "flood";
|
||||
req.is_ok = flood_extban_is_ok;
|
||||
req.conv_param = flood_extban_conv_param;
|
||||
req.options = EXTBOPT_ACTMODIFIER;
|
||||
if (!ExtbanAdd(modinfo->handle, req))
|
||||
{
|
||||
config_error("could not register extended ban type 'flood'");
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** Called upon module load */
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** Called upon unload */
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** Check if letters in 'str' are valid flood-types.
|
||||
* TODO: ideally this would call a function in chanmode +F module!!
|
||||
*/
|
||||
static int flood_type_ok(char *str)
|
||||
{
|
||||
char *p;
|
||||
|
||||
/* The * (asterisk) simply means ALL. */
|
||||
if (!strcmp(str, "*"))
|
||||
return 1;
|
||||
|
||||
for (p = str; *p; p++)
|
||||
if (!strchr("cjkmntr", *p))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *flood_extban_conv_param(BanContext *b, Extban *extban)
|
||||
{
|
||||
static char retbuf[MAX_FLOODBAN_LENGTH+1];
|
||||
char para[MAX_FLOODBAN_LENGTH+1];
|
||||
char tmpmask[MAX_FLOODBAN_LENGTH+1];
|
||||
char *type; /**< Type(s), such as 'j' */
|
||||
char *matchby; /**< Matching method, such as 'n!u@h' */
|
||||
const char *newmask; /**< Cleaned matching method, such as 'n!u@h' */
|
||||
|
||||
strlcpy(para, b->banstr, sizeof(para)); /* work on a copy (and truncate it) */
|
||||
|
||||
/* ~flood:type:n!u@h for direct matching
|
||||
* ~flood:type:~x:.... when calling another bantype
|
||||
*/
|
||||
|
||||
type = para;
|
||||
matchby = strchr(para, ':');
|
||||
if (!matchby || !matchby[1])
|
||||
return NULL;
|
||||
*matchby++ = '\0';
|
||||
|
||||
/* don't verify type(s), already done in is_ok for local clients */
|
||||
//if (!flood_type_ok(type))
|
||||
// return NULL;
|
||||
/* ... but limit them to a reasonable value :D */
|
||||
if (strlen(type) > 16)
|
||||
return NULL;
|
||||
|
||||
b->banstr = matchby;
|
||||
newmask = extban_conv_param_nuh_or_extban(b, extban);
|
||||
if (BadPtr(newmask))
|
||||
return NULL;
|
||||
|
||||
snprintf(retbuf, sizeof(retbuf), "%s:%s", type, newmask);
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
int flood_extban_syntax(Client *client, int checkt, char *reason)
|
||||
{
|
||||
if (MyUser(client) && (checkt == EXBCHK_PARAM))
|
||||
{
|
||||
sendnotice(client, "Error when setting ban exception: %s", reason);
|
||||
sendnotice(client, " Syntax: +e ~flood:floodtype(s):mask");
|
||||
sendnotice(client, "Example: +e ~flood:*:~account:TrustedUser");
|
||||
sendnotice(client, "Valid flood types are: c, j, k, m, n, t, r, and * for all");
|
||||
sendnotice(client, "Valid masks are: nick!user@host or another extban type such as ~account, ~certfp, etc.");
|
||||
}
|
||||
return 0; /* FAIL: ban rejected */
|
||||
}
|
||||
|
||||
int flood_extban_is_ok(BanContext *b)
|
||||
{
|
||||
static char para[MAX_FLOODBAN_LENGTH+1];
|
||||
char *type; /**< Type(s), such as 'j' */
|
||||
char *matchby; /**< Matching method, such as 'n!u@h' */
|
||||
char *newmask; /**< Cleaned matching method, such as 'n!u@h' */
|
||||
|
||||
/* Always permit deletion */
|
||||
if (b->what == MODE_DEL)
|
||||
return 1;
|
||||
|
||||
if (b->ban_type != EXBTYPE_EXCEPT)
|
||||
{
|
||||
if (b->is_ok_check == EXBCHK_PARAM)
|
||||
sendnotice(b->client, "Ban type ~flood only works with exceptions (+e) and not with bans or invex (+b/+I)");
|
||||
return 0; /* reject */
|
||||
}
|
||||
|
||||
strlcpy(para, b->banstr, sizeof(para)); /* work on a copy (and truncate it) */
|
||||
|
||||
/* ~flood:type:n!u@h for direct matching
|
||||
* ~flood:type:~x:.... when calling another bantype
|
||||
*/
|
||||
|
||||
type = para;
|
||||
matchby = strchr(para, ':');
|
||||
if (!matchby || !matchby[1])
|
||||
return flood_extban_syntax(b->client, b->is_ok_check, "Invalid syntax");
|
||||
*matchby++ = '\0';
|
||||
|
||||
if (!flood_type_ok(type))
|
||||
return flood_extban_syntax(b->client, b->is_ok_check, "Unknown flood type");
|
||||
if (strlen(type) > 16)
|
||||
return flood_extban_syntax(b->client, b->is_ok_check, "Too many flood types specified");
|
||||
|
||||
b->banstr = matchby;
|
||||
if (extban_is_ok_nuh_extban(b) == 0)
|
||||
{
|
||||
/* This could be anything ranging from:
|
||||
* invalid n!u@h syntax, unknown (sub)extbantype,
|
||||
* disabled extban type in conf, too much recursion, etc.
|
||||
*/
|
||||
return flood_extban_syntax(b->client, b->is_ok_check, "Invalid matcher");
|
||||
}
|
||||
|
||||
return 1; /* OK */
|
||||
}
|
@ -112,8 +112,6 @@ MOD_UNLOAD()
|
||||
const char *generic_clean_ban_mask(BanContext *b, Extban *extban)
|
||||
{
|
||||
char *cp, *x;
|
||||
char *user;
|
||||
char *host;
|
||||
static char maskbuf[512];
|
||||
char *mask;
|
||||
|
||||
@ -162,23 +160,7 @@ const char *generic_clean_ban_mask(BanContext *b, Extban *extban)
|
||||
return mask;
|
||||
}
|
||||
|
||||
if ((*mask == '~') && !strchr(mask, '@'))
|
||||
return NULL; /* not an extended ban and not a ~user@host ban either. */
|
||||
|
||||
if ((user = strchr((cp = mask), '!')))
|
||||
*user++ = '\0';
|
||||
if ((host = strrchr(user ? user : cp, '@')))
|
||||
{
|
||||
*host++ = '\0';
|
||||
|
||||
if (!user)
|
||||
return make_nick_user_host(NULL, trim_str(cp,USERLEN),
|
||||
trim_str(host,HOSTLEN));
|
||||
}
|
||||
else if (!user && strchr(cp, '.'))
|
||||
return make_nick_user_host(NULL, NULL, trim_str(cp,HOSTLEN));
|
||||
return make_nick_user_host(trim_str(cp,NICKLEN), trim_str(user,USERLEN),
|
||||
trim_str(host,HOSTLEN));
|
||||
return convert_regular_ban(mask, NULL, 0);
|
||||
}
|
||||
|
||||
/** Convert ban to an acceptable format (or return NULL to fully reject it) */
|
||||
|
@ -28,7 +28,7 @@ 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_log(Client *client, int detail, json_t *j);
|
||||
int geoip_json_expand_client(Client *client, int detail, json_t *j);
|
||||
int geoip_base_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
|
||||
int geoip_base_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
|
||||
EVENT(geoip_base_set_existing_users_evt);
|
||||
@ -126,7 +126,7 @@ MOD_INIT()
|
||||
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_WHOIS, 0, geoip_base_whois);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, geoip_log);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, geoip_json_expand_client);
|
||||
|
||||
CommandAdd(modinfo->handle, "GEOIP", cmd_geoip, MAXPARA, CMD_USER);
|
||||
|
||||
@ -256,7 +256,7 @@ int geoip_connect_extinfo(Client *client, NameValuePrioList **list)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int geoip_log(Client *client, int detail, json_t *j)
|
||||
int geoip_json_expand_client(Client *client, int detail, json_t *j)
|
||||
{
|
||||
GeoIPResult *geo = GEOIPDATA(client);
|
||||
json_t *geoip;
|
||||
|
@ -386,7 +386,7 @@ CMD_OVERRIDE_FUNC(override_map)
|
||||
|
||||
if (IsOper(client))
|
||||
{
|
||||
CallCommandOverride(ovr, client, recv_mtags, parc, parv);
|
||||
CALL_NEXT_COMMAND_OVERRIDE();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -435,7 +435,7 @@ CMD_OVERRIDE_FUNC(override_links)
|
||||
|
||||
if (IsOper(client))
|
||||
{
|
||||
CallCommandOverride(ovr, client, recv_mtags, parc, parv);
|
||||
CALL_NEXT_COMMAND_OVERRIDE();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ MOD_INIT()
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
/* We must unload early, when all channel modes and such are still in place: */
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_UNLOAD_PRIORITY, -99999999);
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -99999999);
|
||||
|
||||
setcfg(&cfg);
|
||||
|
||||
|
155
src/modules/issued-by-tag.c
Normal file
155
src/modules/issued-by-tag.c
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* unrealircd.org/issued-by message tag (server only)
|
||||
* Shows who or what actually issued the command.
|
||||
* (C) Copyright 2023-.. Syzop and The UnrealIRCd Team
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"issued-by-tag",
|
||||
"6.0",
|
||||
"unrealircd.org/issued-by message tag",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
int issued_by_mtag_is_ok(Client *client, const char *name, const char *value);
|
||||
int issued_by_mtag_should_send_to_client(Client *target);
|
||||
void mtag_inherit_issued_by(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature);
|
||||
void _mtag_add_issued_by(MessageTag **mtags, Client *client, MessageTag *recv_mtags);
|
||||
|
||||
MOD_TEST()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_MTAG_GENERATE_ISSUED_BY_IRC, _mtag_add_issued_by);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
MessageTagHandlerInfo mtag;
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
memset(&mtag, 0, sizeof(mtag));
|
||||
mtag.name = "unrealircd.org/issued-by";
|
||||
mtag.is_ok = issued_by_mtag_is_ok;
|
||||
mtag.should_send_to_client = issued_by_mtag_should_send_to_client;
|
||||
mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
|
||||
MessageTagHandlerAdd(modinfo->handle, &mtag);
|
||||
|
||||
HookAddVoid(modinfo->handle, HOOKTYPE_NEW_MESSAGE, 0, mtag_inherit_issued_by);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** This function verifies if the client sending 'unrealircd.org/issued-by'
|
||||
* is permitted to do so and uses a permitted syntax.
|
||||
* We simply allow unrealircd.org/issued-by ONLY from servers and with any syntax.
|
||||
*/
|
||||
int issued_by_mtag_is_ok(Client *client, const char *name, const char *value)
|
||||
{
|
||||
if (IsServer(client))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mtag_inherit_issued_by(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature)
|
||||
{
|
||||
MessageTag *m = find_mtag(recv_mtags, "unrealircd.org/issued-by");
|
||||
if (m)
|
||||
{
|
||||
m = duplicate_mtag(m);
|
||||
AddListItem(m, *mtag_list);
|
||||
}
|
||||
}
|
||||
|
||||
/** Outgoing filter for this message tag */
|
||||
int issued_by_mtag_should_send_to_client(Client *target)
|
||||
{
|
||||
if (IsServer(target) || IsOper(target))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Add "unrealircd.org/issued-by" tag, if applicable.
|
||||
* @param mtags Pointer to the message tags linked list head
|
||||
* @param client The client issuing the command, or NULL for none.
|
||||
* @param recv_mtags The mtags to inherit from, or NULL for none.
|
||||
* @notes If specifying both 'client' and 'recv_mtags' then
|
||||
* if inheritance through 'recv_mtags' takes precedence (if it exists).
|
||||
*
|
||||
* Typical usage is:
|
||||
* For locally generated:
|
||||
* mtag_add_issued_by(&mtags, client, NULL);
|
||||
* For inheriting from remote requests:
|
||||
* mtag_add_issued_by(&mtags, NULL, recv_mtags);
|
||||
* For both, such as if the command is used from RPC:
|
||||
* mtag_add_issued_by(&mtags, client, recv_mtags);
|
||||
*/
|
||||
void _mtag_add_issued_by(MessageTag **mtags, Client *client, MessageTag *recv_mtags)
|
||||
{
|
||||
MessageTag *m;
|
||||
char buf[512];
|
||||
|
||||
m = find_mtag(recv_mtags, "unrealircd.org/issued-by");
|
||||
if (m)
|
||||
{
|
||||
m = duplicate_mtag(m);
|
||||
AddListItem(m, *mtags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client == NULL)
|
||||
return;
|
||||
|
||||
if (IsRPC(client) && client->rpc)
|
||||
{
|
||||
// TODO: test with all of: local rpc through unix socket, local rpc web, RRPC
|
||||
if (client->rpc->issuer)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "RPC:%s@%s:%s", client->rpc->rpc_user, client->uplink->name, client->rpc->issuer);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "RPC:%s@%s", client->rpc->rpc_user, client->uplink->name);
|
||||
}
|
||||
} else
|
||||
if (IsULine(client))
|
||||
{
|
||||
if (IsUser(client))
|
||||
snprintf(buf, sizeof(buf), "SERVICES:%s@%s", client->name, client->uplink->name);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "SERVICES:%s", client->name);
|
||||
} else
|
||||
if (IsOper(client))
|
||||
{
|
||||
const char *operlogin = moddata_client_get(client, "operlogin");
|
||||
if (operlogin)
|
||||
snprintf(buf, sizeof(buf), "OPER:%s@%s:%s", client->name, client->uplink->name, operlogin);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "OPER:%s@%s", client->name, client->uplink->name);
|
||||
} else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m = safe_alloc(sizeof(MessageTag));
|
||||
safe_strdup(m->name, "unrealircd.org/issued-by");
|
||||
safe_strdup(m->value, buf);
|
||||
AddListItem(m, *mtags);
|
||||
}
|
@ -207,7 +207,8 @@ void _send_join_to_local_users(Client *client, Channel *channel, MessageTag *mta
|
||||
}
|
||||
|
||||
/* Routine that actually makes a user join the channel
|
||||
* this does no actual checking (banned, etc.) it just adds the user
|
||||
* this does no actual checking (banned, etc.) it just adds the user.
|
||||
* Note: this is called for local JOIN and remote JOIN, but not for SJOIN.
|
||||
*/
|
||||
void _join_channel(Channel *channel, Client *client, MessageTag *recv_mtags, const char *member_modes)
|
||||
{
|
||||
@ -491,7 +492,7 @@ void _do_join(Client *client, int parc, const char *parv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ValidatePermissionsForPath("immune:server-ban:deny-channel",client,NULL,NULL,NULL) && (tklban = find_qline(client, name, &ishold)))
|
||||
if (!ValidatePermissionsForPath("immune:server-ban:deny-channel",client,NULL,NULL,NULL) && (tklban = find_qline(client, name, &ishold)))
|
||||
{
|
||||
sendnumeric(client, ERR_FORBIDDENCHANNEL, name, tklban->ptr.nameban->reason);
|
||||
continue;
|
||||
|
@ -38,6 +38,12 @@ long CAP_JSON_LOG = 0L;
|
||||
int json_log_mtag_is_ok(Client *client, const char *name, const char *value);
|
||||
int json_log_mtag_should_send_to_client(Client *target);
|
||||
|
||||
MOD_TEST()
|
||||
{
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, -1000000001); /* load very early */
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
ClientCapabilityInfo cap;
|
||||
@ -57,6 +63,7 @@ MOD_INIT()
|
||||
mtag.clicap_handler = c;
|
||||
MessageTagHandlerAdd(modinfo->handle, &mtag);
|
||||
|
||||
ModuleSetOptions(modinfo->handle, MOD_OPT_PRIORITY, 1000000001); /* unload very late */
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ CMD_FUNC(cmd_kick)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsULine(client) || IsServer(client))
|
||||
if (IsULine(client) || IsServer(client) || IsMe(client))
|
||||
goto attack;
|
||||
|
||||
/* Note for coders regarding oper override:
|
||||
|
@ -39,7 +39,7 @@ struct LabeledResponseContext {
|
||||
char batch[BATCHLEN+1]; /**< The generated batch id */
|
||||
int responses; /**< Number of lines sent back to client */
|
||||
int sent_remote; /**< Command has been sent to remote server */
|
||||
char firstbuf[4096]; /**< First buffered response */
|
||||
char firstbuf[MAXLINELENGTH]; /**< First buffered response */
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
@ -59,7 +59,7 @@ void _labeled_response_force_end(void);
|
||||
static LabeledResponseContext currentcmd;
|
||||
static long CAP_LABELED_RESPONSE = 0L;
|
||||
|
||||
static char packet[8192];
|
||||
static char packet[MAXLINELENGTH*2];
|
||||
|
||||
int labeled_response_mtag_is_ok(Client *client, const char *name, const char *value);
|
||||
|
||||
|
@ -107,7 +107,7 @@ MOD_UNLOAD()
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Originally from bahamut, modified a bit for Unreal by codemastr
|
||||
/* Originally from bahamut, modified a bit for UnrealIRCd by codemastr
|
||||
* also Opers can now see +s channels -- codemastr */
|
||||
|
||||
/*
|
||||
@ -316,7 +316,7 @@ CMD_FUNC(cmd_list)
|
||||
* Operates by stepping through the hashtable, sending the entries back if
|
||||
* they match the criteria.
|
||||
* client = Local client to send the output back to.
|
||||
* Taken from bahamut, modified for Unreal by codemastr.
|
||||
* Taken from bahamut, modified for UnrealIRCd by codemastr.
|
||||
*/
|
||||
int send_list(Client *client)
|
||||
{
|
||||
|
96
src/modules/max-unknown-connections-per-ip.c
Normal file
96
src/modules/max-unknown-connections-per-ip.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Connection throttling (set::max-unknown-connections-per-ip)
|
||||
* (C) Copyright 2022- Bram Matthys and the UnrealIRCd team.
|
||||
* License: GPLv2 or later
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
"max-unknown-connections-per-ip",
|
||||
"6.0.0",
|
||||
"set::max-unknown-connections-per-ip",
|
||||
"UnrealIRCd Team",
|
||||
"unrealircd-6",
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
int max_unknown_connections_accept(Client *client);
|
||||
int max_unknown_connections_ip_change(Client *client, const char *oldip);
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
HookAdd(modinfo->handle, HOOKTYPE_ACCEPT, -2000, max_unknown_connections_accept);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, -2000, max_unknown_connections_ip_change);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_UNLOAD()
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
/** This checks set::max-unknown-connections-per-ip,
|
||||
* which is an important safety feature.
|
||||
*/
|
||||
static int check_too_many_unknown_connections(Client *client)
|
||||
{
|
||||
int cnt = 1;
|
||||
Client *c;
|
||||
|
||||
if (!find_tkl_exception(TKL_CONNECT_FLOOD, client))
|
||||
{
|
||||
list_for_each_entry(c, &unknown_list, lclient_node)
|
||||
{
|
||||
if (client->local && client->local->listener &&
|
||||
(client->local->listener->options & LISTENER_NO_CHECK_CONNECT_FLOOD))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(client->ip,GetIP(c)))
|
||||
{
|
||||
cnt++;
|
||||
if (cnt > iConf.max_unknown_connections_per_ip)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max_unknown_connections_accept(Client *client)
|
||||
{
|
||||
if (client->local->listener->options & LISTENER_NO_CHECK_CONNECT_FLOOD)
|
||||
return 0;
|
||||
|
||||
/* Check set::max-unknown-connections-per-ip */
|
||||
if (check_too_many_unknown_connections(client))
|
||||
{
|
||||
send_raw_direct(client, "ERROR :Closing Link: [%s] (Too many unknown connections from your IP)", client->ip);
|
||||
return HOOK_DENY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max_unknown_connections_ip_change(Client *client, const char *oldip)
|
||||
{
|
||||
/* Check set::max-unknown-connections-per-ip */
|
||||
if (check_too_many_unknown_connections(client))
|
||||
{
|
||||
sendto_one(client, NULL, "ERROR :Closing Link: [%s] (Too many unknown connections from your IP)", client->ip);
|
||||
return HOOK_DENY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -170,18 +170,27 @@ void _parse_message_tags(Client *client, char **str, MessageTag **mtag_list)
|
||||
MessageTag *m;
|
||||
|
||||
remainder = strchr(*str, ' ');
|
||||
if (remainder)
|
||||
*remainder = '\0';
|
||||
|
||||
if (!IsServer(client) && (strlen(*str) > 4094))
|
||||
{
|
||||
sendnumeric(client, ERR_INPUTTOOLONG);
|
||||
remainder = NULL; /* stop parsing */
|
||||
}
|
||||
|
||||
if (!remainder)
|
||||
{
|
||||
/* A message with only message tags (or starting with @ anyway).
|
||||
* This is useless. So we make it point to the NUL byte,
|
||||
* aka: empty message.
|
||||
* This is also used by a line-length-check above to force the
|
||||
* same error condition ("don't parse this").
|
||||
*/
|
||||
for (; **str; *str += 1);
|
||||
return;
|
||||
}
|
||||
|
||||
*remainder = '\0';
|
||||
|
||||
/* Now actually parse the tags: */
|
||||
for (element = strtoken(&p, *str+1, ";"); element; element = strtoken(&p, NULL, ";"))
|
||||
{
|
||||
|
@ -537,11 +537,15 @@ const char *_StripColors(const char *text)
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
if ((col && isdigit(*text) && nc < 2) || (col && *text == ',' && nc < 3))
|
||||
if ((col && isdigit(*text) && nc < 2) ||
|
||||
((col == 1) && (*text == ',') && isdigit(text[1]) && (nc > 0) && (nc < 3)))
|
||||
{
|
||||
nc++;
|
||||
if (*text == ',')
|
||||
{
|
||||
nc = 0;
|
||||
col++;
|
||||
}
|
||||
}
|
||||
/* Syntax for RGB is ^DHHHHHH where H is a hex digit.
|
||||
* If < 6 hex digits are specified, the code is displayed
|
||||
|
@ -38,7 +38,7 @@ CMD_FUNC(cmd_mlock);
|
||||
void _do_mode(Channel *channel, Client *client, MessageTag *recv_mtags, int parc, const char *parv[], time_t sendts, int samode);
|
||||
MultiLineMode *_set_mode(Channel *channel, Client *client, int parc, const char *parv[], u_int *pcount,
|
||||
char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]);
|
||||
void _set_channel_mode(Channel *channel, char *modes, char *parameters);
|
||||
void _set_channel_mode(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters);
|
||||
CMD_FUNC(_cmd_umode);
|
||||
|
||||
/* local: */
|
||||
@ -107,12 +107,12 @@ CMD_FUNC(cmd_mode)
|
||||
channel = find_channel(parv[1]);
|
||||
if (!channel)
|
||||
{
|
||||
cmd_umode(client, recv_mtags, parc, parv);
|
||||
CALL_CMD_FUNC(cmd_umode);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
{
|
||||
cmd_umode(client, recv_mtags, parc, parv);
|
||||
CALL_CMD_FUNC(cmd_umode);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
@ -312,6 +312,22 @@ void _do_mode(Channel *channel, Client *client, MessageTag *recv_mtags, int parc
|
||||
MessageTag *mtags = NULL;
|
||||
int should_destroy = 0;
|
||||
|
||||
if (IsUser(orig_client) && samode && MyUser(orig_client))
|
||||
{
|
||||
if (!sajoinmode)
|
||||
{
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf), "%s%s%s", modebuf, *parabuf ? " " : "", parabuf);
|
||||
unreal_log(ULOG_INFO, "samode", "SAMODE_COMMAND", orig_client,
|
||||
"Client $client used SAMODE $channel ($mode)",
|
||||
log_data_channel("channel", channel),
|
||||
log_data_string("mode", buf));
|
||||
}
|
||||
|
||||
client = &me;
|
||||
sendts = 0;
|
||||
}
|
||||
|
||||
if (m->numlines == 1)
|
||||
{
|
||||
/* Single mode lines are easy: retain original msgid etc */
|
||||
@ -350,22 +366,6 @@ void _do_mode(Channel *channel, Client *client, MessageTag *recv_mtags, int parc
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IsUser(orig_client) && samode && MyUser(orig_client))
|
||||
{
|
||||
if (!sajoinmode)
|
||||
{
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf), "%s%s%s", modebuf, *parabuf ? " " : "", parabuf);
|
||||
unreal_log(ULOG_INFO, "samode", "SAMODE_COMMAND", orig_client,
|
||||
"Client $client used SAMODE $channel ($mode)",
|
||||
log_data_channel("channel", channel),
|
||||
log_data_string("mode", buf));
|
||||
}
|
||||
|
||||
client = &me;
|
||||
sendts = 0;
|
||||
}
|
||||
|
||||
sendto_channel(channel, client, NULL, 0, 0, SEND_LOCAL, mtags,
|
||||
":%s MODE %s %s %s",
|
||||
client->name, channel->name, modebuf, parabuf);
|
||||
@ -1545,7 +1545,7 @@ int list_mode_request(Client *client, Channel *channel, const char *req)
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
void _set_channel_mode(Channel *channel, char *modes, char *parameters)
|
||||
void _set_channel_mode(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters)
|
||||
{
|
||||
char buf[512];
|
||||
char *p, *param;
|
||||
@ -1561,7 +1561,7 @@ void _set_channel_mode(Channel *channel, char *modes, char *parameters)
|
||||
myparv[myparc] = NULL;
|
||||
|
||||
SetULine(&me); // hack for crash.. set ulined so no access checks.
|
||||
do_mode(channel, &me, NULL, myparc, (const char **)myparv, 0, 0);
|
||||
do_mode(channel, &me, mtags, myparc, (const char **)myparv, 0, 0);
|
||||
ClearULine(&me); // and clear it again..
|
||||
|
||||
for (i = 0; i < myparc; i++)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user