aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Langhoff <martin@laptop.org>2010-01-24 14:39:15 +0100
committerBadlop <badlop@process-one.net>2010-02-12 20:23:33 +0100
commit10c16b1cdf29799251f5ea19c1c004c60840b94d (patch)
tree537adc8edbe923050197ca8b60cd8bb3a0313b2b /src
parentRemove unnecessary section about Snow Leopard with Erlang R13B (diff)
ejabberdctl: support concurrent connections with bound conn names
If flock is available, ejabberdctl will use it to grab one of a bound number of connection names. This allows concurrent connections while using a bound number of atoms. Using PID, timestamps or random strings for transient connection IDs (which would avoid the need for flock) uses an unbound number of atoms. This can effectively DoS servers, as these connection names are not garbage collected.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in10
-rw-r--r--src/ejabberdctl.template78
2 files changed, 81 insertions, 7 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 8485caa09..02f05e89d 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -110,6 +110,9 @@ MSGSDIR = $(PRIVDIR)/msgs
# /var/lib/ejabberd/
SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
+# /var/lock/ejabberdctl
+CTLLOCKDIR = $(DESTDIR)@localstatedir@/lock/ejabberdctl
+
# /var/lib/ejabberd/.erlang.cookie
COOKIEFILE = $(SPOOLDIR)/.erlang.cookie
@@ -230,6 +233,12 @@ install: all
install -d -m 750 $(O_USER) $(SPOOLDIR)
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(SPOOLDIR) >$(CHOWN_OUTPUT)
chmod -R 750 $(SPOOLDIR)
+
+ # ejabberdctl lock directory
+ install -d -m 750 $(O_USER) $(CTLLOCKDIR)
+ $(CHOWN_COMMAND) -R @INSTALLUSER@ $(CTLLOCKDIR) >$(CHOWN_OUTPUT)
+ chmod -R 750 $(CTLLOCKDIR)
+
[ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; }
#
# Log directory
@@ -265,6 +274,7 @@ uninstall-all: uninstall-binary
rm -rf $(ETCDIR)
rm -rf $(EJABBERDDIR)
rm -rf $(SPOOLDIR)
+ rm -rf $(CTLLOCKDIR)
rm -rf $(LOGDIR)
clean: clean-recursive clean-local
diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template
index 2df7be710..f5af13be2 100644
--- a/src/ejabberdctl.template
+++ b/src/ejabberdctl.template
@@ -14,6 +14,17 @@ ERLANG_NODE=$NODE@$HOST
ERL=@erl@
INSTALLUSER=@installuser@
+# Control number of connections identifiers
+# using flock if available. Expects a linux-style
+# flock that can lock a file descriptor.
+MAXCONNID=100
+CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl
+FLOCK='/usr/bin/flock'
+if [ ! -x "$FLOCK" ];then
+ FLOCK=""
+fi
+
+
# parse command line parameters
ARGS=
while [ $# -ne 0 ] ; do
@@ -228,13 +239,54 @@ help ()
ctl ()
{
COMMAND=$@
- $EXEC_CMD "$ERL \
- $NAME ctl-${ERLANG_NODE} \
- -noinput \
- -hidden \
- -pa $EJABBERD_EBIN_PATH \
- -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
- result=$?
+
+ if [ ! "$FLOCK" ];then
+ # no flock, simply invoke ctlexec()
+ CTL_CONN="ctl-${EJABBERD_NODE}"
+ ctlexec $CTL_CONN $COMMAND
+ result=$?
+ else
+ # we have flock so we get a lock
+ # on one of a limited number of
+ # conn names -- this allows
+ # concurrent invokations using a bound
+ # number of atoms
+ for N in $(seq 1 $MAXCONNID); do
+ CTL_CONN="ejabberdctl-$N"
+ CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN"
+ (
+ exec 8>"$CTL_LOCKFILE"
+ if flock --nb 8; then
+ ctlexec $CTL_CONN $COMMAND
+ ssresult=$?
+ # segregate from possible flock exit(1)
+ ssresult=$(expr $ssresult \* 10)
+ exit $ssresult
+ else
+ exit 1
+ fi
+ )
+ result=$?
+ if [ $result -eq 1 ]; then
+ # means we errored out in flock
+ # rather than in the exec - stay in the loop
+ # trying other conn names...
+ badlock=1
+ else
+ badlock=""
+ break;
+ fi
+ done
+ result=$(expr $result / 10)
+ fi
+
+ if [ "$badlock" ];then
+ echo "Ran out of connections to try. Your ejabberd processes" >&2
+ echo "may be stuck or this is a very busy server. For very" >&2
+ echo "busy servers, consider raising MAXCONNIDS" >&2
+ exit 1;
+ fi
+
case $result in
0) :;;
1) :;;
@@ -244,6 +296,18 @@ ctl ()
return $result
}
+ctlexec ()
+{
+ CONN_NAME=$1; shift
+ COMMAND=$@
+ $EXEC_CMD "$ERL \
+ $NAME ${CONN_NAME} \
+ -noinput \
+ -hidden \
+ -pa $EJABBERD_EBIN_PATH \
+ -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
+}
+
# display ctl usage
usage ()
{