Project

General

Profile

Bug #4337

Multiple radiusd instances are launched upon WAN interface change

Added by Paul K almost 5 years ago. Updated over 4 years ago.

Status:
Resolved
Priority:
Low
Assignee:
-
Category:
FreeRADIUS
Target version:
-
Start date:
01/28/2015
Due date:
% Done:

100%

Estimated time:
Affected Version:
2.2
Affected Architecture:
amd64

Description

I noticed that whenever I change WAN interface settings and apply them multiple radiusd instances are launched. System log looks like this:

Jan 28 18:16:47  radiusd[29916]: /usr/local/etc/raddb/radiusd.conf[36]: Error binding to port for 192.168.20.1 port 1812
Jan 28 18:16:47  radiusd[29916]: Failed binding to authentication address 192.168.20.1 port 1812: Address already in use
Jan 28 18:16:47  radiusd[12359]: Loaded virtual server <default>
Jan 28 18:16:47  radiusd[29600]: Ready to process requests.
Jan 28 18:16:47  radiusd[4843]: Loaded virtual server <default>
Jan 28 18:16:47  radiusd[21581]: Exiting normally.
Jan 28 18:16:47  radiusd[21581]: Signalled to terminate

As we can see old process 21581 was terminated and 2 new processes 29600 and 29916 were spawned. 29916 dies because 29600 was first to bind to the port 1812.

This is the time line of events:

  • /etc/rc.start_packages
  • pkg-utils.inc::sync_package($pkgid)
  • eval($pkg_config['custom_php_resync_config_command']) RUNS freeradius.inc::freeradius_users_resync()
  • service-utils.inc::restart_service('radiusd')
  • service-utils.inc::stop_service($name)
  • /usr/local/etc/rc.d/radiusd.sh stop NOTE: old process stopped
  • service-utils.inc::start_service($name) NOTE: $name is set to "radiusd"
  • /usr/local/etc/rc.d/radiusd.sh start NOTE: first process started
  • service-utils.inc::start_service($internal_name) NOTE: this is second call to function start_service but $internal_name is set to freeradius2 instead of radiusd so this call does not start a process
  • /usr/local/etc/rc.d/radiusd.sh start >>/tmp/bootup_messages 2>&1 & NOTE: this starts second process

This happens because both processes are started almost simultaneously.
If you run "/usr/local/etc/rc.d/radiusd.sh start" while radiusd is running it outputs "radiusd already running? (pid=39987).". That is what I would expect to be saved in /tmp/bootup_messages when second process is started, but "Starting radiusd." is saved in /tmp/bootup_messages instead.

History

#1 Updated by Paul K almost 5 years ago

This also happens on system boot.

#2 Updated by Paul K almost 5 years ago

I dug a little deeper and here is what I discovered.

By the time "radiusd.sh start" is invoked second time, first instance of "radiusd.sh start" has finished executing, but radiusd is not running yet. What is actually running is process "/usr/pbi/.pbirun /usr/local/sbin/radiusd". Function _find_processes() in /etc/rc.subr does not check for this (it only looks for radiusd in the process name which would be /usr/pbi/.pbirun) and thus does not stop script execution and print "radiusd already running? (pid=xxx).".

#3 Updated by Paul K almost 5 years ago

I have modified radiusd.sh to prevent it from being executed in parallel and to wait a bit for the process to start before releasing the lock. It appears to be working great on v2.2. Devs, if you are ok with this solution I can test it with v2.1 and create a proper patch.

#!/bin/sh
# This file was automatically generated
# by the pfSense service handler.

rc_start() {
    SERVICENAME="radiusd" 
    LOCKFILE="/tmp/${SERVICENAME}_start.lock" 
    PIDFILE="/var/run/${SERVICENAME}.pid" 

    # prevent this part of script from running in parallel 
    if ( set -o noclobber; echo "$$" > "$LOCKFILE") 2> /dev/null; then
        # make sure lock file is removed even if script is terminated 
        trap 'rm -f "$LOCKFILE"; exit $?' INT TERM EXIT

        /usr/pbi/freeradius-amd64/local/etc/rc.d/radiusd onestart

        # try to wait until the service starts 
        if [ ! -f "$PIDFILE" ]; then
            echo "$SERVICENAME.sh: PID file was not found" 

            for i in 1 2 3 4 5; do
                if [ -f "$PIDFILE" ]; then
                    echo "$SERVICENAME.sh: Service started PID: `cat $PIDFILE`" 
                    break
                else
                    echo "$SERVICENAME.sh: Waiting 0.5 seconds" 
                    sleep 0.5 
                fi
            done
        else
            echo "$SERVICENAME.sh: Service running PID: `cat $PIDFILE`" 
        fi

        rm -f "$LOCKFILE" 
        trap - INT TERM EXIT
    else
        echo "$SERVICENAME.sh: Cannot continue at this moment, this script is already trying to start service PID: $(cat $LOCKFILE)" 
    fi
}

rc_stop() {
    /usr/pbi/freeradius-amd64/local/etc/rc.d/radiusd onestop
}

case $1 in
    start)
        rc_start
        ;;
    stop)
        rc_stop
        ;;
    restart)
        rc_stop
        rc_start
        ;;
esac

#5 Updated by Anonymous over 4 years ago

  • Status changed from New to Feedback
  • % Done changed from 0 to 100

Applied in changeset commit:00561b63b7171dafe5906abf17cb413e647cdecc.

#6 Updated by Paul K over 4 years ago

Tested, changes are working as expected.

Strangely for the change to show up package must be removed/installed rather than reinstalled. Even though output when reinstalling says "Executing custom_php_install_command()...done.".

#7 Updated by Chris Buechler over 4 years ago

  • Status changed from Feedback to Resolved

Also available in: Atom PDF