Disable Concurent User Is Useless



  • Pfsense Captive Portal is perfect.But i got naughty users…

    My Target is : 1 Voucher for 1 user . so i cecked Disable Concurrent user logins at captive portal feature.The scenario is running good . if user logged with voucher A , so if another user using this voucher A to login . old user terminating by system. this is good ...but..

    After Running several month i got naughty user , they are shared this voucher about 5 device. My server is busy to terminate old session every seconds...so they are logged to CP alternately.
    So i tested this problem with 2 device can share 1 voucher alternately ,especialy only for browsing or youtube.

    please any solustions besides freeradius ?
    like range login from another device for 15 minutes or denied login if logged
    Please help


  • Netgate

    I would just expire that voucher if you notice and actually care.



  • @Derelict:

    I would just expire that voucher if you notice and actually care.

    U are right but isnt my server only being busy ..me too..  :(



  • Try this :

    Open /etc/inc/captiveportal.inc
    Goto line 2251.

    You will find :

    ....
    		/* on the same ip */
    		if ($cpentry[2] == $clientip) {
    			if (isset($config['captiveportal'][$cpzone]['nomacfilter']) || $cpentry[3] == $clientmac) {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING OLD SESSION");
    			} else {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING IP {$cpentry[2]} WITH DIFFERENT MAC ADDRESS {$cpentry[3]}");
    			}
    			$sessionid = $cpentry[5];
    			break;
    		} elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username)) {
    			// user logged in with an active voucher. Check for how long and calculate
    			// how much time we can give him (voucher credit - used time)
    			$remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
    			if ($remaining_time < 0) { // just in case.
    				$remaining_time = 0;
    			}
    
    			/* This user was already logged in so we disconnect the old one */
    			captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
    			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
    			$unsetindexes[] = $cpentry[5];
    			break;
    		} elseif ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && ($username != 'unauthenticated')) {
    			/* on the same username */
    ....
    

    See also line https://github.com/pfsense/pfsense/blob/9dd655a0c36b907979d497586f9789170de748de/src/etc/inc/captiveportal.inc#L2277 - the
    break;
    command on line 2277 (the github version has env 20 lines more because of the constant evolving of pfSense)
    Insert like this :

    
    		} elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username) && (isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) ) {
    			// user logged in with an active voucher. Check for how long and calculate
    			// how much time we can give him (voucher credit - used time)
    			$remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
    			if ($remaining_time < 0) { // just in case.
    				$remaining_time = 0;
    			}
    
    			/* This user was already logged in so .... we do nothing because "noconcurrentlogins" is set */
    			/* See https://forum.pfsense.org/index.php?topic=147038.0 */ 
    			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING NEW SESSION - NO noconcurrentlogins !");
    			return 0;
    			break;
    
    

    Now, the entire foreach loop look like this :

    	foreach ($cpdb as $cpentry) {
    		if (empty($cpentry[11])) {
    			$cpentry[11] = 'first';
    		}
    		/* on the same ip */
    		if ($cpentry[2] == $clientip) {
    			if (isset($config['captiveportal'][$cpzone]['nomacfilter']) || $cpentry[3] == $clientmac) {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING OLD SESSION");
    			} else {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING IP {$cpentry[2]} WITH DIFFERENT MAC ADDRESS {$cpentry[3]}");
    			}
    			$sessionid = $cpentry[5];
    			break;
    
    		} elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username)) {
    			// user logged in with an active voucher. Check for how long and calculate
    			// how much time we can give him (voucher credit - used time)
    			$remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
    			if ($remaining_time < 0) { // just in case.
    				$remaining_time = 0;
    			}
    
    			/* This user was already logged in so we disconnect the old one */
    			captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
    			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
    			$unsetindexes[] = $cpentry[5];
    			break;
    
    		} elseif ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && ($username != 'unauthenticated')) {
    			/* on the same username */
    			if (strcasecmp($cpentry[4], $username) == 0) {
    				/* This user was already logged in so we disconnect the old one */
    				captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
    				$unsetindexes[] = $cpentry[5];
    				break;
    			}
    		}
    	}
    

    The new special case is
    If vouchers are used and username is not "unauthenticated" and username is already present and noconcurrentlogins is set then the result will be :
    A log line : "CONCURRENT LOGIN - TERMINATING NEW SESSION - NO noconcurrentlogins !");
    And a return 0; so the user will be presented a "voucher expired" message (good english for : "use your own voucher - don't borrow !!" ;)

    Be carefull : I tested this. It worked. A second login using a voucher that was already used ones - and has an session - from another device was ignored, the user will get an error page.
    Normally, the last login using a voucher will remain if "noconcurrentlogins" is set, the old, existing session, is deleted
    You wanted the FIRST session to stay up- and no further usage of the same voucher.

    So I "abused" the "noconcurrentlogins" setting somewhat making a special case for it.

    If this works for you, you have to apply this patch every time you upgrade ( and /etc/inc/captiveportal.inc gets modified/upgraded).

    edit :
    "noconcurrentlogins" should be a tri-state flag in the GUI.
    Like not set = 0 : user can login using the same identification multiple time
    Or
    Set to 1 : user can only use 1 login, the last login will have a session - earlier session using voucher or login with user and paswword will be deleted.
    Or
    Set to 2 : user can only login ones, further logins using the same identification (voucher or login with user and paswword) will not be granted.

    Option 0 and 1 exist already - "2" will be the new one.



  • @Gertjan:

    Try this :

    Open /etc/inc/captiveportal.inc
    Goto line 2251.

    You will find :

    ....
    		/* on the same ip */
    		if ($cpentry[2] == $clientip) {
    			if (isset($config['captiveportal'][$cpzone]['nomacfilter']) || $cpentry[3] == $clientmac) {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING OLD SESSION");
    			} else {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING IP {$cpentry[2]} WITH DIFFERENT MAC ADDRESS {$cpentry[3]}");
    			}
    			$sessionid = $cpentry[5];
    			break;
    		} elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username)) {
    			// user logged in with an active voucher. Check for how long and calculate
    			// how much time we can give him (voucher credit - used time)
    			$remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
    			if ($remaining_time < 0) { // just in case.
    				$remaining_time = 0;
    			}
    
    			/* This user was already logged in so we disconnect the old one */
    			captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
    			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
    			$unsetindexes[] = $cpentry[5];
    			break;
    		} elseif ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && ($username != 'unauthenticated')) {
    			/* on the same username */
    ....
    

    See also line https://github.com/pfsense/pfsense/blob/9dd655a0c36b907979d497586f9789170de748de/src/etc/inc/captiveportal.inc#L2277 - the
    break;
    command on line 2277 (the github version has env 20 lines more because of the constant evolving of pfSense)
    Insert like this :

    
    		} elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username) && (isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) ) {
    			// user logged in with an active voucher. Check for how long and calculate
    			// how much time we can give him (voucher credit - used time)
    			$remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
    			if ($remaining_time < 0) { // just in case.
    				$remaining_time = 0;
    			}
    
    			/* This user was already logged in so .... we do nothing because "noconcurrentlogins" is set */
    			/* See https://forum.pfsense.org/index.php?topic=147038.0 */ 
    			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING NEW SESSION - NO noconcurrentlogins !");
    			return 0;
    			break;
    
    

    Now, the entire foreach loop look like this :

    	foreach ($cpdb as $cpentry) {
    		if (empty($cpentry[11])) {
    			$cpentry[11] = 'first';
    		}
    		/* on the same ip */
    		if ($cpentry[2] == $clientip) {
    			if (isset($config['captiveportal'][$cpzone]['nomacfilter']) || $cpentry[3] == $clientmac) {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING OLD SESSION");
    			} else {
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - REUSING IP {$cpentry[2]} WITH DIFFERENT MAC ADDRESS {$cpentry[3]}");
    			}
    			$sessionid = $cpentry[5];
    			break;
    			
    		} elseif (($attributes['voucher']) && ($username != 'unauthenticated') && ($cpentry[4] == $username)) {
    			// user logged in with an active voucher. Check for how long and calculate
    			// how much time we can give him (voucher credit - used time)
    			$remaining_time = $cpentry[0] + $cpentry[7] - $allow_time;
    			if ($remaining_time < 0) { // just in case.
    				$remaining_time = 0;
    			}
    
    			/* This user was already logged in so we disconnect the old one */
    			captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
    			captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
    			$unsetindexes[] = $cpentry[5];
    			break;
    
    		} elseif ((isset($config['captiveportal'][$cpzone]['noconcurrentlogins'])) && ($username != 'unauthenticated')) {
    			/* on the same username */
    			if (strcasecmp($cpentry[4], $username) == 0) {
    				/* This user was already logged in so we disconnect the old one */
    				captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13);
    				captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION");
    				$unsetindexes[] = $cpentry[5];
    				break;
    			}
    		}
    	}
    

    The new special case is
    If vouchers are used and username is not "unauthenticated" and username is already present and noconcurrentlogins is set then the result will be :
    A log line : "CONCURRENT LOGIN - TERMINATING NEW SESSION - NO noconcurrentlogins !");
    And a return 0; so the user will be presented a "voucher expired" message (good english for : "use your own voucher - don't borrow !!" ;)

    Be carefull : I tested this. It worked. A second login using a voucher that was already used ones - and has an session - from another device was ignored, the user will get an error page.
    Normally, the last login using a voucher will remain if "noconcurrentlogins" is set, the old, existing session, is deleted
    You wanted the FIRST session to stay up- and no further usage of the same voucher.

    So I "abused" the "noconcurrentlogins" setting somewhat making a special case for it.

    If this works for you, you have to apply this patch every time you upgrade ( and /etc/inc/captiveportal.inc gets modified/upgraded).

    edit :
    "noconcurrentlogins" should be a tri-state flag in the GUI.
    Like not set = 0 : user can login using the same identification multiple time
    Or
    Set to 1 : user can only use 1 login, the last login will have a session - earlier session using voucher or login with user and paswword will be deleted.
    Or
    Set to 2 : user can only login ones, further logins using the same identification (voucher or login with user and paswword) will not be granted.

    Option 0 and 1 exist already - "2" will be the new one.

    Thank So much

    I Hope this :

    Set to 2 : user can only login ones, further logins using the same identification (voucher or login with user and paswword) will not be granted.



  • @ayruel:


    I Hope this :
    Set to 2 : user can only login ones, further logins using the same identification (voucher or login with user and paswword) will not be granted.

    Ask for a Feature request here : https://redmine.pfsense.org/projects/pfsense/issues?per_page=100&set_filter=1&tracker_id=2  ;)