Updated to 6.1.0

This commit is contained in:
Dionysus 2023-05-05 18:12:01 -04:00
parent 66d0369626
commit d53bf1d1c0
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
185 changed files with 18624 additions and 7380 deletions

29
Config
View File

@ -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

View File

@ -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).

View File

@ -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)

View File

@ -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

View File

@ -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"],

7557
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ dnl src/windows/unrealinst.iss
dnl doc/Config.header
dnl src/version.c.SH
AC_INIT([unrealircd], [6.0.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])

View File

@ -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.

View File

@ -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.

View File

@ -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";

View File

@ -16,6 +16,7 @@ log {
nomatch;
oper;
operoverride;
rpc;
sacmds;
tkl.BAN_REALNAME;
tkl.RMTKL_COMMAND;

View File

@ -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 {

View File

@ -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

Binary file not shown.

View File

@ -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 ""

View File

@ -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.

View File

@ -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

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "UnrealIRCd"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 6.0.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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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.

View 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);

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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"

View File

@ -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. */

View File

@ -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"

View File

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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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
View 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);
}
}

View File

@ -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' */

File diff suppressed because it is too large Load Diff

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;

View File

@ -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];

View File

@ -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);
}

View File

@ -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
View 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)));
}
}

View File

@ -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
View File

@ -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 */

View File

@ -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>

View File

@ -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)

View File

@ -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;
}

View File

@ -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[])

View File

@ -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);

View File

@ -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:

View File

@ -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 ****/

View File

@ -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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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));

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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]);
}

View 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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -26,7 +26,7 @@ ModuleHeader MOD_HEADER
= {
"echo-message",
"5.0",
"Batch CAP",
"echo-message CAP",
"UnrealIRCd Team",
"unrealircd-6",
};

View File

@ -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@

View File

@ -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
View 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 */
}

View File

@ -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) */

View File

@ -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;

View File

@ -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;
}

View File

@ -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
View 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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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)
{

View 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;
}

View File

@ -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, ";"))
{

View File

@ -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

View File

@ -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